mod algebraic;
mod constant_folding;
mod propagation;
pub(crate) mod substitution;
pub use algebraic::algebraic_simplify;
pub use constant_folding::constant_fold;
pub use propagation::propagate_constants;
use crate::expr::TLExpr;
pub fn optimize_expr(expr: &TLExpr) -> TLExpr {
let mut current = expr.clone();
let mut iterations = 0;
const MAX_ITERATIONS: usize = 10;
loop {
let propagated = propagate_constants(¤t);
let folded = constant_fold(&propagated);
let simplified = algebraic_simplify(&folded);
if simplified == current || iterations >= MAX_ITERATIONS {
return simplified;
}
current = simplified;
iterations += 1;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_constant_fold_addition() {
let expr = TLExpr::add(TLExpr::constant(2.0), TLExpr::constant(3.0));
let folded = constant_fold(&expr);
assert_eq!(folded, TLExpr::Constant(5.0));
}
#[test]
fn test_constant_fold_multiplication() {
let expr = TLExpr::mul(TLExpr::constant(4.0), TLExpr::constant(5.0));
let folded = constant_fold(&expr);
assert_eq!(folded, TLExpr::Constant(20.0));
}
#[test]
fn test_constant_fold_nested() {
let expr = TLExpr::mul(
TLExpr::add(TLExpr::constant(2.0), TLExpr::constant(3.0)),
TLExpr::constant(4.0),
);
let folded = constant_fold(&expr);
assert_eq!(folded, TLExpr::Constant(20.0));
}
#[test]
fn test_algebraic_simplify_add_zero() {
let expr = TLExpr::add(TLExpr::constant(5.0), TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(5.0));
}
#[test]
fn test_algebraic_simplify_mul_one() {
let expr = TLExpr::mul(TLExpr::constant(7.0), TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(7.0));
}
#[test]
fn test_algebraic_simplify_mul_zero() {
let expr = TLExpr::mul(TLExpr::constant(7.0), TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_algebraic_simplify_double_negation() {
let expr = TLExpr::negate(TLExpr::negate(TLExpr::constant(5.0)));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(5.0));
}
#[test]
fn test_optimize_expr_combined() {
let expr = TLExpr::mul(
TLExpr::add(TLExpr::constant(2.0), TLExpr::constant(3.0)),
TLExpr::constant(1.0),
);
let optimized = optimize_expr(&expr);
assert_eq!(optimized, TLExpr::Constant(5.0));
}
#[test]
fn test_propagate_constants_let_binding() {
let expr = TLExpr::let_binding(
"x".to_string(),
TLExpr::constant(5.0),
TLExpr::add(TLExpr::pred("x", vec![]), TLExpr::constant(3.0)),
);
let propagated = propagate_constants(&expr);
let folded = constant_fold(&propagated);
assert_eq!(folded, TLExpr::Constant(8.0));
}
#[test]
fn test_propagate_constants_nested_let() {
let expr = TLExpr::let_binding(
"x".to_string(),
TLExpr::constant(2.0),
TLExpr::let_binding(
"y".to_string(),
TLExpr::add(TLExpr::pred("x", vec![]), TLExpr::constant(1.0)),
TLExpr::mul(TLExpr::pred("y", vec![]), TLExpr::constant(3.0)),
),
);
let optimized = optimize_expr(&expr);
assert_eq!(optimized, TLExpr::Constant(9.0));
}
#[test]
fn test_algebraic_simplify_and_true() {
let expr = TLExpr::and(TLExpr::pred("P", vec![]), TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::pred("P", vec![]));
}
#[test]
fn test_algebraic_simplify_and_false() {
let expr = TLExpr::and(TLExpr::pred("P", vec![]), TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_algebraic_simplify_or_false() {
let expr = TLExpr::or(TLExpr::pred("P", vec![]), TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::pred("P", vec![]));
}
#[test]
fn test_algebraic_simplify_or_true() {
let expr = TLExpr::or(TLExpr::pred("P", vec![]), TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_algebraic_simplify_implies_true_antecedent() {
let expr = TLExpr::imply(TLExpr::constant(1.0), TLExpr::pred("Q", vec![]));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::pred("Q", vec![]));
}
#[test]
fn test_algebraic_simplify_implies_false_antecedent() {
let expr = TLExpr::imply(TLExpr::constant(0.0), TLExpr::pred("Q", vec![]));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_algebraic_simplify_implies_true_consequent() {
let expr = TLExpr::imply(TLExpr::pred("P", vec![]), TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_algebraic_simplify_implies_false_consequent() {
let expr = TLExpr::imply(TLExpr::pred("P", vec![]), TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
matches!(simplified, TLExpr::Not(_));
}
#[test]
fn test_algebraic_simplify_same_comparison() {
let x = TLExpr::pred("x", vec![]);
let expr = TLExpr::eq(x.clone(), x);
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_algebraic_simplify_comparison_lt_same() {
let x = TLExpr::pred("x", vec![]);
let expr = TLExpr::lt(x.clone(), x);
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_algebraic_simplify_comparison_lte_same() {
let x = TLExpr::pred("x", vec![]);
let expr = TLExpr::lte(x.clone(), x);
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_algebraic_simplify_division_same_constant() {
let expr = TLExpr::div(TLExpr::constant(5.0), TLExpr::constant(5.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_modal_simplify_box_true() {
let expr = TLExpr::modal_box(TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_modal_simplify_box_false() {
let expr = TLExpr::modal_box(TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_modal_simplify_diamond_true() {
let expr = TLExpr::modal_diamond(TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_modal_simplify_diamond_false() {
let expr = TLExpr::modal_diamond(TLExpr::constant(0.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_temporal_simplify_next_true() {
let expr = TLExpr::next(TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_temporal_simplify_eventually_true() {
let expr = TLExpr::eventually(TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_temporal_simplify_always_true() {
let expr = TLExpr::always(TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_temporal_simplify_eventually_idempotent() {
let p = TLExpr::pred("P", vec![]);
let expr = TLExpr::eventually(TLExpr::eventually(p.clone()));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::eventually(p));
}
#[test]
fn test_temporal_simplify_always_idempotent() {
let p = TLExpr::pred("P", vec![]);
let expr = TLExpr::always(TLExpr::always(p.clone()));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::always(p));
}
#[test]
fn test_temporal_simplify_until_true() {
let expr = TLExpr::until(TLExpr::pred("P", vec![]), TLExpr::constant(1.0));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
#[test]
fn test_temporal_simplify_until_false_left() {
let p = TLExpr::pred("P", vec![]);
let expr = TLExpr::until(TLExpr::constant(0.0), p.clone());
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::eventually(p));
}
#[test]
fn test_algebraic_simplify_absorption_and_or() {
let a = TLExpr::pred("A", vec![]);
let b = TLExpr::pred("B", vec![]);
let expr = TLExpr::and(a.clone(), TLExpr::or(a.clone(), b));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, a);
}
#[test]
fn test_algebraic_simplify_absorption_or_and() {
let a = TLExpr::pred("A", vec![]);
let b = TLExpr::pred("B", vec![]);
let expr = TLExpr::or(a.clone(), TLExpr::and(a.clone(), b));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, a);
}
#[test]
fn test_algebraic_simplify_idempotence_and() {
let a = TLExpr::pred("A", vec![]);
let expr = TLExpr::and(a.clone(), a.clone());
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, a);
}
#[test]
fn test_algebraic_simplify_idempotence_or() {
let a = TLExpr::pred("A", vec![]);
let expr = TLExpr::or(a.clone(), a.clone());
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, a);
}
#[test]
fn test_algebraic_simplify_complement_and() {
let a = TLExpr::pred("A", vec![]);
let expr = TLExpr::and(a.clone(), TLExpr::negate(a));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(0.0));
}
#[test]
fn test_algebraic_simplify_complement_or() {
let a = TLExpr::pred("A", vec![]);
let expr = TLExpr::or(a.clone(), TLExpr::negate(a));
let simplified = algebraic_simplify(&expr);
assert_eq!(simplified, TLExpr::Constant(1.0));
}
}