1use std::cmp;
6
7use linalg::Matrix;
8
9use crate::linalg::{self, CsrMatrix};
10
11#[derive(Hash)]
15pub struct GeLineq {
16 pub id : Option<u32>,
18 pub coeffs : Vec<i64>,
20 pub bounds : Vec<(i64, i64)>,
22 pub bias : i64,
24 pub indices : Vec<u32>
26}
27
28impl Clone for GeLineq {
29 fn clone(&self) -> Self {
30 return GeLineq {
31 id: self.id,
32 coeffs: self.coeffs.to_vec(),
33 bounds: self.bounds.to_vec(),
34 bias: self.bias,
35 indices: self.indices.to_vec(),
36 }
37 }
38}
39
40impl GeLineq {
41
42 fn _eqmax(&self) -> i64 {
43 let mut res : i64 = 0;
44 for i in 0..self.coeffs.len() {
45 if self.coeffs[i] < 0 {
46 res = res + self.coeffs[i] * self.bounds[i].0;
47 } else {
48 res = res + self.coeffs[i] * self.bounds[i].1;
49 }
50 }
51 return res;
52 }
53
54 fn _eqmin(&self) -> i64 {
55 let mut res : i64 = 0;
56 for i in 0..self.coeffs.len() {
57 if self.coeffs[i] > 0 {
58 res = res + self.coeffs[i] * self.bounds[i].0;
59 } else {
60 res = res + self.coeffs[i] * self.bounds[i].1;
61 }
62 }
63 return res;
64 }
65
66 pub fn merge_disj(ge_lineq1: &GeLineq, ge_lineq2: &GeLineq) -> Option<GeLineq> {
104 if ge_lineq1._eqmin() + ge_lineq1.bias == -1 {
105 let mut equal_indices : Vec<(usize, usize)> = Vec::new();
106 for i in 0..ge_lineq1.indices.len(){
107 for j in 0..ge_lineq2.indices.len(){
108 if ge_lineq1.indices[i]==ge_lineq2.indices[j] {
109 equal_indices.push((i, j));
110 }
111 }
112 }
113 let n: usize = ge_lineq1.coeffs.len() + ge_lineq2.coeffs.len() - equal_indices.len();
114 let mut new_coeffs : Vec<i64> = Vec::with_capacity(n);
115 let mut equal_index_pointer: usize = 0;
116 let mut corrector: i64 = 0;
117 let mut new_bounds : Vec<(i64, i64)> = Vec::with_capacity(n);
118 let mut new_indices : Vec<u32> = Vec::with_capacity(n);
119
120 for i in 0..ge_lineq1.coeffs.len() {
121 if equal_index_pointer < equal_indices.len() && equal_indices[equal_index_pointer].0 == i {
122 corrector = ge_lineq2.coeffs[equal_indices[equal_index_pointer].1];
123 equal_index_pointer = equal_index_pointer + 1;
124 }
125 new_coeffs.push(-ge_lineq1.coeffs[i]*(ge_lineq2._eqmin() + ge_lineq2.bias) + corrector);
126 new_indices.push(ge_lineq1.indices[i]);
127 new_bounds.push(ge_lineq1.bounds[i]);
128 corrector = 0;
129 }
130 let mut skip_equal_index = false;
131 for i in 0..ge_lineq2.coeffs.len(){
132 for j in 0..equal_indices.len(){
133 if equal_indices[j].1 == i {
134 equal_indices.remove(j);
135 skip_equal_index = true;
136 break;
137 }
138 }
139 if !skip_equal_index {
140 new_coeffs.push(ge_lineq2.coeffs[i]);
141 new_indices.push(ge_lineq2.indices[i]);
142 new_bounds.push(ge_lineq2.bounds[i]);
143 }
144 skip_equal_index = false;
145 }
146 return Some(
147 GeLineq {
148 id: None,
149 coeffs: new_coeffs,
150 bounds: new_bounds,
151 bias: ge_lineq1._eqmin()*(ge_lineq2._eqmin() + ge_lineq2.bias)+ge_lineq2.bias,
152 indices: new_indices
153 }
154 );
155 } else if ge_lineq2._eqmin() + ge_lineq2.bias == -1 {
156 return GeLineq::merge_disj(ge_lineq2, ge_lineq1);
157 }
158
159 None
160
161 }
162
163 pub fn merge_conj(ge_lineq1: &GeLineq, ge_lineq2: &GeLineq) -> Option<GeLineq> {
166
167 if ge_lineq1._eqmax() + ge_lineq1.bias == 0 {
168 let mut equal_indices : Vec<(usize, usize)> = Vec::new();
169 for i in 0..ge_lineq1.indices.len(){
170 for j in 0..ge_lineq2.indices.len(){
171 if ge_lineq1.indices[i]==ge_lineq2.indices[j] {
172 equal_indices.push((i, j));
173 }
174 }
175 }
176 let n: usize = ge_lineq1.coeffs.len() + ge_lineq2.coeffs.len() - equal_indices.len();
177 let mut new_coeffs : Vec<i64> = Vec::with_capacity(n);
178 let mut equal_index_pointer: usize = 0;
179 let mut corrector: i64 = 0;
180 let mut new_bounds : Vec<(i64, i64)> = Vec::with_capacity(n);
181 let mut new_indices : Vec<u32> = Vec::with_capacity(n);
182
183 for i in 0..ge_lineq1.coeffs.len() {
184 if equal_index_pointer < equal_indices.len() && equal_indices[equal_index_pointer].0 == i {
185 corrector = ge_lineq2.coeffs[equal_indices[equal_index_pointer].1];
186 equal_index_pointer = equal_index_pointer + 1;
187 }
188 new_coeffs.push(ge_lineq1.coeffs[i]*(cmp::max(ge_lineq2._eqmax().abs(), ge_lineq2._eqmin().abs())+1) + corrector);
189 new_indices.push(ge_lineq1.indices[i]);
190 new_bounds.push(ge_lineq1.bounds[i]);
191 corrector = 0;
192 }
193 let mut skip_equal_index = false;
194 for i in 0..ge_lineq2.coeffs.len(){
195 for j in 0..equal_indices.len(){
196 if equal_indices[j].1 == i {
197 equal_indices.remove(j);
198 skip_equal_index = true;
199 break;
200 }
201 }
202 if !skip_equal_index {
203 new_coeffs.push(ge_lineq2.coeffs[i]);
204 new_indices.push(ge_lineq2.indices[i]);
205 new_bounds.push(ge_lineq2.bounds[i]);
206 }
207 skip_equal_index = false;
208 }
209 return Some(
210 GeLineq {
211 id: None,
212 coeffs: new_coeffs,
213 bounds: new_bounds,
214 bias: ge_lineq1.bias*(cmp::max(ge_lineq2._eqmax().abs(), ge_lineq2._eqmin().abs())+1) + ge_lineq2.bias - cmp::max(ge_lineq2._eqmin() + ge_lineq2.bias, 0),
215 indices: new_indices
216 }
217 );
218 } else if ge_lineq2._eqmax() + ge_lineq2.bias == 0 {
219 return GeLineq::merge_conj(&ge_lineq2, &ge_lineq1);
220 }
221
222 None
223
224 }
225
226 pub fn substitution(main_gelineq: &GeLineq, variable_index: u32, sub_gelineq: &GeLineq) -> Option<GeLineq> {
256 let var_to_substitute = main_gelineq.indices.iter().position(|&x| x == variable_index).expect(&format!("Variable '{variable_index}' to substitute not found"));
257 if main_gelineq.coeffs[var_to_substitute] < 0 {
258 let new_sub_coeffs: Vec<i64> = sub_gelineq.coeffs.iter().map(|x| -1*x).collect();
259 let new_sub_bias = -sub_gelineq.bias - 1;
260 let new_sub_gelineq = GeLineq {
261 id: None,
262 coeffs: new_sub_coeffs,
263 bounds: sub_gelineq.bounds.to_vec(),
264 bias: new_sub_bias,
265 indices: sub_gelineq.indices.to_vec()
266 };
267 return GeLineq::_substitution(main_gelineq, var_to_substitute, &new_sub_gelineq);
268 }
269 return GeLineq::_substitution(main_gelineq, var_to_substitute, sub_gelineq);
270 }
271
272 fn _substitution(main_gelineq: &GeLineq, variable_index: usize, sub_gelineq: &GeLineq) -> Option<GeLineq> {
273 if !GeLineq::is_homogenous(main_gelineq) && sub_gelineq.coeffs.len() > 1 {
274 return None;
276 }
277 if sub_gelineq.bias < 0 {
278 if sub_gelineq._eqmax() > 0 && (main_gelineq.coeffs[variable_index]*(2*sub_gelineq._eqmax() + sub_gelineq.bias)/sub_gelineq._eqmax()) >= 2 {
279 return None;
281 }
282 } else {
283 if (main_gelineq.coeffs[variable_index]*(sub_gelineq._eqmax() + sub_gelineq._eqmin().abs() + sub_gelineq.bias) / sub_gelineq._eqmin().abs()) >= 2 {
284 return None;
286 }
287 }
288 let mut equal_indices : Vec<(usize, usize)> = Vec::new();
289 for i in 0..main_gelineq.indices.len(){
290 for j in 0..sub_gelineq.indices.len(){
291 if main_gelineq.indices[i]==sub_gelineq.indices[j] {
292 equal_indices.push((i, j));
293 }
294 }
295 }
296 let n: usize = main_gelineq.coeffs.len() + sub_gelineq.coeffs.len() - equal_indices.len() - 1;
297 let mut new_coeffs : Vec<i64> = Vec::with_capacity(n);
298 let mut equal_index_pointer: usize = 0;
299 let mut corrector: i64 = 0;
300 let mut new_bounds : Vec<(i64, i64)> = Vec::with_capacity(n);
301 let mut new_indices : Vec<u32> = Vec::with_capacity(n);
302
303 for i in 0..main_gelineq.coeffs.len() {
304 if i == variable_index {
305 continue;
306 }
307 if equal_index_pointer < equal_indices.len() && equal_indices[equal_index_pointer].0 == i {
308 corrector = sub_gelineq.coeffs[equal_indices[equal_index_pointer].1];
309 equal_index_pointer = equal_index_pointer + 1;
310 }
311 if sub_gelineq.bias < 0 {
312 new_coeffs.push(main_gelineq.coeffs[i]*sub_gelineq._eqmax() + corrector);
313 } else {
314 new_coeffs.push(main_gelineq.coeffs[i]*sub_gelineq._eqmin().abs() + corrector);
315 }
316 new_indices.push(main_gelineq.indices[i]);
317 new_bounds.push(main_gelineq.bounds[i]);
318 corrector = 0;
319 }
320 let mut skip_equal_index = 0;
321 for i in 0..sub_gelineq.coeffs.len(){
322 for j in 0..equal_indices.len(){
323 if equal_indices[j].1 == i {
324 equal_indices.remove(j);
325 skip_equal_index = 1;
326 break;
327 }
328 }
329 if skip_equal_index < 1 {
330 new_coeffs.push(sub_gelineq.coeffs[i]);
331 new_indices.push(sub_gelineq.indices[i]);
332 new_bounds.push(sub_gelineq.bounds[i]);
333 }
334 skip_equal_index = 0;
335 }
336 let adjuster = if main_gelineq.bias != 0 {1} else {0};
337 let new_bias = if sub_gelineq.bias < 0 {(main_gelineq.bias + adjuster)*sub_gelineq._eqmax() + sub_gelineq.bias} else {(main_gelineq.bias+adjuster)*sub_gelineq._eqmin().abs() + sub_gelineq.bias};
338 return Some(
339 GeLineq {
340 id: main_gelineq.id,
341 coeffs: new_coeffs,
342 bounds: new_bounds,
343 bias: new_bias,
344 indices: new_indices
345 }
346 );
347 }
348
349 fn is_homogenous(ge_lineq: &GeLineq) -> bool {
350 let first = ge_lineq.coeffs[0];
351 ge_lineq.coeffs.iter().all(|x| *x==first)
352 }
353
354 fn is_mixed(gelineq: &GeLineq) -> bool {
355 let mut is_mixed = false;
356 let mut positive = false;
357 let mut negative = false;
358 let mut i: usize = 0;
359 while !is_mixed && i < gelineq.coeffs.len() {
360 if gelineq.coeffs[i]*gelineq.bounds[i].0 > 0 || gelineq.coeffs[i]*gelineq.bounds[i].1 > 0 {
361 positive = true;
362 }
363 if gelineq.coeffs[i]*gelineq.bounds[i].0 < 0 || gelineq.coeffs[i]*gelineq.bounds[i].1 < 0 {
364 negative = true
365 }
366 if positive && negative {
367 is_mixed = true;
368 }
369 i = i + 1;
370 }
371 return is_mixed;
372 }
373
374 pub fn min_max_coefficients(gelineq: &GeLineq) -> Option<GeLineq> {
392 if GeLineq::is_mixed(gelineq){
393 return None;
394 }
395 let mut new_coeffs: Vec<i64> = Vec::with_capacity(gelineq.coeffs.len());
396 for i in 0..gelineq.coeffs.len(){
397 if gelineq.coeffs[i]*gelineq.bounds[i].0 > 0 || gelineq.coeffs[i]*gelineq.bounds[i].1 > 0 {
398 new_coeffs.push(cmp::min(gelineq.coeffs[i], cmp::max(-gelineq.bias, 0)));
399 } else if gelineq.coeffs[i]*gelineq.bounds[i].0 < 0 || gelineq.coeffs[i]*gelineq.bounds[i].1 < 0 {
400 new_coeffs.push(cmp::max(gelineq.coeffs[i], cmp::min(-gelineq.bias, 0)-1));
401 } else {
402 new_coeffs.push(0);
403 }
404 }
405 return Some(
406 GeLineq {
407 id: gelineq.id,
408 coeffs: new_coeffs,
409 bounds: gelineq.bounds.to_vec(),
410 bias: gelineq.bias,
411 indices: gelineq.indices.to_vec()
412 }
413 )
414 }
415
416
417 }
418
419
420#[derive(Debug)]
421pub struct VariableFloat {
422 pub id : u32,
423 pub bounds : (f64, f64)
424}
425
426impl Clone for VariableFloat {
427 fn clone(&self) -> Self {
428 return VariableFloat {
429 id: self.id,
430 bounds: self.bounds
431 }
432 }
433}
434
435impl PartialEq for VariableFloat {
436 fn eq(&self, other: &Self) -> bool {
437 return self.id == other.id;
438 }
439}
440
441
442#[derive(Copy, Eq, Debug)]
445pub struct Variable {
446 pub id : u32,
447 pub bounds : (i64, i64)
448}
449
450impl Clone for Variable {
451 fn clone(&self) -> Self {
452 return Variable {
453 id : self.id,
454 bounds: self.bounds
455 }
456 }
457}
458
459impl PartialEq for Variable {
460 fn eq(&self, other: &Self) -> bool {
461 return self.id == other.id;
462 }
463}
464
465impl Variable {
466
467 pub fn to_lineq_neg(&self) -> GeLineq {
485 return GeLineq {
486 id: Some(self.id),
487 coeffs: vec![-1],
488 bias: 0,
489 bounds: vec![(0,1)],
490 indices: vec![self.id]
491 }
492 }
493
494 pub fn to_variable_float(&self) -> VariableFloat {
495 return VariableFloat { id: self.id, bounds: (self.bounds.0 as f64, self.bounds.1 as f64) }
496 }
497}
498
499#[derive(Default, Debug)]
503pub struct Polyhedron {
504 pub a: Matrix,
506 pub b: Vec<f64>,
508 pub variables: Vec<VariableFloat>,
510 pub index: Vec<Option<u32>>
512}
513impl Clone for Polyhedron {
514 fn clone(&self) -> Self {
515 return Polyhedron { a: self.a.clone(), b: self.b.clone(), variables: self.variables.clone(), index: self.index.clone() }
516 }
517}
518impl PartialEq for Polyhedron {
519 fn eq(&self, other: &Self) -> bool {
520 return (self.a == other.a) & (self.b == other.b) & (self.variables == other.variables) & (self.index == other.index);
521 }
522}
523impl Polyhedron {
524 pub fn bounds(&self) -> Vec<(f64, f64)> {
526 return self.variables.iter().map(|x| x.bounds).collect();
527 }
528
529 pub fn ids(&self) -> Vec<u32> {
531 return self.variables.iter().map(|x| x.id).collect();
532 }
533}
534
535pub struct CsrPolyhedron {
536 pub a: CsrMatrix,
538 pub b: Vec<f64>,
540 pub variables: Vec<VariableFloat>,
542 pub index: Vec<Option<u32>>
544}
545
546impl Clone for CsrPolyhedron {
547 fn clone(&self) -> Self {
548 return CsrPolyhedron { a: self.a.clone(), b: self.b.clone(), variables: self.variables.clone(), index: self.index.clone() }
549 }
550}
551impl PartialEq for CsrPolyhedron {
552 fn eq(&self, other: &Self) -> bool {
553 return (self.a == other.a) & (self.b == other.b) & (self.variables == other.variables) & (self.index == other.index);
554 }
555}
556impl CsrPolyhedron {
557 pub fn bounds(&self) -> Vec<(f64, f64)> {
559 return self.variables.iter().map(|x| x.bounds).collect();
560 }
561
562 pub fn ids(&self) -> Vec<u32> {
564 return self.variables.iter().map(|x| x.id).collect();
565 }
566
567 pub fn to_dense_polyhedron(&self) -> Polyhedron {
568 return Polyhedron {
569 a: self.a.to_matrix(),
570 b: self.b.clone(),
571 index: self.index.clone(),
572 variables: self.variables.clone()
573 }
574 }
575}