3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-15 13:28:47 +00:00

working on hitting sets

Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
Nikolaj Bjorner 2014-06-08 14:12:54 +01:00
commit 960e8ea1d5
38 changed files with 1130 additions and 203 deletions

View file

@ -912,6 +912,7 @@ def _coerce_expr_merge(s, a):
return s return s
else: else:
if __debug__: if __debug__:
_z3_assert(s1.ctx == s.ctx, "context mismatch")
_z3_assert(False, "sort mismatch") _z3_assert(False, "sort mismatch")
else: else:
return s return s
@ -1472,9 +1473,18 @@ def And(*args):
>>> And(P) >>> And(P)
And(p__0, p__1, p__2, p__3, p__4) And(p__0, p__1, p__2, p__3, p__4)
""" """
args = _get_args(args) last_arg = None
ctx = _ctx_from_ast_arg_list(args) if len(args) > 0:
last_arg = args[len(args)-1]
if isinstance(last_arg, Context):
ctx = args[len(args)-1]
args = args[:len(args)-1]
else:
ctx = main_ctx()
args = _get_args(args)
ctx_args = _ctx_from_ast_arg_list(args, ctx)
if __debug__: if __debug__:
_z3_assert(ctx_args == None or ctx_args == ctx, "context mismatch")
_z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe") _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe")
if _has_probe(args): if _has_probe(args):
return _probe_and(args, ctx) return _probe_and(args, ctx)
@ -1493,9 +1503,18 @@ def Or(*args):
>>> Or(P) >>> Or(P)
Or(p__0, p__1, p__2, p__3, p__4) Or(p__0, p__1, p__2, p__3, p__4)
""" """
args = _get_args(args) last_arg = None
ctx = _ctx_from_ast_arg_list(args) if len(args) > 0:
last_arg = args[len(args)-1]
if isinstance(last_arg, Context):
ctx = args[len(args)-1]
args = args[:len(args)-1]
else:
ctx = main_ctx()
args = _get_args(args)
ctx_args = _ctx_from_ast_arg_list(args, ctx)
if __debug__: if __debug__:
_z3_assert(ctx_args == None or ctx_args == ctx, "context mismatch")
_z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe") _z3_assert(ctx != None, "At least one of the arguments must be a Z3 expression or probe")
if _has_probe(args): if _has_probe(args):
return _probe_or(args, ctx) return _probe_or(args, ctx)
@ -4147,6 +4166,7 @@ class Datatype:
""" """
if __debug__: if __debug__:
_z3_assert(isinstance(name, str), "String expected") _z3_assert(isinstance(name, str), "String expected")
_z3_assert(name != "", "Constructor name cannot be empty")
return self.declare_core(name, "is_" + name, *args) return self.declare_core(name, "is_" + name, *args)
def __repr__(self): def __repr__(self):

View file

@ -599,7 +599,23 @@ namespace datalog {
return 0; return 0;
} }
result = mk_compare(OP_DL_LT, m_lt_sym, domain); result = mk_compare(OP_DL_LT, m_lt_sym, domain);
break; break;
case OP_DL_REP: {
if (!check_domain(0, 0, num_parameters) ||
!check_domain(1, 1, arity)) return 0;
func_decl_info info(m_family_id, k, 0, 0);
result = m_manager->mk_func_decl(symbol("rep"), 1, domain, range, info);
break;
}
case OP_DL_ABS: {
if (!check_domain(0, 0, num_parameters) ||
!check_domain(1, 1, arity)) return 0;
func_decl_info info(m_family_id, k, 0, 0);
result = m_manager->mk_func_decl(symbol("abs"), 1, domain, range, info);
break;
}
default: default:
m_manager->raise_exception("operator not recognized"); m_manager->raise_exception("operator not recognized");

View file

@ -48,6 +48,8 @@ namespace datalog {
OP_RA_CLONE, OP_RA_CLONE,
OP_DL_CONSTANT, OP_DL_CONSTANT,
OP_DL_LT, OP_DL_LT,
OP_DL_REP,
OP_DL_ABS,
LAST_RA_OP LAST_RA_OP
}; };

View file

@ -16,8 +16,8 @@ Author:
Revision History: Revision History:
--*/ --*/
#ifndef _SCOPED_PROOF_H_ #ifndef _SCOPED_PROOF__H_
#define _SCOPED_PROOF_H_ #define _SCOPED_PROOF__H_
#include "ast.h" #include "ast.h"

View file

@ -189,7 +189,7 @@ class psort_app : public psort {
m.inc_ref(d); m.inc_ref(d);
m.inc_ref(num_args, args); m.inc_ref(num_args, args);
SASSERT(num_args == m_decl->get_num_params() || m_decl->has_var_params()); SASSERT(num_args == m_decl->get_num_params() || m_decl->has_var_params());
DEBUG_CODE(for (unsigned i = 0; i < num_params; i++) args[i]->check_num_params(this);); DEBUG_CODE(if (num_args == num_params) { for (unsigned i = 0; i < num_params; i++) args[i]->check_num_params(this); });
} }
virtual void finalize(pdecl_manager & m) { virtual void finalize(pdecl_manager & m) {

View file

@ -253,6 +253,27 @@ protected:
} }
void assert_axiom(const expr &axiom){ void assert_axiom(const expr &axiom){
#if 1
// HACK: large "distict" predicates can kill the legacy SMT solver.
// encode them with a UIF
if(axiom.is_app() && axiom.decl().get_decl_kind() == Distinct)
if(axiom.num_args() > 10){
sort s = axiom.arg(0).get_sort();
std::vector<sort> sv;
sv.push_back(s);
int nargs = axiom.num_args();
std::vector<expr> args(nargs);
func_decl f = ctx->fresh_func_decl("@distinct",sv,ctx->int_sort());
for(int i = 0; i < nargs; i++){
expr a = axiom.arg(i);
expr new_cnstr = f(a) == ctx->int_val(i);
args[i] = new_cnstr;
}
expr cnstr = ctx->make(And,args);
islvr->AssertInterpolationAxiom(cnstr);
return;
}
#endif
islvr->AssertInterpolationAxiom(axiom); islvr->AssertInterpolationAxiom(axiom);
} }

View file

