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.
//!
//! Groups.
//!
//! An algebraic _group_ is a _monoid_ `M`, where each group element `g`
//! has a unique _inverse_ element denoted `g^-1`.
//!
//! # Axioms
//!
//! ```text
//! ∀g, e ∈ M
//!
//! Inverse: ∃g^-1 ∈ M: g ∘ g^-1 = g^-1 ∘ g = e.
//! ```
//!
//! # References
//!
//! See [references] for a formal definition of a group.
//!
#![doc(include = "../../doc/references.md")]

use crate::monoid::*;
use crate::helpers::*;


///
/// An algebraic _group_.
///
pub trait Group: Monoid {

  /// The unique _inverse_ of a group element.
  fn inverse(&self) -> Self;


  /// The cancellation of a group element.
  fn cancel(&self) -> Self {
    self.op(&self.inverse())
  }
}


///
/// Laws of groups.
///
pub trait GroupLaws: Group {

  /// The _left_ _inverse_ axiom.
  fn left_inverse(&self) -> bool {
    self.inverse().op(self) == Self::id()
  }


  /// The _right_ _inverse_ axiom.
  fn right_inverse(&self) -> bool {
    self.op(&self.inverse()) == Self::id()
  }


  /// The _two_-_sided_ _inverse_ axiom.
  fn inverses(&self) -> bool {
    self.left_inverse() && self.right_inverse()
  }
}


///
/// Blanket implementation of group laws for group implementations.
///
impl<S: Group> GroupLaws for S {}


///
/// 0-tuples form a group.
///
impl Group for () {

  /// Inverse value can only be `()`.
  fn inverse(&self) -> Self {}
}


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

  /// Inverse is by element type.
  fn inverse(&self) -> Self {
    (self.0.inverse(), )
  }
}


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

  /// Inverse is by element type.
  fn inverse(&self) -> Self {
    (self.0.inverse(), self.1.inverse())
  }
}


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

  /// Inverse is by element type.
  fn inverse(&self) -> Self {
    (self.0.inverse(), self.1.inverse(), self.2.inverse())
  }
}


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

     fn inverse(&self) -> Self {
       self.map(&|&x| x.inverse())
     }
    }
  };

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


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