| 1 /*! |
1 /*! |
| 2 Second order polynomical (P2) models on real intervals and planar 2D simplices. |
2 Second order polynomical (P2) models on real intervals and planar 2D simplices. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use crate::types::*; |
5 use super::base::{LocalModel, RealLocalModel}; |
| 6 use crate::loc::Loc; |
|
| 7 use crate::sets::{Set,NPolygon,SpannedHalfspace}; |
|
| 8 use crate::linsolve::*; |
|
| 9 use crate::euclidean::Euclidean; |
6 use crate::euclidean::Euclidean; |
| 10 use crate::instance::Instance; |
7 use crate::instance::Instance; |
| 11 use super::base::{LocalModel,RealLocalModel}; |
8 use crate::linsolve::*; |
| |
9 use crate::loc::Loc; |
| 12 use crate::sets::Cube; |
10 use crate::sets::Cube; |
| |
11 use crate::sets::{NPolygon, Set, SpannedHalfspace}; |
| |
12 use crate::types::*; |
| 13 use numeric_literals::replace_float_literals; |
13 use numeric_literals::replace_float_literals; |
| 14 |
14 |
| 15 /// Type for simplices of arbitrary dimension `N`. |
15 /// Type for simplices of arbitrary dimension `N`. |
| 16 /// |
16 /// |
| 17 /// The type parameter `D` indicates the number of nodes. (Rust's const generics do not currently |
17 /// The type parameter `D` indicates the number of nodes. (Rust's const generics do not currently |
| 18 /// allow its automatic calculation from `N`.) |
18 /// allow its automatic calculation from `N`.) |
| 19 pub struct Simplex<F : Float, const N : usize, const D : usize>(pub [Loc<F, N>; D]); |
19 pub struct Simplex<F: Float, const N: usize, const D: usize>(pub [Loc<N, F>; D]); |
| 20 /// A two-dimensional planar simplex |
20 /// A two-dimensional planar simplex |
| 21 pub type PlanarSimplex<F> = Simplex<F, 2, 3>; |
21 pub type PlanarSimplex<F> = Simplex<F, 2, 3>; |
| 22 /// A real interval |
22 /// A real interval |
| 23 pub type RealInterval<F> = Simplex<F, 1, 2>; |
23 pub type RealInterval<F> = Simplex<F, 1, 2>; |
| 24 |
24 |
| 25 /// Calculates (a+b)/2 |
25 /// Calculates (a+b)/2 |
| 26 #[inline] |
26 #[inline] |
| 27 #[replace_float_literals(F::cast_from(literal))] |
27 #[replace_float_literals(F::cast_from(literal))] |
| 28 pub(crate) fn midpoint<F : Float, const N : usize>(a : &Loc<F,N>, b : &Loc<F,N>) -> Loc<F, N> { |
28 pub(crate) fn midpoint<F: Float, const N: usize>(a: &Loc<N, F>, b: &Loc<N, F>) -> Loc<N, F> { |
| 29 (a+b)/2.0 |
29 (a + b) / 2.0 |
| 30 } |
30 } |
| 31 |
31 |
| 32 impl<'a, F : Float> Set<Loc<F,1>> for RealInterval<F> { |
32 impl<'a, F: Float> Set<Loc<1, F>> for RealInterval<F> { |
| 33 #[inline] |
33 #[inline] |
| 34 fn contains<I : Instance<Loc<F, 1>>>(&self, z : I) -> bool { |
34 fn contains<I: Instance<Loc<1, F>>>(&self, z: I) -> bool { |
| 35 let &Loc([x]) = z.ref_instance(); |
35 let &Loc([x]) = z.ref_instance(); |
| 36 let &[Loc([x0]), Loc([x1])] = &self.0; |
36 let &[Loc([x0]), Loc([x1])] = &self.0; |
| 37 (x0 < x && x < x1) || (x1 < x && x < x0) |
37 (x0 < x && x < x1) || (x1 < x && x < x0) |
| 38 } |
38 } |
| 39 } |
39 } |
| 40 |
40 |
| 41 impl<'a, F : Float> Set<Loc<F,2>> for PlanarSimplex<F> { |
41 impl<'a, F: Float> Set<Loc<2, F>> for PlanarSimplex<F> { |
| 42 #[inline] |
42 #[inline] |
| 43 fn contains<I : Instance<Loc<F, 2>>>(&self, z : I) -> bool { |
43 fn contains<I: Instance<Loc<2, F>>>(&self, z: I) -> bool { |
| 44 let &[x0, x1, x2] = &self.0; |
44 let &[x0, x1, x2] = &self.0; |
| 45 NPolygon([[x0, x1].spanned_halfspace(), |
45 NPolygon([ |
| 46 [x1, x2].spanned_halfspace(), |
46 [x0, x1].spanned_halfspace(), |
| 47 [x2, x0].spanned_halfspace()]).contains(z) |
47 [x1, x2].spanned_halfspace(), |
| |
48 [x2, x0].spanned_halfspace(), |
| |
49 ]) |
| |
50 .contains(z) |
| 48 } |
51 } |
| 49 } |
52 } |
| 50 |
53 |
| 51 trait P2Powers { |
54 trait P2Powers { |
| 52 type Output; |
55 type Output; |
| 56 fn p2powers_full(&self) -> Self::Full; |
59 fn p2powers_full(&self) -> Self::Full; |
| 57 fn p2powers_diff(&self) -> Self::Diff; |
60 fn p2powers_diff(&self) -> Self::Diff; |
| 58 } |
61 } |
| 59 |
62 |
| 60 #[replace_float_literals(F::cast_from(literal))] |
63 #[replace_float_literals(F::cast_from(literal))] |
| 61 impl<F : Float> P2Powers for Loc<F, 1> { |
64 impl<F: Float> P2Powers for Loc<1, F> { |
| 62 type Output = Loc<F, 1>; |
65 type Output = Loc<1, F>; |
| 63 type Full = Loc<F, 3>; |
66 type Full = Loc<3, F>; |
| 64 type Diff = Loc<Loc<F, 1>, 1>; |
67 type Diff = Loc<1, Loc<1, F>>; |
| 65 |
68 |
| 66 #[inline] |
69 #[inline] |
| 67 fn p2powers(&self) -> Self::Output { |
70 fn p2powers(&self) -> Self::Output { |
| 68 let &Loc([x0]) = self; |
71 let &Loc([x0]) = self; |
| 69 [x0*x0].into() |
72 [x0 * x0].into() |
| 70 } |
73 } |
| 71 |
74 |
| 72 #[inline] |
75 #[inline] |
| 73 fn p2powers_full(&self) -> Self::Full { |
76 fn p2powers_full(&self) -> Self::Full { |
| 74 let &Loc([x0]) = self; |
77 let &Loc([x0]) = self; |
| 75 [1.0, x0, x0*x0].into() |
78 [1.0, x0, x0 * x0].into() |
| 76 } |
79 } |
| 77 |
80 |
| 78 #[inline] |
81 #[inline] |
| 79 fn p2powers_diff(&self) -> Self::Diff { |
82 fn p2powers_diff(&self) -> Self::Diff { |
| 80 let &Loc([x0]) = self; |
83 let &Loc([x0]) = self; |
| 81 [[x0+x0].into()].into() |
84 [[x0 + x0].into()].into() |
| 82 } |
85 } |
| 83 } |
86 } |
| 84 |
87 |
| 85 #[replace_float_literals(F::cast_from(literal))] |
88 #[replace_float_literals(F::cast_from(literal))] |
| 86 impl<F : Float> P2Powers for Loc<F, 2> { |
89 impl<F: Float> P2Powers for Loc<2, F> { |
| 87 type Output = Loc<F, 3>; |
90 type Output = Loc<3, F>; |
| 88 type Full = Loc<F, 6>; |
91 type Full = Loc<6, F>; |
| 89 type Diff = Loc<Loc<F, 3>, 2>; |
92 type Diff = Loc<2, Loc<3, F>>; |
| 90 |
93 |
| 91 #[inline] |
94 #[inline] |
| 92 fn p2powers(&self) -> Self::Output { |
95 fn p2powers(&self) -> Self::Output { |
| 93 let &Loc([x0, x1]) = self; |
96 let &Loc([x0, x1]) = self; |
| 94 [x0*x0, x0*x1, x1*x1].into() |
97 [x0 * x0, x0 * x1, x1 * x1].into() |
| 95 } |
98 } |
| 96 |
99 |
| 97 #[inline] |
100 #[inline] |
| 98 fn p2powers_full(&self) -> Self::Full { |
101 fn p2powers_full(&self) -> Self::Full { |
| 99 let &Loc([x0, x1]) = self; |
102 let &Loc([x0, x1]) = self; |
| 100 [1.0, x0, x1, x0*x0, x0*x1, x1*x1].into() |
103 [1.0, x0, x1, x0 * x0, x0 * x1, x1 * x1].into() |
| 101 } |
104 } |
| 102 |
105 |
| 103 #[inline] |
106 #[inline] |
| 104 fn p2powers_diff(&self) -> Self::Diff { |
107 fn p2powers_diff(&self) -> Self::Diff { |
| 105 let &Loc([x0, x1]) = self; |
108 let &Loc([x0, x1]) = self; |
| 106 [[x0+x0, x1, 0.0].into(), [0.0, x0, x1+x1].into()].into() |
109 [[x0 + x0, x1, 0.0].into(), [0.0, x0, x1 + x1].into()].into() |
| 107 } |
110 } |
| 108 } |
111 } |
| 109 |
112 |
| 110 /// A trait for generating second order polynomial model of dimension `N` on `Self´. |
113 /// A trait for generating second order polynomial model of dimension `N` on `Self´. |
| 111 /// |
114 /// |
| 112 /// `Self` should present a subset aset of elements of the type [`Loc`]`<F, N>`. |
115 /// `Self` should present a subset aset of elements of the type [`Loc`]`<F, N>`. |
| 113 pub trait P2Model<F : Num, const N : usize> { |
116 pub trait P2Model<F: Num, const N: usize> { |
| 114 /// Implementation type of the second order polynomical model. |
117 /// Implementation type of the second order polynomical model. |
| 115 /// Typically a [`P2LocalModel`]. |
118 /// Typically a [`P2LocalModel`]. |
| 116 type Model : LocalModel<Loc<F,N>,F>; |
119 type Model: LocalModel<Loc<N, F>, F>; |
| 117 /// Generates a second order polynomial model of the function `g` on `Self`. |
120 /// Generates a second order polynomial model of the function `g` on `Self`. |
| 118 fn p2_model<G : Fn(&Loc<F, N>) -> F>(&self, g : G) -> Self::Model; |
121 fn p2_model<G: Fn(&Loc<N, F>) -> F>(&self, g: G) -> Self::Model; |
| 119 } |
122 } |
| 120 |
123 |
| 121 /// A local second order polynomical model of dimension `N` with `E` edges |
124 /// A local second order polynomical model of dimension `N` with `E` edges |
| 122 pub struct P2LocalModel<F : Num, const N : usize, const E : usize/*, const V : usize, const Q : usize*/> { |
125 pub struct P2LocalModel< |
| 123 a0 : F, |
126 F: Num, |
| 124 a1 : Loc<F, N>, |
127 const N: usize, |
| 125 a2 : Loc<F, E>, |
128 const E: usize, /*, const V : usize, const Q : usize*/ |
| 126 //node_values : Loc<F, V>, |
129 > { |
| 127 //edge_values : Loc<F, Q>, |
130 a0: F, |
| |
131 a1: Loc<N, F>, |
| |
132 a2: Loc<E, F>, |
| |
133 //node_values : Loc<V, F>, |
| |
134 //edge_values : Loc<Q, F>, |
| 128 } |
135 } |
| 129 |
136 |
| 130 // |
137 // |
| 131 // 1D planar model construction |
138 // 1D planar model construction |
| 132 // |
139 // |
| 133 |
140 |
| 134 impl<F : Float> RealInterval<F> { |
141 impl<F: Float> RealInterval<F> { |
| 135 #[inline] |
142 #[inline] |
| 136 fn midpoints(&self) -> [Loc<F, 1>; 1] { |
143 fn midpoints(&self) -> [Loc<1, F>; 1] { |
| 137 let [ref n0, ref n1] = &self.0; |
144 let [ref n0, ref n1] = &self.0; |
| 138 let n01 = midpoint(n0, n1); |
145 let n01 = midpoint(n0, n1); |
| 139 [n01] |
146 [n01] |
| 140 } |
147 } |
| 141 } |
148 } |
| 142 |
149 |
| 143 impl<F : Float> P2LocalModel<F, 1, 1/*, 2, 0*/> { |
150 impl<F: Float> P2LocalModel<F, 1, 1 /*, 2, 0*/> { |
| 144 /// Creates a new 1D second order polynomical model based on three nodal coordinates and |
151 /// Creates a new 1D second order polynomical model based on three nodal coordinates and |
| 145 /// corresponding function values. |
152 /// corresponding function values. |
| 146 #[inline] |
153 #[inline] |
| 147 pub fn new( |
154 pub fn new(&[n0, n1, n01]: &[Loc<1, F>; 3], &[v0, v1, v01]: &[F; 3]) -> Self { |
| 148 &[n0, n1, n01] : &[Loc<F, 1>; 3], |
155 let p = move |x: &Loc<1, F>, v: F| { |
| 149 &[v0, v1, v01] : &[F; 3], |
|
| 150 ) -> Self { |
|
| 151 let p = move |x : &Loc<F, 1>, v : F| { |
|
| 152 let Loc([c, d, e]) = x.p2powers_full(); |
156 let Loc([c, d, e]) = x.p2powers_full(); |
| 153 [c, d, e, v] |
157 [c, d, e, v] |
| 154 }; |
158 }; |
| 155 let [a0, a1, a11] = linsolve([ |
159 let [a0, a1, a11] = linsolve([p(&n0, v0), p(&n1, v1), p(&n01, v01)]); |
| 156 p(&n0, v0), |
|
| 157 p(&n1, v1), |
|
| 158 p(&n01, v01) |
|
| 159 ]); |
|
| 160 P2LocalModel { |
160 P2LocalModel { |
| 161 a0 : a0, |
161 a0: a0, |
| 162 a1 : [a1].into(), |
162 a1: [a1].into(), |
| 163 a2 : [a11].into(), |
163 a2: [a11].into(), |
| 164 //node_values : [v0, v1].into(), |
164 //node_values : [v0, v1].into(), |
| 165 //edge_values: [].into(), |
165 //edge_values: [].into(), |
| 166 } |
166 } |
| 167 } |
167 } |
| 168 } |
168 } |
| 169 |
169 |
| 170 impl<F : Float> P2Model<F,1> for RealInterval<F> { |
170 impl<F: Float> P2Model<F, 1> for RealInterval<F> { |
| 171 type Model = P2LocalModel<F, 1, 1/*, 2, 0*/>; |
171 type Model = P2LocalModel<F, 1, 1 /*, 2, 0*/>; |
| 172 |
172 |
| 173 #[inline] |
173 #[inline] |
| 174 fn p2_model<G : Fn(&Loc<F, 1>) -> F>(&self, g : G) -> Self::Model { |
174 fn p2_model<G: Fn(&Loc<1, F>) -> F>(&self, g: G) -> Self::Model { |
| 175 let [n01] = self.midpoints(); |
175 let [n01] = self.midpoints(); |
| 176 let [n0, n1] = self.0; |
176 let [n0, n1] = self.0; |
| 177 let vals = [g(&n0), g(&n1), g(&n01)]; |
177 let vals = [g(&n0), g(&n1), g(&n01)]; |
| 178 let nodes = [n0, n1, n01]; |
178 let nodes = [n0, n1, n01]; |
| 179 Self::Model::new(&nodes, &vals) |
179 Self::Model::new(&nodes, &vals) |
| 180 } |
180 } |
| 182 |
182 |
| 183 // |
183 // |
| 184 // 2D planar model construction |
184 // 2D planar model construction |
| 185 // |
185 // |
| 186 |
186 |
| 187 impl<F : Float> PlanarSimplex<F> { |
187 impl<F: Float> PlanarSimplex<F> { |
| 188 #[inline] |
188 #[inline] |
| 189 /// Returns the midpoints of all the edges of the simplex |
189 /// Returns the midpoints of all the edges of the simplex |
| 190 fn midpoints(&self) -> [Loc<F, 2>; 3] { |
190 fn midpoints(&self) -> [Loc<2, F>; 3] { |
| 191 let [ref n0, ref n1, ref n2] = &self.0; |
191 let [ref n0, ref n1, ref n2] = &self.0; |
| 192 let n01 = midpoint(n0, n1); |
192 let n01 = midpoint(n0, n1); |
| 193 let n12 = midpoint(n1, n2); |
193 let n12 = midpoint(n1, n2); |
| 194 let n20 = midpoint(n2, n0); |
194 let n20 = midpoint(n2, n0); |
| 195 [n01, n12, n20] |
195 [n01, n12, n20] |
| 196 } |
196 } |
| 197 } |
197 } |
| 198 |
198 |
| 199 impl<F : Float> P2LocalModel<F, 2, 3/*, 3, 3*/> { |
199 impl<F: Float> P2LocalModel<F, 2, 3 /*, 3, 3*/> { |
| 200 /// Creates a new 2D second order polynomical model based on six nodal coordinates and |
200 /// Creates a new 2D second order polynomical model based on six nodal coordinates and |
| 201 /// corresponding function values. |
201 /// corresponding function values. |
| 202 #[inline] |
202 #[inline] |
| 203 pub fn new( |
203 pub fn new( |
| 204 &[n0, n1, n2, n01, n12, n20] : &[Loc<F, 2>; 6], |
204 &[n0, n1, n2, n01, n12, n20]: &[Loc<2, F>; 6], |
| 205 &[v0, v1, v2, v01, v12, v20] : &[F; 6], |
205 &[v0, v1, v2, v01, v12, v20]: &[F; 6], |
| 206 ) -> Self { |
206 ) -> Self { |
| 207 let p = move |x : &Loc<F,2>, v :F| { |
207 let p = move |x: &Loc<2, F>, v: F| { |
| 208 let Loc([c, d, e, f, g, h]) = x.p2powers_full(); |
208 let Loc([c, d, e, f, g, h]) = x.p2powers_full(); |
| 209 [c, d, e, f, g, h, v] |
209 [c, d, e, f, g, h, v] |
| 210 }; |
210 }; |
| 211 let [a0, a1, a2, a11, a12, a22] = linsolve([ |
211 let [a0, a1, a2, a11, a12, a22] = linsolve([ |
| 212 p(&n0, v0), |
212 p(&n0, v0), |
| 215 p(&n01, v01), |
215 p(&n01, v01), |
| 216 p(&n12, v12), |
216 p(&n12, v12), |
| 217 p(&n20, v20), |
217 p(&n20, v20), |
| 218 ]); |
218 ]); |
| 219 P2LocalModel { |
219 P2LocalModel { |
| 220 a0 : a0, |
220 a0: a0, |
| 221 a1 : [a1, a2].into(), |
221 a1: [a1, a2].into(), |
| 222 a2 : [a11, a12, a22].into(), |
222 a2: [a11, a12, a22].into(), |
| 223 //node_values : [v0, v1, v2].into(), |
223 //node_values : [v0, v1, v2].into(), |
| 224 //edge_values: [v01, v12, v20].into(), |
224 //edge_values: [v01, v12, v20].into(), |
| 225 } |
225 } |
| 226 } |
226 } |
| 227 } |
227 } |
| 228 |
228 |
| 229 impl<F : Float> P2Model<F,2> for PlanarSimplex<F> { |
229 impl<F: Float> P2Model<F, 2> for PlanarSimplex<F> { |
| 230 type Model = P2LocalModel<F, 2, 3/*, 3, 3*/>; |
230 type Model = P2LocalModel<F, 2, 3 /*, 3, 3*/>; |
| 231 |
231 |
| 232 #[inline] |
232 #[inline] |
| 233 fn p2_model<G : Fn(&Loc<F, 2>) -> F>(&self, g : G) -> Self::Model { |
233 fn p2_model<G: Fn(&Loc<2, F>) -> F>(&self, g: G) -> Self::Model { |
| 234 let midpoints = self.midpoints(); |
234 let midpoints = self.midpoints(); |
| 235 let [ref n0, ref n1, ref n2] = self.0; |
235 let [ref n0, ref n1, ref n2] = self.0; |
| 236 let [ref n01, ref n12, ref n20] = midpoints; |
236 let [ref n01, ref n12, ref n20] = midpoints; |
| 237 let vals = [g(n0), g(n1), g(n2), g(n01), g(n12), g(n20)]; |
237 let vals = [g(n0), g(n1), g(n2), g(n01), g(n12), g(n20)]; |
| 238 let nodes = [*n0, *n1, *n2, *n01, *n12, *n20]; |
238 let nodes = [*n0, *n1, *n2, *n01, *n12, *n20]; |
| 240 } |
240 } |
| 241 } |
241 } |
| 242 |
242 |
| 243 macro_rules! impl_local_model { |
243 macro_rules! impl_local_model { |
| 244 ($n:literal, $e:literal, $v:literal, $q:literal) => { |
244 ($n:literal, $e:literal, $v:literal, $q:literal) => { |
| 245 impl<F : Float> LocalModel<Loc<F, $n>, F> for P2LocalModel<F, $n, $e/*, $v, $q*/> { |
245 impl<F: Float> LocalModel<Loc<$n, F>, F> for P2LocalModel<F, $n, /*, $v, $q*/ $e> { |
| 246 #[inline] |
246 #[inline] |
| 247 fn value(&self, x : &Loc<F,$n>) -> F { |
247 fn value(&self, x: &Loc<$n, F>) -> F { |
| 248 self.a0 + x.dot(&self.a1) + x.p2powers().dot(&self.a2) |
248 self.a0 + x.dot(&self.a1) + x.p2powers().dot(&self.a2) |
| 249 } |
249 } |
| 250 |
250 |
| 251 #[inline] |
251 #[inline] |
| 252 fn differential(&self, x : &Loc<F,$n>) -> Loc<F,$n> { |
252 fn differential(&self, x: &Loc<$n, F>) -> Loc<$n, F> { |
| 253 self.a1 + x.p2powers_diff().map(|di| di.dot(&self.a2)) |
253 self.a1 + x.p2powers_diff().map(|di| di.dot(&self.a2)) |
| 254 } |
254 } |
| 255 } |
255 } |
| 256 } |
256 }; |
| 257 } |
257 } |
| 258 |
258 |
| 259 impl_local_model!(1, 1, 2, 0); |
259 impl_local_model!(1, 1, 2, 0); |
| 260 impl_local_model!(2, 3, 3, 3); |
260 impl_local_model!(2, 3, 3, 3); |
| 261 |
261 |
| 262 |
|
| 263 // |
262 // |
| 264 // Minimisation |
263 // Minimisation |
| 265 // |
264 // |
| 266 |
265 |
| 267 #[replace_float_literals(F::cast_from(literal))] |
266 #[replace_float_literals(F::cast_from(literal))] |
| 268 impl<F : Float> P2LocalModel<F, 1, 1/*, 2, 0*/> { |
267 impl<F: Float> P2LocalModel<F, 1, 1 /*, 2, 0*/> { |
| 269 /// Minimises the model along the edge `[x0, x1]`. |
268 /// Minimises the model along the edge `[x0, x1]`. |
| 270 #[inline] |
269 #[inline] |
| 271 fn minimise_edge(&self, x0 : Loc<F, 1>, x1 : Loc<F,1>) -> (Loc<F,1>, F) { |
270 fn minimise_edge(&self, x0: Loc<1, F>, x1: Loc<1, F>) -> (Loc<1, F>, F) { |
| 272 let &P2LocalModel{ |
271 let &P2LocalModel { |
| 273 a1 : Loc([a1]), |
272 a1: Loc([a1]), |
| 274 a2 : Loc([a11]), |
273 a2: Loc([a11]), |
| 275 //node_values : Loc([v0, v1]), |
274 //node_values : Loc([v0, v1]), |
| 276 .. |
275 .. |
| 277 } = self; |
276 } = self; |
| 278 // We do this in cases, first trying for an interior solution, then edges. |
277 // We do this in cases, first trying for an interior solution, then edges. |
| 279 // For interior solution, first check determinant; no point trying if non-positive |
278 // For interior solution, first check determinant; no point trying if non-positive |
| 280 if a11 > 0.0 { |
279 if a11 > 0.0 { |
| 281 // An interior solution x[1] has to satisfy |
280 // An interior solution x[1] has to satisfy |
| 282 // 2a₁₁*x[1] + a₁ =0 |
281 // 2a₁₁*x[1] + a₁ =0 |
| 283 // This gives |
282 // This gives |
| 284 let t = -a1/(2.0*a11); |
283 let t = -a1 / (2.0 * a11); |
| 285 let (Loc([t0]), Loc([t1])) = (x0, x1); |
284 let (Loc([t0]), Loc([t1])) = (x0, x1); |
| 286 if (t0 <= t && t <= t1) || (t1 <= t && t <= t0) { |
285 if (t0 <= t && t <= t1) || (t1 <= t && t <= t0) { |
| 287 let x = [t].into(); |
286 let x = [t].into(); |
| 288 let v = self.value(&x); |
287 let v = self.value(&x); |
| 289 return (x, v) |
288 return (x, v); |
| 290 } |
289 } |
| 291 } |
290 } |
| 292 |
291 |
| 293 let v0 = self.value(&x0); |
292 let v0 = self.value(&x0); |
| 294 let v1 = self.value(&x1); |
293 let v1 = self.value(&x1); |
| 295 if v0 < v1 { (x0, v0) } else { (x1, v1) } |
294 if v0 < v1 { |
| 296 } |
295 (x0, v0) |
| 297 } |
296 } else { |
| 298 |
297 (x1, v1) |
| 299 impl<'a, F : Float> RealLocalModel<RealInterval<F>,Loc<F,1>,F> |
298 } |
| 300 for P2LocalModel<F, 1, 1/*, 2, 0*/> { |
299 } |
| 301 #[inline] |
300 } |
| 302 fn minimise(&self, &Simplex([x0, x1]) : &RealInterval<F>) -> (Loc<F,1>, F) { |
301 |
| |
302 impl<'a, F: Float> RealLocalModel<RealInterval<F>, Loc<1, F>, F> |
| |
303 for P2LocalModel<F, 1, 1 /*, 2, 0*/> |
| |
304 { |
| |
305 #[inline] |
| |
306 fn minimise(&self, &Simplex([x0, x1]): &RealInterval<F>) -> (Loc<1, F>, F) { |
| 303 self.minimise_edge(x0, x1) |
307 self.minimise_edge(x0, x1) |
| 304 } |
308 } |
| 305 } |
309 } |
| 306 |
310 |
| 307 #[replace_float_literals(F::cast_from(literal))] |
311 #[replace_float_literals(F::cast_from(literal))] |
| 308 impl<F : Float> P2LocalModel<F, 2, 3/*, 3, 3*/> { |
312 impl<F: Float> P2LocalModel<F, 2, 3 /*, 3, 3*/> { |
| 309 /// Minimise the 2D model along the edge `[x0, x1] = {x0 + t(x1 - x0) | t ∈ [0, 1] }`. |
313 /// Minimise the 2D model along the edge `[x0, x1] = {x0 + t(x1 - x0) | t ∈ [0, 1] }`. |
| 310 #[inline] |
314 #[inline] |
| 311 fn minimise_edge(&self, x0 : &Loc<F,2>, x1 : &Loc<F,2>/*, v0 : F, v1 : F*/) -> (Loc<F,2>, F) { |
315 fn minimise_edge( |
| |
316 &self, |
| |
317 x0: &Loc<2, F>, |
| |
318 x1: &Loc<2, F>, /*, v0 : F, v1 : F*/ |
| |
319 ) -> (Loc<2, F>, F) { |
| 312 let &P2LocalModel { |
320 let &P2LocalModel { |
| 313 a0, |
321 a0, |
| 314 a1 : Loc([a1, a2]), |
322 a1: Loc([a1, a2]), |
| 315 a2 : Loc([a11, a12, a22]), |
323 a2: Loc([a11, a12, a22]), |
| 316 .. |
324 .. |
| 317 } = self; |
325 } = self; |
| 318 let &Loc([x00, x01]) = x0; |
326 let &Loc([x00, x01]) = x0; |
| 319 let d@Loc([d0, d1]) = x1 - x0; |
327 let d @ Loc([d0, d1]) = x1 - x0; |
| 320 let b0 = a0 + a1*x00 + a2*x01 + a11*x00*x00 + a12*x00*x01 + a22*x01*x01; |
328 let b0 = a0 + a1 * x00 + a2 * x01 + a11 * x00 * x00 + a12 * x00 * x01 + a22 * x01 * x01; |
| 321 let b1 = a1*d0 + a2*d1 + 2.0*a11*d0*x00 + a12*(d0*x01 + d1*x00) + 2.0*a22*d1*x01; |
329 let b1 = a1 * d0 |
| 322 let b11 = a11*d0*d0 + a12*d0*d1 + a22*d1*d1; |
330 + a2 * d1 |
| |
331 + 2.0 * a11 * d0 * x00 |
| |
332 + a12 * (d0 * x01 + d1 * x00) |
| |
333 + 2.0 * a22 * d1 * x01; |
| |
334 let b11 = a11 * d0 * d0 + a12 * d0 * d1 + a22 * d1 * d1; |
| 323 let edge_1d_model = P2LocalModel { |
335 let edge_1d_model = P2LocalModel { |
| 324 a0 : b0, |
336 a0: b0, |
| 325 a1 : Loc([b1]), |
337 a1: Loc([b1]), |
| 326 a2 : Loc([b11]), |
338 a2: Loc([b11]), |
| 327 //node_values : Loc([v0, v1]), |
339 //node_values : Loc([v0, v1]), |
| 328 }; |
340 }; |
| 329 let (Loc([t]), v) = edge_1d_model.minimise_edge(0.0.into(), 1.0.into()); |
341 let (Loc([t]), v) = edge_1d_model.minimise_edge(0.0.into(), 1.0.into()); |
| 330 (x0 + d*t, v) |
342 (x0 + d * t, v) |
| 331 } |
343 } |
| 332 } |
344 } |
| 333 |
345 |
| 334 #[replace_float_literals(F::cast_from(literal))] |
346 #[replace_float_literals(F::cast_from(literal))] |
| 335 impl<'a, F : Float> RealLocalModel<PlanarSimplex<F>,Loc<F,2>,F> |
347 impl<'a, F: Float> RealLocalModel<PlanarSimplex<F>, Loc<2, F>, F> |
| 336 for P2LocalModel<F, 2, 3/*, 3, 3*/> { |
348 for P2LocalModel<F, 2, 3 /*, 3, 3*/> |
| 337 #[inline] |
349 { |
| 338 fn minimise(&self, el : &PlanarSimplex<F>) -> (Loc<F,2>, F) { |
350 #[inline] |
| |
351 fn minimise(&self, el: &PlanarSimplex<F>) -> (Loc<2, F>, F) { |
| 339 let &P2LocalModel { |
352 let &P2LocalModel { |
| 340 a1 : Loc([a1, a2]), |
353 a1: Loc([a1, a2]), |
| 341 a2 : Loc([a11, a12, a22]), |
354 a2: Loc([a11, a12, a22]), |
| 342 //node_values : Loc([v0, v1, v2]), |
355 //node_values : Loc([v0, v1, v2]), |
| 343 .. |
356 .. |
| 344 } = self; |
357 } = self; |
| 345 |
358 |
| 346 // We do this in cases, first trying for an interior solution, then edges. |
359 // We do this in cases, first trying for an interior solution, then edges. |
| 347 // For interior solution, first check determinant; no point trying if non-positive |
360 // For interior solution, first check determinant; no point trying if non-positive |
| 348 let r = 2.0*(a11*a22-a12*a12); |
361 let r = 2.0 * (a11 * a22 - a12 * a12); |
| 349 if r > 0.0 { |
362 if r > 0.0 { |
| 350 // An interior solution (x[1], x[2]) has to satisfy |
363 // An interior solution (x[1], x[2]) has to satisfy |
| 351 // 2a₁₁*x[1] + 2a₁₂*x[2]+a₁ =0 and 2a₂₂*x[1] + 2a₁₂*x[1]+a₂=0 |
364 // 2a₁₁*x[1] + 2a₁₂*x[2]+a₁ =0 and 2a₂₂*x[1] + 2a₁₂*x[1]+a₂=0 |
| 352 // This gives |
365 // This gives |
| 353 let x = [(a22*a1-a12*a2)/r, (a12*a1-a11*a2)/r].into(); |
366 let x = [(a22 * a1 - a12 * a2) / r, (a12 * a1 - a11 * a2) / r].into(); |
| 354 if el.contains(&x) { |
367 if el.contains(&x) { |
| 355 return (x, self.value(&x)) |
368 return (x, self.value(&x)); |
| 356 } |
369 } |
| 357 } |
370 } |
| 358 |
371 |
| 359 let &[ref x0, ref x1, ref x2] = &el.0; |
372 let &[ref x0, ref x1, ref x2] = &el.0; |
| 360 let mut min_edge = self.minimise_edge(x0, x1); |
373 let mut min_edge = self.minimise_edge(x0, x1); |
| 361 let more_edge = [self.minimise_edge(x1, x2), |
374 let more_edge = [self.minimise_edge(x1, x2), self.minimise_edge(x2, x0)]; |
| 362 self.minimise_edge(x2, x0)]; |
375 |
| 363 |
|
| 364 for edge in more_edge { |
376 for edge in more_edge { |
| 365 if edge.1 < min_edge.1 { |
377 if edge.1 < min_edge.1 { |
| 366 min_edge = edge; |
378 min_edge = edge; |
| 367 } |
379 } |
| 368 } |
380 } |
| 370 min_edge |
382 min_edge |
| 371 } |
383 } |
| 372 } |
384 } |
| 373 |
385 |
| 374 #[replace_float_literals(F::cast_from(literal))] |
386 #[replace_float_literals(F::cast_from(literal))] |
| 375 impl<'a, F : Float> RealLocalModel<Cube<F, 2>,Loc<F,2>,F> |
387 impl<'a, F: Float> RealLocalModel<Cube<2, F>, Loc<2, F>, F> |
| 376 for P2LocalModel<F, 2, 3/*, 3, 3*/> { |
388 for P2LocalModel<F, 2, 3 /*, 3, 3*/> |
| 377 #[inline] |
389 { |
| 378 fn minimise(&self, el : &Cube<F, 2>) -> (Loc<F,2>, F) { |
390 #[inline] |
| |
391 fn minimise(&self, el: &Cube<2, F>) -> (Loc<2, F>, F) { |
| 379 let &P2LocalModel { |
392 let &P2LocalModel { |
| 380 a1 : Loc([a1, a2]), |
393 a1: Loc([a1, a2]), |
| 381 a2 : Loc([a11, a12, a22]), |
394 a2: Loc([a11, a12, a22]), |
| 382 //node_values : Loc([v0, v1, v2]), |
395 //node_values : Loc([v0, v1, v2]), |
| 383 .. |
396 .. |
| 384 } = self; |
397 } = self; |
| 385 |
398 |
| 386 // We do this in cases, first trying for an interior solution, then edges. |
399 // We do this in cases, first trying for an interior solution, then edges. |
| 387 // For interior solution, first check determinant; no point trying if non-positive |
400 // For interior solution, first check determinant; no point trying if non-positive |
| 388 let r = 2.0*(a11*a22-a12*a12); |
401 let r = 2.0 * (a11 * a22 - a12 * a12); |
| 389 if r > 0.0 { |
402 if r > 0.0 { |
| 390 // An interior solution (x[1], x[2]) has to satisfy |
403 // An interior solution (x[1], x[2]) has to satisfy |
| 391 // 2a₁₁*x[1] + 2a₁₂*x[2]+a₁ =0 and 2a₂₂*x[1] + 2a₁₂*x[1]+a₂=0 |
404 // 2a₁₁*x[1] + 2a₁₂*x[2]+a₁ =0 and 2a₂₂*x[1] + 2a₁₂*x[1]+a₂=0 |
| 392 // This gives |
405 // This gives |
| 393 let x = [(a22*a1-a12*a2)/r, (a12*a1-a11*a2)/r].into(); |
406 let x = [(a22 * a1 - a12 * a2) / r, (a12 * a1 - a11 * a2) / r].into(); |
| 394 if el.contains(&x) { |
407 if el.contains(&x) { |
| 395 return (x, self.value(&x)) |
408 return (x, self.value(&x)); |
| 396 } |
409 } |
| 397 } |
410 } |
| 398 |
411 |
| 399 let [x0, x1, x2, x3] = el.corners(); |
412 let [x0, x1, x2, x3] = el.corners(); |
| 400 let mut min_edge = self.minimise_edge(&x0, &x1); |
413 let mut min_edge = self.minimise_edge(&x0, &x1); |
| 401 let more_edge = [self.minimise_edge(&x1, &x2), |
414 let more_edge = [ |
| 402 self.minimise_edge(&x2, &x3), |
415 self.minimise_edge(&x1, &x2), |
| 403 self.minimise_edge(&x3, &x0)]; |
416 self.minimise_edge(&x2, &x3), |
| |
417 self.minimise_edge(&x3, &x0), |
| |
418 ]; |
| 404 |
419 |
| 405 for edge in more_edge { |
420 for edge in more_edge { |
| 406 if edge.1 < min_edge.1 { |
421 if edge.1 < min_edge.1 { |
| 407 min_edge = edge; |
422 min_edge = edge; |
| 408 } |
423 } |