use super::functions::*;
use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct IntegerQuotient {
pub pos: u64,
pub neg: u64,
}
#[allow(dead_code)]
impl IntegerQuotient {
pub fn from_i64(n: i64) -> Self {
if n >= 0 {
Self {
pos: n as u64,
neg: 0,
}
} else {
Self {
pos: 0,
neg: (-n) as u64,
}
}
}
pub fn reduce(&self) -> Self {
if self.pos >= self.neg {
Self {
pos: self.pos - self.neg,
neg: 0,
}
} else {
Self {
pos: 0,
neg: self.neg - self.pos,
}
}
}
pub fn to_i64(&self) -> i64 {
(self.pos as i64) - (self.neg as i64)
}
pub fn add(&self, other: &Self) -> Self {
Self {
pos: self.pos + other.pos,
neg: self.neg + other.neg,
}
.reduce()
}
pub fn negate(&self) -> Self {
Self {
pos: self.neg,
neg: self.pos,
}
}
pub fn mul(&self, other: &Self) -> Self {
let pos = self.pos * other.pos + self.neg * other.neg;
let neg = self.pos * other.neg + self.neg * other.pos;
Self { pos, neg }.reduce()
}
pub fn equiv(&self, other: &Self) -> bool {
self.pos + other.neg == other.pos + self.neg
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct QuotientMap {
pub name: String,
pub well_defined: bool,
pub injective: bool,
pub surjective: bool,
}
#[allow(dead_code)]
impl QuotientMap {
pub fn new(name: impl Into<String>) -> Self {
Self {
name: name.into(),
well_defined: false,
injective: false,
surjective: false,
}
}
pub fn mark_well_defined(mut self) -> Self {
self.well_defined = true;
self
}
pub fn mark_injective(mut self) -> Self {
self.injective = true;
self
}
pub fn mark_surjective(mut self) -> Self {
self.surjective = true;
self
}
pub fn is_bijective(&self) -> bool {
self.injective && self.surjective
}
pub fn is_isomorphism(&self) -> bool {
self.well_defined && self.is_bijective()
}
}
#[allow(dead_code)]
pub struct ConcreteSetoid<T> {
pub equiv: Box<dyn Fn(&T, &T) -> bool>,
}
#[allow(dead_code)]
impl<T: Clone> ConcreteSetoid<T> {
pub fn new(equiv: impl Fn(&T, &T) -> bool + 'static) -> Self {
Self {
equiv: Box::new(equiv),
}
}
pub fn are_equiv(&self, a: &T, b: &T) -> bool {
(self.equiv)(a, b)
}
pub fn partition(&self, xs: &[T]) -> Vec<Vec<T>> {
let mut classes: Vec<Vec<T>> = Vec::new();
for x in xs {
let mut found = false;
for cls in &mut classes {
if (self.equiv)(x, &cls[0]) {
cls.push(x.clone());
found = true;
break;
}
}
if !found {
classes.push(vec![x.clone()]);
}
}
classes
}
pub fn count_classes(&self, xs: &[T]) -> usize {
self.partition(xs).len()
}
pub fn function_respects<U: PartialEq>(&self, xs: &[T], f: impl Fn(&T) -> U) -> bool {
for i in 0..xs.len() {
for j in 0..xs.len() {
if (self.equiv)(&xs[i], &xs[j]) && f(&xs[i]) != f(&xs[j]) {
return false;
}
}
}
true
}
}
#[allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FreeGroupElement {
pub letters: Vec<(char, bool)>,
}
#[allow(dead_code)]
impl FreeGroupElement {
pub fn identity() -> Self {
Self { letters: vec![] }
}
pub fn generator(c: char) -> Self {
Self {
letters: vec![(c, true)],
}
}
pub fn generator_inv(c: char) -> Self {
Self {
letters: vec![(c, false)],
}
}
pub fn mul(&self, other: &Self) -> Self {
let mut result = self.letters.clone();
for &letter in &other.letters {
if let Some(&last) = result.last() {
if last.0 == letter.0 && last.1 != letter.1 {
result.pop();
continue;
}
}
result.push(letter);
}
Self { letters: result }
}
pub fn inverse(&self) -> Self {
let letters = self.letters.iter().rev().map(|&(c, b)| (c, !b)).collect();
Self { letters }
}
pub fn length(&self) -> usize {
self.letters.len()
}
pub fn is_identity(&self) -> bool {
self.letters.is_empty()
}
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct RationalQuotient {
pub numer: i64,
pub denom: i64,
}
#[allow(dead_code)]
impl RationalQuotient {
pub fn new(numer: i64, denom: i64) -> Self {
assert!(denom != 0, "denominator must be nonzero");
Self { numer, denom }
}
fn gcd(mut a: i64, mut b: i64) -> i64 {
a = a.abs();
b = b.abs();
while b != 0 {
let t = b;
b = a % b;
a = t;
}
a
}
pub fn reduce(&self) -> Self {
if self.numer == 0 {
return Self { numer: 0, denom: 1 };
}
let g = Self::gcd(self.numer.abs(), self.denom.abs());
let sign = if self.denom < 0 { -1 } else { 1 };
Self {
numer: sign * self.numer / g,
denom: sign * self.denom / g,
}
}
pub fn equiv(&self, other: &Self) -> bool {
self.numer * other.denom == other.numer * self.denom
}
pub fn add(&self, other: &Self) -> Self {
Self {
numer: self.numer * other.denom + other.numer * self.denom,
denom: self.denom * other.denom,
}
.reduce()
}
pub fn mul(&self, other: &Self) -> Self {
Self {
numer: self.numer * other.numer,
denom: self.denom * other.denom,
}
.reduce()
}
pub fn to_f64(&self) -> f64 {
(self.numer as f64) / (self.denom as f64)
}
}