use ndarray::Array1;
pub use opt::{HessianMaterialization, HessianOperator, HessianValue, ObjectiveEvalError};
#[derive(Debug, Clone)]
pub enum OuterStrategyError {
RhoBlockShape { reason: String },
}
impl_reason_error_boilerplate! {
OuterStrategyError {
RhoBlockShape,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Derivative {
Analytic,
Unavailable,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum DeclaredHessianForm {
Dense,
Operator {
materialization: HessianMaterialization,
estimated_materialization_cost: Option<f64>,
},
Either,
Unavailable,
}
impl DeclaredHessianForm {
pub const fn is_analytic(self) -> bool {
!matches!(self, DeclaredHessianForm::Unavailable)
}
}
pub struct OuterEval {
pub cost: f64,
pub gradient: Array1<f64>,
pub hessian: HessianValue,
pub inner_beta_hint: Option<Array1<f64>>,
}
impl OuterEval {
pub fn infeasible(n_params: usize) -> Self {
Self {
cost: f64::INFINITY,
gradient: Array1::zeros(n_params),
hessian: HessianValue::Unavailable,
inner_beta_hint: None,
}
}
pub fn value_only(cost: f64, n_params: usize, inner_beta_hint: Option<Array1<f64>>) -> Self {
Self {
cost,
gradient: Array1::zeros(n_params),
hessian: HessianValue::Unavailable,
inner_beta_hint,
}
}
}
impl Clone for OuterEval {
fn clone(&self) -> Self {
Self {
cost: self.cost,
gradient: self.gradient.clone(),
hessian: self.hessian.clone(),
inner_beta_hint: self.inner_beta_hint.clone(),
}
}
}
impl std::fmt::Debug for OuterEval {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("OuterEval")
.field("cost", &self.cost)
.field("gradient", &self.gradient)
.field("hessian", &self.hessian)
.finish()
}
}
#[derive(Clone, Debug)]
pub struct EfsEval {
pub cost: f64,
pub steps: Vec<f64>,
pub beta: Option<Array1<f64>>,
pub psi_gradient: Option<Array1<f64>>,
pub psi_indices: Option<Vec<usize>>,
pub inner_hessian_scale: Option<f64>,
pub logdet_enclosure_gap: Option<f64>,
pub consecutive_restored_incumbents: Option<usize>,
}
#[derive(Clone, Debug)]
pub enum FixedPointCoordinateCertificate {
Covered { update: f64, scale: f64 },
Uncovered { reason: String },
}
impl FixedPointCoordinateCertificate {
pub fn covered(update: f64, scale: f64) -> Self {
Self::Covered { update, scale }
}
pub fn uncovered(reason: impl Into<String>) -> Self {
Self::Uncovered {
reason: reason.into(),
}
}
}
#[derive(Clone, Debug)]
pub struct FixedPointCertificateEval {
pub cost: f64,
pub coordinates: Vec<FixedPointCoordinateCertificate>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn declared_unavailable_is_not_analytic() {
assert!(!DeclaredHessianForm::Unavailable.is_analytic());
}
#[test]
fn declared_dense_is_analytic() {
assert!(DeclaredHessianForm::Dense.is_analytic());
}
#[test]
fn declared_either_is_analytic() {
assert!(DeclaredHessianForm::Either.is_analytic());
}
#[test]
fn declared_operator_is_analytic() {
let form = DeclaredHessianForm::Operator {
materialization: HessianMaterialization::Explicit,
estimated_materialization_cost: None,
};
assert!(form.is_analytic());
}
#[test]
fn infeasible_eval_has_infinity_cost() {
let eval = OuterEval::infeasible(3);
assert_eq!(eval.cost, f64::INFINITY);
assert_eq!(eval.gradient.len(), 3);
}
#[test]
fn value_only_eval_has_specified_cost() {
let eval = OuterEval::value_only(42.5, 2, None);
assert_eq!(eval.cost, 42.5);
assert_eq!(eval.gradient.len(), 2);
assert!(eval.inner_beta_hint.is_none());
}
}