Skip to content

Commit

Permalink
Merge pull request #923 from diffblue/k-induction6-fix
Browse files Browse the repository at this point in the history
Engine heuristic: fix for assumptions unsupported by k-induction
  • Loading branch information
kroening authored Jan 16, 2025
2 parents 4f09a7e + 600f348 commit f334106
Show file tree
Hide file tree
Showing 18 changed files with 227 additions and 26 deletions.
10 changes: 10 additions & 0 deletions regression/ebmc/engine-heuristic/basic1.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
basic1.sv

^\[main\.a0\] always not s_eventually !main\.x: ASSUMED$
^\[main\.p0\] always main\.x: PROVED up to bound 5$
^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
--
8 changes: 8 additions & 0 deletions regression/ebmc/engine-heuristic/basic1.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module main(input clk, input x);

// not supported by k-induction
a0: assume property (not s_eventually !x);

p0: assert property (x);

endmodule
11 changes: 11 additions & 0 deletions regression/ebmc/engine-heuristic/basic2.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CORE
basic2.sv

^\[main\.a0\] always not s_eventually !main\.y: UNSUPPORTED: unsupported by k-induction$
^\[main\.a1\] always !main\.x: ASSUMED$
^\[main\.p0\] always !main\.z: PROVED$
^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
--
15 changes: 15 additions & 0 deletions regression/ebmc/engine-heuristic/basic2.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module main(input clk, input x, input y);

reg z = 0;
always_ff @(posedge clk) z <= z || x;

// unsupported assumption
a0: assume property (not s_eventually !y);

// supported assumption
a1: assume property (!x);

// inductive property
p0: assert property (!z);

endmodule
10 changes: 10 additions & 0 deletions regression/ebmc/engine-heuristic/basic3.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CORE
basic3.sv

^\[main\.a0\] always not s_eventually !main\.x: ASSUMED$
^\[main\.p0\] always 0: REFUTED$
^EXIT=10$
^SIGNAL=0$
--
^warning: ignoring
--
9 changes: 9 additions & 0 deletions regression/ebmc/engine-heuristic/basic3.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module main(input clk, input x);

// unsupported
a0: assume property (not s_eventually !x);

// should fail
p0: assert property (0);

endmodule
2 changes: 1 addition & 1 deletion regression/ebmc/k-induction/k-induction-unsupported2.desc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ k-induction-unsupported2.sv
--module main --k-induction
^EXIT=10$
^SIGNAL=0$
^\[main\.p0\] always s_eventually main\.x == 10: FAILURE: property unsupported by k-induction$
^\[main\.p0\] always s_eventually main\.x == 10: UNSUPPORTED: unsupported by k-induction$
^\[main\.p1\] always main\.x <= 10: PROVED$
--
^warning: ignoring
7 changes: 4 additions & 3 deletions regression/ebmc/k-induction/k-induction6.desc
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
KNOWNBUG
CORE
k-induction6.sv

--k-induction
^\[main\.a0\] always not s_eventually !main\.x: UNSUPPORTED: unsupported by k-induction$
^\[main\.p0\] always main\.x: INCONCLUSIVE$
^EXIT=10$
^SIGNAL=0$
--
^warning: ignoring
--
The property should hold, but is reported as refuted.
11 changes: 11 additions & 0 deletions regression/ebmc/k-induction/k-induction7.desc
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
CORE
k-induction7.sv
--k-induction
^\[main\.a0\] always not s_eventually !main\.y: UNSUPPORTED: unsupported by k-induction$
^\[main\.a1\] always !main\.x: ASSUMED$
^\[main\.p0\] always !main\.z: PROVED$
^EXIT=0$
^SIGNAL=0$
--
^warning: ignoring
--
15 changes: 15 additions & 0 deletions regression/ebmc/k-induction/k-induction7.sv
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module main(input clk, input x, input y);

reg z = 0;
always_ff @(posedge clk) z <= z || x;

// unsupported assumption
a0: assume property (not s_eventually !y);

// supported assumption
a1: assume property (!x);

// inductive property
p0: assert property (!z);

