use crate::NonlinearInequalityConstraints;
use crate::core::executor::Executor;
use crate::core::problem::CostFunction;
use crate::core::state::CobylaState;
use crate::core::termination::TerminationReason;
use crate::solver::Cobyla;
struct Prob {
f: fn(&[f64]) -> f64,
c: fn(&[f64]) -> Vec<f64>,
m: usize,
}
impl CostFunction for Prob {
type Param = Vec<f64>;
type Output = f64;
type Error = std::convert::Infallible;
fn cost(&self, x: &Vec<f64>) -> Result<f64, std::convert::Infallible> {
Ok((self.f)(x))
}
}
impl NonlinearInequalityConstraints for Prob {
fn constraints(&self, x: &Vec<f64>) -> Result<Vec<f64>, std::convert::Infallible> {
Ok((self.c)(x))
}
fn num_constraints(&self) -> usize {
self.m
}
}
#[test]
fn problem_b_disk_min_product() {
let prob = Prob {
f: |x| x[0] * x[1],
c: |x| vec![x[0] * x[0] + x[1] * x[1] - 1.0],
m: 1,
};
let solver = Cobyla::new().with_rho_beg(0.5).with_rho_end(1e-4);
let state = CobylaState::new(vec![1.0, 1.0]);
let result = Executor::new(prob, solver, state)
.terminate_on(crate::MaxCostEvals(2000))
.run()
.unwrap();
assert!(
(result.best_cost() - (-0.5)).abs() < 1e-3,
"F = {}",
result.best_cost()
);
assert_eq!(result.reason, TerminationReason::SolverConverged);
}
#[test]
fn problem_c_ellipsoid_min_product3() {
let prob = Prob {
f: |x| x[0] * x[1] * x[2],
c: |x| vec![x[0] * x[0] + 2.0 * x[1] * x[1] + 3.0 * x[2] * x[2] - 1.0],
m: 1,
};
let solver = Cobyla::new().with_rho_beg(0.5).with_rho_end(1e-5);
let state = CobylaState::new(vec![1.0, 1.0, 1.0]);
let result = Executor::new(prob, solver, state)
.terminate_on(crate::MaxCostEvals(3000))
.run()
.unwrap();
assert!(
(result.best_cost() - (-0.078567)).abs() < 1e-3,
"F = {}",
result.best_cost()
);
}
#[test]
fn problem_f_fletcher() {
let prob = Prob {
f: |x| -x[0] - x[1],
c: |x| vec![x[0] * x[0] - x[1], x[0] * x[0] + x[1] * x[1] - 1.0],
m: 2,
};
let solver = Cobyla::new().with_rho_beg(0.5).with_rho_end(1e-5);
let state = CobylaState::new(vec![1.0, 1.0]);
let result = Executor::new(prob, solver, state)
.terminate_on(crate::MaxCostEvals(3000))
.run()
.unwrap();
assert!(
(result.best_cost() - (-2.0_f64.sqrt())).abs() < 1e-3,
"F = {}",
result.best_cost()
);
let x = result.best_param();
assert!(x[0] * x[0] - x[1] <= 1e-4);
assert!(x[0] * x[0] + x[1] * x[1] - 1.0 <= 1e-4);
}
#[test]
fn problem_g_fletcher() {
let prob = Prob {
f: |x| x[2],
c: |x| {
vec![
-(5.0 * x[0] - x[1] + x[2]),
-(-5.0 * x[0] - x[1] + x[2]),
x[0] * x[0] + x[1] * x[1] + 4.0 * x[1] - x[2],
]
},
m: 3,
};
let solver = Cobyla::new().with_rho_beg(0.5).with_rho_end(1e-5);
let state = CobylaState::new(vec![1.0, 1.0, 1.0]);
let result = Executor::new(prob, solver, state)
.terminate_on(crate::MaxCostEvals(3000))
.run()
.unwrap();
assert!(
(result.best_cost() - (-3.0)).abs() < 1e-2,
"F = {}",
result.best_cost()
);
}
#[test]
fn unconstrained_rosenbrock_like() {
let prob = Prob {
f: |x| 10.0 * (x[1] - x[0] * x[0]).powi(2) + (1.0 - x[0]).powi(2),
c: |_x| vec![],
m: 0,
};
let solver = Cobyla::new().with_rho_beg(0.5).with_rho_end(1e-6);
let state = CobylaState::new(vec![-1.0, 1.0]);
let result = Executor::new(prob, solver, state)
.terminate_on(crate::MaxCostEvals(5000))
.run()
.unwrap();
assert!(result.best_cost() < 1e-3, "F = {}", result.best_cost());
}