1pub mod gadgets;
17pub mod mapping;
18
19pub use gadgets::{
21 apply_crossing_gadgets, apply_simplifier_gadgets, tape_entry_mis_overhead, SourceCell,
22 WeightedTriBranch, WeightedTriBranchFix, WeightedTriBranchFixB, WeightedTriCross,
23 WeightedTriEndTurn, WeightedTriTConDown, WeightedTriTConLeft, WeightedTriTConUp,
24 WeightedTriTapeEntry, WeightedTriTrivialTurnLeft, WeightedTriTrivialTurnRight, WeightedTriTurn,
25 WeightedTriWTurn, WeightedTriangularGadget,
26};
27
28pub use mapping::{
30 map_weighted, map_weighted_with_method, map_weighted_with_order, map_weights, trace_centers,
31 weighted_ruleset,
32};
33
34pub const SPACING: usize = 6;
36
37pub const PADDING: usize = 2;
39
40use super::copyline::create_copylines;
45use super::grid::MappingGrid;
46use super::ksg::mapping::MappingResult;
47use super::ksg::KsgTapeEntry as TapeEntry;
48use super::pathdecomposition::{pathwidth, vertex_order_from_layout, PathDecompositionMethod};
49use crate::rules::unitdiskmapping::ksg::mapping::GridKind;
50use serde::{Deserialize, Serialize};
51
52pub const TRIANGULAR_SPACING: usize = 6;
53pub const TRIANGULAR_PADDING: usize = 2;
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct TriangularTapeEntry {
58 pub gadget_idx: usize,
60 pub row: usize,
62 pub col: usize,
64}
65
66fn crossat_triangular(
68 copylines: &[super::copyline::CopyLine],
69 v: usize,
70 w: usize,
71 spacing: usize,
72 padding: usize,
73) -> (usize, usize) {
74 let line_v = ©lines[v];
75 let line_w = ©lines[w];
76
77 let (line_first, line_second) = if line_v.vslot < line_w.vslot {
79 (line_v, line_w)
80 } else {
81 (line_w, line_v)
82 };
83
84 let hslot = line_first.hslot;
85 let max_vslot = line_second.vslot;
86
87 let row = (hslot - 1) * spacing + 1 + padding; let col = (max_vslot - 1) * spacing + padding; (row, col)
92}
93
94#[derive(Debug, Clone, Copy, PartialEq, Eq)]
96pub enum LegacySourceCell {
97 Empty,
98 Occupied,
99 Connected,
100}
101
102#[allow(dead_code)]
107#[allow(clippy::type_complexity)]
108pub trait TriangularGadget {
109 fn size(&self) -> (usize, usize);
110 fn cross_location(&self) -> (usize, usize);
111 fn is_connected(&self) -> bool;
112 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>);
114 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>);
116 fn mis_overhead(&self) -> i32;
117
118 fn connected_nodes(&self) -> Vec<usize> {
120 vec![]
121 }
122
123 fn source_weights(&self) -> Vec<i32> {
125 let (locs, _, _) = self.source_graph();
126 vec![2; locs.len()]
127 }
128
129 fn mapped_weights(&self) -> Vec<i32> {
131 let (locs, _) = self.mapped_graph();
132 vec![2; locs.len()]
133 }
134
135 fn source_matrix(&self) -> Vec<Vec<LegacySourceCell>> {
138 let (rows, cols) = self.size();
139 let (locs, _, _) = self.source_graph();
140 let mut matrix = vec![vec![LegacySourceCell::Empty; cols]; rows];
141
142 let connected_set: std::collections::HashSet<usize> = if self.is_connected() {
144 self.connected_nodes().into_iter().collect()
145 } else {
146 std::collections::HashSet::new()
147 };
148
149 for (idx, (r, c)) in locs.iter().enumerate() {
150 if *r > 0 && *c > 0 && *r <= rows && *c <= cols {
151 let cell_type = if connected_set.contains(&(idx + 1)) {
152 LegacySourceCell::Connected
153 } else {
154 LegacySourceCell::Occupied
155 };
156 matrix[r - 1][c - 1] = cell_type;
157 }
158 }
159 matrix
160 }
161
162 fn mapped_matrix(&self) -> Vec<Vec<bool>> {
164 let (rows, cols) = self.size();
165 let (locs, _) = self.mapped_graph();
166 let mut matrix = vec![vec![false; cols]; rows];
167 for (r, c) in locs {
168 if r > 0 && c > 0 && r <= rows && c <= cols {
169 matrix[r - 1][c - 1] = true;
170 }
171 }
172 matrix
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
182pub struct TriCross<const CON: bool>;
183
184impl TriangularGadget for TriCross<true> {
185 fn size(&self) -> (usize, usize) {
186 (6, 4)
187 }
188
189 fn cross_location(&self) -> (usize, usize) {
190 (2, 2)
191 }
192
193 fn is_connected(&self) -> bool {
194 true
195 }
196
197 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
198 let locs = vec![
201 (2, 1),
202 (2, 2),
203 (2, 3),
204 (2, 4),
205 (1, 2),
206 (2, 2),
207 (3, 2),
208 (4, 2),
209 (5, 2),
210 (6, 2),
211 ];
212 let edges = vec![
215 (0, 1),
216 (1, 2),
217 (2, 3),
218 (4, 5),
219 (5, 6),
220 (6, 7),
221 (7, 8),
222 (8, 9),
223 (0, 4),
224 ];
225 let pins = vec![0, 4, 9, 3];
227 (locs, edges, pins)
228 }
229
230 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
231 let locs = vec![
233 (1, 2),
234 (2, 1),
235 (2, 2),
236 (2, 3),
237 (1, 4),
238 (3, 3),
239 (4, 2),
240 (4, 3),
241 (5, 1),
242 (6, 1),
243 (6, 2),
244 ];
245 let pins = vec![1, 0, 10, 4];
247 (locs, pins)
248 }
249
250 fn mis_overhead(&self) -> i32 {
251 1
252 }
253
254 fn connected_nodes(&self) -> Vec<usize> {
255 vec![1, 5]
257 }
258
259 fn source_weights(&self) -> Vec<i32> {
260 vec![2; 10]
262 }
263
264 fn mapped_weights(&self) -> Vec<i32> {
265 vec![3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2]
267 }
268}
269
270impl TriangularGadget for TriCross<false> {
271 fn size(&self) -> (usize, usize) {
272 (6, 6)
273 }
274
275 fn cross_location(&self) -> (usize, usize) {
276 (2, 4)
277 }
278
279 fn is_connected(&self) -> bool {
280 false
281 }
282
283 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
284 let locs = vec![
287 (2, 2),
288 (2, 3),
289 (2, 4),
290 (2, 5),
291 (2, 6),
292 (1, 4),
293 (2, 4),
294 (3, 4),
295 (4, 4),
296 (5, 4),
297 (6, 4),
298 (2, 1),
299 ];
300 let edges = vec![
303 (0, 1),
304 (1, 2),
305 (2, 3),
306 (3, 4),
307 (5, 6),
308 (6, 7),
309 (7, 8),
310 (8, 9),
311 (9, 10),
312 (11, 0),
313 ];
314 let pins = vec![11, 5, 10, 4];
316 (locs, edges, pins)
317 }
318
319 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
320 let locs = vec![
322 (1, 4),
323 (2, 2),
324 (2, 3),
325 (2, 4),
326 (2, 5),
327 (2, 6),
328 (3, 2),
329 (3, 3),
330 (3, 4),
331 (3, 5),
332 (4, 2),
333 (4, 3),
334 (5, 2),
335 (6, 3),
336 (6, 4),
337 (2, 1),
338 ];
339 let pins = vec![15, 0, 14, 5];
341 (locs, pins)
342 }
343
344 fn mis_overhead(&self) -> i32 {
345 3
346 }
347
348 fn source_weights(&self) -> Vec<i32> {
349 vec![2; 12]
350 }
351
352 fn mapped_weights(&self) -> Vec<i32> {
353 vec![3, 3, 2, 4, 2, 2, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2]
354 }
355}
356
357#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
365pub struct TriTurn;
366
367impl TriangularGadget for TriTurn {
368 fn size(&self) -> (usize, usize) {
369 (3, 4)
370 }
371
372 fn cross_location(&self) -> (usize, usize) {
373 (2, 2)
374 }
375
376 fn is_connected(&self) -> bool {
377 false
378 }
379
380 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
381 let locs = vec![(1, 2), (2, 2), (2, 3), (2, 4)];
384 let edges = vec![(0, 1), (1, 2), (2, 3)];
385 let pins = vec![0, 3];
387 (locs, edges, pins)
388 }
389
390 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
391 let locs = vec![(1, 2), (2, 2), (3, 3), (2, 4)];
393 let pins = vec![0, 3];
395 (locs, pins)
396 }
397
398 fn mis_overhead(&self) -> i32 {
399 0
400 }
401
402 fn source_weights(&self) -> Vec<i32> {
403 vec![2; 4]
404 }
405
406 fn mapped_weights(&self) -> Vec<i32> {
407 vec![2; 4]
408 }
409}
410
411#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
420pub struct TriBranch;
421
422impl TriangularGadget for TriBranch {
423 fn size(&self) -> (usize, usize) {
424 (6, 4)
425 }
426
427 fn cross_location(&self) -> (usize, usize) {
428 (2, 2)
429 }
430
431 fn is_connected(&self) -> bool {
432 false
433 }
434
435 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
436 let locs = vec![
438 (1, 2),
439 (2, 2),
440 (2, 3),
441 (2, 4),
442 (3, 3),
443 (3, 2),
444 (4, 2),
445 (5, 2),
446 (6, 2),
447 ];
448 let edges = vec![
451 (0, 1),
452 (1, 2),
453 (2, 3),
454 (2, 4),
455 (4, 5),
456 (5, 6),
457 (6, 7),
458 (7, 8),
459 ];
460 let pins = vec![0, 3, 8];
462 (locs, edges, pins)
463 }
464
465 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
466 let locs = vec![
468 (1, 2),
469 (2, 2),
470 (2, 4),
471 (3, 3),
472 (4, 2),
473 (4, 3),
474 (5, 1),
475 (6, 1),
476 (6, 2),
477 ];
478 let pins = vec![0, 2, 8];
480 (locs, pins)
481 }
482
483 fn mis_overhead(&self) -> i32 {
484 0
485 }
486
487 fn source_weights(&self) -> Vec<i32> {
488 vec![2, 2, 3, 2, 2, 2, 2, 2, 2]
490 }
491
492 fn mapped_weights(&self) -> Vec<i32> {
493 vec![2, 2, 2, 3, 2, 2, 2, 2, 2]
495 }
496}
497
498#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
508pub struct TriTConLeft;
509
510impl TriangularGadget for TriTConLeft {
511 fn size(&self) -> (usize, usize) {
512 (6, 5)
513 }
514
515 fn cross_location(&self) -> (usize, usize) {
516 (2, 2)
517 }
518
519 fn is_connected(&self) -> bool {
520 true
521 }
522
523 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
524 let locs = vec![(1, 2), (2, 1), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2)];
526 let edges = vec![(0, 1), (0, 2), (2, 3), (3, 4), (4, 5), (5, 6)];
529 let pins = vec![0, 1, 6];
531 (locs, edges, pins)
532 }
533
534 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
535 let locs = vec![
537 (1, 2),
538 (2, 1),
539 (2, 2),
540 (2, 3),
541 (2, 4),
542 (3, 3),
543 (4, 2),
544 (4, 3),
545 (5, 1),
546 (6, 1),
547 (6, 2),
548 ];
549 let pins = vec![0, 1, 10];
551 (locs, pins)
552 }
553
554 fn mis_overhead(&self) -> i32 {
555 4
556 }
557
558 fn connected_nodes(&self) -> Vec<usize> {
559 vec![1, 2]
561 }
562
563 fn source_weights(&self) -> Vec<i32> {
564 vec![2, 1, 2, 2, 2, 2, 2]
566 }
567
568 fn mapped_weights(&self) -> Vec<i32> {
569 vec![3, 2, 3, 3, 1, 3, 2, 2, 2, 2, 2]
571 }
572}
573
574#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
576pub struct TriTConDown;
577
578impl TriangularGadget for TriTConDown {
579 fn size(&self) -> (usize, usize) {
580 (3, 3)
581 }
582
583 fn cross_location(&self) -> (usize, usize) {
584 (2, 2)
585 }
586
587 fn is_connected(&self) -> bool {
588 true
589 }
590
591 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
592 let locs = vec![(2, 1), (2, 2), (2, 3), (3, 2)];
596 let edges = vec![(0, 1), (1, 2), (0, 3)];
597 let pins = vec![0, 3, 2];
599 (locs, edges, pins)
600 }
601
602 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
603 let locs = vec![(2, 2), (3, 1), (3, 2), (3, 3)];
605 let pins = vec![1, 2, 3];
607 (locs, pins)
608 }
609
610 fn mis_overhead(&self) -> i32 {
611 0
612 }
613
614 fn connected_nodes(&self) -> Vec<usize> {
615 vec![1, 4]
617 }
618
619 fn source_weights(&self) -> Vec<i32> {
620 vec![2, 2, 2, 1]
621 }
622
623 fn mapped_weights(&self) -> Vec<i32> {
624 vec![2, 2, 3, 2]
625 }
626}
627
628#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
630pub struct TriTConUp;
631
632impl TriangularGadget for TriTConUp {
633 fn size(&self) -> (usize, usize) {
634 (3, 3)
635 }
636
637 fn cross_location(&self) -> (usize, usize) {
638 (2, 2)
639 }
640
641 fn is_connected(&self) -> bool {
642 true
643 }
644
645 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
646 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
650 let edges = vec![(0, 1), (1, 2), (2, 3)];
651 let pins = vec![1, 0, 3];
653 (locs, edges, pins)
654 }
655
656 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
657 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
659 let pins = vec![1, 0, 3];
661 (locs, pins)
662 }
663
664 fn mis_overhead(&self) -> i32 {
665 0
666 }
667
668 fn connected_nodes(&self) -> Vec<usize> {
669 vec![1, 2]
671 }
672
673 fn source_weights(&self) -> Vec<i32> {
674 vec![1, 2, 2, 2]
675 }
676
677 fn mapped_weights(&self) -> Vec<i32> {
678 vec![3, 2, 2, 2]
679 }
680}
681
682#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
684pub struct TriTrivialTurnLeft;
685
686impl TriangularGadget for TriTrivialTurnLeft {
687 fn size(&self) -> (usize, usize) {
688 (2, 2)
689 }
690
691 fn cross_location(&self) -> (usize, usize) {
692 (2, 2)
693 }
694
695 fn is_connected(&self) -> bool {
696 true
697 }
698
699 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
700 let locs = vec![(1, 2), (2, 1)];
702 let edges = vec![(0, 1)];
703 let pins = vec![0, 1];
704 (locs, edges, pins)
705 }
706
707 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
708 let locs = vec![(1, 2), (2, 1)];
710 let pins = vec![0, 1];
711 (locs, pins)
712 }
713
714 fn mis_overhead(&self) -> i32 {
715 0
716 }
717
718 fn connected_nodes(&self) -> Vec<usize> {
719 vec![1, 2]
721 }
722
723 fn source_weights(&self) -> Vec<i32> {
724 vec![1, 1]
725 }
726
727 fn mapped_weights(&self) -> Vec<i32> {
728 vec![1, 1]
729 }
730}
731
732#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
734pub struct TriTrivialTurnRight;
735
736impl TriangularGadget for TriTrivialTurnRight {
737 fn size(&self) -> (usize, usize) {
738 (2, 2)
739 }
740
741 fn cross_location(&self) -> (usize, usize) {
742 (1, 2)
743 }
744
745 fn is_connected(&self) -> bool {
746 true
747 }
748
749 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
750 let locs = vec![(1, 1), (2, 2)];
752 let edges = vec![(0, 1)];
753 let pins = vec![0, 1];
754 (locs, edges, pins)
755 }
756
757 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
758 let locs = vec![(2, 1), (2, 2)];
760 let pins = vec![0, 1];
761 (locs, pins)
762 }
763
764 fn mis_overhead(&self) -> i32 {
765 0
766 }
767
768 fn connected_nodes(&self) -> Vec<usize> {
769 vec![1, 2]
771 }
772
773 fn source_weights(&self) -> Vec<i32> {
774 vec![1, 1]
775 }
776
777 fn mapped_weights(&self) -> Vec<i32> {
778 vec![1, 1]
779 }
780}
781
782#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
791pub struct TriEndTurn;
792
793impl TriangularGadget for TriEndTurn {
794 fn size(&self) -> (usize, usize) {
795 (3, 4)
796 }
797
798 fn cross_location(&self) -> (usize, usize) {
799 (2, 2)
800 }
801
802 fn is_connected(&self) -> bool {
803 false
804 }
805
806 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
807 let locs = vec![(1, 2), (2, 2), (2, 3)];
810 let edges = vec![(0, 1), (1, 2)];
811 let pins = vec![0];
813 (locs, edges, pins)
814 }
815
816 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
817 let locs = vec![(1, 2)];
819 let pins = vec![0];
821 (locs, pins)
822 }
823
824 fn mis_overhead(&self) -> i32 {
825 -2
826 }
827
828 fn source_weights(&self) -> Vec<i32> {
829 vec![2, 2, 1]
830 }
831
832 fn mapped_weights(&self) -> Vec<i32> {
833 vec![1]
834 }
835}
836
837#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
845pub struct TriWTurn;
846
847impl TriangularGadget for TriWTurn {
848 fn size(&self) -> (usize, usize) {
849 (4, 4)
850 }
851
852 fn cross_location(&self) -> (usize, usize) {
853 (2, 2)
854 }
855
856 fn is_connected(&self) -> bool {
857 false
858 }
859
860 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
861 let locs = vec![(2, 3), (2, 4), (3, 2), (3, 3), (4, 2)];
863 let edges = vec![(0, 1), (0, 3), (2, 3), (2, 4)];
866 let pins = vec![1, 4];
868 (locs, edges, pins)
869 }
870
871 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
872 let locs = vec![(1, 4), (2, 3), (3, 2), (3, 3), (4, 2)];
874 let pins = vec![0, 4];
876 (locs, pins)
877 }
878
879 fn mis_overhead(&self) -> i32 {
880 0
881 }
882
883 fn source_weights(&self) -> Vec<i32> {
884 vec![2; 5]
885 }
886
887 fn mapped_weights(&self) -> Vec<i32> {
888 vec![2; 5]
889 }
890}
891
892#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
894pub struct TriBranchFix;
895
896impl TriangularGadget for TriBranchFix {
897 fn size(&self) -> (usize, usize) {
898 (4, 4)
899 }
900
901 fn cross_location(&self) -> (usize, usize) {
902 (2, 2)
903 }
904
905 fn is_connected(&self) -> bool {
906 false
907 }
908
909 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
910 let locs = vec![(1, 2), (2, 2), (2, 3), (3, 3), (3, 2), (4, 2)];
913 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
915 let pins = vec![0, 5];
917 (locs, edges, pins)
918 }
919
920 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
921 let locs = vec![(1, 2), (2, 2), (3, 2), (4, 2)];
923 let pins = vec![0, 3];
925 (locs, pins)
926 }
927
928 fn mis_overhead(&self) -> i32 {
929 -2
930 }
931
932 fn source_weights(&self) -> Vec<i32> {
933 vec![2; 6]
934 }
935
936 fn mapped_weights(&self) -> Vec<i32> {
937 vec![2; 4]
938 }
939}
940
941#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
943pub struct TriBranchFixB;
944
945impl TriangularGadget for TriBranchFixB {
946 fn size(&self) -> (usize, usize) {
947 (4, 4)
948 }
949
950 fn cross_location(&self) -> (usize, usize) {
951 (2, 2)
952 }
953
954 fn is_connected(&self) -> bool {
955 false
956 }
957
958 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
959 let locs = vec![(2, 3), (3, 2), (3, 3), (4, 2)];
962 let edges = vec![(0, 2), (1, 2), (1, 3)];
964 let pins = vec![0, 3];
966 (locs, edges, pins)
967 }
968
969 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
970 let locs = vec![(3, 2), (4, 2)];
972 let pins = vec![0, 1];
974 (locs, pins)
975 }
976
977 fn mis_overhead(&self) -> i32 {
978 -2
979 }
980
981 fn source_weights(&self) -> Vec<i32> {
982 vec![2; 4]
983 }
984
985 fn mapped_weights(&self) -> Vec<i32> {
986 vec![2; 2]
987 }
988}
989
990#[allow(clippy::needless_range_loop)]
997fn pattern_matches_triangular<G: TriangularGadget>(
998 gadget: &G,
999 grid: &MappingGrid,
1000 i: usize,
1001 j: usize,
1002) -> bool {
1003 use super::grid::CellState;
1004
1005 let source = gadget.source_matrix();
1006 let (m, n) = gadget.size();
1007
1008 for r in 0..m {
1010 for c in 0..n {
1011 let grid_r = i + r;
1012 let grid_c = j + c;
1013 let expected = source[r][c];
1014 let actual = grid.get(grid_r, grid_c);
1015
1016 match expected {
1017 LegacySourceCell::Empty => {
1018 if actual.map(|c| !c.is_empty()).unwrap_or(false) {
1020 return false;
1021 }
1022 }
1023 LegacySourceCell::Occupied => {
1024 if !actual.map(|c| !c.is_empty()).unwrap_or(false) {
1026 return false;
1027 }
1028 }
1029 LegacySourceCell::Connected => {
1030 match actual {
1032 Some(CellState::Connected { .. }) => {}
1033 _ => return false,
1034 }
1035 }
1036 }
1037 }
1038 }
1039
1040 let (locs, _, _) = gadget.source_graph();
1043 let weights = gadget.source_weights();
1044
1045 for (idx, (loc_r, loc_c)) in locs.iter().enumerate() {
1046 let grid_r = i + loc_r - 1;
1048 let grid_c = j + loc_c - 1;
1049 let expected_weight = weights[idx];
1050
1051 if let Some(cell) = grid.get(grid_r, grid_c) {
1052 if cell.weight() != expected_weight {
1053 return false;
1054 }
1055 } else {
1056 return false;
1057 }
1058 }
1059
1060 true
1061}
1062
1063#[allow(clippy::needless_range_loop)]
1066fn apply_triangular_gadget<G: TriangularGadget>(
1067 gadget: &G,
1068 grid: &mut MappingGrid,
1069 i: usize,
1070 j: usize,
1071) {
1072 use super::grid::CellState;
1073
1074 let source = gadget.source_matrix();
1075 let (m, n) = gadget.size();
1076
1077 for r in 0..m {
1079 for c in 0..n {
1080 if source[r][c] != LegacySourceCell::Empty {
1081 grid.set(i + r, j + c, CellState::Empty);
1082 }
1083 }
1084 }
1085
1086 let (locs, _) = gadget.mapped_graph();
1089 let weights = gadget.mapped_weights();
1090 for (idx, (r, c)) in locs.iter().enumerate() {
1091 if *r > 0 && *c > 0 && *r <= m && *c <= n {
1092 let weight = weights.get(idx).copied().unwrap_or(2);
1093 grid.add_node(i + r - 1, j + c - 1, weight);
1095 }
1096 }
1097}
1098
1099pub fn apply_triangular_crossing_gadgets(
1105 grid: &mut MappingGrid,
1106 copylines: &[super::copyline::CopyLine],
1107 spacing: usize,
1108 padding: usize,
1109) -> Vec<TriangularTapeEntry> {
1110 use std::collections::HashSet;
1111
1112 let mut tape = Vec::new();
1113 let mut processed = HashSet::new();
1114 let n = copylines.len();
1115
1116 for j in 0..n {
1118 for i in 0..n {
1119 let (cross_row, cross_col) = crossat_triangular(copylines, i, j, spacing, padding);
1120
1121 if processed.contains(&(cross_row, cross_col)) {
1124 continue;
1125 }
1126
1127 if let Some(entry) = try_match_triangular_gadget(grid, cross_row, cross_col) {
1129 tape.push(entry);
1130 processed.insert((cross_row, cross_col));
1131 }
1132 }
1133 }
1134
1135 tape
1136}
1137
1138fn try_match_triangular_gadget(
1140 grid: &mut MappingGrid,
1141 cross_row: usize,
1142 cross_col: usize,
1143) -> Option<TriangularTapeEntry> {
1144 macro_rules! try_gadget {
1146 ($gadget:expr, $idx:expr) => {{
1147 let g = $gadget;
1148 let (cr, cc) = g.cross_location();
1149 if cross_row >= cr && cross_col >= cc {
1150 let x = cross_row - cr + 1;
1151 let y = cross_col - cc + 1;
1152 if pattern_matches_triangular(&g, grid, x, y) {
1153 apply_triangular_gadget(&g, grid, x, y);
1154 return Some(TriangularTapeEntry {
1155 gadget_idx: $idx,
1156 row: x,
1157 col: y,
1158 });
1159 }
1160 }
1161 }};
1162 }
1163
1164 try_gadget!(TriCross::<true>, 1);
1169 try_gadget!(TriCross::<false>, 0);
1170 try_gadget!(TriTConLeft, 2);
1171 try_gadget!(TriTConUp, 3);
1172 try_gadget!(TriTConDown, 4);
1173 try_gadget!(TriTrivialTurnLeft, 5);
1174 try_gadget!(TriTrivialTurnRight, 6);
1175 try_gadget!(TriEndTurn, 7);
1176 try_gadget!(TriTurn, 8);
1177 try_gadget!(TriWTurn, 9);
1178 try_gadget!(TriBranchFix, 10);
1179 try_gadget!(TriBranchFixB, 11);
1180 try_gadget!(TriBranch, 12);
1181
1182 None
1183}
1184
1185pub fn triangular_tape_entry_mis_overhead(entry: &TriangularTapeEntry) -> i32 {
1190 match entry.gadget_idx {
1191 0 => TriCross::<false>.mis_overhead(),
1192 1 => TriCross::<true>.mis_overhead(),
1193 2 => TriTConLeft.mis_overhead(),
1194 3 => TriTConUp.mis_overhead(),
1195 4 => TriTConDown.mis_overhead(),
1196 5 => TriTrivialTurnLeft.mis_overhead(),
1197 6 => TriTrivialTurnRight.mis_overhead(),
1198 7 => TriEndTurn.mis_overhead(),
1199 8 => TriTurn.mis_overhead(),
1200 9 => TriWTurn.mis_overhead(),
1201 10 => TriBranchFix.mis_overhead(),
1202 11 => TriBranchFixB.mis_overhead(),
1203 12 => TriBranch.mis_overhead(),
1204 idx if idx >= 100 => -2,
1206 _ => 0,
1207 }
1208}
1209
1210#[allow(dead_code)]
1222pub fn apply_triangular_simplifier_gadgets(
1223 grid: &mut MappingGrid,
1224 nrepeat: usize,
1225) -> Vec<TriangularTapeEntry> {
1226 #[allow(unused)]
1227 use super::grid::CellState;
1228
1229 let mut tape = Vec::new();
1230 let (rows, cols) = grid.size();
1231
1232 for _ in 0..nrepeat {
1233 for j in 0..cols {
1236 for i in 0..rows {
1237 if try_apply_dangling_leg_down(grid, i, j) {
1239 tape.push(TriangularTapeEntry {
1240 gadget_idx: 100, row: i,
1242 col: j,
1243 });
1244 }
1245 if try_apply_dangling_leg_up(grid, i, j) {
1247 tape.push(TriangularTapeEntry {
1248 gadget_idx: 101, row: i,
1250 col: j,
1251 });
1252 }
1253 if try_apply_dangling_leg_right(grid, i, j) {
1255 tape.push(TriangularTapeEntry {
1256 gadget_idx: 102, row: i,
1258 col: j,
1259 });
1260 }
1261 if try_apply_dangling_leg_left(grid, i, j) {
1263 tape.push(TriangularTapeEntry {
1264 gadget_idx: 103, row: i,
1266 col: j,
1267 });
1268 }
1269 }
1270 }
1271 }
1272
1273 tape
1274}
1275
1276#[allow(dead_code)]
1278fn try_apply_dangling_leg_down(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1279 use super::grid::CellState;
1280
1281 let (rows, cols) = grid.size();
1282
1283 if i + 3 >= rows || j + 2 >= cols {
1285 return false;
1286 }
1287
1288 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1290
1291 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1293 grid.get(row, col).is_some_and(|c| c.weight() == w)
1294 };
1295
1296 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) {
1298 return false;
1299 }
1300
1301 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 1) || !is_empty(i + 1, j + 2) {
1303 return false;
1304 }
1305
1306 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 2) || !is_empty(i + 2, j + 2) {
1308 return false;
1309 }
1310
1311 if !is_empty(i + 3, j) || !has_weight(i + 3, j + 1, 2) || !is_empty(i + 3, j + 2) {
1313 return false;
1314 }
1315
1316 grid.set(i + 1, j + 1, CellState::Empty);
1318 grid.set(i + 2, j + 1, CellState::Empty);
1319 grid.set(i + 3, j + 1, CellState::Occupied { weight: 1 });
1320
1321 true
1322}
1323
1324#[allow(dead_code)]
1326fn try_apply_dangling_leg_up(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1327 use super::grid::CellState;
1328
1329 let (rows, cols) = grid.size();
1330
1331 if i + 3 >= rows || j + 2 >= cols {
1333 return false;
1334 }
1335
1336 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1337
1338 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1339 grid.get(row, col).is_some_and(|c| c.weight() == w)
1340 };
1341
1342 if !is_empty(i, j) || !has_weight(i, j + 1, 2) || !is_empty(i, j + 2) {
1344 return false;
1345 }
1346
1347 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 2) || !is_empty(i + 1, j + 2) {
1349 return false;
1350 }
1351
1352 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 1) || !is_empty(i + 2, j + 2) {
1354 return false;
1355 }
1356
1357 if !is_empty(i + 3, j) || !is_empty(i + 3, j + 1) || !is_empty(i + 3, j + 2) {
1359 return false;
1360 }
1361
1362 grid.set(i + 1, j + 1, CellState::Empty);
1364 grid.set(i + 2, j + 1, CellState::Empty);
1365 grid.set(i, j + 1, CellState::Occupied { weight: 1 });
1366
1367 true
1368}
1369
1370#[allow(dead_code)]
1372fn try_apply_dangling_leg_right(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1373 use super::grid::CellState;
1374
1375 let (rows, cols) = grid.size();
1376
1377 if i + 2 >= rows || j + 3 >= cols {
1379 return false;
1380 }
1381
1382 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1383
1384 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1385 grid.get(row, col).is_some_and(|c| c.weight() == w)
1386 };
1387
1388 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1390 return false;
1391 }
1392
1393 if !has_weight(i + 1, j, 2)
1395 || !has_weight(i + 1, j + 1, 2)
1396 || !has_weight(i + 1, j + 2, 1)
1397 || !is_empty(i + 1, j + 3)
1398 {
1399 return false;
1400 }
1401
1402 if !is_empty(i + 2, j)
1404 || !is_empty(i + 2, j + 1)
1405 || !is_empty(i + 2, j + 2)
1406 || !is_empty(i + 2, j + 3)
1407 {
1408 return false;
1409 }
1410
1411 grid.set(i + 1, j + 1, CellState::Empty);
1413 grid.set(i + 1, j + 2, CellState::Empty);
1414 grid.set(i + 1, j, CellState::Occupied { weight: 1 });
1415
1416 true
1417}
1418
1419#[allow(dead_code)]
1421fn try_apply_dangling_leg_left(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1422 use super::grid::CellState;
1423
1424 let (rows, cols) = grid.size();
1425
1426 if i + 2 >= rows || j + 3 >= cols {
1428 return false;
1429 }
1430
1431 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1432
1433 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1434 grid.get(row, col).is_some_and(|c| c.weight() == w)
1435 };
1436
1437 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1439 return false;
1440 }
1441
1442 if !is_empty(i + 1, j)
1444 || !has_weight(i + 1, j + 1, 1)
1445 || !has_weight(i + 1, j + 2, 2)
1446 || !has_weight(i + 1, j + 3, 2)
1447 {
1448 return false;
1449 }
1450
1451 if !is_empty(i + 2, j)
1453 || !is_empty(i + 2, j + 1)
1454 || !is_empty(i + 2, j + 2)
1455 || !is_empty(i + 2, j + 3)
1456 {
1457 return false;
1458 }
1459
1460 grid.set(i + 1, j + 1, CellState::Empty);
1462 grid.set(i + 1, j + 2, CellState::Empty);
1463 grid.set(i + 1, j + 3, CellState::Occupied { weight: 1 });
1464
1465 true
1466}
1467
1468pub fn map_graph_triangular(num_vertices: usize, edges: &[(usize, usize)]) -> MappingResult {
1473 map_graph_triangular_with_method(num_vertices, edges, PathDecompositionMethod::Auto)
1474}
1475
1476pub fn map_graph_triangular_with_method(
1478 num_vertices: usize,
1479 edges: &[(usize, usize)],
1480 method: PathDecompositionMethod,
1481) -> MappingResult {
1482 let layout = pathwidth(num_vertices, edges, method);
1483 let vertex_order = vertex_order_from_layout(&layout);
1484 map_graph_triangular_with_order(num_vertices, edges, &vertex_order)
1485}
1486
1487pub fn map_graph_triangular_with_order(
1492 num_vertices: usize,
1493 edges: &[(usize, usize)],
1494 vertex_order: &[usize],
1495) -> MappingResult {
1496 assert!(num_vertices > 0, "num_vertices must be > 0");
1497
1498 let spacing = TRIANGULAR_SPACING;
1499 let padding = TRIANGULAR_PADDING;
1500
1501 let copylines = create_copylines(num_vertices, edges, vertex_order);
1502
1503 let max_hslot = copylines.iter().map(|l| l.hslot).max().unwrap_or(1);
1508 let max_vstop = copylines.iter().map(|l| l.vstop).max().unwrap_or(1);
1509
1510 let rows = max_hslot.max(max_vstop) * spacing + 2 + 2 * padding;
1511 let cols = (num_vertices - 1) * spacing + 2 + 2 * padding;
1513
1514 let mut grid = MappingGrid::with_padding(rows, cols, spacing, padding);
1515
1516 for line in ©lines {
1519 for (row, col, weight) in line.copyline_locations_triangular(padding, spacing) {
1520 grid.add_node(row, col, weight as i32);
1521 }
1522 }
1523
1524 for &(u, v) in edges {
1526 let u_line = ©lines[u];
1527 let v_line = ©lines[v];
1528
1529 let (smaller_line, larger_line) = if u_line.vslot < v_line.vslot {
1530 (u_line, v_line)
1531 } else {
1532 (v_line, u_line)
1533 };
1534
1535 let (row, col) = crossat_triangular(
1536 ©lines,
1537 smaller_line.vertex,
1538 larger_line.vertex,
1539 spacing,
1540 padding,
1541 );
1542
1543 if col > 0 {
1545 grid.connect(row, col - 1);
1546 }
1547 if row > 0 && grid.is_occupied(row - 1, col) {
1548 grid.connect(row - 1, col);
1549 } else if row + 1 < grid.size().0 && grid.is_occupied(row + 1, col) {
1550 grid.connect(row + 1, col);
1551 }
1552 }
1553
1554 let mut triangular_tape =
1556 apply_triangular_crossing_gadgets(&mut grid, ©lines, spacing, padding);
1557
1558 let simplifier_tape = apply_triangular_simplifier_gadgets(&mut grid, 10);
1562 triangular_tape.extend(simplifier_tape);
1563
1564 let copyline_overhead: i32 = copylines
1567 .iter()
1568 .map(|line| super::copyline::mis_overhead_copyline_triangular(line, spacing))
1569 .sum();
1570
1571 let gadget_overhead: i32 = triangular_tape
1573 .iter()
1574 .map(triangular_tape_entry_mis_overhead)
1575 .sum();
1576 let mis_overhead = copyline_overhead + gadget_overhead;
1577
1578 let tape: Vec<TapeEntry> = triangular_tape
1580 .into_iter()
1581 .map(|entry| TapeEntry {
1582 pattern_idx: entry.gadget_idx,
1583 row: entry.row,
1584 col: entry.col,
1585 })
1586 .collect();
1587
1588 let doubled_cells = grid.doubled_cells();
1590
1591 let (positions, node_weights): (Vec<(i32, i32)>, Vec<i32>) = grid
1593 .occupied_coords()
1594 .into_iter()
1595 .filter_map(|(row, col)| {
1596 grid.get(row, col)
1597 .map(|cell| ((row as i32, col as i32), cell.weight()))
1598 })
1599 .filter(|&(_, w)| w > 0)
1600 .unzip();
1601
1602 MappingResult {
1603 positions,
1604 node_weights,
1605 grid_dimensions: grid.size(),
1606 kind: GridKind::Triangular,
1607 lines: copylines,
1608 padding,
1609 spacing,
1610 mis_overhead,
1611 tape,
1612 doubled_cells,
1613 }
1614}
1615
1616#[cfg(test)]
1617#[path = "../../../unit_tests/rules/unitdiskmapping/triangular/mod.rs"]
1618mod tests;