math_utils/
traits.rs

1//! Abstract traits
2
3use either::Either;
4#[cfg(feature = "derive_serdes")]
5use serde;
6
7use crate::num_traits as num;
8use crate::types::{Affinity, Projectivity, Sign};
9
10/// Projective completion (homogeneous coordinates)
11pub trait ProjectiveSpace <S, V> : VectorSpace <S> where
12  V : VectorSpace <S> + std::fmt::Display,
13  S : Field + std::fmt::Display
14{
15  /// Construct an augmented matrix for the affinity
16  fn homography <A> (
17    affinity : Affinity <S, A, A, <A::Vector as Module <S>>::LinearEndo>
18  ) -> Projectivity <S, V, V, Self, Self, Self::LinearEndo> where
19    A : AffineSpace <S, Vector=V>;
20  /// Return the projective completion (homogeneous coordinates) of the affine
21  /// point or vector
22  fn homogeneous <A> (point_or_vector : Either <A::Point, A::Vector>)
23    -> Self
24  where
25    A : AffineSpace <S, Vector=V>,
26    V : GroupAction <A::Point>;
27}
28
29/// `AffineSpace` with translations in a (Euclidean) real inner product space
30pub trait EuclideanSpace <S : Real> : AffineSpace <S> where
31  Self::Vector : InnerProductSpace <S>
32{
33  fn origin() -> Self::Point {
34    use num::Zero;
35    Self::Point::from_vector (Self::Vector::zero())
36  }
37}
38
39/// Space of `Point` and `Vector` (translations)
40pub trait AffineSpace <S : Field> {
41  type Point  : Point <Self::Vector>;
42  type Vector : VectorSpace <S> + GroupAction <Self::Point>;
43}
44
45impl <S, V> AffineSpace <S> for V where
46  S : Field,
47  V : VectorSpace <S> + GroupAction <V> + Point <V>
48{
49  type Point  = Self;
50  type Vector = Self;
51}
52
53/// Point types convertible to and from a vector type, with difference function
54/// that follows from the free and transitive group action
55pub trait Point <V> : Sized + std::ops::Sub <Self, Output=V> where
56  V : AdditiveGroup + GroupAction <Self>
57{
58  fn to_vector (self) -> V;
59  fn from_vector (vector : V) -> Self;
60  fn origin() -> Self {
61    Self::from_vector (V::zero())
62  }
63}
64
65/// (Right) action of a group on a set
66pub trait GroupAction <X> : Group {
67  fn action (self, x : X) -> X;
68}
69
70impl <G> GroupAction <G> for G where G : Group {
71  fn action (self, g : Self) -> Self {
72    Self::operation (g, self)
73  }
74}
75
76/// Bilinear form on a `VectorSpace`
77pub trait InnerProductSpace <S : Field> : VectorSpace <S> + Dot <S> {
78  fn inner_product (self, other : Self) -> S {
79    self.dot (other)
80  }
81}
82
83impl <V, S> NormedVectorSpace <S> for V where
84  V : InnerProductSpace <S>,
85  S : Field
86{
87  fn norm_squared (self) -> S {
88    self.self_dot()
89  }
90}
91
92/// Scalar product (bilinear form) on a `Module`
93pub trait Dot <S : Ring> : Module <S> {
94  fn dot (self, other : Self) -> S;
95  /// Self dot product
96  fn self_dot (self) -> S {
97    self.dot (self)
98  }
99}
100
101/// `VectorSpace` with vector length/magnitude function
102pub trait NormedVectorSpace <S : Field> : VectorSpace <S> {
103  fn norm_squared (self) -> S;
104  fn norm (self) -> S where S : Sqrt {
105    self.norm_squared().sqrt()
106  }
107  fn normalize (self) -> Self where S : Sqrt {
108    self / self.norm()
109  }
110  fn unit_sigvec (self) -> Self where S : SignedExt + Sqrt {
111    let v = self.sigvec();
112    if v.is_zero() {
113      v
114    } else {
115      v.normalize()
116    }
117  }
118}
119
120impl <V, S> MetricSpace <S> for V where
121  V : NormedVectorSpace <S>,
122  S : Field
123{
124  fn distance_squared (self, other : Self) -> S {
125    (self - other).norm_squared()
126  }
127}
128
129/// Set of points with distance function
130pub trait MetricSpace <S> : Sized {
131  fn distance_squared (self, other : Self) -> S;
132  fn distance (self, other : Self) -> S where S : Sqrt {
133    self.distance_squared (other).sqrt()
134  }
135}
136
137/// Module with scalars taken from a `Field`
138pub trait VectorSpace <S : Field> :
139  Module <S> + std::ops::Div <S, Output=Self> + Copy
140{
141  // required
142  fn map <F> (self, f : F) -> Self where F : FnMut (S) -> S;
143  // provided
144  /// Map `signum_or_zero` over each element of the given vector
145  fn sigvec (self) -> Self where S : SignedExt {
146    self.map (|x| x.signum_or_zero())
147  }
148}
149
150/// Additive group combined with scalar multiplication
151pub trait Module <S : Ring> :
152  AdditiveGroup + std::ops::Mul <S, Output=Self> + Copy
153{
154  /// Linear endomorphism represented by a square matrix type
155  type LinearEndo : LinearMap <S, Self, Self> + MultiplicativeMonoid;
156}
157
158/// Module homomorphism
159pub trait LinearMap <S, V, W> : std::ops::Mul <V, Output=W> + Copy where
160  S : Ring,
161  V : Module <S>,
162  W : Module <S>
163{
164  fn determinant (self) -> S;
165  fn transpose   (self) -> Self;
166}
167
168/// `Field` with special functions and partial ordering
169pub trait Real : Field + SignedExt + Exp + Sqrt + Trig + MinMax {
170  // TODO: more constants
171  fn pi() -> Self;
172  fn frac_pi_3() -> Self;
173  fn sqrt_3() -> Self;
174  fn frac_1_sqrt_3() -> Self;
175  fn floor (self) -> Self;
176  fn ceil (self) -> Self;
177  fn trunc (self) -> Self;
178  fn fract (self) -> Self;
179}
180
181/// A (commutative) `Ring` where $1 \neq 0$ and all non-zero elements are
182/// invertible
183pub trait Field : Ring + MultiplicativeGroup + Powi + Powf {
184  // some generic constants
185  fn half() -> Self {
186    Self::one() / Self::two()
187  }
188  fn two() -> Self {
189    Self::one() + Self::one()
190  }
191  fn three() -> Self {
192    Self::one() + Self::one() + Self::one()
193  }
194  fn four() -> Self {
195    Self::two() * Self::two()
196  }
197  fn five() -> Self {
198    Self::two() + Self::three()
199  }
200  fn six() -> Self {
201    Self::two() * Self::three()
202  }
203  fn seven() -> Self {
204    Self::three() + Self::four()
205  }
206  fn eight() -> Self {
207    Self::two() * Self::two() * Self::two()
208  }
209  fn nine() -> Self {
210    Self::three() * Self::three()
211  }
212  fn ten() -> Self {
213    Self::two() * Self::five()
214  }
215}
216
217/// Interface for a group with identity represented by `one`, operation
218/// defined by `*` and `/`
219pub trait MultiplicativeGroup : MultiplicativeMonoid +
220  std::ops::Div <Self, Output=Self> + std::ops::DivAssign +
221  num::Inv <Output=Self>
222{ }
223
224/// Ring of integers
225pub trait Integer : Ring + num::PrimInt + num::Signed { }
226
227/// Interface for a (partially ordered) ring as a combination of an additive
228/// group and a distributive multiplication operation
229pub trait Ring : Copy + PartialOrd + MinMax + AdditiveGroup +
230  std::ops::Mul <Self, Output=Self> + std::ops::MulAssign + num::Signed +
231  num::MulAdd <Self, Self, Output=Self> + num::MulAddAssign <Self, Self>
232{
233  fn squared (self) -> Self {
234    self * self
235  }
236  fn cubed (self) -> Self {
237    self * self * self
238  }
239}
240
241/// Interface for a group with identity represented by `zero`, and operation
242/// defined by `+` and `-`
243pub trait AdditiveGroup : AdditiveMonoid +
244  std::ops::Sub <Self, Output=Self> + std::ops::SubAssign +
245  std::ops::Neg <Output=Self>
246{ }
247
248/// Set with identity, inverses, and (associative) binary operation
249pub trait Group : PartialEq + std::ops::Neg <Output=Self> {
250  fn identity() -> Self;
251  fn operation (a : Self, b : Self) -> Self;
252}
253
254/// Set with identity represented by `one` and (associative) binary operation
255/// defined by `*`
256pub trait MultiplicativeMonoid : Sized + PartialEq +
257  std::ops::Mul <Self, Output=Self> + std::ops::MulAssign + num::One
258{ }
259
260/// Set with identity represented by `zero` and (associative) binary operation
261/// defined by `+`
262pub trait AdditiveMonoid : Sized + PartialEq +
263  std::ops::Add <Self, Output=Self> + std::ops::AddAssign + num::Zero
264{ }
265
266/// Interface for angle units
267pub trait Angle <S : Real> : Clone + Copy + PartialEq + PartialOrd + Sized +
268  AdditiveGroup + std::ops::Div <Self, Output=S> +
269  std::ops::Mul <S, Output=Self> + std::ops::Div <S, Output=Self> +
270  std::ops::Rem <Self, Output=Self>
271{
272  // required
273  /// Full rotation
274  fn full_turn() -> Self;
275  // provided
276  /// Half rotation
277  fn half_turn() -> Self {
278    Self::full_turn() / S::two()
279  }
280  /// Restrict to (-half_turn, half_turn]
281  fn wrap_signed (self) -> Self {
282    let out = (self + Self::half_turn()).wrap_unsigned() - Self::half_turn();
283    if out == -Self::half_turn() {
284        Self::half_turn()
285    } else {
286        out
287    }
288  }
289  /// Restrict to [0, full_turn)
290  fn wrap_unsigned (self) -> Self {
291    if self >= Self::full_turn() {
292        self % Self::full_turn()
293    } else if self < Self::zero() {
294        self + Self::full_turn() *
295          ((self / Self::full_turn()).trunc().abs() + S::one())
296    } else {
297        self
298    }
299  }
300}
301
302/// Unsigned integer power function
303pub trait Pow {
304  fn pow (self, exp : u32) -> Self;
305}
306/// Signed integer power function
307pub trait Powi {
308  fn powi (self, n : i32) -> Self;
309}
310/// Fractional power function
311pub trait Powf {
312  fn powf (self, n : Self) -> Self;
313}
314/// Exponential function
315pub trait Exp {
316  fn exp (self) -> Self;
317}
318/// Square root function
319pub trait Sqrt {
320  fn sqrt (self) -> Self;
321}
322/// Trigonometric functions
323pub trait Trig : Sized {
324  fn sin      (self) -> Self;
325  fn sin_cos  (self) -> (Self, Self);
326  fn cos      (self) -> Self;
327  fn tan      (self) -> Self;
328  fn asin     (self) -> Self;
329  fn acos     (self) -> Self;
330  fn atan     (self) -> Self;
331  fn atan2    (self, other : Self) -> Self;
332}
333
334/// Provides `min`, `max`, and `clamp` that are not necessarily consistent with
335/// those from `Ord`. This is provided because `f32` and `f64` do not implement
336/// `Ord`, so this trait is defined to give a uniform interface with `Ord`
337/// types.
338pub trait MinMax {
339  fn min   (self, other : Self) -> Self;
340  fn max   (self, other : Self) -> Self;
341  fn clamp (self, min : Self, max : Self) -> Self;
342}
343
344/// Function returning number representing sign of self
345pub trait SignedExt : num::Signed {
346  #[inline]
347  fn sign (self) -> Sign {
348    if self.is_zero() {
349      Sign::Zero
350    } else if self.is_positive() {
351      Sign::Positive
352    } else {
353      debug_assert!(self.is_negative());
354      Sign::Negative
355    }
356  }
357  /// Maps `0.0` to `0.0`, otherwise equal to `S::signum` (which would otherwise
358  /// map `+0.0 -> 1.0` and `-0.0 -> -1.0`)
359  #[inline]
360  fn signum_or_zero (self) -> Self where Self : num::Zero {
361    if self.is_zero() {
362      Self::zero()
363    } else {
364      self.signum()
365    }
366  }
367}
368
369/// Adds serde Serialize and DeserializeOwned constraints.
370///
371/// This makes it easier to conditionally add these constraints to type
372/// definitions when `derive_serdes` feature is enabled.
373#[cfg(not(feature = "derive_serdes"))]
374pub trait MaybeSerDes { }
375#[cfg(feature = "derive_serdes")]
376pub trait MaybeSerDes : serde::Serialize + serde::de::DeserializeOwned { }
377
378impl <
379  #[cfg(not(feature = "derive_serdes"))]
380  T,
381  #[cfg(feature = "derive_serdes")]
382  T : serde::Serialize + serde::de::DeserializeOwned
383> MaybeSerDes for T { }
384
385macro impl_integer ($type:ty) {
386  impl Integer        for $type { }
387  impl Ring           for $type { }
388  impl AdditiveGroup  for $type { }
389  impl AdditiveMonoid for $type { }
390  impl SignedExt      for $type { }
391  impl MinMax         for $type {
392    fn min (self, other : Self) -> Self {
393      Ord::min (self, other)
394    }
395    fn max (self, other : Self) -> Self {
396      Ord::max (self, other)
397    }
398    fn clamp (self, min : Self, max : Self) -> Self {
399      Ord::clamp (self, min, max)
400    }
401  }
402  impl Pow for $type {
403    fn pow (self, exp : u32) -> Self {
404      self.pow (exp)
405    }
406  }
407}
408impl_integer!(i8);
409impl_integer!(i16);
410impl_integer!(i32);
411impl_integer!(i64);
412
413macro impl_real_float ($type:ident) {
414  impl VectorSpace <Self> for $type {
415    fn map <F> (self, mut f : F) -> Self where F : FnMut (Self) -> Self {
416      f (self)
417    }
418  }
419  impl Module <Self> for $type {
420    type LinearEndo = Self;
421  }
422  impl LinearMap <Self, Self, Self> for $type {
423    fn determinant (self) -> Self {
424      self
425    }
426    fn transpose (self) -> Self {
427      self
428    }
429  }
430  impl Real for $type {
431    fn pi() -> Self {
432      std::$type::consts::PI
433    }
434    fn frac_pi_3() -> Self {
435      std::$type::consts::FRAC_PI_3
436    }
437    #[allow(clippy::excessive_precision)]
438    fn sqrt_3() -> Self {
439      1.732050807568877293527446341505872366942805253810380628055f64 as $type
440    }
441    #[allow(clippy::excessive_precision)]
442    fn frac_1_sqrt_3() -> Self {
443      (1.0f64 / 1.732050807568877293527446341505872366942805253810380628055f64) as $type
444    }
445    fn floor (self) -> Self {
446      self.floor()
447    }
448    fn ceil (self) -> Self {
449      self.ceil()
450    }
451    fn trunc (self) -> Self {
452      self.trunc()
453    }
454    fn fract (self) -> Self {
455      self.fract()
456    }
457  }
458  impl Field                for $type { }
459  impl MultiplicativeGroup  for $type { }
460  impl MultiplicativeMonoid for $type { }
461  impl Ring                 for $type { }
462  impl AdditiveGroup        for $type { }
463  impl AdditiveMonoid       for $type { }
464  impl SignedExt            for $type { }
465  impl MinMax               for $type {
466    fn min (self, other : Self) -> Self {
467      self.min (other)
468    }
469    fn max (self, other : Self) -> Self {
470      self.max (other)
471    }
472    fn clamp (self, min : Self, max : Self) -> Self {
473      self.clamp (min, max)
474    }
475  }
476  impl Powi for $type {
477    fn powi (self, n : i32) -> Self {
478      self.powi (n as i32)
479    }
480  }
481  impl Powf for $type {
482    fn powf (self, n : Self) -> Self {
483      self.powf (n)
484    }
485  }
486  impl Exp for $type {
487    fn exp (self) -> Self {
488      self.exp()
489    }
490  }
491  impl Sqrt for $type {
492    fn sqrt (self) -> Self {
493      self.sqrt()
494    }
495  }
496  impl Trig for $type {
497    fn sin (self) -> Self {
498      self.sin()
499    }
500    fn sin_cos (self) -> (Self, Self) {
501      self.sin_cos()
502    }
503    fn cos (self) -> Self {
504      self.cos()
505    }
506    fn tan (self) -> Self {
507      self.tan()
508    }
509    fn asin (self) -> Self {
510      self.asin()
511    }
512    fn acos (self) -> Self {
513      self.acos()
514    }
515    fn atan (self) -> Self {
516      self.atan()
517    }
518    fn atan2 (self, other : Self) -> Self {
519      self.atan2 (other)
520    }
521  }
522}
523
524impl_real_float!(f32);
525impl_real_float!(f64);