Skip to content

ebmc: normalize properties #430

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

Merged
merged 1 commit into from
Apr 15, 2024
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
20 changes: 11 additions & 9 deletions src/ebmc/bdd_engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ int bdd_enginet::operator()()
cmdline, transition_system, message.get_message_handler());

for(const propertyt &p : properties.properties)
get_atomic_propositions(p.expr);
get_atomic_propositions(p.normalized_expr);

message.status() << "Building BDD for netlist" << messaget::eom;

Expand Down Expand Up @@ -376,7 +376,7 @@ void bdd_enginet::compute_counterexample(

::unwind(netlist, bmc_map, message, solver);
::unwind_property(
property.expr,
property.normalized_expr,
property.timeframe_literals,
message.get_message_handler(),
solver,
Expand Down Expand Up @@ -450,17 +450,18 @@ void bdd_enginet::check_property(propertyt &property)
!has_temporal_operator(to_F_expr(to_G_expr(expr).op()).op());
};

if(is_AGp(property.expr))
if(is_AGp(property.normalized_expr))
{
AGp(property);
}
else if(
is_AG_AFp(property.expr) || is_always_eventually(property.expr) ||
is_GFp(property.expr))
is_AG_AFp(property.normalized_expr) ||
is_always_eventually(property.normalized_expr) ||
is_GFp(property.normalized_expr))
{
AGAFp(property);
}
else if(!has_temporal_operator(property.expr))
else if(!has_temporal_operator(property.normalized_expr))
{
just_p(property);
}
Expand All @@ -482,7 +483,7 @@ Function: bdd_enginet::AGp

