tenferro_ext_tropical/algebra.rs
1//! Tropical algebra markers, [`HasAlgebra`], and [`Semiring`] implementations.
2//!
3//! Each zero-sized struct identifies a tropical algebra for use with
4//! semiring-family execution traits such as
5//! [`TensorSemiringCore<Alg>`](tenferro_prims::TensorSemiringCore). The orphan
6//! rule is satisfied because the algebra markers are defined in this crate.
7//!
8//! | Algebra marker | Scalar wrapper | ⊕ | ⊗ |
9//! |----------------|---------------|---|---|
10//! | [`MaxPlusAlgebra<T>`] | [`MaxPlus<T>`](crate::MaxPlus) | max | + |
11//! | [`MinPlusAlgebra<T>`] | [`MinPlus<T>`](crate::MinPlus) | min | + |
12//! | [`MaxMulAlgebra<T>`] | [`MaxMul<T>`](crate::MaxMul) | max | × |
13
14use std::marker::PhantomData;
15
16use tenferro_algebra::{Algebra, HasAlgebra, Semiring};
17
18use crate::scalar::{MaxMul, MaxPlus, MinPlus};
19
20/// Generates a tropical algebra marker struct with HasAlgebra and Semiring impls.
21///
22/// For each invocation, this creates:
23/// - A generic zero-sized marker struct `$marker<T>`
24/// - `HasAlgebra` impls mapping `$wrapper<f32>` and `$wrapper<f64>` to the marker
25/// - `Semiring` impls for `$marker<f32>` and `$marker<f64>`
26///
27/// The `$add_fn` and `$mul_fn` closures define the semiring operations and must
28/// be valid for both f32 and f64.
29macro_rules! define_tropical_algebra {
30 (
31 $(#[$meta:meta])*
32 $marker:ident, $wrapper:ident,
33 zero_f32: $z32:expr, one_f32: $o32:expr,
34 zero_f64: $z64:expr, one_f64: $o64:expr
35 ) => {
36 $(#[$meta])*
37 #[derive(Debug, Clone, Copy)]
38 pub struct $marker<T>(PhantomData<T>);
39
40 impl HasAlgebra for $wrapper<f32> {
41 type Algebra = $marker<f32>;
42 }
43
44 impl HasAlgebra for $wrapper<f64> {
45 type Algebra = $marker<f64>;
46 }
47
48 impl Algebra for $marker<f32> {
49 type Scalar = $wrapper<f32>;
50 }
51
52 impl Algebra for $marker<f64> {
53 type Scalar = $wrapper<f64>;
54 }
55
56 impl Semiring for $marker<f32> {
57 fn zero() -> Self::Scalar { $z32 }
58 fn one() -> Self::Scalar { $o32 }
59 fn add(a: Self::Scalar, b: Self::Scalar) -> Self::Scalar { a + b }
60 fn mul(a: Self::Scalar, b: Self::Scalar) -> Self::Scalar { a * b }
61 }
62
63 impl Semiring for $marker<f64> {
64 fn zero() -> Self::Scalar { $z64 }
65 fn one() -> Self::Scalar { $o64 }
66 fn add(a: Self::Scalar, b: Self::Scalar) -> Self::Scalar { a + b }
67 fn mul(a: Self::Scalar, b: Self::Scalar) -> Self::Scalar { a * b }
68 }
69 };
70}
71
72define_tropical_algebra!(
73 /// Algebra marker for the max-plus tropical semiring (⊕ = max, ⊗ = +).
74 ///
75 /// Generic over the inner scalar type `T` (typically `f32` or `f64`).
76 /// Used as the algebra parameter `Alg` in semiring-family execution traits
77 /// such as
78 /// [`TensorSemiringCore<MaxPlusAlgebra<T>>`](tenferro_prims::TensorSemiringCore).
79 ///
80 /// # Examples
81 ///
82 /// ```
83 /// use tenferro_algebra::Semiring;
84 /// use tenferro_ext_tropical::{MaxPlus, MaxPlusAlgebra};
85 ///
86 /// let z = <MaxPlusAlgebra<f64> as Semiring>::zero();
87 /// assert_eq!(z, MaxPlus(f64::NEG_INFINITY));
88 /// let z32 = <MaxPlusAlgebra<f32> as Semiring>::zero();
89 /// assert_eq!(z32, MaxPlus(f32::NEG_INFINITY));
90 /// ```
91 MaxPlusAlgebra, MaxPlus,
92 zero_f32: MaxPlus(f32::NEG_INFINITY), one_f32: MaxPlus(0.0f32),
93 zero_f64: MaxPlus(f64::NEG_INFINITY), one_f64: MaxPlus(0.0f64)
94);
95
96define_tropical_algebra!(
97 /// Algebra marker for the min-plus tropical semiring (⊕ = min, ⊗ = +).
98 ///
99 /// # Examples
100 ///
101 /// ```
102 /// use tenferro_algebra::Semiring;
103 /// use tenferro_ext_tropical::{MinPlus, MinPlusAlgebra};
104 ///
105 /// let z = <MinPlusAlgebra<f64> as Semiring>::zero();
106 /// assert_eq!(z, MinPlus(f64::INFINITY));
107 /// ```
108 MinPlusAlgebra, MinPlus,
109 zero_f32: MinPlus(f32::INFINITY), one_f32: MinPlus(0.0f32),
110 zero_f64: MinPlus(f64::INFINITY), one_f64: MinPlus(0.0f64)
111);
112
113define_tropical_algebra!(
114 /// Algebra marker for the max-times tropical semiring (⊕ = max, ⊗ = ×).
115 ///
116 /// # Examples
117 ///
118 /// ```
119 /// use tenferro_algebra::Semiring;
120 /// use tenferro_ext_tropical::{MaxMul, MaxMulAlgebra};
121 ///
122 /// let z = <MaxMulAlgebra<f64> as Semiring>::zero();
123 /// assert_eq!(z, MaxMul(0.0f64));
124 /// ```
125 MaxMulAlgebra, MaxMul,
126 zero_f32: MaxMul(0.0f32), one_f32: MaxMul(1.0f32),
127 zero_f64: MaxMul(0.0f64), one_f64: MaxMul(1.0f64)
128);
129
130#[cfg(test)]
131mod tests;