#ifndef KNOWLEDGE_RULE_H_
#define KNOWLEDGE_RULE_H_
namespace rule {
namespace internal {
class extract_variables_action;
class optimize_indexes_action;
}; /* internal namespace */
using internal::knowledge_term;
typedef std::tr1::shared_ptr<knowledge_term> kterm_ptr_type;
/////////////////////////////////////////////////////////////////////////////////////////
// enum rule_type
//
// Identify the type of rule. head_rule_rt is a special type to indicate that the rule
// is associated with the head_term and is not really a rule but serve as a place holder.
/////////////////////////////////////////////////////////////////////////////////////////
enum rule_type {
query_rule, forward_chaining_rule, backward_chaining_rule, head_rule_rt
};
/////////////////////////////////////////////////////////////////////////////////////////
// class knowledge_rule
//
/////////////////////////////////////////////////////////////////////////////////////////
class knowledge_rule
{
public:
typedef internal::expression_term_ptr_type xprsn_ptr_t;
typedef std::list<kterm_ptr_type> term_list;
typedef std::list<xprsn_ptr_t> xprsn_list;
typedef internal::rule_term_ptr_type rule_term_ptr_t;
typedef std::vector<rule_term_ptr_t> explain_rule_term_vec_t;
typedef explain_rule_term_vec_t::const_iterator rule_term_ptr_const_iterator;
typedef term_list::const_iterator kterm_ptr_const_iterator;
typedef term_list::iterator kterm_ptr_iterator;
typedef internal::var_set_t::const_iterator string_const_iterator;
typedef xprsn_list::const_iterator xprsn_ptr_const_iterator;
typedef internal::rule_vertex rule_vertex_type;
typedef std::vector<internal::rule_vertex> body_term_vertices_t;
typedef body_term_vertices_t::const_iterator rule_vertex_const_iterator;
// mappings needed for query - map old var name (user supplied name) to beta relation index
typedef std::tr1::unordered_map<std::string, unsigned int> select_vars_map_t;
knowledge_rule(rule_type const type, std::string const& name, knowledge_base & kbase, unsigned int s, bool has_explain_info, bool opt_flag):
m_type(type),
m_name(name),
m_text(),
m_salience(s),
m_has_explain_info(has_explain_info),
m_opt_flag(opt_flag),
m_kbase(kbase),
m_head_term(),
m_body_terms(),
m_filters(),
m_consequent_terms(),
m_select_vars(),
m_select_vars_map(),
m_explain_terms(),
m_rule_dep_vertex(),
m_body_term_vertices()
{};
virtual ~knowledge_rule() {};
inline rule_type get_rule_type()const {return m_type;};
inline std::string const& get_rule_name()const{return m_name;};
inline void set_rule_text(std::string const& text){m_text = text;};
inline std::string const& get_rule_text()const{return m_text;};
inline void set_rule_salience(unsigned int s){m_salience = s;};
inline unsigned int get_rule_salience()const{return m_salience;};
inline void keep_explain_info(bool b){m_has_explain_info = b;};
inline bool has_explain_info()const{return m_has_explain_info;};
inline void set_optimization_flag(bool b){m_opt_flag = b;};
inline bool get_optimization_flag()const{return m_opt_flag;};
// for backward chaining rule only
template<class O>
inline kterm_ptr_type
set_head_term(std::string const& s, index_type const p, O const& o)
{
if(m_type != backward_chaining_rule) {
const char * msg = "ERROR-R11: knowledge_rule::set_head_term: Available only to backward_chaining_rule";
std::cout << msg << std::endl;
throw rdf::rdf_exception(rdf::invalid_rule_def, msg);
}
m_head_term = kterm_ptr_type(new internal::backward_head_term<std::string, index_type, O>(*this, s, p, o));
add_consequent_term(s, p, o);
return m_head_term;
};
// for query, forward, and backward chaining rules
template<class U, class V, class W>
inline kterm_ptr_type
add_rule_term(U const& u, V const& v, W const& w)
{
kterm_ptr_type term_p = kterm_ptr_type(new internal::body_term<U, V, W>(*this, u, v, w));
m_body_terms.push_back(term_p);
return term_p;
};
// for query, forward, and backward chaining rules
template<class U, class V, class W>
inline kterm_ptr_type
add_negated_rule_term(U const& u, V const& v, W const& w)
{
kterm_ptr_type term_p = kterm_ptr_type(new internal::body_term<U, V, W>(*this, u, v, w, true));
m_body_terms.push_back(term_p);
return term_p;
};
// for query, forward, and backward chaining rules
template<class Oper, class X, class Y>
xprsn_ptr_t
create_expression(Oper const& oper, X const& x, Y const& y)
{
return xprsn_ptr_t(new internal::binary_expression_term<Oper, X, Y>(oper, x, y));
};
template<class Oper, class X>
xprsn_ptr_t
create_expression(Oper const& oper, X const& x)
{
return xprsn_ptr_t(new internal::unary_expression_term<Oper, X>(oper, x));
};
void
set_filter(kterm_ptr_type rule_term_p, xprsn_ptr_t filter_p)
{
if(m_opt_flag) m_filters.push_back(filter_p);
else rule_term_p->set_filter(filter_p);
};
// used by forward chaining rules only (consequent term for backward chaining rules are created from head term)
template<class U, class V, class W>
inline kterm_ptr_type
add_consequent_term(U const& u, V const& v, W const& w)
{
kterm_ptr_type term_p = kterm_ptr_type(new internal::consequent_term<U, V, W>(*this, u, v, w));
term_p->set_consequent(true);
m_consequent_terms.push_back(term_p);
return term_p;
};
// used for query rule only
inline void
add_select_variable(std::string const& v)
{
m_select_vars.insert(v);
};
inline unsigned int
get_select_vars_count()const
{
return m_select_vars_map.size();
};
// used to get the index of a select variable
inline unsigned int
get_select_var_mapping(std::string var)const
{
select_vars_map_t::const_iterator itor = m_select_vars_map.find(var);
if(itor == m_select_vars_map.end()) {
std::string msg("ERROR-R14: knowledge_rule::get_select_var_mapping: Variable '"+var+"' does not exist in the select clause of the query.");
std::cout << msg << std::endl;
throw rdf::rdf_exception(rdf::invalid_rule_def, msg);
}
return itor->second;
};
inline bool
contains_select_var(std::string var)const
{
select_vars_map_t::const_iterator itor = m_select_vars_map.find(var);
if(itor == m_select_vars_map.end()) return false;
return true;
};
inline void
add_select_var_mapping(std::string var, unsigned int index)
{
m_select_vars_map.insert(select_vars_map_t::value_type(var, index));
};
void
set_dependency_graph_vertex(rule_vertex_type const v)
{
m_rule_dep_vertex = v;
};
rule_vertex_type
get_dependency_graph_vertex()const
{
return m_rule_dep_vertex;
};
// usefull for discovering and printing
inline kterm_ptr_const_iterator get_body_terms_begin()const{return m_body_terms.begin();};
inline kterm_ptr_const_iterator get_body_terms_end() const{return m_body_terms.end();};
inline kterm_ptr_iterator get_body_terms_begin(){return m_body_terms.begin();};
inline kterm_ptr_iterator get_body_terms_end() {return m_body_terms.end();};
inline kterm_ptr_const_iterator get_consequent_terms_begin()const{return m_consequent_terms.begin();};
inline kterm_ptr_const_iterator get_consequent_terms_end() const{return m_consequent_terms.end();};
inline kterm_ptr_iterator get_consequent_terms_begin(){return m_consequent_terms.begin();};
inline kterm_ptr_iterator get_consequent_terms_end() {return m_consequent_terms.end();};
inline rule_term_ptr_const_iterator get_explain_terms_begin()const{return m_explain_terms.begin();};
inline rule_term_ptr_const_iterator get_explain_terms_end ()const{return m_explain_terms.end();};
inline kterm_ptr_type const& get_head_term()const{return m_head_term;};
inline kterm_ptr_type & get_head_term(){return m_head_term;};
inline string_const_iterator get_select_vars_begin()const{return m_select_vars.begin();};
inline string_const_iterator get_select_vars_end() const{return m_select_vars.end();};
inline xprsn_ptr_const_iterator get_unallocated_filters_begin()const{return m_filters.begin();};
inline xprsn_ptr_const_iterator get_unallocated_filters_end() const{return m_filters.end();};
inline void add_body_term_vertex(rule_vertex_type v){m_body_term_vertices.push_back(v);};
inline rule_vertex_const_iterator get_body_term_vertices_begin()const{return m_body_term_vertices.begin();};
inline rule_vertex_const_iterator get_body_term_vertices_end() const{return m_body_term_vertices.end();};
inline rule_vertex_type get_tail_body_term_vertex()const{return m_body_term_vertices.back();};
// used in index_triple_cback::perform_merge_row and index_triple_cback::perform_remove_row
// argument v should not be the graph head vertex.
inline rule_vertex_type
get_parent_of(rule_vertex_type v)const
{
rule_vertex_const_iterator itor = get_body_term_vertices_begin();
rule_vertex_const_iterator end = get_body_term_vertices_end();
rule_vertex_const_iterator parent_itor = itor;
// the first one is the graph head vertex which should not be the argument v
for(; itor!=end; ++itor) {
if(*itor == v) {
if(itor == parent_itor) {
// something went wrong
throw rdf::rdf_exception(rdf::unexpected_logic_error, "ERROR: knowledge_rule::get_parent_of: Called with graph head vertex!");
}
return *parent_itor;
}
parent_itor = itor;
}
throw rdf::rdf_exception(rdf::invalid_rule_def, "ERROR: knowledge_rule::get_parent_of: Vertex not found!");
};
protected:
void setup_for_query (rule_term_ptr_t & left_term, internal::var_set_t & right_vars);
void setup_for_head (rule_term_ptr_t & left_term, internal::var_set_t & right_vars);
void setup_for_forward (rule_term_ptr_t & left_term, internal::var_set_t & right_vars);
void setup_for_backward(rule_term_ptr_t & left_term, internal::var_set_t & right_vars);
void
build_consequent_and_explaination_terms(rule_term_ptr_t & left_term, internal::var_set_t & right_vars);
// called by knowledge base
void
compile_rule();
inline unsigned int
nbr_rule_vertices()
{
switch(m_type) {
case head_rule_rt: return 1;
case query_rule: return m_body_terms.size()+1;
case forward_chaining_rule: return m_body_terms.size();
case backward_chaining_rule: return m_body_terms.size()+1;
}
const char * msg = "ERROR-R12: knowledge_rule::nbr_rule_vertices: Missing rule type in switch statement";
std::cout << msg << std::endl;
throw rdf::rdf_exception(rdf::invalid_rule_def, msg);
};
void
create_rule_vertices(bool verbose);
void
check_for_register_inferred_triple(rule_term_ptr_t rule_term_p);
private:
friend class knowledge_base;
friend class internal::optimize_indexes_action;
friend std::ostream & operator<<(std::ostream &, knowledge_rule const&);
void optimize_rule_term_ordering();
void rename_variables();
rule_type m_type;
std::string m_name;
std::string m_text;
unsigned int m_salience;
bool m_has_explain_info;
bool m_opt_flag;
knowledge_base & m_kbase;
kterm_ptr_type m_head_term;
term_list m_body_terms;
xprsn_list m_filters;
term_list m_consequent_terms;
internal::var_set_t m_select_vars;
select_vars_map_t m_select_vars_map; // mapping of user supplied name to index of result set (query case)
explain_rule_term_vec_t m_explain_terms;
rule_vertex_type m_rule_dep_vertex;
body_term_vertices_t m_body_term_vertices;
};
inline std::ostream & operator<<(std::ostream & sout, knowledge_rule const& krule)
{
sout << krule.m_name<< "[salience " << krule.m_salience << "]: ";
if(krule.m_type == backward_chaining_rule) {
sout << (*krule.m_head_term) << " <- ";
}
if(krule.m_type == query_rule) {
sout << " SELECT ";
knowledge_rule::string_const_iterator itor = krule.get_select_vars_begin();
knowledge_rule::string_const_iterator end = krule.get_select_vars_end();
if(itor == end) sout << "*";
for(; itor!=end; ++itor) sout << (*itor) << " ";
sout << " FROM ";
}
knowledge_rule::kterm_ptr_const_iterator itor = krule.get_body_terms_begin();
knowledge_rule::kterm_ptr_const_iterator end = krule.get_body_terms_end();
while(itor != end) {
sout << **itor;
++itor;
if(itor != end) sout << ".";
}
knowledge_rule::xprsn_ptr_const_iterator fitor = krule.get_unallocated_filters_begin();
knowledge_rule::xprsn_ptr_const_iterator fend = krule.get_unallocated_filters_end();
while(fitor != fend) {
sout << "[" << **fitor << "]";
++fitor;
if(fitor != fend) sout << ".";
}
if(krule.m_type == forward_chaining_rule) {
sout << " -> ";
itor = krule.get_consequent_terms_begin();
end = krule.get_consequent_terms_end();
while(itor != end) {
sout << (**itor);
++itor;
if(itor != end) sout << ".";
}
}
return sout;
};
}; /* rule namespace */
#endif /*KNOWLEDGE_RULE_H_*/