use std::time::Instant;
use super::config::ClpAlgorithm;
use super::solver::ClpSolver;
use crate::clp_ffi;
pub(crate) const LADDER_RUNGS: usize = 5;
#[derive(Debug, Clone, Copy)]
pub(super) struct EscalationOutcome {
pub(super) objective: f64,
pub(super) iterations: u64,
pub(super) solve_time: f64,
pub(super) attempts: u64,
}
impl ClpSolver {
fn escalate_run(&mut self, algorithm: ClpAlgorithm) -> i32 {
self.reset_cold_basis();
match algorithm {
ClpAlgorithm::Dual => {
unsafe { clp_ffi::cobre_clp_dual(self.handle, 0) }
}
ClpAlgorithm::Primal => {
unsafe { clp_ffi::cobre_clp_primal(self.handle, 0) }
}
}
}
pub(super) fn escalate_solve(&mut self) -> Option<EscalationOutcome> {
const RUNGS: [(i32, i32, ClpAlgorithm); LADDER_RUNGS] = [
(102, 0, ClpAlgorithm::Primal),
(50, 0, ClpAlgorithm::Dual),
(50, 0, ClpAlgorithm::Primal),
(50, 1, ClpAlgorithm::Dual),
(50, 1, ClpAlgorithm::Primal),
];
let t0 = Instant::now();
for (idx, &(perturbation, scaling, algorithm)) in RUNGS.iter().enumerate() {
unsafe {
clp_ffi::cobre_clp_set_perturbation(self.handle, perturbation);
clp_ffi::cobre_clp_scaling(self.handle, scaling);
}
let status = self.escalate_run(algorithm);
if status == clp_ffi::CLP_STATUS_OPTIMAL {
#[allow(clippy::cast_sign_loss)]
let iterations =
unsafe { clp_ffi::cobre_clp_number_iterations(self.handle) } as u64;
let objective = unsafe { clp_ffi::cobre_clp_objective_value(self.handle) };
self.copy_solution();
return Some(EscalationOutcome {
objective,
iterations,
solve_time: t0.elapsed().as_secs_f64(),
attempts: idx as u64 + 1,
});
}
}
None
}
}