Skip to main content

sim_lib_discrete_algebra/
real.rs

1//! The real semiring over `f64` with ordinary `+` and `*`, plus a total order
2//! for algorithms that need to compare entries. No `star` (left as default).
3
4use crate::semiring::Semiring;
5
6/// Real semiring: `add` is `+`, `mul` is `*`, `zero` is `0.0`, `one` is `1.0`.
7///
8/// Equality is the underlying `f64` equality (so `NaN` is never equal to
9/// itself); algorithm fixtures should avoid `NaN`. [`RealF64::total_cmp`]
10/// provides a total order for matrix algorithms that pivot or sort.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct RealF64(pub f64);
13
14impl RealF64 {
15    /// Wrap a raw `f64`.
16    pub fn new(value: f64) -> Self {
17        RealF64(value)
18    }
19    /// A total order over all `f64` values (including `NaN` and signed zero),
20    /// delegating to [`f64::total_cmp`].
21    pub fn total_cmp(&self, other: &Self) -> core::cmp::Ordering {
22        self.0.total_cmp(&other.0)
23    }
24}
25
26impl Semiring for RealF64 {
27    fn zero() -> Self {
28        RealF64(0.0)
29    }
30    fn one() -> Self {
31        RealF64(1.0)
32    }
33    fn add(&self, other: &Self) -> Self {
34        RealF64(self.0 + other.0)
35    }
36    fn mul(&self, other: &Self) -> Self {
37        RealF64(self.0 * other.0)
38    }
39    fn is_zero(&self) -> bool {
40        self.0 == 0.0
41    }
42    // star intentionally left as the default `None`: the geometric series
43    // `1/(1-a)` is outside the scope of the structural closure engine.
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use crate::semiring::laws::assert_semiring_laws;
50    use core::cmp::Ordering;
51
52    #[test]
53    fn laws_hold() {
54        // Small integers are exact in f64, so the semiring laws hold exactly.
55        assert_semiring_laws(&[RealF64(0.0), RealF64(1.0), RealF64(2.0), RealF64(4.0)]);
56    }
57
58    #[test]
59    fn total_order_is_total() {
60        assert_eq!(RealF64(1.0).total_cmp(&RealF64(2.0)), Ordering::Less);
61        assert_eq!(RealF64(2.0).total_cmp(&RealF64(2.0)), Ordering::Equal);
62        assert_eq!(RealF64::zero().star(), None);
63    }
64}