diff -r 1f19c6bbf07b -r 3868555d135c src/euclidean.rs --- a/src/euclidean.rs Sun Apr 27 20:29:43 2025 -0500 +++ b/src/euclidean.rs Fri May 15 14:46:30 2026 -0500 @@ -2,31 +2,30 @@ Euclidean spaces. */ -use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; +use crate::instance::Instance; +use crate::linops::{VectorSpace, AXPY}; +use crate::norms::{HasDual, Norm, Normed, Reflexive, L2}; use crate::types::*; -use crate::instance::Instance; -use crate::norms::{HasDual, Reflexive}; + +pub mod wrap; +// TODO: Euclidean & EuclideanMut +// /// Space (type) with Euclidean and vector space structure /// /// The type should implement vector space operations (addition, subtraction, scalar /// multiplication and scalar division) along with their assignment versions, as well /// as an inner product. -pub trait Euclidean : HasDual + Reflexive - + Mul>::Output> + MulAssign - + Div>::Output> + DivAssign - + Add>::Output> - + Sub>::Output> - + for<'b> Add<&'b Self, Output=>::Output> - + for<'b> Sub<&'b Self, Output=>::Output> - + AddAssign + for<'b> AddAssign<&'b Self> - + SubAssign + for<'b> SubAssign<&'b Self> - + Neg>::Output> +// TODO: remove F parameter, use VectorSpace::Field +pub trait Euclidean: + VectorSpace + Reflexive { - type Output : Euclidean; + /// Principal form of the space; always equal to [`crate::linops::Space::Principal`] and + /// [`VectorSpace::PrincipalV`], but with more traits guaranteed. + type PrincipalE: ClosedEuclidean; // Inner product - fn dot>(&self, other : I) -> F; + fn dot>(&self, other: I) -> F; /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. /// @@ -38,7 +37,7 @@ /// where `self` is $x$. #[inline] fn norm2_squared_div2(&self) -> F { - self.norm2_squared()/F::TWO + self.norm2_squared() / F::TWO } /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$. @@ -48,33 +47,119 @@ } /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$. - fn dist2_squared>(&self, y : I) -> F; + fn dist2_squared>(&self, y: I) -> F; /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$. #[inline] - fn dist2>(&self, y : I) -> F { + fn dist2>(&self, y: I) -> F { self.dist2_squared(y).sqrt() } /// Projection to the 2-ball. #[inline] - fn proj_ball2(mut self, ρ : F) -> Self { - self.proj_ball2_mut(ρ); - self + fn proj_ball2(self, ρ: F) -> Self::PrincipalV { + let r = self.norm2(); + if r > ρ { + self * (ρ / r) + } else { + self.into_owned() + } } +} +pub trait ClosedEuclidean: + Instance + Euclidean +{ +} +impl + Euclidean> ClosedEuclidean for X {} + +// TODO: remove F parameter, use AXPY::Field +pub trait EuclideanMut: Euclidean + AXPY { /// In-place projection to the 2-ball. #[inline] - fn proj_ball2_mut(&mut self, ρ : F) { + fn proj_ball2_mut(&mut self, ρ: F) { let r = self.norm2(); - if r>ρ { - *self *= ρ/r + if r > ρ { + *self *= ρ / r } } } +impl EuclideanMut for X where X: Euclidean + AXPY {} + /// Trait for [`Euclidean`] spaces with dimensions known at compile time. -pub trait StaticEuclidean : Euclidean { +pub trait StaticEuclidean: Euclidean { /// Returns the origin - fn origin() -> >::Output; + fn origin() -> >::PrincipalE; } + +macro_rules! scalar_euclidean { + ($f:ident) => { + impl VectorSpace for $f { + type Field = $f; + type PrincipalV = $f; + + #[inline] + fn similar_origin(&self) -> Self::PrincipalV { + 0.0 + } + } + impl AXPY for $f { + #[inline] + fn axpy>(&mut self, α: $f, x: I, β: $f) { + *self = β * *self + α * x.own() + } + + #[inline] + fn set_zero(&mut self) { + *self = 0.0 + } + } + + impl Norm for $f { + fn norm(&self, _p: L2) -> $f { + self.abs() + } + } + + impl Normed<$f> for $f { + type NormExp = L2; + + fn norm_exponent(&self) -> Self::NormExp { + L2 + } + } + + impl HasDual<$f> for $f { + type DualSpace = $f; + + #[inline] + fn dual_origin(&self) -> $f { + 0.0 + } + } + + impl Euclidean<$f> for $f { + type PrincipalE = $f; + + #[inline] + fn dot>(&self, other: I) -> $f { + *self * other.own() + } + + #[inline] + fn norm2_squared(&self) -> $f { + *self * *self + } + + #[inline] + fn dist2_squared>(&self, y: I) -> $f { + let d = *self - y.own(); + d * d + } + } + }; +} + +scalar_euclidean!(f64); +scalar_euclidean!(f32);