1#![allow(clippy::needless_range_loop, clippy::too_many_arguments)]
6#![deny(clippy::print_stdout, clippy::print_stderr)]
7
8pub mod error;
14pub use error::MpsError;
15pub use error::SolverError;
16pub(crate) mod basis;
17pub mod options;
18#[doc(hidden)]
19pub mod presolve;
20pub mod problem;
21pub(crate) mod simplex;
22pub mod sparse;
23pub mod tolerances;
24pub use options::{
25 BranchingStrategy, DualPricing, GlobalOptimizationConfig, LpWarmStart, MipBranching, MipConfig,
26 SolverOptions, Tolerance, WarmStartBasis,
27};
28#[doc(hidden)]
29pub mod linalg;
30pub mod lp;
31pub mod mip;
32pub mod qp;
33
34#[cfg(test)]
35pub(crate) mod test_kkt;
36
37pub use lp::solve_lp_with;
39pub use mip::{
40 solve_milp, solve_milp_with_stats, solve_miqp, solve_miqp_with_stats, MilpProblem,
41 MipProblemError, MipStats, MiqpProblem,
42};
43pub use problem::certificate::{BoundGapCertificate, NotProven, OptimalCertificate};
44pub use problem::{SolveRoute, SolveStats, SolveStatus, SolverResult};
45pub use qp::certificate::prove_optimal;
46pub use qp::{solve_qp, solve_qp_global, solve_qp_with, QpProblem, QpWarmStart};
47pub use sparse::CscMatrix;
48
49pub fn solve(problem: &crate::problem::LpProblem) -> crate::problem::SolverResult {
53 lp::solve_lp_with(problem, &SolverOptions::default())
54}
55
56pub use lp::solve_lp_with as solve_with;
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61 use crate::problem::{ConstraintType, SolveStatus};
62 use crate::sparse::CscMatrix;
63
64 fn make_offset_lp(obj_offset: f64) -> crate::problem::LpProblem {
65 let a = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
67 let mut lp = crate::problem::LpProblem::new_general(
68 vec![1.0],
69 a,
70 vec![5.0],
71 vec![ConstraintType::Le],
72 vec![(0.0, f64::INFINITY)],
73 None,
74 )
75 .unwrap();
76 lp.obj_offset = obj_offset;
77 lp
78 }
79
80 #[test]
85 fn test_legacy_lp_exports_apply_obj_offset() {
86 let lp = make_offset_lp(5.0);
87
88 let r1 = solve(&lp);
89 assert_eq!(r1.status, SolveStatus::Optimal);
90 assert!(
91 (r1.objective - 5.0).abs() < 1e-9,
92 "solve: expected 5.0 (c^Tx=0 + offset 5), got {}",
93 r1.objective
94 );
95
96 let r2 = solve_with(&lp, &SolverOptions::default());
97 assert_eq!(r2.status, SolveStatus::Optimal);
98 assert!(
99 (r2.objective - 5.0).abs() < 1e-9,
100 "solve_with: expected 5.0 (c^Tx=0 + offset 5), got {}",
101 r2.objective
102 );
103 }
104}
105
106#[doc(hidden)]
109pub mod bound_flip {
110 pub use crate::simplex::dual_advanced::bound_flip::{
111 bfrt_flip_invocations, bfrt_select_entering, reset_bfrt_flip_invocations, BfrtResult,
112 ColBound,
113 };
114}
115
116#[cfg(test)]
122pub(crate) struct ScopedDisable<D: Fn()> {
123 restore: D,
124}
125
126#[cfg(test)]
127impl<D: Fn()> ScopedDisable<D> {
128 pub(crate) fn new<E: Fn()>(enable: E, restore: D) -> Self {
129 enable();
130 ScopedDisable { restore }
131 }
132}
133
134#[cfg(test)]
135impl<D: Fn()> Drop for ScopedDisable<D> {
136 fn drop(&mut self) {
137 (self.restore)();
138 }
139}
140
141#[doc(hidden)]
147pub fn apply_lp_primal_guard(
148 result: crate::problem::SolverResult,
149 problem: &crate::problem::LpProblem,
150) -> crate::problem::SolverResult {
151 crate::qp::certificate::guard_lp_optimal(result, problem)
152}