| 3 For working with small vectors in $ℝ^2$ or $ℝ^3$. |
3 For working with small vectors in $ℝ^2$ or $ℝ^3$. |
| 4 */ |
4 */ |
| 5 |
5 |
| 6 use std::ops::{Add,Sub,AddAssign,SubAssign,Mul,Div,MulAssign,DivAssign,Neg,Index,IndexMut}; |
6 use std::ops::{Add,Sub,AddAssign,SubAssign,Mul,Div,MulAssign,DivAssign,Neg,Index,IndexMut}; |
| 7 use std::slice::{Iter,IterMut}; |
7 use std::slice::{Iter,IterMut}; |
| |
8 use std::fmt::{Display, Formatter}; |
| 8 use crate::types::{Float,Num,SignedNum}; |
9 use crate::types::{Float,Num,SignedNum}; |
| 9 use crate::maputil::{FixedLength,FixedLengthMut,map1,map2,map1_mut,map2_mut}; |
10 use crate::maputil::{FixedLength,FixedLengthMut,map1,map2,map1_mut,map2_mut}; |
| 10 use crate::euclidean::*; |
11 use crate::euclidean::*; |
| 11 use crate::norms::*; |
12 use crate::norms::*; |
| 12 use crate::linops::AXPY; |
13 use crate::linops::{AXPY, Mapping, Linear}; |
| |
14 use crate::instance::{Instance, BasicDecomposition}; |
| |
15 use crate::mapping::Space; |
| 13 use serde::ser::{Serialize, Serializer, SerializeSeq}; |
16 use serde::ser::{Serialize, Serializer, SerializeSeq}; |
| |
17 |
| 14 |
18 |
| 15 /// A container type for (short) `N`-dimensional vectors of element type `F`. |
19 /// A container type for (short) `N`-dimensional vectors of element type `F`. |
| 16 /// |
20 /// |
| 17 /// Supports basic operations of an [`Euclidean`] space, several [`Norm`]s, and |
21 /// Supports basic operations of an [`Euclidean`] space, several [`Norm`]s, and |
| 18 /// fused [`AXPY`] operations, among others. |
22 /// fused [`AXPY`] operations, among others. |
| 19 #[derive(Copy,Clone,Debug,PartialEq,Eq)] |
23 #[derive(Copy,Clone,Debug,PartialEq,Eq)] |
| 20 pub struct Loc<F, const N : usize>( |
24 pub struct Loc<F, const N : usize>( |
| 21 /// An array of the elements of the vector |
25 /// An array of the elements of the vector |
| 22 pub [F; N] |
26 pub [F; N] |
| 23 ); |
27 ); |
| |
28 |
| |
29 impl<F : Display, const N : usize> Display for Loc<F, N>{ |
| |
30 // Required method |
| |
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { |
| |
32 write!(f, "[")?; |
| |
33 let mut comma = ""; |
| |
34 for e in self.iter() { |
| |
35 write!(f, "{comma}{e}")?; |
| |
36 comma = ", "; |
| |
37 } |
| |
38 write!(f, "]") |
| |
39 } |
| |
40 } |
| 24 |
41 |
| 25 // Need to manually implement as [F; N] serialisation is provided only for some N. |
42 // Need to manually implement as [F; N] serialisation is provided only for some N. |
| 26 impl<F, const N : usize> Serialize for Loc<F, N> |
43 impl<F, const N : usize> Serialize for Loc<F, N> |
| 27 where |
44 where |
| 28 F: Serialize, |
45 F: Serialize, |
| 234 } |
259 } |
| 235 } |
260 } |
| 236 |
261 |
| 237 make_binop!(Add, add, AddAssign, add_assign); |
262 make_binop!(Add, add, AddAssign, add_assign); |
| 238 make_binop!(Sub, sub, SubAssign, sub_assign); |
263 make_binop!(Sub, sub, SubAssign, sub_assign); |
| |
264 |
| |
265 impl<F : Float, const N : usize> std::iter::Sum for Loc<F, N> { |
| |
266 fn sum<I: Iterator<Item = Loc<F, N>>>(mut iter: I) -> Self { |
| |
267 match iter.next() { |
| |
268 None => Self::ORIGIN, |
| |
269 Some(mut v) => { |
| |
270 for w in iter { |
| |
271 v += w |
| |
272 } |
| |
273 v |
| |
274 } |
| |
275 } |
| |
276 } |
| |
277 } |
| 239 |
278 |
| 240 macro_rules! make_scalarop_rhs { |
279 macro_rules! make_scalarop_rhs { |
| 241 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { |
280 ($trait:ident, $fn:ident, $trait_assign:ident, $fn_assign:ident) => { |
| 242 impl<F : Num, const N : usize> $trait<F> for Loc<F, N> { |
281 impl<F : Num, const N : usize> $trait<F> for Loc<F, N> { |
| 243 type Output = Loc<F, N>; |
282 type Output = Loc<F, N>; |
| 388 |
427 |
| 389 domination!(Linfinity, L1); |
428 domination!(Linfinity, L1); |
| 390 domination!(Linfinity, L2); |
429 domination!(Linfinity, L2); |
| 391 domination!(L2, L1); |
430 domination!(L2, L1); |
| 392 |
431 |
| 393 impl<F : Num,const N : usize> Dot<Loc<F, N>,F> for Loc<F, N> { |
432 impl<F : Float,const N : usize> Euclidean<F> for Loc<F, N> { |
| |
433 type Output = Self; |
| |
434 |
| 394 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
435 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
| 395 /// Use [`nalgebra`] for larger vectors. |
436 /// Use [`nalgebra`] for larger vectors. |
| 396 #[inline] |
437 #[inline] |
| 397 fn dot(&self, other : &Loc<F, N>) -> F { |
438 fn dot<I : Instance<Self>>(&self, other : I) -> F { |
| 398 self.0.iter() |
439 self.0.iter() |
| 399 .zip(other.0.iter()) |
440 .zip(other.ref_instance().0.iter()) |
| 400 .fold(F::ZERO, |m, (&v, &w)| m + v * w) |
441 .fold(F::ZERO, |m, (&v, &w)| m + v * w) |
| 401 } |
|
| 402 } |
|
| 403 |
|
| 404 impl<F : Float,const N : usize> Euclidean<F> for Loc<F, N> { |
|
| 405 type Output = Self; |
|
| 406 |
|
| 407 #[inline] |
|
| 408 fn similar_origin(&self) -> Self { |
|
| 409 Self::ORIGIN |
|
| 410 } |
442 } |
| 411 |
443 |
| 412 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
444 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
| 413 /// Use [`nalgebra`] for larger vectors. |
445 /// Use [`nalgebra`] for larger vectors. |
| 414 #[inline] |
446 #[inline] |
| 415 fn norm2_squared(&self) -> F { |
447 fn norm2_squared(&self) -> F { |
| 416 self.iter().fold(F::ZERO, |m, &v| m + v * v) |
448 self.iter().fold(F::ZERO, |m, &v| m + v * v) |
| 417 } |
449 } |
| 418 |
450 |
| 419 fn dist2_squared(&self, other : &Self) -> F { |
451 fn dist2_squared<I : Instance<Self>>(&self, other : I) -> F { |
| 420 self.iter() |
452 self.iter() |
| 421 .zip(other.iter()) |
453 .zip(other.ref_instance().iter()) |
| 422 .fold(F::ZERO, |m, (&v, &w)| { let d = v - w; m + d * d }) |
454 .fold(F::ZERO, |m, (&v, &w)| { let d = v - w; m + d * d }) |
| 423 } |
455 } |
| 424 |
456 |
| 425 #[inline] |
457 #[inline] |
| 426 fn norm2(&self) -> F { |
458 fn norm2(&self) -> F { |
| 431 self.norm2_squared().sqrt() |
463 self.norm2_squared().sqrt() |
| 432 } |
464 } |
| 433 } |
465 } |
| 434 |
466 |
| 435 #[inline] |
467 #[inline] |
| 436 fn dist2(&self, other : &Self) -> F { |
468 fn dist2<I : Instance<Self>>(&self, other : I) -> F { |
| 437 // Optimisation for N==1 that avoids squaring and square rooting. |
469 // Optimisation for N==1 that avoids squaring and square rooting. |
| |
470 let otherr = other.ref_instance(); |
| 438 if N==1 { |
471 if N==1 { |
| 439 unsafe { *self.0.get_unchecked(0) - *other.0.get_unchecked(0) }.abs() |
472 unsafe { *self.0.get_unchecked(0) - *otherr.0.get_unchecked(0) }.abs() |
| 440 } else { |
473 } else { |
| 441 self.dist2_squared(other).sqrt() |
474 self.dist2_squared(other).sqrt() |
| 442 } |
475 } |
| 443 } |
476 } |
| 444 } |
477 } |
| 445 |
478 |
| 446 impl<F : Num, const N : usize> Loc<F, N> { |
479 impl<F : Num, const N : usize> Loc<F, N> { |
| |
480 /// Origin point |
| 447 pub const ORIGIN : Self = Loc([F::ZERO; N]); |
481 pub const ORIGIN : Self = Loc([F::ZERO; N]); |
| |
482 } |
| |
483 |
| |
484 impl<F : Num + std::ops::Neg<Output=F>, const N : usize> Loc<F, N> { |
| |
485 /// Reflects along the given coordinate |
| |
486 pub fn reflect(mut self, i : usize) -> Self { |
| |
487 self[i] = -self[i]; |
| |
488 self |
| |
489 } |
| |
490 |
| |
491 /// Reflects along the given coordinate sequences |
| |
492 pub fn reflect_many<I : IntoIterator<Item=usize>>(mut self, idxs : I) -> Self { |
| |
493 for i in idxs { |
| |
494 self[i]=-self[i] |
| |
495 } |
| |
496 self |
| |
497 } |
| |
498 } |
| |
499 |
| |
500 impl<F : std::ops::Neg<Output=F>> Loc<F, 2> { |
| |
501 /// Reflect x coordinate |
| |
502 pub fn reflect_x(self) -> Self { |
| |
503 let Loc([x, y]) = self; |
| |
504 [-x, y].into() |
| |
505 } |
| |
506 |
| |
507 /// Reflect y coordinate |
| |
508 pub fn reflect_y(self) -> Self { |
| |
509 let Loc([x, y]) = self; |
| |
510 [x, -y].into() |
| |
511 } |
| |
512 } |
| |
513 |
| |
514 impl<F : Float> Loc<F, 2> { |
| |
515 /// Rotate by angle φ |
| |
516 pub fn rotate(self, φ : F) -> Self { |
| |
517 let Loc([x, y]) = self; |
| |
518 let sin_φ = φ.sin(); |
| |
519 let cos_φ = φ.cos(); |
| |
520 [cos_φ * x - sin_φ * y, |
| |
521 sin_φ * x + cos_φ * y].into() |
| |
522 } |
| |
523 } |
| |
524 |
| |
525 impl<F : std::ops::Neg<Output=F>> Loc<F, 3> { |
| |
526 /// Reflect x coordinate |
| |
527 pub fn reflect_x(self) -> Self { |
| |
528 let Loc([x, y, z]) = self; |
| |
529 [-x, y, z].into() |
| |
530 } |
| |
531 |
| |
532 /// Reflect y coordinate |
| |
533 pub fn reflect_y(self) -> Self { |
| |
534 let Loc([x, y, z]) = self; |
| |
535 [x, -y, z].into() |
| |
536 } |
| |
537 |
| |
538 /// Reflect y coordinate |
| |
539 pub fn reflect_z(self) -> Self { |
| |
540 let Loc([x, y, z]) = self; |
| |
541 [x, y, -z].into() |
| |
542 } |
| |
543 } |
| |
544 |
| |
545 impl<F : Float> Loc<F, 3> { |
| |
546 /// Rotate by angles (yaw, pitch, roll) |
| |
547 pub fn rotate(self, Loc([φ, ψ, θ]) : Self) -> Self { |
| |
548 let Loc([mut x, mut y, mut z]) = self; |
| |
549 let sin_φ = φ.sin(); |
| |
550 let cos_φ = φ.cos(); |
| |
551 [x, y, z] = [cos_φ * x - sin_φ *y, |
| |
552 sin_φ * x + cos_φ * y, |
| |
553 z]; |
| |
554 let sin_ψ = ψ.sin(); |
| |
555 let cos_ψ = ψ.cos(); |
| |
556 [x, y, z] = [cos_ψ * x + sin_ψ * z, |
| |
557 y, |
| |
558 -sin_ψ * x + cos_ψ * z]; |
| |
559 let sin_θ = θ.sin(); |
| |
560 let cos_θ = θ.cos(); |
| |
561 [x, y, z] = [x, |
| |
562 cos_θ * y - sin_θ * z, |
| |
563 sin_θ * y + cos_θ * z]; |
| |
564 [x, y, z].into() |
| |
565 } |
| 448 } |
566 } |
| 449 |
567 |
| 450 impl<F : Float,const N : usize> StaticEuclidean<F> for Loc<F, N> { |
568 impl<F : Float,const N : usize> StaticEuclidean<F> for Loc<F, N> { |
| 451 #[inline] |
569 #[inline] |
| 452 fn origin() -> Self { |
570 fn origin() -> Self { |
| 453 Self::ORIGIN |
571 Self::ORIGIN |
| 454 } |
572 } |
| 455 } |
573 } |
| 456 |
574 |
| |
575 |
| |
576 /// The default norm for `Loc` is [`L2`]. |
| |
577 impl<F : Float, const N : usize> Normed<F> for Loc<F, N> { |
| |
578 type NormExp = L2; |
| |
579 |
| |
580 #[inline] |
| |
581 fn norm_exponent(&self) -> Self::NormExp { |
| |
582 L2 |
| |
583 } |
| |
584 |
| |
585 // #[inline] |
| |
586 // fn similar_origin(&self) -> Self { |
| |
587 // [F::ZERO; N].into() |
| |
588 // } |
| |
589 |
| |
590 #[inline] |
| |
591 fn is_zero(&self) -> bool { |
| |
592 self.norm2_squared() == F::ZERO |
| |
593 } |
| |
594 } |
| |
595 |
| |
596 impl<F : Float, const N : usize> HasDual<F> for Loc<F, N> { |
| |
597 type DualSpace = Self; |
| |
598 } |
| |
599 |
| 457 impl<F : Float, const N : usize> Norm<F, L2> for Loc<F, N> { |
600 impl<F : Float, const N : usize> Norm<F, L2> for Loc<F, N> { |
| 458 #[inline] |
601 #[inline] |
| 459 fn norm(&self, _ : L2) -> F { self.norm2() } |
602 fn norm(&self, _ : L2) -> F { self.norm2() } |
| 460 } |
603 } |
| 461 |
604 |
| 462 impl<F : Float, const N : usize> Dist<F, L2> for Loc<F, N> { |
605 impl<F : Float, const N : usize> Dist<F, L2> for Loc<F, N> { |
| 463 #[inline] |
606 #[inline] |
| 464 fn dist(&self, other : &Self, _ : L2) -> F { self.dist2(other) } |
607 fn dist<I : Instance<Self>>(&self, other : I, _ : L2) -> F { self.dist2(other) } |
| 465 } |
608 } |
| |
609 |
| |
610 /* Implemented automatically as Euclidean. |
| |
611 impl<F : Float, const N : usize> Projection<F, L2> for Loc<F, N> { |
| |
612 #[inline] |
| |
613 fn proj_ball_mut(&mut self, ρ : F, nrm : L2) { |
| |
614 let n = self.norm(nrm); |
| |
615 if n > ρ { |
| |
616 *self *= ρ/n; |
| |
617 } |
| |
618 } |
| |
619 }*/ |
| 466 |
620 |
| 467 impl<F : Float, const N : usize> Norm<F, L1> for Loc<F, N> { |
621 impl<F : Float, const N : usize> Norm<F, L1> for Loc<F, N> { |
| 468 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
622 /// This implementation is not stabilised as it's meant to be used for very small vectors. |
| 469 /// Use [`nalgebra`] for larger vectors. |
623 /// Use [`nalgebra`] for larger vectors. |
| 470 #[inline] |
624 #[inline] |
| 534 fn fl_iter(self) -> Self::Iter { |
688 fn fl_iter(self) -> Self::Iter { |
| 535 self.iter() |
689 self.iter() |
| 536 } |
690 } |
| 537 } |
691 } |
| 538 |
692 |
| 539 impl<F : Num, const N : usize> AXPY<F, Loc<F, N>> for Loc<F, N> { |
693 |
| 540 |
694 impl<F : Num, const N : usize> Space for Loc<F, N> { |
| 541 #[inline] |
695 type Decomp = BasicDecomposition; |
| 542 fn axpy(&mut self, α : F, x : &Loc<F, N>, β : F) { |
696 } |
| 543 if β == F::ZERO { |
697 |
| 544 map2_mut(self, x, |yi, xi| { *yi = α * (*xi) }) |
698 impl<F : Float, const N : usize> Mapping<Loc<F, N>> for Loc<F, N> { |
| 545 } else { |
699 type Codomain = F; |
| 546 map2_mut(self, x, |yi, xi| { *yi = β * (*yi) + α * (*xi) }) |
700 |
| 547 } |
701 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { |
| 548 } |
702 x.eval(|x̃| self.dot(x̃)) |
| 549 |
703 } |
| 550 #[inline] |
704 } |
| 551 fn copy_from(&mut self, x : &Loc<F, N>) { |
705 |
| 552 map2_mut(self, x, |yi, xi| *yi = *xi ) |
706 impl<F : Float, const N : usize> Linear<Loc<F, N>> for Loc<F, N> { } |
| 553 } |
707 |
| 554 } |
708 impl<F : Float, const N : usize> AXPY<F, Loc<F, N>> for Loc<F, N> { |
| |
709 type Owned = Self; |
| |
710 |
| |
711 #[inline] |
| |
712 fn axpy<I : Instance<Loc<F, N>>>(&mut self, α : F, x : I, β : F) { |
| |
713 x.eval(|x̃| { |
| |
714 if β == F::ZERO { |
| |
715 map2_mut(self, x̃, |yi, xi| { *yi = α * (*xi) }) |
| |
716 } else { |
| |
717 map2_mut(self, x̃, |yi, xi| { *yi = β * (*yi) + α * (*xi) }) |
| |
718 } |
| |
719 }) |
| |
720 } |
| |
721 |
| |
722 #[inline] |
| |
723 fn copy_from<I : Instance<Loc<F, N>>>(&mut self, x : I) { |
| |
724 x.eval(|x̃| map2_mut(self, x̃, |yi, xi| *yi = *xi )) |
| |
725 } |
| |
726 |
| |
727 #[inline] |
| |
728 fn similar_origin(&self) -> Self::Owned { |
| |
729 Self::ORIGIN |
| |
730 } |
| |
731 |
| |
732 #[inline] |
| |
733 fn set_zero(&mut self) { |
| |
734 *self = Self::ORIGIN; |
| |
735 } |
| |
736 } |
| |
737 |