Skip to content

Commit 28e4383

Browse files
committed
Buechi: identify special cases where reachability is sufficient
This adds treatment for the special case where all nonaccepting states of the Buechi automaton have an unconditional self-loop. In this case, when these nonaccepting states is reached, the trace cannot be extended to an accepting trace, and will hence be rejected. Hence, in this case, the Buechi acceptance condition is unnecessary, and a simple reachability property is sufficient. Among the 74 tests in regression/ebmc-spot/sva-buechi, only 3 require the Büchi acceptance condition with this change applied.
1 parent 5f9a562 commit 28e4383

File tree

4 files changed

+49
-14
lines changed

4 files changed

+49
-14
lines changed

regression/ebmc-spot/sva-buechi/initial2.desc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
CORE
22
../../verilog/SVA/initial2.sv
33
--buechi --module main
4-
^\[main\.assert\.1\] main\.counter == 1: PROVED up to bound \d+$
5-
^\[main\.assert\.2\] main\.counter == 2: PROVED up to bound \d+$
4+
^\[main\.assert\.1\] main\.counter == 1: PROVED \(1-induction\)$
5+
^\[main\.assert\.2\] main\.counter == 2: PROVED \(1-induction\)$
66
^EXIT=0$
77
^SIGNAL=0$
88
--

regression/ebmc-spot/sva-buechi/static_final1.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
CORE
22
../../verilog/SVA/static_final1.sv
33
--buechi
4-
^\[full_adder\.p0\] always \{ full_adder\.carry, full_adder\.sum \} == \{ 1'b0, full_adder\.a \} \+ full_adder\.b \+ full_adder\.c: PROVED up to bound \d+$
4+
^\[full_adder\.p0\] always \{ full_adder\.carry, full_adder\.sum \} == \{ 1'b0, full_adder\.a \} \+ full_adder\.b \+ full_adder\.c: PROVED \(1-induction\)$
55
^EXIT=0$
66
^SIGNAL=0$
77
--

src/ebmc/instrument_buechi.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,19 +68,31 @@ void instrument_buechi(
6868
// by the Buechi acceptance condition.
6969
exprt::operandst property_conjuncts;
7070

71+
bool have_liveness = false, have_safety = false;
72+
7173
if(!buechi.liveness_signal.is_false())
7274
{
7375
// Note that we have negated the property,
7476
// so this is the negation of the Buechi acceptance condition.
7577
property_conjuncts.push_back(
7678
F_exprt{G_exprt{not_exprt{buechi.liveness_signal}}});
79+
have_liveness = true;
7780
}
7881

7982
if(!buechi.error_signal.is_true())
8083
{
8184
property_conjuncts.push_back(G_exprt{not_exprt{buechi.error_signal}});
85+
have_safety = true;
8286
}
8387

88+
if(have_liveness && have_safety)
89+
message.debug() << "Buechi automaton has liveness and safety components"
90+
<< messaget::eom;
91+
else if(have_liveness)
92+
message.debug() << "Buechi automaton is liveness only" << messaget::eom;
93+
else if(have_safety)
94+
message.debug() << "Buechi automaton is safety only" << messaget::eom;
95+
8496
property.normalized_expr = conjunction(property_conjuncts);
8597

8698
message.debug() << "New property: " << format(property.normalized_expr)

src/temporal-logic/ltl_to_buechi.cpp

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,17 @@ bool is_error_state(const std::pair<hoat::state_namet, hoat::edgest> &state)
100100
return false;
101101
}
102102

103+
/// Returns true iff all accepting states of the automaton have
104+
/// unconditional self loops
105+
bool is_safety_only(const hoat &hoa)
106+
{
107+
for(auto &state : hoa.body)
108+
if(state.first.is_accepting() && !is_error_state(state))
109+
return false;
110+
111+
return true;
112+
}
113+
103114
buechi_transt
104115
ltl_to_buechi(const exprt &property, message_handlert &message_handler)
105116
{
@@ -162,20 +173,32 @@ ltl_to_buechi(const exprt &property, message_handlert &message_handler)
162173
message.debug() << "Buechi initial state: " << format(init)
163174
<< messaget::eom;
164175

165-
// construct the liveness signal
166-
std::vector<exprt> liveness_disjuncts;
176+
exprt liveness_signal;
167177

168-
for(auto &state : hoa.body)
169-
if(state.first.is_accepting())
170-
{
171-
liveness_disjuncts.push_back(equal_exprt{
172-
buechi_state, from_integer(state.first.number, state_type)});
173-
}
178+
// Is safety sufficient?
179+
if(is_safety_only(hoa))
180+
{
181+
liveness_signal = false_exprt{};
174182

175-
auto liveness_signal = disjunction(liveness_disjuncts);
183+
message.debug() << "Buechi liveness signal not required" << messaget::eom;
184+
}
185+
else
186+
{
187+
// construct the liveness signal
188+
std::vector<exprt> liveness_disjuncts;
176189

177-
message.debug() << "Buechi liveness signal: " << format(liveness_signal)
178-
<< messaget::eom;
190+
for(auto &state : hoa.body)
191+
if(state.first.is_accepting())
192+
{
193+
liveness_disjuncts.push_back(equal_exprt{
194+
buechi_state, from_integer(state.first.number, state_type)});
195+
}
196+
197+
liveness_signal = disjunction(liveness_disjuncts);
198+
199+
message.debug() << "Buechi liveness signal: " << format(liveness_signal)
200+
<< messaget::eom;
201+
}
179202

180203
// construct the error signal -- true when the next automaton state
181204
// is nonaccepting with an unconditional self-loop.

0 commit comments

Comments
 (0)