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:
commit
960e8ea1d5
|
@ -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):
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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"
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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){
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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";);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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'),
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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";
|
||||||
|
|
|
@ -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
370
src/opt/hitting_sets.cpp
Normal 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
47
src/opt/hitting_sets.h
Normal 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
|
|
@ -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
|
||||||
|
|
|
@ -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]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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'),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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() {}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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_)
|
||||||
|
|
Loading…
Reference in a new issue