organicomplex 0.7.0

Interactive complex-valued cellular automaton on 2D and 3D grids in search of that stuff - emergence, open-endedness, organicity etc.
use rand::prelude::*;

use serde::{
	Deserialize,
	Serialize
};

use std::{
	io::{
 		Read,
    	Write
	},
	ops::{
		Add,
		AddAssign,
		Div,
		DivAssign,
		Mul,
		MulAssign,
		Neg,
		Sub,
		SubAssign
	}
};

use super::{
	real::Real,
	rwbin::{
		ReadBin,
		WriteBin
	}
};

// Fixed-point arithmetic with FPA_BINLOG bits for fractional part
#[derive(Clone, Copy, PartialEq, Debug, Deserialize, Serialize)]
pub struct Complex {
	pub re: f64,
	pub im: f64
}

#[allow(dead_code)]
pub const COMPLEX_UNIT: Complex = Complex{re: 1.0, im: 0.0};

#[allow(dead_code)]
pub const COMPLEX_ZERO: Complex = Complex{re: 0.0, im: 0.0};

impl Complex {
	#[allow(dead_code)]
	pub fn new(re: f64, im: f64) -> Self {
		Self{re, im}
	}

	#[allow(dead_code)]
	pub fn new_default() -> Self {
		COMPLEX_ZERO
	}

	#[allow(dead_code)]
	pub fn new_random(ampl: f64, irng: &mut impl Rng) -> Self {
		Self {
			re: irng.random_range(-ampl..=ampl),
			im: irng.random_range(-ampl..=ampl)
		}
	}

	#[allow(dead_code)]
	pub fn absqr(&self) -> Real {
		Real(self.re * self.re + self.im * self.im)
	}

	#[allow(dead_code)]
	pub fn abs(&self) -> Real {
		Real((self.re * self.re + self.im * self.im).sqrt())
	}

	#[allow(dead_code)]
	pub fn arg(&self) -> Real {
		Real(self.im.atan2(self.re))
	}

	#[allow(dead_code)]
	pub fn conj(&self) -> Self {
		Self{
			re: self.re,
			im: -self.im
		}
	}

	#[allow(dead_code)]
	pub fn swap(&self) -> Self {
		Self{
			re: self.im,
			im: self.re
		}
	}

	#[allow(dead_code)]
	pub fn deim(&self) -> Self {
		Self{
			re: self.re,
			im: 0.0
		}
	}

	#[allow(dead_code)]
	pub fn sqr(&self) -> Self {
		Self{
			re: self.re * self.re - self.im * self.im,
			im: 2.0 * self.re * self.im
		}
	}

	#[allow(dead_code)]
	pub fn exp(&self) -> Self {
		let modulus = self.re.exp();
		Self{
			re: modulus * self.im.cos(),
			im: modulus * self.im.sin()
		}
	}

}

impl From<(f64, f64)> for Complex {
	fn from((re, im): (f64, f64)) -> Self {
		Self{
			re,
			im
		}
	}
}

// ----------------------------------------------------------------

impl Add for Complex {
	type Output = Self;
    fn add(self, rhs: Self) -> Self {
        Self {
            re: self.re + rhs.re,
            im: self.im + rhs.im
        }
    }
}

impl AddAssign for Complex {
    fn add_assign(&mut self, rhs: Self) {
		self.re += rhs.re;
		self.im += rhs.im;
    }
}

impl Div for Complex {
	type Output = Self;
    fn div(self, rhs: Self) -> Self {
		let modulusqr = rhs.re * rhs.re + rhs.im * rhs.im;
        Self {
            re: (self.re * rhs.re + self.im * rhs.im) / modulusqr,
            im: (-self.re * rhs.im + self.im * rhs.re) / modulusqr
        }
    }
}

impl Div<Real> for Complex {
	type Output = Self;
    fn div(self, rhs: Real) -> Self {
        Self {
            re: self.re / rhs.0,
            im: self.im / rhs.0
        }
    }
}

impl DivAssign for Complex {
    fn div_assign(&mut self, rhs: Self) {
		let modulusqr = rhs.re * rhs.re + rhs.im * rhs.im;
		*self = Self {
            re: (self.re * rhs.re + self.im * rhs.im) / modulusqr,
            im: (-self.re * rhs.im + self.im * rhs.re) / modulusqr			
		}
    }
}

impl DivAssign<Real> for Complex {
    fn div_assign(&mut self, rhs: Real) {
		self.re /= rhs.0;
		self.im /= rhs.0;
    }
}

impl Mul for Complex {
	type Output = Self;
	fn mul(self, rhs: Self) -> Self {
		Self {
			re: self.re * rhs.re - self.im * rhs.im,
			im: self.re * rhs.im + self.im * rhs.re
		}
	}
}

impl Mul<Real> for Complex {
	type Output = Self;
	fn mul(self, rhs: Real) -> Self {
		Self {
			re: self.re * rhs.0,
			im: self.im * rhs.0
		}
	}
}

impl MulAssign for Complex {
	fn mul_assign(&mut self, rhs: Self) {
		*self = Self {
			re: self.re * rhs.re - self.im * rhs.im,
			im: self.re * rhs.im + self.im * rhs.re
		}
	}
}

impl MulAssign<Real> for Complex {
	fn mul_assign(&mut self, rhs: Real) {
		self.re *= rhs.0;
		self.im *= rhs.0;
	}
}

impl Neg for Complex {
	type Output = Self;
	fn neg(self) -> Self {
		Self{
			re: -self.re,
			im: -self.im
		}
	}
}

impl Sub for Complex {
	type Output = Self;
	fn sub(self, rhs: Self) -> Self {
        Self {
            re: self.re - rhs.re,
            im: self.im - rhs.im
        }
    }
}

impl SubAssign for Complex {
    fn sub_assign(&mut self, rhs: Self) {
		self.re -= rhs.re;
		self.im -= rhs.im;
    }
}

// ----------------------------------------------------------------

impl<W: Write> WriteBin<&Complex> for W {
    fn write_bin(&mut self, x: &Complex) -> Result<(), String> {
        self.write_bin(x.re)?;
        self.write_bin(x.im)?;
        Ok(())
    }
}

impl<R: Read> ReadBin<Complex> for R {
    fn read_bin(&mut self) -> Result<Complex, String> {
        let re = self.read_bin()?;
        let im = self.read_bin()?;
        Ok(Complex{re, im})
    }
}