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

use crate::helpers::*;


///
/// An abstract algebraic _magma_.
///
pub trait Magma: Sized + PartialEq {

  /// Magma _binary_ _operation_.
  fn op(&self, other: &Self) -> Self;
}


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

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


///
/// Blanket implementation of magma laws for magma implementations.
///
impl<M: Magma> MagmaLaws for M {}


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

  /// Binary operation can only be `()`.
  fn op(&self, _: &Self) -> Self {}
}


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

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


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

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


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

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


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

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

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


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