#include "knowledge_base.h"
#include "rule_session.h"
#include "rule_term.h"
#include "kb_parser.h"
#include "psearch_db.h"
namespace rule {
knowledge_base::knowledge_base(rdf::rdf_graph_ptr_type const& meta_graph_p):
m_meta_graph_p(meta_graph_p),
m_nbr_vertice(1),
m_nbr_dep_graph_vertice(0),
m_head_vertices(),
m_rule_graph(),
m_rule_dependency_graph(),
m_head(0),
m_dependency_head(0),
m_query_rule_map(),
m_kterm_map(),
m_has_explain_info(true),
m_optimization_flag(false),
m_lookup_index(false),
m_max_rule_visit(10),
m_knowledge_rules(),
m_back_reasoner_mgr(),
m_rdf_inferred_cback_mgr(),
m_rdf_asserted_cback_mgr(),
m_name_set(),
m_psearch_db_p(),
m_tpl_encoder_model_p(new parser::tpl_encoder_model(m_meta_graph_p, false))
{
m_knowledge_rules.reserve(100);
m_head_vertices.reserve(50);
m_head_vertices.push_back(m_head);
create_knowledge_rule(head_rule_rt, "_top_head_rule_", 0);
m_psearch_db_p = psearch::psearch_db_ptr_type(new psearch::PSearchDB(m_meta_graph_p));
};
void
knowledge_base::activate_knowledge_rules(bool verbose)
{
// compile the knowledge rules
// -----------------------------------------------------------------------------------------
unsigned int graph_size = m_nbr_vertice;
knowledge_rule_map_type::iterator itor = m_knowledge_rules.begin();
knowledge_rule_map_type::iterator end = m_knowledge_rules.end();
for(; itor != end; ++itor) {
try {
(*itor)->compile_rule();
graph_size += (*itor)->nbr_rule_vertices();
} catch(rdf::rdf_exception const& e) {
std::string msg = "knowledge_base::activate_knowledge_rules: Exception caught while compiling rule "+(*itor)->get_rule_name()+", message: "+e.what();
std::cout << msg << std::endl;
throw rdf::rdf_exception(rdf::invalid_rule_def, msg);
} catch(...) {
std::string msg("knowledge_base::activate_knowledge_rules: Unknown (general) Exception caught while compiling rules "+(*itor)->get_rule_name()+", no message available");
std::cout << msg << std::endl;
throw rdf::rdf_exception(rdf::none, msg);
}
}
// create data structure of sufficient size
// -----------------------------------------------------------------------------------------
m_rule_graph = rule_graph_type(graph_size);
m_kterm_map = knowledge_term_map_type(graph_size);
// create the head terms
// -----------------------------------------------------------------------------------------
// kterm_ptr_type head_term_p = kterm_ptr_type(new internal::rule_head_term(**m_knowledge_rules.begin()));
// internal::rule_term_ptr_type left_term = head_term_p->create_rule_term(internal::rule_term_ptr_type(), internal::var_set_t());
// head_term_p->set_rule_term(left_term);
// head_term_p->set_name("head");
// add_knowledge_term_mapping(m_head, head_term_p);
// create the rule graph vertices for the knowledge rules
// -----------------------------------------------------------------------------------------
itor = m_knowledge_rules.begin();
for(; itor != end; ++itor) {
knowledge_rule_ptr_type rule_p = *itor;
// create the rule vertices
//---------------------------
rule_p->create_rule_vertices(verbose);
}
// for each consequent term, check if rule terms need to register to the inferred graph
// -----------------------------------------------------------------------------------------
itor = m_knowledge_rules.begin();
for(; itor != end; ++itor) {
knowledge_rule_ptr_type rule_p = *itor;
// for each consequent term, check if rule terms need to register to the inferred graph
knowledge_rule::kterm_ptr_const_iterator citor = rule_p->get_consequent_terms_begin();
knowledge_rule::kterm_ptr_const_iterator cend = rule_p->get_consequent_terms_end();
for(; citor != cend; ++citor) {
internal::rule_term_ptr_type rule_term_p = (*citor)->get_rule_term();
kterm_ptr_const_iterator k_itor = get_knowledge_terms_begin();
kterm_ptr_const_iterator k_end = get_knowledge_terms_end();
for(; k_itor != k_end; ++k_itor) {
if(*k_itor) (*k_itor)->check_for_register_inferred_triple(rule_term_p);
}
}
}
// optimize beta relation indexes and create the rule_term
// -----------------------------------------------------------------------------------------
// visit all head vertices, including query rules
internal::optimize_indexes_action action(this);
rule_vertices_type::const_iterator v_itor = m_head_vertices.begin();
rule_vertices_type::const_iterator v_end = m_head_vertices.end();
for(; v_itor!=v_end; ++v_itor) {
deep_first_search(*v_itor, action);
}
if(verbose) {
std::cout << std::endl;
std::cout << "KB: Asserted callback manager: " << m_rdf_asserted_cback_mgr << std::endl;
std::cout << "KB: Inferred callback manager: " << m_rdf_inferred_cback_mgr << std::endl;
std::cout << std::endl;
}
// compute the rule dependency graph
// -----------------------------------------------------------------------------------------
compute_dependency_graph();
};
template<class A>
void
knowledge_base::deep_first_search(rule_vertex_type from_vertex, A & action)
{
// visit the graph from the root node toward the leafs
// use a deep first search approach but need to calculate the index of the parent node before doing the children
// as a consequence, will need to revisit the children nodes for each parent nodes.
typedef rule_graph_type::adjacency_iterator iter_t;
typedef std::pair<iter_t, iter_t> iter_pair_t;
typedef std::pair<internal::rule_vertex, iter_pair_t > stack_elm;
std::vector<stack_elm> stack;
stack.reserve(get_nbr_vertices());
iter_pair_t iter_pair = boost::adjacent_vertices(from_vertex, m_rule_graph);
stack.push_back(stack_elm(from_vertex, iter_pair));
while(!stack.empty()) {
stack_elm & elm = stack.back();
internal::rule_vertex u = elm.first;
iter_t itor = elm.second.first;
iter_t end = elm.second.second;
stack.pop_back();
for(; itor!=end; ++itor) {
internal::rule_vertex v = *itor;
// apply the action on the current vertex
action(u, v);
stack.push_back(stack_elm(v, boost::adjacent_vertices(v, m_rule_graph)));
}
}
};
void
knowledge_base::compute_dependency_graph()
{
m_rule_dependency_graph = rule_graph_type(m_knowledge_rules.size());
knowledge_rule_map_type::iterator itor = m_knowledge_rules.begin();
knowledge_rule_map_type::iterator end = m_knowledge_rules.end();
for(; itor != end; ++itor) {
add_rule_dependency_graph_edge(
get_head_rule_dependency_vertex(), // dependency graph head vertex -->
(*itor)->get_dependency_graph_vertex()); // rule vertex
knowledge_rule::kterm_ptr_const_iterator citor = (*itor)->get_consequent_terms_begin();
knowledge_rule::kterm_ptr_const_iterator cend = (*itor)->get_consequent_terms_end();
for(; citor != cend; ++citor) {
knowledge_rule_map_type::iterator jtor = m_knowledge_rules.begin();
for(; jtor != end; ++jtor) {
if(jtor != itor) {
knowledge_rule::kterm_ptr_const_iterator b_itor = (*jtor)->get_body_terms_begin();
knowledge_rule::kterm_ptr_const_iterator b_end = (*jtor)->get_body_terms_end();
for(; b_itor != b_end; ++b_itor) {
if((*b_itor)->get_rule_term()->check_for_match((*citor)->get_rule_term())) {
add_rule_dependency_graph_edge(
(*jtor)->get_dependency_graph_vertex(), // rule of body term --->
(*itor)->get_dependency_graph_vertex()); // rule of consequent term
}
}
}
}
}
if((*itor)->get_rule_type() == backward_chaining_rule) {
knowledge_rule_map_type::iterator jtor = m_knowledge_rules.begin();
for(; jtor != end; ++jtor) {
if(jtor != itor) {
knowledge_rule::kterm_ptr_const_iterator b_itor = (*jtor)->get_body_terms_begin();
knowledge_rule::kterm_ptr_const_iterator b_end = (*jtor)->get_body_terms_end();
internal::rule_term_ptr_type rule_head_term_p = (*itor)->get_head_term()->get_rule_term();
for(; b_itor != b_end; ++b_itor) {
if((*b_itor)->get_rule_term()->check_for_match(rule_head_term_p)) {
add_rule_dependency_graph_edge(
(*jtor)->get_dependency_graph_vertex(), // rule of body term --->
(*itor)->get_dependency_graph_vertex()); // backward chaining rule
}
}
}
}
}
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// decode_meta_graph
//
// Decode the rdf meta graph using the encoded_buffer
// returns a knowledge_base created w/ the meta graph and loading the kbase config
/////////////////////////////////////////////////////////////////////////////////////////
knowledge_base_ptr_type
decode_meta_graph(std::string const& kbase_fname, std::string const& encoded_buffer, bool verbose)
{
rdf::rdf_graph_ptr_type meta_graph_p = rdf::create_rdf_graph();
parser::tpl_encoder_model_ptr_type encoder_model_p = parser::create_tpl_encoder_model(meta_graph_p, verbose);
encoder_model_p->decode(encoded_buffer);
knowledge_base_ptr_type kbase_p = parser::load_knowledge_base(kbase_fname, meta_graph_p, verbose);
kbase_p->set_tpl_encoder_model(encoder_model_p);
return kbase_p;
};
namespace internal {
void
extract_variables_action::operator()(rule_vertex, rule_vertex v)
{
knowledge_term & kterm = m_kbase_p->get_knowledge_term(v);
kterm.extract_vars(m_var_set);
if(kterm.has_filter()) kterm.get_filter()->extract_vars(m_var_set);
if(kterm.is_consequent()) {
knowledge_rule const& rule = kterm.get_knowledge_rule();
// get the set of variables that are in the consequent term - case forward and backward chaining rule
knowledge_rule::kterm_ptr_const_iterator itor = rule.get_consequent_terms_begin();
knowledge_rule::kterm_ptr_const_iterator end = rule.get_consequent_terms_end();
for(; itor!=end; ++itor) (*itor)->extract_vars(m_var_set);
// if keeping all variables, i.e., having explain terms, then take all body terms variable
// this is a bit of a duplicate work but some rule may kkep all variables while some other may not
// and two such rules may share terms!
if(rule.has_explain_info()) {
knowledge_rule::kterm_ptr_const_iterator itor = rule.get_body_terms_begin();
knowledge_rule::kterm_ptr_const_iterator end = rule.get_body_terms_end();
for(; itor!=end; ++itor) (*itor)->extract_vars(m_var_set);
}
}
};
void
optimize_indexes_action::operator()(rule_vertex parent, rule_vertex v)
{
knowledge_term & kterm = m_kbase_p->get_knowledge_term(v);
knowledge_rule & rule = kterm.get_knowledge_rule();
// calculate the variables to the right of the rule term identified by v
extract_variables_action action(m_kbase_p);
var_set_t & right_vars = action.get_variables();
// extract the variables to the right of current rule term
action(0, v);
// if this is a query, add the select variables into right_vars
if(rule.get_rule_type() == query_rule) {
knowledge_rule::string_const_iterator itor = rule.get_select_vars_begin();
knowledge_rule::string_const_iterator end = rule.get_select_vars_end();
for(; itor!=end; ++itor) {
right_vars.insert(*itor);
}
}
// use deep first seach on apply action oin all children of v
m_kbase_p->deep_first_search(v, action);
// update the beta relation indexes
rule_term_ptr_type left_term_p = m_kbase_p->get_knowledge_term(parent).get_rule_term();
rule_term_ptr_type rule_term_p = kterm.get_rule_term();
// rebuild the rule term
rule_term_p = kterm.create_rule_term(left_term_p, right_vars);
kterm.set_rule_term(rule_term_p);
// register knowledge term to the inferred graph for insert/delete notification
if(kterm.register_to_inferred_graph()) {
m_kbase_p->register_edge_to_inferred_graph(&rule, parent, v);
// notify parent to build lookup index
if(m_kbase_p->get_lookup_index_flag()) {
left_term_p->set_lookup_index(rule_term_p->get_preferred_lookup_index());
}
}
// register the rule term to fire backward chaining rule as needed
rule_term_p->register_backward_chaining_rules(m_kbase_p->get_back_reasoner_mgr());
// rebuild the consequent and explaination terms
if(kterm.is_consequent()) {
rule.build_consequent_and_explaination_terms(rule_term_p, right_vars);
}
};
}; /* internal namespace */
}; /* rule namespace */