mirror of
https://github.com/Z3Prover/z3
synced 2025-04-13 12:28:44 +00:00
367 lines
15 KiB
C++
367 lines
15 KiB
C++
/*++
|
|
Copyright (c) 2006 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
dl_finite_product_relation.h
|
|
|
|
Abstract:
|
|
|
|
<abstract>
|
|
|
|
Author:
|
|
|
|
Krystof Hoder (t-khoder) 2010-09-24.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
#ifndef _DL_FINITE_PRODUCT_RELATION_H_
|
|
#define _DL_FINITE_PRODUCT_RELATION_H_
|
|
|
|
|
|
#include "dl_base.h"
|
|
#include "dl_relation_manager.h"
|
|
#include "dl_table_relation.h"
|
|
|
|
namespace datalog {
|
|
|
|
class finite_product_relation;
|
|
|
|
void universal_delete(finite_product_relation* ptr);
|
|
|
|
|
|
class finite_product_relation_plugin : public relation_plugin {
|
|
friend class finite_product_relation;
|
|
public:
|
|
struct rel_spec {
|
|
family_id m_inner_kind; //null_family_id means we don't care about the kind
|
|
svector<bool> m_table_cols;
|
|
|
|
rel_spec() : m_inner_kind(null_family_id) {}
|
|
rel_spec(const svector<bool>& table_cols)
|
|
: m_inner_kind(null_family_id), m_table_cols(table_cols) {}
|
|
|
|
bool operator==(const rel_spec & o) const {
|
|
return m_inner_kind==o.m_inner_kind && vectors_equal(m_table_cols, o.m_table_cols);
|
|
}
|
|
struct hash {
|
|
unsigned operator()(const rel_spec & o) const {
|
|
return o.m_inner_kind^int_vector_hash(o.m_table_cols);
|
|
}
|
|
};
|
|
};
|
|
private:
|
|
|
|
class join_fn;
|
|
class converting_join_fn;
|
|
class project_fn;
|
|
class rename_fn;
|
|
class union_fn;
|
|
class inner_singleton_union_fn;
|
|
class converting_union_fn;
|
|
class filter_identical_fn;
|
|
class filter_equal_fn;
|
|
class filter_interpreted_fn;
|
|
class negation_filter_fn;
|
|
class filter_identical_pairs_fn;
|
|
|
|
relation_plugin & m_inner_plugin;
|
|
|
|
rel_spec_store<rel_spec, rel_spec::hash, default_eq<rel_spec> > m_spec_store;
|
|
|
|
static symbol get_name(relation_plugin & inner_plugin);
|
|
family_id get_relation_kind(finite_product_relation & r, const bool * table_columns);
|
|
|
|
static void get_all_possible_table_columns(relation_manager & rmgr, const relation_signature & s,
|
|
svector<bool> & table_columns);
|
|
void get_all_possible_table_columns(const relation_signature & s, svector<bool> & table_columns) {
|
|
get_all_possible_table_columns(get_manager(), s, table_columns);
|
|
}
|
|
|
|
void split_signatures(const relation_signature & s, table_signature & table_sig,
|
|
relation_signature & remaining_sig);
|
|
void split_signatures(const relation_signature & s, const bool * table_columns,
|
|
table_signature & table_sig, relation_signature & remaining_sig);
|
|
public:
|
|
static finite_product_relation & get(relation_base & r);
|
|
static const finite_product_relation & get(const relation_base & r);
|
|
static finite_product_relation * get(relation_base * r);
|
|
static const finite_product_relation * get(const relation_base * r);
|
|
|
|
static finite_product_relation_plugin & get_plugin(relation_manager & rmgr, relation_plugin & inner);
|
|
|
|
finite_product_relation_plugin(relation_plugin & inner_plugin, relation_manager & manager);
|
|
|
|
virtual void initialize(family_id fid);
|
|
|
|
relation_plugin & get_inner_plugin() const { return m_inner_plugin; }
|
|
|
|
virtual bool can_handle_signature(const relation_signature & s);
|
|
|
|
virtual relation_base * mk_empty(const relation_signature & s);
|
|
/**
|
|
\c inner_kind==null_family_id means we don't care about the kind of the inner relation
|
|
*/
|
|
finite_product_relation * mk_empty(const relation_signature & s, const bool * table_columns,
|
|
family_id inner_kind=null_family_id);
|
|
finite_product_relation * mk_empty(const finite_product_relation & original);
|
|
virtual relation_base * mk_empty(const relation_base & original);
|
|
virtual relation_base * mk_empty(const relation_signature & s, family_id kind);
|
|
|
|
virtual relation_base * mk_full(func_decl* p, const relation_signature & s);
|
|
|
|
/**
|
|
\brief Return true if \c r can be converted to \c finite_product_relation_plugin either
|
|
by \c mk_from_table_relation or by \c mk_from_inner_relation.
|
|
*/
|
|
bool can_be_converted(const relation_base & r);
|
|
|
|
/**
|
|
If the conversion cannot be performed, 0 is returned.
|
|
*/
|
|
finite_product_relation * mk_from_table_relation(const table_relation & r);
|
|
finite_product_relation * mk_from_inner_relation(const relation_base & r);
|
|
|
|
bool can_convert_to_table_relation(const finite_product_relation & r);
|
|
table_relation * to_table_relation(const finite_product_relation & r);
|
|
|
|
protected:
|
|
virtual relation_join_fn * mk_join_fn(const relation_base & t1, const relation_base & t2,
|
|
unsigned col_cnt, const unsigned * cols1, const unsigned * cols2);
|
|
virtual relation_transformer_fn * mk_project_fn(const relation_base & t, unsigned col_cnt,
|
|
const unsigned * removed_cols);
|
|
virtual relation_transformer_fn * mk_rename_fn(const relation_base & t, unsigned permutation_cycle_len,
|
|
const unsigned * permutation_cycle);
|
|
virtual relation_union_fn * mk_union_fn(const relation_base & tgt, const relation_base & src,
|
|
const relation_base * delta);
|
|
virtual relation_mutator_fn * mk_filter_identical_fn(const relation_base & t, unsigned col_cnt,
|
|
const unsigned * identical_cols);
|
|
virtual relation_mutator_fn * mk_filter_equal_fn(const relation_base & t, const relation_element & value,
|
|
unsigned col);
|
|
virtual relation_mutator_fn * mk_filter_interpreted_fn(const relation_base & t, app * condition);
|
|
virtual relation_intersection_filter_fn * mk_filter_by_negation_fn(const relation_base & t,
|
|
const relation_base & negated_obj, unsigned joined_col_cnt,
|
|
const unsigned * t_cols, const unsigned * negated_cols);
|
|
|
|
private:
|
|
/**
|
|
\brief Create a filter that enforces equality between pairs of table and relation columns
|
|
|
|
The column numbers in arrays \c table_cols and \c rel_cols must be local to the table/inner relation.
|
|
*/
|
|
relation_mutator_fn * mk_filter_identical_pairs(const finite_product_relation & r, unsigned col_cnt,
|
|
const unsigned * table_cols, const unsigned * rel_cols);
|
|
|
|
/**
|
|
\brief Create a join-project operation that creates a table according to \c relation_table
|
|
but with references to relations updated and removed according to the content of \c filtered_table.
|
|
\c selected_columns contains sorted indexes of data columns in \c relation_table that are also in
|
|
the \c filtered_table (so that the first column in \c filtered_table corresponds to
|
|
\c selected_columns[0] -th column in \c relation_table etc...)
|
|
|
|
Signature of \c relation_table:
|
|
(data columns)(functional column with indexes of relation objects)
|
|
|
|
Signature of \c filtered_table:
|
|
(selected data columns)(non-functional column with original relation object indexes)
|
|
(functional column with indexes of filtered relation objects)
|
|
|
|
*/
|
|
static table_join_fn * mk_assembler_of_filter_result(const table_base & relation_table,
|
|
const table_base & filtered_table, const unsigned_vector & selected_columns);
|
|
|
|
};
|
|
|
|
class finite_product_relation : public relation_base {
|
|
friend class finite_product_relation_plugin;
|
|
friend class finite_product_relation_plugin::join_fn;
|
|
friend class finite_product_relation_plugin::project_fn;
|
|
friend class finite_product_relation_plugin::union_fn;
|
|
friend class finite_product_relation_plugin::rename_fn;
|
|
friend class finite_product_relation_plugin::inner_singleton_union_fn;
|
|
friend class finite_product_relation_plugin::filter_equal_fn;
|
|
friend class finite_product_relation_plugin::filter_identical_pairs_fn;
|
|
|
|
class live_rel_collection_reducer;
|
|
|
|
|
|
public:
|
|
/**
|
|
Size of this sort determines how many different relation objects can we refer to.
|
|
*/
|
|
static const table_sort s_rel_idx_sort;
|
|
|
|
|
|
/**
|
|
\brief The last column in the signature is a functional column with index of the
|
|
associated inner relation. The other columns correspond to the relation signature
|
|
according to \c m_table2sig.
|
|
|
|
It holds that \c m_table_sig.size()-1==m_table2sig.size()
|
|
*/
|
|
|
|
table_signature m_table_sig;
|
|
unsigned_vector m_table2sig; // (ordered list)
|
|
unsigned_vector m_sig2table; //index of corresponding table column or UINT_MAX
|
|
private:
|
|
relation_signature m_other_sig;
|
|
unsigned_vector m_other2sig; // (ordered list)
|
|
public:
|
|
unsigned_vector m_sig2other; //index of corresponding other relation column or UINT_MAX
|
|
private:
|
|
relation_plugin & m_other_plugin;
|
|
family_id m_other_kind;
|
|
|
|
mutable table_base * m_table;
|
|
public:
|
|
mutable relation_vector m_others;
|
|
private:
|
|
mutable unsigned_vector m_available_rel_indexes;
|
|
|
|
/**
|
|
\c UINT_MAX means uninitialized.
|
|
If we can get away with it, we want to have a single full relation to refer to.
|
|
*/
|
|
mutable unsigned m_full_rel_idx;
|
|
|
|
mutable idx_set m_live_rel_collection_acc;
|
|
mutable scoped_ptr<table_transformer_fn> m_live_rel_collection_project;
|
|
|
|
mutable scoped_ptr<table_intersection_filter_fn> m_empty_rel_removal_filter;
|
|
|
|
void recycle_rel_idx(unsigned idx) const;
|
|
|
|
// creates a full relation if it does not exist.
|
|
unsigned get_full_rel_idx();
|
|
|
|
|
|
|
|
public:
|
|
relation_base & get_inner_rel(table_element idx)
|
|
{ SASSERT(idx<UINT_MAX); return get_inner_rel(static_cast<unsigned>(idx)); }
|
|
relation_base & get_inner_rel(unsigned idx) { SASSERT(m_others[idx]); return *m_others[idx]; }
|
|
const relation_base & get_inner_rel(unsigned idx) const
|
|
{ return const_cast<finite_product_relation &>(*this).get_inner_rel(idx); }
|
|
|
|
unsigned get_next_rel_idx() const;
|
|
|
|
/**
|
|
The relation takes ownership of the \c inner object.
|
|
*/
|
|
void set_inner_rel(table_element idx, relation_base * inner)
|
|
{ SASSERT(idx<UINT_MAX); return set_inner_rel(static_cast<unsigned>(idx), inner); }
|
|
/**
|
|
The relation takes ownership of the \c inner object.
|
|
*/
|
|
void set_inner_rel(unsigned idx, relation_base * inner) {
|
|
SASSERT(!m_others[idx]);
|
|
SASSERT(inner);
|
|
m_others[idx] = inner;
|
|
}
|
|
table_base & get_table() { return *m_table; }
|
|
|
|
table_plugin & get_table_plugin() const { return get_table().get_plugin(); }
|
|
|
|
void garbage_collect(bool remove_empty) const;
|
|
|
|
/**
|
|
\brief Initialize an empty relation with table \c table_vals and relations in \c others.
|
|
|
|
The relation object takes ownership of relations inside the \c others vector.
|
|
|
|
If \c contiguous is true, it can be assumed that there are no zero elements in the \c others array.
|
|
*/
|
|
void init(const table_base & table_vals, const relation_vector & others, bool contiguous);
|
|
|
|
private:
|
|
|
|
|
|
/**
|
|
\brief Extract the values of table non-functional columns from the relation fact.
|
|
The value of the functional column which determines index of the inner relation is undefined.
|
|
*/
|
|
void extract_table_fact(const relation_fact rf, table_fact & tf) const;
|
|
/**
|
|
\brief Extract the values of the inner relation columns from the relation fact.
|
|
*/
|
|
void extract_other_fact(const relation_fact rf, relation_fact & of) const;
|
|
|
|
relation_base * mk_empty_inner();
|
|
relation_base * mk_full_inner(func_decl* pred);
|
|
|
|
|
|
void complement_self(func_decl* pred);
|
|
|
|
void collect_live_relation_indexes(idx_set & res) const;
|
|
|
|
|
|
/**
|
|
\brief Try to modify relations in \c rels so that they have the same columns corresponding to the table
|
|
and the inner relation (so that the union can be perofrmed on theim in a straightforward way).
|
|
|
|
Relations in \c rels must all have equal signature.
|
|
|
|
Even if the function fails and false is returned, some relations may already be modified. They are
|
|
in a valid state, but with different specification.
|
|
*/
|
|
static bool try_unify_specifications(ptr_vector<finite_product_relation> & rels);
|
|
|
|
bool try_modify_specification(const bool * table_cols);
|
|
|
|
virtual bool can_swap(const relation_base & r) const
|
|
{ return &get_plugin()==&r.get_plugin(); }
|
|
|
|
/**
|
|
\brief Swap content of the current relation with the content of \c r.
|
|
|
|
Both relations must come from the same plugin and be of the same signature.
|
|
*/
|
|
virtual void swap(relation_base & r);
|
|
|
|
/**
|
|
\brief Create a \c finite_product_relation object.
|
|
*/
|
|
finite_product_relation(finite_product_relation_plugin & p, const relation_signature & s,
|
|
const bool * table_columns, table_plugin & tplugin, relation_plugin & oplugin, family_id other_kind);
|
|
finite_product_relation(const finite_product_relation & r);
|
|
virtual ~finite_product_relation();
|
|
public:
|
|
context & get_context() const;
|
|
finite_product_relation_plugin & get_plugin() const {
|
|
return static_cast<finite_product_relation_plugin &>(relation_base::get_plugin());
|
|
}
|
|
|
|
bool is_table_column(unsigned col_idx) const { return m_sig2table[col_idx]!=UINT_MAX; }
|
|
|
|
const table_base & get_table() const { return *m_table; }
|
|
|
|
const relation_base & get_inner_rel(table_element idx) const
|
|
{ SASSERT(idx<UINT_MAX); return get_inner_rel(static_cast<unsigned>(idx)); }
|
|
|
|
/**
|
|
The function calls garbage_collect, so the internal state may change when it is called.
|
|
*/
|
|
virtual bool empty() const;
|
|
void reset() { m_table->reset(); garbage_collect(false); }
|
|
|
|
virtual void add_fact(const relation_fact & f);
|
|
virtual bool contains_fact(const relation_fact & f) const;
|
|
|
|
virtual finite_product_relation * clone() const;
|
|
virtual finite_product_relation * complement(func_decl* p) const;
|
|
|
|
virtual void display(std::ostream & out) const;
|
|
virtual void display_tuples(func_decl & pred, std::ostream & out) const;
|
|
|
|
virtual unsigned get_size_estimate_rows() const { return m_table->get_size_estimate_rows(); }
|
|
virtual unsigned get_size_estimate_bytes() const { return m_table->get_size_estimate_bytes(); }
|
|
|
|
virtual void to_formula(expr_ref& fml) const;
|
|
};
|
|
|
|
};
|
|
|
|
#endif /* _DL_FINITE_PRODUCT_RELATION_H_ */
|
|
|