# HG changeset patch # User Tuomo Valkonen # Date 1734897286 18000 # Node ID f7b87d84864d2bbf91921439c936ec5780e39f49 # Parent d8305c9b6fdfe68335390b181e708b27d83fb873 Extra reflexivity and hilbert-like requirements for Euclidean. Fuse Dot into Euclidean. diff -r d8305c9b6fdf -r f7b87d84864d src/bisection_tree/aggregator.rs --- a/src/bisection_tree/aggregator.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/bisection_tree/aggregator.rs Sun Dec 22 14:54:46 2024 -0500 @@ -4,6 +4,7 @@ use crate::types::*; use crate::sets::Set; +use crate::instance::Instance; /// Trait for aggregating information about a branch of a [bisection tree][super::BT]. /// @@ -136,10 +137,11 @@ } impl Set for Bounds { - fn contains(&self, item : &F) -> bool { + fn contains>(&self, item : I) -> bool { + let v = item.own(); let &Bounds(l, u) = self; debug_assert!(l <= u); - l <= *item && *item <= u + l <= v && v <= u } } diff -r d8305c9b6fdf -r f7b87d84864d src/bisection_tree/btfn.rs --- a/src/bisection_tree/btfn.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/bisection_tree/btfn.rs Sun Dec 22 14:54:46 2024 -0500 @@ -505,7 +505,7 @@ /// /// `U` is the domain, generally [`Loc`]``, and `F` the type of floating point numbers. /// `Self` is generally a set of `U`, for example, [`Cube`]``. -pub trait P2Minimise : Set { +pub trait P2Minimise : Set { /// Minimise `g` over the set presented by `Self`. /// /// The function returns `(x, v)` where `x` is the minimiser `v` an approximation of `g(x)`. diff -r d8305c9b6fdf -r f7b87d84864d src/direct_product.rs --- a/src/direct_product.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/direct_product.rs Sun Dec 22 14:54:46 2024 -0500 @@ -10,7 +10,7 @@ use serde::{Serialize, Deserialize}; use crate::types::{Num, Float}; use crate::{maybe_lifetime, maybe_ref}; -use crate::euclidean::{Dot, Euclidean}; +use crate::euclidean::Euclidean; use crate::instance::{Instance, InstanceMut, Decomposition, DecompositionMut, MyCow}; use crate::mapping::Space; use crate::linops::AXPY; @@ -237,18 +237,6 @@ impl_pair_vectorspace_ops!((f32, f32), f32); impl_pair_vectorspace_ops!((f64, f64), f64); -impl Dot, F> for Pair -where - A : Dot, - B : Dot, - F : Num -{ - - fn dot(&self, Pair(ref u, ref v) : &Pair) -> F { - self.0.dot(u) + self.1.dot(v) - } -} - type PairOutput = Pair<>::Output, >::Output>; impl Euclidean for Pair @@ -257,7 +245,7 @@ B : Euclidean, F : Float, PairOutput : Euclidean, - Self : Sized + Dot + Self : Sized + Mul> + MulAssign + Div> + DivAssign + Add> @@ -270,6 +258,15 @@ { type Output = PairOutput; + fn dot>(&self, other : I) -> F { + let Pair(u, v) = other.decompose(); + self.0.dot(u) + self.1.dot(v) + } + + fn norm2_squared(&self) -> F { + self.0.norm2_squared() + self.1.norm2_squared() + } + fn dist2_squared(&self, Pair(ref u, ref v) : &Self) -> F { self.0.dist2_squared(u) + self.1.dist2_squared(v) } diff -r d8305c9b6fdf -r f7b87d84864d src/euclidean.rs --- a/src/euclidean.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/euclidean.rs Sun Dec 22 14:54:46 2024 -0500 @@ -4,38 +4,35 @@ use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; use crate::types::*; -use crate::mapping::Space; - -/// Space (type) with a defined dot product. -/// -/// `U` is the space of the multiplier, and `F` the space of scalars. -/// Since `U` ≠ `Self`, this trait can also implement dual products. -pub trait Dot { - fn dot(&self, other : &U) -> F; -} +use crate::instance::Instance; +use crate::norms::{HasDual, Reflexive}; /// 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 the [`Dot`] product with respect to `Self`. -pub trait Euclidean : Space + Dot - + 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> { +/// 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> +{ type Output : Euclidean; + // Inner product + fn dot>(&self, other : I) -> F; + /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. - #[inline] - fn norm2_squared(&self) -> F { - self.dot(self) - } + /// + /// This is not automatically implemented to avoid imposing + /// `for <'a> &'a Self : Instance` trait bound bloat. + fn norm2_squared(&self) -> F; /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$, /// where `self` is $x$. diff -r d8305c9b6fdf -r f7b87d84864d src/fe_model/p2_local_model.rs --- a/src/fe_model/p2_local_model.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/fe_model/p2_local_model.rs Sun Dec 22 14:54:46 2024 -0500 @@ -6,7 +6,8 @@ use crate::loc::Loc; use crate::sets::{Set,NPolygon,SpannedHalfspace}; use crate::linsolve::*; -use crate::euclidean::Dot; +use crate::euclidean::Euclidean; +use crate::instance::Instance; use super::base::{LocalModel,RealLocalModel}; use crate::sets::Cube; use numeric_literals::replace_float_literals; @@ -30,7 +31,8 @@ impl<'a, F : Float> Set> for RealInterval { #[inline] - fn contains(&self, &Loc([x]) : &Loc) -> bool { + fn contains>>(&self, z : I) -> bool { + let &Loc([x]) = z.ref_instance(); let &[Loc([x0]), Loc([x1])] = &self.0; (x0 < x && x < x1) || (x1 < x && x < x0) } @@ -38,11 +40,11 @@ impl<'a, F : Float> Set> for PlanarSimplex { #[inline] - fn contains(&self, x : &Loc) -> bool { + fn contains>>(&self, z : I) -> bool { let &[x0, x1, x2] = &self.0; NPolygon([[x0, x1].spanned_halfspace(), [x1, x2].spanned_halfspace(), - [x2, x0].spanned_halfspace()]).contains(x) + [x2, x0].spanned_halfspace()]).contains(z) } } diff -r d8305c9b6fdf -r f7b87d84864d src/loc.rs --- a/src/loc.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/loc.rs Sun Dec 22 14:54:46 2024 -0500 @@ -429,19 +429,17 @@ domination!(Linfinity, L2); domination!(L2, L1); -impl Dot,F> for Loc { +impl Euclidean for Loc { + type Output = Self; + /// This implementation is not stabilised as it's meant to be used for very small vectors. /// Use [`nalgebra`] for larger vectors. #[inline] - fn dot(&self, other : &Loc) -> F { + fn dot>(&self, other : I) -> F { self.0.iter() - .zip(other.0.iter()) + .zip(other.ref_instance().0.iter()) .fold(F::ZERO, |m, (&v, &w)| m + v * w) } -} - -impl Euclidean for Loc { - type Output = Self; /// This implementation is not stabilised as it's meant to be used for very small vectors. /// Use [`nalgebra`] for larger vectors. @@ -696,7 +694,7 @@ type Decomp = BasicDecomposition; } -impl Mapping> for Loc { +impl Mapping> for Loc { type Codomain = F; fn apply>>(&self, x : I) -> Self::Codomain { @@ -704,9 +702,9 @@ } } -impl Linear> for Loc { } +impl Linear> for Loc { } -impl AXPY> for Loc { +impl AXPY> for Loc { type Owned = Self; #[inline] diff -r d8305c9b6fdf -r f7b87d84864d src/nalgebra_support.rs --- a/src/nalgebra_support.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/nalgebra_support.rs Sun Dec 22 14:54:46 2024 -0500 @@ -1,7 +1,7 @@ /*! Integration with nalgebra. -This module mainly implements [`Euclidean`], [`Norm`], [`Dot`], [`Linear`], etc. for [`nalgebra`] +This module mainly implements [`Euclidean`], [`Norm`], [`Linear`], etc. for [`nalgebra`] matrices and vectors. It also provides [`ToNalgebraRealField`] as a vomit-inducingly ugly workaround to nalgebra force-feeding its own versions of the same basic mathematical methods on `f32` and `f64` as @@ -153,20 +153,6 @@ } } -impl Dot,E> -for Vector -where M : Dim, - E : Float + Scalar + Zero + One, - S : Storage, - Si : Storage, - DefaultAllocator : Allocator { - - #[inline] - fn dot(&self, other : &Vector) -> E { - Vector::::dot(self, other) - } -} - /// This function is [`nalgebra::EuclideanNorm::metric_distance`] without the `sqrt`. #[inline] fn metric_distance_squared( @@ -200,7 +186,12 @@ DefaultAllocator : Allocator { type Output = OVector; - + + #[inline] + fn dot>(&self, other : I) -> E { + Vector::::dot(self, other.ref_instance()) + } + #[inline] fn norm2_squared(&self) -> E { Vector::::norm_squared(self) diff -r d8305c9b6fdf -r f7b87d84864d src/norms.rs --- a/src/norms.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/norms.rs Sun Dec 22 14:54:46 2024 -0500 @@ -221,11 +221,16 @@ type DualSpace : Normed; } +/// Automatically implemented trait for reflexive spaces pub trait Reflexive : HasDual where Self::DualSpace : HasDual { } +impl> Reflexive for X +where + X::DualSpace : HasDual +{ } pub trait HasDualExponent : NormExponent { type DualExp : NormExponent; diff -r d8305c9b6fdf -r f7b87d84864d src/sets.rs --- a/src/sets.rs Sat Dec 21 23:32:20 2024 -0500 +++ b/src/sets.rs Sun Dec 22 14:54:46 2024 -0500 @@ -3,19 +3,19 @@ */ use std::ops::{RangeFull,RangeFrom,Range,RangeInclusive,RangeTo,RangeToInclusive}; -use std::marker::PhantomData; use crate::types::*; use crate::loc::Loc; -use crate::euclidean::Dot; +use crate::euclidean::Euclidean; +use crate::instance::{Space, Instance}; use serde::Serialize; pub mod cube; pub use cube::Cube; /// Trait for arbitrary sets. The parameter `U` is the element type. -pub trait Set where U : ?Sized { +pub trait Set where U : Space { /// Check for element containment - fn contains(&self, item : &U) -> bool; + fn contains>(&self, item : I) -> bool; } /// Additional ordering (besides [`PartialOrd`]) of a subfamily of sets: @@ -31,22 +31,27 @@ impl Set> for Cube where U : Num + PartialOrd + Sized { - fn contains(&self, item : &Loc) -> bool { - self.0.iter().zip(item.iter()).all(|(s, x)| s.contains(x)) + fn contains>>(&self, item : I) -> bool { + self.0.iter().zip(item.ref_instance().iter()).all(|(s, x)| s.contains(x)) } } -impl Set for RangeFull { - fn contains(&self, _item : &U) -> bool { true } +impl Set for RangeFull { + fn contains>(&self, _item : I) -> bool { true } } macro_rules! impl_ranges { ($($range:ident),*) => { $( - impl Set - for $range - where Idx : PartialOrd, U : PartialOrd + ?Sized, Idx : PartialOrd { + impl Set for $range + where + Idx : PartialOrd, + U : PartialOrd + Space, + Idx : PartialOrd + { #[inline] - fn contains(&self, item : &U) -> bool { $range::contains(&self, item) } + fn contains>(&self, item : I) -> bool { + item.eval(|x| $range::contains(&self, x)) + } } )* } } @@ -61,40 +66,39 @@ /// `U` is the element type, `F` the floating point number type, and `A` the type of the /// orthogonal (dual) vectors. They need implement [`Dot`]. #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct Halfspace where A : Dot, F : Float { +pub struct Halfspace where A : Euclidean, F : Float { pub orthogonal : A, pub offset : F, - _phantom : PhantomData, } -impl Halfspace where A : Dot, F : Float { +impl Halfspace where A : Euclidean, F : Float { #[inline] pub fn new(orthogonal : A, offset : F) -> Self { - Halfspace{ orthogonal : orthogonal, offset : offset, _phantom : PhantomData } + Halfspace{ orthogonal : orthogonal, offset : offset } } } /// Trait for generating a halfspace spanned by another set `Self` of elements of type `U`. -pub trait SpannedHalfspace where F : Float { +pub trait SpannedHalfspace where F : Float { /// Type of the orthogonal vector describing the halfspace. - type A : Dot; + type A : Euclidean; /// Returns the halfspace spanned by this set. - fn spanned_halfspace(&self) -> Halfspace; + fn spanned_halfspace(&self) -> Halfspace; } // TODO: Gram-Schmidt for higher N. -impl SpannedHalfspace> for [Loc; 2] { +impl SpannedHalfspace for [Loc; 2] { type A = Loc; - fn spanned_halfspace(&self) -> Halfspace> { + fn spanned_halfspace(&self) -> Halfspace { let (x0, x1) = (self[0], self[1]); Halfspace::new(x1-x0, x0[0]) } } // TODO: Gram-Schmidt for higher N. -impl SpannedHalfspace> for [Loc; 2] { +impl SpannedHalfspace for [Loc; 2] { type A = Loc; - fn spanned_halfspace(&self) -> Halfspace> { + fn spanned_halfspace(&self) -> Halfspace { let (x0, x1) = (&self[0], &self[1]); let d = x1 - x0; let orthog = loc![d[1], -d[0]]; // We don't normalise for efficiency @@ -103,19 +107,29 @@ } } -impl Set for Halfspace where A : Dot, F : Float { +impl Set for Halfspace +where + A : Euclidean, + F : Float, +{ #[inline] - fn contains(&self, item : &U) -> bool { + fn contains>(&self, item : I) -> bool { self.orthogonal.dot(item) >= self.offset } } /// Polygons defined by `N` `Halfspace`s. #[derive(Clone,Copy,Debug,Eq,PartialEq)] -pub struct NPolygon(pub [Halfspace; N]) where A : Dot, F : Float; +pub struct NPolygon(pub [Halfspace; N]) +where A : Euclidean, F : Float; -impl Set for NPolygon where A : Dot, F : Float { - fn contains(&self, item : &U) -> bool { - self.0.iter().all(|halfspace| halfspace.contains(item)) +impl Set for NPolygon +where + A : Euclidean, + F : Float, +{ + fn contains>(&self, item : I) -> bool { + let r = item.ref_instance(); + self.0.iter().all(|halfspace| halfspace.contains(r)) } }