use crate::errors::QlResult;
use crate::math::array::Array;
use crate::math::optimization::endcriteria::{EndCriteria, EndCriteriaType};
use crate::math::optimization::linesearch::LineSearch;
use crate::math::optimization::problem::Problem;
use crate::types::{Real, Size};
pub(crate) fn line_search_based_minimize(
problem: &mut Problem<'_>,
end_criteria: &EndCriteria,
line_search: &mut dyn LineSearch,
mut updated_direction: impl FnMut(&Problem<'_>, Real, &dyn LineSearch) -> Array,
) -> QlResult<EndCriteriaType> {
let ftol = end_criteria.function_epsilon();
let mut max_stationary_state_iterations = end_criteria.max_stationary_state_iterations();
let mut ec_type = EndCriteriaType::None;
problem.reset();
line_search.reset();
let mut x = problem.current_value().clone();
let mut iteration_number: Size = 0;
let mut t = 1.0;
let mut gradient = Array::with_size(x.size());
let function_value = problem.value_and_gradient(&mut gradient, &x);
problem.set_function_value(function_value);
problem.set_gradient_norm_value(gradient.dot(&gradient));
line_search.set_search_direction(-&gradient);
loop {
t = line_search.search(problem, &mut ec_type, end_criteria, t)?;
if !line_search.succeeded() {
problem.set_current_value(x);
return Ok(ec_type);
}
x = line_search.last_x().clone();
let fold = problem.function_value();
problem.set_function_value(line_search.last_function_value());
let gold2 = problem.gradient_norm_value();
problem.set_gradient_norm_value(line_search.last_gradient_norm2());
let direction = updated_direction(problem, gold2, line_search);
line_search.set_search_direction(direction);
let fnew = problem.function_value();
let fdiff = 2.0 * (fnew - fold).abs() / (fnew.abs() + fold.abs() + Real::EPSILON);
if fdiff < ftol || end_criteria.check_max_iterations(iteration_number, &mut ec_type) {
end_criteria.check_stationary_function_value(
0.0,
0.0,
&mut max_stationary_state_iterations,
&mut ec_type,
);
end_criteria.check_max_iterations(iteration_number, &mut ec_type);
problem.set_current_value(x);
return Ok(ec_type);
}
problem.set_current_value(x.clone());
iteration_number += 1;
}
}