#![allow(clippy::needless_range_loop, clippy::too_many_arguments)]
#![deny(clippy::print_stdout, clippy::print_stderr)]
pub mod error;
pub use error::MpsError;
pub use error::SolverError;
pub(crate) mod basis;
pub mod options;
#[doc(hidden)]
pub mod presolve;
pub mod problem;
pub(crate) mod simplex;
pub mod sparse;
pub mod tolerances;
pub use options::{
BranchingStrategy, DualPricing, GlobalOptimizationConfig, LpWarmStart, MipBranching, MipConfig,
SolverOptions, Tolerance, WarmStartBasis,
};
#[doc(hidden)]
pub mod linalg;
pub mod lp;
pub mod mip;
pub mod qp;
#[cfg(test)]
pub(crate) mod test_kkt;
pub use lp::solve_lp_with;
pub use mip::{
solve_milp, solve_milp_with_stats, solve_miqp, solve_miqp_with_stats, MilpProblem,
MipProblemError, MipStats, MiqpProblem,
};
pub use problem::certificate::{BoundGapCertificate, NotProven, OptimalCertificate};
pub use problem::{SolveRoute, SolveStats, SolveStatus, SolverResult};
pub use qp::certificate::prove_optimal;
pub use qp::{solve_qp, solve_qp_global, solve_qp_with, QpProblem, QpWarmStart};
pub use sparse::CscMatrix;
pub fn solve(problem: &crate::problem::LpProblem) -> crate::problem::SolverResult {
lp::solve_lp_with(problem, &SolverOptions::default())
}
pub use lp::solve_lp_with as solve_with;
#[cfg(test)]
mod tests {
use super::*;
use crate::problem::{ConstraintType, SolveStatus};
use crate::sparse::CscMatrix;
fn make_offset_lp(obj_offset: f64) -> crate::problem::LpProblem {
let a = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
let mut lp = crate::problem::LpProblem::new_general(
vec![1.0],
a,
vec![5.0],
vec![ConstraintType::Le],
vec![(0.0, f64::INFINITY)],
None,
)
.unwrap();
lp.obj_offset = obj_offset;
lp
}
#[test]
fn test_legacy_lp_exports_apply_obj_offset() {
let lp = make_offset_lp(5.0);
let r1 = solve(&lp);
assert_eq!(r1.status, SolveStatus::Optimal);
assert!(
(r1.objective - 5.0).abs() < 1e-9,
"solve: expected 5.0 (c^Tx=0 + offset 5), got {}",
r1.objective
);
let r2 = solve_with(&lp, &SolverOptions::default());
assert_eq!(r2.status, SolveStatus::Optimal);
assert!(
(r2.objective - 5.0).abs() < 1e-9,
"solve_with: expected 5.0 (c^Tx=0 + offset 5), got {}",
r2.objective
);
}
}
#[doc(hidden)]
pub mod bound_flip {
pub use crate::simplex::dual_advanced::bound_flip::{
bfrt_flip_invocations, bfrt_select_entering, reset_bfrt_flip_invocations, BfrtResult,
ColBound,
};
}
#[cfg(test)]
pub(crate) struct ScopedDisable<D: Fn()> {
restore: D,
}
#[cfg(test)]
impl<D: Fn()> ScopedDisable<D> {
pub(crate) fn new<E: Fn()>(enable: E, restore: D) -> Self {
enable();
ScopedDisable { restore }
}
}
#[cfg(test)]
impl<D: Fn()> Drop for ScopedDisable<D> {
fn drop(&mut self) {
(self.restore)();
}
}
#[doc(hidden)]
pub fn apply_lp_primal_guard(
result: crate::problem::SolverResult,
problem: &crate::problem::LpProblem,
) -> crate::problem::SolverResult {
crate::qp::certificate::guard_lp_optimal(result, problem)
}