use super::projected_gradient_norm;
use ndarray::array;
const EPS: f64 = 1e-12;
#[test]
fn no_bounds_is_plain_euclidean_norm() {
let x = array![0.0, 0.0, 0.0];
let g = array![3.0, -4.0, 0.0];
let n = projected_gradient_norm(&x, &g, None);
assert!((n - 5.0).abs() < EPS, "expected ‖g‖₂ = 5, got {n}");
}
#[test]
fn interior_point_keeps_full_gradient() {
let lower = array![-10.0, -10.0];
let upper = array![10.0, 10.0];
let x = array![0.0, 0.0];
let g = array![3.0, 4.0];
let n = projected_gradient_norm(&x, &g, Some(&(lower, upper)));
assert!((n - 5.0).abs() < EPS, "interior must keep ‖g‖, got {n}");
}
#[test]
fn lower_bound_drops_infeasible_multiplier_keeps_feasible_descent() {
let lower = array![0.0, 0.0];
let upper = array![10.0, 10.0];
let x = array![0.0, 0.0];
let g_multiplier = array![1.0, 2.0];
let n0 = projected_gradient_norm(&x, &g_multiplier, Some(&(lower.clone(), upper.clone())));
assert!(
n0 < EPS,
"g>0 at lower bound is an infeasible multiplier and must project to 0; got {n0}"
);
let g_descent = array![-3.0, -4.0];
let n1 = projected_gradient_norm(&x, &g_descent, Some(&(lower, upper)));
assert!(
(n1 - 5.0).abs() < EPS,
"g<0 at lower bound is feasible descent and must be retained (‖g‖=5); got {n1}"
);
}
#[test]
fn upper_bound_drops_infeasible_multiplier_keeps_feasible_descent() {
let lower = array![-10.0, -10.0];
let upper = array![0.0, 0.0];
let x = array![0.0, 0.0];
let g_multiplier = array![-1.0, -2.0];
let n0 = projected_gradient_norm(&x, &g_multiplier, Some(&(lower.clone(), upper.clone())));
assert!(
n0 < EPS,
"g<0 at upper bound is an infeasible multiplier and must project to 0; got {n0}"
);
let g_descent = array![3.0, 4.0];
let n1 = projected_gradient_norm(&x, &g_descent, Some(&(lower, upper)));
assert!(
(n1 - 5.0).abs() < EPS,
"g>0 at upper bound is feasible descent and must be retained (‖g‖=5); got {n1}"
);
}
#[test]
fn mixed_active_set_matches_kkt_residual() {
let lower = array![0.0, 0.0, -10.0, -10.0];
let upper = array![10.0, 10.0, 10.0, 0.0];
let x = array![0.0, 0.0, 5.0, 0.0];
let g = array![-3.0, 7.0, 4.0, 12.0];
let n = projected_gradient_norm(&x, &g, Some(&(lower, upper)));
assert!(
(n - 13.0).abs() < EPS,
"mixed active set KKT residual should be 13, got {n}"
);
}