3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-07-19 02:42:02 +00:00

Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable

This commit is contained in:
Christoph M. Wintersteiger 2014-10-22 19:47:55 +01:00
commit 93337fedeb
23 changed files with 664 additions and 97 deletions

View file

@ -617,7 +617,7 @@ extern "C" {
} }
for (unsigned j = 0; j < num - 1; j++) for (unsigned j = 0; j < num - 1; j++)
if (read_parents[j] == SHRT_MIN){ if (read_parents[j] == SHRT_MAX){
read_error << "formula " << j + 1 << ": unreferenced"; read_error << "formula " << j + 1 << ": unreferenced";
goto fail; goto fail;
} }
@ -717,4 +717,4 @@ Z3_lbool Z3_API Z3_interpolate(__in Z3_context ctx,
__in unsigned incremental, __in unsigned incremental,
__in unsigned num_theory, __in unsigned num_theory,
__in_ecount(num_theory) Z3_ast *theory); __in_ecount(num_theory) Z3_ast *theory);
#endif #endif

View file

@ -241,7 +241,6 @@ protected:
symbol m_produce_models; symbol m_produce_models;
symbol m_produce_assignments; symbol m_produce_assignments;
symbol m_produce_interpolants; symbol m_produce_interpolants;
symbol m_check_interpolants;
symbol m_regular_output_channel; symbol m_regular_output_channel;
symbol m_diagnostic_output_channel; symbol m_diagnostic_output_channel;
symbol m_random_seed; symbol m_random_seed;
@ -256,7 +255,6 @@ protected:
s == m_print_success || s == m_print_warning || s == m_expand_definitions || s == m_print_success || s == m_print_warning || s == m_expand_definitions ||
s == m_interactive_mode || s == m_produce_proofs || s == m_produce_unsat_cores || s == m_interactive_mode || s == m_produce_proofs || s == m_produce_unsat_cores ||
s == m_produce_models || s == m_produce_assignments || s == m_produce_interpolants || s == m_produce_models || s == m_produce_assignments || s == m_produce_interpolants ||
s == m_check_interpolants ||
s == m_regular_output_channel || s == m_diagnostic_output_channel || s == m_regular_output_channel || s == m_diagnostic_output_channel ||
s == m_random_seed || s == m_verbosity || s == m_global_decls; s == m_random_seed || s == m_verbosity || s == m_global_decls;
} }
@ -275,7 +273,6 @@ public:
m_produce_models(":produce-models"), m_produce_models(":produce-models"),
m_produce_assignments(":produce-assignments"), m_produce_assignments(":produce-assignments"),
m_produce_interpolants(":produce-interpolants"), m_produce_interpolants(":produce-interpolants"),
m_check_interpolants(":check-interpolants"),
m_regular_output_channel(":regular-output-channel"), m_regular_output_channel(":regular-output-channel"),
m_diagnostic_output_channel(":diagnostic-output-channel"), m_diagnostic_output_channel(":diagnostic-output-channel"),
m_random_seed(":random-seed"), m_random_seed(":random-seed"),
@ -347,9 +344,6 @@ class set_option_cmd : public set_get_option_cmd {
check_not_initialized(ctx, m_produce_interpolants); check_not_initialized(ctx, m_produce_interpolants);
ctx.set_produce_interpolants(to_bool(value)); ctx.set_produce_interpolants(to_bool(value));
} }
else if (m_option == m_check_interpolants) {
ctx.set_check_interpolants(to_bool(value));
}
else if (m_option == m_produce_unsat_cores) { else if (m_option == m_produce_unsat_cores) {
check_not_initialized(ctx, m_produce_unsat_cores); check_not_initialized(ctx, m_produce_unsat_cores);
ctx.set_produce_unsat_cores(to_bool(value)); ctx.set_produce_unsat_cores(to_bool(value));

View file

@ -397,10 +397,6 @@ void cmd_context::set_produce_interpolants(bool f) {
// set_solver_factory(mk_smt_solver_factory()); // set_solver_factory(mk_smt_solver_factory());
} }
void cmd_context::set_check_interpolants(bool f) {
m_params.m_check_interpolants = f;
}
bool cmd_context::produce_models() const { bool cmd_context::produce_models() const {
return m_params.m_model; return m_params.m_model;
} }
@ -414,10 +410,6 @@ bool cmd_context::produce_interpolants() const {
return m_params.m_proof; return m_params.m_proof;
} }
bool cmd_context::check_interpolants() const {
return m_params.m_check_interpolants;
}
bool cmd_context::produce_unsat_cores() const { bool cmd_context::produce_unsat_cores() const {
return m_params.m_unsat_core; return m_params.m_unsat_core;
} }

View file

@ -279,7 +279,6 @@ public:
bool produce_models() const; bool produce_models() const;
bool produce_proofs() const; bool produce_proofs() const;
bool produce_interpolants() const; bool produce_interpolants() const;
bool check_interpolants() const;
bool produce_unsat_cores() const; bool produce_unsat_cores() const;
bool well_sorted_check_enabled() const; bool well_sorted_check_enabled() const;
bool validate_model_enabled() const; bool validate_model_enabled() const;
@ -287,7 +286,6 @@ public:
void set_produce_unsat_cores(bool flag); void set_produce_unsat_cores(bool flag);
void set_produce_proofs(bool flag); void set_produce_proofs(bool flag);
void set_produce_interpolants(bool flag); void set_produce_interpolants(bool flag);
void set_check_interpolants(bool flag);
bool produce_assignments() const { return m_produce_assignments; } bool produce_assignments() const { return m_produce_assignments; }
void set_produce_assignments(bool flag) { m_produce_assignments = flag; } void set_produce_assignments(bool flag) { m_produce_assignments = flag; }
void set_status(status st) { m_status = st; } void set_status(status st) { m_status = st; }

View file

