use crate::scalar::Scalar;
#[derive(Clone, PartialEq)]
pub struct Surcomplex<S: Scalar> {
pub re: S,
pub im: S,
}
impl<S: Scalar> std::fmt::Display for Surcomplex<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if self.im.is_zero() {
write!(f, "{}", self.re)
} else if self.re.is_zero() {
write!(f, "{}·i", self.im)
} else {
write!(f, "{} + {}·i", self.re, self.im)
}
}
}
impl<S: Scalar> std::fmt::Debug for Surcomplex<S> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self, f)
}
}
impl<S: Scalar> Surcomplex<S> {
pub fn new(re: S, im: S) -> Self {
Surcomplex { re, im }
}
pub fn i() -> Self {
Surcomplex {
re: S::zero(),
im: S::one(),
}
}
pub fn conj(&self) -> Self {
Surcomplex {
re: self.re.clone(),
im: self.im.neg(),
}
}
}
impl<S: Scalar> Scalar for Surcomplex<S> {
fn zero() -> Self {
Surcomplex {
re: S::zero(),
im: S::zero(),
}
}
fn one() -> Self {
Surcomplex {
re: S::one(),
im: S::zero(),
}
}
fn add(&self, rhs: &Self) -> Self {
Surcomplex {
re: self.re.add(&rhs.re),
im: self.im.add(&rhs.im),
}
}
fn neg(&self) -> Self {
Surcomplex {
re: self.re.neg(),
im: self.im.neg(),
}
}
fn mul(&self, rhs: &Self) -> Self {
let ac = self.re.mul(&rhs.re);
let bd = self.im.mul(&rhs.im);
let ad = self.re.mul(&rhs.im);
let bc = self.im.mul(&rhs.re);
Surcomplex {
re: ac.sub(&bd),
im: ad.add(&bc),
}
}
fn characteristic() -> u128 {
S::characteristic()
}
fn inv(&self) -> Option<Self> {
let n = self.re.mul(&self.re).add(&self.im.mul(&self.im));
let ninv = n.inv()?;
Some(Surcomplex {
re: self.re.mul(&ninv),
im: self.im.neg().mul(&ninv),
})
}
fn is_zero(&self) -> bool {
self.re.is_zero() && self.im.is_zero()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::scalar::Nimber;
use crate::scalar::Rational;
type Gauss = Surcomplex<Rational>;
fn g(re: i128, im: i128) -> Gauss {
Surcomplex::new(Rational::from_int(re), Rational::from_int(im))
}
#[test]
fn gaussian_arithmetic() {
let i = Gauss::i();
assert_eq!(i.mul(&i), g(-1, 0)); let one_plus_i = g(1, 1);
assert_eq!(one_plus_i.mul(&one_plus_i), g(0, 2)); assert_eq!(one_plus_i.mul(&one_plus_i.conj()), g(2, 0)); }
#[test]
fn gaussian_inverse() {
let z = g(1, 1); assert_eq!(z.mul(&z.inv().unwrap()), Gauss::one());
let z2 = g(3, -2);
assert_eq!(z2.mul(&z2.inv().unwrap()), Gauss::one());
assert!(Gauss::zero().inv().is_none());
}
#[test]
fn nimber_surcomplex_is_degenerate() {
type NC = Surcomplex<Nimber>;
let i = NC::i();
assert_eq!(i.mul(&i), NC::one()); let one_plus_i = NC::new(Nimber(1), Nimber(1));
assert!(one_plus_i.mul(&one_plus_i).is_zero()); assert!(!one_plus_i.is_zero()); }
}