--- 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<Self::Type> { - /// The type of the value - type Type : Float; +pub trait Constant : Copy + Sync + Send + 'static + + std::fmt::Debug + HasRealField + + Into<Self::Field> { /// Returns the value of the constant - fn value(&self) -> Self::Type; + fn value(&self) -> Self::Field; } impl<F : Float> 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<F : Num, const N : usize> : Sized + Sync + Send + 'static { +pub trait Support<const N : usize> : 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<F,N>; + fn support_hint(&self) -> Cube<Self::Field,N>; /// Indicate whether `x` is in the support of the function represented by `self`. - fn in_support(&self, x : &Loc<F,N>) -> bool; + fn in_support(&self, x : &Loc<Self::Field,N>) -> bool; // Indicate whether `cube` is fully in the support of the function represented by `self`. - //fn fully_in_support(&self, cube : &Cube<F,N>) -> bool; + //fn fully_in_support(&self, cube : &Cube<Self::Field,N>) -> 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<F, N>) -> [Option<F>; N] { + fn bisection_hint(&self, cube : &Cube<Self::Field, N>) -> [Option<Self::Field>; N] { [None; N] } /// Translate `self` by `x`. #[inline] - fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> { + fn shift(self, x : Loc<Self::Field, N>) -> Shift<Self, Self::Field, N> { Shift { shift : x, base_fn : self } } /// Multiply `self` by the scalar `a`. #[inline] - fn weigh<C : Constant<Type=F>>(self, a : C) -> Weighted<Self, C> { + fn weigh<C : Constant<RealField=Self::RealField>>(self, a : C) -> Weighted<Self, C> { 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<F : Num, A> { +pub trait GlobalAnalysis<A> { /// 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<F, A, N, L> GlobalAnalysis<F, A, N> for L -// where L : LocalAnalysis<F, A, N> { -// #[inline] -// fn global_analysis(&self) -> Bounds<F> { -// 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<F : Num, A, const N : usize> : GlobalAnalysis<F, A> + Support<F, N> { +pub trait LocalAnalysis<A, LocalSet> : GlobalAnalysis<A> { /// 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<F, N>) -> 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`]`<F, Bounds<F>>` /// [`Apply`] is not a supertrait to allow flexibility in the implementation of either /// reference or non-reference arguments. -pub trait Bounded<F : Float> : GlobalAnalysis<F, Bounds<F>> { +pub trait Bounded : GlobalAnalysis<Bounds<Self::Field>> + HasScalarField { /// Return lower and upper bounds for the values of of `self`. #[inline] - fn bounds(&self) -> Bounds<F> { + fn bounds(&self) -> Bounds<Self::Field> { self.global_analysis() } } -impl<F : Float, T : GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T { } +impl<T : GlobalAnalysis<Bounds<Self::Field>> + 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<T, F : Num, const N : usize> HasScalarField for Shift<T, F, N> { + type Field = F; +} + impl<'a, T, V, F : Float, const N : usize> Apply<&'a Loc<F, N>> for Shift<T,F,N> where T : Apply<Loc<F, N>, Output=V> { type Output = V; @@ -145,7 +140,8 @@ } } -impl<'a, T, V, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> for Shift<T,F,N> +impl<'a, T, V : HasRealField<RealField=F>, F : Float, const N : usize> +Differentiable<&'a Loc<F, N>> for Shift<T,F,N> where T : Differentiable<Loc<F, N>, Derivative=V> { type Derivative = V; #[inline] @@ -154,7 +150,8 @@ } } -impl<'a, T, V, F : Float, const N : usize> Differentiable<Loc<F, N>> for Shift<T,F,N> +impl<'a, T, V : HasRealField<RealField=F>, F : Float, const N : usize> +Differentiable<Loc<F, N>> for Shift<T,F,N> where T : Differentiable<Loc<F, N>, Derivative=V> { type Derivative = V; #[inline] @@ -163,8 +160,8 @@ } } -impl<'a, T, F : Float, const N : usize> Support<F,N> for Shift<T,F,N> -where T : Support<F, N> { +impl<'a, T, F : Float, const N : usize> Support<N> for Shift<T,F,N> +where T : Support<N, RealField = F> { #[inline] fn support_hint(&self) -> Cube<F,N> { self.base_fn.support_hint().shift(&self.shift) @@ -188,16 +185,17 @@ } -impl<'a, T, F : Float, const N : usize> GlobalAnalysis<F, Bounds<F>> for Shift<T,F,N> -where T : LocalAnalysis<F, Bounds<F>, N> { +impl<'a, T, F : Float, const N : usize> GlobalAnalysis<Bounds<F>> for Shift<T,F,N> +where T : GlobalAnalysis<Bounds<F>> { #[inline] fn global_analysis(&self) -> Bounds<F> { self.base_fn.global_analysis() } } -impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Shift<T,F,N> -where T : LocalAnalysis<F, Bounds<F>, N> { +impl<'a, T, F : Float, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> +for Shift<T,F,N> +where T : LocalAnalysis<Bounds<F>, Cube<F, N>> { #[inline] fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 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<F, $norm> for Shift<T,F,N> - where T : Norm<F, $norm> { + impl<'a, T, const N : usize> Norm<$norm> for Shift<T,T::Field,N> + 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<T, C, F : Float> HasScalarField for Weighted<T, C> +where T : HasRealField<RealField = F>, + C : Constant<RealField = F> { + type Field = F; +} + impl<'a, T, V, F : Float, C, const N : usize> Apply<&'a Loc<F, N>> for Weighted<T, C> where T : for<'b> Apply<&'b Loc<F, N>, Output=V>, V : std::ops::Mul<F,Output=V>, - C : Constant<Type=F> { + C : Constant<RealField=F> { type Output = V; #[inline] fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { @@ -242,7 +246,7 @@ impl<'a, T, V, F : Float, C, const N : usize> Apply<Loc<F, N>> for Weighted<T, C> where T : Apply<Loc<F, N>, Output=V>, V : std::ops::Mul<F,Output=V>, - C : Constant<Type=F> { + C : Constant<RealField=F> { type Output = V; #[inline] fn apply(&self, x : Loc<F, N>) -> Self::Output { @@ -250,10 +254,11 @@ } } -impl<'a, T, V, F : Float, C, const N : usize> Differentiable<&'a Loc<F, N>> for Weighted<T, C> -where T : for<'b> Differentiable<&'b Loc<F, N>, Derivative=V>, +impl<'a, T, V : HasRealField<RealField=F>, F : Float, C, const N : usize> +Differentiable<&'a Loc<F, N>> for Weighted<T, C> +where T : for<'b> Differentiable<&'b Loc<F, N>, Derivative=V, RealField=F>, V : std::ops::Mul<F, Output=V>, - C : Constant<Type=F> { + C : Constant<RealField=F> { type Derivative = V; #[inline] fn differential(&self, x : &'a Loc<F, N>) -> Self::Derivative { @@ -261,10 +266,11 @@ } } -impl<'a, T, V, F : Float, C, const N : usize> Differentiable<Loc<F, N>> for Weighted<T, C> -where T : Differentiable<Loc<F, N>, Derivative=V>, +impl<'a, T, V : HasRealField<RealField = F>, F : Float, C, const N : usize> +Differentiable<Loc<F, N>> for Weighted<T, C> +where T : Differentiable<Loc<F, N>, Derivative=V, RealField = F>, V : std::ops::Mul<F, Output=V>, - C : Constant<Type=F> { + C : Constant<RealField=F> { type Derivative = V; #[inline] fn differential(&self, x : Loc<F, N>) -> Self::Derivative { @@ -272,9 +278,9 @@ } } -impl<'a, T, F : Float, C, const N : usize> Support<F,N> for Weighted<T, C> -where T : Support<F, N>, - C : Constant<Type=F> { +impl<'a, T, F : Float, C, const N : usize> Support<N> for Weighted<T, C> +where T : Support<N, RealField = F>, + C : Constant<RealField=F> { #[inline] fn support_hint(&self) -> Cube<F,N> { @@ -296,9 +302,9 @@ } } -impl<'a, T, F : Float, C> GlobalAnalysis<F, Bounds<F>> for Weighted<T, C> -where T : GlobalAnalysis<F, Bounds<F>>, - C : Constant<Type=F> { +impl<'a, T, F : Float, C> GlobalAnalysis<Bounds<F>> for Weighted<T, C> +where T : GlobalAnalysis<Bounds<F>>, + C : Constant<RealField=F> { #[inline] fn global_analysis(&self) -> Bounds<F> { let Bounds(lower, upper) = self.base_fn.global_analysis(); @@ -310,9 +316,10 @@ } } -impl<'a, T, F : Float, C, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Weighted<T, C> -where T : LocalAnalysis<F, Bounds<F>, N>, - C : Constant<Type=F> { +impl<'a, T, F : Float, C, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> +for Weighted<T, C> +where T : LocalAnalysis<Bounds<F>, Cube<F, N>>, + C : Constant<RealField=F> { #[inline] fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { 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<F, $norm> for Weighted<T,F> - where T : Norm<F, $norm> { + impl<'a, T, F : Float> Norm<$norm> for Weighted<T,F> + 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<F, N>> for Normalised<T> -where T : Norm<F, L1> + for<'b> Apply<&'b Loc<F, N>, Output=F> { +where T : Norm<L1, Field=F> + for<'b> Apply<&'b Loc<F, N>, Output=F> { type Output = F; #[inline] fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { @@ -391,7 +399,7 @@ } impl<'a, T, F : Float, const N : usize> Apply<Loc<F, N>> for Normalised<T> -where T : Norm<F, L1> + Apply<Loc<F,N>, Output=F> { +where T : Norm<L1, Field = F> + Apply<Loc<F,N>, Output=F> { type Output = F; #[inline] fn apply(&self, x : Loc<F, N>) -> Self::Output { @@ -400,8 +408,8 @@ } } -impl<'a, T, F : Float, const N : usize> Support<F,N> for Normalised<T> -where T : Norm<F, L1> + Support<F, N> { +impl<'a, T, F : Float, const N : usize> Support<N> for Normalised<T> +where T : Norm<L1> + Support<N, RealField = F> { #[inline] fn support_hint(&self) -> Cube<F,N> { @@ -423,8 +431,8 @@ } } -impl<'a, T, F : Float> GlobalAnalysis<F, Bounds<F>> for Normalised<T> -where T : Norm<F, L1> + GlobalAnalysis<F, Bounds<F>> { +impl<'a, T, F : Float> GlobalAnalysis<Bounds<F>> for Normalised<T> +where T : Norm<L1, Field = F> + GlobalAnalysis<Bounds<F>> { #[inline] fn global_analysis(&self) -> Bounds<F> { let Bounds(lower, upper) = self.0.global_analysis(); @@ -435,8 +443,9 @@ } } -impl<'a, T, F : Float, const N : usize> LocalAnalysis<F, Bounds<F>, N> for Normalised<T> -where T : Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N> { +impl<'a, T, F : Float, const N : usize> LocalAnalysis<Bounds<F>, Cube<F, N>> +for Normalised<T> +where T : Norm<L1, Field = F> + LocalAnalysis<Bounds<F>, Cube<F, N>> { #[inline] fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { let Bounds(lower, upper) = self.0.local_analysis(cube); @@ -447,23 +456,26 @@ } } -impl<'a, T, F : Float> Norm<F, L1> for Normalised<T> -where T : Norm<F, L1> { +impl<'a, T> HasScalarField for Normalised<T> where T : HasScalarField { + type Field = T::Field; +} + +impl<'a, T> Norm<L1> for Normalised<T> where T : Norm<L1> { #[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<F, $norm> for Normalised<T> - where T : Norm<F, $norm> + Norm<F, L1> { + impl<'a, T> Norm<$norm> for Normalised<T> where T : Norm<$norm> + Norm<L1> { + #[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<F : Num, S : Support<F, N>, const N : usize> LocalAnalysis<F, NullAggregator, N> for S { - fn local_analysis(&self, _cube : &Cube<F, N>) -> NullAggregator { NullAggregator } -} - -impl<F : Float, S : Bounded<F>, const N : usize> LocalAnalysis<F, Bounds<F>, N> for S { - #[inline] - fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { - self.bounds(cube) - } -}*/ /// Generator of [`Support`]-implementing component functions based on low storage requirement /// [ids][`Self::Id`]. -pub trait SupportGenerator<F : Float, const N : usize> -: MulAssign<F> + DivAssign<F> + Neg<Output=Self> + Clone + Sync + Send + 'static { +pub trait SupportGenerator<const N : usize> +: MulAssign<Self::Field> + DivAssign<Self::Field> + Neg<Output=Self> + 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<F, N>; + type SupportType : 'static + Support<N, RealField=Self::RealField>; /// An iterator over all the [`Support`]s of the generator. type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a;