src/bisection_tree/either.rs

Mon, 24 Oct 2022 10:52:19 +0300

author
Tuomo Valkonen <tuomov@iki.fi>
date
Mon, 24 Oct 2022 10:52:19 +0300
changeset 4
61b068c50e25
parent 0
9f27689eb130
child 5
59dc4c5883f4
permissions
-rw-r--r--

Added type for numerical errors


use crate::types::*;
use super::support::*;
use crate::mapping::Mapping;
use std::iter::Chain;
use crate::iter::{Mappable,MapF,MapZ};
use super::aggregator::*;

// TODO: try to remove F and N
#[derive(Debug,Clone)]
pub struct BothGenerators<A, B>(
    pub(super) A,
    pub(super) B,
);

#[derive(Debug,Clone)]
pub enum EitherSupport<A, B> {
    Left(A),
    Right(B),
}

// We need type alias bounds to access associate types.
#[allow(type_alias_bounds)]
type BothAllDataIter<
    'a, F,
    G1 : SupportGenerator<F, N>,
    G2 : SupportGenerator<F, N>,
    const N : usize
> = Chain<
    MapF<G1::AllDataIter<'a>, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>,
    MapZ<G2::AllDataIter<'a>, usize, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>,
>;

impl<G1, G2> BothGenerators<G1, G2> {
    /// Helper for [`all_data`].
    #[inline]
    fn map_left<F : Float, const N : usize>((d, support) : (G1::Id, G1::SupportType))
    -> (usize, EitherSupport<G1::SupportType, G2::SupportType>)
    where G1 : SupportGenerator<F, N, Id=usize>,
          G2 : SupportGenerator<F, N, Id=usize> {

        let id : usize = d.into();
        (id.into(), EitherSupport::Left(support))
    }

    /// Helper for [`all_data`].
    #[inline]
    fn map_right<F : Float, const N : usize>(n0 : &usize, (d, support) : (G2::Id, G2::SupportType))
    -> (usize, EitherSupport<G1::SupportType, G2::SupportType>)
    where G1 : SupportGenerator<F, N, Id=usize>,
          G2 : SupportGenerator<F, N, Id=usize> {

        let id : usize = d.into();
        ((n0+id).into(), EitherSupport::Right(support))
    }

    #[inline]
    pub(super) fn all_left_data<F : Float, const N : usize>(&self)
    -> MapF<G1::AllDataIter<'_>, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>
    where G1 : SupportGenerator<F, N, Id=usize>,
          G2 : SupportGenerator<F, N, Id=usize> {
        self.0.all_data().mapF(Self::map_left)
    }

    #[inline]
    pub(super) fn all_right_data<F : Float, const N : usize>(&self)
    -> MapZ<G2::AllDataIter<'_>, usize, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>
    where G1 : SupportGenerator<F, N, Id=usize>,
          G2 : SupportGenerator<F, N, 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<F, N>
for BothGenerators<G1, G2>
where G1 : SupportGenerator<F, N, Id=usize>,
      G2 : SupportGenerator<F, N, Id=usize> {

    type Id = usize;
    type SupportType = EitherSupport<G1::SupportType, G2::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<F, N> for EitherSupport<S1, S2>
where S1 : Support<F, N>,
      S2 : Support<F, N> {

    #[inline]
    fn support_hint(&self) -> Cube<F,N> {
        match self {
            EitherSupport::Left(ref a) => a.support_hint(),
            EitherSupport::Right(ref b) => b.support_hint(),
        }
    }

    #[inline]
    fn in_support(&self, x : &Loc<F,N>) -> 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<F, N>) -> [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<S1, S2>
where A : Aggregator,
      S1 : LocalAnalysis<F, A, N>,
      S2 : LocalAnalysis<F, A, N>, {

    #[inline]
    fn local_analysis(&self, cube : &Cube<F, N>) -> 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<S1, S2>
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<S1, S2>
where S1 : Mapping<X, Codomain=F>,
      S2 : Mapping<X, Codomain=F> {
    type Codomain = F;
    #[inline]
    fn value(&self, x : X) -> F {
        match self {
            EitherSupport::Left(ref a) => a.value(x),
            EitherSupport::Right(ref b) => b.value(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>,
              G2 : std::ops::$trait_assign<F>, {
            #[inline]
            fn $fn_assign(&mut self, t : F) {
                self.0.$fn_assign(t);
                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(self.0.$fn(t), 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, G2 : std::ops::Neg, {
    type Output = BothGenerators<G1::Output, G2::Output>;
    #[inline]
    fn neg(self) -> Self::Output {
        BothGenerators(self.0.neg(), 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())
    }
}
*/

mercurial