use mathhook_core::core::{Expression, Number};
use mathhook_core::matrices::unified::Matrix;
use mathhook_core::simplify::Simplify;
use num_bigint::BigInt;
fn expr_equals_integer(expr: &Expression, value: i64) -> bool {
let simplified = expr.clone().simplify();
match simplified {
Expression::Number(Number::Integer(i)) => i == value,
Expression::Number(Number::Rational(r)) => {
r.denom() == &BigInt::from(1) && r.numer() == &BigInt::from(value)
}
_ => false,
}
}
#[test]
fn test_electrical_circuit_kirchhoff() {
let a = Matrix::from_arrays([
[6, -4, 0], [-4, 7, -3], [0, -3, 4], ]);
let b = vec![
Expression::integer(10),
Expression::integer(0),
Expression::integer(5),
];
let currents = a.solve(&b).unwrap();
assert_eq!(currents.len(), 3);
let eq1 = Expression::add(vec![
Expression::mul(vec![Expression::integer(6), currents[0].clone()]),
Expression::mul(vec![Expression::integer(-4), currents[1].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq1, 10),
"Circuit equation 1 failed: 6*I1 - 4*I2 should equal 10, got {:?}",
eq1
);
let eq2 = Expression::add(vec![
Expression::mul(vec![Expression::integer(-4), currents[0].clone()]),
Expression::mul(vec![Expression::integer(7), currents[1].clone()]),
Expression::mul(vec![Expression::integer(-3), currents[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq2, 0),
"Circuit equation 2 failed: -4*I1 + 7*I2 - 3*I3 should equal 0, got {:?}",
eq2
);
let eq3 = Expression::add(vec![
Expression::mul(vec![Expression::integer(-3), currents[1].clone()]),
Expression::mul(vec![Expression::integer(4), currents[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq3, 5),
"Circuit equation 3 failed: -3*I2 + 4*I3 should equal 5, got {:?}",
eq3
);
}
#[test]
fn test_network_flow_distribution() {
let a = Matrix::from_arrays([
[1, 1, 1], [1, -2, 0], [0, 1, -1], ]);
let b = vec![
Expression::integer(100),
Expression::integer(0),
Expression::integer(0),
];
let flows = a.solve(&b).unwrap();
assert_eq!(flows.len(), 3);
let total =
Expression::add(vec![flows[0].clone(), flows[1].clone(), flows[2].clone()]).simplify();
assert!(
expr_equals_integer(&total, 100),
"Total flow should be 100, got {:?}",
total
);
assert!(
expr_equals_integer(&flows[0].clone().simplify(), 50),
"x should be 50, got {:?}",
flows[0].clone().simplify()
);
assert!(
expr_equals_integer(&flows[1].clone().simplify(), 25),
"y should be 25, got {:?}",
flows[1].clone().simplify()
);
assert!(
expr_equals_integer(&flows[2].clone().simplify(), 25),
"z should be 25, got {:?}",
flows[2].clone().simplify()
);
}
#[test]
fn test_chemical_equation_balancing() {
let a = Matrix::from_arrays([
[0, 1, 0], [0, 0, 1], [2, -2, -1], ]);
let b = vec![
Expression::integer(3), Expression::integer(4), Expression::integer(0), ];
let coeffs = a.solve(&b).unwrap();
assert!(
expr_equals_integer(&coeffs[0].clone().simplify(), 5),
"O2 coefficient should be 5, got {:?}",
coeffs[0].clone().simplify()
);
assert!(
expr_equals_integer(&coeffs[1].clone().simplify(), 3),
"CO2 coefficient should be 3, got {:?}",
coeffs[1].clone().simplify()
);
assert!(
expr_equals_integer(&coeffs[2].clone().simplify(), 4),
"H2O coefficient should be 4, got {:?}",
coeffs[2].clone().simplify()
);
}
#[test]
fn test_structural_truss_equilibrium() {
let a = Matrix::from_arrays([
[1, 0, -1], [1, 0, 1], [0, 1, 0], ]);
let b = vec![
Expression::integer(0),
Expression::integer(2),
Expression::integer(0),
];
let forces = a.solve(&b).unwrap();
assert!(
expr_equals_integer(&forces[0].clone().simplify(), 1),
"F1 should be 1, got {:?}",
forces[0].clone().simplify()
);
assert!(
expr_equals_integer(&forces[1].clone().simplify(), 0),
"F2 should be 0, got {:?}",
forces[1].clone().simplify()
);
assert!(
expr_equals_integer(&forces[2].clone().simplify(), 1),
"F3 should be 1, got {:?}",
forces[2].clone().simplify()
);
}
#[test]
fn test_leontief_economic_model() {
let a = Matrix::from_arrays([
[9, -2, -1], [-3, 8, -2], [-1, -3, 7], ]);
let b = vec![
Expression::integer(100), Expression::integer(150), Expression::integer(200), ];
let production = a.solve(&b).unwrap();
assert_eq!(production.len(), 3);
let eq1 = Expression::add(vec![
Expression::mul(vec![Expression::integer(9), production[0].clone()]),
Expression::mul(vec![Expression::integer(-2), production[1].clone()]),
Expression::mul(vec![Expression::integer(-1), production[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq1, 100),
"Leontief eq1 failed: got {:?}, expected 100",
eq1
);
let eq2 = Expression::add(vec![
Expression::mul(vec![Expression::integer(-3), production[0].clone()]),
Expression::mul(vec![Expression::integer(8), production[1].clone()]),
Expression::mul(vec![Expression::integer(-2), production[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq2, 150),
"Leontief eq2 failed: got {:?}, expected 150",
eq2
);
let eq3 = Expression::add(vec![
Expression::mul(vec![Expression::integer(-1), production[0].clone()]),
Expression::mul(vec![Expression::integer(-3), production[1].clone()]),
Expression::mul(vec![Expression::integer(7), production[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&eq3, 200),
"Leontief eq3 failed: got {:?}, expected 200",
eq3
);
}
#[test]
fn test_mixture_blending_problem() {
let a = Matrix::from_arrays([
[1, 1, 1], [10, 25, 50], [2, 4, 7], ]);
let b = vec![
Expression::integer(100), Expression::integer(3000), Expression::integer(450), ];
let volumes = a.solve(&b).unwrap();
assert_eq!(volumes.len(), 3);
let total_vol = Expression::add(vec![
volumes[0].clone(),
volumes[1].clone(),
volumes[2].clone(),
])
.simplify();
assert!(
expr_equals_integer(&total_vol, 100),
"Total volume should be 100, got {:?}",
total_vol
);
let total_chem = Expression::add(vec![
Expression::mul(vec![Expression::integer(10), volumes[0].clone()]),
Expression::mul(vec![Expression::integer(25), volumes[1].clone()]),
Expression::mul(vec![Expression::integer(50), volumes[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&total_chem, 3000),
"Total chemical (scaled) should be 3000, got {:?}",
total_chem
);
let total_cost = Expression::add(vec![
Expression::mul(vec![Expression::integer(2), volumes[0].clone()]),
Expression::mul(vec![Expression::integer(4), volumes[1].clone()]),
Expression::mul(vec![Expression::integer(7), volumes[2].clone()]),
])
.simplify();
assert!(
expr_equals_integer(&total_cost, 450),
"Total cost should be $450, got {:?}",
total_cost
);
}
#[test]
fn test_heat_transfer_steady_state() {
let a = Matrix::from_arrays([
[2, -1, 0, 0], [-1, 2, -1, 0], [0, -1, 2, -1], [0, 0, -1, 2], ]);
let b = vec![
Expression::integer(100), Expression::integer(0),
Expression::integer(0),
Expression::integer(0), ];
let temps = a.solve(&b).unwrap();
assert_eq!(temps.len(), 4);
assert!(
expr_equals_integer(&temps[0].clone().simplify(), 80),
"T1 should be 80°C, got {:?}",
temps[0].clone().simplify()
);
assert!(
expr_equals_integer(&temps[1].clone().simplify(), 60),
"T2 should be 60°C, got {:?}",
temps[1].clone().simplify()
);
assert!(
expr_equals_integer(&temps[2].clone().simplify(), 40),
"T3 should be 40°C, got {:?}",
temps[2].clone().simplify()
);
assert!(
expr_equals_integer(&temps[3].clone().simplify(), 20),
"T4 should be 20°C, got {:?}",
temps[3].clone().simplify()
);
}