1use core::fmt;
9use std::collections::HashMap;
10
11use taco_display_utils::join_iterator;
12
13use simple_order_generator::SimpleOrderGeneratorContext;
14use taco_smt_encoder::SMTSolverBuilder;
15use taco_threshold_automaton::{
16 ThresholdAutomaton,
17 expressions::{Atomic, BooleanExpression, ComparisonOp, Variable},
18 lia_threshold_automaton::integer_thresholds::{
19 IntoNoDivBooleanExpr, ThresholdCompOp, ThresholdConstraint, WeightedSum,
20 },
21};
22
23use crate::{
24 HasAssociatedIntervals,
25 interval::{Interval, IntervalBoundary, IntervalOrder, IntervalOrderError, IntervalOrderFor},
26};
27
28mod simple_order_generator;
29
30trait DefinesStaticIntervalOrder<T>: fmt::Display + IntervalOrder
33where
34 T: HasAssociatedIntervals,
35{
36 fn get_intervals<'a>(&'a self, var: &T) -> Result<&'a Vec<Interval>, IntervalOrderError<T>>;
37
38 fn get_interval_index(&self, var: &T, i: &Interval) -> Result<usize, IntervalOrderError<T>>;
39
40 fn get_interval_by_index<'a>(
41 &'a self,
42 var: &T,
43 idx: usize,
44 ) -> Result<&'a Interval, IntervalOrderError<T>>;
45
46 fn check_interval_replaced_by_eq(&self, ib: IntervalBoundary) -> IntervalBoundary;
56}
57
58#[derive(Debug, Clone, PartialEq)]
61pub struct StaticIntervalOrder {
62 single_var_order: HashMap<Variable, Vec<Interval>>,
64 multi_var_order: HashMap<WeightedSum<Variable>, Vec<Interval>>,
66 equal_boundaries: HashMap<IntervalBoundary, IntervalBoundary>,
68}
69impl StaticIntervalOrder {
70 pub fn single_var_order(&self) -> &HashMap<Variable, Vec<Interval>> {
72 &self.single_var_order
73 }
74}
75
76#[cfg(test)]
77impl StaticIntervalOrder {
78 pub fn new(
80 single_var_order: HashMap<Variable, Vec<Interval>>,
81 multi_var_order: HashMap<WeightedSum<Variable>, Vec<Interval>>,
82 equal_boundaries: HashMap<IntervalBoundary, IntervalBoundary>,
83 ) -> StaticIntervalOrder {
84 StaticIntervalOrder {
85 single_var_order,
86 multi_var_order,
87 equal_boundaries,
88 }
89 }
90}
91
92impl DefinesStaticIntervalOrder<Variable> for StaticIntervalOrder {
93 fn get_intervals<'a>(
94 &'a self,
95 var: &Variable,
96 ) -> Result<&'a Vec<Interval>, IntervalOrderError<Variable>> {
97 let intervals = self
98 .single_var_order
99 .get(var)
100 .ok_or_else(|| IntervalOrderError::VariableNotFound { var: var.clone() })?;
101 Ok(intervals)
102 }
103
104 fn get_interval_index(
105 &self,
106 var: &Variable,
107 i: &Interval,
108 ) -> Result<usize, IntervalOrderError<Variable>> {
109 let intervals = self.get_intervals(var)?;
110
111 intervals.iter().position(|x| *x == *i).ok_or_else(|| {
112 IntervalOrderError::IntervalNotFound {
113 var: var.clone(),
114 interval: i.clone(),
115 }
116 })
117 }
118
119 fn get_interval_by_index<'a>(
120 &'a self,
121 var: &Variable,
122 mut idx: usize,
123 ) -> Result<&'a Interval, IntervalOrderError<Variable>> {
124 let intervals = self.get_intervals(var)?;
125
126 if idx >= intervals.len() {
127 idx = intervals.len() - 1;
128 }
129
130 Ok(&intervals[idx])
131 }
132
133 fn check_interval_replaced_by_eq(&self, ib: IntervalBoundary) -> IntervalBoundary {
139 if let Some(ib) = self.equal_boundaries.get(&ib) {
140 return ib.clone();
141 }
142
143 ib
144 }
145}
146
147impl DefinesStaticIntervalOrder<WeightedSum<Variable>> for StaticIntervalOrder {
148 fn get_intervals<'a>(
149 &'a self,
150 var: &WeightedSum<Variable>,
151 ) -> Result<&'a Vec<Interval>, IntervalOrderError<WeightedSum<Variable>>> {
152 let intervals = self
153 .multi_var_order
154 .get(var)
155 .ok_or_else(|| IntervalOrderError::VariableNotFound { var: var.clone() })?;
156
157 Ok(intervals)
158 }
159
160 fn get_interval_index(
161 &self,
162 var: &WeightedSum<Variable>,
163 i: &Interval,
164 ) -> Result<usize, IntervalOrderError<WeightedSum<Variable>>> {
165 let intervals = self.get_intervals(var)?;
166
167 intervals.iter().position(|x| *x == *i).ok_or_else(|| {
168 IntervalOrderError::IntervalNotFound {
169 var: var.clone(),
170 interval: i.clone(),
171 }
172 })
173 }
174
175 fn get_interval_by_index<'a>(
176 &'a self,
177 var: &WeightedSum<Variable>,
178 mut idx: usize,
179 ) -> Result<&'a Interval, IntervalOrderError<WeightedSum<Variable>>> {
180 let intervals = self.get_intervals(var)?;
181
182 if intervals.is_empty() {
183 unreachable!("Should at least contain one interval!");
184 }
185 if idx >= intervals.len() {
186 idx = intervals.len() - 1;
187 }
188
189 Ok(&intervals[idx])
190 }
191
192 fn check_interval_replaced_by_eq(&self, ib: IntervalBoundary) -> IntervalBoundary {
193 if let Some(ib) = self.equal_boundaries.get(&ib) {
194 return ib.clone();
195 }
196
197 ib
198 }
199}
200
201impl<T: HasAssociatedIntervals, U: DefinesStaticIntervalOrder<T>> IntervalOrderFor<T> for U {
202 fn get_number_of_intervals(&self, var: &T) -> Result<usize, IntervalOrderError<T>> {
203 Ok(self.get_intervals(var)?.len())
204 }
205
206 fn lt(&self, var: &T, i1: &Interval, i2: &Interval) -> Result<bool, IntervalOrderError<T>> {
207 let idx1 = self.get_interval_index(var, i1)?;
208 let idx2 = self.get_interval_index(var, i2)?;
209
210 Ok(idx1 < idx2)
211 }
212
213 fn gt(&self, var: &T, i1: &Interval, i2: &Interval) -> Result<bool, IntervalOrderError<T>> {
214 let idx1 = self.get_interval_index(var, i1)?;
215 let idx2 = self.get_interval_index(var, i2)?;
216
217 Ok(idx1 > idx2)
218 }
219
220 fn get_next_interval<'a>(
221 &'a self,
222 var: &T,
223 i: &Interval,
224 ) -> Result<Option<&'a Interval>, IntervalOrderError<T>> {
225 let idx = self.get_interval_index(var, i)?;
226
227 if idx >= self.get_number_of_intervals(var)? - 1 {
228 return Ok(None);
229 }
230
231 Ok(Some(self.get_interval_by_index(var, idx + 1)?))
232 }
233
234 fn get_previous_interval<'a>(
235 &'a self,
236 var: &T,
237 i: &Interval,
238 ) -> Result<Option<&'a Interval>, IntervalOrderError<T>> {
239 let idx = self.get_interval_index(var, i)?;
240
241 if idx == 0 {
242 return Ok(None);
243 }
244
245 Ok(Some(self.get_interval_by_index(var, idx - 1)?))
246 }
247
248 fn compute_enabled_intervals_of_threshold(
249 &self,
250 t: &T,
251 thr: &ThresholdConstraint,
252 ) -> Result<Vec<Interval>, IntervalOrderError<T>> {
253 let lb = IntervalBoundary::from_threshold_constraint(thr);
254
255 let lb: IntervalBoundary = self.check_interval_replaced_by_eq(lb);
256
257 let intervals = self.get_intervals(t)?;
258
259 let (idx, _) = intervals
260 .iter()
261 .enumerate()
262 .find(|(_index, i)| i.check_is_contained(&lb))
263 .ok_or_else(|| IntervalOrderError::ThresholdExtractionError {
264 var: t.clone(),
265 thr: thr.clone(),
266 })?;
267
268 let result = match thr.get_op() {
269 ThresholdCompOp::Geq => intervals[idx..].to_vec(),
270 ThresholdCompOp::Lt => intervals[..idx].to_vec(),
271 ThresholdCompOp::Gt => {
272 let idx = idx + 1;
273 intervals[idx..].to_vec()
274 }
275 ThresholdCompOp::Leq => {
276 let idx = idx + 1;
277 intervals[..idx].to_vec()
278 }
279 };
280
281 Ok(result)
282 }
283
284 fn get_zero_interval(&self, t: &T) -> Result<&Interval, IntervalOrderError<T>> {
285 Ok(self.get_intervals(t)?.first().unwrap())
286 }
287
288 fn get_all_intervals_of_t(&self, t: &T) -> Result<&Vec<Interval>, IntervalOrderError<T>> {
289 self.get_intervals(t)
290 }
291
292 fn check_interval_replaced(&self, ib: IntervalBoundary) -> IntervalBoundary {
293 self.check_interval_replaced_by_eq(ib)
294 }
295}
296
297impl IntervalOrder for StaticIntervalOrder {
298 fn order_to_boolean_expr<T: Atomic>(&self) -> Vec<BooleanExpression<T>> {
299 let eq_constr = self.equal_boundaries.iter().map(|(ib_1, ib_2)| {
300 let ib_1 = ib_1.get_threshold().expect("Infinite interval in order");
301 let ib_2 = ib_2.get_threshold().expect("Infinite interval in order");
302
303 ib_1.encode_comparison_to_boolean_expression(ComparisonOp::Eq, ib_2)
304 });
305
306 let interval_constr = self
308 .single_var_order
309 .values()
310 .chain(self.multi_var_order.values())
311 .flat_map(|intervals| {
312 intervals
313 .iter()
314 .filter(|i| i.ub() != &IntervalBoundary::Infty)
315 .filter(|i| i.lb() != i.ub() || i.is_left_open() || i.is_right_open())
316 .map(|interval| {
317 if interval.lb() == &IntervalBoundary::Infty {
318 debug_assert!(false, "Interval with lower bound ∞ found");
319 return BooleanExpression::False;
320 }
321
322 let lb = interval
323 .lb()
324 .get_threshold()
325 .expect("Infinite interval in order");
326 let ub = interval
327 .ub()
328 .get_threshold()
329 .expect("Infinite interval in order");
330
331 lb.encode_comparison_to_boolean_expression(ComparisonOp::Lt, ub)
332 })
333 });
334
335 eq_constr.chain(interval_constr).collect()
336 }
337}
338
339impl fmt::Display for StaticIntervalOrder {
340 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
341 writeln!(f, "intervalOrder {{")?;
342
343 if !self.equal_boundaries.is_empty() {
344 writeln!(
345 f,
346 " {};",
347 join_iterator(
348 self.equal_boundaries
349 .iter()
350 .map(|(ib1, ib2)| format!("{ib1} == {ib2}")),
351 " && "
352 )
353 )?;
354 }
355
356 if !self.single_var_order.is_empty() {
357 let mut sorted_single_var = self.single_var_order.iter().collect::<Vec<_>>();
358 sorted_single_var.sort_by_key(|(a, _)| *a);
359
360 for (var, intervals) in sorted_single_var {
361 writeln!(f, " {}: {};", var, join_iterator(intervals.iter(), ", "))?;
362 }
363 }
364
365 if !self.multi_var_order.is_empty() {
366 for (var, intervals) in &self.multi_var_order {
367 writeln!(f, " {}: {};", var, join_iterator(intervals.iter(), ", "))?;
368 }
369 }
370
371 write!(f, "}}")
372 }
373}
374
375pub struct StaticIntervalOrderBuilder {
377 order_generator: SimpleOrderGeneratorContext,
378 vars: Vec<Variable>,
379}
380
381impl StaticIntervalOrderBuilder {
382 pub fn new<T: ThresholdAutomaton>(ta: &T, smt_solver_builder: SMTSolverBuilder) -> Self {
384 let orders = SimpleOrderGeneratorContext::new(ta, smt_solver_builder);
385 let vars = ta.variables().cloned().collect::<Vec<_>>();
386
387 StaticIntervalOrderBuilder {
388 order_generator: orders,
389 vars,
390 }
391 }
392
393 pub fn add_single_variable_interval(
395 self,
396 var: &Variable,
397 interval: &IntervalBoundary,
398 needs_exact: bool,
399 ) -> Self {
400 let orders = self
401 .order_generator
402 .extend_order_with_interval_for_single_variable(var, interval, needs_exact);
403
404 StaticIntervalOrderBuilder {
405 order_generator: orders,
406 vars: self.vars,
407 }
408 }
409
410 pub fn add_multi_variable_interval(
412 self,
413 sum: &WeightedSum<Variable>,
414 interval: &IntervalBoundary,
415 needs_exact: bool,
416 ) -> Self {
417 let orders = self
418 .order_generator
419 .extend_order_with_interval_for_multi_variable(sum, interval, needs_exact);
420
421 StaticIntervalOrderBuilder {
422 order_generator: orders,
423 vars: self.vars,
424 }
425 }
426
427 pub fn build(self) -> Vec<StaticIntervalOrder> {
429 self.order_generator.build_orders(&self.vars)
430 }
431}
432
433#[cfg(test)]
434mod tests {
435
436 use std::collections::{BTreeMap, HashMap};
437
438 use taco_threshold_automaton::expressions::fraction::Fraction;
439 use taco_threshold_automaton::expressions::{
440 BooleanExpression, ComparisonOp, IntegerExpression, Parameter,
441 };
442
443 use taco_threshold_automaton::expressions::Variable;
444 use taco_threshold_automaton::lia_threshold_automaton::integer_thresholds::{
445 Threshold, ThresholdCompOp, ThresholdConstraint, WeightedSum,
446 };
447
448 use crate::builder::static_interval_order::{DefinesStaticIntervalOrder, StaticIntervalOrder};
449 use crate::interval::{
450 Interval, IntervalBoundary, IntervalOrder, IntervalOrderError, IntervalOrderFor,
451 };
452
453 #[test]
454 fn test_get_interval_index_single_var() {
455 let var = Variable::new("x");
456 let interval1 = Interval::new(
457 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
458 false,
459 IntervalBoundary::Infty,
460 false,
461 );
462
463 let mut internal_order = HashMap::new();
464 internal_order.insert(var.clone(), vec![interval1.clone()]);
465
466 let order = StaticIntervalOrder {
467 single_var_order: internal_order,
468 multi_var_order: HashMap::new(),
469 equal_boundaries: HashMap::new(),
470 };
471
472 assert_eq!(order.get_interval_index(&var, &interval1).unwrap(), 0);
473
474 let interval2 = Interval::new(
475 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
476 false,
477 IntervalBoundary::Infty,
478 true,
479 );
480 let err = order.get_interval_index(&var, &interval2);
481 assert!(err.is_err());
482 assert!(matches!(
483 err.unwrap_err(),
484 IntervalOrderError::IntervalNotFound { .. }
485 ));
486 }
487
488 #[test]
489 fn get_interval_index_multi_var() {
490 let var1 = Variable::new("x");
491 let var2 = Variable::new("y");
492 let sum = WeightedSum::new(BTreeMap::from([(var1.clone(), 1), (var2.clone(), 1)]));
493 let interval1 = Interval::new(
494 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
495 false,
496 IntervalBoundary::Infty,
497 true,
498 );
499
500 let mut internal_order = HashMap::new();
501 internal_order.insert(sum.clone(), vec![interval1.clone()]);
502
503 let order = StaticIntervalOrder {
504 single_var_order: HashMap::new(),
505 multi_var_order: internal_order,
506 equal_boundaries: HashMap::new(),
507 };
508
509 assert_eq!(order.get_interval_index(&sum, &interval1).unwrap(), 0);
510
511 let interval2 = Interval::new(
512 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
513 false,
514 IntervalBoundary::Infty,
515 true,
516 );
517 let err = order.get_interval_index(&sum, &interval2);
518 assert!(err.is_err());
519 assert!(matches!(
520 err.unwrap_err(),
521 IntervalOrderError::IntervalNotFound { .. }
522 ));
523 }
524
525 #[test]
526 fn test_get_interval_by_index_single_var() {
527 let var = Variable::new("x");
528 let interval1 = Interval::new(
529 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
530 false,
531 IntervalBoundary::Infty,
532 true,
533 );
534
535 let mut internal_order = HashMap::new();
536 internal_order.insert(var.clone(), vec![interval1.clone()]);
537
538 let order = StaticIntervalOrder {
539 single_var_order: internal_order,
540 multi_var_order: HashMap::new(),
541 equal_boundaries: HashMap::new(),
542 };
543
544 assert_eq!(order.get_interval_by_index(&var, 0).unwrap(), &interval1);
545 assert_eq!(order.get_interval_by_index(&var, 1).unwrap(), &interval1);
546 }
547
548 #[test]
549 fn get_interval_by_index_multi_var() {
550 let var1 = Variable::new("x");
551 let var2 = Variable::new("y");
552 let sum = WeightedSum::new(BTreeMap::from([(var1.clone(), 1), (var2.clone(), 1)]));
553 let interval1 = Interval::new(
554 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
555 false,
556 IntervalBoundary::Infty,
557 true,
558 );
559
560 let mut internal_order = HashMap::new();
561 internal_order.insert(sum.clone(), vec![interval1.clone()]);
562
563 let order = StaticIntervalOrder {
564 single_var_order: HashMap::new(),
565 multi_var_order: internal_order,
566 equal_boundaries: HashMap::new(),
567 };
568
569 assert_eq!(order.get_interval_by_index(&sum, 0).unwrap(), &interval1);
570 assert_eq!(order.get_interval_by_index(&sum, 1).unwrap(), &interval1);
571 }
572
573 #[test]
574 fn test_interval_order_lt() {
575 let var = Variable::new("x");
576 let interval1 = Interval::new(
577 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
578 false,
579 IntervalBoundary::Infty,
580 true,
581 );
582 let interval2 = Interval::new(
583 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
584 false,
585 IntervalBoundary::Infty,
586 true,
587 );
588 let mut internal_order = HashMap::new();
589 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
590 let order = StaticIntervalOrder {
591 single_var_order: internal_order,
592 multi_var_order: HashMap::new(),
593 equal_boundaries: HashMap::new(),
594 };
595
596 assert!(order.lt(&var, &interval1, &interval2).unwrap());
597 assert!(!order.lt(&var, &interval2, &interval1).unwrap());
598 }
599
600 #[test]
601 fn test_interval_order_gt() {
602 let var = Variable::new("x");
603 let interval1 = Interval::new(
604 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
605 false,
606 IntervalBoundary::Infty,
607 true,
608 );
609 let interval2 = Interval::new(
610 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
611 false,
612 IntervalBoundary::Infty,
613 true,
614 );
615 let mut internal_order = HashMap::new();
616 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
617 let order = StaticIntervalOrder {
618 single_var_order: internal_order,
619 multi_var_order: HashMap::new(),
620 equal_boundaries: HashMap::new(),
621 };
622
623 assert!(order.gt(&var, &interval2, &interval1).unwrap());
624 assert!(!order.gt(&var, &interval1, &interval2).unwrap());
625 }
626
627 #[test]
628 fn test_get_next_interval() {
629 let var = Variable::new("x");
630 let interval1 = Interval::new(
631 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
632 false,
633 IntervalBoundary::Infty,
634 true,
635 );
636 let interval2 = Interval::new(
637 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
638 false,
639 IntervalBoundary::Infty,
640 true,
641 );
642 let mut internal_order = HashMap::new();
643 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
644 let order = StaticIntervalOrder {
645 single_var_order: internal_order,
646 multi_var_order: HashMap::new(),
647 equal_boundaries: HashMap::new(),
648 };
649
650 assert_eq!(
651 order.get_next_interval(&var, &interval1).unwrap(),
652 Some(&interval2)
653 );
654 assert_eq!(order.get_next_interval(&var, &interval2).unwrap(), None);
655 }
656
657 #[test]
658 fn test_get_previous_interval() {
659 let var = Variable::new("x");
660 let interval1 = Interval::new(
661 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
662 false,
663 IntervalBoundary::Infty,
664 true,
665 );
666 let interval2 = Interval::new(
667 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
668 false,
669 IntervalBoundary::Infty,
670 true,
671 );
672 let mut internal_order = HashMap::new();
673 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
674 let order = StaticIntervalOrder {
675 single_var_order: internal_order,
676 multi_var_order: HashMap::new(),
677 equal_boundaries: HashMap::new(),
678 };
679
680 assert_eq!(
681 order.get_previous_interval(&var, &interval2).unwrap(),
682 Some(&interval1)
683 );
684 assert_eq!(order.get_previous_interval(&var, &interval1).unwrap(), None);
685 }
686
687 #[test]
688 fn test_get_number_of_intervals() {
689 let var = Variable::new("x");
690 let interval1 = Interval::new(
691 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
692 false,
693 IntervalBoundary::Infty,
694 true,
695 );
696 let interval2 = Interval::new(
697 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
698 false,
699 IntervalBoundary::Infty,
700 true,
701 );
702 let mut internal_order = HashMap::new();
703 internal_order.insert(var.clone(), vec![interval1, interval2]);
704 let order = StaticIntervalOrder {
705 single_var_order: internal_order,
706 multi_var_order: HashMap::new(),
707 equal_boundaries: HashMap::new(),
708 };
709
710 assert_eq!(order.get_number_of_intervals(&var).unwrap(), 2);
711 }
712
713 #[test]
714 fn test_empty_intervals() {
715 let var = Variable::new("x");
716 let mut internal_order = HashMap::new();
717 internal_order.insert(var.clone(), vec![]);
718 let order = StaticIntervalOrder {
719 single_var_order: internal_order,
720 multi_var_order: HashMap::new(),
721 equal_boundaries: HashMap::new(),
722 };
723
724 assert_eq!(order.get_number_of_intervals(&var).unwrap(), 0);
725 }
726
727 #[test]
728 fn test_variable_not_found() {
729 let var = Variable::new("x");
730 let order = StaticIntervalOrder {
731 single_var_order: HashMap::new(),
732 multi_var_order: HashMap::new(),
733 equal_boundaries: HashMap::new(),
734 };
735
736 assert!(order.get_number_of_intervals(&var).is_err());
737 }
738
739 #[test]
740 fn test_interval_order_with_multiple_variables() {
741 let var1 = Variable::new("x");
742 let var2 = Variable::new("y");
743 let interval1 = Interval::new(
744 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
745 false,
746 IntervalBoundary::Infty,
747 true,
748 );
749 let interval2 = Interval::new(
750 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
751 false,
752 IntervalBoundary::Infty,
753 true,
754 );
755
756 let mut internal_order = HashMap::new();
757 internal_order.insert(var1.clone(), vec![interval1.clone()]);
758 internal_order.insert(var2.clone(), vec![interval2.clone()]);
759
760 let order = StaticIntervalOrder {
761 single_var_order: internal_order,
762 multi_var_order: HashMap::new(),
763 equal_boundaries: HashMap::new(),
764 };
765
766 assert_eq!(order.get_number_of_intervals(&var1).unwrap(), 1);
767 assert_eq!(order.get_number_of_intervals(&var2).unwrap(), 1);
768 assert!(
769 order
770 .get_next_interval(&var1, &interval1)
771 .unwrap()
772 .is_none()
773 );
774 assert!(
775 order
776 .get_next_interval(&var2, &interval2)
777 .unwrap()
778 .is_none()
779 );
780 assert!(
781 order
782 .get_previous_interval(&var1, &interval1)
783 .unwrap()
784 .is_none()
785 );
786 assert!(
787 order
788 .get_previous_interval(&var2, &interval2)
789 .unwrap()
790 .is_none()
791 );
792 }
793
794 #[test]
795 fn test_get_intervals_of_threshold() {
796 let var = Variable::new("x");
797 let interval1 = Interval::new(
798 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
799 false,
800 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
801 false,
802 );
803 let interval2 = Interval::new(
804 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
805 false,
806 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
807 false,
808 );
809 let interval3 = Interval::new(
810 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 3)),
811 false,
812 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 3)),
813 false,
814 );
815
816 let mut internal_order = HashMap::new();
817 internal_order.insert(
818 var.clone(),
819 vec![interval1.clone(), interval2.clone(), interval3.clone()],
820 );
821
822 let order = StaticIntervalOrder {
823 single_var_order: internal_order,
824 multi_var_order: HashMap::new(),
825 equal_boundaries: HashMap::new(),
826 };
827
828 let threshold_geq =
830 ThresholdConstraint::new(ThresholdCompOp::Geq, Vec::<(Parameter, Fraction)>::new(), 2);
831 let intervals_geq = order
832 .compute_enabled_intervals_of_threshold(&var, &threshold_geq)
833 .unwrap();
834 assert_eq!(intervals_geq.len(), 2);
835 assert_eq!(intervals_geq, vec![interval2.clone(), interval3.clone()]);
836
837 let threshold_lt =
839 ThresholdConstraint::new(ThresholdCompOp::Lt, Vec::<(Parameter, Fraction)>::new(), 3);
840 let intervals_lt = order
841 .compute_enabled_intervals_of_threshold(&var, &threshold_lt)
842 .unwrap();
843 assert_eq!(intervals_lt.len(), 2);
844 assert_eq!(intervals_lt, vec![interval1.clone(), interval2.clone()]);
845 }
846
847 #[test]
848 fn test_get_intervals_of_threshold_err() {
849 let var = Variable::new("x");
850 let interval1 = Interval::new(
851 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
852 false,
853 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
854 false,
855 );
856 let interval2 = Interval::new(
857 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
858 false,
859 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
860 false,
861 );
862 let interval3 = Interval::new(
863 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 3)),
864 false,
865 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 3)),
866 false,
867 );
868
869 let mut internal_order = HashMap::new();
870 internal_order.insert(
871 var.clone(),
872 vec![interval1.clone(), interval2.clone(), interval3.clone()],
873 );
874
875 let order = StaticIntervalOrder {
876 single_var_order: internal_order,
877 multi_var_order: HashMap::new(),
878 equal_boundaries: HashMap::new(),
879 };
880
881 let threshold =
883 ThresholdConstraint::new(ThresholdCompOp::Geq, Vec::<(Parameter, Fraction)>::new(), 4);
884 let err = order.compute_enabled_intervals_of_threshold(&var, &threshold);
885 assert!(err.is_err());
886 assert!(matches!(
887 err.unwrap_err(),
888 IntervalOrderError::ThresholdExtractionError { .. }
889 ));
890 }
891
892 #[test]
893 fn test_get_zero_interval() {
894 let var = Variable::new("x");
895 let interval1 = Interval::new(
896 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
897 false,
898 IntervalBoundary::Infty,
899 false,
900 );
901 let interval2 = Interval::new(
902 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
903 false,
904 IntervalBoundary::Infty,
905 false,
906 );
907 let mut internal_order = HashMap::new();
908 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
909 let order = StaticIntervalOrder {
910 single_var_order: internal_order,
911 multi_var_order: HashMap::new(),
912 equal_boundaries: HashMap::new(),
913 };
914
915 assert_eq!(order.get_zero_interval(&var).unwrap(), &interval1);
916 }
917
918 #[test]
919 fn test_order_to_boolean_expr() {
920 let var = Variable::new("x");
921 let interval1 = Interval::new(
922 IntervalBoundary::from_const(1),
923 false,
924 IntervalBoundary::from_const(2),
925 true,
926 );
927 let interval2 = Interval::new(
928 IntervalBoundary::from_const(2),
929 false,
930 IntervalBoundary::Infty,
931 true,
932 );
933
934 let ib1 = IntervalBoundary::new_bound(WeightedSum::new([(Parameter::new("n"), 1)]), 0);
935 let ib2 = IntervalBoundary::new_bound(WeightedSum::new([(Parameter::new("n"), 2)]), 0);
936
937 let mut internal_order = HashMap::new();
938 internal_order.insert(var.clone(), vec![interval1.clone(), interval2.clone()]);
939 let order = StaticIntervalOrder {
940 single_var_order: HashMap::from([(
941 var.clone(),
942 vec![interval1.clone(), interval2.clone()],
943 )]),
944 multi_var_order: HashMap::new(),
945 equal_boundaries: HashMap::from([(ib2, ib1)]),
946 };
947
948 let exprs = order.order_to_boolean_expr::<Parameter>();
949
950 assert_eq!(exprs.len(), 2);
951
952 let expected_expr_1 = BooleanExpression::ComparisonExpression(
953 Box::new(IntegerExpression::Const(1)),
954 ComparisonOp::Lt,
955 Box::new(IntegerExpression::Const(2)),
956 );
957 assert!(exprs.contains(&expected_expr_1));
958
959 let expected_expr_2 = BooleanExpression::ComparisonExpression(
960 Box::new(IntegerExpression::Const(2) * IntegerExpression::Param(Parameter::new("n"))),
961 ComparisonOp::Eq,
962 Box::new(IntegerExpression::Param(Parameter::new("n"))),
963 );
964 assert!(exprs.contains(&expected_expr_2));
965 }
966
967 #[test]
968 fn test_order_to_boolean_expr_skips_exact_intervals() {
969 let sum = WeightedSum::new(BTreeMap::from([
970 (Variable::new("x"), 1),
971 (Variable::new("y"), 1),
972 ]));
973 let ib = IntervalBoundary::from_const(2);
974 let intervals = vec![
975 Interval::new(IntervalBoundary::from_const(0), false, ib.clone(), true),
976 Interval::new(ib.clone(), false, ib.clone(), false),
977 Interval::new(ib, true, IntervalBoundary::Infty, true),
978 ];
979
980 let order = StaticIntervalOrder {
981 single_var_order: HashMap::from([(Variable::new("z"), intervals.clone())]),
982 multi_var_order: HashMap::from([(sum, intervals)]),
983 equal_boundaries: HashMap::new(),
984 };
985
986 let exact = BooleanExpression::ComparisonExpression(
988 Box::new(IntegerExpression::Const(2)),
989 ComparisonOp::Lt,
990 Box::new(IntegerExpression::Const(2)),
991 );
992 let exprs = order.order_to_boolean_expr::<Parameter>();
993 assert_eq!(exprs.len(), 2);
994 assert!(!exprs.contains(&exact));
995 }
996
997 #[test]
998 fn test_display_static_interval_order() {
999 let var1 = Variable::new("x");
1000 let var2 = Variable::new("y");
1001 let sum = WeightedSum::new(BTreeMap::from([(var1.clone(), 1), (var2.clone(), 1)]));
1002 let interval1 = Interval::new(
1003 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 1)),
1004 false,
1005 IntervalBoundary::Infty,
1006 false,
1007 );
1008 let interval2 = Interval::new(
1009 IntervalBoundary::Bound(Threshold::new(WeightedSum::new_empty(), 2)),
1010 false,
1011 IntervalBoundary::Infty,
1012 false,
1013 );
1014 let ib = IntervalBoundary::Bound(Threshold::new(
1015 WeightedSum::new([(Parameter::new("n"), 1)]),
1016 0,
1017 ));
1018
1019 let single_var_internal_order = HashMap::from([
1020 (var1.clone(), vec![interval1.clone()]),
1021 (var2.clone(), vec![interval2.clone()]),
1022 ]);
1023
1024 let multi_var_internal_order = HashMap::from([(sum.clone(), vec![interval1.clone()])]);
1025
1026 let order = StaticIntervalOrder {
1027 single_var_order: single_var_internal_order,
1028 multi_var_order: multi_var_internal_order,
1029 equal_boundaries: HashMap::from([(IntervalBoundary::from_const(1), ib)]),
1030 };
1031
1032 let expected =
1033 "intervalOrder {\n 1 == n;\n x: [1, ∞[;\n y: [2, ∞[;\n x + y: [1, ∞[;\n}";
1034 assert_eq!(format!("{order}"), expected);
1035 }
1036}