1use std::fmt::Debug;
53
54use super::*;
55use crate::rings::Semiring;
56
57#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)]
65pub enum TropicalElement<F>
66where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
67{
68 Element(F),
70 NegInfinity,
72}
73
74impl<F> Eq for TropicalElement<F> where F: Copy + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One {}
75impl<F> TropicalElement<F>
76where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
77{
78 pub fn new(value: F) -> Self { TropicalElement::Element(value) }
80
81 pub fn value(&self) -> TropicalElement<F> { *self }
83}
84
85impl<F> Add for TropicalElement<F>
86where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
87{
88 type Output = Self;
89
90 fn add(self, other: Self) -> Self::Output {
91 match self {
92 TropicalElement::Element(a) => {
93 match other {
94 TropicalElement::Element(b) => {
95 Self::Element(if a > b { a } else { b })
97 },
98 TropicalElement::NegInfinity => Self::Element(a),
99 }
100 },
101 TropicalElement::NegInfinity => match other {
102 TropicalElement::Element(b) => Self::Element(b),
103 TropicalElement::NegInfinity => Self::NegInfinity,
104 },
105 }
106 }
107}
108
109impl<F> AddAssign for TropicalElement<F>
110where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
111{
112 fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; }
113}
114
115impl<F> Mul for TropicalElement<F>
116where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
117{
118 type Output = Self;
119
120 fn mul(self, other: Self) -> Self::Output {
121 match self {
122 TropicalElement::Element(a) => {
123 match other {
124 TropicalElement::Element(b) => {
125 #[allow(clippy::suspicious_arithmetic_impl)]
127 Self::Element(a + b)
128 },
129 TropicalElement::NegInfinity => Self::NegInfinity,
130 }
131 },
132 TropicalElement::NegInfinity => Self::NegInfinity,
133 }
134 }
135}
136
137impl<F> MulAssign for TropicalElement<F>
138where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
139{
140 fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; }
141}
142
143impl<F> Zero for TropicalElement<F>
144where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
145{
146 fn zero() -> Self { TropicalElement::NegInfinity }
147
148 fn is_zero(&self) -> bool { *self == TropicalElement::NegInfinity }
149}
150
151impl<F> One for TropicalElement<F>
152where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One
153{
154 fn one() -> Self { TropicalElement::Element(F::zero()) }
155}
156
157impl<F> Additive for TropicalElement<F> where F: Copy + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One {}
158impl<F> Multiplicative for TropicalElement<F> where F: Copy + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One {}
159impl<F> Semiring for TropicalElement<F> where F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One {}
160
161#[derive(Debug, PartialEq, Eq)]
163pub struct BilinearForm<const N: usize, F>
164where
165 F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One,
166 [(); N * (N + 1) / 2]:, {
167 matrix: [TropicalElement<F>; N * (N + 1) / 2],
170}
171
172impl<const N: usize, F> BilinearForm<N, F>
173where
174 F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One,
175 [(); N * (N + 1) / 2]:, {
177 pub fn new(matrix: [[TropicalElement<F>; N]; N]) -> Self {
180 let mut upper_triangular = [TropicalElement::NegInfinity; N * (N + 1) / 2];
181 let mut idx = 0;
182 for (i, row) in matrix.iter().enumerate() {
183 for (_j, &element) in row.iter().enumerate().skip(i) {
184 upper_triangular[idx] = element;
185 idx += 1;
186 }
187 }
188 Self { matrix: upper_triangular }
189 }
190
191 fn get(&self, i: usize, j: usize) -> TropicalElement<F> {
194 if i <= j {
195 let n = N;
199 let idx = i
200 .checked_mul(2 * n - i + 1)
201 .and_then(|x| x.checked_div(2))
202 .and_then(|x| x.checked_add(j - i))
203 .expect("Index calculation overflow");
204 self.matrix[idx]
205 } else {
206 self.get(j, i)
208 }
209 }
210
211 pub fn evaluate(
213 &self,
214 x: &[TropicalElement<F>; N],
215 y: &[TropicalElement<F>; N],
216 ) -> TropicalElement<F> {
217 let mut result = TropicalElement::<F>::zero();
218
219 for (i, &xi) in x.iter().enumerate() {
220 for (j, &yj) in y.iter().enumerate() {
221 let term = xi * self.get(i, j) * yj;
222 result = match (term, result) {
226 (TropicalElement::Element(_), TropicalElement::NegInfinity) => term,
227 (TropicalElement::NegInfinity, TropicalElement::Element(_)) => result,
228 (TropicalElement::Element(t), TropicalElement::Element(r)) =>
229 if t > r {
230 term
231 } else {
232 result
233 },
234 (TropicalElement::NegInfinity, TropicalElement::NegInfinity) => result,
235 };
236 }
237 }
238
239 result
240 }
241}
242
243pub struct TropicalAlgebra<const N: usize, F>
245where
246 F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One,
247 [(); N * (N + 1) / 2]:, {
248 bilinear_form: BilinearForm<N, F>,
250}
251
252impl<const N: usize, F> TropicalAlgebra<N, F>
253where
254 F: Copy + Clone + Debug + PartialEq + PartialOrd + Add<Output = F> + Mul<Output = F> + Zero + One,
255 [(); N * (N + 1) / 2]:,
256{
257 pub fn new(bilinear_form: BilinearForm<N, F>) -> Self { Self { bilinear_form } }
259
260 pub fn evaluate(
262 &self,
263 x: &[TropicalElement<F>; N],
264 y: &[TropicalElement<F>; N],
265 ) -> TropicalElement<F> {
266 self.bilinear_form.evaluate(x, y)
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_tropical_element_operations() {
276 let a = TropicalElement::new(3.0);
277 let b = TropicalElement::new(5.0);
278 let c = TropicalElement::new(2.0);
279
280 assert_eq!(a + b, TropicalElement::new(5.0));
282 assert_eq!(a + c, TropicalElement::new(3.0));
283 assert_eq!(b + c, TropicalElement::new(5.0));
284
285 assert_eq!(a * b, TropicalElement::new(8.0));
287 assert_eq!(a * c, TropicalElement::new(5.0));
288 assert_eq!(b * c, TropicalElement::new(7.0));
289
290 assert_eq!(TropicalElement::<f64>::zero().value(), TropicalElement::NegInfinity);
292 assert_eq!(TropicalElement::<f64>::one().value(), TropicalElement::Element(0.0));
293
294 assert_eq!(a + TropicalElement::<f64>::zero(), a);
296 assert_eq!(TropicalElement::<f64>::zero() + a, a);
297
298 assert_eq!(a * TropicalElement::<f64>::one(), a);
300 assert_eq!(TropicalElement::<f64>::one() * a, a);
301
302 let mut x = a;
304 x += b;
305 assert_eq!(x, TropicalElement::new(5.0));
306
307 let mut y = a;
309 y *= b;
310 assert_eq!(y, TropicalElement::new(8.0));
311 }
312
313 #[test]
314 fn test_bilinear_form_evaluation() {
315 let matrix = [[TropicalElement::new(1.0), TropicalElement::new(2.0)], [
316 TropicalElement::new(2.0),
317 TropicalElement::new(1.0),
318 ]];
319 let bilinear_form = BilinearForm::new(matrix);
320
321 let x = [TropicalElement::new(3.0), TropicalElement::new(4.0)];
323 let y = [TropicalElement::new(5.0), TropicalElement::new(6.0)];
324
325 assert_eq!(bilinear_form.evaluate(&x, &y), TropicalElement::new(11.0));
330
331 let zero = [TropicalElement::<f64>::zero(), TropicalElement::<f64>::zero()];
333 assert_eq!(bilinear_form.evaluate(&zero, &y), TropicalElement::<f64>::zero());
334 assert_eq!(bilinear_form.evaluate(&x, &zero), TropicalElement::<f64>::zero());
335
336 let one = [TropicalElement::<f64>::one(), TropicalElement::<f64>::one()];
338 assert_eq!(bilinear_form.evaluate(&one, &one), TropicalElement::new(2.0));
339 }
340
341 #[test]
342 fn test_tropical_algebra() {
343 let matrix = [[TropicalElement::new(1.0), TropicalElement::new(2.0)], [
344 TropicalElement::new(2.0),
345 TropicalElement::new(1.0),
346 ]];
347 let bilinear_form = BilinearForm::new(matrix);
348 let algebra = TropicalAlgebra::new(bilinear_form);
349
350 let x = [TropicalElement::new(3.0), TropicalElement::new(4.0)];
352 let y = [TropicalElement::new(5.0), TropicalElement::new(6.0)];
353 assert_eq!(algebra.evaluate(&x, &y), TropicalElement::new(11.0));
354
355 let a = [TropicalElement::new(0.0), TropicalElement::new(1.0)];
357 let b = [TropicalElement::new(2.0), TropicalElement::new(3.0)];
358 assert_eq!(algebra.evaluate(&a, &b), TropicalElement::new(5.0));
359 }
360
361 #[test]
362 fn test_tropical_element_ordering() {
363 let a = TropicalElement::new(3.0);
364 let b = TropicalElement::new(5.0);
365 let c = TropicalElement::new(3.0);
366
367 assert!(a < b);
368 assert!(b > a);
369 assert!(a <= c);
370 assert!(a >= c);
371 assert_eq!(a, c);
372 }
373
374 #[test]
375 fn test_tropical_element_zero_one_properties() {
376 let a = TropicalElement::new(3.0);
377 let zero = TropicalElement::<f64>::zero();
378 let one = TropicalElement::<f64>::one();
379
380 assert!(zero.is_zero());
382 dbg!(a);
383 dbg!(zero);
384 assert_eq!(a + zero, a);
385 assert_eq!(zero + a, a);
386 assert_eq!(a * zero, zero);
387 assert_eq!(zero * a, zero);
388
389 assert_eq!(a * one, a);
391 assert_eq!(one * a, a);
392 }
393}