src/bisection_tree/bt.rs

branch
dev
changeset 96
962c8e346ab9
parent 9
f40dfaf2166d
child 97
4e80fb049dca
--- a/src/bisection_tree/bt.rs	Sun Apr 27 14:48:13 2025 -0500
+++ b/src/bisection_tree/bt.rs	Sun Apr 27 15:45:40 2025 -0500
@@ -1,34 +1,28 @@
-
 /*!
 Bisection tree basics, [`BT`] type and the [`BTImpl`] trait.
 */
 
-use std::slice::IterMut;
-use std::iter::once;
-use std::sync::Arc;
-use serde::{Serialize, Deserialize};
+use itertools::izip;
 pub(super) use nalgebra::Const;
-use itertools::izip;
+use serde::{Deserialize, Serialize};
+use std::iter::once;
+use std::slice::IterMut;
+use std::sync::Arc;
 
-use crate::types::{Float, Num};
-use crate::parallelism::{with_task_budget, TaskBudget};
+use super::aggregator::*;
+use super::support::*;
 use crate::coefficients::pow;
-use crate::maputil::{
-    array_init,
-    map2,
-    map2_indexed,
-    collect_into_array_unchecked
-};
+use crate::loc::Loc;
+use crate::maputil::{array_init, collect_into_array_unchecked, map2, map2_indexed};
+use crate::parallelism::{with_task_budget, TaskBudget};
 use crate::sets::Cube;
-use crate::loc::Loc;
-use super::support::*;
-use super::aggregator::*;
+use crate::types::{Float, Num};
 
 /// An enum that indicates whether a [`Node`] of a [`BT`] is uninitialised, leaf, or branch.
 ///
 /// For the type and const parametere, see the [module level documentation][super].
