permutation_rs/group/
free.rs1use std::fmt;
21use std::fmt::Display;
22use super::GroupElement;
23
24#[derive(Debug, PartialEq, Eq, Hash, Clone)]
26pub struct Word {
27 terms: Vec<(char, i64)>,
28}
29
30impl Word {
31 pub fn identity() -> Word {
33 Word::new(vec!())
34 }
35
36 pub fn generator(symbol: char) -> Word {
38 Word::new(vec!((symbol, 1)))
39 }
40
41 pub fn new(elements: Vec<(char, i64)>) -> Word {
43 Word { terms : normalize(&elements) }
44 }
45}
46
47
48fn normalize(elements: &Vec<(char, i64)>) -> Vec<(char, i64)> {
49 let mut not_normalized : Vec<(char, i64)> = vec!();
50 not_normalized.extend(elements);
51
52 if not_normalized.len() <= 1 {
53 not_normalized
54 } else {
55 let mut normalized : Vec<(char, i64)> = vec!();
56 let mut current: (char, i64) = not_normalized.get(0).expect("at least two elements").clone();
57 let mut index = 1;
58 while index < not_normalized.len() {
59 let primitive = not_normalized.get(index).expect("index within bound").clone();
60 if current.0 == primitive.0 {
61 current = (current.0.clone(), current.1 + primitive.1)
62 } else {
63 if current.1 != 0 {
64 normalized.push(current)
65 } else {
66 if !normalized.is_empty() {
67 current = normalized.pop().expect("non-empty stack");
68 continue;
69 }
70 }
71 current = primitive
72 }
73 index += 1;
74 }
75 if current.1 != 0 {
76 normalized.push(current);
77 }
78
79 normalized
80 }
81}
82
83impl GroupElement for Word {
84 fn is_identity(&self) -> bool {
85 self.terms.len() == 0
86 }
87
88 fn times(&self, multiplicant: &Word) -> Word {
89 let mut terms: Vec<(char, i64)>= vec!();
90 terms.extend(&self.terms);
91 terms.extend(&multiplicant.terms);
92 let terms = normalize(&terms);
93 Word { terms: terms }
94 }
95
96 fn inverse(&self) -> Word {
97 let mut terms: Vec<(char, i64)> = vec!();
98 terms.extend(&self.terms);
99 terms.reverse();
100 for element in terms.iter_mut() {
101 element.1 *= -1;
102 }
103 Word { terms: terms }
104 }
105}
106
107impl Display for Word {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 if self.terms.len() > 0 {
110 for primitive in &self.terms {
111 write!(f, "{}^{}", primitive.0, primitive.1)?;
112 }
113 write!(f, "")
114 } else {
115 write!(f, "Id")
116 }
117 }
118}
119
120#[cfg(test)]
121mod tests {
122 use super::super::GroupElement;
123 use super::*;
124
125 #[test]
126 fn permutaion_should_know_when_it_is_the_identity() {
127 let not_identity = Word::generator('g');
128
129 assert!(!not_identity.is_identity());
130
131 let identity = Word::identity();
132
133 assert!(identity.is_identity());
134 }
135
136 #[test]
137 fn multiplication_should_be_from_left_to_right() {
138 let first = Word::generator('g');
139 let second = Word::generator('h');
140
141 let product = first.times(&second);
142
143 let expected = Word::new(vec!(('g', 1), ('h',1)));
144
145 assert_eq!(product, expected);
146 }
147
148 #[test]
149 fn inverse_should_multiply_to_identity() {
150 let first = Word::new(vec!(('g', 1), ('h',1)));
151
152 let second = first.inverse();
153
154 let product = first.times(&second);
155
156 assert!(product.is_identity());
157 }
158
159 #[test]
160 fn word_should_display_correctly() {
161 let identity = Word::identity();
162
163 let word = Word::new(vec!(('x', 2), ('y', -3), ('x', -2), ('y', 3)));
164
165 assert_eq!("Id", format!("{}", identity));
166 assert_eq!("x^2y^-3x^-2y^3", format!("{}", word));
167 }
168}