use super::common;
use symplex::prelude::*;
#[test]
fn solve_x_gt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let result = x.solve_gt(&x);
let s = format!("{result}");
assert!(!s.contains("EmptySet"), "x > 0 should not be empty: {s}");
assert!(
s.contains("oo") || s.contains("∞") || s.contains("Interval"),
"x > 0 should contain an interval to infinity: {s}"
);
common::assert_positive_at(&x, &x, 3, "x > 0 interior at x=3");
common::assert_negative_at(&x, &x, -1, "x > 0 exterior at x=-1");
}
#[test]
fn solve_x2_minus_4_gt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 4;
let result = poly.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-4 > 0 should have solutions: {s}"
);
assert!(s.contains("2"), "solution should reference 2: {s}");
common::assert_positive_at(&poly, &x, 3, "x²-4 > 0 interior at x=3");
common::assert_positive_at(&poly, &x, -3, "x²-4 > 0 interior at x=-3");
common::assert_negative_at(&poly, &x, 0, "x²-4 > 0 exterior at x=0");
}
#[test]
fn solve_positive_constant_gt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let five = ctx.int(5);
let result = five.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"5 > 0 should be satisfied everywhere: {s}"
);
common::assert_positive_at(&five, &x, 0, "5 > 0 constant check");
}
#[test]
fn solve_negative_constant_gt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let neg = ctx.int(-3);
let result = neg.solve_gt(&x);
assert_eq!(format!("{result}"), "EmptySet");
common::assert_negative_at(&neg, &x, 0, "-3 > 0 constant check");
}
#[test]
fn solve_zero_gt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let zero = ctx.int(0);
let result = zero.solve_gt(&x);
assert_eq!(format!("{result}"), "EmptySet");
}
#[test]
fn solve_zero_ge() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let zero = ctx.int(0);
let result = zero.solve_ge(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"0 >= 0 should be satisfied everywhere: {s}"
);
}
#[test]
fn solve_x2_minus_4_ge_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 4;
let result = poly.solve_ge(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-4 >= 0 should have solutions: {s}"
);
common::assert_positive_at(&poly, &x, 5, "x²-4 >= 0 interior at x=5");
common::assert_negative_at(&poly, &x, 1, "x²-4 >= 0 exterior at x=1");
}
#[test]
fn solve_positive_constant_ge() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let seven = ctx.int(7);
let result = seven.solve_ge(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"7 >= 0 should be true everywhere: {s}"
);
common::assert_positive_at(&seven, &x, 0, "7 >= 0 constant check");
}
#[test]
fn solve_x_lt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let result = x.solve_lt(&x);
let s = format!("{result}");
assert!(!s.contains("EmptySet"), "x < 0 should not be empty: {s}");
common::assert_negative_at(&x, &x, -2, "x < 0 interior at x=-2");
common::assert_positive_at(&x, &x, 1, "x < 0 exterior at x=1");
}
#[test]
fn solve_x2_minus_4_lt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 4;
let result = poly.solve_lt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-4 < 0 should have solutions: {s}"
);
assert!(s.contains("2"), "solution should reference 2: {s}");
common::assert_negative_at(&poly, &x, 0, "x²-4 < 0 interior at x=0");
common::assert_negative_at(&poly, &x, 1, "x²-4 < 0 interior at x=1");
common::assert_positive_at(&poly, &x, 3, "x²-4 < 0 exterior at x=3");
}
#[test]
fn solve_negative_constant_lt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let neg = ctx.int(-5);
let result = neg.solve_lt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"-5 < 0 should be true everywhere: {s}"
);
common::assert_negative_at(&neg, &x, 0, "-5 < 0 constant check");
}
#[test]
fn solve_positive_constant_lt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let pos = ctx.int(3);
let result = pos.solve_lt(&x);
assert_eq!(format!("{result}"), "EmptySet");
common::assert_positive_at(&pos, &x, 0, "3 < 0 constant is positive");
}
#[test]
fn solve_x2_minus_4_le_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 4;
let result = poly.solve_le(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-4 ≤ 0 should have solutions: {s}"
);
common::assert_negative_at(&poly, &x, 0, "x²-4 ≤ 0 interior at x=0");
common::assert_positive_at(&poly, &x, 5, "x²-4 ≤ 0 exterior at x=5");
}
#[test]
fn solve_zero_le() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let zero = ctx.int(0);
let result = zero.solve_le(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"0 <= 0 should be satisfied everywhere: {s}"
);
}
#[test]
fn solve_negative_constant_le() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let neg = ctx.int(-2);
let result = neg.solve_le(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"-2 <= 0 should be true everywhere: {s}"
);
common::assert_negative_at(&neg, &x, 0, "-2 <= 0 constant check");
}
#[test]
fn solveset_quadratic() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - &x * 5 + 6;
let result = poly.solve_as_set(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"solveset of x²-5x+6 should find roots: {s}"
);
assert!(s.contains("2"), "should contain root 2: {s}");
assert!(s.contains("3"), "should contain root 3: {s}");
let val_at_2 = poly
.subs(&x, &ctx.int(2))
.eval_f64()
.expect("eval at root 2 should succeed");
assert!(
val_at_2.abs() < 1e-10,
"poly(2) should be 0, got {val_at_2}"
);
let val_at_3 = poly
.subs(&x, &ctx.int(3))
.eval_f64()
.expect("eval at root 3 should succeed");
assert!(
val_at_3.abs() < 1e-10,
"poly(3) should be 0, got {val_at_3}"
);
}
#[test]
fn solveset_linear() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let expr = &x - 7;
let result = expr.solve_as_set(&x);
let s = format!("{result}");
assert!(s.contains("7"), "should contain root 7: {s}");
let val_at_7 = expr
.subs(&x, &ctx.int(7))
.eval_f64()
.expect("eval at root 7 should succeed");
assert!(
val_at_7.abs() < 1e-10,
"expr(7) should be 0, got {val_at_7}"
);
}
#[test]
fn solveset_no_real_roots() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let expr = &x.powi(2) + 1;
let result = expr.solve_as_set(&x);
let s = format!("{result}");
assert!(!s.is_empty(), "solveset should produce output: {s}");
common::assert_positive_at(&expr, &x, 0, "x²+1 at x=0");
common::assert_positive_at(&expr, &x, 5, "x²+1 at x=5");
common::assert_positive_at(&expr, &x, -3, "x²+1 at x=-3");
}
#[test]
fn solveset_constant_nonzero() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let five = ctx.int(5);
let result = five.solve_as_set(&x);
assert_eq!(format!("{result}"), "EmptySet");
}
#[test]
fn quadratic_positive_leading_coeff_gt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 1;
let result = poly.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-1 > 0 should have solutions: {s}"
);
common::assert_positive_at(&poly, &x, 2, "x²-1 > 0 interior at x=2");
common::assert_positive_at(&poly, &x, -2, "x²-1 > 0 interior at x=-2");
common::assert_negative_at(&poly, &x, 0, "x²-1 > 0 exterior at x=0");
}
#[test]
fn quadratic_positive_leading_coeff_lt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 1;
let result = poly.solve_lt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-1 < 0 should have solutions: {s}"
);
assert!(s.contains("1"), "solution should reference 1: {s}");
common::assert_negative_at(&poly, &x, 0, "x²-1 < 0 interior at x=0");
common::assert_positive_at(&poly, &x, 3, "x²-1 < 0 exterior at x=3");
}
#[test]
fn linear_2x_minus_6_gt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let expr = &x * 2 - 6;
let result = expr.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"2x-6 > 0 should have solutions: {s}"
);
assert!(s.contains("3"), "solution should reference 3: {s}");
common::assert_positive_at(&expr, &x, 5, "2x-6 > 0 interior at x=5");
common::assert_negative_at(&expr, &x, 1, "2x-6 > 0 exterior at x=1");
}
#[test]
fn linear_neg_x_plus_5_le_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let expr = -&x + 5;
let result = expr.solve_le(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"-x+5 ≤ 0 should have solutions: {s}"
);
assert!(s.contains("5"), "solution should reference 5: {s}");
common::assert_negative_at(&expr, &x, 10, "-x+5 ≤ 0 interior at x=10");
common::assert_positive_at(&expr, &x, 2, "-x+5 ≤ 0 exterior at x=2");
}
#[test]
fn cubic_x3_minus_x_gt_0() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(3) - &x;
let result = poly.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x³-x > 0 should have solutions: {s}"
);
common::assert_positive_at(&poly, &x, 2, "x³-x > 0 interior at x=2");
common::assert_negative_at(&poly, &x, -2, "x³-x > 0 exterior at x=-2");
}
#[test]
fn large_positive_constant_gt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let big = ctx.int(999999);
let result = big.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"999999 > 0 should be true everywhere: {s}"
);
common::assert_positive_at(&big, &x, 0, "999999 > 0 constant check");
}
#[test]
fn large_negative_constant_lt() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let big_neg = ctx.int(-999999);
let result = big_neg.solve_lt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"-999999 < 0 should be true everywhere: {s}"
);
common::assert_negative_at(&big_neg, &x, 0, "-999999 < 0 constant check");
}
#[test]
fn solveset_with_context() {
let ctx = Context::new();
let x = ctx.symbol("x");
let poly = &x.powi(2) - &x * 5 + 6;
let result = poly.solve_as_set(&x);
let s = format!("{result}");
assert!(s.contains("2"), "should contain 2: {s}");
assert!(s.contains("3"), "should contain 3: {s}");
}
#[test]
fn solve_gt_with_context() {
let ctx = Context::new();
let x = ctx.symbol("x");
let five = ctx.int(5);
let result = five.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"5 > 0 via context should be true: {s}"
);
}
#[test]
fn solveset_with_rational_roots() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let expr = &x * 2 - 1;
let result = expr.solve_as_set(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"2x - 1 = 0 should have a solution: {s}"
);
}
#[test]
fn solve_always_positive() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) + 1;
let result = poly.solve_gt(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²+1 > 0 should be always true, got: {s}"
);
assert!(
s.contains("UniversalSet") || (s.contains("-oo") && s.contains("oo")),
"x²+1 > 0 should be the entire real line, got: {s}"
);
common::assert_positive_at(&poly, &x, 0, "x²+1 at x=0");
common::assert_positive_at(&poly, &x, 100, "x²+1 at x=100");
common::assert_positive_at(&poly, &x, -100, "x²+1 at x=-100");
}
#[test]
fn solve_always_negative() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = -&(&x.powi(2) + 1);
let result = poly.solve_gt(&x);
let s = format!("{result}");
assert_eq!(s, "EmptySet", "-(x²+1) > 0 should be EmptySet, got: {s}");
common::assert_negative_at(&poly, &x, 0, "-(x²+1) at x=0");
common::assert_negative_at(&poly, &x, 5, "-(x²+1) at x=5");
common::assert_negative_at(&poly, &x, -5, "-(x²+1) at x=-5");
}
#[test]
fn solve_ge_includes_boundary() {
let ctx = Context::new();
symplex::syms!(ctx; x);
let poly = &x.powi(2) - 4;
let result = poly.solve_ge(&x);
let s = format!("{result}");
assert!(
!s.contains("EmptySet"),
"x²-4 >= 0 should have solutions: {s}"
);
let val_at_2 = poly
.subs(&x, &ctx.int(2))
.eval_f64()
.expect("eval at boundary x=2 should succeed");
assert!(
val_at_2.abs() < 1e-10,
"x²-4 at x=2 should be 0, got {val_at_2}"
);
let val_at_neg2 = poly
.subs(&x, &ctx.int(-2))
.eval_f64()
.expect("eval at boundary x=-2 should succeed");
assert!(
val_at_neg2.abs() < 1e-10,
"x²-4 at x=-2 should be 0, got {val_at_neg2}"
);
common::assert_positive_at(&poly, &x, 3, "x²-4 >= 0 interior at x=3");
common::assert_negative_at(&poly, &x, 0, "x²-4 >= 0 exterior at x=0");
}