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