diff -r 1f19c6bbf07b -r 3868555d135c src/bisection_tree/aggregator.rs --- a/src/bisection_tree/aggregator.rs Sun Apr 27 20:29:43 2025 -0500 +++ b/src/bisection_tree/aggregator.rs Fri May 15 14:46:30 2026 -0500 @@ -2,9 +2,8 @@ Aggregation / summarisation of information in branches of bisection trees. */ +pub use crate::bounds::Bounds; use crate::types::*; -use crate::sets::Set; -use crate::instance::Instance; /// Trait for aggregating information about a branch of a [bisection tree][super::BT]. /// @@ -19,180 +18,60 @@ /// of a function on a greater domain from bounds on subdomains /// (in practise [`Cube`][crate::sets::Cube]s). /// -pub trait Aggregator : Clone + Sync + Send + 'static + std::fmt::Debug { +pub trait Aggregator: Clone + Sync + Send + 'static + std::fmt::Debug { /// Aggregate a new data to current state. - fn aggregate(&mut self, aggregates : I) - where I : Iterator; + fn aggregate(&mut self, aggregates: I) + where + I: Iterator; /// Summarise several other aggregators, resetting current state. - fn summarise<'a, I>(&'a mut self, aggregates : I) - where I : Iterator; + fn summarise<'a, I>(&'a mut self, aggregates: I) + where + I: Iterator; /// Create a new “empty” aggregate data. fn new() -> Self; } /// An [`Aggregator`] that doesn't aggregate anything. -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct NullAggregator; impl Aggregator for NullAggregator { - fn aggregate(&mut self, _aggregates : I) - where I : Iterator {} - - fn summarise<'a, I>(&'a mut self, _aggregates : I) - where I : Iterator {} - - fn new() -> Self { NullAggregator } -} - -/// Upper and lower bounds on an `F`-valued function. -#[derive(Copy,Clone,Debug)] -pub struct Bounds( - /// Lower bound - pub F, - /// Upper bound - pub F -); - -impl Bounds { - /// Returns the lower bound - #[inline] - pub fn lower(&self) -> F { self.0 } - - /// Returns the upper bound - #[inline] - pub fn upper(&self) -> F { self.1 } -} - -impl Bounds { - /// Returns a uniform bound. - /// - /// This is maximum over the absolute values of the upper and lower bound. - #[inline] - pub fn uniform(&self) -> F { - let &Bounds(lower, upper) = self; - lower.abs().max(upper.abs()) + fn aggregate(&mut self, _aggregates: I) + where + I: Iterator, + { } - /// Construct a bounds, making sure `lower` bound is less than `upper` - #[inline] - pub fn corrected(lower : F, upper : F) -> Self { - if lower <= upper { - Bounds(lower, upper) - } else { - Bounds(upper, lower) - } + fn summarise<'a, I>(&'a mut self, _aggregates: I) + where + I: Iterator, + { } - /// Refine the lower bound - #[inline] - pub fn refine_lower(&self, lower : F) -> Self { - let &Bounds(l, u) = self; - debug_assert!(l <= u); - Bounds(l.max(lower), u.max(lower)) - } - - /// Refine the lower bound - #[inline] - pub fn refine_upper(&self, upper : F) -> Self { - let &Bounds(l, u) = self; - debug_assert!(l <= u); - Bounds(l.min(upper), u.min(upper)) + fn new() -> Self { + NullAggregator } } -impl<'a, F : Float> std::ops::Add for Bounds { - type Output = Self; - #[inline] - fn add(self, Bounds(l2, u2) : Self) -> Self::Output { - let Bounds(l1, u1) = self; - debug_assert!(l1 <= u1 && l2 <= u2); - Bounds(l1 + l2, u1 + u2) - } -} - -impl<'a, F : Float> std::ops::Mul for Bounds { - type Output = Self; - #[inline] - fn mul(self, Bounds(l2, u2) : Self) -> Self::Output { - let Bounds(l1, u1) = self; - debug_assert!(l1 <= u1 && l2 <= u2); - let a = l1 * l2; - let b = u1 * u2; - // The order may flip when negative numbers are involved, so need min/max - Bounds(a.min(b), a.max(b)) - } -} - -impl std::iter::Product for Bounds { +impl Aggregator for Bounds { #[inline] - fn product(mut iter: I) -> Self - where I: Iterator { - match iter.next() { - None => Bounds(F::ZERO, F::ZERO), - Some(init) => iter.fold(init, |a, b| a*b) - } - } -} - -impl Set for Bounds { - fn contains>(&self, item : I) -> bool { - let v = item.own(); - let &Bounds(l, u) = self; - debug_assert!(l <= u); - l <= v && v <= u - } -} - -impl Bounds { - /// Calculate a common bound (glb, lub) for two bounds. - #[inline] - pub fn common(&self, &Bounds(l2, u2) : &Self) -> Self { - let &Bounds(l1, u1) = self; - debug_assert!(l1 <= u1 && l2 <= u2); - Bounds(l1.min(l2), u1.max(u2)) - } - - /// Indicates whether `Self` is a superset of the argument bound. - #[inline] - pub fn superset(&self, &Bounds(l2, u2) : &Self) -> bool { - let &Bounds(l1, u1) = self; - debug_assert!(l1 <= u1 && l2 <= u2); - l1 <= l2 && u2 <= u1 - } - - /// Returns the greatest bound contained by both argument bounds, if one exists. - #[inline] - pub fn glb(&self, &Bounds(l2, u2) : &Self) -> Option { - let &Bounds(l1, u1) = self; - debug_assert!(l1 <= u1 && l2 <= u2); - let l = l1.max(l2); - let u = u1.min(u2); - debug_assert!(l <= u); - if l < u { - Some(Bounds(l, u)) - } else { - None - } - } -} - -impl Aggregator for Bounds { - #[inline] - fn aggregate(&mut self, aggregates : I) - where I : Iterator { + fn aggregate(&mut self, aggregates: I) + where + I: Iterator, + { *self = aggregates.fold(*self, |a, b| a + b); } #[inline] - fn summarise<'a, I>(&'a mut self, mut aggregates : I) - where I : Iterator { + fn summarise<'a, I>(&'a mut self, mut aggregates: I) + where + I: Iterator, + { *self = match aggregates.next() { None => Bounds(F::ZERO, F::ZERO), // No parts in this cube; the function is zero - Some(&bounds) => { - aggregates.fold(bounds, |a, b| a.common(b)) - } + Some(&bounds) => aggregates.fold(bounds, |a, b| a.common(b)), } }