diff -r 2f1798c65fd6 -r c4e394a9c84c src/direct_product.rs --- a/src/direct_product.rs Mon Sep 01 00:04:22 2025 -0500 +++ b/src/direct_product.rs Mon Sep 01 13:51:03 2025 -0500 @@ -6,8 +6,10 @@ */ use crate::euclidean::Euclidean; -use crate::instance::{Decomposition, DecompositionMut, Instance, InstanceMut, MyCow}; -use crate::linops::AXPY; +use crate::instance::{ + ClosedSpace, Decomposition, DecompositionMut, Instance, InstanceMut, MyCow, Ownable, +}; +use crate::linops::{VectorSpace, AXPY}; use crate::loc::Loc; use crate::mapping::Space; use crate::norms::{HasDual, Norm, NormExponent, Normed, PairNorm, L2}; @@ -262,6 +264,25 @@ impl_scalar_mut!(MulAssign, mul_assign); impl_scalar_mut!(DivAssign, div_assign); +/// Trait for ownable-by-consumption objects +impl Ownable for Pair +where + A: Ownable, + B: Ownable, +{ + type OwnedVariant = Pair; + + #[inline] + fn into_owned(self) -> Self::OwnedVariant { + Pair(self.0.into_owned(), self.1.into_owned()) + } + + /// Returns an owned instance of a reference. + fn clone_owned(&self) -> Self::OwnedVariant { + Pair(self.0.clone_owned(), self.1.clone_owned()) + } +} + /// We only support 'closed' `Euclidean` `Pair`s, as more general ones cause /// compiler overflows. impl Euclidean for Pair @@ -270,19 +291,19 @@ B: Euclidean, //Pair: Euclidean, Self: Sized - + Mul::Owned> + + Mul::Owned> + MulAssign - + Div::Owned> + + Div::Owned> + DivAssign - + Add::Owned> - + Sub::Owned> - + for<'b> Add<&'b Self, Output = ::Owned> - + for<'b> Sub<&'b Self, Output = ::Owned> + + Add::Owned> + + Sub::Owned> + + for<'b> Add<&'b Self, Output = ::Owned> + + for<'b> Sub<&'b Self, Output = ::Owned> + AddAssign + for<'b> AddAssign<&'b Self> + SubAssign + for<'b> SubAssign<&'b Self> - + Neg::Owned>, + + Neg::Owned>, { fn dot>(&self, other: I) -> F { other.eval_decompose(|Pair(u, v)| self.0.dot(u) + self.1.dot(v)) @@ -297,6 +318,28 @@ } } +impl VectorSpace for Pair +where + A: VectorSpace, + B: VectorSpace, + O: ClosedSpace + AXPY, + P: ClosedSpace + AXPY, + F: Num, +{ + type Field = F; + type Owned = Pair; + + /// Return a similar zero as `self`. + fn similar_origin(&self) -> Self::Owned { + Pair(self.0.similar_origin(), self.1.similar_origin()) + } + + // #[inline] + // fn into_owned(self) -> Self::Owned { + // Pair(self.0.into_owned(), self.1.into_owned()) + // } +} + impl AXPY> for Pair where U: Space, @@ -306,13 +349,7 @@ F: Num, Self: MulAssign + DivAssign, Pair: MulAssign + DivAssign, - //A::Owned: MulAssign, - //B::Owned: MulAssign, - //Pair: AXPY, Field = F>, { - type Field = F; - type Owned = Pair; - fn axpy>>(&mut self, α: F, x: I, β: F) { x.eval_decompose(|Pair(u, v)| { self.0.axpy(α, u, β); @@ -334,11 +371,6 @@ }) } - /// Return a similar zero as `self`. - fn similar_origin(&self) -> Self::Owned { - Pair(self.0.similar_origin(), self.1.similar_origin()) - } - /// Set self to zero. fn set_zero(&mut self) { self.0.set_zero(); @@ -562,7 +594,7 @@ { type DualSpace = Pair; - fn dual_origin(&self) -> ::Owned { + fn dual_origin(&self) -> ::Owned { Pair(self.0.dual_origin(), self.1.dual_origin()) } }