use symplex::prelude::*;
fn unique(sol: LinearSolution) -> Vec<Ex> {
match sol {
LinearSolution::Unique(pairs) => pairs.into_iter().map(|(_, v)| v).collect(),
other => panic!("expected a unique solution, got {other:?}"),
}
}
fn check_vanishes(eqs: &[Ex], vars: &[Ex], values: &[Ex]) {
for eq in eqs {
let mut e = eq.clone();
for (v, val) in vars.iter().zip(values) {
e = e.subs(v, val);
}
assert_eq!(format!("{}", e.eval()), "0", "residual of {eq}");
}
}
#[test]
fn solve_system_2x2() {
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let eqs = [&x + &y - 3, &x - &y - 1];
let vars = [x, y];
let vals = unique(ctx.solve_system(&eqs, &vars).unwrap());
assert_eq!(vals.len(), 2);
assert_eq!(format!("{}", vals[0]), "2");
assert_eq!(format!("{}", vals[1]), "1");
check_vanishes(&eqs, &vars, &vals);
}
#[test]
fn solve_system_with_coefficients() {
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let eqs = [&x * 2 + &y * 3 - 7, &x - &y - 1];
let vars = [x, y];
let vals = unique(ctx.solve_system(&eqs, &vars).unwrap());
assert_eq!(format!("{}", vals[0]), "2");
assert_eq!(format!("{}", vals[1]), "1");
check_vanishes(&eqs, &vars, &vals);
}
#[test]
fn solve_system_single_equation() {
let ctx = Context::new();
let x = ctx.symbol("x");
let vals = unique(ctx.solve_system(&[&x * 2 - 6], &[x]).unwrap());
assert_eq!(format!("{}", vals[0]), "3");
}
#[test]
fn solve_system_inconsistent() {
let ctx = Context::new();
let x = ctx.symbol("x");
let sol = ctx.solve_system(&[&x - 1, &x - 2], &[x]).unwrap();
assert!(
matches!(sol, LinearSolution::Inconsistent),
"expected Inconsistent, got {sol:?}"
);
}
#[test]
fn solve_system_rational_solution() {
let ctx = Context::new();
let x = ctx.symbol("x");
let vals = unique(ctx.solve_system(&[&x * 3 - 1], &[x]).unwrap());
assert_eq!(format!("{}", vals[0]), "1/3");
}
#[test]
fn solve_system_3x3() {
let ctx = Context::new();
let (x, y, z) = (ctx.symbol("x"), ctx.symbol("y"), ctx.symbol("z"));
let eqs = [&x + &y + &z - 6, &x - &y + &z - 2, &x + &y - &z];
let vars = [x, y, z];
let vals = unique(ctx.solve_system(&eqs, &vars).unwrap());
assert_eq!(format!("{}", vals[0]), "1");
assert_eq!(format!("{}", vals[1]), "2");
assert_eq!(format!("{}", vals[2]), "3");
check_vanishes(&eqs, &vars, &vals);
}
#[test]
fn solve_system_accepts_equations() {
let ctx = Context::new();
let (x, y) = (ctx.symbol("x"), ctx.symbol("y"));
let eqs = [
Equation::new(&x + &y, ctx.int(3)),
Equation::new(&x - &y, ctx.int(1)),
];
let vals = unique(ctx.solve_system(&eqs, &[x, y]).unwrap());
assert_eq!(format!("{}", vals[0]), "2");
assert_eq!(format!("{}", vals[1]), "1");
}
#[test]
fn solve_system_symbolic_coefficients() {
let ctx = Context::new();
let (x, y, a) = (ctx.symbol("x"), ctx.symbol("y"), ctx.symbol("a"));
let eqs = [&a * &x + &y - 1, &x - &y];
let vars = [x.clone(), y.clone()];
let vals = unique(ctx.solve_system(&eqs, &vars).unwrap());
for eq in &eqs {
let r = eq.subs(&x, &vals[0]).subs(&y, &vals[1]).simplify();
assert_eq!(format!("{r}"), "0", "residual of {eq}: {r}");
}
let at3 = vals[0].subs(&a, &ctx.int(3)).eval();
assert_eq!(format!("{at3}"), "1/4");
}