diff --git a/src/api/api_special_relations.cpp b/src/api/api_special_relations.cpp index 497ac15e0..2bb40a5e1 100644 --- a/src/api/api_special_relations.cpp +++ b/src/api/api_special_relations.cpp @@ -28,22 +28,22 @@ Revision History: extern "C" { -#define MK_TERN(NAME, FID) \ - Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \ - LOG_ ##NAME(c, index, a, b); \ +#define MK_SPECIAL_R(NAME, FID) \ + Z3_func_decl Z3_API NAME(Z3_context c, Z3_sort s, unsigned index) { \ + LOG_ ##NAME(c, s, index); \ Z3_TRY; \ - expr* args[2] = { to_expr(a), to_expr(b) }; \ parameter p(index); \ - ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \ - mk_c(c)->save_ast_trail(a); \ - RETURN_Z3(of_ast(a)); \ + sort* domain[2] = { to_sort(s), to_sort(s) }; \ + func_decl* f = mk_c(c)->m().mk_func_decl(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, domain, mk_c(c)->m().mk_bool_sort()); \ + mk_c(c)->save_ast_trail(f); \ + RETURN_Z3(of_func_decl(f)); \ Z3_CATCH_RETURN(nullptr); \ } - MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); - MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); - MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); - MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); + MK_SPECIAL_R(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO); + MK_SPECIAL_R(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO); + MK_SPECIAL_R(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO); + MK_SPECIAL_R(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO); #define MK_DECL(NAME, FID) \ diff --git a/src/api/c++/z3++.h b/src/api/c++/z3++.h index fd7cb3a90..a7f1259a0 100644 --- a/src/api/c++/z3++.h +++ b/src/api/c++/z3++.h @@ -1715,25 +1715,17 @@ namespace z3 { */ inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); } - typedef Z3_ast Z3_apply_order(Z3_context, unsigned, Z3_ast, Z3_ast); - - inline expr apply_order(Z3_apply_order app, unsigned index, expr const& a, expr const& b) { - check_context(a, b); - Z3_ast r = app(a.ctx(), index, a, b); - a.check_error(); - return expr(a.ctx(), r); + inline func_decl linear_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_linear_order(a.ctx(), a, index)); } - inline expr linear_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_linear_order, index, a, b); + inline func_decl partial_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_partial_order(a.ctx(), a, index)); } - inline expr partial_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_partial_order, index, a, b); + inline func_decl piecewise_linear_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_piecewise_linear_order(a.ctx(), a, index)); } - inline expr piecewise_linear_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_piecewise_linear_order, index, a, b); - } - inline expr tree_order(unsigned index, expr const& a, expr const& b) { - return apply_order(Z3_mk_tree_order, index, a, b); + inline func_decl tree_order(sort const& a, unsigned index) { + return to_func_decl(a.ctx(), Z3_mk_tree_order(a.ctx(), a, index)); } template class cast_ast; diff --git a/src/api/python/z3/z3.py b/src/api/python/z3/z3.py index 242c73e67..dfa5a0b41 100644 --- a/src/api/python/z3/z3.py +++ b/src/api/python/z3/z3.py @@ -10379,6 +10379,18 @@ def Range(lo, hi, ctx = None): # Special Relations +def PartialOrder(a, index): + return FuncDeclRef(Z3_mk_partial_order(a.ctx_ref(), a.ast, index), a.ctx); + +def LinearOrder(a, index): + return FuncDeclRef(Z3_mk_linear_order(a.ctx_ref(), a.ast, index), a.ctx); + +def TreeOrder(a, index): + return FuncDeclRef(Z3_mk_tree_order(a.ctx_ref(), a.ast, index), a.ctx); + +def PiecewiseLinearOrder(a, index): + return FuncDeclRef(Z3_mk_piecewise_linear_order(a.ctx_ref(), a.ast, index), a.ctx); + def TransitiveClosure(f): """Given a binary relation R, such that the two arguments have the same sort create the transitive closure relation R+. diff --git a/src/api/z3_api.h b/src/api/z3_api.h index e154eaf50..2c07ae73a 100644 --- a/src/api/z3_api.h +++ b/src/api/z3_api.h @@ -3627,36 +3627,30 @@ extern "C" { \pre a and b are of same type. - def_API('Z3_mk_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_linear_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in partial order over a relation indexed by \c id. + \brief create a partial ordering relation over signature \c a and index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_partial_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_partial_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_partial_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in piecewise linear order indexed by relation \c id. + \brief create a piecewise linear ordering relation over signature \c a and index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_piecewise_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_piecewise_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_piecewise_linear_order(Z3_context c, Z3_sort a, unsigned id); /** - \brief declare \c a and \c b are in tree order indexed by \c id. + \brief create a tree ordering lreation over signature \c a identified using index \c id. - \pre a and b are of same type. - - def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST))) + def_API('Z3_mk_tree_order', FUNC_DECL, (_in(CONTEXT), _in(SORT), _in(UINT))) */ - Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b); + Z3_func_decl Z3_API Z3_mk_tree_order(Z3_context c, Z3_sort a, unsigned id); /** \brief create transitive closure of binary relation. diff --git a/src/ast/reg_decl_plugins.cpp b/src/ast/reg_decl_plugins.cpp index 7e121eb7f..6c88f2503 100644 --- a/src/ast/reg_decl_plugins.cpp +++ b/src/ast/reg_decl_plugins.cpp @@ -27,6 +27,7 @@ Revision History: #include "ast/seq_decl_plugin.h" #include "ast/pb_decl_plugin.h" #include "ast/fpa_decl_plugin.h" +#include "ast/special_relations_decl_plugin.h" void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("arith")))) { @@ -56,4 +57,7 @@ void reg_decl_plugins(ast_manager & m) { if (!m.get_plugin(m.mk_family_id(symbol("pb")))) { m.register_plugin(symbol("pb"), alloc(pb_decl_plugin)); } + if (!m.get_plugin(m.mk_family_id(symbol("special_relations")))) { + m.register_plugin(symbol("special_relations"), alloc(special_relations_decl_plugin)); + } } diff --git a/src/smt/diff_logic.h b/src/smt/diff_logic.h index 0e8bd47e1..7899ef8da 100644 --- a/src/smt/diff_logic.h +++ b/src/smt/diff_logic.h @@ -663,19 +663,19 @@ public: visited.reset(); svector nodes; nodes.push_back(start); - for (dl_var n : nodes) { + for (unsigned i = 0; i < nodes.size(); ++i) { + dl_var n = nodes[i]; if (visited.contains(n)) continue; visited.insert(n); edge_id_vector & edges = m_out_edges[n]; for (edge_id e_id : edges) { - edge & e = m_edges[e_id]; - if (e.is_enabled()) { - dst = e.get_target(); - if (target.contains(dst)) { - return true; - } - nodes.push_back(dst); + edge & e = m_edges[e_id]; + if (!e.is_enabled()) continue; + dst = e.get_target(); + if (target.contains(dst)) { + return true; } + nodes.push_back(dst); } } return false; diff --git a/src/smt/theory_special_relations.cpp b/src/smt/theory_special_relations.cpp index 07fd42ad6..e385034b8 100644 --- a/src/smt/theory_special_relations.cpp +++ b/src/smt/theory_special_relations.cpp @@ -20,16 +20,14 @@ Notes: #include -#include "smt/smt_context.h" -#include "smt/theory_arith.h" -#include "smt/theory_special_relations.h" -#include "smt/smt_solver.h" -#include "solver/solver.h" #include "ast/reg_decl_plugins.h" #include "ast/datatype_decl_plugin.h" #include "ast/recfun_decl_plugin.h" #include "ast/ast_pp.h" #include "ast/rewriter/recfun_replace.h" +#include "smt/smt_context.h" +#include "smt/theory_arith.h" +#include "smt/theory_special_relations.h" namespace smt { @@ -411,19 +409,22 @@ namespace smt { uint_set visited, target; for (atom* ap : r.m_asserted_atoms) { atom& a = *ap; - if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) { + if (a.phase()) { continue; } + TRACE("special_relations", tout << a.v1() << " !<= " << a.v2() << "\n";); target.reset(); theory_var w; - // v2 !<= v1 is asserted - target.insert(a.v2()); - if (r.m_graph.reachable(a.v1(), target, visited, w)) { - // we already have v1 <= v2 + // v1 !<= v2 is asserted + target.insert(a.v1()); + if (r.m_graph.reachable(a.v2(), target, visited, w)) { + // we already have v2 <= v1 + TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";); continue; } // the nodes visited from v1 become target for v2 if (r.m_graph.reachable(a.v2(), visited, target, w)) { + // // we have the following: // v1 <= w // v2 <= w @@ -437,6 +438,7 @@ namespace smt { r.m_explanation.reset(); r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r); + TRACE("special_relations", tout << "added edge\n";); r.m_explanation.push_back(a.explanation()); literal_vector const& lits = r.m_explanation; if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) { @@ -444,6 +446,18 @@ namespace smt { return l_false; } } + target.reset(); + visited.reset(); + target.insert(a.v2()); + if (r.m_graph.reachable(a.v1(), target, visited, w)) { + // we have v1 <= v2 + unsigned timestamp = r.m_graph.get_timestamp(); + r.m_explanation.reset(); + r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r); + r.m_explanation.push_back(a.explanation()); + set_conflict(r); + } + } return l_true; } @@ -743,24 +757,26 @@ namespace smt { TRACE("special_relations", g.display(tout);); } + /** + src1 <= i, src2 <= i, src1 != src2 => src1 !<= src2 + */ + void theory_special_relations::ensure_tree(graph& g) { unsigned sz = g.get_num_nodes(); for (unsigned i = 0; i < sz; ++i) { int_vector const& edges = g.get_in_edges(i); for (unsigned j = 0; j < edges.size(); ++j) { edge_id e1 = edges[j]; - if (g.is_enabled(e1)) { - SASSERT (i == g.get_target(e1)); - dl_var src1 = g.get_source(e1); - for (unsigned k = j + 1; k < edges.size(); ++k) { - edge_id e2 = edges[k]; - if (g.is_enabled(e2)) { - dl_var src2 = g.get_source(e2); - if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && - disconnected(g, src1, src2)) { - VERIFY(g.add_strict_edge(src1, src2, literal_vector())); - } - } + if (!g.is_enabled(e1)) continue; + SASSERT (i == g.get_target(e1)); + dl_var src1 = g.get_source(e1); + for (unsigned k = j + 1; k < edges.size(); ++k) { + edge_id e2 = edges[k]; + if (!g.is_enabled(e2)) continue; + dl_var src2 = g.get_source(e2); + if (get_enode(src1)->get_root() != get_enode(src2)->get_root() && + disconnected(g, src1, src2)) { + VERIFY(g.add_strict_edge(src1, src2, literal_vector())); } } } @@ -889,20 +905,6 @@ namespace smt { a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e number of edges. - connected1(x, y, v, w, S) = - if x = v then - if y = w then (S, true) else - if w in S then (S, false) else - connected2(w, y, S u { w }, edges) - else (S, false) - - connected2(x, y, S, []) = (S, false) - connected2(x, y, S, (u,w)::edges) = - let (S, c) = connected1(x, y, u, w, S) - if c then (S, true) else connected2(x, y, S, edges) - - -Take 2: connected(A, dst, S) = let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S))) if A' = nil then false else diff --git a/src/smt/theory_special_relations.h b/src/smt/theory_special_relations.h index 83beb35bb..ae134a366 100644 --- a/src/smt/theory_special_relations.h +++ b/src/smt/theory_special_relations.h @@ -127,9 +127,6 @@ namespace smt { std::ostream& display(theory_special_relations const& sr, std::ostream& out) const; }; - - - typedef u_map bool_var2atom; special_relations_util m_util;