Mon, 01 Sep 2025 20:55:34 -0500
lots of space changes
use std::iter::Chain; use std::sync::Arc; use crate::iter::{MapF, MapZ, Mappable}; use crate::loc::Loc; use crate::mapping::{ ClosedSpace, DifferentiableImpl, DifferentiableMapping, Instance, Mapping, Space, }; use crate::sets::Cube; use crate::types::*; use super::aggregator::*; use super::support::*; /// A structure for storing two [`SupportGenerator`]s summed/chain together. /// /// This is needed to work with sums of different types of [`Support`]s. #[derive(Debug, Clone)] pub struct BothGenerators<A, B>(pub(super) Arc<A>, pub(super) Arc<B>); /// A structure for a [`Support`] that can be either `A` or `B`. /// /// This is needed to work with sums of different types of [`Support`]s. #[derive(Debug, Clone)] pub enum EitherSupport<B, A> { Left(A), Right(B), } // We need type alias bounds to access associate types. #[allow(type_alias_bounds)] type BothAllDataIter< 'a, F, G1: SupportGenerator<N, F>, G2: SupportGenerator<N, F>, const N: usize, > = Chain< MapF<G1::AllDataIter<'a>, (usize, EitherSupport<G2::SupportType, G1::SupportType>)>, MapZ<G2::AllDataIter<'a>, usize, (usize, EitherSupport<G2::SupportType, G1::SupportType>)>, >; impl<G1, G2> BothGenerators<G1, G2> { /// Helper for [`all_left_data`]. #[inline] fn map_left<F: Float, const N: usize>( (d, support): (G1::Id, G1::SupportType), ) -> (usize, EitherSupport<G2::SupportType, G1::SupportType>) where G1: SupportGenerator<N, F, Id = usize>, G2: SupportGenerator<N, F, Id = usize>, { let id: usize = d.into(); (id.into(), EitherSupport::Left(support)) } /// Helper for [`all_right_data`]. #[inline] fn map_right<F: Float, const N: usize>( n0: &usize, (d, support): (G2::Id, G2::SupportType), ) -> (usize, EitherSupport<G2::SupportType, G1::SupportType>) where G1: SupportGenerator<N, F, Id = usize>, G2: SupportGenerator<N, F, Id = usize>, { let id: usize = d.into(); ((n0 + id).into(), EitherSupport::Right(support)) } /// Calls [`SupportGenerator::all_data`] on the “left” support generator. /// /// Converts both the id and the [`Support`] into a form that corresponds to `BothGenerators`. #[inline] pub(super) fn all_left_data<F: Float, const N: usize>( &self, ) -> MapF<G1::AllDataIter<'_>, (usize, EitherSupport<G2::SupportType, G1::SupportType>)> where G1: SupportGenerator<N, F, Id = usize>, G2: SupportGenerator<N, F, Id = usize>, { self.0.all_data().mapF(Self::map_left) } /// Calls [`SupportGenerator::all_data`] on the “right” support generator. /// /// Converts both the id and the [`Support`] into a form that corresponds to `BothGenerators`. #[inline] pub(super) fn all_right_data<F: Float, const N: usize>( &self, ) -> MapZ<G2::AllDataIter<'_>, usize, (usize, EitherSupport<G2::SupportType, G1::SupportType>)> where G1: SupportGenerator<N, F, Id = usize>, G2: SupportGenerator<N, F, Id = usize>, { let n0 = self.0.support_count(); self.1.all_data().mapZ(n0, Self::map_right) } } impl<F: Float, G1, G2, const N: usize> SupportGenerator<N, F> for BothGenerators<G1, G2> where G1: SupportGenerator<N, F, Id = usize>, G2: SupportGenerator<N, F, Id = usize>, { type Id = usize; type SupportType = EitherSupport<G2::SupportType, G1::SupportType>; type AllDataIter<'a> = BothAllDataIter<'a, F, G1, G2, N> where G1: 'a, G2: 'a; #[inline] fn support_for(&self, id: Self::Id) -> Self::SupportType { let n0 = self.0.support_count(); if id < n0 { EitherSupport::Left(self.0.support_for(id.into())) } else { EitherSupport::Right(self.1.support_for((id - n0).into())) } } #[inline] fn support_count(&self) -> usize { self.0.support_count() + self.1.support_count() } #[inline] fn all_data(&self) -> Self::AllDataIter<'_> { self.all_left_data().chain(self.all_right_data()) } } impl<F: Float, S1, S2, const N: usize> Support<N, F> for EitherSupport<S2, S1> where S1: Support<N, F>, S2: Support<N, F>, { #[inline] fn support_hint(&self) -> Cube<N, F> { match self { EitherSupport::Left(ref a) => a.support_hint(), EitherSupport::Right(ref b) => b.support_hint(), } } #[inline] fn in_support(&self, x: &Loc<N, F>) -> bool { match self { EitherSupport::Left(ref a) => a.in_support(x), EitherSupport::Right(ref b) => b.in_support(x), } } #[inline] fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] { match self { EitherSupport::Left(ref a) => a.bisection_hint(cube), EitherSupport::Right(ref b) => b.bisection_hint(cube), } } } impl<F: Float, A, S1, S2, const N: usize> LocalAnalysis<F, A, N> for EitherSupport<S2, S1> where A: Aggregator, S1: LocalAnalysis<F, A, N>, S2: LocalAnalysis<F, A, N>, { #[inline] fn local_analysis(&self, cube: &Cube<N, F>) -> A { match self { EitherSupport::Left(ref a) => a.local_analysis(cube), EitherSupport::Right(ref b) => b.local_analysis(cube), } } } impl<F: Float, A, S1, S2> GlobalAnalysis<F, A> for EitherSupport<S2, S1> where A: Aggregator, S1: GlobalAnalysis<F, A>, S2: GlobalAnalysis<F, A>, { #[inline] fn global_analysis(&self) -> A { match self { EitherSupport::Left(ref a) => a.global_analysis(), EitherSupport::Right(ref b) => b.global_analysis(), } } } impl<F, S1, S2, X> Mapping<X> for EitherSupport<S2, S1> where F: ClosedSpace, X: Space, S1: Mapping<X, Codomain = F>, S2: Mapping<X, Codomain = F>, { type Codomain = F; #[inline] fn apply<I: Instance<X>>(&self, x: I) -> F { match self { EitherSupport::Left(ref a) => a.apply(x), EitherSupport::Right(ref b) => b.apply(x), } } } impl<X, S1, S2, O> DifferentiableImpl<X> for EitherSupport<S2, S1> where O: ClosedSpace, X: ClosedSpace, S1: DifferentiableMapping<X, DerivativeDomain = O>, S2: DifferentiableMapping<X, DerivativeDomain = O>, { type Derivative = O; #[inline] fn differential_impl<I: Instance<X>>(&self, x: I) -> O { match self { EitherSupport::Left(ref a) => a.differential(x), EitherSupport::Right(ref b) => b.differential(x), } } } macro_rules! make_either_scalarop_rhs { ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { impl<F: Float, G1, G2> std::ops::$trait_assign<F> for BothGenerators<G1, G2> where G1: std::ops::$trait_assign<F> + Clone, G2: std::ops::$trait_assign<F> + Clone, { #[inline] fn $fn_assign(&mut self, t: F) { Arc::make_mut(&mut self.0).$fn_assign(t); Arc::make_mut(&mut self.1).$fn_assign(t); } } impl<'a, F: Float, G1, G2> std::ops::$trait<F> for &'a BothGenerators<G1, G2> where &'a G1: std::ops::$trait<F, Output = G1>, &'a G2: std::ops::$trait<F, Output = G2>, { type Output = BothGenerators<G1, G2>; #[inline] fn $fn(self, t: F) -> BothGenerators<G1, G2> { BothGenerators(Arc::new(self.0.$fn(t)), Arc::new(self.1.$fn(t))) } } }; } make_either_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); make_either_scalarop_rhs!(Div, div, DivAssign, div_assign); impl<G1, G2> std::ops::Neg for BothGenerators<G1, G2> where G1: std::ops::Neg + Clone, G2: std::ops::Neg + Clone, { type Output = BothGenerators<G1::Output, G2::Output>; #[inline] fn neg(self) -> Self::Output { BothGenerators( Arc::new(Arc::unwrap_or_clone(self.0).neg()), Arc::new(Arc::unwrap_or_clone(self.1).neg()), ) } } /* impl<'a, G1, G2> std::ops::Neg for &'a BothGenerators<G1, G2> where &'a G1 : std::ops::Neg, &'a G2 : std::ops::Neg, { type Output = BothGenerators<<&'a G1 as std::ops::Neg>::Output, <&'a G2 as std::ops::Neg>::Output>; fn neg(self) -> Self::Output { BothGenerators(self.0.neg(), self.1.neg()) } } */