Skip to content

Commit

Permalink
Implement property generalization
Browse files Browse the repository at this point in the history
  • Loading branch information
CyanoKobalamyne committed Sep 14, 2024
1 parent 158bfaf commit 9c9cd3a
Show file tree
Hide file tree
Showing 7 changed files with 127 additions and 2 deletions.
34 changes: 33 additions & 1 deletion modifiers/mod_ts_prop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@
#include "modifiers/mod_ts_prop.h"

#include "core/rts.h"
#include "smt-switch/smt.h"
#include "smt-switch/utils.h"
#include "utils/logger.h"
#include "utils/term_analysis.h"
#include "utils/term_walkers.h"
#include "utils/ts_manipulation.h"

using namespace smt;
Expand Down Expand Up @@ -151,4 +152,35 @@ TransitionSystem promote_inputvars(const TransitionSystem & ts)
return new_ts;
}

void generalize_property(TransitionSystem & ts, Term & prop)
{
// Universally quantify all free variables (inputs and update-less states).
SubTermParametrizer term_parametrizer{
ts.solver(), { ts.inputvars(), ts.statevars_with_no_update() }
};
auto parametrized_prop = term_parametrizer.parametrize_subterms(prop);
auto params = term_parametrizer.parameters();
if (params.size() == 0) {
logger.log(1, "Property cannot be generalized (yet)");
// Nothing to generalize.
return;
}
params.emplace_back(parametrized_prop);
auto generalized_prop = ts.solver()->make_term(PrimOp::Forall, params);

// Verify that this still implies the property.
ts.solver()->push();
ts.solver()->assert_formula(
ts.solver()->make_term(PrimOp::And,
generalized_prop,
ts.solver()->make_term(PrimOp::Not, prop)));
if (ts.solver()->check_sat().is_sat()) {
logger.log(1, "Property generalization failed, using original one");
} else {
prop = generalized_prop;
logger.log(1, "Generalized property to: {}", prop->to_string());
}
ts.solver()->pop();
}

} // namespace pono
8 changes: 8 additions & 0 deletions modifiers/mod_ts_prop.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#pragma once

#include "core/ts.h"
#include "smt-switch/smt.h"

namespace pono {

Expand Down Expand Up @@ -50,4 +51,11 @@ void prop_in_trans(TransitionSystem & ts, const smt::Term & prop);
*/
TransitionSystem promote_inputvars(const TransitionSystem & ts);

/** Generalizes the property by adding quantifiers over variables that don't
* have a next state defined which can help to prove it.
* @param ts the transition system that the property refers to
* @param prop the property to generalize, modified in place
*/
void generalize_property(TransitionSystem & ts, smt::Term & prop);

} // namespace pono
11 changes: 11 additions & 0 deletions options/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
**/

#include "options/options.h"

#include <iostream>
#include <string>
#include <vector>

#include "optionparser.h"
#include "utils/exceptions.h"

