Skip to content

Commit 6158ea6

Browse files
fix tree-order, change API for special relations to produce function declarations
Signed-off-by: Nikolaj Bjorner <[email protected]>
1 parent b4ba44c commit 6158ea6

8 files changed

+92
-91
lines changed

src/api/api_special_relations.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,22 @@ Revision History:
2828
extern "C" {
2929

3030

31-
#define MK_TERN(NAME, FID) \
32-
Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \
33-
LOG_ ##NAME(c, index, a, b); \
31+
#define MK_SPECIAL_R(NAME, FID) \
32+
Z3_func_decl Z3_API NAME(Z3_context c, Z3_sort s, unsigned index) { \
33+
LOG_ ##NAME(c, s, index); \
3434
Z3_TRY; \
35-
expr* args[2] = { to_expr(a), to_expr(b) }; \
3635
parameter p(index); \
37-
ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \
38-
mk_c(c)->save_ast_trail(a); \
39-
RETURN_Z3(of_ast(a)); \
36+
sort* domain[2] = { to_sort(s), to_sort(s) }; \
37+
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()); \
38+
mk_c(c)->save_ast_trail(f); \
39+
RETURN_Z3(of_func_decl(f)); \
4040
Z3_CATCH_RETURN(nullptr); \
4141
}
4242

43-
MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO);
44-
MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO);
45-
MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO);
46-
MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO);
43+
MK_SPECIAL_R(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO);
44+
MK_SPECIAL_R(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO);
45+
MK_SPECIAL_R(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO);
46+
MK_SPECIAL_R(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO);
4747

4848

4949
#define MK_DECL(NAME, FID) \

