use std::ops::{Add, AddAssign, Deref, DerefMut, Div, DivAssign, Mul, MulAssign, Sub, SubAssign};
use approx::AbsDiffEq;
use num_complex::Complex;
use num_traits::{float::FloatCore, Float, Num, NumAssign, Zero};
#[derive(Clone, Copy, Default, PartialEq)]
pub struct Jones<F: Float + Num>([Complex<F>; 4]);
impl<F: Float> Jones<F> {
#[inline]
pub fn identity() -> Self {
Self::from([
Complex::new(F::one(), F::zero()),
Complex::new(F::zero(), F::zero()),
Complex::new(F::zero(), F::zero()),
Complex::new(F::one(), F::zero()),
])
}
#[inline]
pub fn nan() -> Self {
Self::from([
Complex::new(F::nan(), F::zero()),
Complex::new(F::nan(), F::zero()),
Complex::new(F::nan(), F::zero()),
Complex::new(F::nan(), F::zero()),
])
}
#[inline]
pub fn h(self) -> Self {
Self::from([
self[0].conj(),
self[2].conj(),
self[1].conj(),
self[3].conj(),
])
}
#[inline]
pub fn mul_hermitian(self, b: Self) -> Self {
self * b.h()
}
#[inline]
pub fn inv(self) -> Self {
let inv_det = Complex::new(F::one(), F::zero()) / (self[0] * self[3] - self[1] * self[2]);
Self::from([
inv_det * self[3],
-inv_det * self[1],
-inv_det * self[2],
inv_det * self[0],
])
}
#[inline]
pub fn norm_sqr(self) -> [F; 4] {
[
self[0].norm_sqr(),
self[1].norm_sqr(),
self[2].norm_sqr(),
self[3].norm_sqr(),
]
}
#[inline]
pub fn axb(a: Self, b: Self) -> Self {
a * b
}
#[inline]
pub fn axbh(a: Self, b: Self) -> Self {
a * b.h()
}
}
impl<F: Float + FloatCore> Jones<F> {
#[inline]
pub fn any_nan(self) -> bool {
self.iter().any(|f| f.is_nan())
}
}
impl<F: Float + NumAssign> Jones<F> {
#[inline]
pub fn plus_axb(c: &mut Self, a: Self, b: Self) {
c[0] += a[0] * b[0] + a[1] * b[2];
c[1] += a[0] * b[1] + a[1] * b[3];
c[2] += a[2] * b[0] + a[3] * b[2];
c[3] += a[2] * b[1] + a[3] * b[3];
}
#[inline]
pub fn plus_ahxb(c: &mut Self, a: Self, b: Self) {
c[0] += a[0].conj() * b[0] + a[2].conj() * b[2];
c[1] += a[0].conj() * b[1] + a[2].conj() * b[3];
c[2] += a[1].conj() * b[0] + a[3].conj() * b[2];
c[3] += a[1].conj() * b[1] + a[3].conj() * b[3];
}
}
impl<F: Float> Deref for Jones<F> {
type Target = [Complex<F>; 4];
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<F: Float> DerefMut for Jones<F> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<F: Float> From<[Complex<F>; 4]> for Jones<F> {
#[inline]
fn from(arr: [Complex<F>; 4]) -> Self {
Self(arr)
}
}
impl<F: Float> Add<Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn add(self, rhs: Self) -> Self {
Self::from([
self[0] + rhs[0],
self[1] + rhs[1],
self[2] + rhs[2],
self[3] + rhs[3],
])
}
}
impl<F: Float + NumAssign> AddAssign<Jones<F>> for Jones<F> {
#[inline]
fn add_assign(&mut self, rhs: Self) {
self[0] += rhs[0];
self[1] += rhs[1];
self[2] += rhs[2];
self[3] += rhs[3];
}
}
impl<F: Float + NumAssign> AddAssign<&Jones<F>> for Jones<F> {
#[inline]
fn add_assign(&mut self, rhs: &Self) {
self[0] += rhs[0];
self[1] += rhs[1];
self[2] += rhs[2];
self[3] += rhs[3];
}
}
impl<F: Float> Sub<Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn sub(self, rhs: Self) -> Self {
Self::from([
self[0] - rhs[0],
self[1] - rhs[1],
self[2] - rhs[2],
self[3] - rhs[3],
])
}
}
impl<F: Float> Sub<&Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn sub(self, rhs: &Self) -> Self {
Self::from([
self[0] - rhs[0],
self[1] - rhs[1],
self[2] - rhs[2],
self[3] - rhs[3],
])
}
}
impl<F: Float> Sub<&mut Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn sub(self, rhs: &mut Self) -> Self {
Self::from([
self[0] - rhs[0],
self[1] - rhs[1],
self[2] - rhs[2],
self[3] - rhs[3],
])
}
}
impl<F: Float + NumAssign> SubAssign<Jones<F>> for Jones<F> {
#[inline]
fn sub_assign(&mut self, rhs: Self) {
self[0] -= rhs[0];
self[1] -= rhs[1];
self[2] -= rhs[2];
self[3] -= rhs[3];
}
}
impl<F: Float + NumAssign> SubAssign<&Jones<F>> for Jones<F> {
#[inline]
fn sub_assign(&mut self, rhs: &Self) {
self[0] -= rhs[0];
self[1] -= rhs[1];
self[2] -= rhs[2];
self[3] -= rhs[3];
}
}
impl<F: Float> Mul<F> for Jones<F> {
type Output = Self;
#[inline]
fn mul(self, rhs: F) -> Self {
Jones::from([self[0] * rhs, self[1] * rhs, self[2] * rhs, self[3] * rhs])
}
}
impl<F: Float> Mul<Complex<F>> for Jones<F> {
type Output = Self;
#[inline]
fn mul(self, rhs: Complex<F>) -> Self {
Jones::from([self[0] * rhs, self[1] * rhs, self[2] * rhs, self[3] * rhs])
}
}
impl<F: Float> Mul<Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn mul(self, rhs: Self) -> Self {
Self::from([
self[0] * rhs[0] + self[1] * rhs[2],
self[0] * rhs[1] + self[1] * rhs[3],
self[2] * rhs[0] + self[3] * rhs[2],
self[2] * rhs[1] + self[3] * rhs[3],
])
}
}
impl<F: Float> Mul<&Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn mul(self, rhs: &Self) -> Self {
Self::from([
self[0] * rhs[0] + self[1] * rhs[2],
self[0] * rhs[1] + self[1] * rhs[3],
self[2] * rhs[0] + self[3] * rhs[2],
self[2] * rhs[1] + self[3] * rhs[3],
])
}
}
impl<F: Float + NumAssign> MulAssign<F> for Jones<F> {
#[inline]
fn mul_assign(&mut self, rhs: F) {
self[0] *= rhs;
self[1] *= rhs;
self[2] *= rhs;
self[3] *= rhs;
}
}
impl<F: Float + NumAssign> MulAssign<Complex<F>> for Jones<F> {
#[inline]
fn mul_assign(&mut self, rhs: Complex<F>) {
self[0] *= rhs;
self[1] *= rhs;
self[2] *= rhs;
self[3] *= rhs;
}
}
impl<F: Float + NumAssign> MulAssign<Jones<F>> for Jones<F> {
#[inline]
fn mul_assign(&mut self, rhs: Self) {
self.0 = [
self[0] * rhs[0] + self[1] * rhs[2],
self[0] * rhs[1] + self[1] * rhs[3],
self[2] * rhs[0] + self[3] * rhs[2],
self[2] * rhs[1] + self[3] * rhs[3],
];
}
}
impl<F: Float + NumAssign> MulAssign<&Jones<F>> for Jones<F> {
#[inline]
fn mul_assign(&mut self, rhs: &Self) {
self.0 = [
self[0] * rhs[0] + self[1] * rhs[2],
self[0] * rhs[1] + self[1] * rhs[3],
self[2] * rhs[0] + self[3] * rhs[2],
self[2] * rhs[1] + self[3] * rhs[3],
];
}
}
impl<F: Float> Div<F> for Jones<F> {
type Output = Self;
#[inline]
fn div(self, rhs: F) -> Self {
Jones::from([self[0] / rhs, self[1] / rhs, self[2] / rhs, self[3] / rhs])
}
}
impl<F: Float> Div<Complex<F>> for Jones<F> {
type Output = Self;
#[inline]
fn div(self, rhs: Complex<F>) -> Self {
Jones::from([self[0] / rhs, self[1] / rhs, self[2] / rhs, self[3] / rhs])
}
}
impl<F: Float> Div<Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn div(self, rhs: Self) -> Self {
let inv_det = Complex::new(F::one(), F::zero()) / (rhs[0] * rhs[3] - rhs[1] * rhs[2]);
Self::from([
(self[0] * rhs[3] - self[1] * rhs[2]) * inv_det,
(self[1] * rhs[0] - self[0] * rhs[1]) * inv_det,
(self[2] * rhs[3] - self[3] * rhs[2]) * inv_det,
(self[3] * rhs[0] - self[2] * rhs[1]) * inv_det,
])
}
}
impl<F: Float> Div<&Jones<F>> for Jones<F> {
type Output = Self;
#[inline]
fn div(self, rhs: &Self) -> Self {
let inv_det = Complex::new(F::one(), F::zero()) / (rhs[0] * rhs[3] - rhs[1] * rhs[2]);
Self::from([
(self[0] * rhs[3] - self[1] * rhs[2]) * inv_det,
(self[1] * rhs[0] - self[0] * rhs[1]) * inv_det,
(self[2] * rhs[3] - self[3] * rhs[2]) * inv_det,
(self[3] * rhs[0] - self[2] * rhs[1]) * inv_det,
])
}
}
impl<F: Float + NumAssign> DivAssign<F> for Jones<F> {
#[inline]
fn div_assign(&mut self, rhs: F) {
self[0] /= rhs;
self[1] /= rhs;
self[2] /= rhs;
self[3] /= rhs;
}
}
impl<F: Float + NumAssign> DivAssign<Complex<F>> for Jones<F> {
#[inline]
fn div_assign(&mut self, rhs: Complex<F>) {
self[0] /= rhs;
self[1] /= rhs;
self[2] /= rhs;
self[3] /= rhs;
}
}
impl<F: Float + NumAssign> DivAssign<Jones<F>> for Jones<F> {
#[inline]
fn div_assign(&mut self, rhs: Self) {
let inv_det = Complex::new(F::one(), F::zero()) / (rhs[0] * rhs[3] - rhs[1] * rhs[2]);
*self = Self::from([
(self[0] * rhs[3] - self[1] * rhs[2]) * inv_det,
(self[1] * rhs[0] - self[0] * rhs[1]) * inv_det,
(self[2] * rhs[3] - self[3] * rhs[2]) * inv_det,
(self[3] * rhs[0] - self[2] * rhs[1]) * inv_det,
]);
}
}
impl<F: Float + NumAssign> DivAssign<&Jones<F>> for Jones<F> {
#[inline]
fn div_assign(&mut self, rhs: &Self) {
let inv_det = Complex::new(F::one(), F::zero()) / (rhs[0] * rhs[3] - rhs[1] * rhs[2]);
*self = Self::from([
(self[0] * rhs[3] - self[1] * rhs[2]) * inv_det,
(self[1] * rhs[0] - self[0] * rhs[1]) * inv_det,
(self[2] * rhs[3] - self[3] * rhs[2]) * inv_det,
(self[3] * rhs[0] - self[2] * rhs[1]) * inv_det,
]);
}
}
impl<F: Float> Zero for Jones<F> {
#[inline]
fn zero() -> Self {
Self::from([Complex::zero(); 4])
}
#[inline]
fn is_zero(&self) -> bool {
self == &Self::zero()
}
}
impl From<Jones<f32>> for Jones<f64> {
#[inline]
fn from(j_c32: Jones<f32>) -> Self {
Self::from([
Complex::new(j_c32[0].re as _, j_c32[0].im as _),
Complex::new(j_c32[1].re as _, j_c32[1].im as _),
Complex::new(j_c32[2].re as _, j_c32[2].im as _),
Complex::new(j_c32[3].re as _, j_c32[3].im as _),
])
}
}
impl From<&Jones<f32>> for Jones<f64> {
#[inline]
fn from(j_c32: &Jones<f32>) -> Self {
Self::from([
Complex::new(j_c32[0].re as _, j_c32[0].im as _),
Complex::new(j_c32[1].re as _, j_c32[1].im as _),
Complex::new(j_c32[2].re as _, j_c32[2].im as _),
Complex::new(j_c32[3].re as _, j_c32[3].im as _),
])
}
}
impl From<Jones<f64>> for Jones<f32> {
#[inline]
fn from(j_c64: Jones<f64>) -> Self {
Self::from([
Complex::new(j_c64[0].re as _, j_c64[0].im as _),
Complex::new(j_c64[1].re as _, j_c64[1].im as _),
Complex::new(j_c64[2].re as _, j_c64[2].im as _),
Complex::new(j_c64[3].re as _, j_c64[3].im as _),
])
}
}
impl From<&Jones<f64>> for Jones<f32> {
#[inline]
fn from(j_c64: &Jones<f64>) -> Self {
Self::from([
Complex::new(j_c64[0].re as _, j_c64[0].im as _),
Complex::new(j_c64[1].re as _, j_c64[1].im as _),
Complex::new(j_c64[2].re as _, j_c64[2].im as _),
Complex::new(j_c64[3].re as _, j_c64[3].im as _),
])
}
}
impl std::fmt::Display for Jones<f32> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[[{:e}{:+e}j, {:e}{:+e}j] [{:e}{:+e}j, {:e}{:+e}j]]",
self[0].re,
self[0].im,
self[1].re,
self[1].im,
self[2].re,
self[2].im,
self[3].re,
self[3].im,
)
}
}
impl std::fmt::Display for Jones<f64> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[[{:e}{:+e}j, {:e}{:+e}j] [{:e}{:+e}j, {:e}{:+e}j]]",
self[0].re,
self[0].im,
self[1].re,
self[1].im,
self[2].re,
self[2].im,
self[3].re,
self[3].im,
)
}
}
impl std::fmt::Debug for Jones<f32> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[[{:e}{:+e}j, {:e}{:+e}j] [{:e}{:+e}j, {:e}{:+e}j]]",
self[0].re,
self[0].im,
self[1].re,
self[1].im,
self[2].re,
self[2].im,
self[3].re,
self[3].im,
)
}
}
impl std::fmt::Debug for Jones<f64> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"[[{:e}{:+e}j, {:e}{:+e}j] [{:e}{:+e}j, {:e}{:+e}j]]",
self[0].re,
self[0].im,
self[1].re,
self[1].im,
self[2].re,
self[2].im,
self[3].re,
self[3].im,
)
}
}
impl<F: Float + AbsDiffEq> approx::AbsDiffEq for Jones<F>
where
F::Epsilon: Clone,
{
type Epsilon = F::Epsilon;
#[inline]
fn default_epsilon() -> F::Epsilon {
F::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: F::Epsilon) -> bool {
Complex::<F>::abs_diff_eq(&self[0], &other[0], epsilon.clone())
&& Complex::<F>::abs_diff_eq(&self[1], &other[1], epsilon.clone())
&& Complex::<F>::abs_diff_eq(&self[2], &other[2], epsilon.clone())
&& Complex::<F>::abs_diff_eq(&self[3], &other[3], epsilon)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{c32, c64};
use approx::*;
fn one_through_eight() -> Jones<f64> {
Jones([
c64::new(1.0, 2.0),
c64::new(3.0, 4.0),
c64::new(5.0, 6.0),
c64::new(7.0, 8.0),
])
}
#[test]
fn test_add() {
let a = one_through_eight();
let b = one_through_eight();
let c = a + b;
let expected_c = Jones([
c64::new(2.0, 4.0),
c64::new(6.0, 8.0),
c64::new(10.0, 12.0),
c64::new(14.0, 16.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_sub() {
let a = one_through_eight();
let b = one_through_eight();
let c = a - b;
let expected_c = Jones::default();
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_mul() {
let i = c64::new(1.0, 2.0);
let a = Jones([i, i + 1.0, i + 2.0, i + 3.0]);
let b = Jones([i * 2.0, i * 3.0, i * 4.0, i * 5.0]);
let c = a * &b;
let expected_c = Jones([
c64::new(-14.0, 32.0),
c64::new(-19.0, 42.0),
c64::new(-2.0, 56.0),
c64::new(-3.0, 74.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_mul_assign() {
let i = c64::new(1.0, 2.0);
let mut a = Jones([i, i + 1.0, i + 2.0, i + 3.0]);
let b = Jones([i * 2.0, i * 3.0, i * 4.0, i * 5.0]);
a *= b;
let expected = Jones([
c64::new(-14.0, 32.0),
c64::new(-19.0, 42.0),
c64::new(-2.0, 56.0),
c64::new(-3.0, 74.0),
]);
assert_abs_diff_eq!(a, expected, epsilon = 1e-10);
}
#[test]
fn test_mul_hermitian() {
let ident = Jones::identity();
let a = Jones([
c64::new(1.0, 2.0),
c64::new(3.0, 4.0),
c64::new(5.0, 6.0),
c64::new(7.0, 8.0),
]);
let result = ident.mul_hermitian(a);
let expected = Jones([
c64::new(1.0, -2.0),
c64::new(5.0, -6.0),
c64::new(3.0, -4.0),
c64::new(7.0, -8.0),
]);
assert_abs_diff_eq!(result, expected, epsilon = 1e-10);
}
#[test]
fn test_div() {
let a = Jones([
c64::new(1.0, 0.0),
c64::new(2.0, 0.0),
c64::new(3.0, 0.0),
c64::new(4.0, 0.0),
]);
let b = Jones([
c64::new(2.0, 0.0),
c64::new(3.0, 0.0),
c64::new(4.0, 0.0),
c64::new(5.0, 0.0),
]);
let expected = Jones([
c64::new(1.5, 0.0),
c64::new(-0.5, 0.0),
c64::new(0.5, 0.0),
c64::new(0.5, 0.0),
]);
assert_abs_diff_eq!(a.div(&b), expected, epsilon = 1e-10);
let a = Jones([
c32::new(-1295920.9, -1150667.5),
c32::new(-1116357.0, 1234393.3),
c32::new(-4028358.8, -281923.3),
c32::new(-325126.38, 3929351.3),
]);
let b = Jones([
c32::new(1377080.5, 0.0),
c32::new(5765.743, -1371240.9),
c32::new(5765.743, 1371240.9),
c32::new(1365932.0, 0.0),
]);
let expected = Jones([
c32::new(-107.08988, -72.43006),
c32::new(72.34611, -106.29652),
c32::new(-169.56223, 57.398113),
c32::new(-57.14347, -167.58751),
]);
assert_abs_diff_eq!(a.div(&b), expected, epsilon = 1e-5);
}
#[test]
fn test_div_singular() {
let a = Jones([
c64::new(1.0, 0.0),
c64::new(2.0, 0.0),
c64::new(2.0, 0.0),
c64::new(4.0, 0.0),
]);
let b = a.clone();
assert!((a / b).any_nan());
}
#[test]
fn test_inv() {
let a = Jones([
c64::new(1.0, 2.0),
c64::new(3.0, 4.0),
c64::new(5.0, 6.0),
c64::new(7.0, 8.0),
]);
let result = a.inv() * a;
let expected = Jones::identity();
assert_abs_diff_eq!(result, expected, epsilon = 1e-10);
}
#[test]
fn test_inv_singular() {
let a = Jones([
c64::new(1.0, 0.0),
c64::new(2.0, 0.0),
c64::new(2.0, 0.0),
c64::new(4.0, 0.0),
]);
assert!(a.inv().any_nan());
}
#[test]
fn test_is_nan_works() {
let j: Jones<f64> = Jones::nan();
assert!(j.iter().any(|f| f.is_nan()));
assert!(j.any_nan());
}
#[test]
fn test_axb() {
let i = c64::new(1.0, 2.0);
let a = Jones([i, i + 1.0, i + 2.0, i + 3.0]);
let b = Jones([i * 2.0, i * 3.0, i * 4.0, i * 5.0]);
let c = Jones::axb(a, b);
let expected_c = Jones([
c64::new(-14.0, 32.0),
c64::new(-19.0, 42.0),
c64::new(-2.0, 56.0),
c64::new(-3.0, 74.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_axbh() {
let i = c64::new(1.0, 2.0);
let a = Jones([i, i + 1.0, i + 2.0, i + 3.0]);
let b = Jones([i * 2.0, i * 3.0, i * 4.0, i * 5.0]);
let c = Jones::axbh(a, b);
let expected_c = Jones([
c64::new(28.0, -6.0),
c64::new(50.0, -10.0),
c64::new(38.0, -26.0),
c64::new(68.0, -46.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_plus_axb() {
let a = one_through_eight();
let b = one_through_eight();
let mut c = Jones::default();
Jones::plus_axb(&mut c, a, b);
let expected_c = Jones([
c64::new(-12.0, 42.0),
c64::new(-16.0, 62.0),
c64::new(-20.0, 98.0),
c64::new(-24.0, 150.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
#[test]
fn test_plus_ahxb() {
let a = one_through_eight();
let b = one_through_eight();
let mut c = Jones::default();
Jones::plus_ahxb(&mut c, a, b);
let expected_c = Jones([
c64::new(66.0, 0.0),
c64::new(94.0, -4.0),
c64::new(94.0, 4.0),
c64::new(138.0, 0.0),
]);
assert_abs_diff_eq!(c, expected_c, epsilon = 1e-10);
}
}