1717#include < chrono>
1818#include < fstream>
1919
20+ void bmc_with_assumptions (
21+ std::size_t bound,
22+ const transition_systemt &transition_system,
23+ ebmc_propertiest &properties,
24+ decision_proceduret &solver,
25+ message_handlert &message_handler)
26+ {
27+ messaget message (message_handler);
28+ const namespacet ns (transition_system.symbol_table );
29+
30+ // Use assumptions to check the properties separately
31+
32+ for (auto &property : properties.properties )
33+ {
34+ if (property.is_disabled () || property.is_failure () || property.is_assumed ())
35+ {
36+ continue ;
37+ }
38+
39+ message.status () << " Checking " << property.name << messaget::eom;
40+
41+ auto assumption = not_exprt{conjunction (property.timeframe_handles )};
42+
43+ decision_proceduret::resultt dec_result = solver (assumption);
44+
45+ switch (dec_result)
46+ {
47+ case decision_proceduret::resultt::D_SATISFIABLE:
48+ if (property.is_exists_path ())
49+ {
50+ property.proved ();
51+ message.result () << " SAT: path found" << messaget::eom;
52+ }
53+ else // universal path property
54+ {
55+ property.refuted ();
56+ message.result () << " SAT: counterexample found" << messaget::eom;
57+ }
58+
59+ property.witness_trace = compute_trans_trace (
60+ property.timeframe_handles ,
61+ solver,
62+ bound + 1 ,
63+ ns,
64+ transition_system.main_symbol ->name );
65+ break ;
66+
67+ case decision_proceduret::resultt::D_UNSATISFIABLE:
68+ if (property.is_exists_path ())
69+ {
70+ message.result () << " UNSAT: No path found within bound"
71+ << messaget::eom;
72+ property.refuted_with_bound (bound);
73+ }
74+ else // universal path property
75+ {
76+ message.result () << " UNSAT: No counterexample found within bound"
77+ << messaget::eom;
78+ property.proved_with_bound (bound);
79+ }
80+ break ;
81+
82+ case decision_proceduret::resultt::D_ERROR:
83+ message.error () << " Error from decision procedure" << messaget::eom;
84+ property.failure ();
85+ break ;
86+
87+ default :
88+ property.failure ();
89+ throw ebmc_errort () << " Unexpected result from decision procedure" ;
90+ }
91+ }
92+ }
93+
94+ // / VMCAI 2009 Query-driven program testing,
95+ // / "iterative constraint strengthening"
96+ void bmc_with_iterative_constraint_strengthening (
97+ std::size_t bound,
98+ const transition_systemt &transition_system,
99+ ebmc_propertiest &properties,
100+ decision_proceduret &solver,
101+ message_handlert &message_handler)
102+ {
103+ messaget message (message_handler);
104+ const namespacet ns (transition_system.symbol_table );
105+
106+ auto trace_found = [&solver](const ebmc_propertiest::propertyt &property)
107+ {
108+ for (auto &h : property.timeframe_handles )
109+ if (solver.get (h).is_false ())
110+ return true ;
111+ return false ;
112+ };
113+
114+ while (true )
115+ {
116+ // At least one of the remaining properties
117+ // should be falsified.
118+ exprt::operandst disjuncts;
119+
120+ for (auto &property : properties.properties )
121+ {
122+ if (property.is_unknown ())
123+ {
124+ for (auto &h : property.timeframe_handles )
125+ disjuncts.push_back (not_exprt{h});
126+ }
127+ }
128+
129+ // This constraint is strenthened in each iteration.
130+ solver.set_to_true (disjunction (disjuncts));
131+
132+ decision_proceduret::resultt dec_result = solver ();
133+
134+ switch (dec_result)
135+ {
136+ case decision_proceduret::resultt::D_SATISFIABLE:
137+ // Found a trace for at least one further property with unknown state
138+ message.result () << " SAT: path found" << messaget::eom;
139+
140+ for (auto &property : properties.properties )
141+ {
142+ if (property.is_unknown () && trace_found (property))
143+ {
144+ if (property.is_exists_path ())
145+ property.proved ();
146+ else // universal path property
147+ property.refuted ();
148+
149+ property.witness_trace = compute_trans_trace (
150+ property.timeframe_handles ,
151+ solver,
152+ bound + 1 ,
153+ ns,
154+ transition_system.main_symbol ->name );
155+ }
156+ }
157+ break ; // next iteration of while loop
158+
159+ case decision_proceduret::resultt::D_UNSATISFIABLE:
160+ message.result () << " UNSAT: No path found within bound" << messaget::eom;
161+
162+ for (auto &property : properties.properties )
163+ {
164+ if (property.is_unknown ())
165+ {
166+ if (property.is_exists_path ())
167+ property.refuted_with_bound (bound);
168+ else // universal path property
169+ property.proved_with_bound (bound);
170+ }
171+ }
172+ return ;
173+
174+ case decision_proceduret::resultt::D_ERROR:
175+ for (auto &property : properties.properties )
176+ {
177+ if (property.is_unknown ())
178+ property.failure ();
179+ }
180+ message.error () << " Error from decision procedure" << messaget::eom;
181+ return ;
182+
183+ default :
184+ for (auto &property : properties.properties )
185+ {
186+ if (property.is_unknown ())
187+ property.failure ();
188+ }
189+ throw ebmc_errort () << " Unexpected result from decision procedure" ;
190+ }
191+ }
192+ }
193+
20194void bmc (
21195 std::size_t bound,
22196 bool convert_only,
197+ bool bmc_with_assumptions,
23198 const transition_systemt &transition_system,
24199 ebmc_propertiest &properties,
25200 const ebmc_solver_factoryt &solver_factory,
@@ -76,12 +251,25 @@ void bmc(
76251
77252 if (convert_only)
78253 {
254+ // At least one property must be violated in at least one
255+ // timeframe.
256+ exprt::operandst disjuncts;
257+
79258 for (const auto &property : properties.properties )
80259 {
81- if (!property.is_disabled ())
82- solver.set_to_false (conjunction (property.timeframe_handles ));
260+ if (property.is_assumed ())
261+ {
262+ solver.set_to_true (conjunction (property.timeframe_handles ));
263+ }
264+ else if (!property.is_disabled ())
265+ {
266+ for (auto &h : property.timeframe_handles )
267+ disjuncts.push_back (not_exprt{h});
268+ }
83269 }
84270
271+ solver.set_to_true (disjunction (disjuncts));
272+
85273 // Call decision_proceduret::dec_solve to finish the conversion
86274 // process.
87275 (void )solver ();
@@ -93,69 +281,15 @@ void bmc(
93281
94282 auto sat_start_time = std::chrono::steady_clock::now ();
95283
96- // Use assumptions to check the properties separately
97-
98- for (auto &property : properties.properties )
284+ if (bmc_with_assumptions)
99285 {
100- if (
101- property.is_disabled () || property.is_failure () ||
102- property.is_assumed ())
103- {
104- continue ;
105- }
106-
107- message.status () << " Checking " << property.name << messaget::eom;
108-
109- auto assumption = not_exprt{conjunction (property.timeframe_handles )};
110-
111- decision_proceduret::resultt dec_result = solver (assumption);
112-
113- switch (dec_result)
114- {
115- case decision_proceduret::resultt::D_SATISFIABLE:
116- if (property.is_exists_path ())
117- {
118- property.proved ();
119- message.result () << " SAT: path found" << messaget::eom;
120- }
121- else // universal path property
122- {
123- property.refuted ();
124- message.result () << " SAT: counterexample found" << messaget::eom;
125- }
126-
127- property.witness_trace = compute_trans_trace (
128- property.timeframe_handles ,
129- solver,
130- bound + 1 ,
131- ns,
132- transition_system.main_symbol ->name );
133- break ;
134-
135- case decision_proceduret::resultt::D_UNSATISFIABLE:
136- if (property.is_exists_path ())
137- {
138- message.result () << " UNSAT: No path found within bound"
139- << messaget::eom;
140- property.refuted_with_bound (bound);
141- }
142- else // universal path property
143- {
144- message.result () << " UNSAT: No counterexample found within bound"
145- << messaget::eom;
146- property.proved_with_bound (bound);
147- }
148- break ;
149-
150- case decision_proceduret::resultt::D_ERROR:
151- message.error () << " Error from decision procedure" << messaget::eom;
152- property.failure ();
153- break ;
154-
155- default :
156- property.failure ();
157- throw ebmc_errort () << " Unexpected result from decision procedure" ;
158- }
286+ ::bmc_with_assumptions (
287+ bound, transition_system, properties, solver, message_handler);
288+ }
289+ else
290+ {
291+ ::bmc_with_iterative_constraint_strengthening (
292+ bound, transition_system, properties, solver, message_handler);
159293 }
160294
161295 auto sat_stop_time = std::chrono::steady_clock::now ();
0 commit comments