1use super::super::grid::{CellState, MappingGrid};
7use crate::rules::unitdiskmapping::mapping_invalid;
8use crate::rules::ReductionError;
9use serde::{Deserialize, Serialize};
10use std::collections::HashSet;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum SourceCell {
15 Empty,
16 Occupied,
17 Connected,
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
22pub struct WeightedTriTapeEntry {
23 pub gadget_idx: usize,
25 pub row: usize,
27 pub col: usize,
29}
30
31#[allow(dead_code)]
36#[allow(clippy::type_complexity)]
37pub trait WeightedTriangularGadget {
38 fn size(&self) -> (usize, usize);
39 fn cross_location(&self) -> (usize, usize);
40 fn is_connected(&self) -> bool;
41 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>);
43 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>);
45 fn mis_overhead(&self) -> i64;
46
47 fn connected_nodes(&self) -> Vec<usize> {
49 vec![]
50 }
51
52 fn source_weights(&self) -> Vec<i64> {
54 let (locs, _, _) = self.source_graph();
55 vec![2; locs.len()]
56 }
57
58 fn mapped_weights(&self) -> Vec<i64> {
60 let (locs, _) = self.mapped_graph();
61 vec![2; locs.len()]
62 }
63
64 fn source_matrix(&self) -> Vec<Vec<SourceCell>> {
67 let (rows, cols) = self.size();
68 let (locs, _, _) = self.source_graph();
69 let mut matrix = vec![vec![SourceCell::Empty; cols]; rows];
70
71 let connected_set: HashSet<usize> = if self.is_connected() {
73 self.connected_nodes().into_iter().collect()
74 } else {
75 HashSet::new()
76 };
77
78 for (idx, (r, c)) in locs.iter().enumerate() {
79 if *r > 0 && *c > 0 && *r <= rows && *c <= cols {
80 let cell_type = if connected_set.contains(&(idx + 1)) {
81 SourceCell::Connected
82 } else {
83 SourceCell::Occupied
84 };
85 matrix[r - 1][c - 1] = cell_type;
86 }
87 }
88 matrix
89 }
90
91 fn mapped_matrix(&self) -> Vec<Vec<bool>> {
93 let (rows, cols) = self.size();
94 let (locs, _) = self.mapped_graph();
95 let mut matrix = vec![vec![false; cols]; rows];
96 for (r, c) in locs {
97 if r > 0 && c > 0 && r <= rows && c <= cols {
98 matrix[r - 1][c - 1] = true;
99 }
100 }
101 matrix
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
111pub struct WeightedTriCross<const CON: bool>;
112
113impl WeightedTriangularGadget for WeightedTriCross<true> {
114 fn size(&self) -> (usize, usize) {
115 (6, 4)
116 }
117
118 fn cross_location(&self) -> (usize, usize) {
119 (2, 2)
120 }
121
122 fn is_connected(&self) -> bool {
123 true
124 }
125
126 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
127 let locs = vec![
130 (2, 1),
131 (2, 2),
132 (2, 3),
133 (2, 4),
134 (1, 2),
135 (2, 2),
136 (3, 2),
137 (4, 2),
138 (5, 2),
139 (6, 2),
140 ];
141 let edges = vec![
144 (0, 1),
145 (1, 2),
146 (2, 3),
147 (4, 5),
148 (5, 6),
149 (6, 7),
150 (7, 8),
151 (8, 9),
152 (0, 4),
153 ];
154 let pins = vec![0, 4, 9, 3];
156 (locs, edges, pins)
157 }
158
159 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
160 let locs = vec![
162 (1, 2),
163 (2, 1),
164 (2, 2),
165 (2, 3),
166 (1, 4),
167 (3, 3),
168 (4, 2),
169 (4, 3),
170 (5, 1),
171 (6, 1),
172 (6, 2),
173 ];
174 let pins = vec![1, 0, 10, 4];
176 (locs, pins)
177 }
178
179 fn mis_overhead(&self) -> i64 {
180 1
181 }
182
183 fn connected_nodes(&self) -> Vec<usize> {
184 vec![1, 5]
186 }
187
188 fn source_weights(&self) -> Vec<i64> {
189 vec![2; 10]
191 }
192
193 fn mapped_weights(&self) -> Vec<i64> {
194 vec![3, 2, 3, 3, 2, 2, 2, 2, 2, 2, 2]
196 }
197}
198
199impl WeightedTriangularGadget for WeightedTriCross<false> {
200 fn size(&self) -> (usize, usize) {
201 (6, 6)
202 }
203
204 fn cross_location(&self) -> (usize, usize) {
205 (2, 4)
206 }
207
208 fn is_connected(&self) -> bool {
209 false
210 }
211
212 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
213 let locs = vec![
216 (2, 2),
217 (2, 3),
218 (2, 4),
219 (2, 5),
220 (2, 6),
221 (1, 4),
222 (2, 4),
223 (3, 4),
224 (4, 4),
225 (5, 4),
226 (6, 4),
227 (2, 1),
228 ];
229 let edges = vec![
232 (0, 1),
233 (1, 2),
234 (2, 3),
235 (3, 4),
236 (5, 6),
237 (6, 7),
238 (7, 8),
239 (8, 9),
240 (9, 10),
241 (11, 0),
242 ];
243 let pins = vec![11, 5, 10, 4];
245 (locs, edges, pins)
246 }
247
248 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
249 let locs = vec![
251 (1, 4),
252 (2, 2),
253 (2, 3),
254 (2, 4),
255 (2, 5),
256 (2, 6),
257 (3, 2),
258 (3, 3),
259 (3, 4),
260 (3, 5),
261 (4, 2),
262 (4, 3),
263 (5, 2),
264 (6, 3),
265 (6, 4),
266 (2, 1),
267 ];
268 let pins = vec![15, 0, 14, 5];
270 (locs, pins)
271 }
272
273 fn mis_overhead(&self) -> i64 {
274 3
275 }
276
277 fn source_weights(&self) -> Vec<i64> {
278 vec![2; 12]
279 }
280
281 fn mapped_weights(&self) -> Vec<i64> {
282 vec![3, 3, 2, 4, 2, 2, 2, 4, 3, 2, 2, 2, 2, 2, 2, 2]
283 }
284}
285
286#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
294pub struct WeightedTriTurn;
295
296impl WeightedTriangularGadget for WeightedTriTurn {
297 fn size(&self) -> (usize, usize) {
298 (3, 4)
299 }
300
301 fn cross_location(&self) -> (usize, usize) {
302 (2, 2)
303 }
304
305 fn is_connected(&self) -> bool {
306 false
307 }
308
309 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
310 let locs = vec![(1, 2), (2, 2), (2, 3), (2, 4)];
313 let edges = vec![(0, 1), (1, 2), (2, 3)];
314 let pins = vec![0, 3];
316 (locs, edges, pins)
317 }
318
319 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
320 let locs = vec![(1, 2), (2, 2), (3, 3), (2, 4)];
322 let pins = vec![0, 3];
324 (locs, pins)
325 }
326
327 fn mis_overhead(&self) -> i64 {
328 0
329 }
330
331 fn source_weights(&self) -> Vec<i64> {
332 vec![2; 4]
333 }
334
335 fn mapped_weights(&self) -> Vec<i64> {
336 vec![2; 4]
337 }
338}
339
340#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
349pub struct WeightedTriBranch;
350
351impl WeightedTriangularGadget for WeightedTriBranch {
352 fn size(&self) -> (usize, usize) {
353 (6, 4)
354 }
355
356 fn cross_location(&self) -> (usize, usize) {
357 (2, 2)
358 }
359
360 fn is_connected(&self) -> bool {
361 false
362 }
363
364 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
365 let locs = vec![
367 (1, 2),
368 (2, 2),
369 (2, 3),
370 (2, 4),
371 (3, 3),
372 (3, 2),
373 (4, 2),
374 (5, 2),
375 (6, 2),
376 ];
377 let edges = vec![
380 (0, 1),
381 (1, 2),
382 (2, 3),
383 (2, 4),
384 (4, 5),
385 (5, 6),
386 (6, 7),
387 (7, 8),
388 ];
389 let pins = vec![0, 3, 8];
391 (locs, edges, pins)
392 }
393
394 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
395 let locs = vec![
397 (1, 2),
398 (2, 2),
399 (2, 4),
400 (3, 3),
401 (4, 2),
402 (4, 3),
403 (5, 1),
404 (6, 1),
405 (6, 2),
406 ];
407 let pins = vec![0, 2, 8];
409 (locs, pins)
410 }
411
412 fn mis_overhead(&self) -> i64 {
413 0
414 }
415
416 fn source_weights(&self) -> Vec<i64> {
417 vec![2, 2, 3, 2, 2, 2, 2, 2, 2]
419 }
420
421 fn mapped_weights(&self) -> Vec<i64> {
422 vec![2, 2, 2, 3, 2, 2, 2, 2, 2]
424 }
425}
426
427#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
437pub struct WeightedTriTConLeft;
438
439impl WeightedTriangularGadget for WeightedTriTConLeft {
440 fn size(&self) -> (usize, usize) {
441 (6, 5)
442 }
443
444 fn cross_location(&self) -> (usize, usize) {
445 (2, 2)
446 }
447
448 fn is_connected(&self) -> bool {
449 true
450 }
451
452 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
453 let locs = vec![(1, 2), (2, 1), (2, 2), (3, 2), (4, 2), (5, 2), (6, 2)];
455 let edges = vec![(0, 1), (0, 2), (2, 3), (3, 4), (4, 5), (5, 6)];
458 let pins = vec![0, 1, 6];
460 (locs, edges, pins)
461 }
462
463 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
464 let locs = vec![
466 (1, 2),
467 (2, 1),
468 (2, 2),
469 (2, 3),
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, 1, 10];
480 (locs, pins)
481 }
482
483 fn mis_overhead(&self) -> i64 {
484 4
485 }
486
487 fn connected_nodes(&self) -> Vec<usize> {
488 vec![1, 2]
490 }
491
492 fn source_weights(&self) -> Vec<i64> {
493 vec![2, 1, 2, 2, 2, 2, 2]
495 }
496
497 fn mapped_weights(&self) -> Vec<i64> {
498 vec![3, 2, 3, 3, 1, 3, 2, 2, 2, 2, 2]
500 }
501}
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
505pub struct WeightedTriTConDown;
506
507impl WeightedTriangularGadget for WeightedTriTConDown {
508 fn size(&self) -> (usize, usize) {
509 (3, 3)
510 }
511
512 fn cross_location(&self) -> (usize, usize) {
513 (2, 2)
514 }
515
516 fn is_connected(&self) -> bool {
517 true
518 }
519
520 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
521 let locs = vec![(2, 1), (2, 2), (2, 3), (3, 2)];
525 let edges = vec![(0, 1), (1, 2), (0, 3)];
526 let pins = vec![0, 3, 2];
528 (locs, edges, pins)
529 }
530
531 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
532 let locs = vec![(2, 2), (3, 1), (3, 2), (3, 3)];
534 let pins = vec![1, 2, 3];
536 (locs, pins)
537 }
538
539 fn mis_overhead(&self) -> i64 {
540 0
541 }
542
543 fn connected_nodes(&self) -> Vec<usize> {
544 vec![1, 4]
546 }
547
548 fn source_weights(&self) -> Vec<i64> {
549 vec![2, 2, 2, 1]
550 }
551
552 fn mapped_weights(&self) -> Vec<i64> {
553 vec![2, 2, 3, 2]
554 }
555}
556
557#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
559pub struct WeightedTriTConUp;
560
561impl WeightedTriangularGadget for WeightedTriTConUp {
562 fn size(&self) -> (usize, usize) {
563 (3, 3)
564 }
565
566 fn cross_location(&self) -> (usize, usize) {
567 (2, 2)
568 }
569
570 fn is_connected(&self) -> bool {
571 true
572 }
573
574 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
575 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
579 let edges = vec![(0, 1), (1, 2), (2, 3)];
580 let pins = vec![1, 0, 3];
582 (locs, edges, pins)
583 }
584
585 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
586 let locs = vec![(1, 2), (2, 1), (2, 2), (2, 3)];
588 let pins = vec![1, 0, 3];
590 (locs, pins)
591 }
592
593 fn mis_overhead(&self) -> i64 {
594 0
595 }
596
597 fn connected_nodes(&self) -> Vec<usize> {
598 vec![1, 2]
600 }
601
602 fn source_weights(&self) -> Vec<i64> {
603 vec![1, 2, 2, 2]
604 }
605
606 fn mapped_weights(&self) -> Vec<i64> {
607 vec![3, 2, 2, 2]
608 }
609}
610
611#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
613pub struct WeightedTriTrivialTurnLeft;
614
615impl WeightedTriangularGadget for WeightedTriTrivialTurnLeft {
616 fn size(&self) -> (usize, usize) {
617 (2, 2)
618 }
619
620 fn cross_location(&self) -> (usize, usize) {
621 (2, 2)
622 }
623
624 fn is_connected(&self) -> bool {
625 true
626 }
627
628 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
629 let locs = vec![(1, 2), (2, 1)];
631 let edges = vec![(0, 1)];
632 let pins = vec![0, 1];
633 (locs, edges, pins)
634 }
635
636 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
637 let locs = vec![(1, 2), (2, 1)];
639 let pins = vec![0, 1];
640 (locs, pins)
641 }
642
643 fn mis_overhead(&self) -> i64 {
644 0
645 }
646
647 fn connected_nodes(&self) -> Vec<usize> {
648 vec![1, 2]
650 }
651
652 fn source_weights(&self) -> Vec<i64> {
653 vec![1, 1]
654 }
655
656 fn mapped_weights(&self) -> Vec<i64> {
657 vec![1, 1]
658 }
659}
660
661#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
663pub struct WeightedTriTrivialTurnRight;
664
665impl WeightedTriangularGadget for WeightedTriTrivialTurnRight {
666 fn size(&self) -> (usize, usize) {
667 (2, 2)
668 }
669
670 fn cross_location(&self) -> (usize, usize) {
671 (1, 2)
672 }
673
674 fn is_connected(&self) -> bool {
675 true
676 }
677
678 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
679 let locs = vec![(1, 1), (2, 2)];
681 let edges = vec![(0, 1)];
682 let pins = vec![0, 1];
683 (locs, edges, pins)
684 }
685
686 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
687 let locs = vec![(2, 1), (2, 2)];
689 let pins = vec![0, 1];
690 (locs, pins)
691 }
692
693 fn mis_overhead(&self) -> i64 {
694 0
695 }
696
697 fn connected_nodes(&self) -> Vec<usize> {
698 vec![1, 2]
700 }
701
702 fn source_weights(&self) -> Vec<i64> {
703 vec![1, 1]
704 }
705
706 fn mapped_weights(&self) -> Vec<i64> {
707 vec![1, 1]
708 }
709}
710
711#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
720pub struct WeightedTriEndTurn;
721
722impl WeightedTriangularGadget for WeightedTriEndTurn {
723 fn size(&self) -> (usize, usize) {
724 (3, 4)
725 }
726
727 fn cross_location(&self) -> (usize, usize) {
728 (2, 2)
729 }
730
731 fn is_connected(&self) -> bool {
732 false
733 }
734
735 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
736 let locs = vec![(1, 2), (2, 2), (2, 3)];
739 let edges = vec![(0, 1), (1, 2)];
740 let pins = vec![0];
742 (locs, edges, pins)
743 }
744
745 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
746 let locs = vec![(1, 2)];
748 let pins = vec![0];
750 (locs, pins)
751 }
752
753 fn mis_overhead(&self) -> i64 {
754 -2
755 }
756
757 fn source_weights(&self) -> Vec<i64> {
758 vec![2, 2, 1]
759 }
760
761 fn mapped_weights(&self) -> Vec<i64> {
762 vec![1]
763 }
764}
765
766#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
774pub struct WeightedTriWTurn;
775
776impl WeightedTriangularGadget for WeightedTriWTurn {
777 fn size(&self) -> (usize, usize) {
778 (4, 4)
779 }
780
781 fn cross_location(&self) -> (usize, usize) {
782 (2, 2)
783 }
784
785 fn is_connected(&self) -> bool {
786 false
787 }
788
789 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
790 let locs = vec![(2, 3), (2, 4), (3, 2), (3, 3), (4, 2)];
792 let edges = vec![(0, 1), (0, 3), (2, 3), (2, 4)];
795 let pins = vec![1, 4];
797 (locs, edges, pins)
798 }
799
800 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
801 let locs = vec![(1, 4), (2, 3), (3, 2), (3, 3), (4, 2)];
803 let pins = vec![0, 4];
805 (locs, pins)
806 }
807
808 fn mis_overhead(&self) -> i64 {
809 0
810 }
811
812 fn source_weights(&self) -> Vec<i64> {
813 vec![2; 5]
814 }
815
816 fn mapped_weights(&self) -> Vec<i64> {
817 vec![2; 5]
818 }
819}
820
821#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
823pub struct WeightedTriBranchFix;
824
825impl WeightedTriangularGadget for WeightedTriBranchFix {
826 fn size(&self) -> (usize, usize) {
827 (4, 4)
828 }
829
830 fn cross_location(&self) -> (usize, usize) {
831 (2, 2)
832 }
833
834 fn is_connected(&self) -> bool {
835 false
836 }
837
838 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
839 let locs = vec![(1, 2), (2, 2), (2, 3), (3, 3), (3, 2), (4, 2)];
842 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
844 let pins = vec![0, 5];
846 (locs, edges, pins)
847 }
848
849 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
850 let locs = vec![(1, 2), (2, 2), (3, 2), (4, 2)];
852 let pins = vec![0, 3];
854 (locs, pins)
855 }
856
857 fn mis_overhead(&self) -> i64 {
858 -2
859 }
860
861 fn source_weights(&self) -> Vec<i64> {
862 vec![2; 6]
863 }
864
865 fn mapped_weights(&self) -> Vec<i64> {
866 vec![2; 4]
867 }
868}
869
870#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
872pub struct WeightedTriBranchFixB;
873
874impl WeightedTriangularGadget for WeightedTriBranchFixB {
875 fn size(&self) -> (usize, usize) {
876 (4, 4)
877 }
878
879 fn cross_location(&self) -> (usize, usize) {
880 (2, 2)
881 }
882
883 fn is_connected(&self) -> bool {
884 false
885 }
886
887 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
888 let locs = vec![(2, 3), (3, 2), (3, 3), (4, 2)];
891 let edges = vec![(0, 2), (1, 2), (1, 3)];
893 let pins = vec![0, 3];
895 (locs, edges, pins)
896 }
897
898 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
899 let locs = vec![(3, 2), (4, 2)];
901 let pins = vec![0, 1];
903 (locs, pins)
904 }
905
906 fn mis_overhead(&self) -> i64 {
907 -2
908 }
909
910 fn source_weights(&self) -> Vec<i64> {
911 vec![2; 4]
912 }
913
914 fn mapped_weights(&self) -> Vec<i64> {
915 vec![2; 2]
916 }
917}
918
919#[allow(clippy::needless_range_loop)]
930fn pattern_matches<G: WeightedTriangularGadget>(
931 gadget: &G,
932 grid: &MappingGrid,
933 i: usize,
934 j: usize,
935) -> bool {
936 let source = gadget.source_matrix();
937 let (m, n) = gadget.size();
938
939 for r in 0..m {
941 for c in 0..n {
942 let grid_r = i + r;
943 let grid_c = j + c;
944 let expected = source[r][c];
945 let actual = grid.get(grid_r, grid_c);
946
947 match expected {
948 SourceCell::Empty => {
949 if actual.map(|c| !c.is_empty()).unwrap_or(false) {
951 return false;
952 }
953 }
954 SourceCell::Occupied => {
955 if !actual.map(|c| !c.is_empty()).unwrap_or(false) {
957 return false;
958 }
959 }
960 SourceCell::Connected => {
961 match actual {
963 Some(CellState::Connected { .. }) => {}
964 _ => return false,
965 }
966 }
967 }
968 }
969 }
970
971 let (locs, _, _) = gadget.source_graph();
974 let weights = gadget.source_weights();
975
976 for (idx, (loc_r, loc_c)) in locs.iter().enumerate() {
977 let grid_r = i + loc_r - 1;
979 let grid_c = j + loc_c - 1;
980 let expected_weight = weights[idx];
981
982 if let Some(cell) = grid.get(grid_r, grid_c) {
983 if cell.weight() != expected_weight {
984 return false;
985 }
986 } else {
987 return false;
988 }
989 }
990
991 true
992}
993
994#[allow(clippy::needless_range_loop)]
997fn apply_gadget<G: WeightedTriangularGadget>(
998 gadget: &G,
999 grid: &mut MappingGrid,
1000 i: usize,
1001 j: usize,
1002) {
1003 let source = gadget.source_matrix();
1004 let (m, n) = gadget.size();
1005
1006 for r in 0..m {
1008 for c in 0..n {
1009 if source[r][c] != SourceCell::Empty {
1010 grid.set(i + r, j + c, CellState::Empty);
1011 }
1012 }
1013 }
1014
1015 let (locs, _) = gadget.mapped_graph();
1018 let weights = gadget.mapped_weights();
1019 for (idx, (r, c)) in locs.iter().enumerate() {
1020 if *r > 0 && *c > 0 && *r <= m && *c <= n {
1021 let weight = weights[idx];
1022 grid.add_node(i + r - 1, j + c - 1, weight);
1024 }
1025 }
1026}
1027
1028fn try_match_gadget(
1030 grid: &mut MappingGrid,
1031 cross_row: usize,
1032 cross_col: usize,
1033) -> Option<WeightedTriTapeEntry> {
1034 macro_rules! try_gadget {
1036 ($gadget:expr, $idx:expr) => {{
1037 let g = $gadget;
1038 let (cr, cc) = g.cross_location();
1039 if cross_row >= cr && cross_col >= cc {
1040 let x = cross_row - cr + 1;
1041 let y = cross_col - cc + 1;
1042 if pattern_matches(&g, grid, x, y) {
1043 apply_gadget(&g, grid, x, y);
1044 return Some(WeightedTriTapeEntry {
1045 gadget_idx: $idx,
1046 row: x,
1047 col: y,
1048 });
1049 }
1050 }
1051 }};
1052 }
1053
1054 try_gadget!(WeightedTriCross::<true>, 1);
1059 try_gadget!(WeightedTriCross::<false>, 0);
1060 try_gadget!(WeightedTriTConLeft, 2);
1061 try_gadget!(WeightedTriTConUp, 3);
1062 try_gadget!(WeightedTriTConDown, 4);
1063 try_gadget!(WeightedTriTrivialTurnLeft, 5);
1064 try_gadget!(WeightedTriTrivialTurnRight, 6);
1065 try_gadget!(WeightedTriEndTurn, 7);
1066 try_gadget!(WeightedTriTurn, 8);
1067 try_gadget!(WeightedTriWTurn, 9);
1068 try_gadget!(WeightedTriBranchFix, 10);
1069 try_gadget!(WeightedTriBranchFixB, 11);
1070 try_gadget!(WeightedTriBranch, 12);
1071
1072 None
1073}
1074
1075fn crossat(
1077 copylines: &[super::super::copyline::CopyLine],
1078 v: usize,
1079 w: usize,
1080 spacing: usize,
1081 padding: usize,
1082) -> (usize, usize) {
1083 let line_v = ©lines[v];
1084 let line_w = ©lines[w];
1085
1086 let (line_first, line_second) = if line_v.vslot < line_w.vslot {
1088 (line_v, line_w)
1089 } else {
1090 (line_w, line_v)
1091 };
1092
1093 let hslot = line_first.hslot;
1094 let max_vslot = line_second.vslot;
1095
1096 let row = (hslot - 1) * spacing + 1 + padding; let col = (max_vslot - 1) * spacing + padding; (row, col)
1101}
1102
1103pub fn apply_crossing_gadgets(
1109 grid: &mut MappingGrid,
1110 copylines: &[super::super::copyline::CopyLine],
1111 spacing: usize,
1112 padding: usize,
1113) -> Vec<WeightedTriTapeEntry> {
1114 let mut tape = Vec::new();
1115 let mut processed = HashSet::new();
1116 let n = copylines.len();
1117
1118 for j in 0..n {
1120 for i in 0..n {
1121 let (cross_row, cross_col) = crossat(copylines, i, j, spacing, padding);
1122
1123 if processed.contains(&(cross_row, cross_col)) {
1126 continue;
1127 }
1128
1129 if let Some(entry) = try_match_gadget(grid, cross_row, cross_col) {
1131 tape.push(entry);
1132 processed.insert((cross_row, cross_col));
1133 }
1134 }
1135 }
1136
1137 tape
1138}
1139
1140#[allow(dead_code)]
1148pub fn apply_simplifier_gadgets(
1149 grid: &mut MappingGrid,
1150 nrepeat: usize,
1151) -> Vec<WeightedTriTapeEntry> {
1152 let mut tape = Vec::new();
1153 let (rows, cols) = grid.size();
1154
1155 for _ in 0..nrepeat {
1156 for j in 0..cols {
1159 for i in 0..rows {
1160 if try_apply_dangling_leg_down(grid, i, j) {
1162 tape.push(WeightedTriTapeEntry {
1163 gadget_idx: 100, row: i,
1165 col: j,
1166 });
1167 }
1168 if try_apply_dangling_leg_up(grid, i, j) {
1170 tape.push(WeightedTriTapeEntry {
1171 gadget_idx: 101, row: i,
1173 col: j,
1174 });
1175 }
1176 if try_apply_dangling_leg_right(grid, i, j) {
1178 tape.push(WeightedTriTapeEntry {
1179 gadget_idx: 102, row: i,
1181 col: j,
1182 });
1183 }
1184 if try_apply_dangling_leg_left(grid, i, j) {
1186 tape.push(WeightedTriTapeEntry {
1187 gadget_idx: 103, row: i,
1189 col: j,
1190 });
1191 }
1192 }
1193 }
1194 }
1195
1196 tape
1197}
1198
1199#[allow(dead_code)]
1207fn try_apply_dangling_leg_down(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1208 let (rows, cols) = grid.size();
1209
1210 if i + 3 >= rows || j + 2 >= cols {
1212 return false;
1213 }
1214
1215 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1217
1218 let has_weight = |row: usize, col: usize, w: i64| -> bool {
1220 grid.get(row, col).is_some_and(|c| c.weight() == w)
1221 };
1222
1223 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) {
1225 return false;
1226 }
1227
1228 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 1) || !is_empty(i + 1, j + 2) {
1230 return false;
1231 }
1232
1233 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 2) || !is_empty(i + 2, j + 2) {
1235 return false;
1236 }
1237
1238 if !is_empty(i + 3, j) || !has_weight(i + 3, j + 1, 2) || !is_empty(i + 3, j + 2) {
1240 return false;
1241 }
1242
1243 grid.set(i + 1, j + 1, CellState::Empty);
1245 grid.set(i + 2, j + 1, CellState::Empty);
1246 grid.set(i + 3, j + 1, CellState::Occupied { weight: 1 });
1247
1248 true
1249}
1250
1251#[allow(dead_code)]
1259fn try_apply_dangling_leg_up(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1260 let (rows, cols) = grid.size();
1261
1262 if i + 3 >= rows || j + 2 >= cols {
1264 return false;
1265 }
1266
1267 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1268
1269 let has_weight = |row: usize, col: usize, w: i64| -> bool {
1270 grid.get(row, col).is_some_and(|c| c.weight() == w)
1271 };
1272
1273 if !is_empty(i, j) || !has_weight(i, j + 1, 2) || !is_empty(i, j + 2) {
1275 return false;
1276 }
1277
1278 if !is_empty(i + 1, j) || !has_weight(i + 1, j + 1, 2) || !is_empty(i + 1, j + 2) {
1280 return false;
1281 }
1282
1283 if !is_empty(i + 2, j) || !has_weight(i + 2, j + 1, 1) || !is_empty(i + 2, j + 2) {
1285 return false;
1286 }
1287
1288 if !is_empty(i + 3, j) || !is_empty(i + 3, j + 1) || !is_empty(i + 3, j + 2) {
1290 return false;
1291 }
1292
1293 grid.set(i + 1, j + 1, CellState::Empty);
1295 grid.set(i + 2, j + 1, CellState::Empty);
1296 grid.set(i, j + 1, CellState::Occupied { weight: 1 });
1297
1298 true
1299}
1300
1301#[allow(dead_code)]
1308fn try_apply_dangling_leg_right(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1309 let (rows, cols) = grid.size();
1310
1311 if i + 2 >= rows || j + 3 >= cols {
1313 return false;
1314 }
1315
1316 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1317
1318 let has_weight = |row: usize, col: usize, w: i64| -> bool {
1319 grid.get(row, col).is_some_and(|c| c.weight() == w)
1320 };
1321
1322 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1324 return false;
1325 }
1326
1327 if !has_weight(i + 1, j, 2)
1329 || !has_weight(i + 1, j + 1, 2)
1330 || !has_weight(i + 1, j + 2, 1)
1331 || !is_empty(i + 1, j + 3)
1332 {
1333 return false;
1334 }
1335
1336 if !is_empty(i + 2, j)
1338 || !is_empty(i + 2, j + 1)
1339 || !is_empty(i + 2, j + 2)
1340 || !is_empty(i + 2, j + 3)
1341 {
1342 return false;
1343 }
1344
1345 grid.set(i + 1, j + 1, CellState::Empty);
1347 grid.set(i + 1, j + 2, CellState::Empty);
1348 grid.set(i + 1, j, CellState::Occupied { weight: 1 });
1349
1350 true
1351}
1352
1353#[allow(dead_code)]
1360fn try_apply_dangling_leg_left(grid: &mut MappingGrid, i: usize, j: usize) -> bool {
1361 let (rows, cols) = grid.size();
1362
1363 if i + 2 >= rows || j + 3 >= cols {
1365 return false;
1366 }
1367
1368 let is_empty = |row: usize, col: usize| -> bool { !grid.is_occupied(row, col) };
1369
1370 let has_weight = |row: usize, col: usize, w: i64| -> bool {
1371 grid.get(row, col).is_some_and(|c| c.weight() == w)
1372 };
1373
1374 if !is_empty(i, j) || !is_empty(i, j + 1) || !is_empty(i, j + 2) || !is_empty(i, j + 3) {
1376 return false;
1377 }
1378
1379 if !is_empty(i + 1, j)
1381 || !has_weight(i + 1, j + 1, 1)
1382 || !has_weight(i + 1, j + 2, 2)
1383 || !has_weight(i + 1, j + 3, 2)
1384 {
1385 return false;
1386 }
1387
1388 if !is_empty(i + 2, j)
1390 || !is_empty(i + 2, j + 1)
1391 || !is_empty(i + 2, j + 2)
1392 || !is_empty(i + 2, j + 3)
1393 {
1394 return false;
1395 }
1396
1397 grid.set(i + 1, j + 1, CellState::Empty);
1399 grid.set(i + 1, j + 2, CellState::Empty);
1400 grid.set(i + 1, j + 3, CellState::Occupied { weight: 1 });
1401
1402 true
1403}
1404
1405pub fn tape_entry_mis_overhead(entry: &WeightedTriTapeEntry) -> Result<i64, ReductionError> {
1410 Ok(match entry.gadget_idx {
1411 0 => WeightedTriCross::<false>.mis_overhead(),
1412 1 => WeightedTriCross::<true>.mis_overhead(),
1413 2 => WeightedTriTConLeft.mis_overhead(),
1414 3 => WeightedTriTConUp.mis_overhead(),
1415 4 => WeightedTriTConDown.mis_overhead(),
1416 5 => WeightedTriTrivialTurnLeft.mis_overhead(),
1417 6 => WeightedTriTrivialTurnRight.mis_overhead(),
1418 7 => WeightedTriEndTurn.mis_overhead(),
1419 8 => WeightedTriTurn.mis_overhead(),
1420 9 => WeightedTriWTurn.mis_overhead(),
1421 10 => WeightedTriBranchFix.mis_overhead(),
1422 11 => WeightedTriBranchFixB.mis_overhead(),
1423 12 => WeightedTriBranch.mis_overhead(),
1424 100..=103 => -2,
1426 _ => {
1427 return Err(mapping_invalid(
1428 "tape contains an unknown weighted triangular gadget index",
1429 ))
1430 }
1431 })
1432}
1433
1434pub(crate) fn tape_entry_size(gadget_idx: usize) -> Option<(usize, usize)> {
1435 match gadget_idx {
1436 0 => Some(WeightedTriCross::<false>.size()),
1437 1 => Some(WeightedTriCross::<true>.size()),
1438 2 => Some(WeightedTriTConLeft.size()),
1439 3 => Some(WeightedTriTConUp.size()),
1440 4 => Some(WeightedTriTConDown.size()),
1441 5 => Some(WeightedTriTrivialTurnLeft.size()),
1442 6 => Some(WeightedTriTrivialTurnRight.size()),
1443 7 => Some(WeightedTriEndTurn.size()),
1444 8 => Some(WeightedTriTurn.size()),
1445 9 => Some(WeightedTriWTurn.size()),
1446 10 => Some(WeightedTriBranchFix.size()),
1447 11 => Some(WeightedTriBranchFixB.size()),
1448 12 => Some(WeightedTriBranch.size()),
1449 100 | 101 => Some((4, 3)),
1450 102 | 103 => Some((3, 4)),
1451 _ => None,
1452 }
1453}
1454
1455pub(crate) fn tape_entry_center_transform(
1456 gadget_idx: usize,
1457) -> Option<((usize, usize), (isize, isize))> {
1458 match gadget_idx {
1459 7 | 8 | 12 => Some(((2, 3), (-1, -1))),
1460 9 => Some(((2, 3), (0, 0))),
1461 10 | 11 => Some(((2, 3), (1, -1))),
1462 100 => Some(((2, 2), (2, 0))),
1463 101 => Some(((3, 2), (-2, 0))),
1464 102 => Some(((2, 3), (0, -2))),
1465 103 => Some(((2, 2), (0, 2))),
1466 _ => None,
1467 }
1468}