use crate::games::piecewise::{add_pl, combine, Pl};
use crate::games::thermography::{walls_with, Thermograph};
use crate::games::Game;
impl Pl {
pub fn oplus_max(&self, other: &Pl) -> Pl {
combine(self, other, true)
}
pub fn oplus_min(&self, other: &Pl) -> Pl {
combine(self, other, false)
}
pub fn otimes(&self, other: &Pl) -> Pl {
add_pl(self, other)
}
}
pub fn thermograph_via_tropical(g: &Game) -> Option<Thermograph> {
let (left_wall, right_wall, mast, temperature) = walls_with(g, |acc, wall, is_max| {
if is_max {
acc.oplus_max(wall)
} else {
acc.oplus_min(wall)
}
})?;
Some(Thermograph {
mast,
temperature,
left_wall,
right_wall,
})
}
#[cfg(test)]
mod tests {
use super::*;
use crate::games::piecewise::req;
use crate::games::thermography::thermograph;
use crate::scalar::Rational;
use crate::scalar::Scalar;
fn same(a: &Thermograph, b: &Thermograph) -> bool {
req(&a.mast, &b.mast)
&& req(&a.temperature, &b.temperature)
&& a.left_wall.points() == b.left_wall.points()
&& a.right_wall.points() == b.right_wall.points()
}
fn star2() -> Game {
Game::new(
vec![Game::integer(0), Game::star()],
vec![Game::integer(0), Game::star()],
)
}
#[test]
fn via_tropical_matches_thermograph() {
let mut games = vec![
Game::integer(-3),
Game::integer(0),
Game::integer(5),
Game::new(vec![Game::integer(0)], vec![Game::integer(1)]),
Game::star(),
Game::up(),
Game::up().neg(),
star2(),
Game::new(vec![Game::integer(3)], vec![Game::switch(1, -1)]),
];
for (a, b) in [(1i128, -1i128), (2, -2), (3, -1), (0, -4), (5, 1)] {
games.push(Game::switch(a, b));
}
games.push(Game::switch(4, -4).add(&Game::switch(2, 0)));
for g in &games {
let golden = thermograph(g);
let named = thermograph_via_tropical(g);
match (&golden, &named) {
(Some(x), Some(y)) => assert!(same(x, y), "mismatch on {}", g.display()),
(None, None) => {}
_ => panic!("Some/None disagreement on {}", g.display()),
}
}
}
#[test]
fn oplus_wrappers_pin_to_combine() {
let th = thermograph(&Game::switch(3, -1)).unwrap();
let (l, r) = (&th.left_wall, &th.right_wall);
assert_eq!(l.oplus_max(r).points(), combine(l, r, true).points());
assert_eq!(l.oplus_min(r).points(), combine(l, r, false).points());
}
#[test]
fn otimes_pins_to_add_pl() {
let th = thermograph(&Game::switch(3, -1)).unwrap();
let (l, r) = (&th.left_wall, &th.right_wall);
assert_eq!(l.otimes(r).points(), add_pl(l, r).points());
}
#[test]
fn dual_semiring_recovers_classic_stops() {
for (a, b) in [(1i128, -1i128), (5, 1), (3, -1)] {
let th = thermograph_via_tropical(&Game::switch(a, b)).unwrap();
assert!(
req(&th.left_stop(), &Rational::from_int(a)),
"LS {{{a}|{b}}}"
);
assert!(
req(&th.right_stop(), &Rational::from_int(b)),
"RS {{{a}|{b}}}"
);
}
}
}