--- a/src/direct_product.rs Sat Dec 14 09:31:27 2024 -0500 +++ b/src/direct_product.rs Tue Dec 31 08:30:02 2024 -0500 @@ -9,65 +9,81 @@ use std::clone::Clone; use serde::{Serialize, Deserialize}; use crate::types::{Num, Float}; -use crate::{maybe_lifetime, maybe_ref, impl_vectorspace_ops}; +use crate::{maybe_lifetime, maybe_ref}; use crate::euclidean::{Dot, Euclidean}; +use crate::instance::{Instance, InstanceMut, Decomposition, DecompositionMut, MyCow}; +use crate::mapping::Space; +use crate::linops::AXPY; +use crate::loc::Loc; +use crate::norms::{Norm, PairNorm, NormExponent}; -#[derive(Debug,Clone,PartialEq,Eq,Serialize,Deserialize)] +#[derive(Debug,Clone,Copy,PartialEq,Eq,Serialize,Deserialize)] pub struct Pair<A, B> (pub A, pub B); impl<A, B> Pair<A,B> { - pub fn new(a : A, b : B) -> Pair<A,B> { Pair{ 0 : a, 1 : b } } + pub fn new(a : A, b : B) -> Pair<A,B> { Pair(a, b) } } impl<A, B> From<(A,B)> for Pair<A,B> { #[inline] - fn from((a, b) : (A, B)) -> Pair<A,B> { Pair{ 0 : a, 1 : b } } + fn from((a, b) : (A, B)) -> Pair<A,B> { Pair(a, b) } +} + +impl<A, B> From<Pair<A,B>> for (A,B) { + #[inline] + fn from(Pair(a, b) : Pair<A, B>) -> (A,B) { (a, b) } } macro_rules! impl_binop { - ($trait : ident, $fn : ident, $refl:ident, $refr:ident) => { - impl_binop!(@doit: $trait, $fn; - maybe_lifetime!($refl, &'l Pair<A,B>), - (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + (($a : ty, $b : ty), $trait : ident, $fn : ident, $refl:ident, $refr:ident) => { + impl_binop!(@doit: $a, $b, $trait, $fn; + maybe_lifetime!($refl, &'l Pair<$a,$b>), + (maybe_lifetime!($refl, &'l $a), + maybe_lifetime!($refl, &'l $b)); maybe_lifetime!($refr, &'r Pair<Ai,Bi>), - (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + (maybe_lifetime!($refr, &'r Ai), + maybe_lifetime!($refr, &'r Bi)); $refl, $refr); }; - (@doit: $trait:ident, $fn:ident; + (@doit: $a:ty, $b:ty, + $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> + impl<'l, 'r, 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>; + <$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)) } + Pair(maybe_ref!($refl, self.0).$fn(maybe_ref!($refr, y.0)), + 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; + (($a : ty, $b : ty), $trait : ident, $fn : ident, $refr:ident) => { + impl_assignop!(@doit: $a, $b, + $trait, $fn; maybe_lifetime!($refr, &'r Pair<Ai,Bi>), - (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + (maybe_lifetime!($refr, &'r Ai), + maybe_lifetime!($refr, &'r Bi)); $refr); }; - (@doit: $trait:ident, $fn:ident; + (@doit: $a : ty, $b : ty, + $trait:ident, $fn:ident; $in:ty, ($ain:ty, $bin:ty); $refr:ident) => { - impl<'r, A, B, Ai, Bi> $trait<$in> - for Pair<A,B> - where A: $trait<$ain>, - B: $trait<$bin> { + impl<'r, Ai, Bi> $trait<$in> + for Pair<$a,$b> + where $a: $trait<$ain>, + $b: $trait<$bin> { #[inline] fn $fn(&mut self, y : $in) -> () { self.0.$fn(maybe_ref!($refr, y.0)); @@ -78,26 +94,29 @@ } macro_rules! impl_scalarop { - ($trait : ident, $fn : ident, $refl:ident) => { - impl_scalarop!(@doit: $trait, $fn; - maybe_lifetime!($refl, &'l Pair<A,B>), - (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + (($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident, $refl:ident) => { + impl_scalarop!(@doit: $field, + $trait, $fn; + maybe_lifetime!($refl, &'l Pair<$a,$b>), + (maybe_lifetime!($refl, &'l $a), + maybe_lifetime!($refl, &'l $b)); $refl); }; - (@doit: $trait:ident, $fn:ident; + (@doit: $field : ty, + $trait:ident, $fn:ident; $self:ty, ($aself:ty, $bself:ty); $refl:ident) => { // Scalar as Rhs - impl<'l, F : Num, A, B> $trait<F> + impl<'l> $trait<$field> for $self - where $aself: $trait<F>, - $bself: $trait<F> { - type Output = Pair<<$aself as $trait<F>>::Output, - <$bself as $trait<F>>::Output>; + where $aself: $trait<$field>, + $bself: $trait<$field> { + type Output = Pair<<$aself as $trait<$field>>::Output, + <$bself as $trait<$field>>::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)} + fn $fn(self, a : $field) -> Self::Output { + Pair(maybe_ref!($refl, self.0).$fn(a), + maybe_ref!($refl, self.1).$fn(a)) } } } @@ -106,37 +125,38 @@ // 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<Ai,Bi>), - (maybe_lifetime!($refr, &'r Ai), maybe_lifetime!($refr, &'r Bi)); + (($a : ty, $b : ty), $field : ty, $trait:ident, $fn:ident, $refr:ident) => { + impl_scalarlhs_op!(@doit: $trait, $fn, + maybe_lifetime!($refr, &'r Pair<$a,$b>), + (maybe_lifetime!($refr, &'r $a), + maybe_lifetime!($refr, &'r $b)); $refr, $field); }; - (@doit: $trait:ident, $fn:ident, + (@doit: $trait:ident, $fn:ident, $in:ty, ($ain:ty, $bin:ty); $refr:ident, $field:ty) => { - impl<'r, Ai, Bi> $trait<$in> + impl<'r> $trait<$in> for $field where $field : $trait<$ain> + $trait<$bin> { type Output = Pair<<$field as $trait<$ain>>::Output, - <$field as $trait<$bin>>::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))} + Pair(self.$fn(maybe_ref!($refr, x.0)), + self.$fn(maybe_ref!($refr, x.1))) } } }; } macro_rules! impl_scalar_assignop { - ($trait : ident, $fn : ident) => { - impl<'r, F : Num, A, B> $trait<F> - for Pair<A,B> - where A: $trait<F>, B: $trait<F> { + (($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { + impl<'r> $trait<$field> + for Pair<$a, $b> + where $a: $trait<$field>, $b: $trait<$field> { #[inline] - fn $fn(&mut self, a : F) -> () { + fn $fn(&mut self, a : $field) -> () { self.0.$fn(a); self.1.$fn(a); } @@ -145,34 +165,77 @@ } macro_rules! impl_unaryop { - ($trait:ident, $fn:ident, $refl:ident) => { + (($a : ty, $b : ty), $trait:ident, $fn:ident, $refl:ident) => { impl_unaryop!(@doit: $trait, $fn; - maybe_lifetime!($refl, &'l Pair<A,B>), - (maybe_lifetime!($refl, &'l A), maybe_lifetime!($refl, &'l B)); + maybe_lifetime!($refl, &'l Pair<$a,$b>), + (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 + impl<'l> $trait for $self where $aself: $trait, $bself: $trait { type Output = Pair<<$aself as $trait>::Output, - <$bself 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()} + Pair(maybe_ref!($refl, self.0).$fn(), + maybe_ref!($refl, self.1).$fn()) } } } } +#[macro_export] +macro_rules! impl_pair_vectorspace_ops { + (($a:ty, $b:ty), $field:ty) => { + impl_pair_vectorspace_ops!(@binary, ($a, $b), Add, add); + impl_pair_vectorspace_ops!(@binary, ($a, $b), Sub, sub); + impl_pair_vectorspace_ops!(@assign, ($a, $b), AddAssign, add_assign); + impl_pair_vectorspace_ops!(@assign, ($a, $b), SubAssign, sub_assign); + impl_pair_vectorspace_ops!(@scalar, ($a, $b), $field, Mul, mul); + impl_pair_vectorspace_ops!(@scalar, ($a, $b), $field, Div, div); + // Compiler overflow + // $( + // impl_pair_vectorspace_ops!(@scalar_lhs, ($a, $b), $field, $impl_scalarlhs_op, Mul, mul); + // )* + impl_pair_vectorspace_ops!(@scalar_assign, ($a, $b), $field, MulAssign, mul_assign); + impl_pair_vectorspace_ops!(@scalar_assign, ($a, $b), $field, DivAssign, div_assign); + impl_pair_vectorspace_ops!(@unary, ($a, $b), Neg, neg); + }; + (@binary, ($a : ty, $b : ty), $trait : ident, $fn : ident) => { + impl_binop!(($a, $b), $trait, $fn, ref, ref); + impl_binop!(($a, $b), $trait, $fn, ref, noref); + impl_binop!(($a, $b), $trait, $fn, noref, ref); + impl_binop!(($a, $b), $trait, $fn, noref, noref); + }; + (@assign, ($a : ty, $b : ty), $trait : ident, $fn :ident) => { + impl_assignop!(($a, $b), $trait, $fn, ref); + impl_assignop!(($a, $b), $trait, $fn, noref); + }; + (@scalar, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn :ident) => { + impl_scalarop!(($a, $b), $field, $trait, $fn, ref); + impl_scalarop!(($a, $b), $field, $trait, $fn, noref); + }; + (@scalar_lhs, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { + impl_scalarlhs_op!(($a, $b), $field, $trait, $fn, ref); + impl_scalarlhs_op!(($a, $b), $field, $trait, $fn, noref); + }; + (@scalar_assign, ($a : ty, $b : ty), $field : ty, $trait : ident, $fn : ident) => { + impl_scalar_assignop!(($a, $b), $field, $trait, $fn); + }; + (@unary, ($a : ty, $b : ty), $trait : ident, $fn : ident) => { + impl_unaryop!(($a, $b), $trait, $fn, ref); + impl_unaryop!(($a, $b), $trait, $fn, noref); + }; +} -impl_vectorspace_ops!(impl_binop, impl_assignop, impl_scalarop, impl_scalarlhs_op, - impl_scalar_assignop, impl_unaryop); - +impl_pair_vectorspace_ops!((f32, f32), f32); +impl_pair_vectorspace_ops!((f64, f64), f64); impl<A, B, U, V, F> Dot<Pair<U, V>, F> for Pair<A, B> where @@ -186,15 +249,28 @@ } } -impl<A, B, F> Euclidean<F> for Pair<A, B> +type PairOutput<F, A, B> = Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output>; + +impl<A, B, F> Euclidean<F> for Pair<A, B> where A : Euclidean<F>, B : Euclidean<F>, - F : Float + F : Float, + PairOutput<F, A, B> : Euclidean<F>, + Self : Sized + Dot<Self,F> + + Mul<F, Output=PairOutput<F, A, B>> + MulAssign<F> + + Div<F, Output=PairOutput<F, A, B>> + DivAssign<F> + + Add<Self, Output=PairOutput<F, A, B>> + + Sub<Self, Output=PairOutput<F, A, B>> + + for<'b> Add<&'b Self, Output=PairOutput<F, A, B>> + + for<'b> Sub<&'b Self, Output=PairOutput<F, A, B>> + + AddAssign<Self> + for<'b> AddAssign<&'b Self> + + SubAssign<Self> + for<'b> SubAssign<&'b Self> + + Neg<Output=PairOutput<F, A, B>> { - type Output = Pair<<A as Euclidean<F>>::Output, <B as Euclidean<F>>::Output>; + type Output = PairOutput<F, A, B>; - fn similar_origin(&self) -> <Self as Euclidean<F>>::Output { + fn similar_origin(&self) -> PairOutput<F, A, B> { Pair(self.0.similar_origin(), self.1.similar_origin()) } @@ -203,26 +279,192 @@ } } -use crate::linops::AXPY; - impl<F, A, B, U, V> AXPY<F, Pair<U, V>> for Pair<A, B> where + U : Space, + V : Space, A : AXPY<F, U>, B : AXPY<F, V>, F : Num { - fn axpy(&mut self, α : F, x : &Pair<U, V>, β : F) { - self.0.axpy(α, &x.0, β); - self.1.axpy(α, &x.1, β); + + fn axpy<I : Instance<Pair<U,V>>>(&mut self, α : F, x : I, β : F) { + let Pair(u, v) = x.decompose(); + self.0.axpy(α, u, β); + self.1.axpy(α, v, β); + } + + fn copy_from<I : Instance<Pair<U,V>>>(&mut self, x : I) { + let Pair(u, v) = x.decompose(); + self.0.copy_from(u); + self.1.copy_from(v); + } + + fn scale_from<I : Instance<Pair<U,V>>>(&mut self, α : F, x : I) { + let Pair(u, v) = x.decompose(); + self.0.scale_from(α, u); + self.1.scale_from(α, v); + } +} + +/// [`Decomposition`] for working with [`Pair`]s. +#[derive(Copy, Clone, Debug)] +pub struct PairDecomposition<D, Q>(D, Q); + +impl<A : Space, B : Space> Space for Pair<A, B> { + type Decomp = PairDecomposition<A::Decomp, B::Decomp>; +} + +impl<A, B, D, Q> Decomposition<Pair<A, B>> for PairDecomposition<D,Q> +where + A : Space, + B : Space, + D : Decomposition<A>, + Q : Decomposition<B>, +{ + type Decomposition<'b> = Pair<D::Decomposition<'b>, Q::Decomposition<'b>> where Pair<A, B> : 'b; + type Reference<'b> = Pair<D::Reference<'b>, Q::Reference<'b>> where Pair<A, B> : 'b; + + #[inline] + fn lift<'b>(Pair(u, v) : Self::Reference<'b>) -> Self::Decomposition<'b> { + Pair(D::lift(u), Q::lift(v)) + } +} + +impl<A, B, U, V, D, Q> Instance<Pair<A, B>, PairDecomposition<D, Q>> for Pair<U, V> +where + A : Space, + B : Space, + D : Decomposition<A>, + Q : Decomposition<B>, + U : Instance<A, D>, + V : Instance<B, Q>, +{ + #[inline] + fn decompose<'b>(self) + -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Decomposition<'b> + where Self : 'b, Pair<A, B> : 'b + { + Pair(self.0.decompose(), self.1.decompose()) + } + + #[inline] + fn ref_instance(&self) + -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Reference<'_> + { + Pair(self.0.ref_instance(), self.1.ref_instance()) + } + + #[inline] + fn cow<'b>(self) -> MyCow<'b, Pair<A, B>> where Self : 'b{ + MyCow::Owned(Pair(self.0.own(), self.1.own())) } - fn copy_from(&mut self, x : &Pair<U, V>,) { - self.0.copy_from(&x.0); - self.1.copy_from(&x.1); + #[inline] + fn own(self) -> Pair<A, B> { + Pair(self.0.own(), self.1.own()) + } +} + + +impl<'a, A, B, U, V, D, Q> Instance<Pair<A, B>, PairDecomposition<D, Q>> for &'a Pair<U, V> +where + A : Space, + B : Space, + D : Decomposition<A>, + Q : Decomposition<B>, + U : Instance<A, D>, + V : Instance<B, Q>, + &'a U : Instance<A, D>, + &'a V : Instance<B, Q>, +{ + #[inline] + fn decompose<'b>(self) + -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Decomposition<'b> + where Self : 'b, Pair<A, B> : 'b + { + Pair(D::lift(self.0.ref_instance()), Q::lift(self.1.ref_instance())) + } + + #[inline] + fn ref_instance(&self) + -> <PairDecomposition<D, Q> as Decomposition<Pair<A, B>>>::Reference<'_> + { + Pair(self.0.ref_instance(), self.1.ref_instance()) + } + + #[inline] + fn cow<'b>(self) -> MyCow<'b, Pair<A, B>> where Self : 'b { + MyCow::Owned(self.own()) + } + + #[inline] + fn own(self) -> Pair<A, B> { + let Pair(ref u, ref v) = self; + Pair(u.own(), v.own()) } - fn scale_from(&mut self, α : F, x : &Pair<U, V>) { - self.0.scale_from(α, &x.0); - self.1.scale_from(α, &x.1); +} + +impl<A, B, D, Q> DecompositionMut<Pair<A, B>> for PairDecomposition<D,Q> +where + A : Space, + B : Space, + D : DecompositionMut<A>, + Q : DecompositionMut<B>, +{ + type ReferenceMut<'b> = Pair<D::ReferenceMut<'b>, Q::ReferenceMut<'b>> where Pair<A, B> : 'b; +} + +impl<A, B, U, V, D, Q> InstanceMut<Pair<A, B>, PairDecomposition<D, Q>> for Pair<U, V> +where + A : Space, + B : Space, + D : DecompositionMut<A>, + Q : DecompositionMut<B>, + U : InstanceMut<A, D>, + V : InstanceMut<B, Q>, +{ + #[inline] + fn ref_instance_mut(&mut self) + -> <PairDecomposition<D, Q> as DecompositionMut<Pair<A, B>>>::ReferenceMut<'_> + { + Pair(self.0.ref_instance_mut(), self.1.ref_instance_mut()) } -} \ No newline at end of file +} + +impl<'a, A, B, U, V, D, Q> InstanceMut<Pair<A, B>, PairDecomposition<D, Q>> for &'a mut Pair<U, V> +where + A : Space, + B : Space, + D : DecompositionMut<A>, + Q : DecompositionMut<B>, + U : InstanceMut<A, D>, + V : InstanceMut<B, Q>, +{ + #[inline] + fn ref_instance_mut(&mut self) + -> <PairDecomposition<D, Q> as DecompositionMut<Pair<A, B>>>::ReferenceMut<'_> + { + Pair(self.0.ref_instance_mut(), self.1.ref_instance_mut()) + } +} + + +impl<F, A, B, ExpA, ExpB, ExpJ> Norm<F, PairNorm<ExpA, ExpB, ExpJ>> +for Pair<A,B> +where + F : Num, + ExpA : NormExponent, + ExpB : NormExponent, + ExpJ : NormExponent, + A : Norm<F, ExpA>, + B : Norm<F, ExpB>, + Loc<F, 2> : Norm<F, ExpJ>, +{ + fn norm(&self, PairNorm(expa, expb, expj) : PairNorm<ExpA, ExpB, ExpJ>) -> F { + Loc([self.0.norm(expa), self.1.norm(expb)]).norm(expj) + } +} + +