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
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
//!
//! Multiplicative semigroups.
//!
//! An algebraic _multiplicative_ _semigroup_ is a _multiplicative_
//! _magma_ `M`, where the multiplication operation `×` is
//! _associative_.
//!
//! # Axioms
//!
//! ```text
//! ∀x, y, z ∈ M
//!
//! Associativity: (x × y) × z = x × (y × z).
//! ```
//!
//! # References
//!
//! See [references] for a formal definition of a multiplicative
//! semigroup.
//!
#![doc(include = "../../doc/references.md")]

use crate::magma::*;
use crate::numeric::*;


///
/// An algebraic _multiplicative semigroup_.
///
pub trait MulSemigroup: MulMagma {}


///
/// Laws of multiplicative semigroups.
///
pub trait MulSemigroupLaws: MulSemigroup {

  /// The multiplicative _associativity_ axiom.
  fn associativity(&self, x: &Self, y: &Self) -> bool {
      self.mul(&x.mul(y)) == self.mul(x).mul(y)
  }
}


///
/// Blanket implementation of multiplicative semigroup laws for
/// multiplicative semigroup implementations.
///
impl<S: MulSemigroup> MulSemigroupLaws for S {}


///
/// Numeric laws of multiplicative semigroups.
///
pub trait NumMulSemigroupLaws: NumEq + MulSemigroup {

  /// The numeric multiplicative _associativity_ axiom.
  fn num_associativity(&self, x: &Self, y: &Self, eps: &Self::Eps) -> bool {
      self.mul(&x.mul(y)).num_eq(&self.mul(x).mul(y), eps)
  }
}


///
/// Blanket implementation of numeric multiplicative semigroup laws for
/// multiplicative semigroup implementations.
///
impl<S: NumEq + MulSemigroup> NumMulSemigroupLaws for S {}


///
/// Define `MulSemigroup` implementations for numeric types.
///
macro_rules! numeric_mul_semigroup {
  ($type:ty) => {
    impl MulSemigroup for $type {}
  };

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


// Numeric multiplicative semigroups.
numeric_mul_semigroup! {
  u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize, f32, f64
}


///
/// 0-tuples form a multiplicative semigroup.
///
impl MulSemigroup for () {}


///
/// 1-tuples form a multiplicative semigroup when their items do.
///
impl<A: MulSemigroup> MulSemigroup for (A,) {}


///
/// 2-tuples form a multiplicative semigroup when their items do.
///
impl<A: MulSemigroup, B: MulSemigroup> MulSemigroup for (A, B) {}


///
/// 3-tuples form a multiplicative semigroup when their items do.
///
impl<A: MulSemigroup, B: MulSemigroup, C: MulSemigroup> MulSemigroup for (A, B, C) {}


///
/// Define `MulSemigroup` implementations for arrays. Maybe not needed
/// if Rust had _const_ _generics_.
///
macro_rules! array_mul_semigroup {
  ($size:expr) => {
    impl<T: Copy + MulSemigroup> MulSemigroup for [T; $size] {}
  };

  ($size:expr, $($others:expr),+) => {
    array_mul_semigroup! {$size}
    array_mul_semigroup! {$($others),+}
  };
}


// Array multiplicative semigroup types.
array_mul_semigroup! {
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
}


// Module unit tests are in a sub-module.
#[cfg(test)]
mod tests;