-#[derive(Clone,Debug)]
-pub(super) enum NodeOption<F : Num, D, A : Aggregator, const N : usize, const P : usize> {
+#[derive(Clone, Debug)]
+pub(super) enum NodeOption<F: Num, D, A: Aggregator, const N: usize, const P: usize> {
     /// Indicates an uninitilised node; may become a branch or a leaf.
     // TODO: Could optimise Uninitialised away by simply treat Leaf with an empty Vec as
     // something that can be still replaced with Branches.
@@ -44,39 +38,41 @@
 ///
 /// For the type and const parameteres, see the [module level documentation][super].
 #[derive(Clone, Debug)]
-pub struct Node<F : Num, D, A : Aggregator, const N : usize, const P : usize> {
+pub struct Node<F: Num, D, A: Aggregator, const N: usize, const P: usize> {
     /// The data or branches under the node.
-    pub(super) data : NodeOption<F, D, A, N, P>,
+    pub(super) data: NodeOption<F, D, A, N, P>,
     /// Aggregator for `data`.
-    pub(super) aggregator : A,
+    pub(super) aggregator: A,
 }
 
 /// Branching information of a [`Node`] of a [`BT`] bisection tree into `P` subnodes.
 ///
 /// For the type and const parameters, see the [module level documentation][super].
 #[derive(Clone, Debug)]
-pub(super) struct Branches<F : Num, D, A : Aggregator, const N : usize, const P : usize> {
+pub(super) struct Branches<F: Num, D, A: Aggregator, const N: usize, const P: usize> {
     /// Point for subdivision of the (unstored) [`Cube`] corresponding to the node.
-    pub(super) branch_at : Loc<F, N>,
+    pub(super) branch_at: Loc<F, N>,
     /// Subnodes
-    pub(super) nodes : [Node<F, D, A, N, P>; P],
+    pub(super) nodes: [Node<F, D, A, N, P>; P],
 }
 
 /// Dirty workaround to broken Rust drop, see [https://github.com/rust-lang/rust/issues/58068]().
-impl<F : Num, D, A : Aggregator, const N : usize, const P : usize>
-Drop for Node<F, D, A, N, P> {
+impl<F: Num, D, A: Aggregator, const N: usize, const P: usize> Drop for Node<F, D, A, N, P> {
     fn drop(&mut self) {
         use NodeOption as NO;
 
-        let process = |brc : Arc<Branches<F, D, A, N, P>>,
-                       to_drop : &mut Vec<Arc<Branches<F, D, A, N, P>>>| {
+        let process = |brc: Arc<Branches<F, D, A, N, P>>,
+                       to_drop: &mut Vec<Arc<Branches<F, D, A, N, P>>>| {
             // We only drop Branches if we have the only strong reference.
             // FIXME: update the RwLocks on Nodes.
-            Arc::try_unwrap(brc).ok().map(|branches| branches.nodes.map(|mut node| {
-                if let NO::Branches(brc2) = std::mem::replace(&mut node.data, NO::Uninitialised) {
-                    to_drop.push(brc2)
-                }
-            }));
+            Arc::try_unwrap(brc).ok().map(|branches| {
+                branches.nodes.map(|mut node| {
+                    if let NO::Branches(brc2) = std::mem::replace(&mut node.data, NO::Uninitialised)
+                    {
+                        to_drop.push(brc2)
+                    }
+                })
+            });
         };
 
         // We mark Self as NodeOption::Uninitialised, extracting the real contents.
@@ -98,9 +94,9 @@
 /// Trait for the depth of a [`BT`].
 ///
 /// This will generally be either a runtime [`DynamicDepth`] or compile-time [`Const`] depth.
-pub trait Depth : 'static + Copy + Send + Sync + std::fmt::Debug {
+pub trait Depth: 'static + Copy + Send + Sync + std::fmt::Debug {
     /// Lower depth type.
-    type Lower : Depth;
+    type Lower: Depth;
 
     /// Returns a lower depth, if there still is one.
     fn lower(&self) -> Option<Self::Lower>;
@@ -113,26 +109,26 @@
 }
 
 /// Dynamic (runtime) [`Depth`] for a [`BT`].
-#[derive(Copy,Clone,Debug,Serialize,Deserialize)]
+#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
 pub struct DynamicDepth(
     /// The depth
-    pub u8
+    pub u8,
 );
 
 impl Depth for DynamicDepth {
     type Lower = Self;
     #[inline]
     fn lower(&self) -> Option<Self> {
-        if self.0>0 {
-            Some(DynamicDepth(self.0-1))
-         } else {
+        if self.0 > 0 {
+            Some(DynamicDepth(self.0 - 1))
+        } else {
             None
         }
     }
 
     #[inline]
     fn lower_or(&self) -> Self {
-        DynamicDepth(if self.0>0 { self.0 - 1 } else { 0 })
+        DynamicDepth(if self.0 > 0 { self.0 - 1 } else { 0 })
     }
 
     #[inline]
@@ -143,9 +139,15 @@
 
 impl Depth for Const<0> {
     type Lower = Self;
-    fn lower(&self) -> Option<Self::Lower> { None }
-    fn lower_or(&self) -> Self::Lower { Const }
-    fn value(&self) -> u32 { 0 }
+    fn lower(&self) -> Option<Self::Lower> {
+        None
+    }
+    fn lower_or(&self) -> Self::Lower {
+        Const
+    }
+    fn value(&self) -> u32 {
+        0
+    }
 }
 
 macro_rules! impl_constdepth {
@@ -165,7 +167,7 @@
 /// The const parameter `P` from the [module level documentation][super] is required to satisfy
 /// `Const<P> : Branchcount<N>`.
 /// This trait is implemented for `P=pow(2, N)` for small `N`.
-pub trait BranchCount<const N : usize> {}
+pub trait BranchCount<const N: usize> {}
 macro_rules! impl_branchcount {
     ($($n:literal)*) => { $(
         impl BranchCount<$n> for Const<{pow(2, $n)}>{}
@@ -173,18 +175,19 @@
 }
 impl_branchcount!(1 2 3 4 5 6 7 8);
 
-impl<F : Float, D, A, const N : usize, const P : usize> Branches<F,D,A,N,P>
-where Const<P> : BranchCount<N>,
-      A : Aggregator
+impl<F: Float, D, A, const N: usize, const P: usize> Branches<F, D, A, N, P>
+where
+    Const<P>: BranchCount<N>,
+    A: Aggregator,
 {
     /// Returns the index in {0, …, `P`-1} for the branch to which the point `x` corresponds.
     ///
     /// This only takes the branch subdivision point $d$ into account, so is always succesfull.
     /// Thus, for this point, each branch corresponds to a quadrant of $ℝ^N$ relative to $d$.
-    fn get_node_index(&self, x : &Loc<F, N>) -> usize {
-        izip!(0..P, x.iter(), self.branch_at.iter()).map(|(i, x_i, branch_i)|
-            if x_i > branch_i { 1<<i } else { 0 }
-        ).sum()
+    fn get_node_index(&self, x: &Loc<F, N>) -> usize {
+        izip!(0..P, x.iter(), self.branch_at.iter())
+            .map(|(i, x_i, branch_i)| if x_i > branch_i { 1 << i } else { 0 })
+            .sum()
     }
 
     /// Returns the node within `Self` containing the point `x`.
@@ -192,24 +195,24 @@
     /// This only takes the branch subdivision point $d$ into account, so is always succesfull.
     /// Thus, for this point, each branch corresponds to a quadrant of $ℝ^N$ relative to $d$.
     #[inline]
-    fn get_node(&self, x : &Loc<F,N>) -> &Node<F,D,A,N,P> {
-         &self.nodes[self.get_node_index(x)]
+    fn get_node(&self, x: &Loc<F, N>) -> &Node<F, D, A, N, P> {
+        &self.nodes[self.get_node_index(x)]
     }
 }
 
 /// An iterator over the $P=2^N$ subcubes of a [`Cube`] subdivided at a point `d`.
-pub(super) struct SubcubeIter<'b, F : Float, const N : usize, const P : usize> {
-    domain : &'b Cube<F, N>,
-    branch_at : Loc<F, N>,
-    index : usize,
+pub(super) struct SubcubeIter<'b, F: Float, const N: usize, const P: usize> {
+    domain: &'b Cube<F, N>,
+    branch_at: Loc<F, N>,
+    index: usize,
 }
 
 /// Returns the `i`:th subcube of `domain` subdivided at `branch_at`.
 #[inline]
-fn get_subcube<F : Float, const N : usize>(
-    branch_at : &Loc<F, N>,
-    domain : &Cube<F, N>,
-    i : usize
+fn get_subcube<F: Float, const N: usize>(
+    branch_at: &Loc<F, N>,
+    domain: &Cube<F, N>,
+    i: usize,
 ) -> Cube<F, N> {
     map2_indexed(branch_at, domain, move |j, &branch, &[start, end]| {
         if i & (1 << j) != 0 {
@@ -217,11 +220,11 @@
         } else {
             [start, branch]
         }
-    }).into()
+    })
+    .into()
 }
 
-impl<'a, 'b, F : Float, const N : usize, const P : usize> Iterator
-for SubcubeIter<'b, F, N, P> {
+impl<'a, 'b, F: Float, const N: usize, const P: usize> Iterator for SubcubeIter<'b, F, N, P> {
     type Item = Cube<F, N>;
     #[inline]
     fn next(&mut self) -> Option<Self::Item> {
@@ -235,30 +238,30 @@
     }
 }
 
-impl<F : Float, D, A, const N : usize, const P : usize>
-Branches<F,D,A,N,P>
-where Const<P> : BranchCount<N>,
-      A : Aggregator,
-      D : 'static + Copy + Send + Sync {
-
+impl<F: Float, D, A, const N: usize, const P: usize> Branches<F, D, A, N, P>
+where
+    Const<P>: BranchCount<N>,
+    A: Aggregator,
+    D: 'static + Copy + Send + Sync,
+{
     /// Creates a new node branching structure, subdividing `domain` based on the
     /// [hint][Support::support_hint] of `support`.
-    pub(super) fn new_with<S : LocalAnalysis <F, A, N>>(
-        domain : &Cube<F,N>,
-        support : &S
-    ) -> Self {
+    pub(super) fn new_with<S: LocalAnalysis<F, A, N>>(domain: &Cube<F, N>, support: &S) -> Self {
         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])
-        }).into();
-        Branches{
-            branch_at : branch_at,
-            nodes : array_init(|| Node::new()),
+            h.unwrap_or_else(|| (r[0] + r[1]) / F::TWO)
+                .max(r[0])
+                .min(r[1])
+        })
+        .into();
+        Branches {
+            branch_at: branch_at,
+            nodes: array_init(|| Node::new()),
         }
     }
 
     /// Summarises the aggregators of these branches into `agg`
-    pub(super) fn summarise_into(&self, agg : &mut A) {
+    pub(super) fn summarise_into(&self, agg: &mut A) {
         // We need to create an array of the aggregators clones due to the RwLock.
         agg.summarise(self.nodes.iter().map(Node::get_aggregator));
     }
@@ -266,12 +269,11 @@
     /// Returns an iterator over the subcubes of `domain` subdivided at the branching point
     /// of `self`.
     #[inline]
-    pub(super) fn iter_subcubes<'b>(&self, domain : &'b Cube<F, N>)
-    -> SubcubeIter<'b, F, N, P> {
+    pub(super) fn iter_subcubes<'b>(&self, domain: &'b Cube<F, N>) -> SubcubeIter<'b, F, N, P> {
         SubcubeIter {
-            domain : domain,
-            branch_at : self.branch_at,
-            index : 0,
+            domain: domain,
+            branch_at: self.branch_at,
+            index: 0,
         }
     }
 
@@ -286,8 +288,10 @@
 
     /// Mutably iterate over all nodes and corresponding subcubes of `self`.
     #[inline]
-    pub(super) fn nodes_and_cubes_mut<'a, 'b>(&'a mut self, domain : &'b Cube<F, N>)
-    -> std::iter::Zip<IterMut<'a, Node<F,D,A,N,P>>, SubcubeIter<'b, F, N, P>> {
+    pub(super) fn nodes_and_cubes_mut<'a, 'b>(
+        &'a mut self,
+        domain: &'b Cube<F, N>,
+    ) -> std::iter::Zip<IterMut<'a, Node<F, D, A, N, P>>, SubcubeIter<'b, F, N, P>> {
         let subcube_iter = self.iter_subcubes(domain);
         self.nodes.iter_mut().zip(subcube_iter)
     }
@@ -296,12 +300,16 @@
     #[inline]
     fn recurse<'scope, 'smaller, 'refs>(
         &'smaller mut self,
-        domain : &'smaller Cube<F, N>,
-        task_budget : TaskBudget<'scope, 'refs>,
-        guard : impl Fn(&Node<F,D,A,N,P>, &Cube<F, N>) -> bool + Send + 'smaller,
-        mut f : impl for<'a> FnMut(&mut Node<F,D,A,N,P>, &Cube<F, N>, TaskBudget<'smaller, 'a>)
-                + Send + Copy + 'smaller
-    ) where 'scope : 'smaller {
+        domain: &'smaller Cube<F, N>,
+        task_budget: TaskBudget<'scope, 'refs>,
+        guard: impl Fn(&Node<F, D, A, N, P>, &Cube<F, N>) -> bool + Send + 'smaller,
+        mut f: impl for<'a> FnMut(&mut Node<F, D, A, N, P>, &Cube<F, N>, TaskBudget<'smaller, 'a>)
+            + Send
+            + Copy
+            + 'smaller,
+    ) where
+        'scope: 'smaller,
+    {
         let subs = self.nodes_and_cubes_mut(domain);
         task_budget.zoom(move |s| {
             for (node, subcube) in subs {
@@ -321,19 +329,23 @@
     ///  * `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<F, A, N>>(
+    pub(super) fn insert<'refs, 'scope, M: Depth, S: LocalAnalysis<F, A, N>>(
         &mut self,
-        domain : &Cube<F,N>,
-        d : D,
-        new_leaf_depth : M,
-        support : &S,
-        task_budget : TaskBudget<'scope, 'refs>,
+        domain: &Cube<F, N>,
+        d: D,
+        new_leaf_depth: M,
+        support: &S,
+        task_budget: TaskBudget<'scope, 'refs>,
     ) {
         let support_hint = support.support_hint();
-        self.recurse(domain, task_budget,
-                     |_, subcube| support_hint.intersects(&subcube),
-                     move |node, subcube, new_budget| node.insert(subcube, d, new_leaf_depth, support,
-                                                                  new_budget));
+        self.recurse(
+            domain,
+            task_budget,
+            |_, subcube| support_hint.intersects(&subcube),
+            move |node, subcube, new_budget| {
+                node.insert(subcube, d, new_leaf_depth, support, new_budget)
+            },
+        );
     }
 
     /// Construct a new instance of the branch for a different aggregator.
@@ -344,20 +356,24 @@
     /// generator's `SupportType`.
     pub(super) fn convert_aggregator<ANew, G>(
         self,
-        generator : &G,
-        domain : &Cube<F, N>
-    ) -> Branches<F,D,ANew,N,P>
-    where ANew : Aggregator,
-          G : SupportGenerator<F, N, Id=D>,
-          G::SupportType : LocalAnalysis<F, ANew, N> {
+        generator: &G,
+        domain: &Cube<F, N>,
+    ) -> Branches<F, D, ANew, N, P>
+    where
+        ANew: Aggregator,
+        G: SupportGenerator<F, N, Id = D>,
+        G::SupportType: LocalAnalysis<F, ANew, N>,
+    {
         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)| {
-            Node::convert_aggregator(node, generator, &subcube)
-        });
+        let new_nodes = self
+            .nodes
+            .into_iter()
+            .zip(subcube_iter)
+            .map(|(node, subcube)| Node::convert_aggregator(node, generator, &subcube));
         Branches {
-            branch_at : branch_at,
-            nodes : collect_into_array_unchecked(new_nodes),
+            branch_at: branch_at,
+            nodes: collect_into_array_unchecked(new_nodes),
         }
     }
 
@@ -367,30 +383,36 @@
     /// [`Support`]s. The `domain` is the cube corresponding to `self`.
     pub(super) fn refresh_aggregator<'refs, 'scope, G>(
         &mut self,
-        generator : &G,
-        domain : &Cube<F, N>,
-        task_budget : TaskBudget<'scope, 'refs>,
-    ) where G : SupportGenerator<F, N, Id=D>,
-            G::SupportType : LocalAnalysis<F, A, N> {
-        self.recurse(domain, task_budget,
-                     |_, _| true,
-                     move |node, subcube, new_budget| node.refresh_aggregator(generator, subcube,
-                                                                              new_budget));
+        generator: &G,
+        domain: &Cube<F, N>,
+        task_budget: TaskBudget<'scope, 'refs>,
+    ) where
+        G: SupportGenerator<F, N, Id = D>,
+        G::SupportType: LocalAnalysis<F, A, N>,
+    {
+        self.recurse(
+            domain,
+            task_budget,
+            |_, _| true,
+            move |node, subcube, new_budget| {
+                node.refresh_aggregator(generator, subcube, new_budget)
+            },
+        );
     }
 }
 
-impl<F : Float, D, A, const N : usize, const P : usize>
-Node<F,D,A,N,P>
-where Const<P> : BranchCount<N>,
-      A : Aggregator,
-      D : 'static + Copy + Send + Sync {
-
+impl<F: Float, D, A, const N: usize, const P: usize> Node<F, D, A, N, P>
+where
+    Const<P>: BranchCount<N>,
+    A: Aggregator,
+    D: 'static + Copy + Send + Sync,
+{
     /// Create a new node
     #[inline]
     pub(super) fn new() -> Self {
         Node {
-            data : NodeOption::Uninitialised,
-            aggregator : A::new(),
+            data: NodeOption::Uninitialised,
+            aggregator: A::new(),
         }
     }
 
@@ -407,7 +429,7 @@
 
     /// Get leaf data iterator
     #[inline]
-    pub(super) fn get_leaf_data_iter(&self, x : &Loc<F, N>) -> Option<std::slice::Iter<'_, D>> {
+    pub(super) fn get_leaf_data_iter(&self, x: &Loc<F, N>) -> Option<std::slice::Iter<'_, D>> {
         match self.data {
             NodeOption::Uninitialised => None,
             NodeOption::Leaf(ref data) => Some(data.iter()),
@@ -434,13 +456,13 @@
     /// 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 <F, A, N>>(
+    pub(super) fn insert<'refs, 'scope, M: Depth, S: LocalAnalysis<F, A, N>>(
         &mut self,
-        domain : &Cube<F,N>,
-        d : D,
-        new_leaf_depth : M,
-        support : &S,
-        task_budget : TaskBudget<'scope, 'refs>,
+        domain: &Cube<F, N>,
+        d: D,
+        new_leaf_depth: M,
+        support: &S,
+        task_budget: TaskBudget<'scope, 'refs>,
     ) {
         match &mut self.data {
             NodeOption::Uninitialised => {
@@ -451,10 +473,10 @@
                         self.aggregator.aggregate(once(a));
                         // TODO: this is currently a dirty hard-coded heuristic;
                         // should add capacity as a parameter
-                        let mut vec = Vec::with_capacity(2*P+1);
+                        let mut vec = Vec::with_capacity(2 * P + 1);
                         vec.push(d);
                         NodeOption::Leaf(vec)
-                    },
+                    }
                     Some(lower) => {
                         let b = Arc::new({
                             let mut b0 = Branches::new_with(domain, support);
@@ -465,19 +487,19 @@
                         NodeOption::Branches(b)
                     }
                 }
-            },
+            }
             NodeOption::Leaf(leaf) => {
                 leaf.push(d);
                 let a = support.local_analysis(&domain);
                 self.aggregator.aggregate(once(a));
-            },
+            }
             NodeOption::Branches(b) => {
                 // FIXME: recursion that may cause stack overflow if the tree becomes
                 // very deep, e.g. due to [`BTSearch::search_and_refine`].
                 let bm = Arc::make_mut(b);
                 bm.insert(domain, d, new_leaf_depth.lower_or(), support, task_budget);
                 bm.summarise_into(&mut self.aggregator);
-            },
+            }
         }
     }
 
@@ -489,18 +511,19 @@
     /// generator's `SupportType`.
     pub(super) fn convert_aggregator<ANew, G>(
         mut self,
-        generator : &G,
-        domain : &Cube<F, N>
-    ) -> Node<F,D,ANew,N,P>
-    where ANew : Aggregator,
-          G : SupportGenerator<F, N, Id=D>,
-          G::SupportType : LocalAnalysis<F, ANew, N> {
-
+        generator: &G,
+        domain: &Cube<F, N>,
+    ) -> Node<F, D, ANew, N, P>
+    where
+        ANew: Aggregator,
+        G: SupportGenerator<F, N, Id = D>,
+        G::SupportType: LocalAnalysis<F, ANew, N>,
+    {
         // The mem::replace is needed due to the [`Drop`] implementation to extract self.data.
         match std::mem::replace(&mut self.data, NodeOption::Uninitialised) {
             NodeOption::Uninitialised => Node {
-                data : NodeOption::Uninitialised,
-                aggregator : ANew::new(),
+                data: NodeOption::Uninitialised,
+                aggregator: ANew::new(),
             },
             NodeOption::Leaf(v) => {
                 let mut anew = ANew::new();
@@ -510,10 +533,10 @@
                 }));
 
                 Node {
-                    data : NodeOption::Leaf(v),
-                    aggregator : anew,
+                    data: NodeOption::Leaf(v),
+                    aggregator: anew,
                 }
-            },
+            }
             NodeOption::Branches(b) => {
                 // FIXME: recursion that may cause stack overflow if the tree becomes
                 // very deep, e.g. due to [`BTSearch::search_and_refine`].
@@ -521,8 +544,8 @@
                 let mut anew = ANew::new();
                 bnew.summarise_into(&mut anew);
                 Node {
-                    data : NodeOption::Branches(Arc::new(bnew)),
-                    aggregator : anew,
+                    data: NodeOption::Branches(Arc::new(bnew)),
+                    aggregator: anew,
                 }
             }
         }
@@ -534,20 +557,22 @@
     /// [`Support`]s. The `domain` is the cube corresponding to `self`.
     pub(super) fn refresh_aggregator<'refs, 'scope, G>(
         &mut self,
-        generator : &G,
-        domain : &Cube<F, N>,
-        task_budget : TaskBudget<'scope, 'refs>,
-    ) where G : SupportGenerator<F, N, Id=D>,
-            G::SupportType : LocalAnalysis<F, A, N> {
+        generator: &G,
+        domain: &Cube<F, N>,
+        task_budget: TaskBudget<'scope, 'refs>,
+    ) where
+        G: SupportGenerator<F, N, Id = D>,
+        G::SupportType: LocalAnalysis<F, A, N>,
+    {
         match &mut self.data {
-            NodeOption::Uninitialised => { },
+            NodeOption::Uninitialised => {}
             NodeOption::Leaf(v) => {
                 self.aggregator = A::new();
-                self.aggregator.aggregate(v.iter().map(|d| {
-                    generator.support_for(*d)
-                             .local_analysis(&domain)
-                }));
-            },
+                self.aggregator.aggregate(
+                    v.iter()
+                        .map(|d| generator.support_for(*d).local_analysis(&domain)),
+                );
+            }
             NodeOption::Branches(ref mut b) => {
                 // FIXME: recursion that may cause stack overflow if the tree becomes
                 // very deep, e.g. due to [`BTSearch::search_and_refine`].
@@ -563,11 +588,13 @@
 ///
 /// This can be removed and the methods implemented directly on [`BT`] once Rust's const generics
 /// are flexible enough to allow fixing `P=pow(2, N)`.
-pub trait BTNode<F, D, A, const N : usize>
-where F : Float,
-        D : 'static + Copy,
-        A : Aggregator {
-    type Node : Clone + std::fmt::Debug;
+pub trait BTNode<F, D, A, const N: usize>
+where
+    F: Float,
+    D: 'static + Copy,
+    A: Aggregator,
+{
+    type Node: Clone + std::fmt::Debug;
 }
 
 /// Helper structure for looking up a [`Node`] without the knowledge of `P`.
@@ -580,48 +607,48 @@
 /// Basic interface to a [`BT`] bisection tree.
 ///
 /// Further routines are provided by the [`BTSearch`][super::refine::BTSearch] trait.
-pub trait BTImpl<F : Float, const N : usize> : std::fmt::Debug + Clone + GlobalAnalysis<F, Self::Agg> {
+pub trait BTImpl<F: Float, const N: usize>:
+    std::fmt::Debug + Clone + GlobalAnalysis<F, Self::Agg>
+{
     /// The data type stored in the tree
-    type Data : 'static + Copy + Send + Sync;
+    type Data: 'static + Copy + Send + Sync;
     /// The depth type of the tree
-    type Depth : Depth;
+    type Depth: Depth;
     /// The type for the [aggregate information][Aggregator] about the `Data` stored in each node
     /// of the tree.
-    type Agg : Aggregator;
+    type Agg: Aggregator;
     /// The type of the tree with the aggregator converted to `ANew`.
-    type Converted<ANew> : BTImpl<F, N, Data=Self::Data, Agg=ANew> where ANew : Aggregator;
+    type Converted<ANew>: BTImpl<F, N, Data = Self::Data, Agg = ANew>
+    where
+        ANew: Aggregator;
 
     /// Insert the data `d` into the tree for `support`.
     ///
     /// Every leaf node of the tree that intersects the `support` will contain a copy of
     /// `d`.
-    fn insert<S : LocalAnalysis<F, Self::Agg, N>>(
-        &mut self,
-        d : Self::Data,
-        support : &S
-    );
+    fn insert<S: LocalAnalysis<F, Self::Agg, N>>(&mut self, d: Self::Data, support: &S);
 
     /// Construct a new instance of the tree for a different aggregator
     ///
     /// The `generator` is used to convert the data of type [`Self::Data`] contained in the tree
     /// into corresponding [`Support`]s.
-    fn convert_aggregator<ANew, G>(self, generator : &G)
-    -> Self::Converted<ANew>
-    where ANew : Aggregator,
-          G : SupportGenerator<F, N, Id=Self::Data>,
-          G::SupportType : LocalAnalysis<F, ANew, N>;
-
+    fn convert_aggregator<ANew, G>(self, generator: &G) -> Self::Converted<ANew>
+    where
+        ANew: Aggregator,
+        G: SupportGenerator<F, N, Id = Self::Data>,
+        G::SupportType: LocalAnalysis<F, ANew, N>;
 
     /// Refreshes the aggregator of the three after possible changes to the support generator.
     ///
     /// The `generator` is used to convert the data of type [`Self::Data`] contained in the tree
     /// into corresponding [`Support`]s.
-    fn refresh_aggregator<G>(&mut self, generator : &G)
-    where G : SupportGenerator<F, N, Id=Self::Data>,
-          G::SupportType : LocalAnalysis<F, Self::Agg, N>;
+    fn refresh_aggregator<G>(&mut self, generator: &G)
+    where
+        G: SupportGenerator<F, N, Id = Self::Data>,
+        G::SupportType: LocalAnalysis<F, Self::Agg, N>;
 
     /// Returns an iterator over all [`Self::Data`] items at the point `x` of the domain.
-    fn iter_at(&self, x : &Loc<F,N>) -> std::slice::Iter<'_, Self::Data>;
+    fn iter_at(&self, x: &Loc<F, N>) -> std::slice::Iter<'_, Self::Data>;
 
     /*
     /// Returns all [`Self::Data`] items at the point `x` of the domain.
@@ -629,7 +656,7 @@
     */
 
     /// Create a new tree on `domain` of indicated `depth`.
-    fn new(domain : Cube<F, N>, depth : Self::Depth) -> Self;
+    fn new(domain: Cube<F, N>, depth: Self::Depth) -> Self;
 }
 
 /// The main bisection tree structure.
@@ -637,20 +664,17 @@
 /// It should be accessed via the [`BTImpl`] trait to hide the `const P : usize` parameter until
 /// const generics are flexible enough to fix `P=pow(2, N)` and thus also get rid of
 /// the `BTNodeLookup : BTNode<F, D, A, N>` trait bound.
-#[derive(Clone,Debug)]
-pub struct BT<
-    M : Depth,
-    F : Float,
-    D : 'static + Copy,
-    A : Aggregator,
-    const N : usize,
-> where BTNodeLookup : BTNode<F, D, A, N> {
+#[derive(Clone, Debug)]
+pub struct BT<M: Depth, F: Float, D: 'static + Copy, A: Aggregator, const N: usize>
+where
+    BTNodeLookup: BTNode<F, D, A, N>,
+{
     /// The depth of the tree (initial, before refinement)
-    pub(super) depth : M,
+    pub(super) depth: M,
     /// The domain of the toplevel node
-    pub(super) domain : Cube<F, N>,
+    pub(super) domain: Cube<F, N>,
     /// The toplevel node of the tree
-    pub(super) topnode : <BTNodeLookup as BTNode<F, D, A, N>>::Node,
+    pub(super) topnode: <BTNodeLookup as BTNode<F, D, A, N>>::Node,
 }
 
 macro_rules! impl_bt {
@@ -739,4 +763,3 @@
 }
 
 impl_bt!(1 2 3 4);
-

mercurial