use crate::{
constraints,
core::{
fbs::fbs_engine::FBSEngine, fbs::FBSCache, AlgorithmEngine, Optimizer, Problem,
SolverStatus,
},
Error,
};
use std::time;
const MAX_ITER: usize = 100_usize;
pub struct FBSOptimizer<'a, GradientType, ConstraintType, CostType>
where
GradientType: Fn(&[f64], &mut [f64]) -> Result<(), Error>,
CostType: Fn(&[f64], &mut f64) -> Result<(), Error>,
ConstraintType: constraints::Constraint,
{
fbs_engine: FBSEngine<'a, GradientType, ConstraintType, CostType>,
max_iter: usize,
max_duration: Option<time::Duration>,
}
impl<'a, GradientType, ConstraintType, CostType>
FBSOptimizer<'a, GradientType, ConstraintType, CostType>
where
GradientType: Fn(&[f64], &mut [f64]) -> Result<(), Error>,
CostType: Fn(&[f64], &mut f64) -> Result<(), Error>,
ConstraintType: constraints::Constraint,
{
pub fn new(
problem: Problem<GradientType, ConstraintType, CostType>,
cache: &'a mut FBSCache,
) -> FBSOptimizer<'a, GradientType, ConstraintType, CostType> {
FBSOptimizer {
fbs_engine: FBSEngine::new(problem, cache),
max_iter: MAX_ITER,
max_duration: None,
}
}
pub fn with_tolerance(
mut self,
tolerance: f64,
) -> FBSOptimizer<'a, GradientType, ConstraintType, CostType> {
assert!(tolerance > 0.0);
self.fbs_engine.cache.tolerance = tolerance;
self
}
pub fn with_max_iter(
mut self,
max_iter: usize,
) -> FBSOptimizer<'a, GradientType, ConstraintType, CostType> {
self.max_iter = max_iter;
self
}
pub fn with_max_duration(
mut self,
max_duration: time::Duration,
) -> FBSOptimizer<'a, GradientType, ConstraintType, CostType> {
self.max_duration = Some(max_duration);
self
}
}
impl<'life, GradientType, ConstraintType, CostType> Optimizer
for FBSOptimizer<'life, GradientType, ConstraintType, CostType>
where
GradientType: Fn(&[f64], &mut [f64]) -> Result<(), Error> + 'life,
CostType: Fn(&[f64], &mut f64) -> Result<(), Error> + 'life,
ConstraintType: constraints::Constraint + 'life,
{
fn solve(&mut self, u: &mut [f64]) -> SolverStatus {
let now = time::Instant::now();
if let Ok(_) = self.fbs_engine.init(u) {
let mut num_iter: usize = 0;
if let Some(dur) = self.max_duration {
while self.fbs_engine.step(u) == Ok(true)
&& num_iter < self.max_iter
&& dur <= now.elapsed()
{
num_iter += 1;
}
} else {
while self.fbs_engine.step(u) == Ok(true) && num_iter < self.max_iter {
num_iter += 1;
}
}
let mut cost_value = 0.0;
assert_eq!(
Ok(()),
(self.fbs_engine.problem.cost)(u, &mut cost_value),
"The computation of the cost value at the solution failed"
);
SolverStatus::new(
num_iter < self.max_iter,
num_iter,
now.elapsed(),
self.fbs_engine.cache.norm_fpr,
cost_value,
)
} else {
SolverStatus::new(
false,
0,
now.elapsed(),
std::f64::INFINITY,
std::f64::INFINITY,
)
}
}
}