tenferro_ext_tropical/
scalar.rs

1//! Tropical scalar wrapper types.
2//!
3//! Each newtype redefines `Add` and `Mul` so that the [`Scalar`](tenferro_algebra::Scalar)
4//! blanket impl is satisfied with tropical semantics:
5//!
6//! | Type | `+` (⊕) | `*` (⊗) | Zero | One |
7//! |------|---------|---------|------|-----|
8//! | [`MaxPlus<T>`] | max | + | −∞ | 0 |
9//! | [`MinPlus<T>`] | min | + | +∞ | 0 |
10//! | [`MaxMul<T>`] | max | × | 0 | 1 |
11//!
12//! All arithmetic operations are fully implemented.
13
14use std::fmt;
15use std::ops;
16
17use tenferro_algebra::Conjugate;
18
19/// Max-plus tropical scalar: ⊕ = max, ⊗ = +.
20///
21/// The most common tropical semiring, used for shortest-path and
22/// optimal-alignment problems. Wraps any ordered numeric type `T`.
23///
24/// # Examples
25///
26/// ```
27/// use tenferro_ext_tropical::MaxPlus;
28///
29/// let a = MaxPlus(3.0_f64);
30/// let b = MaxPlus(5.0_f64);
31///
32/// // Tropical addition = max
33/// let c = a + b;
34/// assert_eq!(c, MaxPlus(5.0));
35///
36/// // Tropical multiplication = ordinary addition
37/// let d = a * b;
38/// assert_eq!(d, MaxPlus(8.0));
39/// ```
40#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
41#[repr(transparent)]
42pub struct MaxPlus<T>(pub T);
43
44/// Min-plus tropical scalar: ⊕ = min, ⊗ = +.
45///
46/// Used for shortest-path problems (Dijkstra, Bellman–Ford).
47///
48/// # Examples
49///
50/// ```
51/// use tenferro_ext_tropical::MinPlus;
52///
53/// let a = MinPlus(3.0_f64);
54/// let b = MinPlus(5.0_f64);
55///
56/// // Tropical addition = min
57/// let c = a + b;
58/// assert_eq!(c, MinPlus(3.0));
59///
60/// // Tropical multiplication = ordinary addition
61/// let d = a * b;
62/// assert_eq!(d, MinPlus(8.0));
63/// ```
64#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
65#[repr(transparent)]
66pub struct MinPlus<T>(pub T);
67
68/// Max-times tropical scalar: ⊕ = max, ⊗ = ×.
69///
70/// Used for probabilistic models where you want the most likely
71/// path (Viterbi algorithm with probabilities in [0, 1]).
72///
73/// # Examples
74///
75/// ```
76/// use tenferro_ext_tropical::MaxMul;
77///
78/// let a = MaxMul(0.3_f64);
79/// let b = MaxMul(0.7_f64);
80///
81/// // Tropical addition = max
82/// let c = a + b;
83/// assert_eq!(c, MaxMul(0.7));
84///
85/// // Tropical multiplication = ordinary multiplication
86/// let d = a * b;
87/// assert!((d.0 - 0.21).abs() < 1e-15);
88/// ```
89#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
90#[repr(transparent)]
91pub struct MaxMul<T>(pub T);
92
93impl<T: Copy> Conjugate for MaxPlus<T> {}
94
95impl<T: Copy> Conjugate for MinPlus<T> {}
96
97impl<T: Copy> Conjugate for MaxMul<T> {}
98
99// ---------------------------------------------------------------------------
100// Display
101// ---------------------------------------------------------------------------
102
103impl<T: fmt::Display> fmt::Display for MaxPlus<T> {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        write!(f, "MaxPlus({})", self.0)
106    }
107}
108
109impl<T: fmt::Display> fmt::Display for MinPlus<T> {
110    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
111        write!(f, "MinPlus({})", self.0)
112    }
113}
114
115impl<T: fmt::Display> fmt::Display for MaxMul<T> {
116    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
117        write!(f, "MaxMul({})", self.0)
118    }
119}
120
121// ---------------------------------------------------------------------------
122// MaxPlus<T>: Add (= max), Mul (= +), Zero (= −∞), One (= 0)
123// ---------------------------------------------------------------------------
124
125impl<T: Copy + PartialOrd> ops::Add for MaxPlus<T> {
126    type Output = Self;
127
128    /// Tropical addition: max(a, b).
129    fn add(self, rhs: Self) -> Self {
130        if self.0 >= rhs.0 {
131            self
132        } else {
133            rhs
134        }
135    }
136}
137
138impl<T: Copy + ops::Add<Output = T>> ops::Mul for MaxPlus<T> {
139    type Output = Self;
140
141    /// Tropical multiplication: a + b (ordinary addition).
142    fn mul(self, rhs: Self) -> Self {
143        MaxPlus(self.0 + rhs.0)
144    }
145}
146
147impl<T: num_traits::Float> num_traits::Zero for MaxPlus<T> {
148    /// Additive identity: −∞ (negative infinity).
149    fn zero() -> Self {
150        MaxPlus(T::neg_infinity())
151    }
152
153    fn is_zero(&self) -> bool {
154        self.0 == T::neg_infinity()
155    }
156}
157
158impl<T: num_traits::Float> num_traits::One for MaxPlus<T> {
159    /// Multiplicative identity: 0.
160    fn one() -> Self {
161        MaxPlus(T::zero())
162    }
163}
164
165// ---------------------------------------------------------------------------
166// MinPlus<T>: Add (= min), Mul (= +), Zero (= +∞), One (= 0)
167// ---------------------------------------------------------------------------
168
169impl<T: Copy + PartialOrd> ops::Add for MinPlus<T> {
170    type Output = Self;
171
172    /// Tropical addition: min(a, b).
173    fn add(self, rhs: Self) -> Self {
174        if self.0 <= rhs.0 {
175            self
176        } else {
177            rhs
178        }
179    }
180}
181
182impl<T: Copy + ops::Add<Output = T>> ops::Mul for MinPlus<T> {
183    type Output = Self;
184
185    /// Tropical multiplication: a + b (ordinary addition).
186    fn mul(self, rhs: Self) -> Self {
187        MinPlus(self.0 + rhs.0)
188    }
189}
190
191impl<T: num_traits::Float> num_traits::Zero for MinPlus<T> {
192    /// Additive identity: +∞ (positive infinity).
193    fn zero() -> Self {
194        MinPlus(T::infinity())
195    }
196
197    fn is_zero(&self) -> bool {
198        self.0 == T::infinity()
199    }
200}
201
202impl<T: num_traits::Float> num_traits::One for MinPlus<T> {
203    /// Multiplicative identity: 0.
204    fn one() -> Self {
205        MinPlus(T::zero())
206    }
207}
208
209// ---------------------------------------------------------------------------
210// MaxMul<T>: Add (= max), Mul (= ×), Zero (= 0), One (= 1)
211// ---------------------------------------------------------------------------
212
213impl<T: Copy + PartialOrd> ops::Add for MaxMul<T> {
214    type Output = Self;
215
216    /// Tropical addition: max(a, b).
217    fn add(self, rhs: Self) -> Self {
218        if self.0 >= rhs.0 {
219            self
220        } else {
221            rhs
222        }
223    }
224}
225
226impl<T: Copy + ops::Mul<Output = T>> ops::Mul for MaxMul<T> {
227    type Output = Self;
228
229    /// Tropical multiplication: a × b (ordinary multiplication).
230    fn mul(self, rhs: Self) -> Self {
231        MaxMul(self.0 * rhs.0)
232    }
233}
234
235impl<T: num_traits::Float> num_traits::Zero for MaxMul<T> {
236    /// Additive identity: 0 (for max, 0 is the identity when values are non-negative).
237    fn zero() -> Self {
238        MaxMul(T::zero())
239    }
240
241    fn is_zero(&self) -> bool {
242        self.0 == T::zero()
243    }
244}
245
246impl<T: num_traits::Float> num_traits::One for MaxMul<T> {
247    /// Multiplicative identity: 1.
248    fn one() -> Self {
249        MaxMul(T::one())
250    }
251}
252
253// ---------------------------------------------------------------------------
254// Unsafe marker traits — MaxPlus/MinPlus/MaxMul are Send + Sync if T is.
255// These are automatically derived from the inner T via #[repr(transparent)].
256// ---------------------------------------------------------------------------
257
258// Send and Sync are auto-derived since the wrapper is transparent over T.