use crate::sqp::line_search::{l1_violation, LineSearchResult};
use crate::sqp::options::SqpOptions;
use crate::sqp::problem::SqpProblemSpec;
use pounce_common::Number;
#[derive(Debug, Clone, Default)]
pub struct SqpFilter {
entries: Vec<(Number, Number)>,
pub gamma_theta: Number,
pub gamma_phi: Number,
}
impl SqpFilter {
pub fn new() -> Self {
Self {
entries: Vec::new(),
gamma_theta: 1e-5,
gamma_phi: 1e-5,
}
}
pub fn accepts(&self, theta: Number, phi: Number) -> bool {
for &(t_e, p_e) in &self.entries {
let ok = theta <= (1.0 - self.gamma_theta) * t_e || phi <= p_e - self.gamma_phi * t_e;
if !ok {
return false;
}
}
true
}
pub fn add(&mut self, theta_curr: Number, phi_curr: Number) {
let new_theta = theta_curr * (1.0 - self.gamma_theta);
let new_phi = phi_curr - self.gamma_phi * theta_curr;
self.entries
.retain(|&(t_e, p_e)| !(new_theta <= t_e && new_phi <= p_e));
self.entries.push((new_theta, new_phi));
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[allow(clippy::too_many_arguments)]
pub fn filter_line_search<N: SqpProblemSpec>(
nlp: &mut N,
filter: &mut SqpFilter,
x: &[Number],
p: &[Number],
f_curr: Number,
c_curr: &[Number],
bl: &[Number],
bu: &[Number],
xl: &[Number],
xu: &[Number],
current_nu: Number,
opts: &SqpOptions,
) -> LineSearchResult {
let theta_curr = l1_violation(x, c_curr, bl, bu, xl, xu);
let phi_curr = f_curr;
let mut alpha = 1.0_f64;
let mut x_trial = vec![0.0; x.len()];
let mut last_f = f_curr;
let mut last_c = c_curr.to_vec();
while alpha > opts.bt_min_alpha {
for (xt, (&xi, &pi)) in x_trial.iter_mut().zip(x.iter().zip(p.iter())) {
*xt = xi + alpha * pi;
}
let f_trial = nlp.eval_f(&x_trial);
let c_trial = nlp.eval_c(&x_trial);
let theta_trial = l1_violation(&x_trial, &c_trial, bl, bu, xl, xu);
let phi_trial = f_trial;
last_f = f_trial;
last_c.clone_from(&c_trial);
let theta_progress = theta_trial <= (1.0 - filter.gamma_theta) * theta_curr;
let phi_progress = phi_trial <= phi_curr - filter.gamma_phi * theta_curr;
let progress = theta_progress || phi_progress;
if progress && filter.accepts(theta_trial, phi_trial) {
filter.add(theta_curr, phi_curr);
return LineSearchResult {
alpha,
nu: current_nu,
x_new: x_trial,
f_new: f_trial,
c_new: c_trial,
success: true,
};
}
alpha *= opts.bt_reduction;
}
LineSearchResult {
alpha,
nu: current_nu,
x_new: x_trial,
f_new: last_f,
c_new: last_c,
success: false,
}
}