#[derive(Debug, Clone)]
pub struct DiffQPConfig {
pub tolerance: f64,
pub max_iterations: usize,
pub regularization: f64,
pub backward_mode: BackwardMode,
}
impl Default for DiffQPConfig {
fn default() -> Self {
Self {
tolerance: 1e-8,
max_iterations: 100,
regularization: 1e-7,
backward_mode: BackwardMode::FullDifferentiation,
}
}
}
#[derive(Debug, Clone)]
pub struct DiffLPConfig {
pub tolerance: f64,
pub max_iterations: usize,
pub active_constraint_tol: f64,
pub regularization: f64,
}
impl Default for DiffLPConfig {
fn default() -> Self {
Self {
tolerance: 1e-8,
max_iterations: 100,
active_constraint_tol: 1e-6,
regularization: 1e-7,
}
}
}
#[derive(Debug, Clone)]
pub struct DiffQPResult {
pub optimal_x: Vec<f64>,
pub optimal_lambda: Vec<f64>,
pub optimal_nu: Vec<f64>,
pub objective: f64,
pub converged: bool,
pub iterations: usize,
}
#[derive(Debug, Clone)]
pub struct DiffLPResult {
pub optimal_x: Vec<f64>,
pub optimal_lambda: Vec<f64>,
pub optimal_nu: Vec<f64>,
pub objective: f64,
pub converged: bool,
pub iterations: usize,
}
#[derive(Debug, Clone)]
pub struct ImplicitGradient {
pub dl_dq: Option<Vec<Vec<f64>>>,
pub dl_dc: Vec<f64>,
pub dl_dg: Option<Vec<Vec<f64>>>,
pub dl_dh: Vec<f64>,
pub dl_da: Option<Vec<Vec<f64>>>,
pub dl_db: Vec<f64>,
}
#[derive(Debug, Clone, Default)]
pub struct DiffOptParams {
pub q: Vec<Vec<f64>>,
pub c: Vec<f64>,
pub a: Vec<Vec<f64>>,
pub b: Vec<f64>,
pub g: Vec<Vec<f64>>,
pub h: Vec<f64>,
}
#[derive(Debug, Clone)]
pub struct DiffOptResult {
pub x: Vec<f64>,
pub lambda: Vec<f64>,
pub nu: Vec<f64>,
pub objective: f64,
pub status: DiffOptStatus,
pub iterations: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum DiffOptStatus {
Optimal,
MaxIterations,
Infeasible,
Unbounded,
}
impl Default for DiffOptStatus {
fn default() -> Self {
DiffOptStatus::Optimal
}
}
#[derive(Debug, Clone)]
pub struct DiffOptGrad {
pub dl_dq: Option<Vec<Vec<f64>>>,
pub dl_dc: Vec<f64>,
pub dl_da: Option<Vec<Vec<f64>>>,
pub dl_db: Vec<f64>,
pub dl_dg: Option<Vec<Vec<f64>>>,
pub dl_dh: Vec<f64>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum BackwardMode {
FullDifferentiation,
ActiveSetOnly,
}
#[derive(Debug, Clone)]
pub struct KKTSystem {
pub stationarity: Vec<f64>,
pub primal_eq: Vec<f64>,
pub primal_ineq: Vec<f64>,
pub complementarity: Vec<f64>,
pub max_residual: f64,
}
impl KKTSystem {
pub fn is_satisfied(&self, tol: f64) -> bool {
self.max_residual < tol
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_diff_qp_config_default() {
let cfg = DiffQPConfig::default();
assert!((cfg.tolerance - 1e-8).abs() < 1e-15);
assert_eq!(cfg.max_iterations, 100);
assert!((cfg.regularization - 1e-7).abs() < 1e-15);
assert_eq!(cfg.backward_mode, BackwardMode::FullDifferentiation);
}
#[test]
fn test_diff_lp_config_default() {
let cfg = DiffLPConfig::default();
assert!((cfg.tolerance - 1e-8).abs() < 1e-15);
assert_eq!(cfg.max_iterations, 100);
assert!((cfg.active_constraint_tol - 1e-6).abs() < 1e-15);
}
#[test]
fn test_kkt_system_satisfied() {
let kkt = KKTSystem {
stationarity: vec![1e-10],
primal_eq: vec![1e-10],
primal_ineq: vec![-0.5],
complementarity: vec![1e-12],
max_residual: 1e-10,
};
assert!(kkt.is_satisfied(1e-8));
assert!(!kkt.is_satisfied(1e-12));
}
#[test]
fn test_backward_mode_non_exhaustive() {
let mode = BackwardMode::ActiveSetOnly;
match mode {
BackwardMode::FullDifferentiation => panic!("wrong variant"),
BackwardMode::ActiveSetOnly => {}
_ => {}
}
}
}