# HG changeset patch # User Tuomo Valkonen # Date 1735654363 18000 # Node ID d2acaaddd9af19198a530d09ebd4116588f91122 # Parent edb95d2b83ccb541d736e1742643068c95ef32f7 Try to have Field as member type in Mappings etc. diff -r edb95d2b83cc -r d2acaaddd9af src/bisection_tree/bt.rs --- a/src/bisection_tree/bt.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/bisection_tree/bt.rs Tue Dec 31 09:12:43 2024 -0500 @@ -243,10 +243,11 @@ /// Creates a new node branching structure, subdividing `domain` based on the /// [hint][Support::support_hint] of `support`. - pub(super) fn new_with>( + pub(super) fn new_with( domain : &Cube, support : &S - ) -> Self { + ) -> Self + where S : Support + LocalAnalysis> { let hint = support.bisection_hint(domain); let branch_at = map2(&hint, domain, |h, r| { h.unwrap_or_else(|| (r[0]+r[1])/F::TWO).max(r[0]).min(r[1]) @@ -321,14 +322,15 @@ /// * `support` is the [`Support`] that is used determine with which subcubes of `domain` /// (at subdivision depth `new_leaf_depth`) the data `d` is to be associated with. /// - pub(super) fn insert<'refs, 'scope, M : Depth, S : LocalAnalysis>( + pub(super) fn insert<'refs, 'scope, M : Depth, S>( &mut self, domain : &Cube, d : D, new_leaf_depth : M, support : &S, task_budget : TaskBudget<'scope, 'refs>, - ) { + ) + where S : Support + LocalAnalysis> { let support_hint = support.support_hint(); self.recurse(domain, task_budget, |_, subcube| support_hint.intersects(&subcube), @@ -348,8 +350,8 @@ domain : &Cube ) -> Branches where ANew : Aggregator, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { let branch_at = self.branch_at; let subcube_iter = self.iter_subcubes(domain); let new_nodes = self.nodes.into_iter().zip(subcube_iter).map(|(node, subcube)| { @@ -370,8 +372,8 @@ generator : &G, domain : &Cube, task_budget : TaskBudget<'scope, 'refs>, - ) where G : SupportGenerator, - G::SupportType : LocalAnalysis { + ) where G : SupportGenerator, + G::SupportType : LocalAnalysis> { self.recurse(domain, task_budget, |_, _| true, move |node, subcube, new_budget| node.refresh_aggregator(generator, subcube, @@ -434,14 +436,15 @@ /// If `self` is a [`NodeOption::Branches`], the data is passed to branches whose subcubes /// `support` intersects. If an [`NodeOption::Uninitialised`] node is encountered, a new leaf is /// created at a minimum depth of `new_leaf_depth`. - pub(super) fn insert<'refs, 'scope, M : Depth, S : LocalAnalysis >( + pub(super) fn insert<'refs, 'scope, M : Depth, S>( &mut self, domain : &Cube, d : D, new_leaf_depth : M, support : &S, task_budget : TaskBudget<'scope, 'refs>, - ) { + ) + where S : Support + LocalAnalysis> { match &mut self.data { NodeOption::Uninitialised => { // Replace uninitialised node with a leaf or a branch @@ -493,8 +496,8 @@ domain : &Cube ) -> Node where ANew : Aggregator, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { // The mem::replace is needed due to the [`Drop`] implementation to extract self.data. match std::mem::replace(&mut self.data, NodeOption::Uninitialised) { @@ -537,8 +540,8 @@ generator : &G, domain : &Cube, task_budget : TaskBudget<'scope, 'refs>, - ) where G : SupportGenerator, - G::SupportType : LocalAnalysis { + ) where G : SupportGenerator, + G::SupportType : LocalAnalysis> { match &mut self.data { NodeOption::Uninitialised => { }, NodeOption::Leaf(v) => { @@ -580,7 +583,7 @@ /// Basic interface to a [`BT`] bisection tree. /// /// Further routines are provided by the [`BTSearch`][super::refine::BTSearch] trait. -pub trait BTImpl : std::fmt::Debug + Clone + GlobalAnalysis { +pub trait BTImpl : std::fmt::Debug + Clone + GlobalAnalysis { /// The data type stored in the tree type Data : 'static + Copy + Send + Sync; /// The depth type of the tree @@ -595,11 +598,12 @@ /// /// Every leaf node of the tree that intersects the `support` will contain a copy of /// `d`. - fn insert>( + fn insert( &mut self, d : Self::Data, support : &S - ); + ) + where S: Support + LocalAnalysis>; /// Construct a new instance of the tree for a different aggregator /// @@ -608,8 +612,8 @@ fn convert_aggregator(self, generator : &G) -> Self::Converted where ANew : Aggregator, - G : SupportGenerator, - G::SupportType : LocalAnalysis; + G : SupportGenerator< N, Id=Self::Data, RealField = F>, + G::SupportType : LocalAnalysis>; /// Refreshes the aggregator of the three after possible changes to the support generator. @@ -617,8 +621,8 @@ /// The `generator` is used to convert the data of type [`Self::Data`] contained in the tree /// into corresponding [`Support`]s. fn refresh_aggregator(&mut self, generator : &G) - where G : SupportGenerator, - G::SupportType : LocalAnalysis; + where G : SupportGenerator, + G::SupportType : LocalAnalysis>; /// Returns an iterator over all [`Self::Data`] items at the point `x` of the domain. fn iter_at(&self, x : &Loc) -> std::slice::Iter<'_, Self::Data>; @@ -672,11 +676,12 @@ type Agg = A; type Converted = BT where ANew : Aggregator; - fn insert>( + fn insert( &mut self, d : D, support : &S - ) { + ) + where S : Support<$n, RealField = F> + LocalAnalysis> { with_task_budget(|task_budget| self.topnode.insert( &self.domain, @@ -690,8 +695,8 @@ fn convert_aggregator(self, generator : &G) -> Self::Converted where ANew : Aggregator, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator<$n, Id=D, RealField = F>, + G::SupportType : LocalAnalysis> { let topnode = self.topnode.convert_aggregator(generator, &self.domain); BT { @@ -702,8 +707,8 @@ } fn refresh_aggregator(&mut self, generator : &G) - where G : SupportGenerator, - G::SupportType : LocalAnalysis { + where G : SupportGenerator<$n, Id=Self::Data, RealField = F>, + G::SupportType : LocalAnalysis> { with_task_budget(|task_budget| self.topnode.refresh_aggregator(generator, &self.domain, task_budget) ) @@ -726,7 +731,7 @@ } } - impl GlobalAnalysis for BT + impl GlobalAnalysis for BT where M : Depth, F : Float, D : 'static + Copy + Send + Sync + std::fmt::Debug, diff -r edb95d2b83cc -r d2acaaddd9af src/bisection_tree/btfn.rs --- a/src/bisection_tree/btfn.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/bisection_tree/btfn.rs Tue Dec 31 09:12:43 2024 -0500 @@ -1,9 +1,8 @@ use numeric_literals::replace_float_literals; use std::iter::Sum; -use std::marker::PhantomData; use std::sync::Arc; -use crate::types::Float; +use crate::types::{Float, HasScalarField, HasRealField}; use crate::mapping::{Apply, Mapping, Differentiable}; //use crate::linops::{Apply, Linear}; use crate::sets::Set; @@ -29,21 +28,23 @@ /// for a [`PreBTFN`] that is only useful for vector space operations with a full [`BTFN`]. #[derive(Clone,Debug)] pub struct BTFN< - F : Float, - G : SupportGenerator, + G : SupportGenerator, BT /*: BTImpl*/, const N : usize -> /*where G::SupportType : LocalAnalysis*/ { +> { bt : BT, generator : Arc, - _phantoms : PhantomData, +} + +impl, BT, const N : usize> HasScalarField for BTFN { + type Field = G::Field; } impl -BTFN -where G : SupportGenerator, - G::SupportType : LocalAnalysis, - BT : BTImpl { +BTFN +where G : SupportGenerator, + G::SupportType : LocalAnalysis>, + BT : BTImpl { /// Create a new BTFN from a support generator and a pre-initialised bisection tree. /// @@ -60,7 +61,6 @@ BTFN { bt : bt, generator : generator, - _phantoms : std::marker::PhantomData, } } @@ -85,11 +85,11 @@ /// The top node of the created [`BT`] will have the given `domain`. /// /// See the documentation for [`BTFN`] on the role of the `generator`. - pub fn construct(domain : Cube, depth : BT::Depth, generator : G) -> Self { + pub fn construct(domain : Cube, depth : BT::Depth, generator : G) -> Self { Self::construct_arc(domain, depth, Arc::new(generator)) } - fn construct_arc(domain : Cube, depth : BT::Depth, generator : Arc) -> Self { + fn construct_arc(domain : Cube, depth : BT::Depth, generator : Arc) -> Self { let mut bt = BT::new(domain, depth); for (d, support) in generator.all_data() { bt.insert(d, &support); @@ -101,10 +101,10 @@ /// /// This will construct a [`BTFN`] with the same components and generator as the (consumed) /// `self`, but a new `BT` with [`Aggregator`]s of type `ANew`. - pub fn convert_aggregator(self) -> BTFN, N> + pub fn convert_aggregator(self) -> BTFN, N> where ANew : Aggregator, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { BTFN::new_arc(self.bt.convert_aggregator(&*self.generator), self.generator) } @@ -121,16 +121,16 @@ } impl -BTFN -where G : SupportGenerator { +BTFN +where G : SupportGenerator { /// Change the [bisection tree][BTImpl] of the [`BTFN`] to a different one. /// /// This can be used to convert a [`PreBTFN`] to a full [`BTFN`], or the change /// the aggreagator; see also [`self.convert_aggregator`]. pub fn instantiate< BTNew : BTImpl, - > (self, domain : Cube, depth : BTNew::Depth) -> BTFN - where G::SupportType : LocalAnalysis { + > (self, domain : Cube, depth : BTNew::Depth) -> BTFN + where G::SupportType : LocalAnalysis> { BTFN::construct_arc(domain, depth, self.generator) } } @@ -140,30 +140,29 @@ /// Most BTFN methods are not available, but if a BTFN is going to be summed with another /// before other use, it will be more efficient to not construct an unnecessary bisection tree /// that would be shortly dropped. -pub type PreBTFN = BTFN; +pub type PreBTFN = BTFN; -impl PreBTFN where G : SupportGenerator { +impl PreBTFN where G : SupportGenerator { /// Create a new [`PreBTFN`] with no bisection tree. pub fn new_pre(generator : G) -> Self { BTFN { bt : (), generator : Arc::new(generator), - _phantoms : std::marker::PhantomData, } } } impl -BTFN -where G : SupportGenerator, - G::SupportType : LocalAnalysis, +BTFN +where G : SupportGenerator, + G::SupportType : LocalAnalysis>, BT : BTImpl { /// Helper function for implementing [`std::ops::Add`]. - fn add_another(&self, g2 : Arc) -> BTFN, BT, N> - where G2 : SupportGenerator, - G2::SupportType : LocalAnalysis { + fn add_another(&self, g2 : Arc) -> BTFN, BT, N> + where G2 : SupportGenerator, + G2::SupportType : LocalAnalysis> { let mut bt = self.bt.clone(); let both = BothGenerators(Arc::clone(&self.generator), g2); @@ -175,7 +174,6 @@ BTFN { bt : bt, generator : Arc::new(both), - _phantoms : std::marker::PhantomData, } } } @@ -183,54 +181,54 @@ macro_rules! make_btfn_add { ($lhs:ty, $preprocess:path, $($extra_trait:ident)?) => { impl<'a, F : Float, G1, G2, BT1, BT2, const N : usize> - std::ops::Add> for + std::ops::Add> for $lhs where BT1 : BTImpl, - G1 : SupportGenerator + $($extra_trait)?, - G2 : SupportGenerator, - G1::SupportType : LocalAnalysis, - G2::SupportType : LocalAnalysis { - type Output = BTFN, BT1, N>; + G1 : SupportGenerator + $($extra_trait)?, + G2 : SupportGenerator, + G1::SupportType : LocalAnalysis>, + G2::SupportType : LocalAnalysis> { + type Output = BTFN, BT1, N>; #[inline] - fn add(self, other : BTFN) -> Self::Output { + fn add(self, other : BTFN) -> Self::Output { $preprocess(self).add_another(other.generator) } } impl<'a, 'b, F : Float, G1, G2, BT1, BT2, const N : usize> - std::ops::Add<&'b BTFN> for + std::ops::Add<&'b BTFN> for $lhs where BT1 : BTImpl, - G1 : SupportGenerator + $($extra_trait)?, - G2 : SupportGenerator, - G1::SupportType : LocalAnalysis, - G2::SupportType : LocalAnalysis { + G1 : SupportGenerator + $($extra_trait)?, + G2 : SupportGenerator, + G1::SupportType : LocalAnalysis>, + G2::SupportType : LocalAnalysis> { - type Output = BTFN, BT1, N>; + type Output = BTFN, BT1, N>; #[inline] - fn add(self, other : &'b BTFN) -> Self::Output { + fn add(self, other : &'b BTFN) -> Self::Output { $preprocess(self).add_another(other.generator.clone()) } } } } -make_btfn_add!(BTFN, std::convert::identity, ); -make_btfn_add!(&'a BTFN, Clone::clone, ); +make_btfn_add!(BTFN, std::convert::identity, ); +make_btfn_add!(&'a BTFN, Clone::clone, ); macro_rules! make_btfn_sub { ($lhs:ty, $preprocess:path, $($extra_trait:ident)?) => { impl<'a, F : Float, G1, G2, BT1, BT2, const N : usize> - std::ops::Sub> for + std::ops::Sub> for $lhs where BT1 : BTImpl, - G1 : SupportGenerator + $($extra_trait)?, - G2 : SupportGenerator, - G1::SupportType : LocalAnalysis, - G2::SupportType : LocalAnalysis { - type Output = BTFN, BT1, N>; + G1 : SupportGenerator + $($extra_trait)?, + G2 : SupportGenerator, + G1::SupportType : LocalAnalysis>, + G2::SupportType : LocalAnalysis> { + type Output = BTFN, BT1, N>; #[inline] - fn sub(self, other : BTFN) -> Self::Output { + fn sub(self, other : BTFN) -> Self::Output { $preprocess(self).add_another(Arc::new( Arc::try_unwrap(other.generator) .unwrap_or_else(|arc| (*arc).clone()) @@ -240,35 +238,35 @@ } impl<'a, 'b, F : Float, G1, G2, BT1, BT2, const N : usize> - std::ops::Sub<&'b BTFN> for + std::ops::Sub<&'b BTFN> for $lhs where BT1 : BTImpl, - G1 : SupportGenerator + $($extra_trait)?, - G2 : SupportGenerator + Clone, - G1::SupportType : LocalAnalysis, - G2::SupportType : LocalAnalysis, + G1 : SupportGenerator + $($extra_trait)?, + G2 : SupportGenerator + Clone, + G1::SupportType : LocalAnalysis>, + G2::SupportType : LocalAnalysis>, &'b G2 : std::ops::Neg { - type Output = BTFN, BT1, N>; + type Output = BTFN, BT1, N>; #[inline] - fn sub(self, other : &'b BTFN) -> Self::Output { + fn sub(self, other : &'b BTFN) -> Self::Output { $preprocess(self).add_another(Arc::new((*other.generator).clone().neg())) } } } } -make_btfn_sub!(BTFN, std::convert::identity, ); -make_btfn_sub!(&'a BTFN, std::convert::identity, ); +make_btfn_sub!(BTFN, std::convert::identity, ); +make_btfn_sub!(&'a BTFN, std::convert::identity, ); macro_rules! make_btfn_scalarop_rhs { ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { impl std::ops::$trait_assign - for BTFN + for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { #[inline] fn $fn_assign(&mut self, t : F) { Arc::make_mut(&mut self.generator).$fn_assign(t); @@ -278,10 +276,10 @@ impl std::ops::$trait - for BTFN + for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { type Output = Self; #[inline] fn $fn(mut self, t : F) -> Self::Output { @@ -293,12 +291,12 @@ impl<'a, F : Float, G, BT, const N : usize> std::ops::$trait - for &'a BTFN + for &'a BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis, + G : SupportGenerator, + G::SupportType : LocalAnalysis>, &'a G : std::ops::$trait { - type Output = BTFN; + type Output = BTFN; #[inline] fn $fn(self, t : F) -> Self::Output { self.new_generator(self.generator.$fn(t)) @@ -313,14 +311,14 @@ macro_rules! make_btfn_scalarop_lhs { ($trait:ident, $fn:ident, $fn_assign:ident, $($f:ident)+) => { $( impl - std::ops::$trait> + std::ops::$trait> for $f where BT : BTImpl<$f, N>, - G : SupportGenerator<$f, N, Id=BT::Data>, - G::SupportType : LocalAnalysis<$f, BT::Agg, N> { - type Output = BTFN<$f, G, BT, N>; + G : SupportGenerator, + G::SupportType : LocalAnalysis> { + type Output = BTFN; #[inline] - fn $fn(self, mut a : BTFN<$f, G, BT, N>) -> Self::Output { + fn $fn(self, mut a : BTFN) -> Self::Output { Arc::make_mut(&mut a.generator).$fn_assign(self); a.refresh_aggregator(); a @@ -328,16 +326,16 @@ } impl<'a, G, BT, const N : usize> - std::ops::$trait<&'a BTFN<$f, G, BT, N>> + std::ops::$trait<&'a BTFN> for $f where BT : BTImpl<$f, N>, - G : SupportGenerator<$f, N, Id=BT::Data> + Clone, - G::SupportType : LocalAnalysis<$f, BT::Agg, N>, + G : SupportGenerator + Clone, + G::SupportType : LocalAnalysis>, // FIXME: This causes compiler overflow /*&'a G : std::ops::$trait<$f,Output=G>*/ { - type Output = BTFN<$f, G, BT, N>; + type Output = BTFN; #[inline] - fn $fn(self, a : &'a BTFN<$f, G, BT, N>) -> Self::Output { + fn $fn(self, a : &'a BTFN) -> Self::Output { let mut tmp = (*a.generator).clone(); tmp.$fn_assign(self); a.new_generator(tmp) @@ -355,10 +353,10 @@ ($trait:ident, $fn:ident) => { impl std::ops::$trait - for BTFN + for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { type Output = Self; #[inline] fn $fn(mut self) -> Self::Output { @@ -391,10 +389,11 @@ // impl<'a, F : Float, G, BT, V, const N : usize> Apply<&'a Loc> -for BTFN +for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis + Apply<&'a Loc, Output = V>, + G : SupportGenerator, + G::SupportType : LocalAnalysis> + + Apply<&'a Loc, Output = V>, V : Sum { type Output = V; @@ -406,10 +405,11 @@ } impl Apply> -for BTFN +for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis + Apply, Output = V>, + G : SupportGenerator, + G::SupportType : LocalAnalysis> + + Apply, Output = V>, V : Sum { type Output = V; @@ -420,11 +420,13 @@ } } -impl<'a, F : Float, G, BT, V, const N : usize> Differentiable<&'a Loc> -for BTFN +impl<'a, F : Float, G, BT, V : HasRealField, const N : usize> +Differentiable<&'a Loc> +for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis + Differentiable<&'a Loc, Derivative = V>, + G : SupportGenerator, + G::SupportType : LocalAnalysis> + + Differentiable<&'a Loc, Derivative = V>, V : Sum { type Derivative = V; @@ -437,11 +439,12 @@ } impl Differentiable> -for BTFN +for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis + Differentiable, Derivative = V>, - V : Sum { + G : SupportGenerator, + G::SupportType : LocalAnalysis> + + Differentiable, Derivative = V>, + V : Sum + HasRealField { type Derivative = V; @@ -456,11 +459,11 @@ // GlobalAnalysis // -impl GlobalAnalysis -for BTFN +impl GlobalAnalysis +for BTFN where BT : BTImpl, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + G : SupportGenerator, + G::SupportType : LocalAnalysis> { #[inline] fn global_analysis(&self) -> BT::Agg { @@ -617,12 +620,12 @@ how : T, } -impl Refiner, G, N> +impl Refiner, G, N> for P2Refiner where Cube : P2Minimise, F>, - G : SupportGenerator, + G : SupportGenerator, G::SupportType : Mapping, Codomain=F> - + LocalAnalysis, N> { + + LocalAnalysis, Cube> { type Result = Option<(Loc, F)>; type Sorting = UpperBoundSorting; @@ -674,12 +677,12 @@ } -impl Refiner, G, N> +impl Refiner, G, N> for P2Refiner where Cube : P2Minimise, F>, - G : SupportGenerator, + G : SupportGenerator, G::SupportType : Mapping, Codomain=F> - + LocalAnalysis, N> { + + LocalAnalysis, Cube> { type Result = Option<(Loc, F)>; type Sorting = LowerBoundSorting; @@ -754,9 +757,9 @@ how : T, } -impl Refiner, G, N> +impl Refiner, G, N> for BoundRefiner -where G : SupportGenerator { +where G : SupportGenerator { type Result = bool; type Sorting = UpperBoundSorting; @@ -788,9 +791,9 @@ } } -impl Refiner, G, N> +impl Refiner, G, N> for BoundRefiner -where G : SupportGenerator { +where G : SupportGenerator { type Result = bool; type Sorting = UpperBoundSorting; @@ -837,11 +840,11 @@ // there should be a result, or new nodes above the `glb` inserted into the queue. Then the waiting // threads can also continue processing. If, however, numerical inaccuracy destroyes the `glb`, // the queue may run out, and we get “Refiner failure”. -impl BTFN +impl BTFN where BT : BTSearch>, - G : SupportGenerator, + G : SupportGenerator, G::SupportType : Mapping,Codomain=F> - + LocalAnalysis, N>, + + LocalAnalysis, Cube>, Cube : P2Minimise, F> { /// Maximise the `BTFN` within stated value `tolerance`. diff -r edb95d2b83cc -r d2acaaddd9af src/bisection_tree/either.rs --- a/src/bisection_tree/either.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/bisection_tree/either.rs Tue Dec 31 09:12:43 2024 -0500 @@ -29,12 +29,18 @@ Right(B), } +impl HasScalarField for EitherSupport +where A : HasScalarField, + B : HasScalarField { + type Field = F; +} + // We need type alias bounds to access associate types. #[allow(type_alias_bounds)] type BothAllDataIter< - 'a, F, - G1 : SupportGenerator, - G2 : SupportGenerator, + 'a, + G1 : SupportGenerator, + G2 : SupportGenerator, const N : usize > = Chain< MapF, (usize, EitherSupport)>, @@ -46,8 +52,8 @@ #[inline] fn map_left((d, support) : (G1::Id, G1::SupportType)) -> (usize, EitherSupport) - where G1 : SupportGenerator, - G2 : SupportGenerator { + where G1 : SupportGenerator, + G2 : SupportGenerator { let id : usize = d.into(); (id.into(), EitherSupport::Left(support)) @@ -57,8 +63,8 @@ #[inline] fn map_right(n0 : &usize, (d, support) : (G2::Id, G2::SupportType)) -> (usize, EitherSupport) - where G1 : SupportGenerator, - G2 : SupportGenerator { + where G1 : SupportGenerator, + G2 : SupportGenerator { let id : usize = d.into(); ((n0+id).into(), EitherSupport::Right(support)) @@ -70,8 +76,8 @@ #[inline] pub(super) fn all_left_data(&self) -> MapF, (usize, EitherSupport)> - where G1 : SupportGenerator, - G2 : SupportGenerator { + where G1 : SupportGenerator, + G2 : SupportGenerator { self.0.all_data().mapF(Self::map_left) } @@ -81,22 +87,29 @@ #[inline] pub(super) fn all_right_data(&self) -> MapZ, usize, (usize, EitherSupport)> - where G1 : SupportGenerator, - G2 : SupportGenerator { + where G1 : SupportGenerator, + G2 : SupportGenerator { let n0 = self.0.support_count(); self.1.all_data().mapZ(n0, Self::map_right) } } +impl HasScalarField for BothGenerators +where G1 : HasScalarField, + G2 : HasScalarField { + type Field = F; +} + impl -SupportGenerator +SupportGenerator for BothGenerators -where G1 : SupportGenerator, - G2 : SupportGenerator { +where G1 : SupportGenerator + HasRealField, + G2 : SupportGenerator + HasRealField, + Self : HasRealField { type Id = usize; type SupportType = EitherSupport; - type AllDataIter<'a> = BothAllDataIter<'a, F, G1, G2, N> where G1 : 'a, G2 : 'a; + type AllDataIter<'a> = BothAllDataIter<'a, G1, G2, N> where G1 : 'a, G2 : 'a; #[inline] fn support_for(&self, id : Self::Id) @@ -120,9 +133,9 @@ } } -impl Support for EitherSupport -where S1 : Support, - S2 : Support { +impl Support for EitherSupport +where S1 : Support, + S2 : Support { #[inline] fn support_hint(&self) -> Cube { @@ -149,10 +162,11 @@ } } -impl LocalAnalysis for EitherSupport +impl LocalAnalysis> +for EitherSupport where A : Aggregator, - S1 : LocalAnalysis, - S2 : LocalAnalysis, { + S1 : LocalAnalysis>, + S2 : LocalAnalysis> { #[inline] fn local_analysis(&self, cube : &Cube) -> A { @@ -163,10 +177,10 @@ } } -impl GlobalAnalysis for EitherSupport +impl GlobalAnalysis for EitherSupport where A : Aggregator, - S1 : GlobalAnalysis, - S2 : GlobalAnalysis, { + S1 : GlobalAnalysis, + S2 : GlobalAnalysis, { #[inline] fn global_analysis(&self) -> A { @@ -190,9 +204,9 @@ } } -impl Differentiable for EitherSupport -where S1 : Differentiable, - S2 : Differentiable { +impl Differentiable for EitherSupport +where S1 : Differentiable, + S2 : Differentiable { type Derivative = F; #[inline] fn differential(&self, x : X) -> F { diff -r edb95d2b83cc -r d2acaaddd9af src/bisection_tree/refine.rs --- a/src/bisection_tree/refine.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/bisection_tree/refine.rs Tue Dec 31 09:12:43 2024 -0500 @@ -92,10 +92,9 @@ /// The `Refiner` is used to determine whether an [`Aggregator`] `A` stored in the [`BT`] is /// sufficiently refined within a [`Cube`], and in such a case, produce a desired result (e.g. /// a maximum value of a function). -pub trait Refiner : Sync + Send + 'static -where F : Num, - A : Aggregator, - G : SupportGenerator { +pub trait Refiner : Sync + Send + 'static +where A : Aggregator, + G : SupportGenerator { /// The result type of the refiner type Result : std::fmt::Debug + Sync + Send + 'static; @@ -125,7 +124,7 @@ fn refine( &self, aggregator : &A, - domain : &Cube, + domain : &Cube, data : &[G::Id], generator : &G, step : usize, @@ -323,9 +322,9 @@ container_arc : &'c Arc>>, step : usize ) -> Result>> - where R : Refiner, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + where R : Refiner, + G : SupportGenerator, + G::SupportType : LocalAnalysis> { //drop(container); @@ -435,9 +434,9 @@ refiner : R, generator : &Arc, ) -> Option - where R : Refiner + Sync + Send + 'static, - G : SupportGenerator + Sync + Send + 'static, - G::SupportType : LocalAnalysis; + where R : Refiner + Sync + Send + 'static, + G : SupportGenerator + Sync + Send + 'static, + G::SupportType : LocalAnalysis>; } fn refinement_loop ( @@ -446,9 +445,9 @@ generator_arc : &Arc, container_arc : &Arc>>, ) where A : Aggregator, - R : Refiner, - G : SupportGenerator, - G::SupportType : LocalAnalysis, + R : Refiner, + G : SupportGenerator, + G::SupportType : LocalAnalysis>, Const

