dlvhex  2.5.0
src/Nogood.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 
00034 #include "dlvhex2/Nogood.h"
00035 
00036 #include <iostream>
00037 #include <sstream>
00038 #include <algorithm>
00039 #include "dlvhex2/Logger.h"
00040 #include "dlvhex2/Printer.h"
00041 #include <boost/functional/hash.hpp>
00042 
00043 DLVHEX_NAMESPACE_BEGIN
00044 
00045 // ---------- Class Nogood ----------
00046 
00047 //#define DBGLOGD(X,Y) DBGLOG(X,Y)
00048 #define DBGLOGD(X,Y) do{}while(false);
00049 
00050 namespace
00051 {
00052     struct VariableSorter
00053     {
00054         typedef std::pair<ID, std::vector<int> > VarType;
00055         bool operator() (VarType p1, VarType p2) {
00056             for (uint32_t i = 0; i < p1.second.size(); i++) {
00057                 if (p1.second[i] < p2.second[i]) return true;
00058                 if (p1.second[i] > p2.second[i]) return false;
00059             }
00060             if (p2.second.size() > p1.second.size()) return true;
00061 
00062             // they are considered equal
00063             return false;
00064         }
00065     };
00066 }
00067 
00068 
00069 Nogood::Nogood() : ground(true)
00070 {
00071 }
00072 
00073 Nogood::Nogood(InterpretationConstPtr assigned, InterpretationConstPtr interpretation)
00074     : ground(true)
00075 {
00076     bm::bvector<>::enumerator en = assigned->getStorage().first();
00077     bm::bvector<>::enumerator en_end = assigned->getStorage().end();
00078     while (en < en_end) {
00079         insert(NogoodContainer::createLiteral(*en, interpretation->getFact(*en)));
00080         en++;
00081     }
00082 }
00083 
00084 void Nogood::recomputeHash()
00085 {
00086     hashValue = 0;
00087     BOOST_FOREACH (ID lit, *this) {
00088         boost::hash_combine(hashValue, lit.kind);
00089         boost::hash_combine(hashValue, lit.address);
00090     }
00091 }
00092 
00093 
00094 size_t Nogood::getHash()
00095 {
00096     return hashValue;
00097 }
00098 
00099 
00100 const Nogood& Nogood::operator=(const Nogood& other)
00101 {
00102     this->Set<ID>::operator=(other);
00103     hashValue = other.hashValue;
00104     ground = other.ground;
00105     return *this;
00106 }
00107 
00108 
00109 bool Nogood::operator==(const Nogood& ng2) const
00110 {
00111 
00112     // compare hash value
00113     if (hashValue != ng2.hashValue) return false;
00114 
00115     // compare content
00116     if (size() != ng2.size()) return false;
00117 
00118     const_set_iterator<ID> it1 = ((const Nogood*)this)->begin();
00119     const_set_iterator<ID> it2 = ng2.begin();
00120     while(it1 != end()) {
00121         if (*it1 != *it2) return false;
00122         ++it1;
00123         ++it2;
00124     }
00125 
00126     return true;
00127 }
00128 
00129 
00130 bool Nogood::operator!=(const Nogood& ng2) const
00131 {
00132     return !(this->operator==(ng2));
00133 }
00134 
00135 
00136 std::ostream& Nogood::print(std::ostream& o) const
00137 {
00138     o << "{ ";
00139     bool first = true;
00140     BOOST_FOREACH (ID lit, *this) {
00141         if (!first) {
00142             o << ", ";
00143         }
00144         first = false;
00145         o << (lit.isNaf() ? std::string("-") : std::string("")) << lit.address;
00146     }
00147     o << " }";
00148     return o;
00149 }
00150 
00151 
00152 std::string Nogood::getStringRepresentation(RegistryPtr reg) const
00153 {
00154 
00155     std::stringstream ss;
00156     RawPrinter printer(ss, reg);
00157     ss << "{ ";
00158     bool first = true;
00159     BOOST_FOREACH (ID lit, *this) {
00160         if (!first) {
00161             ss << ", ";
00162         }
00163         first = false;
00164         ss << (lit.isNaf() ? "-" : "");
00165         if (lit.isOrdinaryGroundAtom()) {
00166             printer.print(reg->ogatoms.getIDByAddress(lit.address));
00167         }
00168         else {
00169             printer.print(reg->onatoms.getIDByAddress(lit.address));
00170         }
00171     }
00172     ss << " }";
00173     return ss.str();
00174 }
00175 
00176 
00177 Nogood Nogood::resolve(const Nogood& ng2, IDAddress groundlitadr)
00178 {
00179     // resolvent = union of this and ng2 minus both polarities of the resolved literal
00180     Nogood resolvent = *this;
00181     resolvent.insert(ng2.begin(), ng2.end());
00182     resolvent.erase(NogoodContainer::createLiteral(groundlitadr, true));
00183     resolvent.erase(NogoodContainer::createLiteral(groundlitadr, false));
00184     DBGLOG(DBG, "Resolution " << *this << " with " << ng2 << ": " << resolvent);
00185     assert(resolvent.size() < this->size() + ng2.size() && "resolvent is not smaller than the union of the two nogoods; ensure that the resolved literal is chosen correctly");
00186     return resolvent;
00187 }
00188 
00189 
00190 Nogood Nogood::resolve(const Nogood& ng2, ID lit)
00191 {
00192     // resolvent = union of this and ng2 minus both polarities of the resolved literal
00193     Nogood resolvent = *this;
00194     resolvent.insert(ng2.begin(), ng2.end());
00195     resolvent.erase(NogoodContainer::createLiteral(lit.address, true, lit.isOrdinaryGroundAtom()));
00196     resolvent.erase(NogoodContainer::createLiteral(lit.address, false, lit.isOrdinaryGroundAtom()));
00197     DBGLOG(DBG, "Resolution " << *this << " with " << ng2 << ": " << resolvent);
00198     assert(resolvent.size() < this->size() + ng2.size() && "resolvent is not smaller than the union of the two nogoods; ensure that the resolved literal is chosen correctly");
00199     return resolvent;
00200 }
00201 
00202 
00203 void Nogood::applyVariableSubstitution(RegistryPtr reg, const std::map<ID, ID>& subst)
00204 {
00205 
00206     DBGLOG(DBG, "Applying variable substitution to " << getStringRepresentation(reg));
00207     Nogood newng;
00208     BOOST_FOREACH (ID lit, *this) {
00209         OrdinaryAtom oatom = reg->lookupOrdinaryAtom(lit);
00210         bool changed = false;
00211         for (uint32_t t = 1; t < oatom.tuple.size(); t++) {
00212             if (subst.count(oatom.tuple[t]) > 0) {
00213                 oatom.tuple[t] = subst.at(oatom.tuple[t]);
00214                 changed = true;
00215             }
00216         }
00217         ID newlit = lit;
00218         if (changed) newlit.address = reg->storeOrdinaryAtom(oatom).address;
00219         newng.insert(NogoodContainer::createLiteral(newlit));
00220     }
00221     DBGLOG(DBG, "New nogood is " << newng.getStringRepresentation(reg));
00222     *this = newng;
00223 }
00224 
00225 
00226 void Nogood::heuristicNormalization(RegistryPtr reg)
00227 {
00228 
00229     // This method renames the variables in a nonground nogood
00230     // such that multiple nogoods which differ only in the variable naming
00231     // are likely to become equivalent.
00232     // This is useful for reducing redundancy in resolution.
00233 
00234     // For this we sort the variables such that for variables X, Y
00235     // we have X < Y
00236     // iff Y occurs more often than X
00237     //     or Y occurs as often as X but more often at first argument position
00238     //     or Y occurs as often as X also at first argument position but more often at the second,
00239     //     etc.
00240     // and X = Y otherwise.
00241 
00242     if (isGround()) return;
00243     DBGLOG(DBG, "Normalizing " << getStringRepresentation(reg));
00244 
00245     // prepare statistics
00246     std::map<ID, std::vector<int> > vars;
00247     BOOST_FOREACH (ID id, *this) {
00248         const OrdinaryAtom& oatom = reg->lookupOrdinaryAtom(id);
00249         for (uint32_t i = 1; i < oatom.tuple.size(); ++i) {
00250             if (oatom.tuple[i].isVariableTerm()) {
00251                 std::vector<int>& pos = vars[oatom.tuple[i]];
00252                 while (pos.size() < i + 1) pos.push_back(0);
00253                 pos[0]++;
00254                 pos[i]++;
00255             }
00256         }
00257     }
00258     std::vector<VariableSorter::VarType> sortedVars;
00259     BOOST_FOREACH (VariableSorter::VarType v, vars) {
00260         sortedVars.push_back(v);
00261     }
00262 
00263     // sort
00264     VariableSorter sorter;
00265     std::sort(sortedVars.begin(), sortedVars.end(), sorter);
00266 
00267     // assign new variable names
00268     std::map<ID, ID> renaming;
00269     int i = 0;
00270     BOOST_FOREACH (VariableSorter::VarType v, sortedVars) {
00271         std::stringstream ss;
00272         ss << "X" << i++;
00273         renaming[v.first] = reg->storeVariableTerm(ss.str());
00274     }
00275     applyVariableSubstitution(reg, renaming);
00276     DBGLOG(DBG, "Normalized " << getStringRepresentation(reg));
00277 }
00278 
00279 
00280 void Nogood::insert(ID lit)
00281 {
00282     // strip off property flags
00283     lit = NogoodContainer::createLiteral(lit);
00284 
00285     // actual insertion
00286     Set<ID>::insert(lit);
00287     ground &= lit.isOrdinaryGroundAtom();
00288 }
00289 
00290 
00291 bool Nogood::isGround() const
00292 {
00293     return ground;
00294 }
00295 
00296 
00297 bool Nogood::match(RegistryPtr reg, ID atomID, Nogood& instance) const
00298 {
00299 
00300     DBGLOG(DBG, "Matching " << *this << " with " << atomID);
00301 
00302     const OrdinaryAtom& atom = reg->ogatoms.getByID(atomID);
00303 
00304     // find an element in the nogood with unifies with atom
00305     BOOST_FOREACH (ID natID, *this) {
00306         const OrdinaryAtom& nat = natID.isOrdinaryGroundAtom() ? reg->ogatoms.getByID(natID) : reg->onatoms.getByID(natID);
00307 
00308         if (atom.unifiesWith(nat, reg)) {
00309             DBGLOG(DBG, "Unifies with " << natID);
00310 
00311             // compute unifier
00312             std::map<ID, ID> unifier;
00313             int i = 0;
00314             BOOST_FOREACH (ID t, nat.tuple) {
00315                 if (t.isVariableTerm()) {
00316                     unifier[t] = atom.tuple[i];
00317                     DBGLOG(DBG, "Unifier: " << t << " --> " << atom.tuple[i]);
00318                 }
00319                 i++;
00320             }
00321 
00322             // apply unifier to the overall nogood
00323             DBGLOG(DBG, "Applying unifier");
00324             BOOST_FOREACH (ID natID2, *this) {
00325                 if (natID2.isOrdinaryGroundAtom()) {
00326                     instance.insert(natID2);
00327                 }
00328                 else {
00329                     OrdinaryAtom nat2 = reg->onatoms.getByID(natID2);
00330                     bool ground = true;
00331                     for (uint32_t i = 0; i < nat2.tuple.size(); ++i) {
00332                         if (unifier.find(nat2.tuple[i]) != unifier.end()) {
00333                             DBGLOG(DBG, "Substituting " << nat2.tuple[i] << " by " << unifier[nat2.tuple[i]]);
00334                             nat2.tuple[i] = unifier[nat2.tuple[i]];
00335                         }
00336                         if (nat2.tuple[i].isVariableTerm()) ground = false;
00337                     }
00338                     if (ground) {
00339                         nat2.kind &= (ID::ALL_ONES ^ ID::SUBKIND_MASK);
00340                         nat2.kind |= ID::SUBKIND_ATOM_ORDINARYG;
00341                     }
00342                     instance.insert(NogoodContainer::createLiteral(reg->storeOrdinaryAtom(nat2).address, !natID2.isNaf(), ground));
00343                 }
00344             }
00345             DBGLOG(DBG, "Instance: " << instance);
00346             if (!instance.isGround()) DBGLOG(DBG, "Note: Instance is not ground!");
00347             return true;
00348         }
00349     }
00350     // no match
00351     return false;
00352 }
00353 
00354 
00355 #ifndef NDEBUG
00356 
00357 std::string Nogood::dbgsave() const
00358 {
00359     std::stringstream ss;
00360     BOOST_FOREACH (ID id, *this) {
00361         ss << (id.isNaf() ? "-" : "+") << "/" << id.address << ";";
00362     }
00363     return ss.str();
00364 }
00365 
00366 
00367 void Nogood::dbgload(std::string str)
00368 {
00369 
00370     while (str.find_first_of("/") != std::string::npos) {
00371         std::string sign = str.substr(0, str.find_first_of("/"));
00372         std::string adr = str.substr(str.find_first_of("/") + 1, str.find_first_of(";"));
00373         str = str.substr(str.find_first_of(";") + 1);
00374         insert(NogoodContainer::createLiteral(atoi(str.c_str()), sign[0] == '+'));
00375     }
00376 }
00377 #endif
00378 
00379 // ---------- Class NogoodSet ----------
00380 
00381 const NogoodSet& NogoodSet::operator=(const NogoodSet& other)
00382 {
00383     nogoods = other.nogoods;
00384     freeIndices = other.freeIndices;
00385     nogoodsWithHash = other.nogoodsWithHash;
00386 
00387     return *this;
00388 }
00389 
00390 
00391 // reorders the nogoods such that there are no free indices in the range 0-(getNogoodCount()-1)
00392 void NogoodSet::defragment()
00393 {
00394     if (freeIndices.size() == 0) return;
00395 
00396     int free = 0;
00397     int used = nogoods.size() - 1;
00398     while (free < used) {
00399         // let used point to the last element which is not free
00400         while (used > 0 && freeIndices.count(used) > 0) {
00401             nogoods.pop_back();
00402             used--;
00403         }
00404         // let free point to the next free index in the range 0-(ngg.nogoods.size()-1)
00405         while (free < (int)nogoods.size() - 1 && freeIndices.count(free) == 0) free++;
00406         // move used to free
00407         if (free < used) {
00408             nogoods[free] = nogoods[used];
00409             addCount[free] = addCount[used];
00410             nogoods.pop_back();
00411             addCount.pop_back();
00412             nogoodsWithHash[nogoods[free].getHash()].erase(used);
00413             nogoodsWithHash[nogoods[free].getHash()].insert(free);
00414             freeIndices.erase(free);
00415             free++;
00416             used--;
00417         }
00418     }
00419     #ifndef NDEBUG
00420     // there must not be pointers to non-existing nogoods
00421     {
00422         typedef std::pair<size_t, Set<int> > Pair;
00423         BOOST_FOREACH (Pair p, nogoodsWithHash) {
00424             BOOST_FOREACH (int i, p.second) {
00425                 assert (i < (int)nogoods.size());
00426             }
00427         }
00428     }
00429     #endif
00430     freeIndices.clear();
00431 }
00432 
00433 
00434 int NogoodSet::addNogood(Nogood ng)
00435 {
00436 
00437     ng.recomputeHash();
00438     DBGLOG(DBG, "Hash of " << ng << " is " << ng.getHash());
00439 
00440     // check if ng is already present
00441     BOOST_FOREACH (int i, nogoodsWithHash[ng.getHash()]) {
00442         if (nogoods[i] == ng) {
00443             addCount[i]++;
00444             DBGLOG(DBG, "Already contained with index " << i);
00445             return i;
00446         }
00447     }
00448 
00449     // nogood is not present
00450     int index;
00451     if (freeIndices.size() == 0) {
00452         nogoods.push_back(ng);
00453         addCount.push_back(1);
00454         index = nogoods.size() - 1;
00455     }
00456     else {
00457         index = *freeIndices.begin();
00458         nogoods[index] = ng;
00459         addCount[index] = 1;
00460         freeIndices.erase(index);
00461     }
00462     DBGLOG(DBG, "Adding with index " << index);
00463 
00464     nogoodsWithHash[ng.getHash()].insert(index);
00465     return index;
00466 }
00467 
00468 
00469 Nogood& NogoodSet::getNogood(int index)
00470 {
00471     return nogoods[index];
00472 }
00473 
00474 
00475 const Nogood& NogoodSet::getNogood(int index) const
00476 {
00477     return nogoods[index];
00478 }
00479 
00480 
00481 void NogoodSet::removeNogood(int nogoodIndex)
00482 {
00483     addCount[nogoodIndex] = 0;
00484     nogoodsWithHash[nogoods[nogoodIndex].getHash()].erase(nogoodIndex);
00485     freeIndices.insert(nogoodIndex);
00486     //  defragment();   // make sure that the nogood vector does not contain free slots
00487 }
00488 
00489 
00490 void NogoodSet::removeNogood(Nogood ng)
00491 {
00492     ng.recomputeHash();
00493 
00494     // check if ng is present
00495     BOOST_FOREACH (int i, nogoodsWithHash[ng.getHash()]) {
00496         if (nogoods[i] == ng) {
00497             DBGLOG(DBG, "Deleting nogood " << ng << " (index: " << i << ")");
00498             // yes: delete it
00499             removeNogood(i);
00500             return;
00501         }
00502     }
00503     return;
00504 }
00505 
00506 
00507 int NogoodSet::getNogoodCount() const
00508 {
00509     return nogoods.size() - freeIndices.size();
00510 }
00511 
00512 
00513 void NogoodSet::forgetLeastFrequentlyAdded()
00514 {
00515 
00516     int mac = 0;
00517     for (uint32_t i = 0; i < nogoods.size(); i++) {
00518         mac = mac > addCount[i] ? mac : addCount[i];
00519     }
00520     // delete those with an add count of less than 5% of the maximum add count
00521     for (uint32_t i = 0; i < nogoods.size(); i++) {
00522         if (addCount[i] < mac * 0.05) {
00523             DBGLOG(DBG, "Forgetting nogood " << nogoods[i]);
00524             removeNogood(i);
00525         }
00526     }
00527 }
00528 
00529 
00530 std::string NogoodSet::getStringRepresentation(RegistryPtr reg) const
00531 {
00532 
00533     std::stringstream ss;
00534     bool first = true;
00535     BOOST_FOREACH (Nogood ng, nogoods) {
00536         if (!first) {
00537             ss << ", ";
00538         }
00539         first = false;
00540         ss << ng.getStringRepresentation(reg);
00541     }
00542     return ss.str();
00543 }
00544 
00545 
00546 std::ostream& NogoodSet::print(std::ostream& o) const
00547 {
00548     o << "{ ";
00549     for (std::vector<Nogood>::const_iterator it = nogoods.begin(); it != nogoods.end(); ++it) {
00550         if (it != nogoods.begin()) o << ", ";
00551         o << (*it);
00552     }
00553     o << " }";
00554     return o;
00555 }
00556 
00557 
00558 void SimpleNogoodContainer::addNogood(Nogood ng)
00559 {
00560     boost::mutex::scoped_lock lock(mutex);
00561     ngg.addNogood(ng);
00562 }
00563 
00564 
00565 void SimpleNogoodContainer::removeNogood(Nogood ng)
00566 {
00567     boost::mutex::scoped_lock lock(mutex);
00568     ngg.removeNogood(ng);
00569 }
00570 
00571 
00572 Nogood& SimpleNogoodContainer::getNogood(int index)
00573 {
00574     boost::mutex::scoped_lock lock(mutex);
00575     return ngg.getNogood(index);
00576 }
00577 
00578 
00579 int SimpleNogoodContainer::getNogoodCount()
00580 {
00581     boost::mutex::scoped_lock lock(mutex);
00582     return ngg.getNogoodCount();
00583 }
00584 
00585 
00586 void SimpleNogoodContainer::clear()
00587 {
00588     boost::mutex::scoped_lock lock(mutex);
00589     ngg = NogoodSet();
00590 }
00591 
00592 
00593 void SimpleNogoodContainer::addAllResolvents(RegistryPtr reg, int maxSize)
00594 {
00595 
00596     std::vector<Nogood> nogoodList;
00597     for (int i = 0; i < getNogoodCount(); i++) {
00598         nogoodList.push_back(getNogood(i));
00599         nogoodList[nogoodList.size() - 1].heuristicNormalization(reg);
00600     }
00601 
00602     // for all nogoods
00603     std::vector<Nogood> addList;
00604     int ng1i = 0;
00605     while (ng1i < (int)nogoodList.size()) {
00606         Nogood ng1 = nogoodList[ng1i];
00607         DBGLOG(DBG, "Trying to resolve " << ng1.getStringRepresentation(reg));
00608 
00609         // rename all variables in ng1 to avoid name clashes
00610         DBGLOG(DBG, "Renaming all variables");
00611         std::set<ID> vars;
00612         std::map<ID, ID> renaming;
00613         BOOST_FOREACH (ID id1, ng1) reg->getVariablesInID(id1, vars);
00614         BOOST_FOREACH (ID v, vars) {
00615             assert(!v.isAnonymousVariable() && "do not support anonymous variables in nogoods");
00616             // just mark the variables as anonymous to ensure that they have a different ID
00617             renaming[v] = ID(v.kind | ID::PROPERTY_VAR_ANONYMOUS,  v.address);
00618         }
00619         ng1.applyVariableSubstitution(reg, renaming);
00620 
00621         // for all other nogoods
00622         for (uint32_t ng2i = 0; ng2i < nogoodList.size(); ng2i++) {
00623             const Nogood& ng2 = nogoodList[ng2i];
00624 
00625             // check if they unify
00626             DBGLOG(DBG, "Checking if " << ng1.getStringRepresentation(reg) << " unifies with " << ng2.getStringRepresentation(reg));
00627             BOOST_FOREACH (ID id1, ng1) {
00628                 BOOST_FOREACH (ID id2, ng2) {
00629                     if (id1.isNaf() != id2.isNaf() && reg->lookupOrdinaryAtom(id1).unifiesWith(reg->lookupOrdinaryAtom(id2))) {
00630                         // match id1 with id2
00631                         std::map<ID, ID> match;
00632                         const OrdinaryAtom& at1 = reg->lookupOrdinaryAtom(id1);
00633                         const OrdinaryAtom& at2 = reg->lookupOrdinaryAtom(id2);
00634                         for (uint32_t i = 1; i < at1.tuple.size(); i++) match[at1.tuple[i]] = at2.tuple[i];
00635                         Nogood ng1matched = ng1;
00636                         ng1matched.applyVariableSubstitution(reg, match);
00637 
00638                         DBGLOG(DBG, "Resolving " << ng1matched.getStringRepresentation(reg) << "(" << ng1matched << ") with " << ng2.getStringRepresentation(reg) << " (" << ng2 << ")" << " on " << id2);
00639                         Nogood resolvent = ng1matched.resolve(ng2, id2);
00640                         // now assign new variable names to the renamed variables (names which occur neither in ng1 nor in ng2)
00641                         std::set<ID> vars;
00642                         std::map<ID, ID> backrenaming;
00643                         BOOST_FOREACH (ID id1, ng1matched) reg->getVariablesInID(id1, vars);
00644                         BOOST_FOREACH (ID id1, ng2) reg->getVariablesInID(id1, vars);
00645                         typedef std::pair<ID, ID> KVPair;
00646                         BOOST_FOREACH (KVPair kv, renaming) {
00647                             ID newVar = ID_FAIL;
00648                             int cnt = 0;
00649                             while (newVar == ID_FAIL || vars.count(newVar) > 0) {
00650                                 std::stringstream ss;
00651                                 ss << reg->terms.getByID(kv.first).getUnquotedString();
00652                                 if (cnt++ > 0) ss << cnt;
00653                                 newVar = reg->storeVariableTerm(ss.str());
00654                             }
00655                             backrenaming[renaming[kv.first]] = newVar;
00656                         }
00657                         resolvent.applyVariableSubstitution(reg, backrenaming);
00658                         resolvent.heuristicNormalization(reg);
00659                         #ifdef DEBUG
00660                         std::stringstream ss;
00661                         RawPrinter printer(ss, reg);
00662                         printer.print(id1);
00663                         DBGLOG(DBG, "Computed resolvent " << resolvent.getStringRepresentation(reg) << " by resolving " << ss.str());
00664                         #endif
00665                         // finally add the resolvent if its size is within the limit
00666                         if (maxSize == -1 || resolvent.size() <= maxSize) {
00667                             DBGLOG(DBG, "Adding the resolvent");
00668                             addNogood(resolvent);
00669                             // if the nogood is not already present, then we also need to resolve it
00670                             if (getNogoodCount() > (int)(nogoodList.size() + addList.size())) {
00671                                 DBGLOG(DBG, "Adding the resolvent " << resolvent.getStringRepresentation(reg) << " for further resolution because there were " << (getNogoodCount() - (nogoodList.size() + addList.size())) << " new nogoods");
00672                                 addList.push_back(resolvent);
00673                             }
00674                         }
00675                     }
00676                 }
00677             }
00678             DBGLOG(DBG, "Finished checking " << ng2.getStringRepresentation(reg));
00679         }
00680 
00681         DBGLOG(DBG, "Finished checking " << ng1.getStringRepresentation(reg));
00682         nogoodList.insert(nogoodList.end(), addList.begin(), addList.end());
00683         addList.clear();
00684         ng1i++;
00685     }
00686 }
00687 
00688 
00689 void SimpleNogoodContainer::forgetLeastFrequentlyAdded()
00690 {
00691     boost::mutex::scoped_lock lock(mutex);
00692     DBGLOG(DBG, "Nogood count before forgetting " << ngg.getNogoodCount());
00693     ngg.forgetLeastFrequentlyAdded();
00694     ngg.defragment();
00695     DBGLOG(DBG, "Nogood count after forgetting " << ngg.getNogoodCount());
00696 }
00697 
00698 
00699 void SimpleNogoodContainer::defragment()
00700 {
00701     ngg.defragment();
00702 }
00703 
00704 
00705 DLVHEX_NAMESPACE_END
00706 
00707 // vim:expandtab:ts=4:sw=4:
00708 // mode: C++
00709 // End: