1use mathru::optimization::{
91 LevenbergMarquardt,
92 Optim
93};
94use mathru::algebra::linear::vector::vector::Vector;
95use mathru::algebra::linear::matrix::matrix::Matrix;
96use anyhow::{Result, anyhow, bail};
97
98struct MultilaterationFunction {
99 measurements: Vec<Measurement>,
100}
101
102impl MultilaterationFunction {
103 pub fn new(measurements: Vec<Measurement>) -> MultilaterationFunction {
104 MultilaterationFunction{
105 measurements,
106 }
107 }
108
109 pub fn estimate_intial_point(&self) -> Point {
110 let position_dimensions = self.measurements[0].point.0.len();
111 let number_of_measurements = self.measurements.len();
112
113 let mut initial_position = vec![0f64; position_dimensions];
114 for i in 0..number_of_measurements {
115 for j in 0..position_dimensions {
116 initial_position[j] = self
117 .measurements[i].point.0[j];
118 }
119 }
120 for i in 0..position_dimensions {
121 initial_position[i] /= number_of_measurements as f64;
122 }
123
124 Point(initial_position)
125 }
126}
127
128impl Optim<f64> for MultilaterationFunction {
129 fn eval(&self, input: &Vector<f64>) -> Vector<f64> {
130 let mut result = vec![0f64; self.measurements.len()];
131
132 for i in 0..self.measurements.len() {
133 result[i] = 0f64;
134 for j in 0..input.clone().convert_to_vec().len() {
135 result[i] +=
136 f64::powf(
137 *input.get(j) -
138 self.measurements[i].point.0[j],
139 2f64
140 );
141 }
142 result[i] -= f64::powf(self.measurements[i].distance, 2f64);
143 }
144
145 Vector::new_column(self.measurements.len(), result)
146 }
147
148 fn jacobian(&self, input: &Vector<f64>) -> Matrix<f64> {
149 let input_length = input.clone().convert_to_vec().len();
150 let data = vec![
151 0f64;
152 self.measurements.len() * input_length
153 ];
154 let mut matrix = Matrix::new(
155 self.measurements.len(),
156 input_length,
157 data
158 );
159
160 for i in 0..self.measurements.len() {
161 for j in 0..input_length {
162 *matrix.get_mut(i, j) =
163 2f64 * input.get(j) -
164 2f64 * self.measurements[i].point.0[j];
165 }
166 }
167
168 matrix
169 }
170}
171
172#[derive(Debug, Clone)]
173pub struct Point(pub Vec<f64>);
174
175#[derive(Debug)]
176pub struct Measurement {
177 point: Point,
178 distance: f64
179}
180
181impl Measurement {
182 pub fn new(point: Point, distance: f64) -> Measurement {
183 Measurement {
184 point,
185 distance
186 }
187 }
188}
189
190fn validate_measurements(measurements: &[Measurement]) -> Result<()> {
191 let point_dimensions: Vec<usize> = measurements.iter().map(|measurement| measurement.point.0.len()).collect();
192 let min_length = *point_dimensions.iter().min().ok_or(anyhow!("Failed to calculate minimal dimension"))?;
193 let max_length = *point_dimensions.iter().max().ok_or(anyhow!("Failed to calculate maximal dimension"))?;
194
195 if min_length != max_length {
196 bail!("All points must have the same dimensions");
197 }
198 if min_length < 1usize {
199 bail!("Points must contain at least one dimension");
200 }
201 Ok(())
202}
203
204pub fn multilaterate(
205 measurements: Vec<Measurement>
206) -> Result<Point> {
207 validate_measurements(&measurements)?;
208 let multilateration_function = MultilaterationFunction::new(measurements);
209 let optimization = LevenbergMarquardt::new(1000, -1f64, 1f64);
210 let initial_point = multilateration_function.estimate_intial_point();
211 let result = optimization.minimize(
212 &multilateration_function,
213 &Vector::new_column(
214 initial_point.0.len(),
215 initial_point.0
216 )
217 ).map_err(|_| anyhow!("Failed to calculate a result"))?;
218
219 Ok(Point(result.arg().convert_to_vec()))
220}
221
222#[cfg(test)]
223mod tests {
224 use super::Point;
225 use super::Measurement;
226 use super::multilaterate;
227
228 fn is_in_delta(
229 delta: f64,
230 value: f64,
231 comparison: f64
232 ) -> bool {
233 value >= (comparison - delta) && value <= (comparison + delta)
234 }
235
236 #[test]
237 fn multilat_1() {
238 let measurements = vec![
239 Measurement {
240 point: Point(vec![5.0, -6.0]),
241 distance: 8.06
242 },
243 Measurement {
244 point: Point(vec![13.0, -15.0]),
245 distance: 13.97
246 },
247 Measurement {
248 point: Point(vec![21.0, -3.0]),
249 distance: 23.32
250 },
251 Measurement {
252 point: Point(vec![12.4, -21.2]),
253 distance: 15.31
254 },
255 ];
256
257 let result = multilaterate(measurements).unwrap().0;
258 assert_eq!(result.len(), 2);
259 let delta = 1f64;
260 assert!(is_in_delta(delta, result[0], -0.6));
261 assert!(is_in_delta(delta, result[1], -11.8));
262 }
263
264 #[test]
265 fn multilat_2() {
266 let measurements = vec![
267 Measurement {
268 point: Point(vec![1.0, 1.0]),
269 distance: 0.5
270 },
271 Measurement {
272 point: Point(vec![3.0, 1.0]),
273 distance: 0.5
274 },
275 Measurement {
276 point: Point(vec![2.0, 2.0]),
277 distance: 0.5
278 }
279 ];
280
281 let result = multilaterate(measurements).unwrap().0;
282 assert_eq!(result.len(), 2);
283 let delta = 0.4;
284 assert!(is_in_delta(delta, result[0], 2.0));
285 assert!(is_in_delta(delta, result[1], 1.0));
286 }
287
288 #[test]
289 fn multilat_3() {
290 let measurements = vec![
291 Measurement {
292 point: Point(vec![1.0, 1.0]),
293 distance: 2.0
294 },
295 Measurement {
296 point: Point(vec![3.0, 1.0]),
297 distance: 2.0
298 },
299 Measurement {
300 point: Point(vec![2.0, 2.0]),
301 distance: 2.0
302 }
303 ];
304
305 let result = multilaterate(measurements).unwrap().0;
306 assert_eq!(result.len(), 2);
307 let delta = 2.0;
308 assert!(is_in_delta(delta, result[0], 2.0));
309 assert!(is_in_delta(delta, result[1], 1.0));
310 }
311
312 #[test]
313 fn multilat_4() {
314 let measurements = vec![
315 Measurement {
316 point: Point(vec![1.0, 1.0]),
317 distance: 1.0
318 },
319 Measurement {
320 point: Point(vec![1.0, 1.0]),
321 distance: 1.0
322 },
323 Measurement {
324 point: Point(vec![3.0, 1.0]),
325 distance: 1.0
326 }
327 ];
328
329 let result = multilaterate(measurements).unwrap().0;
330 assert_eq!(result.len(), 2);
331 let delta = 0.5;
332 assert!(is_in_delta(delta, result[0], 2.0));
333 assert!(is_in_delta(delta, result[1], 1.0));
334 }
335
336 #[test]
337 fn multilat_5() {
338 let measurements = vec![
339 Measurement {
340 point: Point(vec![1.0, 1.0]),
341 distance: 1.0
342 },
343 Measurement {
344 point: Point(vec![3.0, 1.0]),
345 distance: 1.0
346 }
347 ];
348
349 let result = multilaterate(measurements).unwrap().0;
350 assert_eq!(result.len(), 2);
351 let delta = 0.5;
352 assert!(is_in_delta(delta, result[0], 2.0));
353 assert!(is_in_delta(delta, result[1], 1.0));
354 }
355
356 #[test]
357 fn multilat_6() {
358 let measurements = vec![
359 Measurement {
360 point: Point(vec![1.0, 1.0]),
361 distance: 0.9
362 },
363 Measurement {
364 point: Point(vec![3.0, 1.0]),
365 distance: 1.0
366 },
367 Measurement {
368 point: Point(vec![2.0, 2.0]),
369 distance: 1.0
370 }
371 ];
372
373 let result = multilaterate(measurements).unwrap().0;
374 assert_eq!(result.len(), 2);
375 let delta = 0.1;
376 assert!(is_in_delta(delta, result[0], 2.0));
377 assert!(is_in_delta(delta, result[1], 1.0));
378 }
379
380 #[test]
381 fn multilat_7() {
382 let measurements = vec![
383 Measurement {
384 point: Point(vec![1.0, 1.0, 1.0]),
385 distance: 1.0
386 },
387 Measurement {
388 point: Point(vec![3.0, 1.0, 1.0]),
389 distance: 1.0
390 },
391 Measurement {
392 point: Point(vec![2.0, 2.0, 1.0]),
393 distance: 1.0
394 }
395 ];
396
397 let result = multilaterate(measurements).unwrap().0;
398 assert_eq!(result.len(), 3);
399 let delta = 0.1;
400 assert!(is_in_delta(delta, result[0], 2.0));
401 assert!(is_in_delta(delta, result[1], 1.0));
402 assert!(is_in_delta(delta, result[2], 1.0));
403 }
404
405 #[test]
406 fn multilat_fails_on_different_dimension() {
407 let measurements = vec![
408 Measurement {
409 point: Point(vec![1.0, 1.0 ]),
410 distance: 1.0
411 },
412 Measurement {
413 point: Point(vec![3.0, 1.0, 1.0]),
414 distance: 1.0
415 },
416 Measurement {
417 point: Point(vec![2.0, 1.0]),
418 distance: 1.0
419 }
420 ];
421
422 let result = multilaterate(measurements);
423 assert!(result.is_err());
424 }
425
426 #[test]
427 fn multilat_fails_on_zero_dimensions() {
428 let measurements = vec![
429 Measurement {
430 point: Point(vec![]),
431 distance: 1.0
432 },
433 Measurement {
434 point: Point(vec![]),
435 distance: 1.0
436 },
437 Measurement {
438 point: Point(vec![]),
439 distance: 1.0
440 }
441 ];
442
443 let result = multilaterate(measurements);
444 assert!(result.is_err());
445 }
446}