oxilean_std/quotient_types/
types.rs1use super::functions::*;
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7
8#[allow(dead_code)]
11#[derive(Debug, Clone)]
12pub struct IntegerQuotient {
13 pub pos: u64,
15 pub neg: u64,
16}
17#[allow(dead_code)]
18impl IntegerQuotient {
19 pub fn from_i64(n: i64) -> Self {
21 if n >= 0 {
22 Self {
23 pos: n as u64,
24 neg: 0,
25 }
26 } else {
27 Self {
28 pos: 0,
29 neg: (-n) as u64,
30 }
31 }
32 }
33 pub fn reduce(&self) -> Self {
35 if self.pos >= self.neg {
36 Self {
37 pos: self.pos - self.neg,
38 neg: 0,
39 }
40 } else {
41 Self {
42 pos: 0,
43 neg: self.neg - self.pos,
44 }
45 }
46 }
47 pub fn to_i64(&self) -> i64 {
49 (self.pos as i64) - (self.neg as i64)
50 }
51 pub fn add(&self, other: &Self) -> Self {
53 Self {
54 pos: self.pos + other.pos,
55 neg: self.neg + other.neg,
56 }
57 .reduce()
58 }
59 pub fn negate(&self) -> Self {
61 Self {
62 pos: self.neg,
63 neg: self.pos,
64 }
65 }
66 pub fn mul(&self, other: &Self) -> Self {
68 let pos = self.pos * other.pos + self.neg * other.neg;
69 let neg = self.pos * other.neg + self.neg * other.pos;
70 Self { pos, neg }.reduce()
71 }
72 pub fn equiv(&self, other: &Self) -> bool {
74 self.pos + other.neg == other.pos + self.neg
75 }
76}
77#[allow(dead_code)]
81#[derive(Debug, Clone)]
82pub struct QuotientMap {
83 pub name: String,
85 pub well_defined: bool,
87 pub injective: bool,
89 pub surjective: bool,
91}
92#[allow(dead_code)]
93impl QuotientMap {
94 pub fn new(name: impl Into<String>) -> Self {
96 Self {
97 name: name.into(),
98 well_defined: false,
99 injective: false,
100 surjective: false,
101 }
102 }
103 pub fn mark_well_defined(mut self) -> Self {
105 self.well_defined = true;
106 self
107 }
108 pub fn mark_injective(mut self) -> Self {
110 self.injective = true;
111 self
112 }
113 pub fn mark_surjective(mut self) -> Self {
115 self.surjective = true;
116 self
117 }
118 pub fn is_bijective(&self) -> bool {
120 self.injective && self.surjective
121 }
122 pub fn is_isomorphism(&self) -> bool {
124 self.well_defined && self.is_bijective()
125 }
126}
127#[allow(dead_code)]
131pub struct ConcreteSetoid<T> {
132 pub equiv: Box<dyn Fn(&T, &T) -> bool>,
134}
135#[allow(dead_code)]
136impl<T: Clone> ConcreteSetoid<T> {
137 pub fn new(equiv: impl Fn(&T, &T) -> bool + 'static) -> Self {
139 Self {
140 equiv: Box::new(equiv),
141 }
142 }
143 pub fn are_equiv(&self, a: &T, b: &T) -> bool {
145 (self.equiv)(a, b)
146 }
147 pub fn partition(&self, xs: &[T]) -> Vec<Vec<T>> {
149 let mut classes: Vec<Vec<T>> = Vec::new();
150 for x in xs {
151 let mut found = false;
152 for cls in &mut classes {
153 if (self.equiv)(x, &cls[0]) {
154 cls.push(x.clone());
155 found = true;
156 break;
157 }
158 }
159 if !found {
160 classes.push(vec![x.clone()]);
161 }
162 }
163 classes
164 }
165 pub fn count_classes(&self, xs: &[T]) -> usize {
167 self.partition(xs).len()
168 }
169 pub fn function_respects<U: PartialEq>(&self, xs: &[T], f: impl Fn(&T) -> U) -> bool {
171 for i in 0..xs.len() {
172 for j in 0..xs.len() {
173 if (self.equiv)(&xs[i], &xs[j]) && f(&xs[i]) != f(&xs[j]) {
174 return false;
175 }
176 }
177 }
178 true
179 }
180}
181#[allow(dead_code)]
184#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct FreeGroupElement {
186 pub letters: Vec<(char, bool)>,
189}
190#[allow(dead_code)]
191impl FreeGroupElement {
192 pub fn identity() -> Self {
194 Self { letters: vec![] }
195 }
196 pub fn generator(c: char) -> Self {
198 Self {
199 letters: vec![(c, true)],
200 }
201 }
202 pub fn generator_inv(c: char) -> Self {
204 Self {
205 letters: vec![(c, false)],
206 }
207 }
208 pub fn mul(&self, other: &Self) -> Self {
210 let mut result = self.letters.clone();
211 for &letter in &other.letters {
212 if let Some(&last) = result.last() {
213 if last.0 == letter.0 && last.1 != letter.1 {
214 result.pop();
215 continue;
216 }
217 }
218 result.push(letter);
219 }
220 Self { letters: result }
221 }
222 pub fn inverse(&self) -> Self {
224 let letters = self.letters.iter().rev().map(|&(c, b)| (c, !b)).collect();
225 Self { letters }
226 }
227 pub fn length(&self) -> usize {
229 self.letters.len()
230 }
231 pub fn is_identity(&self) -> bool {
233 self.letters.is_empty()
234 }
235}
236#[allow(dead_code)]
239#[derive(Debug, Clone)]
240pub struct RationalQuotient {
241 pub numer: i64,
243 pub denom: i64,
245}
246#[allow(dead_code)]
247impl RationalQuotient {
248 pub fn new(numer: i64, denom: i64) -> Self {
250 assert!(denom != 0, "denominator must be nonzero");
251 Self { numer, denom }
252 }
253 fn gcd(mut a: i64, mut b: i64) -> i64 {
255 a = a.abs();
256 b = b.abs();
257 while b != 0 {
258 let t = b;
259 b = a % b;
260 a = t;
261 }
262 a
263 }
264 pub fn reduce(&self) -> Self {
266 if self.numer == 0 {
267 return Self { numer: 0, denom: 1 };
268 }
269 let g = Self::gcd(self.numer.abs(), self.denom.abs());
270 let sign = if self.denom < 0 { -1 } else { 1 };
271 Self {
272 numer: sign * self.numer / g,
273 denom: sign * self.denom / g,
274 }
275 }
276 pub fn equiv(&self, other: &Self) -> bool {
278 self.numer * other.denom == other.numer * self.denom
279 }
280 pub fn add(&self, other: &Self) -> Self {
282 Self {
283 numer: self.numer * other.denom + other.numer * self.denom,
284 denom: self.denom * other.denom,
285 }
286 .reduce()
287 }
288 pub fn mul(&self, other: &Self) -> Self {
290 Self {
291 numer: self.numer * other.numer,
292 denom: self.denom * other.denom,
293 }
294 .reduce()
295 }
296 pub fn to_f64(&self) -> f64 {
298 (self.numer as f64) / (self.denom as f64)
299 }
300}