dlvhex  2.5.0
src/Registry.cpp
Go to the documentation of this file.
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: