#include "psearch_db.h"
#include "psearch_query.h"
namespace psearch {
/////////////////////////////////////////////////////////////////////////////////////////
// Category::apply_value_partition_rule
//
/////////////////////////////////////////////////////////////////////////////////////////
void
Category::apply_value_partition_rule()
{
if(not is_value_partition()) return;
// for each pattern in db
pattern_list_iterator pitor = m_db_p->get_patterns_begin();
pattern_list_iterator pend = m_db_p->get_patterns_end();
for(; pitor!=pend; ++pitor) {
pattern_ptr_type pattern_p = *pitor;
// if it has any node of this category, then add/remove other nodes as negated node
node_set_const_iterator itor = get_nodes_iterator();
while(not itor.is_end()) {
node_index_type node_index = itor.get_value_by_value();
if(pattern_p->is_c2_node(node_index)) {
// add/remove all other nodes of this category as negated node
node_set_const_iterator jtor = get_nodes_iterator();
while(not jtor.is_end()) {
node_index_type jnode_index = jtor.get_value_by_value();
if(node_index != jnode_index) {
if(not pattern_p->is_negated_by_node(jnode_index)) {
pattern_p->add_negated_node(jnode_index);
}
}
jtor.next();
}
}
itor.next();
}
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// Rule::is_consistent
//
/////////////////////////////////////////////////////////////////////////////////////////
bool
Rule::is_consistent()const
{
node_set_const_iterator itor = get_negated_nodes_iterator();
while(not itor.is_end()) {
node_index_type node_index = itor.get_value_by_value();
// rule is inconsistent if a negated node is also a c2 node
if(is_c2_node(node_index)) return false;
itor.next();
}
return true;
};
/////////////////////////////////////////////////////////////////////////////////////////
// Rule::generate_patterns
//
/////////////////////////////////////////////////////////////////////////////////////////
void
Rule::generate_patterns(PSearchDB * db_p, bool verbose)
{
if(is_patterns_generated()) return;
if(verbose) {
std::cout << "Rule::generate_patterns: for " << *this << std::endl;
}
// perform the cross product of all ex_categories
// x_nodes: set of nodes forming an elm of the product (having one node of each category)
// categories_stack: stack of category for which nodes must be taken from.
node_set_type x_nodes;
category_vector_type categories_stack;
// initial condition: x_nodes is empty and categories_stack contains all categories.
category_set_const_iterator itor = get_ex_categories_iterator();
while(not itor.is_end()) {
categories_stack.push_back(itor.get_value());
itor.next();
}
generate_xp_patterns(db_p, x_nodes, categories_stack, verbose);
if(verbose) std::cout << std::endl;
};
/////////////////////////////////////////////////////////////////////////////////////////
// Rule::generate_xp_patterns
//
/////////////////////////////////////////////////////////////////////////////////////////
void
Rule::generate_xp_patterns(PSearchDB * db_p, node_set_type const& x_nodes, category_vector_type const& categories_stack, bool verbose)
{
if(not categories_stack.empty()) {
// create a cross product with the next ex_category from the ex_c_itor
// pop front a category from category_stack and pass on the rest of the stack into a copy
// add a node to x_nodes from the poped category.
category_vector_type cc_stack(categories_stack);
category_index_type category_index = cc_stack.back();
cc_stack.pop_back();
node_set_const_iterator itor = category_index->get_nodes_iterator();
while(not itor.is_end()) {
node_index_type node_index = itor.get_value_by_value();
node_set_type xc_nodes(x_nodes);
xc_nodes.insert(node_index);
generate_xp_patterns(db_p, xc_nodes, cc_stack, verbose);
itor.next();
}
} else {
// generate the pattern with x_nodes as c1 nodes from the ex_categories (existential condition)
Pattern & pattern = db_p->create_pattern();
init_pattern(db_p, pattern);
for(node_set_type::const_iterator xtor=x_nodes.begin(); xtor!=x_nodes.end(); ++xtor) {
node_index_type node_index = *xtor;
pattern.add_c1_node(node_index);
db_p->get_node(node_index).add_pattern(pattern.get_pattern_index());
}
if(verbose) std::cout << " - " << pattern << std::endl;
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// Rule::init_pattern
//
/////////////////////////////////////////////////////////////////////////////////////////
void
Rule::init_pattern(PSearchDB * db_p, Pattern & pattern)
{
pattern.set_active(is_active());
pattern.set_weight(get_weight());
pattern.set_rule_index(get_rule_index());
pattern.set_name(get_name()+" ("+pattern.get_index_name()+")");
for(node_const_iterator_type itor=get_c1_nodes_begin(); itor!=get_c1_nodes_end(); ++itor) {
node_index_type node_index = *itor;
pattern.add_c1_node(node_index);
db_p->get_node(node_index).add_pattern(pattern.get_pattern_index());
}
for(node_const_iterator_type itor=get_c2_nodes_begin(); itor!=get_c2_nodes_end(); ++itor) {
pattern.add_c2_node(*itor);
}
for(node_const_iterator_type itor=get_negated_nodes_begin(); itor!=get_negated_nodes_end(); ++itor) {
pattern.add_negated_node(*itor);
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::load_from_meta_graph
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::load_from_meta_graph(bool verbose)
{
rdf::rdf_graph::index_iterator itor;
// check if there is anything to load at all
itor = m_meta_graph_p->find_index(rdf::all_subjects(), rdf_type, top_PSearchDB);
if(itor.is_end()) return;
// load nodes
itor = m_meta_graph_p->find_index(rdf::all_subjects(), rdf_type, top_Node);
while(not itor.is_end()) {
index_type index = itor.get_triple().get_subject();
std::string name = m_meta_graph_p->get_literal_object(index, top_name).get_string();
node_index_type node_index = create_node(index, name);
int b = m_meta_graph_p->get_literal_object(index, top_skip_activation).get_int();
get_node(node_index).set_skip_pattern_activation(b>0 ? true:false);
itor.next();
}
// load categories
itor = m_meta_graph_p->find_index(rdf::all_subjects(), rdf_type, top_Category);
while(not itor.is_end()) {
index_type index = itor.get_triple().get_subject();
std::string name = m_meta_graph_p->get_literal_object(index, top_name).get_string();
category_index_type category_index = create_category(index, name);
int b = m_meta_graph_p->get_literal_object(index, top_value_partition).get_int();
get_category(category_index).set_value_partition(b>0 ? true:false);
itor.next();
}
itor = m_meta_graph_p->find_index(rdf::all_subjects(), top_has_node, rdf::all_objects());
while(not itor.is_end()) {
rdf::index_triple t3 = itor.get_triple();
category_index_type category_index = get_category_index(t3.get_subject());
node_index_type node_index = get_node_index(t3.get_object());
if(category_index and node_index) {
get_category(category_index).add_node(node_index);
get_node(node_index).add_category(category_index);
}
itor.next();
}
// load rules
itor = m_meta_graph_p->find_index(rdf::all_subjects(), rdf_type, top_Rule);
while(not itor.is_end()) {
index_type index = itor.get_triple().get_subject();
std::string name = m_meta_graph_p->get_literal_object(index, top_name).get_string();
Rule & rule = get_rule(create_rule(index, name));
unsigned int w = m_meta_graph_p->get_literal_object(index, top_weight).get_uint();
int b = m_meta_graph_p->get_literal_object(index, top_is_active).get_int();
rule.set_weight(w);
rule.set_active(b>0 ? true:false);
itor.next();
}
itor = m_meta_graph_p->find_index(rdf::all_subjects(), top_has_ex_category, rdf::all_objects());
while(not itor.is_end()) {
rdf::index_triple t3 = itor.get_triple();
rule_index_type rule_index = get_rule_index(t3.get_subject());
category_index_type category_index = get_category_index(t3.get_object());
if(rule_index and category_index) {
get_rule(rule_index).add_ex_category(category_index);
}
itor.next();
}
itor = m_meta_graph_p->find_index(rdf::all_subjects(), top_has_c1_node, rdf::all_objects());
while(not itor.is_end()) {
rdf::index_triple t3 = itor.get_triple();
rule_index_type rule_index = get_rule_index(t3.get_subject());
node_index_type node_index = get_node_index(t3.get_object());
if(rule_index and node_index) {
get_rule(rule_index).add_c1_node(node_index);
get_node(node_index).add_rule(rule_index);
}
itor.next();
}
itor = m_meta_graph_p->find_index(rdf::all_subjects(), top_has_c2_node, rdf::all_objects());
while(not itor.is_end()) {
rdf::index_triple t3 = itor.get_triple();
rule_index_type rule_index = get_rule_index(t3.get_subject());
node_index_type node_index = get_node_index(t3.get_object());
if(rule_index and node_index) {
get_rule(rule_index).add_c2_node(node_index);
}
itor.next();
}
itor = m_meta_graph_p->find_index(rdf::all_subjects(), top_has_negated_node, rdf::all_objects());
while(not itor.is_end()) {
rdf::index_triple t3 = itor.get_triple();
rule_index_type rule_index = get_rule_index(t3.get_subject());
node_index_type node_index = get_node_index(t3.get_object());
if(rule_index and node_index) {
get_rule(rule_index).add_negated_node(node_index);
}
itor.next();
}
// generate all patterns associated to the rules
generate_patterns(verbose);
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::get_next_name_index
//
/////////////////////////////////////////////////////////////////////////////////////////
index_type
PSearchDB::get_next_name_index(std::string const& name)
{
return m_meta_graph_p->create_string_literal_as_index(name);
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::copy_rule
//
/////////////////////////////////////////////////////////////////////////////////////////
rule_index_type
PSearchDB::copy_rule(rule_index_type rule_index)
{
if(!rule_index) {
std::cout << "*** Invalid rule_index for copy rule\n";
throw rdf::rdf_exception(rdf::invalid_index, "*** Invalid rule_index for copy rule");
}
std::string name = "copy of "+rule_index->get_name();
int n=1;
while(is_rule_index(name)) {
name = "copy " + boost::lexical_cast<std::string>(++n) + " of " + rule_index->get_name();
}
index_type index = m_meta_graph_p->create_bnode_as_index();
rule_index_type new_rule_index = add_rule(index, name, rule_index->get_weight(),
rule_index->m_ex_categories,
rule_index->m_c1_nodes,
rule_index->m_c2_nodes,
rule_index->m_negated_nodes);
set_rule_active(new_rule_index, rule_index->is_active());
return new_rule_index;
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::add_rule
//
/////////////////////////////////////////////////////////////////////////////////////////
rule_index_type
PSearchDB::add_rule(index_type index,
std::string const& name,
unsigned int weight,
category_set_type const& ex_categories,
node_set_type const& c1_nodes,
node_set_type const& c2_nodes,
node_set_type const& negated_nodes)
{
// validate pattern id
if(!index) {
std::cout << "*** Invalid index_type for rule creation, use a bnode instead of NULL\n";
throw rdf::rdf_exception(rdf::invalid_index, "*** Invalid index_type for rule creation, use a bnode instead of NULL");
}
// check if rule already exist, if so ignore
rule_index_type rule_index = get_rule_index(index);
if(rule_index) return rule_index;
rule_index = create_rule(index, name);
m_meta_graph_p->insert(index, rdf_type, top_Rule);
m_meta_graph_p->insert(index, top_is_active, top_true);
m_meta_graph_p->insert(index, top_name, get_next_name_index(name));
// weight
set_rule_weight(rule_index, weight);
// has existential category
for (category_const_iterator_type itor = ex_categories.begin(); itor != ex_categories.end(); ++itor) {
add_ex_category_to_rule(rule_index, *itor);
}
// has c1 nodes
for (node_const_iterator_type itor = c1_nodes.begin(); itor != c1_nodes.end(); ++itor) {
add_c1_node_to_rule(rule_index, *itor);
}
// has c2 nodes
for (node_const_iterator_type itor = c2_nodes.begin(); itor != c2_nodes.end(); ++itor) {
add_c2_node_to_rule(rule_index, *itor);
}
// negated nodes (has_not nodes)
for (node_const_iterator_type itor = negated_nodes.begin(); itor != negated_nodes.end(); ++itor) {
add_negated_node_to_rule(rule_index, *itor);
}
return rule_index;
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::generate_patterns
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::generate_patterns(bool verbose)
{
// clear all generated patterns
rule_map_const_iterator itor = get_rules_iterator();
while(!itor.is_end()) {
get_rule(itor.get_value()).clear_generated_patterns();
itor.next();
};
node_map_const_iterator ntor = get_nodes_iterator();
while(!ntor.is_end()) {
get_node(ntor.get_value()).remove_all_patterns();
ntor.next();
};
m_pattern_ptr_list.clear();
// generate the patterns
itor = get_rules_iterator();
while(!itor.is_end()) {
get_rule(itor.get_value()).generate_patterns(this, verbose);
itor.next();
}
// apply the value partition rule
category_map_const_iterator ctor = get_categories_iterator();
while(!ctor.is_end()) {
get_category(ctor.get_value()).apply_value_partition_rule();
ctor.next();
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::remove_node
//
// Must call generate_patterns before calling query or infer.
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::remove_node(node_index_type node_index)
{
index_type index = node_index->get_rdf_index();
get_node(node_index).remove_all_patterns();
// remove from the index map
m_node_index_map.erase(index);
// remove from the name map
m_node_name_map.erase(node_index->get_name());
// remove from meta graph
m_meta_graph_p->erase(index, top_name);
m_meta_graph_p->erase(index, top_skip_activation);
m_meta_graph_p->erase(index, rdf_type, top_Node);
// remove the shared ptr from the list
node_list_type::iterator jtor = m_node_ptr_list.begin();
node_list_type::iterator jend = m_node_ptr_list.end();
while(jtor != jend) {
if(&**jtor == node_index) {
m_node_ptr_list.erase(jtor);
break;
}
++jtor;
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::remove_category
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::remove_category(category_index_type category_index)
{
index_type index = category_index->get_rdf_index();
node_const_iterator_type itor = category_index->get_nodes_begin();
node_const_iterator_type end = category_index->get_nodes_end();
for(; itor!=end; ++itor) get_node(*itor).remove_category(category_index);
get_category(category_index).remove_all_nodes();
// remove from the index map
m_category_index_map.erase(index);
// remove from the name map
m_category_name_map.erase(category_index->get_name());
// remove from meta graph
m_meta_graph_p->erase(index, top_name);
m_meta_graph_p->erase(index, top_value_partition);
m_meta_graph_p->erase(index, top_has_node);
m_meta_graph_p->erase(index, rdf_type, top_Category);
// remove the shared ptr from the list
category_list_type::iterator jtor = m_category_ptr_list.begin();
category_list_type::iterator jend = m_category_ptr_list.end();
while(jtor != jend) {
if(&**jtor == category_index) {
m_category_ptr_list.erase(jtor);
break;
}
++jtor;
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::remove_rule
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::remove_rule(rule_index_type rule_index)
{
index_type index = rule_index->get_rdf_index();
get_rule(rule_index).remove_all_ex_categories();
get_rule(rule_index).remove_all_nodes();
// remove from the index map
m_rule_index_map.erase(index);
// remove from the name map
m_rule_name_map.erase(rule_index->get_name());
// remove from meta graph
m_meta_graph_p->erase(index, top_name);
m_meta_graph_p->erase(index, top_weight);
m_meta_graph_p->erase(index, top_has_c1_node);
m_meta_graph_p->erase(index, top_has_c2_node);
m_meta_graph_p->erase(index, top_has_negated_node);
m_meta_graph_p->erase(index, rdf_type, top_Rule);
// remove the shared ptr from the list
rule_list_type::iterator jtor = m_rule_ptr_list.begin();
rule_list_type::iterator jend = m_rule_ptr_list.end();
while(jtor != jend) {
if(&**jtor == rule_index) {
m_rule_ptr_list.erase(jtor);
break;
}
++jtor;
}
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::set_node_name
//
/////////////////////////////////////////////////////////////////////////////////////////
int
PSearchDB::set_node_name(node_index_type node_index, std::string const& name)
{
if(not node_index or name == "") return -1;
if(name == node_index->get_name()) return 0;
// check if name already in use
if(get_node_index(name)) return 1;
// remove old name
m_node_name_map.erase(node_index->get_name());
index_type index = node_index->get_rdf_index();
m_meta_graph_p->erase(index, top_name);
// set new name
get_node(node_index).set_name(name);
m_node_name_map.insert(std::make_pair(name, node_index));
m_meta_graph_p->insert(index, top_name, get_next_name_index(name));
return 0;
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::set_category_name
//
/////////////////////////////////////////////////////////////////////////////////////////
int
PSearchDB::set_category_name(category_index_type category_index, std::string const& name)
{
if(not category_index or name == "") return -1;
if(name == category_index->get_name()) return 0;
// check if name already in use
if(get_category_index(name)) return 1;
// remove old name
m_category_name_map.erase(category_index->get_name());
index_type index = category_index->get_rdf_index();
m_meta_graph_p->erase(index, top_name);
// set new name
get_category(category_index).set_name(name);
m_category_name_map.insert(std::make_pair(name, category_index));
m_meta_graph_p->insert(index, top_name, get_next_name_index(name));
return 0;
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::set_rule_name
//
/////////////////////////////////////////////////////////////////////////////////////////
int
PSearchDB::set_rule_name(rule_index_type rule_index, std::string const& name)
{
if(not rule_index or name == "") return -1;
if(name == rule_index->get_name()) return 0;
// check if name already in use
if(get_rule_index(name)) return 1;
// remove old name
m_rule_name_map.erase(rule_index->get_name());
index_type index = rule_index->get_rdf_index();
m_meta_graph_p->erase(index, top_name);
// set new name
get_rule(rule_index).set_name(name);
m_rule_name_map.insert(std::make_pair(name, rule_index));
m_meta_graph_p->insert(index, top_name, get_next_name_index(name));
pattern_set_const_iterator itor = rule_index->get_patterns_iterator();
while(not itor.is_end()) {
Pattern & pattern = get_pattern(itor.get_value());
pattern.set_name(name);
itor.next();
}
return 0;
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::printAllNode
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::printAllNodes()const
{
node_map_const_iterator itor = get_nodes_iterator();
while(!itor.is_end()) {
std::cout << itor.get_value() << std::endl;
itor.next();
};
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::printAllCategory
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::printAllCategories()const
{
category_map_const_iterator itor = get_categories_iterator();
while(!itor.is_end()) {
std::cout << itor.get_value() << std::endl;
itor.next();
};
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::printAllRules
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::printAllRules()const
{
rule_map_const_iterator itor = get_rules_iterator();
while(!itor.is_end()) {
std::cout << itor.get_value() << std::endl;
itor.next();
};
};
/////////////////////////////////////////////////////////////////////////////////////////
// PSearchDB::printAllPatterns
//
/////////////////////////////////////////////////////////////////////////////////////////
void
PSearchDB::printAllPatterns()const
{
pattern_list_iterator itor = get_patterns_begin();
pattern_list_iterator end = get_patterns_end();
for(; itor!=end; ++itor) {
std::cout << *itor << std::endl;
};
};
}; /* psearch namespace */