1use core::{error, fmt};
5use std::ops::Not;
6
7use taco_threshold_automaton::{
8 expressions::BooleanExpression,
9 lia_threshold_automaton::{
10 ConstraintRewriteError, LIAVariableConstraint, integer_thresholds::DeriveFromIntegerComp,
11 },
12};
13
14use crate::{
15 eltl::{ELTLExpression, remove_negations::NonNegatedELTLExpression},
16 internal_spec::{
17 Disjunction, ErrorAtom, ErrorFormula, ErrorSpec,
18 ErrorTarget::{self, Ensure, Invariant, Reach, Repeat, Top},
19 InitRestriction,
20 extraction::ExtractionError::NestedTemporalOperator,
21 upwards_closed_set::{UpwardsClosedSet, UpwardsClosedSetExtractionError},
22 },
23};
24
25impl ErrorSpec {
26 pub fn from_named_eltl<S: Into<String>>(
33 name: S,
34 property: ELTLExpression,
35 ) -> Result<Self, ExtractionError> {
36 let ef = extract_error_formula(property.clone().not().into())?;
37
38 Ok(Self {
39 name: name.into(),
40 source: Box::new(property),
41 ef,
42 })
43 }
44}
45
46impl ErrorFormula {
47 pub fn new(init: InitRestriction, tgt: ErrorTarget) -> Self {
49 Disjunction::from([ErrorAtom::new(init, tgt)])
50 }
51}
52
53impl ErrorAtom {
54 fn try_and(self, other: Self) -> Result<Self, ExtractionError> {
60 let target = self
61 .target
62 .try_unify_and(&other.target)
63 .ok_or_else(|| ExtractionError::UnsupportedConjunction(self.target, other.target))?;
64
65 Ok(Self::new(
66 self.init_restriction & other.init_restriction,
67 target,
68 ))
69 }
70
71 fn try_unify_or(&self, other: &Self) -> Option<Self> {
73 if self.target == other.target {
75 let init = self.init_restriction.try_or(&other.init_restriction)?;
76 return Some(Self::new(init, self.target.clone()));
77 }
78
79 if self.init_restriction == other.init_restriction {
81 let target = self.target.try_unify_or(&other.target)?;
82 return Some(Self::new(self.init_restriction.clone(), target));
83 }
84
85 None
86 }
87}
88
89impl ErrorTarget {
90 fn try_unify_and(&self, other: &Self) -> Option<Self> {
92 match (self, other) {
94 (Top, tgt) | (tgt, Top) => Some(tgt.clone()),
95 (Invariant(l), Invariant(r)) => Some(Invariant(l.clone() & r.clone())),
96 (Invariant(a), Repeat { pre, inv }) | (Repeat { pre, inv }, Invariant(a)) => {
98 Some(Repeat {
99 pre: pre.clone() & a.clone(),
100 inv: inv.clone(),
101 })
102 }
103 (_, _) => None,
105 }
106 }
107
108 fn try_unify_or(&self, other: &Self) -> Option<Self> {
110 match (self, other) {
111 (Reach(l), Reach(r)) => Some(Self::Reach(l.clone() | r.clone())),
112 (
113 Ensure {
114 pre: pre_l,
115 inv: inv_l,
116 },
117 Ensure {
118 pre: pre_r,
119 inv: inv_r,
120 },
121 ) => {
122 if inv_l != inv_r {
123 return None;
124 }
125
126 let pre = pre_l.clone() | pre_r.clone();
127 Some(Ensure {
128 pre,
129 inv: inv_l.clone(),
130 })
131 }
132 (_, _) => None,
133 }
134 }
135
136 fn extract_from_inner_globally(
138 expr: NonNegatedELTLExpression,
139 ) -> Result<ErrorTarget, ExtractionError> {
140 extract_from_inner_globally_helper(expr, true)
141 }
142
143 fn extract_from_inner_eventually(
145 expr: NonNegatedELTLExpression,
146 ) -> Result<Disjunction<ErrorTarget>, ExtractionError> {
147 extract_from_inner_eventually_helper(expr, true)
148 }
149}
150
151fn extract_error_formula(expr: NonNegatedELTLExpression) -> Result<ErrorFormula, ExtractionError> {
157 match expr {
158 NonNegatedELTLExpression::Globally(inner) => {
159 let tgt = ErrorTarget::extract_from_inner_globally(*inner)?;
160 Ok(ErrorFormula::new(InitRestriction::new_top(), tgt))
161 }
162 NonNegatedELTLExpression::Eventually(inner) => {
163 let tgts = ErrorTarget::extract_from_inner_eventually(*inner)?;
164 Ok(tgts
165 .into_iter()
166 .map(|tgt| ErrorAtom::new(InitRestriction::new_top(), tgt))
167 .collect())
168 }
169 NonNegatedELTLExpression::And(lhs, rhs) => {
172 let lhs = extract_error_formula(*lhs)?;
173 let rhs = extract_error_formula(*rhs)?;
174
175 lhs.into_iter()
176 .flat_map(|l| rhs.iter().map(move |r| l.clone().try_and(r.clone())))
177 .collect()
178 }
179 NonNegatedELTLExpression::Or(lhs, rhs) => {
180 let lhs = extract_error_formula(*lhs)?;
181 let rhs = extract_error_formula(*rhs)?;
182
183 Ok(unify_all_possible(lhs, rhs, ErrorAtom::try_unify_or))
184 }
185 NonNegatedELTLExpression::LocationExpr(lhs, op, rhs) => {
188 let constr = BooleanExpression::ComparisonExpression(lhs, op, rhs);
189 let init = InitRestriction::new_location_constraint(constr);
190 Ok(ErrorFormula::new(init, Top))
191 }
192 NonNegatedELTLExpression::VariableExpr(lhs, op, rhs) => {
193 let constr = BooleanExpression::ComparisonExpression(lhs, op, rhs);
194 let init = InitRestriction::new_variable_constraint(constr);
195 Ok(ErrorFormula::new(init, Top))
196 }
197 NonNegatedELTLExpression::ParameterExpr(lhs, op, rhs) => {
198 let constr = BooleanExpression::ComparisonExpression(lhs, op, rhs);
199 let init = InitRestriction::new_parameter_constraint(constr);
200 Ok(ErrorFormula::new(init, Top))
201 }
202 NonNegatedELTLExpression::True => Ok(ErrorFormula::new(InitRestriction::new_top(), Top)),
203 NonNegatedELTLExpression::False => Ok(ErrorFormula::new_bot()),
205 }
206}
207
208fn extract_from_inner_eventually_helper(
215 expr: NonNegatedELTLExpression,
216 ev_not_in_conj: bool,
217) -> Result<Disjunction<ErrorTarget>, ExtractionError> {
218 match expr {
219 NonNegatedELTLExpression::Globally(expr) => {
220 match ErrorTarget::extract_from_inner_globally(*expr)? {
221 Invariant(inv) => {
223 let tgt = ErrorTarget::new_ensure(UpwardsClosedSet::new_top(), inv);
224 Ok([tgt].into())
225 }
226 _ => Err(NestedTemporalOperator),
228 }
229 }
230 NonNegatedELTLExpression::Eventually(expr) => {
231 if !ev_not_in_conj {
233 return Err(ExtractionError::NestedTemporalOperator);
234 }
235 extract_from_inner_eventually_helper(*expr, true)
236 }
237 NonNegatedELTLExpression::And(lhs, rhs) => {
240 let lhs = extract_from_inner_eventually_helper(*lhs, false)?;
241 let rhs = extract_from_inner_eventually_helper(*rhs, false)?;
242
243 Ok(lhs
248 .into_iter()
249 .flat_map(|l| {
250 rhs.iter()
251 .map(move |r| and_inside_eventually(l.clone(), r.clone()))
252 })
253 .collect())
254 }
255
256 NonNegatedELTLExpression::Or(lhs, rhs) => {
257 let lhs = extract_from_inner_eventually_helper(*lhs, ev_not_in_conj)?;
258 let rhs = extract_from_inner_eventually_helper(*rhs, ev_not_in_conj)?;
259
260 let tgts = unify_all_possible(lhs, rhs, ErrorTarget::try_unify_or);
261
262 Ok(tgts)
263 }
264 s => Ok([Reach(extract_atom_helper(s)?)].into()),
265 }
266}
267
268fn extract_from_inner_globally_helper(
276 expr: NonNegatedELTLExpression,
277 appears_in_conj: bool,
278) -> Result<ErrorTarget, ExtractionError> {
279 match expr {
280 NonNegatedELTLExpression::Globally(expr) => {
281 if !appears_in_conj {
282 return Err(ExtractionError::NestedTemporalOperator);
283 }
284
285 extract_from_inner_globally_helper(*expr, true)
286 }
287
288 NonNegatedELTLExpression::Eventually(expr) => {
289 let tgts = ErrorTarget::extract_from_inner_eventually(*expr)?;
290 let inv = tgts
291 .into_iter()
292 .try_fold(UpwardsClosedSet::new_bot(), |acc, tgt| match tgt {
294 Reach(set) => Ok(acc | set),
295 _ => Err(NestedTemporalOperator),
296 })?;
297
298 Ok(Repeat {
299 pre: UpwardsClosedSet::new_top(),
300 inv,
301 })
302 }
303 NonNegatedELTLExpression::And(lhs, rhs) => {
304 let lhs = extract_from_inner_globally_helper(*lhs, appears_in_conj)?;
305 let rhs = extract_from_inner_globally_helper(*rhs, appears_in_conj)?;
306
307 lhs.try_unify_and(&rhs)
308 .ok_or(ExtractionError::UnsupportedConjunction(lhs, rhs))
309 }
310 NonNegatedELTLExpression::Or(lhs, rhs) => {
311 let lhs = extract_from_inner_globally_helper(*lhs, false)?;
312 let rhs = extract_from_inner_globally_helper(*rhs, false)?;
313
314 or_inside_globally(lhs, rhs)
315 }
316 s => Ok(Invariant(extract_atom_helper(s)?)),
318 }
319}
320
321fn or_inside_globally(l: ErrorTarget, r: ErrorTarget) -> Result<ErrorTarget, ExtractionError> {
327 match (l, r) {
328 (Invariant(a), Invariant(b)) => Ok(Invariant(a | b)),
329 (
331 Repeat {
332 pre: pre_l,
333 inv: inv_l,
334 },
335 Repeat {
336 pre: pre_r,
337 inv: inv_r,
338 },
339 ) if pre_l == pre_r => Ok(Repeat {
340 pre: pre_l,
341 inv: inv_l | inv_r,
342 }),
343 (_, _) => Err(NestedTemporalOperator),
345 }
346}
347
348fn and_inside_eventually(l: ErrorTarget, r: ErrorTarget) -> ErrorTarget {
355 match (l, r) {
356 (Top, o) | (o, Top) => o,
357 (Reach(r1), Reach(r2)) => Reach(r1 & r2),
358 (Reach(r), Ensure { pre, inv }) | (Ensure { pre, inv }, Reach(r)) => {
359 Ensure { pre: pre & r, inv }
360 }
361 (
362 Ensure {
363 pre: pre1,
364 inv: inv1,
365 },
366 Ensure {
367 pre: pre2,
368 inv: inv2,
369 },
370 ) => Ensure {
371 pre: pre1 & pre2,
372 inv: inv1 & inv2,
373 },
374 (_, _) => unreachable!("No other target should have been parsed"),
375 }
376}
377
378fn extract_atom_helper(
380 expr: NonNegatedELTLExpression,
381) -> Result<UpwardsClosedSet, ExtractionError> {
382 match expr {
383 NonNegatedELTLExpression::LocationExpr(lhs, op, rhs) => {
384 Ok(UpwardsClosedSet::from_integer_expr(*lhs, op, *rhs)?)
385 }
386 NonNegatedELTLExpression::VariableExpr(lhs, op, rhs) => {
387 let var = LIAVariableConstraint::from_integer_expr(*lhs, op, *rhs)?;
388
389 Ok(UpwardsClosedSet::new_var_constraint(var))
390 }
391 NonNegatedELTLExpression::True => Ok(UpwardsClosedSet::new_top()),
392 NonNegatedELTLExpression::False => Ok(UpwardsClosedSet::new_bot()),
393 NonNegatedELTLExpression::ParameterExpr(_, _, _) => unreachable!(
394 "This case should have been filtered out when validating the specification"
395 ),
396
397 NonNegatedELTLExpression::And(_, _)
398 | NonNegatedELTLExpression::Or(_, _)
399 | NonNegatedELTLExpression::Globally(_)
400 | NonNegatedELTLExpression::Eventually(_) => {
401 unreachable!("This helper should only be used for atoms")
402 }
403 }
404}
405
406fn unify_all_possible<T: PartialEq>(
411 mut lhs: Disjunction<T>,
412 mut rhs: Disjunction<T>,
413 try_unify: impl Fn(&T, &T) -> Option<T>,
414) -> Disjunction<T> {
415 let mut lhs_idx = 0;
416 let mut rhs_idx = 0;
417
418 while lhs_idx < lhs.len() && rhs_idx < rhs.len() {
419 if let Some(unified) = try_unify(&lhs[lhs_idx], &rhs[rhs_idx]) {
420 lhs.0.remove(lhs_idx);
421 rhs.0.remove(rhs_idx);
422
423 lhs.0.push(unified);
424 rhs_idx = 0;
425 continue;
426 }
427
428 if rhs_idx + 1 < rhs.len() {
429 rhs_idx += 1;
430 continue;
431 }
432
433 lhs_idx += 1;
434 rhs_idx = 0;
435 }
436
437 lhs.into_iter().chain(rhs).collect::<Vec<_>>().into()
438}
439
440#[derive(Debug, Clone, PartialEq)]
441pub enum ExtractionError {
442 NestedTemporalOperator,
443 UnsupportedConjunction(ErrorTarget, ErrorTarget),
445 LocationConstraintNotUpwardsClosed(UpwardsClosedSetExtractionError),
446 VariableExprNonLinear(ConstraintRewriteError),
447}
448
449impl fmt::Display for ExtractionError {
450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
451 match self {
452 NestedTemporalOperator => write!(f, "Temporal Operator alternation"),
453 ExtractionError::UnsupportedConjunction(a, b) => {
454 write!(f, "Unsupported Conjunction between'{a}' and {b}")
455 }
456 ExtractionError::LocationConstraintNotUpwardsClosed(err) => {
457 write!(f, "Unsupported Specification: {err}")
458 }
459 ExtractionError::VariableExprNonLinear(err) => {
460 write!(f, "Unsupported Specification: {err}")
461 }
462 }
463 }
464}
465
466impl error::Error for ExtractionError {}
467
468impl From<UpwardsClosedSetExtractionError> for ExtractionError {
469 fn from(value: UpwardsClosedSetExtractionError) -> Self {
470 Self::LocationConstraintNotUpwardsClosed(value)
471 }
472}
473
474impl From<ConstraintRewriteError> for ExtractionError {
475 fn from(value: ConstraintRewriteError) -> Self {
476 Self::VariableExprNonLinear(value)
477 }
478}
479
480#[cfg(test)]
481mod test {
482 use taco_threshold_automaton::{
483 expressions::{
484 BooleanExpression, ComparisonOp, IntegerExpression, Location, Parameter, Variable,
485 },
486 lia_threshold_automaton::{
487 LIAVariableConstraint, integer_thresholds::DeriveFromIntegerComp,
488 },
489 };
490
491 use crate::{
492 eltl::ELTLExpression,
493 internal_spec::{
494 ErrorAtom, ErrorFormula, ErrorSpec, ErrorTarget, InitRestriction,
495 extraction::ExtractionError, upwards_closed_set::UpwardsClosedSet,
496 },
497 };
498
499 #[test]
500 fn simple_ensure() {
501 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
503 Box::new(ELTLExpression::And(
504 Box::new(ELTLExpression::LocationExpr(
505 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
506 ComparisonOp::Gt,
507 Box::new(IntegerExpression::Const(1)),
508 )),
509 Box::new(ELTLExpression::LocationExpr(
510 Box::new(IntegerExpression::Atom(Location::new("loc1"))),
511 ComparisonOp::Eq,
512 Box::new(IntegerExpression::Const(0)),
513 )),
514 )),
515 Box::new(ELTLExpression::VariableExpr(
516 Box::new(IntegerExpression::Atom(Variable::new("var"))),
517 ComparisonOp::Eq,
518 Box::new(IntegerExpression::Const(1)),
519 )),
520 )));
521
522 let got = ErrorSpec::from_named_eltl("test", eltl.clone());
523
524 let loc0_gt_1 = UpwardsClosedSet::from_integer_expr(
527 IntegerExpression::Atom(Location::new("loc0")),
528 ComparisonOp::Gt,
529 IntegerExpression::Const(1),
530 )
531 .unwrap();
532 let loc1_eq_0 = UpwardsClosedSet::from_integer_expr(
533 IntegerExpression::Atom(Location::new("loc1")),
534 ComparisonOp::Eq,
535 IntegerExpression::Const(0),
536 )
537 .unwrap();
538 let var_eq_1 = LIAVariableConstraint::from_integer_expr(
539 IntegerExpression::Atom(Variable::new("var")),
540 ComparisonOp::Eq,
541 IntegerExpression::Const(1),
542 )
543 .unwrap();
544 let inv = (loc0_gt_1 & loc1_eq_0) | UpwardsClosedSet::new_var_constraint(var_eq_1);
545
546 let expected = ErrorSpec {
547 name: "test".to_string(),
548 source: Box::new(eltl.clone()),
549 ef: ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Invariant(inv)),
550 };
551
552 assert!(got.is_ok(), "Error:{}", got.unwrap_err());
553 let got = got.unwrap();
554
555 assert_eq!(got, expected, "Expected:{expected}\nGot:{got}");
556 }
557
558 #[test]
559 fn simple_ensure_distributivity() {
560 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::And(
562 Box::new(ELTLExpression::LocationExpr(
563 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
564 ComparisonOp::Gt,
565 Box::new(IntegerExpression::Const(1)),
566 )),
567 Box::new(ELTLExpression::Globally(Box::new(
568 ELTLExpression::LocationExpr(
569 Box::new(IntegerExpression::Atom(Location::new("loc1"))),
570 ComparisonOp::Eq,
571 Box::new(IntegerExpression::Const(0)),
572 ),
573 ))),
574 )));
575
576 let got = ErrorSpec::from_named_eltl("test", eltl.clone());
577
578 let loc0_gt_1 = UpwardsClosedSet::from_integer_expr(
580 IntegerExpression::Atom(Location::new("loc0")),
581 ComparisonOp::Gt,
582 IntegerExpression::Const(1),
583 )
584 .unwrap();
585 let loc1_eq_0 = UpwardsClosedSet::from_integer_expr(
586 IntegerExpression::Atom(Location::new("loc1")),
587 ComparisonOp::Eq,
588 IntegerExpression::Const(0),
589 )
590 .unwrap();
591
592 let inv = loc0_gt_1 & loc1_eq_0;
593
594 let expected = ErrorSpec {
595 name: "test".to_string(),
596 source: Box::new(eltl.clone()),
597 ef: ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Invariant(inv)),
598 };
599
600 assert!(got.is_ok(), "Error:{}", got.unwrap_err());
601 let got = got.unwrap();
602
603 assert_eq!(got, expected, "Expected:{expected}\nGot:{got}");
604 }
605
606 #[test]
607 fn simple_ensure_not_distributive() {
608 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
610 Box::new(ELTLExpression::LocationExpr(
611 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
612 ComparisonOp::Gt,
613 Box::new(IntegerExpression::Const(1)),
614 )),
615 Box::new(ELTLExpression::Globally(Box::new(
616 ELTLExpression::LocationExpr(
617 Box::new(IntegerExpression::Atom(Location::new("loc1"))),
618 ComparisonOp::Eq,
619 Box::new(IntegerExpression::Const(0)),
620 ),
621 ))),
622 )));
623
624 let got = ErrorSpec::from_named_eltl("test", eltl.clone());
625
626 assert!(
627 !got.is_ok(),
628 "Unexpectedly extracted specification:{}",
629 got.unwrap()
630 );
631 let got = got.unwrap_err();
632
633 let expected = ExtractionError::NestedTemporalOperator;
634
635 assert_eq!(got, expected, "Expected:{expected}\nGot:{got}");
636 }
637
638 #[test]
639 fn simple_ensure_with_init_constr() {
640 let ltl = !ELTLExpression::And(
642 Box::new(ELTLExpression::LocationExpr(
643 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
644 ComparisonOp::Gt,
645 Box::new(IntegerExpression::Const(1)),
646 )),
647 Box::new(ELTLExpression::Globally(Box::new(
648 ELTLExpression::LocationExpr(
649 Box::new(IntegerExpression::Atom(Location::new("loc1"))),
650 ComparisonOp::Eq,
651 Box::new(IntegerExpression::Const(0)),
652 ),
653 ))),
654 );
655
656 let got = ErrorSpec::from_named_eltl("test", ltl.clone());
657
658 let init =
661 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
662 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
663 ComparisonOp::Gt,
664 Box::new(IntegerExpression::Const(1)),
665 ));
666 let inv = UpwardsClosedSet::from_integer_expr(
667 IntegerExpression::Atom(Location::new("loc1")),
668 ComparisonOp::Eq,
669 IntegerExpression::Const(0),
670 )
671 .unwrap();
672
673 let expected = ErrorSpec {
674 name: "test".to_string(),
675 source: Box::new(ltl.clone()),
676 ef: ErrorFormula::new(init, ErrorTarget::Invariant(inv)),
677 };
678
679 assert!(got.is_ok(), "Error:{}", got.unwrap_err());
680 let got = got.unwrap();
681
682 assert_eq!(got, expected, "Expected:{expected}\nGot:{got}");
683 }
684
685 #[test]
686 fn simple_ensure_with_init_constr_two() {
687 let ltl = !ELTLExpression::And(
689 Box::new(ELTLExpression::Or(
690 Box::new(ELTLExpression::LocationExpr(
691 Box::new(IntegerExpression::Atom(Location::new("loc3"))),
692 ComparisonOp::Eq,
693 Box::new(IntegerExpression::Const(0)),
694 )),
695 Box::new(ELTLExpression::LocationExpr(
696 Box::new(IntegerExpression::Atom(Location::new("loc2"))),
697 ComparisonOp::Eq,
698 Box::new(IntegerExpression::Const(0)),
699 )),
700 )),
701 Box::new(ELTLExpression::And(
702 Box::new(ELTLExpression::LocationExpr(
703 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
704 ComparisonOp::Gt,
705 Box::new(IntegerExpression::Const(1)),
706 )),
707 Box::new(ELTLExpression::Globally(Box::new(
708 ELTLExpression::LocationExpr(
709 Box::new(IntegerExpression::Atom(Location::new("loc1"))),
710 ComparisonOp::Eq,
711 Box::new(IntegerExpression::Const(0)),
712 ),
713 ))),
714 )),
715 );
716
717 let got = ErrorSpec::from_named_eltl("test", ltl.clone());
718
719 let loc3_eq_0 = BooleanExpression::ComparisonExpression(
720 Box::new(IntegerExpression::Atom(Location::new("loc3"))),
721 ComparisonOp::Eq,
722 Box::new(IntegerExpression::Const(0)),
723 );
724
725 let loc2_eq_0 = BooleanExpression::ComparisonExpression(
726 Box::new(IntegerExpression::Atom(Location::new("loc2"))),
727 ComparisonOp::Eq,
728 Box::new(IntegerExpression::Const(0)),
729 );
730 let loc0_gt_1 = BooleanExpression::ComparisonExpression(
731 Box::new(IntegerExpression::Atom(Location::new("loc0"))),
732 ComparisonOp::Gt,
733 Box::new(IntegerExpression::Const(1)),
734 );
735 let init = InitRestriction::new_location_constraint(loc3_eq_0 | loc2_eq_0)
736 & InitRestriction::new_location_constraint(loc0_gt_1);
737 let inv = UpwardsClosedSet::from_integer_expr(
738 IntegerExpression::Atom(Location::new("loc1")),
739 ComparisonOp::Eq,
740 IntegerExpression::Const(0),
741 )
742 .unwrap();
743
744 let expected = ErrorSpec {
745 name: "test".to_string(),
746 source: Box::new(ltl.clone()),
747 ef: ErrorFormula::new(init, ErrorTarget::Invariant(inv)),
748 };
749
750 assert!(got.is_ok(), "Error:{}", got.unwrap_err());
751 let got = got.unwrap();
752
753 assert_eq!(got, expected, "Expected:{}\nGot:{}", expected.ef, got.ef);
754 }
755
756 #[test]
757 fn reachability_true() {
758 let eltl = !ELTLExpression::Not(Box::new(ELTLExpression::True));
760
761 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
762
763 assert_eq!(got, ErrorFormula::new_bot());
764 }
765
766 #[test]
767 fn reachability_false() {
768 let eltl = ELTLExpression::False;
770
771 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
772
773 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Top);
774 assert_eq!(got, expected);
775 }
776
777 #[test]
778 fn reachability_parameter_atom() {
779 let eltl = ELTLExpression::ParameterExpr(
781 Box::new(IntegerExpression::Param(Parameter::new("n"))),
782 ComparisonOp::Eq,
783 Box::new(IntegerExpression::Const(3)),
784 );
785
786 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
787
788 let init =
789 InitRestriction::new_parameter_constraint(BooleanExpression::ComparisonExpression(
790 Box::new(IntegerExpression::Param(Parameter::new("n"))),
791 ComparisonOp::Neq,
792 Box::new(IntegerExpression::Const(3)),
793 ));
794 let expected = ErrorFormula::new(init, ErrorTarget::Top);
795 assert_eq!(got, expected);
796 }
797
798 #[test]
799 fn reachability_variable_atom() {
800 let eltl = ELTLExpression::VariableExpr(
802 Box::new(IntegerExpression::Atom(Variable::new("v"))),
803 ComparisonOp::Lt,
804 Box::new(IntegerExpression::Param(Parameter::new("n"))),
805 );
806
807 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
808
809 let init =
810 InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
811 Box::new(IntegerExpression::Atom(Variable::new("v"))),
812 ComparisonOp::Geq,
813 Box::new(IntegerExpression::Param(Parameter::new("n"))),
814 ));
815 let expected = ErrorFormula::new(init, ErrorTarget::Top);
816 assert_eq!(got, expected);
817 }
818
819 #[test]
820 fn reachability_location_atom() {
821 let eltl = ELTLExpression::LocationExpr(
823 Box::new(IntegerExpression::Atom(Location::new("l"))),
824 ComparisonOp::Lt,
825 Box::new(IntegerExpression::Param(Parameter::new("n"))),
826 );
827
828 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
829
830 let init =
831 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
832 Box::new(IntegerExpression::Atom(Location::new("l"))),
833 ComparisonOp::Geq,
834 Box::new(IntegerExpression::Param(Parameter::new("n"))),
835 ));
836 let expected = ErrorFormula::new(init, ErrorTarget::Top);
837 assert_eq!(got, expected);
838 }
839
840 #[test]
841 fn reachability_and_of_atoms() {
842 let eltl = ELTLExpression::And(
844 Box::new(ELTLExpression::LocationExpr(
845 Box::new(IntegerExpression::Atom(Location::new("l"))),
846 ComparisonOp::Lt,
847 Box::new(IntegerExpression::Const(1)),
848 )),
849 Box::new(ELTLExpression::VariableExpr(
850 Box::new(IntegerExpression::Atom(Variable::new("v"))),
851 ComparisonOp::Lt,
852 Box::new(IntegerExpression::Const(3)),
853 )),
854 );
855
856 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
857
858 let init_l =
861 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
862 Box::new(IntegerExpression::Atom(Location::new("l"))),
863 ComparisonOp::Geq,
864 Box::new(IntegerExpression::Const(1)),
865 ));
866 let init_v =
867 InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
868 Box::new(IntegerExpression::Atom(Variable::new("v"))),
869 ComparisonOp::Geq,
870 Box::new(IntegerExpression::Const(3)),
871 ));
872 let expected = ErrorFormula::from([
873 ErrorAtom::new(init_l, ErrorTarget::Top),
874 ErrorAtom::new(init_v, ErrorTarget::Top),
875 ]);
876 assert_eq!(got, expected);
877 }
878
879 #[test]
880 fn reachability_or_of_atoms() {
881 let eltl = ELTLExpression::Or(
884 Box::new(ELTLExpression::LocationExpr(
885 Box::new(IntegerExpression::Atom(Location::new("l"))),
886 ComparisonOp::Lt,
887 Box::new(IntegerExpression::Const(1)),
888 )),
889 Box::new(ELTLExpression::VariableExpr(
890 Box::new(IntegerExpression::Atom(Variable::new("v"))),
891 ComparisonOp::Lt,
892 Box::new(IntegerExpression::Const(3)),
893 )),
894 );
895
896 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
897
898 let init =
899 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
900 Box::new(IntegerExpression::Atom(Location::new("l"))),
901 ComparisonOp::Geq,
902 Box::new(IntegerExpression::Const(1)),
903 )) & InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
904 Box::new(IntegerExpression::Atom(Variable::new("v"))),
905 ComparisonOp::Geq,
906 Box::new(IntegerExpression::Const(3)),
907 ));
908 let expected = ErrorFormula::new(init, ErrorTarget::Top);
909 assert_eq!(got, expected);
910 }
911
912 #[test]
913 fn reachability_negated_and_of_atoms() {
914 let eltl = ELTLExpression::Not(Box::new(ELTLExpression::And(
916 Box::new(ELTLExpression::LocationExpr(
917 Box::new(IntegerExpression::Atom(Location::new("l"))),
918 ComparisonOp::Lt,
919 Box::new(IntegerExpression::Const(1)),
920 )),
921 Box::new(ELTLExpression::VariableExpr(
922 Box::new(IntegerExpression::Atom(Variable::new("v"))),
923 ComparisonOp::Lt,
924 Box::new(IntegerExpression::Const(3)),
925 )),
926 )));
927
928 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
929
930 let init =
931 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
932 Box::new(IntegerExpression::Atom(Location::new("l"))),
933 ComparisonOp::Lt,
934 Box::new(IntegerExpression::Const(1)),
935 )) & InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
936 Box::new(IntegerExpression::Atom(Variable::new("v"))),
937 ComparisonOp::Lt,
938 Box::new(IntegerExpression::Const(3)),
939 ));
940 let expected = ErrorFormula::new(init, ErrorTarget::Top);
941 assert_eq!(got, expected);
942 }
943
944 #[test]
945 fn reachability_globally_true() {
946 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::True));
948
949 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
950
951 let expected = ErrorFormula::new(
952 InitRestriction::new_top(),
953 ErrorTarget::Reach(UpwardsClosedSet::new_bot()),
954 );
955 assert_eq!(got, expected);
956 }
957
958 #[test]
959 fn reachability_globally_false() {
960 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::False));
962
963 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
964
965 let expected = ErrorFormula::new(
966 InitRestriction::new_top(),
967 ErrorTarget::Reach(UpwardsClosedSet::new_top()),
968 );
969 assert_eq!(got, expected);
970 }
971
972 #[test]
973 fn reachability_globally_variable() {
974 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::VariableExpr(
976 Box::new(IntegerExpression::Atom(Variable::new("v"))),
977 ComparisonOp::Lt,
978 Box::new(IntegerExpression::Param(Parameter::new("n"))),
979 )));
980
981 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
982
983 let target = UpwardsClosedSet::new_var_constraint(
984 LIAVariableConstraint::from_integer_expr(
985 IntegerExpression::Atom(Variable::new("v")),
986 ComparisonOp::Geq,
987 IntegerExpression::Param(Parameter::new("n")),
988 )
989 .unwrap(),
990 );
991 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Reach(target));
992 assert_eq!(got, expected);
993 }
994
995 #[test]
996 fn reachability_globally_location() {
997 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::LocationExpr(
999 Box::new(IntegerExpression::Atom(Location::new("l"))),
1000 ComparisonOp::Eq,
1001 Box::new(IntegerExpression::Const(0)),
1002 )));
1003
1004 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1005
1006 let target = UpwardsClosedSet::new_cover([Location::new("l")]);
1007 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Reach(target));
1008 assert_eq!(got, expected);
1009 }
1010
1011 #[test]
1012 fn reachability_globally_or() {
1013 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::Or(
1015 Box::new(ELTLExpression::LocationExpr(
1016 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1017 ComparisonOp::Eq,
1018 Box::new(IntegerExpression::Const(0)),
1019 )),
1020 Box::new(ELTLExpression::LocationExpr(
1021 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1022 ComparisonOp::Neq,
1023 Box::new(IntegerExpression::Const(0)),
1024 )),
1025 )));
1026
1027 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1028
1029 let target = UpwardsClosedSet::new_reach([(Location::new("l1"), 1)], [Location::new("l2")]);
1030 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Reach(target));
1031 assert_eq!(got, expected);
1032 }
1033
1034 #[test]
1035 fn reachability_globally_and() {
1036 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::And(
1038 Box::new(ELTLExpression::LocationExpr(
1039 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1040 ComparisonOp::Eq,
1041 Box::new(IntegerExpression::Const(0)),
1042 )),
1043 Box::new(ELTLExpression::LocationExpr(
1044 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1045 ComparisonOp::Neq,
1046 Box::new(IntegerExpression::Const(0)),
1047 )),
1048 )));
1049
1050 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1051
1052 let target = UpwardsClosedSet::new_cover([Location::new("l1")])
1054 | UpwardsClosedSet::new_reach([], [Location::new("l2")]);
1055 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Reach(target));
1056 assert_eq!(got, expected);
1057 }
1058
1059 #[test]
1060 fn reachability_nested_globally() {
1061 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::Globally(Box::new(
1063 ELTLExpression::Or(
1064 Box::new(ELTLExpression::LocationExpr(
1065 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1066 ComparisonOp::Eq,
1067 Box::new(IntegerExpression::Const(0)),
1068 )),
1069 Box::new(ELTLExpression::LocationExpr(
1070 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1071 ComparisonOp::Neq,
1072 Box::new(IntegerExpression::Const(0)),
1073 )),
1074 ),
1075 ))));
1076
1077 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1078
1079 let target = UpwardsClosedSet::new_reach([(Location::new("l1"), 1)], [Location::new("l2")]);
1080 let expected = ErrorFormula::new(InitRestriction::new_top(), ErrorTarget::Reach(target));
1081 assert_eq!(got, expected);
1082 }
1083
1084 #[test]
1085 fn reachability_globally_or_nested_globally() {
1086 let eltl = ELTLExpression::Globally(Box::new(ELTLExpression::Or(
1092 Box::new(ELTLExpression::LocationExpr(
1093 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1094 ComparisonOp::Eq,
1095 Box::new(IntegerExpression::Const(0)),
1096 )),
1097 Box::new(ELTLExpression::Globally(Box::new(
1098 ELTLExpression::LocationExpr(
1099 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1100 ComparisonOp::Neq,
1101 Box::new(IntegerExpression::Const(0)),
1102 ),
1103 ))),
1104 )));
1105
1106 let got = ErrorSpec::from_named_eltl("test", eltl);
1107
1108 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
1109 }
1110
1111 #[test]
1112 fn reachability_implies_globally_or_nested_globally() {
1113 let eltl = ELTLExpression::Implies(
1118 Box::new(ELTLExpression::VariableExpr(
1119 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1120 ComparisonOp::Eq,
1121 Box::new(IntegerExpression::Const(0)),
1122 )),
1123 Box::new(ELTLExpression::Globally(Box::new(ELTLExpression::Or(
1124 Box::new(ELTLExpression::LocationExpr(
1125 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1126 ComparisonOp::Eq,
1127 Box::new(IntegerExpression::Const(0)),
1128 )),
1129 Box::new(ELTLExpression::Globally(Box::new(
1130 ELTLExpression::LocationExpr(
1131 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1132 ComparisonOp::Neq,
1133 Box::new(IntegerExpression::Const(0)),
1134 ),
1135 ))),
1136 )))),
1137 );
1138
1139 let got = ErrorSpec::from_named_eltl("test", eltl);
1140
1141 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
1142 }
1143
1144 #[test]
1145 fn reachability_or_negated_and_globally() {
1146 let eltl = ELTLExpression::Or(
1149 Box::new(ELTLExpression::Not(Box::new(ELTLExpression::And(
1150 Box::new(ELTLExpression::LocationExpr(
1151 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1152 ComparisonOp::Eq,
1153 Box::new(IntegerExpression::Const(0)),
1154 )),
1155 Box::new(ELTLExpression::LocationExpr(
1156 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1157 ComparisonOp::Eq,
1158 Box::new(IntegerExpression::Const(0)),
1159 )),
1160 )))),
1161 Box::new(ELTLExpression::Globally(Box::new(
1162 ELTLExpression::LocationExpr(
1163 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1164 ComparisonOp::Eq,
1165 Box::new(IntegerExpression::Const(0)),
1166 ),
1167 ))),
1168 );
1169
1170 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1171
1172 let init =
1173 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
1174 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1175 ComparisonOp::Eq,
1176 Box::new(IntegerExpression::Const(0)),
1177 )) & InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
1178 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1179 ComparisonOp::Eq,
1180 Box::new(IntegerExpression::Const(0)),
1181 ));
1182 let target = UpwardsClosedSet::new_cover([Location::new("l2")]);
1183 let expected = ErrorFormula::new(init, ErrorTarget::Reach(target));
1184 assert_eq!(got, expected);
1185 }
1186
1187 #[test]
1191 fn ensure_true_and_false() {
1192 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::True));
1194
1195 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1196
1197 let expected = ErrorFormula::new(
1198 InitRestriction::new_top(),
1199 ErrorTarget::Invariant(UpwardsClosedSet::new_top()),
1200 );
1201 assert_eq!(got, expected);
1202
1203 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::False));
1205
1206 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1207
1208 let expected = ErrorFormula::new(
1209 InitRestriction::new_top(),
1210 ErrorTarget::Invariant(UpwardsClosedSet::new_bot()),
1211 );
1212 assert_eq!(got, expected);
1213 }
1214
1215 #[test]
1216 fn ensure_and_of_globally() {
1217 let eltl = !ELTLExpression::And(
1219 Box::new(ELTLExpression::Globally(Box::new(
1220 ELTLExpression::LocationExpr(
1221 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1222 ComparisonOp::Gt,
1223 Box::new(IntegerExpression::Const(1)),
1224 ),
1225 ))),
1226 Box::new(ELTLExpression::Globally(Box::new(
1227 ELTLExpression::LocationExpr(
1228 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1229 ComparisonOp::Eq,
1230 Box::new(IntegerExpression::Const(0)),
1231 ),
1232 ))),
1233 );
1234
1235 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1236
1237 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1238 IntegerExpression::Atom(Location::new("l0")),
1239 ComparisonOp::Gt,
1240 IntegerExpression::Const(1),
1241 )
1242 .unwrap();
1243 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1244 IntegerExpression::Atom(Location::new("l1")),
1245 ComparisonOp::Eq,
1246 IntegerExpression::Const(0),
1247 )
1248 .unwrap();
1249 let expected = ErrorFormula::new(
1250 InitRestriction::new_top(),
1251 ErrorTarget::Invariant(l0_gt_1 & l1_eq_0),
1252 );
1253 assert_eq!(got, expected);
1254 }
1255
1256 #[test]
1257 fn ensure_or_of_globally() {
1258 let eltl = !ELTLExpression::Or(
1260 Box::new(ELTLExpression::Globally(Box::new(
1261 ELTLExpression::LocationExpr(
1262 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1263 ComparisonOp::Gt,
1264 Box::new(IntegerExpression::Const(1)),
1265 ),
1266 ))),
1267 Box::new(ELTLExpression::Globally(Box::new(
1268 ELTLExpression::LocationExpr(
1269 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1270 ComparisonOp::Eq,
1271 Box::new(IntegerExpression::Const(0)),
1272 ),
1273 ))),
1274 );
1275
1276 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1277
1278 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1279 IntegerExpression::Atom(Location::new("l0")),
1280 ComparisonOp::Gt,
1281 IntegerExpression::Const(1),
1282 )
1283 .unwrap();
1284 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1285 IntegerExpression::Atom(Location::new("l1")),
1286 ComparisonOp::Eq,
1287 IntegerExpression::Const(0),
1288 )
1289 .unwrap();
1290 let expected = ErrorFormula::from([
1291 ErrorAtom::new(InitRestriction::new_top(), ErrorTarget::Invariant(l0_gt_1)),
1292 ErrorAtom::new(InitRestriction::new_top(), ErrorTarget::Invariant(l1_eq_0)),
1293 ]);
1294 assert_eq!(got, expected);
1295 }
1296
1297 #[test]
1298 fn ensure_or_with_init_atom() {
1299 let eltl = !ELTLExpression::Or(
1301 Box::new(ELTLExpression::Globally(Box::new(
1302 ELTLExpression::LocationExpr(
1303 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1304 ComparisonOp::Gt,
1305 Box::new(IntegerExpression::Const(1)),
1306 ),
1307 ))),
1308 Box::new(ELTLExpression::VariableExpr(
1309 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1310 ComparisonOp::Eq,
1311 Box::new(IntegerExpression::Const(1)),
1312 )),
1313 );
1314
1315 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1316
1317 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1318 IntegerExpression::Atom(Location::new("l0")),
1319 ComparisonOp::Gt,
1320 IntegerExpression::Const(1),
1321 )
1322 .unwrap();
1323 let init_v =
1324 InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
1325 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1326 ComparisonOp::Eq,
1327 Box::new(IntegerExpression::Const(1)),
1328 ));
1329 let expected = ErrorFormula::from([
1330 ErrorAtom::new(InitRestriction::new_top(), ErrorTarget::Invariant(l0_gt_1)),
1331 ErrorAtom::new(init_v, ErrorTarget::Top),
1332 ]);
1333 assert_eq!(got, expected);
1334 }
1335
1336 #[test]
1337 fn ensure_with_init_or_of_two_kinds() {
1338 let eltl = !ELTLExpression::And(
1341 Box::new(ELTLExpression::Or(
1342 Box::new(ELTLExpression::LocationExpr(
1343 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1344 ComparisonOp::Gt,
1345 Box::new(IntegerExpression::Const(1)),
1346 )),
1347 Box::new(ELTLExpression::VariableExpr(
1348 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1349 ComparisonOp::Eq,
1350 Box::new(IntegerExpression::Const(1)),
1351 )),
1352 )),
1353 Box::new(ELTLExpression::Globally(Box::new(
1354 ELTLExpression::LocationExpr(
1355 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1356 ComparisonOp::Eq,
1357 Box::new(IntegerExpression::Const(0)),
1358 ),
1359 ))),
1360 );
1361
1362 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1363
1364 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1365 IntegerExpression::Atom(Location::new("l1")),
1366 ComparisonOp::Eq,
1367 IntegerExpression::Const(0),
1368 )
1369 .unwrap();
1370 let init_l0 =
1371 InitRestriction::new_location_constraint(BooleanExpression::ComparisonExpression(
1372 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1373 ComparisonOp::Gt,
1374 Box::new(IntegerExpression::Const(1)),
1375 ));
1376 let init_v =
1377 InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
1378 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1379 ComparisonOp::Eq,
1380 Box::new(IntegerExpression::Const(1)),
1381 ));
1382 let expected = ErrorFormula::from([
1383 ErrorAtom::new(init_l0, ErrorTarget::Invariant(l1_eq_0.clone())),
1384 ErrorAtom::new(init_v, ErrorTarget::Invariant(l1_eq_0)),
1385 ]);
1386 assert_eq!(got, expected);
1387 }
1388
1389 #[test]
1390 fn ensure_or_below_and_with_nested_globally() {
1391 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::And(
1394 Box::new(ELTLExpression::Or(
1395 Box::new(ELTLExpression::LocationExpr(
1396 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1397 ComparisonOp::Gt,
1398 Box::new(IntegerExpression::Const(1)),
1399 )),
1400 Box::new(ELTLExpression::LocationExpr(
1401 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1402 ComparisonOp::Eq,
1403 Box::new(IntegerExpression::Const(0)),
1404 )),
1405 )),
1406 Box::new(ELTLExpression::Globally(Box::new(
1407 ELTLExpression::VariableExpr(
1408 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1409 ComparisonOp::Eq,
1410 Box::new(IntegerExpression::Const(1)),
1411 ),
1412 ))),
1413 )));
1414
1415 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1416
1417 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1418 IntegerExpression::Atom(Location::new("l0")),
1419 ComparisonOp::Gt,
1420 IntegerExpression::Const(1),
1421 )
1422 .unwrap();
1423 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1424 IntegerExpression::Atom(Location::new("l1")),
1425 ComparisonOp::Eq,
1426 IntegerExpression::Const(0),
1427 )
1428 .unwrap();
1429 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1430 LIAVariableConstraint::from_integer_expr(
1431 IntegerExpression::Atom(Variable::new("v")),
1432 ComparisonOp::Eq,
1433 IntegerExpression::Const(1),
1434 )
1435 .unwrap(),
1436 );
1437 let expected = ErrorFormula::new(
1438 InitRestriction::new_top(),
1439 ErrorTarget::Invariant((l0_gt_1 | l1_eq_0) & v_eq_1),
1440 );
1441 assert_eq!(got, expected);
1442 }
1443
1444 #[test]
1445 fn ensure_and_below_or_with_nested_globally() {
1446 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
1448 Box::new(ELTLExpression::LocationExpr(
1449 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1450 ComparisonOp::Gt,
1451 Box::new(IntegerExpression::Const(1)),
1452 )),
1453 Box::new(ELTLExpression::And(
1454 Box::new(ELTLExpression::LocationExpr(
1455 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1456 ComparisonOp::Eq,
1457 Box::new(IntegerExpression::Const(0)),
1458 )),
1459 Box::new(ELTLExpression::Globally(Box::new(
1460 ELTLExpression::VariableExpr(
1461 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1462 ComparisonOp::Eq,
1463 Box::new(IntegerExpression::Const(1)),
1464 ),
1465 ))),
1466 )),
1467 )));
1468
1469 let got = ErrorSpec::from_named_eltl("test", eltl);
1470
1471 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
1472 }
1473
1474 #[test]
1475 fn ensure_and_reach_unsupported() {
1476 let eltl = !ELTLExpression::And(
1478 Box::new(ELTLExpression::Globally(Box::new(
1479 ELTLExpression::LocationExpr(
1480 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1481 ComparisonOp::Gt,
1482 Box::new(IntegerExpression::Const(1)),
1483 ),
1484 ))),
1485 Box::new(ELTLExpression::Eventually(Box::new(
1486 ELTLExpression::LocationExpr(
1487 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1488 ComparisonOp::Eq,
1489 Box::new(IntegerExpression::Const(0)),
1490 ),
1491 ))),
1492 );
1493
1494 let got = ErrorSpec::from_named_eltl("test", eltl);
1495
1496 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1497 IntegerExpression::Atom(Location::new("l0")),
1498 ComparisonOp::Gt,
1499 IntegerExpression::Const(1),
1500 )
1501 .unwrap();
1502 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1503 IntegerExpression::Atom(Location::new("l1")),
1504 ComparisonOp::Eq,
1505 IntegerExpression::Const(0),
1506 )
1507 .unwrap();
1508 let expected = ExtractionError::UnsupportedConjunction(
1509 ErrorTarget::Invariant(l0_gt_1),
1510 ErrorTarget::Reach(l1_eq_0),
1511 );
1512 assert_eq!(got, Err(expected));
1513 }
1514
1515 #[test]
1516 fn repeat_simple() {
1517 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1519 Box::new(ELTLExpression::LocationExpr(
1520 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1521 ComparisonOp::Gt,
1522 Box::new(IntegerExpression::Const(1)),
1523 )),
1524 Box::new(ELTLExpression::Globally(Box::new(
1525 ELTLExpression::LocationExpr(
1526 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1527 ComparisonOp::Eq,
1528 Box::new(IntegerExpression::Const(0)),
1529 ),
1530 ))),
1531 )));
1532
1533 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1534
1535 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1536 IntegerExpression::Atom(Location::new("l0")),
1537 ComparisonOp::Gt,
1538 IntegerExpression::Const(1),
1539 )
1540 .unwrap();
1541 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1542 IntegerExpression::Atom(Location::new("l1")),
1543 ComparisonOp::Eq,
1544 IntegerExpression::Const(0),
1545 )
1546 .unwrap();
1547 let expected = ErrorFormula::new(
1548 InitRestriction::new_top(),
1549 ErrorTarget::new_ensure(l0_gt_1, l1_eq_0),
1550 );
1551 assert_eq!(got, expected);
1552 }
1553
1554 #[test]
1555 fn repeat_globally_only() {
1556 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::Globally(Box::new(
1558 ELTLExpression::LocationExpr(
1559 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1560 ComparisonOp::Eq,
1561 Box::new(IntegerExpression::Const(0)),
1562 ),
1563 ))));
1564
1565 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1566
1567 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1568 IntegerExpression::Atom(Location::new("l1")),
1569 ComparisonOp::Eq,
1570 IntegerExpression::Const(0),
1571 )
1572 .unwrap();
1573 let expected = ErrorFormula::new(
1574 InitRestriction::new_top(),
1575 ErrorTarget::new_ensure(UpwardsClosedSet::new_top(), l1_eq_0),
1576 );
1577 assert_eq!(got, expected);
1578 }
1579
1580 #[test]
1581 fn repeat_with_init() {
1582 let eltl = !ELTLExpression::And(
1584 Box::new(ELTLExpression::VariableExpr(
1585 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1586 ComparisonOp::Eq,
1587 Box::new(IntegerExpression::Const(1)),
1588 )),
1589 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1590 Box::new(ELTLExpression::LocationExpr(
1591 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1592 ComparisonOp::Gt,
1593 Box::new(IntegerExpression::Const(1)),
1594 )),
1595 Box::new(ELTLExpression::Globally(Box::new(
1596 ELTLExpression::LocationExpr(
1597 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1598 ComparisonOp::Eq,
1599 Box::new(IntegerExpression::Const(0)),
1600 ),
1601 ))),
1602 )))),
1603 );
1604
1605 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1606
1607 let init =
1608 InitRestriction::new_variable_constraint(BooleanExpression::ComparisonExpression(
1609 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1610 ComparisonOp::Eq,
1611 Box::new(IntegerExpression::Const(1)),
1612 ));
1613 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1614 IntegerExpression::Atom(Location::new("l0")),
1615 ComparisonOp::Gt,
1616 IntegerExpression::Const(1),
1617 )
1618 .unwrap();
1619 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1620 IntegerExpression::Atom(Location::new("l1")),
1621 ComparisonOp::Eq,
1622 IntegerExpression::Const(0),
1623 )
1624 .unwrap();
1625 let expected = ErrorFormula::new(init, ErrorTarget::new_ensure(l0_gt_1, l1_eq_0));
1626 assert_eq!(got, expected);
1627 }
1628
1629 #[test]
1630 fn repeat_and_of_two_globally() {
1631 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1634 Box::new(ELTLExpression::LocationExpr(
1635 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1636 ComparisonOp::Gt,
1637 Box::new(IntegerExpression::Const(1)),
1638 )),
1639 Box::new(ELTLExpression::And(
1640 Box::new(ELTLExpression::Globally(Box::new(
1641 ELTLExpression::LocationExpr(
1642 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1643 ComparisonOp::Eq,
1644 Box::new(IntegerExpression::Const(0)),
1645 ),
1646 ))),
1647 Box::new(ELTLExpression::Globally(Box::new(
1648 ELTLExpression::VariableExpr(
1649 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1650 ComparisonOp::Eq,
1651 Box::new(IntegerExpression::Const(1)),
1652 ),
1653 ))),
1654 )),
1655 )));
1656
1657 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1658
1659 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1660 IntegerExpression::Atom(Location::new("l0")),
1661 ComparisonOp::Gt,
1662 IntegerExpression::Const(1),
1663 )
1664 .unwrap();
1665 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1666 IntegerExpression::Atom(Location::new("l1")),
1667 ComparisonOp::Eq,
1668 IntegerExpression::Const(0),
1669 )
1670 .unwrap();
1671 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1672 LIAVariableConstraint::from_integer_expr(
1673 IntegerExpression::Atom(Variable::new("v")),
1674 ComparisonOp::Eq,
1675 IntegerExpression::Const(1),
1676 )
1677 .unwrap(),
1678 );
1679 let expected = ErrorFormula::new(
1680 InitRestriction::new_top(),
1681 ErrorTarget::new_ensure(l0_gt_1, l1_eq_0 & v_eq_1),
1682 );
1683 assert_eq!(got, expected);
1684 }
1685
1686 #[test]
1687 fn repeat_nested_globally_in_globally() {
1688 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1691 Box::new(ELTLExpression::LocationExpr(
1692 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1693 ComparisonOp::Gt,
1694 Box::new(IntegerExpression::Const(1)),
1695 )),
1696 Box::new(ELTLExpression::Globally(Box::new(ELTLExpression::And(
1697 Box::new(ELTLExpression::LocationExpr(
1698 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1699 ComparisonOp::Eq,
1700 Box::new(IntegerExpression::Const(0)),
1701 )),
1702 Box::new(ELTLExpression::Globally(Box::new(
1703 ELTLExpression::VariableExpr(
1704 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1705 ComparisonOp::Eq,
1706 Box::new(IntegerExpression::Const(1)),
1707 ),
1708 ))),
1709 )))),
1710 )));
1711
1712 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1713
1714 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1715 IntegerExpression::Atom(Location::new("l0")),
1716 ComparisonOp::Gt,
1717 IntegerExpression::Const(1),
1718 )
1719 .unwrap();
1720 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1721 IntegerExpression::Atom(Location::new("l1")),
1722 ComparisonOp::Eq,
1723 IntegerExpression::Const(0),
1724 )
1725 .unwrap();
1726 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1727 LIAVariableConstraint::from_integer_expr(
1728 IntegerExpression::Atom(Variable::new("v")),
1729 ComparisonOp::Eq,
1730 IntegerExpression::Const(1),
1731 )
1732 .unwrap(),
1733 );
1734 let expected = ErrorFormula::new(
1735 InitRestriction::new_top(),
1736 ErrorTarget::new_ensure(l0_gt_1, l1_eq_0 & v_eq_1),
1737 );
1738 assert_eq!(got, expected);
1739 }
1740
1741 #[test]
1742 fn repeat_or_of_same_invariant() {
1743 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::Or(
1746 Box::new(ELTLExpression::And(
1747 Box::new(ELTLExpression::LocationExpr(
1748 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1749 ComparisonOp::Gt,
1750 Box::new(IntegerExpression::Const(1)),
1751 )),
1752 Box::new(ELTLExpression::Globally(Box::new(
1753 ELTLExpression::VariableExpr(
1754 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1755 ComparisonOp::Eq,
1756 Box::new(IntegerExpression::Const(1)),
1757 ),
1758 ))),
1759 )),
1760 Box::new(ELTLExpression::And(
1761 Box::new(ELTLExpression::LocationExpr(
1762 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1763 ComparisonOp::Eq,
1764 Box::new(IntegerExpression::Const(0)),
1765 )),
1766 Box::new(ELTLExpression::Globally(Box::new(
1767 ELTLExpression::VariableExpr(
1768 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1769 ComparisonOp::Eq,
1770 Box::new(IntegerExpression::Const(1)),
1771 ),
1772 ))),
1773 )),
1774 )));
1775
1776 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1777
1778 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1779 IntegerExpression::Atom(Location::new("l0")),
1780 ComparisonOp::Gt,
1781 IntegerExpression::Const(1),
1782 )
1783 .unwrap();
1784 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1785 IntegerExpression::Atom(Location::new("l1")),
1786 ComparisonOp::Eq,
1787 IntegerExpression::Const(0),
1788 )
1789 .unwrap();
1790 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1791 LIAVariableConstraint::from_integer_expr(
1792 IntegerExpression::Atom(Variable::new("v")),
1793 ComparisonOp::Eq,
1794 IntegerExpression::Const(1),
1795 )
1796 .unwrap(),
1797 );
1798 let expected = ErrorFormula::new(
1799 InitRestriction::new_top(),
1800 ErrorTarget::new_ensure(l0_gt_1 | l1_eq_0, v_eq_1),
1801 );
1802 assert_eq!(got, expected);
1803 }
1804
1805 #[test]
1806 fn repeat_or_of_different_invariants() {
1807 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::Or(
1809 Box::new(ELTLExpression::Globally(Box::new(
1810 ELTLExpression::LocationExpr(
1811 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1812 ComparisonOp::Gt,
1813 Box::new(IntegerExpression::Const(1)),
1814 ),
1815 ))),
1816 Box::new(ELTLExpression::Globally(Box::new(
1817 ELTLExpression::LocationExpr(
1818 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1819 ComparisonOp::Eq,
1820 Box::new(IntegerExpression::Const(0)),
1821 ),
1822 ))),
1823 )));
1824
1825 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1826
1827 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1828 IntegerExpression::Atom(Location::new("l0")),
1829 ComparisonOp::Gt,
1830 IntegerExpression::Const(1),
1831 )
1832 .unwrap();
1833 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1834 IntegerExpression::Atom(Location::new("l1")),
1835 ComparisonOp::Eq,
1836 IntegerExpression::Const(0),
1837 )
1838 .unwrap();
1839 let expected = ErrorFormula::from([
1840 ErrorAtom::new(
1841 InitRestriction::new_top(),
1842 ErrorTarget::new_ensure(UpwardsClosedSet::new_top(), l0_gt_1),
1843 ),
1844 ErrorAtom::new(
1845 InitRestriction::new_top(),
1846 ErrorTarget::new_ensure(UpwardsClosedSet::new_top(), l1_eq_0),
1847 ),
1848 ]);
1849 assert_eq!(got, expected);
1850 }
1851
1852 #[test]
1853 fn repeat_and_distributes_over_or() {
1854 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1857 Box::new(ELTLExpression::LocationExpr(
1858 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1859 ComparisonOp::Gt,
1860 Box::new(IntegerExpression::Const(1)),
1861 )),
1862 Box::new(ELTLExpression::Or(
1863 Box::new(ELTLExpression::LocationExpr(
1864 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1865 ComparisonOp::Eq,
1866 Box::new(IntegerExpression::Const(0)),
1867 )),
1868 Box::new(ELTLExpression::Globally(Box::new(
1869 ELTLExpression::VariableExpr(
1870 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1871 ComparisonOp::Eq,
1872 Box::new(IntegerExpression::Const(1)),
1873 ),
1874 ))),
1875 )),
1876 )));
1877
1878 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1879
1880 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1881 IntegerExpression::Atom(Location::new("l0")),
1882 ComparisonOp::Gt,
1883 IntegerExpression::Const(1),
1884 )
1885 .unwrap();
1886 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1887 IntegerExpression::Atom(Location::new("l1")),
1888 ComparisonOp::Eq,
1889 IntegerExpression::Const(0),
1890 )
1891 .unwrap();
1892 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1893 LIAVariableConstraint::from_integer_expr(
1894 IntegerExpression::Atom(Variable::new("v")),
1895 ComparisonOp::Eq,
1896 IntegerExpression::Const(1),
1897 )
1898 .unwrap(),
1899 );
1900 let expected = ErrorFormula::from([
1901 ErrorAtom::new(
1902 InitRestriction::new_top(),
1903 ErrorTarget::Reach(l0_gt_1.clone() & l1_eq_0),
1904 ),
1905 ErrorAtom::new(
1906 InitRestriction::new_top(),
1907 ErrorTarget::new_ensure(l0_gt_1, v_eq_1),
1908 ),
1909 ]);
1910 assert_eq!(got, expected);
1911 }
1912
1913 #[test]
1914 fn repeat_product_of_two_ors() {
1915 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
1917 Box::new(ELTLExpression::Or(
1918 Box::new(ELTLExpression::Globally(Box::new(
1919 ELTLExpression::LocationExpr(
1920 Box::new(IntegerExpression::Atom(Location::new("l0"))),
1921 ComparisonOp::Gt,
1922 Box::new(IntegerExpression::Const(1)),
1923 ),
1924 ))),
1925 Box::new(ELTLExpression::LocationExpr(
1926 Box::new(IntegerExpression::Atom(Location::new("l1"))),
1927 ComparisonOp::Eq,
1928 Box::new(IntegerExpression::Const(0)),
1929 )),
1930 )),
1931 Box::new(ELTLExpression::Or(
1932 Box::new(ELTLExpression::Globally(Box::new(
1933 ELTLExpression::VariableExpr(
1934 Box::new(IntegerExpression::Atom(Variable::new("v"))),
1935 ComparisonOp::Eq,
1936 Box::new(IntegerExpression::Const(1)),
1937 ),
1938 ))),
1939 Box::new(ELTLExpression::LocationExpr(
1940 Box::new(IntegerExpression::Atom(Location::new("l2"))),
1941 ComparisonOp::Gt,
1942 Box::new(IntegerExpression::Const(0)),
1943 )),
1944 )),
1945 )));
1946
1947 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
1948
1949 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
1950 IntegerExpression::Atom(Location::new("l0")),
1951 ComparisonOp::Gt,
1952 IntegerExpression::Const(1),
1953 )
1954 .unwrap();
1955 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
1956 IntegerExpression::Atom(Location::new("l1")),
1957 ComparisonOp::Eq,
1958 IntegerExpression::Const(0),
1959 )
1960 .unwrap();
1961 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
1962 LIAVariableConstraint::from_integer_expr(
1963 IntegerExpression::Atom(Variable::new("v")),
1964 ComparisonOp::Eq,
1965 IntegerExpression::Const(1),
1966 )
1967 .unwrap(),
1968 );
1969 let l2_gt_0 = UpwardsClosedSet::from_integer_expr(
1970 IntegerExpression::Atom(Location::new("l2")),
1971 ComparisonOp::Gt,
1972 IntegerExpression::Const(0),
1973 )
1974 .unwrap();
1975 let expected = ErrorFormula::from([
1976 ErrorAtom::new(
1978 InitRestriction::new_top(),
1979 ErrorTarget::new_ensure(
1980 UpwardsClosedSet::new_top(),
1981 l0_gt_1.clone() & v_eq_1.clone(),
1982 ),
1983 ),
1984 ErrorAtom::new(
1986 InitRestriction::new_top(),
1987 ErrorTarget::new_ensure(l2_gt_0.clone(), l0_gt_1),
1988 ),
1989 ErrorAtom::new(
1991 InitRestriction::new_top(),
1992 ErrorTarget::new_ensure(l1_eq_0.clone(), v_eq_1),
1993 ),
1994 ErrorAtom::new(
1996 InitRestriction::new_top(),
1997 ErrorTarget::Reach(l1_eq_0 & l2_gt_0),
1998 ),
1999 ]);
2000 assert_eq!(got, expected);
2001 }
2002
2003 #[test]
2004 fn repeat_nested_eventually_in_or() {
2005 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::Or(
2008 Box::new(ELTLExpression::LocationExpr(
2009 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2010 ComparisonOp::Gt,
2011 Box::new(IntegerExpression::Const(1)),
2012 )),
2013 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2014 Box::new(ELTLExpression::LocationExpr(
2015 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2016 ComparisonOp::Eq,
2017 Box::new(IntegerExpression::Const(0)),
2018 )),
2019 Box::new(ELTLExpression::Globally(Box::new(
2020 ELTLExpression::VariableExpr(
2021 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2022 ComparisonOp::Eq,
2023 Box::new(IntegerExpression::Const(1)),
2024 ),
2025 ))),
2026 )))),
2027 )));
2028
2029 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2030
2031 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2032 IntegerExpression::Atom(Location::new("l0")),
2033 ComparisonOp::Gt,
2034 IntegerExpression::Const(1),
2035 )
2036 .unwrap();
2037 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2038 IntegerExpression::Atom(Location::new("l1")),
2039 ComparisonOp::Eq,
2040 IntegerExpression::Const(0),
2041 )
2042 .unwrap();
2043 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
2044 LIAVariableConstraint::from_integer_expr(
2045 IntegerExpression::Atom(Variable::new("v")),
2046 ComparisonOp::Eq,
2047 IntegerExpression::Const(1),
2048 )
2049 .unwrap(),
2050 );
2051 let expected = ErrorFormula::from([
2052 ErrorAtom::new(InitRestriction::new_top(), ErrorTarget::Reach(l0_gt_1)),
2053 ErrorAtom::new(
2054 InitRestriction::new_top(),
2055 ErrorTarget::new_ensure(l1_eq_0, v_eq_1),
2056 ),
2057 ]);
2058 assert_eq!(got, expected);
2059 }
2060
2061 #[test]
2062 fn repeat_nested_eventually_in_and() {
2063 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2065 Box::new(ELTLExpression::LocationExpr(
2066 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2067 ComparisonOp::Gt,
2068 Box::new(IntegerExpression::Const(1)),
2069 )),
2070 Box::new(ELTLExpression::Eventually(Box::new(
2071 ELTLExpression::Globally(Box::new(ELTLExpression::LocationExpr(
2072 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2073 ComparisonOp::Eq,
2074 Box::new(IntegerExpression::Const(0)),
2075 ))),
2076 ))),
2077 )));
2078
2079 let got = ErrorSpec::from_named_eltl("test", eltl);
2080
2081 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2082 }
2083
2084 #[test]
2085 fn repeat_or_below_globally() {
2086 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2088 Box::new(ELTLExpression::LocationExpr(
2089 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2090 ComparisonOp::Gt,
2091 Box::new(IntegerExpression::Const(1)),
2092 )),
2093 Box::new(ELTLExpression::Globally(Box::new(ELTLExpression::Or(
2094 Box::new(ELTLExpression::LocationExpr(
2095 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2096 ComparisonOp::Eq,
2097 Box::new(IntegerExpression::Const(0)),
2098 )),
2099 Box::new(ELTLExpression::Globally(Box::new(
2100 ELTLExpression::VariableExpr(
2101 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2102 ComparisonOp::Eq,
2103 Box::new(IntegerExpression::Const(1)),
2104 ),
2105 ))),
2106 )))),
2107 )));
2108
2109 let got = ErrorSpec::from_named_eltl("test", eltl);
2110
2111 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2112 }
2113
2114 #[test]
2115 fn repeat_globally_eventually() {
2116 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::Globally(Box::new(
2118 ELTLExpression::Eventually(Box::new(ELTLExpression::LocationExpr(
2119 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2120 ComparisonOp::Gt,
2121 Box::new(IntegerExpression::Const(1)),
2122 ))),
2123 ))));
2124
2125 let got = ErrorSpec::from_named_eltl("test", eltl);
2126
2127 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2128 }
2129
2130 #[test]
2131 fn repeat_and_repeat_unsupported() {
2132 let eltl = !ELTLExpression::And(
2135 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2136 Box::new(ELTLExpression::LocationExpr(
2137 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2138 ComparisonOp::Gt,
2139 Box::new(IntegerExpression::Const(1)),
2140 )),
2141 Box::new(ELTLExpression::Globally(Box::new(
2142 ELTLExpression::LocationExpr(
2143 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2144 ComparisonOp::Eq,
2145 Box::new(IntegerExpression::Const(0)),
2146 ),
2147 ))),
2148 )))),
2149 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2150 Box::new(ELTLExpression::VariableExpr(
2151 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2152 ComparisonOp::Eq,
2153 Box::new(IntegerExpression::Const(1)),
2154 )),
2155 Box::new(ELTLExpression::Globally(Box::new(
2156 ELTLExpression::LocationExpr(
2157 Box::new(IntegerExpression::Atom(Location::new("l2"))),
2158 ComparisonOp::Gt,
2159 Box::new(IntegerExpression::Const(0)),
2160 ),
2161 ))),
2162 )))),
2163 );
2164
2165 let got = ErrorSpec::from_named_eltl("test", eltl);
2166
2167 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2168 IntegerExpression::Atom(Location::new("l0")),
2169 ComparisonOp::Gt,
2170 IntegerExpression::Const(1),
2171 )
2172 .unwrap();
2173 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2174 IntegerExpression::Atom(Location::new("l1")),
2175 ComparisonOp::Eq,
2176 IntegerExpression::Const(0),
2177 )
2178 .unwrap();
2179 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
2180 LIAVariableConstraint::from_integer_expr(
2181 IntegerExpression::Atom(Variable::new("v")),
2182 ComparisonOp::Eq,
2183 IntegerExpression::Const(1),
2184 )
2185 .unwrap(),
2186 );
2187 let l2_gt_0 = UpwardsClosedSet::from_integer_expr(
2188 IntegerExpression::Atom(Location::new("l2")),
2189 ComparisonOp::Gt,
2190 IntegerExpression::Const(0),
2191 )
2192 .unwrap();
2193 let expected = ExtractionError::UnsupportedConjunction(
2194 ErrorTarget::new_ensure(l0_gt_1, l1_eq_0),
2195 ErrorTarget::new_ensure(v_eq_1, l2_gt_0),
2196 );
2197 assert_eq!(got, Err(expected));
2198 }
2199
2200 #[test]
2201 fn repeat_and_ensure_unsupported() {
2202 let eltl = !ELTLExpression::And(
2204 Box::new(ELTLExpression::Globally(Box::new(
2205 ELTLExpression::LocationExpr(
2206 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2207 ComparisonOp::Gt,
2208 Box::new(IntegerExpression::Const(1)),
2209 ),
2210 ))),
2211 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2212 Box::new(ELTLExpression::LocationExpr(
2213 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2214 ComparisonOp::Eq,
2215 Box::new(IntegerExpression::Const(0)),
2216 )),
2217 Box::new(ELTLExpression::Globally(Box::new(
2218 ELTLExpression::VariableExpr(
2219 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2220 ComparisonOp::Eq,
2221 Box::new(IntegerExpression::Const(1)),
2222 ),
2223 ))),
2224 )))),
2225 );
2226
2227 let got = ErrorSpec::from_named_eltl("test", eltl);
2228
2229 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2230 IntegerExpression::Atom(Location::new("l0")),
2231 ComparisonOp::Gt,
2232 IntegerExpression::Const(1),
2233 )
2234 .unwrap();
2235 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2236 IntegerExpression::Atom(Location::new("l1")),
2237 ComparisonOp::Eq,
2238 IntegerExpression::Const(0),
2239 )
2240 .unwrap();
2241 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
2242 LIAVariableConstraint::from_integer_expr(
2243 IntegerExpression::Atom(Variable::new("v")),
2244 ComparisonOp::Eq,
2245 IntegerExpression::Const(1),
2246 )
2247 .unwrap(),
2248 );
2249 let expected = ExtractionError::UnsupportedConjunction(
2250 ErrorTarget::Invariant(l0_gt_1),
2251 ErrorTarget::new_ensure(l1_eq_0, v_eq_1),
2252 );
2253 assert_eq!(got, Err(expected));
2254 }
2255
2256 #[test]
2257 fn repeat_or_ensure() {
2258 let eltl = !ELTLExpression::Or(
2260 Box::new(ELTLExpression::Globally(Box::new(
2261 ELTLExpression::LocationExpr(
2262 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2263 ComparisonOp::Gt,
2264 Box::new(IntegerExpression::Const(1)),
2265 ),
2266 ))),
2267 Box::new(ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2268 Box::new(ELTLExpression::LocationExpr(
2269 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2270 ComparisonOp::Eq,
2271 Box::new(IntegerExpression::Const(0)),
2272 )),
2273 Box::new(ELTLExpression::Globally(Box::new(
2274 ELTLExpression::VariableExpr(
2275 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2276 ComparisonOp::Eq,
2277 Box::new(IntegerExpression::Const(1)),
2278 ),
2279 ))),
2280 )))),
2281 );
2282
2283 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2284
2285 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2286 IntegerExpression::Atom(Location::new("l0")),
2287 ComparisonOp::Gt,
2288 IntegerExpression::Const(1),
2289 )
2290 .unwrap();
2291 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2292 IntegerExpression::Atom(Location::new("l1")),
2293 ComparisonOp::Eq,
2294 IntegerExpression::Const(0),
2295 )
2296 .unwrap();
2297 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
2298 LIAVariableConstraint::from_integer_expr(
2299 IntegerExpression::Atom(Variable::new("v")),
2300 ComparisonOp::Eq,
2301 IntegerExpression::Const(1),
2302 )
2303 .unwrap(),
2304 );
2305 let expected = ErrorFormula::from([
2306 ErrorAtom::new(InitRestriction::new_top(), ErrorTarget::Invariant(l0_gt_1)),
2307 ErrorAtom::new(
2308 InitRestriction::new_top(),
2309 ErrorTarget::new_ensure(l1_eq_0, v_eq_1),
2310 ),
2311 ]);
2312 assert_eq!(got, expected);
2313 }
2314
2315 #[test]
2316 fn globally_eventually_simple() {
2317 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::And(
2319 Box::new(ELTLExpression::LocationExpr(
2320 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2321 ComparisonOp::Gt,
2322 Box::new(IntegerExpression::Const(1)),
2323 )),
2324 Box::new(ELTLExpression::Eventually(Box::new(
2325 ELTLExpression::LocationExpr(
2326 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2327 ComparisonOp::Eq,
2328 Box::new(IntegerExpression::Const(0)),
2329 ),
2330 ))),
2331 )));
2332
2333 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2334
2335 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2336 IntegerExpression::Atom(Location::new("l0")),
2337 ComparisonOp::Gt,
2338 IntegerExpression::Const(1),
2339 )
2340 .unwrap();
2341 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2342 IntegerExpression::Atom(Location::new("l1")),
2343 ComparisonOp::Eq,
2344 IntegerExpression::Const(0),
2345 )
2346 .unwrap();
2347 let expected = ErrorFormula::new(
2348 InitRestriction::new_top(),
2349 ErrorTarget::Repeat {
2350 pre: l0_gt_1,
2351 inv: l1_eq_0,
2352 },
2353 );
2354 assert_eq!(got, expected);
2355 }
2356
2357 #[test]
2358 fn globally_eventually_only() {
2359 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Eventually(Box::new(
2361 ELTLExpression::LocationExpr(
2362 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2363 ComparisonOp::Eq,
2364 Box::new(IntegerExpression::Const(0)),
2365 ),
2366 ))));
2367
2368 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2369
2370 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2371 IntegerExpression::Atom(Location::new("l1")),
2372 ComparisonOp::Eq,
2373 IntegerExpression::Const(0),
2374 )
2375 .unwrap();
2376 let expected = ErrorFormula::new(
2377 InitRestriction::new_top(),
2378 ErrorTarget::Repeat {
2379 pre: UpwardsClosedSet::new_top(),
2380 inv: l1_eq_0,
2381 },
2382 );
2383 assert_eq!(got, expected);
2384 }
2385
2386 #[test]
2387 fn globally_eventually_or_of_eventually() {
2388 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
2390 Box::new(ELTLExpression::Eventually(Box::new(
2391 ELTLExpression::LocationExpr(
2392 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2393 ComparisonOp::Gt,
2394 Box::new(IntegerExpression::Const(1)),
2395 ),
2396 ))),
2397 Box::new(ELTLExpression::Eventually(Box::new(
2398 ELTLExpression::LocationExpr(
2399 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2400 ComparisonOp::Eq,
2401 Box::new(IntegerExpression::Const(0)),
2402 ),
2403 ))),
2404 )));
2405
2406 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2407
2408 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2409 IntegerExpression::Atom(Location::new("l0")),
2410 ComparisonOp::Gt,
2411 IntegerExpression::Const(1),
2412 )
2413 .unwrap();
2414 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2415 IntegerExpression::Atom(Location::new("l1")),
2416 ComparisonOp::Eq,
2417 IntegerExpression::Const(0),
2418 )
2419 .unwrap();
2420 let expected = ErrorFormula::new(
2421 InitRestriction::new_top(),
2422 ErrorTarget::Repeat {
2423 pre: UpwardsClosedSet::new_top(),
2424 inv: l0_gt_1 | l1_eq_0,
2425 },
2426 );
2427 assert_eq!(got, expected);
2428 }
2429
2430 #[test]
2431 fn globally_eventually_nested_eventually() {
2432 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::And(
2434 Box::new(ELTLExpression::LocationExpr(
2435 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2436 ComparisonOp::Gt,
2437 Box::new(IntegerExpression::Const(1)),
2438 )),
2439 Box::new(ELTLExpression::Eventually(Box::new(
2440 ELTLExpression::Eventually(Box::new(ELTLExpression::LocationExpr(
2441 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2442 ComparisonOp::Eq,
2443 Box::new(IntegerExpression::Const(0)),
2444 ))),
2445 ))),
2446 )));
2447
2448 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2449
2450 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2451 IntegerExpression::Atom(Location::new("l0")),
2452 ComparisonOp::Gt,
2453 IntegerExpression::Const(1),
2454 )
2455 .unwrap();
2456 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2457 IntegerExpression::Atom(Location::new("l1")),
2458 ComparisonOp::Eq,
2459 IntegerExpression::Const(0),
2460 )
2461 .unwrap();
2462 let expected = ErrorFormula::new(
2463 InitRestriction::new_top(),
2464 ErrorTarget::Repeat {
2465 pre: l0_gt_1,
2466 inv: l1_eq_0,
2467 },
2468 );
2469 assert_eq!(got, expected);
2470 }
2471
2472 #[test]
2473 fn globally_eventually_and_of_globally_top_level() {
2474 let eltl = !ELTLExpression::And(
2476 Box::new(ELTLExpression::Globally(Box::new(
2477 ELTLExpression::LocationExpr(
2478 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2479 ComparisonOp::Gt,
2480 Box::new(IntegerExpression::Const(1)),
2481 ),
2482 ))),
2483 Box::new(ELTLExpression::Globally(Box::new(
2484 ELTLExpression::Eventually(Box::new(ELTLExpression::LocationExpr(
2485 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2486 ComparisonOp::Eq,
2487 Box::new(IntegerExpression::Const(0)),
2488 ))),
2489 ))),
2490 );
2491
2492 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2493
2494 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2495 IntegerExpression::Atom(Location::new("l0")),
2496 ComparisonOp::Gt,
2497 IntegerExpression::Const(1),
2498 )
2499 .unwrap();
2500 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2501 IntegerExpression::Atom(Location::new("l1")),
2502 ComparisonOp::Eq,
2503 IntegerExpression::Const(0),
2504 )
2505 .unwrap();
2506 let expected = ErrorFormula::new(
2507 InitRestriction::new_top(),
2508 ErrorTarget::Repeat {
2509 pre: l0_gt_1,
2510 inv: l1_eq_0,
2511 },
2512 );
2513 assert_eq!(got, expected);
2514 }
2515
2516 #[test]
2517 fn globally_eventually_or_of_same_invariant() {
2518 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
2521 Box::new(ELTLExpression::And(
2522 Box::new(ELTLExpression::VariableExpr(
2523 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2524 ComparisonOp::Eq,
2525 Box::new(IntegerExpression::Const(1)),
2526 )),
2527 Box::new(ELTLExpression::Eventually(Box::new(
2528 ELTLExpression::LocationExpr(
2529 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2530 ComparisonOp::Gt,
2531 Box::new(IntegerExpression::Const(1)),
2532 ),
2533 ))),
2534 )),
2535 Box::new(ELTLExpression::And(
2536 Box::new(ELTLExpression::VariableExpr(
2537 Box::new(IntegerExpression::Atom(Variable::new("v"))),
2538 ComparisonOp::Eq,
2539 Box::new(IntegerExpression::Const(1)),
2540 )),
2541 Box::new(ELTLExpression::Eventually(Box::new(
2542 ELTLExpression::LocationExpr(
2543 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2544 ComparisonOp::Eq,
2545 Box::new(IntegerExpression::Const(0)),
2546 ),
2547 ))),
2548 )),
2549 )));
2550
2551 let got = ErrorSpec::from_named_eltl("test", eltl).unwrap().ef;
2552
2553 let v_eq_1 = UpwardsClosedSet::new_var_constraint(
2554 LIAVariableConstraint::from_integer_expr(
2555 IntegerExpression::Atom(Variable::new("v")),
2556 ComparisonOp::Eq,
2557 IntegerExpression::Const(1),
2558 )
2559 .unwrap(),
2560 );
2561 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2562 IntegerExpression::Atom(Location::new("l0")),
2563 ComparisonOp::Gt,
2564 IntegerExpression::Const(1),
2565 )
2566 .unwrap();
2567 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2568 IntegerExpression::Atom(Location::new("l1")),
2569 ComparisonOp::Eq,
2570 IntegerExpression::Const(0),
2571 )
2572 .unwrap();
2573 let expected = ErrorFormula::new(
2574 InitRestriction::new_top(),
2575 ErrorTarget::Repeat {
2576 pre: v_eq_1,
2577 inv: l0_gt_1 | l1_eq_0,
2578 },
2579 );
2580 assert_eq!(got, expected);
2581 }
2582
2583 #[test]
2584 fn globally_eventually_two_eventually_unsupported() {
2585 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::And(
2587 Box::new(ELTLExpression::Eventually(Box::new(
2588 ELTLExpression::LocationExpr(
2589 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2590 ComparisonOp::Gt,
2591 Box::new(IntegerExpression::Const(1)),
2592 ),
2593 ))),
2594 Box::new(ELTLExpression::Eventually(Box::new(
2595 ELTLExpression::LocationExpr(
2596 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2597 ComparisonOp::Eq,
2598 Box::new(IntegerExpression::Const(0)),
2599 ),
2600 ))),
2601 )));
2602
2603 let got = ErrorSpec::from_named_eltl("test", eltl);
2604
2605 let l0_gt_1 = UpwardsClosedSet::from_integer_expr(
2606 IntegerExpression::Atom(Location::new("l0")),
2607 ComparisonOp::Gt,
2608 IntegerExpression::Const(1),
2609 )
2610 .unwrap();
2611 let l1_eq_0 = UpwardsClosedSet::from_integer_expr(
2612 IntegerExpression::Atom(Location::new("l1")),
2613 ComparisonOp::Eq,
2614 IntegerExpression::Const(0),
2615 )
2616 .unwrap();
2617 let expected = ExtractionError::UnsupportedConjunction(
2618 ErrorTarget::Repeat {
2619 pre: UpwardsClosedSet::new_top(),
2620 inv: l0_gt_1,
2621 },
2622 ErrorTarget::Repeat {
2623 pre: UpwardsClosedSet::new_top(),
2624 inv: l1_eq_0,
2625 },
2626 );
2627 assert_eq!(got, Err(expected));
2628 }
2629
2630 #[test]
2631 fn globally_eventually_atom_or_eventually() {
2632 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Or(
2634 Box::new(ELTLExpression::LocationExpr(
2635 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2636 ComparisonOp::Gt,
2637 Box::new(IntegerExpression::Const(1)),
2638 )),
2639 Box::new(ELTLExpression::Eventually(Box::new(
2640 ELTLExpression::LocationExpr(
2641 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2642 ComparisonOp::Eq,
2643 Box::new(IntegerExpression::Const(0)),
2644 ),
2645 ))),
2646 )));
2647
2648 let got = ErrorSpec::from_named_eltl("test", eltl);
2649
2650 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2651 }
2652
2653 #[test]
2654 fn globally_eventually_globally_below_eventually() {
2655 let eltl = !ELTLExpression::Globally(Box::new(ELTLExpression::Eventually(Box::new(
2657 ELTLExpression::And(
2658 Box::new(ELTLExpression::LocationExpr(
2659 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2660 ComparisonOp::Gt,
2661 Box::new(IntegerExpression::Const(1)),
2662 )),
2663 Box::new(ELTLExpression::Globally(Box::new(
2664 ELTLExpression::LocationExpr(
2665 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2666 ComparisonOp::Eq,
2667 Box::new(IntegerExpression::Const(0)),
2668 ),
2669 ))),
2670 ),
2671 ))));
2672
2673 let got = ErrorSpec::from_named_eltl("test", eltl);
2674
2675 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2676 }
2677
2678 #[test]
2679 fn globally_eventually_below_eventually_unsupported() {
2680 let eltl = !ELTLExpression::Eventually(Box::new(ELTLExpression::And(
2682 Box::new(ELTLExpression::LocationExpr(
2683 Box::new(IntegerExpression::Atom(Location::new("l0"))),
2684 ComparisonOp::Gt,
2685 Box::new(IntegerExpression::Const(1)),
2686 )),
2687 Box::new(ELTLExpression::Globally(Box::new(
2688 ELTLExpression::Eventually(Box::new(ELTLExpression::LocationExpr(
2689 Box::new(IntegerExpression::Atom(Location::new("l1"))),
2690 ComparisonOp::Eq,
2691 Box::new(IntegerExpression::Const(0)),
2692 ))),
2693 ))),
2694 )));
2695
2696 let got = ErrorSpec::from_named_eltl("test", eltl);
2697
2698 assert_eq!(got, Err(ExtractionError::NestedTemporalOperator));
2699 }
2700}