#pragma once
#include "util/obj_hashtable.h"
#include "muz/base/dl_rule.h"
namespace datalog {
class rule_set;
class rule_dependencies {
public:
typedef obj_hashtable<func_decl> item_set;
typedef obj_map<func_decl, item_set * > deps_type;
typedef deps_type::iterator iterator;
private:
deps_type m_data;
context & m_context;
ptr_vector<expr> m_todo;
expr_sparse_mark m_visited;
void remove_m_data_entry(func_decl * key);
item_set m_empty_item_set;
item_set & ensure_key(func_decl * pred);
void insert(func_decl * depending, func_decl * master);
void populate(rule const* r);
public:
rule_dependencies(context& ctx);
rule_dependencies(const rule_dependencies & o, bool reversed = false);
~rule_dependencies();
void reset();
void populate(const rule_set & rules);
void populate(unsigned n, rule * const * rules);
void restrict_dependencies(const item_set & allowed);
void remove(func_decl * itm);
void remove(const item_set & to_remove);
bool empty() const { return m_data.empty(); }
const item_set & get_deps(func_decl * f) const;
unsigned in_degree(func_decl * f) const { return get_deps(f).size(); }
unsigned out_degree(func_decl * f) const;
bool sort_deps(ptr_vector<func_decl> & res);
iterator begin() const { return m_data.begin(); }
iterator end() const { return m_data.end(); }
void display( std::ostream & out ) const;
};
class rule_stratifier {
public:
typedef func_decl T;
typedef obj_hashtable<T> item_set;
typedef ptr_vector<item_set> comp_vector;
typedef obj_map<T, item_set *> deps_type;
private:
const rule_dependencies & m_deps;
comp_vector m_strats;
obj_map<T, unsigned> m_preorder_nums;
ptr_vector<T> m_stack_S;
ptr_vector<T> m_stack_P;
obj_map<T, unsigned> m_component_nums;
comp_vector m_components;
obj_map<T, unsigned> m_pred_strat_nums;
unsigned m_next_preorder;
unsigned m_first_preorder;
void traverse(T* el);
void process();
public:
rule_stratifier(const rule_dependencies & deps)
: m_deps(deps), m_next_preorder(0)
{
process();
}
~rule_stratifier();
const comp_vector & get_strats() const { return m_strats; }
unsigned get_predicate_strat(func_decl * pred) const;
void display( std::ostream & out ) const;
};
class rule_set {
friend class rule_dependencies;
public:
typedef ptr_vector<func_decl_set> pred_set_vector;
typedef obj_map<func_decl, rule_vector*> decl2rules;
private:
typedef obj_map<func_decl, func_decl_set*> decl2deps;
context & m_context;
rule_manager & m_rule_manager;
rule_ref_vector m_rules; decl2rules m_head2rules; rule_dependencies m_deps; scoped_ptr<rule_stratifier> m_stratifier; func_decl_set m_output_preds; obj_map<func_decl,func_decl*> m_orig2pred;
obj_map<func_decl,func_decl*> m_pred2orig;
func_decl_ref_vector m_refs;
rule_vector m_empty_rule_vector;
void compute_deps();
void compute_tc_deps();
bool stratified_negation();
public:
rule_set(context & ctx);
rule_set(const rule_set & rs);
~rule_set();
ast_manager & get_manager() const;
rule_manager & get_rule_manager() const { return const_cast<rule_manager&>(m_rule_manager); }
context& get_context() const { return m_context; }
void inherit_predicates(rule_set const& other);
void inherit_predicate(rule_set const& other, func_decl* orig, func_decl* pred);
func_decl* get_orig(func_decl* pred) const;
func_decl* get_pred(func_decl* orig) const;
void add_rule(rule * r);
void del_rule(rule * r);
void replace_rule(rule * r, rule * other);
void add_rules(const rule_set& src);
void replace_rules(const rule_set& other);
bool close();
void ensure_closed();
void reopen();
bool is_closed() const { return m_stratifier != 0; }
unsigned get_num_rules() const { return m_rules.size(); }
bool empty() const { return m_rules.empty(); }
rule * get_rule(unsigned i) const { return m_rules[i]; }
rule * last() const { return m_rules[m_rules.size()-1]; }
rule_ref_vector const& get_rules() const { return m_rules; }
const rule_vector & get_predicate_rules(func_decl * pred) const;
bool contains(func_decl* pred) const { return m_head2rules.contains(pred); }
const rule_stratifier & get_stratifier() const {
SASSERT(m_stratifier);
return *m_stratifier;
}
const pred_set_vector & get_strats() const;
unsigned get_predicate_strat(func_decl * pred) const;
const rule_dependencies & get_dependencies() const { SASSERT(is_closed()); return m_deps; }
void split_founded_rules(func_decl_set& founded, func_decl_set& non_founded);
void reset();
void set_output_predicate(func_decl * pred) { m_refs.push_back(pred); m_output_preds.insert(pred); }
bool is_output_predicate(func_decl * pred) const { return m_output_preds.contains(pred); }
void inherit_output_predicate(rule_set const& src, func_decl* pred) { if (src.is_output_predicate(pred) && !is_output_predicate(pred)) set_output_predicate(pred); }
const func_decl_set & get_output_predicates() const { return m_output_preds; }
func_decl* get_output_predicate() const { SASSERT(m_output_preds.size() == 1); return *m_output_preds.begin(); }
bool is_finite_domain() const;
void display(std::ostream & out) const;
void display_deps(std::ostream & out) const;
typedef rule * const * iterator;
iterator begin() const { return m_rules.data(); }
iterator end() const { return m_rules.data()+m_rules.size(); }
decl2rules::iterator begin_grouped_rules() const { return m_head2rules.begin(); }
decl2rules::iterator end_grouped_rules() const { return m_head2rules.end(); }
};
inline std::ostream& operator<<(std::ostream& out, rule_set const& r) { r.display(out); return out; }
};