dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 00035 #include "dlvhex2/Registry.h" 00036 00037 // activate benchmarking if activated by configure option --enable-debug 00038 #ifdef HAVE_CONFIG_H 00039 # include "config.h" 00040 #endif 00041 00042 #include "dlvhex2/Benchmarking.h" 00043 #include "dlvhex2/Error.h" 00044 #include "dlvhex2/Printer.h" 00045 #include "dlvhex2/Printhelpers.h" 00046 #include "dlvhex2/Interpretation.h" 00047 00048 #include <boost/functional/hash.hpp> 00049 #include <boost/unordered_map.hpp> 00050 #include <boost/range/join.hpp> 00051 #include <boost/foreach.hpp> 00052 #include <boost/lexical_cast.hpp> 00053 #include <boost/bimap/bimap.hpp> 00054 00055 DLVHEX_NAMESPACE_BEGIN 00056 00085 namespace 00086 { 00087 00088 struct AuxiliaryKey 00089 { 00090 char type; 00091 ID id; 00092 00093 AuxiliaryKey(char type, ID id): 00094 type(type), id(id) {} 00095 inline bool operator==(const AuxiliaryKey& k2) const 00096 { return type == k2.type && id == k2.id; } 00097 00098 inline bool operator<(const AuxiliaryKey& k2) const 00099 { // order by type, or by id if types are equal 00100 return type == k2.type ? id < k2.id : type < k2.type; 00101 } 00102 }; 00103 00104 std::size_t hash_value(const AuxiliaryKey& key) { 00105 std::size_t seed = 0; 00106 boost::hash_combine(seed, key.type); 00107 boost::hash_combine(seed, key.id.kind); 00108 boost::hash_combine(seed, key.id.address); 00109 return seed; 00110 } 00111 00112 // we cannot use Term here because we want to store the 00113 // whole ID, not only the kind 00114 struct AuxiliaryValue 00115 { 00116 std::string symbol; 00117 ID id; 00118 AuxiliaryValue(const std::string& symbol, ID id): 00119 symbol(symbol), id(id) {} 00120 00121 inline bool operator<(const AuxiliaryValue& v2) const 00122 { // lookup by ID 00123 return id < v2.id; 00124 } 00125 }; 00126 00127 typedef boost::bimaps::bimap<AuxiliaryKey, AuxiliaryValue> 00128 AuxiliaryStorage; 00129 typedef AuxiliaryStorage::value_type AuxiliaryStorageTranslation; 00130 //typedef boost::unordered_map<AuxiliaryKey, AuxiliaryValue> 00131 // AuxiliaryStorage; 00132 00133 } // namespace { 00134 00135 00136 struct Registry::Impl 00137 { 00138 AuxiliaryStorage auxSymbols; 00139 PredicateMaskPtr auxGroundAtomMask; 00140 std::list<AuxPrinterPtr> auxPrinters; 00141 AuxPrinterPtr defaultAuxPrinter; 00142 00143 Impl(): 00144 auxGroundAtomMask(new PredicateMask) {} 00145 }; 00146 00147 Registry::Registry(): 00148 pimpl(new Impl) 00149 { 00150 // do not initialize pimpl->auxGroundAtomMask here! (we can do this only outside of the constructor) 00151 } 00152 00153 00154 // creates a real deep copy 00155 //explicit 00156 Registry::Registry(const Registry& other): 00157 terms(other.terms), 00158 preds(other.preds), 00159 ogatoms(other.ogatoms), 00160 onatoms(other.onatoms), 00161 batoms(other.batoms), 00162 aatoms(other.aatoms), 00163 eatoms(other.eatoms), 00164 matoms(other.matoms), 00165 rules(other.rules), 00166 moduleTable(other.moduleTable), 00167 inputList(other.inputList), 00168 pimpl(new Impl(*other.pimpl)) 00169 { 00170 // do not initialize pimpl->auxGroundAtomMask here! (we can do this only outside of the constructor) 00171 } 00172 00173 00174 // it is very important that this destructor is not in the .hpp file, 00175 // because only in the .cpp file it knows how to free pimpl 00176 Registry::~Registry() 00177 { 00178 } 00179 00180 00181 // implementation from RuleTable.hpp 00182 std::ostream& RuleTable::print(std::ostream& o, RegistryPtr reg) const throw() 00183 { 00184 const AddressIndex& aidx = container.get<impl::AddressTag>(); 00185 for(AddressIndex::const_iterator it = aidx.begin(); 00186 it != aidx.end(); ++it) { 00187 const uint32_t address = static_cast<uint32_t>(it - aidx.begin()); 00188 o << 00189 " " << ID(it->kind, address) << std::endl << 00190 " " << printToString<RawPrinter>(ID(it->kind, address), reg) << std::endl << 00191 " ->" << *it << std::endl; 00192 } 00193 return o; 00194 } 00195 00196 00197 // implementation from ExternalAtomTable.hpp 00198 std::ostream& ExternalAtomTable::print(std::ostream& o, RegistryPtr reg) const throw() 00199 { 00200 const AddressIndex& aidx = container.get<impl::AddressTag>(); 00201 for(AddressIndex::const_iterator it = aidx.begin(); 00202 it != aidx.end(); ++it) { 00203 const uint32_t address = static_cast<uint32_t>(it - aidx.begin()); 00204 o << 00205 " " << ID(it->kind, address) << std::endl << 00206 " " << printToString<RawPrinter>(ID(it->kind, address), reg) << std::endl << 00207 " ->" << *it << std::endl; 00208 } 00209 return o; 00210 } 00211 00212 00213 //const 00214 std::ostream& Registry::print(std::ostream& o) 00215 { 00216 o << 00217 "REGISTRY BEGIN" << std::endl << 00218 "terms:" << std::endl << 00219 terms << 00220 "preds:" << std::endl << 00221 preds << 00222 "ogatoms:" << std::endl << 00223 ogatoms << 00224 "onatoms:" << std::endl << 00225 onatoms << 00226 "batoms:" << std::endl << 00227 batoms << 00228 "aatoms:" << std::endl << 00229 aatoms << 00230 "eatoms:" << std::endl; 00231 eatoms.print(o, shared_from_this()); 00232 o << 00233 "matoms:" << std::endl << 00234 matoms << 00235 "rules:" << std::endl; 00236 rules.print(o, shared_from_this()); 00237 o << "moduleTable:" << std::endl << 00238 moduleTable << 00239 "inputList:" << std::endl; 00240 for (uint32_t i=0;i<inputList.size();i++) { 00241 o << printvector(inputList.at(i)) << std::endl; 00242 } 00243 00244 o << "REGISTRY END" << std::endl; 00245 00246 return o; 00247 00248 } 00249 00250 00251 // lookup ground or nonground ordinary atoms (ID specifies this) 00252 const OrdinaryAtom& Registry::lookupOrdinaryAtom(ID id) const 00253 { 00254 assert(id.isOrdinaryAtom()); 00255 if( id.isOrdinaryGroundAtom() ) 00256 return ogatoms.getByID(id); 00257 else 00258 return onatoms.getByID(id); 00259 } 00260 00261 00262 // get all external atom IDs in tuple and recursively in aggregates in tuple 00263 // append these ids to second given tuple 00264 void Registry::getExternalAtomsInTuple( 00265 const Tuple& t, Tuple& out) const 00266 { 00267 for(Tuple::const_iterator itt = t.begin(); itt != t.end(); ++itt) { 00268 if( itt->isExternalAtom() ) { 00269 out.push_back(*itt); 00270 } 00271 else if( itt->isAggregateAtom() ) { 00272 // check recursively within! 00273 const AggregateAtom& aatom = aatoms.getByID(*itt); 00274 getExternalAtomsInTuple(aatom.literals, out); 00275 } 00276 } 00277 } 00278 00279 00280 // get all IDs of variables in atom given by ID 00281 // add these ids to out 00282 // id is a literal or atom 00283 void Registry::getVariablesInID(ID id, std::set<ID>& out, bool includeAnonymous, bool includeLocalAggVar) const 00284 { 00285 if (id.isTerm()) { 00286 if (id.isVariableTerm() && (includeAnonymous || !id.isAnonymousVariable())) out.insert(id); 00287 if (id.isNestedTerm()) { 00288 const Term& t = terms.getByID(id); 00289 BOOST_FOREACH (ID nid, t.arguments) getVariablesInID(nid, out, includeAnonymous); 00290 } 00291 } 00292 else if (id.isLiteral() || id.isAtom()) { 00293 if( id.isOrdinaryGroundAtom() ) 00294 return; 00295 if( id.isOrdinaryNongroundAtom() ) { 00296 const OrdinaryAtom& atom = onatoms.getByID(id); 00297 BOOST_FOREACH(ID idt, atom.tuple) { 00298 getVariablesInID(idt, out, includeAnonymous); 00299 } 00300 } 00301 else if( id.isBuiltinAtom() ) { 00302 const BuiltinAtom& atom = batoms.getByID(id); 00303 BOOST_FOREACH(ID idt, atom.tuple) { 00304 getVariablesInID(idt, out, includeAnonymous); 00305 } 00306 } 00307 else if( id.isAggregateAtom() ) { 00308 const AggregateAtom& atom = aatoms.getByID(id); 00309 if (includeLocalAggVar){ 00310 // body atoms 00311 BOOST_FOREACH(ID idt, atom.literals) { 00312 getVariablesInID(idt, out, includeAnonymous); 00313 } 00314 // local variables 00315 BOOST_FOREACH(ID idv, atom.variables) { 00316 if (idv.isVariableTerm()) out.insert(idv); 00317 } 00318 } 00319 // left and right term 00320 assert(atom.tuple.size() == 5); 00321 if( atom.tuple[0].isTerm() ) 00322 getVariablesInID(atom.tuple[0], out, includeAnonymous); 00323 if( atom.tuple[4].isTerm() ) 00324 getVariablesInID(atom.tuple[4], out, includeAnonymous); 00325 } 00326 else if( id.isExternalAtom() ) { 00327 const ExternalAtom& atom = eatoms.getByID(id); 00328 BOOST_FOREACH(ID idt, boost::join(atom.tuple, atom.inputs)) { 00329 getVariablesInID(idt, out, includeAnonymous); 00330 } 00331 } 00332 } 00333 } 00334 00335 00336 void Registry::getOutVariablesInID(ID id, std::set<ID>& out, bool includeAnonymous, bool includeLocalAggVar) const 00337 { 00338 if (id.isTerm()) { 00339 if (id.isVariableTerm() && (includeAnonymous || !id.isAnonymousVariable())) out.insert(id); 00340 if (id.isNestedTerm()) { 00341 const Term& t = terms.getByID(id); 00342 BOOST_FOREACH (ID nid, t.arguments) getOutVariablesInID(nid, out); 00343 } 00344 } 00345 else if (id.isLiteral() || id.isAtom()) { 00346 if( id.isOrdinaryGroundAtom() ) 00347 return; 00348 if( id.isOrdinaryNongroundAtom() ) { 00349 const OrdinaryAtom& atom = onatoms.getByID(id); 00350 BOOST_FOREACH(ID idt, atom.tuple) { 00351 getOutVariablesInID(idt, out); 00352 } 00353 } 00354 else if( id.isBuiltinAtom() ) { 00355 const BuiltinAtom& atom = batoms.getByID(id); 00356 BOOST_FOREACH(ID idt, atom.tuple) { 00357 getOutVariablesInID(idt, out); 00358 } 00359 } 00360 else if( id.isAggregateAtom() ) { 00361 const AggregateAtom& atom = aatoms.getByID(id); 00362 if (includeLocalAggVar){ 00363 // body atoms 00364 BOOST_FOREACH(ID idt, atom.literals) { 00365 getOutVariablesInID(idt, out); 00366 } 00367 // local variables 00368 BOOST_FOREACH(ID idv, atom.variables) { 00369 out.insert(idv); 00370 } 00371 } 00372 // left and right term 00373 assert(atom.tuple.size() == 5); 00374 if( atom.tuple[0].isTerm() ) 00375 getOutVariablesInID(atom.tuple[0], out); 00376 if( atom.tuple[4].isTerm() ) 00377 getOutVariablesInID(atom.tuple[4], out); 00378 } 00379 else if( id.isExternalAtom() ) { 00380 const ExternalAtom& atom = eatoms.getByID(id); 00381 BOOST_FOREACH(ID idt, atom.tuple) { 00382 getOutVariablesInID(idt, out); 00383 } 00384 } 00385 } 00386 } 00387 00388 00389 std::set<ID> Registry::getVariablesInID(const ID& id, bool includeAnonymous, bool includeLocalAggVar) const 00390 { 00391 std::set<ID> out; 00392 getVariablesInID(id, out, includeAnonymous, includeLocalAggVar); 00393 return out; 00394 } 00395 00396 00397 // get all IDs of variables in atoms in given tuple 00398 // add these ids to out 00399 // tuple t contains IDs of literals or atoms 00400 void Registry::getVariablesInTuple(const Tuple& t, std::set<ID>& out, bool includeAnonymous, bool includeLocalAggVar) const 00401 { 00402 BOOST_FOREACH(ID id, t) { 00403 getVariablesInID(id, out, includeAnonymous, includeLocalAggVar); 00404 } 00405 } 00406 00407 00408 std::set<ID> Registry::getVariablesInTuple(const Tuple& t, bool includeAnonymous, bool includeLocalAggVar) const 00409 { 00410 std::set<ID> out; 00411 getVariablesInTuple(t, out, includeAnonymous); 00412 return out; 00413 } 00414 00415 00416 ID Registry::replaceVariablesInTerm(const ID term, const ID var, const ID by) 00417 { 00418 assert (term.isTerm()); 00419 00420 DBGLOG(DBG, "Replacing variable in term " << term << ": " << var << " --> " << by); 00421 if ((term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_VARIABLE) { 00422 return (term == var ? by : var); 00423 } 00424 else if ((term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_CONSTANT || (term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_PREDICATE || (term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_INTEGER || (term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_BUILTIN) { 00425 return term; 00426 } 00427 else if ((term.kind & ID::SUBKIND_MASK) == ID::SUBKIND_TERM_NESTED) { 00428 Term t = terms.getByID(term); 00429 00430 for (uint32_t i = 1; i < t.arguments.size(); ++i) { 00431 t.arguments[i] = replaceVariablesInTerm(t.arguments[i], var, by); 00432 } 00433 00434 t.updateSymbolOfNestedTerm(this); 00435 ID tid = terms.getIDByString(t.symbol); 00436 if (tid == ID_FAIL) tid = terms.storeAndGetID(t); 00437 return tid; 00438 } 00439 assert (false); 00440 return ID_FAIL; 00441 } 00442 00443 00444 // get the predicate of an ordinary or external atom 00445 ID Registry::getPredicateOfAtom(ID atom) 00446 { 00447 if (atom.isOrdinaryAtom()) { 00448 return lookupOrdinaryAtom(atom).tuple[0]; 00449 } 00450 else if (atom.isExternalAtom()) { 00451 return eatoms.getByID(atom).predicate; 00452 } 00453 else { 00454 assert(false); 00455 return ID_FAIL; 00456 } 00457 } 00458 00459 00460 namespace 00461 { 00462 // assume, that oatom.id and oatom.tuple is initialized! 00463 // assume, that oatom.text is not initialized! 00464 // oatom.text will be modified 00465 ID storeOrdinaryAtomHelper( 00466 Registry* reg, 00467 OrdinaryAtom& oatom, 00468 OrdinaryAtomTable& oat) { 00469 ID ret = oat.getIDByTuple(oatom.tuple); 00470 if( ret == ID_FAIL ) { 00471 // text 00472 std::stringstream s; 00473 RawPrinter printer(s, reg); 00474 // predicate 00475 printer.print(oatom.tuple.front()); 00476 if( oatom.tuple.size() > 1 ) { 00477 Tuple t(oatom.tuple.begin()+1, oatom.tuple.end()); 00478 s << "("; 00479 printer.printmany(t,","); 00480 s << ")"; 00481 } 00482 oatom.text = s.str(); 00483 00484 ret = oat.storeAndGetID(oatom); 00485 DBGLOG(DBG,"stored oatom " << oatom << " which got " << ret); 00486 } 00487 return ret; 00488 } 00489 } 00490 00491 00492 ID Registry::storeOrdinaryAtom(OrdinaryAtom& oatom) 00493 { 00494 return ((oatom.kind & ID::SUBKIND_MASK) == ID::SUBKIND_ATOM_ORDINARYG) ? storeOrdinaryAtomHelper(this, oatom, ogatoms) : storeOrdinaryAtomHelper(this, oatom, onatoms); 00495 } 00496 00497 00498 // ground version 00499 ID Registry::storeOrdinaryGAtom(OrdinaryAtom& ogatom) 00500 { 00501 //for (int i = 0; i < ogatom.tuple.size(); ++i) std::cerr << "Storing " << i << "/" << ogatom.tuple[i] << ":" << printToString<RawPrinter>(ogatom.tuple[i], RegistryPtr(this,Deleter)) << std::endl; 00502 return storeOrdinaryAtomHelper(this, ogatom, ogatoms); 00503 } 00504 00505 00506 // nonground version 00507 ID Registry::storeOrdinaryNAtom(OrdinaryAtom& onatom) 00508 { 00509 //for (int i = 0; i < onatom.tuple.size(); ++i) std::cerr << "Storing " << i << "/" << onatom.tuple[i] << ":" << printToString<RawPrinter>(onatom.tuple[i], RegistryPtr(this,Deleter)) << std::endl; 00510 return storeOrdinaryAtomHelper(this, onatom, onatoms); 00511 } 00512 00513 00514 ID Registry::storeConstOrVarTerm(Term& term) 00515 { 00516 // ensure the symbol does not start with a number 00517 assert(!term.symbol.empty() && !isdigit(term.symbol[0])); 00518 ID ret = terms.getIDByString(term.symbol); 00519 // check if might registered as a predicate 00520 if( ret == ID_FAIL ) { 00521 ret = preds.getIDByString(term.symbol); 00522 if( ret == ID_FAIL ) { 00523 ret = terms.storeAndGetID(term); 00524 DBGLOG(DBG,"stored term " << term << " which got " << ret); 00525 } 00526 } 00527 return ret; 00528 } 00529 00530 00531 ID Registry::storeConstantTerm(const std::string& symbol, bool aux) 00532 { 00533 assert(!symbol.empty() && (::islower(symbol[0]) || symbol[0] == '"')); 00534 00535 ID ret = terms.getIDByString(symbol); 00536 if( ret == ID_FAIL ) { 00537 ret = preds.getIDByString(symbol); 00538 if( ret == ID_FAIL ) { 00539 Term term(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, symbol); 00540 if( aux ) 00541 term.kind |= ID::PROPERTY_AUX; 00542 ret = terms.storeAndGetID(term); 00543 DBGLOG(DBG,"stored term " << term << " which got " << ret); 00544 } 00545 } 00546 return ret; 00547 } 00548 00549 00550 ID Registry::storeVariableTerm(const std::string& symbol, bool aux) 00551 { 00552 assert(!symbol.empty() && ::isupper(symbol[0])); 00553 00554 ID ret = terms.getIDByString(symbol); 00555 if( ret == ID_FAIL ) { 00556 Term term(ID::MAINKIND_TERM | ID::SUBKIND_TERM_VARIABLE, symbol); 00557 if( aux ) 00558 term.kind |= ID::PROPERTY_AUX; 00559 ret = terms.storeAndGetID(term); 00560 DBGLOG(DBG,"stored term " << term << " which got " << ret); 00561 } 00562 return ret; 00563 } 00564 00565 00566 ID Registry::storeTerm(Term& term) 00567 { 00568 assert(!term.symbol.empty()); 00569 if( isdigit(term.symbol[0]) ) { 00570 try 00571 { 00572 return ID::termFromInteger(boost::lexical_cast<uint32_t>(term.symbol)); 00573 } 00574 catch( const boost::bad_lexical_cast&) { 00575 throw FatalError("bad term to convert to integer: '" + term.symbol + "'"); 00576 } 00577 } 00578 00579 // add subkind flags 00580 if( term.symbol[0] == '"' || islower(term.symbol[0]) ) { 00581 term.kind |= ID::SUBKIND_TERM_CONSTANT; 00582 } 00583 else if( term.symbol[0] == '_' || isupper(term.symbol[0]) ) { 00584 term.kind |= ID::SUBKIND_TERM_VARIABLE; 00585 } 00586 else { 00587 throw FatalError("could not identify term type for symbol '" + term.symbol +"'"); 00588 } 00589 00590 return storeConstOrVarTerm(term); 00591 } 00592 00593 00594 ID Registry::getNewConstantTerm(std::string prefix) 00595 { 00596 static long nr = 0; 00597 std::stringstream ss; 00598 do { 00599 ss.str(""); 00600 ss << prefix << nr; 00601 nr++; 00602 }while(terms.getIDByString(ss.str()) != ID_FAIL); 00603 DBGLOG(DBG, "Creating new term with name '" << ss.str() << "'"); 00604 Term term(ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT, ss.str()); 00605 return storeTerm(term); 00606 } 00607 00608 00609 // check if rule is contained in registry 00610 // if yes return integer id 00611 // otherwise store and return new id 00612 // assume rule is fully initialized 00613 ID Registry::storeRule(Rule& rule) 00614 { 00615 assert(ID(rule.kind,0).isRule()); 00616 assert(!rule.head.empty() || !rule.body.empty()); 00617 00618 ID ret = rules.getIDByElement(rule); 00619 if( ret == ID_FAIL ) 00620 return rules.storeAndGetID(rule); 00621 else 00622 return ret; 00623 } 00624 00625 00626 void Registry::setupAuxiliaryGroundAtomMask() 00627 { 00628 if( !pimpl->auxGroundAtomMask->mask() ) 00629 pimpl->auxGroundAtomMask->setRegistry(shared_from_this()); 00630 } 00631 00632 00633 ID Registry::getAuxiliaryConstantSymbol(char type, ID id) 00634 { 00635 DBGLOG_SCOPE(DBG,"gACS",false); 00636 DBGLOG(DBG,"getAuxiliaryConstantSymbol for " << type << " " << id); 00637 assert(!!pimpl->auxGroundAtomMask->mask() && 00638 "setupAuxiliaryGroundAtomMask has not been called before calling getAuxiliaryConstantSymbol!"); 00639 00640 // lookup auxiliary 00641 AuxiliaryKey key(type,id); 00642 AuxiliaryStorage::left_const_iterator it = 00643 pimpl->auxSymbols.left.find(key); 00644 if( it != pimpl->auxSymbols.left.end() ) { 00645 DBGLOG(DBG,"found " << it->second.id); 00646 return it->second.id; 00647 } 00648 00649 // not found 00650 00651 // create symbol 00652 std::ostringstream s; 00653 s << "aux_" << type << "_" << std::hex << id.kind << "_" << id.address; 00654 AuxiliaryValue av(s.str(), ID_FAIL); 00655 DBGLOG(DBG,"created symbol '" << av.symbol << "'"); 00656 Term term( 00657 ID::MAINKIND_TERM | ID::SUBKIND_TERM_CONSTANT | ID::PROPERTY_AUX, 00658 av.symbol); 00659 00660 // remember which auxiliaries represent in fact external atoms (used by genuine solvers) 00661 if (type == 'r' || type == 'n') term.kind |= ID(ID::PROPERTY_EXTERNALAUX, 0); 00662 if (type == 'i') term.kind |= ID(ID::PROPERTY_EXTERNALINPUTAUX, 0); 00663 00664 // register ID for symbol 00665 av.id = terms.getIDByString(term.symbol); 00666 if( av.id != ID_FAIL) 00667 throw FatalError("auxiliary collision with symbol '" + 00668 term.symbol + "' (or programming error)!"); 00669 av.id = terms.storeAndGetID(term); 00670 00671 // register auxiliary 00672 pimpl->auxSymbols.insert(AuxiliaryStorageTranslation(key, av)); 00673 00674 // update predicate mask 00675 pimpl->auxGroundAtomMask->addPredicate(av.id); 00676 00677 // return 00678 DBGLOG(DBG,"returning id " << av.id << " for aux symbol " << av.symbol); 00679 return av.id; 00680 } 00681 00682 00683 ID Registry::getAuxiliaryVariableSymbol(char type, ID id) 00684 { 00685 DBGLOG_SCOPE(DBG,"gAVS",false); 00686 DBGLOG(DBG,"getAuxiliaryVariableSymbol for " << type << " " << id); 00687 00688 // lookup auxiliary 00689 AuxiliaryKey key(type,id); 00690 AuxiliaryStorage::left_const_iterator it = 00691 pimpl->auxSymbols.left.find(key); 00692 if( it != pimpl->auxSymbols.left.end() ) { 00693 DBGLOG(DBG,"found " << it->second.id); 00694 return it->second.id; 00695 } 00696 00697 // not found 00698 00699 // create symbol 00700 std::ostringstream s; 00701 s << "Auxvar_" << type << "_" << std::hex << id.kind << "_" << id.address; 00702 AuxiliaryValue av(s.str(), ID_FAIL); 00703 DBGLOG(DBG,"created symbol '" << av.symbol << "'"); 00704 Term term( 00705 ID::MAINKIND_TERM | ID::SUBKIND_TERM_VARIABLE | ID::PROPERTY_AUX, 00706 av.symbol); 00707 00708 // register ID for symbol 00709 av.id = terms.getIDByString(term.symbol); 00710 if( av.id != ID_FAIL) 00711 throw FatalError("auxiliary collision with symbol '" + 00712 term.symbol + "' (or programming error)!"); 00713 av.id = terms.storeAndGetID(term); 00714 00715 // register auxiliary 00716 pimpl->auxSymbols.insert(AuxiliaryStorageTranslation(key, av)); 00717 00718 // return 00719 DBGLOG(DBG,"returning id " << av.id << " for aux var symbol " << av.symbol); 00720 return av.id; 00721 } 00722 00723 00724 namespace 00725 { 00726 void EmptyDeleter(Registry* ptr) 00727 {} 00728 } 00729 00730 00731 ID Registry::getAuxiliaryAtom(char type, ID id) 00732 { 00733 OrdinaryAtom oatom = lookupOrdinaryAtom(id); 00734 oatom.tuple[0] = getAuxiliaryConstantSymbol(type, oatom.tuple[0]); 00735 // the only property of new atom is AUX 00736 oatom.kind &= (ID::ALL_ONES ^ ID::PROPERTY_MASK); 00737 oatom.kind |= ID::PROPERTY_AUX; 00738 ID newAtomID = storeOrdinaryAtom(oatom); 00739 DBGLOG(DBG, "Created auxiliary atom " << printToString<RawPrinter>(newAtomID, RegistryPtr(this,EmptyDeleter)) << " for atom " << printToString<RawPrinter>(id, RegistryPtr(this,EmptyDeleter))); 00740 return newAtomID; 00741 } 00742 00743 00744 // maps an auxiliary constant symbol back to the ID behind 00745 ID Registry::getIDByAuxiliaryConstantSymbol(ID auxConstantID) const 00746 { 00747 assert(auxConstantID.isConstantTerm()); 00748 00749 // lookup ID of auxiliary 00750 DBGLOG(DBG,"getIDByAuxiliaryConstantSymbol for " << auxConstantID); 00751 AuxiliaryStorage::right_const_iterator it = 00752 pimpl->auxSymbols.right.find(AuxiliaryValue("", auxConstantID)); 00753 if( it != pimpl->auxSymbols.right.end() ) { 00754 DBGLOG(DBG,"found " << it->first.id); 00755 return it->second.id; 00756 } 00757 else { 00758 return ID_FAIL; 00759 } 00760 } 00761 00762 00763 // maps an auxiliary constant symbol back to the ID behind 00764 ID Registry::getIDByAuxiliaryVariableSymbol(ID auxVariableID) const 00765 { 00766 assert(auxVariableID.isVariableTerm()); 00767 00768 // lookup ID of auxiliary 00769 DBGLOG(DBG,"getIDByAuxiliaryVariableSymbol for " << auxVariableID); 00770 AuxiliaryStorage::right_const_iterator it = 00771 pimpl->auxSymbols.right.find(AuxiliaryValue("", auxVariableID)); 00772 if( it != pimpl->auxSymbols.right.end() ) { 00773 DBGLOG(DBG,"found " << it->first.id); 00774 return it->second.id; 00775 } 00776 else { 00777 return ID_FAIL; 00778 } 00779 } 00780 00781 00782 bool Registry::isPositiveExternalAtomAuxiliaryAtom(ID auxID) 00783 { 00784 assert(auxID.isExternalAuxiliary() && !auxID.isExternalInputAuxiliary() && "auxID must be an external atom auxiliary ID"); 00785 00786 const OrdinaryAtom& oatom = lookupOrdinaryAtom(auxID); 00787 ID pos = getAuxiliaryConstantSymbol('r', getIDByAuxiliaryConstantSymbol(oatom.tuple[0])); 00788 return (oatom.tuple[0] == pos); 00789 } 00790 00791 00792 bool Registry::isNegativeExternalAtomAuxiliaryAtom(ID auxID) 00793 { 00794 assert(auxID.isExternalAuxiliary() && !auxID.isExternalInputAuxiliary() && "auxID must be an external atom auxiliary ID"); 00795 00796 const OrdinaryAtom& oatom = lookupOrdinaryAtom(auxID); 00797 ID neg = getAuxiliaryConstantSymbol('n', getIDByAuxiliaryConstantSymbol(oatom.tuple[0])); 00798 return (oatom.tuple[0] == neg); 00799 } 00800 00801 00802 ID Registry::swapExternalAtomAuxiliaryAtom(ID auxID) 00803 { 00804 assert(auxID.isExternalAuxiliary() && !auxID.isExternalInputAuxiliary() && "auxID must be an external atom auxiliary ID"); 00805 00806 OrdinaryAtom oatom = lookupOrdinaryAtom(auxID); 00807 ID pos = getAuxiliaryConstantSymbol('r', getIDByAuxiliaryConstantSymbol(oatom.tuple[0])); 00808 ID neg = getAuxiliaryConstantSymbol('n', getIDByAuxiliaryConstantSymbol(oatom.tuple[0])); 00809 00810 oatom.tuple[0] = (oatom.tuple[0] == pos ? neg : pos); 00811 ID newID = storeOrdinaryAtom(oatom); 00812 newID.kind = auxID.kind; 00813 00814 return newID; 00815 } 00816 00817 00818 // maps an auxiliary constant symbol back to the type behind 00819 char Registry::getTypeByAuxiliaryConstantSymbol(ID auxConstantID) const 00820 { 00821 00822 // lookup ID of auxiliary 00823 DBGLOG(DBG,"getTypeByAuxiliaryConstantSymbol for " << auxConstantID); 00824 AuxiliaryStorage::right_const_iterator it = 00825 pimpl->auxSymbols.right.find(AuxiliaryValue("", auxConstantID)); 00826 if( it != pimpl->auxSymbols.right.end() ) { 00827 DBGLOG(DBG,"found " << it->first.id); 00828 return it->second.type; 00829 } 00830 else { 00831 return ' ' /* fail */; 00832 } 00833 } 00834 00835 00836 // get predicate mask to auxiliary ground atoms 00837 InterpretationConstPtr Registry::getAuxiliaryGroundAtomMask() 00838 { 00839 assert(!!pimpl->auxGroundAtomMask->mask() && 00840 "setupAuxiliaryGroundAtomMask has not been called before calling getAuxiliaryConstantSymbol!"); 00841 pimpl->auxGroundAtomMask->updateMask(); 00842 return pimpl->auxGroundAtomMask->mask(); 00843 } 00844 00845 00846 // 00847 // printing framework 00848 // 00849 00850 // these printers are used as long as none prints it 00851 void Registry::registerUserAuxPrinter(AuxPrinterPtr printer) 00852 { 00853 DBGLOG(DBG,"added auxiliary printer"); 00854 pimpl->auxPrinters.push_back(printer); 00855 } 00856 00857 00858 // this one printer is used last 00859 void Registry::registerUserDefaultAuxPrinter(AuxPrinterPtr printer) 00860 { 00861 DBGLOG(DBG,"configured default auxiliary printer"); 00862 pimpl->defaultAuxPrinter = printer; 00863 } 00864 00865 00866 // true if anything was printed 00867 // false if nothing was printed 00868 bool Registry::printAtomForUser(std::ostream& o, IDAddress address, const std::string& prefix) 00869 { 00870 DBGLOG(DBG,"printing for user id " << address); 00871 if( !getAuxiliaryGroundAtomMask()->getFact(address) ) { 00872 // fast direct output 00873 if (ogatoms.getIDByAddress(address).isHiddenAtom()) return false; 00874 o << prefix << ogatoms.getByAddress(address).text; 00875 return true; 00876 } 00877 else { 00878 DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sid,"Registry aux printing"); 00879 00880 ID id(ID::MAINKIND_ATOM | ID::SUBKIND_ATOM_ORDINARYG | ID::PROPERTY_AUX, address); 00881 DBGLOG(DBG,"printing auxiliary " << address << " (reconstructed id " << id << ")"); 00882 typedef std::list<AuxPrinterPtr> AuxPrinterList; 00883 for(AuxPrinterList::const_iterator it = pimpl->auxPrinters.begin(); 00884 it != pimpl->auxPrinters.end(); ++it) { 00885 DBGLOG(DBG,"trying registered aux printer"); 00886 if( (*it)->print(o, id, prefix) ) 00887 return true; 00888 } 00889 if( !!pimpl->defaultAuxPrinter ) { 00890 DBGLOG(DBG,"trying default aux printer"); 00891 return pimpl->defaultAuxPrinter->print(o, id, prefix); 00892 } 00893 return false; 00894 } 00895 } 00896 00897 00898 DLVHEX_NAMESPACE_END 00899 00900 // vim:expandtab:ts=4:sw=4: 00901 // mode: C++ 00902 // End: