3
0
Fork 0
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:
Nikolaj Bjorner 2014-02-11 15:44:53 -08:00
commit 596796f7ef
26 changed files with 2067 additions and 221 deletions

View file

@ -17,6 +17,7 @@ Revision History:
--*/
#include<iostream>
#include<sstream>
#include<vector>
#include"z3.h"
#include"api_log_macros.h"
#include"api_context.h"

View file

@ -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){

View file

@ -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> &params);
expr AddParamsToApp(const expr &app, const func_decl &new_decl, const std::vector<expr> &params);
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> &params);
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;
}
};
};
}

View file

@ -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

View file

@ -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;

View file

@ -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){

View file

@ -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

View file

@ -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>

View file

@ -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"

View file

@ -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());

View file

@ -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>

View file

@ -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;

View file

@ -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)));

View file

@ -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();

View file

@ -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>

View file

@ -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"

View file

@ -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

View file

@ -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();

View file

@ -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

View file

@ -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;
};

View file

@ -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

View file

@ -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);

View file

@ -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);
}

View file

@ -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!

View file

@ -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();
}