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
//!
//! Algebraic _multiplicative_ _semigroups_.
//!
//! An algebraic _multiplicative_ _semigroup_ is a _multiplicative_
//! _magma_ `M`, where the multiplication operation `×` is
//! _associative_.
//!
//! # Axioms
//!
//! ```notrust
//! ∀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 {}


///
/// The _associativity_ axiom.
//
pub fn associativity<T: MulSemigroup>(x: &T, y: &T, z: &T) -> bool {
  x.mul(&y.mul(z)) == x.mul(y).mul(z)
}


///
/// The _numeric_ _associativity_ axiom.
///
pub fn num_associativity<T: MulSemigroup + NumEq>(x: &T, y: &T, z: &T, eps: &T::Eps) -> bool {
  x.mul(&y.mul(z)).num_eq(&x.mul(y).mul(z), eps)
}


///
/// A macro for `MulSemigroup` implementations for built-in 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) {}


///
/// A macro for `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;