use super::builder::VariableMetricBuilder;
use super::seed::MigradSeedGenerator;
use crate::fcn::FCNGradient;
use crate::minimum::FunctionMinimum;
use crate::mn_fcn::MnFcn;
use crate::strategy::MnStrategy;
use crate::user_transformation::MnUserTransformation;
pub struct VariableMetricMinimizer;
impl VariableMetricMinimizer {
pub fn minimize(
fcn: &MnFcn,
trafo: &MnUserTransformation,
strategy: &MnStrategy,
maxfcn: usize,
tolerance: f64,
) -> FunctionMinimum {
let up = fcn.error_def();
let seed = MigradSeedGenerator::generate(fcn, trafo, strategy);
if !seed.is_valid() {
return FunctionMinimum::new(seed, Vec::new(), up);
}
let edmval = tolerance * up * 0.002;
let states = VariableMetricBuilder::minimum(fcn, &seed, strategy, maxfcn, edmval);
let nfcn = fcn.num_of_calls();
if nfcn >= maxfcn {
FunctionMinimum::with_call_limit(seed, states, up)
} else if let Some(last) = states.last() {
if last.edm() > 10.0 * edmval {
FunctionMinimum::above_max_edm(seed, states, up)
} else {
FunctionMinimum::new(seed, states, up)
}
} else {
FunctionMinimum::new(seed, states, up)
}
}
pub fn minimize_with_gradient(
fcn: &dyn FCNGradient,
trafo: &MnUserTransformation,
strategy: &MnStrategy,
maxfcn: usize,
tolerance: f64,
) -> FunctionMinimum {
let up = fcn.error_def();
let seed = MigradSeedGenerator::generate_with_gradient(fcn, trafo, strategy);
if !seed.is_valid() {
return FunctionMinimum::new(seed, Vec::new(), up);
}
let edmval = tolerance * up * 0.002;
let mn_fcn = MnFcn::new(fcn, trafo);
let states = VariableMetricBuilder::minimum_with_gradient(
&mn_fcn, fcn, &seed, strategy, maxfcn, edmval,
);
let nfcn = mn_fcn.num_of_calls();
if nfcn >= maxfcn {
FunctionMinimum::with_call_limit(seed, states, up)
} else if let Some(last) = states.last() {
if last.edm() > 10.0 * edmval {
FunctionMinimum::above_max_edm(seed, states, up)
} else {
FunctionMinimum::new(seed, states, up)
}
} else {
FunctionMinimum::new(seed, states, up)
}
}
}