src/lingrid.rs

branch
dev
changeset 124
6aa955ad8122
parent 8
4e09b7829b51
equal deleted inserted replaced
122:495448cca603 124:6aa955ad8122
13 The starting points for the use of this module are the [`linspace`], [`lingrid`], and 13 The starting points for the use of this module are the [`linspace`], [`lingrid`], and
14 [`lingrid_centered`] functions. They return a [`LinSpace`]s that implements [`IntoIterator`] for 14 [`lingrid_centered`] functions. They return a [`LinSpace`]s that implements [`IntoIterator`] for
15 iteration over the grid. Additional utility functions are in the [`Grid`] trait. 15 iteration over the grid. Additional utility functions are in the [`Grid`] trait.
16 */ 16 */
17 17
18 use crate::iter::{RestartableIterator, StatefulIterator};
19 use crate::loc::Loc;
20 use crate::maputil::{map2, map4};
21 use crate::sets::Cube;
18 use crate::types::*; 22 use crate::types::*;
19 use crate::loc::Loc; 23 use serde::{Deserialize, Serialize};
20 use crate::sets::Cube;
21 use crate::iter::{RestartableIterator, StatefulIterator};
22 use crate::maputil::{map2, map4};
23 use serde::{Serialize, Deserialize};
24 24
25 // TODO: rewrite this using crate::sets::Cube. 25 // TODO: rewrite this using crate::sets::Cube.
26 26
27 /// An abstraction of possibly multi-dimensional linear grids. 27 /// An abstraction of possibly multi-dimensional linear grids.
28 /// 28 ///
29 /// `U` is typically a `F` for a `Float` `F` for one-dimensional grids created by `linspace`, 29 /// `U` is typically a `F` for a `Float` `F` for one-dimensional grids created by `linspace`,
30 /// or [`Loc`]`<F, N>` for multi-dimensional grids created by `lingrid`. 30 /// or [`Loc`]`<N, F>` for multi-dimensional grids created by `lingrid`.
31 /// In the first case `count` of nodes is `usize`, and in the second case `[usize; N]`. 31 /// In the first case `count` of nodes is `usize`, and in the second case `[usize; N]`.
32 #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] 32 #[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)]
33 pub struct LinSpace<U, I> { 33 pub struct LinSpace<U, I> {
34 pub start : U, 34 pub start: U,
35 pub end : U, 35 pub end: U,
36 pub count : I, 36 pub count: I,
37 } 37 }
38 38
39 /// A `N`-dimensional interval divided into an indicated number of equally-spaced nodes along 39 /// A `N`-dimensional interval divided into an indicated number of equally-spaced nodes along
40 /// each dimension. 40 /// each dimension.
41 #[allow(type_alias_bounds)] // Need it to access F::CompatibleSize. 41 #[allow(type_alias_bounds)] // Need it to access F::CompatibleSize.
42 pub type LinGrid<F : Float, const N : usize> = LinSpace<Loc<F, N>, [usize; N]>; 42 pub type LinGrid<const N: usize, F: Float = f64> = LinSpace<Loc<N, F>, [usize; N]>;
43 43
44 /// Creates a [`LinSpace`] on the real line. 44 /// Creates a [`LinSpace`] on the real line.
45 pub fn linspace<F : Float>(start : F, end : F, count : usize) -> LinSpace<F, usize> { 45 pub fn linspace<F: Float>(start: F, end: F, count: usize) -> LinSpace<F, usize> {
46 LinSpace{ start : start, end : end, count : count } 46 LinSpace {
47 start: start,
48 end: end,
49 count: count,
50 }
47 } 51 }
48 52
49 /// Creates a multi-dimensional linear grid. 53 /// Creates a multi-dimensional linear grid.
50 /// 54 ///
51 /// The first and last point in each dimension are the boundaries of the corresponding 55 /// The first and last point in each dimension are the boundaries of the corresponding
52 /// dimensions of `cube`, and there are `count` nodes along each dimension. 56 /// dimensions of `cube`, and there are `count` nodes along each dimension.
53 pub fn lingrid<F : Float, const N : usize>( 57 pub fn lingrid<F: Float, const N: usize>(
54 cube : &Cube<F, N>, 58 cube: &Cube<N, F>,
55 count : &[usize; N] 59 count: &[usize; N],
56 ) -> LinSpace<Loc<F, N>, [usize; N]> { 60 ) -> LinSpace<Loc<N, F>, [usize; N]> {
57 LinSpace{ start : cube.span_start(), end : cube.span_end(), count : *count } 61 LinSpace {
62 start: cube.span_start(),
63 end: cube.span_end(),
64 count: *count,
65 }
58 } 66 }
59 67
60 /// Create a multi-dimensional linear grid with centered nodes. 68 /// Create a multi-dimensional linear grid with centered nodes.
61 /// 69 ///
62 /// There are `count` along each dimension and each node has equally-sized subcube surrounding it 70 /// There are `count` along each dimension and each node has equally-sized subcube surrounding it
63 /// inside `cube`. Thus, if $w\_i$ is the width of the cube along dimension $i$, and $n_i$ the number 71 /// inside `cube`. Thus, if $w\_i$ is the width of the cube along dimension $i$, and $n_i$ the number
64 /// of nodes, the width of the subcube along this dimension is $h_i = w\_i/(n\_i+1)$, and the first 72 /// of nodes, the width of the subcube along this dimension is $h_i = w\_i/(n\_i+1)$, and the first
65 /// and last nodes are at a distance $h\_i/2$ from the closest boundary. 73 /// and last nodes are at a distance $h\_i/2$ from the closest boundary.
66 pub fn lingrid_centered<F : Float, const N : usize>( 74 pub fn lingrid_centered<F: Float, const N: usize>(
67 cube : &Cube<F, N>, 75 cube: &Cube<N, F>,
68 count : &[usize; N] 76 count: &[usize; N],
69 ) -> LinSpace<Loc<F, N>, [usize; N]> { 77 ) -> LinSpace<Loc<N, F>, [usize; N]> {
70 let h_div_2 = map2(cube.width(), count, |w, &n| w / F::cast_from(2 * (n + 1))); 78 let h_div_2 = map2(cube.width(), count, |w, &n| w / F::cast_from(2 * (n + 1)));
71 let span_start = map2(cube.span_start(), &h_div_2, |a, &t| a + t).into(); 79 let span_start = map2(cube.span_start(), &h_div_2, |a, &t| a + t).into();
72 let span_end = map2(cube.span_end(), &h_div_2, |b, &t| b - t).into(); 80 let span_end = map2(cube.span_end(), &h_div_2, |b, &t| b - t).into();
73 LinSpace{ start : span_start, end : span_end, count : *count } 81 LinSpace {
74 } 82 start: span_start,
75 83 end: span_end,
84 count: *count,
85 }
86 }
76 87
77 /// Iterator over a `LinSpace`. 88 /// Iterator over a `LinSpace`.
78 #[derive(Clone, Debug)] 89 #[derive(Clone, Debug)]
79 pub struct LinSpaceIterator<F, I> { 90 pub struct LinSpaceIterator<F, I> {
80 lingrid : LinSpace<F,I>, 91 lingrid: LinSpace<F, I>,
81 current : Option<I>, 92 current: Option<I>,
82 } 93 }
83 94
84 /// Abstraction of a linear grid over space `U` with multi-dimensional index set `I`. 95 /// Abstraction of a linear grid over space `U` with multi-dimensional index set `I`.
85 pub trait Grid<U, I> { 96 pub trait Grid<U, I> {
86 /// Converts a linear index `i` into a grid point. 97 /// Converts a linear index `i` into a grid point.
87 fn entry_linear_unchecked(&self, i : usize) -> U; 98 fn entry_linear_unchecked(&self, i: usize) -> U;
88 // Converts a multi-dimensional index `i` into a grid point. 99 // Converts a multi-dimensional index `i` into a grid point.
89 fn entry_unchecked(&self, i : &I) -> U; 100 fn entry_unchecked(&self, i: &I) -> U;
90 101
91 // fn entry(&self, i : I) -> Option<F> 102 // fn entry(&self, i : I) -> Option<F>
92 } 103 }
93 104
94 /// Helper trait for iteration of [`Grid`]s. 105 /// Helper trait for iteration of [`Grid`]s.
95 pub trait GridIteration<F, I> { 106 pub trait GridIteration<F, I> {
96 /// Returns the next multi-dimensional index (not yet converted into grid point). 107 /// Returns the next multi-dimensional index (not yet converted into grid point).
97 fn next_index(&mut self) -> Option<I>; 108 fn next_index(&mut self) -> Option<I>;
98 } 109 }
99 110
100 impl<F : Float + CastFrom<I>, I : Unsigned> Grid<F, I> for LinSpace<F, I> { 111 impl<F: Float + CastFrom<I>, I: Unsigned> Grid<F, I> for LinSpace<F, I> {
101 /*fn entry(&self, i : I) -> Option<F> { 112 /*fn entry(&self, i : I) -> Option<F> {
102 if i < self.count { 113 if i < self.count {
103 Some(self.entry_unchecked(i)) 114 Some(self.entry_unchecked(i))
104 } else { 115 } else {
105 None 116 None
106 } 117 }
107 }*/ 118 }*/
108 119
109 #[inline] 120 #[inline]
110 fn entry_linear_unchecked(&self, i : usize) -> F { 121 fn entry_linear_unchecked(&self, i: usize) -> F {
111 self.entry_unchecked(&I::cast_from(i)) 122 self.entry_unchecked(&I::cast_from(i))
112 } 123 }
113 124
114 #[inline] 125 #[inline]
115 fn entry_unchecked(&self, i : &I) -> F { 126 fn entry_unchecked(&self, i: &I) -> F {
116 let idx = F::cast_from(*i); 127 let idx = F::cast_from(*i);
117 let scale = F::cast_from(self.count-I::ONE); 128 let scale = F::cast_from(self.count - I::ONE);
118 self.start + (self.end-self.start)*idx/scale 129 self.start + (self.end - self.start) * idx / scale
119 } 130 }
120 } 131 }
121 132
122 impl<F : Float + CastFrom<I>, I : Unsigned> GridIteration<F, I> 133 impl<F: Float + CastFrom<I>, I: Unsigned> GridIteration<F, I> for LinSpaceIterator<F, I> {
123 for LinSpaceIterator<F, I> {
124 #[inline] 134 #[inline]
125 fn next_index(&mut self) -> Option<I> { 135 fn next_index(&mut self) -> Option<I> {
126 match self.current { 136 match self.current {
127 None if I::ZERO < self.lingrid.count 137 None if I::ZERO < self.lingrid.count => {
128 => { self.current = Some(I::ZERO); self.current } 138 self.current = Some(I::ZERO);
129 Some(v) if v+I::ONE < self.lingrid.count 139 self.current
130 => { self.current = Some(v+I::ONE); self.current } 140 }
131 _ 141 Some(v) if v + I::ONE < self.lingrid.count => {
132 => { None } 142 self.current = Some(v + I::ONE);
133 } 143 self.current
134 } 144 }
135 } 145 _ => None,
136 146 }
137 impl<F : Float + CastFrom<I>, I : Unsigned, const N : usize> Grid<Loc<F,N>, [I; N]> 147 }
138 for LinSpace<Loc<F,N>, [I; N]> { 148 }
139 #[inline] 149
140 fn entry_linear_unchecked(&self, i_ : usize) -> Loc<F, N> { 150 impl<F: Float + CastFrom<I>, I: Unsigned, const N: usize> Grid<Loc<N, F>, [I; N]>
151 for LinSpace<Loc<N, F>, [I; N]>
152 {
153 #[inline]
154 fn entry_linear_unchecked(&self, i_: usize) -> Loc<N, F> {
141 let mut i = I::cast_from(i_); 155 let mut i = I::cast_from(i_);
142 let mut tmp = [I::ZERO; N]; 156 let mut tmp = [I::ZERO; N];
143 for k in 0..N { 157 for k in 0..N {
144 tmp[k] = i % self.count[k]; 158 tmp[k] = i % self.count[k];
145 i /= self.count[k]; 159 i /= self.count[k];
146 } 160 }
147 self.entry_unchecked(&tmp) 161 self.entry_unchecked(&tmp)
148 } 162 }
149 163
150 #[inline] 164 #[inline]
151 fn entry_unchecked(&self, i : &[I; N]) -> Loc<F, N> { 165 fn entry_unchecked(&self, i: &[I; N]) -> Loc<N, F> {
152 let LinSpace{ start, end, count } = self; 166 let LinSpace { start, end, count } = self;
153 map4(i, start, end, count, |&ik, &sk, &ek, &ck| { 167 map4(i, start, end, count, |&ik, &sk, &ek, &ck| {
154 let idx = F::cast_from(ik); 168 let idx = F::cast_from(ik);
155 let scale = F::cast_from(ck-I::ONE); 169 let scale = F::cast_from(ck - I::ONE);
156 sk + (ek - sk) * idx / scale 170 sk + (ek - sk) * idx / scale
157 }).into() 171 })
158 } 172 .into()
159 } 173 }
160 174 }
161 impl<F : Float + CastFrom<I>, I : Unsigned, const N : usize> GridIteration<Loc<F,N>, [I; N]> 175
162 for LinSpaceIterator<Loc<F,N>, [I; N]> { 176 impl<F: Float + CastFrom<I>, I: Unsigned, const N: usize> GridIteration<Loc<N, F>, [I; N]>
163 177 for LinSpaceIterator<Loc<N, F>, [I; N]>
178 {
164 #[inline] 179 #[inline]
165 fn next_index(&mut self) -> Option<[I; N]> { 180 fn next_index(&mut self) -> Option<[I; N]> {
166 match self.current { 181 match self.current {
167 None if self.lingrid.count.iter().all(|v| I::ZERO < *v) => { 182 None if self.lingrid.count.iter().all(|v| I::ZERO < *v) => {
168 self.current = Some([I::ZERO; N]); 183 self.current = Some([I::ZERO; N]);
169 self.current 184 self.current
170 }, 185 }
171 Some(ref mut v) => { 186 Some(ref mut v) => {
172 for k in 0..N { 187 for k in 0..N {
173 let a = v[k] + I::ONE; 188 let a = v[k] + I::ONE;
174 if a < self.lingrid.count[k] { 189 if a < self.lingrid.count[k] {
175 v[k] = a; 190 v[k] = a;
176 return self.current 191 return self.current;
177 } else { 192 } else {
178 v[k] = I::ZERO; 193 v[k] = I::ZERO;
179 } 194 }
180 } 195 }
181 None 196 None
182 }, 197 }
183 _ => None 198 _ => None,
184 } 199 }
185 } 200 }
186 } 201 }
187 202
188 impl<F, I> IntoIterator for LinSpace<F,I> 203 impl<F, I> IntoIterator for LinSpace<F, I>
189 where LinSpace<F, I> : Grid<F, I>, 204 where
190 LinSpaceIterator<F, I> : GridIteration<F, I> { 205 LinSpace<F, I>: Grid<F, I>,
206 LinSpaceIterator<F, I>: GridIteration<F, I>,
207 {
191 type Item = F; 208 type Item = F;
192 type IntoIter = LinSpaceIterator<F,I>; 209 type IntoIter = LinSpaceIterator<F, I>;
193 210
194 #[inline] 211 #[inline]
195 fn into_iter(self) -> Self::IntoIter { 212 fn into_iter(self) -> Self::IntoIter {
196 LinSpaceIterator { lingrid : self, current : None } 213 LinSpaceIterator {
197 } 214 lingrid: self,
198 } 215 current: None,
199 216 }
200 impl<F, I> Iterator for LinSpaceIterator<F,I> 217 }
201 where LinSpace<F, I> : Grid<F, I>, 218 }
202 LinSpaceIterator<F, I> : GridIteration<F, I> { 219
220 impl<F, I> Iterator for LinSpaceIterator<F, I>
221 where
222 LinSpace<F, I>: Grid<F, I>,
223 LinSpaceIterator<F, I>: GridIteration<F, I>,
224 {
203 type Item = F; 225 type Item = F;
204 #[inline] 226 #[inline]
205 fn next(&mut self) -> Option<F> { 227 fn next(&mut self) -> Option<F> {
206 self.next_index().map(|v| self.lingrid.entry_unchecked(&v)) 228 self.next_index().map(|v| self.lingrid.entry_unchecked(&v))
207 } 229 }
208 } 230 }
209 231
210 impl<F, I> StatefulIterator for LinSpaceIterator<F,I> 232 impl<F, I> StatefulIterator for LinSpaceIterator<F, I>
211 where LinSpace<F, I> : Grid<F, I>, 233 where
212 LinSpaceIterator<F, I> : GridIteration<F, I> { 234 LinSpace<F, I>: Grid<F, I>,
235 LinSpaceIterator<F, I>: GridIteration<F, I>,
236 {
213 #[inline] 237 #[inline]
214 fn current(&self) -> Option<F> { 238 fn current(&self) -> Option<F> {
215 self.current.as_ref().map(|c| self.lingrid.entry_unchecked(c)) 239 self.current
216 } 240 .as_ref()
217 } 241 .map(|c| self.lingrid.entry_unchecked(c))
218 242 }
219 243 }
220 impl<F, I> RestartableIterator for LinSpaceIterator<F,I> 244
221 where LinSpace<F, I> : Grid<F, I>, 245 impl<F, I> RestartableIterator for LinSpaceIterator<F, I>
222 LinSpaceIterator<F, I> : GridIteration<F, I> { 246 where
247 LinSpace<F, I>: Grid<F, I>,
248 LinSpaceIterator<F, I>: GridIteration<F, I>,
249 {
223 #[inline] 250 #[inline]
224 fn restart(&mut self) -> Option<F> { 251 fn restart(&mut self) -> Option<F> {
225 self.current = None; 252 self.current = None;
226 self.next() 253 self.next()
227 } 254 }

mercurial