use std::time::Instant;
use oximo_core::{Model, ModelKind};
use oximo_solver::{Solver, SolverError, SolverResult};
use crate::options::PounceOptions;
use crate::translate::{WarmStart, assemble, setup};
#[cfg(feature = "enzyme")]
use crate::exact as backend;
#[cfg(not(feature = "enzyme"))]
use crate::stable as backend;
struct State {
oracle: backend::Oracle,
warm: Option<WarmStart>,
}
#[derive(Default)]
pub struct PouncePersistent {
state: Option<State>,
}
impl std::fmt::Debug for PouncePersistent {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PouncePersistent").field("resident", &self.state.is_some()).finish()
}
}
impl PouncePersistent {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn reset(&mut self) {
self.state = None;
}
fn solve_resident(
&mut self,
model: &Model,
opts: &PounceOptions,
) -> Result<SolverResult, SolverError> {
let prep = setup(model, opts)?;
let started = Instant::now();
let state = match &mut self.state {
Some(state) if backend::try_reuse(&state.oracle, model) => state,
state => state.insert(State { oracle: backend::build(model)?, warm: None }),
};
let mut outcome = backend::run(&state.oracle, &prep, opts, state.warm.as_ref())?;
let elapsed = started.elapsed();
state.warm = outcome.warm.take();
Ok(assemble(prep.sign, outcome, elapsed))
}
}
impl Solver for PouncePersistent {
type Options = PounceOptions;
fn name(&self) -> &str {
"pounce"
}
fn supports(&self, kind: ModelKind) -> bool {
matches!(kind, ModelKind::LP | ModelKind::QP | ModelKind::QCP | ModelKind::NLP)
}
fn solve(&mut self, model: &Model, opts: &PounceOptions) -> Result<SolverResult, SolverError> {
match self.solve_resident(model, opts) {
Ok(result) => Ok(result),
Err(e) => {
self.state = None;
Err(e)
}
}
}
}