#[cfg(test)]
use crate::determinant::determinant;
#[cfg(test)]
use crate::dual::MaxPlus;
#[cfg(test)]
use crate::eigenvalue::eigenvalue;
#[cfg(test)]
use crate::element::Tropical;
#[cfg(test)]
use crate::encoding::{decode_element, decode_matrix, encode_element, encode_matrix};
#[cfg(test)]
use crate::kleene::kleene_star;
#[cfg(test)]
use crate::matrix::TropMatrix;
#[test]
fn element_add_basic() {
let a = Tropical::from_u64(3);
let b = Tropical::from_u64(7);
assert_eq!(a.add(b), Tropical::from_u64(3));
}
#[test]
fn element_add_equal() {
let a = Tropical::from_u64(5);
assert_eq!(a.add(a), Tropical::from_u64(5));
}
#[test]
fn element_add_identity_left() {
let a = Tropical::from_u64(42);
assert_eq!(Tropical::INF.add(a), a);
}
#[test]
fn element_add_identity_right() {
let a = Tropical::from_u64(42);
assert_eq!(a.add(Tropical::INF), a);
}
#[test]
fn element_add_both_inf() {
assert_eq!(Tropical::INF.add(Tropical::INF), Tropical::INF);
}
#[test]
fn element_add_commutativity() {
let a = Tropical::from_u64(10);
let b = Tropical::from_u64(20);
assert_eq!(a.add(b), b.add(a));
}
#[test]
fn element_add_associativity() {
let a = Tropical::from_u64(5);
let b = Tropical::from_u64(3);
let c = Tropical::from_u64(8);
assert_eq!(a.add(b).add(c), a.add(b.add(c)));
}
#[test]
fn element_mul_basic() {
let a = Tropical::from_u64(3);
let b = Tropical::from_u64(7);
assert_eq!(a.mul(b), Tropical::from_u64(10));
}
#[test]
fn element_mul_identity_left() {
let a = Tropical::from_u64(42);
assert_eq!(Tropical::ONE.mul(a), a);
}
#[test]
fn element_mul_identity_right() {
let a = Tropical::from_u64(42);
assert_eq!(a.mul(Tropical::ONE), a);
}
#[test]
fn element_mul_zero_left() {
let a = Tropical::from_u64(42);
assert_eq!(Tropical::INF.mul(a), Tropical::INF);
}
#[test]
fn element_mul_zero_right() {
let a = Tropical::from_u64(42);
assert_eq!(a.mul(Tropical::INF), Tropical::INF);
}
#[test]
fn element_mul_commutativity() {
let a = Tropical::from_u64(10);
let b = Tropical::from_u64(20);
assert_eq!(a.mul(b), b.mul(a));
}
#[test]
fn element_mul_associativity() {
let a = Tropical::from_u64(5);
let b = Tropical::from_u64(3);
let c = Tropical::from_u64(8);
assert_eq!(a.mul(b).mul(c), a.mul(b.mul(c)));
}
#[test]
fn element_mul_overflow() {
let a = Tropical::from_u64(u64::MAX - 1);
let b = Tropical::from_u64(2);
assert_eq!(a.mul(b), Tropical::INF);
}
#[test]
fn element_mul_near_max() {
let a = Tropical::from_u64(u64::MAX - 2);
let b = Tropical::from_u64(1);
assert_eq!(a.mul(b), Tropical::from_u64(u64::MAX - 1));
}
#[test]
fn element_mul_sum_equals_max() {
let a = Tropical::from_u64(u64::MAX - 1);
let b = Tropical::from_u64(1);
assert_eq!(a.mul(b), Tropical::INF);
}
#[test]
fn element_distributivity() {
let a = Tropical::from_u64(2);
let b = Tropical::from_u64(3);
let c = Tropical::from_u64(5);
assert_eq!(a.mul(b.add(c)), a.mul(b).add(a.mul(c)));
}
#[test]
fn element_distributivity_with_inf() {
let a = Tropical::from_u64(10);
let b = Tropical::INF;
let c = Tropical::from_u64(5);
assert_eq!(a.mul(b.add(c)), a.mul(b).add(a.mul(c)));
}
#[test]
fn element_is_inf() {
assert!(Tropical::INF.is_inf());
assert!(Tropical::ZERO.is_inf());
assert!(!Tropical::ONE.is_inf());
assert!(!Tropical::from_u64(42).is_inf());
}
#[test]
fn element_is_finite() {
assert!(!Tropical::INF.is_finite());
assert!(Tropical::ONE.is_finite());
assert!(Tropical::from_u64(0).is_finite());
}
#[test]
fn element_zero_is_inf() {
assert_eq!(Tropical::ZERO, Tropical::INF);
}
#[test]
fn element_one_is_zero() {
assert_eq!(Tropical::ONE.as_u64(), 0);
}
#[test]
fn element_constants() {
assert_eq!(Tropical::ZERO.as_u64(), u64::MAX);
assert_eq!(Tropical::ONE.as_u64(), 0);
assert_eq!(Tropical::INF.as_u64(), u64::MAX);
}
#[test]
fn matrix_new_all_inf() {
let m = TropMatrix::new(3);
for i in 0..3 {
for j in 0..3 {
assert_eq!(m.get(i, j), Tropical::INF);
}
}
}
#[test]
fn matrix_identity_diagonal() {
let m = TropMatrix::identity(3);
for i in 0..3 {
assert_eq!(m.get(i, i), Tropical::ONE);
}
}
#[test]
fn matrix_identity_off_diagonal() {
let m = TropMatrix::identity(3);
assert_eq!(m.get(0, 1), Tropical::INF);
assert_eq!(m.get(1, 0), Tropical::INF);
assert_eq!(m.get(0, 2), Tropical::INF);
}
#[test]
fn matrix_set_get() {
let mut m = TropMatrix::new(2);
m.set(0, 1, Tropical::from_u64(5));
assert_eq!(m.get(0, 1), Tropical::from_u64(5));
assert_eq!(m.get(0, 0), Tropical::INF);
}
#[test]
fn matrix_add_elementwise_min() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(3));
a.set(0, 1, Tropical::from_u64(7));
let mut b = TropMatrix::new(2);
b.set(0, 0, Tropical::from_u64(5));
b.set(0, 1, Tropical::from_u64(2));
let c = a.add(&b);
assert_eq!(c.get(0, 0), Tropical::from_u64(3));
assert_eq!(c.get(0, 1), Tropical::from_u64(2));
}
#[test]
fn matrix_mul_identity() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(1));
a.set(0, 1, Tropical::from_u64(3));
a.set(1, 0, Tropical::from_u64(2));
a.set(1, 1, Tropical::from_u64(4));
let id = TropMatrix::identity(2);
let r = a.mul(&id);
assert_eq!(r.get(0, 0), Tropical::from_u64(1));
assert_eq!(r.get(0, 1), Tropical::from_u64(3));
assert_eq!(r.get(1, 0), Tropical::from_u64(2));
assert_eq!(r.get(1, 1), Tropical::from_u64(4));
}
#[test]
fn matrix_mul_2x2() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(1));
a.set(0, 1, Tropical::from_u64(3));
a.set(1, 0, Tropical::from_u64(2));
a.set(1, 1, Tropical::from_u64(4));
let mut b = TropMatrix::new(2);
b.set(0, 0, Tropical::from_u64(0));
b.set(0, 1, Tropical::from_u64(1));
b.set(1, 0, Tropical::from_u64(2));
b.set(1, 1, Tropical::from_u64(0));
let c = a.mul(&b);
assert_eq!(c.get(0, 0), Tropical::from_u64(1));
assert_eq!(c.get(0, 1), Tropical::from_u64(2));
assert_eq!(c.get(1, 0), Tropical::from_u64(2));
assert_eq!(c.get(1, 1), Tropical::from_u64(3));
}
#[test]
fn matrix_mul_with_inf() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(1));
a.set(1, 1, Tropical::from_u64(2));
let mut b = TropMatrix::new(2);
b.set(0, 1, Tropical::from_u64(3));
b.set(1, 0, Tropical::from_u64(4));
let c = a.mul(&b);
assert_eq!(c.get(0, 0), Tropical::INF);
assert_eq!(c.get(0, 1), Tropical::from_u64(4)); assert_eq!(c.get(1, 0), Tropical::from_u64(6)); assert_eq!(c.get(1, 1), Tropical::INF);
}
#[test]
fn matrix_power_zero() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(5));
a.set(0, 1, Tropical::from_u64(3));
let r = a.power(0);
assert_eq!(r.get(0, 0), Tropical::ONE);
assert_eq!(r.get(0, 1), Tropical::INF);
assert_eq!(r.get(1, 1), Tropical::ONE);
}
#[test]
fn matrix_power_one() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(5));
a.set(0, 1, Tropical::from_u64(3));
a.set(1, 0, Tropical::from_u64(2));
a.set(1, 1, Tropical::from_u64(7));
let r = a.power(1);
assert_eq!(r.get(0, 0), Tropical::from_u64(5));
assert_eq!(r.get(0, 1), Tropical::from_u64(3));
}
#[test]
fn matrix_power_two() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(1));
a.set(0, 1, Tropical::from_u64(3));
a.set(1, 0, Tropical::from_u64(2));
a.set(1, 1, Tropical::from_u64(4));
let r = a.power(2);
let expected = a.mul(&a);
for i in 0..2 {
for j in 0..2 {
assert_eq!(r.get(i, j), expected.get(i, j));
}
}
}
#[test]
fn matrix_from_weights() {
let m = TropMatrix::from_weights(3, &[(0, 1, 5), (1, 2, 3), (0, 2, 10)]);
assert_eq!(m.get(0, 1), Tropical::from_u64(5));
assert_eq!(m.get(1, 2), Tropical::from_u64(3));
assert_eq!(m.get(0, 2), Tropical::from_u64(10));
assert_eq!(m.get(0, 0), Tropical::INF);
}
#[test]
fn matrix_from_weights_duplicate_takes_min() {
let m = TropMatrix::from_weights(2, &[(0, 1, 5), (0, 1, 3)]);
assert_eq!(m.get(0, 1), Tropical::from_u64(3));
}
#[test]
fn matrix_add_zero() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(3));
a.set(1, 1, Tropical::from_u64(7));
let zero = TropMatrix::new(2); let r = a.add(&zero);
assert_eq!(r.get(0, 0), Tropical::from_u64(3));
assert_eq!(r.get(1, 1), Tropical::from_u64(7));
}
#[test]
fn kleene_star_single_node() {
let m = TropMatrix::new(1);
let star = kleene_star(&m);
assert_eq!(star.get(0, 0), Tropical::ONE); }
#[test]
fn kleene_star_triangle() {
let m = TropMatrix::from_weights(3, &[(0, 1, 1), (1, 2, 2), (2, 0, 3)]);
let star = kleene_star(&m);
assert_eq!(star.get(0, 0), Tropical::ONE); assert_eq!(star.get(0, 1), Tropical::from_u64(1)); assert_eq!(star.get(0, 2), Tropical::from_u64(3)); assert_eq!(star.get(1, 0), Tropical::from_u64(5)); assert_eq!(star.get(2, 0), Tropical::from_u64(3)); }
#[test]
fn kleene_star_shortest_path_diamond() {
let m = TropMatrix::from_weights(4, &[(0, 1, 1), (0, 2, 2), (1, 3, 1), (2, 3, 1)]);
let star = kleene_star(&m);
assert_eq!(star.get(0, 3), Tropical::from_u64(2));
assert_eq!(star.get(0, 2), Tropical::from_u64(2));
}
#[test]
fn kleene_star_disconnected() {
let m = TropMatrix::from_weights(3, &[(0, 1, 5)]);
let star = kleene_star(&m);
assert_eq!(star.get(0, 1), Tropical::from_u64(5));
assert_eq!(star.get(0, 2), Tropical::INF); assert_eq!(star.get(1, 0), Tropical::INF); }
#[test]
fn kleene_star_complete_graph() {
let m = TropMatrix::from_weights(
3,
&[
(0, 1, 2),
(0, 2, 4),
(1, 0, 3),
(1, 2, 1),
(2, 0, 5),
(2, 1, 6),
],
);
let star = kleene_star(&m);
assert_eq!(star.get(0, 0), Tropical::ONE);
assert_eq!(star.get(0, 1), Tropical::from_u64(2));
assert_eq!(star.get(0, 2), Tropical::from_u64(3)); assert_eq!(star.get(1, 0), Tropical::from_u64(3));
assert_eq!(star.get(2, 1), Tropical::from_u64(6));
}
#[test]
fn kleene_star_identity_idempotent() {
let id = TropMatrix::identity(3);
let star = kleene_star(&id);
for i in 0..3 {
for j in 0..3 {
assert_eq!(star.get(i, j), id.get(i, j));
}
}
}
#[test]
fn eigenvalue_self_loop() {
let m = TropMatrix::from_weights(1, &[(0, 0, 5)]);
assert_eq!(eigenvalue(&m), Tropical::from_u64(5));
}
#[test]
fn eigenvalue_triangle_uniform() {
let m = TropMatrix::from_weights(3, &[(0, 1, 3), (1, 2, 3), (2, 0, 3)]);
assert_eq!(eigenvalue(&m), Tropical::from_u64(3));
}
#[test]
fn eigenvalue_two_node_cycle() {
let m = TropMatrix::from_weights(2, &[(0, 1, 2), (1, 0, 4)]);
assert_eq!(eigenvalue(&m), Tropical::from_u64(3));
}
#[test]
fn eigenvalue_no_cycle() {
let m = TropMatrix::from_weights(3, &[(0, 1, 1), (1, 2, 2)]);
assert_eq!(eigenvalue(&m), Tropical::INF);
}
#[test]
fn eigenvalue_self_loop_zero() {
let m = TropMatrix::from_weights(1, &[(0, 0, 0)]);
assert_eq!(eigenvalue(&m), Tropical::from_u64(0));
}
#[test]
fn eigenvalue_multiple_cycles() {
let m = TropMatrix::from_weights(3, &[(0, 1, 2), (1, 0, 4), (1, 2, 1), (2, 0, 3)]);
assert_eq!(eigenvalue(&m), Tropical::from_u64(2));
}
#[test]
fn determinant_1x1() {
let mut m = TropMatrix::new(1);
m.set(0, 0, Tropical::from_u64(7));
assert_eq!(determinant(&m), Tropical::from_u64(7));
}
#[test]
fn determinant_identity() {
let id = TropMatrix::identity(3);
assert_eq!(determinant(&id), Tropical::from_u64(0));
}
#[test]
fn determinant_2x2() {
let mut m = TropMatrix::new(2);
m.set(0, 0, Tropical::from_u64(1));
m.set(0, 1, Tropical::from_u64(3));
m.set(1, 0, Tropical::from_u64(2));
m.set(1, 1, Tropical::from_u64(4));
assert_eq!(determinant(&m), Tropical::from_u64(5));
}
#[test]
fn determinant_2x2_asymmetric() {
let mut m = TropMatrix::new(2);
m.set(0, 0, Tropical::from_u64(1));
m.set(0, 1, Tropical::from_u64(10));
m.set(1, 0, Tropical::from_u64(2));
m.set(1, 1, Tropical::from_u64(4));
assert_eq!(determinant(&m), Tropical::from_u64(5));
}
#[test]
fn determinant_3x3() {
let mut m = TropMatrix::new(3);
m.set(0, 0, Tropical::from_u64(0));
m.set(0, 1, Tropical::from_u64(1));
m.set(0, 2, Tropical::from_u64(2));
m.set(1, 0, Tropical::from_u64(2));
m.set(1, 1, Tropical::from_u64(0));
m.set(1, 2, Tropical::from_u64(1));
m.set(2, 0, Tropical::from_u64(1));
m.set(2, 1, Tropical::from_u64(2));
m.set(2, 2, Tropical::from_u64(0));
assert_eq!(determinant(&m), Tropical::from_u64(0));
}
#[test]
fn determinant_with_inf() {
let mut m = TropMatrix::new(2);
m.set(0, 0, Tropical::from_u64(0));
m.set(1, 1, Tropical::from_u64(0));
assert_eq!(determinant(&m), Tropical::from_u64(0));
}
#[test]
fn determinant_all_inf() {
let m = TropMatrix::new(2);
assert_eq!(determinant(&m), Tropical::INF);
}
#[test]
fn determinant_empty() {
let m = TropMatrix::new(0);
assert_eq!(determinant(&m), Tropical::ONE);
}
#[test]
fn maxplus_add_basic() {
let a = MaxPlus::from_val(3);
let b = MaxPlus::from_val(7);
assert_eq!(a.add(b), MaxPlus::from_val(7));
}
#[test]
fn maxplus_add_identity() {
let a = MaxPlus::from_val(5);
assert_eq!(MaxPlus::ZERO.add(a), a);
assert_eq!(a.add(MaxPlus::ZERO), a);
}
#[test]
fn maxplus_mul_basic() {
let a = MaxPlus::from_val(3);
let b = MaxPlus::from_val(7);
assert_eq!(a.mul(b).to_val(), Some(10));
}
#[test]
fn maxplus_mul_identity() {
let a = MaxPlus::from_val(5);
assert_eq!(a.mul(MaxPlus::ONE).to_val(), Some(5));
assert_eq!(MaxPlus::ONE.mul(a).to_val(), Some(5));
}
#[test]
fn maxplus_mul_zero() {
let a = MaxPlus::from_val(5);
assert_eq!(a.mul(MaxPlus::ZERO), MaxPlus::ZERO);
assert_eq!(MaxPlus::ZERO.mul(a), MaxPlus::ZERO);
}
#[test]
fn maxplus_is_neg_inf() {
assert!(MaxPlus::ZERO.is_neg_inf());
assert!(MaxPlus::NEG_INF.is_neg_inf());
assert!(!MaxPlus::ONE.is_neg_inf());
}
#[test]
fn maxplus_to_val() {
assert_eq!(MaxPlus::ZERO.to_val(), None);
assert_eq!(MaxPlus::ONE.to_val(), Some(0));
assert_eq!(MaxPlus::from_val(42).to_val(), Some(42));
}
#[test]
fn maxplus_commutativity() {
let a = MaxPlus::from_val(10);
let b = MaxPlus::from_val(20);
assert_eq!(a.add(b), b.add(a));
assert_eq!(a.mul(b), b.mul(a));
}
#[test]
fn maxplus_constants() {
assert_eq!(MaxPlus::ZERO.0, 0);
assert_eq!(MaxPlus::ONE.0, 1);
assert_eq!(MaxPlus::NEG_INF.0, 0);
}
#[test]
fn encoding_element_roundtrip() {
let t = Tropical::from_u64(0x0102030405060708);
let bytes = decode_element(t);
let recovered = encode_element(&bytes);
assert_eq!(recovered, t);
}
#[test]
fn encoding_element_inf() {
let bytes = decode_element(Tropical::INF);
assert_eq!(bytes, [0xFF; 8]);
let recovered = encode_element(&bytes);
assert_eq!(recovered, Tropical::INF);
}
#[test]
fn encoding_element_zero() {
let bytes = decode_element(Tropical::ONE);
assert_eq!(bytes, [0; 8]);
}
#[test]
fn encoding_matrix_roundtrip() {
let mut m = TropMatrix::new(2);
m.set(0, 0, Tropical::from_u64(1));
m.set(0, 1, Tropical::from_u64(2));
m.set(1, 0, Tropical::from_u64(3));
m.set(1, 1, Tropical::from_u64(4));
let mut buf = [0u8; 2 * 2 * 8];
decode_matrix(&m, &mut buf);
let recovered = encode_matrix(2, &buf);
for i in 0..2 {
for j in 0..2 {
assert_eq!(recovered.get(i, j), m.get(i, j));
}
}
}
#[test]
fn encoding_matrix_with_inf() {
let m = TropMatrix::new(2); let mut buf = [0u8; 2 * 2 * 8];
decode_matrix(&m, &mut buf);
for &b in buf.iter() {
assert_eq!(b, 0xFF);
}
}
#[test]
fn integration_shortest_path_4node() {
let m = TropMatrix::from_weights(4, &[(0, 1, 1), (1, 3, 2), (0, 2, 4), (2, 3, 1), (1, 2, 1)]);
let star = kleene_star(&m);
assert_eq!(star.get(0, 3), Tropical::from_u64(3));
}
#[test]
fn integration_power_vs_manual() {
let m = TropMatrix::from_weights(3, &[(0, 1, 2), (1, 2, 3), (2, 0, 1)]);
let cube_power = m.power(3);
let cube_manual = m.mul(&m).mul(&m);
for i in 0..3 {
for j in 0..3 {
assert_eq!(cube_power.get(i, j), cube_manual.get(i, j));
}
}
}
#[test]
fn integration_kleene_star_via_powers() {
let m = TropMatrix::from_weights(3, &[(0, 1, 2), (1, 2, 3)]);
let star = kleene_star(&m);
let id = TropMatrix::identity(3);
let a1 = m.clone();
let a2 = m.mul(&m);
let manual_star = id.add(&a1).add(&a2);
for i in 0..3 {
for j in 0..3 {
assert_eq!(star.get(i, j), manual_star.get(i, j));
}
}
}
#[test]
fn integration_matrix_mul_zero() {
let mut a = TropMatrix::new(2);
a.set(0, 0, Tropical::from_u64(1));
a.set(0, 1, Tropical::from_u64(2));
a.set(1, 0, Tropical::from_u64(3));
a.set(1, 1, Tropical::from_u64(4));
let zero = TropMatrix::new(2);
let r = a.mul(&zero);
for i in 0..2 {
for j in 0..2 {
assert_eq!(r.get(i, j), Tropical::INF);
}
}
}
#[test]
fn integration_determinant_permutation_matrix() {
let mut m = TropMatrix::new(3);
m.set(0, 1, Tropical::from_u64(0));
m.set(1, 2, Tropical::from_u64(0));
m.set(2, 0, Tropical::from_u64(0));
assert_eq!(determinant(&m), Tropical::from_u64(0));
}