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 monoids.
//!
//! An algebraic _multiplicative_ _monoid_ is a _multiplicative_
//! _semigroup_ `S`, with a unique multiplicative _identity_ element,
//! called _one_, and denoted `1`.
//!
//! # Axioms
//!
//! ```text
//! ∀x ∈ S
//!
//! Identity: ∃1 ∈ S: 1 × x = x × 1 = x.
//! ```
//!
//! # References
//!
//! See [references] for a formal definition of a multiplicative
//! monoid.
//!
#![doc(include = "../../doc/references.md")]

use crate::numeric::*;
use crate::semigroup::*;


///
/// An algebraic _multiplicative monoid_.
///
pub trait MulMonoid: MulSemigroup {

  /// The unique _multiplicative_ _identity_ (i.e. one) element. This
  /// should be an associated const, but we need more upstream crates to
  /// support them first.
  fn one() -> Self;


  /// Test for the one (multiplicative identity) element.
  fn is_one(&self) -> bool {
    *self == Self::one()
  }
}


///
/// Laws of multiplicative monoids.
///
pub trait MulMonoidLaws: MulMonoid {

  /// The _left_ _multiplicative_ _identity_ axiom.
  fn left_identity(&self) -> bool {
    Self::one().mul(self) == *self
  }


  /// The _right_ _multiplicative_ _identity_ axiom.
  fn right_identity(&self) -> bool {
    self.mul(&Self::one()) == *self
  }


  /// The _two_ _sided_ _multiplicative_ _identity_ axiom.
  fn identity(&self) -> bool {
    self.left_identity() && self.right_identity()
  }
}


///
/// Blanket implementation of multiplicative monoid laws for
/// multiplicative monoid implementations.
///
impl<M: MulMonoid> MulMonoidLaws for M {}


///
/// Numeric laws of multiplicative monoids.
///
pub trait NumMulMonoidLaws: NumEq + MulMonoid {

  /// The _left_ _numeric_ _multiplicative_ _identity_ axiom.
  fn num_left_identity(&self, eps: &Self::Eps) -> bool {
    Self::one().mul(self).num_eq(&self, eps)
  }


  /// The _right_ _numeric_ _multiplicative_ _identity_ axiom.
  fn num_right_identity(&self, eps: &Self::Eps) -> bool {
    self.mul(&Self::one()).num_eq(&self, eps)
  }


  /// The _two_ _sided_ _numeric+ _multiplicative_ _identity_ axiom.
  fn num_identity(&self, eps: &Self::Eps) -> bool {
    self.num_left_identity(eps) && self.num_right_identity(eps)
  }
}


///
/// Blanket implementation of numeric additive monoid laws for additive
/// monoid implementations.
///
impl<M: NumEq + MulMonoid> NumMulMonoidLaws for M {}


///
/// Define `MulMonoid` implementations for numeric types.
///
macro_rules! numeric_mul_monoid {
  ($type:ty) => {
    impl MulMonoid for $type {

      /// One is just type one.
      fn one() -> Self {
        1 as Self
      }
    }
  };

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


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


///
/// 0-tuples form a multiplicative monoid.
///
impl MulMonoid for () {

  /// One value can only be `()`.
  fn one() -> Self {}
}


///
/// 1-tuples form a multiplicative monoid when their items do.
///
impl<T: MulMonoid> MulMonoid for (T,) {

  /// One is by element type.
  fn one() -> Self {
    (T::one(), )
  }
}


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

  /// One is by element type.
  fn one() -> Self {
    (A::one(), B::one())
  }
}


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

  /// One is by element type.
  fn one() -> Self {
    (A::one(), B::one(), C::one())
  }
}


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

      // Create array of ones.
      fn one() -> Self {
        [T::one(); $size]
      }
    }
  };

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


// Array multiplicative monoid types.
array_mul_monoid! {
  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;