@ -61,9 +61,6 @@ void context_params::set(char const * param, char const * value) {
else if (p == "proof") { else if (p == "proof") {
set_bool(m_proof, param, value); set_bool(m_proof, param, value);
} }
else if (p == "check_interpolants") {
set_bool(m_check_interpolants, param, value);
}
else if (p == "model") { else if (p == "model") {
set_bool(m_model, param, value); set_bool(m_model, param, value);
} }
@ -105,7 +102,6 @@ void context_params::updt_params(params_ref const & p) {
m_well_sorted_check = p.get_bool("type_check", p.get_bool("well_sorted_check", true)); m_well_sorted_check = p.get_bool("type_check", p.get_bool("well_sorted_check", true));
m_auto_config = p.get_bool("auto_config", true); m_auto_config = p.get_bool("auto_config", true);
m_proof = p.get_bool("proof", false); m_proof = p.get_bool("proof", false);
m_check_interpolants = p.get_bool("check_interpolants", false);
m_model = p.get_bool("model", true); m_model = p.get_bool("model", true);
m_model_validate = p.get_bool("model_validate", false); m_model_validate = p.get_bool("model_validate", false);
m_trace = p.get_bool("trace", false); m_trace = p.get_bool("trace", false);
@ -120,7 +116,6 @@ void context_params::collect_param_descrs(param_descrs & d) {
d.insert("well_sorted_check", CPK_BOOL, "type checker", "true"); d.insert("well_sorted_check", CPK_BOOL, "type checker", "true");
d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true"); d.insert("type_check", CPK_BOOL, "type checker (alias for well_sorted_check)", "true");
d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true"); d.insert("auto_config", CPK_BOOL, "use heuristics to automatically select solver and configure it", "true");
d.insert("check_interpolants", CPK_BOOL, "check correctness of interpolants", "false");
d.insert("model_validate", CPK_BOOL, "validate models produced by solvers", "false"); d.insert("model_validate", CPK_BOOL, "validate models produced by solvers", "false");
d.insert("trace", CPK_BOOL, "trace generation for VCC", "false"); d.insert("trace", CPK_BOOL, "trace generation for VCC", "false");
d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log"); d.insert("trace_file_name", CPK_STRING, "trace out file name (see option 'trace')", "z3.log");

View file

@ -30,7 +30,6 @@ public:
bool m_auto_config; bool m_auto_config;
bool m_proof; bool m_proof;
bool m_interpolants; bool m_interpolants;
bool m_check_interpolants;
bool m_debug_ref_count; bool m_debug_ref_count;
bool m_trace; bool m_trace;
std::string m_trace_file_name; std::string m_trace_file_name;

View file

@ -65,7 +65,7 @@ static void show_interpolant_and_maybe_check(cmd_context & ctx,
s.cleanup(); s.cleanup();
// verify, for the paranoid... // verify, for the paranoid...
if(check || ctx.check_interpolants()){ if(check || interp_params(m_params).check()){
std::ostringstream err; std::ostringstream err;
ast_manager &_m = ctx.m(); ast_manager &_m = ctx.m();

View file

@ -104,6 +104,8 @@ namespace Duality {
FuncDecl RenumberPred(const FuncDecl &f, int n); FuncDecl RenumberPred(const FuncDecl &f, int n);
FuncDecl NumberPred(const FuncDecl &f, int n);
Term ExtractStores(hash_map<ast, Term> &memo, const Term &t, std::vector<expr> &cnstrs, hash_map<ast,expr> &renaming); Term ExtractStores(hash_map<ast, Term> &memo, const Term &t, std::vector<expr> &cnstrs, hash_map<ast,expr> &renaming);
@ -488,9 +490,10 @@ protected:
std::vector<Edge *> Incoming; std::vector<Edge *> Incoming;
Term dual; Term dual;
Node *map; Node *map;
unsigned recursion_bound;
Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number) Node(const FuncDecl &_Name, const Transformer &_Annotation, const Transformer &_Bound, const Transformer &_Underapprox, const Term &_dual, RPFP *_owner, int _number)
: Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = 0;} : Name(_Name), Annotation(_Annotation), Bound(_Bound), Underapprox(_Underapprox), dual(_dual) {owner = _owner; number = _number; Outgoing = 0; recursion_bound = UINT_MAX;}
}; };
/** Create a node in the graph. The input is a term R(v_1...v_n) /** Create a node in the graph. The input is a term R(v_1...v_n)
@ -829,7 +832,7 @@ protected:
#ifdef _WINDOWS #ifdef _WINDOWS
__declspec(dllexport) __declspec(dllexport)
#endif #endif
void FromClauses(const std::vector<Term> &clauses); void FromClauses(const std::vector<Term> &clauses, const std::vector<unsigned> *bounds = 0);
void FromFixpointContext(fixedpoint fp, std::vector<Term> &queries); void FromFixpointContext(fixedpoint fp, std::vector<Term> &queries);
@ -902,6 +905,10 @@ protected:
int CumulativeDecisions(); int CumulativeDecisions();
void GreedyReduceNodes(std::vector<Node *> &nodes);
check_result CheckWithConstrainedNodes(std::vector<Node *> &posnodes,std::vector<Node *> &negnodes);
solver &slvr(){ solver &slvr(){
return *ls->slvr; return *ls->slvr;
} }

View file

@ -125,8 +125,18 @@ namespace Duality {
void timer_stop(const char *name){ void timer_stop(const char *name){
if(current->name != name || !current->parent){ if(current->name != name || !current->parent){
#if 0
std::cerr << "imbalanced timer_start and timer_stop"; std::cerr << "imbalanced timer_start and timer_stop";
exit(1); exit(1);
#endif
// in case we lost a timer stop due to an exception
while(current->name != name && current->parent)
current = current->parent;
if(current->parent){
current->time += (current_time() - current->start_time);
current = current->parent;
}
return;
} }
current->time += (current_time() - current->start_time); current->time += (current_time() - current->start_time);
current = current->parent; current = current->parent;

View file

@ -2816,6 +2816,62 @@ namespace Duality {
} }
} }
void foobar(){
}
void RPFP::GreedyReduceNodes(std::vector<Node *> &nodes){
std::vector<expr> lits;
for(unsigned i = 0; i < nodes.size(); i++){
Term b; std::vector<Term> v;
RedVars(nodes[i], b, v);
lits.push_back(!b);
expr bv = dualModel.eval(b);
if(eq(bv,ctx.bool_val(true))){
check_result res = slvr_check(lits.size(),&lits[0]);
if(res == unsat)
lits.pop_back();
else
foobar();
}
}
}
check_result RPFP::CheckWithConstrainedNodes(std::vector<Node *> &posnodes,std::vector<Node *> &negnodes){
timer_start("Check");
std::vector<expr> lits;
for(unsigned i = 0; i < posnodes.size(); i++){
Term b; std::vector<Term> v;
RedVars(posnodes[i], b, v);
lits.push_back(b);
}
for(unsigned i = 0; i < negnodes.size(); i++){
Term b; std::vector<Term> v;
RedVars(negnodes[i], b, v);
lits.push_back(!b);
}
check_result res = slvr_check(lits.size(),&lits[0]);
if(res == unsat && posnodes.size()){
lits.resize(posnodes.size());
res = slvr_check(lits.size(),&lits[0]);
}
dualModel = slvr().get_model();
#if 0
if(!dualModel.null()){
std::cout << "posnodes called:\n";
for(unsigned i = 0; i < posnodes.size(); i++)
if(!Empty(posnodes[i]))
std::cout << posnodes[i]->Name.name() << "\n";
std::cout << "negnodes called:\n";
for(unsigned i = 0; i < negnodes.size(); i++)
if(!Empty(negnodes[i]))
std::cout << negnodes[i]->Name.name() << "\n";
}
#endif
timer_stop("Check");
return res;
}
void RPFP_caching::FilterCore(std::vector<expr> &core, std::vector<expr> &full_core){ void RPFP_caching::FilterCore(std::vector<expr> &core, std::vector<expr> &full_core){
hash_set<ast> core_set; hash_set<ast> core_set;
std::copy(full_core.begin(),full_core.end(),std::inserter(core_set,core_set.begin())); std::copy(full_core.begin(),full_core.end(),std::inserter(core_set,core_set.begin()));
@ -3333,6 +3389,17 @@ namespace Duality {
return ctx.function(name.c_str(), arity, &domain[0], f.range()); return ctx.function(name.c_str(), arity, &domain[0], f.range());
} }
Z3User::FuncDecl Z3User::NumberPred(const FuncDecl &f, int n)
{
std::string name = f.name().str();
name = name + "_" + string_of_int(n);
int arity = f.arity();
std::vector<sort> domain;
for(int i = 0; i < arity; i++)
domain.push_back(f.domain(i));
return ctx.function(name.c_str(), arity, &domain[0], f.range());
}
// Scan the clause body for occurrences of the predicate unknowns // Scan the clause body for occurrences of the predicate unknowns
RPFP::Term RPFP::ScanBody(hash_map<ast,Term> &memo, RPFP::Term RPFP::ScanBody(hash_map<ast,Term> &memo,
@ -3570,7 +3637,7 @@ namespace Duality {
#define USE_QE_LITE #define USE_QE_LITE
void RPFP::FromClauses(const std::vector<Term> &unskolemized_clauses){ void RPFP::FromClauses(const std::vector<Term> &unskolemized_clauses, const std::vector<unsigned> *bounds){
hash_map<func_decl,Node *> pmap; hash_map<func_decl,Node *> pmap;
func_decl fail_pred = ctx.fresh_func_decl("@Fail", ctx.bool_sort()); func_decl fail_pred = ctx.fresh_func_decl("@Fail", ctx.bool_sort());
@ -3663,6 +3730,7 @@ namespace Duality {
pmap[R] = node; pmap[R] = node;
if (is_query) if (is_query)
node->Bound = CreateRelation(std::vector<Term>(), ctx.bool_val(false)); node->Bound = CreateRelation(std::vector<Term>(), ctx.bool_val(false));
node->recursion_bound = bounds ? 0 : UINT_MAX;
} }
} }
@ -3728,6 +3796,8 @@ namespace Duality {
Transformer T = CreateTransformer(Relparams,Indparams,body); Transformer T = CreateTransformer(Relparams,Indparams,body);
Edge *edge = CreateEdge(Parent,T,Children); Edge *edge = CreateEdge(Parent,T,Children);
edge->labeled = labeled;; // remember for label extraction edge->labeled = labeled;; // remember for label extraction
if(bounds)
Parent->recursion_bound = std::max(Parent->recursion_bound,(*bounds)[i]);
// edges.push_back(edge); // edges.push_back(edge);
} }

View file

@ -33,6 +33,7 @@ Revision History:
#include <map> #include <map>
#include <list> #include <list>
#include <iterator> #include <iterator>
#include <sstream>
// TODO: make these official options or get rid of them // TODO: make these official options or get rid of them
@ -254,6 +255,13 @@ namespace Duality {
/** Called when done expanding a tree */ /** Called when done expanding a tree */
virtual void Done() {} virtual void Done() {}
/** Ask whether a node should be used/unused in the tree. Returns,
1 if yes, -1 if no, and 0 if don't care. */
virtual int UseNode(Node *node){
return 0;
}
}; };
/** The Proposer class proposes conjectures eagerly. These can come /** The Proposer class proposes conjectures eagerly. These can come
@ -301,10 +309,11 @@ namespace Duality {
hash_set<Node *> overapproxes; hash_set<Node *> overapproxes;
std::vector<Proposer *> proposers; std::vector<Proposer *> proposers;
std::string ConjectureFile; std::string ConjectureFile;
bool stratified_inlining_done;
#ifdef BOUNDED #ifdef BOUNDED
struct Counter { struct Counter {
int val; unsigned val;
Counter(){val = 0;} Counter(){val = 0;}
}; };
typedef std::map<Node *,Counter> NodeToCounter; typedef std::map<Node *,Counter> NodeToCounter;
@ -313,6 +322,13 @@ namespace Duality {
/** Solve the problem. */ /** Solve the problem. */
virtual bool Solve(){ virtual bool Solve(){
PreSolve();
bool res = SolveMain(); // does the actual work
PostSolve();
return res;
}
void PreSolve(){
reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp); reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp);
conj_reporter = ConjectureFile.empty() ? 0 : CreateConjectureFileReporter(rpfp,ConjectureFile); conj_reporter = ConjectureFile.empty() ? 0 : CreateConjectureFileReporter(rpfp,ConjectureFile);
#ifndef LOCALIZE_CONJECTURES #ifndef LOCALIZE_CONJECTURES
@ -321,6 +337,10 @@ namespace Duality {
heuristic = !cex.get_tree() ? (Heuristic *)(new LocalHeuristic(rpfp)) heuristic = !cex.get_tree() ? (Heuristic *)(new LocalHeuristic(rpfp))
: (Heuristic *)(new ReplayHeuristic(rpfp,cex)); : (Heuristic *)(new ReplayHeuristic(rpfp,cex));
#endif #endif
// determine if we are recursion bounded
for(unsigned i = 0; i < rpfp->nodes.size(); i++)
if(rpfp->nodes[i]->recursion_bound < UINT_MAX)
RecursionBound = 0;
cex.clear(); // in case we didn't use it for heuristic cex.clear(); // in case we didn't use it for heuristic
if(unwinding) delete unwinding; if(unwinding) delete unwinding;
unwinding = new RPFP(rpfp->ls); unwinding = new RPFP(rpfp->ls);
@ -337,9 +357,10 @@ namespace Duality {
return false; return false;
#endif #endif
StratifiedLeafCount = -1; StratifiedLeafCount = -1;
timer_start("SolveMain"); stratified_inlining_done = false;
bool res = SolveMain(); // does the actual work }
timer_stop("SolveMain");
void PostSolve(){
// print_profile(std::cout); // print_profile(std::cout);
delete indset; delete indset;
delete heuristic; delete heuristic;
@ -349,7 +370,16 @@ namespace Duality {
delete conj_reporter; delete conj_reporter;
for(unsigned i = 0; i < proposers.size(); i++) for(unsigned i = 0; i < proposers.size(); i++)
delete proposers[i]; delete proposers[i];
return res; }
bool RecheckBounds(){
for(unsigned i = 0; i < unwinding->nodes.size(); i++){
Node *node = unwinding->nodes[i];
node->Bound = node->map->Bound;
if(!SatisfyUpperBound(node))
return false;
}
return true;
} }
void CreateInitialUnwinding(){ void CreateInitialUnwinding(){
@ -412,6 +442,7 @@ namespace Duality {
bool StratifiedInlining; // Do stratified inlining as preprocessing step bool StratifiedInlining; // Do stratified inlining as preprocessing step
int RecursionBound; // Recursion bound for bounded verification int RecursionBound; // Recursion bound for bounded verification
bool BatchExpand; bool BatchExpand;
bool EnableRestarts;
bool SetBoolOption(bool &opt, const std::string &value){ bool SetBoolOption(bool &opt, const std::string &value){
if(value == "0") { if(value == "0") {
@ -459,9 +490,12 @@ namespace Duality {
if(option == "conjecture_file"){ if(option == "conjecture_file"){
ConjectureFile = value; ConjectureFile = value;
} }
if(option == "enable_restarts"){
return SetBoolOption(EnableRestarts,value);
}
return false; return false;
} }
/** Create an instance of a node in the unwinding. Set its /** Create an instance of a node in the unwinding. Set its
annotation to true, and mark it unexpanded. */ annotation to true, and mark it unexpanded. */
Node* CreateNodeInstance(Node *node, int number = 0){ Node* CreateNodeInstance(Node *node, int number = 0){
@ -768,6 +802,15 @@ namespace Duality {
annot.Simplify(); annot.Simplify();
} }
bool NodeSolutionFromIndSetFull(Node *node){
std::vector<Node *> &insts = insts_of_node[node];
for(unsigned j = 0; j < insts.size(); j++)
if(indset->Contains(insts[j]))
if(insts[j]->Annotation.IsFull())
return true;
return false;
}
bool recursionBounded; bool recursionBounded;
/** See if the solution might be bounded. */ /** See if the solution might be bounded. */
@ -780,10 +823,8 @@ namespace Duality {
std::vector<Node *> &insts = insts_of_node[node]; std::vector<Node *> &insts = insts_of_node[node];
for(unsigned j = 0; j < insts.size(); j++) for(unsigned j = 0; j < insts.size(); j++)
if(indset->Contains(insts[j])) if(indset->Contains(insts[j]))
if(NodePastRecursionBound(insts[j])){ if(NodePastRecursionBound(insts[j],true))
recursionBounded = true; recursionBounded = true;
return;
}
} }
} }
@ -801,12 +842,18 @@ namespace Duality {
} }
#ifdef BOUNDED #ifdef BOUNDED
bool NodePastRecursionBound(Node *node){ bool NodePastRecursionBound(Node *node, bool report = false){
if(RecursionBound < 0) return false; if(RecursionBound < 0) return false;
NodeToCounter &backs = back_edges[node]; NodeToCounter &backs = back_edges[node];
for(NodeToCounter::iterator it = backs.begin(), en = backs.end(); it != en; ++it){ for(NodeToCounter::iterator it = backs.begin(), en = backs.end(); it != en; ++it){
if(it->second.val > RecursionBound) if(it->second.val > it->first->recursion_bound){
if(report){
std::ostringstream os;
os << "cut off " << it->first->Name.name() << " at depth " << it->second.val;
reporter->Message(os.str());
}
return true; return true;
}
} }
return false; return false;
} }
@ -892,6 +939,9 @@ namespace Duality {
*/ */
bool DoStratifiedInlining(){ bool DoStratifiedInlining(){
if(stratified_inlining_done)
return true;
stratified_inlining_done = true;
DoTopoSort(); DoTopoSort();
int depth = 1; // TODO: make this an option int depth = 1; // TODO: make this an option
std::vector<hash_map<Node *,Node *> > unfolding_levels(depth+1); std::vector<hash_map<Node *,Node *> > unfolding_levels(depth+1);
@ -1034,10 +1084,17 @@ namespace Duality {
h->SetOldNode(node); h->SetOldNode(node);
} }
bool SolveMain(){
timer_start("SolveMain");
bool res = SolveMainInt(); // does the actual work
timer_stop("SolveMain");
return res;
}
/** This does the actual solving work. We try to generate /** This does the actual solving work. We try to generate
candidates for extension. If we succed, we extend the candidates for extension. If we succed, we extend the
unwinding. If we fail, we have a solution. */ unwinding. If we fail, we have a solution. */
bool SolveMain(){ bool SolveMainInt(){
if(StratifiedInlining && !DoStratifiedInlining()) if(StratifiedInlining && !DoStratifiedInlining())
return false; return false;
#ifdef BOUNDED #ifdef BOUNDED
@ -1405,16 +1462,18 @@ namespace Duality {
slvr.pop(1); slvr.pop(1);
delete checker; delete checker;
#else #else
RPFP_caching::scoped_solver_for_edge ssfe(gen_cands_rpfp,edge,true /* models */, true /*axioms*/); if(!NodeSolutionFromIndSetFull(edge->Parent)){
gen_cands_rpfp->Push(); RPFP_caching::scoped_solver_for_edge ssfe(gen_cands_rpfp,edge,true /* models */, true /*axioms*/);
Node *root = CheckerForEdgeClone(edge,gen_cands_rpfp); gen_cands_rpfp->Push();
if(gen_cands_rpfp->Check(root) != unsat){ Node *root = CheckerForEdgeClone(edge,gen_cands_rpfp);
Candidate candidate; if(gen_cands_rpfp->Check(root) != unsat){
ExtractCandidateFromCex(edge,gen_cands_rpfp,root,candidate); Candidate candidate;
reporter->InductionFailure(edge,candidate.Children); ExtractCandidateFromCex(edge,gen_cands_rpfp,root,candidate);
candidates.push_back(candidate); reporter->InductionFailure(edge,candidate.Children);
candidates.push_back(candidate);
}
gen_cands_rpfp->Pop(1);
} }
gen_cands_rpfp->Pop(1);
#endif #endif
} }
updated_nodes.clear(); updated_nodes.clear();
@ -1767,6 +1826,7 @@ namespace Duality {
} }
timer_stop("Propagate"); timer_stop("Propagate");
} }
/** This class represents a derivation tree. */ /** This class represents a derivation tree. */
class DerivationTree { class DerivationTree {
@ -2118,6 +2178,8 @@ namespace Duality {
hash_map<Node *, expr> updates; hash_map<Node *, expr> updates;
int restart_interval;
DerivationTreeSlow(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand) DerivationTreeSlow(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand)
: DerivationTree(_duality, rpfp, _reporter, _heuristic, _full_expand) { : DerivationTree(_duality, rpfp, _reporter, _heuristic, _full_expand) {
stack.push_back(stack_entry()); stack.push_back(stack_entry());
@ -2126,6 +2188,7 @@ namespace Duality {
struct DoRestart {}; struct DoRestart {};
virtual bool Build(){ virtual bool Build(){
restart_interval = 3;
while (true) { while (true) {
try { try {
return BuildMain(); return BuildMain();
@ -2136,15 +2199,47 @@ namespace Duality {
while(stack.size() > 1) while(stack.size() > 1)
PopLevel(); PopLevel();
reporter->Message("restarted"); reporter->Message("restarted");
restart_interval += 1;
} }
} }
} }
// When we check, try to use the same children that were used in the
// previous counterexample.
check_result Check(){
#if 0
std::vector<Node *> posnodes, negnodes;
std::vector<Node *> &expansions = stack.back().expansions;
for(unsigned i = 0; i < expansions.size(); i++){
Node *node = expansions[i];
std::vector<Node*> &chs = node->Outgoing->Children;
for(unsigned j = 0; j < chs.size(); j++){
Node *ch = chs[j];
int use = heuristic->UseNode(ch);
if(use == 1)
posnodes.push_back(ch);
else if (use == -1)
negnodes.push_back(ch);
}
}
if(!(posnodes.empty() && negnodes.empty())){
check_result res = tree->CheckWithConstrainedNodes(posnodes,negnodes);
if(res != unsat){
reporter->Message("matched previous counterexample");
return res;
}
}
#endif
return tree->Check(top);
}
bool BuildMain(){ bool BuildMain(){
stack.back().level = tree->slvr().get_scope_level(); stack.back().level = tree->slvr().get_scope_level();
bool was_sat = true; bool was_sat = true;
int update_failures = 0; int update_failures = 0;
int total_updates = 0;
while (true) while (true)
{ {
@ -2156,7 +2251,7 @@ namespace Duality {
reporter->Depth(stack.size()); reporter->Depth(stack.size());
// res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop // res = tree->Solve(top, 1); // incremental solve, keep interpolants for one pop
check_result foo = tree->Check(top); check_result foo = Check();
res = foo == unsat ? l_false : l_true; res = foo == unsat ? l_false : l_true;
if (res == l_false) { if (res == l_false) {
@ -2168,32 +2263,50 @@ namespace Duality {
int update_count = 0; int update_count = 0;
for(unsigned i = 0; i < expansions.size(); i++){ for(unsigned i = 0; i < expansions.size(); i++){
Node *node = expansions[i]; Node *node = expansions[i];
tree->SolveSingleNode(top,node);
#ifdef NO_GENERALIZE
node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify();
#else
try { try {
tree->SolveSingleNode(top,node);
#ifdef NO_GENERALIZE
node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify();
#else
if(expansions.size() == 1 && NodeTooComplicated(node)) if(expansions.size() == 1 && NodeTooComplicated(node))
SimplifyNode(node); SimplifyNode(node);
else else
node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify(); node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify();
Generalize(node); Generalize(node);
#endif
} }
catch(const RPFP::Bad &){ catch(const RPFP::Bad &){
// bad interpolants can get us here // bad interpolants can get us here
throw DoRestart(); throw DoRestart();
} }
#endif catch(char const *msg){
if(RecordUpdate(node)) // bad interpolants can get us here
reporter->Message(std::string("interpolation failure:") + msg);
throw DoRestart();
}
if(RecordUpdate(node)){
update_count++; update_count++;
total_updates++;
}
else else
heuristic->Update(node->map); // make it less likely to expand this node in future heuristic->Update(node->map); // make it less likely to expand this node in future
} }
#if 1
if(duality->EnableRestarts)
if(total_updates >= restart_interval)
throw DoRestart();
#endif
if(update_count == 0){ if(update_count == 0){
if(was_sat){ if(was_sat){
update_failures++; update_failures++;
if(update_failures > 10) if(update_failures > 10){
throw Incompleteness(); for(unsigned i = 0; i < expansions.size(); i++){
Node *node = expansions[i];
node->map->Annotation.SetFull();
reporter->Message("incompleteness: cleared annotation");
}
throw DoRestart();
}
} }
reporter->Message("backtracked without learning"); reporter->Message("backtracked without learning");
} }
@ -2234,6 +2347,10 @@ namespace Duality {
tree->Push(); tree->Push();
std::vector<Node *> &expansions = stack.back().expansions; std::vector<Node *> &expansions = stack.back().expansions;
#ifndef NO_DECISIONS #ifndef NO_DECISIONS
#if 0
if(expansions.size() > 0)
tree->GreedyReduceNodes(expansions[0]->Outgoing->Children); // try to reduce number of children
#endif
for(unsigned i = 0; i < expansions.size(); i++){ for(unsigned i = 0; i < expansions.size(); i++){
tree->FixCurrentState(expansions[i]->Outgoing); tree->FixCurrentState(expansions[i]->Outgoing);
} }
@ -2253,15 +2370,42 @@ namespace Duality {
if(ExpandSomeNodes(false,expand_max)) if(ExpandSomeNodes(false,expand_max))
continue; continue;
tree->Pop(1); tree->Pop(1);
node_order.clear();
while(stack.size() > 1){ while(stack.size() > 1){
tree->Pop(1); tree->Pop(1);
std::vector<Node *> &expansions = stack.back().expansions;
for(unsigned i = 0; i < expansions.size(); i++)
node_order.push_back(expansions[i]);
stack.pop_back(); stack.pop_back();
} }
#if 0
Reduce();
#endif
return true; return true;
} }
} }
} }
std::vector<Node *> node_order;
void Reduce(){
tree->Push();
// tree->AssertNode(top); // assert the negation of the top-level spec
for(int i = node_order.size()-1; i >= 0; --i){
Edge *edge = node_order[i]->Outgoing;
if(edge){
for(unsigned j = 0; j < edge->Children.size(); j++){
Node *ch = edge->Children[j];
if(!ch->Outgoing)
ch->Annotation.SetEmpty();
}
tree->AssertEdge(edge,0,true);
}
}
tree->GreedyReduceNodes(node_order); // try to reduce the counterexample size
tree->Pop(1);
}
void PopLevel(){ void PopLevel(){
std::vector<Node *> &expansions = stack.back().expansions; std::vector<Node *> &expansions = stack.back().expansions;
tree->Pop(1); tree->Pop(1);
@ -2860,17 +3004,7 @@ namespace Duality {
return name; return name;
} }
virtual void ChooseExpand(const std::set<RPFP::Node *> &choices, std::set<RPFP::Node *> &best, bool high_priority, bool best_only){ Node *MatchNode(Node *node){
if(!high_priority || !old_cex.get_tree()){
Heuristic::ChooseExpand(choices,best,false);
return;
}
// first, try to match the derivatino tree nodes to the old cex
std::set<Node *> matched, unmatched;
for(std::set<Node *>::iterator it = choices.begin(), en = choices.end(); it != en; ++it){
Node *node = (*it);
if(cex_map.empty())
cex_map[node] = old_cex.get_root(); // match the root nodes
if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node if(cex_map.find(node) == cex_map.end()){ // try to match an unmatched node
Node *parent = node->Incoming[0]->Parent; // assumes we are a tree! Node *parent = node->Incoming[0]->Parent; // assumes we are a tree!
if(cex_map.find(parent) == cex_map.end()) if(cex_map.find(parent) == cex_map.end())
@ -2893,7 +3027,30 @@ namespace Duality {
cex_map[chs[i]] = 0; cex_map[chs[i]] = 0;
} }
matching_done: matching_done:
Node *old_node = cex_map[node]; return cex_map[node];
}
int UseNode(Node *node){
if (!old_cex.get_tree())
return 0;
Node *old_node = MatchNode(node);
if(!old_node)
return 0;
return old_cex.get_tree()->Empty(old_node) ? -1 : 1;
}
virtual void ChooseExpand(const std::set<RPFP::Node *> &choices, std::set<RPFP::Node *> &best, bool high_priority, bool best_only){
if(cex_map.empty())
cex_map[*(choices.begin())] = old_cex.get_root(); // match the root nodes
if(!high_priority || !old_cex.get_tree()){
Heuristic::ChooseExpand(choices,best,false);
return;
}
// first, try to match the derivatino tree nodes to the old cex
std::set<Node *> matched, unmatched;
for(std::set<Node *>::iterator it = choices.begin(), en = choices.end(); it != en; ++it){
Node *node = (*it);
Node *old_node = MatchNode(node);
if(!old_node) if(!old_node)
unmatched.insert(node); unmatched.insert(node);
else if(old_cex.get_tree()->Empty(old_node)) else if(old_cex.get_tree()->Empty(old_node))
@ -3168,8 +3325,233 @@ namespace Duality {
}; };
class DualityDepthBounded : public Solver {
Duality *duality;
context &ctx; // Z3 context
solver &slvr; // Z3 solver
public:
DualityDepthBounded(RPFP *_rpfp) :
ctx(_rpfp->ctx),
slvr(_rpfp->slvr()){
rpfp = _rpfp;
DepthBoundRPFP();
duality = alloc(Duality,drpfp);
}
~DualityDepthBounded(){
dealloc(duality);
delete drpfp;
}
bool Solve(){
int depth_bound = 10;
bool res;
SetMaxDepthRPFP(depth_bound);
duality->PreSolve();
while(true){
res = duality->SolveMain();
if(!res || GetSolution())
break;
depth_bound++;
SetMaxDepthRPFP(depth_bound);
res = duality->RecheckBounds();
if(!res)
break;
}
duality->PostSolve();
if(!res)
ConvertCex();
return res;
}
Counterexample &GetCounterexample(){
return cex;
}
bool SetOption(const std::string &option, const std::string &value){
return duality->SetOption(option,value);
}
virtual void LearnFrom(Solver *old_solver){
DualityDepthBounded *old = dynamic_cast<DualityDepthBounded *>(old_solver);
if(old){
duality->LearnFrom(old->duality);
}
}
bool IsResultRecursionBounded(){
return duality->IsResultRecursionBounded();
}
void Cancel(){
duality->Cancel();
}
typedef RPFP::Node Node;
typedef RPFP::Edge Edge;
RPFP *rpfp, *drpfp;
hash_map<Node *, Node *> db_map, db_rev_map;
hash_map<Edge *, Edge *> db_edge_rev_map;
std::vector<expr> db_saved_bounds;
Counterexample cex;
expr AddParamToRels(hash_map<ast,expr> &memo, hash_map<func_decl,func_decl> &rmap, const expr &p, const expr &t) {
std::pair<ast,expr> foo(t,expr(ctx));
std::pair<hash_map<ast,expr>::iterator, bool> bar = memo.insert(foo);
expr &res = bar.first->second;
if(!bar.second) return res;
if (t.is_app())
{
func_decl f = t.decl();
std::vector<expr> args;
int nargs = t.num_args();
for(int i = 0; i < nargs; i++)
args.push_back(AddParamToRels(memo, rmap, p, t.arg(i)));
hash_map<func_decl,func_decl>::iterator rit = rmap.find(f);
if(rit != rmap.end()){
args.push_back(p);
res = (rit->second)(args);
res = ctx.make(And,res,ctx.make(Geq,p,ctx.int_val(0)));
}
else
res = f(args);
}
else if (t.is_quantifier())
{
expr body = AddParamToRels(memo, rmap, p, t.body());
res = clone_quantifier(t, body);
}
else res = t;
return res;
}
void DepthBoundRPFP(){
drpfp = new RPFP(rpfp->ls);
expr dvar = ctx.int_const("@depth");
expr dmax = ctx.int_const("@depth_max");
for(unsigned i = 0; i < rpfp->nodes.size(); i++){
Node *node = rpfp->nodes[i];
std::vector<sort> arg_sorts;
const std::vector<expr> &params = node->Annotation.IndParams;
for(unsigned j = 0; j < params.size(); j++)
arg_sorts.push_back(params[j].get_sort());
arg_sorts.push_back(ctx.int_sort());
std::string new_name = std::string("@db@") + node->Name.name().str();
func_decl f = ctx.function(new_name.c_str(),arg_sorts.size(), &arg_sorts[0],ctx.bool_sort());
std::vector<expr> args = params;
args.push_back(dvar);
expr pat = f(args);
Node *dnode = drpfp->CreateNode(pat);
db_map[node] = dnode;
db_rev_map[dnode] = node;
expr bound_fmla = node->Bound.Formula;
if(!eq(bound_fmla,ctx.bool_val(true))){
bound_fmla = implies(dvar == dmax,bound_fmla);
dnode->Bound.Formula = bound_fmla;
}
db_saved_bounds.push_back(bound_fmla);
// dnode->Annotation.Formula = ctx.make(And,node->Annotation.Formula,ctx.make(Geq,dvar,ctx.int_val(0)));
}
for(unsigned i = 0; i < rpfp->edges.size(); i++){
Edge *edge = rpfp->edges[i];
std::vector<Node *> new_children;
std::vector<func_decl> new_relparams;
hash_map<func_decl,func_decl> rmap;
for(unsigned j = 0; j < edge->Children.size(); j++){
Node *ch = edge->Children[j];
Node *nch = db_map[ch];
func_decl f = nch->Name;
func_decl sf = drpfp->NumberPred(f,j);
new_children.push_back(nch);
new_relparams.push_back(sf);
rmap[edge->F.RelParams[j]] = sf;
}
std::vector<expr> new_indparams = edge->F.IndParams;
new_indparams.push_back(dvar);
hash_map<ast,expr> memo;
expr new_fmla = AddParamToRels(memo,rmap,ctx.make(Sub,dvar,ctx.int_val(1)),edge->F.Formula);
RPFP::Transformer new_t = drpfp->CreateTransformer(new_relparams,new_indparams,new_fmla);
Node *new_parent = db_map[edge->Parent];
db_edge_rev_map[drpfp->CreateEdge(new_parent,new_t,new_children)] = edge;
}
}
void SetMaxDepthRPFP(int depth){
hash_map<ast,expr> subst;
expr dmax = ctx.int_const("@depth_max");
subst[dmax] = ctx.int_val(depth);
for(unsigned i = 0; i < drpfp->nodes.size(); i++){
Node *node = drpfp->nodes[i];
expr fmla = db_saved_bounds[i];
fmla = drpfp->SubstRec(subst,fmla);
node->Bound.Formula = fmla;
}
}
void ConvertCex(){
cex.clear();
RPFP *tree = new RPFP(rpfp->ls);
Node *root;
Counterexample &dctx = duality->GetCounterexample();
hash_map<Node *, Node *> ctx_node_map;
for(unsigned i = 0; i < dctx.get_tree()->nodes.size(); i++){
Node *dnode = dctx.get_tree()->nodes[i];
Node *onode = db_rev_map[dnode->map->map];
Node *node = tree->CloneNode(onode);
node->number = dnode->number; // numbers have to match for model to make sense
ctx_node_map[dnode] = node;
if(dnode == dctx.get_root())
root = node;
}
for(unsigned i = 0; i < dctx.get_tree()->edges.size(); i++){
Edge *dedge = dctx.get_tree()->edges[i];
Edge *oedge = db_edge_rev_map[dedge->map];
Node *parent = ctx_node_map[dedge->Parent];
std::vector<Node *> chs;
for(unsigned j = 0; j < dedge->Children.size(); j++)
chs.push_back(ctx_node_map[dedge->Children[j]]);
Edge *edge = tree->CreateEdge(parent,oedge->F,chs);
edge->number = dedge->number; // numbers have to match for model to make sense
edge->map = oedge;
}
tree->dualModel = dctx.get_tree()->dualModel;
cex.set(tree,root);
}
bool GetSolution(){
for(unsigned i = 0; i < rpfp->nodes.size(); i++)
if(!drpfp->nodes[i]->Annotation.SubsetEq(rpfp->nodes[i]->Bound))
return false;
expr dvar = ctx.int_const("@depth");
hash_map<ast,expr> subst;
subst[dvar] = ctx.int_val(INT_MAX);
for(unsigned i = 0; i < rpfp->nodes.size(); i++){
expr fmla = drpfp->nodes[i]->Annotation.Formula;
fmla = drpfp->SubstRec(subst,fmla);
fmla = fmla.simplify();
rpfp->nodes[i]->Annotation.Formula = fmla;
}
return true;
}
void UndoDepthBoundRPFP(){
#if 0
if(cex.get_tree()){
// here, need to map the cex back...
}
// also need to map the proof back, but we don't...
#endif
}
};
Solver *Solver::Create(const std::string &solver_class, RPFP *rpfp){ Solver *Solver::Create(const std::string &solver_class, RPFP *rpfp){
Duality *s = alloc(Duality,rpfp); // Solver *s = alloc(DualityDepthBounded,rpfp);
Solver *s = alloc(Duality,rpfp);
return s; return s;
} }

View file

@ -2,4 +2,5 @@ def_module_params('interp',
description='interpolation parameters', description='interpolation parameters',
export=True, export=True,
params=(('profile', BOOL, False, '(INTERP) profile interpolation'), params=(('profile', BOOL, False, '(INTERP) profile interpolation'),
('check', BOOL, False, '(INTERP) check interpolants'),
)) ))

View file

@ -246,6 +246,7 @@ namespace datalog {
m_rule_fmls_head = 0; m_rule_fmls_head = 0;
m_rule_fmls.reset(); m_rule_fmls.reset();
m_rule_names.reset(); m_rule_names.reset();
m_rule_bounds.reset();
m_argument_var_names.reset(); m_argument_var_names.reset();
m_preds.reset(); m_preds.reset();
m_preds_by_name.reset(); m_preds_by_name.reset();
@ -474,9 +475,10 @@ namespace datalog {
return new_pred; return new_pred;
} }
void context::add_rule(expr* rl, symbol const& name) { void context::add_rule(expr* rl, symbol const& name, unsigned bound) {
m_rule_fmls.push_back(rl); m_rule_fmls.push_back(rl);
m_rule_names.push_back(name); m_rule_names.push_back(name);
m_rule_bounds.push_back(bound);
} }
void context::flush_add_rules() { void context::flush_add_rules() {
@ -983,6 +985,9 @@ namespace datalog {
flush_add_rules(); flush_add_rules();
break; break;
case DUALITY_ENGINE: case DUALITY_ENGINE:
// this lets us use duality with SAS 2013 abstraction
if(quantify_arrays())
flush_add_rules();
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
@ -1102,12 +1107,13 @@ namespace datalog {
} }
} }
void context::get_raw_rule_formulas(expr_ref_vector& rules, svector<symbol>& names){ void context::get_raw_rule_formulas(expr_ref_vector& rules, svector<symbol>& names, vector<unsigned> &bounds){
for (unsigned i = 0; i < m_rule_fmls.size(); ++i) { for (unsigned i = 0; i < m_rule_fmls.size(); ++i) {
expr_ref r = bind_variables(m_rule_fmls[i].get(), true); expr_ref r = bind_variables(m_rule_fmls[i].get(), true);
rules.push_back(r.get()); rules.push_back(r.get());
// rules.push_back(m_rule_fmls[i].get()); // rules.push_back(m_rule_fmls[i].get());
names.push_back(m_rule_names[i]); names.push_back(m_rule_names[i]);
bounds.push_back(m_rule_bounds[i]);
} }
} }
@ -1125,6 +1131,7 @@ namespace datalog {
m_rule_names[i] = m_rule_names.back(); m_rule_names[i] = m_rule_names.back();
m_rule_fmls.pop_back(); m_rule_fmls.pop_back();
m_rule_names.pop_back(); m_rule_names.pop_back();
m_rule_bounds.pop_back();
--i; --i;
} }
} }

View file

@ -194,6 +194,7 @@ namespace datalog {
unsigned m_rule_fmls_head; unsigned m_rule_fmls_head;
expr_ref_vector m_rule_fmls; expr_ref_vector m_rule_fmls;
svector<symbol> m_rule_names; svector<symbol> m_rule_names;
vector<unsigned> m_rule_bounds;
expr_ref_vector m_background; expr_ref_vector m_background;
model_converter_ref m_mc; model_converter_ref m_mc;
proof_converter_ref m_pc; proof_converter_ref m_pc;
@ -366,7 +367,7 @@ namespace datalog {
rule_set & get_rules() { flush_add_rules(); return m_rule_set; } rule_set & get_rules() { flush_add_rules(); return m_rule_set; }
void get_rules_as_formulas(expr_ref_vector& fmls, svector<symbol>& names); void get_rules_as_formulas(expr_ref_vector& fmls, svector<symbol>& names);
void get_raw_rule_formulas(expr_ref_vector& fmls, svector<symbol>& names); void get_raw_rule_formulas(expr_ref_vector& fmls, svector<symbol>& names, vector<unsigned> &bounds);
void add_fact(app * head); void add_fact(app * head);
void add_fact(func_decl * pred, const relation_fact & fact); void add_fact(func_decl * pred, const relation_fact & fact);
@ -383,7 +384,7 @@ namespace datalog {
/** /**
Method exposed from API for adding rules. Method exposed from API for adding rules.
*/ */
void add_rule(expr* rl, symbol const& name); void add_rule(expr* rl, symbol const& name, unsigned bound = UINT_MAX);
/** /**

View file

@ -78,6 +78,7 @@ def_module_params('fixedpoint',
('batch_expand', BOOL, False, 'DUALITY: use batch expansion'), ('batch_expand', BOOL, False, 'DUALITY: use batch expansion'),
('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), ('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'),
('conjecture_file', STRING, '', 'DUALITY: save conjectures to file'), ('conjecture_file', STRING, '', 'DUALITY: save conjectures to file'),
('enable_restarts', BOOL, False, 'DUALITY: enable restarts'),
)) ))

View file

@ -37,6 +37,7 @@ Revision History:
#include "fixedpoint_params.hpp" #include "fixedpoint_params.hpp"
#include "used_vars.h" #include "used_vars.h"
#include "func_decl_dependencies.h" #include "func_decl_dependencies.h"
#include "dl_transforms.h"
// template class symbol_table<family_id>; // template class symbol_table<family_id>;
@ -155,8 +156,41 @@ lbool dl_interface::query(::expr * query) {
expr_ref_vector rules(m_ctx.get_manager()); expr_ref_vector rules(m_ctx.get_manager());
svector< ::symbol> names; svector< ::symbol> names;
vector<unsigned> bounds;
// m_ctx.get_rules_as_formulas(rules, names); // m_ctx.get_rules_as_formulas(rules, names);
m_ctx.get_raw_rule_formulas(rules, names);
// If using SAS 2013 abstractiion, we need to perform some transforms
expr_ref query_ref(m_ctx.get_manager());
if(m_ctx.quantify_arrays()){
datalog::rule_manager& rm = m_ctx.get_rule_manager();
rm.mk_query(query, m_ctx.get_rules());
apply_default_transformation(m_ctx);
datalog::rule_set &rs = m_ctx.get_rules();
if(m_ctx.get_rules().get_output_predicates().empty())
query_ref = m_ctx.get_manager().mk_false();
else {
func_decl_ref query_pred(m_ctx.get_manager());
query_pred = m_ctx.get_rules().get_output_predicate();
ptr_vector<sort> sorts;
unsigned nargs = query_pred.get()->get_arity();
expr_ref_vector vars(m_ctx.get_manager());
for(unsigned i = 0; i < nargs; i++){
::sort *s = query_pred.get()->get_domain(i);
vars.push_back(m_ctx.get_manager().mk_var(nargs-1-i,s));
}
query_ref = m_ctx.get_manager().mk_app(query_pred.get(),nargs,vars.c_ptr());
query = query_ref.get();
}
unsigned nrules = rs.get_num_rules();
for(unsigned i = 0; i < nrules; i++){
expr_ref f(m_ctx.get_manager());
rs.get_rule(i)->to_formula(f);
rules.push_back(f);
}
}
else
m_ctx.get_raw_rule_formulas(rules, names, bounds);
// get all the rules as clauses // get all the rules as clauses
std::vector<expr> &clauses = _d->clauses; std::vector<expr> &clauses = _d->clauses;
@ -200,6 +234,7 @@ lbool dl_interface::query(::expr * query) {
expr qc = implies(q,_d->ctx.bool_val(false)); expr qc = implies(q,_d->ctx.bool_val(false));
qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc); qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc);
clauses.push_back(qc); clauses.push_back(qc);
bounds.push_back(UINT_MAX);
// get the background axioms // get the background axioms
unsigned num_asserts = m_ctx.get_num_assertions(); unsigned num_asserts = m_ctx.get_num_assertions();
@ -243,13 +278,21 @@ lbool dl_interface::query(::expr * query) {
expr c = implies(_d->ctx.bool_val(false),f(args)); expr c = implies(_d->ctx.bool_val(false),f(args));
c = _d->ctx.make_quant(Forall,args,c); c = _d->ctx.make_quant(Forall,args,c);
clauses.push_back(c); clauses.push_back(c);
bounds.push_back(UINT_MAX);
} }
} }
} }
} }
unsigned rb = m_ctx.get_params().recursion_bound();
std::vector<unsigned> std_bounds;
for(unsigned i = 0; i < bounds.size(); i++){
unsigned b = bounds[i];
if (b == UINT_MAX) b = rb;
std_bounds.push_back(b);
}
// creates 1-1 map between clauses and rpfp edges // creates 1-1 map between clauses and rpfp edges
_d->rpfp->FromClauses(clauses); _d->rpfp->FromClauses(clauses,&std_bounds);
// populate the edge-to-clause map // populate the edge-to-clause map
for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i) for(unsigned i = 0; i < _d->rpfp->edges.size(); ++i)
@ -271,11 +314,13 @@ lbool dl_interface::query(::expr * query) {
rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0"); rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0");
rs->SetOption("batch_expand",m_ctx.get_params().batch_expand() ? "1" : "0"); rs->SetOption("batch_expand",m_ctx.get_params().batch_expand() ? "1" : "0");
rs->SetOption("conjecture_file",m_ctx.get_params().conjecture_file()); rs->SetOption("conjecture_file",m_ctx.get_params().conjecture_file());
unsigned rb = m_ctx.get_params().recursion_bound(); rs->SetOption("enable_restarts",m_ctx.get_params().enable_restarts() ? "1" : "0");
#if 0
if(rb != UINT_MAX){ if(rb != UINT_MAX){
std::ostringstream os; os << rb; std::ostringstream os; os << rb;
rs->SetOption("recursion_bound", os.str()); rs->SetOption("recursion_bound", os.str());
} }
#endif
// Solve! // Solve!
bool ans; bool ans;

View file

@ -100,7 +100,7 @@ struct dl_context {
dlctx().set_predicate_representation(pred, num_kinds, kinds); dlctx().set_predicate_representation(pred, num_kinds, kinds);
} }
void add_rule(expr * rule, symbol const& name) { void add_rule(expr * rule, symbol const& name, unsigned bound) {
init(); init();
if (m_collected_cmds) { if (m_collected_cmds) {
expr_ref rl = m_context->bind_variables(rule, true); expr_ref rl = m_context->bind_variables(rule, true);
@ -110,7 +110,7 @@ struct dl_context {
m_trail.push(push_back_vector<dl_context, svector<symbol> >(m_collected_cmds->m_names)); m_trail.push(push_back_vector<dl_context, svector<symbol> >(m_collected_cmds->m_names));
} }
else { else {
m_context->add_rule(rule, name); m_context->add_rule(rule, name, bound);
} }
} }
@ -151,19 +151,22 @@ class dl_rule_cmd : public cmd {
mutable unsigned m_arg_idx; mutable unsigned m_arg_idx;
expr* m_t; expr* m_t;
symbol m_name; symbol m_name;
unsigned m_bound;
public: public:
dl_rule_cmd(dl_context * dl_ctx): dl_rule_cmd(dl_context * dl_ctx):
cmd("rule"), cmd("rule"),
m_dl_ctx(dl_ctx), m_dl_ctx(dl_ctx),
m_arg_idx(0), m_arg_idx(0),
m_t(0) {} m_t(0),
virtual char const * get_usage() const { return "(forall (q) (=> (and body) head)) :optional-name"; } m_bound(UINT_MAX) {}
virtual char const * get_usage() const { return "(forall (q) (=> (and body) head)) :optional-name :optional-recursion-bound"; }
virtual char const * get_descr(cmd_context & ctx) const { return "add a Horn rule."; } virtual char const * get_descr(cmd_context & ctx) const { return "add a Horn rule."; }
virtual unsigned get_arity() const { return VAR_ARITY; } virtual unsigned get_arity() const { return VAR_ARITY; }
virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const { virtual cmd_arg_kind next_arg_kind(cmd_context & ctx) const {
switch(m_arg_idx) { switch(m_arg_idx) {
case 0: return CPK_EXPR; case 0: return CPK_EXPR;
case 1: return CPK_SYMBOL; case 1: return CPK_SYMBOL;
case 2: return CPK_UINT;
default: return CPK_SYMBOL; default: return CPK_SYMBOL;
} }
} }
@ -173,13 +176,18 @@ public:
} }
virtual void set_next_arg(cmd_context & ctx, symbol const & s) { virtual void set_next_arg(cmd_context & ctx, symbol const & s) {
m_name = s; m_name = s;
m_arg_idx++;
}
virtual void set_next_arg(cmd_context & ctx, unsigned bound) {
m_bound = bound;
m_arg_idx++;
} }
virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); } virtual void reset(cmd_context & ctx) { m_dl_ctx->reset(); prepare(ctx); }
virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; } virtual void prepare(cmd_context& ctx) { m_arg_idx = 0; m_name = symbol::null; m_bound = UINT_MAX; }
virtual void finalize(cmd_context & ctx) { virtual void finalize(cmd_context & ctx) {
} }
virtual void execute(cmd_context & ctx) { virtual void execute(cmd_context & ctx) {
m_dl_ctx->add_rule(m_t, m_name); m_dl_ctx->add_rule(m_t, m_name, m_bound);
} }
}; };

View file

@ -71,7 +71,8 @@ namespace datalog {
transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 32000)); transf.register_plugin(alloc(datalog::mk_quantifier_instantiation, ctx, 32000));
transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000)); transf.register_plugin(alloc(datalog::mk_bit_blast, ctx, 35000));
transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000)); if (!ctx.get_params().quantify_arrays())
transf.register_plugin(alloc(datalog::mk_array_blast, ctx, 36000));
transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010)); transf.register_plugin(alloc(datalog::mk_karr_invariants, ctx, 36010));
if (ctx.get_params().magic()) { if (ctx.get_params().magic()) {
transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020)); transf.register_plugin(alloc(datalog::mk_magic_symbolic, ctx, 36020));

View file

@ -54,7 +54,11 @@ Revision History:
// the case that each context only references a few expressions. // the case that each context only references a few expressions.
// Using a map instead of a vector for the literals can compress space // Using a map instead of a vector for the literals can compress space
// consumption. // consumption.
#ifdef SPARSE_MAP
#define USE_BOOL_VAR_VECTOR 0
#else
#define USE_BOOL_VAR_VECTOR 1 #define USE_BOOL_VAR_VECTOR 1
#endif
namespace smt { namespace smt {
@ -69,6 +73,7 @@ namespace smt {
std::string last_failure_as_string() const; std::string last_failure_as_string() const;
void set_progress_callback(progress_callback *callback); void set_progress_callback(progress_callback *callback);
protected: protected:
ast_manager & m_manager; ast_manager & m_manager;
smt_params & m_fparams; smt_params & m_fparams;
@ -106,7 +111,7 @@ namespace smt {
// ----------------------------------- // -----------------------------------
enode * m_true_enode; enode * m_true_enode;
enode * m_false_enode; enode * m_false_enode;
ptr_vector<enode> m_app2enode; // app -> enode app2enode_t m_app2enode; // app -> enode
ptr_vector<enode> m_enodes; ptr_vector<enode> m_enodes;
plugin_manager<theory> m_theories; // mapping from theory_id -> theory plugin_manager<theory> m_theories; // mapping from theory_id -> theory
ptr_vector<theory> m_theory_set; // set of theories for fast traversal ptr_vector<theory> m_theory_set; // set of theories for fast traversal

View file

@ -24,7 +24,7 @@ namespace smt {
/** /**
\brief Initialize an enode in the given memory position. \brief Initialize an enode in the given memory position.
*/ */
enode * enode::init(ast_manager & m, void * mem, ptr_vector<enode> const & app2enode, app * owner, enode * enode::init(ast_manager & m, void * mem, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent) { bool cgc_enabled, bool update_children_parent) {
SASSERT(m.is_bool(owner) || !merge_tf); SASSERT(m.is_bool(owner) || !merge_tf);
@ -60,7 +60,7 @@ namespace smt {
return n; return n;
} }
enode * enode::mk(ast_manager & m, region & r, ptr_vector<enode> const & app2enode, app * owner, enode * enode::mk(ast_manager & m, region & r, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent) { bool cgc_enabled, bool update_children_parent) {
SASSERT(m.is_bool(owner) || !merge_tf); SASSERT(m.is_bool(owner) || !merge_tf);
@ -69,7 +69,7 @@ namespace smt {
return init(m, mem, app2enode, owner, generation, suppress_args, merge_tf, iscope_lvl, cgc_enabled, update_children_parent); return init(m, mem, app2enode, owner, generation, suppress_args, merge_tf, iscope_lvl, cgc_enabled, update_children_parent);
} }
enode * enode::mk_dummy(ast_manager & m, ptr_vector<enode> const & app2enode, app * owner) { enode * enode::mk_dummy(ast_manager & m, app2enode_t const & app2enode, app * owner) {
unsigned sz = get_enode_size(owner->get_num_args()); unsigned sz = get_enode_size(owner->get_num_args());
void * mem = alloc_svect(char, sz); void * mem = alloc_svect(char, sz);
return init(m, mem, app2enode, owner, 0, false, false, 0, true, false); return init(m, mem, app2enode, owner, 0, false, false, 0, true, false);

View file

@ -38,6 +38,29 @@ namespace smt {
} }
}; };
/** \ brief Use sparse maps in SMT solver.
Define this to use hash maps rather than vectors over ast
nodes. This is useful in the case there are many solvers, each
referencing few nodes from a large ast manager. There is some
unknown performance penalty for this. */
// #define SPARSE_MAP
#ifndef SPARSE_MAP
typedef ptr_vector<enode> app2enode_t; // app -> enode
#else
class app2enode_t : public u_map<enode *> {
public:
void setx(unsigned x, enode *val, enode *def){
if(val == 0)
erase(x);
else
insert(x,val);
}
};
#endif
class tmp_enode; class tmp_enode;
/** /**
@ -115,7 +138,7 @@ namespace smt {
friend class tmp_enode; friend class tmp_enode;
static enode * init(ast_manager & m, void * mem, ptr_vector<enode> const & app2enode, app * owner, static enode * init(ast_manager & m, void * mem, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent); bool cgc_enabled, bool update_children_parent);
public: public:
@ -124,11 +147,11 @@ namespace smt {
return sizeof(enode) + num_args * sizeof(enode*); return sizeof(enode) + num_args * sizeof(enode*);
} }
static enode * mk(ast_manager & m, region & r, ptr_vector<enode> const & app2enode, app * owner, static enode * mk(ast_manager & m, region & r, app2enode_t const & app2enode, app * owner,
unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl, unsigned generation, bool suppress_args, bool merge_tf, unsigned iscope_lvl,
bool cgc_enabled, bool update_children_parent); bool cgc_enabled, bool update_children_parent);
static enode * mk_dummy(ast_manager & m, ptr_vector<enode> const & app2enode, app * owner); static enode * mk_dummy(ast_manager & m, app2enode_t const & app2enode, app * owner);
static void del_dummy(enode * n) { dealloc_svect(reinterpret_cast<char*>(n)); } static void del_dummy(enode * n) { dealloc_svect(reinterpret_cast<char*>(n)); }

View file

@ -376,8 +376,10 @@ namespace smt {
enode_vector::const_iterator end = r->end_parents(); enode_vector::const_iterator end = r->end_parents();
for (; it != end; ++it) { for (; it != end; ++it) {
enode * parent = *it; enode * parent = *it;
#if 0
if (!ctx.is_relevant(parent)) if (!ctx.is_relevant(parent))
continue; continue;
#endif
unsigned num_args = parent->get_num_args(); unsigned num_args = parent->get_num_args();
if (is_store(parent)) { if (is_store(parent)) {
SET_ARRAY(parent->get_arg(0)); SET_ARRAY(parent->get_arg(0));
@ -399,6 +401,7 @@ namespace smt {
return false; return false;
} }
#if 0
void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) { void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) {
TRACE("array_shared", tout << "collecting shared vars...\n";); TRACE("array_shared", tout << "collecting shared vars...\n";);
context & ctx = get_context(); context & ctx = get_context();
@ -420,6 +423,31 @@ namespace smt {
} }
unmark_enodes(to_unmark.size(), to_unmark.c_ptr()); unmark_enodes(to_unmark.size(), to_unmark.c_ptr());
} }
#else
void theory_array_base::collect_shared_vars(sbuffer<theory_var> & result) {
TRACE("array_shared", tout << "collecting shared vars...\n";);
context & ctx = get_context();
ptr_buffer<enode> to_unmark;
unsigned num_vars = get_num_vars();
for (unsigned i = 0; i < num_vars; i++) {
enode * n = get_enode(i);
if (ctx.is_relevant(n)) {
enode * r = n->get_root();
if (!r->is_marked()){
if(is_array_sort(r) && ctx.is_shared(r)) {
TRACE("array_shared", tout << "new shared var: #" << r->get_owner_id() << "\n";);
theory_var r_th_var = r->get_th_var(get_id());
SASSERT(r_th_var != null_theory_var);
result.push_back(r_th_var);
}
r->set_mark();
to_unmark.push_back(r);
}
}
}
unmark_enodes(to_unmark.size(), to_unmark.c_ptr());
}
#endif
/** /**
\brief Create interface variables for shared array variables. \brief Create interface variables for shared array variables.

View file

@ -131,7 +131,7 @@ public:
value const& get(key const& k, value const& default_value) const { value const& get(key const& k, value const& default_value) const {
entry* e = find_core(k); entry* e = find_core(k);
if (e) { if (e) {
return e->m_value; return e->get_data().m_value;
} }
else { else {
return default_value; return default_value;