src/bisection_tree/support.rs

branch
dev
changeset 96
962c8e346ab9
parent 75
e9f4550cfa18
child 97
4e80fb049dca
--- a/src/bisection_tree/support.rs	Sun Apr 27 14:48:13 2025 -0500
+++ b/src/bisection_tree/support.rs	Sun Apr 27 15:45:40 2025 -0500
@@ -1,31 +1,28 @@
-
 /*!
 Traits for representing the support of a [`Mapping`], and analysing the mapping on a [`Cube`].
 */
-use serde::Serialize;
-use std::ops::{MulAssign,DivAssign,Neg};
-use crate::types::{Float, Num};
+use super::aggregator::Bounds;
+use crate::loc::Loc;
+use crate::mapping::{DifferentiableImpl, DifferentiableMapping, Instance, Mapping, Space};
 use crate::maputil::map2;
-use crate::mapping::{
-    Instance, Mapping, DifferentiableImpl, DifferentiableMapping, Space
-};
+use crate::norms::{Linfinity, Norm, L1, L2};
+pub use crate::operator_arithmetic::{Constant, Weighted};
 use crate::sets::Cube;
-use crate::loc::Loc;
-use super::aggregator::Bounds;
-use crate::norms::{Norm, L1, L2, Linfinity};
-pub use crate::operator_arithmetic::{Weighted, Constant};
+use crate::types::{Float, Num};
+use serde::Serialize;
+use std::ops::{DivAssign, MulAssign, Neg};
 
 /// A trait for working with the supports of [`Mapping`]s.
 ///
 /// `Mapping` 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<F: Num, const N: usize>: Sized + Sync + Send + 'static {
     /// 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<F, 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<F, 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;
@@ -41,14 +38,17 @@
     /// 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<F, N>) -> [Option<F>; N] {
         [None; N]
     }
 
     /// Translate `self` by `x`.
     #[inline]
-    fn shift(self, x : Loc<F, N>) -> Shift<Self, F, N> {
-        Shift { shift : x, base_fn : self }
+    fn shift(self, x: Loc<F, N>) -> Shift<Self, F, N> {
+        Shift {
+            shift: x,
+            base_fn: self,
+        }
     }
 }
 
@@ -56,7 +56,7 @@
 ///
 /// Typically `A` is an [`Aggregator`][super::aggregator::Aggregator] such as
 /// [`Bounds`][super::aggregator::Bounds].
-pub trait GlobalAnalysis<F : Num, A> {
+pub trait GlobalAnalysis<F: Num, A> {
     /// Perform global analysis of the property `A` of `Self`.
     ///
     /// As an example, in the case of `A` being [`Bounds`][super::aggregator::Bounds],
@@ -78,13 +78,13 @@
 ///
 /// 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<F: Num, A, const N: usize>: GlobalAnalysis<F, A> + Support<F, N> {
     /// 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: &Cube<F, N>) -> A;
 }
 
 /// Trait for determining the upper and lower bounds of an float-valued [`Mapping`].
@@ -92,7 +92,7 @@
 /// This is a blanket-implemented alias for [`GlobalAnalysis`]`<F, Bounds<F>>`
 /// [`Mapping`] 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<F: Float>: GlobalAnalysis<F, Bounds<F>> {
     /// Return lower and upper bounds for the values of of `self`.
     #[inline]
     fn bounds(&self) -> Bounds<F> {
@@ -100,72 +100,81 @@
     }
 }
 
-impl<F : Float, T : GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T { }
+impl<F: Float, T: GlobalAnalysis<F, Bounds<F>>> Bounded<F> for T {}
 
 /// Shift of [`Support`] and [`Mapping`]; output of [`Support::shift`].
