Skip to content

BMC: completeness thresholds larger than one #1115

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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: 1 addition & 1 deletion regression/verilog/SVA/sequence_and1.bmc.desc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ sequence_and1.sv
^\[main\.p1\] strong\(main\.x == 0 and main\.x == 1\): REFUTED$
^\[main\.p2\] main\.x == 0 and \(nexttime main\.x == 1\): PROVED up to bound \d+$
^\[main\.p3\] \(nexttime main\.x == 1\) and main\.x == 0: PROVED up to bound \d+$
^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED up to bound \d+$
^\[main\.p4\] \(main\.x == 0 and main\.x != 10\) |=> main\.x == 1: PROVED$
^EXIT=10$
^SIGNAL=0$
--
Expand Down
6 changes: 3 additions & 3 deletions regression/verilog/SVA/sequence_and2.bmc.desc
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
CORE
sequence_and2.sv

\[.*\] \(1 and \(##2 1\)\) \|-> main\.x == 2: PROVED up to bound 5$
\[.*\] \(\(##2 1\) and 1\) \|-> main\.x == 2: PROVED up to bound 5$
\[.*\] \(\(##2 1\) and 1\) #-# main\.x == 2: PROVED up to bound 5$
^\[.*\] \(1 and \(##2 1\)\) \|-> main\.x == 2: PROVED up to bound 5$
^\[.*\] \(\(##2 1\) and 1\) \|-> main\.x == 2: PROVED up to bound 5$
^\[.*\] \(\(##2 1\) and 1\) #-# main\.x == 2: PROVED up to bound 5$
^EXIT=0$
^SIGNAL=0$
--
Expand Down
101 changes: 67 additions & 34 deletions src/ebmc/completeness_threshold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,22 @@ Author: Daniel Kroening, [email protected]

#include "bmc.h"

bool has_low_completeness_threshold(const exprt &expr)
// counting number of transitions
std::optional<mp_integer> completeness_threshold(const exprt &expr)
{
if(!has_temporal_operator(expr))
{
return true; // state predicate only
return 0; // state predicate only
}
else if(expr.id() == ID_X)
{
// X p
return !has_temporal_operator(to_X_expr(expr).op());
// Increases the CT by one.
auto ct_p = completeness_threshold(to_X_expr(expr).op());
if(ct_p.has_value())
return *ct_p + 1;
else
return {};
}
else if(
expr.id() == ID_sva_nexttime || expr.id() == ID_sva_s_nexttime ||
Expand All @@ -37,69 +43,94 @@ bool has_low_completeness_threshold(const exprt &expr)
else if(expr.id() == ID_sva_ranged_always)
{
auto &always_expr = to_sva_ranged_always_expr(expr);
if(has_temporal_operator(always_expr.op()))
return false;
else if(always_expr.upper().is_constant())
if(always_expr.upper().is_constant())
{
auto lower_int = numeric_cast_v<mp_integer>(always_expr.lower());
auto upper_int =
numeric_cast_v<mp_integer>(to_constant_expr(always_expr.upper()));
return lower_int >= 0 && lower_int <= 1 && upper_int >= 0 &&
upper_int <= 1;

if(upper_int < 0)
return {};

// increases the CT by upper_int
auto ct_op = completeness_threshold(always_expr.op());
if(ct_op.has_value())
return *ct_op + upper_int;
else
return {};
}
else
return false;
return {};
}
else if(expr.id() == ID_sva_s_always)
{
auto &s_always_expr = to_sva_s_always_expr(expr);
if(has_temporal_operator(s_always_expr.op()))
return false;

auto upper_int =
numeric_cast_v<mp_integer>(to_constant_expr(s_always_expr.upper()));

if(upper_int < 0)
return {};

// increases the CT by upper_int
auto ct_op = completeness_threshold(s_always_expr.op());
if(ct_op.has_value())
return *ct_op + upper_int;
else
{
auto lower_int = numeric_cast_v<mp_integer>(s_always_expr.lower());
auto upper_int = numeric_cast_v<mp_integer>(s_always_expr.upper());
return lower_int >= 0 && lower_int <= 1 && upper_int >= 0 &&
upper_int <= 1;
}
return {};
}
else if(
expr.id() == ID_sva_strong || expr.id() == ID_sva_weak ||
expr.id() == ID_sva_implicit_strong || expr.id() == ID_sva_implicit_weak)
{
auto &sequence = to_sva_sequence_property_expr_base(expr).sequence();
return has_low_completeness_threshold(sequence);
return completeness_threshold(sequence);
}
else if(expr.id() == ID_sva_boolean)
{
return true;
return 0; // state predicate only
}
else if(expr.id() == ID_sva_or || expr.id() == ID_sva_and)
{
mp_integer max_ct = 0;

for(auto &op : expr.operands())
if(!has_low_completeness_threshold(op))
return false;
return true;
{
auto ct_op = completeness_threshold(op);
if(ct_op.has_value())
max_ct = std::max(*ct_op, max_ct);
else
return {}; // no CT
}

return max_ct;
}
else if(expr.id() == ID_sva_sequence_property)
{
PRECONDITION(false); // should have been turned into implicit weak/strong
}
else
return false;
return {};
}

bool has_low_completeness_threshold(const ebmc_propertiest::propertyt &property)
std::optional<mp_integer>
completeness_threshold(const ebmc_propertiest::propertyt &property)
{
return has_low_completeness_threshold(property.normalized_expr);
return completeness_threshold(property.normalized_expr);
}

bool have_low_completeness_threshold(const ebmc_propertiest &properties)
std::optional<mp_integer>
completeness_threshold(const ebmc_propertiest &properties)
{
std::optional<mp_integer> max_ct;

for(auto &property : properties.properties)
if(has_low_completeness_threshold(property))
return true;
return false;
{
auto ct_opt = completeness_threshold(property);
if(ct_opt.has_value())
max_ct = std::max(max_ct.value_or(0), *ct_opt);
}

return max_ct;
}

property_checker_resultt completeness_threshold(
Expand All @@ -110,13 +141,15 @@ property_checker_resultt completeness_threshold(
message_handlert &message_handler)
{
// Do we have an eligibile property?
if(!have_low_completeness_threshold(properties))
auto ct_opt = completeness_threshold(properties);

if(!ct_opt.has_value())
return property_checker_resultt{properties}; // give up

// Do BMC with two timeframes
auto result = bmc(
1, // bound
false, // convert_only
numeric_cast_v<std::size_t>(*ct_opt), // bound
false, // convert_only
cmdline.isset("bmc-with-assumptions"),
transition_system,
properties,
Expand All @@ -128,7 +161,7 @@ property_checker_resultt completeness_threshold(
if(property.is_proved_with_bound())
{
// Turn "PROVED up to bound k" into "PROVED" if k>=CT
if(has_low_completeness_threshold(property) && property.bound >= 1)
if(completeness_threshold(property).has_value())
property.proved();
else
property.unknown();
Expand Down
Loading