1use core::panic;
2use std::collections::{HashMap, HashSet};
3use std::fmt::Display;
4use itertools::Itertools;
5use yui_core::{hashmap, CloneAnd, Sign};
6use yui_core::bitseq::Bit;
7
8use super::{Node, NodeType, Path};
9
10pub type Edge = usize;
11pub type State = yui_core::bitseq::BitSeq;
12pub type XCode = [Edge; 4];
13
14#[derive(Debug, Clone)]
15pub struct Link {
16 nodes: Vec<Node>,
17 edges: HashSet<Edge>
18}
19
20impl Link {
21 pub fn new(nodes: Vec<Node>) -> Self {
22 let edges = nodes.iter().flat_map(|x| x.edges()).cloned().collect();
23 let l = Self { nodes, edges };
24 l.validate();
25 l
26 }
27
28 fn validate(&self) {
29 assert_eq!(self.edges.len(), self.nodes.len() * 2, "Invalid data.");
30 self.traverse(|_, _, _| ());
31 }
32
33 pub fn empty() -> Link {
34 Link { nodes: vec![], edges: HashSet::new() }
35 }
36
37 pub fn is_empty(&self) -> bool {
38 self.nodes.is_empty()
39 }
40
41 pub fn is_knot(&self) -> bool {
42 self.n_components() == 1
43 }
44
45 pub fn writhe(&self) -> i32 {
46 let (p, n) = self.count_signed_crossings();
47 (p as i32) - (n as i32)
48 }
49
50 pub fn mirror(&self) -> Self {
51 self.clone_and(|l|
52 l.nodes.iter_mut().for_each(|x| x.cc())
53 )
54 }
55
56 pub fn n_nodes(&self) -> usize {
57 self.nodes.len()
58 }
59
60 pub fn nodes(&self) -> impl Iterator<Item = &Node> {
61 self.nodes.iter()
62 }
63
64 pub fn node(&self, i: usize) -> &Node {
65 &self.nodes[i]
66 }
67
68 pub fn node_mut(&mut self, i: usize) -> &mut Node {
69 &mut self.nodes[i]
70 }
71
72 pub fn crossings(&self) -> impl Iterator<Item = &Node> {
73 self.nodes.iter().filter(|x| x.is_crossing())
74 }
75
76 pub fn count_crossings(&self) -> usize {
77 self.nodes.iter()
78 .filter(|x| x.is_crossing())
79 .count()
80 }
81
82 pub fn count_signed_crossings(&self) -> (usize, usize) {
83 let signs = self.collect_crossing_signs();
84 let pos = signs.iter().filter(|(_, s)| s.is_positive()).count();
85 let neg = signs.len() - pos;
86 (pos, neg)
87 }
88
89 pub fn collect_crossing_signs(&self) -> HashMap<usize, Sign> {
90 use NodeType::{X, Xm};
91
92 let mut result = hashmap!{};
93
94 self.traverse(|_, i, j| {
95 let c = self.node(i);
96 match (c.ntype(), j) {
97 (Xm, 1) | (X, 3) => result.insert(i, Sign::Pos),
98 (Xm, 3) | (X, 1) => result.insert(i, Sign::Neg),
99 _ => None
100 };
101 });
102
103 result
104 }
105
106 pub fn n_edges(&self) -> usize {
107 self.edges.len()
108 }
109
110 pub fn edges(&self) -> impl Iterator<Item = &Edge> {
111 self.edges.iter()
112 }
113
114 pub fn min_edge(&self) -> Option<Edge> {
115 self.nodes.first().map(|x| x.min_edge())
116 }
117
118 pub fn n_components(&self) -> usize {
119 let mut count = 0;
120 self.traverse(|c, _, _|
121 if count <= c { count = c + 1 }
122 );
123 count
124 }
125
126 pub fn collect_components(&self) -> Vec<Path> {
127 let mut comps = vec![];
128
129 self.traverse(|c, i, j| {
130 if c == comps.len() {
131 comps.push(vec![]);
132 }
133
134 let e = self.node(i).edge(j);
135 comps[c].push(e);
136 });
137
138 comps.into_iter().map(|edges|
139 Path::circ(edges)
140 ).collect()
141 }
142
143 pub fn crossing_change(&self, i: usize) -> Self {
144 assert!(self.node(i).is_crossing());
145 self.clone_and(|l| l.node_mut(i).cc())
146 }
147
148 pub fn resolved_at(&self, i: usize, r: Bit) -> Self {
149 assert!(self.node(i).is_crossing());
150 self.clone_and(|l| l.node_mut(i).resolve(r))
151 }
152
153 pub fn resolved_by(&self, s: &State) -> Self {
154 assert!(s.len() == self.count_crossings());
155
156 let n = self.nodes.len();
157 let itr = (0..n).filter(|&i| self.node(i).is_crossing());
158
159 self.clone_and(|l| {
160 for (i, r) in Iterator::zip(itr, s.iter()) {
161 l.node_mut(i).resolve(r);
162 }
163 })
164 }
165
166 pub fn seifert_state(&self) -> State {
167 let signs = self.collect_crossing_signs();
168 let seq = signs.iter().sorted_by_key(|(&i, _)| i).map(|(_, s)|
169 match s {
170 Sign::Pos => 0,
171 Sign::Neg => 1
172 }
173 );
174 State::from_iter(seq)
175 }
176
177 pub fn seifert_circles(&self) -> Vec<Path> {
178 self.resolved_by(&self.seifert_state()).collect_components()
179 }
180
181 fn traverse<F>(&self, mut f: F) where
182 F: FnMut(usize, usize, usize) {
183 let n = self.n_nodes();
184
185 let mut c = 0; let mut remain = self.edges.clone();
187
188 for j0 in [0, 1, 2] {
192 for i0 in 0..n {
193 let e0 = self.node(i0).edge(j0);
194 if !remain.remove(&e0) {
195 continue
196 }
197
198 self.traverse_from((i0, j0), |i, j| {
199 let e = self.node(i).edge(j);
200 remain.remove(&e);
201
202 f(c, i, j);
203 });
204
205 c += 1;
206 }
207
208 if remain.is_empty() {
209 break
210 }
211 }
212
213 assert!(remain.is_empty())
214 }
215
216 fn traverse_from<F>(&self, start: (usize, usize), mut f:F) where
217 F: FnMut(usize, usize)
218 {
219 let (mut i, mut j) = start;
220
221 f(i, j); loop {
224 let c = self.node(i);
225 let k = c.traverse_inner(j);
226 let next = self.traverse_outer(i, k);
227
228 if next == start {
229 break
230 }
231
232 (i, j) = next;
233
234 f(i, j)
235 }
236 }
237
238 fn traverse_outer(&self, n_index: usize, e_index: usize) -> (usize, usize) {
239 let e = self.nodes[n_index].edge(e_index);
240
241 for (i, c) in self.nodes.iter().enumerate() {
242 for (j, &f) in c.edges().iter().enumerate() {
243 if e == f && (n_index != i || (n_index == i && e_index != j)) {
244 return (i, j)
245 }
246 }
247 }
248
249 panic!("Broken data")
250 }
251}
252
253impl Link {
254 pub fn from_pd_code<I>(pd_code: I) -> Self
267 where I: IntoIterator<Item = XCode> {
268 let nodes = pd_code.into_iter().map(Node::from_pd_code).collect();
269 Self::new(nodes)
270 }
271
272 pub fn is_valid_name(str: &str) -> bool {
273 use regex::Regex;
274 let r1 = Regex::new(r"^([1-9]|10)_[0-9]+$").unwrap();
275 let r2 = Regex::new(r"^(K|L)?[1-9]+(a|n)_?[0-9]+$").unwrap(); r1.is_match(str) || r2.is_match(str)
277 }
278
279 pub fn load(name_or_path: &str) -> Result<Link, Box<dyn std::error::Error>> {
280 const RESOURCE_DIR: &str = "resources/links/";
281
282 if Self::is_valid_name(name_or_path) {
283 let dir = std::env!("CARGO_MANIFEST_DIR");
284 let path = format!("{dir}/{RESOURCE_DIR}{name_or_path}.json");
285 Self::_load(&path)
286 } else {
287 Self::_load(name_or_path)
288 }
289 }
290
291 fn _load(path: &str) -> Result<Link, Box<dyn std::error::Error>> {
292 let json = std::fs::read_to_string(path)?;
293 let data: Vec<XCode> = serde_json::from_str(&json)?;
294 let l = Link::from_pd_code(data);
295 Ok(l)
296 }
297
298 pub fn unknot() -> Link {
299 Link::from_pd_code([[0, 1, 1, 0]]).resolved_at(0, Bit::Bit0)
300 }
301
302 pub fn trefoil() -> Link {
303 Link::from_pd_code([[1,4,2,5],[3,6,4,1],[5,2,6,3]])
304 }
305
306 pub fn figure8() -> Link {
307 Link::from_pd_code([[4,2,5,1],[8,6,1,5],[6,3,7,4],[2,7,3,8]])
308 }
309
310 pub fn hopf_link() -> Link {
311 Link::from_pd_code([[4,1,3,2],[2,3,1,4]])
312 }
313}
314
315impl Display for Link {
316 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
317 write!(f, "L[{}]", self.nodes.iter().map(|x| x.to_string()).join(", "))
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use yui_core::hashmap;
324
325 use super::*;
326 use super::NodeType::{X, Xm};
327
328 #[test]
329 fn link_init() {
330 let l = Link::new(vec![]);
331 assert_eq!(l.nodes.len(), 0);
332 }
333
334 #[test]
335 fn link_from_pd_code() {
336 let pd_code = [[0,0,1,1]];
337 let l = Link::from_pd_code(pd_code);
338 assert_eq!(l.nodes.len(), 1);
339 assert_eq!(l.node(0).ntype(), X);
340 }
341
342 #[test]
343 fn link_is_empty() {
344 let l = Link::empty();
345 assert!(l.is_empty());
346
347 let pd_code = [[0,0,1,1]];
348 let l = Link::from_pd_code(pd_code);
349 assert!(!l.is_empty());
350 }
351
352 #[test]
353 fn link_crossing_num() {
354 let l = Link::empty();
355 assert_eq!(l.count_crossings(), 0);
356
357 let pd_code = [[0,0,1,1]];
358 let l = Link::from_pd_code(pd_code);
359 assert_eq!(l.count_crossings(), 1);
360
361 let pd_code = [[1,4,2,5],[3,6,4,1],[5,2,6,3]];
362 let l = Link::from_pd_code(pd_code);
363 assert_eq!(l.count_crossings(), 3);
364 }
365
366 #[test]
367 fn link_next() {
368 let pd_code = [[0,0,1,1]];
369 let l = Link::from_pd_code(pd_code);
370
371 assert_eq!(l.traverse_outer(0, 0), (0, 1));
372 assert_eq!(l.traverse_outer(0, 1), (0, 0));
373 assert_eq!(l.traverse_outer(0, 2), (0, 3));
374 assert_eq!(l.traverse_outer(0, 3), (0, 2));
375 }
376
377 #[test]
378 fn link_traverse() {
379 let traverse = |l: &Link, (i0, j0)| {
380 let mut queue = vec![];
381 l.traverse_from((i0, j0), |i, j| queue.push((i, j)));
382 queue
383 };
384
385 let pd_code = [[0,0,1,1]];
386 let l = Link::from_pd_code(pd_code);
387 let path = traverse(&l, (0, 0));
388
389 assert_eq!(path, [(0, 0), (0, 3)]); }
391
392 #[test]
393 fn link_crossing_signs() {
394 let pd_code = [[0,0,1,1]];
395 let l = Link::from_pd_code(pd_code);
396 assert_eq!(l.collect_crossing_signs(), hashmap!{ 0 => Sign::Pos});
397
398 let pd_code = [[0,1,1,0]];
399 let l = Link::from_pd_code(pd_code);
400 assert_eq!(l.collect_crossing_signs(), hashmap!{ 0 => Sign::Neg} );
401
402 let pd_code = [[0,0,1,1]];
403 let l = Link::from_pd_code(pd_code).resolved_at(0, Bit::Bit0);
404 assert_eq!(l.collect_crossing_signs(), hashmap!{});
405 }
406
407 #[test]
408 fn link_writhe() {
409 let pd_code = [[0,0,1,1]];
410 let l = Link::from_pd_code(pd_code);
411 assert_eq!(l.writhe(), 1);
412
413 let pd_code = [[0,1,1,0]];
414 let l = Link::from_pd_code(pd_code);
415 assert_eq!(l.writhe(), -1);
416
417 let pd_code = [[0,0,1,1]];
418 let l = Link::from_pd_code(pd_code).resolved_at(0, Bit::Bit0);
419 assert_eq!(l.writhe(), 0);
420
421 }
422
423 #[test]
424 fn link_components() {
425 let pd_code = [[0,0,1,1]];
426 let l = Link::from_pd_code(pd_code);
427 let comps = l.collect_components();
428 assert_eq!(comps, vec![ Path::new(vec![0, 1], true)]);
429 }
430
431 #[test]
432 fn link_mirror() {
433 let pd_code = [[0,0,1,1]];
434 let l = Link::from_pd_code(pd_code);
435 assert_eq!(l.node(0).ntype(), X);
436
437 let l = l.mirror();
438 assert_eq!(l.node(0).ntype(), Xm);
439 }
440
441 #[test]
442 fn link_resolve() {
443 let s = State::from([0, 0, 0]);
444 let l = Link::from_pd_code([[1,4,2,5],[3,6,4,1],[5,2,6,3]]) .resolved_by(&s);
446
447 let comps = l.collect_components();
448 assert_eq!(comps.len(), 3);
449 assert!(comps.iter().all(|c| c.is_circle()));
450
451 let s = State::from([1, 1, 1]);
452 let l = Link::from_pd_code([[1,4,2,5],[3,6,4,1],[5,2,6,3]]) .resolved_by(&s);
454
455 let comps = l.collect_components();
456 assert_eq!(comps.len(), 2);
457 assert!(comps.iter().all(|c| c.is_circle()));
458 }
459
460 #[test]
461 fn empty_link() {
462 let l = Link::empty();
463 assert_eq!(l.count_crossings(), 0);
464 assert_eq!(l.writhe(), 0);
465 assert_eq!(l.n_components(), 0);
466 }
467
468 #[test]
469 fn unknot() {
470 let l = Link::unknot();
471 assert_eq!(l.count_crossings(), 0);
472 assert_eq!(l.writhe(), 0);
473 assert_eq!(l.n_components(), 1);
474 }
475
476 #[test]
477 fn trefoil() {
478 let l = Link::trefoil();
479 assert_eq!(l.count_crossings(), 3);
480 assert_eq!(l.writhe(), -3);
481 assert_eq!(l.n_components(), 1);
482 }
483
484 #[test]
485 fn figure8() {
486 let l = Link::figure8();
487 assert_eq!(l.count_crossings(), 4);
488 assert_eq!(l.writhe(), 0);
489 assert_eq!(l.n_components(), 1);
490 }
491
492 #[test]
493 fn hopf_link() {
494 let l = Link::hopf_link();
495 assert_eq!(l.count_crossings(), 2);
496 assert_eq!(l.writhe(), -2);
497 assert_eq!(l.n_components(), 2);
498 }
499
500 #[test]
501 fn unlink_2() {
502 let pd_code = [[1,2,3,4], [3,2,1,4]];
503 let l = Link::from_pd_code(pd_code);
504 assert_eq!(l.count_crossings(), 2);
505 assert_eq!(l.writhe(), 0);
506 assert_eq!(l.n_components(), 2);
507 }
508
509
510 #[test]
511 fn l2x4() {
512 let pd_code = [[1,5,2,8],[5,3,6,2],[3,7,4,6],[7,1,8,4]];
513 let l = Link::from_pd_code(pd_code);
514 assert_eq!(l.count_crossings(), 4);
515 assert_eq!(l.writhe(), 4);
516 assert_eq!(l.n_components(), 2);
517 }
518
519 #[test]
520 fn load() {
521 let l = Link::load("3_1");
522 assert!(l.is_ok());
523
524 let l = l.unwrap();
525 assert_eq!(l.count_crossings(), 3);
526 }
527
528 #[test]
529 fn crossing_change() {
530 let l = Link::from_pd_code([[1,4,2,5],[3,6,4,1],[5,2,6,3]]);
531 let l2 = l.crossing_change(1);
532
533 assert_eq!(l.node(1), &Node::new(NodeType::X, [3,6,4,1]));
534 assert_eq!(l2.node(1), &Node::new(NodeType::Xm, [3,6,4,1]));
535 }
536}