Skip to content

Commit 0337e2c

Browse files
authored
Merge pull request #733 from diffblue/fix-U
BMC: fix encoding of `p U q`
2 parents 5976577 + 76f99e5 commit 0337e2c

File tree

9 files changed

+68
-34
lines changed

9 files changed

+68
-34
lines changed

regression/ebmc/smv/smv_ltlspec_U1.desc

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
CORE broken-smt-backend
22
smv_ltlspec_U1.smv
3-
--bound 10
4-
\[.*\] x = 1 U x = 2: PROVED up to bound 10$
5-
\[.*\] x != 0 U FALSE: PROVED up to bound 10$
3+
--bound 3
4+
\[.*\] TRUE U x = 3: PROVED up to bound 3$
5+
\[.*\] x = 1 U x = 2: PROVED up to bound 3$
6+
\[.*\] x <= 2 U x = 3: PROVED up to bound 3$
7+
\[.*\] x != 0 U FALSE: REFUTED$
68
\[.*\] x = 1 U x = 3: REFUTED$
7-
\[.*\] x = 1 U x = 2 & x <= 2 U x = 3: PROVED up to bound 10$
8-
\[.*\] x = 1 U x = 2 \| x = 1 U x = 3: PROVED up to bound 10$
9+
\[.*\] x = 1 U x = 2 & x <= 2 U x = 3: PROVED up to bound 3$
10+
\[.*\] x = 1 U x = 2 \| x = 1 U x = 3: PROVED up to bound 3$
911
^EXIT=10$
1012
^SIGNAL=0$
1113
--

regression/ebmc/smv/smv_ltlspec_U1.smv

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ VAR x : 0..10;
55
ASSIGN
66
init(x) := 1;
77

8+
-- 1, 2, 3, 3, 3...
89
next(x) :=
910
case
1011
x>=3 : 3;
1112
TRUE: x+1;
1213
esac;
1314

15+
LTLSPEC TRUE U x = 3 -- should pass
1416
LTLSPEC x = 1 U x = 2 -- should pass
15-
LTLSPEC x !=0 U FALSE -- should pass
17+
LTLSPEC x <= 2 U x = 3 -- should pass
18+
LTLSPEC x !=0 U FALSE -- should fail, "FALSE" never becomes true
1619
LTLSPEC x = 1 U x = 3 -- should fail
17-
LTLSPEC x = 1 U x = 2 & x<=2 U x = 3 -- should pass
20+
LTLSPEC x = 1 U x = 2 & x <= 2 U x = 3 -- should pass
1821
LTLSPEC x = 1 U x = 2 | x = 1 U x = 3 -- should pass

regression/ebmc/smv/smv_ltlspec_U2.desc

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
KNOWNBUG broken-smt-backend
1+
CORE broken-smt-backend
22
smv_ltlspec_U2.smv
3-
--bound 10
3+
--bound 10 --numbered-trace
44
^\[.*\] TRUE U x = 0: REFUTED$
55
^Counterexample with 4 states:$
66
^x@0 = 1$
@@ -12,4 +12,3 @@ smv_ltlspec_U2.smv
1212
--
1313
^warning: ignoring
1414
--
15-
The property is proven, but should be refuted.

src/hw_cbmc_irep_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ IREP_ID_ONE(EX)
99
IREP_ID_ONE(EU)
1010
IREP_ID_ONE(ER)
1111
IREP_ID_ONE(U)
12+
IREP_ID_ONE(weak_U)
1213
IREP_ID_ONE(R)
1314
IREP_ID_ONE(A)
1415
IREP_ID_ONE(F)

src/temporal-logic/temporal_expr.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,8 @@ static inline G_exprt &to_G_expr(exprt &expr)
143143
return static_cast<G_exprt &>(expr);
144144
}
145145

146+
/// standard (strong) LTL until, i.e.,
147+
/// the rhs must become true eventually
146148
class U_exprt : public binary_predicate_exprt
147149
{
148150
public:
@@ -166,6 +168,31 @@ static inline U_exprt &to_U_expr(exprt &expr)
166168
return static_cast<U_exprt &>(expr);
167169
}
168170

171+
/// weak LTL until, i.e.,
172+
/// the rhs is not required to become true eventually
173+
class weak_U_exprt : public binary_predicate_exprt
174+
{
175+
public:
176+
explicit weak_U_exprt(exprt op0, exprt op1)
177+
: binary_predicate_exprt(std::move(op0), ID_weak_U, std::move(op1))
178+
{
179+
}
180+
};
181+
182+
static inline const weak_U_exprt &to_weak_U_expr(const exprt &expr)
183+
{
184+
PRECONDITION(expr.id() == ID_weak_U);
185+
weak_U_exprt::check(expr);
186+
return static_cast<const weak_U_exprt &>(expr);
187+
}
188+
189+
static inline weak_U_exprt &to_weak_U_expr(exprt &expr)
190+
{
191+
PRECONDITION(expr.id() == ID_weak_U);
192+
weak_U_exprt::check(expr);
193+
return static_cast<weak_U_exprt &>(expr);
194+
}
195+
169196
class EU_exprt : public binary_predicate_exprt
170197
{
171198
public:

src/trans-word-level/lasso.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ bool requires_lasso_constraints(const exprt &expr)
156156
subexpr_it->id() == ID_sva_until || subexpr_it->id() == ID_sva_s_until ||
157157
subexpr_it->id() == ID_sva_eventually ||
158158
subexpr_it->id() == ID_sva_s_eventually || subexpr_it->id() == ID_AF ||
159-
subexpr_it->id() == ID_F)
159+
subexpr_it->id() == ID_F || subexpr_it->id() == ID_U)
160160
{
161161
return true;
162162
}

src/trans-word-level/obligations.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,9 @@ std::pair<mp_integer, exprt> obligationst::conjunction() const
2222
}
2323
return {max, ::conjunction(conjuncts)};
2424
}
25+
26+
obligationst obligations_union(obligationst a, obligationst b)
27+
{
28+
a.add(b);
29+
return a;
30+
}

src/trans-word-level/obligations.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,6 @@ class obligationst
5858
std::pair<mp_integer, exprt> conjunction() const;
5959
};
6060

61+
obligationst obligations_union(obligationst, obligationst);
62+
6163
#endif

src/trans-word-level/property.cpp

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -380,32 +380,26 @@ static obligationst property_obligations_rec(
380380
property_expr.id() == ID_sva_until ||
381381
property_expr.id() == ID_sva_s_until || property_expr.id() == ID_U)
382382
{
383-
// non-overlapping until
384-
// we need a lasso to refute these
385-
386-
// we expand: p U q <=> q ∨ (p ∧ X(p U q))
387-
exprt tmp_q = to_binary_expr(property_expr).op1();
388-
tmp_q = property_obligations_rec(tmp_q, solver, current, no_timeframes, ns)
389-
.conjunction()
390-
.second;
391-
392-
exprt expansion = to_binary_expr(property_expr).op0();
393-
expansion =
394-
property_obligations_rec(expansion, solver, current, no_timeframes, ns)
395-
.conjunction()
396-
.second;
383+
auto &p = to_binary_expr(property_expr).lhs();
384+
auto &q = to_binary_expr(property_expr).rhs();
397385

398-
const auto next = current + 1;
386+
// p U q ≡ Fq ∧ (p W q)
387+
exprt tmp = and_exprt{F_exprt{q}, weak_U_exprt{p, q}};
399388

400-
if(next < no_timeframes)
401-
{
402-
auto obligations_rec = property_obligations_rec(
403-
property_expr, solver, next, no_timeframes, ns);
404-
expansion = and_exprt{expansion, obligations_rec.conjunction().second};
405-
}
389+
return property_obligations_rec(tmp, solver, current, no_timeframes, ns);
390+
}
391+
else if(property_expr.id() == ID_weak_U)
392+
{
393+
// we expand: p W q ≡ q ∨ ( p ∧ X(p W q) )
394+
auto &p = to_weak_U_expr(property_expr).lhs();
395+
auto &q = to_weak_U_expr(property_expr).rhs();
406396

407-
DATA_INVARIANT(no_timeframes != 0, "must have timeframe");
408-
return obligationst{no_timeframes - 1, or_exprt{tmp_q, expansion}};
397+
// Once we reach the end of the unwinding, replace X(p W q) by 'true'.
398+
auto tmp = or_exprt{
399+
q,
400+
(current + 1) < no_timeframes ? and_exprt{p, X_exprt{property_expr}} : p};
401+
402+
return property_obligations_rec(tmp, solver, current, no_timeframes, ns);
409403
}
410404
else if(property_expr.id() == ID_R)
411405
{

0 commit comments

Comments
 (0)