algebra 0.2.0

Abstract algebra for Rust
Documentation
extern crate algebra;

use std::mem::swap;
use std::fmt::{Display, Formatter, Error};

use algebra::ops::{Additive, Multiplicative, Inverse, inv};
use algebra::cmp::ApproxEq;
use algebra::structure::*;
use algebra::wrapper::Wrapper as W;
use algebra::wrapper::id as wrap_id;
use algebra::ident::{Identity, id};

#[derive(PartialEq, Clone)]
struct Vec2<Scalar: FieldApprox> {
    x: Scalar,
    y: Scalar,
}

impl<Scalar: FieldApprox> Vec2<Scalar> {
    fn new(x: Scalar, y: Scalar) -> Vec2<Scalar> {
        Vec2 {
            x: x,
            y: y,
        }
    }
}

impl<Scalar: FieldApprox + Display> Display for Vec2<Scalar> {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        fmt.write_fmt(format_args!("({}, {})", self.x, self.y))
    }
}

impl<Scalar: FieldApprox> ApproxEq for Vec2<Scalar> {
    type Eps = Scalar::Eps;

    fn default_epsilon() -> Self::Eps {
        Scalar::default_epsilon()
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        self.x.approx_eq_eps(&b.x, epsilon) &&
        self.y.approx_eq_eps(&b.y, epsilon)
    }
}

impl<Scalar: FieldApprox> MagmaApprox<Additive> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Additive, lhs.x);
        self.y = self.y.ap(Additive, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Inverse<Additive> for Vec2<Scalar> {
    fn inv(mut self) -> Self {
        self.x = inv(Additive, self.x);
        self.y = inv(Additive, self.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Additive> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Additive),
            y: id(Additive),
        }
    }
}

impl<Scalar: FieldApprox> QuasigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> LoopApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> SemigroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> MonoidApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> GroupApprox<Additive> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> GroupAbelianApprox<Additive> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> ModuleApprox<Scalar> for Vec2<Scalar> {}
impl<Scalar: FieldApprox> VectorApprox<Scalar> for Vec2<Scalar> {}

impl<Scalar: FieldApprox> MagmaApprox<Multiplicative> for Vec2<Scalar> {
    fn approx(mut self, lhs: Self) -> Self {
        self.x = self.x.ap(Multiplicative, lhs.x);
        self.y = self.y.ap(Multiplicative, lhs.y);
        self
    }
}

impl<Scalar: FieldApprox> Identity<Multiplicative> for Vec2<Scalar> {
    fn id() -> Self {
        Vec2 {
            x: id(Multiplicative),
            y: id(Multiplicative),
        }
    }
}

fn gcd<T: RingCommutativeApprox + PartialOrd>(a: T, b: T) -> T {
    let (mut a, mut b) = (W(a), W(b));
    if a < wrap_id(Additive) {
        a = -a;
    }
    if b < wrap_id(Multiplicative) {
        b = -b;
    }
    while a != b {
        if a > b {
            a = a - b.clone();
        } else {
            b = b - a.clone();
        }
    }
    a.0
}

#[test]
fn gcd_works() {
    assert_eq!(2, gcd(8, 6));
    assert_eq!(2, gcd(6, 8));
    assert_eq!(3, gcd(15, 6));
    assert_eq!(3, gcd(6, 15));
    assert_eq!(1, gcd(17, 12345));
    assert_eq!(1, gcd(42312, 17));
    println!("1");
    assert_eq!(5, gcd(15, -35));
    println!("2");
    assert_eq!(5, gcd(-15, 35));
    println!("3");
    assert_eq!(5, gcd(-15, -35));
    println!("4");
}

#[derive(Clone)]
struct Rational {
    a: i64,
    b: i64,
}

impl Rational {
    fn new(a: i64, b: i64) -> Self {
        assert!(b != 0);
        Rational {
            a: a,
            b: b,
        }
    }

    fn whole(n: i64) -> Self {
        Rational {
            a: n,
            b: 1,
        }
    }
}

impl Display for Rational {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
        if self.b == 1 {
            fmt.write_fmt(format_args!("{}", self.a))
        } else {
            fmt.write_fmt(format_args!("{}⁄{}", self.a, self.b))
        }
    }
}

impl PartialEq for Rational {
    fn eq(&self, lhs: &Self) -> bool {
        self.a * lhs.b == lhs.a * self.b
    }
}

impl ApproxEq for Rational {
    type Eps = f64;

    fn default_epsilon() -> Self::Eps {
        0.
    }

    fn approx_eq_eps(&self, b: &Self, epsilon: &Self::Eps) -> bool {
        let us = self.a as f64 / self.b as f64;
        let them = b.a as f64 / b.b as f64;
        (us - them).abs() <= *epsilon
    }
}

impl MagmaApprox<Additive> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a = self.a * lhs.b + lhs.a * self.b;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Additive> for Rational {
    fn inv(mut self) -> Self {
        self.a = -self.a;
        self.b = self.b;
        self
    }
}

impl Identity<Additive> for Rational {
    fn id() -> Self {
        Rational {
            a: 0,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Additive> for Rational {}
impl LoopApprox<Additive> for Rational {}

impl SemigroupApprox<Additive> for Rational {}
impl MonoidApprox<Additive> for Rational {}

impl GroupApprox<Additive> for Rational {}
impl GroupAbelianApprox<Additive> for Rational {}

impl MagmaApprox<Multiplicative> for Rational {
    fn approx(mut self, lhs: Self) -> Self {
        self.a *= lhs.a;
        self.b *= lhs.b;
        let gcd = gcd(self.a, self.b);
        self.a /= gcd;
        self.b /= gcd;
        self
    }
}

impl Inverse<Multiplicative> for Rational {
    fn inv(mut self) -> Self {
        swap(&mut self.a, &mut self.b);
        self
    }
}

impl Identity<Multiplicative> for Rational {
    fn id() -> Self {
        Rational {
            a: 1,
            b: 1,
        }
    }
}

impl QuasigroupApprox<Multiplicative> for Rational {}
impl LoopApprox<Multiplicative> for Rational {}

impl SemigroupApprox<Multiplicative> for Rational {}
impl MonoidApprox<Multiplicative> for Rational {}

impl GroupApprox<Multiplicative> for Rational {}
impl GroupAbelianApprox<Multiplicative> for Rational {}

impl RingApprox for Rational {}
impl RingCommutativeApprox for Rational {}
impl FieldApprox for Rational {}

fn main() {
    let vec = || W(Vec2::new(Rational::new(1, 2), Rational::whole(3)));
    let vec2 = || W(Vec2::new(Rational::whole(5), Rational::new(11, 7)));
    let vec3 = || W(Vec2::new(Rational::new(7, 11), Rational::whole(17)));

    let vec4 = (vec() * vec2()) + (vec() * vec3());
    let vec5 = vec() * (vec2() + vec3());
    if vec4.approx_eq(&vec5) {
        println!("{} == {}", vec4, vec5);
    } else {
        println!("{} != {}", vec4, vec5);
    }
}