use batch_impl::batch_trait;
use crate::complex::Complex;
use crate::op::{Additive, Multiplicative};
use crate::tower::{
AbelianGroup, CommutativeRing, ComplexField, DivisionRing, Field, FieldExtension, Group, Loop,
Magma, Module, Monoid, Quasigroup, Real, Ring, Semigroup, Semiring, VectorSpace,
};
batch_trait! {
@with_add=<T: @trait> Complex<T>;
@with_mul=@trait<Multiplicative> <T: Ring> Complex<T>;
@am=Additive,Multiplicative;
Magma: @with_add{
fn combine(&self, rhs: &Self) -> Self {
Complex::new(
<T as Magma<>>::combine(self.re(), rhs.re()),
<T as Magma<>>::combine(self.im(), rhs.im()),
)
}
},
@with_mul impl{@trait<>}{
fn combine(&self, rhs: &Self) -> Self {
Complex::new(
<T as Magma>::combine(
&<T as Magma<>>::combine(self.re(), rhs.re()),
&<T as Group>::inverse(&<T as Magma<>>::combine(
self.im(),
rhs.im(),
)),
),
<T as Magma>::combine(
&<T as Magma<>>::combine(self.re(), rhs.im()),
&<T as Magma<>>::combine(self.im(), rhs.re()),
),
)
}
};
Semigroup: @with_add, @with_mul;
Monoid: [@with_add, @with_mul]impl{@trait<>}{
fn identity() -> Self {
Complex::new(<T as Monoid<>>::identity(), <T as Monoid>::identity())
}
};
Quasigroup: @with_add;
Loop: @with_add;
Group: @with_add{
fn inverse(&self) -> Self {
Complex::new(
<T as Group>::inverse(self.re()),
<T as Group>::inverse(self.im()),
)
}
};
AbelianGroup: @with_add;
Semiring: <T: Ring> Complex<T>;
Ring: <T: @trait> Complex<T>;
CommutativeRing: <T: @trait> Complex<T>;
Field: <T: @trait> Complex<T>;
Module: @trait<@am> <T: Field> Complex<T>{
type Scalar = T;
fn scale(s: &Self::Scalar, v: Self) -> Self {
Complex::new(
<T as Magma<Multiplicative>>::combine(s, v.re()),
<T as Magma<Multiplicative>>::combine(s, v.im()),
)
}
};
VectorSpace: @trait<@am> <T: Field> Complex<T>
where Self::Scalar: Field;
DivisionRing: <T: Field> Complex<T>{
fn inv(&self) -> Self {
let d = <T as Magma>::combine(
&<T as Magma<Multiplicative>>::combine(self.re(), self.re()),
&<T as Magma<Multiplicative>>::combine(self.im(), self.im()),
);
let inv_d = <T as DivisionRing>::inv(&d);
Complex::new(
<T as Magma<Multiplicative>>::combine(self.re(), &inv_d),
<T as Magma<Multiplicative>>::combine(
&<T as Group>::inverse(self.im()),
&inv_d,
),
)
}
};
ComplexField: <T: Real + Copy> Complex<T>{
type RealField = T;
fn from_real(re: Self::RealField) -> Self {
Complex::new(re, <T as Monoid>::identity())
}
fn re(&self) -> Self::RealField { *self.re() }
fn im(&self) -> Self::RealField { *self.im() }
fn conjugate(&self) -> Self {
Complex::new(*self.re(), <T as Group>::inverse(self.im()))
}
};
FieldExtension: <T: Real + Copy> Complex<T>{
type BaseField = T;
fn degree() -> usize { 2 }
fn trace(&self) -> Self::BaseField {
<T as Magma>::combine(self.re(), self.re())
}
fn norm(&self) -> Self::BaseField {
<T as Magma>::combine(
&<T as Magma<Multiplicative>>::combine(self.re(), self.re()),
&<T as Magma<Multiplicative>>::combine(self.im(), self.im()),
)
}
};
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tower::Magma;
fn add<T: Magma<Additive>>(a: T, b: T) -> T {
<T as Magma<Additive>>::combine(&a, &b)
}
fn mul<T: Magma<Multiplicative>>(a: T, b: T) -> T {
<T as Magma<Multiplicative>>::combine(&a, &b)
}
#[test]
fn complex_add() {
let z = add(Complex::new(1i32, 2), Complex::new(3, 4));
assert_eq!(z.re(), &4);
assert_eq!(z.im(), &6);
}
#[test]
fn complex_mul() {
let z = mul(Complex::new(1i32, 2), Complex::new(3, 4));
assert_eq!(z.re(), &-5);
assert_eq!(z.im(), &10);
let one = <Complex<i32> as Monoid<Multiplicative>>::identity();
assert_eq!(mul(Complex::new(3, 4), one).re(), &3);
assert_eq!(mul(Complex::new(3, 4), one).im(), &4);
}
#[test]
fn complex_field_inverse() {
let z = Complex::new(1.0f64, 0.0);
let inv = <Complex<f64> as DivisionRing<Additive, Multiplicative>>::inv(&z);
assert_eq!(inv.re(), &1.0);
assert_eq!(inv.im(), &0.0);
let z = Complex::new(0.0, 1.0);
let inv = <Complex<f64> as DivisionRing<Additive, Multiplicative>>::inv(&z);
assert_eq!(inv.re(), &0.0);
assert_eq!(inv.im(), &-1.0);
}
#[test]
fn complex_field_structure() {
use crate::tower::ComplexField;
let z = Complex::new(3.0f64, 4.0);
assert_eq!(z.re(), &3.0);
assert_eq!(z.im(), &4.0);
assert_eq!(z.conjugate(), Complex::new(3.0, -4.0));
assert_eq!(<Complex<f64> as ComplexField>::from_real(2.5), Complex::new(2.5, 0.0));
use crate::tower::FieldExtension;
assert_eq!(<Complex<f64> as FieldExtension<Additive, Multiplicative>>::degree(), 2);
assert_eq!(z.trace(), 6.0);
assert_eq!(z.norm(), 25.0);
}
}