use num_complex::Complex;
use num_traits::Num;
pub trait ElementOpApply: Copy {
#[inline(always)]
fn conj(self) -> Self {
self
}
#[inline(always)]
fn transpose(self) -> Self {
self
}
#[inline(always)]
fn adjoint(self) -> Self {
self
}
}
macro_rules! impl_element_op_apply_real {
($($t:ty),*) => {
$(impl ElementOpApply for $t {})*
};
}
impl_element_op_apply_real!(
f32, f64, i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
);
impl<T: Num + Copy + Clone + std::ops::Neg<Output = T>> ElementOpApply for Complex<T> {
#[inline(always)]
fn conj(self) -> Self {
Complex::conj(&self)
}
#[inline(always)]
fn transpose(self) -> Self {
self
}
#[inline(always)]
fn adjoint(self) -> Self {
Complex::conj(&self)
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Identity;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Conj;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Transpose;
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct Adjoint;
pub trait ElementOp<T>: Copy + Default + 'static {
const IS_IDENTITY: bool = false;
fn apply(value: T) -> T;
}
impl<T: Copy> ElementOp<T> for Identity {
const IS_IDENTITY: bool = true;
#[inline(always)]
fn apply(value: T) -> T {
value
}
}
impl<T: ElementOpApply> ElementOp<T> for Conj {
#[inline(always)]
fn apply(value: T) -> T {
value.conj()
}
}
impl<T: ElementOpApply> ElementOp<T> for Transpose {
#[inline(always)]
fn apply(value: T) -> T {
value.transpose()
}
}
impl<T: ElementOpApply> ElementOp<T> for Adjoint {
#[inline(always)]
fn apply(value: T) -> T {
value.adjoint()
}
}
pub trait ComposableElementOp<T: ElementOpApply>: ElementOp<T> {
type Inverse: ComposableElementOp<T>;
type ComposeConj: ComposableElementOp<T>;
type ComposeTranspose: ComposableElementOp<T>;
type ComposeAdjoint: ComposableElementOp<T>;
}
impl<T: ElementOpApply> ComposableElementOp<T> for Identity {
type Inverse = Identity;
type ComposeConj = Conj;
type ComposeTranspose = Transpose;
type ComposeAdjoint = Adjoint;
}
impl<T: ElementOpApply> ComposableElementOp<T> for Conj {
type Inverse = Conj;
type ComposeConj = Identity;
type ComposeTranspose = Adjoint;
type ComposeAdjoint = Transpose;
}
impl<T: ElementOpApply> ComposableElementOp<T> for Transpose {
type Inverse = Transpose;
type ComposeConj = Adjoint;
type ComposeTranspose = Identity;
type ComposeAdjoint = Conj;
}
impl<T: ElementOpApply> ComposableElementOp<T> for Adjoint {
type Inverse = Adjoint;
type ComposeConj = Transpose;
type ComposeTranspose = Conj;
type ComposeAdjoint = Identity;
}
pub trait Compose<T: ElementOpApply, Other: ComposableElementOp<T>>:
ComposableElementOp<T>
{
type Result: ComposableElementOp<T>;
}
impl<T: ElementOpApply, Op: ComposableElementOp<T>> Compose<T, Identity> for Op {
type Result = Op;
}
impl<T: ElementOpApply> Compose<T, Conj> for Identity {
type Result = Conj;
}
impl<T: ElementOpApply> Compose<T, Conj> for Conj {
type Result = Identity;
}
impl<T: ElementOpApply> Compose<T, Conj> for Transpose {
type Result = Adjoint;
}
impl<T: ElementOpApply> Compose<T, Conj> for Adjoint {
type Result = Transpose;
}
impl<T: ElementOpApply> Compose<T, Transpose> for Identity {
type Result = Transpose;
}
impl<T: ElementOpApply> Compose<T, Transpose> for Conj {
type Result = Adjoint;
}
impl<T: ElementOpApply> Compose<T, Transpose> for Transpose {
type Result = Identity;
}
impl<T: ElementOpApply> Compose<T, Transpose> for Adjoint {
type Result = Conj;
}
impl<T: ElementOpApply> Compose<T, Adjoint> for Identity {
type Result = Adjoint;
}
impl<T: ElementOpApply> Compose<T, Adjoint> for Conj {
type Result = Transpose;
}
impl<T: ElementOpApply> Compose<T, Adjoint> for Transpose {
type Result = Conj;
}
impl<T: ElementOpApply> Compose<T, Adjoint> for Adjoint {
type Result = Identity;
}
#[cfg(test)]
mod tests;