endmodule
2 changes: 1 addition & 1 deletion src/ebmc/bdd_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ property_checker_resultt bdd_enginet::operator()()
try
{
// any properties left?
if(!properties.has_unknown_property())
if(!properties.has_unfinished_property())
return property_checker_resultt{properties};

// possibly apply liveness-to-safety
Expand Down
17 changes: 10 additions & 7 deletions src/ebmc/ebmc_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ Author: Daniel Kroening, [email protected]

std::string ebmc_propertiest::propertyt::status_as_string() const
{
auto suffix = failure_reason.has_value() ? ": " + failure_reason.value() : "";

switch(status)
{
case statust::ASSUMED:
Expand All @@ -31,14 +33,15 @@ std::string ebmc_propertiest::propertyt::status_as_string() const
case statust::REFUTED_WITH_BOUND:
return "REFUTED up to bound " + std::to_string(bound);
case statust::UNKNOWN:
return "UNKNOWN";
return "UNKNOWN" + suffix;
case statust::UNSUPPORTED:
return "UNSUPPORTED" + suffix;
case statust::INCONCLUSIVE:
return "INCONCLUSIVE";
return "INCONCLUSIVE" + suffix;
case statust::FAILURE:
return failure_reason.has_value() ? "FAILURE: " + failure_reason.value()
: "FAILURE";
return "FAILURE" + suffix;
case statust::DROPPED:
return "DROPPED";
return "DROPPED" + suffix;
case statust::DISABLED:
default:
UNREACHABLE;
Expand Down Expand Up @@ -78,9 +81,9 @@ ebmc_propertiest ebmc_propertiest::from_transition_system(
id2string(symbol.location.get_comment());

// Don't try to prove assumption properties.
if(symbol.value.id() == ID_sva_assume)
if(properties.properties.back().is_assumption())
{
properties.properties.back().status = propertyt::statust::ASSUMED;
properties.properties.back().assumed();
properties.properties.back().normalized_expr =
normalize_property(to_sva_assume_expr(symbol.value).op());
}
Expand Down
73 changes: 70 additions & 3 deletions src/ebmc/ebmc_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class ebmc_propertiest
UNKNOWN, // no work done yet
DISABLED, // turned off by user
ASSUMED, // property is assumed to be true, unbounded
UNSUPPORTED, // property is unsupported
PROVED, // property is true, unbounded
PROVED_WITH_BOUND, // property is true, with bound
REFUTED, // property is false, possibly counterexample
Expand Down Expand Up @@ -98,24 +99,38 @@ class ebmc_propertiest
return status == statust::FAILURE;
}

bool is_unsupported() const
{
return status == statust::UNSUPPORTED;
}

bool is_inconclusive() const
{
return status == statust::INCONCLUSIVE;
}

void assumed()
{
status = statust::ASSUMED;
failure_reason = {};
}

void unknown()
{
status = statust::UNKNOWN;
failure_reason = {};
}

void disable()
{
status = statust::DISABLED;
failure_reason = {};
}

void proved()
{
status = statust::PROVED;
failure_reason = {};
}

void proved_with_bound(std::size_t _bound)
Expand All @@ -127,17 +142,20 @@ class ebmc_propertiest
void refuted()
{
status = statust::REFUTED;
failure_reason = {};
}

void refuted_with_bound(std::size_t _bound)
{
status = statust::REFUTED_WITH_BOUND;
bound = _bound;
failure_reason = {};
}

void drop()
{
status = statust::DROPPED;
failure_reason = {};
}

void failure(const std::optional<std::string> &reason = {})
Expand All @@ -146,9 +164,16 @@ class ebmc_propertiest
failure_reason = reason;
}

void unsupported(const std::optional<std::string> &reason = {})
{
status = statust::UNSUPPORTED;
failure_reason = reason;
}

void inconclusive()
{
status = statust::INCONCLUSIVE;
failure_reason = {};
}

std::string status_as_string() const;
Expand All @@ -164,16 +189,30 @@ class ebmc_propertiest
{
return ::is_exists_path(original_expr);
}

bool is_assumption() const
{
return original_expr.id() == ID_sva_assume;
}
};

typedef std::list<propertyt> propertiest;
propertiest properties;

bool has_unknown_property() const
bool has_unfinished_property() const
{
for(const auto &p : properties)
if(p.is_unknown())
{
if(p.is_assumption())
{
}
else if(
p.is_unknown() || p.is_unsupported() || p.is_failure() ||
p.is_inconclusive())
{
return true;
}
}

return false;
}
Expand Down Expand Up @@ -209,12 +248,40 @@ class ebmc_propertiest
return result;
}

void reset_failure_to_unknown()
/// Resets properties/assumptions in FAILURE state to
/// ASSUMED/UNKNOWN respectively.
void reset_failure()
{
for(auto &p : properties)
if(p.is_failure())
{
if(p.is_assumption())
p.assumed();
else
p.unknown();
}
}

/// Resets properties in INCONCLUSIVE state to UNKNOWN.
void reset_inconclusive()
{
for(auto &p : properties)
if(p.is_inconclusive())
p.unknown();
}

/// Resets properties in UNSUPPORTED state to UNKNOWN/ASSUMED.
void reset_unsupported()
{
for(auto &p : properties)
if(p.is_unsupported())
{
if(p.is_assumption())
p.assumed();
else
p.unknown();
}
}
};

#endif // CPROVER_EBMC_PROPERTIES_H
36 changes: 33 additions & 3 deletions src/ebmc/k_induction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,44 @@ Function: k_inductiont::operator()

void k_inductiont::operator()()
{
// Unsupported assumption? Mark as such.
bool assumption_unsupported = false;
for(auto &property : properties.properties)
{
if(!supported(property) && property.is_assumed())
{
assumption_unsupported = true;
property.unsupported("unsupported by k-induction");
}
}

// Fail unsupported properties
for(auto &property : properties.properties)
{
if(!supported(property))
property.failure("property unsupported by k-induction");
if(
!supported(property) && !property.is_assumed() && !property.is_disabled())
{
property.unsupported("unsupported by k-induction");
}
}

// do induction base
induction_base();

// do induction step
induction_step();

// Any refuted properties are really inconclusive if there are
// unsupported assumptions, as the assumption might have
// proven the property.
if(assumption_unsupported)
{
for(auto &property : properties.properties)
{
if(property.is_refuted())
property.inconclusive();
}
}
}

/*******************************************************************\
Expand Down Expand Up @@ -231,8 +257,12 @@ void k_inductiont::induction_step()

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

// If it's not failed, then it's supported.
DATA_INVARIANT(supported(p_it), "property must be supported");
Expand Down
Loading

0 comments on commit f334106

Please sign in to comment.