Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# EBMC 5.4

* BMC: Cadical support with --cadical
* BMC: iterative constraint strengthening is now default;
use --bmc-with-assumptions to re-enable the previous algorithm.

# EBMC 5.3

Expand Down
8 changes: 8 additions & 0 deletions regression/ebmc/assumptions/assume2.bmc-with-assumptions.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CORE
assume2.sv
--bound 0 --bmc-with-assumptions
^\[main\.a1\] assume always 10 <= main\.a && main\.a <= 100: ASSUMED$
^\[main\.p1\] always main\.a != 200: PROVED up to bound 0$
^\[main\.p2\] always main.a != 20: REFUTED$
^EXIT=10$
^SIGNAL=0$
2 changes: 1 addition & 1 deletion regression/ebmc/example4_trace/test.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ example4.sv
--bound 10 --trace
^\[counter\.assert\.1\] .* PROVED up to bound 10$
^\[counter\.assert\.2\] .* REFUTED$
^ counter\.state = 254 \(11111110\)$
^ counter\.state = \d+ \([01]+\)$
^EXIT=10$
^SIGNAL=0$
2 changes: 1 addition & 1 deletion regression/verilog/functioncall/functioncall2.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ functioncall2.v
--module main --bound 1
^EXIT=0$
^SIGNAL=0$
^UNSAT: No counterexample found within bound$
^UNSAT: .*$
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use this (or any other) test to exercise bmc-with-assumptions?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test added

--
^warning: ignoring
2 changes: 1 addition & 1 deletion regression/verilog/functioncall/functioncall3.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@ functioncall3.v
--module main --bound 0
^EXIT=0$
^SIGNAL=0$
^UNSAT: No counterexample found within bound$
^UNSAT: .*$
--
^warning: ignoring
2 changes: 1 addition & 1 deletion regression/verilog/functioncall/functioncall4.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ functioncall4.v
--module main --bound 0
^EXIT=0$
^SIGNAL=0$
^UNSAT: No counterexample found within bound$
^UNSAT: .*$
--
^warning: ignoring
--
262 changes: 198 additions & 64 deletions src/ebmc/bmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,184 @@ Author: Daniel Kroening, dkr@amazon.com
#include <chrono>
#include <fstream>

void bmc_with_assumptions(
std::size_t bound,
const transition_systemt &transition_system,
ebmc_propertiest &properties,
decision_proceduret &solver,
message_handlert &message_handler)
{
messaget message(message_handler);
const namespacet ns(transition_system.symbol_table);

// Use assumptions to check the properties separately

for(auto &property : properties.properties)
{
if(property.is_disabled() || property.is_failure() || property.is_assumed())
{
continue;
}

message.status() << "Checking " << property.name << messaget::eom;

auto assumption = not_exprt{conjunction(property.timeframe_handles)};

decision_proceduret::resultt dec_result = solver(assumption);

switch(dec_result)
{
case decision_proceduret::resultt::D_SATISFIABLE:
if(property.is_exists_path())
{
property.proved();
message.result() << "SAT: path found" << messaget::eom;
}
else // universal path property
{
property.refuted();
message.result() << "SAT: counterexample found" << messaget::eom;
}

property.witness_trace = compute_trans_trace(
property.timeframe_handles,
solver,
bound + 1,
ns,
transition_system.main_symbol->name);
break;

case decision_proceduret::resultt::D_UNSATISFIABLE:
if(property.is_exists_path())
{
message.result() << "UNSAT: No path found within bound"
<< messaget::eom;
property.refuted_with_bound(bound);
}
else // universal path property
{
message.result() << "UNSAT: No counterexample found within bound"
<< messaget::eom;
property.proved_with_bound(bound);
}
break;

case decision_proceduret::resultt::D_ERROR:
message.error() << "Error from decision procedure" << messaget::eom;
property.failure();
break;

default:
property.failure();
throw ebmc_errort() << "Unexpected result from decision procedure";
}
}
}

/// VMCAI 2009 Query-driven program testing,
/// "iterative constraint strengthening"
void bmc_with_iterative_constraint_strengthening(
std::size_t bound,
const transition_systemt &transition_system,
ebmc_propertiest &properties,
decision_proceduret &solver,
message_handlert &message_handler)
{
messaget message(message_handler);
const namespacet ns(transition_system.symbol_table);

auto trace_found = [&solver](const ebmc_propertiest::propertyt &property)
{
for(auto &h : property.timeframe_handles)
if(solver.get(h).is_false())
return true;
return false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about return solver.get(h).is_false();

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That won't work -- note the loop.

};

while(true)
{
// At least one of the remaining properties
// should be falsified.
exprt::operandst disjuncts;

for(auto &property : properties.properties)
{
if(property.is_unknown())
{
for(auto &h : property.timeframe_handles)
disjuncts.push_back(not_exprt{h});
}
}

// This constraint is strenthened in each iteration.
solver.set_to_true(disjunction(disjuncts));

decision_proceduret::resultt dec_result = solver();

switch(dec_result)
{
case decision_proceduret::resultt::D_SATISFIABLE:
// Found a trace for at least one further property with unknown state
message.result() << "SAT: path found" << messaget::eom;

for(auto &property : properties.properties)
{
if(property.is_unknown() && trace_found(property))
{
if(property.is_exists_path())
property.proved();
else // universal path property
property.refuted();

property.witness_trace = compute_trans_trace(
property.timeframe_handles,
solver,
bound + 1,
ns,
transition_system.main_symbol->name);
}
}
break; // next iteration of while loop

case decision_proceduret::resultt::D_UNSATISFIABLE:
message.result() << "UNSAT: No path found within bound" << messaget::eom;

for(auto &property : properties.properties)
{
if(property.is_unknown())
{
if(property.is_exists_path())
property.refuted_with_bound(bound);
else // universal path property
property.proved_with_bound(bound);
}
}
return;

case decision_proceduret::resultt::D_ERROR:
for(auto &property : properties.properties)
{
if(property.is_unknown())
property.failure();
}
message.error() << "Error from decision procedure" << messaget::eom;
return;

default:
for(auto &property : properties.properties)
{
if(property.is_unknown())
property.failure();
}
throw ebmc_errort() << "Unexpected result from decision procedure";
}
}
}

