1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
//!
//! Algebraic _multiplicative_ _commutative_ _group_ traits.
//!
//! An algebraic _multiplicative_ _commutative_ _group_ is a
//! _multiplicative_ _group_ `M`, where group multiplication `×` is
//! required to be _commutative_.
//!
//! # Axioms
//!
//! ```notrust
//! ∀g, h ∈ M
//! 
//! Commutativity: g × h = h × g.
//! ```
//!
//! # References
//!
//! See [references] for a formal definition of a multiplicative
//! commutative group.
//!
#![doc(include = "../doc/references.md")]

use types::*;
use group::mul_group::*;


///
/// An algebraic _multiplicative commutative group_.
///
pub trait MulComGroup: MulGroup {

  /// Test the axiom of multiplicative commutivity.
  fn axiom_mul_commutivity(xs: Pair<Self>) -> bool {
    let (x, y) = xs;

    x.mul(y) == y.mul(x)
  }
}


///
/// A "numeric" algebraic _multiplicative commutative group_.
///
/// `NumMulComGroup` trait is for types that only form
/// multiplicative commutative groups when "numeric" comparisons are
/// used, e.g.  floating point types.
///
pub trait NumMulComGroup: NumMulGroup {

  /// Numerically test the axiom of multiplicative commutivity.
  fn axiom_mul_commutivity(xs: NumPair<Self>) -> bool {
     let (x, y, eps) = xs;

     x.mul(y).num_eq(&y.mul(x), eps)
   }
}


///
/// Trait implementation macro for floating point types.
///
/// A macro used to avoid writing repetitive, boilerplate
/// `NumMulComGroup` implementations for built-in floating point
/// types. Probably not needed if Rust had a `Float` super-trait.
///
macro_rules! float_mul_com_group {
  ($type:ty) => {
    impl NumMulComGroup for $type {}
  };

  ($type:ty, $($others:ty),+) => {
    float_mul_com_group! {$type}
    float_mul_com_group! {$($others),+}
  };
}


// Numeric multiplicative commutative group floating point types.
float_mul_com_group! {
  f32, f64
}


// Module unit tests are in a separate file.
#[cfg(test)]
#[path = "mul_com_group_test.rs"]
mod mul_com_group_test;