Skip to main content

deep_causality_num/algebra/
monoid.rs

1/*
2 * SPDX-License-Identifier: MIT
3 * Copyright (c) 2023 - 2026. The DeepCausality Authors and Contributors. All Rights Reserved.
4 */
5use crate::{Associative, MulMagma, One, Zero};
6use core::ops::{Add, AddAssign, Div, DivAssign};
7
8/// Represents an **Additive Monoid**.
9///
10/// A monoid is an algebraic structure with a single associative binary
11/// operation and an identity element. An additive monoid is one where the
12/// operation is addition (`+`).
13///
14/// # Mathematical Definition
15///
16/// A set `S` with a binary operation `+` is an additive monoid if it satisfies:
17/// 1.  **Closure:** `a + b` is in `S`. (Implicit in Rust).
18/// 2.  **Associativity:** `(a + b) + c = a + (b + c)` for all `a, b, c` in `S`.
19///     (A property the implementor must uphold).
20/// 3.  **Identity Element:** There exists an element `0` in `S` such that
21///     `a + 0 = 0 + a = a` for all `a` in `S`. (Provided by the `Zero` trait).
22///
23/// The `Clone` and `AddAssign` bounds are included for practical purposes.
24pub trait AddMonoid: Add<Output = Self> + AddAssign + Zero + Clone {}
25
26// Blanket Implementation for all types that implement Add, AddAssign, and Zero
27impl<T> AddMonoid for T where T: Add<Output = Self> + AddAssign + Zero + Clone {}
28
29/// Represents a **Multiplicative Monoid**.
30///
31/// A monoid is an algebraic structure with a single associative binary
32/// operation and an identity element. A multiplicative monoid is one where the
33/// operation is multiplication (`*`).
34///
35/// # Mathematical Definition
36///
37/// A set `S` with a binary operation `*` is a multiplicative monoid if it satisfies:
38/// 1.  **Closure:** `a * b` is in `S`. (Implicit in Rust).
39/// 2.  **Associativity:** `(a * b) * c = a * (b * c)` for all `a, b, c` in `S`.
40///     (A property the implementor must uphold).
41/// 3.  **Identity Element:** There exists an element `1` in `S` such that
42///     `a * 1 = 1 * a = a` for all `a` in `S`. (Provided by the `One` trait).
43///
44/// The `Clone` and `MulAssign` bounds are included for practical purposes.
45pub trait MulMonoid: MulMagma + One + Associative {}
46
47// Blanket Implementation for all types that implement Mul, MulAssign, and One
48impl<T> MulMonoid for T where T: MulMagma + One + Associative {}
49
50/// Represents a **Multiplicative Monoid** with the additional property
51/// that every element has a multiplicative inverse.
52///
53/// This trait effectively defines the "inverse" operation within a multiplicative
54/// context, sitting between `MulMonoid` and `MulGroup` in the hierarchy.
55///
56/// # Mathematical Definition
57///
58/// An `InvMonoid` is a `MulMonoid` where for every element `a`, there exists
59/// an element `a⁻¹` such that `a * a⁻¹ = 1` and `a⁻¹ * a = 1`.
60///
61/// # Justification for Deviation (for floating-point types)
62///
63/// In pure mathematics, the zero element does not have a multiplicative inverse.
64/// To align with standard floating-point behavior (IEEE 754), implementations
65/// for types that can be zero (like `f32`, `f64`) should handle this case
66/// gracefully by returning `Infinity` or `NaN` rather than panicking.
67pub trait InvMonoid: MulMonoid + Div<Output = Self> + DivAssign {
68    /// Computes the multiplicative inverse of an element.
69    ///
70    /// For a non-zero element `a`, its inverse `a⁻¹` is the unique element
71    /// such that `a * a⁻¹ = 1`.
72    fn inverse(&self) -> Self;
73}
74
75// Blanket Implementation for types that already satisfy MulMonoid and
76// implement Div and DivAssign. This blanket assumes a standard inverse
77// calculation using 1 / self.
78impl<T> InvMonoid for T
79where
80    T: MulMonoid + Div<Output = Self> + DivAssign + One + Clone,
81{
82    #[inline]
83    fn inverse(&self) -> Self {
84        // The inverse is typically defined as Identity / Value.
85        // We utilize the Div trait which is required by InvMonoid.
86        // We clone self because Div takes operands by value (T / T).
87        // For Copy types like f64/Complex, clone() is a no-op copy.
88        T::one() / self.clone()
89    }
90}