1use std::collections::HashMap;
2
3use itertools::Itertools;
4use num_integer::Integer;
5use yui_core::CloneAnd;
6use crate::{Node, Edge, Link, XCode};
7
8#[derive(Debug, Clone)]
10pub struct InvLink {
11 link: Link,
12 base_pt: Option<Edge>,
13 e_map: HashMap<Edge, Edge>,
14 x_map: HashMap<Node, Node>
15}
16
17impl InvLink {
18 pub fn new<F>(link: Link, e_map: F, base_pt: Option<Edge>) -> InvLink
19 where F: Fn(Edge) -> Edge {
20 let e_map = link.edges().map(|&e| (e, e_map(e))).collect::<HashMap<_, _>>();
21 let mut x_map = HashMap::new();
22
23 for x in link.nodes() {
25 let edges = x.edges().map(|e| e_map.get(&e).unwrap());
26 let find = link.nodes().find_position(|y|
27 edges.iter().all(|e| y.edges().contains(e))
28 );
29
30 assert!(find.is_some(), "no match for x: {x} -> {edges:?}");
31
32 let j = find.unwrap().0;
33 let y = link.node(j);
34
35 x_map.insert(x.clone(), y.clone());
36
37 if x != y {
38 x_map.insert(y.clone(), x.clone());
39 }
40 }
41
42 assert_eq!(x_map.len(), link.n_nodes());
43
44 if let Some(p) = base_pt {
45 assert_eq!(p, e_map[&p], "base-pt must be on-axis.");
46 }
47
48 Self { link, base_pt, e_map, x_map }
49 }
50
51 pub fn sinv_knot_from_code<I1>(pd_code: I1) -> Self
52 where I1: IntoIterator<Item = XCode> {
53 let code = pd_code.into_iter().collect_vec();
54 let l = Link::from_pd_code(code);
55 let n = l.n_edges();
56
57 assert!(n.is_even(), "number of edges must be even.");
58 assert_eq!(l.edges().min(), Some(&1), "edge must start from index 1.");
59 assert_eq!(l.edges().max(), Some(&n), "edges must have sequential indexing.");
60
61 Self::new(l, |e| (n + 1 - e) % n + 1, Some(1))
62 }
63
64 pub fn link(&self) -> &Link {
65 &self.link
66 }
67
68 pub fn base_pt(&self) -> Option<Edge> {
69 self.base_pt
70 }
71
72 pub fn inv_e(&self, e: Edge) -> Edge {
73 self.e_map.get(&e).cloned().unwrap()
74 }
75
76 pub fn inv_x(&self, x: &Node) -> &Node {
77 self.x_map.get(x).unwrap()
78 }
79
80 pub fn mirror(&self) -> Self {
81 Self {
82 link: self.link.mirror(),
83 base_pt: self.base_pt,
84 e_map: self.e_map.clone(),
85 x_map: self.x_map.iter().map(|(x, y)|
86 (x.clone_and(|x| x.cc()), y.clone_and(|y| y.cc()))
87 ).collect(),
88 }
89 }
90}
91
92impl InvLink {
93 pub fn load(name: &str) -> Result<InvLink, Box<dyn std::error::Error>> {
94 match name {
95 "3_1" => Ok(InvLink::sinv_knot_from_code(
96 [[1,5,2,4],[3,1,4,6],[5,3,6,2]]
97 )),
98 "4_1" => Ok(InvLink::sinv_knot_from_code(
99 [[2,7,3,8],[4,2,5,1],[6,3,7,4],[8,6,1,5]],
100 )),
101 "5_1" => Ok(InvLink::sinv_knot_from_code(
102 [[1,7,2,6],[3,9,4,8],[5,1,6,10],[7,3,8,2],[9,5,10,4]],
103 )),
104 "5_2a" => Ok(InvLink::sinv_knot_from_code(
105 [[3,11,4,10],[5,9,6,8],[6,2,7,1],[9,5,10,4],[11,3,12,2],[12,8,1,7]],
106 )),
107 "5_2b" => Ok(InvLink::sinv_knot_from_code(
108 [[1,7,2,6],[4,10,5,9],[5,3,6,2],[7,1,8,12],[10,4,11,3],[11,9,12,8]],
109 )),
110 "6_1a" => Ok(InvLink::sinv_knot_from_code(
111 [[1,6,2,7],[3,11,4,10],[5,9,6,8],[7,12,8,1],[9,5,10,4],[11,3,12,2]],
112 )),
113 "6_1b" => Ok(InvLink::sinv_knot_from_code(
114 [[1,7,2,6],[3,10,4,11],[5,3,6,2],[7,1,8,12],[9,4,10,5],[11,9,12,8]],
115 )),
116 "6_2a" => Ok(InvLink::sinv_knot_from_code(
117 [[1,6,2,7],[3,11,4,10],[5,9,6,8],[7,12,8,1],[9,3,10,2],[11,5,12,4]],
118 )),
119 "6_2b" => Ok(InvLink::sinv_knot_from_code(
120 [[1,9,2,8],[4,11,5,12],[7,1,8,14],[9,3,10,2],[10,5,11,6],[12,3,13,4],[13,7,14,6]],
121 )),
122 "6_3" => Ok(InvLink::sinv_knot_from_code(
123 [[3,13,4,12],[6,9,7,10],[8,1,9,2],[10,5,11,6],[11,3,12,2],[13,5,14,4],[14,7,1,8]],
124 )),
125 "7_1" => Ok(InvLink::sinv_knot_from_code(
126 [[1,9,2,8],[3,11,4,10],[5,13,6,12],[7,1,8,14],[9,3,10,2],[11,5,12,4],[13,7,14,6]],
127 )),
128 "7_2a" => Ok(InvLink::sinv_knot_from_code(
129 [[3,15,4,14],[5,13,6,12],[7,11,8,10],[8,2,9,1],[11,7,12,6],[13,5,14,4],[15,3,16,2],[16,10,1,9]],
130 )),
131 "7_2b" => Ok(InvLink::sinv_knot_from_code(
132 [[1,9,2,8],[3,7,4,6],[4,14,5,13],[7,3,8,2],[9,1,10,16],[11,15,12,14],[12,6,13,5],[15,11,16,10]],
133 )),
134 "7_3a" => Ok(InvLink::sinv_knot_from_code(
135 [[1,9,2,8],[3,13,4,12],[5,11,6,10],[7,1,8,14],[9,3,10,2],[11,5,12,4],[13,7,14,6]],
136 )),
137 "7_3b" => Ok(InvLink::sinv_knot_from_code(
138 [[3,13,4,12],[5,15,6,14],[8,2,9,1],[10,7,11,8],[11,3,12,2],[13,5,14,4],[15,7,16,6],[16,10,1,9]],
139 )),
140 "7_4a" => Ok(InvLink::sinv_knot_from_code(
141 [[2,8,3,7],[3,15,4,14],[5,13,6,12],[8,2,9,1],[10,16,11,15],[11,7,12,6],[13,5,14,4],[16,10,1,9]],
142 )),
143 "7_4b" => Ok(InvLink::sinv_knot_from_code(
144 [[2,10,3,9],[4,12,5,11],[6,14,7,13],[8,4,9,3],[10,2,11,1],[12,8,13,7],[14,6,1,5]],
145 )),
146 "7_5a" => Ok(InvLink::sinv_knot_from_code(
147 [[1,9,2,8],[3,13,4,12],[5,11,6,10],[7,1,8,14],[9,7,10,6],[11,3,12,2],[13,5,14,4]],
148 )),
149 "7_5b" => Ok(InvLink::sinv_knot_from_code(
150 [[1,11,2,10],[4,8,5,7],[5,15,6,14],[9,1,10,18],[11,3,12,2],[12,16,13,15],[13,7,14,6],[16,3,17,4],[17,9,18,8]],
151 )),
152 "7_6a" => Ok(InvLink::sinv_knot_from_code(
153 [[2,13,3,14],[4,11,5,12],[6,4,7,3],[8,1,9,2],[10,5,11,6],[12,10,13,9],[14,7,1,8]],
154 )),
155 "7_6b" => Ok(InvLink::sinv_knot_from_code(
156 [[1,8,2,9],[3,15,4,14],[6,11,7,12],[7,4,8,5],[9,16,10,1],[12,5,13,6],[13,10,14,11],[15,3,16,2]],
157 )),
158 "7_7a" => Ok(InvLink::sinv_knot_from_code(
159 [[1,8,2,9],[4,13,5,14],[7,11,8,10],[9,16,10,1],[11,3,12,2],[12,5,13,6],[14,3,15,4],[15,7,16,6]],
160 )),
161 "7_7b" => Ok(InvLink::sinv_knot_from_code(
162 [[1,10,2,11],[3,13,4,12],[5,14,6,1],[7,5,8,4],[9,2,10,3],[11,9,12,8],[13,6,14,7]],
163 )),
164 _ => todo!()
165 }
166 }
167}
168
169#[cfg(test)]
170mod tests {
171 use super::*;
172
173 #[test]
174 fn inv_e() {
175 let l = Link::from_pd_code([[1,5,2,4],[3,1,4,6],[5,3,6,2]]);
176 let l = InvLink::new(l, |e| (7 - e) % 6 + 1, None);
177
178 assert_eq!(l.inv_e(1), 1);
179 assert_eq!(l.inv_e(2), 6);
180 assert_eq!(l.inv_e(3), 5);
181 assert_eq!(l.inv_e(4), 4);
182 assert_eq!(l.inv_e(5), 3);
183 assert_eq!(l.inv_e(6), 2);
184 }
185
186 #[test]
187 fn inv_x() {
188 let l = Link::from_pd_code([[1,5,2,4],[3,1,4,6],[5,3,6,2]]);
189 let l = InvLink::new(l, |e| (7 - e) % 6 + 1, None);
190 let nodes = l.link.nodes().collect_vec();
191
192 assert_eq!(l.inv_x(&nodes[0]), nodes[1]);
193 assert_eq!(l.inv_x(&nodes[1]), nodes[0]);
194 assert_eq!(l.inv_x(&nodes[2]), nodes[2]);
195 }
196
197 #[test]
198 fn from_sinv() {
199 let l = InvLink::sinv_knot_from_code([[1,5,2,4],[3,1,4,6],[5,3,6,2]]);
200
201 assert_eq!(l.inv_e(1), 1);
202 assert_eq!(l.inv_e(2), 6);
203 assert_eq!(l.inv_e(3), 5);
204 assert_eq!(l.inv_e(4), 4);
205 assert_eq!(l.inv_e(5), 3);
206 assert_eq!(l.inv_e(6), 2);
207 }
208
209 #[test]
210 fn load_3_1() {
211 let l = InvLink::load("3_1").unwrap();
212 assert_eq!(l.link().count_crossings(), 3);
213 }
214
215 #[test]
216 fn load_4_1() {
217 let l = InvLink::load("4_1").unwrap();
218 assert_eq!(l.link().count_crossings(), 4);
219 }
220}