un_algebra 0.9.0

Simple implementations of selected abstract algebraic structures--including groups, rings, and fields. Intended for self-study of abstract algebra concepts and not for production use.
//!
//! 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;