1use super::super::grid::{CellState, MappingGrid};
8use super::super::traits::{apply_gadget, pattern_matches, Pattern, PatternCell};
9use crate::rules::unitdiskmapping::{mapping_integer_overflow, mapping_invalid};
10use crate::rules::ReductionError;
11use serde::{Deserialize, Serialize};
12use std::collections::HashMap;
13
14type PatternFactory = Box<dyn Fn() -> Box<dyn KsgPatternBoxed>>;
16
17pub type SourceGraph = (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>);
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
29pub struct KsgCross<const CON: bool>;
30
31impl Pattern for KsgCross<true> {
32 fn size(&self) -> (usize, usize) {
33 (3, 3)
34 }
35
36 fn cross_location(&self) -> (usize, usize) {
37 (2, 2)
38 }
39
40 fn is_connected(&self) -> bool {
41 true
42 }
43
44 fn is_cross_gadget(&self) -> bool {
45 true
46 }
47
48 fn connected_nodes(&self) -> Vec<usize> {
49 vec![0, 5]
50 }
51
52 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
53 let locs = vec![(2, 1), (2, 2), (2, 3), (1, 2), (2, 2), (3, 2)];
54 let edges = vec![(0, 1), (1, 2), (3, 4), (4, 5), (0, 5)];
55 let pins = vec![0, 3, 5, 2];
56 (locs, edges, pins)
57 }
58
59 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
60 let locs = vec![(2, 1), (2, 2), (2, 3), (1, 2), (3, 2)];
61 let pins = vec![0, 3, 4, 2];
62 (locs, pins)
63 }
64
65 fn mis_overhead(&self) -> i64 {
66 -1
67 }
68
69 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
70 [
71 (5, 5),
72 (12, 12),
73 (8, 0),
74 (1, 0),
75 (0, 0),
76 (6, 6),
77 (11, 11),
78 (9, 9),
79 (14, 14),
80 (3, 3),
81 (7, 7),
82 (4, 0),
83 (13, 13),
84 (15, 15),
85 (2, 0),
86 (10, 10),
87 ]
88 .into_iter()
89 .collect()
90 }
91
92 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
93 let mut map = HashMap::new();
94 map.insert(0, vec![vec![false, true, false, false, true, false]]);
95 map.insert(1, vec![vec![true, false, false, false, true, false]]);
96 map.insert(3, vec![vec![true, false, false, true, false, false]]);
97 map.insert(4, vec![vec![false, true, false, false, false, true]]);
98 map.insert(6, vec![vec![false, true, false, true, false, true]]);
99 map.insert(8, vec![vec![false, false, true, false, true, false]]);
100 map.insert(9, vec![vec![true, false, true, false, true, false]]);
101 map.insert(10, vec![vec![false, false, true, true, false, false]]);
102 map.insert(11, vec![vec![true, false, true, true, false, false]]);
103 map.insert(12, vec![vec![false, false, true, false, false, true]]);
104 map.insert(14, vec![vec![false, false, true, true, false, true]]);
105 map.insert(5, vec![]);
106 map.insert(7, vec![]);
107 map.insert(13, vec![]);
108 map.insert(15, vec![]);
109 map.insert(2, vec![vec![false, true, false, true, false, false]]);
110 map
111 }
112}
113
114impl Pattern for KsgCross<false> {
115 fn size(&self) -> (usize, usize) {
116 (4, 5)
117 }
118
119 fn cross_location(&self) -> (usize, usize) {
120 (2, 3)
121 }
122
123 fn is_connected(&self) -> bool {
124 false
125 }
126
127 fn is_cross_gadget(&self) -> bool {
128 true
129 }
130
131 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
132 let locs = vec![
133 (2, 1),
134 (2, 2),
135 (2, 3),
136 (2, 4),
137 (2, 5),
138 (1, 3),
139 (2, 3),
140 (3, 3),
141 (4, 3),
142 ];
143 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (5, 6), (6, 7), (7, 8)];
144 let pins = vec![0, 5, 8, 4];
145 (locs, edges, pins)
146 }
147
148 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
149 let locs = vec![
150 (2, 1),
151 (2, 2),
152 (2, 3),
153 (2, 4),
154 (2, 5),
155 (1, 3),
156 (3, 3),
157 (4, 3),
158 (3, 2),
159 (3, 4),
160 ];
161 let pins = vec![0, 5, 7, 4];
162 (locs, pins)
163 }
164
165 fn mis_overhead(&self) -> i64 {
166 -1
167 }
168
169 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
170 [
171 (5, 4),
172 (12, 4),
173 (8, 0),
174 (1, 0),
175 (0, 0),
176 (6, 0),
177 (11, 11),
178 (9, 9),
179 (14, 2),
180 (3, 2),
181 (7, 2),
182 (4, 4),
183 (13, 13),
184 (15, 11),
185 (2, 2),
186 (10, 2),
187 ]
188 .into_iter()
189 .collect()
190 }
191
192 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
193 let mut map = HashMap::new();
194 map.insert(
195 0,
196 vec![
197 vec![false, true, false, true, false, false, false, true, false],
198 vec![false, true, false, true, false, false, true, false, false],
199 ],
200 );
201 map.insert(
202 2,
203 vec![vec![
204 false, true, false, true, false, true, false, true, false,
205 ]],
206 );
207 map.insert(
208 4,
209 vec![vec![
210 false, true, false, true, false, false, true, false, true,
211 ]],
212 );
213 map.insert(
214 9,
215 vec![
216 vec![true, false, true, false, true, false, false, true, false],
217 vec![true, false, true, false, true, false, true, false, false],
218 ],
219 );
220 map.insert(
221 11,
222 vec![vec![
223 true, false, true, false, true, true, false, true, false,
224 ]],
225 );
226 map.insert(
227 13,
228 vec![vec![
229 true, false, true, false, true, false, true, false, true,
230 ]],
231 );
232 for i in [1, 3, 5, 6, 7, 8, 10, 12, 14, 15] {
233 map.entry(i).or_insert_with(Vec::new);
234 }
235 map
236 }
237}
238
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
241pub struct KsgTurn;
242
243impl Pattern for KsgTurn {
244 fn size(&self) -> (usize, usize) {
245 (4, 4)
246 }
247 fn cross_location(&self) -> (usize, usize) {
248 (3, 2)
249 }
250 fn is_connected(&self) -> bool {
251 false
252 }
253
254 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
255 let locs = vec![(1, 2), (2, 2), (3, 2), (3, 3), (3, 4)];
256 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4)];
257 let pins = vec![0, 4];
258 (locs, edges, pins)
259 }
260
261 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
262 let locs = vec![(1, 2), (2, 3), (3, 4)];
263 let pins = vec![0, 2];
264 (locs, pins)
265 }
266
267 fn mis_overhead(&self) -> i64 {
268 -1
269 }
270
271 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
272 [(0, 0), (2, 0), (3, 3), (1, 0)].into_iter().collect()
273 }
274
275 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
276 let mut map = HashMap::new();
277 map.insert(0, vec![vec![false, true, false, true, false]]);
278 map.insert(
279 1,
280 vec![
281 vec![true, false, true, false, false],
282 vec![true, false, false, true, false],
283 ],
284 );
285 map.insert(
286 2,
287 vec![
288 vec![false, true, false, false, true],
289 vec![false, false, true, false, true],
290 ],
291 );
292 map.insert(3, vec![vec![true, false, true, false, true]]);
293 map
294 }
295}
296
297#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
299pub struct KsgWTurn;
300
301impl Pattern for KsgWTurn {
302 fn size(&self) -> (usize, usize) {
303 (4, 4)
304 }
305 fn cross_location(&self) -> (usize, usize) {
306 (2, 2)
307 }
308 fn is_connected(&self) -> bool {
309 false
310 }
311
312 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
313 let locs = vec![(2, 3), (2, 4), (3, 2), (3, 3), (4, 2)];
314 let edges = vec![(0, 1), (0, 3), (2, 3), (2, 4)];
315 let pins = vec![1, 4];
316 (locs, edges, pins)
317 }
318
319 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
320 let locs = vec![(2, 4), (3, 3), (4, 2)];
321 let pins = vec![0, 2];
322 (locs, pins)
323 }
324
325 fn mis_overhead(&self) -> i64 {
326 -1
327 }
328
329 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
330 [(0, 0), (2, 0), (3, 3), (1, 0)].into_iter().collect()
331 }
332
333 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
334 let mut map = HashMap::new();
335 map.insert(0, vec![vec![true, false, true, false, false]]);
336 map.insert(
337 1,
338 vec![
339 vec![false, true, false, true, false],
340 vec![false, true, true, false, false],
341 ],
342 );
343 map.insert(
344 2,
345 vec![
346 vec![false, false, false, true, true],
347 vec![true, false, false, false, true],
348 ],
349 );
350 map.insert(3, vec![vec![false, true, false, true, true]]);
351 map
352 }
353}
354
355#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
357pub struct KsgBranch;
358
359impl Pattern for KsgBranch {
360 fn size(&self) -> (usize, usize) {
361 (5, 4)
362 }
363 fn cross_location(&self) -> (usize, usize) {
364 (3, 2)
365 }
366 fn is_connected(&self) -> bool {
367 false
368 }
369
370 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
371 let locs = vec![
372 (1, 2),
373 (2, 2),
374 (3, 2),
375 (3, 3),
376 (3, 4),
377 (4, 3),
378 (4, 2),
379 (5, 2),
380 ];
381 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (3, 5), (5, 6), (6, 7)];
382 let pins = vec![0, 4, 7];
383 (locs, edges, pins)
384 }
385
386 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
387 let locs = vec![(1, 2), (2, 3), (3, 2), (3, 4), (4, 3), (5, 2)];
388 let pins = vec![0, 3, 5];
389 (locs, pins)
390 }
391
392 fn mis_overhead(&self) -> i64 {
393 -1
394 }
395
396 fn source_weights(&self) -> Vec<i64> {
398 vec![2, 2, 2, 3, 2, 2, 2, 2]
399 }
400 fn mapped_weights(&self) -> Vec<i64> {
402 vec![2, 3, 2, 2, 2, 2]
403 }
404
405 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
406 [
407 (0, 0),
408 (4, 0),
409 (5, 5),
410 (6, 6),
411 (2, 0),
412 (7, 7),
413 (3, 3),
414 (1, 0),
415 ]
416 .into_iter()
417 .collect()
418 }
419
420 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
421 let mut map = HashMap::new();
422 map.insert(
423 0,
424 vec![vec![false, true, false, true, false, false, true, false]],
425 );
426 map.insert(
427 3,
428 vec![
429 vec![true, false, true, false, true, false, true, false],
430 vec![true, false, true, false, true, true, false, false],
431 ],
432 );
433 map.insert(
434 5,
435 vec![vec![true, false, true, false, false, true, false, true]],
436 );
437 map.insert(
438 6,
439 vec![
440 vec![false, false, true, false, true, true, false, true],
441 vec![false, true, false, false, true, true, false, true],
442 ],
443 );
444 map.insert(
445 7,
446 vec![vec![true, false, true, false, true, true, false, true]],
447 );
448 for i in [1, 2, 4] {
449 map.insert(i, vec![]);
450 }
451 map
452 }
453}
454
455#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
457pub struct KsgBranchFix;
458
459impl Pattern for KsgBranchFix {
460 fn size(&self) -> (usize, usize) {
461 (4, 4)
462 }
463 fn cross_location(&self) -> (usize, usize) {
464 (2, 2)
465 }
466 fn is_connected(&self) -> bool {
467 false
468 }
469
470 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
471 let locs = vec![(1, 2), (2, 2), (2, 3), (3, 3), (3, 2), (4, 2)];
472 let edges = vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)];
473 let pins = vec![0, 5];
474 (locs, edges, pins)
475 }
476
477 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
478 let locs = vec![(1, 2), (2, 2), (3, 2), (4, 2)];
479 let pins = vec![0, 3];
480 (locs, pins)
481 }
482
483 fn mis_overhead(&self) -> i64 {
484 -1
485 }
486
487 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
488 [(0, 0), (2, 2), (3, 1), (1, 1)].into_iter().collect()
489 }
490
491 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
492 let mut map = HashMap::new();
493 map.insert(
494 0,
495 vec![
496 vec![false, true, false, true, false, false],
497 vec![false, true, false, false, true, false],
498 vec![false, false, true, false, true, false],
499 ],
500 );
501 map.insert(1, vec![vec![true, false, true, false, true, false]]);
502 map.insert(2, vec![vec![false, true, false, true, false, true]]);
503 map.insert(
504 3,
505 vec![
506 vec![true, false, false, true, false, true],
507 vec![true, false, true, false, false, true],
508 ],
509 );
510 map
511 }
512}
513
514#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
516pub struct KsgTCon;
517
518impl Pattern for KsgTCon {
519 fn size(&self) -> (usize, usize) {
520 (3, 4)
521 }
522 fn cross_location(&self) -> (usize, usize) {
523 (2, 2)
524 }
525 fn is_connected(&self) -> bool {
526 true
527 }
528 fn connected_nodes(&self) -> Vec<usize> {
529 vec![0, 1]
530 }
531
532 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
533 let locs = vec![(1, 2), (2, 1), (2, 2), (3, 2)];
534 let edges = vec![(0, 1), (0, 2), (2, 3)];
535 let pins = vec![0, 1, 3];
536 (locs, edges, pins)
537 }
538
539 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
540 let locs = vec![(1, 2), (2, 1), (2, 3), (3, 2)];
541 let pins = vec![0, 1, 3];
542 (locs, pins)
543 }
544
545 fn mis_overhead(&self) -> i64 {
546 0
547 }
548
549 fn source_weights(&self) -> Vec<i64> {
551 vec![2, 1, 2, 2]
552 }
553 fn mapped_weights(&self) -> Vec<i64> {
555 vec![2, 1, 2, 2]
556 }
557
558 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
559 [
560 (0, 0),
561 (4, 0),
562 (5, 5),
563 (6, 6),
564 (2, 2),
565 (7, 7),
566 (3, 3),
567 (1, 0),
568 ]
569 .into_iter()
570 .collect()
571 }
572
573 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
574 let mut map = HashMap::new();
575 map.insert(0, vec![vec![false, false, true, false]]);
576 map.insert(1, vec![vec![true, false, false, false]]);
577 map.insert(2, vec![vec![false, true, true, false]]);
578 map.insert(4, vec![vec![false, false, false, true]]);
579 map.insert(5, vec![vec![true, false, false, true]]);
580 map.insert(6, vec![vec![false, true, false, true]]);
581 map.insert(3, vec![]);
582 map.insert(7, vec![]);
583 map
584 }
585}
586
587#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
589pub struct KsgTrivialTurn;
590
591impl Pattern for KsgTrivialTurn {
592 fn size(&self) -> (usize, usize) {
593 (2, 2)
594 }
595 fn cross_location(&self) -> (usize, usize) {
596 (2, 2)
597 }
598 fn is_connected(&self) -> bool {
599 true
600 }
601 fn connected_nodes(&self) -> Vec<usize> {
602 vec![0, 1]
603 }
604
605 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
606 let locs = vec![(1, 2), (2, 1)];
607 let edges = vec![(0, 1)];
608 let pins = vec![0, 1];
609 (locs, edges, pins)
610 }
611
612 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
613 let locs = vec![(1, 2), (2, 1)];
614 let pins = vec![0, 1];
615 (locs, pins)
616 }
617
618 fn mis_overhead(&self) -> i64 {
619 0
620 }
621
622 fn source_weights(&self) -> Vec<i64> {
624 vec![1, 1]
625 }
626 fn mapped_weights(&self) -> Vec<i64> {
628 vec![1, 1]
629 }
630
631 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
632 [(0, 0), (2, 2), (3, 3), (1, 1)].into_iter().collect()
633 }
634
635 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
636 let mut map = HashMap::new();
637 map.insert(0, vec![vec![false, false]]);
638 map.insert(1, vec![vec![true, false]]);
639 map.insert(2, vec![vec![false, true]]);
640 map.insert(3, vec![]);
641 map
642 }
643}
644
645#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
647pub struct KsgEndTurn;
648
649impl Pattern for KsgEndTurn {
650 fn size(&self) -> (usize, usize) {
651 (3, 4)
652 }
653 fn cross_location(&self) -> (usize, usize) {
654 (2, 2)
655 }
656 fn is_connected(&self) -> bool {
657 false
658 }
659
660 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
661 let locs = vec![(1, 2), (2, 2), (2, 3)];
662 let edges = vec![(0, 1), (1, 2)];
663 let pins = vec![0];
664 (locs, edges, pins)
665 }
666
667 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
668 let locs = vec![(1, 2)];
669 let pins = vec![0];
670 (locs, pins)
671 }
672
673 fn mis_overhead(&self) -> i64 {
674 -1
675 }
676
677 fn source_weights(&self) -> Vec<i64> {
679 vec![2, 2, 1]
680 }
681 fn mapped_weights(&self) -> Vec<i64> {
683 vec![1]
684 }
685
686 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
687 [(0, 0), (1, 1)].into_iter().collect()
688 }
689
690 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
691 let mut map = HashMap::new();
692 map.insert(0, vec![vec![false, false, true], vec![false, true, false]]);
693 map.insert(1, vec![vec![true, false, true]]);
694 map
695 }
696}
697
698#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
700pub struct KsgBranchFixB;
701
702impl Pattern for KsgBranchFixB {
703 fn size(&self) -> (usize, usize) {
704 (4, 4)
705 }
706 fn cross_location(&self) -> (usize, usize) {
707 (2, 2)
708 }
709 fn is_connected(&self) -> bool {
710 false
711 }
712
713 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
714 let locs = vec![(2, 3), (3, 2), (3, 3), (4, 2)];
715 let edges = vec![(0, 2), (1, 2), (1, 3)];
716 let pins = vec![0, 3];
717 (locs, edges, pins)
718 }
719
720 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
721 let locs = vec![(3, 2), (4, 2)];
722 let pins = vec![0, 1];
723 (locs, pins)
724 }
725
726 fn mis_overhead(&self) -> i64 {
727 -1
728 }
729
730 fn source_weights(&self) -> Vec<i64> {
732 vec![1, 2, 2, 2]
733 }
734 fn mapped_weights(&self) -> Vec<i64> {
736 vec![1, 2]
737 }
738
739 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
740 [(0, 0), (2, 2), (3, 3), (1, 1)].into_iter().collect()
741 }
742
743 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
744 let mut map = HashMap::new();
745 map.insert(
746 0,
747 vec![
748 vec![false, false, true, false],
749 vec![false, true, false, false],
750 ],
751 );
752 map.insert(1, vec![vec![true, true, false, false]]);
753 map.insert(2, vec![vec![false, false, true, true]]);
754 map.insert(3, vec![vec![true, false, false, true]]);
755 map
756 }
757}
758
759#[derive(Debug, Clone)]
765pub struct KsgRotatedGadget<G: Pattern> {
766 pub gadget: G,
767 pub n: usize,
769}
770
771impl<G: Pattern> KsgRotatedGadget<G> {
772 pub fn new(gadget: G, n: usize) -> Self {
773 Self { gadget, n: n % 4 }
774 }
775}
776
777fn rotate90(loc: (i64, i64)) -> (i64, i64) {
778 (-loc.1, loc.0)
779}
780
781fn rotate_around_center(loc: (usize, usize), center: (usize, usize), n: usize) -> (i64, i64) {
782 let center = (
783 i64::try_from(center.0).expect("gadget coordinates fit i64"),
784 i64::try_from(center.1).expect("gadget coordinates fit i64"),
785 );
786 let mut dx = i64::try_from(loc.0).expect("gadget coordinates fit i64") - center.0;
787 let mut dy = i64::try_from(loc.1).expect("gadget coordinates fit i64") - center.1;
788 for _ in 0..n {
789 let (nx, ny) = rotate90((dx, dy));
790 dx = nx;
791 dy = ny;
792 }
793 (center.0 + dx, center.1 + dy)
794}
795
796impl<G: Pattern> Pattern for KsgRotatedGadget<G> {
797 fn size(&self) -> (usize, usize) {
798 let (m, n) = self.gadget.size();
799 if self.n.is_multiple_of(2) {
800 (m, n)
801 } else {
802 (n, m)
803 }
804 }
805
806 fn cross_location(&self) -> (usize, usize) {
807 let center = self.gadget.cross_location();
808 let (m, n) = self.gadget.size();
809 let rotated = rotate_around_center(center, center, self.n);
810 let corners = [(1, 1), (m, n)];
811 let rotated_corners: Vec<_> = corners
812 .iter()
813 .map(|&c| rotate_around_center(c, center, self.n))
814 .collect();
815 let min_r = rotated_corners.iter().map(|c| c.0).min().unwrap();
816 let min_c = rotated_corners.iter().map(|c| c.1).min().unwrap();
817 let offset_r = 1 - min_r;
818 let offset_c = 1 - min_c;
819 (
820 (rotated.0 + offset_r) as usize,
821 (rotated.1 + offset_c) as usize,
822 )
823 }
824
825 fn is_connected(&self) -> bool {
826 self.gadget.is_connected()
827 }
828 fn is_cross_gadget(&self) -> bool {
829 self.gadget.is_cross_gadget()
830 }
831 fn connected_nodes(&self) -> Vec<usize> {
832 self.gadget.connected_nodes()
833 }
834
835 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
836 let (locs, edges, pins) = self.gadget.source_graph();
837 let center = self.gadget.cross_location();
838 let (m, n) = self.gadget.size();
839 let corners = [(1usize, 1usize), (m, n)];
840 let rotated_corners: Vec<_> = corners
841 .iter()
842 .map(|&c| rotate_around_center(c, center, self.n))
843 .collect();
844 let min_r = rotated_corners.iter().map(|c| c.0).min().unwrap();
845 let min_c = rotated_corners.iter().map(|c| c.1).min().unwrap();
846 let offset_r = 1 - min_r;
847 let offset_c = 1 - min_c;
848 let new_locs: Vec<_> = locs
849 .into_iter()
850 .map(|loc| {
851 let rotated = rotate_around_center(loc, center, self.n);
852 (
853 (rotated.0 + offset_r) as usize,
854 (rotated.1 + offset_c) as usize,
855 )
856 })
857 .collect();
858 (new_locs, edges, pins)
859 }
860
861 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
862 let (locs, pins) = self.gadget.mapped_graph();
863 let center = self.gadget.cross_location();
864 let (m, n) = self.gadget.size();
865 let corners = [(1usize, 1usize), (m, n)];
866 let rotated_corners: Vec<_> = corners
867 .iter()
868 .map(|&c| rotate_around_center(c, center, self.n))
869 .collect();
870 let min_r = rotated_corners.iter().map(|c| c.0).min().unwrap();
871 let min_c = rotated_corners.iter().map(|c| c.1).min().unwrap();
872 let offset_r = 1 - min_r;
873 let offset_c = 1 - min_c;
874 let new_locs: Vec<_> = locs
875 .into_iter()
876 .map(|loc| {
877 let rotated = rotate_around_center(loc, center, self.n);
878 (
879 (rotated.0 + offset_r) as usize,
880 (rotated.1 + offset_c) as usize,
881 )
882 })
883 .collect();
884 (new_locs, pins)
885 }
886
887 fn mis_overhead(&self) -> i64 {
888 self.gadget.mis_overhead()
889 }
890 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
891 self.gadget.mapped_entry_to_compact()
892 }
893 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
894 self.gadget.source_entry_to_configs()
895 }
896
897 fn source_weights(&self) -> Vec<i64> {
899 self.gadget.source_weights()
900 }
901 fn mapped_weights(&self) -> Vec<i64> {
902 self.gadget.mapped_weights()
903 }
904}
905
906#[derive(Debug, Clone, Copy, PartialEq, Eq)]
908pub enum Mirror {
909 X,
910 Y,
911 Diag,
912 OffDiag,
913}
914
915#[derive(Debug, Clone)]
917pub struct KsgReflectedGadget<G: Pattern> {
918 pub gadget: G,
919 pub mirror: Mirror,
920}
921
922impl<G: Pattern> KsgReflectedGadget<G> {
923 pub fn new(gadget: G, mirror: Mirror) -> Self {
924 Self { gadget, mirror }
925 }
926}
927
928fn reflect(loc: (i64, i64), mirror: Mirror) -> (i64, i64) {
929 match mirror {
930 Mirror::X => (loc.0, -loc.1),
931 Mirror::Y => (-loc.0, loc.1),
932 Mirror::Diag => (-loc.1, -loc.0),
933 Mirror::OffDiag => (loc.1, loc.0),
934 }
935}
936
937fn reflect_around_center(
938 loc: (usize, usize),
939 center: (usize, usize),
940 mirror: Mirror,
941) -> (i64, i64) {
942 let center = (
943 i64::try_from(center.0).expect("gadget coordinates fit i64"),
944 i64::try_from(center.1).expect("gadget coordinates fit i64"),
945 );
946 let dx = i64::try_from(loc.0).expect("gadget coordinates fit i64") - center.0;
947 let dy = i64::try_from(loc.1).expect("gadget coordinates fit i64") - center.1;
948 let (nx, ny) = reflect((dx, dy), mirror);
949 (center.0 + nx, center.1 + ny)
950}
951
952impl<G: Pattern> Pattern for KsgReflectedGadget<G> {
953 fn size(&self) -> (usize, usize) {
954 let (m, n) = self.gadget.size();
955 match self.mirror {
956 Mirror::X | Mirror::Y => (m, n),
957 Mirror::Diag | Mirror::OffDiag => (n, m),
958 }
959 }
960
961 fn cross_location(&self) -> (usize, usize) {
962 let center = self.gadget.cross_location();
963 let (m, n) = self.gadget.size();
964 let reflected = reflect_around_center(center, center, self.mirror);
965 let corners = [(1, 1), (m, n)];
966 let reflected_corners: Vec<_> = corners
967 .iter()
968 .map(|&c| reflect_around_center(c, center, self.mirror))
969 .collect();
970 let min_r = reflected_corners.iter().map(|c| c.0).min().unwrap();
971 let min_c = reflected_corners.iter().map(|c| c.1).min().unwrap();
972 let offset_r = 1 - min_r;
973 let offset_c = 1 - min_c;
974 (
975 (reflected.0 + offset_r) as usize,
976 (reflected.1 + offset_c) as usize,
977 )
978 }
979
980 fn is_connected(&self) -> bool {
981 self.gadget.is_connected()
982 }
983 fn is_cross_gadget(&self) -> bool {
984 self.gadget.is_cross_gadget()
985 }
986 fn connected_nodes(&self) -> Vec<usize> {
987 self.gadget.connected_nodes()
988 }
989
990 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
991 let (locs, edges, pins) = self.gadget.source_graph();
992 let center = self.gadget.cross_location();
993 let (m, n) = self.gadget.size();
994 let corners = [(1usize, 1usize), (m, n)];
995 let reflected_corners: Vec<_> = corners
996 .iter()
997 .map(|&c| reflect_around_center(c, center, self.mirror))
998 .collect();
999 let min_r = reflected_corners.iter().map(|c| c.0).min().unwrap();
1000 let min_c = reflected_corners.iter().map(|c| c.1).min().unwrap();
1001 let offset_r = 1 - min_r;
1002 let offset_c = 1 - min_c;
1003 let new_locs: Vec<_> = locs
1004 .into_iter()
1005 .map(|loc| {
1006 let reflected = reflect_around_center(loc, center, self.mirror);
1007 (
1008 (reflected.0 + offset_r) as usize,
1009 (reflected.1 + offset_c) as usize,
1010 )
1011 })
1012 .collect();
1013 (new_locs, edges, pins)
1014 }
1015
1016 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
1017 let (locs, pins) = self.gadget.mapped_graph();
1018 let center = self.gadget.cross_location();
1019 let (m, n) = self.gadget.size();
1020 let corners = [(1usize, 1usize), (m, n)];
1021 let reflected_corners: Vec<_> = corners
1022 .iter()
1023 .map(|&c| reflect_around_center(c, center, self.mirror))
1024 .collect();
1025 let min_r = reflected_corners.iter().map(|c| c.0).min().unwrap();
1026 let min_c = reflected_corners.iter().map(|c| c.1).min().unwrap();
1027 let offset_r = 1 - min_r;
1028 let offset_c = 1 - min_c;
1029 let new_locs: Vec<_> = locs
1030 .into_iter()
1031 .map(|loc| {
1032 let reflected = reflect_around_center(loc, center, self.mirror);
1033 (
1034 (reflected.0 + offset_r) as usize,
1035 (reflected.1 + offset_c) as usize,
1036 )
1037 })
1038 .collect();
1039 (new_locs, pins)
1040 }
1041
1042 fn mis_overhead(&self) -> i64 {
1043 self.gadget.mis_overhead()
1044 }
1045 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
1046 self.gadget.mapped_entry_to_compact()
1047 }
1048 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
1049 self.gadget.source_entry_to_configs()
1050 }
1051
1052 fn source_weights(&self) -> Vec<i64> {
1054 self.gadget.source_weights()
1055 }
1056 fn mapped_weights(&self) -> Vec<i64> {
1057 self.gadget.mapped_weights()
1058 }
1059}
1060
1061#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
1077pub struct KsgDanglingLeg;
1078
1079impl Pattern for KsgDanglingLeg {
1080 fn size(&self) -> (usize, usize) {
1081 (4, 3)
1082 }
1083 fn cross_location(&self) -> (usize, usize) {
1085 (2, 1)
1086 }
1087 fn is_connected(&self) -> bool {
1088 false
1089 }
1090
1091 fn source_graph(&self) -> (Vec<(usize, usize)>, Vec<(usize, usize)>, Vec<usize>) {
1092 let locs = vec![(2, 2), (3, 2), (4, 2)];
1094 let edges = vec![(0, 1), (1, 2)];
1095 let pins = vec![2];
1097 (locs, edges, pins)
1098 }
1099
1100 fn mapped_graph(&self) -> (Vec<(usize, usize)>, Vec<usize>) {
1101 let locs = vec![(4, 2)];
1103 let pins = vec![0];
1104 (locs, pins)
1105 }
1106
1107 fn mis_overhead(&self) -> i64 {
1108 -1
1109 }
1110
1111 fn source_weights(&self) -> Vec<i64> {
1113 vec![1, 2, 2]
1114 }
1115 fn mapped_weights(&self) -> Vec<i64> {
1117 vec![1]
1118 }
1119
1120 fn mapped_entry_to_compact(&self) -> HashMap<usize, usize> {
1121 [(0, 0), (1, 1)].into_iter().collect()
1123 }
1124
1125 fn source_entry_to_configs(&self) -> HashMap<usize, Vec<Vec<bool>>> {
1126 let mut map = HashMap::new();
1130 map.insert(0, vec![vec![true, false, false], vec![false, true, false]]);
1131 map.insert(1, vec![vec![true, false, true]]);
1132 map
1133 }
1134}
1135
1136#[derive(Debug, Clone)]
1142pub enum KsgPattern {
1143 CrossFalse(KsgCross<false>),
1144 CrossTrue(KsgCross<true>),
1145 Turn(KsgTurn),
1146 WTurn(KsgWTurn),
1147 Branch(KsgBranch),
1148 BranchFix(KsgBranchFix),
1149 TCon(KsgTCon),
1150 TrivialTurn(KsgTrivialTurn),
1151 EndTurn(KsgEndTurn),
1152 BranchFixB(KsgBranchFixB),
1153 DanglingLeg(KsgDanglingLeg),
1154 RotatedTCon1(KsgRotatedGadget<KsgTCon>),
1155 ReflectedCrossTrue(KsgReflectedGadget<KsgCross<true>>),
1156 ReflectedTrivialTurn(KsgReflectedGadget<KsgTrivialTurn>),
1157 ReflectedRotatedTCon1(KsgReflectedGadget<KsgRotatedGadget<KsgTCon>>),
1158 DanglingLegRot1(KsgRotatedGadget<KsgDanglingLeg>),
1159 DanglingLegRot2(KsgRotatedGadget<KsgRotatedGadget<KsgDanglingLeg>>),
1160 DanglingLegRot3(KsgRotatedGadget<KsgRotatedGadget<KsgRotatedGadget<KsgDanglingLeg>>>),
1161 DanglingLegReflX(KsgReflectedGadget<KsgDanglingLeg>),
1162 DanglingLegReflY(KsgReflectedGadget<KsgDanglingLeg>),
1163}
1164
1165impl KsgPattern {
1166 pub fn from_tape_idx(idx: usize) -> Option<Self> {
1168 match idx {
1169 0 => Some(Self::CrossFalse(KsgCross::<false>)),
1170 1 => Some(Self::Turn(KsgTurn)),
1171 2 => Some(Self::WTurn(KsgWTurn)),
1172 3 => Some(Self::Branch(KsgBranch)),
1173 4 => Some(Self::BranchFix(KsgBranchFix)),
1174 5 => Some(Self::TCon(KsgTCon)),
1175 6 => Some(Self::TrivialTurn(KsgTrivialTurn)),
1176 7 => Some(Self::RotatedTCon1(KsgRotatedGadget::new(KsgTCon, 1))),
1177 8 => Some(Self::ReflectedCrossTrue(KsgReflectedGadget::new(
1178 KsgCross::<true>,
1179 Mirror::Y,
1180 ))),
1181 9 => Some(Self::ReflectedTrivialTurn(KsgReflectedGadget::new(
1182 KsgTrivialTurn,
1183 Mirror::Y,
1184 ))),
1185 10 => Some(Self::BranchFixB(KsgBranchFixB)),
1186 11 => Some(Self::EndTurn(KsgEndTurn)),
1187 12 => Some(Self::ReflectedRotatedTCon1(KsgReflectedGadget::new(
1188 KsgRotatedGadget::new(KsgTCon, 1),
1189 Mirror::Y,
1190 ))),
1191 100 => Some(Self::DanglingLeg(KsgDanglingLeg)),
1192 101 => Some(Self::DanglingLegRot1(KsgRotatedGadget::new(
1193 KsgDanglingLeg,
1194 1,
1195 ))),
1196 102 => Some(Self::DanglingLegRot2(KsgRotatedGadget::new(
1197 KsgRotatedGadget::new(KsgDanglingLeg, 1),
1198 1,
1199 ))),
1200 103 => Some(Self::DanglingLegRot3(KsgRotatedGadget::new(
1201 KsgRotatedGadget::new(KsgRotatedGadget::new(KsgDanglingLeg, 1), 1),
1202 1,
1203 ))),
1204 104 => Some(Self::DanglingLegReflX(KsgReflectedGadget::new(
1205 KsgDanglingLeg,
1206 Mirror::X,
1207 ))),
1208 105 => Some(Self::DanglingLegReflY(KsgReflectedGadget::new(
1209 KsgDanglingLeg,
1210 Mirror::Y,
1211 ))),
1212 _ => None,
1213 }
1214 }
1215
1216 pub(crate) fn map_config_back(
1218 &self,
1219 gi: usize,
1220 gj: usize,
1221 config: &mut [Vec<usize>],
1222 ) -> Result<(), ReductionError> {
1223 match self {
1224 Self::CrossFalse(p) => map_config_back_pattern(p, gi, gj, config),
1225 Self::CrossTrue(p) => map_config_back_pattern(p, gi, gj, config),
1226 Self::Turn(p) => map_config_back_pattern(p, gi, gj, config),
1227 Self::WTurn(p) => map_config_back_pattern(p, gi, gj, config),
1228 Self::Branch(p) => map_config_back_pattern(p, gi, gj, config),
1229 Self::BranchFix(p) => map_config_back_pattern(p, gi, gj, config),
1230 Self::TCon(p) => map_config_back_pattern(p, gi, gj, config),
1231 Self::TrivialTurn(p) => map_config_back_pattern(p, gi, gj, config),
1232 Self::EndTurn(p) => map_config_back_pattern(p, gi, gj, config),
1233 Self::BranchFixB(p) => map_config_back_pattern(p, gi, gj, config),
1234 Self::DanglingLeg(p) => map_config_back_pattern(p, gi, gj, config),
1235 Self::RotatedTCon1(p) => map_config_back_pattern(p, gi, gj, config),
1236 Self::ReflectedCrossTrue(p) => map_config_back_pattern(p, gi, gj, config),
1237 Self::ReflectedTrivialTurn(p) => map_config_back_pattern(p, gi, gj, config),
1238 Self::ReflectedRotatedTCon1(p) => map_config_back_pattern(p, gi, gj, config),
1239 Self::DanglingLegRot1(p) => map_config_back_pattern(p, gi, gj, config),
1240 Self::DanglingLegRot2(p) => map_config_back_pattern(p, gi, gj, config),
1241 Self::DanglingLegRot3(p) => map_config_back_pattern(p, gi, gj, config),
1242 Self::DanglingLegReflX(p) => map_config_back_pattern(p, gi, gj, config),
1243 Self::DanglingLegReflY(p) => map_config_back_pattern(p, gi, gj, config),
1244 }
1245 }
1246}
1247
1248#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
1254pub struct KsgTapeEntry {
1255 pub pattern_idx: usize,
1256 pub row: usize,
1257 pub col: usize,
1258}
1259
1260pub fn tape_entry_mis_overhead(entry: &KsgTapeEntry) -> Result<i64, ReductionError> {
1262 Ok(match entry.pattern_idx {
1263 0 => KsgCross::<false>.mis_overhead(),
1264 1 => KsgTurn.mis_overhead(),
1265 2 => KsgWTurn.mis_overhead(),
1266 3 => KsgBranch.mis_overhead(),
1267 4 => KsgBranchFix.mis_overhead(),
1268 5 => KsgTCon.mis_overhead(),
1269 6 => KsgTrivialTurn.mis_overhead(),
1270 7 => KsgRotatedGadget::new(KsgTCon, 1).mis_overhead(),
1271 8 => KsgReflectedGadget::new(KsgCross::<true>, Mirror::Y).mis_overhead(),
1272 9 => KsgReflectedGadget::new(KsgTrivialTurn, Mirror::Y).mis_overhead(),
1273 10 => KsgBranchFixB.mis_overhead(),
1274 11 => KsgEndTurn.mis_overhead(),
1275 12 => KsgReflectedGadget::new(KsgRotatedGadget::new(KsgTCon, 1), Mirror::Y).mis_overhead(),
1276 100..=105 => KsgDanglingLeg.mis_overhead(),
1277 _ => {
1278 return Err(mapping_invalid(
1279 "tape contains an unknown unweighted KSG gadget index",
1280 ))
1281 }
1282 })
1283}
1284
1285#[allow(dead_code)]
1287pub fn crossing_ruleset_indices() -> Vec<usize> {
1288 (0..13).collect()
1289}
1290
1291pub fn apply_crossing_gadgets(
1297 grid: &mut MappingGrid,
1298 copylines: &[super::super::copyline::CopyLine],
1299) -> Vec<KsgTapeEntry> {
1300 let mut tape = Vec::new();
1301 let n = copylines.len();
1302
1303 for j in 0..n {
1304 for i in 0..n {
1305 let (cross_row, cross_col) = crossat(grid, copylines, i, j);
1306 if let Some((pattern_idx, row, col)) =
1307 try_match_and_apply_crossing(grid, cross_row, cross_col)
1308 {
1309 tape.push(KsgTapeEntry {
1310 pattern_idx,
1311 row,
1312 col,
1313 });
1314 }
1315 }
1316 }
1317 tape
1318}
1319
1320fn crossat(
1323 grid: &MappingGrid,
1324 copylines: &[super::super::copyline::CopyLine],
1325 v: usize,
1326 w: usize,
1327) -> (usize, usize) {
1328 let line_v = copylines.get(v);
1329 let line_w = copylines.get(w);
1330
1331 match (line_v, line_w) {
1332 (Some(lv), Some(lw)) => {
1333 let (line_first, line_second) = if lv.vslot < lw.vslot {
1334 (lv, lw)
1335 } else {
1336 (lw, lv)
1337 };
1338 grid.cross_at(line_first.vslot, line_second.vslot, line_first.hslot)
1340 }
1341 _ => (0, 0),
1342 }
1343}
1344
1345fn try_match_and_apply_crossing(
1346 grid: &mut MappingGrid,
1347 cross_row: usize,
1348 cross_col: usize,
1349) -> Option<(usize, usize, usize)> {
1350 let patterns: Vec<(usize, PatternFactory)> = vec![
1352 (0, Box::new(|| Box::new(KsgCross::<false>))),
1353 (1, Box::new(|| Box::new(KsgTurn))),
1354 (2, Box::new(|| Box::new(KsgWTurn))),
1355 (3, Box::new(|| Box::new(KsgBranch))),
1356 (4, Box::new(|| Box::new(KsgBranchFix))),
1357 (5, Box::new(|| Box::new(KsgTCon))),
1358 (6, Box::new(|| Box::new(KsgTrivialTurn))),
1359 (7, Box::new(|| Box::new(KsgRotatedGadget::new(KsgTCon, 1)))),
1360 (
1361 8,
1362 Box::new(|| Box::new(KsgReflectedGadget::new(KsgCross::<true>, Mirror::Y))),
1363 ),
1364 (
1365 9,
1366 Box::new(|| Box::new(KsgReflectedGadget::new(KsgTrivialTurn, Mirror::Y))),
1367 ),
1368 (10, Box::new(|| Box::new(KsgBranchFixB))),
1369 (11, Box::new(|| Box::new(KsgEndTurn))),
1370 (
1371 12,
1372 Box::new(|| {
1373 Box::new(KsgReflectedGadget::new(
1374 KsgRotatedGadget::new(KsgTCon, 1),
1375 Mirror::Y,
1376 ))
1377 }),
1378 ),
1379 ];
1380
1381 for (idx, make_pattern) in patterns {
1382 let pattern = make_pattern();
1383 let cl = pattern.cross_location();
1384 if cross_row + 1 >= cl.0 && cross_col + 1 >= cl.1 {
1387 let x = cross_row + 1 - cl.0;
1388 let y = cross_col + 1 - cl.1;
1389 if pattern.pattern_matches_boxed(grid, x, y) {
1390 pattern.apply_gadget_boxed(grid, x, y);
1391 return Some((idx, x, y));
1392 }
1393 }
1394 }
1395 None
1396}
1397
1398pub fn apply_weighted_crossing_gadgets(
1401 grid: &mut MappingGrid,
1402 copylines: &[super::super::copyline::CopyLine],
1403) -> Vec<KsgTapeEntry> {
1404 let mut tape = Vec::new();
1405 let n = copylines.len();
1406
1407 for j in 0..n {
1408 for i in 0..n {
1409 let (cross_row, cross_col) = crossat(grid, copylines, i, j);
1410 if let Some((pattern_idx, row, col)) =
1411 try_match_and_apply_weighted_crossing(grid, cross_row, cross_col)
1412 {
1413 tape.push(KsgTapeEntry {
1414 pattern_idx,
1415 row,
1416 col,
1417 });
1418 }
1419 }
1420 }
1421 tape
1422}
1423
1424fn try_match_and_apply_weighted_crossing(
1425 grid: &mut MappingGrid,
1426 cross_row: usize,
1427 cross_col: usize,
1428) -> Option<(usize, usize, usize)> {
1429 let patterns: Vec<(usize, PatternFactory)> = vec![
1431 (0, Box::new(|| Box::new(KsgCross::<false>))),
1432 (1, Box::new(|| Box::new(KsgTurn))),
1433 (2, Box::new(|| Box::new(KsgWTurn))),
1434 (3, Box::new(|| Box::new(KsgBranch))),
1435 (4, Box::new(|| Box::new(KsgBranchFix))),
1436 (5, Box::new(|| Box::new(KsgTCon))),
1437 (6, Box::new(|| Box::new(KsgTrivialTurn))),
1438 (7, Box::new(|| Box::new(KsgRotatedGadget::new(KsgTCon, 1)))),
1439 (
1440 8,
1441 Box::new(|| Box::new(KsgReflectedGadget::new(KsgCross::<true>, Mirror::Y))),
1442 ),
1443 (
1444 9,
1445 Box::new(|| Box::new(KsgReflectedGadget::new(KsgTrivialTurn, Mirror::Y))),
1446 ),
1447 (10, Box::new(|| Box::new(KsgBranchFixB))),
1448 (11, Box::new(|| Box::new(KsgEndTurn))),
1449 (
1450 12,
1451 Box::new(|| {
1452 Box::new(KsgReflectedGadget::new(
1453 KsgRotatedGadget::new(KsgTCon, 1),
1454 Mirror::Y,
1455 ))
1456 }),
1457 ),
1458 ];
1459
1460 for (idx, make_pattern) in patterns {
1461 let pattern = make_pattern();
1462 let cl = pattern.cross_location();
1463 if cross_row + 1 >= cl.0 && cross_col + 1 >= cl.1 {
1464 let x = cross_row + 1 - cl.0;
1465 let y = cross_col + 1 - cl.1;
1466 let matches = pattern.pattern_matches_boxed(grid, x, y);
1467 if matches {
1468 pattern.apply_weighted_gadget_boxed(grid, x, y);
1469 return Some((idx, x, y));
1470 }
1471 }
1472 }
1473 None
1474}
1475
1476pub fn apply_simplifier_gadgets(grid: &mut MappingGrid, nrepeat: usize) -> Vec<KsgTapeEntry> {
1479 let mut tape = Vec::new();
1480 let (rows, cols) = grid.size();
1481
1482 let patterns = rotated_and_reflected_danglinleg();
1484
1485 for _ in 0..nrepeat {
1486 for (pattern_idx, pattern) in patterns.iter().enumerate() {
1487 for j in 0..cols {
1488 for i in 0..rows {
1489 if pattern_matches_boxed(pattern.as_ref(), grid, i, j) {
1490 apply_gadget_boxed(pattern.as_ref(), grid, i, j);
1491 tape.push(KsgTapeEntry {
1492 pattern_idx: 100 + pattern_idx, row: i,
1494 col: j,
1495 });
1496 }
1497 }
1498 }
1499 }
1500 }
1501
1502 tape
1503}
1504
1505pub fn apply_weighted_simplifier_gadgets(
1509 grid: &mut MappingGrid,
1510 nrepeat: usize,
1511) -> Vec<KsgTapeEntry> {
1512 let mut tape = Vec::new();
1513 let (rows, cols) = grid.size();
1514
1515 let patterns = rotated_and_reflected_danglinleg();
1516
1517 for _ in 0..nrepeat {
1518 for (pattern_idx, pattern) in patterns.iter().enumerate() {
1519 for j in 0..cols {
1520 for i in 0..rows {
1521 if pattern_matches_weighted(pattern.as_ref(), grid, i, j) {
1522 pattern.apply_weighted_gadget_boxed(grid, i, j);
1523 tape.push(KsgTapeEntry {
1524 pattern_idx: 100 + pattern_idx,
1525 row: i,
1526 col: j,
1527 });
1528 }
1529 }
1530 }
1531 }
1532 }
1533
1534 tape
1535}
1536
1537fn pattern_matches_weighted(
1541 pattern: &dyn KsgPatternBoxed,
1542 grid: &MappingGrid,
1543 i: usize,
1544 j: usize,
1545) -> bool {
1546 if !pattern_matches_boxed(pattern, grid, i, j) {
1548 return false;
1549 }
1550
1551 let (locs, _, _) = pattern.source_graph_boxed();
1555 if let Some((loc_r, loc_c)) = locs.first() {
1558 let grid_r = i + loc_r - 1;
1559 let grid_c = j + loc_c - 1;
1560 if let Some(cell) = grid.get(grid_r, grid_c) {
1561 if cell.weight() != 1 {
1563 return false;
1564 }
1565 }
1566 }
1567
1568 for (_idx, (loc_r, loc_c)) in locs.iter().enumerate().skip(1) {
1570 let grid_r = i + loc_r - 1;
1571 let grid_c = j + loc_c - 1;
1572 if let Some(cell) = grid.get(grid_r, grid_c) {
1573 if cell.weight() != 2 {
1574 return false;
1575 }
1576 }
1577 }
1578
1579 true
1580}
1581
1582fn rotated_and_reflected_danglinleg() -> Vec<Box<dyn KsgPatternBoxed>> {
1583 vec![
1584 Box::new(KsgDanglingLeg),
1585 Box::new(KsgRotatedGadget::new(KsgDanglingLeg, 1)),
1586 Box::new(KsgRotatedGadget::new(KsgDanglingLeg, 2)),
1587 Box::new(KsgRotatedGadget::new(KsgDanglingLeg, 3)),
1588 Box::new(KsgReflectedGadget::new(KsgDanglingLeg, Mirror::X)),
1589 Box::new(KsgReflectedGadget::new(KsgDanglingLeg, Mirror::Y)),
1590 ]
1591}
1592
1593#[allow(clippy::needless_range_loop)]
1595fn pattern_matches_boxed(
1596 pattern: &dyn KsgPatternBoxed,
1597 grid: &MappingGrid,
1598 i: usize,
1599 j: usize,
1600) -> bool {
1601 let source = pattern.source_matrix();
1602 let (m, n) = pattern.size_boxed();
1603
1604 for r in 0..m {
1605 for c in 0..n {
1606 let grid_r = i + r;
1607 let grid_c = j + c;
1608
1609 let expected = source[r][c];
1610 let actual = safe_get_pattern_cell(grid, grid_r, grid_c);
1611
1612 let matches = match (expected, actual) {
1615 (a, b) if a == b => true,
1616 (PatternCell::Connected, PatternCell::Occupied) => true,
1617 (PatternCell::Occupied, PatternCell::Connected) => true,
1618 _ => false,
1619 };
1620 if !matches {
1621 return false;
1622 }
1623 }
1624 }
1625 true
1626}
1627
1628fn safe_get_pattern_cell(grid: &MappingGrid, row: usize, col: usize) -> PatternCell {
1629 let (rows, cols) = grid.size();
1630 if row >= rows || col >= cols {
1631 return PatternCell::Empty;
1632 }
1633 match grid.get(row, col) {
1634 Some(CellState::Empty) => PatternCell::Empty,
1635 Some(CellState::Occupied { .. }) => PatternCell::Occupied,
1636 Some(CellState::Doubled { .. }) => PatternCell::Doubled,
1637 Some(CellState::Connected { .. }) => PatternCell::Connected,
1638 None => PatternCell::Empty,
1639 }
1640}
1641
1642#[allow(clippy::needless_range_loop)]
1644fn apply_gadget_boxed(pattern: &dyn KsgPatternBoxed, grid: &mut MappingGrid, i: usize, j: usize) {
1645 let mapped = pattern.mapped_matrix();
1646 let (m, n) = pattern.size_boxed();
1647
1648 for r in 0..m {
1649 for c in 0..n {
1650 let grid_r = i + r;
1651 let grid_c = j + c;
1652
1653 let cell = mapped[r][c];
1654 let state = match cell {
1655 PatternCell::Empty => CellState::Empty,
1656 PatternCell::Occupied => CellState::Occupied { weight: 1 },
1657 PatternCell::Doubled => CellState::Doubled { weight: 1 },
1658 PatternCell::Connected => CellState::Connected { weight: 1 },
1659 };
1660 grid.set(grid_r, grid_c, state);
1661 }
1662 }
1663}
1664
1665#[allow(dead_code)]
1667fn apply_weighted_gadget_boxed_fn(
1668 pattern: &dyn KsgPatternBoxed,
1669 grid: &mut MappingGrid,
1670 i: usize,
1671 j: usize,
1672) {
1673 pattern.apply_weighted_gadget_boxed(grid, i, j);
1674}
1675
1676pub trait KsgPatternBoxed {
1678 fn size_boxed(&self) -> (usize, usize);
1679 fn cross_location(&self) -> (usize, usize);
1680 fn source_matrix(&self) -> Vec<Vec<PatternCell>>;
1681 fn mapped_matrix(&self) -> Vec<Vec<PatternCell>>;
1682 fn source_graph_boxed(&self) -> SourceGraph;
1683 fn pattern_matches_boxed(&self, grid: &MappingGrid, i: usize, j: usize) -> bool;
1684 fn apply_gadget_boxed(&self, grid: &mut MappingGrid, i: usize, j: usize);
1685 fn apply_weighted_gadget_boxed(&self, grid: &mut MappingGrid, i: usize, j: usize);
1686}
1687
1688impl<P: Pattern> KsgPatternBoxed for P {
1689 fn size_boxed(&self) -> (usize, usize) {
1690 self.size()
1691 }
1692 fn cross_location(&self) -> (usize, usize) {
1693 Pattern::cross_location(self)
1694 }
1695 fn source_matrix(&self) -> Vec<Vec<PatternCell>> {
1696 Pattern::source_matrix(self)
1697 }
1698 fn mapped_matrix(&self) -> Vec<Vec<PatternCell>> {
1699 Pattern::mapped_matrix(self)
1700 }
1701 fn source_graph_boxed(&self) -> SourceGraph {
1702 Pattern::source_graph(self)
1703 }
1704 fn pattern_matches_boxed(&self, grid: &MappingGrid, i: usize, j: usize) -> bool {
1705 pattern_matches(self, grid, i, j)
1706 }
1707 fn apply_gadget_boxed(&self, grid: &mut MappingGrid, i: usize, j: usize) {
1708 apply_gadget(self, grid, i, j);
1709 }
1710 fn apply_weighted_gadget_boxed(&self, grid: &mut MappingGrid, i: usize, j: usize) {
1711 apply_weighted_gadget(self, grid, i, j);
1712 }
1713}
1714
1715#[allow(clippy::needless_range_loop)]
1718pub fn apply_weighted_gadget<P: Pattern>(pattern: &P, grid: &mut MappingGrid, i: usize, j: usize) {
1719 let (m, n) = pattern.size();
1720 let (mapped_locs, _) = pattern.mapped_graph();
1721 let mapped_weights = pattern.mapped_weights();
1722
1723 for r in 0..m {
1725 for c in 0..n {
1726 let grid_r = i + r;
1727 let grid_c = j + c;
1728 grid.set(grid_r, grid_c, CellState::Empty);
1729 }
1730 }
1731
1732 let mut weight_map: HashMap<(usize, usize), i64> = HashMap::new();
1734 for (idx, &(r, c)) in mapped_locs.iter().enumerate() {
1735 let weight = mapped_weights[idx];
1736 *weight_map.entry((r, c)).or_insert(0) += weight;
1737 }
1738
1739 let mut count_map: HashMap<(usize, usize), usize> = HashMap::new();
1741 for &(r, c) in &mapped_locs {
1742 *count_map.entry((r, c)).or_insert(0) += 1;
1743 }
1744
1745 for (&(r, c), &total_weight) in &weight_map {
1747 let grid_r = i + r - 1; let grid_c = j + c - 1;
1749 let count = count_map[&(r, c)];
1750
1751 let state = if count > 1 {
1752 CellState::Doubled {
1753 weight: total_weight,
1754 }
1755 } else {
1756 CellState::Occupied {
1757 weight: total_weight,
1758 }
1759 };
1760 grid.set(grid_r, grid_c, state);
1761 }
1762}
1763
1764pub(crate) fn map_config_back_pattern<P: Pattern>(
1766 pattern: &P,
1767 gi: usize,
1768 gj: usize,
1769 config: &mut [Vec<usize>],
1770) -> Result<(), ReductionError> {
1771 let (m, n) = pattern.size();
1772 let (mapped_locs, mapped_pins) = pattern.mapped_graph();
1773 let (source_locs, _, _) = pattern.source_graph();
1774
1775 let mapped_config: Vec<usize> = mapped_locs
1777 .iter()
1778 .map(|&(r, c)| {
1779 let row = gi + r - 1;
1780 let col = gj + c - 1;
1781 config
1782 .get(row)
1783 .and_then(|row_vec| row_vec.get(col))
1784 .copied()
1785 .ok_or(mapping_invalid(
1786 "unweighted KSG gadget lies outside the configuration grid",
1787 ))
1788 })
1789 .collect::<Result<_, _>>()?;
1790
1791 let bc = {
1793 let mut result = 0usize;
1794 for (i, &pin_idx) in mapped_pins.iter().enumerate() {
1795 if *mapped_config.get(pin_idx).ok_or(mapping_invalid(
1796 "unweighted KSG gadget contains an invalid mapped pin index",
1797 ))? > 0
1798 {
1799 result |= 1 << i;
1800 }
1801 }
1802 result
1803 };
1804
1805 let d1 = pattern.mapped_entry_to_compact();
1807 let d2 = pattern.source_entry_to_configs();
1808
1809 let compact = d1.get(&bc).copied().ok_or(mapping_invalid(
1810 "unweighted KSG boundary configuration has no source equivalent",
1811 ))?;
1812 let new_config =
1813 d2.get(&compact)
1814 .and_then(|configs| configs.first())
1815 .ok_or(mapping_invalid(
1816 "unweighted KSG compact state has no source configuration",
1817 ))?;
1818 if new_config.len() != source_locs.len() {
1819 return Err(mapping_invalid(
1820 "unweighted KSG source configuration has the wrong length",
1821 ));
1822 }
1823
1824 for row in gi..gi + m {
1826 for col in gj..gj + n {
1827 *config
1828 .get_mut(row)
1829 .and_then(|row_vec| row_vec.get_mut(col))
1830 .ok_or(mapping_invalid(
1831 "unweighted KSG gadget lies outside the configuration grid",
1832 ))? = 0;
1833 }
1834 }
1835
1836 for (k, &(r, c)) in source_locs.iter().enumerate() {
1838 let row = gi + r - 1;
1839 let col = gj + c - 1;
1840 let cell = config
1841 .get_mut(row)
1842 .and_then(|row_vec| row_vec.get_mut(col))
1843 .ok_or(mapping_invalid(
1844 "unweighted KSG source position lies outside the configuration grid",
1845 ))?;
1846 *cell = cell
1847 .checked_add(usize::from(new_config[k]))
1848 .ok_or(mapping_integer_overflow(
1849 "accumulating an unweighted KSG source configuration",
1850 ))?;
1851 }
1852
1853 Ok(())
1854}