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#[doc(hidden)]
35pub mod diag {
36 pub use crate::presolve::scaling::{
37 lp_scale_profile_enabled, lp_scale_profile_snapshot, reset_lp_scale_profile,
38 LpScaleProfileSnapshot,
39 };
40
41 #[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
42 pub struct SimplexFallbackSnapshot {
43 pub ub_violation_out_of_scope: u64,
44 pub phase1_bound_violation: u64,
45 pub crash_infeasible: u64,
46 }
47
48 pub fn reset_simplex_fallback_profile() {
49 crate::simplex::dual_advanced::reset_fallback_profile();
50 }
51
52 pub fn simplex_fallback_profile_snapshot() -> SimplexFallbackSnapshot {
53 let s = crate::simplex::dual_advanced::fallback_profile_snapshot();
54 SimplexFallbackSnapshot {
55 ub_violation_out_of_scope: s.ub_violation_out_of_scope,
56 phase1_bound_violation: s.phase1_bound_violation,
57 crash_infeasible: s.crash_infeasible,
58 }
59 }
60}
61
62#[cfg(test)]
63pub(crate) mod test_kkt;
64
65pub use lp::solve_lp_with;
67pub use mip::{
68 solve_milp, solve_milp_with_stats, solve_miqp, solve_miqp_with_stats, MilpProblem,
69 MipProblemError, MipStats, MiqpProblem,
70};
71pub use problem::certificate::{BoundGapCertificate, NotProven, OptimalCertificate};
72pub use problem::{SolveRoute, SolveStats, SolveStatus, SolverResult};
73pub use qp::certificate::prove_optimal;
74pub use qp::{solve_qp, solve_qp_global, solve_qp_with, QpProblem, QpWarmStart};
75pub use sparse::CscMatrix;
76
77pub fn solve(problem: &crate::problem::LpProblem) -> crate::problem::SolverResult {
81 lp::solve_lp_with(problem, &SolverOptions::default())
82}
83
84pub use lp::solve_lp_with as solve_with;
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use crate::problem::{ConstraintType, SolveStatus};
90 use crate::sparse::CscMatrix;
91
92 fn make_offset_lp(obj_offset: f64) -> crate::problem::LpProblem {
93 let a = CscMatrix::from_triplets(&[0], &[0], &[1.0], 1, 1).unwrap();
95 let mut lp = crate::problem::LpProblem::new_general(
96 vec![1.0],
97 a,
98 vec![5.0],
99 vec![ConstraintType::Le],
100 vec![(0.0, f64::INFINITY)],
101 None,
102 )
103 .unwrap();
104 lp.obj_offset = obj_offset;
105 lp
106 }
107
108 #[test]
113 fn test_legacy_lp_exports_apply_obj_offset() {
114 let lp = make_offset_lp(5.0);
115
116 let r1 = solve(&lp);
117 assert_eq!(r1.status, SolveStatus::Optimal);
118 assert!(
119 (r1.objective - 5.0).abs() < 1e-9,
120 "solve: expected 5.0 (c^Tx=0 + offset 5), got {}",
121 r1.objective
122 );
123
124 let r2 = solve_with(&lp, &SolverOptions::default());
125 assert_eq!(r2.status, SolveStatus::Optimal);
126 assert!(
127 (r2.objective - 5.0).abs() < 1e-9,
128 "solve_with: expected 5.0 (c^Tx=0 + offset 5), got {}",
129 r2.objective
130 );
131 }
132}
133
134#[doc(hidden)]
137pub mod bound_flip {
138 pub use crate::simplex::dual_advanced::bound_flip::{
139 bfrt_flip_invocations, bfrt_select_entering, reset_bfrt_flip_invocations, BfrtResult,
140 ColBound,
141 };
142}
143
144#[cfg(test)]
150pub(crate) struct ScopedDisable<D: Fn()> {
151 restore: D,
152}
153
154#[cfg(test)]
155impl<D: Fn()> ScopedDisable<D> {
156 pub(crate) fn new<E: Fn()>(enable: E, restore: D) -> Self {
157 enable();
158 ScopedDisable { restore }
159 }
160}
161
162#[cfg(test)]
163impl<D: Fn()> Drop for ScopedDisable<D> {
164 fn drop(&mut self) {
165 (self.restore)();
166 }
167}
168
169#[doc(hidden)]
175pub fn apply_lp_primal_guard(
176 result: crate::problem::SolverResult,
177 problem: &crate::problem::LpProblem,
178) -> crate::problem::SolverResult {
179 crate::qp::certificate::guard_lp_optimal(result, problem)
180}