@ -100,6 +100,7 @@ namespace Duality {
}; };
Reporter *CreateStdoutReporter(RPFP *rpfp); Reporter *CreateStdoutReporter(RPFP *rpfp);
Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname);
/** Object we throw in case of catastrophe. */ /** Object we throw in case of catastrophe. */
@ -125,6 +126,7 @@ namespace Duality {
{ {
rpfp = _rpfp; rpfp = _rpfp;
reporter = 0; reporter = 0;
conj_reporter = 0;
heuristic = 0; heuristic = 0;
unwinding = 0; unwinding = 0;
FullExpand = false; FullExpand = false;
@ -274,6 +276,7 @@ namespace Duality {
RPFP *rpfp; // the input RPFP RPFP *rpfp; // the input RPFP
Reporter *reporter; // object for logging Reporter *reporter; // object for logging
Reporter *conj_reporter; // object for logging conjectures
Heuristic *heuristic; // expansion heuristic Heuristic *heuristic; // expansion heuristic
context &ctx; // Z3 context context &ctx; // Z3 context
solver &slvr; // Z3 solver solver &slvr; // Z3 solver
@ -297,6 +300,7 @@ namespace Duality {
int last_decisions; int last_decisions;
hash_set<Node *> overapproxes; hash_set<Node *> overapproxes;
std::vector<Proposer *> proposers; std::vector<Proposer *> proposers;
std::string ConjectureFile;
#ifdef BOUNDED #ifdef BOUNDED
struct Counter { struct Counter {
@ -310,6 +314,7 @@ namespace Duality {
/** Solve the problem. */ /** Solve the problem. */
virtual bool Solve(){ virtual bool Solve(){
reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp); reporter = Report ? CreateStdoutReporter(rpfp) : new Reporter(rpfp);
conj_reporter = ConjectureFile.empty() ? 0 : CreateConjectureFileReporter(rpfp,ConjectureFile);
#ifndef LOCALIZE_CONJECTURES #ifndef LOCALIZE_CONJECTURES
heuristic = !cex.get_tree() ? new Heuristic(rpfp) : new ReplayHeuristic(rpfp,cex); heuristic = !cex.get_tree() ? new Heuristic(rpfp) : new ReplayHeuristic(rpfp,cex);
#else #else
@ -340,6 +345,8 @@ namespace Duality {
delete heuristic; delete heuristic;
// delete unwinding; // keep the unwinding for future mining of predicates // delete unwinding; // keep the unwinding for future mining of predicates
delete reporter; delete reporter;
if(conj_reporter)
delete conj_reporter;
for(unsigned i = 0; i < proposers.size(); i++) for(unsigned i = 0; i < proposers.size(); i++)
delete proposers[i]; delete proposers[i];
return res; return res;
@ -449,6 +456,9 @@ namespace Duality {
if(option == "recursion_bound"){ if(option == "recursion_bound"){
return SetIntOption(RecursionBound,value); return SetIntOption(RecursionBound,value);
} }
if(option == "conjecture_file"){
ConjectureFile = value;
}
return false; return false;
} }
@ -728,6 +738,13 @@ namespace Duality {
return ctx.constant(name.c_str(),ctx.bool_sort()); return ctx.constant(name.c_str(),ctx.bool_sort());
} }
/** Make a boolean variable to act as a "marker" for a pair of nodes. */
expr NodeMarker(Node *node1, Node *node2){
std::string name = std::string("@m_") + string_of_int(node1->number);
name += std::string("_") + string_of_int(node2->number);
return ctx.constant(name.c_str(),ctx.bool_sort());
}
/** Union the annotation of dst into src. If with_markers is /** Union the annotation of dst into src. If with_markers is
true, we conjoin the annotation formula of dst with its true, we conjoin the annotation formula of dst with its
marker. This allows us to discover which disjunct is marker. This allows us to discover which disjunct is
@ -1136,19 +1153,19 @@ namespace Duality {
} }
void GenNodeSolutionWithMarkersAux(Node *node, RPFP::Transformer &annot, expr &marker_disjunction){ void GenNodeSolutionWithMarkersAux(Node *node, RPFP::Transformer &annot, expr &marker_disjunction, Node *other_node){
#ifdef BOUNDED #ifdef BOUNDED
if(RecursionBound >= 0 && NodePastRecursionBound(node)) if(RecursionBound >= 0 && NodePastRecursionBound(node))
return; return;
#endif #endif
RPFP::Transformer temp = node->Annotation; RPFP::Transformer temp = node->Annotation;
expr marker = NodeMarker(node); expr marker = (!other_node) ? NodeMarker(node) : NodeMarker(node, other_node);
temp.Formula = (!marker || temp.Formula); temp.Formula = (!marker || temp.Formula);
annot.IntersectWith(temp); annot.IntersectWith(temp);
marker_disjunction = marker_disjunction || marker; marker_disjunction = marker_disjunction || marker;
} }
bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false){ bool GenNodeSolutionWithMarkers(Node *node, RPFP::Transformer &annot, bool expanded_only = false, Node *other_node = 0){
bool res = false; bool res = false;
annot.SetFull(); annot.SetFull();
expr marker_disjunction = ctx.bool_val(false); expr marker_disjunction = ctx.bool_val(false);
@ -1156,7 +1173,7 @@ namespace Duality {
for(unsigned j = 0; j < insts.size(); j++){ for(unsigned j = 0; j < insts.size(); j++){
Node *node = insts[j]; Node *node = insts[j];
if(indset->Contains(insts[j])){ if(indset->Contains(insts[j])){
GenNodeSolutionWithMarkersAux(node, annot, marker_disjunction); res = true; GenNodeSolutionWithMarkersAux(node, annot, marker_disjunction, other_node); res = true;
} }
} }
annot.Formula = annot.Formula && marker_disjunction; annot.Formula = annot.Formula && marker_disjunction;
@ -1253,7 +1270,7 @@ namespace Duality {
Node *inst = insts[k]; Node *inst = insts[k];
if(indset->Contains(inst)){ if(indset->Contains(inst)){
if(checker->Empty(node) || if(checker->Empty(node) ||
eq(lb ? checker->Eval(lb,NodeMarker(inst)) : checker->dualModel.eval(NodeMarker(inst)),ctx.bool_val(true))){ eq(lb ? checker->Eval(lb,NodeMarker(inst)) : checker->dualModel.eval(NodeMarker(inst,node)),ctx.bool_val(true))){
candidate.Children.push_back(inst); candidate.Children.push_back(inst);
goto next_child; goto next_child;
} }
@ -1336,7 +1353,7 @@ namespace Duality {
for(unsigned j = 0; j < edge->Children.size(); j++){ for(unsigned j = 0; j < edge->Children.size(); j++){
Node *oc = edge->Children[j]; Node *oc = edge->Children[j];
Node *nc = gen_cands_edge->Children[j]; Node *nc = gen_cands_edge->Children[j];
GenNodeSolutionWithMarkers(oc,nc->Annotation,true); GenNodeSolutionWithMarkers(oc,nc->Annotation,true,nc);
} }
checker->AssertEdge(gen_cands_edge,1,true); checker->AssertEdge(gen_cands_edge,1,true);
return root; return root;
@ -1462,6 +1479,8 @@ namespace Duality {
bool Update(Node *node, const RPFP::Transformer &fact, bool eager=false){ bool Update(Node *node, const RPFP::Transformer &fact, bool eager=false){
if(!node->Annotation.SubsetEq(fact)){ if(!node->Annotation.SubsetEq(fact)){
reporter->Update(node,fact,eager); reporter->Update(node,fact,eager);
if(conj_reporter)
conj_reporter->Update(node,fact,eager);
indset->Update(node,fact); indset->Update(node,fact);
updated_nodes.insert(node->map); updated_nodes.insert(node->map);
node->Annotation.IntersectWith(fact); node->Annotation.IntersectWith(fact);
@ -2201,7 +2220,7 @@ namespace Duality {
#endif #endif
int expand_max = 1; int expand_max = 1;
if(0&&duality->BatchExpand){ if(0&&duality->BatchExpand){
int thing = static_cast<int>(stack.size() * 0.1); int thing = stack.size() / 10; // * 0.1;
expand_max = std::max(1,thing); expand_max = std::max(1,thing);
if(expand_max > 1) if(expand_max > 1)
std::cout << "foo!\n"; std::cout << "foo!\n";
@ -3043,6 +3062,7 @@ namespace Duality {
}; };
}; };
static int stop_event = -1;
class StreamReporter : public Reporter { class StreamReporter : public Reporter {
std::ostream &s; std::ostream &s;
@ -3052,6 +3072,9 @@ namespace Duality {
int event; int event;
int depth; int depth;
void ev(){ void ev(){
if(stop_event == event){
std::cout << "stop!\n";
}
s << "[" << event++ << "]" ; s << "[" << event++ << "]" ;
} }
virtual void Extend(RPFP::Node *node){ virtual void Extend(RPFP::Node *node){
@ -3129,4 +3152,28 @@ namespace Duality {
Reporter *CreateStdoutReporter(RPFP *rpfp){ Reporter *CreateStdoutReporter(RPFP *rpfp){
return new StreamReporter(rpfp, std::cout); return new StreamReporter(rpfp, std::cout);
} }
class ConjectureFileReporter : public Reporter {
std::ofstream s;
public:
ConjectureFileReporter(RPFP *_rpfp, const std::string &fname)
: Reporter(_rpfp), s(fname.c_str()) {}
virtual void Update(RPFP::Node *node, const RPFP::Transformer &update, bool eager){
s << "(define-fun " << node->Name.name() << " (";
for(unsigned i = 0; i < update.IndParams.size(); i++){
if(i != 0)
s << " ";
s << "(" << update.IndParams[i] << " " << update.IndParams[i].get_sort() << ")";
}
s << ") Bool \n";
s << update.Formula << ")\n";
s << std::endl;
}
};
Reporter *CreateConjectureFileReporter(RPFP *rpfp, const std::string &fname){
return new ConjectureFileReporter(rpfp, fname);
}
} }

View file

@ -397,6 +397,11 @@ namespace Duality {
sort array_domain() const; sort array_domain() const;
sort array_range() const; sort array_range() const;
friend std::ostream & operator<<(std::ostream & out, sort const & m){
m.ctx().print_expr(out,m);
return out;
}
}; };

View file

@ -260,7 +260,7 @@ void iz3base::check_interp(const std::vector<ast> &itps, std::vector<ast> &theor
#endif #endif
} }
bool iz3base::is_sat(const std::vector<ast> &q, ast &_proof){ bool iz3base::is_sat(const std::vector<ast> &q, ast &_proof, std::vector<ast> &vars){
params_ref p; params_ref p;
p.set_bool("proof", true); // this is currently useless p.set_bool("proof", true); // this is currently useless
@ -277,6 +277,15 @@ bool iz3base::is_sat(const std::vector<ast> &q, ast &_proof){
::ast *proof = s.get_proof(); ::ast *proof = s.get_proof();
_proof = cook(proof); _proof = cook(proof);
} }
else if(vars.size()) {
model_ref(_m);
s.get_model(_m);
for(unsigned i = 0; i < vars.size(); i++){
expr_ref r(m());
_m.get()->eval(to_expr(vars[i].raw()),r,true);
vars[i] = cook(r.get());
}
}
dealloc(m_solver); dealloc(m_solver);
return res != l_false; return res != l_false;
} }

View file

@ -113,7 +113,7 @@ class iz3base : public iz3mgr, public scopes {
void check_interp(const std::vector<ast> &itps, std::vector<ast> &theory); void check_interp(const std::vector<ast> &itps, std::vector<ast> &theory);
/** For convenience -- is this formula SAT? */ /** For convenience -- is this formula SAT? */
bool is_sat(const std::vector<ast> &consts, ast &_proof); bool is_sat(const std::vector<ast> &consts, ast &_proof, std::vector<ast> &vars);
/** Interpolator for clauses, to be implemented */ /** Interpolator for clauses, to be implemented */
virtual void interpolate_clause(std::vector<ast> &lits, std::vector<ast> &itps){ virtual void interpolate_clause(std::vector<ast> &lits, std::vector<ast> &itps){

View file

@ -29,6 +29,10 @@ Revision History:
#ifndef IZ3_HASH_H #ifndef IZ3_HASH_H
#define IZ3_HASH_H #define IZ3_HASH_H
#ifdef _WINDOWS
#pragma warning(disable:4267)
#endif
#include <string> #include <string>
#include <vector> #include <vector>
#include <iterator> #include <iterator>

View file

@ -387,10 +387,13 @@ class iz3mgr {
return UnknownTheory; return UnknownTheory;
} }
enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,UnknownKind}; enum lemma_kind {FarkasKind,Leq2EqKind,Eq2LeqKind,GCDTestKind,AssignBoundsKind,EqPropagateKind,ArithMysteryKind,UnknownKind};
lemma_kind get_theory_lemma_kind(const ast &proof){ lemma_kind get_theory_lemma_kind(const ast &proof){
symb s = sym(proof); symb s = sym(proof);
if(s->get_num_parameters() < 2) {
return ArithMysteryKind; // Bad -- Z3 hasn't told us
}
::symbol p0; ::symbol p0;
bool ok = s->get_parameter(1).is_symbol(p0); bool ok = s->get_parameter(1).is_symbol(p0);
if(!ok) return UnknownKind; if(!ok) return UnknownKind;

View file

@ -607,7 +607,29 @@ class iz3proof_itp_impl : public iz3proof_itp {
return res; return res;
} }
ast distribute_coeff(const ast &coeff, const ast &s){
if(sym(s) == sum){
if(sym(arg(s,2)) == sum)
return make(sum,
distribute_coeff(coeff,arg(s,0)),
make_int(rational(1)),
distribute_coeff(make(Times,coeff,arg(s,1)), arg(s,2)));
else
return make(sum,
distribute_coeff(coeff,arg(s,0)),
make(Times,coeff,arg(s,1)),
arg(s,2));
}
if(op(s) == Leq && arg(s,1) == make_int(rational(0)) && arg(s,2) == make_int(rational(0)))
return s;
return make(sum,make(Leq,make_int(rational(0)),make_int(rational(0))),coeff,s);
}
ast simplify_sum(std::vector<ast> &args){ ast simplify_sum(std::vector<ast> &args){
if(args[1] != make_int(rational(1))){
if(sym(args[2]) == sum)
return make(sum,args[0],make_int(rational(1)),distribute_coeff(args[1],args[2]));
}
ast Aproves = mk_true(), Bproves = mk_true(); ast Aproves = mk_true(), Bproves = mk_true();
ast ineq = destruct_cond_ineq(args[0],Aproves,Bproves); ast ineq = destruct_cond_ineq(args[0],Aproves,Bproves);
if(!is_normal_ineq(ineq)) throw cannot_simplify(); if(!is_normal_ineq(ineq)) throw cannot_simplify();
@ -757,6 +779,22 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast Bcond = my_implies(Bproves1,my_and(Aproves1,z3_simplify(ineq2))); ast Bcond = my_implies(Bproves1,my_and(Aproves1,z3_simplify(ineq2)));
// if(!is_true(Aproves1) || !is_true(Bproves1)) // if(!is_true(Aproves1) || !is_true(Bproves1))
// std::cout << "foo!\n";; // std::cout << "foo!\n";;
if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){
if(get_term_type(arg(x,0)) == LitA){
ast iter = z3_simplify(make(Plus,arg(x,0),get_ineq_rhs(xleqy)));
ast rewrite1 = make_rewrite(LitA,pos_add(0,top_pos),Acond,make(Equal,arg(x,0),iter));
iter = make(Plus,iter,arg(x,1));
ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y));
return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2);
}
if(get_term_type(arg(x,1)) == LitA){
ast iter = z3_simplify(make(Plus,arg(x,1),get_ineq_rhs(xleqy)));
ast rewrite1 = make_rewrite(LitA,pos_add(1,top_pos),Acond,make(Equal,arg(x,1),iter));
iter = make(Plus,arg(x,0),iter);
ast rewrite2 = make_rewrite(LitB,top_pos,Bcond,make(Equal,iter,y));
return chain_cons(chain_cons(mk_true(),rewrite1),rewrite2);
}
}
if(get_term_type(x) == LitA){ if(get_term_type(x) == LitA){
ast iter = z3_simplify(make(Plus,x,get_ineq_rhs(xleqy))); ast iter = z3_simplify(make(Plus,x,get_ineq_rhs(xleqy)));
ast rewrite1 = make_rewrite(LitA,top_pos,Acond,make(Equal,x,iter)); ast rewrite1 = make_rewrite(LitA,top_pos,Acond,make(Equal,x,iter));
@ -1014,6 +1052,7 @@ class iz3proof_itp_impl : public iz3proof_itp {
coeff = argpos ? make_int(rational(-1)) : make_int(rational(1)); coeff = argpos ? make_int(rational(-1)) : make_int(rational(1));
break; break;
case Not: case Not:
coeff = make_int(rational(-1));
case Plus: case Plus:
break; break;
case Times: case Times:
@ -2568,12 +2607,17 @@ class iz3proof_itp_impl : public iz3proof_itp {
break; break;
default: { // mixed equality default: { // mixed equality
if(get_term_type(x) == LitMixed || get_term_type(y) == LitMixed){ if(get_term_type(x) == LitMixed || get_term_type(y) == LitMixed){
// std::cerr << "WARNING: mixed term in leq2eq\n"; if(y == make_int(rational(0)) && op(x) == Plus && num_args(x) == 2){
std::vector<ast> lits; // std::cerr << "WARNING: untested case in leq2eq\n";
lits.push_back(con); }
lits.push_back(make(Not,xleqy)); else {
lits.push_back(make(Not,yleqx)); // std::cerr << "WARNING: mixed term in leq2eq\n";
return make_axiom(lits); std::vector<ast> lits;
lits.push_back(con);
lits.push_back(make(Not,xleqy));
lits.push_back(make(Not,yleqx));
return make_axiom(lits);
}
} }
std::vector<ast> conjs; conjs.resize(3); std::vector<ast> conjs; conjs.resize(3);
conjs[0] = mk_not(con); conjs[0] = mk_not(con);
@ -2655,8 +2699,13 @@ class iz3proof_itp_impl : public iz3proof_itp {
}; };
std::vector<LocVar> localization_vars; // localization vars in order of creation std::vector<LocVar> localization_vars; // localization vars in order of creation
hash_map<ast,ast> localization_map; // maps terms to their localization vars
hash_map<ast,ast> localization_pf_map; // maps terms to proofs of their localizations struct locmaps {
hash_map<ast,ast> localization_map; // maps terms to their localization vars
hash_map<ast,ast> localization_pf_map; // maps terms to proofs of their localizations
};
hash_map<prover::range,locmaps> localization_maps_per_range;
/* "localize" a term e to a given frame range, creating new symbols to /* "localize" a term e to a given frame range, creating new symbols to
represent non-local subterms. This returns the localized version e_l, represent non-local subterms. This returns the localized version e_l,
@ -2677,7 +2726,24 @@ class iz3proof_itp_impl : public iz3proof_itp {
return make(Equal,x,y); return make(Equal,x,y);
} }
bool range_is_global(const prover::range &r){
if(pv->range_contained(r,rng))
return false;
if(!pv->ranges_intersect(r,rng))
return false;
return true;
}
ast localize_term(ast e, const prover::range &rng, ast &pf){ ast localize_term(ast e, const prover::range &rng, ast &pf){
// we need to memoize this function separately for A, B and global
prover::range map_range = rng;
if(range_is_global(map_range))
map_range = pv->range_full();
locmaps &maps = localization_maps_per_range[map_range];
hash_map<ast,ast> &localization_map = maps.localization_map;
hash_map<ast,ast> &localization_pf_map = maps.localization_pf_map;
ast orig_e = e; ast orig_e = e;
pf = make_refl(e); // proof that e = e pf = make_refl(e); // proof that e = e
@ -2764,6 +2830,21 @@ class iz3proof_itp_impl : public iz3proof_itp {
ast bar = make_assumption(frame,foo); ast bar = make_assumption(frame,foo);
pf = make_transitivity(new_var,e,orig_e,bar,pf); pf = make_transitivity(new_var,e,orig_e,bar,pf);
localization_pf_map[orig_e] = pf; localization_pf_map[orig_e] = pf;
// HACK: try to bias this term in the future
if(!pv->range_is_full(rng)){
prover::range rf = pv->range_full();
locmaps &fmaps = localization_maps_per_range[rf];
hash_map<ast,ast> &flocalization_map = fmaps.localization_map;
hash_map<ast,ast> &flocalization_pf_map = fmaps.localization_pf_map;
// if(flocalization_map.find(orig_e) == flocalization_map.end())
{
flocalization_map[orig_e] = new_var;
flocalization_pf_map[orig_e] = pf;
}
}
return new_var; return new_var;
} }

View file

@ -23,6 +23,7 @@ Revision History:
#include <vector> #include <vector>
#include <limits.h> #include <limits.h>
#include "iz3hash.h"
class scopes { class scopes {
@ -63,6 +64,11 @@ class scopes {
return rng.hi < rng.lo; return rng.hi < rng.lo;
} }
/** is this range full? */
bool range_is_full(const range &rng){
return rng.lo == SHRT_MIN && rng.hi == SHRT_MAX;
}
/** return an empty range */ /** return an empty range */
range range_empty(){ range range_empty(){
range res; range res;
@ -194,4 +200,23 @@ class scopes {
}; };
// let us hash on ranges
#ifndef FULL_TREE
namespace hash_space {
template <>
class hash<scopes::range> {
public:
size_t operator()(const scopes::range &p) const {
return (size_t)p.lo + (size_t)p.hi;
}
};
}
inline bool operator==(const scopes::range &x, const scopes::range &y){
return x.lo == y.lo && x.hi == y.hi;
}
#endif
#endif #endif

View file

@ -1058,36 +1058,66 @@ public:
} }
rational get_first_coefficient(const ast &t, ast &v){
if(op(t) == Plus){
unsigned best_id = UINT_MAX;
rational best_coeff(0);
int nargs = num_args(t);
for(int i = 0; i < nargs; i++)
if(op(arg(t,i)) != Numeral){
ast lv = get_linear_var(arg(t,i));
unsigned id = ast_id(lv);
if(id < best_id) {
v = lv;
best_id = id;
best_coeff = get_coeff(arg(t,i));
}
}
return best_coeff;
}
else
if(op(t) != Numeral)
return(get_coeff(t));
return rational(0);
}
ast divide_inequalities(const ast &x, const ast&y){ ast divide_inequalities(const ast &x, const ast&y){
std::vector<rational> xcoeffs,ycoeffs; ast xvar, yvar;
get_linear_coefficients(arg(x,1),xcoeffs); rational xcoeff = get_first_coefficient(arg(x,0),xvar);
get_linear_coefficients(arg(y,1),ycoeffs); rational ycoeff = get_first_coefficient(arg(y,0),yvar);
if(xcoeffs.size() != ycoeffs.size() || xcoeffs.size() == 0) if(xcoeff == rational(0) || ycoeff == rational(0) || xvar != yvar)
throw "bad assign-bounds lemma";
rational ratio = xcoeff/ycoeff;
if(denominator(ratio) != rational(1))
throw "bad assign-bounds lemma"; throw "bad assign-bounds lemma";
rational ratio = xcoeffs[0]/ycoeffs[0];
return make_int(ratio); // better be integer! return make_int(ratio); // better be integer!
} }
ast AssignBounds2Farkas(const ast &proof, const ast &con){ ast AssignBounds2Farkas(const ast &proof, const ast &con){
std::vector<ast> farkas_coeffs; std::vector<ast> farkas_coeffs;
get_assign_bounds_coeffs(proof,farkas_coeffs); get_assign_bounds_coeffs(proof,farkas_coeffs);
std::vector<ast> lits;
int nargs = num_args(con); int nargs = num_args(con);
if(nargs != (int)(farkas_coeffs.size())) if(nargs != (int)(farkas_coeffs.size()))
throw "bad assign-bounds theory lemma"; throw "bad assign-bounds theory lemma";
#if 0 #if 0
for(int i = 1; i < nargs; i++) if(farkas_coeffs[0] != make_int(rational(1)))
lits.push_back(mk_not(arg(con,i))); farkas_coeffs[0] = make_int(rational(1));
ast sum = sum_inequalities(farkas_coeffs,lits);
ast conseq = rhs_normalize_inequality(arg(con,0));
ast d = divide_inequalities(sum,conseq);
std::vector<ast> my_coeffs;
my_coeffs.push_back(d);
for(unsigned i = 0; i < farkas_coeffs.size(); i++)
my_coeffs.push_back(farkas_coeffs[i]);
#else #else
std::vector<ast> my_coeffs; std::vector<ast> lits, lit_coeffs;
for(int i = 1; i < nargs; i++){
lits.push_back(mk_not(arg(con,i)));
lit_coeffs.push_back(farkas_coeffs[i]);
}
ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits));
ast conseq = normalize_inequality(arg(con,0));
ast d = divide_inequalities(sum,conseq);
#if 0
if(d != farkas_coeffs[0])
std::cout << "wow!\n";
#endif #endif
farkas_coeffs[0] = d;
#endif
std::vector<ast> my_coeffs;
std::vector<ast> my_cons; std::vector<ast> my_cons;
for(int i = 1; i < nargs; i++){ for(int i = 1; i < nargs; i++){
my_cons.push_back(mk_not(arg(con,i))); my_cons.push_back(mk_not(arg(con,i)));
@ -1107,10 +1137,27 @@ public:
ast AssignBoundsRule2Farkas(const ast &proof, const ast &con, std::vector<Iproof::node> prems){ ast AssignBoundsRule2Farkas(const ast &proof, const ast &con, std::vector<Iproof::node> prems){
std::vector<ast> farkas_coeffs; std::vector<ast> farkas_coeffs;
get_assign_bounds_rule_coeffs(proof,farkas_coeffs); get_assign_bounds_rule_coeffs(proof,farkas_coeffs);
std::vector<ast> lits;
int nargs = num_prems(proof)+1; int nargs = num_prems(proof)+1;
if(nargs != (int)(farkas_coeffs.size())) if(nargs != (int)(farkas_coeffs.size()))
throw "bad assign-bounds theory lemma"; throw "bad assign-bounds theory lemma";
#if 0
if(farkas_coeffs[0] != make_int(rational(1)))
farkas_coeffs[0] = make_int(rational(1));
#else
std::vector<ast> lits, lit_coeffs;
for(int i = 1; i < nargs; i++){
lits.push_back(conc(prem(proof,i-1)));
lit_coeffs.push_back(farkas_coeffs[i]);
}
ast sum = normalize_inequality(sum_inequalities(lit_coeffs,lits));
ast conseq = normalize_inequality(con);
ast d = divide_inequalities(sum,conseq);
#if 0
if(d != farkas_coeffs[0])
std::cout << "wow!\n";
#endif
farkas_coeffs[0] = d;
#endif
std::vector<ast> my_coeffs; std::vector<ast> my_coeffs;
std::vector<ast> my_cons; std::vector<ast> my_cons;
for(int i = 1; i < nargs; i++){ for(int i = 1; i < nargs; i++){
@ -1278,6 +1325,17 @@ public:
return make(Plus,args); return make(Plus,args);
} }
void get_sum_as_vector(const ast &t, std::vector<rational> &coeffs, std::vector<ast> &vars){
if(!(op(t) == Plus)){
coeffs.push_back(get_coeff(t));
vars.push_back(get_linear_var(t));
}
else {
int nargs = num_args(t);
for(int i = 0; i < nargs; i++)
get_sum_as_vector(arg(t,i),coeffs,vars);
}
}
ast replace_summands_with_fresh_vars(const ast &t, hash_map<ast,ast> &map){ ast replace_summands_with_fresh_vars(const ast &t, hash_map<ast,ast> &map){
if(op(t) == Plus){ if(op(t) == Plus){
@ -1294,6 +1352,99 @@ public:
return map[t]; return map[t];
} }
rational lcd(const std::vector<rational> &rats){
rational res = rational(1);
for(unsigned i = 0; i < rats.size(); i++){
res = lcm(res,denominator(rats[i]));
}
return res;
}
Iproof::node reconstruct_farkas_with_dual(const std::vector<ast> &prems, const std::vector<Iproof::node> &pfs, const ast &con){
int nprems = prems.size();
std::vector<ast> npcons(nprems);
hash_map<ast,ast> pain_map; // not needed
for(int i = 0; i < nprems; i++){
npcons[i] = painfully_normalize_ineq(conc(prems[i]),pain_map);
if(op(npcons[i]) == Lt){
ast constval = z3_simplify(make(Sub,arg(npcons[i],1),make_int(rational(1))));
npcons[i] = make(Leq,arg(npcons[i],0),constval);
}
}
ast ncon = painfully_normalize_ineq(mk_not(con),pain_map);
npcons.push_back(ncon);
hash_map<ast,ast> dual_map;
std::vector<ast> cvec, vars_seen;
ast rhs = make_real(rational(0));
for(unsigned i = 0; i < npcons.size(); i++){
ast c= mk_fresh_constant("@c",real_type());
cvec.push_back(c);
ast lhs = arg(npcons[i],0);
std::vector<rational> coeffs;
std::vector<ast> vars;
get_sum_as_vector(lhs,coeffs,vars);
for(unsigned j = 0; j < coeffs.size(); j++){
rational coeff = coeffs[j];
ast var = vars[j];
if(dual_map.find(var) == dual_map.end()){
dual_map[var] = make_real(rational(0));
vars_seen.push_back(var);
}
ast foo = make(Plus,dual_map[var],make(Times,make_real(coeff),c));
dual_map[var] = foo;
}
rhs = make(Plus,rhs,make(Times,c,arg(npcons[i],1)));
}
std::vector<ast> cnstrs;
for(unsigned i = 0; i < vars_seen.size(); i++)
cnstrs.push_back(make(Equal,dual_map[vars_seen[i]],make_real(rational(0))));
cnstrs.push_back(make(Leq,rhs,make_real(rational(0))));
for(unsigned i = 0; i < cvec.size() - 1; i++)
cnstrs.push_back(make(Geq,cvec[i],make_real(rational(0))));
cnstrs.push_back(make(Equal,cvec.back(),make_real(rational(1))));
ast new_proof;
// greedily reduce the core
for(unsigned i = 0; i < cvec.size() - 1; i++){
std::vector<ast> dummy;
cnstrs.push_back(make(Equal,cvec[i],make_real(rational(0))));
if(!is_sat(cnstrs,new_proof,dummy))
cnstrs.pop_back();
}
std::vector<ast> vals = cvec;
if(!is_sat(cnstrs,new_proof,vals))
throw "Proof error!";
std::vector<rational> rat_farkas_coeffs;
for(unsigned i = 0; i < cvec.size(); i++){
ast bar = vals[i];
rational r;
if(is_numeral(bar,r))
rat_farkas_coeffs.push_back(r);
else
throw "Proof error!";
}
rational the_lcd = lcd(rat_farkas_coeffs);
std::vector<ast> farkas_coeffs;
std::vector<Iproof::node> my_prems;
std::vector<ast> my_pcons;
for(unsigned i = 0; i < prems.size(); i++){
ast fc = make_int(rat_farkas_coeffs[i] * the_lcd);
if(!(fc == make_int(rational(0)))){
farkas_coeffs.push_back(fc);
my_prems.push_back(pfs[i]);
my_pcons.push_back(conc(prems[i]));
}
}
farkas_coeffs.push_back(make_int(the_lcd));
my_prems.push_back(iproof->make_hypothesis(mk_not(con)));
my_pcons.push_back(mk_not(con));
Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs);
return res;
}
ast painfully_normalize_ineq(const ast &ineq, hash_map<ast,ast> &map){ ast painfully_normalize_ineq(const ast &ineq, hash_map<ast,ast> &map){
ast res = normalize_inequality(ineq); ast res = normalize_inequality(ineq);
ast lhs = arg(res,0); ast lhs = arg(res,0);
@ -1318,7 +1469,8 @@ public:
npcons.push_back(ncon); npcons.push_back(ncon);
// ast assumps = make(And,pcons); // ast assumps = make(And,pcons);
ast new_proof; ast new_proof;
if(is_sat(npcons,new_proof)) std::vector<ast> dummy;
if(is_sat(npcons,new_proof,dummy))
throw "Proof error!"; throw "Proof error!";
pfrule dk = pr(new_proof); pfrule dk = pr(new_proof);
int nnp = num_prems(new_proof); int nnp = num_prems(new_proof);
@ -1334,7 +1486,7 @@ public:
farkas_coeffs.push_back(make_int(rational(1))); farkas_coeffs.push_back(make_int(rational(1)));
} }
else else
throw "cannot reconstruct farkas proof"; return reconstruct_farkas_with_dual(prems,pfs,con);
for(int i = 0; i < nnp; i++){ for(int i = 0; i < nnp; i++){
ast p = conc(prem(new_proof,i)); ast p = conc(prem(new_proof,i));
@ -1348,7 +1500,7 @@ public:
my_pcons.push_back(mk_not(con)); my_pcons.push_back(mk_not(con));
} }
else else
throw "cannot reconstruct farkas proof"; return reconstruct_farkas_with_dual(prems,pfs,con);
} }
Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs);
return res; return res;
@ -1378,7 +1530,8 @@ public:
npcons.push_back(ncon); npcons.push_back(ncon);
// ast assumps = make(And,pcons); // ast assumps = make(And,pcons);
ast new_proof; ast new_proof;
if(is_sat(npcons,new_proof)) std::vector<ast> dummy;
if(is_sat(npcons,new_proof,dummy))
throw "Proof error!"; throw "Proof error!";
pfrule dk = pr(new_proof); pfrule dk = pr(new_proof);
int nnp = num_prems(new_proof); int nnp = num_prems(new_proof);
@ -1408,7 +1561,7 @@ public:
my_pcons.push_back(mk_not(con)); my_pcons.push_back(mk_not(con));
} }
else else
throw "cannot reconstruct farkas proof"; return painfully_reconstruct_farkas(prems,pfs,con);
} }
Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs); Iproof::node res = iproof->make_farkas(mk_false(),my_prems,my_pcons,farkas_coeffs);
return res; return res;
@ -1433,6 +1586,12 @@ public:
return res; return res;
} }
ast ArithMysteryRule(const ast &con, const std::vector<ast> &prems, const std::vector<Iproof::node> &args){
// Hope for the best!
Iproof::node guess = reconstruct_farkas(prems,args,con);
return guess;
}
struct CannotCombineEqPropagate {}; struct CannotCombineEqPropagate {};
void CombineEqPropagateRec(const ast &proof, std::vector<ast> &prems, std::vector<Iproof::node> &args, ast &eqprem){ void CombineEqPropagateRec(const ast &proof, std::vector<ast> &prems, std::vector<Iproof::node> &args, ast &eqprem){
@ -1552,6 +1711,13 @@ public:
if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or) if(dk == PR_MODUS_PONENS && expect_clause && op(con) == Or)
std::cout << "foo!\n"; std::cout << "foo!\n";
// no idea why this shows up
if(dk == PR_MODUS_PONENS_OEQ)
if(conc(prem(proof,0)) == con){
res = translate_main(prem(proof,0),expect_clause);
return res;
}
#if 0 #if 0
if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,1)) == PR_COMMUTATIVITY){ if(1 && dk == PR_TRANSITIVITY && pr(prem(proof,1)) == PR_COMMUTATIVITY){
Iproof::node clause = translate_main(prem(proof,0),true); Iproof::node clause = translate_main(prem(proof,0),true);
@ -1737,6 +1903,14 @@ public:
res = EqPropagate(con,prems,args); res = EqPropagate(con,prems,args);
break; break;
} }
case ArithMysteryKind: {
// Z3 hasn't told us what kind of lemma this is -- maybe we can guess
std::vector<ast> prems(nprems);
for(unsigned i = 0; i < nprems; i++)
prems[i] = prem(proof,i);
res = ArithMysteryRule(con,prems,args);
break;
}
default: default:
throw unsupported(); throw unsupported();
} }

