mirror of
https://github.com/Z3Prover/z3
synced 2025-06-03 12:51:22 +00:00
fix tree-order, change API for special relations to produce function declarations
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
b4ba44ce9d
commit
6158ea61c8
8 changed files with 92 additions and 91 deletions
|
@ -28,22 +28,22 @@ Revision History:
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
|
||||||
#define MK_TERN(NAME, FID) \
|
#define MK_SPECIAL_R(NAME, FID) \
|
||||||
Z3_ast Z3_API NAME(Z3_context c, unsigned index, Z3_ast a, Z3_ast b) { \
|
Z3_func_decl Z3_API NAME(Z3_context c, Z3_sort s, unsigned index) { \
|
||||||
LOG_ ##NAME(c, index, a, b); \
|
LOG_ ##NAME(c, s, index); \
|
||||||
Z3_TRY; \
|
Z3_TRY; \
|
||||||
expr* args[2] = { to_expr(a), to_expr(b) }; \
|
|
||||||
parameter p(index); \
|
parameter p(index); \
|
||||||
ast* a = mk_c(c)->m().mk_app(mk_c(c)->get_special_relations_fid(), FID, 1, &p, 2, args); \
|
sort* domain[2] = { to_sort(s), to_sort(s) }; \
|
||||||
mk_c(c)->save_ast_trail(a); \
|
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()); \
|
||||||
RETURN_Z3(of_ast(a)); \
|
mk_c(c)->save_ast_trail(f); \
|
||||||
|
RETURN_Z3(of_func_decl(f)); \
|
||||||
Z3_CATCH_RETURN(nullptr); \
|
Z3_CATCH_RETURN(nullptr); \
|
||||||
}
|
}
|
||||||
|
|
||||||
MK_TERN(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO);
|
MK_SPECIAL_R(Z3_mk_linear_order, OP_SPECIAL_RELATION_LO);
|
||||||
MK_TERN(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO);
|
MK_SPECIAL_R(Z3_mk_partial_order, OP_SPECIAL_RELATION_PO);
|
||||||
MK_TERN(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO);
|
MK_SPECIAL_R(Z3_mk_piecewise_linear_order, OP_SPECIAL_RELATION_PLO);
|
||||||
MK_TERN(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO);
|
MK_SPECIAL_R(Z3_mk_tree_order, OP_SPECIAL_RELATION_TO);
|
||||||
|
|
||||||
|
|
||||||
#define MK_DECL(NAME, FID) \
|
#define MK_DECL(NAME, FID) \
|
||||||
|
|
|
@ -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)); }
|
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 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 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 expr linear_order(unsigned index, expr const& a, expr const& b) {
|
inline func_decl partial_order(sort const& a, unsigned index) {
|
||||||
return apply_order(Z3_mk_linear_order, index, a, b);
|
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) {
|
inline func_decl piecewise_linear_order(sort const& a, unsigned index) {
|
||||||
return apply_order(Z3_mk_partial_order, index, a, b);
|
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) {
|
inline func_decl tree_order(sort const& a, unsigned index) {
|
||||||
return apply_order(Z3_mk_piecewise_linear_order, index, a, b);
|
return to_func_decl(a.ctx(), Z3_mk_tree_order(a.ctx(), a, index));
|
||||||
}
|
|
||||||
inline expr tree_order(unsigned index, expr const& a, expr const& b) {
|
|
||||||
return apply_order(Z3_mk_tree_order, index, a, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T> class cast_ast;
|
template<typename T> class cast_ast;
|
||||||
|
|
|
@ -10379,6 +10379,18 @@ def Range(lo, hi, ctx = None):
|
||||||
|
|
||||||
# Special Relations
|
# 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):
|
def TransitiveClosure(f):
|
||||||
"""Given a binary relation R, such that the two arguments have the same sort
|
"""Given a binary relation R, such that the two arguments have the same sort
|
||||||
create the transitive closure relation R+.
|
create the transitive closure relation R+.
|
||||||
|
|
|
@ -3627,36 +3627,30 @@ extern "C" {
|
||||||
\pre a and b are of same type.
|
\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', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT)))
|
||||||
|
|
||||||
def_API('Z3_mk_partial_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
|
|
||||||
*/
|
*/
|
||||||
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', FUNC_DECL ,(_in(CONTEXT), _in(SORT), _in(UINT)))
|
||||||
|
|
||||||
def_API('Z3_mk_piecewise_linear_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
|
|
||||||
*/
|
*/
|
||||||
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', FUNC_DECL, (_in(CONTEXT), _in(SORT), _in(UINT)))
|
||||||
|
|
||||||
def_API('Z3_mk_tree_order', AST ,(_in(CONTEXT), _in(UINT), _in(AST), _in(AST)))
|
|
||||||
*/
|
*/
|
||||||
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.
|
\brief create transitive closure of binary relation.
|
||||||
|
|
|
@ -27,6 +27,7 @@ Revision History:
|
||||||
#include "ast/seq_decl_plugin.h"
|
#include "ast/seq_decl_plugin.h"
|
||||||
#include "ast/pb_decl_plugin.h"
|
#include "ast/pb_decl_plugin.h"
|
||||||
#include "ast/fpa_decl_plugin.h"
|
#include "ast/fpa_decl_plugin.h"
|
||||||
|
#include "ast/special_relations_decl_plugin.h"
|
||||||
|
|
||||||
void reg_decl_plugins(ast_manager & m) {
|
void reg_decl_plugins(ast_manager & m) {
|
||||||
if (!m.get_plugin(m.mk_family_id(symbol("arith")))) {
|
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")))) {
|
if (!m.get_plugin(m.mk_family_id(symbol("pb")))) {
|
||||||
m.register_plugin(symbol("pb"), alloc(pb_decl_plugin));
|
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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -663,19 +663,19 @@ public:
|
||||||
visited.reset();
|
visited.reset();
|
||||||
svector<dl_var> nodes;
|
svector<dl_var> nodes;
|
||||||
nodes.push_back(start);
|
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;
|
if (visited.contains(n)) continue;
|
||||||
visited.insert(n);
|
visited.insert(n);
|
||||||
edge_id_vector & edges = m_out_edges[n];
|
edge_id_vector & edges = m_out_edges[n];
|
||||||
for (edge_id e_id : edges) {
|
for (edge_id e_id : edges) {
|
||||||
edge & e = m_edges[e_id];
|
edge & e = m_edges[e_id];
|
||||||
if (e.is_enabled()) {
|
if (!e.is_enabled()) continue;
|
||||||
dst = e.get_target();
|
dst = e.get_target();
|
||||||
if (target.contains(dst)) {
|
if (target.contains(dst)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
nodes.push_back(dst);
|
|
||||||
}
|
}
|
||||||
|
nodes.push_back(dst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -20,16 +20,14 @@ Notes:
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#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/reg_decl_plugins.h"
|
||||||
#include "ast/datatype_decl_plugin.h"
|
#include "ast/datatype_decl_plugin.h"
|
||||||
#include "ast/recfun_decl_plugin.h"
|
#include "ast/recfun_decl_plugin.h"
|
||||||
#include "ast/ast_pp.h"
|
#include "ast/ast_pp.h"
|
||||||
#include "ast/rewriter/recfun_replace.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 {
|
namespace smt {
|
||||||
|
@ -411,19 +409,22 @@ namespace smt {
|
||||||
uint_set visited, target;
|
uint_set visited, target;
|
||||||
for (atom* ap : r.m_asserted_atoms) {
|
for (atom* ap : r.m_asserted_atoms) {
|
||||||
atom& a = *ap;
|
atom& a = *ap;
|
||||||
if (a.phase() || r.m_uf.find(a.v1()) != r.m_uf.find(a.v2())) {
|
if (a.phase()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
TRACE("special_relations", tout << a.v1() << " !<= " << a.v2() << "\n";);
|
||||||
target.reset();
|
target.reset();
|
||||||
theory_var w;
|
theory_var w;
|
||||||
// v2 !<= v1 is asserted
|
// v1 !<= v2 is asserted
|
||||||
target.insert(a.v2());
|
target.insert(a.v1());
|
||||||
if (r.m_graph.reachable(a.v1(), target, visited, w)) {
|
if (r.m_graph.reachable(a.v2(), target, visited, w)) {
|
||||||
// we already have v1 <= v2
|
// we already have v2 <= v1
|
||||||
|
TRACE("special_relations", tout << "already: " << a.v2() << " <= " << a.v1() << "\n";);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// the nodes visited from v1 become target for v2
|
// the nodes visited from v1 become target for v2
|
||||||
if (r.m_graph.reachable(a.v2(), visited, target, w)) {
|
if (r.m_graph.reachable(a.v2(), visited, target, w)) {
|
||||||
|
//
|
||||||
// we have the following:
|
// we have the following:
|
||||||
// v1 <= w
|
// v1 <= w
|
||||||
// v2 <= w
|
// v2 <= w
|
||||||
|
@ -437,6 +438,7 @@ namespace smt {
|
||||||
r.m_explanation.reset();
|
r.m_explanation.reset();
|
||||||
r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r);
|
r.m_graph.find_shortest_reachable_path(a.v1(), w, timestamp, r);
|
||||||
r.m_graph.find_shortest_reachable_path(a.v2(), 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());
|
r.m_explanation.push_back(a.explanation());
|
||||||
literal_vector const& lits = r.m_explanation;
|
literal_vector const& lits = r.m_explanation;
|
||||||
if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) {
|
if (!r.m_graph.add_non_strict_edge(a.v2(), a.v1(), lits)) {
|
||||||
|
@ -444,6 +446,18 @@ namespace smt {
|
||||||
return l_false;
|
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;
|
return l_true;
|
||||||
}
|
}
|
||||||
|
@ -743,24 +757,26 @@ namespace smt {
|
||||||
TRACE("special_relations", g.display(tout););
|
TRACE("special_relations", g.display(tout););
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
src1 <= i, src2 <= i, src1 != src2 => src1 !<= src2
|
||||||
|
*/
|
||||||
|
|
||||||
void theory_special_relations::ensure_tree(graph& g) {
|
void theory_special_relations::ensure_tree(graph& g) {
|
||||||
unsigned sz = g.get_num_nodes();
|
unsigned sz = g.get_num_nodes();
|
||||||
for (unsigned i = 0; i < sz; ++i) {
|
for (unsigned i = 0; i < sz; ++i) {
|
||||||
int_vector const& edges = g.get_in_edges(i);
|
int_vector const& edges = g.get_in_edges(i);
|
||||||
for (unsigned j = 0; j < edges.size(); ++j) {
|
for (unsigned j = 0; j < edges.size(); ++j) {
|
||||||
edge_id e1 = edges[j];
|
edge_id e1 = edges[j];
|
||||||
if (g.is_enabled(e1)) {
|
if (!g.is_enabled(e1)) continue;
|
||||||
SASSERT (i == g.get_target(e1));
|
SASSERT (i == g.get_target(e1));
|
||||||
dl_var src1 = g.get_source(e1);
|
dl_var src1 = g.get_source(e1);
|
||||||
for (unsigned k = j + 1; k < edges.size(); ++k) {
|
for (unsigned k = j + 1; k < edges.size(); ++k) {
|
||||||
edge_id e2 = edges[k];
|
edge_id e2 = edges[k];
|
||||||
if (g.is_enabled(e2)) {
|
if (!g.is_enabled(e2)) continue;
|
||||||
dl_var src2 = g.get_source(e2);
|
dl_var src2 = g.get_source(e2);
|
||||||
if (get_enode(src1)->get_root() != get_enode(src2)->get_root() &&
|
if (get_enode(src1)->get_root() != get_enode(src2)->get_root() &&
|
||||||
disconnected(g, src1, src2)) {
|
disconnected(g, src1, src2)) {
|
||||||
VERIFY(g.add_strict_edge(src1, src2, literal_vector()));
|
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
|
a fixed set of edges. It runs in O(e*n^2) where n is the number of vertices and e
|
||||||
number of edges.
|
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) =
|
connected(A, dst, S) =
|
||||||
let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S)))
|
let (A',S') = next1(a1, b1, A, next1(a2, b2, A, ... S, (nil, S)))
|
||||||
if A' = nil then false else
|
if A' = nil then false else
|
||||||
|
|
|
@ -127,9 +127,6 @@ namespace smt {
|
||||||
std::ostream& display(theory_special_relations const& sr, std::ostream& out) const;
|
std::ostream& display(theory_special_relations const& sr, std::ostream& out) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
typedef u_map<atom*> bool_var2atom;
|
typedef u_map<atom*> bool_var2atom;
|
||||||
|
|
||||||
special_relations_util m_util;
|
special_relations_util m_util;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue