Skip to content

Commit d1e5533

Browse files
authored
Merge pull request #1173 from diffblue/ltl_sva_to_string-throws
`ltl_sva_to_stringt::operator(expr)` now throws error class
2 parents 5d79b02 + 524299e commit d1e5533

File tree

8 files changed

+155
-75
lines changed

8 files changed

+155
-75
lines changed
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CORE
2+
../../verilog/SVA/sequence_first_match1.sv
3+
--buechi --bound 5
4+
^error: failed to convert sva_sequence_first_match$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
^warning: ignoring
9+
^\[.*\] first_match\(main\.x == 0\): PROVED up to bound 5$
10+
^\[.*\] first_match\(main\.x == 0, main\.x\+\+\): PROVED up to bound 5$
11+
--
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
CORE
2+
../../verilog/SVA/sequence_first_match2.sv
3+
--buechi --bound 5
4+
^error: failed to convert sva_sequence_first_match$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
^\[.*\] \(\(##1 1\) or \(##2 1\)\) \|-> main.x == 1: REFUTED$
9+
^\[.*\] first_match\(\(##1 1\) or \(##2 1\)\) \|-> main\.x == 1: PROVED up to bound 5$
10+
^\[.*\] \(1 or \(##1 1\)\) \|-> main\.x == 0: REFUTED$
11+
^\[.*\] first_match\(1 or \(##1 1\)\) \|-> main\.x == 0: PROVED up to bound 5$
12+
^warning: ignoring
13+
--
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CORE
2+
../../verilog/SVA/sequence_throughout1.sv
3+
--buechi --bound 10
4+
^error: failed to convert sva_sequence_throughout$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
^\[main\.p0\] main\.x >= 0 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): PROVED up to bound 10$
9+
^\[main\.p1\] main\.x <= 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 2\): REFUTED$
10+
^\[main\.p2\] 1 throughout \(main\.x == 0 ##1 main\.x == 1 ##1 main\.x == 3\): REFUTED$
11+
^warning: ignoring
12+
--
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
CORE
2+
../../verilog/SVA/sequence_within1.sv
3+
--buechi --bound 20
4+
^error: failed to convert sva_sequence_within$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--
8+
^\[main\.p0\] main\.x == 0 within main\.x == 1: REFUTED$
9+
^\[main\.p1\] main\.x == 0 within \(##10 1\): PROVED up to bound 20$
10+
^\[main\.p2\] main\.x == 5 within \(##10 1\): PROVED up to bound 20$
11+
^\[main\.p3\] main\.x == 10 within \(##10 1\): PROVED up to bound 20$
12+
^\[main\.p4\] main\.x == 11 within \(##10 1\): REFUTED$
13+
^warning: ignoring
14+
--
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CORE
2+
../../verilog/SVA/unbounded1.sv
3+
--buechi --module main --bound 1
4+
^error: failed to convert sva_cycle_delay$
5+
^EXIT=6$
6+
^SIGNAL=0$
7+
--

src/temporal-logic/ltl_sva_to_string.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ Author: Daniel Kroening, [email protected]
1111
#include <util/arith_tools.h>
1212
#include <util/string2int.h>
1313

14-
#include <ebmc/ebmc_error.h>
1514
#include <verilog/sva_expr.h>
1615

1716
#include "ltl.h"
@@ -378,8 +377,7 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
378377
if(from == 0)
379378
{
380379
// requires treatment of empty sequences on lhs
381-
throw ebmc_errort{}
382-
<< "cannot convert 0.. ranged sequence concatenation to Buechi";
380+
throw ltl_sva_to_string_unsupportedt{expr};
383381
}
384382
else if(delay.is_unbounded()) // f ##[n:$] g
385383
{
@@ -448,7 +446,7 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
448446
}
449447
else if(repetition.is_empty_match())
450448
{
451-
throw ebmc_errort{} << "cannot convert [*0] to Buechi";
449+
throw ltl_sva_to_string_unsupportedt{expr};
452450
}
453451
else if(repetition.is_singleton())
454452
{
@@ -547,5 +545,7 @@ ltl_sva_to_stringt::rec(const exprt &expr, modet mode)
547545
return resultt{precedencet::ATOM, s};
548546
}
549547
else
550-
throw ebmc_errort{} << "cannot convert " << expr.id() << " to Buechi";
548+
{
549+
throw ltl_sva_to_string_unsupportedt{expr};
550+
}
551551
}

src/temporal-logic/ltl_sva_to_string.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,22 @@ Author: Daniel Kroening, [email protected]
1212
#include <util/numbering.h>
1313
#include <util/std_expr.h>
1414

15+
class ltl_sva_to_string_unsupportedt
16+
{
17+
public:
18+
explicit ltl_sva_to_string_unsupportedt(exprt __expr)
19+
: expr(std::move(__expr))
20+
{
21+
}
22+
23+
exprt expr;
24+
};
25+
1526
/// create formula strings for external LTL to Buechi tools
1627
class ltl_sva_to_stringt
1728
{
1829
public:
30+
// throws ltl_sva_to_string_unsupportedt when the conversion fails
1931
std::string operator()(const exprt &expr)
2032
{
2133
return rec(expr, PROPERTY).s;

src/temporal-logic/ltl_to_buechi.cpp

Lines changed: 81 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -84,98 +84,109 @@ exprt hoa_label_to_expr(
8484
buechi_transt
8585
ltl_to_buechi(const exprt &property, message_handlert &message_handler)
8686
{
87-
// Turn the skeleton of the property into a string
8887
ltl_sva_to_stringt ltl_sva_to_string;
89-
auto string = ltl_sva_to_string(property);
9088

91-
// Run Spot's ltl2tgba
92-
std::ostringstream hoa_stream;
89+
try
90+
{
91+
// Turn the skeleton of the property into a string
92+
auto string = ltl_sva_to_string(property);
9393

94-
messaget message(message_handler);
94+
// Run Spot's ltl2tgba
95+
std::ostringstream hoa_stream;
9596

96-
message.debug() << "ltl2tgba property: " << string << messaget::eom;
97+
messaget message(message_handler);
9798

98-
// State-based Buchi acceptance. Should compare with transition-based
99-
// acceptance.
100-
// Use --complete to be able to have multiple properties in one
101-
// model.
102-
auto run_result = run(
103-
"ltl2tgba",
104-
{"ltl2tgba", "--sba", "--complete", "--hoaf=1.1", string},
105-
"",
106-
hoa_stream,
107-
"");
99+
message.debug() << "ltl2tgba property: " << string << messaget::eom;
108100

109-
if(run_result != 0)
110-
throw ebmc_errort{} << "failed to run ltl2tgba";
101+
// State-based Buchi acceptance. Should compare with transition-based
102+
// acceptance.
103+
// Use --complete to be able to have multiple properties in one
104+
// model.
105+
auto run_result = run(
106+
"ltl2tgba",
107+
{"ltl2tgba", "--sba", "--complete", "--hoaf=1.1", string},
108+
"",
109+
hoa_stream,
110+
"");
111111

112-
auto hoa = hoat::from_string(hoa_stream.str());
112+
if(run_result != 0)
113+
throw ebmc_errort{} << "failed to run ltl2tgba";
113114

114-
message.debug() << hoa << messaget::eom;
115+
auto hoa = hoat::from_string(hoa_stream.str());
115116

116-
auto max_state_number = hoa.max_state_number();
117-
auto state_type = range_typet{0, max_state_number};
118-
const auto buechi_state = symbol_exprt{"buechi::state", state_type};
119-
const auto buechi_next_state = next_symbol_exprt{"buechi::state", state_type};
117+
message.debug() << hoa << messaget::eom;
120118

121-
// construct the initial state constraint
122-
std::vector<exprt> init_disjuncts;
119+
auto max_state_number = hoa.max_state_number();
120+
auto state_type = range_typet{0, max_state_number};
121+
const auto buechi_state = symbol_exprt{"buechi::state", state_type};
122+
const auto buechi_next_state =
123+
next_symbol_exprt{"buechi::state", state_type};
123124

124-
for(auto &item : hoa.header)
125-
if(item.first == "Start:")
126-
{
127-
if(item.second.size() != 1)
128-
throw ebmc_errort() << "Start header must have one token";
129-
auto state_number = string2integer(item.second.front());
130-
init_disjuncts.push_back(
131-
equal_exprt{buechi_state, from_integer(state_number, state_type)});
132-
}
125+
// construct the initial state constraint
126+
std::vector<exprt> init_disjuncts;
133127

134-
auto init = disjunction(init_disjuncts);
128+
for(auto &item : hoa.header)
129+
if(item.first == "Start:")
130+
{
131+
if(item.second.size() != 1)
132+
throw ebmc_errort() << "Start header must have one token";
133+
auto state_number = string2integer(item.second.front());
134+
init_disjuncts.push_back(
135+
equal_exprt{buechi_state, from_integer(state_number, state_type)});
136+
}
135137

136-
message.debug() << "Buechi initial state: " << format(init) << messaget::eom;
138+
auto init = disjunction(init_disjuncts);
137139

138-
// construct the liveness signal
139-
std::vector<exprt> liveness_disjuncts;
140+
message.debug() << "Buechi initial state: " << format(init)
141+
<< messaget::eom;
140142

141-
for(auto &state : hoa.body)
142-
if(!state.first.acc_sig.empty())
143-
{
144-
liveness_disjuncts.push_back(equal_exprt{
145-
buechi_state, from_integer(state.first.number, state_type)});
146-
}
143+
// construct the liveness signal
144+
std::vector<exprt> liveness_disjuncts;
147145

148-
auto liveness_signal = disjunction(liveness_disjuncts);
146+
for(auto &state : hoa.body)
147+
if(!state.first.acc_sig.empty())
148+
{
149+
liveness_disjuncts.push_back(equal_exprt{
150+
buechi_state, from_integer(state.first.number, state_type)});
151+
}
149152

150-
message.debug() << "Buechi liveness signal: " << format(liveness_signal)
151-
<< messaget::eom;
153+
auto liveness_signal = disjunction(liveness_disjuncts);
152154

153-
// construct the transition relation
154-
std::vector<exprt> trans_disjuncts;
155+
message.debug() << "Buechi liveness signal: " << format(liveness_signal)
156+
<< messaget::eom;
155157

156-
for(auto &state : hoa.body)
157-
{
158-
auto pre =
159-
equal_exprt{buechi_state, from_integer(state.first.number, state_type)};
160-
for(auto &edge : state.second)
158+
// construct the transition relation
159+
std::vector<exprt> trans_disjuncts;
160+
161+
for(auto &state : hoa.body)
161162
{
162-
if(edge.dest_states.size() != 1)
163-
throw ebmc_errort() << "edge must have one destination state";
164-
auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string);
165-
auto post = equal_exprt{
166-
buechi_next_state, from_integer(edge.dest_states.front(), state_type)};
167-
trans_disjuncts.push_back(and_exprt{pre, cond, post});
163+
auto pre =
164+
equal_exprt{buechi_state, from_integer(state.first.number, state_type)};
165+
for(auto &edge : state.second)
166+
{
167+
if(edge.dest_states.size() != 1)
168+
throw ebmc_errort() << "edge must have one destination state";
169+
auto cond = hoa_label_to_expr(edge.label, ltl_sva_to_string);
170+
auto post = equal_exprt{
171+
buechi_next_state,
172+
from_integer(edge.dest_states.front(), state_type)};
173+
trans_disjuncts.push_back(and_exprt{pre, cond, post});
174+
}
168175
}
169-
}
170176

171-
auto trans = disjunction(trans_disjuncts);
177+
auto trans = disjunction(trans_disjuncts);
172178

173-
message.debug() << "Buechi transition constraint: " << format(trans)
174-
<< messaget::eom;
179+
message.debug() << "Buechi transition constraint: " << format(trans)
180+
<< messaget::eom;
175181

176-
return {
177-
buechi_state,
178-
std::move(init),
179-
std::move(trans),
180-
std::move(liveness_signal)};
182+
return {
183+
buechi_state,
184+
std::move(init),
185+
std::move(trans),
186+
std::move(liveness_signal)};
187+
}
188+
catch(ltl_sva_to_string_unsupportedt error)
189+
{
190+
throw ebmc_errort{} << "failed to convert " << error.expr.id();
191+
}
181192
}

0 commit comments

Comments
 (0)