scirs2_optimize/integer/
mod.rs1use crate::error::{OptimizeError, OptimizeResult};
28use scirs2_core::ndarray::{Array1, Array2};
29
30pub mod branch_and_bound;
31pub mod cdcl_branching;
32pub mod column_generation;
33pub mod cutting_plane;
34pub mod knapsack;
35pub mod lift_project;
36pub mod lift_project_mip;
37pub mod lp_relaxation;
38pub mod milp_branch_and_bound;
39
40pub use branch_and_bound::{BranchAndBoundOptions, BranchAndBoundSolver};
41pub use cutting_plane::{CuttingPlaneOptions, CuttingPlaneSolver};
42pub use lp_relaxation::LpRelaxationSolver;
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum IntegerKind {
47 Continuous,
49 Binary,
51 Integer,
53}
54
55#[derive(Debug, Clone)]
57pub struct IntegerVariableSet {
58 pub kinds: Vec<IntegerKind>,
60}
61
62impl IntegerVariableSet {
63 pub fn new(n: usize) -> Self {
65 IntegerVariableSet {
66 kinds: vec![IntegerKind::Continuous; n],
67 }
68 }
69
70 pub fn all_integer(n: usize) -> Self {
72 IntegerVariableSet {
73 kinds: vec![IntegerKind::Integer; n],
74 }
75 }
76
77 pub fn all_binary(n: usize) -> Self {
79 IntegerVariableSet {
80 kinds: vec![IntegerKind::Binary; n],
81 }
82 }
83
84 pub fn set_kind(&mut self, i: usize, kind: IntegerKind) {
86 if i < self.kinds.len() {
87 self.kinds[i] = kind;
88 }
89 }
90
91 pub fn is_integer(&self, i: usize) -> bool {
93 match self.kinds.get(i) {
94 Some(IntegerKind::Integer) | Some(IntegerKind::Binary) => true,
95 _ => false,
96 }
97 }
98
99 pub fn len(&self) -> usize {
101 self.kinds.len()
102 }
103
104 pub fn is_empty(&self) -> bool {
106 self.kinds.iter().all(|k| *k == IntegerKind::Continuous)
107 }
108}
109
110#[derive(Debug, Clone)]
112pub struct MipResult {
113 pub x: Array1<f64>,
115 pub fun: f64,
117 pub success: bool,
119 pub message: String,
121 pub nodes_explored: usize,
123 pub lp_solves: usize,
125 pub lower_bound: f64,
127}
128
129#[derive(Debug, Clone)]
131pub struct LinearProgram {
132 pub c: Array1<f64>,
134 pub a_ub: Option<Array2<f64>>,
136 pub b_ub: Option<Array1<f64>>,
138 pub a_eq: Option<Array2<f64>>,
140 pub b_eq: Option<Array1<f64>>,
142 pub lower: Option<Array1<f64>>,
144 pub upper: Option<Array1<f64>>,
146}
147
148impl LinearProgram {
149 pub fn new(c: Array1<f64>) -> Self {
151 LinearProgram {
152 c,
153 a_ub: None,
154 b_ub: None,
155 a_eq: None,
156 b_eq: None,
157 lower: None,
158 upper: None,
159 }
160 }
161
162 pub fn n_vars(&self) -> usize {
164 self.c.len()
165 }
166}
167
168#[inline]
170pub fn is_integer_valued(v: f64, tol: f64) -> bool {
171 (v - v.round()).abs() <= tol
172}
173
174pub fn most_fractional_variable(x: &[f64], var_set: &IntegerVariableSet) -> Option<usize> {
176 let mut best_idx = None;
177 let mut best_frac = -1.0_f64;
178 for (i, &xi) in x.iter().enumerate() {
179 if var_set.is_integer(i) {
180 let frac = (xi - xi.floor()).abs();
181 let frac = frac.min(1.0 - frac); if frac > 1e-8 && frac > best_frac {
183 best_frac = frac;
184 best_idx = Some(i);
185 }
186 }
187 }
188 best_idx
189}
190
191#[cfg(test)]
192mod tests {
193 use super::*;
194
195 #[test]
196 fn test_integer_variable_set_creation() {
197 let ivs = IntegerVariableSet::new(5);
198 assert_eq!(ivs.len(), 5);
199 assert!(ivs.is_empty());
200 for i in 0..5 {
201 assert!(!ivs.is_integer(i));
202 }
203 }
204
205 #[test]
206 fn test_integer_variable_set_all_integer() {
207 let ivs = IntegerVariableSet::all_integer(3);
208 assert!(!ivs.is_empty());
209 for i in 0..3 {
210 assert!(ivs.is_integer(i));
211 }
212 }
213
214 #[test]
215 fn test_integer_variable_set_mixed() {
216 let mut ivs = IntegerVariableSet::new(4);
217 ivs.set_kind(1, IntegerKind::Integer);
218 ivs.set_kind(3, IntegerKind::Binary);
219 assert!(!ivs.is_integer(0));
220 assert!(ivs.is_integer(1));
221 assert!(!ivs.is_integer(2));
222 assert!(ivs.is_integer(3));
223 }
224
225 #[test]
226 fn test_is_integer_valued() {
227 assert!(is_integer_valued(3.0, 1e-8));
228 assert!(is_integer_valued(3.0000000001, 1e-7));
229 assert!(!is_integer_valued(3.5, 1e-8));
230 assert!(!is_integer_valued(3.1, 1e-8));
231 }
232
233 #[test]
234 fn test_most_fractional_variable() {
235 let x = vec![1.0, 2.6, 3.1, 0.5];
236 let ivs = IntegerVariableSet::all_integer(4);
237 let idx = most_fractional_variable(&x, &ivs);
238 assert_eq!(idx, Some(3));
240 }
241
242 #[test]
243 fn test_linear_program_construction() {
244 use scirs2_core::ndarray::array;
245 let c = array![1.0, -2.0, 3.0];
246 let lp = LinearProgram::new(c);
247 assert_eq!(lp.n_vars(), 3);
248 }
249}