mirror of
https://github.com/Z3Prover/z3
synced 2025-04-06 01:24:08 +00:00
first commit of duality
This commit is contained in:
parent
71275652a7
commit
8488ca24d2
|
@ -54,8 +54,9 @@ def init_project_def():
|
|||
add_lib('fpa', ['core_tactics', 'bv_tactics', 'sat_tactic'], 'tactic/fpa')
|
||||
add_lib('smt_tactic', ['smt'], 'smt/tactic')
|
||||
add_lib('sls_tactic', ['tactic', 'normal_forms', 'core_tactics', 'bv_tactics'], 'tactic/sls')
|
||||
add_lib('duality', ['smt', 'interp'])
|
||||
# TODO: split muz_qe inbto muz, qe. Perhaps, we should also consider breaking muz into muz and pdr.
|
||||
add_lib('muz_qe', ['smt', 'sat', 'smt2parser'])
|
||||
add_lib('muz_qe', ['smt', 'sat', 'smt2parser', 'duality'])
|
||||
add_lib('smtlogic_tactics', ['arith_tactics', 'bv_tactics', 'nlsat_tactic', 'smt_tactic', 'aig_tactic', 'muz_qe'], 'tactic/smtlogics')
|
||||
add_lib('ufbv_tactic', ['normal_forms', 'core_tactics', 'macros', 'smt_tactic', 'rewriter'], 'tactic/ufbv')
|
||||
add_lib('portfolio', ['smtlogic_tactics', 'ufbv_tactic', 'fpa', 'aig_tactic', 'muz_qe', 'sls_tactic', 'subpaving_tactic'], 'tactic/portfolio')
|
||||
|
|
|
@ -34,6 +34,6 @@ using System.Security.Permissions;
|
|||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("4.2.0.0")]
|
||||
[assembly: AssemblyVersion("4.3.2.0")]
|
||||
[assembly: AssemblyFileVersion("4.3.2.0")]
|
||||
[assembly: AssemblyVersion("4.3.2.0")]
|
||||
[assembly: AssemblyFileVersion("4.3.2.0")]
|
||||
|
||||
|
|
792
src/duality/duality.h
Normal file
792
src/duality/duality.h
Normal file
|
@ -0,0 +1,792 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality.h
|
||||
|
||||
Abstract:
|
||||
|
||||
main header for duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
// make hash_map and hash_set available
|
||||
#ifndef WIN32
|
||||
using namespace stl_ext;
|
||||
#endif
|
||||
|
||||
namespace Duality {
|
||||
|
||||
/* Generic operations on Z3 formulas */
|
||||
|
||||
struct Z3User {
|
||||
|
||||
context &ctx;
|
||||
solver &slvr;
|
||||
|
||||
typedef func_decl FuncDecl;
|
||||
typedef expr Term;
|
||||
|
||||
Z3User(context &_ctx, solver &_slvr) : ctx(_ctx), slvr(_slvr){}
|
||||
|
||||
const char *string_of_int(int n);
|
||||
|
||||
Term conjoin(const std::vector<Term> &args);
|
||||
|
||||
Term sum(const std::vector<Term> &args);
|
||||
|
||||
Term CloneQuantifier(const Term &t, const Term &new_body);
|
||||
|
||||
Term SubstRec(hash_map<ast, Term> &memo, const Term &t);
|
||||
|
||||
void Strengthen(Term &x, const Term &y);
|
||||
|
||||
// return the func_del of an app if it is uninterpreted
|
||||
|
||||
bool get_relation(const Term &t, func_decl &R);
|
||||
|
||||
// return true if term is an individual variable
|
||||
// TODO: have to check that it is not a background symbol
|
||||
|
||||
bool is_variable(const Term &t);
|
||||
|
||||
FuncDecl SuffixFuncDecl(Term t, int n);
|
||||
|
||||
|
||||
Term SubstRecHide(hash_map<ast, Term> &memo, const Term &t, int number);
|
||||
|
||||
void CollectConjuncts(const Term &f, std::vector<Term> &lits, bool pos = true);
|
||||
|
||||
void SortTerms(std::vector<Term> &terms);
|
||||
|
||||
Term SortSum(const Term &t);
|
||||
|
||||
void Summarize(const Term &t);
|
||||
|
||||
int CumulativeDecisions();
|
||||
|
||||
Term SubstBoundRec(hash_map<int,hash_map<ast,Term> > &memo, hash_map<int,Term> &subst, int level, const Term &t);
|
||||
|
||||
Term SubstBound(hash_map<int,Term> &subst, const Term &t);
|
||||
|
||||
private:
|
||||
|
||||
void SummarizeRec(hash_set<ast> &memo, std::vector<expr> &lits, int &ops, const Term &t);
|
||||
|
||||
};
|
||||
|
||||
/** This class represents a relation post-fixed point (RPFP) problem as
|
||||
* a "problem graph". The graph consists of Nodes and hyper-edges.
|
||||
*
|
||||
* A node consists of
|
||||
* - Annotation, a symbolic relation
|
||||
* - Bound, a symbolic relation giving an upper bound on Annotation
|
||||
*
|
||||
*
|
||||
* A hyper-edge consists of:
|
||||
* - Children, a sequence of children Nodes,
|
||||
* - F, a symbolic relational transformer,
|
||||
* - Parent, a single parent Node.
|
||||
*
|
||||
* The graph is "solved" when:
|
||||
* - For every Node n, n.Annotation subseteq n.Bound
|
||||
* - For every hyperedge e, e.F(e.Children.Annotation) subseteq e.Parent.Annotation
|
||||
*
|
||||
* where, if x is a sequence of Nodes, x.Annotation is the sequences
|
||||
* of Annotations of the nodes in the sequence.
|
||||
*
|
||||
* A symbolic Transformer consists of
|
||||
* - RelParams, a sequence of relational symbols
|
||||
* - IndParams, a sequence of individual symbols
|
||||
* - Formula, a formula over RelParams and IndParams
|
||||
*
|
||||
* A Transformer t represents a function that takes sequence R of relations
|
||||
* and yields the relation lambda (t.Indparams). Formula(R/RelParams).
|
||||
*
|
||||
* As a special case, a nullary Transformer (where RelParams is the empty sequence)
|
||||
* represents a fixed relation.
|
||||
*
|
||||
* An RPFP consists of
|
||||
* - Nodes, a set of Nodes
|
||||
* - Edges, a set of hyper-edges
|
||||
* - Context, a prover context that contains formula AST's
|
||||
*
|
||||
* Multiple RPFP's can use the same Context, but you should be careful
|
||||
* that only one RPFP asserts constraints in the context at any time.
|
||||
*
|
||||
* */
|
||||
class RPFP : public Z3User
|
||||
{
|
||||
public:
|
||||
|
||||
class Edge;
|
||||
class Node;
|
||||
bool HornClauses;
|
||||
|
||||
|
||||
/** Interface class for interpolating solver. */
|
||||
|
||||
class LogicSolver {
|
||||
public:
|
||||
|
||||
context *ctx; /** Z3 context for formulas */
|
||||
solver *slvr; /** Z3 solver */
|
||||
bool need_goals; /** Can the solver use the goal tree to optimize interpolants? */
|
||||
|
||||
/** Tree interpolation. This method assumes the formulas in TermTree
|
||||
"assumptions" are currently asserted in the solver. The return
|
||||
value indicates whether the assertions are satisfiable. In the
|
||||
UNSAT case, a tree interpolant is returned in "interpolants".
|
||||
In the SAT case, a model is returned.
|
||||
*/
|
||||
|
||||
virtual
|
||||
lbool interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolants,
|
||||
model &_model,
|
||||
TermTree *goals = 0
|
||||
) = 0;
|
||||
|
||||
/** Assert a background axiom. */
|
||||
virtual void assert_axiom(const expr &axiom) = 0;
|
||||
|
||||
/** Return a string describing performance. */
|
||||
virtual std::string profile() = 0;
|
||||
|
||||
virtual void write_interpolation_problem(const std::string &file_name,
|
||||
const std::vector<expr> &assumptions,
|
||||
const std::vector<expr> &theory
|
||||
){}
|
||||
};
|
||||
|
||||
/** This solver uses iZ3. */
|
||||
class iZ3LogicSolver : public LogicSolver {
|
||||
public:
|
||||
interpolating_context *ictx; /** iZ3 context for formulas */
|
||||
interpolating_solver *islvr; /** iZ3 solver */
|
||||
|
||||
lbool interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolants,
|
||||
model &_model,
|
||||
TermTree *goals = 0)
|
||||
{
|
||||
literals _labels;
|
||||
return islvr->interpolate_tree(assumptions,interpolants,_model,_labels,true);
|
||||
}
|
||||
|
||||
void assert_axiom(const expr &axiom){
|
||||
islvr->AssertInterpolationAxiom(axiom);
|
||||
}
|
||||
|
||||
std::string profile(){
|
||||
return islvr->profile();
|
||||
}
|
||||
|
||||
#if 0
|
||||
iZ3LogicSolver(config &_config){
|
||||
ctx = ictx = new interpolating_context(_config);
|
||||
slvr = islvr = new interpolating_solver(*ictx);
|
||||
need_goals = false;
|
||||
islvr->SetWeakInterpolants(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
iZ3LogicSolver(context c){
|
||||
ctx = ictx = new interpolating_context(c);
|
||||
slvr = islvr = new interpolating_solver(*ictx);
|
||||
need_goals = false;
|
||||
islvr->SetWeakInterpolants(true);
|
||||
}
|
||||
|
||||
void write_interpolation_problem(const std::string &file_name,
|
||||
const std::vector<expr> &assumptions,
|
||||
const std::vector<expr> &theory
|
||||
){
|
||||
#if 0
|
||||
islvr->write_interpolation_problem(file_name,assumptions,theory);
|
||||
#endif
|
||||
}
|
||||
~iZ3LogicSolver(){
|
||||
delete ictx;
|
||||
delete islvr;
|
||||
}
|
||||
};
|
||||
|
||||
#if 0
|
||||
/** Create a logic solver from a Z3 configuration. */
|
||||
static iZ3LogicSolver *CreateLogicSolver(config &_config){
|
||||
return new iZ3LogicSolver(_config);
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Create a logic solver from a low-level Z3 context.
|
||||
Only use this if you know what you're doing. */
|
||||
static iZ3LogicSolver *CreateLogicSolver(context c){
|
||||
return new iZ3LogicSolver(c);
|
||||
}
|
||||
|
||||
LogicSolver *ls;
|
||||
|
||||
private:
|
||||
int nodeCount;
|
||||
int edgeCount;
|
||||
|
||||
class stack_entry
|
||||
{
|
||||
public:
|
||||
std::list<Edge *> edges;
|
||||
std::list<Node *> nodes;
|
||||
};
|
||||
|
||||
|
||||
model dualModel;
|
||||
literals dualLabels;
|
||||
std::list<stack_entry> stack;
|
||||
std::vector<Term> axioms; // only saved here for printing purposes
|
||||
|
||||
public:
|
||||
|
||||
/** Construct an RPFP graph with a given interpolating prover context. It is allowed to
|
||||
have multiple RPFP's use the same context, but you should never have teo RPFP's
|
||||
with the same conext asserting nodes or edges at the same time. Note, if you create
|
||||
axioms in one RPFP, them create a second RPFP with the same context, the second will
|
||||
inherit the axioms.
|
||||
*/
|
||||
|
||||
RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx), *(_ls->slvr)), dualModel(*(_ls->ctx))
|
||||
{
|
||||
ls = _ls;
|
||||
nodeCount = 0;
|
||||
edgeCount = 0;
|
||||
stack.push_back(stack_entry());
|
||||
HornClauses = false;
|
||||
}
|
||||
|
||||
~RPFP();
|
||||
|
||||
/** Symbolic representation of a relational transformer */
|
||||
class Transformer
|
||||
{
|
||||
public:
|
||||
std::vector<FuncDecl> RelParams;
|
||||
std::vector<Term> IndParams;
|
||||
Term Formula;
|
||||
RPFP *owner;
|
||||
hash_map<std::string,Term> labels;
|
||||
|
||||
Transformer *Clone()
|
||||
{
|
||||
return new Transformer(*this);
|
||||
}
|
||||
|
||||
void SetEmpty(){
|
||||
Formula = owner->ctx.bool_val(false);
|
||||
}
|
||||
|
||||
void SetFull(){
|
||||
Formula = owner->ctx.bool_val(true);
|
||||
}
|
||||
|
||||
bool IsEmpty(){
|
||||
return eq(Formula,owner->ctx.bool_val(false));
|
||||
}
|
||||
|
||||
bool IsFull(){
|
||||
return eq(Formula,owner->ctx.bool_val(true));
|
||||
}
|
||||
|
||||
void UnionWith(const Transformer &other){
|
||||
Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula);
|
||||
Formula = Formula || t;
|
||||
}
|
||||
|
||||
void IntersectWith(const Transformer &other){
|
||||
Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula);
|
||||
Formula = Formula && t;
|
||||
}
|
||||
|
||||
bool SubsetEq(const Transformer &other){
|
||||
Term t = owner->SubstParams(other.IndParams,IndParams,other.Formula);
|
||||
expr test = Formula && !t;
|
||||
owner->slvr.push();
|
||||
owner->slvr.add(test);
|
||||
check_result res = owner->slvr.check();
|
||||
owner->slvr.pop(1);
|
||||
return res == unsat;
|
||||
}
|
||||
|
||||
void Complement(){
|
||||
Formula = !Formula;
|
||||
}
|
||||
|
||||
void Simplify(){
|
||||
Formula = Formula.simplify();
|
||||
}
|
||||
|
||||
Transformer(const std::vector<FuncDecl> &_RelParams, const std::vector<Term> &_IndParams, const Term &_Formula, RPFP *_owner)
|
||||
: RelParams(_RelParams), IndParams(_IndParams), Formula(_Formula) {owner = _owner;}
|
||||
};
|
||||
|
||||
/** Create a symbolic transformer. */
|
||||
Transformer CreateTransformer(const std::vector<FuncDecl> &_RelParams, const std::vector<Term> &_IndParams, const Term &_Formula)
|
||||
{
|
||||
// var ops = new Util.ContextOps(ctx);
|
||||
// var foo = ops.simplify_lhs(_Formula);
|
||||
// t.Formula = foo.Item1;
|
||||
// t.labels = foo.Item2;
|
||||
return Transformer(_RelParams,_IndParams,_Formula,this);
|
||||
}
|
||||
|
||||
/** Create a relation (nullary relational transformer) */
|
||||
Transformer CreateRelation(const std::vector<Term> &_IndParams, const Term &_Formula)
|
||||
{
|
||||
return CreateTransformer(std::vector<FuncDecl>(), _IndParams, _Formula);
|
||||
}
|
||||
|
||||
/** A node in the RPFP graph */
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
FuncDecl Name;
|
||||
Transformer Annotation;
|
||||
Transformer Bound;
|
||||
Transformer Underapprox;
|
||||
RPFP *owner;
|
||||
int number;
|
||||
Edge *Outgoing;
|
||||
std::vector<Edge *> Incoming;
|
||||
Term dual;
|
||||
Node *map;
|
||||
|
||||
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;}
|
||||
};
|
||||
|
||||
/** Create a node in the graph. The input is a term R(v_1...v_n)
|
||||
* where R is an arbitrary relational symbol and v_1...v_n are
|
||||
* arbitary distinct variables. The names are only of mnemonic value,
|
||||
* however, the number and type of arguments determine the type
|
||||
* of the relation at this node. */
|
||||
|
||||
Node *CreateNode(const Term &t)
|
||||
{
|
||||
std::vector<Term> _IndParams;
|
||||
int nargs = t.num_args();
|
||||
for(int i = 0; i < nargs; i++)
|
||||
_IndParams.push_back(t.arg(i));
|
||||
Node *n = new Node(t.decl(),
|
||||
CreateRelation(_IndParams,ctx.bool_val(true)),
|
||||
CreateRelation(_IndParams,ctx.bool_val(true)),
|
||||
CreateRelation(_IndParams,ctx.bool_val(false)),
|
||||
expr(ctx), this, ++nodeCount
|
||||
);
|
||||
nodes.push_back(n);
|
||||
return n;
|
||||
}
|
||||
|
||||
/** Clone a node (can be from another graph). */
|
||||
|
||||
Node *CloneNode(Node *old)
|
||||
{
|
||||
Node *n = new Node(old->Name,
|
||||
old->Annotation,
|
||||
old->Bound,
|
||||
old->Underapprox,
|
||||
expr(ctx),
|
||||
this,
|
||||
++nodeCount
|
||||
);
|
||||
nodes.push_back(n);
|
||||
n->map = old;
|
||||
return n;
|
||||
}
|
||||
|
||||
/** This class represents a hyper-edge in the RPFP graph */
|
||||
|
||||
class Edge
|
||||
{
|
||||
public:
|
||||
Transformer F;
|
||||
Node *Parent;
|
||||
std::vector<Node *> Children;
|
||||
RPFP *owner;
|
||||
int number;
|
||||
// these should be internal...
|
||||
Term dual;
|
||||
hash_map<func_decl,int> relMap;
|
||||
hash_map<ast,Term> varMap;
|
||||
Edge *map;
|
||||
|
||||
Edge(Node *_Parent, const Transformer &_F, const std::vector<Node *> &_Children, RPFP *_owner, int _number)
|
||||
: F(_F), Parent(_Parent), Children(_Children), dual(expr(_owner->ctx)) {
|
||||
owner = _owner;
|
||||
number = _number;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Create a hyper-edge. */
|
||||
Edge *CreateEdge(Node *_Parent, const Transformer &_F, const std::vector<Node *> &_Children)
|
||||
{
|
||||
Edge *e = new Edge(_Parent,_F,_Children,this,++edgeCount);
|
||||
_Parent->Outgoing = e;
|
||||
for(unsigned i = 0; i < _Children.size(); i++)
|
||||
_Children[i]->Incoming.push_back(e);
|
||||
edges.push_back(e);
|
||||
return e;
|
||||
}
|
||||
|
||||
/** Create an edge that lower-bounds its parent. */
|
||||
Edge *CreateLowerBoundEdge(Node *_Parent)
|
||||
{
|
||||
return CreateEdge(_Parent, _Parent->Annotation, std::vector<Node *>());
|
||||
}
|
||||
|
||||
|
||||
/** For incremental solving, asserts the constraint associated
|
||||
* with this edge in the SMT context. If this edge is removed,
|
||||
* you must pop the context accordingly. The second argument is
|
||||
* the number of pushes we are inside. */
|
||||
|
||||
void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false);
|
||||
|
||||
|
||||
/** For incremental solving, asserts the negation of the upper bound associated
|
||||
* with a node.
|
||||
* */
|
||||
|
||||
void AssertNode(Node *n);
|
||||
|
||||
/** Assert a background axiom. Background axioms can be used to provide the
|
||||
* theory of auxilliary functions or relations. All symbols appearing in
|
||||
* background axioms are considered global, and may appear in both transformer
|
||||
* and relational solutions. Semantically, a solution to the RPFP gives
|
||||
* an interpretation of the unknown relations for each interpretation of the
|
||||
* auxilliary symbols that is consistent with the axioms. Axioms should be
|
||||
* asserted before any calls to Push. They cannot be de-asserted by Pop. */
|
||||
|
||||
void AssertAxiom(const Term &t);
|
||||
|
||||
#if 0
|
||||
/** Do not call this. */
|
||||
|
||||
void RemoveAxiom(const Term &t);
|
||||
#endif
|
||||
|
||||
/** Solve an RPFP graph. This means either strengthen the annotation
|
||||
* so that the bound at the given root node is satisfied, or
|
||||
* show that this cannot be done by giving a dual solution
|
||||
* (i.e., a counterexample).
|
||||
*
|
||||
* In the current implementation, this only works for graphs that
|
||||
* are:
|
||||
* - tree-like
|
||||
*
|
||||
* - closed.
|
||||
*
|
||||
* In a tree-like graph, every nod has out most one incoming and one out-going edge,
|
||||
* and there are no cycles. In a closed graph, every node has exactly one out-going
|
||||
* edge. This means that the leaves of the tree are all hyper-edges with no
|
||||
* children. Such an edge represents a relation (nullary transformer) and thus
|
||||
* a lower bound on its parent. The parameter root must be the root of this tree.
|
||||
*
|
||||
* If Solve returns LBool.False, this indicates success. The annotation of the tree
|
||||
* has been updated to satisfy the upper bound at the root.
|
||||
*
|
||||
* If Solve returns LBool.True, this indicates a counterexample. For each edge,
|
||||
* you can then call Eval to determine the values of symbols in the transformer formula.
|
||||
* You can also call Empty on a node to determine if its value in the counterexample
|
||||
* is the empty relation.
|
||||
*
|
||||
* \param root The root of the tree
|
||||
* \param persist Number of context pops through which result should persist
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
lbool Solve(Node *root, int persist);
|
||||
|
||||
/** Get the constraint tree (but don't solve it) */
|
||||
|
||||
TermTree *GetConstraintTree(Node *root);
|
||||
|
||||
/** Dispose of the dual model (counterexample) if there is one. */
|
||||
|
||||
void DisposeDualModel();
|
||||
|
||||
/** Check satisfiability of asserted edges and nodes. Same functionality as
|
||||
* Solve, except no primal solution (interpolant) is generated in the unsat case. */
|
||||
|
||||
check_result Check(Node *root, std::vector<Node *> underapproxes = std::vector<Node *>(),
|
||||
std::vector<Node *> *underapprox_core = 0);
|
||||
|
||||
/** Update the model, attempting to make the propositional literals in assumps true. If possible,
|
||||
return sat, else return unsat and keep the old model. */
|
||||
|
||||
check_result CheckUpdateModel(Node *root, std::vector<expr> assumps);
|
||||
|
||||
/** Determines the value in the counterexample of a symbol occuring in the transformer formula of
|
||||
* a given edge. */
|
||||
|
||||
Term Eval(Edge *e, Term t);
|
||||
|
||||
/** Return the fact derived at node p in a counterexample. */
|
||||
|
||||
Term EvalNode(Node *p);
|
||||
|
||||
/** Returns true if the given node is empty in the primal solution. For proecudure summaries,
|
||||
this means that the procedure is not called in the current counter-model. */
|
||||
|
||||
bool Empty(Node *p);
|
||||
|
||||
/** Compute an underapproximation of every node in a tree rooted at "root",
|
||||
based on a previously computed counterexample. */
|
||||
|
||||
Term ComputeUnderapprox(Node *root, int persist);
|
||||
|
||||
/** Push a scope. Assertions made after Push can be undone by Pop. */
|
||||
|
||||
void Push();
|
||||
|
||||
/** Exception thrown when bad clause is encountered */
|
||||
|
||||
struct bad_clause {
|
||||
std::string msg;
|
||||
int i;
|
||||
bad_clause(const std::string &_msg, int _i){
|
||||
msg = _msg;
|
||||
i = _i;
|
||||
}
|
||||
};
|
||||
|
||||
struct parse_error {
|
||||
std::string msg;
|
||||
parse_error(const std::string &_msg){
|
||||
msg = _msg;
|
||||
}
|
||||
};
|
||||
|
||||
struct file_not_found {
|
||||
};
|
||||
|
||||
struct bad_format {
|
||||
};
|
||||
|
||||
/** Pop a scope (see Push). Note, you cannot pop axioms. */
|
||||
|
||||
void Pop(int num_scopes);
|
||||
|
||||
/** Convert a collection of clauses to Nodes and Edges in the RPFP.
|
||||
|
||||
Predicate unknowns are uninterpreted predicates not
|
||||
occurring in the background theory.
|
||||
|
||||
Clauses are of the form
|
||||
|
||||
B => P(t_1,...,t_k)
|
||||
|
||||
where P is a predicate unknown and predicate unknowns
|
||||
occur only positivey in H and only under existential
|
||||
quantifiers in prenex form.
|
||||
|
||||
Each predicate unknown maps to a node. Each clause maps to
|
||||
an edge. Let C be a clause B => P(t_1,...,t_k) where the
|
||||
sequence of predicate unknowns occurring in B (in order
|
||||
of occurrence) is P_1..P_n. The clause maps to a transformer
|
||||
T where:
|
||||
|
||||
T.Relparams = P_1..P_n
|
||||
T.Indparams = x_1...x+k
|
||||
T.Formula = B /\ t_1 = x_1 /\ ... /\ t_k = x_k
|
||||
|
||||
Throws exception bad_clause(msg,i) if a clause i is
|
||||
in the wrong form.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
__declspec(dllexport)
|
||||
#endif
|
||||
void FromClauses(const std::vector<Term> &clauses);
|
||||
|
||||
void FromFixpointContext(fixedpoint fp, std::vector<Term> &queries);
|
||||
|
||||
void WriteSolution(std::ostream &s);
|
||||
|
||||
void WriteCounterexample(std::ostream &s, Node *node);
|
||||
|
||||
enum FileFormat {DualityFormat, SMT2Format, HornFormat};
|
||||
|
||||
/** Write the RPFP to a file (currently in SMTLIB 1.2 format) */
|
||||
void WriteProblemToFile(std::string filename, FileFormat format = DualityFormat);
|
||||
|
||||
/** Read the RPFP from a file (in specificed format) */
|
||||
void ReadProblemFromFile(std::string filename, FileFormat format = DualityFormat);
|
||||
|
||||
/** Translate problem to Horn clause form */
|
||||
void ToClauses(std::vector<Term> &cnsts, FileFormat format = DualityFormat);
|
||||
|
||||
/** Translate the RPFP to a fixed point context, with queries */
|
||||
fixedpoint ToFixedPointProblem(std::vector<expr> &queries);
|
||||
|
||||
/** Nodes of the graph. */
|
||||
std::vector<Node *> nodes;
|
||||
|
||||
/** Edges of the graph. */
|
||||
std::vector<Edge *> edges;
|
||||
|
||||
Term SubstParams(const std::vector<Term> &from,
|
||||
const std::vector<Term> &to, const Term &t);
|
||||
|
||||
Term Localize(Edge *e, const Term &t);
|
||||
|
||||
void EvalNodeAsConstraint(Node *p, Transformer &res);
|
||||
|
||||
TermTree *GetGoalTree(Node *root);
|
||||
|
||||
private:
|
||||
|
||||
|
||||
Term SuffixVariable(const Term &t, int n);
|
||||
|
||||
Term HideVariable(const Term &t, int n);
|
||||
|
||||
void RedVars(Node *node, Term &b, std::vector<Term> &v);
|
||||
|
||||
Term RedDualRela(Edge *e, std::vector<Term> &args, int idx);
|
||||
|
||||
Term LocalizeRec(Edge *e, hash_map<ast,Term> &memo, const Term &t);
|
||||
|
||||
void SetEdgeMaps(Edge *e);
|
||||
|
||||
Term ReducedDualEdge(Edge *e);
|
||||
|
||||
TermTree *ToTermTree(Node *root);
|
||||
|
||||
TermTree *ToGoalTree(Node *root);
|
||||
|
||||
void DecodeTree(Node *root, TermTree *interp, int persist);
|
||||
|
||||
Term GetUpperBound(Node *n);
|
||||
|
||||
TermTree *AddUpperBound(Node *root, TermTree *t);
|
||||
|
||||
#if 0
|
||||
void WriteInterps(System.IO.StreamWriter f, TermTree t);
|
||||
#endif
|
||||
|
||||
void WriteEdgeVars(Edge *e, hash_map<ast,int> &memo, const Term &t, std::ostream &s);
|
||||
|
||||
void WriteEdgeAssignment(std::ostream &s, Edge *e);
|
||||
|
||||
|
||||
// Scan the clause body for occurrences of the predicate unknowns
|
||||
|
||||
Term ScanBody(hash_map<ast,Term> &memo,
|
||||
const Term &t,
|
||||
hash_map<func_decl,Node *> &pmap,
|
||||
std::vector<func_decl> &res,
|
||||
std::vector<Node *> &nodes);
|
||||
|
||||
|
||||
Term RemoveLabelsRec(hash_map<ast,Term> &memo, const Term &t);
|
||||
|
||||
Term RemoveLabels(const Term &t);
|
||||
|
||||
Term GetAnnotation(Node *n);
|
||||
|
||||
|
||||
Term GetUnderapprox(Node *n);
|
||||
|
||||
Term UnderapproxFlag(Node *n);
|
||||
|
||||
hash_map<ast,Node *> underapprox_flag_rev;
|
||||
|
||||
Node *UnderapproxFlagRev(const Term &flag);
|
||||
|
||||
Term ProjectFormula(std::vector<Term> &keep_vec, const Term &f);
|
||||
|
||||
int SubtermTruth(hash_map<ast,int> &memo, const Term &);
|
||||
|
||||
void ImplicantRed(hash_map<ast,int> &memo, const Term &f, std::vector<Term> &lits,
|
||||
hash_set<ast> *done, bool truth, hash_set<ast> &dont_cares);
|
||||
|
||||
void Implicant(hash_map<ast,int> &memo, const Term &f, std::vector<Term> &lits, hash_set<ast> &dont_cares);
|
||||
|
||||
Term UnderapproxFormula(const Term &f, hash_set<ast> &dont_cares);
|
||||
|
||||
Term ToRuleRec(Edge *e, hash_map<ast,Term> &memo, const Term &t, std::vector<expr> &quants);
|
||||
|
||||
hash_map<ast,Term> resolve_ite_memo;
|
||||
|
||||
Term ResolveIte(hash_map<ast,int> &memo, const Term &t, std::vector<Term> &lits,
|
||||
hash_set<ast> *done, hash_set<ast> &dont_cares);
|
||||
|
||||
struct ArrayValue {
|
||||
bool defined;
|
||||
std::map<ast,ast> entries;
|
||||
expr def_val;
|
||||
};
|
||||
|
||||
void EvalArrayTerm(const Term &t, ArrayValue &res);
|
||||
|
||||
Term EvalArrayEquality(const Term &f);
|
||||
|
||||
Term ModelValueAsConstraint(const Term &t);
|
||||
|
||||
};
|
||||
|
||||
/** RPFP solver base class. */
|
||||
|
||||
class Solver {
|
||||
|
||||
public:
|
||||
|
||||
struct Counterexample {
|
||||
RPFP *tree;
|
||||
RPFP::Node *root;
|
||||
Counterexample(){
|
||||
tree = 0;
|
||||
root = 0;
|
||||
}
|
||||
};
|
||||
|
||||
/** Solve the problem. You can optionally give an old
|
||||
counterexample to use as a guide. This is chiefly useful for
|
||||
abstraction refinement metholdologies, and is only used as a
|
||||
heuristic. */
|
||||
|
||||
virtual bool Solve() = 0;
|
||||
|
||||
virtual Counterexample GetCounterexample() = 0;
|
||||
|
||||
virtual bool SetOption(const std::string &option, const std::string &value) = 0;
|
||||
|
||||
/** Learn heuristic information from another solver. This
|
||||
is chiefly useful for abstraction refinement, when we want to
|
||||
solve a series of similar problems. */
|
||||
|
||||
virtual void LearnFrom(Solver *old_solver) = 0;
|
||||
|
||||
virtual ~Solver(){}
|
||||
|
||||
static Solver *Create(const std::string &solver_class, RPFP *rpfp);
|
||||
|
||||
|
||||
};
|
||||
}
|
169
src/duality/duality_hash.h
Executable file
169
src/duality/duality_hash.h
Executable file
|
@ -0,0 +1,169 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
iz3hash.h
|
||||
|
||||
Abstract:
|
||||
|
||||
Wrapper for stl hash tables
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
--*/
|
||||
|
||||
// pull in the headers for has_map and hash_set
|
||||
// these live in non-standard places
|
||||
|
||||
#ifndef IZ3_HASH_H
|
||||
#define IZ3_HASH_H
|
||||
|
||||
//#define USE_UNORDERED_MAP
|
||||
#ifdef USE_UNORDERED_MAP
|
||||
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#define hash_map unordered_map
|
||||
#define hash_set unordered_set
|
||||
|
||||
#else
|
||||
|
||||
#if __GNUC__ >= 3
|
||||
#undef __DEPRECATED
|
||||
#define stl_ext __gnu_cxx
|
||||
#define hash_space stl_ext
|
||||
#include <ext/hash_map>
|
||||
#include <ext/hash_set>
|
||||
#else
|
||||
#ifdef WIN32
|
||||
#define stl_ext stdext
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#else
|
||||
#define stl_ext std
|
||||
#define hash_space std
|
||||
#include <hash_map>
|
||||
#include <hash_set>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
// stupid STL doesn't include hash function for class string
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<std::string> {
|
||||
stl_ext::hash<char *> H;
|
||||
public:
|
||||
size_t operator()(const std::string &s) const {
|
||||
return H(s.c_str());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <>
|
||||
class hash<std::pair<int,int> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<int,int> &p) const {
|
||||
return p.first + p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
template <> inline
|
||||
size_t stdext::hash_value<std::pair<int,int> >(const std::pair<int,int>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return p.first + p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace hash_space {
|
||||
template <class T>
|
||||
class hash<std::pair<T *, T *> > {
|
||||
public:
|
||||
size_t operator()(const std::pair<T *,T *> &p) const {
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <class T> inline
|
||||
size_t stdext::hash_value<std::pair<T *, T *> >(const std::pair<T *, T *>& p)
|
||||
{ // hash _Keyval to size_t value one-to-one
|
||||
return (size_t)p.first + (size_t)p.second;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
class less<std::pair<int,int> > {
|
||||
public:
|
||||
bool operator()(const pair<int,int> &x, const pair<int,int> &y) const {
|
||||
return x.first < y.first || x.first == y.first && x.second < y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace std {
|
||||
template <class T>
|
||||
class less<std::pair<T *,T *> > {
|
||||
public:
|
||||
bool operator()(const pair<T *,T *> &x, const pair<T *,T *> &y) const {
|
||||
return (size_t)x.first < (size_t)y.first || (size_t)x.first == (size_t)y.first && (size_t)x.second < (size_t)y.second;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
namespace stl_ext {
|
||||
template <class T>
|
||||
class hash<T *> {
|
||||
public:
|
||||
size_t operator()(const T *p) const {
|
||||
return (size_t) p;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
|
||||
|
||||
|
||||
template <class K, class T>
|
||||
class hash_map : public stl_ext::hash_map<K,T,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
template <class K>
|
||||
class hash_set : public stl_ext::hash_set<K,stl_ext::hash_compare<K,std::less<K> > > {};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
201
src/duality/duality_profiling.cpp
Executable file
201
src/duality/duality_profiling.cpp
Executable file
|
@ -0,0 +1,201 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_profiling.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
collection performance information for duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
// include "Windows.h"
|
||||
|
||||
|
||||
#if 0
|
||||
typedef __int64 clock_t;
|
||||
|
||||
static clock_t current_time(){
|
||||
LARGE_INTEGER lpPerformanceCount;
|
||||
lpPerformanceCount.QuadPart = 0;
|
||||
QueryPerformanceCounter(&lpPerformanceCount);
|
||||
return lpPerformanceCount.QuadPart;
|
||||
}
|
||||
|
||||
static void output_time(std::ostream &os, clock_t time){
|
||||
LARGE_INTEGER lpFrequency;
|
||||
lpFrequency.QuadPart = 1;
|
||||
QueryPerformanceFrequency(&lpFrequency);
|
||||
os << ((double)time)/lpFrequency.QuadPart;
|
||||
}
|
||||
#else
|
||||
|
||||
typedef double clock_t;
|
||||
|
||||
static clock_t current_time(){
|
||||
FILETIME lpCreationTime;
|
||||
FILETIME lpExitTime;
|
||||
FILETIME lpKernelTime;
|
||||
FILETIME lpUserTime;
|
||||
|
||||
GetProcessTimes( GetCurrentProcess(),
|
||||
&lpCreationTime, &lpExitTime, &lpKernelTime, &lpUserTime );
|
||||
|
||||
|
||||
double usr_time = ((double) lpUserTime.dwLowDateTime)/10000000. +
|
||||
((double) lpUserTime.dwHighDateTime)/(10000000. * pow(2.0,32.0));
|
||||
return usr_time;
|
||||
}
|
||||
|
||||
static void output_time(std::ostream &os, clock_t time){
|
||||
os << time;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/times.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
static clock_t current_time(){
|
||||
#if 0
|
||||
struct tms buf;
|
||||
times(&buf);
|
||||
return buf.tms_utime;
|
||||
#else
|
||||
struct rusage r;
|
||||
getrusage(RUSAGE_SELF, &r);
|
||||
return 1000 * r.ru_utime.tv_sec + r.ru_utime.tv_usec / 1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void output_time(std::ostream &os, clock_t time){
|
||||
#if 0
|
||||
os << ((double)time)/sysconf(_SC_CLK_TCK);
|
||||
#else
|
||||
os << ((double)time)/1000;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace Duality {
|
||||
|
||||
void show_time(){
|
||||
output_time(std::cout,current_time());
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
typedef std::map<const char*, struct node> nmap;
|
||||
|
||||
struct node {
|
||||
std::string name;
|
||||
clock_t time;
|
||||
clock_t start_time;
|
||||
nmap sub;
|
||||
struct node *parent;
|
||||
|
||||
node();
|
||||
} top;
|
||||
|
||||
node::node(){
|
||||
time = 0;
|
||||
parent = 0;
|
||||
}
|
||||
|
||||
struct node *current;
|
||||
|
||||
struct init {
|
||||
init(){
|
||||
top.name = "TOTAL";
|
||||
current = ⊤
|
||||
}
|
||||
} initializer;
|
||||
|
||||
struct time_entry {
|
||||
clock_t t;
|
||||
time_entry(){t = 0;};
|
||||
void add(clock_t incr){t += incr;}
|
||||
};
|
||||
|
||||
struct ltstr
|
||||
{
|
||||
bool operator()(const char* s1, const char* s2) const
|
||||
{
|
||||
return strcmp(s1, s2) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<const char*, time_entry, ltstr> tmap;
|
||||
|
||||
static std::ostream *pfs;
|
||||
|
||||
void print_node(node &top, int indent, tmap &totals){
|
||||
for(int i = 0; i < indent; i++) (*pfs) << " ";
|
||||
(*pfs) << top.name;
|
||||
int dots = 70 - 2 * indent - top.name.size();
|
||||
for(int i = 0; i <dots; i++) (*pfs) << ".";
|
||||
output_time(*pfs, top.time);
|
||||
(*pfs) << std::endl;
|
||||
if(indent != 0)totals[top.name.c_str()].add(top.time);
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
print_node(it->second,indent+1,totals);
|
||||
}
|
||||
|
||||
void print_profile(std::ostream &os) {
|
||||
pfs = &os;
|
||||
top.time = 0;
|
||||
for(nmap::iterator it = top.sub.begin(); it != top.sub.end(); it++)
|
||||
top.time += it->second.time;
|
||||
tmap totals;
|
||||
print_node(top,0,totals);
|
||||
(*pfs) << "TOTALS:" << std::endl;
|
||||
for(tmap::iterator it = totals.begin(); it != totals.end(); it++){
|
||||
(*pfs) << (it->first) << " ";
|
||||
output_time(*pfs, it->second.t);
|
||||
(*pfs) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void timer_start(const char *name){
|
||||
node &child = current->sub[name];
|
||||
if(child.name.empty()){ // a new node
|
||||
child.parent = current;
|
||||
child.name = name;
|
||||
}
|
||||
child.start_time = current_time();
|
||||
current = &child;
|
||||
}
|
||||
|
||||
void timer_stop(const char *name){
|
||||
if(current->name != name || !current->parent){
|
||||
std::cerr << "imbalanced timer_start and timer_stop";
|
||||
exit(1);
|
||||
}
|
||||
current->time += (current_time() - current->start_time);
|
||||
current = current->parent;
|
||||
}
|
||||
}
|
38
src/duality/duality_profiling.h
Executable file
38
src/duality/duality_profiling.h
Executable file
|
@ -0,0 +1,38 @@
|
|||
/*++
|
||||
Copyright (c) 2011 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
duality_profiling.h
|
||||
|
||||
Abstract:
|
||||
|
||||
collection performance information for duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#ifndef DUALITYPROFILING_H
|
||||
#define DUALITYPROFILING_H
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace Duality {
|
||||
/** Start a timer with given name */
|
||||
void timer_start(const char *);
|
||||
/** Stop a timer with given name */
|
||||
void timer_stop(const char *);
|
||||
/** Print out timings */
|
||||
void print_profile(std::ostream &s);
|
||||
/** Show the current time. */
|
||||
void show_time();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1991
src/duality/duality_rpfp.cpp
Normal file
1991
src/duality/duality_rpfp.cpp
Normal file
File diff suppressed because it is too large
Load diff
2200
src/duality/duality_solver.cpp
Normal file
2200
src/duality/duality_solver.cpp
Normal file
File diff suppressed because it is too large
Load diff
523
src/duality/duality_wrapper.cpp
Normal file
523
src/duality/duality_wrapper.cpp
Normal file
|
@ -0,0 +1,523 @@
|
|||
/*++
|
||||
Copyright (c) 2012 Microsoft Corporation
|
||||
|
||||
Module Name:
|
||||
|
||||
wrapper.cpp
|
||||
|
||||
Abstract:
|
||||
|
||||
wrap various objects in the style expected by duality
|
||||
|
||||
Author:
|
||||
|
||||
Ken McMillan (kenmcmil)
|
||||
|
||||
Revision History:
|
||||
|
||||
|
||||
--*/
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
#include <iostream>
|
||||
#include "smt_solver.h"
|
||||
#include "iz3interp.h"
|
||||
#include "statistics.h"
|
||||
#include "expr_abstract.h"
|
||||
|
||||
namespace Duality {
|
||||
|
||||
solver::solver(Duality::context& c) : object(c), the_model(c) {
|
||||
// TODO: the following is a HACK to enable proofs in the old smt solver
|
||||
// When we stop using that solver, this hack can be removed
|
||||
m().toggle_proof_mode(PGM_FINE);
|
||||
params_ref p;
|
||||
p.set_bool("proof", true); // this is currently useless
|
||||
p.set_bool("model", true);
|
||||
p.set_bool("unsat_core", true);
|
||||
scoped_ptr<solver_factory> sf = mk_smt_solver_factory();
|
||||
m_solver = (*sf)(m(), p, true, true, true, ::symbol::null);
|
||||
}
|
||||
|
||||
expr context::constant(const std::string &name, const sort &ty){
|
||||
symbol s = str_symbol(name.c_str());
|
||||
return cook(m().mk_const(m().mk_const_decl(s, ty)));
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, int n, ::expr **args){
|
||||
switch(op) {
|
||||
case True: return mki(m_basic_fid,OP_TRUE,n,args);
|
||||
case False: return mki(m_basic_fid,OP_FALSE,n,args);
|
||||
case Equal: return mki(m_basic_fid,OP_EQ,n,args);
|
||||
case Distinct: return mki(m_basic_fid,OP_DISTINCT,n,args);
|
||||
case Ite: return mki(m_basic_fid,OP_ITE,n,args);
|
||||
case And: return mki(m_basic_fid,OP_AND,n,args);
|
||||
case Or: return mki(m_basic_fid,OP_OR,n,args);
|
||||
case Iff: return mki(m_basic_fid,OP_IFF,n,args);
|
||||
case Xor: return mki(m_basic_fid,OP_XOR,n,args);
|
||||
case Not: return mki(m_basic_fid,OP_NOT,n,args);
|
||||
case Implies: return mki(m_basic_fid,OP_IMPLIES,n,args);
|
||||
case Oeq: return mki(m_basic_fid,OP_OEQ,n,args);
|
||||
case Interp: return mki(m_basic_fid,OP_INTERP,n,args);
|
||||
case Leq: return mki(m_arith_fid,OP_LE,n,args);
|
||||
case Geq: return mki(m_arith_fid,OP_GE,n,args);
|
||||
case Lt: return mki(m_arith_fid,OP_LT,n,args);
|
||||
case Gt: return mki(m_arith_fid,OP_GT,n,args);
|
||||
case Plus: return mki(m_arith_fid,OP_ADD,n,args);
|
||||
case Sub: return mki(m_arith_fid,OP_SUB,n,args);
|
||||
case Uminus: return mki(m_arith_fid,OP_UMINUS,n,args);
|
||||
case Times: return mki(m_arith_fid,OP_MUL,n,args);
|
||||
case Div: return mki(m_arith_fid,OP_DIV,n,args);
|
||||
case Idiv: return mki(m_arith_fid,OP_IDIV,n,args);
|
||||
case Rem: return mki(m_arith_fid,OP_REM,n,args);
|
||||
case Mod: return mki(m_arith_fid,OP_MOD,n,args);
|
||||
case Power: return mki(m_arith_fid,OP_POWER,n,args);
|
||||
case ToReal: return mki(m_arith_fid,OP_TO_REAL,n,args);
|
||||
case ToInt: return mki(m_arith_fid,OP_TO_INT,n,args);
|
||||
case IsInt: return mki(m_arith_fid,OP_IS_INT,n,args);
|
||||
case Store: return mki(m_array_fid,OP_STORE,n,args);
|
||||
case Select: return mki(m_array_fid,OP_SELECT,n,args);
|
||||
case ConstArray: return mki(m_array_fid,OP_CONST_ARRAY,n,args);
|
||||
case ArrayDefault: return mki(m_array_fid,OP_ARRAY_DEFAULT,n,args);
|
||||
case ArrayMap: return mki(m_array_fid,OP_ARRAY_MAP,n,args);
|
||||
case SetUnion: return mki(m_array_fid,OP_SET_UNION,n,args);
|
||||
case SetIntersect: return mki(m_array_fid,OP_SET_INTERSECT,n,args);
|
||||
case SetDifference: return mki(m_array_fid,OP_SET_DIFFERENCE,n,args);
|
||||
case SetComplement: return mki(m_array_fid,OP_SET_COMPLEMENT,n,args);
|
||||
case SetSubSet: return mki(m_array_fid,OP_SET_SUBSET,n,args);
|
||||
case AsArray: return mki(m_array_fid,OP_AS_ARRAY,n,args);
|
||||
default:
|
||||
assert(0);
|
||||
return expr(*this);
|
||||
}
|
||||
}
|
||||
|
||||
expr context::mki(family_id fid, ::decl_kind dk, int n, ::expr **args){
|
||||
return cook(m().mk_app(fid, dk, 0, 0, n, (::expr **)args));
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const std::vector<expr> &args){
|
||||
static std::vector< ::expr*> a(10);
|
||||
if(a.size() < args.size())
|
||||
a.resize(args.size());
|
||||
for(unsigned i = 0; i < args.size(); i++)
|
||||
a[i] = to_expr(args[i].raw());
|
||||
return make(op,args.size(), args.size() ? &a[0] : 0);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op){
|
||||
return make(op,0,0);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0){
|
||||
::expr *a = to_expr(arg0.raw());
|
||||
return make(op,1,&a);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0, const expr &arg1){
|
||||
::expr *args[2];
|
||||
args[0] = to_expr(arg0.raw());
|
||||
args[1] = to_expr(arg1.raw());
|
||||
return make(op,2,args);
|
||||
}
|
||||
|
||||
expr context::make(decl_kind op, const expr &arg0, const expr &arg1, const expr &arg2){
|
||||
::expr *args[3];
|
||||
args[0] = to_expr(arg0.raw());
|
||||
args[1] = to_expr(arg1.raw());
|
||||
args[2] = to_expr(arg2.raw());
|
||||
return make(op,3,args);
|
||||
}
|
||||
|
||||
expr context::make_quant(decl_kind op, const std::vector<expr> &bvs, const expr &body){
|
||||
if(bvs.size() == 0) return body;
|
||||
std::vector< ::expr *> foo(bvs.size());
|
||||
|
||||
|
||||
std::vector< ::symbol> names;
|
||||
std::vector< ::sort *> types;
|
||||
std::vector< ::expr *> bound_asts;
|
||||
unsigned num_bound = bvs.size();
|
||||
|
||||
for (unsigned i = 0; i < num_bound; ++i) {
|
||||
app* a = to_app(bvs[i].raw());
|
||||
::symbol s(to_app(a)->get_decl()->get_name());
|
||||
names.push_back(s);
|
||||
types.push_back(m().get_sort(a));
|
||||
bound_asts.push_back(a);
|
||||
}
|
||||
expr_ref abs_body(m());
|
||||
expr_abstract(m(), 0, num_bound, &bound_asts[0], to_expr(body.raw()), abs_body);
|
||||
expr_ref result(m());
|
||||
result = m().mk_quantifier(
|
||||
op == Forall,
|
||||
names.size(), &types[0], &names[0], abs_body.get(),
|
||||
0,
|
||||
::symbol(),
|
||||
::symbol(),
|
||||
0, 0,
|
||||
0, 0
|
||||
);
|
||||
return cook(result.get());
|
||||
}
|
||||
|
||||
decl_kind func_decl::get_decl_kind() const {
|
||||
return ctx().get_decl_kind(*this);
|
||||
}
|
||||
|
||||
decl_kind context::get_decl_kind(const func_decl &t){
|
||||
::func_decl *d = to_func_decl(t.raw());
|
||||
if (null_family_id == d->get_family_id())
|
||||
return Uninterpreted;
|
||||
// return (opr)d->get_decl_kind();
|
||||
if (m_basic_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_TRUE: return True;
|
||||
case OP_FALSE: return False;
|
||||
case OP_EQ: return Equal;
|
||||
case OP_DISTINCT: return Distinct;
|
||||
case OP_ITE: return Ite;
|
||||
case OP_AND: return And;
|
||||
case OP_OR: return Or;
|
||||
case OP_IFF: return Iff;
|
||||
case OP_XOR: return Xor;
|
||||
case OP_NOT: return Not;
|
||||
case OP_IMPLIES: return Implies;
|
||||
case OP_OEQ: return Oeq;
|
||||
case OP_INTERP: return Interp;
|
||||
default:
|
||||
return OtherBasic;
|
||||
}
|
||||
}
|
||||
if (m_arith_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_LE: return Leq;
|
||||
case OP_GE: return Geq;
|
||||
case OP_LT: return Lt;
|
||||
case OP_GT: return Gt;
|
||||
case OP_ADD: return Plus;
|
||||
case OP_SUB: return Sub;
|
||||
case OP_UMINUS: return Uminus;
|
||||
case OP_MUL: return Times;
|
||||
case OP_DIV: return Div;
|
||||
case OP_IDIV: return Idiv;
|
||||
case OP_REM: return Rem;
|
||||
case OP_MOD: return Mod;
|
||||
case OP_POWER: return Power;
|
||||
case OP_TO_REAL: return ToReal;
|
||||
case OP_TO_INT: return ToInt;
|
||||
case OP_IS_INT: return IsInt;
|
||||
default:
|
||||
return OtherArith;
|
||||
}
|
||||
}
|
||||
if (m_array_fid == d->get_family_id()) {
|
||||
switch(d->get_decl_kind()) {
|
||||
case OP_STORE: return Store;
|
||||
case OP_SELECT: return Select;
|
||||
case OP_CONST_ARRAY: return ConstArray;
|
||||
case OP_ARRAY_DEFAULT: return ArrayDefault;
|
||||
case OP_ARRAY_MAP: return ArrayMap;
|
||||
case OP_SET_UNION: return SetUnion;
|
||||
case OP_SET_INTERSECT: return SetIntersect;
|
||||
case OP_SET_DIFFERENCE: return SetDifference;
|
||||
case OP_SET_COMPLEMENT: return SetComplement;
|
||||
case OP_SET_SUBSET: return SetSubSet;
|
||||
case OP_AS_ARRAY: return AsArray;
|
||||
default:
|
||||
return OtherArray;
|
||||
}
|
||||
}
|
||||
|
||||
return Other;
|
||||
}
|
||||
|
||||
|
||||
sort_kind context::get_sort_kind(const sort &s){
|
||||
family_id fid = to_sort(s.raw())->get_family_id();
|
||||
::decl_kind k = to_sort(s.raw())->get_decl_kind();
|
||||
if (m().is_uninterp(to_sort(s.raw()))) {
|
||||
return UninterpretedSort;
|
||||
}
|
||||
else if (fid == m_basic_fid && k == BOOL_SORT) {
|
||||
return BoolSort;
|
||||
}
|
||||
else if (fid == m_arith_fid && k == INT_SORT) {
|
||||
return IntSort;
|
||||
}
|
||||
else if (fid == m_arith_fid && k == REAL_SORT) {
|
||||
return RealSort;
|
||||
}
|
||||
else if (fid == m_array_fid && k == ARRAY_SORT) {
|
||||
return ArraySort;
|
||||
}
|
||||
else {
|
||||
return UnknownSort;
|
||||
}
|
||||
}
|
||||
|
||||
expr func_decl::operator()(unsigned n, expr const * args) const {
|
||||
std::vector< ::expr *> _args(n);
|
||||
for(unsigned i = 0; i < n; i++)
|
||||
_args[i] = to_expr(args[i].raw());
|
||||
return ctx().cook(m().mk_app(to_func_decl(raw()),n,&_args[0]));
|
||||
}
|
||||
|
||||
int solver::get_num_decisions(){
|
||||
::statistics st;
|
||||
m_solver->collect_statistics(st);
|
||||
std::ostringstream ss;
|
||||
st.display(ss);
|
||||
std::string stats = ss.str();
|
||||
int pos = stats.find("decisions:");
|
||||
pos += 10;
|
||||
int end = stats.find('\n',pos);
|
||||
std::string val = stats.substr(pos,end-pos);
|
||||
return atoi(val.c_str());
|
||||
}
|
||||
|
||||
void context::print_expr(std::ostream &s, const ast &e){
|
||||
s << mk_pp(e.raw(), m());
|
||||
}
|
||||
|
||||
|
||||
expr expr::simplify(const params &_p) const {
|
||||
::expr * a = to_expr(raw());
|
||||
params_ref p = _p.get();
|
||||
th_rewriter m_rw(m(), p);
|
||||
expr_ref result(m());
|
||||
m_rw(a, result);
|
||||
return ctx().cook(result);
|
||||
}
|
||||
|
||||
expr expr::simplify() const {
|
||||
params p;
|
||||
return simplify(p);
|
||||
}
|
||||
|
||||
expr clone_quantifier(const expr &q, const expr &b){
|
||||
return q.ctx().cook(q.m().update_quantifier(to_quantifier(q.raw()), to_expr(b.raw())));
|
||||
}
|
||||
|
||||
func_decl context::fresh_func_decl(char const * prefix, const std::vector<sort> &domain, sort const & range){
|
||||
std::vector < ::sort * > _domain(domain.size());
|
||||
for(unsigned i = 0; i < domain.size(); i++)
|
||||
_domain[i] = to_sort(domain[i].raw());
|
||||
::func_decl* d = m().mk_fresh_func_decl(prefix,
|
||||
_domain.size(),
|
||||
&_domain[0],
|
||||
to_sort(range.raw()));
|
||||
return func_decl(*this,d);
|
||||
}
|
||||
|
||||
func_decl context::fresh_func_decl(char const * prefix, sort const & range){
|
||||
::func_decl* d = m().mk_fresh_func_decl(prefix,
|
||||
0,
|
||||
0,
|
||||
to_sort(range.raw()));
|
||||
return func_decl(*this,d);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
|
||||
|
||||
lbool interpolating_solver::interpolate(
|
||||
const std::vector<expr> &assumptions,
|
||||
std::vector<expr> &interpolants,
|
||||
model &model,
|
||||
Z3_literals &labels,
|
||||
bool incremental)
|
||||
{
|
||||
Z3_model _model = 0;
|
||||
Z3_literals _labels = 0;
|
||||
Z3_lbool lb;
|
||||
std::vector<Z3_ast> _assumptions(assumptions.size());
|
||||
std::vector<Z3_ast> _interpolants(assumptions.size()-1);
|
||||
for(unsigned i = 0; i < assumptions.size(); i++)
|
||||
_assumptions[i] = assumptions[i];
|
||||
std::vector<Z3_ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = theory[i];
|
||||
|
||||
lb = Z3_interpolate(
|
||||
ctx(),
|
||||
_assumptions.size(),
|
||||
&_assumptions[0],
|
||||
0,
|
||||
0,
|
||||
&_interpolants[0],
|
||||
&_model,
|
||||
&_labels,
|
||||
incremental,
|
||||
_theory.size(),
|
||||
&_theory[0]
|
||||
);
|
||||
|
||||
if(lb == Z3_L_FALSE){
|
||||
interpolants.resize(_interpolants.size());
|
||||
for (unsigned i = 0; i < _interpolants.size(); ++i) {
|
||||
interpolants[i] = expr(ctx(),_interpolants[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
model = iz3wrapper::model(ctx(), _model);
|
||||
}
|
||||
|
||||
if(_labels){
|
||||
labels = _labels;
|
||||
}
|
||||
|
||||
return lb;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static int linearize_assumptions(int num,
|
||||
TermTree *assumptions,
|
||||
std::vector<expr> &linear_assumptions,
|
||||
std::vector<int> &parents){
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
num = linearize_assumptions(num, assumptions->getChildren()[i], linear_assumptions, parents);
|
||||
linear_assumptions[num] = assumptions->getTerm();
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
parents[assumptions->getChildren()[i]->getNumber()] = num;
|
||||
parents[num] = SHRT_MAX; // in case we have no parent
|
||||
linear_assumptions[num] = assumptions->getTerm();
|
||||
return num + 1;
|
||||
}
|
||||
|
||||
static int unlinearize_interpolants(int num,
|
||||
TermTree* assumptions,
|
||||
const std::vector<expr> &interpolant,
|
||||
TermTree * &tree_interpolant)
|
||||
{
|
||||
std::vector<TermTree *> chs(assumptions->getChildren().size());
|
||||
for(unsigned i = 0; i < assumptions->getChildren().size(); i++)
|
||||
num = unlinearize_interpolants(num, assumptions->getChildren()[i], interpolant,chs[i]);
|
||||
expr f;
|
||||
if(num < (int)interpolant.size()) // last interpolant is missing, presumed false
|
||||
f = interpolant[num];
|
||||
tree_interpolant = new TermTree(f,chs);
|
||||
return num + 1;
|
||||
}
|
||||
|
||||
|
||||
lbool interpolating_solver::interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolant,
|
||||
model &model,
|
||||
literals &labels,
|
||||
bool incremental
|
||||
)
|
||||
|
||||
{
|
||||
int size = assumptions->number(0);
|
||||
std::vector<expr> linear_assumptions(size);
|
||||
std::vector<int> parents(size);
|
||||
linearize_assumptions(0,assumptions,linear_assumptions,parents);
|
||||
|
||||
ptr_vector< ::ast> _interpolants(size-1);
|
||||
ptr_vector< ::ast>_assumptions(size);
|
||||
for(int i = 0; i < size; i++)
|
||||
_assumptions[i] = linear_assumptions[i];
|
||||
::vector<int> _parents(parents.size());
|
||||
for(unsigned i = 0; i < parents.size(); i++)
|
||||
_parents[i] = parents[i];
|
||||
ptr_vector< ::ast> _theory(theory.size());
|
||||
for(unsigned i = 0; i < theory.size(); i++)
|
||||
_theory[i] = theory[i];
|
||||
|
||||
push();
|
||||
|
||||
if(!incremental){
|
||||
for(unsigned i = 0; i < linear_assumptions.size(); i++)
|
||||
add(linear_assumptions[i]);
|
||||
}
|
||||
|
||||
check_result res = check();
|
||||
|
||||
if(res == unsat){
|
||||
|
||||
// TODO
|
||||
#if 0
|
||||
if(weak_mode)
|
||||
Z3_set_interpolation_option(options,"weak","1");
|
||||
#endif
|
||||
|
||||
::ast *proof = m_solver->get_proof();
|
||||
iz3interpolate(m(),proof,_assumptions,_parents,_interpolants,_theory,0);
|
||||
|
||||
std::vector<expr> linearized_interpolants(_interpolants.size());
|
||||
for(unsigned i = 0; i < _interpolants.size(); i++)
|
||||
linearized_interpolants[i] = expr(ctx(),_interpolants[i]);
|
||||
|
||||
unlinearize_interpolants(0,assumptions,linearized_interpolants,interpolant);
|
||||
interpolant->setTerm(ctx().bool_val(false));
|
||||
}
|
||||
|
||||
model_ref _m;
|
||||
m_solver->get_model(_m);
|
||||
model = Duality::model(ctx(),_m.get());
|
||||
|
||||
#if 0
|
||||
if(_labels){
|
||||
labels = _labels;
|
||||
}
|
||||
#endif
|
||||
|
||||
pop();
|
||||
|
||||
return (res == unsat) ? l_false : ((res == sat) ? l_true : l_undef);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::SetWeakInterpolants(bool weak){
|
||||
weak_mode = weak;
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::SetPrintToFile(const std::string &filename){
|
||||
print_filename = filename;
|
||||
}
|
||||
|
||||
void interpolating_solver::AssertInterpolationAxiom(const expr & t){
|
||||
add(t);
|
||||
theory.push_back(t);
|
||||
}
|
||||
|
||||
|
||||
void interpolating_solver::RemoveInterpolationAxiom(const expr & t){
|
||||
// theory.remove(t);
|
||||
}
|
||||
|
||||
|
||||
const char *interpolating_solver::profile(){
|
||||
// return Z3_interpolation_profile(ctx());
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
void ast::show() const{
|
||||
std::cout << mk_pp(raw(), m()) << std::endl;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void model::show() const {
|
||||
std::cout << Z3_model_to_string(ctx(), m_model) << std::endl;
|
||||
}
|
||||
|
||||
Z3_ast ast_to_track = 0;
|
||||
#endif
|
||||
|
||||
void include_ast_show(ast &a){
|
||||
a.show();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
1343
src/duality/duality_wrapper.h
Executable file
1343
src/duality/duality_wrapper.h
Executable file
File diff suppressed because it is too large
Load diff
|
@ -110,6 +110,7 @@ class ast_r : public ast_i {
|
|||
_m->dec_ref(_ast);
|
||||
}
|
||||
|
||||
ast_manager *mgr() const {return _m;}
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -731,6 +731,10 @@ namespace datalog {
|
|||
check_existential_tail(r);
|
||||
check_positive_predicates(r);
|
||||
break;
|
||||
case DUALITY_ENGINE:
|
||||
check_existential_tail(r);
|
||||
check_positive_predicates(r);
|
||||
break;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
break;
|
||||
|
@ -989,6 +993,9 @@ namespace datalog {
|
|||
else if (e == symbol("tab")) {
|
||||
m_engine = TAB_ENGINE;
|
||||
}
|
||||
else if (e == symbol("duality")) {
|
||||
m_engine = DUALITY_ENGINE;
|
||||
}
|
||||
|
||||
if (m_engine == LAST_ENGINE) {
|
||||
expr_fast_mark1 mark;
|
||||
|
@ -1024,6 +1031,8 @@ namespace datalog {
|
|||
return bmc_query(query);
|
||||
case TAB_ENGINE:
|
||||
return tab_query(query);
|
||||
case DUALITY_ENGINE:
|
||||
return duality_query(query);
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return rel_query(query);
|
||||
|
@ -1042,6 +1051,9 @@ namespace datalog {
|
|||
case QPDR_ENGINE:
|
||||
ensure_pdr();
|
||||
return m_pdr->get_model();
|
||||
case DUALITY_ENGINE:
|
||||
ensure_duality();
|
||||
return m_duality->get_model();
|
||||
default:
|
||||
return model_ref(alloc(model, m));
|
||||
}
|
||||
|
@ -1053,6 +1065,9 @@ namespace datalog {
|
|||
case QPDR_ENGINE:
|
||||
ensure_pdr();
|
||||
return m_pdr->get_proof();
|
||||
case DUALITY_ENGINE:
|
||||
ensure_duality();
|
||||
return m_duality->get_proof();
|
||||
default:
|
||||
return proof_ref(m.mk_asserted(m.mk_true()), m);
|
||||
}
|
||||
|
@ -1064,11 +1079,22 @@ namespace datalog {
|
|||
}
|
||||
}
|
||||
|
||||
void context::ensure_duality() {
|
||||
if (!m_duality.get()) {
|
||||
m_duality = alloc(Duality::dl_interface, *this);
|
||||
}
|
||||
}
|
||||
|
||||
lbool context::pdr_query(expr* query) {
|
||||
ensure_pdr();
|
||||
return m_pdr->query(query);
|
||||
}
|
||||
|
||||
lbool context::duality_query(expr* query) {
|
||||
ensure_duality();
|
||||
return m_duality->query(query);
|
||||
}
|
||||
|
||||
void context::ensure_bmc() {
|
||||
if (!m_bmc.get()) {
|
||||
m_bmc = alloc(bmc, *this);
|
||||
|
@ -1131,6 +1157,10 @@ namespace datalog {
|
|||
ensure_tab();
|
||||
m_last_answer = m_tab->get_answer();
|
||||
return m_last_answer.get();
|
||||
case DUALITY_ENGINE:
|
||||
ensure_duality();
|
||||
m_last_answer = m_duality->get_answer();
|
||||
return m_last_answer.get();
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -1155,6 +1185,8 @@ namespace datalog {
|
|||
ensure_tab();
|
||||
m_tab->display_certificate(out);
|
||||
return true;
|
||||
case DUALITY_ENGINE:
|
||||
return false;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -36,6 +36,7 @@ Revision History:
|
|||
#include"pdr_dl_interface.h"
|
||||
#include"dl_bmc_engine.h"
|
||||
#include"tab_context.h"
|
||||
#include"duality_dl_interface.h"
|
||||
#include"rel_context.h"
|
||||
#include"lbool.h"
|
||||
#include"statistics.h"
|
||||
|
@ -102,6 +103,7 @@ namespace datalog {
|
|||
scoped_ptr<bmc> m_bmc;
|
||||
scoped_ptr<rel_context> m_rel;
|
||||
scoped_ptr<tab> m_tab;
|
||||
scoped_ptr<Duality::dl_interface> m_duality;
|
||||
|
||||
bool m_closed;
|
||||
bool m_saturation_was_run;
|
||||
|
@ -373,14 +375,16 @@ namespace datalog {
|
|||
/**
|
||||
\brief retrieve model from inductive invariant that shows query is unsat.
|
||||
|
||||
\pre engine == 'pdr' - this option is only supported for PDR mode.
|
||||
\pre engine == 'pdr' || engine == 'duality' - this option is only supported
|
||||
for PDR mode and Duality mode.
|
||||
*/
|
||||
model_ref get_model();
|
||||
|
||||
/**
|
||||
\brief retrieve proof from derivation of the query.
|
||||
|
||||
\pre engine == 'pdr' - this option is only supported for PDR mode.
|
||||
\pre engine == 'pdr' || engine == 'duality'- this option is only supported
|
||||
for PDR mode and Duality mode.
|
||||
*/
|
||||
proof_ref get_proof();
|
||||
|
||||
|
@ -438,6 +442,8 @@ namespace datalog {
|
|||
|
||||
void ensure_tab();
|
||||
|
||||
void ensure_duality();
|
||||
|
||||
void ensure_rel();
|
||||
|
||||
void new_query();
|
||||
|
@ -450,6 +456,8 @@ namespace datalog {
|
|||
|
||||
lbool tab_query(expr* query);
|
||||
|
||||
lbool duality_query(expr* query);
|
||||
|
||||
void check_quantifier_free(rule_ref& r);
|
||||
void check_uninterpreted_free(rule_ref& r);
|
||||
void check_existential_tail(rule_ref& r);
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace datalog {
|
|||
BMC_ENGINE,
|
||||
QBMC_ENGINE,
|
||||
TAB_ENGINE,
|
||||
DUALITY_ENGINE,
|
||||
LAST_ENGINE
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue