1use super::super::grid::{CellState, MappingGrid};
7use serde::{Deserialize, Serialize};
8use std::collections::HashSet;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum SourceCell {
13 Empty,
14 Occupied,
15 Connected,
16}
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
20pub struct WeightedTriTapeEntry {
21 pub gadget_idx: usize,
23 pub row: usize,
25 pub col: usize,
27}
28
29#[allow(dead_code)]
34#[allow(clippy::type_complexity)]
35pub trait WeightedTriangularGadget {
36 fn size(&self) -> (usize, usize);
37 fn cross_location(&self) -> (usize, usize);
38 fn is_connected(&self) -> bool;
39 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>);
41 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>);
43 fn mis_overhead(&self) -> i32;
44
45 fn connected_nodes(&self) -> Vec<usize> {
47 vec![]
48 }
49
50 fn source_weights(&self) -> Vec<i32> {
52 let (locs, _, _) = self.source_graph();
53 vec![2; locs.len()]
54 }
55
56 fn mapped_weights(&self) -> Vec<i32> {
58 let (locs, _) = self.mapped_graph();
59 vec![2; locs.len()]
60 }
61
62 fn source_matrix(&self) -> Vec<Vec<SourceCell>> {
65 let (rows, cols) = self.size();
66 let (locs, _, _) = self.source_graph();
67 let mut matrix = vec![vec![SourceCell::Empty; cols]; rows];
68
69 let connected_set: HashSet<usize> = if self.is_connected() {
71 self.connected_nodes().into_iter().collect()
72 } else {
73 HashSet::new()
74 };
75
76 for (idx, (r, c)) in locs.iter().enumerate() {
77 if *r > 0 && *c > 0 && *r <= rows && *c <= cols {
78 let cell_type = if connected_set.contains(&(idx + 1)) {
79 SourceCell::Connected
80 } else {
81 SourceCell::Occupied
82 };
83 matrix[r - 1][c - 1] = cell_type;
84 }
85 }
86 matrix
87 }
88
89 fn mapped_matrix(&self) -> Vec<Vec<bool>> {
91 let (rows, cols) = self.size();
92 let (locs, _) = self.mapped_graph();
93 let mut matrix = vec![vec![false; cols]; rows];
94 for (r, c) in locs {
95 if r > 0 && c > 0 && r <= rows && c <= cols {
96 matrix[r - 1][c - 1] = true;
97 }
98 }
99 matrix
100 }
101}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
109pub struct WeightedTriCross<const CON: bool>;
110
111impl WeightedTriangularGadget for WeightedTriCross<true> {
112 fn size(&self) -> (usize, usize) {
113 (6, 4)
114 }
115
116 fn cross_location(&self) -> (usize, usize) {
117 (2, 2)
118 }
119
120 fn is_connected(&self) -> bool {
121 true
122 }
123
124 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
125 let locs = vec![
128 (2, 1),
129 (2, 2),
130 (2, 3),
131 (2, 4),
132 (1, 2),
133 (2, 2),
134 (3, 2),
135 (4, 2),
136 (5, 2),
137 (6, 2),
138 ];
139 let edges = vec![
142 (0, 1),
143 (1, 2),
144 (2, 3),
145 (4, 5),
146 (5, 6),
147 (6, 7),
148 (7, 8),
149 (8, 9),
150 (0, 4),
151 ];
152 let pins = vec![0, 4, 9, 3];
154 (locs, edges, pins)
155 }
156
157 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
158 let locs = vec![
160 (1, 2),
161 (2, 1),
162 (2, 2),
163 (2, 3),
164 (1, 4),
165 (3, 3),
166 (4, 2),
167 (4, 3),
168 (5, 1),
169 (6, 1),
170 (6, 2),
171 ];
172 let pins = vec![1, 0, 10, 4];
174 (locs, pins)
175 }
176
177 fn mis_overhead(&self) -> i32 {
178 1
179 }
180
181 fn connected_nodes(&self) -> Vec<usize> {
182 vec![1, 5]
184 }
185
186 fn source_weights(&self) -> Vec<i32> {
187 vec![2; 10]
189 }
190
191 fn mapped_weights(&self) -> Vec<i32> {
192 vec![3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2]
194 }
195}
196
197impl WeightedTriangularGadget for WeightedTriCross<false> {
198 fn size(&self) -> (usize, usize) {
199 (6, 6)
200 }
201
202 fn cross_location(&self) -> (usize, usize) {
203 (2, 4)
204 }
205
206 fn is_connected(&self) -> bool {
207 false
208 }
209
210 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
211 let locs = vec![
214 (2, 2),
215 (2, 3),
216 (2, 4),
217 (2, 5),
218 (2, 6),
219 (1, 4),
220 (2, 4),
221 (3, 4),
222 (4, 4),
223 (5, 4),
224 (6, 4),
225 (2, 1),
226 ];
227 let edges = vec![
230 (0, 1),
231 (1, 2),
232 (2, 3),
233 (3, 4),
234 (5, 6),
235 (6, 7),
236 (7, 8),
237 (8, 9),
238 (9, 10),
239 (11, 0),
240 ];
241 let pins = vec![11, 5, 10, 4];
243 (locs, edges, pins)
244 }
245
246 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
247 let locs = vec![
249 (1, 4),
250 (2, 2),
251 (2, 3),
252 (2, 4),
253 (2, 5),
254 (2, 6),
255 (3, 2),
256 (3, 3),
257 (3, 4),
258 (3, 5),
259 (4, 2),
260 (4, 3),
261 (5, 2),
262 (6, 3),
263 (6, 4),
264 (2, 1),
265 ];
266 let pins = vec![15, 0, 14, 5];
268 (locs, pins)
269 }
270
271 fn mis_overhead(&self) -> i32 {
272 3
273 }
274
275 fn source_weights(&self) -> Vec<i32> {
276 vec![2; 12]
277 }
278
279 fn mapped_weights(&self) -> Vec<i32> {
280 vec![3, 3, 2, 4, 2, 2, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2]
281 }
282}
283
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
292pub struct WeightedTriTurn;
293
294impl WeightedTriangularGadget for WeightedTriTurn {
295 fn size(&self) -> (usize, usize) {
296 (3, 4)
297 }
298
299 fn cross_location(&self) -> (usize, usize) {
300 (2, 2)
301 }
302
303 fn is_connected(&self) -> bool {
304 false
305 }
306
307 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
308 let locs = vec![(1, 2), (2, 2), (2, 3), (2, 4)];
311 let edges = vec![(0, 1), (1, 2), (2, 3)];
312 let pins = vec![0, 3];
314 (locs, edges, pins)
315 }
316
317 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
318 let locs = vec![(1, 2), (2, 2), (3, 3), (2, 4)];
320 let pins = vec![0, 3];
322 (locs, pins)
323 }
324
325 fn mis_overhead(&self) -> i32 {
326 0
327 }
328
329 fn source_weights(&self) -> Vec<i32> {
330 vec![2; 4]
331 }
332
333 fn mapped_weights(&self) -> Vec<i32> {
334 vec![2; 4]
335 }
336}
337
338#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
347pub struct WeightedTriBranch;
348
349impl WeightedTriangularGadget for WeightedTriBranch {
350 fn size(&self) -> (usize, usize) {
351 (6, 4)
352 }
353
354 fn cross_location(&self) -> (usize, usize) {
355 (2, 2)
356 }
357
358 fn is_connected(&self) -> bool {
359 false
360 }
361
362 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
363 let locs = vec![
365 (1, 2),
366 (2, 2),
367 (2, 3),
368 (2, 4),
369 (3, 3),
370 (3, 2),
371 (4, 2),
372 (5, 2),
373 (6, 2),
374 ];
375 let edges = vec![
378 (0, 1),
379 (1, 2),
380 (2, 3),
381 (2, 4),
382 (4, 5),
383 (5, 6),
384 (6, 7),
385 (7, 8),
386 ];
387 let pins = vec![0, 3, 8];
389 (locs, edges, pins)
390 }
391
392 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
393 let locs = vec![
395 (1, 2),
396 (2, 2),
397 (2, 4),
398 (3, 3),
399 (4, 2),
400 (4, 3),
401 (5, 1),
402 (6, 1),
403 (6, 2),
404 ];
405 let pins = vec![0, 2, 8];
407 (locs, pins)
408 }
409
410 fn mis_overhead(&self) -> i32 {
411 0
412 }
413
414 fn source_weights(&self) -> Vec<i32> {
415 vec![2, 2, 3, 2, 2, 2, 2, 2, 2]
417 }
418
419 fn mapped_weights(&self) -> Vec<i32> {
420 vec![2, 2, 2, 3, 2, 2, 2, 2, 2]
422 }
423}
424
425#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
435pub struct WeightedTriTConLeft;
436
437impl WeightedTriangularGadget for WeightedTriTConLeft {
438 fn size(&self) -> (usize, usize) {
439 (6, 5)
440 }
441
442 fn cross_location(&self) -> (usize, usize) {
443 (2, 2)
444 }
445
446 fn is_connected(&self) -> bool {
447 true
448 }
449
450 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
451 let locs = vec![(1, 2), (2, 1), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2)];
453 let edges = vec![(0, 1), (0, 2), (2, 3), (3, 4), (4, 5), (5, 6)];
456 let pins = vec![0, 1, 6];
458 (locs, edges, pins)
459 }
460
461 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
462 let locs = vec![
464 (1, 2),
465 (2, 1),
466 (2, 2),
467 (2, 3),
468 (2, 4),
469 (3, 3),
470 (4, 2),
471 (4, 3),
472 (5, 1),
473 (6, 1),
474 (6, 2),
475 ];
476 let pins = vec![0, 1, 10];
478 (locs, pins)
479 }
480
481 fn mis_overhead(&self) -> i32 {
482 4
483 }
484
485 fn connected_nodes(&self) -> Vec<usize> {
486 vec![1, 2]
488 }
489
490 fn source_weights(&self) -> Vec<i32> {
491 vec![2, 1, 2, 2, 2, 2, 2]
493 }
494
495 fn mapped_weights(&self) -> Vec<i32> {
496 vec![3, 2, 3, 3, 1, 3, 2, 2, 2, 2, 2]
498 }
499}
500
501#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
503pub struct WeightedTriTConDown;
504
505impl WeightedTriangularGadget for WeightedTriTConDown {
506 fn size(&self) -> (usize, usize) {
507 (3, 3)
508 }
509
510 fn cross_location(&self) -> (usize, usize) {
511 (2, 2)
512 }
513
514 fn is_connected(&self) -> bool {
515 true
516 }
517
518 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
519 let locs = vec![(2, 1), (2, 2), (2, 3), (3, 2)];
523 let edges = vec![(0, 1), (1, 2), (0, 3)];
524 let pins = vec![0, 3, 2];
526 (locs, edges, pins)
527 }
528
529 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
530 let locs = vec![(2, 2), (3, 1), (3, 2), (3, 3)];
532 let pins = vec![1, 2, 3];
534 (locs, pins)
535 }
536
537 fn mis_overhead(&self) -> i32 {
538 0
539 }
540
541 fn connected_nodes(&self) -> Vec<usize> {
542 vec![1, 4]
544 }
545
546 fn source_weights(&self) -> Vec<i32> {
547 vec![2, 2, 2, 1]
548 }
549
550 fn mapped_weights(&self) -> Vec<i32> {
551 vec![2, 2, 3, 2]
552 }
553}
554
555#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
557pub struct WeightedTriTConUp;
558
559impl WeightedTriangularGadget for WeightedTriTConUp {
560 fn size(&self) -> (usize, usize) {
561 (3, 3)
562 }
563
564 fn cross_location(&self) -> (usize, usize) {
565 (2, 2)
566 }
567
568 fn is_connected(&self) -> bool {
569 true
570 }
571
572 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
573 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
577 let edges = vec![(0, 1), (1, 2), (2, 3)];
578 let pins = vec![1, 0, 3];
580 (locs, edges, pins)
581 }
582
583 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
584 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
586 let pins = vec![1, 0, 3];
588 (locs, pins)
589 }
590
591 fn mis_overhead(&self) -> i32 {
592 0
593 }
594
595 fn connected_nodes(&self) -> Vec<usize> {
596 vec![1, 2]
598 }
599
600 fn source_weights(&self) -> Vec<i32> {
601 vec![1, 2, 2, 2]
602 }
603
604 fn mapped_weights(&self) -> Vec<i32> {
605 vec![3, 2, 2, 2]
606 }
607}
608
609#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
611pub struct WeightedTriTrivialTurnLeft;
612
613impl WeightedTriangularGadget for WeightedTriTrivialTurnLeft {
614 fn size(&self) -> (usize, usize) {
615 (2, 2)
616 }
617
618 fn cross_location(&self) -> (usize, usize) {
619 (2, 2)
620 }
621
622 fn is_connected(&self) -> bool {
623 true
624 }
625
626 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
627 let locs = vec![(1, 2), (2, 1)];
629 let edges = vec![(0, 1)];
630 let pins = vec![0, 1];
631 (locs, edges, pins)
632 }
633
634 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
635 let locs = vec![(1, 2), (2, 1)];
637 let pins = vec![0, 1];
638 (locs, pins)
639 }
640
641 fn mis_overhead(&self) -> i32 {
642 0
643 }
644
645 fn connected_nodes(&self) -> Vec<usize> {
646 vec![1, 2]
648 }
649
650 fn source_weights(&self) -> Vec<i32> {
651 vec![1, 1]
652 }
653
654 fn mapped_weights(&self) -> Vec<i32> {
655 vec![1, 1]
656 }
657}
658
659#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
661pub struct WeightedTriTrivialTurnRight;
662
663impl WeightedTriangularGadget for WeightedTriTrivialTurnRight {
664 fn size(&self) -> (usize, usize) {
665 (2, 2)
666 }
667
668 fn cross_location(&self) -> (usize, usize) {
669 (1, 2)
670 }
671
672 fn is_connected(&self) -> bool {
673 true
674 }
675
676 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
677 let locs = vec![(1, 1), (2, 2)];
679 let edges = vec![(0, 1)];
680 let pins = vec![0, 1];
681 (locs, edges, pins)
682 }
683
684 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
685 let locs = vec![(2, 1), (2, 2)];
687 let pins = vec![0, 1];
688 (locs, pins)
689 }
690
691 fn mis_overhead(&self) -> i32 {
692 0
693 }
694
695 fn connected_nodes(&self) -> Vec<usize> {
696 vec![1, 2]
698 }
699
700 fn source_weights(&self) -> Vec<i32> {
701 vec![1, 1]
702 }
703
704 fn mapped_weights(&self) -> Vec<i32> {
705 vec![1, 1]
706 }
707}
708
709#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
718pub struct WeightedTriEndTurn;
719
720impl WeightedTriangularGadget for WeightedTriEndTurn {
721 fn size(&self) -> (usize, usize) {
722 (3, 4)
723 }
724
725 fn cross_location(&self) -> (usize, usize) {
726 (2, 2)
727 }
728
729 fn is_connected(&self) -> bool {
730 false
731 }
732
733 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
734 let locs = vec![(1, 2), (2, 2), (2, 3)];
737 let edges = vec![(0, 1), (1, 2)];
738 let pins = vec![0];
740 (locs, edges, pins)
741 }
742
743 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
744 let locs = vec![(1, 2)];
746 let pins = vec![0];
748 (locs, pins)
749 }
750
751 fn mis_overhead(&self) -> i32 {
752 -2
753 }
754
755 fn source_weights(&self) -> Vec<i32> {
756 vec![2, 2, 1]
757 }
758
759 fn mapped_weights(&self) -> Vec<i32> {
760 vec![1]
761 }
762}
763
764#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
772pub struct WeightedTriWTurn;
773
774impl WeightedTriangularGadget for WeightedTriWTurn {
775 fn size(&self) -> (usize, usize) {
776 (4, 4)
777 }
778
779 fn cross_location(&self) -> (usize, usize) {
780 (2, 2)
781 }
782
783 fn is_connected(&self) -> bool {
784 false
785 }
786
787 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
788 let locs = vec![(2, 3), (2, 4), (3, 2), (3, 3), (4, 2)];
790 let edges = vec![(0, 1), (0, 3), (2, 3), (2, 4)];
793 let pins = vec![1, 4];
795 (locs, edges, pins)
796 }
797
798 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
799 let locs = vec![(1, 4), (2, 3), (3, 2), (3, 3), (4, 2)];
801 let pins = vec![0, 4];
803 (locs, pins)
804 }
805
806 fn mis_overhead(&self) -> i32 {
807 0
808 }
809
810 fn source_weights(&self) -> Vec<i32> {
811 vec![2; 5]
812 }
813
814 fn mapped_weights(&self) -> Vec<i32> {
815 vec![2; 5]
816 }
817}
818
819#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
821pub struct WeightedTriBranchFix;
822
823impl WeightedTriangularGadget for WeightedTriBranchFix {
824 fn size(&self) -> (usize, usize) {
825 (4, 4)
826 }
827
828 fn cross_location(&self) -> (usize, usize) {
829 (2, 2)
830 }
831
832 fn is_connected(&self) -> bool {
833 false
834 }
835
836 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
837 let locs = vec![(1, 2), (2, 2), (2, 3), (3, 3), (3, 2), (4, 2)];
840 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
842 let pins = vec![0, 5];
844 (locs, edges, pins)
845 }
846
847 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
848 let locs = vec![(1, 2), (2, 2), (3, 2), (4, 2)];
850 let pins = vec![0, 3];
852 (locs, pins)
853 }
854
855 fn mis_overhead(&self) -> i32 {
856 -2
857 }
858
859 fn source_weights(&self) -> Vec<i32> {
860 vec![2; 6]
861 }
862
863 fn mapped_weights(&self) -> Vec<i32> {
864 vec![2; 4]
865 }
866}
867
868#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
870pub struct WeightedTriBranchFixB;
871
872impl WeightedTriangularGadget for WeightedTriBranchFixB {
873 fn size(&self) -> (usize, usize) {
874 (4, 4)
875 }
876
877 fn cross_location(&self) -> (usize, usize) {
878 (2, 2)
879 }
880
881 fn is_connected(&self) -> bool {
882 false
883 }
884
885 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
886 let locs = vec![(2, 3), (3, 2), (3, 3), (4, 2)];
889 let edges = vec![(0, 2), (1, 2), (1, 3)];
891 let pins = vec![0, 3];
893 (locs, edges, pins)
894 }
895
896 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
897 let locs = vec![(3, 2), (4, 2)];
899 let pins = vec![0, 1];
901 (locs, pins)
902 }
903
904 fn mis_overhead(&self) -> i32 {
905 -2
906 }
907
908 fn source_weights(&self) -> Vec<i32> {
909 vec![2; 4]
910 }
911
912 fn mapped_weights(&self) -> Vec<i32> {
913 vec![2; 2]
914 }
915}
916
917#[allow(clippy::needless_range_loop)]
928fn pattern_matches<G: WeightedTriangularGadget>(
929 gadget: &G,
930 grid: &MappingGrid,
931 i: usize,
932 j: usize,
933) -> bool {
934 let source = gadget.source_matrix();
935 let (m, n) = gadget.size();
936
937 for r in 0..m {
939 for c in 0..n {
940 let grid_r = i + r;
941 let grid_c = j + c;
942 let expected = source[r][c];
943 let actual = grid.get(grid_r, grid_c);
944
945 match expected {
946 SourceCell::Empty => {
947 if actual.map(|c| !c.is_empty()).unwrap_or(false) {
949 return false;
950 }
951 }
952 SourceCell::Occupied => {
953 if !actual.map(|c| !c.is_empty()).unwrap_or(false) {
955 return false;
956 }
957 }
958 SourceCell::Connected => {
959 match actual {
961 Some(CellState::Connected { .. }) => {}
962 _ => return false,
963 }
964 }
965 }
966 }
967 }
968
969 let (locs, _, _) = gadget.source_graph();
972 let weights = gadget.source_weights();
973
974 for (idx, (loc_r, loc_c)) in locs.iter().enumerate() {
975 let grid_r = i + loc_r - 1;
977 let grid_c = j + loc_c - 1;
978 let expected_weight = weights[idx];
979
980 if let Some(cell) = grid.get(grid_r, grid_c) {
981 if cell.weight() != expected_weight {
982 return false;
983 }
984 } else {
985 return false;
986 }
987 }
988
989 true
990}
991
992#[allow(clippy::needless_range_loop)]
995fn apply_gadget<G: WeightedTriangularGadget>(
996 gadget: &G,
997 grid: &mut MappingGrid,
998 i: usize,
999 j: usize,
1000) {
1001 let source = gadget.source_matrix();
1002 let (m, n) = gadget.size();
1003
1004 for r in 0..m {
1006 for c in 0..n {
1007 if source[r][c] != SourceCell::Empty {
1008 grid.set(i + r, j + c, CellState::Empty);
1009 }
1010 }
1011 }
1012
1013 let (locs, _) = gadget.mapped_graph();
1016 let weights = gadget.mapped_weights();
1017 for (idx, (r, c)) in locs.iter().enumerate() {
1018 if *r > 0 && *c > 0 && *r <= m && *c <= n {
1019 let weight = weights.get(idx).copied().unwrap_or(2);
1020 grid.add_node(i + r - 1, j + c - 1, weight);
1022 }
1023 }
1024}
1025
1026fn try_match_gadget(
1028 grid: &mut MappingGrid,
1029 cross_row: usize,
1030 cross_col: usize,
1031) -> Option<WeightedTriTapeEntry> {
1032 macro_rules! try_gadget {
1034 ($gadget:expr, $idx:expr) => {{
1035 let g = $gadget;
1036 let (cr, cc) = g.cross_location();
1037 if cross_row >= cr && cross_col >= cc {
1038 let x = cross_row - cr + 1;
1039 let y = cross_col - cc + 1;
1040 if pattern_matches(&g, grid, x, y) {
1041 apply_gadget(&g, grid, x, y);
1042 return Some(WeightedTriTapeEntry {
1043 gadget_idx: $idx,
1044 row: x,
1045 col: y,
1046 });
1047 }
1048 }
1049 }};
1050 }
1051
1052 try_gadget!(WeightedTriCross::<true>, 1);
1057 try_gadget!(WeightedTriCross::<false>, 0);
1058 try_gadget!(WeightedTriTConLeft, 2);
1059 try_gadget!(WeightedTriTConUp, 3);
1060 try_gadget!(WeightedTriTConDown, 4);
1061 try_gadget!(WeightedTriTrivialTurnLeft, 5);
1062 try_gadget!(WeightedTriTrivialTurnRight, 6);
1063 try_gadget!(WeightedTriEndTurn, 7);
1064 try_gadget!(WeightedTriTurn, 8);
1065 try_gadget!(WeightedTriWTurn, 9);
1066 try_gadget!(WeightedTriBranchFix, 10);
1067 try_gadget!(WeightedTriBranchFixB, 11);
1068 try_gadget!(WeightedTriBranch, 12);
1069
1070 None
1071}
1072
1073fn crossat(
1075 copylines: &[super::super::copyline::CopyLine],
1076 v: usize,
1077 w: usize,
1078 spacing: usize,
1079 padding: usize,
1080) -> (usize, usize) {
1081 let line_v = ©lines[v];
1082 let line_w = ©lines[w];
1083
1084 let (line_first, line_second) = if line_v.vslot < line_w.vslot {
1086 (line_v, line_w)
1087 } else {
1088 (line_w, line_v)
1089 };
1090
1091 let hslot = line_first.hslot;
1092 let max_vslot = line_second.vslot;
1093
1094 let row = (hslot - 1) * spacing + 1 + padding; let col = (max_vslot - 1) * spacing + padding; (row, col)
1099}
1100
1101pub fn apply_crossing_gadgets(
1107 grid: &mut MappingGrid,
1108 copylines: &[super::super::copyline::CopyLine],
1109 spacing: usize,
1110 padding: usize,
1111) -> Vec<WeightedTriTapeEntry> {
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(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_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
1138#[allow(dead_code)]
1146pub fn apply_simplifier_gadgets(
1147 grid: &mut MappingGrid,
1148 nrepeat: usize,
1149) -> Vec<WeightedTriTapeEntry> {
1150 let mut tape = Vec::new();
1151 let (rows, cols) = grid.size();
1152
1153 for _ in 0..nrepeat {
1154 for j in 0..cols {
1157 for i in 0..rows {
1158 if try_apply_dangling_leg_down(grid, i, j) {
1160 tape.push(WeightedTriTapeEntry {
1161 gadget_idx: 100, row: i,
1163 col: j,
1164 });
1165 }
1166 if try_apply_dangling_leg_up(grid, i, j) {
1168 tape.push(WeightedTriTapeEntry {
1169 gadget_idx: 101, row: i,
1171 col: j,
1172 });
1173 }
1174 if try_apply_dangling_leg_right(grid, i, j) {
1176 tape.push(WeightedTriTapeEntry {
1177 gadget_idx: 102, row: i,
1179 col: j,
1180 });
1181 }
1182 if try_apply_dangling_leg_left(grid, i, j) {
1184 tape.push(WeightedTriTapeEntry {
1185 gadget_idx: 103, row: i,
1187 col: j,
1188 });
1189 }
1190 }
1191 }
1192 }
1193
1194 tape
1195}
1196
1197#[allow(dead_code)]
1205fn try_apply_dangling_leg_down(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1206 let (rows, cols) = grid.size();
1207
1208 if i + 3 >= rows || j + 2 >= cols {
1210 return false;
1211 }
1212
1213 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1215
1216 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1218 grid.get(row, col).is_some_and(|c| c.weight() == w)
1219 };
1220
1221 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) {
1223 return false;
1224 }
1225
1226 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 1) || !is_empty(i + 1, j + 2) {
1228 return false;
1229 }
1230
1231 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 2) || !is_empty(i + 2, j + 2) {
1233 return false;
1234 }
1235
1236 if !is_empty(i + 3, j) || !has_weight(i + 3, j + 1, 2) || !is_empty(i + 3, j + 2) {
1238 return false;
1239 }
1240
1241 grid.set(i + 1, j + 1, CellState::Empty);
1243 grid.set(i + 2, j + 1, CellState::Empty);
1244 grid.set(i + 3, j + 1, CellState::Occupied { weight: 1 });
1245
1246 true
1247}
1248
1249#[allow(dead_code)]
1257fn try_apply_dangling_leg_up(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1258 let (rows, cols) = grid.size();
1259
1260 if i + 3 >= rows || j + 2 >= cols {
1262 return false;
1263 }
1264
1265 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1266
1267 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1268 grid.get(row, col).is_some_and(|c| c.weight() == w)
1269 };
1270
1271 if !is_empty(i, j) || !has_weight(i, j + 1, 2) || !is_empty(i, j + 2) {
1273 return false;
1274 }
1275
1276 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 2) || !is_empty(i + 1, j + 2) {
1278 return false;
1279 }
1280
1281 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 1) || !is_empty(i + 2, j + 2) {
1283 return false;
1284 }
1285
1286 if !is_empty(i + 3, j) || !is_empty(i + 3, j + 1) || !is_empty(i + 3, j + 2) {
1288 return false;
1289 }
1290
1291 grid.set(i + 1, j + 1, CellState::Empty);
1293 grid.set(i + 2, j + 1, CellState::Empty);
1294 grid.set(i, j + 1, CellState::Occupied { weight: 1 });
1295
1296 true
1297}
1298
1299#[allow(dead_code)]
1306fn try_apply_dangling_leg_right(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1307 let (rows, cols) = grid.size();
1308
1309 if i + 2 >= rows || j + 3 >= cols {
1311 return false;
1312 }
1313
1314 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1315
1316 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1317 grid.get(row, col).is_some_and(|c| c.weight() == w)
1318 };
1319
1320 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1322 return false;
1323 }
1324
1325 if !has_weight(i + 1, j, 2)
1327 || !has_weight(i + 1, j + 1, 2)
1328 || !has_weight(i + 1, j + 2, 1)
1329 || !is_empty(i + 1, j + 3)
1330 {
1331 return false;
1332 }
1333
1334 if !is_empty(i + 2, j)
1336 || !is_empty(i + 2, j + 1)
1337 || !is_empty(i + 2, j + 2)
1338 || !is_empty(i + 2, j + 3)
1339 {
1340 return false;
1341 }
1342
1343 grid.set(i + 1, j + 1, CellState::Empty);
1345 grid.set(i + 1, j + 2, CellState::Empty);
1346 grid.set(i + 1, j, CellState::Occupied { weight: 1 });
1347
1348 true
1349}
1350
1351#[allow(dead_code)]
1358fn try_apply_dangling_leg_left(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1359 let (rows, cols) = grid.size();
1360
1361 if i + 2 >= rows || j + 3 >= cols {
1363 return false;
1364 }
1365
1366 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1367
1368 let has_weight = |row: usize, col: usize, w: i32| -> bool {
1369 grid.get(row, col).is_some_and(|c| c.weight() == w)
1370 };
1371
1372 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1374 return false;
1375 }
1376
1377 if !is_empty(i + 1, j)
1379 || !has_weight(i + 1, j + 1, 1)
1380 || !has_weight(i + 1, j + 2, 2)
1381 || !has_weight(i + 1, j + 3, 2)
1382 {
1383 return false;
1384 }
1385
1386 if !is_empty(i + 2, j)
1388 || !is_empty(i + 2, j + 1)
1389 || !is_empty(i + 2, j + 2)
1390 || !is_empty(i + 2, j + 3)
1391 {
1392 return false;
1393 }
1394
1395 grid.set(i + 1, j + 1, CellState::Empty);
1397 grid.set(i + 1, j + 2, CellState::Empty);
1398 grid.set(i + 1, j + 3, CellState::Occupied { weight: 1 });
1399
1400 true
1401}
1402
1403pub fn tape_entry_mis_overhead(entry: &WeightedTriTapeEntry) -> i32 {
1408 match entry.gadget_idx {
1409 0 => WeightedTriCross::<false>.mis_overhead(),
1410 1 => WeightedTriCross::<true>.mis_overhead(),
1411 2 => WeightedTriTConLeft.mis_overhead(),
1412 3 => WeightedTriTConUp.mis_overhead(),
1413 4 => WeightedTriTConDown.mis_overhead(),
1414 5 => WeightedTriTrivialTurnLeft.mis_overhead(),
1415 6 => WeightedTriTrivialTurnRight.mis_overhead(),
1416 7 => WeightedTriEndTurn.mis_overhead(),
1417 8 => WeightedTriTurn.mis_overhead(),
1418 9 => WeightedTriWTurn.mis_overhead(),
1419 10 => WeightedTriBranchFix.mis_overhead(),
1420 11 => WeightedTriBranchFixB.mis_overhead(),
1421 12 => WeightedTriBranch.mis_overhead(),
1422 idx if idx >= 100 => -2,
1424 _ => 0,
1425 }
1426}