diff -r 5e3c1874797d -r 1b3b1687b9ed src/direct_product.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/direct_product.rs Fri Dec 13 22:37:12 2024 -0500 @@ -0,0 +1,228 @@ +/*! +Direct products of the form $A \times B$. + +TODO: This could be easily much more generic if `derive_more` could derive arithmetic +operations on references. +*/ + +use core::ops::{Mul,MulAssign,Div,DivAssign,Add,AddAssign,Sub,SubAssign,Neg}; +use std::clone::Clone; +use serde::{Serialize, Deserialize}; +use crate::types::{Num, Float}; +use crate::{maybe_lifetime, maybe_ref, impl_vectorspace_ops}; +use crate::euclidean::{Dot, Euclidean}; + +#[derive(Debug,Clone,PartialEq,Eq,Serialize,Deserialize)] +pub struct Pair (pub A, pub B); + +impl Pair { + pub fn new(a : A, b : B) -> Pair { Pair{ 0 : a, 1 : b } } +} + +impl From<(A,B)> for Pair { + #[inline] + fn from((a, b) : (A, B)) -> Pair { Pair{ 0 : a, 1 : b } } +} + +macro_rules! impl_binop { + ($trait : ident, $fn : ident, $refl:ident, $refr:ident) => { + impl_binop!(@doit: $trait, $fn; + maybe_lifetime!($refl, &'l Pair), + (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + maybe_lifetime!($refr, &'r Pair), + (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + $refl, $refr); + }; + + (@doit: $trait:ident, $fn:ident; + $self:ty, ($aself:ty, $bself:ty); + $in:ty, ($ain:ty, $bin:ty); + $refl:ident, $refr:ident) => { + impl<'l, 'r, A, B, Ai, Bi> $trait<$in> + for $self + where $aself: $trait<$ain>, + $bself: $trait<$bin> { + type Output = Pair<<$aself as $trait<$ain>>::Output, + <$bself as $trait<$bin>>::Output>; + + #[inline] + fn $fn(self, y : $in) -> Self::Output { + Pair { 0 : maybe_ref!($refl, self.0).$fn(maybe_ref!($refr, y.0)), + 1 : maybe_ref!($refl, self.1).$fn(maybe_ref!($refr, y.1)) } + } + } + }; +} + +macro_rules! impl_assignop { + ($trait : ident, $fn : ident, $refr:ident) => { + impl_assignop!(@doit: $trait, $fn; + maybe_lifetime!($refr, &'r Pair), + (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + $refr); + }; + (@doit: $trait:ident, $fn:ident; + $in:ty, ($ain:ty, $bin:ty); + $refr:ident) => { + impl<'r, A, B, Ai, Bi> $trait<$in> + for Pair + where A: $trait<$ain>, + B: $trait<$bin> { + #[inline] + fn $fn(&mut self, y : $in) -> () { + self.0.$fn(maybe_ref!($refr, y.0)); + self.1.$fn(maybe_ref!($refr, y.1)); + } + } + } +} + +macro_rules! impl_scalarop { + ($trait : ident, $fn : ident, $refl:ident) => { + impl_scalarop!(@doit: $trait, $fn; + maybe_lifetime!($refl, &'l Pair), + (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + $refl); + }; + (@doit: $trait:ident, $fn:ident; + $self:ty, ($aself:ty, $bself:ty); + $refl:ident) => { + // Scalar as Rhs + impl<'l, F : Num, A, B> $trait + for $self + where $aself: $trait, + $bself: $trait { + type Output = Pair<<$aself as $trait>::Output, + <$bself as $trait>::Output>; + #[inline] + fn $fn(self, a : F) -> Self::Output { + Pair{ 0 : maybe_ref!($refl, self.0).$fn(a), + 1 : maybe_ref!($refl, self.1).$fn(a)} + } + } + } +} + +// Not used due to compiler overflow +#[allow(unused_macros)] +macro_rules! impl_scalarlhs_op { + ($trait:ident, $fn:ident, $refr:ident, $field:ty) => { + impl_scalarlhs_op!(@doit: $trait, $fn, + maybe_lifetime!($refr, &'r Pair), + (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + $refr, $field); + }; + (@doit: $trait:ident, $fn:ident, + $in:ty, ($ain:ty, $bin:ty); + $refr:ident, $field:ty) => { + impl<'r, Ai, Bi> $trait<$in> + for $field + where $field : $trait<$ain> + + $trait<$bin> { + type Output = Pair<<$field as $trait<$ain>>::Output, + <$field as $trait<$bin>>::Output>; + #[inline] + fn $fn(self, x : $in) -> Self::Output { + Pair{ 0 : self.$fn(maybe_ref!($refr, x.0)), + 1 : self.$fn(maybe_ref!($refr, x.1))} + } + } + }; +} + +macro_rules! impl_scalar_assignop { + ($trait : ident, $fn : ident) => { + impl<'r, F : Num, A, B> $trait + for Pair + where A: $trait, B: $trait { + #[inline] + fn $fn(&mut self, a : F) -> () { + self.0.$fn(a); + self.1.$fn(a); + } + } + } +} + +macro_rules! impl_unaryop { + ($trait:ident, $fn:ident, $refl:ident) => { + impl_unaryop!(@doit: $trait, $fn; + maybe_lifetime!($refl, &'l Pair), + (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + $refl); + }; + (@doit: $trait:ident, $fn:ident; + $self:ty, ($aself:ty, $bself:ty); + $refl : ident) => { + impl<'l, A, B> $trait + for $self + where $aself: $trait, + $bself: $trait { + type Output = Pair<<$aself as $trait>::Output, + <$bself as $trait>::Output>; + #[inline] + fn $fn(self) -> Self::Output { + Pair{ 0 : maybe_ref!($refl, self.0).$fn(), + 1 : maybe_ref!($refl, self.1).$fn()} + } + } + } +} + + +impl_vectorspace_ops!(impl_binop, impl_assignop, impl_scalarop, impl_scalarlhs_op, + impl_scalar_assignop, impl_unaryop); + + +impl Dot, F> for Pair +where + A : Dot, + B : Dot, + F : Num +{ + + fn dot(&self, Pair(ref u, ref v) : &Pair) -> F { + self.0.dot(u) + self.1.dot(v) + } +} + +impl Euclidean for Pair +where + A : Euclidean, + B : Euclidean, + F : Float +{ + type Output = Pair<>::Output, >::Output>; + + fn similar_origin(&self) -> >::Output { + Pair(self.0.similar_origin(), self.1.similar_origin()) + } + + fn dist2_squared(&self, Pair(ref u, ref v) : &Self) -> F { + self.0.dist2_squared(u) + self.1.dist2_squared(v) + } +} + +use crate::linops::AXPY; + +impl AXPY> for Pair +where + A : AXPY, + B : AXPY, + F : Num +{ + fn axpy(&mut self, α : F, x : &Pair, β : F) { + self.0.axpy(α, &x.0, β); + self.1.axpy(α, &x.1, β); + } + + fn copy_from(&mut self, x : &Pair,) { + self.0.copy_from(&x.0); + self.1.copy_from(&x.1); + } + + fn scale_from(&mut self, α : F, x : &Pair) { + self.0.scale_from(α, &x.0); + self.1.scale_from(α, &x.1); + } +} \ No newline at end of file