3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-10 19:27:06 +00:00

Merge branch 'unstable' of https://git01.codeplex.com/z3 into unstable

This commit is contained in:
Christoph M. Wintersteiger 2014-08-22 12:57:45 +01:00
commit f023b8992f
7 changed files with 127 additions and 18 deletions

View file

@ -1152,6 +1152,13 @@ protected:
virtual void LearnFrom(Solver *old_solver) = 0;
/** Return true if the solution be incorrect due to recursion bounding.
That is, the returned "solution" might contain all derivable facts up to the
given recursion bound, but not be actually a fixed point.
*/
virtual bool IsResultRecursionBounded() = 0;
virtual ~Solver(){}
static Solver *Create(const std::string &solver_class, RPFP *rpfp);

View file

@ -768,6 +768,29 @@ namespace Duality {
annot.Simplify();
}
bool recursionBounded;
/** See if the solution might be bounded. */
void TestRecursionBounded(){
recursionBounded = false;
if(RecursionBound == -1)
return;
for(unsigned i = 0; i < nodes.size(); i++){
Node *node = nodes[i];
std::vector<Node *> &insts = insts_of_node[node];
for(unsigned j = 0; j < insts.size(); j++)
if(indset->Contains(insts[j]))
if(NodePastRecursionBound(insts[j])){
recursionBounded = true;
return;
}
}
}
bool IsResultRecursionBounded(){
return recursionBounded;
}
/** Generate a proposed solution of the input RPFP from
the unwinding, by unioning the instances of each node. */
void GenSolutionFromIndSet(bool with_markers = false){
@ -1026,6 +1049,7 @@ namespace Duality {
timer_stop("ProduceCandidatesForExtension");
if(candidates.empty()){
GenSolutionFromIndSet();
TestRecursionBounded();
return true;
}
Candidate cand = candidates.front();

View file

@ -53,6 +53,7 @@ namespace datalog {
MEMOUT,
INPUT_ERROR,
APPROX,
BOUNDED,
CANCELED
};
@ -304,6 +305,8 @@ namespace datalog {
\brief Retrieve predicates
*/
func_decl_set const& get_predicates() const { return m_preds; }
ast_ref_vector const &get_pinned() const {return m_pinned; }
bool is_predicate(func_decl* pred) const { return m_preds.contains(pred); }
bool is_predicate(expr * e) const { return is_app(e) && is_predicate(to_app(e)->get_decl()); }

View file

@ -36,6 +36,7 @@ Revision History:
#include "model_v2_pp.h"
#include "fixedpoint_params.hpp"
#include "used_vars.h"
#include "func_decl_dependencies.h"
// template class symbol_table<family_id>;
@ -207,6 +208,46 @@ lbool dl_interface::query(::expr * query) {
_d->rpfp->AssertAxiom(e);
}
// make sure each predicate is the head of at least one clause
func_decl_set heads;
for(unsigned i = 0; i < clauses.size(); i++){
expr cl = clauses[i];
while(true){
if(cl.is_app()){
decl_kind k = cl.decl().get_decl_kind();
if(k == Implies)
cl = cl.arg(1);
else {
heads.insert(cl.decl());
break;
}
}
else if(cl.is_quantifier())
cl = cl.body();
else break;
}
}
ast_ref_vector const &pinned = m_ctx.get_pinned();
for(unsigned i = 0; i < pinned.size(); i++){
::ast *fa = pinned[i];
if(is_func_decl(fa)){
::func_decl *fd = to_func_decl(fa);
if(m_ctx.is_predicate(fd)) {
func_decl f(_d->ctx,fd);
if(!heads.contains(fd)){
int arity = f.arity();
std::vector<expr> args;
for(int j = 0; j < arity; j++)
args.push_back(_d->ctx.fresh_func_decl("X",f.domain(j))());
expr c = implies(_d->ctx.bool_val(false),f(args));
c = _d->ctx.make_quant(Forall,args,c);
clauses.push_back(c);
}
}
}
}
// creates 1-1 map between clauses and rpfp edges
_d->rpfp->FromClauses(clauses);
@ -265,7 +306,19 @@ lbool dl_interface::query(::expr * query) {
// dealloc(rs); this is now owned by data
// true means the RPFP problem is SAT, so the query is UNSAT
return ans ? l_false : l_true;
// but we return undef if the UNSAT result is bounded
if(ans){
if(rs->IsResultRecursionBounded()){
#if 0
m_ctx.set_status(datalog::BOUNDED);
return l_undef;
#else
return l_false;
#endif
}
return l_false;
}
return l_true;
}
expr_ref dl_interface::get_cover_delta(int level, ::func_decl* pred_orig) {

View file

@ -252,6 +252,11 @@ public:
print_certificate(ctx);
break;
case l_undef:
if(dlctx.get_status() == datalog::BOUNDED){
ctx.regular_stream() << "bounded\n";
print_certificate(ctx);
break;
}
ctx.regular_stream() << "unknown\n";
switch(dlctx.get_status()) {
case datalog::INPUT_ERROR:

View file

@ -736,6 +736,11 @@ namespace pdr {
m_closed = true;
}
void model_node::reopen() {
SASSERT(m_closed);
m_closed = false;
}
static bool is_ini(datalog::rule const& r) {
return r.get_uninterpreted_tail_size() == 0;
}
@ -745,6 +750,7 @@ namespace pdr {
return const_cast<datalog::rule*>(m_rule);
}
// only initial states are not set by the PDR search.
SASSERT(m_model.get());
datalog::rule const& rl1 = pt().find_rule(*m_model);
if (is_ini(rl1)) {
set_rule(&rl1);
@ -864,9 +870,10 @@ namespace pdr {
}
void model_search::add_leaf(model_node& n) {
unsigned& count = cache(n).insert_if_not_there2(n.state(), 0)->get_data().m_value;
++count;
if (count == 1 || is_repeated(n)) {
model_nodes ns;
model_nodes& nodes = cache(n).insert_if_not_there2(n.state(), ns)->get_data().m_value;
nodes.push_back(&n);
if (nodes.size() == 1 || is_repeated(n)) {
set_leaf(n);
}
else {
@ -875,7 +882,7 @@ namespace pdr {
}
void model_search::set_leaf(model_node& n) {
erase_children(n);
erase_children(n, true);
SASSERT(n.is_open());
enqueue_leaf(n);
}
@ -897,7 +904,7 @@ namespace pdr {
set_leaf(*root);
}
obj_map<expr, unsigned>& model_search::cache(model_node const& n) {
obj_map<expr, ptr_vector<model_node> >& model_search::cache(model_node const& n) {
unsigned l = n.orig_level();
if (l >= m_cache.size()) {
m_cache.resize(l + 1);
@ -905,7 +912,7 @@ namespace pdr {
return m_cache[l];
}
void model_search::erase_children(model_node& n) {
void model_search::erase_children(model_node& n, bool backtrack) {
ptr_vector<model_node> todo, nodes;
todo.append(n.children());
erase_leaf(n);
@ -916,13 +923,20 @@ namespace pdr {
nodes.push_back(m);
todo.append(m->children());
erase_leaf(*m);
remove_node(*m);
remove_node(*m, backtrack);
}
std::for_each(nodes.begin(), nodes.end(), delete_proc<model_node>());
}
void model_search::remove_node(model_node& n) {
if (0 == --cache(n).find(n.state())) {
void model_search::remove_node(model_node& n, bool backtrack) {
model_nodes& nodes = cache(n).find(n.state());
nodes.erase(&n);
if (nodes.size() > 0 && n.is_open() && backtrack) {
for (unsigned i = 0; i < nodes.size(); ++i) {
nodes[i]->reopen();
}
}
if (nodes.empty()) {
cache(n).remove(n.state());
}
}
@ -1203,8 +1217,8 @@ namespace pdr {
void model_search::reset() {
if (m_root) {
erase_children(*m_root);
remove_node(*m_root);
erase_children(*m_root, false);
remove_node(*m_root, false);
dealloc(m_root);
m_root = 0;
}
@ -1240,7 +1254,7 @@ namespace pdr {
m_pm(m_fparams, params.max_num_contexts(), m),
m_query_pred(m),
m_query(0),
m_search(m_params.bfs_model_search()),
m_search(m_params.bfs_model_search(), m),
m_last_result(l_undef),
m_inductive_lvl(0),
m_expanded_lvl(0),

View file

@ -231,6 +231,7 @@ namespace pdr {
}
void set_closed();
void reopen();
void set_pre_closed() { m_closed = true; }
void reset() { m_children.reset(); }
@ -243,19 +244,21 @@ namespace pdr {
};
class model_search {
typedef ptr_vector<model_node> model_nodes;
ast_manager& m;
bool m_bfs;
model_node* m_root;
std::deque<model_node*> m_leaves;
vector<obj_map<expr, unsigned> > m_cache;
vector<obj_map<expr, model_nodes > > m_cache;
obj_map<expr, unsigned>& cache(model_node const& n);
void erase_children(model_node& n);
obj_map<expr, model_nodes>& cache(model_node const& n);
void erase_children(model_node& n, bool backtrack);
void erase_leaf(model_node& n);
void remove_node(model_node& n);
void remove_node(model_node& n, bool backtrack);
void enqueue_leaf(model_node& n); // add leaf to priority queue.
void update_models();
public:
model_search(bool bfs): m_bfs(bfs), m_root(0) {}
model_search(bool bfs, ast_manager& m): m(m), m_bfs(bfs), m_root(0) {}
~model_search();
void reset();