src/direct_product.rs

branch
dev
changeset 59
9226980e45a7
parent 57
1b3b1687b9ed
child 60
848ecc05becf
--- 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)
+    }
+}
+
+

mercurial