#ifndef RULE_PROPAGATION_H_
#define RULE_PROPAGATION_H_
#include "rdf_rule_core.h"
#include "rdf_session.h"
#include "rule_internal.h"
#include "rule_session.h"
#include "rule_term_base.h"
#include "knowledge_base.h"
namespace rule {
namespace internal {
/////////////////////////////////////////////////////////////////////////////////////////
// class apply_rule_action
//
/////////////////////////////////////////////////////////////////////////////////////////
struct apply_rule_action
{
inline apply_rule_action(knowledge_base const* kbase_p):
m_kbase_p(kbase_p)
{};
inline ~apply_rule_action(){};
inline bool terminate(rule_session * session_p, rule_vertex const v)const
{
beta_relation const& b = session_p->get_beta_relation(v);
if(!b.is_consequent_term() and b.is_propagation_qx_empty()) return true;
return false;
};
inline void operator()(rule_session * session_p, rule_vertex u, rule_vertex v)const
{
beta_relation& left_relation = session_p->get_beta_relation(u);
beta_relation& relation = session_p->get_beta_relation(v);
knowledge_term const& kterm = m_kbase_p->get_knowledge_term(v);
internal::rule_term_ptr_type const& rule_term = kterm.get_rule_term();
// this is needed for merge_row and retract_row
// not used for first time rule executon.
relation.reset_propagation_qx();
bool need_all_rows = !relation.has_fired();
beta_relation::const_iterator left_relation_itor = left_relation.propagation_qx_rows_iterator(need_all_rows);
// //*
// if(session_p->is_verbose()) {
// std::cout << "\n>>>apply_rule_action: [" << m_kbase_p->get_knowledge_term(u).get_name()
// << "] --> ["
// << m_kbase_p->get_knowledge_term(v).get_name()
// << "]\n";
// }
unsigned int count = 0;
try {
count = rule_term->compute_rows(session_p, left_relation_itor, relation);
} catch(rdf::rdf_exception const& e) {
std::cout << "apply_rule_action: Exception caught: " << e << std::endl;
std::cout << "while processing rule terms " << kterm.get_name() << std::endl;
throw e;
}
}
private:
knowledge_base const* m_kbase_p;
};
/////////////////////////////////////////////////////////////////////////////////////////
// class retract_rule_action
//
/////////////////////////////////////////////////////////////////////////////////////////
struct retract_rule_action
{
inline retract_rule_action(knowledge_base const* kbase_p):
m_kbase_p(kbase_p)
{};
inline ~retract_rule_action(){};
inline bool terminate(rule_session * session_p, rule_vertex const v)const
{
beta_relation const& b = session_p->get_beta_relation(v);
if(!b.is_consequent_term() and b.is_propagation_qx_empty()) return true;
return false;
};
inline void operator()(rule_session * session_p, rule_vertex u, rule_vertex v)const
{
beta_relation& left_relation = session_p->get_beta_relation(u);
beta_relation::const_iterator left_relation_itor = left_relation.propagation_qx_rows_iterator(false);
beta_relation& relation = session_p->get_beta_relation(v);
knowledge_term const& kterm = m_kbase_p->get_knowledge_term(v);
internal::rule_term_ptr_type const& rule_term = kterm.get_rule_term();
relation.reset_propagation_qx();
// //*
// if(session_p->is_verbose()) {
// std::cout << "\n>>>retract_rule_action: [" << m_kbase_p->get_knowledge_term(u).get_name()
// << "] --> ["
// << m_kbase_p->get_knowledge_term(v).get_name()
// << "]\n";
// }
unsigned int count = 0;
try {
count = rule_term->retract_rows(session_p, left_relation_itor, relation);
} catch(rdf::rdf_exception const& e) {
std::cout << "retract_rule_action: Exception caught: " << e << std::endl;
std::cout << "while processing rule terms " << kterm.get_name() << std::endl;
throw e;
}
}
private:
knowledge_base const* m_kbase_p;
};
/////////////////////////////////////////////////////////////////////////////////////////
// class rule_propagator
//
// functor to perform DFS - propagate rule on the rule graph
/////////////////////////////////////////////////////////////////////////////////////////
template<class Action>
class rule_propagator
{
public:
rule_propagator(knowledge_base const* kbase_p, Action const& action):
m_kbase_p(kbase_p),
m_action(action)
{};
~rule_propagator(){};
inline bool keep_vertex(rule_session * session_p, rule_vertex const v)const
{
if(m_kbase_p->get_knowledge_term(v).get_knowledge_rule().get_rule_type() != backward_chaining_rule) return true;
// //*
// if(session_p->is_verbose()) {
// std::cout << "\tkeep_vertex: '" << m_kbase_p->get_knowledge_term(v).get_name()
// << "' is a backward chaining rule, do not propagate forward beyond this node." << std::endl;
// }
return false;
};
inline bool terminate(rule_session * session_p, rule_vertex const v)const
{
if(m_action.terminate(session_p, v)) {
// //*
// if(session_p->is_verbose()) {
// std::cout << "\trule_propagator::terminate: terminate propagation at node: "
// << m_kbase_p->get_knowledge_term(v).get_name() << std::endl;
// }
return true;
}
return false;
};
inline void operator()(rule_session * session_p, rule_vertex const from_vertex)const
{
typedef rule_graph_type::adjacency_iterator iter_t;
typedef std::pair<iter_t, iter_t> iter_pair_t;
typedef std::pair<rule_vertex, iter_pair_t > stack_elm;
if(terminate(session_p, from_vertex)) return;
rule_graph_type const graph = m_kbase_p->get_rule_graph();
std::vector<stack_elm> stack;
stack.reserve(m_kbase_p->get_nbr_vertices());
iter_pair_t iter_pair = boost::adjacent_vertices(from_vertex, graph);
stack.push_back(stack_elm(from_vertex, iter_pair));
while(!stack.empty()) {
stack_elm & elm = stack.back();
rule_vertex u = elm.first;
iter_t itor = elm.second.first;
iter_t end = elm.second.second;
stack.pop_back();
for(; itor!=end; ++itor) {
rule_vertex v = *itor;
m_action(session_p, u, v);
session_p->get_beta_relation(v).set_has_fired(true);
if(keep_vertex(session_p, v) and !terminate(session_p, v)) {
stack.push_back(stack_elm(v, boost::adjacent_vertices(v, graph)));
}
}
}
};
private:
knowledge_base const* m_kbase_p;
Action m_action;
};
/////////////////////////////////////////////////////////////////////////////////////////
// class single_rule_propagator
//
// propagate rule along a single rule path in the rule graph
/////////////////////////////////////////////////////////////////////////////////////////
template<class Action>
class single_rule_propagator
{
public:
single_rule_propagator(knowledge_base const* kbase_p, Action const& action):
m_kbase_p(kbase_p),
m_action(action)
{};
~single_rule_propagator(){};
inline bool terminate(rule_session * session_p, rule_vertex const v)const
{
if(m_action.terminate(session_p, v)) {
// //*
// if(session_p->is_verbose()) {
// std::cout << "\tsingle_rule_propagator::terminate: terminate propagation at node: "
// << m_kbase_p->get_knowledge_term(v).get_name() << std::endl;
// }
return true;
}
return false;
};
inline void operator()(rule_session * session_p, rule_vertex const rule_vertex)const
{
knowledge_rule const& rule = m_kbase_p->get_knowledge_rule(rule_vertex);
knowledge_rule::rule_vertex_const_iterator itor = rule.get_body_term_vertices_begin();
internal::rule_vertex parent = *itor;
knowledge_rule::rule_vertex_const_iterator end = rule.get_body_term_vertices_end();
// first node is graph head vertex
++itor;
if(itor == end) throw rdf::rdf_exception(rdf::unexpected_logic_error, "ERROR: single_rule_propagator: Rule contains no body terms!");
// advance to the first node that has not fired yet.
while(itor!=end and session_p->get_beta_relation(*itor).has_fired()) {
parent = *itor;
++itor;
}
for(; itor!=end; ++itor) {
m_action(session_p, parent, *itor);
session_p->get_beta_relation(*itor).set_has_fired(true);
parent = *itor;
if(terminate(session_p, *itor)) return;
}
};
private:
knowledge_base const* m_kbase_p;
Action m_action;
};
}; /* internal namespace */
}; /* rule namespace */
#endif /*RULE_PROPAGATION_H_*/