void bdd_enginet::AGp(propertyt &property)
{
const exprt &sub_expr = to_unary_expr(property.expr).op();
const exprt &sub_expr = to_unary_expr(property.normalized_expr).op();
BDD p = property2BDD(sub_expr);

// Start with !p, and go backwards until saturation or we hit an
Expand Down Expand Up @@ -563,7 +564,8 @@ Function: bdd_enginet::AGAFp

void bdd_enginet::AGAFp(propertyt &property)
{
const exprt &sub_expr = to_unary_expr(to_unary_expr(property.expr).op()).op();
const exprt &sub_expr =
to_unary_expr(to_unary_expr(property.normalized_expr).op()).op();
BDD p = property2BDD(sub_expr);

// Start with p, and go backwards until saturation.
Expand Down Expand Up @@ -648,7 +650,7 @@ void bdd_enginet::just_p(propertyt &property)
{
// We check whether the BDD for the negation of the property
// contains an initial state.
exprt negation = negate_property(property.expr);
exprt negation = negate_property(property.normalized_expr);
BDD states = property2BDD(negation);

// do we have an initial state?
Expand Down
4 changes: 2 additions & 2 deletions src/ebmc/bmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ void bmc(
continue;

// Is it supported by the BMC engine?
if(!bmc_supports_property(property.expr))
if(!bmc_supports_property(property.normalized_expr))
{
property.failure("property not supported by BMC engine");
continue;
}

::property(
property.expr,
property.normalized_expr,
property.timeframe_handles,
message_handler,
solver,
Expand Down
2 changes: 1 addition & 1 deletion src/ebmc/ebmc_base.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ int ebmc_baset::do_bit_level_bmc(cnft &solver, bool convert_only)
continue;

::unwind_property(
property.expr,
property.normalized_expr,
property.timeframe_literals,
message.get_message_handler(),
solver,
Expand Down
8 changes: 6 additions & 2 deletions src/ebmc/ebmc_properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Author: Daniel Kroening, [email protected]
#include <langapi/language.h>
#include <langapi/language_util.h>
#include <langapi/mode.h>
#include <temporal-logic/normalize_property.h>
#include <verilog/sva_expr.h>

#include "ebmc_error.h"
Expand Down Expand Up @@ -70,7 +71,9 @@ ebmc_propertiest ebmc_propertiest::from_transition_system(
else
properties.properties.back().name = symbol.pretty_name;

properties.properties.back().expr = symbol.value;
properties.properties.back().original_expr = symbol.value;
properties.properties.back().normalized_expr =
normalize_property(symbol.value);
Comment on lines +74 to +76
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we'll eventually want a non-default constructor for propertyt.

properties.properties.back().location = symbol.location;
properties.properties.back().expr_string = value_as_string;
properties.properties.back().mode = symbol.mode;
Expand Down Expand Up @@ -156,7 +159,8 @@ ebmc_propertiest ebmc_propertiest::from_command_line(
ebmc_propertiest properties;
properties.properties.push_back(propertyt());
auto &p = properties.properties.back();
p.expr = expr;
p.original_expr = expr;
p.normalized_expr = normalize_property(expr);
p.expr_string = expr_as_string;
p.mode = transition_system.main_symbol->mode;
p.location.make_nil();
Expand Down
5 changes: 3 additions & 2 deletions src/ebmc/ebmc_properties.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ class ebmc_propertiest
source_locationt location;
std::string expr_string;
irep_idt mode;
exprt expr;
exprt original_expr;
exprt normalized_expr;
bvt timeframe_literals; // bit level
exprt::operandst timeframe_handles; // word level
std::string description;
Expand Down Expand Up @@ -143,7 +144,7 @@ class ebmc_propertiest

bool requires_lasso_constraints() const
{
return ::requires_lasso_constraints(expr);
return ::requires_lasso_constraints(normalized_expr);
}
};

Expand Down
4 changes: 2 additions & 2 deletions src/ebmc/k_induction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class k_inductiont

static bool supported(const ebmc_propertiest::propertyt &p)
{
auto &expr = p.expr;
auto &expr = p.normalized_expr;
if(expr.id() == ID_sva_always || expr.id() == ID_AG || expr.id() == ID_G)
{
// Must be AG p or equivalent.
Expand Down Expand Up @@ -264,7 +264,7 @@ void k_inductiont::induction_step()
ns,
false);

const exprt property(p_it.expr);
const exprt property(p_it.normalized_expr);
const exprt &p = to_unary_expr(property).op();

// assumption: time frames 0,...,k-1
Expand Down
13 changes: 8 additions & 5 deletions src/ebmc/liveness_to_safety.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -248,9 +248,11 @@ void liveness_to_safetyt::operator()()
{
// We want GFp.
if(
property.expr.id() == ID_sva_always &&
(to_sva_always_expr(property.expr).op().id() == ID_sva_eventually ||
to_sva_always_expr(property.expr).op().id() == ID_sva_s_eventually))
property.normalized_expr.id() == ID_sva_always &&
(to_sva_always_expr(property.normalized_expr).op().id() ==
ID_sva_eventually ||
to_sva_always_expr(property.normalized_expr).op().id() ==
ID_sva_s_eventually))
{
translate_GFp(property);
}
Expand All @@ -265,7 +267,7 @@ void liveness_to_safetyt::operator()()

void liveness_to_safetyt::translate_GFp(propertyt &property)
{
auto &p = to_unary_expr(to_unary_expr(property.expr).op()).op();
auto &p = to_unary_expr(to_unary_expr(property.normalized_expr).op()).op();

// create the 'live' symbol, one for each liveness property
{
Expand Down Expand Up @@ -299,7 +301,8 @@ void liveness_to_safetyt::translate_GFp(propertyt &property)
conjunction({transition_system.trans_expr.trans(), std::move(live_trans)});

// replace the liveness property
property.expr = safety_replacement(property.name, property.expr);
property.normalized_expr =
safety_replacement(property.name, property.normalized_expr);
}

void liveness_to_safety(
Expand Down
11 changes: 6 additions & 5 deletions src/ebmc/neural_liveness.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,13 +162,14 @@ void neural_livenesst::validate_properties()
{
// ignore
}
else if(property.expr.id() == ID_AF)
else if(property.normalized_expr.id() == ID_AF)
{
// ok
}
else if(
property.expr.id() == ID_sva_always &&
to_sva_always_expr(property.expr).op().id() == ID_sva_s_eventually)
property.normalized_expr.id() == ID_sva_always &&
to_sva_always_expr(property.normalized_expr).op().id() ==
ID_sva_s_eventually)
{
// ok
}
Expand All @@ -188,7 +189,7 @@ void neural_livenesst::set_live_signal(
auto main_symbol_writeable = transition_system.symbol_table.get_writeable(
transition_system.main_symbol->name);
main_symbol_writeable->value = original_trans_expr; // copy
::set_live_signal(transition_system, property.expr);
::set_live_signal(transition_system, property.normalized_expr);
}

std::function<void(trans_tracet)>
Expand Down Expand Up @@ -301,7 +302,7 @@ tvt neural_livenesst::verify(

auto result = is_ranking_function(
transition_system,
property.expr,
property.normalized_expr,
candidate,
solver_factory,
message.get_message_handler());
Expand Down
2 changes: 1 addition & 1 deletion src/ebmc/ranking_function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ int do_ranking_function(

auto result = is_ranking_function(
transition_system,
property.expr,
property.normalized_expr,
ranking_function,
solver_factory,
message_handler);
Expand Down
4 changes: 2 additions & 2 deletions src/ic3/r1ead_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ void ic3_enginet::find_prop_lit()
bool found = find_prop(Prop);

assert(found);
assert(Prop.expr.id() == ID_sva_always);
assert(Prop.normalized_expr.id() == ID_sva_always);

exprt Oper = to_unary_expr(Prop.expr).op();
exprt Oper = to_unary_expr(Prop.normalized_expr).op();

found = banned_expr(Oper);
if (found) {
Expand Down
1 change: 1 addition & 0 deletions src/temporal-logic/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
SRC = negate_property.cpp \
normalize_property.cpp \
temporal_logic.cpp \
#empty line

Expand Down
65 changes: 65 additions & 0 deletions src/temporal-logic/normalize_property.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*******************************************************************\

Module: Property Normalization

Author: Daniel Kroening, [email protected]

\*******************************************************************/

#include "normalize_property.h"

#include <util/std_expr.h>

#include <verilog/sva_expr.h>

#include "temporal_expr.h"

exprt normalize_pre_not(not_exprt expr)
{
const auto &op = expr.op();

if(op.id() == ID_and)
{
auto operands = op.operands();
for(auto &op : operands)
op = not_exprt{op};
return or_exprt{std::move(operands)};
}
else if(op.id() == ID_or)
{
auto operands = op.operands();
for(auto &op : operands)
op = not_exprt{op};
return and_exprt{std::move(operands)};
}
else if(op.id() == ID_not)
{
return to_not_expr(op).op();
}

return std::move(expr);
}

exprt normalize_pre_implies(implies_exprt expr)
{
return or_exprt{not_exprt{expr.lhs()}, expr.rhs()};
}

exprt normalize_property(exprt expr)
{
// pre-traversal
if(expr.id() == ID_not)
expr = normalize_pre_not(to_not_expr(expr));
else if(expr.id() == ID_implies)
expr = normalize_pre_implies(to_implies_expr(expr));
else if(expr.id() == ID_sva_cover)
expr = G_exprt{not_exprt{to_sva_cover_expr(expr).op()}};

// normalize the operands
for(auto &op : expr.operands())
op = normalize_property(op);

// post-traversal

return expr;
}
21 changes: 21 additions & 0 deletions src/temporal-logic/normalize_property.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*******************************************************************\

Module: Property Normalization

Author: Daniel Kroening, [email protected]

\*******************************************************************/

#ifndef CPROVER_TEMPORAL_LOGIC_NORMALIZE_PROPERTY_H
#define CPROVER_TEMPORAL_LOGIC_NORMALIZE_PROPERTY_H

#include <util/expr.h>

/// This applies the following rewrites:
/// cover(φ) --> G¬φ
/// ¬(a ∨ b) --> ¬a ∧ ¬b
/// ¬(a ∧ b) --> ¬a ∨ ¬b
/// ¬¬φ --> φ
exprt normalize_property(exprt);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Could you please add comments to describe what the normal form is that is being established?

Copy link
Member Author

Choose a reason for hiding this comment

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

done


#endif
3 changes: 2 additions & 1 deletion src/verilog/verilog_synthesis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1850,7 +1850,8 @@ void verilog_synthesist::synth_assert_cover(

if(module_item.id() == ID_verilog_assert_property)
{
// Concurrent assertions come with an implicit 'always'.
// Concurrent assertions come with an implicit 'always'
// (1800-2017 Sec 16.12.11).
if(cond.id() != ID_sva_always)
cond = sva_always_exprt(cond);
}
Expand Down