1use std::collections::HashMap;
2use std::ops::{MulAssign, Mul};
3use auto_impl_ops::auto_ops;
4use delegate::delegate;
5use derive_more::{Display, Debug};
6use itertools::Itertools;
7use num_traits::Zero;
8use yui_core::{GetSign, Sign};
9
10use crate::{Link, XCode};
11
12#[derive(Clone, Copy, PartialEq, Eq, Display, Debug)]
13#[display("{}", _0)]
14#[ debug("{}", _0)]
15pub struct Generator(i32);
16
17impl Generator {
18 pub fn new(index: usize, sign: Sign) -> Self {
19 assert!(!index.is_zero());
20 if sign.is_positive() {
21 Self(index as i32 )
22 } else {
23 Self(-(index as i32))
24 }
25 }
26
27 pub fn index(&self) -> usize {
28 self.0.abs() as usize
29 }
30
31 pub fn sign(&self) -> Sign {
32 self.0.sign()
33 }
34
35 pub fn inv(&self) -> Self {
36 Self(-self.0)
37 }
38}
39
40impl From<i32> for Generator {
41 fn from(value: i32) -> Self {
42 assert!(!value.is_zero());
43 Self(value)
44 }
45}
46
47#[derive(Clone, PartialEq, Eq, Display, Debug)]
48#[display("{:?}", elements)]
49pub struct Braid {
50 strands: usize,
51 elements: Vec<Generator>
52}
53
54impl Braid {
55 pub fn new(strands: usize, elements: Vec<Generator>) -> Self {
56 Self { strands, elements }
57 }
58
59 pub fn id(strands: usize) -> Self {
60 Self::new(
61 strands,
62 vec![]
63 )
64 }
65
66 pub fn gen(strands: usize, index: usize) -> Self {
67 Self::new(
68 strands,
69 vec![(Generator::new(index, Sign::Pos))]
70 )
71 }
72
73 pub fn all_gens(strands: usize) -> Vec<Self> {
74 (1..strands).map(|index| Self::gen(strands, index)).collect()
75 }
76
77 pub fn strands(&self) -> usize {
78 self.strands
79 }
80
81 pub fn elements(&self) -> &[Generator] {
82 &self.elements
83 }
84
85 delegate! {
86 to self.elements {
87 pub fn len(&self) -> usize;
88 #[call(is_empty)]
89 pub fn is_triv(&self) -> bool;
90 }
91 }
92
93 pub fn inv(&self) -> Self {
94 Self::new(
95 self.strands,
96 self.elements.iter().rev().map(
97 |gen| gen.inv()
98 ).collect()
99 )
100 }
101
102 pub fn reduce(&mut self) {
103 }
105
106 pub fn closure(&self) -> Link {
107 let mut count = self.strands;
108 let mut bottom_edges: Vec<usize> = (0..self.strands).collect();
109 let mut pd_code: Vec<XCode> = Vec::new();
110
111 for s in &self.elements {
112 let i = s.index() - 1;
120 let (a, b) = (bottom_edges[i], bottom_edges[i + 1]);
121 let (c, d) = (count, count + 1);
122
123 if s.sign().is_positive() {
124 pd_code.push([a, c, d, b]);
125 } else {
126 pd_code.push([b, a, c, d]);
127 }
128
129 bottom_edges[i] = c;
130 bottom_edges[i + 1] = d;
131 count += 2;
132 }
133
134 assert!(
135 bottom_edges.iter().enumerate().all(|(i, &j)| i != j),
136 "braid closure contains free loop."
137 );
138
139 let conn: HashMap<_, _> = Iterator::zip(
140 bottom_edges.into_iter(),
141 0..self.strands
142 ).collect();
143
144 let pd_code = pd_code
145 .into_iter()
146 .map(|x| x.map(|a| *conn.get(&a).unwrap_or(&a)))
147 .collect_vec();
148
149 Link::from_pd_code(pd_code)
150 }
151
152 pub fn display(&self) -> String {
153 fn row(strands: usize, gen: &Generator) -> String {
154 let index = gen.index();
155 let sign = gen.sign();
156
157 (0..3).map(|r| {
158 (1..=strands).map(|i| {
159 if i == index {
160 match r {
161 0 => "\\ /",
162 1 => if sign.is_positive() { " / " } else { " \\ " },
163 _ => "/ \\",
164 }
165 } else if i == index + 1 {
166 " "
167 } else {
168 "| "
169 }
170 }).join("")
171 }).join("\n")
172 }
173
174 self.elements.iter().map(|gen|
175 row(self.strands, gen)
176 ).join("\n")
177 }
178
179 pub fn load(name_or_path: &str) -> Result<Braid, Box<dyn std::error::Error>> {
180 const RESOURCE_DIR: &str = "resources/braid/";
181
182 if Link::is_valid_name(name_or_path) {
183 let dir = std::env!("CARGO_MANIFEST_DIR");
184 let path = format!("{dir}/{RESOURCE_DIR}{name_or_path}.json");
185 Self::_load(&path)
186 } else {
187 Self::_load(name_or_path)
188 }
189 }
190
191 fn _load(path: &str) -> Result<Braid, Box<dyn std::error::Error>> {
192 let json = std::fs::read_to_string(path)?;
193 let code: Vec<i32> = serde_json::from_str(&json)?;
194 let braid = Braid::from_iter(code);
195 Ok(braid)
196 }
197}
198
199impl<const N: usize> From<[i32; N]> for Braid {
200 fn from(value: [i32; N]) -> Self {
201 Self::from_iter(value)
202 }
203}
204
205impl FromIterator<i32> for Braid {
206 fn from_iter<T: IntoIterator<Item = i32>>(iter: T) -> Self {
207 let elements = iter.into_iter().map(Generator).collect_vec();
208 let strands = elements.iter().map(|g| g.index() + 1).max().unwrap_or(0);
209 Self::new(strands, elements)
210 }
211}
212
213#[auto_ops]
214impl MulAssign<&Braid> for Braid {
215 fn mul_assign(&mut self, rhs: &Braid) {
216 assert_eq!(self.strands, rhs.strands);
217 self.elements.extend(rhs.elements.iter().cloned());
218 }
219}
220
221#[cfg(test)]
222mod tests {
223 use super::*;
224
225 #[test]
226 fn init_by_code() {
227 let b = Braid::from([1, 1, -2, -1, 3]);
228 assert_eq!(b.strands(), 4);
229 assert_eq!(b.len(), 5);
230 }
231
232 #[test]
233 fn to_string() {
234 let b = Braid::from([1, 1, -2, -1, 3]);
235 assert_eq!(b.to_string(), "[1, 1, -2, -1, 3]");
236 }
237
238 #[test]
239 fn display() {
240 let b = Braid::from([1, 1, -2, -1, 3]);
241 let display = b.display();
242 assert_ne!(display, "")
243 }
244
245 #[test]
246 fn load() {
247 let name = "3_1";
248 let b = Braid::load(name);
249
250 assert!(b.is_ok());
251
252 let b = b.unwrap();
253 assert_eq!(b.strands(), 2);
254 }
255
256 #[test]
257 fn closure() {
258 let b = Braid::from([-1,-1,-2,1,3,2,2,-4,-3,2,-3,-4]); let l = b.closure();
260 assert_eq!(l.count_crossings(), 12);
261 }
262}