use std::fmt;
use crate::api::context::Context;
use crate::api::expr::Ex;
use crate::api::poly_ex::Poly;
use crate::base::errors::SymplexError;
use crate::domains::linprog::Q;
use crate::output::lean::LeanOpts;
#[derive(Clone, Debug, PartialEq)]
pub enum Outcome<C, U> {
Proved(C),
#[non_exhaustive]
Refuted {
point: Vec<(Ex, Q)>,
value: Q,
param_value: Option<Q>,
},
Unknown(U),
}
impl<C, U> Outcome<C, U> {
pub fn is_proved(&self) -> bool {
matches!(self, Outcome::Proved(_))
}
pub fn is_refuted(&self) -> bool {
matches!(self, Outcome::Refuted { .. })
}
pub fn is_unknown(&self) -> bool {
matches!(self, Outcome::Unknown(_))
}
pub fn certificate(&self) -> Option<&C> {
match self {
Outcome::Proved(c) => Some(c),
_ => None,
}
}
pub fn into_certificate(self) -> Option<C> {
match self {
Outcome::Proved(c) => Some(c),
_ => None,
}
}
pub fn refutation(&self) -> Option<(&[(Ex, Q)], &Q)> {
match self {
Outcome::Refuted { point, value, .. } => Some((point.as_slice(), value)),
_ => None,
}
}
pub fn unknown(&self) -> Option<&U> {
match self {
Outcome::Unknown(u) => Some(u),
_ => None,
}
}
pub fn map_certificate<D>(self, f: impl FnOnce(C) -> D) -> Outcome<D, U> {
match self {
Outcome::Proved(c) => Outcome::Proved(f(c)),
Outcome::Refuted {
point,
value,
param_value,
} => Outcome::Refuted {
point,
value,
param_value,
},
Outcome::Unknown(u) => Outcome::Unknown(u),
}
}
}
impl<C: fmt::Display, U: fmt::Display> fmt::Display for Outcome<C, U> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Outcome::Proved(c) => write!(f, "proved: {c}"),
Outcome::Refuted {
point,
value,
param_value,
} => {
write!(f, "refuted at (")?;
for (i, (v, q)) in point.iter().enumerate() {
if i > 0 {
write!(f, ", ")?;
}
write!(f, "{v} = {q}")?;
}
write!(f, "): value {value}")?;
if let Some(p) = param_value {
write!(f, " (parameter {p})")?;
}
Ok(())
}
Outcome::Unknown(u) => write!(f, "unknown: {u}"),
}
}
}
pub trait Certificate: fmt::Display {
fn goal(&self) -> &Poly;
fn verify(&self) -> bool;
fn to_lean_with(&self, theorem_name: &str, opts: &LeanOpts) -> Result<String, SymplexError>;
fn to_lean(&self, theorem_name: &str) -> Result<String, SymplexError> {
self.to_lean_with(theorem_name, &LeanOpts::default())
}
fn to_json(&self) -> Result<String, SymplexError>;
fn from_json(ctx: &Context, json: &str) -> Result<Self, SymplexError>
where
Self: Sized;
}