1#![allow(
6 clippy::needless_range_loop,
7 clippy::too_many_arguments,
8)]
9#![deny(clippy::print_stdout, clippy::print_stderr)]
10
11pub mod error;
42pub use error::SolverError;
43pub use error::MpsError;
44#[doc(hidden)]
45pub mod presolve;
46pub mod sparse;
47pub mod problem;
48pub(crate) mod simplex;
49#[cfg(test)]
55#[allow(dead_code)]
56pub(crate) mod io;
57pub(crate) mod basis;
58pub mod tolerances;
59pub mod options;
60pub use options::{
61 BranchingStrategy, DualPricing, GlobalOptimizationConfig, LpWarmStart, MipBranching, MipConfig,
62 SolverOptions, Tolerance, WarmStartBasis,
63};
64pub mod qp;
65pub mod mip;
66pub mod lp;
67#[doc(hidden)]
68pub mod linalg;
69
70#[cfg(test)]
71pub(crate) mod test_kkt;
72
73#[cfg(test)]
79pub(crate) mod peak_alloc {
80 use std::alloc::{GlobalAlloc, Layout, System};
81 use std::cell::Cell;
82
83 thread_local! {
84 static CURRENT: Cell<isize> = const { Cell::new(0) };
85 }
86
87 #[inline]
88 fn update(delta: isize) {
89 CURRENT.with(|c| c.set(c.get() + delta));
90 }
91
92 pub struct TrackingAlloc;
93
94 unsafe impl GlobalAlloc for TrackingAlloc {
95 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
96 let ptr = System.alloc(layout);
97 if !ptr.is_null() {
98 update(layout.size() as isize);
99 }
100 ptr
101 }
102 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
103 let ptr = System.alloc_zeroed(layout);
104 if !ptr.is_null() {
105 update(layout.size() as isize);
106 }
107 ptr
108 }
109 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
110 System.dealloc(ptr, layout);
111 update(-(layout.size() as isize));
112 }
113 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
114 let new_ptr = System.realloc(ptr, layout, new_size);
115 if !new_ptr.is_null() {
116 update(new_size as isize - layout.size() as isize);
117 }
118 new_ptr
119 }
120 }
121}
122
123#[cfg(test)]
124#[global_allocator]
125static TEST_ALLOC: peak_alloc::TrackingAlloc = peak_alloc::TrackingAlloc;
126
127pub use sparse::CscMatrix;
129pub use problem::{SolveRoute, SolveStats, SolveStatus, SolverResult};
130pub use problem::certificate::{BoundGapCertificate, NotProven, OptimalCertificate};
131pub use qp::certificate::prove_optimal;
132pub use qp::{solve_qp, solve_qp_global, solve_qp_with, QpProblem, QpWarmStart};
133pub use mip::{
134 solve_milp, solve_milp_with_stats, solve_miqp, solve_miqp_with_stats, MilpProblem,
135 MipProblemError, MipStats, MiqpProblem,
136};
137pub use lp::solve_lp_with;
138pub use simplex::{solve, solve_with};
139
140#[doc(hidden)]
143pub mod bound_flip {
144 pub use crate::simplex::dual_advanced::bound_flip::{
145 bfrt_flip_invocations, bfrt_select_entering, reset_bfrt_flip_invocations,
146 BfrtResult, ColBound,
147 };
148}
149
150#[cfg(test)]
156pub(crate) struct ScopedDisable<D: Fn()> {
157 restore: D,
158}
159
160#[cfg(test)]
161impl<D: Fn()> ScopedDisable<D> {
162 pub(crate) fn new<E: Fn()>(enable: E, restore: D) -> Self {
163 enable();
164 ScopedDisable { restore }
165 }
166}
167
168#[cfg(test)]
169impl<D: Fn()> Drop for ScopedDisable<D> {
170 fn drop(&mut self) {
171 (self.restore)();
172 }
173}
174
175#[doc(hidden)]
181pub fn apply_lp_primal_guard(
182 result: crate::problem::SolverResult,
183 problem: &crate::problem::LpProblem,
184) -> crate::problem::SolverResult {
185 crate::qp::certificate::guard_lp_optimal(result, problem)
186}