| 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 } |