void bmc(
std::size_t bound,
bool convert_only,
bool bmc_with_assumptions,
const transition_systemt &transition_system,
ebmc_propertiest &properties,
const ebmc_solver_factoryt &solver_factory,
Expand Down Expand Up @@ -76,12 +251,25 @@ void bmc(

if(convert_only)
{
// At least one property must be violated in at least one
// timeframe.
exprt::operandst disjuncts;

for(const auto &property : properties.properties)
{
if(!property.is_disabled())
solver.set_to_false(conjunction(property.timeframe_handles));
if(property.is_assumed())
{
// already added as constraint above
}
else if(!property.is_disabled())
{
for(auto &h : property.timeframe_handles)
disjuncts.push_back(not_exprt{h});
}
}

solver.set_to_true(disjunction(disjuncts));

// Call decision_proceduret::dec_solve to finish the conversion
// process.
(void)solver();
Expand All @@ -93,69 +281,15 @@ void bmc(

auto sat_start_time = std::chrono::steady_clock::now();

// Use assumptions to check the properties separately

for(auto &property : properties.properties)
if(bmc_with_assumptions)
{
if(
property.is_disabled() || property.is_failure() ||
property.is_assumed())
{
continue;
}

message.status() << "Checking " << property.name << messaget::eom;

auto assumption = not_exprt{conjunction(property.timeframe_handles)};

decision_proceduret::resultt dec_result = solver(assumption);

switch(dec_result)
{
case decision_proceduret::resultt::D_SATISFIABLE:
if(property.is_exists_path())
{
property.proved();
message.result() << "SAT: path found" << messaget::eom;
}
else // universal path property
{
property.refuted();
message.result() << "SAT: counterexample found" << messaget::eom;
}

property.witness_trace = compute_trans_trace(
property.timeframe_handles,
solver,
bound + 1,
ns,
transition_system.main_symbol->name);
break;

case decision_proceduret::resultt::D_UNSATISFIABLE:
if(property.is_exists_path())
{
message.result() << "UNSAT: No path found within bound"
<< messaget::eom;
property.refuted_with_bound(bound);
}
else // universal path property
{
message.result() << "UNSAT: No counterexample found within bound"
<< messaget::eom;
property.proved_with_bound(bound);
}
break;

case decision_proceduret::resultt::D_ERROR:
message.error() << "Error from decision procedure" << messaget::eom;
property.failure();
break;

default:
property.failure();
throw ebmc_errort() << "Unexpected result from decision procedure";
}
::bmc_with_assumptions(
bound, transition_system, properties, solver, message_handler);
}
else
{
::bmc_with_iterative_constraint_strengthening(
bound, transition_system, properties, solver, message_handler);
}

auto sat_stop_time = std::chrono::steady_clock::now();
Expand Down
1 change: 1 addition & 0 deletions src/ebmc/bmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class transition_systemt;
void bmc(
std::size_t bound,
bool convert_only,
bool bmc_with_assumptions,
const transition_systemt &,
ebmc_propertiest &,
const ebmc_solver_factoryt &,
Expand Down
1 change: 1 addition & 0 deletions src/ebmc/ebmc_parse_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class ebmc_parse_optionst:public parse_options_baset
"(compute-ct)(dot-netlist)(smv-netlist)(vcd):"
"(random-traces)(trace-steps):(random-seed):(traces):"
"(random-trace)(random-waveform)"
"(bmc-with-assumptions)"
"(liveness-to-safety)"
"I:D:(preprocess)(systemverilog)(vl2smv-extensions)"
"(warn-implicit-nets)",
Expand Down
3 changes: 2 additions & 1 deletion src/ebmc/k_induction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ void k_inductiont::induction_base()

bmc(
k,
false,
false, // convert_only
false, // bmc_with_assumptions
transition_system,
properties,
solver_factory,
Expand Down
3 changes: 3 additions & 0 deletions src/ebmc/property_checker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,12 @@ property_checker_resultt word_level_bmc(
if(properties.properties.empty())
throw "no properties";

bool bmc_with_assumptions = cmdline.isset("bmc-with-assumptions");

bmc(
bound,
convert_only,
bmc_with_assumptions,
transition_system,
properties,
solver_factory,
Expand Down
Loading