src/api/c++/z3++.h

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1715,25 +1715,17 @@ namespace z3 {
17151715
*/
17161716
inline expr sext(expr const & a, unsigned i) { return to_expr(a.ctx(), Z3_mk_sign_ext(a.ctx(), i, a)); }
17171717

1718-
typedef Z3_ast Z3_apply_order(Z3_context, unsigned, Z3_ast, Z3_ast);
1719-
1720-
inline expr apply_order(Z3_apply_order app, unsigned index, expr const& a, expr const& b) {
1721-
check_context(a, b);
1722-
Z3_ast r = app(a.ctx(), index, a, b);
1723-
a.check_error();
1724-
return expr(a.ctx(), r);
1725-
}
1726-
inline expr linear_order(unsigned index, expr const& a, expr const& b) {
1727-
return apply_order(Z3_mk_linear_order, index, a, b);
1718+
inline func_decl linear_order(sort const& a, unsigned index) {
1719+
return to_func_decl(a.ctx(), Z3_mk_linear_order(a.ctx(), a, index));
17281720
}
1729-
inline expr partial_order(unsigned index, expr const& a, expr const& b) {
1730-
return apply_order(Z3_mk_partial_order, index, a, b);
1721+
inline func_decl partial_order(sort const& a, unsigned index) {
1722+
return to_func_decl(a.ctx(), Z3_mk_partial_order(a.ctx(), a, index));
17311723
}
1732-
inline expr piecewise_linear_order(unsigned index, expr const& a, expr const& b) {
1733-
return apply_order(Z3_mk_piecewise_linear_order, index, a, b);
1724+
inline func_decl piecewise_linear_order(sort const& a, unsigned index) {
1725+
return to_func_decl(a.ctx(), Z3_mk_piecewise_linear_order(a.ctx(), a, index));
17341726
}
1735-
inline expr tree_order(unsigned index, expr const& a, expr const& b) {
1736-
return apply_order(Z3_mk_tree_order, index, a, b);
1727+
inline func_decl tree_order(sort const& a, unsigned index) {
1728+
return to_func_decl(a.ctx(), Z3_mk_tree_order(a.ctx(), a, index));
17371729
}
17381730

17391731
template<typename T> class cast_ast;

src/api/python/z3/z3.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10379,6 +10379,18 @@ def Range(lo, hi, ctx = None):
1037910379

1038010380
# Special Relations
1038110381

10382+
def PartialOrder(a, index):
10383+
return FuncDeclRef(Z3_mk_partial_order(a.ctx_ref(), a.ast, index), a.ctx);
10384+
10385+
def LinearOrder(a, index):
10386+
return FuncDeclRef(Z3_mk_linear_order(a.ctx_ref(), a.ast, index), a.ctx);
10387+
10388+
def TreeOrder(a, index):
10389+
return FuncDeclRef(Z3_mk_tree_order(a.ctx_ref(), a.ast, index), a.ctx);
10390+
10391+
def PiecewiseLinearOrder(a, index):
10392+
return FuncDeclRef(Z3_mk_piecewise_linear_order(a.ctx_ref(), a.ast, index), a.ctx);
10393+
1038210394
def TransitiveClosure(f):
1038310395
"""Given a binary relation R, such that the two arguments have the same sort
1038410396
create the transitive closure relation R+.

src/api/z3_api.h

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -3627,36 +3627,30 @@ extern "C" {
36273627
\pre a and b are of same type.
36283628
36293629
3630-
def_API('Z3_mk_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
3630+
def_API('Z3_mk_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT)))
36313631
*/
3632-
Z3_ast Z3_API Z3_mk_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b);
3632+
Z3_func_decl Z3_API Z3_mk_linear_order(Z3_context c, Z3_sort a, unsigned id);
36333633

36343634
/**
3635-
\brief declare \c a and \c b are in partial order over a relation indexed by \c id.
3635+
\brief create a partial ordering relation over signature \c a and index \c id.
36363636
3637-
\pre a and b are of same type.
3638-
3639-
def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
3637+
def_API('Z3_mk_partial_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT)))
36403638
*/
3641-
Z3_ast Z3_API Z3_mk_partial_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b);
3639+
Z3_func_decl Z3_API Z3_mk_partial_order(Z3_context c, Z3_sort a, unsigned id);
36423640

36433641
/**
3644-
\brief declare \c a and \c b are in piecewise linear order indexed by relation \c id.
3645-
3646-
\pre a and b are of same type.
3642+
\brief create a piecewise linear ordering relation over signature \c a and index \c id.
36473643
3648-
def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
3644+
def_API('Z3_mk_piecewise_linear_order', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT)))
36493645
*/
3650-
Z3_ast Z3_API Z3_mk_piecewise_linear_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b);
3646+
Z3_func_decl Z3_API Z3_mk_piecewise_linear_order(Z3_context c, Z3_sort a, unsigned id);
36513647

36523648
/**
3653-
\brief declare \c a and \c b are in tree order indexed by \c id.
3654-
3655-
\pre a and b are of same type.
3649+
\brief create a tree ordering lreation over signature \c a identified using index \c id.
36563650
3657-
def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
3651+
def_API('Z3_mk_tree_order', FUNC_DECL, (_in(CONTEXT), _in(SORT), _in(UINT)))
36583652
*/
3659-
Z3_ast Z3_API Z3_mk_tree_order(Z3_context c, unsigned id, Z3_ast a, Z3_ast b);
3653+
Z3_func_decl Z3_API Z3_mk_tree_order(Z3_context c, Z3_sort a, unsigned id);
36603654

36613655
/**
36623656
\brief create transitive closure of binary relation.

src/ast/reg_decl_plugins.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Revision History:
2727
#include "ast/seq_decl_plugin.h"
2828
#include "ast/pb_decl_plugin.h"
2929
#include "ast/fpa_decl_plugin.h"
30+
#include "ast/special_relations_decl_plugin.h"
3031

3132
void reg_decl_plugins(ast_manager & m) {
3233
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
@@ -56,4 +57,7 @@ void reg_decl_plugins(ast_manager & m) {
5657
if (!m.get_plugin(m.mk_family_id(symbol("pb")))) {
5758
m.register_plugin(symbol("pb"), alloc(pb_decl_plugin));
5859
}
60+
if (!m.get_plugin(m.mk_family_id(symbol("special_relations")))) {
61+
m.register_plugin(symbol("special_relations"), alloc(special_relations_decl_plugin));
62+
}
5963
}

src/smt/diff_logic.h

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -663,19 +663,19 @@ class dl_graph {
663663
visited.reset();
664664
svector<dl_var> nodes;
665665
nodes.push_back(start);
666-
for (dl_var n : nodes) {
666+
for (unsigned i = 0; i < nodes.size(); ++i) {
667+
dl_var n = nodes[i];
667668
if (visited.contains(n)) continue;
668669
visited.insert(n);
669670
edge_id_vector & edges = m_out_edges[n];
670671
for (edge_id e_id : edges) {
671-
edge & e = m_edges[e_id];
672-
if (e.is_enabled()) {
673-
dst = e.get_target();
674-
if (target.contains(dst)) {
675-
return true;
676-
}
677-
nodes.push_back(dst);
672+
edge & e = m_edges[e_id];
673+
if (!e.is_enabled()) continue;
674+
dst = e.get_target();
675+
if (target.contains(dst)) {
676+
return true;
678677
}
678+
nodes.push_back(dst);
679679
}
680680
}
681681
return false;

src/smt/theory_special_relations.cpp

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,16 +20,14 @@ Module Name:
2020

2121
#include <fstream>
2222

23-
#include "smt/smt_context.h"
24-
#include "smt/theory_arith.h"
25-
#include "smt/theory_special_relations.h"
26-
#include "smt/smt_solver.h"
27-
#include "solver/solver.h"
2823
#include "ast/reg_decl_plugins.h"
2924
#include "ast/datatype_decl_plugin.h"
3025
#include "ast/recfun_decl_plugin.h"
3126
#include "ast/ast_pp.h"
3227
#include "ast/rewriter/recfun_replace.h"
28+
#include "smt/smt_context.h"
29+
#include "smt/theory_arith.h"
30+
#include "smt/theory_special_relations.h"
3331

3432

3533
namespace smt {
@@ -411,19 +409,22 @@ namespace smt {
411409
uint_set visited, target;
412410
for (atom* ap : r.m_asserted_atoms) {
413411
atom& a = *ap;
414-
if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) {
412+
if (a.phase()) {
415413
continue;
416414
}
415+
TRACE("special_relations", tout << a.v1() << " !<= " << a.v2() << "\n";);
417416
target.reset();
418417
theory_var w;
419-
// v2 !<= v1 is asserted
420-
target.insert(a.v2());
421-
if (r.m_graph.reachable(a.v1(), target, visited, w)) {
422-
// we already have v1 <= v2
418+
// v1 !<= v2 is asserted
419+
target.insert(a.v1());
420+
if (r.m_graph.reachable(a.v2(), target, visited, w)) {
421+
// we already have v2 <= v1
422+
TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";);
423423
continue;
424424
}
425425
// the nodes visited from v1 become target for v2
426426
if (r.m_graph.reachable(a.v2(), visited, target, w)) {
427+
//
427428
// we have the following:
428429
// v1 <= w
429430
// v2 <= w
@@ -437,13 +438,26 @@ namespace smt {
437438
r.m_explanation.reset();
438439
r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r);
439440
r.m_graph.find_shortest_reachable_path(a.v2(), w, timestamp, r);
441+
TRACE("special_relations", tout << "added edge\n";);
440442
r.m_explanation.push_back(a.explanation());
441443
literal_vector const& lits = r.m_explanation;
442444
if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) {
443445
set_neg_cycle_conflict(r);
444446
return l_false;
445447
}
446448
}
449+
target.reset();
450+
visited.reset();
451+
target.insert(a.v2());
452+
if (r.m_graph.reachable(a.v1(), target, visited, w)) {
453+
// we have v1 <= v2
454+
unsigned timestamp = r.m_graph.get_timestamp();
455+
r.m_explanation.reset();
456+
r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r);
457+
r.m_explanation.push_back(a.explanation());
458+
set_conflict(r);
459+
}
460+
447461
}
448462
return l_true;
449463
}
@@ -743,24 +757,26 @@ namespace smt {
743757
TRACE("special_relations", g.display(tout););
744758
}
745759

760+
/**
761+
src1 <= i, src2 <= i, src1 != src2 => src1 !<= src2
762+
*/
763+
746764
void theory_special_relations::ensure_tree(graph& g) {
747765
unsigned sz = g.get_num_nodes();
748766
for (unsigned i = 0; i < sz; ++i) {
749767
int_vector const& edges = g.get_in_edges(i);
750768
for (unsigned j = 0; j < edges.size(); ++j) {
751769
edge_id e1 = edges[j];
752-
if (g.is_enabled(e1)) {
753-
SASSERT (i == g.get_target(e1));
754-
dl_var src1 = g.get_source(e1);
755-
for (unsigned k = j + 1; k < edges.size(); ++k) {
756-
edge_id e2 = edges[k];
757-
if (g.is_enabled(e2)) {
758-
dl_var src2 = g.get_source(e2);
759-
if (get_enode(src1)->get_root() != get_enode(src2)->get_root() &&
760-
disconnected(g, src1, src2)) {
761-
VERIFY(g.add_strict_edge(src1, src2, literal_vector()));
762-
}
763-
}
770+
if (!g.is_enabled(e1)) continue;
771+
SASSERT (i == g.get_target(e1));
772+
dl_var src1 = g.get_source(e1);
773+
for (unsigned k = j + 1; k < edges.size(); ++k) {
774+
edge_id e2 = edges[k];
775+
if (!g.is_enabled(e2)) continue;
776+
dl_var src2 = g.get_source(e2);
777+
if (get_enode(src1)->get_root() != get_enode(src2)->get_root() &&
778+
disconnected(g, src1, src2)) {
779+
VERIFY(g.add_strict_edge(src1, src2, literal_vector()));
764780
}
765781
}
766782
}
@@ -889,20 +905,6 @@ namespace smt {
889905
a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e
890906
number of edges.
891907
892-
connected1(x, y, v, w, S) =
893-
if x = v then
894-
if y = w then (S, true) else
895-
if w in S then (S, false) else
896-
connected2(w, y, S u { w }, edges)
897-
else (S, false)
898-
899-
connected2(x, y, S, []) = (S, false)
900-
connected2(x, y, S, (u,w)::edges) =
901-
let (S, c) = connected1(x, y, u, w, S)
902-
if c then (S, true) else connected2(x, y, S, edges)
903-
904-
905-
Take 2:
906908
connected(A, dst, S) =
907909
let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S)))
908910
if A' = nil then false else

src/smt/theory_special_relations.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,6 @@ namespace smt {
127127
std::ostream& display(theory_special_relations const& sr, std::ostream& out) const;
128128
};
129129

130-
131-
132-
133130
typedef u_map<atom*> bool_var2atom;
134131

135132
special_relations_util m_util;

0 commit comments

Comments
 (0)