-#[derive(Copy,Clone,Debug,Serialize)] // Serialize! but not implemented by Loc.
-pub struct Shift<T, F, const N : usize> {
-    shift : Loc<F, N>,
-    base_fn : T,
+#[derive(Copy, Clone, Debug, Serialize)] // Serialize! but not implemented by Loc.
+pub struct Shift<T, F, const N: usize> {
+    shift: Loc<F, N>,
+    base_fn: T,
 }
 
-impl<'a, T, V : Space, F : Float, const N : usize> Mapping<Loc<F, N>> for Shift<T,F,N>
-where T : Mapping<Loc<F, N>, Codomain=V> {
+impl<'a, T, V: Space, F: Float, const N: usize> Mapping<Loc<F, N>> for Shift<T, F, N>
+where
+    T: Mapping<Loc<F, N>, Codomain = V>,
+{
     type Codomain = V;
 
     #[inline]
-    fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain {
+    fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain {
         self.base_fn.apply(x.own() - &self.shift)
     }
 }
 
-impl<'a, T, V : Space, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> for Shift<T,F,N>
-where T : DifferentiableMapping<Loc<F, N>, DerivativeDomain=V> {
+impl<'a, T, V: Space, F: Float, const N: usize> DifferentiableImpl<Loc<F, N>> for Shift<T, F, N>
+where
+    T: DifferentiableMapping<Loc<F, N>, DerivativeDomain = V>,
+{
     type Derivative = V;
 
     #[inline]
-    fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative {
+    fn differential_impl<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Derivative {
         self.base_fn.differential(x.own() - &self.shift)
     }
 }
 
-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<F, N> for Shift<T, F, N>
+where
+    T: Support<F, N>,
+{
     #[inline]
-    fn support_hint(&self) -> Cube<F,N> {
+    fn support_hint(&self) -> Cube<F, N> {
         self.base_fn.support_hint().shift(&self.shift)
     }
 
     #[inline]
-    fn in_support(&self, x : &Loc<F,N>) -> bool {
+    fn in_support(&self, x: &Loc<F, N>) -> bool {
         self.base_fn.in_support(&(x - &self.shift))
     }
-    
+
     // fn fully_in_support(&self, _cube : &Cube<F,N>) -> bool {
     //     //self.base_fn.fully_in_support(cube.shift(&vectorneg(self.shift)))
     //     todo!("Not implemented, but not used at the moment")
     // }
 
     #[inline]
-    fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] {
+    fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
         let base_hint = self.base_fn.bisection_hint(cube);
         map2(base_hint, &self.shift, |h, s| h.map(|z| z + *s))
     }
-
 }
 
-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<F, Bounds<F>> for Shift<T, F, N>
+where
+    T: LocalAnalysis<F, Bounds<F>, N>,
+{
     #[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<F, Bounds<F>, N> for Shift<T, F, N>
+where
+    T: LocalAnalysis<F, Bounds<F>, N>,
+{
     #[inline]
-    fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> {
+    fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
         self.base_fn.local_analysis(&cube.shift(&(-self.shift)))
     }
 }
@@ -184,33 +193,36 @@
 
 impl_shift_norm!(L1 L2 Linfinity);
 
-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<F, N> for Weighted<T, C>
+where
+    T: Support<F, N>,
+    C: Constant<Type = F>,
+{
     #[inline]
-    fn support_hint(&self) -> Cube<F,N> {
+    fn support_hint(&self) -> Cube<F, N> {
         self.base_fn.support_hint()
     }
 
     #[inline]
-    fn in_support(&self, x : &Loc<F,N>) -> bool {
+    fn in_support(&self, x: &Loc<F, N>) -> bool {
         self.base_fn.in_support(x)
     }
-    
+
     // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
     //     self.base_fn.fully_in_support(cube)
     // }
 
     #[inline]
-    fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] {
+    fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
         self.base_fn.bisection_hint(cube)
     }
 }
 
-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<F, Bounds<F>> for Weighted<T, C>
+where
+    T: GlobalAnalysis<F, Bounds<F>>,
+    C: Constant<Type = F>,
+{
     #[inline]
     fn global_analysis(&self) -> Bounds<F> {
         let Bounds(lower, upper) = self.base_fn.global_analysis();
@@ -222,11 +234,13 @@
     }
 }
 
-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<F, Bounds<F>, N> for Weighted<T, C>
+where
+    T: LocalAnalysis<F, Bounds<F>, N>,
+    C: Constant<Type = F>,
+{
     #[inline]
-    fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> {
+    fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
         let Bounds(lower, upper) = self.base_fn.local_analysis(cube);
         debug_assert!(lower <= upper);
         match self.weight.value() {
@@ -238,31 +252,36 @@
 
 macro_rules! make_weighted_scalarop_rhs {
     ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => {
-        impl<F : Float, T> std::ops::$trait_assign<F> for Weighted<T, F> {
+        impl<F: Float, T> std::ops::$trait_assign<F> for Weighted<T, F> {
             #[inline]
-            fn $fn_assign(&mut self, t : F) {
+            fn $fn_assign(&mut self, t: F) {
                 self.weight.$fn_assign(t);
             }
         }
 
-        impl<'a, F : Float, T> std::ops::$trait<F> for Weighted<T, F> {
+        impl<'a, F: Float, T> std::ops::$trait<F> for Weighted<T, F> {
             type Output = Self;
             #[inline]
-            fn $fn(mut self, t : F) -> Self {
+            fn $fn(mut self, t: F) -> Self {
                 self.weight.$fn_assign(t);
                 self
             }
         }
 
-        impl<'a, F : Float, T> std::ops::$trait<F> for &'a Weighted<T, F>
-        where T : Clone {
+        impl<'a, F: Float, T> std::ops::$trait<F> for &'a Weighted<T, F>
+        where
+            T: Clone,
+        {
             type Output = Weighted<T, F>;
             #[inline]
-            fn $fn(self, t : F) -> Self::Output {
-                Weighted { weight : self.weight.$fn(t), base_fn : self.base_fn.clone() }
+            fn $fn(self, t: F) -> Self::Output {
+                Weighted {
+                    weight: self.weight.$fn(t),
+                    base_fn: self.base_fn.clone(),
+                }
             }
         }
-    }
+    };
 }
 
 make_weighted_scalarop_rhs!(Mul, mul, MulAssign, mul_assign);
@@ -282,52 +301,60 @@
 
 impl_weighted_norm!(L1 L2 Linfinity);
 
-
 /// Normalisation of [`Support`] and [`Mapping`] to L¹ norm 1.
 ///
 /// Currently only scalar-valued functions are supported.
 #[derive(Copy, Clone, Debug, Serialize, PartialEq)]
 pub struct Normalised<T>(
     /// The base [`Support`] or [`Mapping`].
-    pub T
+    pub T,
 );
 
-impl<'a, T, F : Float, const N : usize> Mapping<Loc<F, N>> for Normalised<T>
-where T : Norm<F, L1> + Mapping<Loc<F,N>, Codomain=F> {
+impl<'a, T, F: Float, const N: usize> Mapping<Loc<F, N>> for Normalised<T>
+where
+    T: Norm<F, L1> + Mapping<Loc<F, N>, Codomain = F>,
+{
     type Codomain = F;
 
     #[inline]
-    fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain {
+    fn apply<I: Instance<Loc<F, N>>>(&self, x: I) -> Self::Codomain {
         let w = self.0.norm(L1);
-        if w == F::ZERO { F::ZERO } else { self.0.apply(x) / w }
+        if w == F::ZERO {
+            F::ZERO
+        } else {
+            self.0.apply(x) / w
+        }
     }
 }
 
-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<F, N> for Normalised<T>
+where
+    T: Norm<F, L1> + Support<F, N>,
+{
     #[inline]
-    fn support_hint(&self) -> Cube<F,N> {
+    fn support_hint(&self) -> Cube<F, N> {
         self.0.support_hint()
     }
 
     #[inline]
-    fn in_support(&self, x : &Loc<F,N>) -> bool {
+    fn in_support(&self, x: &Loc<F, N>) -> bool {
         self.0.in_support(x)
     }
-    
+
     // fn fully_in_support(&self, cube : &Cube<F,N>) -> bool {
     //     self.0.fully_in_support(cube)
     // }
 
     #[inline]
-    fn bisection_hint(&self, cube : &Cube<F,N>) -> [Option<F>; N] {
+    fn bisection_hint(&self, cube: &Cube<F, N>) -> [Option<F>; N] {
         self.0.bisection_hint(cube)
     }
 }
 
-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<F, Bounds<F>> for Normalised<T>
+where
+    T: Norm<F, L1> + GlobalAnalysis<F, Bounds<F>>,
+{
     #[inline]
     fn global_analysis(&self) -> Bounds<F> {
         let Bounds(lower, upper) = self.0.global_analysis();
@@ -338,10 +365,12 @@
     }
 }
 
-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<F, Bounds<F>, N> for Normalised<T>
+where
+    T: Norm<F, L1> + LocalAnalysis<F, Bounds<F>, N>,
+{
     #[inline]
-    fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> {
+    fn local_analysis(&self, cube: &Cube<F, N>) -> Bounds<F> {
         let Bounds(lower, upper) = self.0.local_analysis(cube);
         debug_assert!(lower <= upper);
         let w = self.0.norm(L1);
@@ -350,12 +379,18 @@
     }
 }
 
-impl<'a, T, F : Float> Norm<F, L1> for Normalised<T>
-where T : Norm<F, L1> {
+impl<'a, T, F: Float> Norm<F, L1> for Normalised<T>
+where
+    T: Norm<F, L1>,
+{
     #[inline]
-    fn norm(&self, _ : L1) -> F {
+    fn norm(&self, _: L1) -> F {
         let w = self.0.norm(L1);
-        if w == F::ZERO { F::ZERO } else { F::ONE }
+        if w == F::ZERO {
+            F::ZERO
+        } else {
+            F::ONE
+        }
     }
 }
 
@@ -388,24 +423,26 @@
 
 /// 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<F: Float, const N: usize>:
+    MulAssign<F> + DivAssign<F> + Neg<Output = Self> + Clone + Sync + Send + 'static
+{
     /// The identification type
-    type Id : 'static + Copy;
+    type Id: 'static + Copy;
     /// The type of the [`Support`] (often also a [`Mapping`]).
-    type SupportType : 'static + Support<F, N>;
+    type SupportType: 'static + Support<F, N>;
     /// An iterator over all the [`Support`]s of the generator.
-    type AllDataIter<'a> : Iterator<Item=(Self::Id, Self::SupportType)> where Self : 'a;
+    type AllDataIter<'a>: Iterator<Item = (Self::Id, Self::SupportType)>
+    where
+        Self: 'a;
 
     /// Returns the component identified by `id`.
     ///
     /// Panics if `id` is an invalid identifier.
-    fn support_for(&self, id : Self::Id) -> Self::SupportType;
-    
+    fn support_for(&self, id: Self::Id) -> Self::SupportType;
+
     /// Returns the number of different components in this generator.
     fn support_count(&self) -> usize;
 
     /// Returns an iterator over all pairs of `(id, support)`.
     fn all_data(&self) -> Self::AllDataIter<'_>;
 }
-

mercurial