Tue, 25 Oct 2022 23:05:40 +0300
Added NormExponent trait for exponents of norms
| 5 | 1 | |
| 2 | use std::iter::Chain; | |
| 0 | 3 | |
| 4 | use crate::types::*; | |
| 5 | 5 | use crate::mapping::Mapping; |
| 6 | use crate::iter::{Mappable,MapF,MapZ}; | |
| 7 | use crate::sets::Cube; | |
| 8 | use crate::loc::Loc; | |
| 9 | ||
| 0 | 10 | use super::support::*; |
| 11 | use super::aggregator::*; | |
| 12 | ||
| 5 | 13 | /// A structure for storing two [`SupportGenerator`]s summed/chain together. |
| 14 | /// | |
| 15 | /// This is needed to work with sums of different types of [`Support`]s. | |
| 0 | 16 | #[derive(Debug,Clone)] |
| 17 | pub struct BothGenerators<A, B>( | |
| 18 | pub(super) A, | |
| 19 | pub(super) B, | |
| 20 | ); | |
| 21 | ||
| 5 | 22 | /// A structure for a [`Support`] that can be either `A` or `B`. |
| 23 | /// | |
| 24 | /// This is needed to work with sums of different types of [`Support`]s. | |
| 0 | 25 | #[derive(Debug,Clone)] |
| 26 | pub enum EitherSupport<A, B> { | |
| 27 | Left(A), | |
| 28 | Right(B), | |
| 29 | } | |
| 30 | ||
| 31 | // We need type alias bounds to access associate types. | |
| 32 | #[allow(type_alias_bounds)] | |
| 33 | type BothAllDataIter< | |
| 34 | 'a, F, | |
| 35 | G1 : SupportGenerator<F, N>, | |
| 36 | G2 : SupportGenerator<F, N>, | |
| 37 | const N : usize | |
| 38 | > = Chain< | |
| 39 | MapF<G1::AllDataIter<'a>, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>, | |
| 40 | MapZ<G2::AllDataIter<'a>, usize, (usize, EitherSupport<G1::SupportType, G2::SupportType>)>, | |
| 41 | >; | |
| 42 | ||
| 43 | impl<G1, G2> BothGenerators<G1, G2> { | |
| 5 | 44 | /// Helper for [`all_left_data`]. |
| 0 | 45 | #[inline] |
| 46 | fn map_left<F : Float, const N : usize>((d, support) : (G1::Id, G1::SupportType)) | |
| 47 | -> (usize, EitherSupport<G1::SupportType, G2::SupportType>) | |
| 48 | where G1 : SupportGenerator<F, N, Id=usize>, | |
| 49 | G2 : SupportGenerator<F, N, Id=usize> { | |
| 50 | ||
| 51 | let id : usize = d.into(); | |
| 52 | (id.into(), EitherSupport::Left(support)) | |
| 53 | } | |
| 54 | ||
| 5 | 55 | /// Helper for [`all_right_data`]. |
| 0 | 56 | #[inline] |
| 57 | fn map_right<F : Float, const N : usize>(n0 : &usize, (d, support) : (G2::Id, G2::SupportType)) | |
| 58 | -> (usize, EitherSupport<G1::SupportType, G2::SupportType>) | |
| 59 | where G1 : SupportGenerator<F, N, Id=usize>, | |
| 60 | G2 : SupportGenerator<F, N, Id=usize> { | |
| 61 | ||
| 62 | let id : usize = d.into(); | |
| 63 | ((n0+id).into(), EitherSupport::Right(support)) | |
| 64 | } | |
| 65 | ||
| 5 | 66 | /// Calls [`SupportGenerator::all_data`] on the “left” support generator. |
| 67 | /// | |
| 68 | /// Converts both the id and the [`Support`] into a form that corresponds to `BothGenerators`. | |
| 0 | 69 | #[inline] |
| 70 | pub(super) fn all_left_data<F : Float, const N : usize>(&self) | |
| 71 | -> MapF<G1::AllDataIter<'_>, (usize, EitherSupport<G1::SupportType, G2::SupportType>)> | |
| 72 | where G1 : SupportGenerator<F, N, Id=usize>, | |
| 73 | G2 : SupportGenerator<F, N, Id=usize> { | |
| 74 | self.0.all_data().mapF(Self::map_left) | |
| 75 | } | |
| 76 | ||
| 5 | 77 | /// Calls [`SupportGenerator::all_data`] on the “right” support generator. |
| 78 | /// | |
| 79 | /// Converts both the id and the [`Support`] into a form that corresponds to `BothGenerators`. | |
| 0 | 80 | #[inline] |
| 81 | pub(super) fn all_right_data<F : Float, const N : usize>(&self) | |
| 82 | -> MapZ<G2::AllDataIter<'_>, usize, (usize, EitherSupport<G1::SupportType, G2::SupportType>)> | |
| 83 | where G1 : SupportGenerator<F, N, Id=usize>, | |
| 84 | G2 : SupportGenerator<F, N, Id=usize> { | |
| 85 | let n0 = self.0.support_count(); | |
| 86 | self.1.all_data().mapZ(n0, Self::map_right) | |
| 87 | } | |
| 88 | } | |
| 89 | ||
| 90 | impl<F : Float, G1, G2, const N : usize> | |
| 91 | SupportGenerator<F, N> | |
| 92 | for BothGenerators<G1, G2> | |
| 93 | where G1 : SupportGenerator<F, N, Id=usize>, | |
| 94 | G2 : SupportGenerator<F, N, Id=usize> { | |
| 95 | ||
| 96 | type Id = usize; | |
| 97 | type SupportType = EitherSupport<G1::SupportType, G2::SupportType>; | |
| 98 | type AllDataIter<'a> = BothAllDataIter<'a, F, G1, G2, N> where G1 : 'a, G2 : 'a; | |
| 99 | ||
| 100 | #[inline] | |
| 101 | fn support_for(&self, id : Self::Id) | |
| 102 | -> Self::SupportType { | |
| 103 | let n0 = self.0.support_count(); | |
| 104 | if id < n0 { | |
| 105 | EitherSupport::Left(self.0.support_for(id.into())) | |
| 106 | } else { | |
| 107 | EitherSupport::Right(self.1.support_for((id-n0).into())) | |
| 108 | } | |
| 109 | } | |
| 110 | ||
| 111 | #[inline] | |
| 112 | fn support_count(&self) -> usize { | |
| 113 | self.0.support_count() + self.1.support_count() | |
| 114 | } | |
| 115 | ||
| 116 | #[inline] | |
| 117 | fn all_data(&self) -> Self::AllDataIter<'_> { | |
| 118 | self.all_left_data().chain(self.all_right_data()) | |
| 119 | } | |
| 120 | } | |
| 121 | ||
| 122 | impl<F: Float, S1, S2, const N : usize> Support<F, N> for EitherSupport<S1, S2> | |
| 123 | where S1 : Support<F, N>, | |
| 124 | S2 : Support<F, N> { | |
| 125 | ||
| 126 | #[inline] | |
| 127 | fn support_hint(&self) -> Cube<F,N> { | |
| 128 | match self { | |
| 129 | EitherSupport::Left(ref a) => a.support_hint(), | |
| 130 | EitherSupport::Right(ref b) => b.support_hint(), | |
| 131 | } | |
| 132 | } | |
| 133 | ||
| 134 | #[inline] | |
| 135 | fn in_support(&self, x : &Loc<F,N>) -> bool { | |
| 136 | match self { | |
| 137 | EitherSupport::Left(ref a) => a.in_support(x), | |
| 138 | EitherSupport::Right(ref b) => b.in_support(x), | |
| 139 | } | |
| 140 | } | |
| 141 | ||
| 142 | #[inline] | |
| 143 | fn bisection_hint(&self, cube : &Cube<F, N>) -> [Option<F>; N] { | |
| 144 | match self { | |
| 145 | EitherSupport::Left(ref a) => a.bisection_hint(cube), | |
| 146 | EitherSupport::Right(ref b) => b.bisection_hint(cube), | |
| 147 | } | |
| 148 | } | |
| 149 | } | |
| 150 | ||
| 151 | impl<F : Float, A, S1, S2, const N : usize> LocalAnalysis<F, A, N> for EitherSupport<S1, S2> | |
| 152 | where A : Aggregator, | |
| 153 | S1 : LocalAnalysis<F, A, N>, | |
| 154 | S2 : LocalAnalysis<F, A, N>, { | |
| 155 | ||
| 156 | #[inline] | |
| 157 | fn local_analysis(&self, cube : &Cube<F, N>) -> A { | |
| 158 | match self { | |
| 159 | EitherSupport::Left(ref a) => a.local_analysis(cube), | |
| 160 | EitherSupport::Right(ref b) => b.local_analysis(cube), | |
| 161 | } | |
| 162 | } | |
| 163 | } | |
| 164 | ||
| 165 | impl<F : Float, A, S1, S2> GlobalAnalysis<F, A> for EitherSupport<S1, S2> | |
| 166 | where A : Aggregator, | |
| 167 | S1 : GlobalAnalysis<F, A>, | |
| 168 | S2 : GlobalAnalysis<F, A>, { | |
| 169 | ||
| 170 | #[inline] | |
| 171 | fn global_analysis(&self) -> A { | |
| 172 | match self { | |
| 173 | EitherSupport::Left(ref a) => a.global_analysis(), | |
| 174 | EitherSupport::Right(ref b) => b.global_analysis(), | |
| 175 | } | |
| 176 | } | |
| 177 | } | |
| 178 | ||
| 179 | impl<F, S1, S2, X> Mapping<X> for EitherSupport<S1, S2> | |
| 180 | where S1 : Mapping<X, Codomain=F>, | |
| 181 | S2 : Mapping<X, Codomain=F> { | |
| 182 | type Codomain = F; | |
| 183 | #[inline] | |
| 184 | fn value(&self, x : X) -> F { | |
| 185 | match self { | |
| 186 | EitherSupport::Left(ref a) => a.value(x), | |
| 187 | EitherSupport::Right(ref b) => b.value(x), | |
| 188 | } | |
| 189 | } | |
| 190 | } | |
| 191 | ||
| 192 | macro_rules! make_either_scalarop_rhs { | |
| 193 | ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { | |
| 194 | impl<F : Float, G1, G2> | |
| 195 | std::ops::$trait_assign<F> | |
| 196 | for BothGenerators<G1, G2> | |
| 197 | where G1 : std::ops::$trait_assign<F>, | |
| 198 | G2 : std::ops::$trait_assign<F>, { | |
| 199 | #[inline] | |
| 200 | fn $fn_assign(&mut self, t : F) { | |
| 201 | self.0.$fn_assign(t); | |
| 202 | self.1.$fn_assign(t); | |
| 203 | } | |
| 204 | } | |
| 205 | ||
| 206 | impl<'a, F : Float, G1, G2> | |
| 207 | std::ops::$trait<F> | |
| 208 | for &'a BothGenerators<G1, G2> | |
| 209 | where &'a G1 : std::ops::$trait<F,Output=G1>, | |
| 210 | &'a G2 : std::ops::$trait<F,Output=G2> { | |
| 211 | type Output = BothGenerators<G1, G2>; | |
| 212 | #[inline] | |
| 213 | fn $fn(self, t : F) -> BothGenerators<G1, G2> { | |
| 214 | BothGenerators(self.0.$fn(t), self.1.$fn(t)) | |
| 215 | } | |
| 216 | } | |
| 217 | } | |
| 218 | } | |
| 219 | ||
| 220 | make_either_scalarop_rhs!(Mul, mul, MulAssign, mul_assign); | |
| 221 | make_either_scalarop_rhs!(Div, div, DivAssign, div_assign); | |
| 222 | ||
| 223 | impl<G1, G2> std::ops::Neg for BothGenerators<G1, G2> | |
| 224 | where G1 : std::ops::Neg, G2 : std::ops::Neg, { | |
| 225 | type Output = BothGenerators<G1::Output, G2::Output>; | |
| 226 | #[inline] | |
| 227 | fn neg(self) -> Self::Output { | |
| 228 | BothGenerators(self.0.neg(), self.1.neg()) | |
| 229 | } | |
| 230 | } | |
| 231 | /* | |
| 232 | impl<'a, G1, G2> std::ops::Neg for &'a BothGenerators<G1, G2> | |
| 233 | where &'a G1 : std::ops::Neg, &'a G2 : std::ops::Neg, { | |
| 234 | type Output = BothGenerators<<&'a G1 as std::ops::Neg>::Output, | |
| 235 | <&'a G2 as std::ops::Neg>::Output>; | |
| 236 | fn neg(self) -> Self::Output { | |
| 237 | BothGenerators(self.0.neg(), self.1.neg()) | |
| 238 | } | |
| 239 | } | |
| 240 | */ |