use crate::types::Number;
use std::any::Any;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Checkpoint {
IterStart,
AfterBarrierUpdate,
AfterSearchDirection,
AfterStep,
StepRejected,
PreRestoration,
PostRestoration,
Terminated,
}
impl Checkpoint {
pub fn as_str(self) -> &'static str {
match self {
Checkpoint::IterStart => "iter_start",
Checkpoint::AfterBarrierUpdate => "after_mu",
Checkpoint::AfterSearchDirection => "after_search_dir",
Checkpoint::AfterStep => "after_step",
Checkpoint::StepRejected => "step_rejected",
Checkpoint::PreRestoration => "pre_restoration_entry",
Checkpoint::PostRestoration => "post_restoration_exit",
Checkpoint::Terminated => "terminated",
}
}
pub fn is_sub_iteration(self) -> bool {
matches!(
self,
Checkpoint::AfterBarrierUpdate
| Checkpoint::AfterSearchDirection
| Checkpoint::AfterStep
| Checkpoint::StepRejected
| Checkpoint::PreRestoration
| Checkpoint::PostRestoration
)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DebugAction {
Resume,
Stop,
}
#[derive(Clone, Debug)]
pub struct KktReport {
pub iter: i32,
pub dim: i32,
pub n_neg: i32,
pub n_pos: i32,
pub expected_neg: i32,
pub provides_inertia: bool,
pub inertia_correct: bool,
pub delta_w: Number,
pub delta_c: Number,
pub status: String,
}
pub type LFactor = (usize, Vec<usize>, Vec<i32>, Vec<i32>, Option<Vec<Number>>);
pub type KktTriplets = (i32, Vec<i32>, Vec<i32>, Vec<Number>);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ResidKind {
Eq,
Ineq,
DualX,
DualS,
}
impl ResidKind {
pub fn tag(self) -> &'static str {
match self {
ResidKind::Eq => "c",
ResidKind::Ineq => "d-s",
ResidKind::DualX => "grad_x_L",
ResidKind::DualS => "grad_s_L",
}
}
pub fn is_primal(self) -> bool {
matches!(self, ResidKind::Eq | ResidKind::Ineq)
}
}
#[derive(Clone, Copy, Debug)]
pub struct Residual {
pub kind: ResidKind,
pub index: usize,
pub value: Number,
}
pub trait IterSnapshot: Any {
fn iter(&self) -> i32;
fn mu(&self) -> Number;
fn block(&self, name: &str) -> Option<Vec<Number>>;
fn as_any(&self) -> &dyn Any;
}
pub trait DebugState {
fn as_any(&self) -> Option<&dyn Any> {
None
}
fn as_any_mut(&mut self) -> Option<&mut dyn Any> {
None
}
fn checkpoint(&self) -> Checkpoint;
fn iter(&self) -> i32;
fn mu(&self) -> Number;
fn objective(&self) -> Number;
fn inf_pr(&self) -> Number;
fn inf_du(&self) -> Number;
fn complementarity(&self) -> Number;
fn alpha(&self) -> (Number, Number);
fn block_dims(&self) -> Vec<(&'static str, usize)>;
fn block(&self, name: &str) -> Option<Vec<Number>>;
fn delta_block(&self, name: &str) -> Option<Vec<Number>>;
fn status(&self) -> Option<&str> {
None
}
fn nlp_error(&self) -> Number {
Number::NAN
}
fn bound_slack(&self, _which: &str) -> Option<Vec<Number>> {
None
}
fn regularization(&self) -> Number {
Number::NAN
}
fn ls_count(&self) -> i32 {
-1
}
fn kkt(&self) -> Option<KktReport> {
None
}
fn kkt_matrix(&self) -> Option<KktTriplets> {
None
}
fn kkt_l_factor(&self) -> Option<LFactor> {
None
}
fn kkt_captured_iter(&self) -> Option<i32> {
None
}
fn request_l_factor(&mut self) -> bool {
false
}
fn request_kkt_matrix(&mut self) -> bool {
false
}
fn set_mu(&mut self, _mu: Number) -> Result<(), String> {
Err("this solver does not support setting mu".into())
}
fn set_block(&mut self, _name: &str, _vals: &[Number]) -> Result<(), String> {
Err("this solver does not support editing the iterate".into())
}
fn set_component(&mut self, name: &str, idx: usize, val: Number) -> Result<(), String> {
let mut vals = self
.block(name)
.ok_or_else(|| format!("unknown block `{name}` or no iterate yet"))?;
if idx >= vals.len() {
return Err(format!(
"index {idx} out of range for block `{name}` (dimension {})",
vals.len()
));
}
vals[idx] = val;
self.set_block(name, &vals)
}
fn snapshot(&self) -> Option<Box<dyn IterSnapshot>> {
None
}
fn restore(&mut self, _snap: &dyn IterSnapshot) -> bool {
false
}
fn constraint_residuals(&self) -> Option<Vec<Residual>> {
None
}
fn dual_residuals(&self) -> Option<Vec<Residual>> {
None
}
}
pub trait DebugHook {
fn at_checkpoint(&mut self, state: &mut dyn DebugState) -> DebugAction;
fn wants_kkt_capture(&self) -> bool {
true
}
fn arm(&mut self) {}
}