: BranchCount, D : 'static + Copy + Sync + Send + std::fmt::Debug { @@ -565,9 +564,9 @@ refiner : R, generator : &Arc, ) -> Option - where R : Refiner, - G : SupportGenerator, - G::SupportType : LocalAnalysis { + where R : Refiner, + G : SupportGenerator<$n, Id=D, RealField = F>, + G::SupportType : LocalAnalysis> { let mut init_container = HeapContainer { heap : BinaryHeap::new(), glb : R::Sorting::bottom(), diff -r edb95d2b83cc -r d2acaaddd9af src/bisection_tree/support.rs --- a/src/bisection_tree/support.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/bisection_tree/support.rs Tue Dec 31 09:12:43 2024 -0500 @@ -10,18 +10,17 @@ use crate::sets::Cube; use crate::loc::Loc; use super::aggregator::Bounds; -use crate::norms::{Norm, L1, L2, Linfinity}; +use crate::norms::{Norm, L1, L2, Linfinity, HasScalarField, HasRealField}; /// A trait for encoding constant [`Float`] values -pub trait Constant : Copy + Sync + Send + 'static + std::fmt::Debug + Into { - /// The type of the value - type Type : Float; +pub trait Constant : Copy + Sync + Send + 'static + + std::fmt::Debug + HasRealField + + Into { /// Returns the value of the constant - fn value(&self) -> Self::Type; + fn value(&self) -> Self::Field; } impl Constant for F { - type Type = F; #[inline] fn value(&self) -> F { *self } } @@ -30,17 +29,17 @@ /// A trait for working with the supports of [`Apply`]s. /// /// Apply is not a super-trait to allow more general use. -pub trait Support : Sized + Sync + Send + 'static { +pub trait Support : Sized + Sync + Send + 'static + HasRealField { /// Return a cube containing the support of the function represented by `self`. /// /// The hint may be larger than the actual support, but must contain it. - fn support_hint(&self) -> Cube; + fn support_hint(&self) -> Cube; /// Indicate whether `x` is in the support of the function represented by `self`. - fn in_support(&self, x : &Loc) -> bool; + fn in_support(&self, x : &Loc) -> bool; // Indicate whether `cube` is fully in the support of the function represented by `self`. - //fn fully_in_support(&self, cube : &Cube) -> bool; + //fn fully_in_support(&self, cube : &Cube) -> bool; /// Return an optional hint for bisecting the support. /// @@ -53,19 +52,19 @@ /// The default implementation returns `[None; N]`. #[inline] #[allow(unused_variables)] - fn bisection_hint(&self, cube : &Cube) -> [Option; N] { + fn bisection_hint(&self, cube : &Cube) -> [Option; N] { [None; N] } /// Translate `self` by `x`. #[inline] - fn shift(self, x : Loc) -> Shift { + fn shift(self, x : Loc) -> Shift { Shift { shift : x, base_fn : self } } /// Multiply `self` by the scalar `a`. #[inline] - fn weigh>(self, a : C) -> Weighted { + fn weigh>(self, a : C) -> Weighted { Weighted { weight : a, base_fn : self } } } @@ -74,7 +73,7 @@ /// /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as /// [`Bounds`][super::aggregator::Bounds]. -pub trait GlobalAnalysis { +pub trait GlobalAnalysis { /// Perform global analysis of the property `A` of `Self`. /// /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], @@ -83,26 +82,18 @@ fn global_analysis(&self) -> A; } -// default impl GlobalAnalysis for L -// where L : LocalAnalysis { -// #[inline] -// fn global_analysis(&self) -> Bounds { -// self.local_analysis(&self.support_hint()) -// } -// } - /// Trait for locally analysing a property `A` of a [`Apply`] (implementing [`Support`]) /// within a [`Cube`]. /// /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as /// [`Bounds`][super::aggregator::Bounds]. -pub trait LocalAnalysis : GlobalAnalysis + Support { +pub trait LocalAnalysis : GlobalAnalysis { /// Perform local analysis of the property `A` of `Self`. /// /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds], /// this function will return upper and lower bounds within `cube` for the mapping /// represented by `self`. - fn local_analysis(&self, cube : &Cube) -> A; + fn local_analysis(&self, cube : &LocalSet) -> A; } /// Trait for determining the upper and lower bounds of an float-valued [`Apply`]. @@ -110,15 +101,15 @@ /// This is a blanket-implemented alias for [`GlobalAnalysis`]`>` /// [`Apply`] is not a supertrait to allow flexibility in the implementation of either /// reference or non-reference arguments. -pub trait Bounded : GlobalAnalysis> { +pub trait Bounded : GlobalAnalysis> + HasScalarField { /// Return lower and upper bounds for the values of of `self`. #[inline] - fn bounds(&self) -> Bounds { + fn bounds(&self) -> Bounds { self.global_analysis() } } -impl>> Bounded for T { } +impl> + HasScalarField> Bounded for T { } /// Shift of [`Support`] and [`Apply`]; output of [`Support::shift`]. #[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc. @@ -127,6 +118,10 @@ base_fn : T, } +impl HasScalarField for Shift { + type Field = F; +} + impl<'a, T, V, F : Float, const N : usize> Apply<&'a Loc> for Shift where T : Apply, Output=V> { type Output = V; @@ -145,7 +140,8 @@ } } -impl<'a, T, V, F : Float, const N : usize> Differentiable<&'a Loc> for Shift +impl<'a, T, V : HasRealField, F : Float, const N : usize> +Differentiable<&'a Loc> for Shift where T : Differentiable, Derivative=V> { type Derivative = V; #[inline] @@ -154,7 +150,8 @@ } } -impl<'a, T, V, F : Float, const N : usize> Differentiable> for Shift +impl<'a, T, V : HasRealField, F : Float, const N : usize> +Differentiable> for Shift where T : Differentiable, Derivative=V> { type Derivative = V; #[inline] @@ -163,8 +160,8 @@ } } -impl<'a, T, F : Float, const N : usize> Support for Shift -where T : Support { +impl<'a, T, F : Float, const N : usize> Support for Shift +where T : Support { #[inline] fn support_hint(&self) -> Cube { self.base_fn.support_hint().shift(&self.shift) @@ -188,16 +185,17 @@ } -impl<'a, T, F : Float, const N : usize> GlobalAnalysis> for Shift -where T : LocalAnalysis, N> { +impl<'a, T, F : Float, const N : usize> GlobalAnalysis> for Shift +where T : GlobalAnalysis> { #[inline] fn global_analysis(&self) -> Bounds { self.base_fn.global_analysis() } } -impl<'a, T, F : Float, const N : usize> LocalAnalysis, N> for Shift -where T : LocalAnalysis, N> { +impl<'a, T, F : Float, const N : usize> LocalAnalysis, Cube> +for Shift +where T : LocalAnalysis, Cube> { #[inline] fn local_analysis(&self, cube : &Cube) -> Bounds { self.base_fn.local_analysis(&cube.shift(&(-self.shift))) @@ -206,10 +204,10 @@ macro_rules! impl_shift_norm { ($($norm:ident)*) => { $( - impl<'a, T, F : Float, const N : usize> Norm for Shift - where T : Norm { + impl<'a, T, const N : usize> Norm<$norm> for Shift + where T : Norm<$norm> { #[inline] - fn norm(&self, n : $norm) -> F { + fn norm(&self, n : $norm) -> T::Field { self.base_fn.norm(n) } } @@ -228,10 +226,16 @@ pub base_fn : T, } +impl HasScalarField for Weighted +where T : HasRealField, + C : Constant { + type Field = F; +} + impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc> for Weighted where T : for<'b> Apply<&'b Loc, Output=V>, V : std::ops::Mul, - C : Constant { + C : Constant { type Output = V; #[inline] fn apply(&self, x : &'a Loc) -> Self::Output { @@ -242,7 +246,7 @@ impl<'a, T, V, F : Float, C, const N : usize> Apply> for Weighted where T : Apply, Output=V>, V : std::ops::Mul, - C : Constant { + C : Constant { type Output = V; #[inline] fn apply(&self, x : Loc) -> Self::Output { @@ -250,10 +254,11 @@ } } -impl<'a, T, V, F : Float, C, const N : usize> Differentiable<&'a Loc> for Weighted -where T : for<'b> Differentiable<&'b Loc, Derivative=V>, +impl<'a, T, V : HasRealField, F : Float, C, const N : usize> +Differentiable<&'a Loc> for Weighted +where T : for<'b> Differentiable<&'b Loc, Derivative=V, RealField=F>, V : std::ops::Mul, - C : Constant { + C : Constant { type Derivative = V; #[inline] fn differential(&self, x : &'a Loc) -> Self::Derivative { @@ -261,10 +266,11 @@ } } -impl<'a, T, V, F : Float, C, const N : usize> Differentiable> for Weighted -where T : Differentiable, Derivative=V>, +impl<'a, T, V : HasRealField, F : Float, C, const N : usize> +Differentiable> for Weighted +where T : Differentiable, Derivative=V, RealField = F>, V : std::ops::Mul, - C : Constant { + C : Constant { type Derivative = V; #[inline] fn differential(&self, x : Loc) -> Self::Derivative { @@ -272,9 +278,9 @@ } } -impl<'a, T, F : Float, C, const N : usize> Support for Weighted -where T : Support, - C : Constant { +impl<'a, T, F : Float, C, const N : usize> Support for Weighted +where T : Support, + C : Constant { #[inline] fn support_hint(&self) -> Cube { @@ -296,9 +302,9 @@ } } -impl<'a, T, F : Float, C> GlobalAnalysis> for Weighted -where T : GlobalAnalysis>, - C : Constant { +impl<'a, T, F : Float, C> GlobalAnalysis> for Weighted +where T : GlobalAnalysis>, + C : Constant { #[inline] fn global_analysis(&self) -> Bounds { let Bounds(lower, upper) = self.base_fn.global_analysis(); @@ -310,9 +316,10 @@ } } -impl<'a, T, F : Float, C, const N : usize> LocalAnalysis, N> for Weighted -where T : LocalAnalysis, N>, - C : Constant { +impl<'a, T, F : Float, C, const N : usize> LocalAnalysis, Cube> +for Weighted +where T : LocalAnalysis, Cube>, + C : Constant { #[inline] fn local_analysis(&self, cube : &Cube) -> Bounds { let Bounds(lower, upper) = self.base_fn.local_analysis(cube); @@ -358,8 +365,9 @@ macro_rules! impl_weighted_norm { ($($norm:ident)*) => { $( - impl<'a, T, F : Float> Norm for Weighted - where T : Norm { + impl<'a, T, F : Float> Norm<$norm> for Weighted + where T : Norm<$norm, Field = F> { + #[inline] fn norm(&self, n : $norm) -> F { self.base_fn.norm(n) * self.weight.abs() @@ -381,7 +389,7 @@ ); impl<'a, T, F : Float, const N : usize> Apply<&'a Loc> for Normalised -where T : Norm + for<'b> Apply<&'b Loc, Output=F> { +where T : Norm + for<'b> Apply<&'b Loc, Output=F> { type Output = F; #[inline] fn apply(&self, x : &'a Loc) -> Self::Output { @@ -391,7 +399,7 @@ } impl<'a, T, F : Float, const N : usize> Apply> for Normalised -where T : Norm + Apply, Output=F> { +where T : Norm + Apply, Output=F> { type Output = F; #[inline] fn apply(&self, x : Loc) -> Self::Output { @@ -400,8 +408,8 @@ } } -impl<'a, T, F : Float, const N : usize> Support for Normalised -where T : Norm + Support { +impl<'a, T, F : Float, const N : usize> Support for Normalised +where T : Norm + Support { #[inline] fn support_hint(&self) -> Cube { @@ -423,8 +431,8 @@ } } -impl<'a, T, F : Float> GlobalAnalysis> for Normalised -where T : Norm + GlobalAnalysis> { +impl<'a, T, F : Float> GlobalAnalysis> for Normalised +where T : Norm + GlobalAnalysis> { #[inline] fn global_analysis(&self) -> Bounds { let Bounds(lower, upper) = self.0.global_analysis(); @@ -435,8 +443,9 @@ } } -impl<'a, T, F : Float, const N : usize> LocalAnalysis, N> for Normalised -where T : Norm + LocalAnalysis, N> { +impl<'a, T, F : Float, const N : usize> LocalAnalysis, Cube> +for Normalised +where T : Norm + LocalAnalysis, Cube> { #[inline] fn local_analysis(&self, cube : &Cube) -> Bounds { let Bounds(lower, upper) = self.0.local_analysis(cube); @@ -447,23 +456,26 @@ } } -impl<'a, T, F : Float> Norm for Normalised -where T : Norm { +impl<'a, T> HasScalarField for Normalised where T : HasScalarField { + type Field = T::Field; +} + +impl<'a, T> Norm for Normalised where T : Norm { #[inline] - fn norm(&self, _ : L1) -> F { + fn norm(&self, _ : L1) -> Self::Field { let w = self.0.norm(L1); - if w == F::ZERO { F::ZERO } else { F::ONE } + if w == Self::Field::ZERO { Self::Field::ZERO } else { Self::Field::ONE } } } macro_rules! impl_normalised_norm { ($($norm:ident)*) => { $( - impl<'a, T, F : Float> Norm for Normalised - where T : Norm + Norm { + impl<'a, T> Norm<$norm> for Normalised where T : Norm<$norm> + Norm { + #[inline] - fn norm(&self, n : $norm) -> F { + fn norm(&self, n : $norm) -> Self::Field { let w = self.0.norm(L1); - if w == F::ZERO { F::ZERO } else { self.0.norm(n) / w } + if w == Self::Field::ZERO { Self::Field::ZERO } else { self.0.norm(n) / w } } } )* } @@ -471,26 +483,16 @@ impl_normalised_norm!(L2 Linfinity); -/* -impl, const N : usize> LocalAnalysis for S { - fn local_analysis(&self, _cube : &Cube) -> NullAggregator { NullAggregator } -} - -impl, const N : usize> LocalAnalysis, N> for S { - #[inline] - fn local_analysis(&self, cube : &Cube) -> Bounds { - self.bounds(cube) - } -}*/ /// Generator of [`Support`]-implementing component functions based on low storage requirement /// [ids][`Self::Id`]. -pub trait SupportGenerator -: MulAssign + DivAssign + Neg + Clone + Sync + Send + 'static { +pub trait SupportGenerator +: MulAssign + DivAssign + Neg + HasRealField + + Clone + Sync + Send + 'static { /// The identification type type Id : 'static + Copy; /// The type of the [`Support`] (often also a [`Apply`]). - type SupportType : 'static + Support; + type SupportType : 'static + Support; /// An iterator over all the [`Support`]s of the generator. type AllDataIter<'a> : Iterator where Self : 'a; diff -r edb95d2b83cc -r d2acaaddd9af src/euclidean.rs --- a/src/euclidean.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/euclidean.rs Tue Dec 31 09:12:43 2024 -0500 @@ -4,13 +4,14 @@ use crate::types::*; use std::ops::{Mul, MulAssign, Div, DivAssign, Add, Sub, AddAssign, SubAssign, Neg}; +pub use crate::types::{HasScalarField, HasRealField}; /// 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; +pub trait Dot : HasScalarField { + fn dot(&self, other : U) -> Self::Field; } /// Space (type) with Euclidean and vector space structure @@ -18,59 +19,64 @@ /// 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 : Sized + 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> +pub trait Euclidean : Sized + + HasRealField + + Dot + for<'a> Dot<&'a Self> + + 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; + + Neg::Output> { + + type Output : Euclidean; /// Returns origin of same dimensions as `self`. - fn similar_origin(&self) -> >::Output; + fn similar_origin(&self) -> ::Output; /// Calculate the square of the 2-norm, $\frac{1}{2}\\|x\\|_2^2$, where `self` is $x$. #[inline] - fn norm2_squared(&self) -> F { + fn norm2_squared(&self) -> Self::Field { self.dot(self) } /// Calculate the square of the 2-norm divided by 2, $\frac{1}{2}\\|x\\|_2^2$, /// where `self` is $x$. #[inline] - fn norm2_squared_div2(&self) -> F { - self.norm2_squared()/F::TWO + fn norm2_squared_div2(&self) -> Self::Field { + self.norm2_squared()/Self::Field::TWO } /// Calculate the 2-norm $‖x‖_2$, where `self` is $x$. #[inline] - fn norm2(&self) -> F { + fn norm2(&self) -> Self::Field { self.norm2_squared().sqrt() } /// Calculate the 2-distance squared $\\|x-y\\|_2^2$, where `self` is $x$. - fn dist2_squared(&self, y : &Self) -> F; + fn dist2_squared(&self, y : &Self) -> Self::Field; /// Calculate the 2-distance $\\|x-y\\|_2$, where `self` is $x$. #[inline] - fn dist2(&self, y : &Self) -> F { + fn dist2(&self, y : &Self) -> Self::Field { self.dist2_squared(y).sqrt() } /// Projection to the 2-ball. #[inline] - fn proj_ball2(mut self, ρ : F) -> Self { + fn proj_ball2(mut self, ρ : Self::Field) -> Self { self.proj_ball2_mut(ρ); self } /// In-place projection to the 2-ball. #[inline] - fn proj_ball2_mut(&mut self, ρ : F) { + fn proj_ball2_mut(&mut self, ρ : Self::Field) { let r = self.norm2(); if r>ρ { *self *= ρ/r @@ -79,7 +85,7 @@ } /// 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() -> ::Output; } diff -r edb95d2b83cc -r d2acaaddd9af src/linops.rs --- a/src/linops.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/linops.rs Tue Dec 31 09:12:43 2024 -0500 @@ -10,7 +10,8 @@ /// Trait for linear operators on `X`. pub trait Linear : Apply - + for<'a> Apply<&'a X, Output=Self::Codomain> { + + for<'a> Apply<&'a X, Output=Self::Codomain> + + HasScalarField { type Codomain; } @@ -18,32 +19,32 @@ #[replace_float_literals(F::cast_from(literal))] pub trait AXPY { /// Computes `y = βy + αx`, where `y` is `Self`. - fn axpy(&mut self, α : F, x : &X, β : F); + fn axpy(&mut self, α : F, x : X, β : F); /// Copies `x` to `self`. - fn copy_from(&mut self, x : &X) { + fn copy_from(&mut self, x : X) { self.axpy(1.0, x, 0.0) } /// Computes `y = αx`, where `y` is `Self`. - fn scale_from(&mut self, α : F, x : &X) { + fn scale_from(&mut self, α : F, x : X) { self.axpy(α, x, 0.0) } } /// Efficient in-place application for [`Linear`] operators. #[replace_float_literals(F::cast_from(literal))] -pub trait GEMV>::Codomain> : Linear { +pub trait GEMV>::Output> : Apply { /// Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv(&self, y : &mut Y, α : F, x : &X, β : F); + fn gemv(&self, y : &mut Y, α : F, x : X, β : F); /// Computes `y = Ax`, where `A` is `Self` - fn apply_mut(&self, y : &mut Y, x : &X){ + fn apply_mut(&self, y : &mut Y, x : X){ self.gemv(y, 1.0, x, 0.0) } /// Computes `y += Ax`, where `A` is `Self` - fn apply_add(&self, y : &mut Y, x : &X){ + fn apply_add(&self, y : &mut Y, x : X){ self.gemv(y, 1.0, x, 1.0) } } @@ -51,11 +52,10 @@ /// Bounded linear operators pub trait BoundedLinear : Linear { - type FloatType : Float; /// A bound on the operator norm $\|A\|$ for the linear operator $A$=`self`. /// This is not expected to be the norm, just any bound on it that can be /// reasonably implemented. - fn opnorm_bound(&self) -> Self::FloatType; + fn opnorm_bound(&self) -> Self::Field; } // Linear operator application into mutable target. The [`AsRef`] bound @@ -70,7 +70,7 @@ /// Trait for forming the adjoint operator of `Self`. pub trait Adjointable : Linear { - type AdjointCodomain; + type AdjointCodomain : HasScalarField; type Adjoint<'a> : Linear where Self : 'a; /// Form the adjoint operator of `self`. @@ -89,7 +89,7 @@ /// domain of the adjointed operator. `Self::Preadjoint` should be /// [`Adjointable`]`<'a,Ypre,X>`. pub trait Preadjointable : Linear { - type PreadjointCodomain; + type PreadjointCodomain : HasScalarField; type Preadjoint<'a> : Adjointable where Self : 'a; /// Form the preadjoint operator of `self`. @@ -100,55 +100,49 @@ pub trait SimplyAdjointable : Adjointable>::Codomain> {} impl<'a,X,T> SimplyAdjointable for T where T : Adjointable>::Codomain> {} -/// The identity operator +/// The identity operator on `X` with scalar field `F`. #[derive(Clone,Copy,Debug,Serialize,Eq,PartialEq)] -pub struct IdOp (PhantomData); +pub struct IdOp (PhantomData<(X, F)>); -impl IdOp { - fn new() -> IdOp { IdOp(PhantomData) } +impl HasScalarField for IdOp { + type Field = F; } -impl Apply for IdOp { +impl IdOp { + fn new() -> IdOp { IdOp(PhantomData) } +} + +impl> Apply for IdOp { type Output = X; - fn apply(&self, x : X) -> X { - x + fn apply(&self, x : T) -> X { + x.clone_if_needed() } } -impl<'a, X> Apply<&'a X> for IdOp where X : Clone { - type Output = X; - - fn apply(&self, x : &'a X) -> X { - x.clone() - } -} - -impl Linear for IdOp where X : Clone { +impl Linear for IdOp { type Codomain = X; } - #[replace_float_literals(F::cast_from(literal))] -impl GEMV for IdOp where Y : AXPY, X : Clone { +impl GEMV for IdOp where Y : AXPY { // Computes `y = αAx + βy`, where `A` is `Self`. - fn gemv(&self, y : &mut Y, α : F, x : &X, β : F) { + fn gemv(&self, y : &mut Y, α : F, x : X, β : F) { y.axpy(α, x, β) } - fn apply_mut(&self, y : &mut Y, x : &X){ + fn apply_mut(&self, y : &mut Y, x : X){ y.copy_from(x); } } -impl BoundedLinear for IdOp where X : Clone { - type FloatType = float; - fn opnorm_bound(&self) -> float { 1.0 } +impl BoundedLinear for IdOp where X : Clone { + fn opnorm_bound(&self) -> F { F::ONE } } -impl Adjointable for IdOp where X : Clone { +impl Adjointable for IdOp where X : Clone + HasScalarField { type AdjointCodomain=X; - type Adjoint<'a> = IdOp where X : 'a; + type Adjoint<'a> = IdOp where X : 'a; fn adjoint(&self) -> Self::Adjoint<'_> { IdOp::new() } } diff -r edb95d2b83cc -r d2acaaddd9af src/loc.rs --- a/src/loc.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/loc.rs Tue Dec 31 09:12:43 2024 -0500 @@ -6,6 +6,7 @@ use std::ops::{Add,Sub,AddAssign,SubAssign,Mul,Div,MulAssign,DivAssign,Neg,Index,IndexMut}; use std::slice::{Iter,IterMut}; use std::fmt::{Display, Formatter}; +use std::borrow::Borrow; use crate::types::{Float,Num,SignedNum}; use crate::maputil::{FixedLength,FixedLengthMut,map1,map2,map1_mut,map2_mut}; use crate::euclidean::*; @@ -23,6 +24,10 @@ pub [F; N] ); +impl HasScalarField for Loc { + type Field = F; +} + impl Display for Loc{ // Required method fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { @@ -393,7 +398,7 @@ macro_rules! domination { ($norm:ident, $dominates:ident) => { - impl Dominated> for $norm { + impl Dominated<$dominates, Loc> for $norm { #[inline] fn norm_factor(&self, _p : $dominates) -> F { F::ONE @@ -405,7 +410,7 @@ } }; ($norm:ident, $dominates:ident, $fn:path) => { - impl Dominated> for $norm { + impl Dominated<$dominates, Loc> for $norm { #[inline] fn norm_factor(&self, _p : $dominates) -> F { $fn(F::cast_from(N)) @@ -426,18 +431,18 @@ domination!(Linfinity, L2); domination!(L2, L1); -impl Dot,F> for Loc { +impl>, const N : usize> Dot for Loc { /// 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 : T) -> F { self.0.iter() - .zip(other.0.iter()) + .zip(other.borrow().0.iter()) .fold(F::ZERO, |m, (&v, &w)| m + v * w) } } -impl Euclidean for Loc { +impl Euclidean for Loc { type Output = Self; #[inline] @@ -483,24 +488,24 @@ pub const ORIGIN : Self = Loc([F::ZERO; N]); } -impl StaticEuclidean for Loc { +impl StaticEuclidean for Loc { #[inline] fn origin() -> Self { Self::ORIGIN } } -impl Norm for Loc { +impl Norm for Loc { #[inline] fn norm(&self, _ : L2) -> F { self.norm2() } } -impl Dist for Loc { +impl Dist for Loc { #[inline] fn dist(&self, other : &Self, _ : L2) -> F { self.dist2(other) } } -impl Norm for Loc { +impl Norm for Loc { /// This implementation is not stabilised as it's meant to be used for very small vectors. /// Use [`nalgebra`] for larger vectors. #[inline] @@ -509,7 +514,7 @@ } } -impl Dist for Loc { +impl Dist for Loc { #[inline] fn dist(&self, other : &Self, _ : L1) -> F { self.iter() @@ -518,14 +523,14 @@ } } -impl Projection for Loc { +impl Projection for Loc { #[inline] fn proj_ball_mut(&mut self, ρ : F, _ : Linfinity) { self.iter_mut().for_each(|v| *v = num_traits::clamp(*v, -ρ, ρ)) } } -impl Norm for Loc { +impl Norm for Loc { /// This implementation is not stabilised as it's meant to be used for very small vectors. /// Use [`nalgebra`] for larger vectors. #[inline] @@ -534,7 +539,7 @@ } } -impl Dist for Loc { +impl Dist for Loc { #[inline] fn dist(&self, other : &Self, _ : Linfinity) -> F { self.iter() @@ -572,19 +577,18 @@ } } -impl AXPY> for Loc { - +impl<'a, T : Borrow>, F : Num, const N : usize> AXPY for Loc { #[inline] - fn axpy(&mut self, α : F, x : &Loc, β : F) { + fn axpy(&mut self, α : F, x : T, β : F) { if β == F::ZERO { - map2_mut(self, x, |yi, xi| { *yi = α * (*xi) }) + map2_mut(self, x.borrow(), |yi, xi| { *yi = α * (*xi) }) } else { - map2_mut(self, x, |yi, xi| { *yi = β * (*yi) + α * (*xi) }) + map2_mut(self, x.borrow(), |yi, xi| { *yi = β * (*yi) + α * (*xi) }) } } #[inline] - fn copy_from(&mut self, x : &Loc) { - map2_mut(self, x, |yi, xi| *yi = *xi ) + fn copy_from(&mut self, x : T) { + map2_mut(self, x.borrow(), |yi, xi| *yi = *xi ) } } diff -r edb95d2b83cc -r d2acaaddd9af src/mapping.rs --- a/src/mapping.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/mapping.rs Tue Dec 31 09:12:43 2024 -0500 @@ -3,9 +3,10 @@ */ use std::marker::PhantomData; -use crate::types::Float; +use crate::types::{Float, HasRealField, HasScalarField}; use serde::Serialize; use crate::loc::Loc; +use std::borrow::Cow; /// Trait for application of `Self` as a mathematical function or operator on `X`. pub trait Apply { @@ -44,43 +45,47 @@ /// Automatically implemented shorthand for referring to [`Mapping`]s from [`Loc`] to `F`. pub trait RealMapping -: Mapping, Codomain = F> {} +: Mapping, Codomain = F> + HasRealField {} impl RealMapping for T -where T : Mapping, Codomain = F> {} +where T : Mapping, Codomain = F> + HasRealField {} /// Automatically implemented shorthand for referring to differentiable [`Mapping`]s from /// [`Loc`] to `F`. pub trait DifferentiableRealMapping -: DifferentiableMapping, Codomain = F, DerivativeDomain=Loc> {} +: DifferentiableMapping, Codomain = F, DerivativeDomain=Loc> + + RealMapping + + HasRealField {} impl DifferentiableRealMapping for T -where T : DifferentiableMapping, Codomain = F, DerivativeDomain=Loc> {} +where T : DifferentiableMapping, Codomain = F, DerivativeDomain=Loc> + + RealMapping + + HasRealField {} /// A helper trait alias for referring to [`Mapping`]s from [`Loc`] to [`Loc`]. pub trait RealVectorField -: Mapping, Codomain = Loc> {} +: Mapping, Codomain = Loc> + HasRealField {} impl RealVectorField for T -where T : Mapping, Codomain = Loc> {} +where T : Mapping, Codomain = Loc> + HasRealField {} /// Trait for calculation the differential of `Self` as a mathematical function on `X`. -pub trait Differentiable : Sized { - type Derivative; +pub trait Differentiable : Sized + HasRealField { + type Derivative : HasRealField; /// Compute the differential of `self` at `x`. fn differential(&self, x : X) -> Self::Derivative; } -impl<'g, X, G : Differentiable> Differentiable for &'g G { - type Derivative = G::Derivative; - #[inline] - fn differential(&self, x : X) -> Self::Derivative { - (*self).differential(x) - } -} +// impl<'g, X, G : Differentiable> Differentiable for &'g G { +// type Derivative = G::Derivative; +// #[inline] +// fn differential(&self, x : X) -> Self::Derivative { +// (*self).differential(x) +// } +// } /// A differentiable mapping from `Domain` to [`Mapping::Codomain`], with differentials /// `Differential`. @@ -90,33 +95,34 @@ : Mapping + Differentiable + for<'a> Differentiable<&'a Domain, Derivative=Self::DerivativeDomain> { - type DerivativeDomain; - type Differential : Mapping; - type DifferentialRef<'b> : Mapping where Self : 'b; + type DerivativeDomain : HasRealField; + type Differential<'b> : Mapping + + HasRealField + + Clone where Self : 'b; /// Form the differential mapping of `self`. - fn diff(self) -> Self::Differential; + fn diff(self) -> Self::Differential<'static>; /// Form the differential mapping of `self`. - fn diff_ref(&self) -> Self::DifferentialRef<'_>; + fn diff_ref(&self) -> Self::Differential<'_>; } -impl DifferentiableMapping for T -where T : Mapping +impl DifferentiableMapping for T +where T : Mapping + Clone + Differentiable - + for<'a> Differentiable<&'a Domain,Derivative=Derivative> { + + for<'a> Differentiable<&'a Domain, Derivative=Derivative>, + Derivative : HasRealField { type DerivativeDomain = Derivative; - type Differential = Differential; - type DifferentialRef<'b> = Differential where Self : 'b; + type Differential<'b> = Differential<'b, Domain, Self> where Self : 'b + Clone; /// Form the differential mapping of `self`. - fn diff(self) -> Self::Differential { - Differential{ g : self, _space : PhantomData } + fn diff(self) -> Self::Differential<'static> { + Differential{ g : Cow::Owned(self), _space : PhantomData } } /// Form the differential mapping of `self`. - fn diff_ref(&self) -> Self::DifferentialRef<'_> { - Differential{ g : self, _space : PhantomData } + fn diff_ref(&self) -> Self::Differential<'_> { + Differential{ g : Cow::Borrowed(self), _space : PhantomData } } } @@ -127,6 +133,10 @@ _domain : PhantomData, } +impl + HasScalarField> HasScalarField for Sum { + type Field = M::Field; +} + impl> Sum { /// Construct from an iterator. pub fn new>(iter : I) -> Self { @@ -174,18 +184,25 @@ } /// Container for the differential [`Mapping`] of a [`Differentiable`] mapping. -pub struct Differential> { - g : G, +#[derive(Clone, Debug)] +pub struct Differential<'a, X, G : 'a + DifferentiableMapping + Clone> { + g : Cow<'a, G>, _space : PhantomData } -impl> Differential { - pub fn base_fn(&self) -> &G { - &self.g +impl<'a, X, G : DifferentiableMapping + Clone> Differential<'a, X, G> { + pub fn base_fn(&'a self) -> &'a G { + &*self.g } } -impl> Apply for Differential { + +impl<'a, X, G> HasScalarField for Differential<'a, X, G> +where G : 'a + DifferentiableMapping + HasScalarField + Clone { + type Field = G::Field; +} + +impl<'b, X, G : DifferentiableMapping + Clone> Apply for Differential<'b, X, G> { type Output = G::DerivativeDomain; #[inline] @@ -194,7 +211,8 @@ } } -impl<'a, X, G : DifferentiableMapping> Apply<&'a X> for Differential { +impl<'a, 'b, X, G : 'b + DifferentiableMapping + Clone> Apply<&'a X> +for Differential<'b, X, G> { type Output = G::DerivativeDomain; #[inline] @@ -232,14 +250,23 @@ /// Container for dimensional slicing [`Loc`]`` codomain of a [`Mapping`] to `F`. -pub struct SlicedCodomain>, const N : usize> { - g : G, +pub struct SlicedCodomain< + 'a, X, F, + G : Mapping> + Clone, + const N : usize +> { + g : Cow<'a, G>, slice : usize, _phantoms : PhantomData<(X, F)> } -impl>, const N : usize> Apply -for SlicedCodomain { +impl<'a, X, F, G, const N : usize> HasScalarField for SlicedCodomain<'a, X, F, G, N> +where G : HasScalarField + Mapping> + Clone { + type Field = G::Field; +} + +impl<'a, X, F : Copy, G : Mapping> + Clone, const N : usize> Apply +for SlicedCodomain<'a, X, F, G, N> { type Output = F; #[inline] @@ -250,12 +277,13 @@ } } -impl<'a, X, F : Copy, G : Mapping>, const N : usize> Apply<&'a X> -for SlicedCodomain { +impl<'a, 'b, X, F : Copy, G : Mapping> + Clone, const N : usize> +Apply<&'b X> +for SlicedCodomain<'a, X, F, G, N> { type Output = F; #[inline] - fn apply(&self, x : &'a X) -> Self::Output { + fn apply(&self, x : &'b X) -> Self::Output { let tmp : [F; N] = self.g.apply(x).into(); // Safety: `slice_codomain` below checks the range. unsafe { *tmp.get_unchecked(self.slice) } @@ -264,21 +292,21 @@ /// An auto-trait for constructing a [`FlattenCodomain`] structure for /// flattening the codomain of a [`Mapping`] from [`Loc`]`` to `F`. -pub trait SliceCodomain : Mapping> + Sized { +pub trait SliceCodomain : Mapping> + Clone + Sized { /// Flatten the codomain from [`Loc`]`` to `F`. - fn slice_codomain(self, slice : usize) -> SlicedCodomain { + fn slice_codomain(self, slice : usize) -> SlicedCodomain<'static, X, F, Self, N> { assert!(slice < N); - SlicedCodomain{ g : self, slice, _phantoms : PhantomData } + SlicedCodomain{ g : Cow::Owned(self), slice, _phantoms : PhantomData } } /// Flatten the codomain from [`Loc`]`` to `F`. - fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain { + fn slice_codomain_ref(&self, slice : usize) -> SlicedCodomain<'_, X, F, Self, N> { assert!(slice < N); - SlicedCodomain{ g : self, slice, _phantoms : PhantomData } + SlicedCodomain{ g : Cow::Borrowed(self), slice, _phantoms : PhantomData } } } -impl>, const N : usize> +impl> + Clone, const N : usize> SliceCodomain for G {} diff -r edb95d2b83cc -r d2acaaddd9af src/nalgebra_support.rs --- a/src/nalgebra_support.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/nalgebra_support.rs Tue Dec 31 09:12:43 2024 -0500 @@ -56,9 +56,9 @@ } } -impl<'a, SM,SV,N,M,K,E> Linear> for Matrix +impl Linear> for Matrix where SM: Storage, SV: Storage, - N : Dim, M : Dim, K : Dim, E : Scalar + ClosedMul + ClosedAdd + Zero + One, + N : Dim, M : Dim, K : Dim, E : Float + Scalar + ClosedMul + ClosedAdd + Zero + One, DefaultAllocator : Allocator, DefaultAllocator : Allocator, DefaultAllocator : Allocator, @@ -75,12 +75,31 @@ DefaultAllocator : Allocator { #[inline] - fn gemv(&self, y : &mut Matrix, α : E, x : &Matrix, β : E) { + fn gemv(&self, y : &mut Matrix, α : E, x : Matrix, β : E) { + Matrix::gemm(y, α, self, &x, β) + } + + #[inline] + fn apply_mut(&self, y : &mut Matrix, x : Matrix) { + self.mul_to(&x, y) + } +} + +impl<'a, SM,SV1,SV2,N,M,K,E> GEMV, Matrix> for Matrix +where SM: Storage, SV1: Storage, SV2: StorageMut, + N : Dim, M : Dim, K : Dim, E : Scalar + ClosedMul + ClosedAdd + Zero + One + Float, + DefaultAllocator : Allocator, + DefaultAllocator : Allocator, + DefaultAllocator : Allocator, + DefaultAllocator : Allocator { + + #[inline] + fn gemv(&self, y : &mut Matrix, α : E, x : &'a Matrix, β : E) { Matrix::gemm(y, α, self, x, β) } #[inline] - fn apply_mut<'a>(&self, y : &mut Matrix, x : &Matrix) { + fn apply_mut(&self, y : &mut Matrix, x : &'a Matrix) { self.mul_to(x, y) } } @@ -91,17 +110,33 @@ DefaultAllocator : Allocator { #[inline] - fn axpy(&mut self, α : E, x : &Vector, β : E) { + fn axpy(&mut self, α : E, x : Vector, β : E) { + Matrix::axpy(self, α, &x, β) + } + + #[inline] + fn copy_from(&mut self, y : Vector) { + Matrix::copy_from(self, &y) + } +} + +impl<'a, SM,SV1,M,E> AXPY> for Vector +where SM: StorageMut, SV1: Storage, + M : Dim, E : Scalar + ClosedMul + ClosedAdd + Zero + One + Float, + DefaultAllocator : Allocator { + + #[inline] + fn axpy(&mut self, α : E, x : &'a Vector, β : E) { Matrix::axpy(self, α, x, β) } #[inline] - fn copy_from(&mut self, y : &Vector) { + fn copy_from(&mut self, y : &'a Vector) { Matrix::copy_from(self, y) } } -impl Projection for Vector +impl Projection for Vector where SM: StorageMut, M : Dim, E : Scalar + ClosedMul + ClosedAdd + Zero + One + Float + RealField, DefaultAllocator : Allocator { @@ -114,7 +149,8 @@ impl<'own,SV1,SV2,SM,N,M,K,E> Adjointable,Matrix> for Matrix where SM: Storage, SV1: Storage, SV2: Storage, - N : Dim, M : Dim, K : Dim, E : Scalar + ClosedMul + ClosedAdd + Zero + One + SimdComplexField, + N : Dim, M : Dim, K : Dim, + E : Float + Scalar + ClosedMul + ClosedAdd + Zero + One + SimdComplexField, DefaultAllocator : Allocator, DefaultAllocator : Allocator, DefaultAllocator : Allocator, @@ -128,7 +164,7 @@ } } -impl Dot,E> +impl Dot> for Vector where M : Dim, E : Float + Scalar + ClosedMul + ClosedAdd + Zero + One, @@ -137,7 +173,21 @@ DefaultAllocator : Allocator { #[inline] - fn dot(&self, other : &Vector) -> E { + fn dot(&self, other : Vector) -> E { + Vector::::dot(self, &other) + } +} + +impl<'a, E,M,S,Si> Dot<&'a Vector> +for Vector +where M : Dim, + E : Float + Scalar + ClosedMul + ClosedAdd + Zero + One, + S : Storage, + Si : Storage, + DefaultAllocator : Allocator { + + #[inline] + fn dot(&self, other : &'a Vector) -> E { Vector::::dot(self, other) } } @@ -167,7 +217,16 @@ // TODO: should allow different input storages in `Euclidean`. -impl Euclidean +impl HasScalarField +for Matrix +where M : Dim, K : Dim, + S : Storage, + E : Float + Scalar, + DefaultAllocator : Allocator { + type Field = E; +} + +impl Euclidean for Vector where M : Dim, S : StorageMut, @@ -192,7 +251,7 @@ } } -impl StaticEuclidean +impl StaticEuclidean for Vector where M : DimName, S : StorageMut, @@ -205,7 +264,7 @@ } } -impl Norm +impl Norm for Vector where M : Dim, S : StorageMut, @@ -218,7 +277,7 @@ } } -impl Dist +impl Dist for Vector where M : Dim, S : StorageMut, @@ -230,7 +289,7 @@ } } -impl Norm +impl Norm for Vector where M : Dim, S : StorageMut, @@ -243,7 +302,7 @@ } } -impl Dist +impl Dist for Vector where M : Dim, S : StorageMut, @@ -255,7 +314,7 @@ } } -impl Norm +impl Norm for Vector where M : Dim, S : StorageMut, @@ -268,7 +327,7 @@ } } -impl Dist +impl Dist for Vector where M : Dim, S : StorageMut, diff -r edb95d2b83cc -r d2acaaddd9af src/norms.rs --- a/src/norms.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/norms.rs Tue Dec 31 09:12:43 2024 -0500 @@ -5,6 +5,7 @@ use serde::Serialize; use crate::types::*; use crate::euclidean::*; +pub use crate::types::{HasScalarField, HasRealField}; // // Abstract norms @@ -53,7 +54,6 @@ pub struct HuberL21(pub F); impl NormExponent for HuberL21 {} - /// A normed space (type) with exponent or other type `Exponent` for the norm. /// /// Use as @@ -64,27 +64,28 @@ /// /// println!("{}, {} {}", x.norm(L1), x.norm(L2), x.norm(Linfinity)) /// ``` -pub trait Norm { +pub trait Norm : HasScalarField { /// Calculate the norm. - fn norm(&self, _p : Exponent) -> F; + fn norm(&self, _p : Exponent) -> Self::Field; } /// Indicates that the `Self`-[`Norm`] is dominated by the `Exponent`-`Norm` on the space /// `Elem` with the corresponding field `F`. -pub trait Dominated { +pub trait Dominated +where Elem : HasScalarField { /// Indicates the factor $c$ for the inequality $‖x‖ ≤ C ‖x‖_p$. - fn norm_factor(&self, p : Exponent) -> F; + fn norm_factor(&self, p : Exponent) -> Elem::Field; /// Given a norm-value $‖x‖_p$, calculates $C‖x‖_p$ such that $‖x‖ ≤ C‖x‖_p$ #[inline] - fn from_norm(&self, p_norm : F, p : Exponent) -> F { + fn from_norm(&self, p_norm : Elem::Field, p : Exponent) -> Elem::Field { p_norm * self.norm_factor(p) } } /// Trait for distances with respect to a norm. -pub trait Dist : Norm { +pub trait Dist : Norm { /// Calculate the distance - fn dist(&self, other : &Self, _p : Exponent) -> F; + fn dist(&self, other : &Self, _p : Exponent) -> Self::Field; } /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball. @@ -97,16 +98,15 @@ /// /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); /// ``` -pub trait Projection : Norm + Euclidean -where F : Float { +pub trait Projection : Norm + Euclidean { /// Projection of `self` to the `q`-norm-ball of radius ρ. - fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { + fn proj_ball(mut self, ρ : Self::Field, q : Exponent) -> Self { self.proj_ball_mut(ρ, q); self } /// In-place projection of `self` to the `q`-norm-ball of radius ρ. - fn proj_ball_mut(&mut self, ρ : F, _q : Exponent); + fn proj_ball_mut(&mut self, ρ : Self::Field, _q : Exponent); } /*impl> Norm for E { @@ -116,12 +116,12 @@ fn dist(&self, other : &Self, _p : L2) -> F { self.dist2(other) } }*/ -impl + Norm> Projection for E { +impl + Euclidean> Projection for E { #[inline] - fn proj_ball(self, ρ : F, _p : L2) -> Self { self.proj_ball2(ρ) } + fn proj_ball(self, ρ : Self::Field, _p : L2) -> Self { self.proj_ball2(ρ) } #[inline] - fn proj_ball_mut(&mut self, ρ : F, _p : L2) { self.proj_ball2_mut(ρ) } + fn proj_ball_mut(&mut self, ρ : Self::Field, _p : L2) { self.proj_ball2_mut(ρ) } } impl HuberL1 { @@ -142,13 +142,13 @@ } } -impl> Norm> for E { +impl> Norm> for E { fn norm(&self, huber : HuberL1) -> F { huber.apply(self.norm2_squared()) } } -impl> Dist> for E { +impl> Dist> for E { fn dist(&self, other : &Self, huber : HuberL1) -> F { huber.apply(self.dist2_squared(other)) } diff -r edb95d2b83cc -r d2acaaddd9af src/sets.rs --- a/src/sets.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/sets.rs Tue Dec 31 09:12:43 2024 -0500 @@ -59,15 +59,19 @@ /// vector and $t$ the offset. /// /// `U` is the element type, `F` the floating point number type, and `A` the type of the -/// orthogonal (dual) vectors. They need implement [`Dot`]. +/// 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 : Dot + for<'a> Dot<&'a U>, + F : Float { pub orthogonal : A, pub offset : F, _phantom : PhantomData, } -impl Halfspace where A : Dot, F : Float { +impl Halfspace +where A : Dot + for<'a> Dot<&'a U>, + F : Float { #[inline] pub fn new(orthogonal : A, offset : F) -> Self { Halfspace{ orthogonal : orthogonal, offset : offset, _phantom : PhantomData } @@ -77,7 +81,7 @@ /// Trait for generating a halfspace spanned by another set `Self` of elements of type `U`. pub trait SpannedHalfspace where F : Float { /// Type of the orthogonal vector describing the halfspace. - type A : Dot; + type A : Dot + for<'a> Dot<&'a U>; /// Returns the halfspace spanned by this set. fn spanned_halfspace(&self) -> Halfspace; } @@ -103,7 +107,9 @@ } } -impl Set for Halfspace where A : Dot, F : Float { +impl Set for Halfspace +where A : Dot + for<'a> Dot<&'a U>, + F : Float { #[inline] fn contains(&self, item : &U) -> bool { self.orthogonal.dot(item) >= self.offset @@ -111,10 +117,14 @@ } /// Polygons defined by `N` `Halfspace`s. -#[derive(Clone,Copy,Debug,Eq,PartialEq)] -pub struct NPolygon(pub [Halfspace; N]) where A : Dot, F : Float; +#[derive(Clone,Debug,Eq,PartialEq)] +pub struct NPolygon(pub [Halfspace; N]) +where A : Dot + for<'a> Dot<&'a U>, + F : Float; -impl Set for NPolygon where A : Dot, F : Float { +impl Set for NPolygon +where A : Dot + for<'a> Dot<&'a U>, + F : Float { fn contains(&self, item : &U) -> bool { self.0.iter().all(|halfspace| halfspace.contains(item)) } diff -r edb95d2b83cc -r d2acaaddd9af src/types.rs --- a/src/types.rs Sun Nov 10 09:02:57 2024 -0500 +++ b/src/types.rs Tue Dec 31 09:12:43 2024 -0500 @@ -57,7 +57,8 @@ + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom + CastFrom - + CastFrom + CastFrom { + + CastFrom + CastFrom + + HasScalarField { const ZERO : Self; const ONE : Self; @@ -106,6 +107,9 @@ const RANGE_MAX : Self = <$type>::MAX; const RANGE_MIN : Self = <$type>::MIN; } + impl HasScalarField for $type { + type Field = $type; + } )* } } @@ -163,3 +167,54 @@ } */ + +/// Trait for on-demand cloning as of `Self` as `Target`. +/// +/// Blanket implementations clone references, but do nothing if `Self` equals `Target`. +/// +/// The idea is to allow other traits to be implemented generically, similar to now one +/// can work with references and owned values through [`std::borrow::Borrow`], but, in +/// contrast to the latter, this trait will provide an owned value instead of reference. +pub trait CloneIfNeeded { + /// Clone `self` if needed as `Target`. + fn clone_if_needed(self) -> Target; +} + +impl<'a, T : Clone> CloneIfNeeded for &'a T { + #[inline] + /// Clone + fn clone_if_needed(self) -> T { + self.clone() + } +} + +impl<'a, T : Clone> CloneIfNeeded for &'a mut T { + #[inline] + /// Clone + fn clone_if_needed(self) -> T { + self.clone() + } +} + +impl<'a, T> CloneIfNeeded for T { + #[inline] + /// No clone needed + fn clone_if_needed(self) -> T { + self + } +} + +/// Trait for objects that have an associated scalar field. +pub trait HasScalarField { + type Field : Num; +} + +/// Trait for objects that have an associated real field. +pub trait HasRealField : HasScalarField { + type RealField : Float; +} + +impl HasRealField for T where T : HasScalarField, T::Field : Float { + type RealField = T::Field; +} +