View file

@ -174,10 +174,11 @@ namespace simplex {
var_t select_pivot_core(var_t x_i, bool is_below, scoped_numeral& out_a_ij); var_t select_pivot_core(var_t x_i, bool is_below, scoped_numeral& out_a_ij);
int get_num_non_free_dep_vars(var_t x_j, int best_so_far); int get_num_non_free_dep_vars(var_t x_j, int best_so_far);
var_t pick_var_to_leave(var_t x_j, bool inc, scoped_eps_numeral& gain, scoped_numeral& new_a_ij); var_t pick_var_to_leave(var_t x_j, bool is_pos,
scoped_eps_numeral& gain, scoped_numeral& new_a_ij, bool& inc);
void select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij, bool& inc); void select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij, bool& inc_x_i, bool& inc_x_j);
bool at_lower(var_t v) const; bool at_lower(var_t v) const;

View file

@ -646,13 +646,13 @@ namespace simplex {
scoped_eps_numeral delta(em); scoped_eps_numeral delta(em);
scoped_numeral a_ij(m); scoped_numeral a_ij(m);
var_t x_i, x_j; var_t x_i, x_j;
bool inc; bool inc_x_i, inc_x_j;
while (true) { while (true) {
if (m_cancel) { if (m_cancel) {
return l_undef; return l_undef;
} }
select_pivot_primal(v, x_i, x_j, a_ij, inc); select_pivot_primal(v, x_i, x_j, a_ij, inc_x_i, inc_x_j);
if (x_j == null_var) { if (x_j == null_var) {
// optimal // optimal
return l_true; return l_true;
@ -660,12 +660,12 @@ namespace simplex {
TRACE("simplex", tout << "x_i: v" << x_i << " x_j: v" << x_j << "\n";); TRACE("simplex", tout << "x_i: v" << x_i << " x_j: v" << x_j << "\n";);
var_info& vj = m_vars[x_j]; var_info& vj = m_vars[x_j];
if (x_i == null_var) { if (x_i == null_var) {
if (inc && vj.m_upper_valid) { if (inc_x_j && vj.m_upper_valid) {
delta = vj.m_upper; delta = vj.m_upper;
delta -= vj.m_value; delta -= vj.m_value;
update_value(x_j, delta); update_value(x_j, delta);
} }
else if (!inc && vj.m_lower_valid) { else if (!inc_x_j && vj.m_lower_valid) {
delta = vj.m_lower; delta = vj.m_lower;
delta -= vj.m_value; delta -= vj.m_value;
update_value(x_j, delta); update_value(x_j, delta);
@ -686,7 +686,7 @@ namespace simplex {
pivot(x_i, x_j, a_ij); pivot(x_i, x_j, a_ij);
TRACE("simplex", display(tout << "after pivot\n");); TRACE("simplex", display(tout << "after pivot\n"););
move_to_bound(x_i, !inc); move_to_bound(x_i, !inc_x_i);
SASSERT(well_formed_row(row(m_vars[x_j].m_base2row))); SASSERT(well_formed_row(row(m_vars[x_j].m_base2row)));
TRACE("simplex", display(tout);); TRACE("simplex", display(tout););
SASSERT(is_feasible()); SASSERT(is_feasible());
@ -705,7 +705,7 @@ namespace simplex {
em.sub(vi.m_upper, vi.m_value, delta); em.sub(vi.m_upper, vi.m_value, delta);
} }
TRACE("simplex", tout << "move " << (to_lower?"to_lower":"to_upper") TRACE("simplex", tout << "move " << (to_lower?"to_lower":"to_upper")
<< " v" << x << " " << em.to_string(delta) << "\n";); << " v" << x << " delta: " << em.to_string(delta) << "\n";);
col_iterator it = M.col_begin(x), end = M.col_end(x); col_iterator it = M.col_begin(x), end = M.col_end(x);
for (; it != end && is_pos(delta); ++it) { for (; it != end && is_pos(delta); ++it) {
// //
@ -756,10 +756,11 @@ namespace simplex {
x_i - base variable of row(x_i) to become non-base x_i - base variable of row(x_i) to become non-base
x_j - variable in row(v) to make a base variable x_j - variable in row(v) to make a base variable
a_ij - coefficient to x_j in row(x_i) a_ij - coefficient to x_j in row(x_i)
inc - whether to increment x_j (true if coefficient in row(v) is negative). inc - whether to increment x_i
*/ */
template<typename Ext> template<typename Ext>
void simplex<Ext>::select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij, bool& inc) { void simplex<Ext>::select_pivot_primal(var_t v, var_t& x_i, var_t& x_j, scoped_numeral& a_ij,
bool& inc_x_i, bool& inc_x_j) {
row r(m_vars[v].m_base2row); row r(m_vars[v].m_base2row);
row_iterator it = M.row_begin(r), end = M.row_end(r); row_iterator it = M.row_begin(r), end = M.row_end(r);
@ -767,25 +768,27 @@ namespace simplex {
scoped_numeral new_a_ij(m); scoped_numeral new_a_ij(m);
x_i = null_var; x_i = null_var;
x_j = null_var; x_j = null_var;
inc = false; inc_x_i = false;
bool inc_y = false;
for (; it != end; ++it) { for (; it != end; ++it) {
var_t x = it->m_var; var_t x = it->m_var;
if (x == v) continue; if (x == v) continue;
bool is_pos = m.is_pos(it->m_coeff) == m.is_pos(m_vars[v].m_base_coeff); bool inc_x = m.is_pos(it->m_coeff) == m.is_pos(m_vars[v].m_base_coeff);
if ((is_pos && at_upper(x)) || (!is_pos && at_lower(x))) { if ((inc_x && at_upper(x)) || (!inc_x && at_lower(x))) {
TRACE("simplex", tout << "v" << x << " pos: " << is_pos TRACE("simplex", tout << "v" << x << " pos: " << inc_x
<< " at upper: " << at_upper(x) << " at upper: " << at_upper(x)
<< " at lower: " << at_lower(x) << "\n";); << " at lower: " << at_lower(x) << "\n";);
continue; // variable cannot be used for improving bounds. continue; // variable cannot be used for improving bounds.
// TBD check? // TBD check?
} }
var_t y = pick_var_to_leave(x, is_pos, new_gain, new_a_ij); var_t y = pick_var_to_leave(x, inc_x, new_gain, new_a_ij, inc_y);
if (y == null_var) { if (y == null_var) {
// unbounded. // unbounded.
x_i = y; x_i = y;
x_j = x; x_j = x;
inc = is_pos; inc_x_i = inc_y;
inc_x_j = inc_x;
a_ij = new_a_ij; a_ij = new_a_ij;
break; break;
} }
@ -794,20 +797,39 @@ namespace simplex {
((is_zero(new_gain) && is_zero(gain) && (x_i == null_var || y < x_i))); ((is_zero(new_gain) && is_zero(gain) && (x_i == null_var || y < x_i)));
if (better) { if (better) {
TRACE("simplex",
em.display(tout << "gain:", gain);
em.display(tout << " new gain:", new_gain);
tout << " base x_i: " << y << ", new base x_j: " << x << ", inc x_j: " << inc_x << "\n";);
x_i = y; x_i = y;
x_j = x; x_j = x;
inc = is_pos; inc_x_i = inc_y;
inc_x_j = inc_x;
gain = new_gain; gain = new_gain;
a_ij = new_a_ij; a_ij = new_a_ij;
} }
} }
} }
//
// y is a base variable.
// v is a base variable.
// v*a_v + x*a_x + E = 0
// y*b_y + x*b_x + F = 0
// inc(x) := sign(a_v) == sign(a_x)
// sign_eq := sign(b_y) == sign(b_x)
// sign_eq => (inc(x) != inc(y))
// !sign_eq => (inc(x) = inc(y))
// ->
// inc(y) := sign_eq != inc(x)
//
template<typename Ext> template<typename Ext>
typename simplex<Ext>::var_t typename simplex<Ext>::var_t
simplex<Ext>::pick_var_to_leave( simplex<Ext>::pick_var_to_leave(
var_t x_j, bool inc, var_t x_j, bool inc_x_j,
scoped_eps_numeral& gain, scoped_numeral& new_a_ij) { scoped_eps_numeral& gain, scoped_numeral& new_a_ij, bool& inc_x_i) {
var_t x_i = null_var; var_t x_i = null_var;
gain.reset(); gain.reset();
scoped_eps_numeral curr_gain(em); scoped_eps_numeral curr_gain(em);
@ -818,10 +840,13 @@ namespace simplex {
var_info& vi = m_vars[s]; var_info& vi = m_vars[s];
numeral const& a_ij = it.get_row_entry().m_coeff; numeral const& a_ij = it.get_row_entry().m_coeff;
numeral const& a_ii = vi.m_base_coeff; numeral const& a_ii = vi.m_base_coeff;
bool inc_s = (m.is_pos(a_ii) != m.is_pos(a_ij)) ? inc : !inc; bool sign_eq = (m.is_pos(a_ii) == m.is_pos(a_ij));
TRACE("simplex", tout << "v" << x_j << " base v" << s << " incs: " << inc_s bool inc_s = sign_eq != inc_x_j;
<< " upper valid:" << vi.m_upper_valid TRACE("simplex", tout << "x_j: v" << x_j << ", base x_i: v" << s
<< " lower valid:" << vi.m_lower_valid << "\n"; << ", inc_x_i: " << inc_s
<< ", inc_x_j: " << inc_x_j
<< ", upper valid:" << vi.m_upper_valid
<< ", lower valid:" << vi.m_lower_valid << "\n";
display_row(tout, r);); display_row(tout, r););
if ((inc_s && !vi.m_upper_valid) || (!inc_s && !vi.m_lower_valid)) { if ((inc_s && !vi.m_upper_valid) || (!inc_s && !vi.m_lower_valid)) {
continue; continue;
@ -841,6 +866,7 @@ namespace simplex {
x_i = s; x_i = s;
gain = curr_gain; gain = curr_gain;
new_a_ij = a_ij; new_a_ij = a_ij;
inc_x_i = inc_s;
TRACE("simplex", tout << "x_j v" << x_j << " x_i v" << x_i << " gain: "; TRACE("simplex", tout << "x_j v" << x_j << " x_i v" << x_i << " gain: ";
tout << curr_gain << "\n";); tout << curr_gain << "\n";);
} }

View file

@ -133,7 +133,9 @@ bool model::eval(expr * e, expr_ref & result, bool model_completion) {
ev(e, result); ev(e, result);
return true; return true;
} }
catch (model_evaluator_exception &) { catch (model_evaluator_exception & ex) {
(void)ex;
TRACE("model_evaluator", tout << ex.msg() << "\n";);
return false; return false;
} }
} }

View file

@ -278,6 +278,12 @@ namespace datalog {
void register_variable(func_decl* var); void register_variable(func_decl* var);
/*
Replace constants that have been registered as
variables by de-Bruijn indices and corresponding
universal (if is_forall is true) or existential
quantifier.
*/
expr_ref bind_variables(expr* fml, bool is_forall); expr_ref bind_variables(expr* fml, bool is_forall);
/** /**

View file

@ -77,6 +77,7 @@ def_module_params('fixedpoint',
('mbqi', BOOL, True, 'DUALITY: use model-based quantifier instantion'), ('mbqi', BOOL, True, 'DUALITY: use model-based quantifier instantion'),
('batch_expand', BOOL, False, 'DUALITY: use batch expansion'), ('batch_expand', BOOL, False, 'DUALITY: use batch expansion'),
('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'), ('dump_aig', SYMBOL, '', 'Dump clauses in AIG text format (AAG) to the given file name'),
('conjecture_file', STRING, '', 'DUALITY: save conjectures to file'),
)) ))

View file

@ -35,6 +35,7 @@ Revision History:
#include "model_smt2_pp.h" #include "model_smt2_pp.h"
#include "model_v2_pp.h" #include "model_v2_pp.h"
#include "fixedpoint_params.hpp" #include "fixedpoint_params.hpp"
#include "used_vars.h"
// template class symbol_table<family_id>; // template class symbol_table<family_id>;
@ -164,6 +165,20 @@ lbool dl_interface::query(::expr * query) {
clauses.push_back(e); clauses.push_back(e);
} }
std::vector<sort> b_sorts;
std::vector<symbol> b_names;
used_vars uv;
uv.process(query);
unsigned nuv = uv.get_max_found_var_idx_plus_1();
for(int i = nuv-1; i >= 0; i--){ // var indices are backward
::sort * s = uv.get(i);
if(!s)
s = _d->ctx.m().mk_bool_sort(); // missing var, whatever
b_sorts.push_back(sort(_d->ctx,s));
b_names.push_back(symbol(_d->ctx,::symbol(i))); // names?
}
#if 0
// turn the query into a clause // turn the query into a clause
expr q(_d->ctx,m_ctx.bind_variables(query,false)); expr q(_d->ctx,m_ctx.bind_variables(query,false));
@ -177,6 +192,9 @@ lbool dl_interface::query(::expr * query) {
} }
q = q.arg(0); q = q.arg(0);
} }
#else
expr q(_d->ctx,query);
#endif
expr qc = implies(q,_d->ctx.bool_val(false)); expr qc = implies(q,_d->ctx.bool_val(false));
qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc); qc = _d->ctx.make_quant(Forall,b_sorts,b_names,qc);
@ -211,6 +229,7 @@ lbool dl_interface::query(::expr * query) {
rs->SetOption("use_underapprox",m_ctx.get_params().use_underapprox() ? "1" : "0"); rs->SetOption("use_underapprox",m_ctx.get_params().use_underapprox() ? "1" : "0");
rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0"); rs->SetOption("stratified_inlining",m_ctx.get_params().stratified_inlining() ? "1" : "0");
rs->SetOption("batch_expand",m_ctx.get_params().batch_expand() ? "1" : "0"); rs->SetOption("batch_expand",m_ctx.get_params().batch_expand() ? "1" : "0");
rs->SetOption("conjecture_file",m_ctx.get_params().conjecture_file());
unsigned rb = m_ctx.get_params().recursion_bound(); unsigned rb = m_ctx.get_params().recursion_bound();
if(rb != UINT_MAX){ if(rb != UINT_MAX){
std::ostringstream os; os << rb; std::ostringstream os; os << rb;
@ -350,7 +369,9 @@ void dl_interface::display_certificate_non_const(std::ostream& out) {
if(_d->status == StatusModel){ if(_d->status == StatusModel){
ast_manager &m = m_ctx.get_manager(); ast_manager &m = m_ctx.get_manager();
model_ref md = get_model(); model_ref md = get_model();
out << "(fixedpoint \n";
model_smt2_pp(out, m, *md.get(), 0); model_smt2_pp(out, m, *md.get(), 0);
out << ")\n";
} }
else if(_d->status == StatusRefutation){ else if(_d->status == StatusRefutation){
out << "(derivation\n"; out << "(derivation\n";

View file

@ -205,7 +205,6 @@ namespace datalog {
for (unsigned i = 0; i < rules.size(); ++i) { for (unsigned i = 0; i < rules.size(); ++i) {
app* head = rules[i]->get_head(); app* head = rules[i]->get_head();
expr_ref_vector conj(m); expr_ref_vector conj(m);
unsigned n = head->get_num_args()-1;
for (unsigned j = 0; j < head->get_num_args(); ++j) { for (unsigned j = 0; j < head->get_num_args(); ++j) {
expr* arg = head->get_arg(j); expr* arg = head->get_arg(j);
if (!is_var(arg)) { if (!is_var(arg)) {

370
src/opt/hitting_sets.cpp Normal file
View file

@ -0,0 +1,370 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
hitting_sets.h
Abstract:
Hitting set approximations.
Author:
Nikolaj Bjorner (nbjorner) 2014-06-06
Notes:
--*/
#include "vector.h"
#include "util.h"
#include "hitting_sets.h"
#include "simplex.h"
#include "sparse_matrix_def.h"
#include "simplex_def.h"
typedef simplex::simplex<simplex::mpz_ext> Simplex;
typedef simplex::sparse_matrix<simplex::mpz_ext> sparse_matrix;
namespace opt {
struct hitting_sets::imp {
typedef unsigned_vector set;
volatile bool m_cancel;
rational m_lower;
rational m_upper;
vector<rational> m_weights;
rational m_max_weight;
rational m_denominator;
vector<set> m_S;
svector<lbool> m_value;
unsigned_vector m_value_trail;
unsigned_vector m_value_lim;
vector<unsigned_vector> m_use_list;
unsynch_mpz_manager m;
Simplex m_simplex;
unsigned m_weights_var;
imp():m_cancel(false) {}
~imp() {}
void add_weight(rational const& w) {
SASSERT(w.is_pos());
unsigned var = m_weights.size();
m_simplex.ensure_var(var);
m_simplex.set_lower(var, mpq_inf(mpq(0),mpq(0)));
m_simplex.set_upper(var, mpq_inf(mpq(1),mpq(0)));
m_weights.push_back(w);
m_value.push_back(l_undef);
m_use_list.push_back(unsigned_vector());
m_max_weight += w;
}
void add_set(unsigned sz, unsigned const* S) {
if (sz == 0) {
return;
}
for (unsigned i = 0; i < sz; ++i) {
m_use_list[S[i]].push_back(m_S.size());
}
init_weights();
m_S.push_back(unsigned_vector(sz, S));
add_simplex_row(sz, S);
}
bool compute_lower() {
m_lower.reset();
return L1() && L2() && L3();
}
bool compute_upper() {
m_upper = m_max_weight;
return U1();
}
rational get_lower() {
return m_lower/m_denominator;
}
rational get_upper() {
return m_upper/m_denominator;
}
void set_cancel(bool f) {
m_cancel = f;
m_simplex.set_cancel(f);
}
void collect_statistics(::statistics& st) const {
m_simplex.collect_statistics(st);
}
void reset() {
m_lower.reset();
m_upper = m_max_weight;
}
void init_weights() {
if (m_weights_var != 0) {
return;
}
m_weights_var = m_weights.size();
unsigned_vector vars;
scoped_mpz_vector coeffs(m);
// normalize weights to integral.
rational d(1);
for (unsigned i = 0; i < m_weights.size(); ++i) {
d = lcm(d, denominator(m_weights[i]));
}
m_denominator = d;
if (!d.is_one()) {
for (unsigned i = 0; i < m_weights.size(); ++i) {
m_weights[i] *= d;
}
}
// set up Simplex objective function.
for (unsigned i = 0; i < m_weights.size(); ++i) {
vars.push_back(i);
coeffs.push_back(m_weights[i].to_mpq().numerator());
}
m_simplex.ensure_var(m_weights_var);
vars.push_back(m_weights_var);
coeffs.push_back(mpz(-1));
m_simplex.add_row(m_weights_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr());
}
struct scoped_select {
imp& s;
unsigned sz;
scoped_select(imp& s):s(s), sz(s.m_value_trail.size()) {
}
~scoped_select() {
s.undo_select(sz);
}
};
struct value_lt {
vector<rational> const& weights;
unsigned_vector const& scores;
value_lt(vector<rational> const& weights, unsigned_vector const& scores):
weights(weights), scores(scores) {}
bool operator()(int v1, int v2) const {
// - score1 / w1 < - score2 / w2
// <=>
// score1 / w1 > score2 / w2
// <=>
// score1*w2 > score2*w1
unsigned score1 = scores[v1];
unsigned score2 = scores[v2];
rational w1 = weights[v1];
rational w2 = weights[v2];
return rational(score1)*w2 > rational(score2)*w1;
}
};
// compute upper bound for hitting set.
bool U1() {
rational w(0);
scoped_select _sc(*this);
// score each variable by the number of
// unassigned sets they occur in.
unsigned_vector scores;
init_scores(scores);
//
// Sort indices.
// The least literals are those where -score/w is minimized.
//
unsigned_vector indices;
for (unsigned i = 0; i < m_value.size(); ++i) {
indices.push_back(i);
}
value_lt lt(m_weights, scores);
while (!m_cancel) {
std::sort(indices.begin(), indices.end(), lt);
unsigned idx = indices[0];
if (scores[idx] == 0) {
break;
}
update_scores(scores, idx);
select(idx);
w += m_weights[idx];
}
if (w < m_upper) {
m_upper = w;
}
return !m_cancel;
}
void init_scores(unsigned_vector & scores) {
scores.reset();
for (unsigned i = 0; i < m_value.size(); ++i) {
scores.push_back(0);
}
for (unsigned i = 0; i < m_S.size(); ++i) {
set const& S = m_S[i];
if (!has_selected(S)) {
for (unsigned j = 0; j < S.size(); ++j) {
scores[S[j]]++;
}
}
}
}
void update_scores(unsigned_vector& scores, unsigned v) {
unsigned_vector const& v_uses = m_use_list[v];
for (unsigned i = 0; i < v_uses.size(); ++i) {
set const& S = m_S[v_uses[i]];
if (!has_selected(S)) {
for (unsigned j = 0; j < S.size(); ++j) {
--scores[S[j]];
}
}
}
}
bool L1() {
rational w(0);
scoped_select _sc(*this);
for (unsigned i = 0; !m_cancel && i < m_S.size(); ++i) {
set const& S = m_S[i];
SASSERT(!S.empty());
if (!has_selected(S)) {
w += m_weights[select_min(S)];
for (unsigned j = 0; j < S.size(); ++j) {
select(S[j]);
}
}
}
if (m_lower < w) {
m_lower = w;
}
return !m_cancel;
}
bool L2() {
rational w(0);
scoped_select _sc(*this);
int n = 0;
for (unsigned i = 0; i < m_S.size(); ++i) {
if (!has_selected(m_S[i])) ++n;
}
unsigned_vector scores;
init_scores(scores);
unsigned_vector indices;
for (unsigned i = 0; i < m_value.size(); ++i) {
indices.push_back(i);
}
value_lt lt(m_weights, scores);
std::sort(indices.begin(), indices.end(), lt);
for(unsigned i = 0; i < indices.size() && n > 0; ++i) {
// deg(c) = score(c)
// wt(c) = m_weights[c]
unsigned idx = indices[i];
if (scores[idx] == 0) {
break;
}
if (scores[idx] < static_cast<unsigned>(n) || m_weights[idx].is_one()) {
w += m_weights[idx];
}
else {
w += div((rational(n)*m_weights[idx]), rational(scores[idx]));
}
n -= scores[idx];
}
if (m_lower < w) {
m_lower = w;
}
return !m_cancel;
}
bool L3() {
TRACE("simplex", m_simplex.display(tout););
VERIFY(l_true == m_simplex.make_feasible());
TRACE("simplex", m_simplex.display(tout););
VERIFY(l_true == m_simplex.minimize(m_weights_var));
mpq_inf const& val = m_simplex.get_value(m_weights_var);
unsynch_mpq_inf_manager mg;
unsynch_mpq_manager& mq = mg.mpq_manager();
scoped_mpq c(mq);
mg.ceil(val, c);
rational w = rational(c);
if (w > m_lower) {
m_lower = w;
}
return true;
}
void add_simplex_row(unsigned sz, unsigned const* S) {
unsigned_vector vars;
scoped_mpz_vector coeffs(m);
for (unsigned i = 0; i < sz; ++i) {
vars.push_back(S[i]);
coeffs.push_back(mpz(1));
}
unsigned base_var = m_S.size() + m_weights.size();
m_simplex.ensure_var(base_var);
vars.push_back(base_var);
coeffs.push_back(mpz(-1));
// S - base_var = 0
// base_var >= 1
m_simplex.set_lower(base_var, mpq_inf(mpq(1),mpq(0)));
m_simplex.add_row(base_var, coeffs.size(), vars.c_ptr(), coeffs.c_ptr());
}
void undo_select(unsigned sz) {
for (unsigned j = sz; j < m_value_trail.size(); ++j) {
m_value[m_value_trail[j]] = l_undef;
}
m_value_trail.resize(sz);
}
unsigned select_min(set const& S) {
unsigned result = S[0];
for (unsigned i = 1; i < S.size(); ++i) {
if (m_weights[result] > m_weights[S[i]]) {
result = S[i];
}
}
return result;
}
lbool selected(unsigned j) const {
return m_value[j];
}
void select(unsigned j) {
m_value[j] = l_true;
m_value_trail.push_back(j);
}
bool has_selected(set const& S) {
for (unsigned i = 0; i < S.size(); ++i) {
if (l_true == selected(S[i])) {
return true;
}
}
return false;
}
};
hitting_sets::hitting_sets() { m_imp = alloc(imp); }
hitting_sets::~hitting_sets() { dealloc(m_imp); }
void hitting_sets::add_weight(rational const& w) { m_imp->add_weight(w); }
void hitting_sets::add_set(unsigned sz, unsigned const* elems) { m_imp->add_set(sz, elems); }
bool hitting_sets::compute_lower() { return m_imp->compute_lower(); }
bool hitting_sets::compute_upper() { return m_imp->compute_upper(); }
rational hitting_sets::get_lower() { return m_imp->get_lower(); }
rational hitting_sets::get_upper() { return m_imp->get_upper(); }
void hitting_sets::set_cancel(bool f) { m_imp->set_cancel(f); }
void hitting_sets::collect_statistics(::statistics& st) const { m_imp->collect_statistics(st); }
void hitting_sets::reset() { m_imp->reset(); }
};

47
src/opt/hitting_sets.h Normal file
View file

@ -0,0 +1,47 @@
/*++
Copyright (c) 2014 Microsoft Corporation
Module Name:
hitting_sets.h
Abstract:
Hitting set approximations.
Author:
Nikolaj Bjorner (nbjorner) 2014-06-06
Notes:
--*/
#ifndef _HITTING_SETS_H_
#define _HITTING_SETS_H_
#include "rational.h"
#include "statistics.h"
namespace opt {
class hitting_sets {
struct imp;
imp* m_imp;
public:
hitting_sets();
~hitting_sets();
void add_weight(rational const& w);
void add_set(unsigned sz, unsigned const* elems);
bool compute_lower();
bool compute_upper();
rational get_lower();
rational get_upper();
void set_cancel(bool f);
void collect_statistics(::statistics& st) const;
void reset();
};
};
#endif

View file

@ -38,8 +38,8 @@ Notes:
#include "cancel_eh.h" #include "cancel_eh.h"
#include "scoped_timer.h" #include "scoped_timer.h"
#include "optsmt.h" #include "optsmt.h"
#include "hitting_sets.h"
#define USE_SIMPLEX 0
namespace opt { namespace opt {
@ -614,9 +614,7 @@ namespace opt {
}; };
scoped_ptr<maxsmt_solver_base> maxs; scoped_ptr<maxsmt_solver_base> maxs;
optsmt m_optsmt; // hitting set optimizer based on simplex. hitting_sets m_hs;
opt_solver m_solver;
unsigned m_objective; // index of objective
expr_ref_vector m_aux; // auxiliary (indicator) variables. expr_ref_vector m_aux; // auxiliary (indicator) variables.
expr_ref_vector m_iaux; // auxiliary integer (indicator) variables. expr_ref_vector m_iaux; // auxiliary integer (indicator) variables.
expr_ref_vector m_naux; // negation of auxiliary variables. expr_ref_vector m_naux; // negation of auxiliary variables.
@ -628,31 +626,29 @@ namespace opt {
pb_util pb; pb_util pb;
arith_util a; arith_util a;
stats m_stats; stats m_stats;
bool m_at_lower_bound;
public: public:
hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs): hsmax(solver* s, ast_manager& m, maxsmt_solver_base* maxs):
maxsmt_solver_base(s, m), maxsmt_solver_base(s, m),
maxs(maxs), maxs(maxs),
m_optsmt(m),
m_solver(m, m_params, symbol()),
m_aux(m), m_aux(m),
m_iaux(m), m_iaux(m),
m_naux(m), m_naux(m),
pb(m), pb(m),
a(m) { a(m),
m_at_lower_bound(false) {
} }
virtual ~hsmax() {} virtual ~hsmax() {}
virtual void set_cancel(bool f) { virtual void set_cancel(bool f) {
maxsmt_solver_base::set_cancel(f); maxsmt_solver_base::set_cancel(f);
maxs->set_cancel(f); maxs->set_cancel(f);
m_optsmt.set_cancel(f);
} }
virtual void updt_params(params_ref& p) { virtual void updt_params(params_ref& p) {
maxsmt_solver_base::updt_params(p); maxsmt_solver_base::updt_params(p);
m_solver.updt_params(p);
} }
virtual void collect_statistics(statistics& st) const { virtual void collect_statistics(statistics& st) const {
@ -685,8 +681,8 @@ namespace opt {
if (m_cancel) { if (m_cancel) {
return l_undef; return l_undef;
} }
lbool core_found = generate_cores(hs);
lbool core_found = generate_cores(hs);
switch(core_found) { switch(core_found) {
case l_undef: case l_undef:
return l_undef; return l_undef;
@ -698,20 +694,20 @@ namespace opt {
break; break;
case l_false: case l_false:
TRACE("opt", tout << "no more seeds\n";); TRACE("opt", tout << "no more seeds\n";);
m_lower = m_upper; m_lower = m_upper;
return l_true; return l_true;
case l_undef: case l_undef:
return l_undef; return l_undef;
} }
break; break;
} }
case l_false: case l_false:
TRACE("opt", tout << "no more cores\n";); TRACE("opt", tout << "no more cores\n";);
m_lower = m_upper; m_lower = m_upper;
return l_true; return l_true;
} }
} }
return l_true; return l_true;
} }
private: private:
@ -740,26 +736,16 @@ namespace opt {
m_aux_active.push_back(false); m_aux_active.push_back(false);
m_core_activity.push_back(0); m_core_activity.push_back(0);
m_aux2index.insert(m_aux.back(), i); m_aux2index.insert(m_aux.back(), i);
#if USE_SIMPLEX
m_aux2index.insert(m_iaux.back(), i);
fml = m.mk_and(a.mk_le(a.mk_numeral(rational::zero(), true), iaux),
a.mk_le(iaux, a.mk_numeral(rational::one(), true)));
rational const& w = m_weights[i];
sum.push_back(a.mk_mul(a.mk_numeral(w, w.is_int()), iaux));
m_solver.assert_expr(fml);
#endif
if (tt) { if (tt) {
m_asms.push_back(m_aux.back()); m_asms.push_back(m_aux.back());
ensure_active(i); ensure_active(i);
} }
} }
#if USE_SIMPLEX
obj = a.mk_add(sum.size(), sum.c_ptr());
m_objective = m_optsmt.add(obj);
m_optsmt.setup(m_solver);
#else
maxs->init_soft(m_weights, m_aux); maxs->init_soft(m_weights, m_aux);
#endif
for (unsigned i = 0; i < m_weights.size(); ++i) {
m_hs.add_weight(m_weights[i]);
}
TRACE("opt", print_seed(tout);); TRACE("opt", print_seed(tout););
} }
@ -895,54 +881,51 @@ namespace opt {
} }
} }
lbool next_seed(ptr_vector<expr>& hs, lbool core_found) {
if (core_found == l_false && m_at_lower_bound) {
return l_true;
}
lbool is_sat = next_seed();
switch(is_sat) {
case l_true:
seed2hs(false, hs);
return m_at_lower_bound?l_true:l_false;
case l_false:
TRACE("opt", tout << "no more seeds\n";);
return l_true;
case l_undef:
return l_undef;
}
return l_undef;
}
// //
// retrieve the next seed that satisfies state of maxs. // retrieve the next seed that satisfies state of maxs.
// state of maxs must be satisfiable before optimization is called. // state of maxs must be satisfiable before optimization is called.
// //
//
// find a satisfying assignment to maxs state, that // find a satisfying assignment to maxs state, that
// minimizes objective function. // minimizes objective function.
// //
lbool next_seed() { lbool next_seed() {
scoped_stopwatch _sw(m_stats.m_aux_sat_time); scoped_stopwatch _sw(m_stats.m_aux_sat_time);
TRACE("opt", tout << "\n";); TRACE("opt", tout << "\n";);
#if USE_SIMPLEX
m_solver.display(std::cout);
lbool is_sat = m_optsmt.lex(m_objective);
if (is_sat == l_true) {
model_ref mdl;
m_optsmt.get_model(mdl);
for (unsigned i = 0; i < num_soft(); ++i) {
if (is_active(i)) {
m_seed[i] = is_one(mdl, m_iaux[i].get());
}
else {
m_seed[i] = false;
}
}
print_seed(std::cout);
TRACE("opt", print_seed(tout););
}
#else
// min c_i*(not x_i) for x_i are soft clauses. // min c_i*(not x_i) for x_i are soft clauses.
// max c_i*x_i for x_i are soft clauses // max c_i*x_i for x_i are soft clauses
lbool is_sat = l_true; lbool is_sat = l_true;
m_at_lower_bound = false;
expr_ref fml(m);
if (m_lower.is_pos()) { if (m_lower.is_pos()) {
expr_ref fml(m);
solver::scoped_push _scope(maxs->s()); solver::scoped_push _scope(maxs->s());
fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower); fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower);
maxs->add_hard(fml); maxs->add_hard(fml);
//fml = pb.mk_ge(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_lower);
//maxs->add_hard(fml);
std::cout << fml << "\n";
is_sat = maxs->s().check_sat(0,0); is_sat = maxs->s().check_sat(0,0);
if (is_sat == l_true) { if (is_sat == l_true) {
maxs->set_model(); maxs->set_model();
extract_seed(); extract_seed();
m_at_lower_bound = true;
return l_true; return l_true;
} }
} }
@ -951,17 +934,32 @@ namespace opt {
maxs->set_model(); maxs->set_model();
} }
else { else {
m_at_lower_bound = true;
return is_sat; return is_sat;
} }
is_sat = (*maxs)(); is_sat = (*maxs)();
if (is_sat == l_true) { if (is_sat == l_true) {
extract_seed(); extract_seed();
} }
#endif
return is_sat; return is_sat;
} }
#if 0
if (!m_hs.compute_upper()) {
return l_undef;
}
solver::scoped_push _scope(maxs->s());
fml = pb.mk_le(num_soft(), m_weights.c_ptr(), m_naux.c_ptr(), m_hs.get_upper());
IF_VERBOSE(0, verbose_stream() << "upper: " << m_hs.get_upper() << " " << m_upper << "\n";);
maxs->add_hard(fml);
TRACE("opt", tout << "checking with upper bound: " << m_hs.get_upper() << "\n";);
is_sat = maxs->s().check_sat(0,0);
std::cout << is_sat << "\n";
// TBD: uper bound estimate does not include the negative constraints.
#endif
void extract_seed() { void extract_seed() {
model_ref mdl; model_ref mdl;
maxs->get_model(mdl); maxs->get_model(mdl);
@ -1140,16 +1138,6 @@ namespace opt {
} }
expr_ref_vector fmls(m); expr_ref_vector fmls(m);
expr_ref fml(m); expr_ref fml(m);
#if USE_SIMPLEX
for (unsigned i = 0; i < num_soft(); ++i) {
if (!indices.contains(i)) {
fmls.push_back(m_iaux[i].get());
}
}
fml = a.mk_ge(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational::one(), true));
m_solver.assert_expr(fml);
#else
for (unsigned i = 0; i < num_soft(); ++i) { for (unsigned i = 0; i < num_soft(); ++i) {
if (!indices.contains(i)) { if (!indices.contains(i)) {
fmls.push_back(m_aux[i].get()); fmls.push_back(m_aux[i].get());
@ -1158,7 +1146,6 @@ namespace opt {
fml = m.mk_or(fmls.size(), fmls.c_ptr()); fml = m.mk_or(fmls.size(), fmls.c_ptr());
maxs->add_hard(fml); maxs->add_hard(fml);
set_upper(); set_upper();
#endif
TRACE("opt", tout << fml << "\n";); TRACE("opt", tout << fml << "\n";);
} }
@ -1174,25 +1161,17 @@ namespace opt {
void block_up() { void block_up() {
expr_ref_vector fmls(m); expr_ref_vector fmls(m);
expr_ref fml(m); expr_ref fml(m);
#if USE_SIMPLEX unsigned_vector indices;
for (unsigned i = 0; i < m_asms.size(); ++i) {
unsigned index = m_aux2index.find(m_asms[i]);
m_core_activity[index]++;
fmls.push_back(m_iaux[index].get());
}
fml = a.mk_lt(a.mk_add(fmls.size(), fmls.c_ptr()), a.mk_numeral(rational(fmls.size()), true));
TRACE("opt", tout << fml << "\n";);
m_solver.assert_expr(fml);
#else
for (unsigned i = 0; i < m_asms.size(); ++i) { for (unsigned i = 0; i < m_asms.size(); ++i) {
unsigned index = m_aux2index.find(m_asms[i]); unsigned index = m_aux2index.find(m_asms[i]);
fmls.push_back(m.mk_not(m_asms[i])); fmls.push_back(m.mk_not(m_asms[i]));
m_core_activity[index]++; m_core_activity[index]++;
indices.push_back(index);
} }
fml = m.mk_or(fmls.size(), fmls.c_ptr()); fml = m.mk_or(fmls.size(), fmls.c_ptr());
TRACE("opt", tout << fml << "\n";); TRACE("opt", tout << fml << "\n";);
m_hs.add_set(indices.size(), indices.c_ptr());
maxs->add_hard(fml); maxs->add_hard(fml);
#endif
} }
@ -1224,7 +1203,6 @@ namespace opt {
rational r; rational r;
expr_ref val(m); expr_ref val(m);
VERIFY(mdl->eval(e, val)); VERIFY(mdl->eval(e, val));
std::cout << mk_pp(e, m) << " |-> " << val << "\n";
return a.is_numeral(val, r) && r.is_one(); return a.is_numeral(val, r) && r.is_one();
} }
@ -1684,10 +1662,12 @@ namespace opt {
m_maxsmt = alloc(bcd2, s.get(), m); m_maxsmt = alloc(bcd2, s.get(), m);
} }
else if (m_engine == symbol("hsmax")) { else if (m_engine == symbol("hsmax")) {
//m_params.set_bool("pb.enable_simplex", true);
ref<opt_solver> s0 = alloc(opt_solver, m, m_params, symbol()); ref<opt_solver> s0 = alloc(opt_solver, m, m_params, symbol());
s0->check_sat(0,0); s0->check_sat(0,0);
maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context()); maxsmt_solver_base* s2 = alloc(pbmax, s0.get(), m); // , s0->get_context());
s2->set_converter(s0->mc_ref().get()); s2->set_converter(s0->mc_ref().get());
m_maxsmt = alloc(hsmax, s.get(), m, s2); m_maxsmt = alloc(hsmax, s.get(), m, s2);
} }
// NB: this is experimental one-round version of SLS // NB: this is experimental one-round version of SLS

View file

@ -226,7 +226,7 @@ namespace qe {
return alloc(sat_tactic, m); return alloc(sat_tactic, m);
} }
~sat_tactic() { virtual ~sat_tactic() {
for (unsigned i = 0; i < m_solvers.size(); ++i) { for (unsigned i = 0; i < m_solvers.size(); ++i) {
dealloc(m_solvers[i]); dealloc(m_solvers[i]);
} }

View file

@ -23,6 +23,7 @@ void preprocessor_params::updt_local_params(params_ref const & _p) {
smt_params_helper p(_p); smt_params_helper p(_p);
m_macro_finder = p.macro_finder(); m_macro_finder = p.macro_finder();
m_pull_nested_quantifiers = p.pull_nested_quantifiers(); m_pull_nested_quantifiers = p.pull_nested_quantifiers();
m_refine_inj_axiom = p.refine_inj_axioms();
} }
void preprocessor_params::updt_params(params_ref const & p) { void preprocessor_params::updt_params(params_ref const & p) {

View file

@ -14,6 +14,7 @@ def_module_params(module_name='smt',
('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'), ('delay_units', BOOL, False, 'if true then z3 will not restart when a unit clause is learned'),
('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'), ('delay_units_threshold', UINT, 32, 'maximum number of learned unit clauses before restarting, ingored if delay_units is false'),
('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'), ('pull_nested_quantifiers', BOOL, False, 'pull nested quantifiers'),
('refine_inj_axioms', BOOL, True, 'refine injectivity axioms'),
('soft_timeout', UINT, 0, 'soft timeout (0 means no timeout)'), ('soft_timeout', UINT, 0, 'soft timeout (0 means no timeout)'),
('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'), ('mbqi', BOOL, True, 'model based quantifier instantiation (MBQI)'),
('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'), ('mbqi.max_cexs', UINT, 1, 'initial maximal number of counterexamples used in MBQI, each counterexample generates a quantifier instantiation'),

View file

@ -20,6 +20,7 @@ Revision History:
#include"proto_model.h" #include"proto_model.h"
#include"ast_pp.h" #include"ast_pp.h"
#include"ast_ll_pp.h" #include"ast_ll_pp.h"
#include"expr_functors.h"
datatype_factory::datatype_factory(ast_manager & m, proto_model & md): datatype_factory::datatype_factory(ast_manager & m, proto_model & md):
struct_factory(m, m.mk_family_id("datatype"), md), struct_factory(m, m.mk_family_id("datatype"), md),
@ -47,8 +48,10 @@ expr * datatype_factory::get_some_value(sort * s) {
*/ */
expr * datatype_factory::get_last_fresh_value(sort * s) { expr * datatype_factory::get_last_fresh_value(sort * s) {
expr * val = 0; expr * val = 0;
if (m_last_fresh_value.find(s, val)) if (m_last_fresh_value.find(s, val)) {
TRACE("datatype_factory", tout << "cached fresh value: " << mk_pp(val, m_manager) << "\n";);
return val; return val;
}
value_set * set = get_value_set(s); value_set * set = get_value_set(s);
if (set->empty()) if (set->empty())
val = get_some_value(s); val = get_some_value(s);
@ -59,6 +62,17 @@ expr * datatype_factory::get_last_fresh_value(sort * s) {
return val; return val;
} }
bool datatype_factory::is_subterm_of_last_value(app* e) {
expr* last;
if (!m_last_fresh_value.find(m_manager.get_sort(e), last)) {
return false;
}
contains_app contains(m_manager, e);
bool result = contains(last);
TRACE("datatype_factory", tout << mk_pp(e, m_manager) << " in " << mk_pp(last, m_manager) << " " << result << "\n";);
return result;
}
/** /**
\brief Create an almost fresh value. If s is recursive, then the result is not 0. \brief Create an almost fresh value. If s is recursive, then the result is not 0.
It also updates m_last_fresh_value It also updates m_last_fresh_value
@ -105,11 +119,18 @@ expr * datatype_factory::get_almost_fresh_value(sort * s) {
} }
} }
if (recursive || found_fresh_arg) { if (recursive || found_fresh_arg) {
expr * new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); app * new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
SASSERT(!found_fresh_arg || !set->contains(new_value)); SASSERT(!found_fresh_arg || !set->contains(new_value));
register_value(new_value); register_value(new_value);
if (m_util.is_recursive(s)) if (m_util.is_recursive(s)) {
m_last_fresh_value.insert(s, new_value); if (is_subterm_of_last_value(new_value)) {
new_value = static_cast<app*>(m_last_fresh_value.find(s));
}
else {
m_last_fresh_value.insert(s, new_value);
}
}
TRACE("datatype_factory", tout << "almost fresh: " << mk_pp(new_value, m_manager) << "\n";);
return new_value; return new_value;
} }
} }
@ -170,8 +191,10 @@ expr * datatype_factory::get_fresh_value(sort * s) {
// Approach 2) // Approach 2)
// For recursive datatypes. // For recursive datatypes.
// search for constructor... // search for constructor...
unsigned num_iterations = 0;
if (m_util.is_recursive(s)) { if (m_util.is_recursive(s)) {
while(true) { while(true) {
++num_iterations;
TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";); TRACE("datatype_factory", tout << mk_pp(get_last_fresh_value(s), m_manager) << "\n";);
ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s); ptr_vector<func_decl> const * constructors = m_util.get_datatype_constructors(s);
ptr_vector<func_decl>::const_iterator it = constructors->begin(); ptr_vector<func_decl>::const_iterator it = constructors->begin();
@ -181,12 +204,26 @@ expr * datatype_factory::get_fresh_value(sort * s) {
expr_ref_vector args(m_manager); expr_ref_vector args(m_manager);
bool found_sibling = false; bool found_sibling = false;
unsigned num = constructor->get_arity(); unsigned num = constructor->get_arity();
TRACE("datatype_factory", tout << "checking constructor: " << constructor->get_name() << "\n";);
for (unsigned i = 0; i < num; i++) { for (unsigned i = 0; i < num; i++) {
sort * s_arg = constructor->get_domain(i); sort * s_arg = constructor->get_domain(i);
TRACE("datatype_factory", tout << mk_pp(s, m_manager) << " "
<< mk_pp(s_arg, m_manager) << " are_siblings "
<< m_util.are_siblings(s, s_arg) << " is_datatype "
<< m_util.is_datatype(s_arg) << " found_sibling "
<< found_sibling << "\n";);
if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) { if (!found_sibling && m_util.is_datatype(s_arg) && m_util.are_siblings(s, s_arg)) {
found_sibling = true; found_sibling = true;
expr * maybe_new_arg = get_almost_fresh_value(s_arg); expr * maybe_new_arg = 0;
if (num_iterations <= 1) {
maybe_new_arg = get_almost_fresh_value(s_arg);
}
else {
maybe_new_arg = get_fresh_value(s_arg);
}
if (!maybe_new_arg) { if (!maybe_new_arg) {
TRACE("datatype_factory",
tout << "no argument found for " << mk_pp(s_arg, m_manager) << "\n";);
maybe_new_arg = m_model.get_some_value(s_arg); maybe_new_arg = m_model.get_some_value(s_arg);
found_sibling = false; found_sibling = false;
} }
@ -202,6 +239,7 @@ expr * datatype_factory::get_fresh_value(sort * s) {
if (found_sibling) { if (found_sibling) {
expr_ref new_value(m_manager); expr_ref new_value(m_manager);
new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr()); new_value = m_manager.mk_app(constructor, args.size(), args.c_ptr());
TRACE("datatype_factory", tout << "potential new value: " << mk_pp(new_value, m_manager) << "\n";);
m_last_fresh_value.insert(s, new_value); m_last_fresh_value.insert(s, new_value);
if (!set->contains(new_value)) { if (!set->contains(new_value)) {
register_value(new_value); register_value(new_value);

View file

@ -29,6 +29,8 @@ class datatype_factory : public struct_factory {
expr * get_last_fresh_value(sort * s); expr * get_last_fresh_value(sort * s);
expr * get_almost_fresh_value(sort * s); expr * get_almost_fresh_value(sort * s);
bool is_subterm_of_last_value(app* e);
public: public:
datatype_factory(ast_manager & m, proto_model & md); datatype_factory(ast_manager & m, proto_model & md);
virtual ~datatype_factory() {} virtual ~datatype_factory() {}

View file

@ -247,6 +247,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
new_t = mk_some_interp_for(f); new_t = mk_some_interp_for(f);
} }
else { else {
TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";);
is_ok = false; is_ok = false;
} }
} }
@ -294,6 +295,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
// f is an uninterpreted function, there is no need to use m_simplifier.mk_app // f is an uninterpreted function, there is no need to use m_simplifier.mk_app
new_t = m_manager.mk_app(f, num_args, args.c_ptr()); new_t = m_manager.mk_app(f, num_args, args.c_ptr());
trail.push_back(new_t); trail.push_back(new_t);
TRACE("model_eval", tout << f->get_name() << " is uninterpreted\n";);
is_ok = false; is_ok = false;
} }
} }
@ -326,6 +328,7 @@ bool proto_model::eval(expr * e, expr_ref & result, bool model_completion) {
todo.pop_back(); todo.pop_back();
break; break;
case AST_QUANTIFIER: case AST_QUANTIFIER:
TRACE("model_eval", tout << "found quantifier\n" << mk_pp(a, m_manager) << "\n";);
is_ok = false; // evaluator does not handle quantifiers. is_ok = false; // evaluator does not handle quantifiers.
SASSERT(a != 0); SASSERT(a != 0);
eval_cache.insert(a, a); eval_cache.insert(a, a);

View file

@ -396,7 +396,7 @@ namespace smt {
// Support for evaluating expressions in the current model. // Support for evaluating expressions in the current model.
proto_model * m_model; proto_model * m_model;
obj_map<expr, expr *> m_eval_cache; obj_map<expr, expr *> m_eval_cache[2];
expr_ref_vector m_eval_cache_range; expr_ref_vector m_eval_cache_range;
ptr_vector<node> m_root_nodes; ptr_vector<node> m_root_nodes;
@ -409,7 +409,8 @@ namespace smt {
} }
void reset_eval_cache() { void reset_eval_cache() {
m_eval_cache.reset(); m_eval_cache[0].reset();
m_eval_cache[1].reset();
m_eval_cache_range.reset(); m_eval_cache_range.reset();
} }
@ -468,6 +469,7 @@ namespace smt {
~auf_solver() { ~auf_solver() {
flush_nodes(); flush_nodes();
reset_eval_cache();
} }
void set_context(context * ctx) { void set_context(context * ctx) {
@ -547,7 +549,7 @@ namespace smt {
for (obj_map<expr, unsigned>::iterator it = elems.begin(); it != elems.end(); it++) { for (obj_map<expr, unsigned>::iterator it = elems.begin(); it != elems.end(); it++) {
expr * n = it->m_key; expr * n = it->m_key;
expr * n_val = eval(n, true); expr * n_val = eval(n, true);
if (!m_manager.is_value(n_val)) if (!n_val || !m_manager.is_value(n_val))
to_delete.push_back(n); to_delete.push_back(n);
} }
for (ptr_vector<expr>::iterator it = to_delete.begin(); it != to_delete.end(); it++) { for (ptr_vector<expr>::iterator it = to_delete.begin(); it != to_delete.end(); it++) {
@ -569,16 +571,19 @@ namespace smt {
virtual expr * eval(expr * n, bool model_completion) { virtual expr * eval(expr * n, bool model_completion) {
expr * r = 0; expr * r = 0;
if (m_eval_cache.find(n, r)) { if (m_eval_cache[model_completion].find(n, r)) {
return r; return r;
} }
expr_ref tmp(m_manager); expr_ref tmp(m_manager);
if (!m_model->eval(n, tmp, model_completion)) if (!m_model->eval(n, tmp, model_completion)) {
r = 0; r = 0;
else TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n-----> null\n";);
}
else {
r = tmp; r = tmp;
TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";); TRACE("model_finder", tout << "eval\n" << mk_pp(n, m_manager) << "\n----->\n" << mk_pp(r, m_manager) << "\n";);
m_eval_cache.insert(n, r); }
m_eval_cache[model_completion].insert(n, r);
m_eval_cache_range.push_back(r); m_eval_cache_range.push_back(r);
return r; return r;
} }

View file

@ -102,6 +102,7 @@ namespace smt {
if (th && th->build_models()) { if (th && th->build_models()) {
if (r->get_th_var(th->get_id()) != null_theory_var) { if (r->get_th_var(th->get_id()) != null_theory_var) {
proc = th->mk_value(r, *this); proc = th->mk_value(r, *this);
SASSERT(proc);
} }
else { else {
TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";); TRACE("model_bug", tout << "creating fresh value for #" << r->get_owner_id() << "\n";);
@ -110,6 +111,7 @@ namespace smt {
} }
else { else {
proc = mk_model_value(r); proc = mk_model_value(r);
SASSERT(proc);
} }
} }
SASSERT(proc); SASSERT(proc);

View file

@ -162,7 +162,7 @@ namespace smt {
m.register_factory(alloc(dl_factory, m_util, m.get_model())); m.register_factory(alloc(dl_factory, m_util, m.get_model()));
} }
virtual smt::model_value_proc * mk_value(smt::enode * n) { virtual smt::model_value_proc * mk_value(smt::enode * n, smt::model_generator&) {
return alloc(dl_value_proc, *this, n); return alloc(dl_value_proc, *this, n);
} }
@ -201,9 +201,8 @@ namespace smt {
if(!m_reps.find(s, r) || !m_vals.find(s,v)) { if(!m_reps.find(s, r) || !m_vals.find(s,v)) {
SASSERT(!m_reps.contains(s)); SASSERT(!m_reps.contains(s));
sort* bv = b().mk_sort(64); sort* bv = b().mk_sort(64);
// TBD: filter these from model. r = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_REP, 0, 0, 1, &s, bv);
r = m().mk_fresh_func_decl("rep",1, &s,bv); v = m().mk_func_decl(m_util.get_family_id(), datalog::OP_DL_ABS, 0, 0, 1, &bv, s);
v = m().mk_fresh_func_decl("val",1, &bv,s);
m_reps.insert(s, r); m_reps.insert(s, r);
m_vals.insert(s, v); m_vals.insert(s, v);
add_trail(r); add_trail(r);

View file

@ -471,7 +471,7 @@ namespace smt {
break; break;
} }
if (c->k().is_one() && c->is_ge()) { if (c->k().is_one() && c->is_ge() && !m_enable_simplex) {
literal_vector& lits = get_lits(); literal_vector& lits = get_lits();
lits.push_back(~lit); lits.push_back(~lit);
for (unsigned i = 0; i < c->size(); ++i) { for (unsigned i = 0; i < c->size(); ++i) {
@ -480,7 +480,7 @@ namespace smt {
ctx.mk_th_axiom(get_id(), lit, ~c->lit(i)); ctx.mk_th_axiom(get_id(), lit, ~c->lit(i));
} }
ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr()); ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
// return true; return true;
} }
// maximal coefficient: // maximal coefficient:

View file

@ -219,6 +219,7 @@ int main(int argc, char ** argv) {
TST(sorting_network); TST(sorting_network);
TST(theory_pb); TST(theory_pb);
TST(simplex); TST(simplex);
//TST_ARGV(hs);
} }
void initialize_mam() {} void initialize_mam() {}

View file

@ -248,7 +248,7 @@ public:
void ceil(mpq_inf const & a, mpq & b) { void ceil(mpq_inf const & a, mpq & b) {
if (m.is_int(a.first)) { if (m.is_int(a.first)) {
// special cases for k - delta*epsilon where k is an integer // special cases for k - delta*epsilon where k is an integer
if (m.is_pos(a.first)) if (m.is_pos(a.second))
m.add(a.first, mpq(1), b); // ceil(k + delta*epsilon) --> k+1 m.add(a.first, mpq(1), b); // ceil(k + delta*epsilon) --> k+1
else else
m.set(b, a.first); m.set(b, a.first);
@ -276,6 +276,7 @@ public:
out << to_string(a); out << to_string(a);
} }
mpq_manager<SYNCH>& mpq_manager() { return m; }
}; };
typedef mpq_inf_manager<true> synch_mpq_inf_manager; typedef mpq_inf_manager<true> synch_mpq_inf_manager;

View file

@ -70,7 +70,9 @@ struct scoped_timer::imp {
pthread_t m_thread_id; pthread_t m_thread_id;
pthread_attr_t m_attributes; pthread_attr_t m_attributes;
unsigned m_interval; unsigned m_interval;
pthread_mutex_t m_mutex;
pthread_cond_t m_condition_var; pthread_cond_t m_condition_var;
struct timespec m_end_time;
#elif defined(_LINUX_) || defined(_FREEBSD_) #elif defined(_LINUX_) || defined(_FREEBSD_)
// Linux & FreeBSD // Linux & FreeBSD
timer_t m_timerid; timer_t m_timerid;
@ -93,35 +95,15 @@ struct scoped_timer::imp {
static void * thread_func(void * arg) { static void * thread_func(void * arg) {
scoped_timer::imp * st = static_cast<scoped_timer::imp*>(arg); scoped_timer::imp * st = static_cast<scoped_timer::imp*>(arg);
pthread_mutex_t mutex; pthread_mutex_lock(&st->m_mutex);
clock_serv_t host_clock;
struct timespec abstime;
mach_timespec_t now;
unsigned long long nano = static_cast<unsigned long long>(st->m_interval) * 1000000ull;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &host_clock); int e = pthread_cond_timedwait(&st->m_condition_var, &st->m_mutex, &st->m_end_time);
if (pthread_mutex_init(&mutex, NULL) != 0)
throw default_exception("failed to initialize timer mutex");
if (pthread_cond_init(&st->m_condition_var, NULL) != 0)
throw default_exception("failed to initialize timer condition variable");
abstime.tv_sec = nano / 1000000000ull;
abstime.tv_nsec = nano % 1000000000ull;
pthread_mutex_lock(&mutex);
clock_get_time(host_clock, &now);
ADD_MACH_TIMESPEC(&abstime, &now);
int e = pthread_cond_timedwait(&st->m_condition_var, &mutex, &abstime);
if (e != 0 && e != ETIMEDOUT) if (e != 0 && e != ETIMEDOUT)
throw default_exception("failed to start timed wait"); throw default_exception("failed to start timed wait");
st->m_eh->operator()(); st->m_eh->operator()();
pthread_mutex_unlock(&mutex);
if (pthread_mutex_destroy(&mutex) != 0) pthread_mutex_unlock(&st->m_mutex);
throw default_exception("failed to destroy pthread mutex");
if (pthread_cond_destroy(&st->m_condition_var) != 0)
throw default_exception("failed to destroy pthread condition variable");
return st; return st;
} }
#elif defined(_LINUX_) || defined(_FREEBSD_) #elif defined(_LINUX_) || defined(_FREEBSD_)
@ -150,6 +132,22 @@ struct scoped_timer::imp {
m_interval = ms; m_interval = ms;
if (pthread_attr_init(&m_attributes) != 0) if (pthread_attr_init(&m_attributes) != 0)
throw default_exception("failed to initialize timer thread attributes"); throw default_exception("failed to initialize timer thread attributes");
if (pthread_cond_init(&m_condition_var, NULL) != 0)
throw default_exception("failed to initialize timer condition variable");
if (pthread_mutex_init(&m_mutex, NULL) != 0)
throw default_exception("failed to initialize timer mutex");
clock_serv_t host_clock;
mach_timespec_t now;
unsigned long long nano = static_cast<unsigned long long>(m_interval) * 1000000ull;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &host_clock);
m_end_time.tv_sec = nano / 1000000000ull;
m_end_time.tv_nsec = nano % 1000000000ull;
clock_get_time(host_clock, &now);
ADD_MACH_TIMESPEC(&m_end_time, &now);
if (pthread_create(&m_thread_id, &m_attributes, &thread_func, this) != 0) if (pthread_create(&m_thread_id, &m_attributes, &thread_func, this) != 0)
throw default_exception("failed to start timer thread"); throw default_exception("failed to start timer thread");
#elif defined(_LINUX_) || defined(_FREEBSD_) #elif defined(_LINUX_) || defined(_FREEBSD_)
@ -183,9 +181,25 @@ struct scoped_timer::imp {
INVALID_HANDLE_VALUE); INVALID_HANDLE_VALUE);
#elif defined(__APPLE__) && defined(__MACH__) #elif defined(__APPLE__) && defined(__MACH__)
// Mac OS X // Mac OS X
pthread_cond_signal(&m_condition_var); // this is okay to fail
// If the waiting-thread is not up and waiting yet,
// we can make sure that it finishes quickly by
// setting the end-time to zero.
m_end_time.tv_sec = 0;
m_end_time.tv_nsec = 0;
// Otherwise it's already up and waiting, and
// we can send a signal on m_condition_var:
pthread_mutex_lock(&m_mutex);
pthread_cond_signal(&m_condition_var);
pthread_mutex_unlock(&m_mutex);
if (pthread_join(m_thread_id, NULL) != 0) if (pthread_join(m_thread_id, NULL) != 0)
throw default_exception("failed to join thread"); throw default_exception("failed to join thread");
if (pthread_mutex_destroy(&m_mutex) != 0)
throw default_exception("failed to destroy pthread mutex");
if (pthread_cond_destroy(&m_condition_var) != 0)
throw default_exception("failed to destroy pthread condition variable");
if (pthread_attr_destroy(&m_attributes) != 0) if (pthread_attr_destroy(&m_attributes) != 0)
throw default_exception("failed to destroy pthread attributes object"); throw default_exception("failed to destroy pthread attributes object");
#elif defined(_LINUX_) || defined(_FREEBSD_) #elif defined(_LINUX_) || defined(_FREEBSD_)