yui_link/
braid.rs

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        // TODO
104    }
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            /*        +       -
113             *  ↓   a   b   a   b
114             *       \ /     \ /
115             *  ↓     /       \
116             *       / \     / \
117             *  ↓   c   d   c   d
118             */
119            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]); // 9_41
259        let l = b.closure();
260        assert_eq!(l.count_crossings(), 12);
261    }
262}