src/bisection_tree/support.rs

branch
dev
changeset 81
d2acaaddd9af
parent 47
a0db98c16ab5
--- 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;
 

mercurial