mirror of
https://github.com/Z3Prover/z3
synced 2026-02-25 01:31:18 +00:00
467 lines
16 KiB
C++
467 lines
16 KiB
C++
/*++
|
|
Copyright (c) 2013 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dl_lazy_table.cpp
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
Nikolaj Bjorner (nbjorner) 2013-09-04
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "muz/rel/dl_lazy_table.h"
|
|
#include "muz/rel/dl_relation_manager.h"
|
|
#include <sstream>
|
|
|
|
namespace datalog {
|
|
|
|
// ------------------
|
|
// lazy_table_plugin:
|
|
|
|
symbol lazy_table_plugin::mk_name(table_plugin& p) {
|
|
std::ostringstream strm;
|
|
strm << "lazy_" << p.get_name();
|
|
return symbol(strm.str());
|
|
}
|
|
|
|
table_base * lazy_table_plugin::mk_empty(const table_signature & s) {
|
|
return alloc(lazy_table, alloc(lazy_table_base, *this, m_plugin.mk_empty(s)));
|
|
}
|
|
|
|
lazy_table const& lazy_table_plugin::get(table_base const& tb) { return dynamic_cast<lazy_table const&>(tb); }
|
|
lazy_table& lazy_table_plugin::get(table_base& tb) { return dynamic_cast<lazy_table&>(tb); }
|
|
lazy_table const* lazy_table_plugin::get(table_base const* tb) { return dynamic_cast<lazy_table const*>(tb); }
|
|
lazy_table* lazy_table_plugin::get(table_base* tb) { return dynamic_cast<lazy_table*>(tb); }
|
|
|
|
// --------------------------
|
|
// lazy_table_plugin::join_fn
|
|
|
|
class lazy_table_plugin::join_fn : public convenient_table_join_fn {
|
|
public:
|
|
join_fn(table_signature const& s1, table_signature const& s2, unsigned col_cnt,
|
|
unsigned const* cols1, unsigned const* cols2):
|
|
convenient_table_join_fn(s1, s2, col_cnt, cols1, cols2) {}
|
|
|
|
table_base* operator()(const table_base& _t1, const table_base& _t2) override {
|
|
lazy_table const& t1 = get(_t1);
|
|
lazy_table const& t2 = get(_t2);
|
|
lazy_table_ref* tr = alloc(lazy_table_join, m_cols1.size(), m_cols1.data(), m_cols2.data(), t1, t2, get_result_signature());
|
|
return alloc(lazy_table, tr);
|
|
}
|
|
};
|
|
|
|
table_join_fn * lazy_table_plugin::mk_join_fn(
|
|
const table_base & t1, const table_base & t2,
|
|
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2) {
|
|
if (check_kind(t1) && check_kind(t2)) {
|
|
return alloc(join_fn, t1.get_signature(), t2.get_signature(), col_cnt, cols1, cols2);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// ------------------------
|
|
// lazy_table_plugin::union
|
|
|
|
class lazy_table_plugin::union_fn : public table_union_fn {
|
|
public:
|
|
void operator()(table_base & _tgt, const table_base & _src,
|
|
table_base * _delta) override {
|
|
lazy_table& tgt = get(_tgt);
|
|
lazy_table const& src = get(_src);
|
|
lazy_table* delta = get(_delta);
|
|
table_base const* t_src = src.eval();
|
|
table_base * t_tgt = tgt.eval();
|
|
table_base * t_delta = delta?delta->eval():nullptr;
|
|
verbose_action _t("union");
|
|
table_union_fn* m = tgt.get_lplugin().get_manager().mk_union_fn(*t_tgt, *t_src, t_delta);
|
|
SASSERT(m);
|
|
(*m)(*t_tgt, *t_src, t_delta);
|
|
dealloc(m);
|
|
}
|
|
};
|
|
|
|
|
|
table_union_fn* lazy_table_plugin::mk_union_fn(
|
|
const table_base & tgt, const table_base & src,
|
|
const table_base * delta) {
|
|
if (check_kind(tgt) && check_kind(src) && (!delta || check_kind(*delta))) {
|
|
return alloc(union_fn);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// --------------------------
|
|
// lazy_table_plugin::project
|
|
|
|
class lazy_table_plugin::project_fn : public convenient_table_project_fn {
|
|
public:
|
|
project_fn(table_signature const& orig_sig, unsigned cnt, unsigned const* cols):
|
|
convenient_table_project_fn(orig_sig, cnt, cols)
|
|
{}
|
|
|
|
table_base* operator()(table_base const& _t) override {
|
|
lazy_table const& t = get(_t);
|
|
return alloc(lazy_table, alloc(lazy_table_project, m_removed_cols.size(), m_removed_cols.data(), t, get_result_signature()));
|
|
}
|
|
};
|
|
|
|
table_transformer_fn * lazy_table_plugin::mk_project_fn(
|
|
const table_base & t, unsigned col_cnt,
|
|
const unsigned * removed_cols) {
|
|
if (check_kind(t)) {
|
|
return alloc(project_fn, t.get_signature(), col_cnt, removed_cols);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// -------------------------
|
|
// lazy_table_plugin::rename
|
|
|
|
class lazy_table_plugin::rename_fn : public convenient_table_rename_fn {
|
|
public:
|
|
rename_fn(table_signature const& orig_sig, unsigned cnt, unsigned const* cols):
|
|
convenient_table_rename_fn(orig_sig, cnt, cols)
|
|
{}
|
|
|
|
table_base* operator()(table_base const& _t) override {
|
|
lazy_table const& t = get(_t);
|
|
return alloc(lazy_table, alloc(lazy_table_rename, m_cycle.size(), m_cycle.data(), t, get_result_signature()));
|
|
}
|
|
};
|
|
|
|
table_transformer_fn * lazy_table_plugin::mk_rename_fn(
|
|
const table_base & t, unsigned col_cnt,
|
|
const unsigned * removed_cols) {
|
|
if (check_kind(t)) {
|
|
return alloc(rename_fn, t.get_signature(), col_cnt, removed_cols);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
// -----------------------------------
|
|
// lazy_table_plugin::filter_identical
|
|
|
|
class lazy_table_plugin::filter_identical_fn : public table_mutator_fn {
|
|
unsigned_vector m_cols;
|
|
public:
|
|
filter_identical_fn(unsigned cnt, unsigned const* cols): m_cols(cnt, cols) {}
|
|
|
|
void operator()(table_base& _t) override {
|
|
lazy_table& t = get(_t);
|
|
t.set(alloc(lazy_table_filter_identical, m_cols.size(), m_cols.data(), t));
|
|
}
|
|
};
|
|
|
|
table_mutator_fn * lazy_table_plugin::mk_filter_identical_fn(
|
|
const table_base & t, unsigned col_cnt, const unsigned * identical_cols) {
|
|
if (check_kind(t)) {
|
|
return alloc(filter_identical_fn, col_cnt, identical_cols);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------------
|
|
// lazy_table_plugin::filter_interpreted
|
|
|
|
class lazy_table_plugin::filter_interpreted_fn : public table_mutator_fn {
|
|
app_ref m_condition;
|
|
public:
|
|
filter_interpreted_fn(app_ref& p): m_condition(p) {}
|
|
|
|
void operator()(table_base& _t) override {
|
|
lazy_table& t = get(_t);
|
|
t.set(alloc(lazy_table_filter_interpreted, t, m_condition));
|
|
}
|
|
};
|
|
|
|
table_mutator_fn * lazy_table_plugin::mk_filter_interpreted_fn(
|
|
const table_base & t, app* condition) {
|
|
if (check_kind(t)) {
|
|
app_ref cond(condition, get_ast_manager());
|
|
return alloc(filter_interpreted_fn, cond);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
// -------------------------------------
|
|
// lazy_table_plugin::filter_by_negation
|
|
|
|
class lazy_table_plugin::filter_by_negation_fn : public table_intersection_filter_fn {
|
|
unsigned_vector m_cols1;
|
|
unsigned_vector m_cols2;
|
|
public:
|
|
filter_by_negation_fn(unsigned cnt, unsigned const* cols1, unsigned const* cols2):
|
|
m_cols1(cnt, cols1), m_cols2(cnt, cols2) {}
|
|
void operator()(table_base & _t, const table_base & _intersected_obj) override {
|
|
lazy_table& t = get(_t);
|
|
lazy_table const& it = get(_intersected_obj);
|
|
t.set(alloc(lazy_table_filter_by_negation, t, it, m_cols1, m_cols2));
|
|
}
|
|
};
|
|
|
|
table_intersection_filter_fn * lazy_table_plugin::mk_filter_by_negation_fn(
|
|
const table_base & t,
|
|
const table_base & negated_obj, unsigned joined_col_cnt,
|
|
const unsigned * t_cols, const unsigned * negated_cols) {
|
|
if (check_kind(t) && check_kind(negated_obj)) {
|
|
return alloc(filter_by_negation_fn, joined_col_cnt, t_cols, negated_cols);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
// -------------------------------
|
|
// lazy_table_plugin::filter_equal
|
|
|
|
class lazy_table_plugin::filter_equal_fn : public table_mutator_fn {
|
|
table_element m_value;
|
|
unsigned m_col;
|
|
public:
|
|
filter_equal_fn(const table_element & value, unsigned col):
|
|
m_value(value),
|
|
m_col(col)
|
|
{ }
|
|
|
|
void operator()(table_base& _t) override {
|
|
lazy_table& t = get(_t);
|
|
t.set(alloc(lazy_table_filter_equal, m_col, m_value, t));
|
|
}
|
|
};
|
|
|
|
table_mutator_fn * lazy_table_plugin::mk_filter_equal_fn(
|
|
const table_base & t, const table_element & value, unsigned col) {
|
|
if (check_kind(t)) {
|
|
return alloc(filter_equal_fn, value, col);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
table_plugin* lazy_table_plugin::mk_sparse(relation_manager& rm) {
|
|
table_plugin* sp = rm.get_table_plugin(symbol("sparse"));
|
|
SASSERT(sp);
|
|
if (sp) {
|
|
return alloc(lazy_table_plugin, *sp);
|
|
}
|
|
else {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
|
|
// ----------
|
|
// lazy_table
|
|
|
|
table_base * lazy_table::clone() const {
|
|
table_base* t = eval();
|
|
verbose_action _t("clone");
|
|
return alloc(lazy_table, alloc(lazy_table_base, get_lplugin(), t->clone()));
|
|
}
|
|
table_base * lazy_table::complement(func_decl* p, const table_element * func_columns) const {
|
|
table_base* t = eval()->complement(p, func_columns);
|
|
return alloc(lazy_table, alloc(lazy_table_base, get_lplugin(), t));
|
|
}
|
|
bool lazy_table::empty() const {
|
|
return m_ref->eval()->empty();
|
|
}
|
|
bool lazy_table::contains_fact(const table_fact & f) const {
|
|
return m_ref->eval()->contains_fact(f);
|
|
}
|
|
void lazy_table::remove_fact(table_element const* fact) {
|
|
m_ref->eval()->remove_fact(fact);
|
|
}
|
|
void lazy_table::remove_facts(unsigned fact_cnt, const table_fact * facts) {
|
|
m_ref->eval()->remove_facts(fact_cnt, facts);
|
|
}
|
|
void lazy_table::remove_facts(unsigned fact_cnt, const table_element * facts) {
|
|
m_ref->eval()->remove_facts(fact_cnt, facts);
|
|
}
|
|
void lazy_table::reset() {
|
|
m_ref = alloc(lazy_table_base, get_lplugin(), get_lplugin().m_plugin.mk_empty(get_signature()));
|
|
}
|
|
void lazy_table::add_fact(table_fact const& f) {
|
|
m_ref->eval()->add_fact(f);
|
|
}
|
|
table_base::iterator lazy_table::begin() const {
|
|
return eval()->begin();
|
|
}
|
|
table_base::iterator lazy_table::end() const {
|
|
return eval()->end();
|
|
}
|
|
table_base* lazy_table::eval() const {
|
|
return m_ref->eval();
|
|
}
|
|
|
|
// -------------------------
|
|
// eval
|
|
|
|
|
|
table_base* lazy_table_join::force() {
|
|
SASSERT(!m_table);
|
|
table_base* t1 = m_t1->eval();
|
|
table_base* t2 = m_t2->eval();
|
|
verbose_action _t("join");
|
|
table_join_fn* join = rm().mk_join_fn(*t1, *t2, m_cols1.size(), m_cols1.data(), m_cols2.data());
|
|
m_table = (*join)(*t1, *t2);
|
|
dealloc(join);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_project::force() {
|
|
SASSERT(!m_table);
|
|
switch(m_src->kind()) {
|
|
case LAZY_TABLE_JOIN: {
|
|
lazy_table_join& src = dynamic_cast<lazy_table_join&>(*m_src);
|
|
table_base* t1 = src.t1()->eval();
|
|
table_base* t2 = src.t2()->eval();
|
|
table_join_fn* j_fn = rm().mk_join_project_fn(*t1, *t2, src.cols1(), src.cols2(), m_cols);
|
|
if (j_fn) {
|
|
verbose_action _t("join_project");
|
|
m_table = (*j_fn)(*t1, *t2);
|
|
dealloc(j_fn);
|
|
}
|
|
break;
|
|
}
|
|
case LAZY_TABLE_FILTER_INTERPRETED: {
|
|
lazy_table_filter_interpreted& src = dynamic_cast<lazy_table_filter_interpreted&>(*m_src);
|
|
table_transformer_fn* tr = rm().mk_filter_interpreted_and_project_fn(*src.eval(), src.condition(), m_cols.size(), m_cols.data());
|
|
if (tr) {
|
|
verbose_action _t("filter_interpreted_project");
|
|
m_table = (*tr)(*src.eval());
|
|
dealloc(tr);
|
|
}
|
|
break;
|
|
}
|
|
case LAZY_TABLE_FILTER_EQUAL: {
|
|
lazy_table_filter_equal& src = dynamic_cast<lazy_table_filter_equal&>(*m_src);
|
|
table_base* t = src.eval();
|
|
table_transformer_fn* tr = rm().mk_select_equal_and_project_fn(*t, src.value(), src.col());
|
|
if (tr) {
|
|
verbose_action _t("select_equal_project");
|
|
m_table = (*tr)(*t);
|
|
dealloc(tr);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
if (m_table) {
|
|
return m_table.get();
|
|
}
|
|
table_base* src = m_src->eval();
|
|
verbose_action _t("project");
|
|
table_transformer_fn* project = rm().mk_project_fn(*src, m_cols.size(), m_cols.data());
|
|
SASSERT(project);
|
|
m_table = (*project)(*src);
|
|
dealloc(project);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_rename::force() {
|
|
SASSERT(!m_table);
|
|
table_base* src = m_src->eval();
|
|
verbose_action _t("rename");
|
|
table_transformer_fn* rename = rm().mk_rename_fn(*src, m_cols.size(), m_cols.data());
|
|
m_table = (*rename)(*src);
|
|
dealloc(rename);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_filter_identical::force() {
|
|
SASSERT(!m_table);
|
|
m_table = m_src->eval();
|
|
m_src->release_table();
|
|
m_src = nullptr;
|
|
verbose_action _t("filter_identical");
|
|
table_mutator_fn* m = rm().mk_filter_identical_fn(*m_table, m_cols.size(), m_cols.data());
|
|
SASSERT(m);
|
|
(*m)(*m_table);
|
|
dealloc(m);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_filter_equal::force() {
|
|
SASSERT(!m_table);
|
|
m_table = m_src->eval();
|
|
m_src->release_table();
|
|
m_src = nullptr;
|
|
verbose_action _t("filter_equal");
|
|
table_mutator_fn* m = rm().mk_filter_equal_fn(*m_table, m_value, m_col);
|
|
SASSERT(m);
|
|
(*m)(*m_table);
|
|
dealloc(m);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_filter_interpreted::force() {
|
|
SASSERT(!m_table);
|
|
m_table = m_src->eval();
|
|
m_src->release_table();
|
|
m_src = nullptr;
|
|
verbose_action _t("filter_interpreted");
|
|
table_mutator_fn* m = rm().mk_filter_interpreted_fn(*m_table, m_condition);
|
|
SASSERT(m);
|
|
(*m)(*m_table);
|
|
dealloc(m);
|
|
return m_table.get();
|
|
}
|
|
|
|
table_base* lazy_table_filter_by_negation::force() {
|
|
SASSERT(!m_table);
|
|
m_table = m_tgt->eval();
|
|
m_tgt->release_table();
|
|
m_tgt = nullptr;
|
|
|
|
switch(m_src->kind()) {
|
|
|
|
case LAZY_TABLE_JOIN: {
|
|
lazy_table_join& src = dynamic_cast<lazy_table_join&>(*m_src);
|
|
table_base* t1 = src.t1()->eval();
|
|
table_base* t2 = src.t2()->eval();
|
|
verbose_action _t("filter_by_negation_join");
|
|
table_intersection_join_filter_fn* jn = rm().mk_filter_by_negated_join_fn(*m_table, *t1, *t2, cols1(), cols2(), src.cols1(), src.cols2());
|
|
if (jn) {
|
|
(*jn)(*m_table, *t1, *t2);
|
|
dealloc(jn);
|
|
return m_table.get();
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
table_base* src = m_src->eval();
|
|
verbose_action _t("filter_by_negation");
|
|
table_intersection_filter_fn* m = rm().mk_filter_by_negation_fn(*m_table, *src, m_cols1, m_cols2);
|
|
SASSERT(m);
|
|
(*m)(*m_table, *src);
|
|
dealloc(m);
|
|
return m_table.get();
|
|
}
|
|
}
|