cplx 0.3.3

Complex and hypercomplex numbers
#![feature(associated_type_defaults)]
#![feature(zero_one)]

#![cfg_attr(test, feature(plugin))]

#![no_std]

#![cfg_attr(test, plugin(quickcheck_macros))]

extern crate peano;

#[cfg(test)] extern crate quickcheck;
#[cfg(test)] #[macro_use] extern crate std;

use core::fmt;
use core::marker::PhantomData;
use core::num::*;
use core::ops::*;
use peano::Natural;

mod array;
mod basis;

pub use basis::Basis;

use array::*;

pub trait TotalDimensional {
    type DimTotal: Natural;
}

pub struct Signature<DimFlat: Natural, DimElliptic: Natural, DimHyperbolic: Natural>(DimFlat, DimElliptic, DimHyperbolic);

impl<DimFlat: Natural, DimElliptic: Natural, DimHyperbolic: Natural> TotalDimensional for Signature<DimFlat, DimElliptic, DimHyperbolic>
  // well this is ridiculous
  where DimFlat: Add<<DimElliptic as Add<DimHyperbolic>>::Output>,
        DimElliptic: Add<DimHyperbolic>,
        <DimFlat as Add<<DimElliptic as Add<DimHyperbolic>>::Output>>::Output: Natural {
    type DimTotal = <DimFlat as Add<<DimElliptic as Add<DimHyperbolic>>::Output>>::Output;
}

pub struct Complex<A, S: TotalDimensional = Signature<peano::Zero, peano::Succ<peano::Zero>, peano::Zero>>(PhantomData<S>, Array<A, S::DimTotal>) where S::DimTotal: LogArrayLength<A>;

impl<A: Clone, S: TotalDimensional> Clone for Complex<A, S> where S::DimTotal: LogArrayLength<A>, Array<A, S::DimTotal>: Clone {
    fn clone(&self) -> Self { let &Complex(_, ref a) = self; Complex(PhantomData, a.clone()) }
}

impl<A: Copy, S: TotalDimensional> Copy for Complex<A, S> where S::DimTotal: LogArrayLength<A>, Array<A, S::DimTotal>: Copy {}

impl<A: PartialEq, S: TotalDimensional> PartialEq for Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    fn eq(&self, &Complex(_, ref b): &Self) -> bool { let &Complex(_, ref a) = self; a[..] == b[..] }
}

impl<A: Eq, S: TotalDimensional> Eq for Complex<A, S> where S::DimTotal: LogArrayLength<A> {}

impl<A: fmt::Debug, S: TotalDimensional> fmt::Debug for Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let &Complex(_, ref a) = self; a[..].fmt(fmt) }
}

impl<A: Copy + Neg<Output = A>, S: TotalDimensional> Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    #[inline] pub fn conjugate(self) -> Self {
        let Complex(_, mut a) = self;
        for p in a.iter_mut() { *p = (*p).neg() }
        Complex(PhantomData, a)
    }
}

impl<A: Copy + Add<Output = A>, S: TotalDimensional> Add for Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    type Output = Self;
    #[inline] fn add(self, Complex(_, b): Self) -> Self {
        let Complex(_, mut a) = self;
        for i in 0..S::DimTotal::to_usize() { a[i] = a[i] + b[i] }
        Complex(PhantomData, a)
    }
}

impl<A: Zero, S: TotalDimensional> Zero for Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    #[inline] fn zero() -> Self { Complex(PhantomData, Zero::zero()) }
}

impl<A: Copy + Add<Output = A> + Sub<Output = A> + Zero + Mul<Output = A>,
     DimFlat: Natural, DimElliptic: Natural, DimHyperbolic: Natural> Mul for Complex<A, Signature<DimFlat, DimElliptic, DimHyperbolic>>
  where Signature<DimFlat, DimElliptic, DimHyperbolic>: TotalDimensional,
        <Signature<DimFlat, DimElliptic, DimHyperbolic> as TotalDimensional>::DimTotal: LogArrayLength<A> {
    type Output = Self;
    #[inline] fn mul(self, Complex(_, b): Self) -> Self {
        let Complex(_, a) = self;
        let Complex(_, mut c) = Self::zero();
        for j in 0..(<Signature<DimFlat, DimElliptic, DimHyperbolic> as TotalDimensional>::DimTotal::to_usize()) {
            for i in 0..(<Signature<DimFlat, DimElliptic, DimHyperbolic> as TotalDimensional>::DimTotal::to_usize()) {
                if let Some((p, k)) = basis::mul::<DimFlat, DimElliptic, DimHyperbolic>(i, j) {
                    c[k] = (if p { Sub::sub as fn(A, A) -> A } else { Add::add as fn (A, A) -> A })(c[k], a[i]*b[j])
                }
            }
        }
        Complex(PhantomData, c)
    }
}

impl<A: Zero + One, S: TotalDimensional> One for Complex<A, S> where S::DimTotal: LogArrayLength<A> {
    #[inline] fn one() -> Self {
        let mut a: Array<A, S::DimTotal> = Zero::zero();
        a[0] = One::one();
        Complex(PhantomData, a)
    }
}

#[cfg(test)] mod tests {
    use quickcheck as qc;
    use std::marker::PhantomData;

    use super::*;

    impl<A: qc::Arbitrary> qc::Arbitrary for Complex<A> {
        fn arbitrary<G: qc::Gen>(g: &mut G) -> Self { Complex(PhantomData, qc::Arbitrary::arbitrary(g)) }
    }

    #[quickcheck] fn multiplication(x: Complex<i32>, y: Complex<i32>) -> bool {
        use array::Array;
        let Complex(_, Array((a, b))) = x;
        let Complex(_, Array((c, d))) = y;
        let w = Complex(PhantomData, Array((a*c-b*d, a*d+b*c)));
        let z = x*y;
        println!("{:?} ?= {:?}", w, z);
        w == z
    }
}