use super::*;
use ndarray::array;
fn quadratic_cost(_: &mut (), rho: &Array1<f64>) -> Result<f64, EstimationError> {
Ok(0.5 * rho.dot(rho))
}
fn quadratic_eval(_: &mut (), rho: &Array1<f64>) -> Result<OuterEval, EstimationError> {
Ok(OuterEval {
cost: 0.5 * rho.dot(rho),
gradient: rho.clone(),
hessian: HessianValue::Dense(array![[1.0]]),
inner_beta_hint: None,
})
}
fn quadratic_problem(bounds: Option<(Array1<f64>, Array1<f64>)>) -> OuterProblem {
let problem = OuterProblem::new(1)
.with_gradient(Derivative::Analytic)
.with_hessian(DeclaredHessianForm::Either)
.with_initial_rho(array![0.0])
.with_problem_size(8, 3);
match bounds {
Some((lower, upper)) => problem.with_bounds(lower, upper),
None => problem,
}
}
macro_rules! quadratic_objective {
($problem:expr) => {
$problem.build_objective(
(),
quadratic_cost,
quadratic_eval,
None::<fn(&mut ())>,
None::<fn(&mut (), &Array1<f64>) -> Result<EfsEval, EstimationError>>,
)
};
}
#[test]
fn the_inverted_box_refusal_carries_both_bound_values_2370() {
let problem = quadratic_problem(Some((array![-10.0], array![-11.855_421_656_441_532])));
let config = problem.config();
let mut objective = quadratic_objective!(problem);
let error = run_outer(&mut objective, &config, "inverted-box-2370")
.expect_err("an inverted rho box must be refused, not clamped");
let message = error.to_string();
assert!(
message.contains("-10") && message.contains("-11.855"),
"the refusal must carry BOTH offending bound values, got: {message}"
);
}
#[test]
fn a_non_finite_bound_is_a_typed_error_2370() {
let problem = quadratic_problem(Some((array![-10.0], array![f64::NAN])));
let config = problem.config();
let mut objective = quadratic_objective!(problem);
let error = run_outer(&mut objective, &config, "nonfinite-box-2370")
.expect_err("a non-finite rho bound must be refused");
assert!(
matches!(error, EstimationError::InvalidInput(_)),
"a non-finite rho bound must be EstimationError::InvalidInput, got: {error:?}"
);
}
#[test]
fn an_ordered_box_still_solves_2370() {
let problem = quadratic_problem(Some((array![-10.0], array![12.0])));
let config = problem.config();
let mut objective = quadratic_objective!(problem);
let result = run_outer(&mut objective, &config, "ordered-box-2370")
.expect("an ordered rho box must solve normally");
assert!(
result.rho[0].abs() < 1e-3,
"the ordered-box solve must reach the interior optimum at rho=0, got {}",
result.rho[0],
);
}
#[test]
fn a_problem_with_no_explicit_box_still_solves_2370() {
let problem = quadratic_problem(None);
let config = problem.config();
let mut objective = quadratic_objective!(problem);
run_outer(&mut objective, &config, "default-box-2370")
.expect("the default rho box must solve normally");
}