src/loc.rs

changeset 90
b3c35d16affe
parent 64
4f6ca107ccb1
child 80
f802ddbabcfc
child 82
981069ef919b
child 86
d5b0e496b72f
equal deleted inserted replaced
25:d14c877e14b7 90:b3c35d16affe
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,
133 fn from(other: F) -> Loc<F, 1> { 150 fn from(other: F) -> Loc<F, 1> {
134 Loc([other]) 151 Loc([other])
135 } 152 }
136 } 153 }
137 154
155 impl<F> Loc<F, 1> {
156 #[inline]
157 pub fn flatten1d(self) -> F {
158 let Loc([v]) = self;
159 v
160 }
161 }
162
138 impl<F, const N : usize> From<Loc<F, N>> for [F; N] { 163 impl<F, const N : usize> From<Loc<F, N>> for [F; N] {
139 #[inline] 164 #[inline]
140 fn from(other : Loc<F, N>) -> [F; N] { 165 fn from(other : Loc<F, N>) -> [F; N] {
141 other.0 166 other.0
142 } 167 }
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]
473 } 627 }
474 } 628 }
475 629
476 impl<F : Float, const N : usize> Dist<F, L1> for Loc<F, N> { 630 impl<F : Float, const N : usize> Dist<F, L1> for Loc<F, N> {
477 #[inline] 631 #[inline]
478 fn dist(&self, other : &Self, _ : L1) -> F { 632 fn dist<I : Instance<Self>>(&self, other : I, _ : L1) -> F {
479 self.iter() 633 self.iter()
480 .zip(other.iter()) 634 .zip(other.ref_instance().iter())
481 .fold(F::ZERO, |m, (&v, &w)| m + (v-w).abs() ) 635 .fold(F::ZERO, |m, (&v, &w)| m + (v-w).abs() )
482 } 636 }
483 } 637 }
484 638
485 impl<F : Float, const N : usize> Projection<F, Linfinity> for Loc<F, N> { 639 impl<F : Float, const N : usize> Projection<F, Linfinity> for Loc<F, N> {
498 } 652 }
499 } 653 }
500 654
501 impl<F : Float, const N : usize> Dist<F, Linfinity> for Loc<F, N> { 655 impl<F : Float, const N : usize> Dist<F, Linfinity> for Loc<F, N> {
502 #[inline] 656 #[inline]
503 fn dist(&self, other : &Self, _ : Linfinity) -> F { 657 fn dist<I : Instance<Self>>(&self, other : I, _ : Linfinity) -> F {
504 self.iter() 658 self.iter()
505 .zip(other.iter()) 659 .zip(other.ref_instance().iter())
506 .fold(F::ZERO, |m, (&v, &w)| m.max((v-w).abs())) 660 .fold(F::ZERO, |m, (&v, &w)| m.max((v-w).abs()))
507 } 661 }
508 } 662 }
509 663
510 664
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

mercurial