void join(Relation &lhs, Relation &rhs, vector<size_t> &vars, Relation &result) { DEBUG("Joining", ""); DEBUG(" LHS size = ", lhs.size()); DEBUG(" RHS size = ", rhs.size()); Relation temp; Order order(vars); lhs.sort(order); rhs.sort(order); Relation::iterator lit = lhs.begin(); Relation::iterator rit = rhs.begin(); while (lit != lhs.end() && rit != rhs.end()) { Tuple joined; if (join(*lit, *rit, joined)) { Relation::iterator it; do { temp.push_back(joined); it = rit; for (++it; it != rhs.end() && join(*lit, *it, joined); ++it) { temp.push_back(joined); } ++lit; } while (lit != lhs.end() && join(*lit, *rit, joined)); rit = it; } else if (order(*rit, *lit)) { ++rit; } else { ++lit; } } result.swap(temp); DEBUG(" Result size = ", result.size()); }
void print_relations(const Relation& relations) { for (Relation::const_iterator rela_iter = relations.begin(); rela_iter != relations.end(); rela_iter++) { copy(rela_iter->begin(), rela_iter->end(), ostream_iterator<int>(cout, " ")); cout << endl; } }
//! recreate html page if something changes void MetadataItemPropertiesPanel::update() { Database* db = dynamic_cast<Database*>(objectM); if (db && !db->isConnected()) { objectM = 0; if (MetadataItemPropertiesFrame* f = getParentFrame()) f->Close(); // MB: This code used to use: //f->removePanel(this); // which would allow us to mix property pages from different // databases in the same Frame, but there are some mysterious // reasons why it causes heap corruption with MSVC return; } // if table or view columns change, we need to reattach if (objectM->getType() == ntTable || objectM->getType() == ntView) // also observe columns { Relation* r = dynamic_cast<Relation*>(objectM); if (!r) return; SubjectLocker locker(r); r->ensureChildrenLoaded(); for (ColumnPtrs::iterator it = r->begin(); it != r->end(); ++it) (*it)->attachObserver(this, false); } // if description of procedure params change, we need to reattach if (objectM->getType() == ntProcedure) { Procedure* p = dynamic_cast<Procedure*>(objectM); if (!p) return; SubjectLocker locker(p); p->ensureChildrenLoaded(); for (ParameterPtrs::iterator it = p->begin(); it != p->end(); ++it) (*it)->attachObserver(this, false); } // with this set to false updates to the same page do not show the // "Please wait while the data is being loaded..." temporary page // this results in less flicker, but may also seem less responsive if (!htmlReloadRequestedM) requestLoadPage(false); }
void act(Atom &atom, Relation &results) { DEBUG("Act: atom = ", atom); Index &index = atoms[atom.predicate]; Relation::iterator result = results.begin(); size_t max = atom.arguments.end - atom.arguments.begin; for (; result != results.end(); ++result) { Tuple tuple(max); size_t i; for (i = 0; i < max; ++i) { if (atom.arguments.begin[i].type == CONSTANT) { tuple[i] = atom.arguments.begin[i].get.constant; DEBUG("part ", tuple[i]); } else if (atom.arguments.begin[i].type == VARIABLE) { tuple[i] = result->at(atom.arguments.begin[i].get.variable); DEBUG("part ", tuple[i]); } else { cerr << "[ERROR] Lists and/or function in target atom are not currently supported." << endl; return; } } DEBUG("inserting (ignore this ->", max); index.insert(tuple); } }
bool special(Condition &condition, Relation &intermediate, Relation &filtered) { if (condition.type != ATOMIC) { return false; } switch (condition.get.atom.type) { case ATOM: case MEMBERSHIP: case SUBCLASS: case FRAME: return false; case EQUALITY: { Term *lhs = &(condition.get.atom.get.sides[0]); Term *rhs = &(condition.get.atom.get.sides[1]); if (lhs->type == VARIABLE && rhs->type == CONSTANT) { swap(lhs, rhs); } if (rhs->type == CONSTANT) { if (lhs->get.constant != rhs->get.constant) { Relation empty; filtered.swap(empty); } else { filtered = intermediate; } } else if (lhs->type == CONSTANT) { Relation result; Relation::iterator it = intermediate.begin(); for (; it != intermediate.end(); ++it) { if (it->size() <= rhs->get.variable) { it->resize(rhs->get.variable + 1); } if (it->at(rhs->get.variable) == 0) { result.push_back(*it); Tuple &t = result.back(); t[rhs->get.variable] = lhs->get.constant; } else if (it->at(rhs->get.variable) == lhs->get.constant) { result.push_back(*it); } } filtered.swap(result); } else { varint_t maxvar = max(lhs->get.variable, rhs->get.variable); Relation result; Relation::iterator it = intermediate.begin(); for (; it != intermediate.end(); ++it) { if (it->size() <= maxvar) { it->resize(maxvar + 1); } constint_t c1 = it->at(lhs->get.variable); constint_t c2 = it->at(rhs->get.variable); if (c1 == 0 && c2 == 0) { cerr << "[ERROR] Please make sure equality statements occur to the right of atomic formulas that bind a variable." << endl; return true; } if (c1 == 0) { result.push_back(*it); Tuple &t = result.back(); t[lhs->get.variable] = c2; } else if (c2 == 0) { result.push_back(*it); Tuple &t = result.back(); t[rhs->get.variable] = c1; } else if (c1 == c2) { result.push_back(*it); } } filtered.swap(result); } return true; } case EXTERNAL: { break; // just handle outside the messy switch statement } default: { cerr << "[ERROR] Unhandled case " << (int)condition.get.atom.type << " at line " << __LINE__ << endl; return false; } } ///// HANDLE BUILTIN (EXTERNAL) ///// Builtin &builtin = condition.get.atom.get.builtin; switch (builtin.predicate) { case BUILTIN_PRED_LIST_CONTAINS: { if (builtin.arguments.end - builtin.arguments.begin != 2) { cerr << "[ERROR] Invalid use of list contains builtin, which should have exactly two arguments, but instead found " << builtin << endl; return false; } Term *arg1 = builtin.arguments.begin; Term *arg2 = arg1 + 1; if (arg1->type != LIST) { cerr << "[ERROR] First argument of list contains builtin must be a list, but instead found " << *arg1 << endl; return false; } switch (arg2->type) { case FUNCTION: cerr << "[ERROR] Functions not supported." << endl; return false; case LIST: cerr << "[ERROR] Currently not supporting nested lists." << endl; return false; case CONSTANT: { Term *t = arg1->get.termlist.begin; for (; t != arg1->get.termlist.end; ++t) { if (t->type == CONSTANT && t->get.constant == arg2->get.constant) { filtered = intermediate; return true; } } Relation empty; filtered.swap(empty); return true; } case VARIABLE: break; // just handle outside messy switch statement default: cerr << "[ERROR] Unhandled case " << (int)builtin.predicate << " at line " << __LINE__ << endl; return false; } Relation results; Relation::iterator it = intermediate.begin(); for (; it != intermediate.end(); ++it) { if (it->size() <= arg2->get.variable) { it->resize(arg2->get.variable + 1); } constint_t c = it->at(arg2->get.variable); if (c == 0) { Term *t = arg1->get.termlist.begin; for (; t != arg1->get.termlist.end; ++t) { if (t->type == CONSTANT) { results.push_back(*it); results.back().at(arg2->get.variable) = t->get.constant; } } } else { Term *t = arg1->get.termlist.begin; for (; t != arg1->get.termlist.end; ++t) { if (t->type == CONSTANT && t->get.constant == c) { results.push_back(*it); break; } } } } filtered.swap(results); return true; } default: { cerr << "[ERROR] Builtin predicate " << (int)builtin.predicate << " is unsupported." << endl; return false; } } }
void act(ActionBlock &action_block, Relation &results, Index &assertions, Index &retractions) { if (action_block.action_variables.begin != action_block.action_variables.end) { cerr << "[ERROR] Action variables are unsupported." << endl; return; } Action *action = action_block.actions.begin; for (; action != action_block.actions.end; ++action) { switch (action->type) { case ASSERT_FACT: case RETRACT_FACT: { if (action->get.atom.type == ATOM) { if (action->type == RETRACT_FACT) { cerr << "[ERROR] Retraction of atoms is currently unsupported." << endl; return; } act(action->get.atom.get.atom, results); continue; } if (action->get.atom.type != FRAME) { cerr << "[ERROR] For now, supporting only assertion of frames/triples." << endl; return; } Frame frame = action->get.atom.get.frame; Tuple triple(3); if (frame.object.type == LIST || frame.object.type == FUNCTION) { cerr << "[ERROR] Not supporting lists or functions in action target." << endl; return; } if (frame.object.type == CONSTANT) { triple[0] = frame.object.get.constant; } pair<Term, Term> *slot = frame.slots.begin; for (; slot != frame.slots.end; ++slot) { if (slot->first.type == LIST || slot->first.type == FUNCTION || slot->second.type == LIST || slot->second.type == FUNCTION) { cerr << "[ERROR] Not supporting lists or function in action target." << endl; return; } if (slot->first.type == CONSTANT) { triple[1] = slot->first.get.constant; } if (slot->second.type == CONSTANT) { triple[2] = slot->second.get.constant; } if (!results.empty() && frame.object.type == CONSTANT && slot->first.type == CONSTANT && slot->second.type == CONSTANT) { if (action->type == ASSERT_FACT) { assertions.insert(triple); } else { retractions.insert(triple); } continue; } Relation::iterator tuple = results.begin(); for (; tuple != results.end(); ++tuple) { if (frame.object.type == VARIABLE) { triple[0] = tuple->at(frame.object.get.variable); } if (slot->first.type == VARIABLE) { triple[1] = tuple->at(slot->first.get.variable); } if (slot->second.type == VARIABLE) { triple[2] = tuple->at(slot->second.get.variable); } if (action->type == ASSERT_FACT) { assertions.insert(triple); } else { retractions.insert(triple); } } } return; } default: { cerr << "[ERROR] Currently supporting on ASSERT_FACT and RETRACT_FACT actions." << endl; return; } } } }
void query(Condition &condition, set<varint_t> &allvars, Relation &results) { deque<void*> negated; Relation intermediate; switch (condition.type) { case ATOMIC: { query(condition.get.atom, allvars, results); return; } case CONJUNCTION: { Condition *subformula = condition.get.subformulas.begin; for (; subformula != condition.get.subformulas.end; ++subformula) { if (subformula->type == NEGATION) { negated.push_back((void*)subformula->get.subformulas.begin); continue; } Relation subresult; set<varint_t> newvars; // TODO vvv this won't work right if a non-special query // has not been performed first if (special(*subformula, intermediate, subresult)) { if (subformula == condition.get.subformulas.begin) { cerr << "[ERROR] Must have non-special query at beginning of conjunction." << endl; } intermediate.swap(subresult); continue; } query(*subformula, newvars, subresult); if (subformula == condition.get.subformulas.begin) { intermediate.swap(subresult); } else { vector<size_t> joinvars(allvars.size() + newvars.size()); vector<size_t>::iterator jit = set_intersection(allvars.begin(), allvars.end(), newvars.begin(), newvars.end(), joinvars.begin()); joinvars.resize(jit - joinvars.begin()); join(intermediate, subresult, joinvars, intermediate); } allvars.insert(newvars.begin(), newvars.end()); } break; } case DISJUNCTION: { cerr << "[ERROR] Disjunction is not supported." << endl; return; } case EXISTENTIAL: { // assuming all quantified variables are uniquely named in the scope of the rule Condition *subformula = condition.get.subformulas.begin; for (; subformula != condition.get.subformulas.end; ++subformula) { if (subformula->type == NEGATION) { negated.push_back((void*)subformula->get.subformulas.begin); } Relation subresult; query(*subformula, allvars, subresult); intermediate.splice(intermediate.end(), subresult); } break; } case NEGATION: { cerr << "[ERROR] This should never happen. query should not be called directly on negated formulas." << endl; return; } default: { cerr << "[ERROR] Unhandled case " << (int)condition.type << " on line " << __LINE__ << endl; return; } } // TODO deal with negation later, if at all #if 1 deque<void*>::iterator it = negated.begin(); for (; !intermediate.empty() && it != negated.end(); ++it) { Relation negresult; Condition *cond = (Condition*) *it; if (special(*cond, intermediate, negresult)) { intermediate.sort(); negresult.sort(); Relation leftover(intermediate.size()); Relation::iterator iit = set_difference(intermediate.begin(), intermediate.end(), negresult.begin(), negresult.end(), leftover.begin()); Relation newinter; newinter.splice(newinter.end(), leftover, leftover.begin(), iit); intermediate.swap(newinter); continue; } query(*((Condition*)(*it)), allvars, negresult); minusrel(intermediate, negresult, intermediate); } #endif results.swap(intermediate); }