use crate::sparse::CscMatrix;
#[derive(Clone, Debug)]
pub struct IpmOutcome {
pub solution: Vec<f64>,
pub dual_solution: Vec<f64>,
pub bound_duals: Vec<f64>,
pub objective: f64,
pub iterations: usize,
pub kkt_residual_rel: f64,
pub primal_residual_rel: f64,
pub bound_violation: f64,
pub complementarity_residual_rel: f64,
pub duality_gap_rel: f64,
pub numerical_failure: bool,
pub infeasibility_status: Option<crate::problem::SolveStatus>,
pub is_locally_optimal: bool,
pub postsolve_krylov_ir_skipped: bool,
pub timing: Option<crate::problem::TimingBreakdown>,
}
impl IpmOutcome {
pub fn empty() -> Self {
Self {
solution: Vec::new(),
dual_solution: Vec::new(),
bound_duals: Vec::new(),
objective: f64::INFINITY,
iterations: 0,
kkt_residual_rel: f64::INFINITY,
primal_residual_rel: f64::INFINITY,
bound_violation: f64::INFINITY,
complementarity_residual_rel: f64::INFINITY,
duality_gap_rel: f64::INFINITY,
numerical_failure: false,
infeasibility_status: None,
is_locally_optimal: false,
postsolve_krylov_ir_skipped: false,
timing: None,
}
}
pub fn infeasibility(status: crate::problem::SolveStatus) -> Self {
debug_assert!(
matches!(
status,
crate::problem::SolveStatus::Infeasible
| crate::problem::SolveStatus::Unbounded
| crate::problem::SolveStatus::NonConvex(_)
),
"infeasibility outcome must be Infeasible / Unbounded / NonConvex, got {:?}",
status
);
Self {
infeasibility_status: Some(status),
..Self::empty()
}
}
pub const PROMOTION_GAP_TOL: f64 = 1e-1;
pub fn satisfies_eps(&self, eps: f64) -> bool {
!self.solution.is_empty()
&& !self.numerical_failure
&& self.kkt_residual_rel <= eps
&& self.primal_residual_rel <= eps
&& self.bound_violation <= eps
&& self.complementarity_residual_rel <= eps
&& self.duality_gap_rel < Self::PROMOTION_GAP_TOL
}
pub fn quality_score(&self) -> f64 {
if self.solution.is_empty() || self.numerical_failure {
return f64::INFINITY;
}
self.kkt_residual_rel
.max(self.primal_residual_rel)
.max(self.bound_violation)
.max(self.complementarity_residual_rel)
}
}
pub struct ProblemView<'a> {
pub q: &'a CscMatrix,
pub a: &'a CscMatrix,
pub c: &'a [f64],
pub b: &'a [f64],
pub bounds: &'a [(f64, f64)],
pub constraint_types: &'a [crate::problem::ConstraintType],
pub eliminated_cols: &'a [bool],
}
impl<'a> ProblemView<'a> {
pub fn from_problem(problem: &'a crate::qp::problem::QpProblem) -> Self {
Self {
q: &problem.q,
a: &problem.a,
c: &problem.c,
b: &problem.b,
bounds: &problem.bounds,
constraint_types: &problem.constraint_types,
eliminated_cols: &[],
}
}
}