mirror of
https://github.com/Z3Prover/z3
synced 2025-04-07 18:05:21 +00:00
Merge branch 'opt' of https://git01.codeplex.com/z3 into opt
This commit is contained in:
commit
596796f7ef
|
@ -17,6 +17,7 @@ Revision History:
|
|||
--*/
|
||||
#include<iostream>
|
||||
#include<sstream>
|
||||
#include<vector>
|
||||
#include"z3.h"
|
||||
#include"api_log_macros.h"
|
||||
#include"api_context.h"
|
||||
|
|
|
@ -114,7 +114,7 @@ static void get_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_
|
|||
|
||||
ptr_vector<expr>::const_iterator it = ctx.begin_assertions();
|
||||
ptr_vector<expr>::const_iterator end = ctx.end_assertions();
|
||||
ptr_vector<ast> cnsts(end - it);
|
||||
ptr_vector<ast> cnsts((unsigned)(end - it));
|
||||
for (int i = 0; it != end; ++it, ++i)
|
||||
cnsts[i] = *it;
|
||||
|
||||
|
@ -139,10 +139,11 @@ static void get_interpolant(cmd_context & ctx, expr * t, params_ref &m_params) {
|
|||
get_interpolant_and_maybe_check(ctx,t,m_params,false);
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void get_and_check_interpolant(cmd_context & ctx, params_ref &m_params, expr * t) {
|
||||
get_interpolant_and_maybe_check(ctx,t,m_params,true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void compute_interpolant_and_maybe_check(cmd_context & ctx, expr * t, params_ref &m_params, bool check){
|
||||
|
||||
|
|
|
@ -36,12 +36,11 @@ namespace Duality {
|
|||
struct Z3User {
|
||||
|
||||
context &ctx;
|
||||
solver &slvr;
|
||||
|
||||
typedef func_decl FuncDecl;
|
||||
typedef expr Term;
|
||||
|
||||
Z3User(context &_ctx, solver &_slvr) : ctx(_ctx), slvr(_slvr){}
|
||||
Z3User(context &_ctx) : ctx(_ctx){}
|
||||
|
||||
const char *string_of_int(int n);
|
||||
|
||||
|
@ -53,6 +52,8 @@ namespace Duality {
|
|||
|
||||
Term SubstRec(hash_map<ast, Term> &memo, const Term &t);
|
||||
|
||||
Term SubstRec(hash_map<ast, Term> &memo, hash_map<func_decl, func_decl> &map, const Term &t);
|
||||
|
||||
void Strengthen(Term &x, const Term &y);
|
||||
|
||||
// return the func_del of an app if it is uninterpreted
|
||||
|
@ -77,14 +78,14 @@ namespace Duality {
|
|||
|
||||
void Summarize(const Term &t);
|
||||
|
||||
int CumulativeDecisions();
|
||||
|
||||
int CountOperators(const Term &t);
|
||||
|
||||
Term SubstAtom(hash_map<ast, Term> &memo, const expr &t, const expr &atom, const expr &val);
|
||||
|
||||
Term RemoveRedundancy(const Term &t);
|
||||
|
||||
Term IneqToEq(const Term &t);
|
||||
|
||||
bool IsLiteral(const expr &lit, expr &atom, expr &val);
|
||||
|
||||
expr Negate(const expr &f);
|
||||
|
@ -98,7 +99,10 @@ namespace Duality {
|
|||
bool IsClosedFormula(const Term &t);
|
||||
|
||||
Term AdjustQuantifiers(const Term &t);
|
||||
private:
|
||||
|
||||
FuncDecl RenumberPred(const FuncDecl &f, int n);
|
||||
|
||||
protected:
|
||||
|
||||
void SummarizeRec(hash_set<ast> &memo, std::vector<expr> &lits, int &ops, const Term &t);
|
||||
int CountOperatorsRec(hash_set<ast> &memo, const Term &t);
|
||||
|
@ -108,6 +112,7 @@ private:
|
|||
expr ReduceAndOr(const std::vector<expr> &args, bool is_and, std::vector<expr> &res);
|
||||
expr FinishAndOr(const std::vector<expr> &args, bool is_and);
|
||||
expr PullCommonFactors(std::vector<expr> &args, bool is_and);
|
||||
Term IneqToEqRec(hash_map<ast, Term> &memo, const Term &t);
|
||||
|
||||
|
||||
};
|
||||
|
@ -256,9 +261,9 @@ private:
|
|||
}
|
||||
#endif
|
||||
|
||||
iZ3LogicSolver(context &c) : LogicSolver(c) {
|
||||
iZ3LogicSolver(context &c, bool models = true) : LogicSolver(c) {
|
||||
ctx = ictx = &c;
|
||||
slvr = islvr = new interpolating_solver(*ictx);
|
||||
slvr = islvr = new interpolating_solver(*ictx, models);
|
||||
need_goals = false;
|
||||
islvr->SetWeakInterpolants(true);
|
||||
}
|
||||
|
@ -308,8 +313,8 @@ private:
|
|||
}
|
||||
|
||||
LogicSolver *ls;
|
||||
|
||||
private:
|
||||
|
||||
protected:
|
||||
int nodeCount;
|
||||
int edgeCount;
|
||||
|
||||
|
@ -324,7 +329,7 @@ private:
|
|||
|
||||
public:
|
||||
model dualModel;
|
||||
private:
|
||||
protected:
|
||||
literals dualLabels;
|
||||
std::list<stack_entry> stack;
|
||||
std::vector<Term> axioms; // only saved here for printing purposes
|
||||
|
@ -340,7 +345,7 @@ private:
|
|||
inherit the axioms.
|
||||
*/
|
||||
|
||||
RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx), *(_ls->slvr)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver)
|
||||
RPFP(LogicSolver *_ls) : Z3User(*(_ls->ctx)), dualModel(*(_ls->ctx)), aux_solver(_ls->aux_solver)
|
||||
{
|
||||
ls = _ls;
|
||||
nodeCount = 0;
|
||||
|
@ -350,7 +355,7 @@ private:
|
|||
proof_core = 0;
|
||||
}
|
||||
|
||||
~RPFP();
|
||||
virtual ~RPFP();
|
||||
|
||||
/** Symbolic representation of a relational transformer */
|
||||
class Transformer
|
||||
|
@ -574,7 +579,7 @@ private:
|
|||
* 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);
|
||||
virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false);
|
||||
|
||||
/* Constrain an edge by the annotation of one of its children. */
|
||||
|
||||
|
@ -808,9 +813,31 @@ private:
|
|||
/** Edges of the graph. */
|
||||
std::vector<Edge *> edges;
|
||||
|
||||
/** Fuse a vector of transformers. If the total number of inputs of the transformers
|
||||
is N, then the result is an N-ary transfomer whose output is the union of
|
||||
the outputs of the given transformers. The is, suppose we have a vetor of transfoermers
|
||||
{T_i(r_i1,...,r_iN(i) : i=1..M}. The the result is a transformer
|
||||
|
||||
F(r_11,...,r_iN(1),...,r_M1,...,r_MN(M)) =
|
||||
T_1(r_11,...,r_iN(1)) U ... U T_M(r_M1,...,r_MN(M))
|
||||
*/
|
||||
|
||||
Transformer Fuse(const std::vector<Transformer *> &trs);
|
||||
|
||||
/** Fuse edges so that each node is the output of at most one edge. This
|
||||
transformation is solution-preserving, but changes the numbering of edges in
|
||||
counterexamples.
|
||||
*/
|
||||
void FuseEdges();
|
||||
|
||||
void RemoveDeadNodes();
|
||||
|
||||
Term SubstParams(const std::vector<Term> &from,
|
||||
const std::vector<Term> &to, const Term &t);
|
||||
|
||||
Term SubstParamsNoCapture(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);
|
||||
|
@ -829,7 +856,13 @@ private:
|
|||
*/
|
||||
void ComputeProofCore();
|
||||
|
||||
private:
|
||||
int CumulativeDecisions();
|
||||
|
||||
solver &slvr(){
|
||||
return *ls->slvr;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void ClearProofCore(){
|
||||
if(proof_core)
|
||||
|
@ -947,6 +980,8 @@ private:
|
|||
|
||||
expr SimplifyOr(std::vector<expr> &lits);
|
||||
|
||||
expr SimplifyAnd(std::vector<expr> &lits);
|
||||
|
||||
void SetAnnotation(Node *root, const expr &t);
|
||||
|
||||
void AddEdgeToSolver(Edge *edge);
|
||||
|
@ -959,9 +994,58 @@ private:
|
|||
|
||||
expr NegateLit(const expr &f);
|
||||
|
||||
expr GetEdgeFormula(Edge *e, int persist, bool with_children, bool underapprox);
|
||||
|
||||
bool IsVar(const expr &t);
|
||||
|
||||
void GetVarsRec(hash_set<ast> &memo, const expr &cnst, std::vector<expr> &vars);
|
||||
|
||||
expr UnhoistPullRec(hash_map<ast,expr> & memo, const expr &w, hash_map<ast,expr> & init_defs, hash_map<ast,expr> & const_params, hash_map<ast,expr> &const_params_inv, std::vector<expr> &new_params);
|
||||
|
||||
void AddParamsToTransformer(Transformer &trans, const std::vector<expr> ¶ms);
|
||||
|
||||
expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector<expr> ¶ms);
|
||||
|
||||
expr GetRelRec(hash_set<ast> &memo, const expr &t, const func_decl &rel);
|
||||
|
||||
expr GetRel(Edge *edge, int child_idx);
|
||||
|
||||
void GetDefs(const expr &cnst, hash_map<ast,expr> &defs);
|
||||
|
||||
void GetDefsRec(const expr &cnst, hash_map<ast,expr> &defs);
|
||||
|
||||
void AddParamsToNode(Node *node, const std::vector<expr> ¶ms);
|
||||
|
||||
void UnhoistLoop(Edge *loop_edge, Edge *init_edge);
|
||||
|
||||
void Unhoist();
|
||||
|
||||
Term ElimIteRec(hash_map<ast,expr> &memo, const Term &t, std::vector<expr> &cnsts);
|
||||
|
||||
Term ElimIte(const Term &t);
|
||||
|
||||
void MarkLiveNodes(hash_map<Node *,std::vector<Edge *> > &outgoing, hash_set<Node *> &live_nodes, Node *node);
|
||||
|
||||
virtual void slvr_add(const expr &e);
|
||||
|
||||
virtual void slvr_pop(int i);
|
||||
|
||||
virtual void slvr_push();
|
||||
|
||||
virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0);
|
||||
|
||||
virtual lbool ls_interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolants,
|
||||
model &_model,
|
||||
TermTree *goals = 0,
|
||||
bool weak = false);
|
||||
|
||||
virtual bool proof_core_contains(const expr &e);
|
||||
|
||||
};
|
||||
|
||||
/** RPFP solver base class. */
|
||||
|
||||
/** RPFP solver base class. */
|
||||
|
||||
class Solver {
|
||||
|
||||
|
@ -1005,6 +1089,8 @@ private:
|
|||
/** Object thrown on cancellation */
|
||||
struct Canceled {};
|
||||
|
||||
/** Object thrown on incompleteness */
|
||||
struct Incompleteness {};
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -1042,3 +1128,130 @@ namespace std {
|
|||
}
|
||||
};
|
||||
}
|
||||
|
||||
// #define LIMIT_STACK_WEIGHT 5
|
||||
|
||||
|
||||
namespace Duality {
|
||||
/** Caching version of RPFP. Instead of asserting constraints, returns assumption literals */
|
||||
|
||||
class RPFP_caching : public RPFP {
|
||||
public:
|
||||
|
||||
/** appends assumption literals for edge to lits. if with_children is true,
|
||||
includes that annotation of the edge's children.
|
||||
*/
|
||||
void AssertEdgeCache(Edge *e, std::vector<Term> &lits, bool with_children = false);
|
||||
|
||||
/** appends assumption literals for node to lits */
|
||||
void AssertNodeCache(Node *, std::vector<Term> lits);
|
||||
|
||||
/** check assumption lits, and return core */
|
||||
check_result CheckCore(const std::vector<Term> &assumps, std::vector<Term> &core);
|
||||
|
||||
/** Clone another RPFP into this one, keeping a map */
|
||||
void Clone(RPFP *other);
|
||||
|
||||
/** Get the clone of a node */
|
||||
Node *GetNodeClone(Node *other_node);
|
||||
|
||||
/** Get the clone of an edge */
|
||||
Edge *GetEdgeClone(Edge *other_edge);
|
||||
|
||||
/** Try to strengthen the parent of an edge */
|
||||
void GeneralizeCache(Edge *edge);
|
||||
|
||||
/** Try to propagate some facts from children to parents of edge.
|
||||
Return true if success. */
|
||||
bool PropagateCache(Edge *edge);
|
||||
|
||||
/** Construct a caching RPFP using a LogicSolver */
|
||||
RPFP_caching(LogicSolver *_ls) : RPFP(_ls) {}
|
||||
|
||||
/** Constraint an edge by its child's annotation. Return
|
||||
assumption lits. */
|
||||
void ConstrainParentCache(Edge *parent, Node *child, std::vector<Term> &lits);
|
||||
|
||||
#ifdef LIMIT_STACK_WEIGHT
|
||||
virtual void AssertEdge(Edge *e, int persist = 0, bool with_children = false, bool underapprox = false);
|
||||
#endif
|
||||
|
||||
virtual ~RPFP_caching(){}
|
||||
|
||||
protected:
|
||||
hash_map<ast,expr> AssumptionLits;
|
||||
hash_map<Node *, Node *> NodeCloneMap;
|
||||
hash_map<Edge *, Edge *> EdgeCloneMap;
|
||||
std::vector<expr> alit_stack;
|
||||
std::vector<unsigned> alit_stack_sizes;
|
||||
hash_map<Edge *, uptr<LogicSolver> > edge_solvers;
|
||||
|
||||
#ifdef LIMIT_STACK_WEIGHT
|
||||
struct weight_counter {
|
||||
int val;
|
||||
weight_counter(){val = 0;}
|
||||
void swap(weight_counter &other){
|
||||
std::swap(val,other.val);
|
||||
}
|
||||
};
|
||||
|
||||
struct big_stack_entry {
|
||||
weight_counter weight_added;
|
||||
std::vector<expr> new_alits;
|
||||
std::vector<expr> alit_stack;
|
||||
std::vector<unsigned> alit_stack_sizes;
|
||||
};
|
||||
|
||||
std::vector<expr> new_alits;
|
||||
weight_counter weight_added;
|
||||
std::vector<big_stack_entry> big_stack;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
void GetAssumptionLits(const expr &fmla, std::vector<expr> &lits, hash_map<ast,expr> *opt_map = 0);
|
||||
|
||||
void GreedyReduceCache(std::vector<expr> &assumps, std::vector<expr> &core);
|
||||
|
||||
void FilterCore(std::vector<expr> &core, std::vector<expr> &full_core);
|
||||
void ConstrainEdgeLocalizedCache(Edge *e, const Term &tl, std::vector<expr> &lits);
|
||||
|
||||
virtual void slvr_add(const expr &e);
|
||||
|
||||
virtual void slvr_pop(int i);
|
||||
|
||||
virtual void slvr_push();
|
||||
|
||||
virtual check_result slvr_check(unsigned n = 0, expr * const assumptions = 0, unsigned *core_size = 0, expr *core = 0);
|
||||
|
||||
virtual lbool ls_interpolate_tree(TermTree *assumptions,
|
||||
TermTree *&interpolants,
|
||||
model &_model,
|
||||
TermTree *goals = 0,
|
||||
bool weak = false);
|
||||
|
||||
virtual bool proof_core_contains(const expr &e);
|
||||
|
||||
void GetTermTreeAssertionLiterals(TermTree *assumptions);
|
||||
|
||||
void GetTermTreeAssertionLiteralsRec(TermTree *assumptions);
|
||||
|
||||
LogicSolver *SolverForEdge(Edge *edge, bool models);
|
||||
|
||||
public:
|
||||
struct scoped_solver_for_edge {
|
||||
LogicSolver *orig_ls;
|
||||
RPFP_caching *rpfp;
|
||||
scoped_solver_for_edge(RPFP_caching *_rpfp, Edge *edge, bool models = false){
|
||||
rpfp = _rpfp;
|
||||
orig_ls = rpfp->ls;
|
||||
rpfp->ls = rpfp->SolverForEdge(edge,models);
|
||||
}
|
||||
~scoped_solver_for_edge(){
|
||||
rpfp->ls = orig_ls;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -25,7 +25,14 @@ Revision History:
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#endif
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
#include "iz3profiling.h"
|
||||
|
||||
namespace Duality {
|
||||
|
||||
|
@ -103,6 +110,7 @@ namespace Duality {
|
|||
output_time(*pfs, it->second.t);
|
||||
(*pfs) << std::endl;
|
||||
}
|
||||
profiling::print(os); // print the interpolation stats
|
||||
}
|
||||
|
||||
void timer_start(const char *name){
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -19,6 +19,12 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#endif
|
||||
|
||||
#include "duality.h"
|
||||
#include "duality_profiling.h"
|
||||
|
||||
|
@ -26,6 +32,7 @@ Revision History:
|
|||
#include <set>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <iterator>
|
||||
|
||||
// TODO: make these official options or get rid of them
|
||||
|
||||
|
@ -37,14 +44,18 @@ Revision History:
|
|||
#define MINIMIZE_CANDIDATES
|
||||
// #define MINIMIZE_CANDIDATES_HARDER
|
||||
#define BOUNDED
|
||||
#define CHECK_CANDS_FROM_IND_SET
|
||||
// #define CHECK_CANDS_FROM_IND_SET
|
||||
#define UNDERAPPROX_NODES
|
||||
#define NEW_EXPAND
|
||||
#define EARLY_EXPAND
|
||||
// #define TOP_DOWN
|
||||
// #define EFFORT_BOUNDED_STRAT
|
||||
#define SKIP_UNDERAPPROX_NODES
|
||||
|
||||
#define USE_RPFP_CLONE
|
||||
// #define KEEP_EXPANSIONS
|
||||
// #define USE_CACHING_RPFP
|
||||
// #define PROPAGATE_BEFORE_CHECK
|
||||
#define USE_NEW_GEN_CANDS
|
||||
|
||||
namespace Duality {
|
||||
|
||||
|
@ -101,7 +112,7 @@ namespace Duality {
|
|||
public:
|
||||
Duality(RPFP *_rpfp)
|
||||
: ctx(_rpfp->ctx),
|
||||
slvr(_rpfp->slvr),
|
||||
slvr(_rpfp->slvr()),
|
||||
nodes(_rpfp->nodes),
|
||||
edges(_rpfp->edges)
|
||||
{
|
||||
|
@ -115,8 +126,42 @@ namespace Duality {
|
|||
Report = false;
|
||||
StratifiedInlining = false;
|
||||
RecursionBound = -1;
|
||||
{
|
||||
scoped_no_proof no_proofs_please(ctx.m());
|
||||
#ifdef USE_RPFP_CLONE
|
||||
clone_ls = new RPFP::iZ3LogicSolver(ctx, false); // no models needed for this one
|
||||
clone_rpfp = new RPFP_caching(clone_ls);
|
||||
clone_rpfp->Clone(rpfp);
|
||||
#endif
|
||||
#ifdef USE_NEW_GEN_CANDS
|
||||
gen_cands_ls = new RPFP::iZ3LogicSolver(ctx);
|
||||
gen_cands_rpfp = new RPFP_caching(gen_cands_ls);
|
||||
gen_cands_rpfp->Clone(rpfp);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
~Duality(){
|
||||
#ifdef USE_RPFP_CLONE
|
||||
delete clone_rpfp;
|
||||
delete clone_ls;
|
||||
#endif
|
||||
#ifdef USE_NEW_GEN_CANDS
|
||||
delete gen_cands_rpfp;
|
||||
delete gen_cands_ls;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef USE_RPFP_CLONE
|
||||
RPFP::LogicSolver *clone_ls;
|
||||
RPFP_caching *clone_rpfp;
|
||||
#endif
|
||||
#ifdef USE_NEW_GEN_CANDS
|
||||
RPFP::LogicSolver *gen_cands_ls;
|
||||
RPFP_caching *gen_cands_rpfp;
|
||||
#endif
|
||||
|
||||
|
||||
typedef RPFP::Node Node;
|
||||
typedef RPFP::Edge Edge;
|
||||
|
||||
|
@ -804,8 +849,10 @@ namespace Duality {
|
|||
Node *child = chs[i];
|
||||
if(TopoSort[child] < TopoSort[node->map]){
|
||||
Node *leaf = LeafMap[child];
|
||||
if(!indset->Contains(leaf))
|
||||
if(!indset->Contains(leaf)){
|
||||
node->Outgoing->F.Formula = ctx.bool_val(false); // make this a proper leaf, else bogus cex
|
||||
return node->Outgoing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1085,7 +1132,8 @@ namespace Duality {
|
|||
void ExtractCandidateFromCex(Edge *edge, RPFP *checker, Node *root, Candidate &candidate){
|
||||
candidate.edge = edge;
|
||||
for(unsigned j = 0; j < edge->Children.size(); j++){
|
||||
Edge *lb = root->Outgoing->Children[j]->Outgoing;
|
||||
Node *node = root->Outgoing->Children[j];
|
||||
Edge *lb = node->Outgoing;
|
||||
std::vector<Node *> &insts = insts_of_node[edge->Children[j]];
|
||||
#ifndef MINIMIZE_CANDIDATES
|
||||
for(int k = insts.size()-1; k >= 0; k--)
|
||||
|
@ -1095,8 +1143,8 @@ namespace Duality {
|
|||
{
|
||||
Node *inst = insts[k];
|
||||
if(indset->Contains(inst)){
|
||||
if(checker->Empty(lb->Parent) ||
|
||||
eq(checker->Eval(lb,NodeMarker(inst)),ctx.bool_val(true))){
|
||||
if(checker->Empty(node) ||
|
||||
eq(lb ? checker->Eval(lb,NodeMarker(inst)) : checker->dualModel.eval(NodeMarker(inst)),ctx.bool_val(true))){
|
||||
candidate.Children.push_back(inst);
|
||||
goto next_child;
|
||||
}
|
||||
|
@ -1166,6 +1214,25 @@ namespace Duality {
|
|||
#endif
|
||||
|
||||
|
||||
Node *CheckerForEdgeClone(Edge *edge, RPFP_caching *checker){
|
||||
Edge *gen_cands_edge = checker->GetEdgeClone(edge);
|
||||
Node *root = gen_cands_edge->Parent;
|
||||
root->Outgoing = gen_cands_edge;
|
||||
GenNodeSolutionFromIndSet(edge->Parent, root->Bound);
|
||||
#if 0
|
||||
if(root->Bound.IsFull())
|
||||
return = 0;
|
||||
#endif
|
||||
checker->AssertNode(root);
|
||||
for(unsigned j = 0; j < edge->Children.size(); j++){
|
||||
Node *oc = edge->Children[j];
|
||||
Node *nc = gen_cands_edge->Children[j];
|
||||
GenNodeSolutionWithMarkers(oc,nc->Annotation,true);
|
||||
}
|
||||
checker->AssertEdge(gen_cands_edge,1,true);
|
||||
return root;
|
||||
}
|
||||
|
||||
/** If the current proposed solution is not inductive,
|
||||
use the induction failure to generate candidates for extension. */
|
||||
void GenCandidatesFromInductionFailure(bool full_scan = false){
|
||||
|
@ -1175,6 +1242,7 @@ namespace Duality {
|
|||
Edge *edge = edges[i];
|
||||
if(!full_scan && updated_nodes.find(edge->Parent) == updated_nodes.end())
|
||||
continue;
|
||||
#ifndef USE_NEW_GEN_CANDS
|
||||
slvr.push();
|
||||
RPFP *checker = new RPFP(rpfp->ls);
|
||||
Node *root = CheckerForEdge(edge,checker);
|
||||
|
@ -1186,6 +1254,18 @@ namespace Duality {
|
|||
}
|
||||
slvr.pop(1);
|
||||
delete checker;
|
||||
#else
|
||||
RPFP_caching::scoped_solver_for_edge(gen_cands_rpfp,edge,true /* models */);
|
||||
gen_cands_rpfp->Push();
|
||||
Node *root = CheckerForEdgeClone(edge,gen_cands_rpfp);
|
||||
if(gen_cands_rpfp->Check(root) != unsat){
|
||||
Candidate candidate;
|
||||
ExtractCandidateFromCex(edge,gen_cands_rpfp,root,candidate);
|
||||
reporter->InductionFailure(edge,candidate.Children);
|
||||
candidates.push_back(candidate);
|
||||
}
|
||||
gen_cands_rpfp->Pop(1);
|
||||
#endif
|
||||
}
|
||||
updated_nodes.clear();
|
||||
timer_stop("GenCandIndFail");
|
||||
|
@ -1309,6 +1389,9 @@ namespace Duality {
|
|||
node. */
|
||||
bool SatisfyUpperBound(Node *node){
|
||||
if(node->Bound.IsFull()) return true;
|
||||
#ifdef PROPAGATE_BEFORE_CHECK
|
||||
Propagate();
|
||||
#endif
|
||||
reporter->Bound(node);
|
||||
int start_decs = rpfp->CumulativeDecisions();
|
||||
DerivationTree *dtp = new DerivationTreeSlow(this,unwinding,reporter,heuristic,FullExpand);
|
||||
|
@ -1412,13 +1495,77 @@ namespace Duality {
|
|||
}
|
||||
}
|
||||
|
||||
// Propagate conjuncts up the unwinding
|
||||
void Propagate(){
|
||||
reporter->Message("beginning propagation");
|
||||
timer_start("Propagate");
|
||||
std::vector<Node *> sorted_nodes = unwinding->nodes;
|
||||
std::sort(sorted_nodes.begin(),sorted_nodes.end(),std::less<Node *>()); // sorts by sequence number
|
||||
hash_map<Node *,std::set<expr> > facts;
|
||||
for(unsigned i = 0; i < sorted_nodes.size(); i++){
|
||||
Node *node = sorted_nodes[i];
|
||||
std::set<expr> &node_facts = facts[node->map];
|
||||
if(!(node->Outgoing && indset->Contains(node)))
|
||||
continue;
|
||||
std::vector<expr> conj_vec;
|
||||
unwinding->CollectConjuncts(node->Annotation.Formula,conj_vec);
|
||||
std::set<expr> conjs;
|
||||
std::copy(conj_vec.begin(),conj_vec.end(),std::inserter(conjs,conjs.begin()));
|
||||
if(!node_facts.empty()){
|
||||
RPFP *checker = new RPFP(rpfp->ls);
|
||||
slvr.push();
|
||||
Node *root = checker->CloneNode(node);
|
||||
Edge *edge = node->Outgoing;
|
||||
// checker->AssertNode(root);
|
||||
std::vector<Node *> cs;
|
||||
for(unsigned j = 0; j < edge->Children.size(); j++){
|
||||
Node *oc = edge->Children[j];
|
||||
Node *nc = checker->CloneNode(oc);
|
||||
nc->Annotation = oc->Annotation; // is this needed?
|
||||
cs.push_back(nc);
|
||||
}
|
||||
Edge *checker_edge = checker->CreateEdge(root,edge->F,cs);
|
||||
checker->AssertEdge(checker_edge, 0, true, false);
|
||||
std::vector<expr> propagated;
|
||||
for(std::set<expr> ::iterator it = node_facts.begin(), en = node_facts.end(); it != en;){
|
||||
const expr &fact = *it;
|
||||
if(conjs.find(fact) == conjs.end()){
|
||||
root->Bound.Formula = fact;
|
||||
slvr.push();
|
||||
checker->AssertNode(root);
|
||||
check_result res = checker->Check(root);
|
||||
slvr.pop();
|
||||
if(res != unsat){
|
||||
std::set<expr> ::iterator victim = it;
|
||||
++it;
|
||||
node_facts.erase(victim); // if it ain't true, nix it
|
||||
continue;
|
||||
}
|
||||
propagated.push_back(fact);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
slvr.pop();
|
||||
for(unsigned i = 0; i < propagated.size(); i++){
|
||||
root->Annotation.Formula = propagated[i];
|
||||
UpdateNodeToNode(node,root);
|
||||
}
|
||||
delete checker;
|
||||
}
|
||||
for(std::set<expr> ::iterator it = conjs.begin(), en = conjs.end(); it != en; ++it){
|
||||
expr foo = *it;
|
||||
node_facts.insert(foo);
|
||||
}
|
||||
}
|
||||
timer_stop("Propagate");
|
||||
}
|
||||
|
||||
/** This class represents a derivation tree. */
|
||||
class DerivationTree {
|
||||
public:
|
||||
|
||||
DerivationTree(Duality *_duality, RPFP *rpfp, Reporter *_reporter, Heuristic *_heuristic, bool _full_expand)
|
||||
: slvr(rpfp->slvr),
|
||||
: slvr(rpfp->slvr()),
|
||||
ctx(rpfp->ctx)
|
||||
{
|
||||
duality = _duality;
|
||||
|
@ -1462,7 +1609,13 @@ namespace Duality {
|
|||
constrained = _constrained;
|
||||
false_approx = true;
|
||||
timer_start("Derive");
|
||||
#ifndef USE_CACHING_RPFP
|
||||
tree = _tree ? _tree : new RPFP(rpfp->ls);
|
||||
#else
|
||||
RPFP::LogicSolver *cache_ls = new RPFP::iZ3LogicSolver(ctx);
|
||||
cache_ls->slvr->push();
|
||||
tree = _tree ? _tree : new RPFP_caching(cache_ls);
|
||||
#endif
|
||||
tree->HornClauses = rpfp->HornClauses;
|
||||
tree->Push(); // so we can clear out the solver later when finished
|
||||
top = CreateApproximatedInstance(root);
|
||||
|
@ -1474,19 +1627,28 @@ namespace Duality {
|
|||
timer_start("Pop");
|
||||
tree->Pop(1);
|
||||
timer_stop("Pop");
|
||||
#ifdef USE_CACHING_RPFP
|
||||
cache_ls->slvr->pop(1);
|
||||
delete cache_ls;
|
||||
tree->ls = rpfp->ls;
|
||||
#endif
|
||||
timer_stop("Derive");
|
||||
return res;
|
||||
}
|
||||
|
||||
#define WITH_CHILDREN
|
||||
|
||||
Node *CreateApproximatedInstance(RPFP::Node *from){
|
||||
Node *to = tree->CloneNode(from);
|
||||
to->Annotation = from->Annotation;
|
||||
void InitializeApproximatedInstance(RPFP::Node *to){
|
||||
to->Annotation = to->map->Annotation;
|
||||
#ifndef WITH_CHILDREN
|
||||
tree->CreateLowerBoundEdge(to);
|
||||
#endif
|
||||
leaves.push_back(to);
|
||||
}
|
||||
|
||||
Node *CreateApproximatedInstance(RPFP::Node *from){
|
||||
Node *to = tree->CloneNode(from);
|
||||
InitializeApproximatedInstance(to);
|
||||
return to;
|
||||
}
|
||||
|
||||
|
@ -1555,13 +1717,23 @@ namespace Duality {
|
|||
|
||||
virtual void ExpandNode(RPFP::Node *p){
|
||||
// tree->RemoveEdge(p->Outgoing);
|
||||
Edge *edge = duality->GetNodeOutgoing(p->map,last_decs);
|
||||
std::vector<RPFP::Node *> &cs = edge->Children;
|
||||
std::vector<RPFP::Node *> children(cs.size());
|
||||
for(unsigned i = 0; i < cs.size(); i++)
|
||||
children[i] = CreateApproximatedInstance(cs[i]);
|
||||
Edge *ne = tree->CreateEdge(p, p->map->Outgoing->F, children);
|
||||
ne->map = p->map->Outgoing->map;
|
||||
Edge *ne = p->Outgoing;
|
||||
if(ne) {
|
||||
// reporter->Message("Recycling edge...");
|
||||
std::vector<RPFP::Node *> &cs = ne->Children;
|
||||
for(unsigned i = 0; i < cs.size(); i++)
|
||||
InitializeApproximatedInstance(cs[i]);
|
||||
// ne->dual = expr();
|
||||
}
|
||||
else {
|
||||
Edge *edge = duality->GetNodeOutgoing(p->map,last_decs);
|
||||
std::vector<RPFP::Node *> &cs = edge->Children;
|
||||
std::vector<RPFP::Node *> children(cs.size());
|
||||
for(unsigned i = 0; i < cs.size(); i++)
|
||||
children[i] = CreateApproximatedInstance(cs[i]);
|
||||
ne = tree->CreateEdge(p, p->map->Outgoing->F, children);
|
||||
ne->map = p->map->Outgoing->map;
|
||||
}
|
||||
#ifndef WITH_CHILDREN
|
||||
tree->AssertEdge(ne); // assert the edge in the solver
|
||||
#else
|
||||
|
@ -1703,12 +1875,25 @@ namespace Duality {
|
|||
void RemoveExpansion(RPFP::Node *p){
|
||||
Edge *edge = p->Outgoing;
|
||||
Node *parent = edge->Parent;
|
||||
#ifndef KEEP_EXPANSIONS
|
||||
std::vector<RPFP::Node *> cs = edge->Children;
|
||||
tree->DeleteEdge(edge);
|
||||
for(unsigned i = 0; i < cs.size(); i++)
|
||||
tree->DeleteNode(cs[i]);
|
||||
#endif
|
||||
leaves.push_back(parent);
|
||||
}
|
||||
|
||||
// remove all the descendants of tree root (but not root itself)
|
||||
void RemoveTree(RPFP *tree, RPFP::Node *root){
|
||||
Edge *edge = root->Outgoing;
|
||||
std::vector<RPFP::Node *> cs = edge->Children;
|
||||
tree->DeleteEdge(edge);
|
||||
for(unsigned i = 0; i < cs.size(); i++){
|
||||
RemoveTree(tree,cs[i]);
|
||||
tree->DeleteNode(cs[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DerivationTreeSlow : public DerivationTree {
|
||||
|
@ -1730,13 +1915,14 @@ namespace Duality {
|
|||
|
||||
virtual bool Build(){
|
||||
|
||||
stack.back().level = tree->slvr.get_scope_level();
|
||||
stack.back().level = tree->slvr().get_scope_level();
|
||||
bool was_sat = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
lbool res;
|
||||
|
||||
unsigned slvr_level = tree->slvr.get_scope_level();
|
||||
unsigned slvr_level = tree->slvr().get_scope_level();
|
||||
if(slvr_level != stack.back().level)
|
||||
throw "stacks out of sync!";
|
||||
|
||||
|
@ -1756,14 +1942,22 @@ namespace Duality {
|
|||
tree->SolveSingleNode(top,node);
|
||||
if(expansions.size() == 1 && NodeTooComplicated(node))
|
||||
SimplifyNode(node);
|
||||
tree->Generalize(top,node);
|
||||
else
|
||||
node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify();
|
||||
Generalize(node);
|
||||
if(RecordUpdate(node))
|
||||
update_count++;
|
||||
else
|
||||
heuristic->Update(node->map); // make it less likely to expand this node in future
|
||||
}
|
||||
if(update_count == 0)
|
||||
if(update_count == 0){
|
||||
if(was_sat)
|
||||
throw Incompleteness();
|
||||
reporter->Message("backtracked without learning");
|
||||
}
|
||||
}
|
||||
tree->ComputeProofCore(); // need to compute the proof core before popping solver
|
||||
bool propagated = false;
|
||||
while(1) {
|
||||
std::vector<Node *> &expansions = stack.back().expansions;
|
||||
bool prev_level_used = LevelUsedInProof(stack.size()-2); // need to compute this before pop
|
||||
|
@ -1787,28 +1981,42 @@ namespace Duality {
|
|||
RemoveExpansion(node);
|
||||
}
|
||||
stack.pop_back();
|
||||
if(prev_level_used || stack.size() == 1) break;
|
||||
if(stack.size() == 1)break;
|
||||
if(prev_level_used){
|
||||
Node *node = stack.back().expansions[0];
|
||||
if(!Propagate(node)) break;
|
||||
if(!RecordUpdate(node)) break; // shouldn't happen!
|
||||
RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list
|
||||
propagated = true;
|
||||
continue;
|
||||
}
|
||||
if(propagated) break; // propagation invalidates the proof core, so disable non-chron backtrack
|
||||
RemoveUpdateNodesAtCurrentLevel(); // this level is about to be deleted -- remove its children from update list
|
||||
std::vector<Node *> &unused_ex = stack.back().expansions;
|
||||
for(unsigned i = 0; i < unused_ex.size(); i++)
|
||||
heuristic->Update(unused_ex[i]->map); // make it less likely to expand this node in future
|
||||
}
|
||||
HandleUpdatedNodes();
|
||||
if(stack.size() == 1)
|
||||
if(stack.size() == 1){
|
||||
if(top->Outgoing)
|
||||
tree->DeleteEdge(top->Outgoing); // in case we kept the tree
|
||||
return false;
|
||||
}
|
||||
was_sat = false;
|
||||
}
|
||||
else {
|
||||
was_sat = true;
|
||||
tree->Push();
|
||||
std::vector<Node *> &expansions = stack.back().expansions;
|
||||
for(unsigned i = 0; i < expansions.size(); i++){
|
||||
tree->FixCurrentState(expansions[i]->Outgoing);
|
||||
}
|
||||
#if 0
|
||||
if(tree->slvr.check() == unsat)
|
||||
if(tree->slvr().check() == unsat)
|
||||
throw "help!";
|
||||
#endif
|
||||
stack.push_back(stack_entry());
|
||||
stack.back().level = tree->slvr.get_scope_level();
|
||||
stack.back().level = tree->slvr().get_scope_level();
|
||||
if(ExpandSomeNodes(false,1)){
|
||||
continue;
|
||||
}
|
||||
|
@ -1822,13 +2030,18 @@ namespace Duality {
|
|||
}
|
||||
|
||||
bool NodeTooComplicated(Node *node){
|
||||
int ops = tree->CountOperators(node->Annotation.Formula);
|
||||
if(ops > 10) return true;
|
||||
node->Annotation.Formula = tree->RemoveRedundancy(node->Annotation.Formula).simplify();
|
||||
return tree->CountOperators(node->Annotation.Formula) > 3;
|
||||
}
|
||||
|
||||
void SimplifyNode(Node *node){
|
||||
// have to destroy the old proof to get a new interpolant
|
||||
timer_start("SimplifyNode");
|
||||
tree->PopPush();
|
||||
tree->InterpolateByCases(top,node);
|
||||
timer_stop("SimplifyNode");
|
||||
}
|
||||
|
||||
bool LevelUsedInProof(unsigned level){
|
||||
|
@ -1927,6 +2140,39 @@ namespace Duality {
|
|||
throw "can't unmap node";
|
||||
}
|
||||
|
||||
void Generalize(Node *node){
|
||||
#ifndef USE_RPFP_CLONE
|
||||
tree->Generalize(top,node);
|
||||
#else
|
||||
RPFP_caching *clone_rpfp = duality->clone_rpfp;
|
||||
if(!node->Outgoing->map) return;
|
||||
Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map);
|
||||
Node *clone_node = clone_edge->Parent;
|
||||
clone_node->Annotation = node->Annotation;
|
||||
for(unsigned i = 0; i < clone_edge->Children.size(); i++)
|
||||
clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation;
|
||||
clone_rpfp->GeneralizeCache(clone_edge);
|
||||
node->Annotation = clone_node->Annotation;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Propagate(Node *node){
|
||||
#ifdef USE_RPFP_CLONE
|
||||
RPFP_caching *clone_rpfp = duality->clone_rpfp;
|
||||
Edge *clone_edge = clone_rpfp->GetEdgeClone(node->Outgoing->map);
|
||||
Node *clone_node = clone_edge->Parent;
|
||||
clone_node->Annotation = node->map->Annotation;
|
||||
for(unsigned i = 0; i < clone_edge->Children.size(); i++)
|
||||
clone_edge->Children[i]->Annotation = node->map->Outgoing->Children[i]->Annotation;
|
||||
bool res = clone_rpfp->PropagateCache(clone_edge);
|
||||
if(res)
|
||||
node->Annotation = clone_node->Annotation;
|
||||
return res;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -1948,6 +2194,11 @@ namespace Duality {
|
|||
Duality *parent;
|
||||
bool some_updates;
|
||||
|
||||
#define NO_CONJ_ON_SIMPLE_LOOPS
|
||||
#ifdef NO_CONJ_ON_SIMPLE_LOOPS
|
||||
hash_set<Node *> simple_loops;
|
||||
#endif
|
||||
|
||||
Node *&covered_by(Node *node){
|
||||
return cm[node].covered_by;
|
||||
}
|
||||
|
@ -1982,6 +2233,24 @@ namespace Duality {
|
|||
Covering(Duality *_parent){
|
||||
parent = _parent;
|
||||
some_updates = false;
|
||||
|
||||
#ifdef NO_CONJ_ON_SIMPLE_LOOPS
|
||||
hash_map<Node *,std::vector<Edge *> > outgoing;
|
||||
for(unsigned i = 0; i < parent->rpfp->edges.size(); i++)
|
||||
outgoing[parent->rpfp->edges[i]->Parent].push_back(parent->rpfp->edges[i]);
|
||||
for(unsigned i = 0; i < parent->rpfp->nodes.size(); i++){
|
||||
Node * node = parent->rpfp->nodes[i];
|
||||
std::vector<Edge *> &outs = outgoing[node];
|
||||
if(outs.size() == 2){
|
||||
for(int j = 0; j < 2; j++){
|
||||
Edge *loop_edge = outs[j];
|
||||
if(loop_edge->Children.size() == 1 && loop_edge->Children[0] == loop_edge->Parent)
|
||||
simple_loops.insert(node);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool IsCoveredRec(hash_set<Node *> &memo, Node *node){
|
||||
|
@ -2144,6 +2413,11 @@ namespace Duality {
|
|||
}
|
||||
|
||||
bool CouldCover(Node *covered, Node *covering){
|
||||
#ifdef NO_CONJ_ON_SIMPLE_LOOPS
|
||||
// Forsimple loops, we rely on propagation, not covering
|
||||
if(simple_loops.find(covered->map) != simple_loops.end())
|
||||
return false;
|
||||
#endif
|
||||
#ifdef UNDERAPPROX_NODES
|
||||
// if(parent->underapprox_map.find(covering) != parent->underapprox_map.end())
|
||||
// return parent->underapprox_map[covering] == covered;
|
||||
|
|
|
@ -18,6 +18,13 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "duality_wrapper.h"
|
||||
#include <iostream>
|
||||
#include "smt_solver.h"
|
||||
|
@ -30,10 +37,11 @@ Revision History:
|
|||
|
||||
namespace Duality {
|
||||
|
||||
solver::solver(Duality::context& c, bool extensional) : object(c), the_model(c) {
|
||||
solver::solver(Duality::context& c, bool extensional, bool models) : object(c), the_model(c) {
|
||||
params_ref p;
|
||||
p.set_bool("proof", true); // this is currently useless
|
||||
p.set_bool("model", true);
|
||||
if(models)
|
||||
p.set_bool("model", true);
|
||||
p.set_bool("unsat_core", true);
|
||||
p.set_bool("mbqi",true);
|
||||
p.set_str("mbqi.id","itp"); // use mbqi for quantifiers in interpolants
|
||||
|
@ -44,6 +52,7 @@ namespace Duality {
|
|||
m_solver = (*sf)(m(), p, true, true, true, ::symbol::null);
|
||||
m_solver->updt_params(p); // why do we have to do this?
|
||||
canceled = false;
|
||||
m_mode = m().proof_mode();
|
||||
}
|
||||
|
||||
expr context::constant(const std::string &name, const sort &ty){
|
||||
|
@ -338,6 +347,17 @@ expr context::make_quant(decl_kind op, const std::vector<sort> &_sorts, const st
|
|||
return ctx().cook(result);
|
||||
}
|
||||
|
||||
expr expr::qe_lite(const std::set<int> &idxs, bool index_of_bound) const {
|
||||
::qe_lite qe(m());
|
||||
expr_ref result(to_expr(raw()),m());
|
||||
proof_ref pf(m());
|
||||
uint_set uis;
|
||||
for(std::set<int>::const_iterator it=idxs.begin(), en = idxs.end(); it != en; ++it)
|
||||
uis.insert(*it);
|
||||
qe(uis,index_of_bound,result);
|
||||
return ctx().cook(result);
|
||||
}
|
||||
|
||||
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())));
|
||||
}
|
||||
|
@ -362,6 +382,18 @@ expr context::make_quant(decl_kind op, const std::vector<sort> &_sorts, const st
|
|||
}
|
||||
|
||||
|
||||
unsigned func_decl::arity() const {
|
||||
return (to_func_decl(raw())->get_arity());
|
||||
}
|
||||
|
||||
sort func_decl::domain(unsigned i) const {
|
||||
return sort(ctx(),(to_func_decl(raw())->get_domain(i)));
|
||||
}
|
||||
|
||||
sort func_decl::range() const {
|
||||
return sort(ctx(),(to_func_decl(raw())->get_range()));
|
||||
}
|
||||
|
||||
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++)
|
||||
|
@ -504,7 +536,10 @@ expr context::make_quant(decl_kind op, const std::vector<sort> &_sorts, const st
|
|||
add(linear_assumptions[i][j]);
|
||||
}
|
||||
|
||||
check_result res = check();
|
||||
check_result res = unsat;
|
||||
|
||||
if(!m_solver->get_proof())
|
||||
res = check();
|
||||
|
||||
if(res == unsat){
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ Revision History:
|
|||
#include<sstream>
|
||||
#include<vector>
|
||||
#include<list>
|
||||
#include <set>
|
||||
#include"version.h"
|
||||
#include<limits.h>
|
||||
|
||||
|
@ -50,6 +51,7 @@ Revision History:
|
|||
#include"scoped_ctrl_c.h"
|
||||
#include"cancel_eh.h"
|
||||
#include"scoped_timer.h"
|
||||
#include"scoped_proof.h"
|
||||
|
||||
namespace Duality {
|
||||
|
||||
|
@ -449,6 +451,7 @@ namespace Duality {
|
|||
bool is_datatype() const { return get_sort().is_datatype(); }
|
||||
bool is_relation() const { return get_sort().is_relation(); }
|
||||
bool is_finite_domain() const { return get_sort().is_finite_domain(); }
|
||||
bool is_true() const {return is_app() && decl().get_decl_kind() == True; }
|
||||
|
||||
bool is_numeral() const {
|
||||
return is_app() && decl().get_decl_kind() == OtherArith && m().is_unique_value(to_expr(raw()));
|
||||
|
@ -560,6 +563,8 @@ namespace Duality {
|
|||
|
||||
expr qe_lite() const;
|
||||
|
||||
expr qe_lite(const std::set<int> &idxs, bool index_of_bound) const;
|
||||
|
||||
friend expr clone_quantifier(const expr &, const expr &);
|
||||
|
||||
friend expr clone_quantifier(const expr &q, const expr &b, const std::vector<expr> &patterns);
|
||||
|
@ -718,6 +723,7 @@ namespace Duality {
|
|||
m_model = s;
|
||||
return *this;
|
||||
}
|
||||
bool null() const {return !m_model;}
|
||||
|
||||
expr eval(expr const & n, bool model_completion=true) const {
|
||||
::model * _m = m_model.get();
|
||||
|
@ -811,8 +817,9 @@ namespace Duality {
|
|||
::solver *m_solver;
|
||||
model the_model;
|
||||
bool canceled;
|
||||
proof_gen_mode m_mode;
|
||||
public:
|
||||
solver(context & c, bool extensional = false);
|
||||
solver(context & c, bool extensional = false, bool models = true);
|
||||
solver(context & c, ::solver *s):object(c),the_model(c) { m_solver = s; canceled = false;}
|
||||
solver(solver const & s):object(s), the_model(s.the_model) { m_solver = s.m_solver; canceled = false;}
|
||||
~solver() {
|
||||
|
@ -824,6 +831,7 @@ namespace Duality {
|
|||
m_ctx = s.m_ctx;
|
||||
m_solver = s.m_solver;
|
||||
the_model = s.the_model;
|
||||
m_mode = s.m_mode;
|
||||
return *this;
|
||||
}
|
||||
struct cancel_exception {};
|
||||
|
@ -832,11 +840,12 @@ namespace Duality {
|
|||
throw(cancel_exception());
|
||||
}
|
||||
// void set(params const & p) { Z3_solver_set_params(ctx(), m_solver, p); check_error(); }
|
||||
void push() { m_solver->push(); }
|
||||
void pop(unsigned n = 1) { m_solver->pop(n); }
|
||||
void push() { scoped_proof_mode spm(m(),m_mode); m_solver->push(); }
|
||||
void pop(unsigned n = 1) { scoped_proof_mode spm(m(),m_mode); m_solver->pop(n); }
|
||||
// void reset() { Z3_solver_reset(ctx(), m_solver); check_error(); }
|
||||
void add(expr const & e) { m_solver->assert_expr(e); }
|
||||
void add(expr const & e) { scoped_proof_mode spm(m(),m_mode); m_solver->assert_expr(e); }
|
||||
check_result check() {
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
checkpoint();
|
||||
lbool r = m_solver->check_sat(0,0);
|
||||
model_ref m;
|
||||
|
@ -845,6 +854,7 @@ namespace Duality {
|
|||
return to_check_result(r);
|
||||
}
|
||||
check_result check_keep_model(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) {
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
model old_model(the_model);
|
||||
check_result res = check(n,assumptions,core_size,core);
|
||||
if(the_model == 0)
|
||||
|
@ -852,6 +862,7 @@ namespace Duality {
|
|||
return res;
|
||||
}
|
||||
check_result check(unsigned n, expr * const assumptions, unsigned *core_size = 0, expr *core = 0) {
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
checkpoint();
|
||||
std::vector< ::expr *> _assumptions(n);
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
|
@ -876,6 +887,7 @@ namespace Duality {
|
|||
}
|
||||
#if 0
|
||||
check_result check(expr_vector assumptions) {
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
unsigned n = assumptions.size();
|
||||
z3array<Z3_ast> _assumptions(n);
|
||||
for (unsigned i = 0; i < n; i++) {
|
||||
|
@ -900,17 +912,19 @@ namespace Duality {
|
|||
int get_num_decisions();
|
||||
|
||||
void cancel(){
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
canceled = true;
|
||||
if(m_solver)
|
||||
m_solver->cancel();
|
||||
}
|
||||
|
||||
unsigned get_scope_level(){return m_solver->get_scope_level();}
|
||||
unsigned get_scope_level(){ scoped_proof_mode spm(m(),m_mode); return m_solver->get_scope_level();}
|
||||
|
||||
void show();
|
||||
void show_assertion_ids();
|
||||
|
||||
proof get_proof(){
|
||||
scoped_proof_mode spm(m(),m_mode);
|
||||
return proof(ctx(),m_solver->get_proof());
|
||||
}
|
||||
|
||||
|
@ -1294,8 +1308,8 @@ namespace Duality {
|
|||
|
||||
class interpolating_solver : public solver {
|
||||
public:
|
||||
interpolating_solver(context &ctx)
|
||||
: solver(ctx)
|
||||
interpolating_solver(context &ctx, bool models = true)
|
||||
: solver(ctx, true, models)
|
||||
{
|
||||
weak_mode = false;
|
||||
}
|
||||
|
@ -1359,6 +1373,21 @@ namespace Duality {
|
|||
typedef double clock_t;
|
||||
clock_t current_time();
|
||||
inline void output_time(std::ostream &os, clock_t time){os << time;}
|
||||
|
||||
template <class X> class uptr {
|
||||
public:
|
||||
X *ptr;
|
||||
uptr(){ptr = 0;}
|
||||
void set(X *_ptr){
|
||||
if(ptr) delete ptr;
|
||||
ptr = _ptr;
|
||||
}
|
||||
X *get(){ return ptr;}
|
||||
~uptr(){
|
||||
if(ptr) delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
// to make Duality::ast hashable
|
||||
|
@ -1393,6 +1422,18 @@ namespace std {
|
|||
};
|
||||
}
|
||||
|
||||
// to make Duality::ast usable in ordered collections
|
||||
namespace std {
|
||||
template <>
|
||||
class less<Duality::expr> {
|
||||
public:
|
||||
bool operator()(const Duality::expr &s, const Duality::expr &t) const {
|
||||
// return s.raw() < t.raw();
|
||||
return s.raw()->get_id() < t.raw()->get_id();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// to make Duality::func_decl hashable
|
||||
namespace hash_space {
|
||||
template <>
|
||||
|
@ -1425,6 +1466,5 @@ namespace std {
|
|||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -18,6 +18,12 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3base.h"
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -17,6 +17,13 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3base.h"
|
||||
#include "iz3checker.h"
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ Revision History:
|
|||
namespace stl_ext {
|
||||
template <>
|
||||
class hash<std::string> {
|
||||
stl_ext::hash<char *> H;
|
||||
stl_ext::hash<const char *> H;
|
||||
public:
|
||||
size_t operator()(const std::string &s) const {
|
||||
return H(s.c_str());
|
||||
|
|
|
@ -18,6 +18,14 @@ Revision History:
|
|||
--*/
|
||||
|
||||
/* Copyright 2011 Microsoft Research. */
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include <assert.h>
|
||||
#include <algorithm>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -18,6 +18,15 @@ Revision History:
|
|||
--*/
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#pragma warning(disable:4805)
|
||||
#pragma warning(disable:4800)
|
||||
#endif
|
||||
|
||||
#include "iz3mgr.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -172,7 +181,7 @@ iz3mgr::ast iz3mgr::make_quant(opr op, const std::vector<ast> &bvs, ast &body){
|
|||
|
||||
|
||||
std::vector<symbol> names;
|
||||
std::vector<sort *> types;
|
||||
std::vector<class sort *> types;
|
||||
std::vector<expr *> bound_asts;
|
||||
unsigned num_bound = bvs.size();
|
||||
|
||||
|
@ -485,7 +494,7 @@ void iz3mgr::get_farkas_coeffs(const ast &proof, std::vector<ast>& coeffs){
|
|||
get_farkas_coeffs(proof,rats);
|
||||
coeffs.resize(rats.size());
|
||||
for(unsigned i = 0; i < rats.size(); i++){
|
||||
sort *is = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
class sort *is = m().mk_sort(m_arith_fid, INT_SORT);
|
||||
ast coeff = cook(m_arith_util.mk_numeral(rats[i],is));
|
||||
coeffs[i] = coeff;
|
||||
}
|
||||
|
@ -640,9 +649,9 @@ void iz3mgr::get_assign_bounds_rule_coeffs(const ast &proof, std::vector<rationa
|
|||
|
||||
/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */
|
||||
|
||||
void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q){
|
||||
void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q, bool round_off){
|
||||
ast Qrhs;
|
||||
bool strict = op(P) == Lt;
|
||||
bool qstrict = false;
|
||||
if(is_not(Q)){
|
||||
ast nQ = arg(Q,0);
|
||||
switch(op(nQ)){
|
||||
|
@ -654,11 +663,11 @@ void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q){
|
|||
break;
|
||||
case Geq:
|
||||
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
case Leq:
|
||||
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
default:
|
||||
throw "not an inequality";
|
||||
|
@ -674,28 +683,31 @@ void iz3mgr::linear_comb(ast &P, const ast &c, const ast &Q){
|
|||
break;
|
||||
case Lt:
|
||||
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
case Gt:
|
||||
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
default:
|
||||
throw "not an inequality";
|
||||
}
|
||||
}
|
||||
Qrhs = make(Times,c,Qrhs);
|
||||
bool pstrict = op(P) == Lt, strict = pstrict || qstrict;
|
||||
if(pstrict && qstrict && round_off)
|
||||
Qrhs = make(Sub,Qrhs,make_int(rational(1)));
|
||||
if(strict)
|
||||
P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
||||
else
|
||||
P = make(Leq,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
||||
}
|
||||
|
||||
iz3mgr::ast iz3mgr::sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs){
|
||||
iz3mgr::ast iz3mgr::sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs, bool round_off){
|
||||
ast zero = make_int("0");
|
||||
ast thing = make(Leq,zero,zero);
|
||||
for(unsigned i = 0; i < ineqs.size(); i++){
|
||||
linear_comb(thing,coeffs[i],ineqs[i]);
|
||||
linear_comb(thing,coeffs[i],ineqs[i], round_off);
|
||||
}
|
||||
thing = simplify_ineq(thing);
|
||||
return thing;
|
||||
|
|
|
@ -22,6 +22,7 @@ Revision History:
|
|||
|
||||
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
#include "iz3hash.h"
|
||||
|
||||
#include"well_sorted.h"
|
||||
|
@ -262,6 +263,7 @@ class iz3mgr {
|
|||
default:;
|
||||
}
|
||||
assert(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ast arg(const ast &t, int i){
|
||||
|
@ -606,9 +608,9 @@ class iz3mgr {
|
|||
return d;
|
||||
}
|
||||
|
||||
void linear_comb(ast &P, const ast &c, const ast &Q);
|
||||
void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false);
|
||||
|
||||
ast sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs);
|
||||
ast sum_inequalities(const std::vector<ast> &coeffs, const std::vector<ast> &ineqs, bool round_off = false);
|
||||
|
||||
ast simplify_ineq(const ast &ineq){
|
||||
ast res = make(op(ineq),arg(ineq,0),z3_simplify(arg(ineq,1)));
|
||||
|
|
|
@ -58,20 +58,20 @@ namespace stl_ext {
|
|||
class free_func_visitor {
|
||||
ast_manager& m;
|
||||
func_decl_set m_funcs;
|
||||
obj_hashtable<sort> m_sorts;
|
||||
obj_hashtable<class sort> m_sorts;
|
||||
public:
|
||||
free_func_visitor(ast_manager& m): m(m) {}
|
||||
void operator()(var * n) { }
|
||||
void operator()(app * n) {
|
||||
m_funcs.insert(n->get_decl());
|
||||
sort* s = m.get_sort(n);
|
||||
class sort* s = m.get_sort(n);
|
||||
if (s->get_family_id() == null_family_id) {
|
||||
m_sorts.insert(s);
|
||||
}
|
||||
}
|
||||
void operator()(quantifier * n) { }
|
||||
func_decl_set& funcs() { return m_funcs; }
|
||||
obj_hashtable<sort>& sorts() { return m_sorts; }
|
||||
obj_hashtable<class sort>& sorts() { return m_sorts; }
|
||||
};
|
||||
|
||||
class iz3pp_helper : public iz3mgr {
|
||||
|
@ -146,8 +146,8 @@ void iz3pp(ast_manager &m,
|
|||
func_decl_set &funcs = visitor.funcs();
|
||||
func_decl_set::iterator it = funcs.begin(), end = funcs.end();
|
||||
|
||||
obj_hashtable<sort>& sorts = visitor.sorts();
|
||||
obj_hashtable<sort>::iterator sit = sorts.begin(), send = sorts.end();
|
||||
obj_hashtable<class sort>& sorts = visitor.sorts();
|
||||
obj_hashtable<class sort>::iterator sit = sorts.begin(), send = sorts.end();
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -17,6 +17,13 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3profiling.h"
|
||||
|
||||
#include <map>
|
||||
|
|
|
@ -18,6 +18,12 @@ Revision History:
|
|||
--*/
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3proof.h"
|
||||
#include "iz3profiling.h"
|
||||
|
|
|
@ -17,6 +17,13 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3proof_itp.h"
|
||||
|
||||
#ifndef WIN32
|
||||
|
@ -2170,7 +2177,8 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
for(unsigned i = 0; i < prem_cons.size(); i++){
|
||||
const ast &lit = prem_cons[i];
|
||||
if(get_term_type(lit) == LitA)
|
||||
linear_comb(thing,coeffs[i],lit);
|
||||
// Farkas rule seems to assume strict integer inequalities are rounded
|
||||
linear_comb(thing,coeffs[i],lit,true /*round_off*/);
|
||||
}
|
||||
thing = simplify_ineq(thing);
|
||||
for(unsigned i = 0; i < prem_cons.size(); i++){
|
||||
|
@ -2195,9 +2203,9 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
|
||||
/** Set P to P + cQ, where P and Q are linear inequalities. Assumes P is 0 <= y or 0 < y. */
|
||||
|
||||
void linear_comb(ast &P, const ast &c, const ast &Q){
|
||||
void linear_comb(ast &P, const ast &c, const ast &Q, bool round_off = false){
|
||||
ast Qrhs;
|
||||
bool strict = op(P) == Lt;
|
||||
bool qstrict = false;
|
||||
if(is_not(Q)){
|
||||
ast nQ = arg(Q,0);
|
||||
switch(op(nQ)){
|
||||
|
@ -2209,11 +2217,11 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
break;
|
||||
case Geq:
|
||||
Qrhs = make(Sub,arg(nQ,1),arg(nQ,0));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
case Leq:
|
||||
Qrhs = make(Sub,arg(nQ,0),arg(nQ,1));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
default:
|
||||
throw proof_error();
|
||||
|
@ -2229,17 +2237,20 @@ class iz3proof_itp_impl : public iz3proof_itp {
|
|||
break;
|
||||
case Lt:
|
||||
Qrhs = make(Sub,arg(Q,1),arg(Q,0));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
case Gt:
|
||||
Qrhs = make(Sub,arg(Q,0),arg(Q,1));
|
||||
strict = true;
|
||||
qstrict = true;
|
||||
break;
|
||||
default:
|
||||
throw proof_error();
|
||||
}
|
||||
}
|
||||
Qrhs = make(Times,c,Qrhs);
|
||||
bool pstrict = op(P) == Lt, strict = pstrict || qstrict;
|
||||
if(pstrict && qstrict && round_off)
|
||||
Qrhs = make(Sub,Qrhs,make_int(rational(1)));
|
||||
if(strict)
|
||||
P = make(Lt,arg(P,0),make(Plus,arg(P,1),Qrhs));
|
||||
else
|
||||
|
|
|
@ -17,6 +17,13 @@ Revision History:
|
|||
|
||||
--*/
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "iz3translate.h"
|
||||
#include "iz3proof.h"
|
||||
#include "iz3profiling.h"
|
||||
|
@ -1079,7 +1086,7 @@ public:
|
|||
my_cons.push_back(mk_not(arg(con,i)));
|
||||
my_coeffs.push_back(farkas_coeffs[i]);
|
||||
}
|
||||
ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons));
|
||||
ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */));
|
||||
my_cons.push_back(mk_not(farkas_con));
|
||||
my_coeffs.push_back(make_int("1"));
|
||||
std::vector<Iproof::node> my_hyps;
|
||||
|
@ -1103,7 +1110,7 @@ public:
|
|||
my_cons.push_back(conc(prem(proof,i-1)));
|
||||
my_coeffs.push_back(farkas_coeffs[i]);
|
||||
}
|
||||
ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons));
|
||||
ast farkas_con = normalize_inequality(sum_inequalities(my_coeffs,my_cons,true /* round_off */));
|
||||
std::vector<Iproof::node> my_hyps;
|
||||
for(int i = 1; i < nargs; i++)
|
||||
my_hyps.push_back(prems[i-1]);
|
||||
|
@ -1642,6 +1649,10 @@ public:
|
|||
res = iproof->make_axiom(lits);
|
||||
break;
|
||||
}
|
||||
case PR_IFF_TRUE: { // turns p into p <-> true, noop for us
|
||||
res = args[0];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
assert(0 && "translate_main: unsupported proof rule");
|
||||
throw unsupported();
|
||||
|
|
|
@ -20,6 +20,14 @@ Revision History:
|
|||
--*/
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#pragma warning(disable:4390)
|
||||
#endif
|
||||
|
||||
#include "iz3translate.h"
|
||||
#include "iz3proof.h"
|
||||
#include "iz3profiling.h"
|
||||
|
@ -58,7 +66,9 @@ namespace stl_ext {
|
|||
|
||||
|
||||
static int lemma_count = 0;
|
||||
#if 0
|
||||
static int nll_lemma_count = 0;
|
||||
#endif
|
||||
#define SHOW_LEMMA_COUNT -1
|
||||
|
||||
// One half of a resolution. We need this to distinguish
|
||||
|
|
|
@ -97,6 +97,7 @@ namespace simplex {
|
|||
unsigned m_blands_rule_threshold;
|
||||
random_gen m_random;
|
||||
uint_set m_left_basis;
|
||||
unsigned m_infeasible_var;
|
||||
|
||||
public:
|
||||
simplex():
|
||||
|
@ -111,7 +112,8 @@ namespace simplex {
|
|||
typedef typename matrix::col_iterator col_iterator;
|
||||
|
||||
void ensure_var(var_t v);
|
||||
row add_row(unsigned num_vars, var_t base, var_t const* vars, numeral const* coeffs);
|
||||
row add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs);
|
||||
row get_infeasible_row();
|
||||
void del_row(row const& r);
|
||||
void set_lower(var_t var, eps_numeral const& b);
|
||||
void set_upper(var_t var, eps_numeral const& b);
|
||||
|
@ -125,6 +127,9 @@ namespace simplex {
|
|||
eps_numeral const& get_value(var_t v);
|
||||
void display(std::ostream& out) const;
|
||||
|
||||
unsigned get_num_vars() const { return m_vars.size(); }
|
||||
|
||||
|
||||
private:
|
||||
|
||||
var_t select_var_to_fix();
|
||||
|
@ -159,10 +164,11 @@ namespace simplex {
|
|||
bool outside_bounds(var_t v) const { return below_lower(v) || above_upper(v); }
|
||||
bool is_free(var_t v) const { return !m_vars[v].m_lower_valid && !m_vars[v].m_upper_valid; }
|
||||
bool is_non_free(var_t v) const { return !is_free(v); }
|
||||
unsigned get_num_vars() const { return m_vars.size(); }
|
||||
bool is_base(var_t x) const { return m_vars[x].m_is_base; }
|
||||
void add_patch(var_t v);
|
||||
|
||||
bool well_formed() const;
|
||||
bool well_formed_row(row const& r) const;
|
||||
bool is_feasible() const;
|
||||
};
|
||||
|
||||
|
|
|
@ -24,19 +24,27 @@ namespace simplex {
|
|||
template<typename Ext>
|
||||
typename simplex<Ext>::row
|
||||
simplex<Ext>::add_row(var_t base, unsigned num_vars, var_t const* vars, numeral const* coeffs) {
|
||||
DEBUG_CODE(
|
||||
bool found = false;
|
||||
for (unsigned i = 0; !found && i < num_vars; ++i) found = vars[i] == base;
|
||||
SASSERT(found);
|
||||
);
|
||||
scoped_numeral base_coeff(m);
|
||||
scoped_eps_numeral value(em), tmp(em);
|
||||
row r = M.mk_row();
|
||||
for (unsigned i = 0; i < num_vars; ++i) {
|
||||
M.add(r, coeffs[i], vars[i]);
|
||||
if (vars[i] == base) {
|
||||
m.set(base_coeff, coeffs[i]);
|
||||
if (!m.is_zero(coeffs[i])) {
|
||||
var_t v = vars[i];
|
||||
M.add_var(r, coeffs[i], v);
|
||||
if (v == base) {
|
||||
m.set(base_coeff, coeffs[i]);
|
||||
}
|
||||
else {
|
||||
SASSERT(!is_base(v));
|
||||
em.mul(m_vars[v].m_value, coeffs[i], tmp);
|
||||
em.add(value, tmp, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
em.neg(value);
|
||||
em.div(value, base_coeff, value);
|
||||
SASSERT(!m.is_zero(base_coeff));
|
||||
SASSERT(!is_base(base));
|
||||
while (m_row2base.size() <= r.id()) {
|
||||
m_row2base.push_back(null_var);
|
||||
}
|
||||
|
@ -44,9 +52,28 @@ namespace simplex {
|
|||
m_vars[base].m_base2row = r.id();
|
||||
m_vars[base].m_is_base = true;
|
||||
m.set(m_vars[base].m_base_coeff, base_coeff);
|
||||
em.set(m_vars[base].m_value, value);
|
||||
add_patch(base);
|
||||
SASSERT(well_formed_row(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
typename simplex<Ext>::row
|
||||
simplex<Ext>::get_infeasible_row() {
|
||||
SASSERT(is_base(m_infeasible_var));
|
||||
unsigned row_id = m_vars[m_infeasible_var].m_base2row;
|
||||
return row(row_id);
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void simplex<Ext>::add_patch(var_t v) {
|
||||
SASSERT(is_base(v));
|
||||
if (outside_bounds(v)) {
|
||||
m_to_patch.insert(v);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
void simplex<Ext>::del_row(row const& r) {
|
||||
m_vars[m_row2base[r.id()]].m_is_base = false;
|
||||
|
@ -114,8 +141,12 @@ namespace simplex {
|
|||
if (vi.m_lower_valid) out << em.to_string(vi.m_lower); else out << "-oo";
|
||||
out << ":";
|
||||
if (vi.m_upper_valid) out << em.to_string(vi.m_upper); else out << "oo";
|
||||
out << "]";
|
||||
if (vi.m_is_base) out << " b:" << vi.m_base2row;
|
||||
out << "] ";
|
||||
if (vi.m_is_base) out << "b:" << vi.m_base2row << " ";
|
||||
//col_iterator it = M.col_begin(i), end = M.col_end(i);
|
||||
//for (; it != end; ++it) {
|
||||
// out << "r" << it.get_row().id() << " ";
|
||||
//}
|
||||
out << "\n";
|
||||
}
|
||||
}
|
||||
|
@ -131,20 +162,23 @@ namespace simplex {
|
|||
template<typename Ext>
|
||||
lbool simplex<Ext>::make_feasible() {
|
||||
m_left_basis.reset();
|
||||
m_infeasible_var = null_var;
|
||||
unsigned num_iterations = 0;
|
||||
unsigned num_repeated = 0;
|
||||
var_t v = null_var;
|
||||
SASSERT(well_formed());
|
||||
while ((v = select_var_to_fix()) != null_var) {
|
||||
if (m_cancel || num_iterations > m_max_iterations) {
|
||||
return l_undef;
|
||||
}
|
||||
check_blands_rule(v, num_repeated);
|
||||
if (!make_var_feasible(v)) {
|
||||
m_infeasible_var = v;
|
||||
return l_false;
|
||||
}
|
||||
++num_iterations;
|
||||
SASSERT(well_formed());
|
||||
}
|
||||
SASSERT(well_formed());
|
||||
return l_true;
|
||||
}
|
||||
|
||||
|
@ -188,18 +222,18 @@ namespace simplex {
|
|||
m.set(x_jI.m_base_coeff, a_ij);
|
||||
x_jI.m_is_base = true;
|
||||
x_iI.m_is_base = false;
|
||||
if (outside_bounds(x_j)) {
|
||||
m_to_patch.insert(x_j);
|
||||
}
|
||||
add_patch(x_j);
|
||||
SASSERT(well_formed_row(row(r_i)));
|
||||
|
||||
col_iterator it = M.col_begin(x_j), end = M.col_end(x_j);
|
||||
scoped_numeral a_kj(m), g(m);
|
||||
for (; it != end; ++it) {
|
||||
row r_k = it.get_row();
|
||||
if (r_k != r_i) {
|
||||
if (r_k.id() != r_i) {
|
||||
a_kj = it.get_row_entry().m_coeff;
|
||||
a_kj.neg();
|
||||
M.mul(r_k, a_ij);
|
||||
M.add(r_k, a_kj, r_i);
|
||||
M.add(r_k, a_kj, row(r_i));
|
||||
var_t s = m_row2base[r_k.id()];
|
||||
numeral& coeff = m_vars[s].m_base_coeff;
|
||||
m.mul(coeff, a_ij, coeff);
|
||||
|
@ -207,6 +241,7 @@ namespace simplex {
|
|||
if (!m.is_one(g)) {
|
||||
m.div(coeff, g, coeff);
|
||||
}
|
||||
SASSERT(well_formed_row(row(r_k)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -240,8 +275,8 @@ namespace simplex {
|
|||
void simplex<Ext>::update_value_core(var_t v, eps_numeral const& delta) {
|
||||
eps_numeral& val = m_vars[v].m_value;
|
||||
em.add(val, delta, val);
|
||||
if (is_base(v) && outside_bounds(v)) {
|
||||
m_to_patch.insert(v);
|
||||
if (is_base(v)) {
|
||||
add_patch(v);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -499,6 +534,7 @@ namespace simplex {
|
|||
|
||||
pivot(x_i, x_j, a_ij);
|
||||
move_to_bound(x_i, inc == m.is_pos(a_ij));
|
||||
SASSERT(well_formed_row(row(m_vars[x_j].m_base2row)));
|
||||
}
|
||||
return l_true;
|
||||
}
|
||||
|
@ -705,18 +741,7 @@ namespace simplex {
|
|||
var_t s = m_row2base[i];
|
||||
if (s == null_var) continue;
|
||||
SASSERT(i == m_vars[s].m_base2row);
|
||||
//
|
||||
// TBD: extract coefficient of base variable and compare
|
||||
// with m_vars[s].m_base_coeff;
|
||||
//
|
||||
// check that sum of assignments add up to 0 for every row.
|
||||
row_iterator it = M.row_begin(row(i)), end = M.row_end(row(i));
|
||||
scoped_eps_numeral sum(em), tmp(em);
|
||||
for (; it != end; ++it) {
|
||||
em.mul(m_vars[it->m_var].m_value, it->m_coeff, tmp);
|
||||
sum += tmp;
|
||||
}
|
||||
SASSERT(em.is_zero(sum));
|
||||
SASSERT(well_formed_row(row(i)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -729,6 +754,25 @@ namespace simplex {
|
|||
return true;
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
bool simplex<Ext>::well_formed_row(row const& r) const {
|
||||
|
||||
//
|
||||
// TBD: extract coefficient of base variable and compare
|
||||
// with m_vars[s].m_base_coeff;
|
||||
//
|
||||
// check that sum of assignments add up to 0 for every row.
|
||||
row_iterator it = M.row_begin(r), end = M.row_end(r);
|
||||
scoped_eps_numeral sum(em), tmp(em);
|
||||
for (; it != end; ++it) {
|
||||
em.mul(m_vars[it->m_var].m_value, it->m_coeff, tmp);
|
||||
sum += tmp;
|
||||
}
|
||||
SASSERT(em.is_zero(sum));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -92,8 +92,7 @@ namespace simplex {
|
|||
void del_row_entry(unsigned idx);
|
||||
void compress(manager& m, vector<column> & cols);
|
||||
void compress_if_needed(manager& m, vector<column> & cols);
|
||||
void save_var_pos(svector<int> & result_map) const;
|
||||
void reset_var_pos(svector<int> & result_map) const;
|
||||
void save_var_pos(svector<int> & result_map, unsigned_vector& idxs) const;
|
||||
bool is_coeff_of(var_t v, numeral const & expected) const;
|
||||
int get_idx_of(var_t v) const;
|
||||
};
|
||||
|
@ -125,6 +124,7 @@ namespace simplex {
|
|||
svector<unsigned> m_dead_rows; // rows to recycle
|
||||
vector<column> m_columns; // per var
|
||||
svector<int> m_var_pos; // temporary map from variables to positions in row
|
||||
unsigned_vector m_var_pos_idx; // indices in m_var_pos
|
||||
|
||||
bool well_formed_row(unsigned row_id) const;
|
||||
bool well_formed_column(unsigned column_id) const;
|
||||
|
@ -138,7 +138,7 @@ namespace simplex {
|
|||
class row {
|
||||
unsigned m_id;
|
||||
public:
|
||||
row(unsigned r):m_id(r) {}
|
||||
explicit row(unsigned r):m_id(r) {}
|
||||
row():m_id(UINT_MAX) {}
|
||||
bool operator!=(row const& other) const {
|
||||
return m_id != other.m_id;
|
||||
|
@ -149,7 +149,7 @@ namespace simplex {
|
|||
void ensure_var(var_t v);
|
||||
|
||||
row mk_row();
|
||||
void add(row r, numeral const& n, var_t var);
|
||||
void add_var(row r, numeral const& n, var_t var);
|
||||
void add(row r, numeral const& n, row src);
|
||||
void mul(row r, numeral const& n);
|
||||
void neg(row r);
|
||||
|
|
|
@ -134,31 +134,18 @@ namespace simplex {
|
|||
\brief Fill the map var -> pos/idx
|
||||
*/
|
||||
template<typename Ext>
|
||||
inline void sparse_matrix<Ext>::_row::save_var_pos(svector<int> & result_map) const {
|
||||
inline void sparse_matrix<Ext>::_row::save_var_pos(svector<int> & result_map, unsigned_vector& idxs) const {
|
||||
typename vector<_row_entry>::const_iterator it = m_entries.begin();
|
||||
typename vector<_row_entry>::const_iterator end = m_entries.end();
|
||||
unsigned idx = 0;
|
||||
for (; it != end; ++it, ++idx) {
|
||||
if (!it->is_dead()) {
|
||||
result_map[it->m_var] = idx;
|
||||
idxs.push_back(it->m_var);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
\brief Reset the map var -> pos/idx. That is for all variables v in the row, set result[v] = -1
|
||||
This method can be viewed as the "inverse" of save_var_pos.
|
||||
*/
|
||||
template<typename Ext>
|
||||
inline void sparse_matrix<Ext>::_row::reset_var_pos(svector<int> & result_map) const {
|
||||
typename vector<_row_entry>::const_iterator it = m_entries.begin();
|
||||
typename vector<_row_entry>::const_iterator end = m_entries.end();
|
||||
for (; it != end; ++it) {
|
||||
if (!it->is_dead()) {
|
||||
result_map[it->m_var] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ext>
|
||||
int sparse_matrix<Ext>::_row::get_idx_of(var_t v) const {
|
||||
|
@ -316,7 +303,7 @@ namespace simplex {
|
|||
}
|
||||
|
||||
template<typename Ext>
|
||||
void sparse_matrix<Ext>::add(row dst, numeral const& n, var_t v) {
|
||||
void sparse_matrix<Ext>::add_var(row dst, numeral const& n, var_t v) {
|
||||
_row& r = m_rows[dst.id()];
|
||||
column& c = m_columns[v];
|
||||
unsigned r_idx;
|
||||
|
@ -339,7 +326,7 @@ namespace simplex {
|
|||
_row & r1 = m_rows[row1.id()];
|
||||
_row & r2 = m_rows[row2.id()];
|
||||
|
||||
r1.save_var_pos(m_var_pos);
|
||||
r1.save_var_pos(m_var_pos, m_var_pos_idx);
|
||||
|
||||
//
|
||||
// loop over variables in row2,
|
||||
|
@ -376,7 +363,6 @@ namespace simplex {
|
|||
} \
|
||||
} \
|
||||
} \
|
||||
|
||||
((void) 0)
|
||||
|
||||
if (m.is_one(n)) {
|
||||
|
@ -394,7 +380,11 @@ namespace simplex {
|
|||
m.add(r_entry.m_coeff, tmp, r_entry.m_coeff));
|
||||
}
|
||||
|
||||
r1.reset_var_pos(m_var_pos);
|
||||
// reset m_var_pos:
|
||||
for (unsigned i = 0; i < m_var_pos_idx.size(); ++i) {
|
||||
m_var_pos[m_var_pos_idx[i]] = -1;
|
||||
}
|
||||
m_var_pos_idx.reset();
|
||||
r1.compress_if_needed(m, m_columns);
|
||||
}
|
||||
|
||||
|
|
|
@ -35,10 +35,15 @@ Revision History:
|
|||
#include "model_smt2_pp.h"
|
||||
#include "model_v2_pp.h"
|
||||
#include "fixedpoint_params.hpp"
|
||||
#include "scoped_proof.h"
|
||||
|
||||
// template class symbol_table<family_id>;
|
||||
|
||||
#ifdef WIN32
|
||||
#pragma warning(disable:4996)
|
||||
#pragma warning(disable:4800)
|
||||
#pragma warning(disable:4267)
|
||||
#pragma warning(disable:4101)
|
||||
#endif
|
||||
|
||||
#include "duality.h"
|
||||
#include "duality_profiling.h"
|
||||
|
@ -213,6 +218,9 @@ lbool dl_interface::query(::expr * query) {
|
|||
catch (Duality::solver::cancel_exception &exn){
|
||||
throw default_exception("duality canceled");
|
||||
}
|
||||
catch (Duality::Solver::Incompleteness &exn){
|
||||
throw default_exception("incompleteness");
|
||||
}
|
||||
|
||||
// profile!
|
||||
|
||||
|
|
|
@ -3,11 +3,130 @@
|
|||
#include "simplex.h"
|
||||
#include "simplex_def.h"
|
||||
#include "mpq_inf.h"
|
||||
#include "vector.h"
|
||||
#include "rational.h"
|
||||
|
||||
#define R rational
|
||||
typedef simplex::simplex<simplex::mpz_ext> Simplex;
|
||||
typedef simplex::sparse_matrix<simplex::mpz_ext> sparse_matrix;
|
||||
|
||||
static vector<R> vec(int i, int j) {
|
||||
vector<R> nv;
|
||||
nv.resize(2);
|
||||
nv[0] = R(i);
|
||||
nv[1] = R(j);
|
||||
return nv;
|
||||
}
|
||||
|
||||
static vector<R> vec(int i, int j, int k) {
|
||||
vector<R> nv = vec(i, j);
|
||||
nv.push_back(R(k));
|
||||
return nv;
|
||||
}
|
||||
|
||||
static vector<R> vec(int i, int j, int k, int l) {
|
||||
vector<R> nv = vec(i, j, k);
|
||||
nv.push_back(R(l));
|
||||
return nv;
|
||||
}
|
||||
|
||||
static vector<R> vec(int i, int j, int k, int l, int x) {
|
||||
vector<R> nv = vec(i, j, k, l);
|
||||
nv.push_back(R(x));
|
||||
return nv;
|
||||
}
|
||||
|
||||
static vector<R> vec(int i, int j, int k, int l, int x, int y) {
|
||||
vector<R> nv = vec(i, j, k, l, x);
|
||||
nv.push_back(R(y));
|
||||
return nv;
|
||||
}
|
||||
|
||||
static vector<R> vec(int i, int j, int k, int l, int x, int y, int z) {
|
||||
vector<R> nv = vec(i, j, k, l, x, y);
|
||||
nv.push_back(R(z));
|
||||
return nv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void add_row(Simplex& S, vector<R> const& _v, R const& _b, bool is_eq = false) {
|
||||
unsynch_mpz_manager m;
|
||||
unsigned_vector vars;
|
||||
vector<R> v(_v);
|
||||
R b(_b);
|
||||
R l(denominator(b));
|
||||
scoped_mpz_vector coeffs(m);
|
||||
for (unsigned i = 0; i < v.size(); ++i) {
|
||||
l = lcm(l, denominator(v[i]));
|
||||
vars.push_back(i);
|
||||
S.ensure_var(i);
|
||||
}
|
||||
b *= l;
|
||||
b.neg();
|
||||
for (unsigned i = 0; i < v.size(); ++i) {
|
||||
v[i] *= l;
|
||||
coeffs.push_back(v[i].to_mpq().numerator());
|
||||
}
|
||||
unsigned nv = S.get_num_vars();
|
||||
vars.push_back(nv);
|
||||
vars.push_back(nv+1);
|
||||
S.ensure_var(nv);
|
||||
S.ensure_var(nv+1);
|
||||
coeffs.push_back(mpz(-1));
|
||||
coeffs.push_back(b.to_mpq().numerator());
|
||||
mpq_inf one(mpq(1),mpq(0));
|
||||
mpq_inf zero(mpq(0),mpq(0));
|
||||
SASSERT(vars.size() == coeffs.size());
|
||||
S.set_lower(nv, zero);
|
||||
if (is_eq) S.set_upper(nv, zero);
|
||||
S.set_lower(nv+1, one);
|
||||
S.set_upper(nv+1, one);
|
||||
S.add_row(nv, coeffs.size(), vars.c_ptr(), coeffs.c_ptr());
|
||||
}
|
||||
|
||||
static void feas(Simplex& S) {
|
||||
S.display(std::cout);
|
||||
lbool is_sat = S.make_feasible();
|
||||
std::cout << "feasible: " << is_sat << "\n";
|
||||
S.display(std::cout);
|
||||
}
|
||||
|
||||
static void test1() {
|
||||
Simplex S;
|
||||
add_row(S, vec(1,0), R(1));
|
||||
add_row(S, vec(0,1), R(1));
|
||||
add_row(S, vec(1,1), R(1));
|
||||
feas(S);
|
||||
}
|
||||
|
||||
static void test2() {
|
||||
Simplex S;
|
||||
add_row(S, vec(1, 0), R(1));
|
||||
add_row(S, vec(0, 1), R(1));
|
||||
add_row(S, vec(1, 1), R(1), true);
|
||||
feas(S);
|
||||
}
|
||||
|
||||
static void test3() {
|
||||
Simplex S;
|
||||
add_row(S, vec(-1, 0), R(-1));
|
||||
add_row(S, vec(0, -1), R(-1));
|
||||
add_row(S, vec(1, 1), R(1), true);
|
||||
feas(S);
|
||||
}
|
||||
|
||||
static void test4() {
|
||||
Simplex S;
|
||||
add_row(S, vec(1, 0), R(1));
|
||||
add_row(S, vec(0, -1), R(-1));
|
||||
add_row(S, vec(1, 1), R(1), true);
|
||||
feas(S);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void tst_simplex() {
|
||||
simplex::sparse_matrix<simplex::mpz_ext> M;
|
||||
Simplex S;
|
||||
|
||||
std::cout << "simplex\n";
|
||||
|
@ -37,4 +156,9 @@ void tst_simplex() {
|
|||
is_sat = S.make_feasible();
|
||||
std::cout << "feasible: " << is_sat << "\n";
|
||||
S.display(std::cout);
|
||||
|
||||
test1();
|
||||
test2();
|
||||
test3();
|
||||
test4();
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue