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 magmas.
//!
//! An algebraic _multiplicative_ _magma_ is a set `S`, equipped with a
//! _binary_ _operation_ `×`, called _multiplication_. `S` is _closed_
//! under multiplication.
//!
//! # Axioms
//!
//! ```text
//! Closure: ∀x, y ∈ S, x × y ∈ S.
//! ```
//!
//! # References
//!
//! See [references] for a formal definition of a multiplicative
//! magma.
//!
#![doc(include = "../../doc/references.md")]

use crate::helpers::*;
use crate::numeric::*;


///
/// An algebraic _multiplicative magma_.
///
pub trait MulMagma: Sized + PartialEq {

  /// Binary _multiplication_ operation.
  fn mul(&self, other: &Self) -> Self;
}


///
/// Laws of multiplicative magmas. The _closure_ axiom defined here is
/// guaranteed by Rust's type system and is implemented only for
/// completeness.
///
pub trait MulMagmaLaws: MulMagma {

  /// The _closure_ axiom.
  fn closure(&self, _x: &Self) -> bool {
    true
  }
}


///
/// Blanket implementation of multiplicative magma laws for
/// multiplicative magma implementations.
///
impl<M: MulMagma> MulMagmaLaws for M {}


///
/// Numeric laws of multiplicative magmas. The _closure_ axiom defined
/// here is guaranteed by Rust's type system and is implemented only for
/// completeness.
///
pub trait NumMulMagmaLaws: NumEq + MulMagma {

  /// The numeric _closure_ axiom.
  fn num_closure(&self, _x: &Self, _eps: &Self::Eps) -> bool {
    true
  }
}


///
/// Blanket implementation of numeric multiplicative magma laws for
/// multiplicative magma implementations.
///
impl<M: NumEq + MulMagma> NumMulMagmaLaws for M {}


///
/// Define `MulMagma` implementations for integer types. Probably not
/// needed if Rust had an `Integer` super-trait.
///
macro_rules! integer_mul_magma {
  ($type:ty) => {
    impl MulMagma for $type {

      /// We use "wrapping" multiply to avoid overflow and guarantee the
      /// closure axiom.
      fn mul(&self, other: &Self) -> Self {
        self.wrapping_mul(*other)
      }
    }
  };

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


// Unsigned integer multiplicative magmas.
integer_mul_magma! {
  u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
}


///
/// Define `MulMagma` implementations for floating point types. Probably
/// not needed if Rust had a `Float` super-trait.
///
macro_rules! float_mul_magma {
  ($type:ty) => {

    impl MulMagma for $type {

      /// magma multiplication is just floating point multiplication.
      fn mul(&self, other: &Self) -> Self {
        *self * *other
      }
    }
  };

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


// Floating point multiplicative magma types.
float_mul_magma! {
  f32, f64
}


///
/// 0-tuples form a multiplicative magma.
///
impl MulMagma for () {

  /// Multiplication can only yield a `()`.
  fn mul(&self, _: &Self) -> Self {}
}


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

  /// Multiplication is by matching element.
  fn mul(&self, other: &Self) -> Self {
    (self.0.mul(&other.0), )
  }
}


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

  /// Multiplication is by matching element.
  fn mul(&self, other: &Self) -> Self {
    (self.0.mul(&other.0), self.1.mul(&other.1))
  }
}


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

  /// Multiplication is by matching element.
  fn mul(&self, other: &Self) -> Self {
    (self.0.mul(&other.0), self.1.mul(&other.1), self.2.mul(&other.2))
  }
}


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

      /// Delegate to `Sequence` trait map_with function.
      fn mul(&self, other: &Self) -> Self {
        self.map_with(other, &|x, y| x.mul(y))
      }
    }
  };

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


// Array magma types.
array_mul_magma! {
  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;