--- a/src/euclidean.rs Mon Sep 01 00:04:22 2025 -0500 +++ b/src/euclidean.rs Mon Sep 01 13:51:03 2025 -0500 @@ -3,13 +3,15 @@ */ use crate::instance::Instance; -use crate::linops::AXPY; +use crate::linops::{VectorSpace, AXPY}; use crate::norms::{HasDual, Reflexive}; use crate::types::*; use std::ops::{Add, AddAssign, Sub, SubAssign}; pub mod wrap; +// TODO: Euclidean & EuclideanMut +// /// Space (type) with Euclidean and vector space structure /// /// The type should implement vector space operations (addition, subtraction, scalar @@ -18,11 +20,11 @@ // TODO: remove F parameter, use AXPY::Field pub trait Euclidean<F: Float = f64>: HasDual<F, DualSpace = Self> - + AXPY<Field = F> + + VectorSpace<Field = F> + Reflexive<F> // TODO: move the following to AXPY - + for<'b> Add<&'b Self, Output = <Self as AXPY>::Owned> - + for<'b> Sub<&'b Self, Output = <Self as AXPY>::Owned> + + for<'b> Add<&'b Self, Output = <Self as VectorSpace>::Owned> + + for<'b> Sub<&'b Self, Output = <Self as VectorSpace>::Owned> + for<'b> AddAssign<&'b Self> + for<'b> SubAssign<&'b Self> { @@ -59,11 +61,20 @@ /// Projection to the 2-ball. #[inline] - fn proj_ball2(mut self, ρ: F) -> Self { - self.proj_ball2_mut(ρ); - self + fn proj_ball2(self, ρ: F) -> Self::Owned { + let r = self.norm2(); + if r > ρ { + self * (ρ / r) + } else { + self.into_owned() + } } +} +// TODO: remove F parameter, use AXPY::Field +pub trait EuclideanMut<F: Float = f64>: + Euclidean<F> + AXPY<Field = F> + for<'b> AddAssign<&'b Self> + for<'b> SubAssign<&'b Self> +{ /// In-place projection to the 2-ball. #[inline] fn proj_ball2_mut(&mut self, ρ: F) { @@ -74,8 +85,13 @@ } } +impl<X, F: Float> EuclideanMut<F> for X where + X: Euclidean<F> + AXPY<Field = F> + for<'b> AddAssign<&'b Self> + for<'b> SubAssign<&'b Self> +{ +} + /// Trait for [`Euclidean`] spaces with dimensions known at compile time. pub trait StaticEuclidean<F: Float = f64>: Euclidean<F> { /// Returns the origin - fn origin() -> <Self as AXPY>::Owned; + fn origin() -> <Self as VectorSpace>::Owned; }