1use std::{collections::HashMap};
6use std::fmt::Display;
7use itertools::Itertools;
8use polyopt::{GeLineq, Variable, Polyhedron, CsrPolyhedron};
9
10pub mod solver;
11pub mod linalg;
12pub mod polyopt;
13
14#[derive(Clone, Copy)]
15pub enum Sign {
16 Positive,
17 Negative
18}
19
20impl Sign {
21
22 pub fn val(&self) -> i8 {
26 return match *self {
27 Sign::Positive => 1,
28 Sign::Negative => -1,
29 }
30 }
31}
32
33
34pub struct AtLeast {
39 pub ids : Vec<u32>,
40 pub bias : i64,
41 pub sign : Sign,
42}
43
44impl Clone for AtLeast {
45 fn clone(&self) -> Self {
46 return AtLeast {
47 bias: self.bias,
48 ids: self.ids.to_vec(),
49 sign: self.sign,
50 }
51 }
52}
53
54impl AtLeast {
55
56 fn size(&self) -> usize {
57 return self.ids.len();
58 }
59
60 pub fn to_lineq(&self, id: Option<u32>, variable_hm: &HashMap<u32, Variable>) -> GeLineq {
87 return GeLineq {
88 id: id,
89 coeffs: vec![self.sign.val() as i64; self.size()],
90 bias: self.bias,
91 bounds: self.ids.iter().map(
92 |id| {
93 variable_hm.get(id).expect(
94 &format!(
95 "got id `{id}` in expression {self} that was not in theory"
96 )
97 ).bounds
98 }
99 ).collect(),
100 indices: self.ids.to_vec()
101 }
102 }
103
104 fn to_lineq_extended(&self, given_id: u32, variable_hm: &HashMap<u32, Variable>) -> GeLineq {
107 return GeLineq::merge_disj(
108 &(variable_hm.get(&given_id).expect(&format!("variable id `{given_id}` does not exist in variable hash map"))).to_lineq_neg(),
109 &self.to_lineq(Some(given_id), variable_hm)
110 ).expect("could not merge disjunctions") }
112
113 fn to_lineq_reduced(&self, extend_default: bool, given_id: u32, variable_hm: &HashMap<u32, Variable>, statement_hm: &HashMap<u32, &Statement>) -> GeLineq {
116 return match (self.bias, self.ids.len()) {
117 (-1, 2) => {
118 let sub_lineqs: Vec<GeLineq> = self.ids.iter().filter_map(|id| {
119 if let Some(statement) = statement_hm.get(id) {
120 if let Some(expression) = statement.expression.clone() {
121 return Some(expression.to_lineq(Some(given_id), variable_hm));
122 }
123 }
124 return None;
125 }).collect();
126 if sub_lineqs.len() == 2 {
127 if let Some(lineq) = GeLineq::merge_disj(&sub_lineqs[0], &sub_lineqs[1]) {
128 return lineq;
129 } else {
130 return match extend_default {
131 false => self.to_lineq(Some(given_id), variable_hm),
132 true => self.to_lineq_extended(given_id, variable_hm),
133 }
134 }
135 } else {
136 return match extend_default {
137 false => self.to_lineq(Some(given_id), variable_hm),
138 true => self.to_lineq_extended(given_id, variable_hm),
139 }
140 }
141 },
142 (-2, 2) => {
143 let sub_lineqs: Vec<GeLineq> = self.ids.iter().filter_map(|id| {
144 if let Some(statement) = statement_hm.get(id) {
145 if let Some(expression) = statement.expression.clone() {
146 return Some(expression.to_lineq(Some(given_id), variable_hm));
147 }
148 }
149 return None;
150 }).collect();
151 if sub_lineqs.len() == 2 {
152 if let Some(lineq) = GeLineq::merge_conj(&sub_lineqs[0], &sub_lineqs[1]) {
153 return lineq;
154 } else {
155 return match extend_default {
156 false => self.to_lineq(Some(given_id), variable_hm),
157 true => self.to_lineq_extended(given_id, variable_hm),
158 }
159 }
160 } else {
161 return match extend_default {
162 false => self.to_lineq(Some(given_id), variable_hm),
163 true => self.to_lineq_extended(given_id, variable_hm),
164 }
165 }
166 },
167 _ => match extend_default {
168 false => self.to_lineq(Some(given_id), variable_hm),
169 true => self.to_lineq_extended(given_id, variable_hm),
170 }
171 }
172 }
173}
174
175impl Display for AtLeast {
176 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
177 write!(f, "({})({}>={})", match self.bias < 0 {true => "+", false => "-"}, self.ids.iter().map(|v| v.to_string()).collect::<Vec<String>>().join(","), self.bias)
178 }
179}
180
181pub struct Statement {
185 pub variable : Variable,
186 pub expression : Option<AtLeast>
187}
188
189impl Clone for Statement {
190 fn clone(&self) -> Self {
191 return Statement {
192 variable: self.variable.clone(),
193 expression: match &self.expression {
194 Some(exp) => Some(exp.clone()),
195 None => None
196 }
197 }
198 }
199}
200
201pub struct Theory {
203 pub id : String,
204 pub statements : Vec<Statement>
205}
206
207impl Clone for Theory {
208 fn clone(&self) -> Self {
209 return Theory {
210 id: self.id.clone(),
211 statements: self.statements.to_vec()
212 }
213 }
214}
215
216impl Theory {
217
218 fn _top(&self) -> &u32 {
220 let mut is_child : bool = true;
221 let mut id_curr : &u32 = &self.statements.first().expect("theory is empty").variable.id;
222 let mut counter = 0;
223 while is_child {
224 if counter >= self.statements.len() {
225 panic!("theory has circular statement references! (a -> b -> c -> a)")
226 }
227 for statement in self.statements.iter() {
228 is_child = match &statement.expression {
229 Some(a) => a.ids.contains(id_curr),
230 None => false
231 };
232 if is_child {
233 id_curr = &statement.variable.id;
234 break;
235 }
236 }
237 counter += 1;
238 }
239 return id_curr;
240 }
241
242 fn _bottoms(&self) -> Vec<&u32> {
244 return self.statements.iter().filter_map(
245 |statement| {
246 match &statement.expression {
247 Some(_) => None,
248 None => Some(&statement.variable.id)
249 }
250 }
251 ).collect()
252 }
253
254 fn _variable_hm(&self) -> HashMap<u32, Variable> {
256 return self.statements.iter().map(|statement: &Statement| {
257 (statement.variable.id, statement.variable)
258 }).collect();
259 }
260
261 fn _statement_hm(&self) -> HashMap<u32, &Statement> {
263 return self.statements.iter().map(|statement: &Statement| {
264 (statement.variable.id, statement)
265 }).collect();
266 }
267
268 pub fn propagate(&self) -> HashMap<u32, (i64, i64)> {
322
323 let mut variable_bounds: HashMap<u32, (i64, i64)> = self.statements
326 .iter()
327 .filter(|statement| statement.expression.is_none())
328 .map(|statement| (statement.variable.id, statement.variable.bounds))
329 .collect();
330 let statements_hm: HashMap<u32, &Statement> = self._statement_hm();
331
332 let mut queue: Vec<u32> = self.statements
335 .iter()
336 .filter(|statement| statement.expression.is_some())
337 .map(|statement| statement.variable.id)
338 .collect();
339
340 while let Some(id) = queue.pop() {
342
343 if let Some(statement) = statements_hm.get(&id) {
344
345 if let Some(expression) = &statement.expression {
346
347 if let Some(bounds) = expression.ids.iter().map(|id| variable_bounds.get(id)).collect::<Option<Vec<&(i64, i64)>>>() {
349
350 let bounds_expression: (i64, i64) = bounds.iter().fold((0,0), |acc, bound| {
352 match expression.sign {
353
354 Sign::Positive => (acc.0 +bound.0, acc.1 + bound.1),
358
359 Sign::Negative => (acc.0 - bound.1, acc.1 - bound.0),
363 }
364 });
365
366 variable_bounds.insert(
368 statement.variable.id,
369 (
370 (bounds_expression.0 + expression.bias >= 0) as i64,
371 (bounds_expression.1 + expression.bias >= 0) as i64,
372 )
373 );
374
375 } else {
376
377 if !statements_hm.contains_key(&id) {
381 panic!("statement id `{id}` does not exist in statements hash map");
382 }
383
384 queue.push(id);
387 }
388
389 } else {
390 variable_bounds.insert(statement.variable.id, statement.variable.bounds);
391 }
392
393 }
394
395 }
396
397 return variable_bounds;
398 }
399
400 pub fn to_lineqs(&self, active: bool, reduced: bool) -> Vec<GeLineq> {
451 let top_node_id = *self._top();
452 let var_hm: HashMap<u32, Variable> = self._variable_hm();
453 let state_hm: HashMap<u32, &Statement> = self._statement_hm();
454 let mut lineqs: Vec<GeLineq> = Vec::default();
455 let mut queue: Vec<u32> = vec![top_node_id];
456
457 while let Some(id) = queue.pop() {
458 if let Some(statement) = state_hm.get(&id) {
459 let pot_lineq = match &statement.expression {
460 Some(a) => match reduced {
461 true => Some(
462 a.to_lineq_reduced(
463 !((statement.variable.id == top_node_id) & active),
464 statement.variable.id,
465 &var_hm,
466 &state_hm,
467 )
468 ),
469 false => match (statement.variable.id == top_node_id) & active {
470 true => Some(a.to_lineq(Some(statement.variable.id), &var_hm)),
471 false => Some(a.to_lineq_extended(statement.variable.id, &var_hm))
472 }
473 },
474 None => None
475 };
476
477 if let Some(act_lineq) = pot_lineq {
478 queue.append(&mut act_lineq.indices.clone().into_iter().filter(|i| (*i) != statement.variable.id).collect());
479 lineqs.push(act_lineq);
480 }
481 }
482 }
483 return lineqs;
484 }
485
486 pub fn to_ge_polyhedron(&self, active: bool, reduced: bool) -> CsrPolyhedron {
490 let lineqs = self.to_lineqs(active, reduced);
491 let mut index_bound_vec: Vec<(u32, (i64,i64))> = Vec::default();
492 for lineq in lineqs.iter() {
493 for (index, bound) in lineq.indices.iter().zip(lineq.bounds.iter()) {
494 let element = (*index, *bound);
495 if !index_bound_vec.contains(&element) {
496 index_bound_vec.push(element);
497 }
498 }
499 }
500
501 let size = lineqs.iter().map(|l| l.indices.len()).sum();
502
503 let mut row: Vec<i64> = vec![0; size];
504 let mut col: Vec<i64> = vec![0; size];
505 let mut val: Vec<f64> = vec![0.0; size];
506 let mut i: usize = 0;
507 for (il, lineq) in lineqs.iter().enumerate() {
508 for (index, cf) in lineq.indices.iter().zip(lineq.coeffs.iter()) {
509 row[i] = il as i64;
510 col[i] = (*index) as i64;
511 val[i] = (*cf) as f64;
512 i += 1;
513 }
514 }
515
516 let actual_indices: Vec<u32> = index_bound_vec.iter().map(|x| x.0).sorted().collect();
517 let index_bound_hm : HashMap<u32, (i64, i64)> = index_bound_vec.clone().into_iter().collect();
518 let variables: Vec<Variable> = actual_indices.iter().filter_map(|i| {
519 if let Some(bounds) = index_bound_hm.get(i) {
520 return Some(
521 Variable {
522 id: *i,
523 bounds: bounds.clone()
524 }
525 )
526 }
527 return None;
528 }).collect();
529 return CsrPolyhedron {
530 a: linalg::CsrMatrix {
531 val: val,
532 row: row,
533 col: col
534 },
535 b: lineqs.iter().map(|x| (-1*x.bias) as f64).collect(),
536 variables: variables.iter().map(|x| x.to_variable_float()).collect(),
537 index: lineqs.iter().map(|x| x.id).collect(),
538 };
539 }
540
541 pub fn solve(&self, objectives: Vec<HashMap<u32, f64>>, reduce_polyhedron: bool) -> Vec<(HashMap<u32, i64>, i64, usize)> {
625 let polyhedron: Polyhedron = self.to_ge_polyhedron(true,reduce_polyhedron).to_dense_polyhedron();
626 let _objectives: Vec<Vec<f64>> = objectives.iter().map(|x| {
627 let mut vector = vec![0.0; polyhedron.variables.len()];
628 for (k, v) in x.iter() {
629 let pot_index = polyhedron.variables.iter().position(|y| y.id == (*k));
630 if let Some(index) = pot_index {
631 vector[index] = *v;
632 }
633 }
634 return vector;
635 }).collect();
636 return _objectives.iter().map(|objective| {
637 let ilp = solver::IntegerLinearProgram {
638 ge_ph: polyhedron.to_owned(),
639 eq_ph: Default::default(),
640 of: objective.to_vec(),
641 };
642 return ilp.solve();
643 }).map(|sol| {
644 (
645 polyhedron.variables.clone().iter().map(|x| x.id).zip(sol.x).collect(),
646 sol.z,
647 sol.status_code,
648 )
649 }).collect();
650 }
651
652 pub fn instance(width: u32, depth: u32, id: String) -> Theory {
658
659 let n: u32 = (0..depth).into_iter().map(|i| width.pow(i as u32)).sum();
660 let n_before_leafs: u32 = n - width.pow(depth-1);
661 return Theory {
662 id,
663 statements: (0..n).into_iter().map(|i| {
664 let start_index = i*width+1;
665 match i < n_before_leafs {
666 true => Statement {
667 variable: Variable {
668 id: i,
669 bounds: (0,1)
670 },
671 expression: Some(
672 AtLeast {
673 bias: -1,
674 ids: (start_index..start_index+width).collect_vec(),
675 sign: Sign::Positive,
676 }
677 )
678 },
679 false => Statement {
680 variable: Variable {
681 id: i,
682 bounds: (0,1)
683 },
684 expression: None
685 }
686 }
687 }).collect(),
688 };
689 }
690
691}
692
693#[cfg(test)]
694mod tests {
695 use std::vec;
696
697 use crate::{linalg::Matrix, polyopt::VariableFloat};
698
699 use super::*;
700
701 use std::ops::Range;
702 use itertools::Itertools;
703
704 impl GeLineq {
705
706 fn satisfied(&self, variables: Vec<(u32, i64)>) -> bool{
707 let mut res = 0;
708 for i in 0..variables.len() {
709 for j in 0..self.coeffs.len() {
710 if self.indices[j] == variables[i].0 {
711 res = res + self.coeffs[j]*variables[i].1;
712 }
713 }
714 }
715 return res + self.bias >= 0;
716 }
717 }
718
719 #[test]
720 fn test_theory_propagate() {
721 let theory: Theory = Theory {
722 id : String::from("A"),
723 statements : vec![
724 Statement {
725 variable : Variable {
726 id : 0,
727 bounds : (0,1),
728 },
729 expression : Some(
730 AtLeast {
731 ids : vec![1,2],
732 bias : -1,
733 sign : Sign::Positive
734 }
735 )
736 },
737 Statement {
738 variable : Variable {
739 id : 1,
740 bounds : (0,1),
741 },
742 expression : None
743 },
744 Statement {
745 variable : Variable {
746 id : 2,
747 bounds : (1,1),
748 },
749 expression : None
750 },
751 ]
752 };
753 let actual: HashMap<u32, (i64, i64)> = theory.propagate();
754 let expected: HashMap<u32, (i64, i64)> = vec![
755 (0, (1,1)),
756 (1, (0,1)),
757 (2, (1,1)),
758 ].into_iter().collect();
759 assert_eq!(actual, expected);
760 }
761
762 #[test]
763 fn test_generate_instance_to_polyhedron() {
764 for (w,d) in [(2,2),(2,3),(2,4),(3,3),(3,4),(4,4)] {
765 let theory: Theory = Theory::instance(w, d, String::from("my-id"));
766 let polyhedron: Polyhedron = theory.to_ge_polyhedron(true, false).to_dense_polyhedron();
767 assert_eq!(polyhedron.variables.len(), theory.statements.len()-1);
768 }
769 }
770
771 fn validate_all_combinations(variable_bounds: Vec<(u32, (i64, i64))>, lineqs0: Vec<GeLineq>, lineqs1: Vec<GeLineq>, all_relation: bool) -> bool {
774
775 let base : i64 = 2;
776 let max_combinations: i64 = base.pow(15);
777 let bound_ranges: Vec<std::ops::Range<i64>> = variable_bounds.iter().map(|x| Range {start: x.1.0, end: x.1.1+1}).collect_vec();
778 let n_combinations : i64 = variable_bounds.iter().map(|x| (x.1.1+1)-x.1.0).product();
779 if n_combinations > max_combinations {
780 panic!("number of combinations ({n_combinations}) to test are more than allowed ({max_combinations})");
781 }
782
783 return bound_ranges.into_iter().multi_cartesian_product().all(|combination| {
784 let variable_ids : Vec<u32> = variable_bounds.iter().map(|x| x.0).collect_vec();
785 let variable_combination: Vec<(u32, i64)> = variable_ids.into_iter().zip(combination).collect();
786
787 let res0: bool;
788 let res1: bool;
789 if all_relation {
790 res0 = lineqs0.iter().all(|x| x.satisfied(variable_combination.clone()));
791 res1 = lineqs1.iter().all(|x| x.satisfied(variable_combination.clone()));
792 } else {
793 res0 = lineqs0.iter().any(|x| x.satisfied(variable_combination.clone()));
794 res1 = lineqs1.iter().any(|x| x.satisfied(variable_combination.clone()));
795 }
796 return (res0 & res1) | !(res0 & res1);
797 })
798 }
799
800 #[test]
801 fn test_theory_to_lineqs_reduced() {
802
803 fn validate(t: Theory) -> bool {
804 let non_reduced: Vec<GeLineq> = t.to_lineqs(true, false);
805 let reduced: Vec<GeLineq> = t.to_lineqs(true, true);
806 let variable_bounds: Vec<(u32, (i64, i64))> = t.statements.into_iter().map(|x| (x.variable.id, x.variable.bounds)).collect();
807 return validate_all_combinations(variable_bounds, non_reduced, reduced, true)
808 }
809
810 let t = Theory {
818 id: String::from("A"),
819 statements: vec![
820 Statement {
821 variable: Variable { id: 0, bounds: (0,1) },
822 expression: Some(
823 AtLeast {
824 ids: vec![1,2],
825 bias: -2,
826 sign: Sign::Positive,
827 }
828 )
829 },
830 Statement {
831 variable: Variable { id: 1, bounds: (0,1) },
832 expression: Some(
833 AtLeast {
834 ids: vec![3,4],
835 bias: -6,
836 sign: Sign::Positive,
837 }
838 )
839 },
840 Statement {
841 variable: Variable { id: 2, bounds: (0,1) },
842 expression: Some(
843 AtLeast {
844 ids: vec![5,6],
845 bias: -4,
846 sign: Sign::Positive,
847 }
848 )
849 },
850 Statement {
851 variable: Variable { id: 3, bounds: (-5,5) },
852 expression: None
853 },
854 Statement {
855 variable: Variable { id: 4, bounds: (0,1) },
856 expression: None
857 },
858 Statement {
859 variable: Variable { id: 5, bounds: (-3,3) },
860 expression: None
861 },
862 Statement {
863 variable: Variable { id: 6, bounds: (0,1) },
864 expression: None
865 },
866 ]
867 };
868 assert!(validate(t));
869
870 let t = Theory {
890 id: String::from("A"),
891 statements: vec![
892 Statement {
893 variable: Variable { id: 0, bounds: (0,1) },
894 expression: Some(
895 AtLeast {
896 ids: vec![1,2,3],
897 bias: -3,
898 sign: Sign::Positive,
899 }
900 )
901 },
902 Statement {
903 variable: Variable { id: 1, bounds: (0,1) },
904 expression: Some(
905 AtLeast {
906 ids: vec![4,5],
907 bias: -1,
908 sign: Sign::Positive,
909 }
910 )
911 },
912 Statement {
913 variable: Variable { id: 2, bounds: (0,1) },
914 expression: Some(
915 AtLeast {
916 ids: vec![5,6],
917 bias: -1,
918 sign: Sign::Positive,
919 }
920 )
921 },
922 Statement {
923 variable: Variable { id: 3, bounds: (0,1) },
924 expression: Some(
925 AtLeast {
926 ids: vec![7,8],
927 bias: -2,
928 sign: Sign::Positive,
929 }
930 )
931 },
932 Statement {
933 variable: Variable { id: 4, bounds: (0,1) },
934 expression: Some(
935 AtLeast {
936 ids: vec![9,10],
937 bias: -2,
938 sign: Sign::Positive,
939 }
940 )
941 },
942 Statement {
943 variable: Variable { id: 5, bounds: (0,1) },
944 expression: Some(
945 AtLeast {
946 ids: vec![11],
947 bias: 0,
948 sign: Sign::Negative,
949 }
950 )
951 },
952 Statement {
953 variable: Variable { id: 6, bounds: (0,1) },
954 expression: Some(
955 AtLeast {
956 ids: vec![12,13],
957 bias: -1,
958 sign: Sign::Positive,
959 }
960 )
961 },
962 Statement {
963 variable: Variable { id: 7, bounds: (0,1) },
964 expression: None
965 },
966 Statement {
967 variable: Variable { id: 8, bounds: (0,1) },
968 expression: None
969 },
970 Statement {
971 variable: Variable { id: 9, bounds: (0,1) },
972 expression: None
973 },
974 Statement {
975 variable: Variable { id: 10, bounds: (0,1) },
976 expression: None
977 },
978 Statement {
979 variable: Variable { id: 11, bounds: (0,1) },
980 expression: None
981 },
982 Statement {
983 variable: Variable { id: 12, bounds: (0,1) },
984 expression: None
985 },
986 Statement {
987 variable: Variable { id: 13, bounds: (0,1) },
988 expression: None
989 },
990 ]
991 };
992 assert!(validate(t));
993
994 let t = Theory {
1002 id: String::from("A"),
1003 statements: vec![
1004 Statement {
1005 variable: Variable { id: 0, bounds: (0,1) },
1006 expression: Some(
1007 AtLeast {
1008 ids: vec![1,2],
1009 bias: -1,
1010 sign: Sign::Positive,
1011 }
1012 )
1013 },
1014 Statement {
1015 variable: Variable { id: 1, bounds: (0,1) },
1016 expression: Some(
1017 AtLeast {
1018 ids: vec![3,4],
1019 bias: 1,
1020 sign: Sign::Negative,
1021 }
1022 )
1023 },
1024 Statement {
1025 variable: Variable { id: 2, bounds: (0,1) },
1026 expression: Some(
1027 AtLeast {
1028 ids: vec![5,6,7],
1029 bias: -3,
1030 sign: Sign::Positive,
1031 }
1032 )
1033 },
1034 Statement {
1035 variable: Variable { id: 3, bounds: (0,1) },
1036 expression: None
1037 },
1038 Statement {
1039 variable: Variable { id: 4, bounds: (0,1) },
1040 expression: None
1041 },
1042 Statement {
1043 variable: Variable { id: 5, bounds: (0,1) },
1044 expression: None
1045 },
1046 Statement {
1047 variable: Variable { id: 6, bounds: (0,1) },
1048 expression: None
1049 },
1050 Statement {
1051 variable: Variable { id: 7, bounds: (0,1) },
1052 expression: None
1053 },
1054 ]
1055 };
1056 assert!(validate(t));
1057
1058 let t = Theory {
1066 id: String::from("A"),
1067 statements: vec![
1068 Statement {
1069 variable: Variable { id: 0, bounds: (0,1) },
1070 expression: Some(
1071 AtLeast {
1072 ids: vec![1,2],
1073 bias: -2,
1074 sign: Sign::Positive,
1075 }
1076 )
1077 },
1078 Statement {
1079 variable: Variable { id: 1, bounds: (0,1) },
1080 expression: Some(
1081 AtLeast {
1082 ids: vec![3,4],
1083 bias: 0,
1084 sign: Sign::Negative,
1085 }
1086 )
1087 },
1088 Statement {
1089 variable: Variable { id: 2, bounds: (0,1) },
1090 expression: Some(
1091 AtLeast {
1092 ids: vec![5,6,7],
1093 bias: -3,
1094 sign: Sign::Positive,
1095 }
1096 )
1097 },
1098 Statement {
1099 variable: Variable { id: 3, bounds: (0,1) },
1100 expression: None
1101 },
1102 Statement {
1103 variable: Variable { id: 4, bounds: (0,1) },
1104 expression: None
1105 },
1106 Statement {
1107 variable: Variable { id: 5, bounds: (0,1) },
1108 expression: None
1109 },
1110 Statement {
1111 variable: Variable { id: 6, bounds: (0,1) },
1112 expression: None
1113 },
1114 Statement {
1115 variable: Variable { id: 7, bounds: (0,1) },
1116 expression: None
1117 },
1118 ]
1119 };
1120 assert!(validate(t));
1121
1122 let t = Theory {
1141 id: String::from("A"),
1142 statements: vec![
1143 Statement {
1144 variable: Variable { id: 0, bounds: (0,1) },
1145 expression: Some(
1146 AtLeast {
1147 ids: vec![1,2],
1148 bias: -2,
1149 sign: Sign::Positive,
1150 }
1151 )
1152 },
1153 Statement {
1154 variable: Variable { id: 1, bounds: (0,1) },
1155 expression: Some(
1156 AtLeast {
1157 ids: vec![3,4],
1158 bias: -2,
1159 sign: Sign::Positive,
1160 }
1161 )
1162 },
1163 Statement {
1164 variable: Variable { id: 2, bounds: (0,1) },
1165 expression: Some(
1166 AtLeast {
1167 ids: vec![5,6],
1168 bias: -1,
1169 sign: Sign::Positive,
1170 }
1171 )
1172 },
1173 Statement {
1174 variable: Variable { id: 3, bounds: (0,1) },
1175 expression: Some(
1176 AtLeast {
1177 ids: vec![7,8],
1178 bias: -1,
1179 sign: Sign::Positive,
1180 }
1181 )
1182 },
1183 Statement {
1184 variable: Variable { id: 4, bounds: (0,1) },
1185 expression: Some(
1186 AtLeast {
1187 ids: vec![9,10],
1188 bias: -1,
1189 sign: Sign::Positive,
1190 }
1191 )
1192 },
1193 Statement {
1194 variable: Variable { id: 5, bounds: (0,1) },
1195 expression: Some(
1196 AtLeast {
1197 ids: vec![11],
1198 bias: 0,
1199 sign: Sign::Negative,
1200 }
1201 )
1202 },
1203 Statement {
1204 variable: Variable { id: 6, bounds: (0,1) },
1205 expression: Some(
1206 AtLeast {
1207 ids: vec![12,13],
1208 bias: -2,
1209 sign: Sign::Positive,
1210 }
1211 )
1212 },
1213 Statement {
1214 variable: Variable { id: 7, bounds: (0,1) },
1215 expression: None
1216 },
1217 Statement {
1218 variable: Variable { id: 8, bounds: (0,1) },
1219 expression: None
1220 },
1221 Statement {
1222 variable: Variable { id: 9, bounds: (0,1) },
1223 expression: None
1224 },
1225 Statement {
1226 variable: Variable { id: 10, bounds: (0,1) },
1227 expression: None
1228 },
1229 Statement {
1230 variable: Variable { id: 11, bounds: (0,1) },
1231 expression: None
1232 },
1233 Statement {
1234 variable: Variable { id: 12, bounds: (0,1) },
1235 expression: None
1236 },
1237 Statement {
1238 variable: Variable { id: 13, bounds: (0,1) },
1239 expression: None
1240 },
1241 ]
1242 };
1243 assert!(validate(t));
1244 }
1245
1246 #[test]
1247 fn test_merge_conj_disj(){
1248
1249 fn validate_all_combinations_single(ge_lineq1: GeLineq, ge_lineq2: GeLineq, conj: bool) -> bool {
1250 let mut variable_bounds_hm: HashMap<u32, (i64,i64)> = HashMap::default();
1251 for lineq in vec![ge_lineq1.clone(), ge_lineq2.clone()] {
1252 for (id, bound) in lineq.indices.iter().zip(lineq.bounds) {
1253 variable_bounds_hm.insert(*id, bound);
1254 }
1255 }
1256 let variable_bounds = variable_bounds_hm.into_iter().collect();
1257 if conj {
1258 if let Some(merged) = GeLineq::merge_conj(&ge_lineq1, &ge_lineq2) {
1259 return validate_all_combinations(
1260 variable_bounds,
1261 vec![ge_lineq1, ge_lineq2],
1262 vec![merged],
1263 true
1264 );
1265 }
1266 return false;
1267 } else {
1268 if let Some(merged) = GeLineq::merge_disj(&ge_lineq1, &ge_lineq2) {
1269 return validate_all_combinations(
1270 variable_bounds,
1271 vec![ge_lineq1, ge_lineq2],
1272 vec![merged],
1273 false
1274 );
1275 }
1276 return false;
1277 }
1278 }
1279
1280 let ge_lineq1:GeLineq = GeLineq {
1282 id: None,
1283 coeffs : vec![1, 1, 1],
1284 bounds : vec![(0, 1), (0, 1), (0, 1)],
1285 bias : -1,
1286 indices : vec![1, 2, 3]
1287 };
1288 let ge_lineq2: GeLineq = GeLineq {
1289 id: None,
1290 coeffs : vec![1, 1],
1291 bounds : vec![(0, 1), (0, 1)],
1292 bias : -1,
1293 indices : vec![1, 6]
1294 };
1295 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1296
1297 let ge_lineq1:GeLineq = GeLineq {
1300 id: None,
1301 coeffs : vec![-1, -1, -1],
1302 bounds : vec![(0, 1), (0, 1), (0, 1)],
1303 bias : 2,
1304 indices : vec![1, 2, 3]
1305 };
1306 let ge_lineq2: GeLineq = GeLineq {
1307 id: None,
1308 coeffs : vec![-1, -1, -1, -1],
1309 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1310 bias : 0,
1311 indices : vec![1, 2, 3, 8]
1312 };
1313 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1314
1315 let ge_lineq1:GeLineq = GeLineq {
1317 id: None,
1318 coeffs : vec![1, 1, 1],
1319 bounds : vec![(0, 1), (0, 1), (0, 1)],
1320 bias : -1,
1321 indices : vec![1, 2, 3]
1322 };
1323 let ge_lineq2: GeLineq = GeLineq {
1324 id: None,
1325 coeffs : vec![1, 1],
1326 bounds : vec![(0, 1), (0, 1)],
1327 bias : 0,
1328 indices : vec![5, 6]
1329 };
1330 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1331
1332 let ge_lineq1:GeLineq = GeLineq {
1334 id: None,
1335 coeffs : vec![1, 1, 1],
1336 bounds : vec![(0, 1), (0, 1), (0, 1)],
1337 bias : -1,
1338 indices : vec![1, 2, 3]
1339 };
1340 let ge_lineq2: GeLineq = GeLineq {
1341 id: None,
1342 coeffs : vec![-1, -1, -1, -1],
1343 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1344 bias : 3,
1345 indices : vec![5, 6, 7, 8]
1346 };
1347 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1348
1349 let ge_lineq1:GeLineq = GeLineq {
1351 id: None,
1352 coeffs : vec![1, 1, 1],
1353 bounds : vec![(0, 1), (0, 1), (0, 1)],
1354 bias : -1,
1355 indices : vec![1, 2, 3]
1356 };
1357 let ge_lineq2: GeLineq = GeLineq {
1358 id: None,
1359 coeffs : vec![-1, -1, -1, -1],
1360 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1361 bias : 0,
1362 indices : vec![5, 6, 7, 8]
1363 };
1364 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1365
1366 let ge_lineq1:GeLineq = GeLineq {
1368 id: None,
1369 coeffs : vec![1, 1, 1],
1370 bounds : vec![(0, 1), (0, 1), (0, 1)],
1371 bias : -1,
1372 indices : vec![1, 2, 3]
1373 };
1374 let ge_lineq2: GeLineq = GeLineq {
1375 id: None,
1376 coeffs : vec![1, 1, 1, 1],
1377 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1378 bias : -4,
1379 indices : vec![5, 6, 7, 8]
1380 };
1381 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1382
1383 let ge_lineq1:GeLineq = GeLineq {
1385 id: None,
1386 coeffs : vec![1, 1, 1],
1387 bounds : vec![(0, 1), (0, 1), (0, 1)],
1388 bias : -1,
1389 indices : vec![1, 2, 3]
1390 };
1391 let ge_lineq2: GeLineq = GeLineq {
1392 id: None,
1393 coeffs : vec![1, 1, 1, 1],
1394 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1395 bias : -2,
1396 indices : vec![5, 6, 7, 8]
1397 };
1398 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1399
1400 let ge_lineq1:GeLineq = GeLineq {
1402 id: None,
1403 coeffs : vec![1, 1, 1],
1404 bounds : vec![(0, 1), (0, 1), (0, 1)],
1405 bias : -1,
1406 indices : vec![1, 2, 3]
1407 };
1408 let ge_lineq2: GeLineq = GeLineq {
1409 id: None,
1410 coeffs : vec![-1, -1, -1, -1],
1411 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1412 bias : 2,
1413 indices : vec![5, 6, 7, 8]
1414 };
1415 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1416
1417 let ge_lineq1:GeLineq = GeLineq {
1419 id: None,
1420 coeffs : vec![-1, -1, -1],
1421 bounds : vec![(0, 1), (0, 1), (0, 1)],
1422 bias : 2,
1423 indices : vec![1, 2, 3]
1424 };
1425 let ge_lineq2: GeLineq = GeLineq {
1426 id: None,
1427 coeffs : vec![-1, -1, -1, -1],
1428 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1429 bias : 3,
1430 indices : vec![5, 6, 7, 8]
1431 };
1432 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1433
1434 let ge_lineq1:GeLineq = GeLineq {
1436 id: None,
1437 coeffs : vec![-1, -1, -1],
1438 bounds : vec![(0, 1), (0, 1), (0, 1)],
1439 bias : 2,
1440 indices : vec![1, 2, 3]
1441 };
1442 let ge_lineq2: GeLineq = GeLineq {
1443 id: None,
1444 coeffs : vec![-1, -1, -1, -1],
1445 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1446 bias : 0,
1447 indices : vec![5, 6, 7, 8]
1448 };
1449 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1450
1451 let ge_lineq1:GeLineq = GeLineq {
1453 id: None,
1454 coeffs : vec![-1, -1, -1],
1455 bounds : vec![(0, 1), (0, 1), (0, 1)],
1456 bias : 2,
1457 indices : vec![1, 2, 3]
1458 };
1459 let ge_lineq2: GeLineq = GeLineq {
1460 id: None,
1461 coeffs : vec![1, 1, 1, 1],
1462 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1463 bias : -4,
1464 indices : vec![5, 6, 7, 8]
1465 };
1466 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1467
1468 let ge_lineq1:GeLineq = GeLineq {
1470 id: None,
1471 coeffs : vec![-1, -1, -1],
1472 bounds : vec![(0, 1), (0, 1), (0, 1)],
1473 bias : 2,
1474 indices : vec![1, 2, 3]
1475 };
1476 let ge_lineq2: GeLineq = GeLineq {
1477 id: None,
1478 coeffs : vec![1, 1, 1, 1],
1479 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1480 bias : -2,
1481 indices : vec![5, 6, 7, 8]
1482 };
1483 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1484
1485 let ge_lineq1:GeLineq = GeLineq {
1487 id: None,
1488 coeffs : vec![-1, -1, -1],
1489 bounds : vec![(0, 1), (0, 1), (0, 1)],
1490 bias : 2,
1491 indices : vec![1, 2, 3]
1492 };
1493 let ge_lineq2: GeLineq = GeLineq {
1494 id: None,
1495 coeffs : vec![-1, -1, -1, -1],
1496 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1497 bias : 2,
1498 indices : vec![5, 6, 7, 8]
1499 };
1500 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1501
1502 let ge_lineq1:GeLineq = GeLineq {
1504 id: None,
1505 coeffs : vec![1, 1, 1],
1506 bounds : vec![(0, 1), (0, 1), (0, 1)],
1507 bias : -3,
1508 indices : vec![1, 2, 3]
1509 };
1510 let ge_lineq2: GeLineq = GeLineq {
1511 id: None,
1512 coeffs : vec![1, 1, 1],
1513 bounds : vec![(0, 1), (0, 1), (0, 1)],
1514 bias : -3,
1515 indices : vec![1, 0, 4]
1516 };
1517 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1518
1519 let ge_lineq1:GeLineq = GeLineq {
1521 id: None,
1522 coeffs : vec![1, 1, 1],
1523 bounds : vec![(0, 1), (0, 1), (0, 1)],
1524 bias : -3,
1525 indices : vec![1, 2, 3]
1526 };
1527 let ge_lineq2: GeLineq = GeLineq {
1528 id: None,
1529 coeffs : vec![-1, -1, -1, -1],
1530 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1531 bias : 0,
1532 indices : vec![5, 6, 7, 8]
1533 };
1534 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1535
1536 let ge_lineq1:GeLineq = GeLineq {
1538 id: None,
1539 coeffs : vec![1, 1, 1],
1540 bounds : vec![(0, 1), (0, 1), (0, 1)],
1541 bias : -1,
1542 indices : vec![1, 2, 3]
1543 };
1544 let ge_lineq2: GeLineq = GeLineq {
1545 id: None,
1546 coeffs : vec![1, 1, 1, 1],
1547 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1548 bias : -4,
1549 indices : vec![5, 6, 7, 8]
1550 };
1551 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1552
1553 let ge_lineq1:GeLineq = GeLineq {
1555 id: None,
1556 coeffs : vec![-1, -1, -1],
1557 bounds : vec![(0, 1), (0, 1), (0, 1)],
1558 bias : 2,
1559 indices : vec![1, 2, 3]
1560 };
1561 let ge_lineq2: GeLineq = GeLineq {
1562 id: None,
1563 coeffs : vec![-1, -1, -1, -1],
1564 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1565 bias : 0,
1566 indices : vec![5, 6, 7, 8]
1567 };
1568 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1569
1570 let ge_lineq1:GeLineq = GeLineq {
1572 id: None,
1573 coeffs : vec![-1, -1, -1],
1574 bounds : vec![(0, 1), (0, 1), (0, 1)],
1575 bias : 2,
1576 indices : vec![1, 2, 3]
1577 };
1578 let ge_lineq2: GeLineq = GeLineq {
1579 id: None,
1580 coeffs : vec![1, 1, 1, 1],
1581 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1582 bias : -4,
1583 indices : vec![5, 6, 7, 8]
1584 };
1585 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1586
1587 let ge_lineq1:GeLineq = GeLineq {
1589 id: None,
1590 coeffs : vec![-1, -1, -1],
1591 bounds : vec![(0, 1), (0, 1), (0, 1)],
1592 bias : 0,
1593 indices : vec![1, 2, 3]
1594 };
1595 let ge_lineq2: GeLineq = GeLineq {
1596 id: None,
1597 coeffs : vec![-1, -1, -1, -1],
1598 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1599 bias : 0,
1600 indices : vec![5, 6, 7, 8]
1601 };
1602 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1603
1604 let ge_lineq1:GeLineq = GeLineq {
1606 id: None,
1607 coeffs : vec![-1, -1, -1],
1608 bounds : vec![(0, 1), (0, 1), (0, 1)],
1609 bias : 0,
1610 indices : vec![1, 2, 3]
1611 };
1612 let ge_lineq2: GeLineq = GeLineq {
1613 id: None,
1614 coeffs : vec![1, 1, 1, 1],
1615 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1616 bias : -4,
1617 indices : vec![5, 6, 7, 8]
1618 };
1619 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1620
1621 let ge_lineq1:GeLineq = GeLineq {
1623 id: None,
1624 coeffs : vec![-1, -1, -1],
1625 bounds : vec![(0, 1), (0, 1), (0, 1)],
1626 bias : 0,
1627 indices : vec![1, 2, 3]
1628 };
1629 let ge_lineq2: GeLineq = GeLineq {
1630 id: None,
1631 coeffs : vec![1, 1, 1, 1],
1632 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1633 bias : -2,
1634 indices : vec![5, 6, 7, 8]
1635 };
1636 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1637
1638 let ge_lineq1:GeLineq = GeLineq {
1640 id: None,
1641 coeffs : vec![-1, -1, -1],
1642 bounds : vec![(0, 1), (0, 1), (0, 1)],
1643 bias : 0,
1644 indices : vec![1, 2, 3]
1645 };
1646 let ge_lineq2: GeLineq = GeLineq {
1647 id: None,
1648 coeffs : vec![-1, -1, -1, -1],
1649 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1650 bias : 2,
1651 indices : vec![5, 6, 7, 8]
1652 };
1653 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1654
1655 let ge_lineq1:GeLineq = GeLineq {
1657 id: None,
1658 coeffs : vec![1, 1, 1],
1659 bounds : vec![(0, 1), (0, 1), (0, 1)],
1660 bias : -3,
1661 indices : vec![1, 2, 3]
1662 };
1663 let ge_lineq2: GeLineq = GeLineq {
1664 id: None,
1665 coeffs : vec![1, 1, 1, 1],
1666 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1667 bias : -4,
1668 indices : vec![5, 6, 7, 8]
1669 };
1670 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1671
1672 let ge_lineq1:GeLineq = GeLineq {
1674 id: None,
1675 coeffs : vec![1, 1, 1],
1676 bounds : vec![(0, 1), (0, 1), (0, 1)],
1677 bias : -3,
1678 indices : vec![1, 2, 3]
1679 };
1680 let ge_lineq2: GeLineq = GeLineq {
1681 id: None,
1682 coeffs : vec![1, 1, 1, 1],
1683 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1684 bias : -2,
1685 indices : vec![5, 6, 7, 8]
1686 };
1687 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1688
1689 let ge_lineq1:GeLineq = GeLineq {
1691 id: None,
1692 coeffs : vec![1, 1, 1],
1693 bounds : vec![(0, 1), (0, 1), (0, 1)],
1694 bias : -3,
1695 indices : vec![1, 2, 3]
1696 };
1697 let ge_lineq2: GeLineq = GeLineq {
1698 id: None,
1699 coeffs : vec![-1, -1, -1, -1],
1700 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1701 bias : 2,
1702 indices : vec![5, 6, 7, 8]
1703 };
1704 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1705
1706 let ge_lineq1:GeLineq = GeLineq {
1708 id: None,
1709 coeffs : vec![1, 1, 1],
1710 bounds : vec![(0, 1), (0, 1), (0, 1)],
1711 bias : 3,
1712 indices : vec![1, 2, 3]
1713 };
1714 let ge_lineq2: GeLineq = GeLineq {
1715 id: None,
1716 coeffs : vec![1, 1, 1, 1],
1717 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1718 bias : -4,
1719 indices : vec![5, 6, 7, 8]
1720 };
1721 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1722
1723 let ge_lineq1:GeLineq = GeLineq {
1725 id: None,
1726 coeffs : vec![1, 1, 1],
1727 bounds : vec![(-2, -1), (2, 3), (2, 3)],
1728 bias : -3,
1729 indices : vec![1, 2, 3]
1730 };
1731 let ge_lineq2: GeLineq = GeLineq {
1732 id: None,
1733 coeffs : vec![1, 1, 1, 1],
1734 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1735 bias : -1,
1736 indices : vec![5, 6, 7, 8]
1737 };
1738 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, false));
1739
1740 let ge_lineq1:GeLineq = GeLineq {
1742 id: None,
1743 coeffs : vec![1, 1, 1],
1744 bounds : vec![(-2, -1), (2, 3), (2, 3)],
1745 bias : -5,
1746 indices : vec![1, 2, 3]
1747 };
1748 let ge_lineq2: GeLineq = GeLineq {
1749 id: None,
1750 coeffs : vec![1, 1, 1, 1],
1751 bounds : vec![(0, 1), (0, 1), (0, 1), (0, 1)],
1752 bias : -1,
1753 indices : vec![5, 6, 7, 8]
1754 };
1755 assert!(validate_all_combinations_single(ge_lineq1, ge_lineq2, true));
1756 }
1757
1758 #[test]
1759 fn test_substitution() {
1760
1761 fn validate_substitution(main_lineq: GeLineq, sub_lineq: GeLineq, variable_index: u32) -> bool {
1762 if let Some(result) = GeLineq::substitution(&main_lineq, variable_index, &sub_lineq) {
1763 let mut variable_bounds_hm: HashMap<u32, (i64,i64)> = HashMap::default();
1764 for lineq in vec![main_lineq.clone(), sub_lineq.clone()] {
1765 for (id, bound) in lineq.indices.iter().zip(lineq.bounds) {
1766 if (*id) != variable_index {
1767 variable_bounds_hm.insert(*id, bound);
1768 }
1769 }
1770 }
1771 let variable_bounds: Vec<(u32, (i64, i64))> = variable_bounds_hm.into_iter().collect();
1772 let variable_ids : Vec<u32> = variable_bounds.iter().map(|x| x.0).collect_vec();
1773 let bound_ranges: Vec<std::ops::Range<i64>> = variable_bounds.iter().map(|x| Range {start: x.1.0, end: x.1.1+1}).collect_vec();
1774 return bound_ranges.into_iter().multi_cartesian_product().all(|combination| {
1775 let mut main_variable_combination: Vec<(u32, i64)> = variable_ids.clone().into_iter().zip(combination.clone()).filter(|(id, _)| {
1776 main_lineq.indices.contains(id)
1777 }).collect();
1778 let sub_variable_combination: Vec<(u32, i64)> = variable_ids.clone().into_iter().zip(combination.clone()).filter(|(id, _)| {
1779 sub_lineq.indices.contains(id)
1780 }).collect();
1781 let sub_value: i64 = sub_lineq.satisfied(sub_variable_combination) as i64;
1782 main_variable_combination.push((variable_index, sub_value));
1783
1784 let main_result = main_lineq.satisfied(main_variable_combination);
1785 let substitution_result = result.satisfied(variable_ids.clone().into_iter().zip(combination.clone()).collect());
1786
1787 return (!main_result & !substitution_result) | (main_result & substitution_result);
1788 });
1789 }
1790
1791 return false;
1792 }
1793
1794 let main_gelineq:GeLineq = GeLineq {
1796 id: None,
1797 coeffs : vec![1, 1, 1],
1798 bounds : vec![(0, 1), (0, 1), (0, 1)],
1799 bias : -2,
1800 indices : vec![1, 2, 3]
1801 };
1802 let sub_gelineq: GeLineq = GeLineq {
1803 id: None,
1804 coeffs : vec![1, 1],
1805 bounds : vec![(0, 1), (0, 1)],
1806 bias : -2,
1807 indices : vec![4,5]
1808 };
1809 assert!(validate_substitution(main_gelineq, sub_gelineq, 3));
1810
1811 let main_gelineq:GeLineq = GeLineq {
1812 id: None,
1813 coeffs : vec![1, 1, 1],
1814 bounds : vec![(0, 1), (0, 1), (0, 1)],
1815 bias : -2,
1816 indices : vec![1, 2, 3]
1817 };
1818 let sub_gelineq: GeLineq = GeLineq {
1819 id: None,
1820 coeffs : vec![1, 1],
1821 bounds : vec![(0, 1), (0, 1)],
1822 bias : -1,
1823 indices : vec![4,5]
1824 };
1825 assert!(validate_substitution(main_gelineq, sub_gelineq, 3));
1826
1827 let main_gelineq:GeLineq = GeLineq {
1829 id: None,
1830 coeffs : vec![1, 1, 1],
1831 bounds : vec![(0, 1), (0, 1), (0, 1)],
1832 bias : -2,
1833 indices : vec![1, 2, 3]
1834 };
1835 let sub_gelineq: GeLineq = GeLineq {
1836 id: None,
1837 coeffs : vec![-1, -1],
1838 bounds : vec![(0, 1), (0, 1)],
1839 bias : 1,
1840 indices : vec![4,5]
1841 };
1842 assert!(validate_substitution(main_gelineq, sub_gelineq, 3));
1843
1844 let main_gelineq:GeLineq = GeLineq {
1846 id: None,
1847 coeffs : vec![1, 1, 1],
1848 bounds : vec![(0, 1), (0, 1), (0, 1)],
1849 bias : -2,
1850 indices : vec![1, 2, 3]
1851 };
1852 let sub_gelineq: GeLineq = GeLineq {
1853 id: None,
1854 coeffs : vec![-1, 1, 1],
1855 bounds : vec![(0, 1), (0, 1), (0, 1)],
1856 bias : 0,
1857 indices : vec![4,5, 6]
1858 };
1859 assert!(!validate_substitution(main_gelineq, sub_gelineq, 3));
1860
1861 let main_gelineq:GeLineq = GeLineq {
1862 id: None,
1863 coeffs : vec![-1],
1864 bounds : vec![(0, 1)],
1865 bias : 0,
1866 indices : vec![1]
1867 };
1868 let sub_gelineq: GeLineq = GeLineq {
1869 id: None,
1870 coeffs : vec![1],
1871 bounds : vec![(0, 10)],
1872 bias : -3,
1873 indices : vec![2]
1874 };
1875 assert!(validate_substitution(main_gelineq.clone(), sub_gelineq.clone(), 1));
1876 let result = GeLineq::substitution(&main_gelineq, 1, &sub_gelineq);
1877 assert_eq!(vec![-1], result.as_ref().expect("").coeffs);
1878 assert_eq!(vec![(0, 10)], result.as_ref().expect("").bounds);
1879 assert_eq!(2, result.as_ref().expect("").bias);
1880
1881 let main_gelineq:GeLineq = GeLineq {
1883 id: None,
1884 coeffs : vec![1, 1, 1],
1885 bounds : vec![(0, 1), (0, 1), (0, 1)],
1886 bias : -2,
1887 indices : vec![1, 2, 3]
1888 };
1889 let sub_gelineq: GeLineq = GeLineq {
1890 id: None,
1891 coeffs : vec![-1, 1, 1],
1892 bounds : vec![(0, 1), (0, 1), (0, 1)],
1893 bias : -1,
1894 indices : vec![4,5, 6]
1895 };
1896 assert!(validate_substitution(main_gelineq, sub_gelineq, 3));
1897
1898 let main_gelineq:GeLineq = GeLineq {
1899 id: None,
1900 coeffs : vec![1, 1],
1901 bounds : vec![(0, 1), (0, 1)],
1902 bias : -2,
1903 indices : vec![1, 2]
1904 };
1905 let sub_gelineq: GeLineq = GeLineq {
1906 id: None,
1907 coeffs : vec![1, 1],
1908 bounds : vec![(0, 1), (0, 1)],
1909 bias : -1,
1910 indices : vec![3, 4]
1911 };
1912 assert!(validate_substitution(main_gelineq, sub_gelineq, 2));
1913
1914 let main_gelineq:GeLineq = GeLineq {
1915 id: None,
1916 coeffs : vec![1, 1],
1917 bounds : vec![(0, 1), (0, 1)],
1918 bias : -1,
1919 indices : vec![1, 2]
1920 };
1921 let sub_gelineq: GeLineq = GeLineq {
1922 id: None,
1923 coeffs : vec![1, 1],
1924 bounds : vec![(0, 1), (0, 1)],
1925 bias : -1,
1926 indices : vec![3, 4]
1927 };
1928 assert!(validate_substitution(main_gelineq, sub_gelineq, 2));
1929
1930 let main_gelineq:GeLineq = GeLineq {
1931 id: None,
1932 coeffs : vec![1, 1, 1],
1933 bounds : vec![(0, 1), (0, 1), (0, 1)],
1934 bias : -2,
1935 indices : vec![1, 2, 3]
1936 };
1937 let sub_gelineq1: GeLineq = GeLineq {
1938 id: None,
1939 coeffs : vec![1, 1],
1940 bounds : vec![(0, 1), (0, 1)],
1941 bias : -2,
1942 indices : vec![4, 5]
1943 };
1944 let sub_gelineq2: GeLineq = GeLineq {
1945 id: None,
1946 coeffs : vec![1, 1],
1947 bounds : vec![(0, 1), (0, 1)],
1948 bias : -2,
1949 indices : vec![6, 7]
1950 };
1951 let result1 = GeLineq::substitution(&main_gelineq, 2, &sub_gelineq1);
1952 assert!(validate_substitution(main_gelineq, sub_gelineq1, 2));
1953 let result2 = GeLineq::substitution(&result1.as_ref().expect("No gelineq created"), 3, &sub_gelineq2);
1954 assert!(result2.is_none());
1955 }
1956
1957 #[test]
1958 fn test_min_max_coefficients() {
1959
1960 fn validate_all_combinations_single_min_max(gelineq: GeLineq, expected_vec: Option<Vec<i64>>) -> bool {
1961 let mut variable_bounds_hm: HashMap<u32, (i64,i64)> = HashMap::default();
1962 for (id, bound) in gelineq.indices.iter().zip(gelineq.bounds.clone()) {
1963 variable_bounds_hm.insert(*id, bound);
1964 }
1965 let variable_bounds = variable_bounds_hm.into_iter().collect();
1966 if let Some(result) = GeLineq::min_max_coefficients(&gelineq) {
1967 let validation = validate_all_combinations(
1968 variable_bounds,
1969 vec![gelineq],
1970 vec![result.clone()],
1971 true
1972 );
1973 if let Some(vec) = expected_vec {
1974 return validation & (vec == result.coeffs)
1975 }
1976 return validation;
1977 }
1978 return false;
1979 }
1980
1981 assert!(
1982 validate_all_combinations_single_min_max(
1983 GeLineq {
1984 id: None,
1985 coeffs: vec![2, 1, 1],
1986 bounds: vec![(0,1),(0,1),(0,1)],
1987 bias: -1,
1988 indices: vec![0, 1, 2]
1989 },
1990 Some(vec![1, 1, 1])
1991 )
1992 );
1993 assert!(
1994 !validate_all_combinations_single_min_max(
1995 GeLineq {
1996 id: None,
1997 coeffs: vec![2, 1, 1],
1998 bounds: vec![(-2,-1),(0,1),(0,1)],
1999 bias: 0,
2000 indices: vec![0, 1, 2]
2001 },
2002 None
2003 )
2004 );
2005 assert!(
2006 validate_all_combinations_single_min_max(
2007 GeLineq {
2008 id: None,
2009 coeffs: vec![5, 6, 3],
2010 bounds: vec![(0,1),(0,1),(0,1)],
2011 bias: -1,
2012 indices: vec![0, 1, 2]
2013 },
2014 Some(vec![1, 1, 1])
2015 )
2016 );
2017 assert!(
2018 validate_all_combinations_single_min_max(
2019 GeLineq {
2020 id: None,
2021 coeffs: vec![-2, -1, -1],
2022 bounds: vec![(0,1),(0,1),(0,1)],
2023 bias: 0,
2024 indices: vec![0, 1, 2]
2025 },
2026 Some(vec![-1, -1, -1]),
2027 )
2028 );
2029 assert!(
2030 validate_all_combinations_single_min_max(
2031 GeLineq {
2032 id: None,
2033 coeffs: vec![-2, -1, -1],
2034 bounds: vec![(0,1),(0,1),(0,1)],
2035 bias: 1,
2036 indices: vec![0, 1, 2]
2037 },
2038 Some(vec![-2,-1,-1]),
2039 )
2040 );
2041 assert!(
2042 !validate_all_combinations_single_min_max(
2043 GeLineq {
2044 id: None,
2045 coeffs: vec![-2, 1, 1],
2046 bounds: vec![(0,1),(0,1),(0,1)],
2047 bias: 0,
2048 indices: vec![0, 1, 2]
2049 },
2050 None
2051 )
2052 );
2053 }
2054
2055 #[test]
2056 fn test_theory_top_ok() {
2057 let t = Theory {
2058 id: String::from("A"),
2059 statements: vec![
2060 Statement {
2061 variable: Variable { id: 0, bounds: (0,1) },
2062 expression: Some(
2063 AtLeast {
2064 ids: vec![1,2],
2065 bias: -1,
2066 sign: Sign::Positive,
2067 }
2068 )
2069 },
2070 Statement {
2071 variable: Variable { id: 1, bounds: (0,1) },
2072 expression: Some(
2073 AtLeast {
2074 ids: vec![3,4],
2075 bias: 1,
2076 sign: Sign::Negative,
2077 }
2078 )
2079 },
2080 Statement {
2081 variable: Variable { id: 2, bounds: (0,1) },
2082 expression: Some(
2083 AtLeast {
2084 ids: vec![5,6,7],
2085 bias: -3,
2086 sign: Sign::Positive,
2087 }
2088 )
2089 },
2090 ]
2091 };
2092 assert_eq!(*t._top(), 0);
2093 }
2094
2095 #[test]
2096 #[should_panic]
2097 fn test_theory_top_has_circular_references() {
2098 let t = Theory {
2099 id: String::from("A"),
2100 statements: vec![
2101 Statement {
2102 variable: Variable { id: 0, bounds: (0,1) },
2103 expression: Some(
2104 AtLeast {
2105 ids: vec![1],
2106 bias: -1,
2107 sign: Sign::Positive,
2108 }
2109 )
2110 },
2111 Statement {
2112 variable: Variable { id: 1, bounds: (0,1) },
2113 expression: Some(
2114 AtLeast {
2115 ids: vec![2],
2116 bias: 1,
2117 sign: Sign::Negative,
2118 }
2119 )
2120 },
2121 Statement {
2122 variable: Variable { id: 2, bounds: (0,1) },
2123 expression: Some(
2124 AtLeast {
2125 ids: vec![0],
2126 bias: -3,
2127 sign: Sign::Positive,
2128 }
2129 )
2130 },
2131 ]
2132 };
2133 t._top();
2134 }
2135
2136 #[test]
2137 fn test_theory_top_should_not_panic() {
2138 let t = Theory {
2139 id: String::from("A"),
2140 statements: vec![
2141 Statement {
2142 variable: Variable { id: 2, bounds: (0,1) },
2143 expression: None
2144 },
2145 Statement {
2146 variable: Variable { id: 1, bounds: (0,1) },
2147 expression: Some(
2148 AtLeast {
2149 ids: vec![2],
2150 bias: 1,
2151 sign: Sign::Negative,
2152 }
2153 )
2154 },
2155 Statement {
2156 variable: Variable { id: 0, bounds: (0,1) },
2157 expression: Some(
2158 AtLeast {
2159 ids: vec![1],
2160 bias: -3,
2161 sign: Sign::Positive,
2162 }
2163 )
2164 },
2165 ]
2166 };
2167 t._top();
2168 }
2169
2170 #[test]
2171 fn test_theory_variable_hm_should_be_correct() {
2172 let t = Theory {
2173 id: String::from("A"),
2174 statements: vec![
2175 Statement {
2176 variable: Variable { id: 0, bounds: (0,1) },
2177 expression: Some(
2178 AtLeast {
2179 ids: vec![1,2],
2180 bias: -1,
2181 sign: Sign::Positive,
2182 }
2183 )
2184 },
2185 Statement {
2186 variable: Variable { id: 1, bounds: (0,1) },
2187 expression: Some(
2188 AtLeast {
2189 ids: vec![3,4],
2190 bias: 1,
2191 sign: Sign::Negative,
2192 }
2193 )
2194 },
2195 Statement {
2196 variable: Variable { id: 2, bounds: (0,1) },
2197 expression: Some(
2198 AtLeast {
2199 ids: vec![5,6,7],
2200 bias: -3,
2201 sign: Sign::Positive,
2202 }
2203 )
2204 },
2205 Statement {
2206 variable: Variable { id: 3, bounds: (0,1) },
2207 expression: None
2208 },
2209 Statement {
2210 variable: Variable { id: 4, bounds: (0,1) },
2211 expression: None
2212 },
2213 Statement {
2214 variable: Variable { id: 5, bounds: (0,1) },
2215 expression: None
2216 },
2217 Statement {
2218 variable: Variable { id: 6, bounds: (0,1) },
2219 expression: None
2220 },
2221 Statement {
2222 variable: Variable { id: 7, bounds: (0,1) },
2223 expression: None
2224 },
2225 ]
2226 };
2227 let vm = t._variable_hm();
2228 let expected_keys : Vec<u32> = vec![0,1,2,3,4,5,6,7];
2229 let test_result = expected_keys.iter().map(|k| vm.contains_key(k)).all(|k| k);
2230 assert!(test_result);
2231 }
2232
2233 #[test]
2234 fn test_theory_variable_hm_have_id_duplicates() {
2235 let t = Theory {
2236 id: String::from("A"),
2237 statements: vec![
2238 Statement {
2239 variable: Variable { id: 0, bounds: (0,1) },
2240 expression: Some(
2241 AtLeast {
2242 ids: vec![1,2],
2243 bias: -1,
2244 sign: Sign::Positive,
2245 }
2246 )
2247 },
2248 Statement {
2249 variable: Variable { id: 1, bounds: (0,1) },
2250 expression: None
2251 },
2252 Statement {
2253 variable: Variable { id: 2, bounds: (0,1) },
2254 expression: None
2255 },
2256 Statement {
2257 variable: Variable { id: 0, bounds: (0,1) },
2258 expression: None
2259 },
2260 ]
2261 };
2262 let vm = t._variable_hm();
2263 let expected_keys : Vec<u32> = vec![0,1,2];
2264 let test_result = expected_keys.iter().map(|k| vm.contains_key(k)).all(|k| k);
2265 assert!(test_result);
2266 }
2267
2268 #[test]
2269 fn test_theory_to_lineqs() {
2270
2271 fn validate_theory_lineqs(t: Theory, actual: Vec<GeLineq>, expected: Vec<GeLineq>) -> bool {
2272 assert!(actual.iter().zip(expected.clone()).all(|(a,b)| {
2273 let bias_eq = a.bias == b.bias;
2274 let indices_eq = a.indices == b.indices;
2275 let coeffs_eq = a.coeffs == b.coeffs;
2276 let bounds_eq = a.bounds == b.bounds;
2277 bias_eq & indices_eq & coeffs_eq & bounds_eq
2278 }));
2279 return validate_all_combinations(
2280 t.statements.into_iter().map(|x| (x.variable.id, x.variable.bounds)).collect(),
2281 actual,
2282 expected,
2283 true
2284 )
2285 }
2286
2287 let t = Theory {
2288 id: String::from("A"),
2289 statements: vec![
2290 Statement {
2291 variable: Variable { id: 0, bounds: (0,1) },
2292 expression: Some(
2293 AtLeast {
2294 ids: vec![1,2],
2295 bias: -1,
2296 sign: Sign::Positive,
2297 }
2298 )
2299 },
2300 Statement {
2301 variable: Variable { id: 1, bounds: (0,1) },
2302 expression: Some(
2303 AtLeast {
2304 ids: vec![3,4],
2305 bias: 1,
2306 sign: Sign::Negative,
2307 }
2308 )
2309 },
2310 Statement {
2311 variable: Variable { id: 2, bounds: (0,1) },
2312 expression: Some(
2313 AtLeast {
2314 ids: vec![5,6,7],
2315 bias: -3,
2316 sign: Sign::Positive,
2317 }
2318 )
2319 },
2320 Statement {
2321 variable: Variable { id: 3, bounds: (0,1) },
2322 expression: None
2323 },
2324 Statement {
2325 variable: Variable { id: 4, bounds: (0,1) },
2326 expression: None
2327 },
2328 Statement {
2329 variable: Variable { id: 5, bounds: (0,1) },
2330 expression: None
2331 },
2332 Statement {
2333 variable: Variable { id: 6, bounds: (0,1) },
2334 expression: None
2335 },
2336 Statement {
2337 variable: Variable { id: 7, bounds: (0,1) },
2338 expression: None
2339 },
2340 ]
2341 };
2342 let actual: Vec<GeLineq> = t.to_lineqs(false, false);
2343 let expected: Vec<GeLineq> = vec![
2344 GeLineq {
2345 id: None,
2346 bias: 0,
2347 bounds: vec![(0,1),(0,1),(0,1)],
2348 coeffs: vec![-1,1,1],
2349 indices: vec![0,1,2]
2350 },
2351 GeLineq {
2352 id: None,
2353 bias: 0,
2354 bounds: vec![(0,1),(0,1),(0,1),(0,1)],
2355 coeffs: vec![-3,1,1,1],
2356 indices: vec![2,5,6,7]
2357 },
2358 GeLineq {
2359 id: None,
2360 bias: 2,
2361 bounds: vec![(0,1),(0,1),(0,1)],
2362 coeffs: vec![-1,-1,-1],
2363 indices: vec![1,3,4]
2364 },
2365 ];
2366 assert!(validate_theory_lineqs(t.clone(), actual, expected));
2367 let actual: Vec<GeLineq> = t.to_lineqs(true, false);
2368 let expected: Vec<GeLineq> = vec![
2369 GeLineq {
2370 id: None,
2371 bias: -1,
2372 bounds: vec![(0,1),(0,1)],
2373 coeffs: vec![1,1],
2374 indices: vec![1,2]
2375 },
2376 GeLineq {
2377 id: None,
2378 bias: 0,
2379 bounds: vec![(0,1),(0,1),(0,1),(0,1)],
2380 coeffs: vec![-3,1,1,1],
2381 indices: vec![2,5,6,7]
2382 },
2383 GeLineq {
2384 id: None,
2385 bias: 2,
2386 bounds: vec![(0,1),(0,1),(0,1)],
2387 coeffs: vec![-1,-1,-1],
2388 indices: vec![1,3,4]
2389 },
2390 ];
2391 assert!(validate_theory_lineqs(t.clone(), actual, expected));
2392 let actual: Vec<GeLineq> = t.to_lineqs(false, true); let expected: Vec<GeLineq> = vec![
2394 GeLineq {
2395 id: None,
2396 bias: 3,
2397 bounds: vec![(0,1),(0,1),(0,1),(0,1),(0,1)],
2398 coeffs: vec![-3,-3,1,1,1],
2399 indices: vec![3,4,5,6,7]
2400 },
2401 ];
2402 assert!(validate_theory_lineqs(t.clone(), actual, expected));
2403 let actual: Vec<GeLineq> = t.to_lineqs(true, true); let expected: Vec<GeLineq> = vec![
2405 GeLineq {
2406 id: None,
2407 bias: 3,
2408 bounds: vec![(0,1),(0,1),(0,1),(0,1),(0,1)],
2409 coeffs: vec![-3,-3,1,1,1],
2410 indices: vec![3,4,5,6,7]
2411 },
2412 ];
2413 assert!(validate_theory_lineqs(t.clone(), actual, expected));
2414 }
2415 #[test]
2416 fn test_solver(){
2417 let obj = vec![3.0, 1.0, -1.0, -1.0, 1.0];
2418 let ilp = solver::IntegerLinearProgram {
2419 ge_ph: Polyhedron {
2420 a: linalg::Matrix {
2421 val: vec![-3.0, -3.0, 1.0, 1.0, 1.0],
2422 ncols: 5,
2423 nrows: 1
2424 },
2425 b: vec![-3.0],
2426 variables: vec![
2427 VariableFloat {id: 3, bounds: (0.0, 1.0) },
2428 VariableFloat {id: 4, bounds: (0.0, 1.0) },
2429 VariableFloat {id: 5, bounds: (0.0, 1.0) },
2430 VariableFloat {id: 6, bounds: (0.0, 1.0) },
2431 VariableFloat {id: 7, bounds: (0.0, 1.0) }
2432 ],
2433 index: (0..1).map(|x| Some(x as u32)).collect(),
2434 },
2435 eq_ph: Default::default(),
2436 of: obj.to_vec(),
2437 };
2438 let actual_solution = ilp.solve();
2439 let expected_solution_x = vec![1,0,0,0,1];
2440 assert_eq!(actual_solution.x, expected_solution_x);
2441 assert_eq!(actual_solution.z, 4);
2442 }
2443
2444 #[test]
2445 fn test_theory_to_ge_polyhedron() {
2446
2447 fn validate(actual: Polyhedron, expected: Polyhedron) -> bool {
2448 if actual.variables != expected.variables {
2449 return false;
2450 }
2451
2452 let variable_bounds: Vec<(f64, f64)> = actual.bounds();
2453 let base : i64 = 2;
2454 let max_combinations: i64 = base.pow(15);
2455 let bound_ranges: Vec<std::ops::Range<i64>> = variable_bounds.iter().map(|x| Range {start: (x.0 as i64), end: (x.1 as i64)+1}).collect_vec();
2456 let n_combinations : i64 = variable_bounds.iter().map(|x| ((x.1 as i64)+1)-(x.0 as i64)).product();
2457 if n_combinations > max_combinations {
2458 panic!("number of combinations ({n_combinations}) to test are more than allowed ({max_combinations})");
2459 }
2460
2461 let combinations: Vec<Vec<i64>> = bound_ranges.clone().into_iter().multi_cartesian_product().collect();
2462 let combination_matrix: Matrix = Matrix {
2463 val: combinations.clone().into_iter().concat().iter().map(|x| (*x) as f64).collect(),
2464 ncols: bound_ranges.len(),
2465 nrows: combinations.len(),
2466 };
2467
2468 let actual_dot: Matrix = actual.a.dot(&combination_matrix.transpose());
2469 let actual_dot_cmp: Vec<bool> = actual_dot.val.chunks(actual_dot.nrows).map(|x| {
2470 x.iter().zip(actual.b.clone()).map(|(v0,v1)| (*v0) >= v1).collect()
2471 }).concat();
2472 let expected_dot: Matrix = expected.a.dot(&combination_matrix.transpose());
2473 let expected_dot_cmp: Vec<bool> = expected_dot.val.chunks(expected_dot.nrows).map(|x| {
2474 x.iter().zip(expected.b.clone()).map(|(v0,v1)| (*v0) >= v1).collect()
2475 }).concat();
2476
2477 return actual_dot_cmp == expected_dot_cmp;
2478 }
2479
2480 let t = Theory {
2490 id: String::from("A"),
2491 statements: vec![
2492 Statement {
2493 variable: Variable { id: 0, bounds: (0,1) },
2494 expression: Some(
2495 AtLeast {
2496 ids: vec![1,2],
2497 bias: -2,
2498 sign: Sign::Positive,
2499 }
2500 )
2501 },
2502 Statement {
2503 variable: Variable { id: 1, bounds: (0,1) },
2504 expression: Some(
2505 AtLeast {
2506 ids: vec![3,4],
2507 bias: -6,
2508 sign: Sign::Positive,
2509 }
2510 )
2511 },
2512 Statement {
2513 variable: Variable { id: 2, bounds: (0,1) },
2514 expression: Some(
2515 AtLeast {
2516 ids: vec![5,6],
2517 bias: -4,
2518 sign: Sign::Positive,
2519 }
2520 )
2521 },
2522 Statement {
2523 variable: Variable { id: 3, bounds: (-5,5) },
2524 expression: None
2525 },
2526 Statement {
2527 variable: Variable { id: 4, bounds: (0,1) },
2528 expression: None
2529 },
2530 Statement {
2531 variable: Variable { id: 5, bounds: (-3,3) },
2532 expression: None
2533 },
2534 Statement {
2535 variable: Variable { id: 6, bounds: (0,1) },
2536 expression: None
2537 },
2538 ]
2539 };
2540
2541 let expected: Polyhedron = Polyhedron {
2542 a: linalg::Matrix {
2543 val: vec![1.0, 1.0, 1.0, 1.0],
2544 ncols: 4,
2545 nrows: 1
2546 },
2547 b: vec![10.0],
2548 variables: vec![
2549 VariableFloat {
2550 id: 3,
2551 bounds: (-5.0, 5.0),
2552 },
2553 VariableFloat {
2554 id: 4,
2555 bounds: (0.0, 1.0),
2556 },
2557 VariableFloat {
2558 id: 5,
2559 bounds: (-3.0, 3.0),
2560 },
2561 VariableFloat {
2562 id: 6,
2563 bounds: (0.0, 1.0),
2564 },
2565 ],
2566 index: (0..1).map(|x| Some(x as u32)).collect(),
2567 };
2568 assert!(validate(t.to_ge_polyhedron(true, true).to_dense_polyhedron(), expected));
2569
2570 let t = Theory {
2590 id: String::from("A"),
2591 statements: vec![
2592 Statement {
2593 variable: Variable { id: 0, bounds: (0,1) },
2594 expression: Some(
2595 AtLeast {
2596 ids: vec![1,2,3],
2597 bias: -3,
2598 sign: Sign::Positive,
2599 }
2600 )
2601 },
2602 Statement {
2603 variable: Variable { id: 1, bounds: (0,1) },
2604 expression: Some(
2605 AtLeast {
2606 ids: vec![4,5],
2607 bias: -1,
2608 sign: Sign::Positive,
2609 }
2610 )
2611 },
2612 Statement {
2613 variable: Variable { id: 2, bounds: (0,1) },
2614 expression: Some(
2615 AtLeast {
2616 ids: vec![5,6],
2617 bias: -1,
2618 sign: Sign::Positive,
2619 }
2620 )
2621 },
2622 Statement {
2623 variable: Variable { id: 3, bounds: (0,1) },
2624 expression: Some(
2625 AtLeast {
2626 ids: vec![7,8],
2627 bias: -2,
2628 sign: Sign::Positive,
2629 }
2630 )
2631 },
2632 Statement {
2633 variable: Variable { id: 4, bounds: (0,1) },
2634 expression: Some(
2635 AtLeast {
2636 ids: vec![9,10],
2637 bias: -2,
2638 sign: Sign::Positive,
2639 }
2640 )
2641 },
2642 Statement {
2643 variable: Variable { id: 5, bounds: (0,1) },
2644 expression: Some(
2645 AtLeast {
2646 ids: vec![11],
2647 bias: 0,
2648 sign: Sign::Negative,
2649 }
2650 )
2651 },
2652 Statement {
2653 variable: Variable { id: 6, bounds: (0,1) },
2654 expression: Some(
2655 AtLeast {
2656 ids: vec![12,13],
2657 bias: -1,
2658 sign: Sign::Positive,
2659 }
2660 )
2661 },
2662 Statement {
2663 variable: Variable { id: 7, bounds: (0,1) },
2664 expression: None
2665 },
2666 Statement {
2667 variable: Variable { id: 8, bounds: (0,1) },
2668 expression: None
2669 },
2670 Statement {
2671 variable: Variable { id: 9, bounds: (0,1) },
2672 expression: None
2673 },
2674 Statement {
2675 variable: Variable { id: 10, bounds: (0,1) },
2676 expression: None
2677 },
2678 Statement {
2679 variable: Variable { id: 11, bounds: (0,1) },
2680 expression: None
2681 },
2682 Statement {
2683 variable: Variable { id: 12, bounds: (0,1) },
2684 expression: None
2685 },
2686 Statement {
2687 variable: Variable { id: 13, bounds: (0,1) },
2688 expression: None
2689 },
2690 ]
2691 };
2692
2693 let expected: Polyhedron = Polyhedron {
2694 a: linalg::Matrix {
2695 val: vec![1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -2.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, -2.0, 0.0, 0.0],
2696 ncols: 10,
2697 nrows: 4
2698 },
2699 b: vec![3.0, 0.0, 0.0, 0.0],
2700 variables: vec![
2701 VariableFloat {id: 1, bounds: (0.0, 1.0)},
2702 VariableFloat {id: 2, bounds: (0.0, 1.0)},
2703 VariableFloat {id: 3, bounds: (0.0, 1.0)},
2704 VariableFloat {id: 7, bounds: (0.0, 1.0)},
2705 VariableFloat {id: 8, bounds: (0.0, 1.0)},
2706 VariableFloat {id: 9, bounds: (0.0, 1.0)},
2707 VariableFloat {id: 10, bounds: (0.0, 1.0)},
2708 VariableFloat {id: 11, bounds: (0.0, 1.0)},
2709 VariableFloat {id: 12, bounds: (0.0, 1.0)},
2710 VariableFloat {id: 13, bounds: (0.0, 1.0)},
2711 ],
2712 index: (0..4).map(|x| Some(x as u32)).collect(),
2713 };
2715 assert!(validate(t.to_ge_polyhedron(true, true).to_dense_polyhedron(), expected));
2716
2717 let t = Theory {
2725 id: String::from("A"),
2726 statements: vec![
2727 Statement {
2728 variable: Variable { id: 0, bounds: (0,1) },
2729 expression: Some(
2730 AtLeast {
2731 ids: vec![1,2],
2732 bias: -1,
2733 sign: Sign::Positive,
2734 }
2735 )
2736 },
2737 Statement {
2738 variable: Variable { id: 1, bounds: (0,1) },
2739 expression: Some(
2740 AtLeast {
2741 ids: vec![3,4],
2742 bias: 1,
2743 sign: Sign::Negative,
2744 }
2745 )
2746 },
2747 Statement {
2748 variable: Variable { id: 2, bounds: (0,1) },
2749 expression: Some(
2750 AtLeast {
2751 ids: vec![5,6,7],
2752 bias: -3,
2753 sign: Sign::Positive,
2754 }
2755 )
2756 },
2757 Statement {
2758 variable: Variable { id: 3, bounds: (0,1) },
2759 expression: None
2760 },
2761 Statement {
2762 variable: Variable { id: 4, bounds: (0,1) },
2763 expression: None
2764 },
2765 Statement {
2766 variable: Variable { id: 5, bounds: (0,1) },
2767 expression: None
2768 },
2769 Statement {
2770 variable: Variable { id: 6, bounds: (0,1) },
2771 expression: None
2772 },
2773 Statement {
2774 variable: Variable { id: 7, bounds: (0,1) },
2775 expression: None
2776 },
2777 ]
2778 };
2779
2780 let expected: Polyhedron = Polyhedron {
2781 a: linalg::Matrix {
2782 val: vec![-3.0, -3.0, 1.0, 1.0, 1.0],
2783 ncols: 5,
2784 nrows: 1
2785 },
2786 b: vec![-3.0],
2787 variables: vec![
2788 VariableFloat {id: 3, bounds: (0.0, 1.0)},
2789 VariableFloat {id: 4, bounds: (0.0, 1.0)},
2790 VariableFloat {id: 5, bounds: (0.0, 1.0)},
2791 VariableFloat {id: 6, bounds: (0.0, 1.0)},
2792 VariableFloat {id: 7, bounds: (0.0, 1.0)},
2793 ],
2794 index: (0..1).map(|x| Some(x as u32)).collect(),
2795 };
2796 assert!(validate(t.to_ge_polyhedron(true, true).to_dense_polyhedron(), expected));
2797 }
2798
2799 #[test]
2800 fn test_theory_solve() {
2801 let t = Theory {
2802 id: String::from("A"),
2803 statements: vec![
2804 Statement {
2805 variable: Variable { id: 0, bounds: (0,1) },
2806 expression: Some(
2807 AtLeast {
2808 ids: vec![1,2],
2809 bias: -1,
2810 sign: Sign::Positive,
2811 }
2812 )
2813 },
2814 Statement {
2815 variable: Variable { id: 1, bounds: (0,1) },
2816 expression: Some(
2817 AtLeast {
2818 ids: vec![3,4],
2819 bias: 1,
2820 sign: Sign::Negative,
2821 }
2822 )
2823 },
2824 Statement {
2825 variable: Variable { id: 2, bounds: (0,1) },
2826 expression: Some(
2827 AtLeast {
2828 ids: vec![5,6,7],
2829 bias: -3,
2830 sign: Sign::Positive,
2831 }
2832 )
2833 },
2834 Statement {
2835 variable: Variable { id: 3, bounds: (0,1) },
2836 expression: None
2837 },
2838 Statement {
2839 variable: Variable { id: 4, bounds: (0,1) },
2840 expression: None
2841 },
2842 Statement {
2843 variable: Variable { id: 5, bounds: (0,1) },
2844 expression: None
2845 },
2846 Statement {
2847 variable: Variable { id: 6, bounds: (0,1) },
2848 expression: None
2849 },
2850 Statement {
2851 variable: Variable { id: 7, bounds: (0,1) },
2852 expression: None
2853 },
2854 ]
2855 };
2856 let actual_solutions = t.solve(
2857 vec![
2858 vec![(3, 1.0), (4, 1.0)].iter().cloned().collect(),
2859 vec![(3, 2.0), (4, 1.0), (5, -1.0), (6, -1.0), (7, -1.0)].iter().cloned().collect(),
2860 ], true);
2862 let expected_solutions = vec![
2863 vec![(3,1),(4,1),(5,1),(6,1),(7,1)].iter().cloned().collect(),
2864 vec![(3,1),(4,0),(5,0),(6,0),(7,0)].iter().cloned().collect(),
2865 ];
2866 assert!(actual_solutions.iter().zip(expected_solutions).all(|(x,y)| x.0 == y));
2867 }
2868}