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
183// TODO: currently the num_traits::Pow<i32> trait cannot be added because fixed
184// point numbers do not implement it
185pub trait Field : Ring + MultiplicativeGroup {
186  // some generic constants
187  fn two() -> Self {
188    Self::one() + Self::one()
189  }
190  fn three() -> Self {
191    Self::one() + Self::one() + Self::one()
192  }
193  fn four() -> Self {
194    Self::two() * Self::two()
195  }
196  fn five() -> Self {
197    Self::two() + Self::three()
198  }
199  fn six() -> Self {
200    Self::two() * Self::three()
201  }
202  fn seven() -> Self {
203    Self::three() + Self::four()
204  }
205  fn eight() -> Self {
206    Self::two() * Self::two() * Self::two()
207  }
208  fn nine() -> Self {
209    Self::three() * Self::three()
210  }
211  fn ten() -> Self {
212    Self::two() * Self::five()
213  }
214}
215
216/// Interface for a group with identity represented by `one`, operation
217/// defined by `*` and `/`
218pub trait MultiplicativeGroup : MultiplicativeMonoid +
219  std::ops::Div <Self, Output=Self> + std::ops::DivAssign +
220  num::Inv <Output=Self>
221{ }
222
223/// Ring of integers
224pub trait Integer : Ring + num::PrimInt + num::Signed { }
225
226/// Interface for a (partially ordered) ring as a combination of an additive
227/// group and a distributive multiplication operation
228pub trait Ring : Copy + PartialOrd + MinMax + AdditiveGroup +
229  std::ops::Mul <Self, Output=Self> + std::ops::MulAssign + num::Signed +
230  num::MulAdd <Self, Self, Output=Self> + num::MulAddAssign <Self, Self>
231{ }
232
233/// Interface for a group with identity represented by `zero`, and operation
234/// defined by `+` and `-`
235pub trait AdditiveGroup : AdditiveMonoid +
236  std::ops::Sub <Self, Output=Self> + std::ops::SubAssign +
237  std::ops::Neg <Output=Self>
238{ }
239
240/// Set with identity, inverses, and (associative) binary operation
241pub trait Group : PartialEq + std::ops::Neg <Output=Self> {
242  fn identity() -> Self;
243  fn operation (a : Self, b : Self) -> Self;
244}
245
246/// Set with identity represented by `one` and (associative) binary operation
247/// defined by `*`
248pub trait MultiplicativeMonoid : Sized + PartialEq +
249  std::ops::Mul <Self, Output=Self> + std::ops::MulAssign + num::One
250{ }
251
252/// Set with identity represented by `zero` and (associative) binary operation
253/// defined by `+`
254pub trait AdditiveMonoid : Sized + PartialEq +
255  std::ops::Add <Self, Output=Self> + std::ops::AddAssign + num::Zero
256{ }
257
258/// Interface for angle units
259pub trait Angle <S : Real> : Clone + Copy + PartialEq + PartialOrd + Sized +
260  AdditiveGroup + std::ops::Div <Self, Output=S> +
261  std::ops::Mul <S, Output=Self> + std::ops::Div <S, Output=Self> +
262  std::ops::Rem <Self, Output=Self>
263{
264  // required
265  /// Full rotation
266  fn full_turn() -> Self;
267  // provided
268  /// Half rotation
269  fn half_turn() -> Self {
270    Self::full_turn() / S::two()
271  }
272  /// Restrict to (-half_turn, half_turn]
273  fn wrap_signed (self) -> Self {
274    let out = (self + Self::half_turn()).wrap_unsigned() - Self::half_turn();
275    if out == -Self::half_turn() {
276        Self::half_turn()
277    } else {
278        out
279    }
280  }
281  /// Restrict to [0, full_turn)
282  fn wrap_unsigned (self) -> Self {
283    if self >= Self::full_turn() {
284        self % Self::full_turn()
285    } else if self < Self::zero() {
286        self + Self::full_turn() *
287          ((self / Self::full_turn()).trunc().abs() + S::one())
288    } else {
289        self
290    }
291  }
292}
293
294/// Square root function
295pub trait Sqrt {
296  fn sqrt (self) -> Self;
297}
298/// Exponential function
299pub trait Exp {
300  fn exp (self) -> Self;
301}
302/// Trigonometric functions
303pub trait Trig : Sized {
304  fn sin      (self) -> Self;
305  fn sin_cos  (self) -> (Self, Self);
306  fn cos      (self) -> Self;
307  fn tan      (self) -> Self;
308  fn asin     (self) -> Self;
309  fn acos     (self) -> Self;
310  fn atan     (self) -> Self;
311  fn atan2    (self, other : Self) -> Self;
312}
313
314/// Provides `min`, `max`, and `clamp` that are not necessarily consistent with
315/// those from `Ord`. This is provided because `f32` and `f64` do not implement
316/// `Ord`, so this trait is defined to give a uniform interface with `Ord`
317/// types.
318pub trait MinMax {
319  fn min   (self, other : Self) -> Self;
320  fn max   (self, other : Self) -> Self;
321  fn clamp (self, min : Self, max : Self) -> Self;
322}
323
324/// Function returning number representing sign of self
325pub trait SignedExt : num::Signed {
326  #[inline]
327  fn sign (self) -> Sign {
328    if self.is_zero() {
329      Sign::Zero
330    } else if self.is_positive() {
331      Sign::Positive
332    } else {
333      debug_assert!(self.is_negative());
334      Sign::Negative
335    }
336  }
337  /// Maps `0.0` to `0.0`, otherwise equal to `S::signum` (which would otherwise
338  /// map `+0.0 -> 1.0` and `-0.0 -> -1.0`)
339  #[inline]
340  fn signum_or_zero (self) -> Self where Self : num::Zero {
341    if self.is_zero() {
342      Self::zero()
343    } else {
344      self.signum()
345    }
346  }
347}
348
349/// Adds serde Serialize and DeserializeOwned constraints.
350///
351/// This makes it easier to conditionally add these constraints to type
352/// definitions when `derive_serdes` feature is enabled.
353#[cfg(not(feature = "derive_serdes"))]
354pub trait MaybeSerDes { }
355#[cfg(feature = "derive_serdes")]
356pub trait MaybeSerDes : serde::Serialize + serde::de::DeserializeOwned { }
357
358impl <
359  #[cfg(not(feature = "derive_serdes"))]
360  T,
361  #[cfg(feature = "derive_serdes")]
362  T : serde::Serialize + serde::de::DeserializeOwned
363> MaybeSerDes for T { }
364
365macro impl_integer ($type:ty) {
366  impl Integer        for $type { }
367  impl Ring           for $type { }
368  impl AdditiveGroup  for $type { }
369  impl AdditiveMonoid for $type { }
370  impl SignedExt      for $type { }
371  impl MinMax         for $type {
372    fn min (self, other : Self) -> Self {
373      Ord::min (self, other)
374    }
375    fn max (self, other : Self) -> Self {
376      Ord::max (self, other)
377    }
378    fn clamp (self, min : Self, max : Self) -> Self {
379      Ord::clamp (self, min, max)
380    }
381  }
382}
383impl_integer!(i8);
384impl_integer!(i16);
385impl_integer!(i32);
386impl_integer!(i64);
387
388macro impl_real_float ($type:ident) {
389  impl VectorSpace <Self> for $type {
390    fn map <F> (self, mut f : F) -> Self where F : FnMut (Self) -> Self {
391      f (self)
392    }
393  }
394  impl Module <Self> for $type {
395    type LinearEndo = Self;
396  }
397  impl LinearMap <Self, Self, Self> for $type {
398    fn determinant (self) -> Self {
399      self
400    }
401    fn transpose (self) -> Self {
402      self
403    }
404  }
405  impl Real for $type {
406    fn pi() -> Self {
407      std::$type::consts::PI
408    }
409    fn frac_pi_3() -> Self {
410      std::$type::consts::FRAC_PI_3
411    }
412    fn sqrt_3() -> Self {
413      1.732050807568877293527446341505872366942805253810380628055f64 as $type
414    }
415    fn frac_1_sqrt_3() -> Self {
416      (1.0f64 / 1.732050807568877293527446341505872366942805253810380628055f64)
417        as $type
418    }
419    fn floor (self) -> Self {
420      self.floor()
421    }
422    fn ceil (self) -> Self {
423      self.ceil()
424    }
425    fn trunc (self) -> Self {
426      self.trunc()
427    }
428    fn fract (self) -> Self {
429      self.fract()
430    }
431  }
432  impl Field                for $type { }
433  impl MultiplicativeGroup  for $type { }
434  impl MultiplicativeMonoid for $type { }
435  impl Ring                 for $type { }
436  impl AdditiveGroup        for $type { }
437  impl AdditiveMonoid       for $type { }
438  impl SignedExt            for $type { }
439  impl MinMax               for $type {
440    fn min (self, other : Self) -> Self {
441      self.min (other)
442    }
443    fn max (self, other : Self) -> Self {
444      self.max (other)
445    }
446    fn clamp (self, min : Self, max : Self) -> Self {
447      self.clamp (min, max)
448    }
449  }
450  impl Exp for $type {
451    fn exp (self) -> Self {
452      self.exp()
453    }
454  }
455  impl Sqrt for $type {
456    fn sqrt (self) -> Self {
457      self.sqrt()
458    }
459  }
460  impl Trig for $type {
461    fn sin (self) -> Self {
462      self.sin()
463    }
464    fn sin_cos (self) -> (Self, Self) {
465      self.sin_cos()
466    }
467    fn cos (self) -> Self {
468      self.cos()
469    }
470    fn tan (self) -> Self {
471      self.tan()
472    }
473    fn asin (self) -> Self {
474      self.asin()
475    }
476    fn acos (self) -> Self {
477      self.acos()
478    }
479    fn atan (self) -> Self {
480      self.atan()
481    }
482    fn atan2 (self, other : Self) -> Self {
483      self.atan2 (other)
484    }
485  }
486}
487
488impl_real_float!(f32);
489impl_real_float!(f64);