Expand All @@ -40,6 +42,7 @@ enum optionIndex
STATICCOI,
SHOW_INVAR,
CHECK_INVAR,
GENERALIZE_PROP,
RESET,
RESET_BND,
CLK,
Expand Down Expand Up @@ -222,6 +225,13 @@ const option::Descriptor usage[] = {
Arg::None,
" --check-invar \tFor engines that produce invariants, check that they "
"hold." },
{ GENERALIZE_PROP,
0,
"",
"generalize-prop",
Arg::None,
" --generalize-prop \tattempt to strengthen the property by universally "
"quantifying variables (default: false)" },
{ RESET,
0,
"r",
Expand Down Expand Up @@ -701,6 +711,7 @@ ProverResult PonoOptions::parse_and_set_options(int argc,
case STATICCOI: static_coi_ = true; break;
case SHOW_INVAR: show_invar_ = true; break;
case CHECK_INVAR: check_invar_ = true; break;
case GENERALIZE_PROP: generalize_prop_ = true; break;
case RESET: reset_name_ = opt.arg; break;
case RESET_BND: reset_bnd_ = atoi(opt.arg); break;
case CLK: clock_name_ = opt.arg; break;
Expand Down
3 changes: 3 additions & 0 deletions options/options.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class PonoOptions
static_coi_(default_static_coi_),
show_invar_(default_show_invar_),
check_invar_(default_check_invar_),
generalize_prop_(default_generalize_prop_),
ic3_pregen_(default_ic3_pregen_),
ic3_indgen_(default_ic3_indgen_),
ic3_gen_max_iter_(default_ic3_gen_max_iter_),
Expand Down Expand Up @@ -192,6 +193,7 @@ class PonoOptions
bool static_coi_;
bool show_invar_; ///< display invariant when running from command line
bool check_invar_; ///< check invariants (if available) when run through CLI
bool generalize_prop_; ///< attempt to strengthen property before proving
// ic3 options
bool ic3_pregen_; ///< generalize counterexamples in IC3
bool ic3_indgen_; ///< inductive generalization in IC3
Expand Down Expand Up @@ -304,6 +306,7 @@ class PonoOptions
static const bool default_static_coi_ = false;
static const bool default_show_invar_ = false;
static const bool default_check_invar_ = false;
static const bool default_generalize_prop_ = false;
static const size_t default_reset_bnd_ = 1;
// TODO distinguish when solver is not set and choose a
// good solver for the provided engine automatically
Expand Down
4 changes: 4 additions & 0 deletions pono.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ ProverResult check_prop(PonoOptions pono_options,
prop_in_trans(ts, prop);
}

if (pono_options.generalize_prop_) {
generalize_property(ts, prop);
}

Property p(s, prop, prop_name);

// end modification of the transition system and property
Expand Down
34 changes: 34 additions & 0 deletions utils/term_walkers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@

#include "utils/term_walkers.h"

#include <algorithm>

#include "assert.h"
#include "smt-switch/identity_walker.h"
#include "smt-switch/smt.h"
#include "utils/term_analysis.h"

using namespace smt;
Expand Down Expand Up @@ -123,4 +127,34 @@ WalkerStepResult SubTermCollector::visit_term(smt::Term & term)
return Walker_Continue;
}

SubTermParametrizer::SubTermParametrizer(
const smt::SmtSolver & solver,
const std::vector<smt::UnorderedTermSet> & filters)
: super(solver, true), filters_(filters)
{
}

Term SubTermParametrizer::parametrize_subterms(Term & term)
{
parameters_ = {};
auto new_term = visit(term);
reverse(parameters_.begin(), parameters_.end());
return new_term;
}

WalkerStepResult SubTermParametrizer::visit_term(Term & term)
{
if (preorder_) {
for (const auto & filter : filters_) {
if (filter.find(term) != filter.end()) {
auto param = solver_->make_param(term->to_string(), term->get_sort());
parameters_.emplace_back(param);
save_in_cache(term, param);
break;
}
}
}
return super::visit_term(term);
}

} // namespace pono
35 changes: 34 additions & 1 deletion utils/term_walkers.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@
**/
#pragma once

#include <unordered_set>
#include <vector>

#include "smt-switch/identity_walker.h"
#include "smt-switch/smt.h"
#include "smt-switch/term.h"

namespace pono {

Expand Down Expand Up @@ -67,7 +71,8 @@ class SubTermCollector : public smt::IdentityWalker

void collect_subterms(smt::Term term);

const std::unordered_map<smt::Sort, smt::UnorderedTermSet> & get_subterms() const
const std::unordered_map<smt::Sort, smt::UnorderedTermSet> & get_subterms()
const
{
return subterms_;
};
Expand All @@ -92,4 +97,32 @@ class SubTermCollector : public smt::IdentityWalker
smt::WalkerStepResult visit_term(smt::Term & term) override;
};

/** Class for transforming a given set of subterms into parameters. */
class SubTermParametrizer : public smt::IdentityWalker
{
public:
/** Constructs a SubTermParametrizer for a given set of terms.
* @param solver the solver instance that the terms are defined in
* @param filters vector of sets which should be searched for terms to replace
*/
SubTermParametrizer(const smt::SmtSolver & solver,
const std::vector<smt::UnorderedTermSet> & filters);

typedef smt::IdentityWalker super;

/** Replaces all occurences of the terms in filters with parameters
* @param term term to transform
* @return transformed term
*/
smt::Term parametrize_subterms(smt::Term & term);

smt::TermVec parameters() const { return parameters_; };

protected:
smt::WalkerStepResult visit_term(smt::Term & term) override;

const std::vector<smt::UnorderedTermSet> filters_;
smt::TermVec parameters_;
};

} // namespace pono

0 comments on commit 9c9cd3a

Please sign in to comment.