dlvhex  2.5.0
src/NogoodGrounder.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 #define DLVHEX_BENCHMARK
00035 
00036 #include "dlvhex2/NogoodGrounder.h"
00037 #include "dlvhex2/Logger.h"
00038 #include "dlvhex2/Registry.h"
00039 #include "dlvhex2/Printer.h"
00040 #include "dlvhex2/Benchmarking.h"
00041 #include "dlvhex2/Nogood.h"
00042 
00043 #include <bm/bmalgo.h>
00044 
00045 #include <boost/foreach.hpp>
00046 
00047 DLVHEX_NAMESPACE_BEGIN
00048 
00049 NogoodGrounder::NogoodGrounder(RegistryPtr reg, SimpleNogoodContainerPtr watched, SimpleNogoodContainerPtr destination, AnnotatedGroundProgram& agp) :
00050 reg(reg), watched(watched), destination(destination), agp(agp)
00051 {
00052 }
00053 
00054 
00055 void NogoodGrounder::resetWatched(SimpleNogoodContainerPtr watched)
00056 {
00057     this->watched = watched;
00058 }
00059 
00060 
00061 ImmediateNogoodGrounder::ImmediateNogoodGrounder(RegistryPtr reg, SimpleNogoodContainerPtr watched, SimpleNogoodContainerPtr destination, AnnotatedGroundProgram& agp) :
00062 NogoodGrounder(reg, watched, destination, agp), instantiatedNongroundNogoodsIndex(0)
00063 {
00064 }
00065 
00066 
00067 void ImmediateNogoodGrounder::update(InterpretationConstPtr partialInterpretation, InterpretationConstPtr factWasSet, InterpretationConstPtr changed)
00068 {
00069 
00070     // go through all nonground nogoods which have not been instantiated so far
00071     int max = watched->getNogoodCount();
00072     if (instantiatedNongroundNogoodsIndex >= max) instantiatedNongroundNogoodsIndex = 0;
00073     DBGLOG(DBG, "Updating nogood grounder from " << instantiatedNongroundNogoodsIndex << " to " << max);
00074     for (int i = instantiatedNongroundNogoodsIndex; i < max; ++i) {
00075         Nogood ng = watched->getNogood(i);
00076         DBGLOG(DBG, "Checking nogood " << ng.getStringRepresentation(reg));
00077         if (ng.isGround()) continue;
00078 
00079         DBGLOG(DBG, "Searching for watched literal in nogood " << i);
00080         int maxBoundVariables = 0;
00081         ID watchedLit = ID_FAIL;
00082         BOOST_FOREACH (ID lit, ng) {
00083             if (lit.isOrdinaryGroundAtom()) continue;
00084             if (reg->onatoms.getIDByAddress(lit.address).isGuardAuxiliary()) continue;
00085 
00086             const OrdinaryAtom& atom = reg->onatoms.getByID(lit);
00087 
00088             std::set<ID> distinctVar;
00089             int var = 0;
00090             BOOST_FOREACH (ID p, atom.tuple) {
00091                 if (p.isVariableTerm()) {
00092                     if (std::find(distinctVar.begin(), distinctVar.end(), p) == distinctVar.end()) {
00093                         distinctVar.insert(p);
00094                         var++;
00095                     }
00096                 }
00097             }
00098 
00099             if (var > maxBoundVariables) {
00100                 maxBoundVariables = var;
00101                 watchedLit = lit;
00102             }
00103         }
00104         if (watchedLit == ID_FAIL) {
00105             DBGLOG(DBG, "Skipping nogood " << i << " because it contains only guard atoms");
00106             continue;
00107         }
00108 
00109         // watch the atom and the corresponding nogood
00110         DBGLOG(DBG, "Watching literal " << watchedLit << " in nogood " << i);
00111         const OrdinaryAtom& watchedAtom = reg->onatoms.getByAddress(watchedLit.address);
00112 
00113         // For each atom A of the program, check if the watched literal unifies with A
00114         bm::bvector<>::enumerator en = agp.getProgramMask()->getStorage().first();
00115         bm::bvector<>::enumerator en_end = agp.getProgramMask()->getStorage().end();
00116 
00117         DBGLOG(DBG, "Searching for unifying program atoms");
00118         while (en < en_end) {
00119 
00120             DBGLOG(DBG, "Checking atom " << *en);
00121 
00122             const OrdinaryAtom& currentAtom = reg->ogatoms.getByAddress(*en);
00123             if (currentAtom.unifiesWith(watchedAtom, reg)) {
00124                 Nogood instantiatedNG;
00125                 ng.match(reg, reg->ogatoms.getIDByAddress(*en), instantiatedNG);
00126                 DBGLOG(DBG, "Instantiated " << instantiatedNG.getStringRepresentation(reg) << " from " << ng.getStringRepresentation(reg));
00127 
00128                 // check if the instance of the nogood contains a ground literal which does not appear in the program
00129                 bool relevant = true;
00130                 Nogood simplifiedNG;
00131                 BOOST_FOREACH (ID lit, instantiatedNG) {
00132                     if (lit.isOrdinaryGroundAtom() && !reg->ogatoms.getIDByAddress(lit.address).isAuxiliary() && !agp.getProgramMask()->getFact(lit.address)) {
00133                         if (!lit.isNaf()) {
00134                             // can never be true --> remove whole instance
00135                             #ifndef NDEBUG
00136                             std::string str = RawPrinter::toString(reg, lit);
00137                             DBGLOG(DBG, "Removing because negative " << str << " can never be true");
00138                             #endif
00139                             relevant = false;
00140                             break;
00141                         }
00142                         else {
00143                             // is always true --> remove literal
00144                         }
00145                     }
00146                     else {
00147                         // might be true --> keep literal
00148                         simplifiedNG.insert(lit);
00149                     }
00150                 }
00151 
00152                 if (relevant) {
00153                     if (simplifiedNG.isGround()) {
00154                         DBGLOG(DBG, "Keeping ground nogood " << simplifiedNG.getStringRepresentation(reg));
00155                         destination->addNogood(simplifiedNG);
00156                     }
00157                     else {
00158                         DBGLOG(DBG, "Keeping nonground nogood " << simplifiedNG.getStringRepresentation(reg));
00159                         watched->addNogood(simplifiedNG);
00160                     }
00161                 }
00162                 else {
00163                     DBGLOG(DBG, "Removing nogood " << simplifiedNG.getStringRepresentation(reg));
00164                 }
00165             }
00166 
00167             en++;
00168         }
00169 
00170     }
00171     DBGLOG(DBG, "Finished updating");
00172     instantiatedNongroundNogoodsIndex = max;
00173 }
00174 
00175 
00176 void ImmediateNogoodGrounder::resetWatched(SimpleNogoodContainerPtr watched)
00177 {
00178     NogoodGrounder::resetWatched(watched);
00179     instantiatedNongroundNogoodsIndex = 0;
00180 }
00181 
00182 
00183 LazyNogoodGrounder::LazyNogoodGrounder(RegistryPtr reg, SimpleNogoodContainerPtr watched, SimpleNogoodContainerPtr destination, AnnotatedGroundProgram& agp) :
00184 NogoodGrounder(reg, watched, destination, agp), watchedNogoodsCount(0)
00185 {
00186 }
00187 
00188 
00189 void LazyNogoodGrounder::update(InterpretationConstPtr partialInterpretation, InterpretationConstPtr factWasSet, InterpretationConstPtr changed)
00190 {
00191 
00192     if (!factWasSet) return;
00193 
00194     // Watch for all new nonground nogoods the literal which binds the highest number of variables
00195     DBGLOG(DBG, "Updating watches of nonground nogoods");
00196     int max = watched->getNogoodCount();
00197     if (watchedNogoodsCount >= max) watchedNogoodsCount = 0;
00198     DBGLOG(DBG, "Updating nogood grounder from " << watchedNogoodsCount << " to " << max);
00199     for (int i = watchedNogoodsCount; i < max; ++i) {
00200         Nogood ng = watched->getNogood(i);
00201         DBGLOG(DBG, "Checking nogood " << ng.getStringRepresentation(reg));
00202         if (ng.isGround()) continue;
00203 
00204         DBGLOG(DBG, "Searching for watched literal in nogood " << i);
00205         int maxBoundVariables = 0;
00206         ID watchedLit = ID_FAIL;
00207         BOOST_FOREACH (ID lit, ng) {
00208             if (lit.isOrdinaryGroundAtom()) continue;
00209             if (reg->onatoms.getIDByAddress(lit.address).isGuardAuxiliary()) continue;
00210 
00211             const OrdinaryAtom& atom = reg->onatoms.getByID(lit);
00212 
00213             std::set<ID> distinctVar;
00214             int var = 0;
00215             BOOST_FOREACH (ID p, atom.tuple) {
00216                 if (p.isVariableTerm()) {
00217                     if (std::find(distinctVar.begin(), distinctVar.end(), p) == distinctVar.end()) {
00218                         distinctVar.insert(p);
00219                         var++;
00220                     }
00221                 }
00222             }
00223 
00224             if (var > maxBoundVariables) {
00225                 maxBoundVariables = var;
00226                 watchedLit = lit;
00227             }
00228         }
00229         if (watchedLit == ID_FAIL) {
00230             DBGLOG(DBG, "Skipping nogood " << i << " because it contains only guard atoms");
00231         }
00232         else {
00233             // watch the atom and the corresponding nogood
00234             DBGLOG(DBG, "Watching literal " << watchedLit << " in nogood " << i);
00235             watchedLiterals.push_back(std::pair<ID, int>(watchedLit, i));
00236         }
00237     }
00238     watchedNogoodsCount = watched->getNogoodCount();
00239 
00240     // For each atom A with changed truth value: go through all watches and check if
00241     // 1. the watched literal unifies with A
00242     // 2. the corresponding clause has not been instantiated for A yet
00243     bm::bvector<>::enumerator en = changed->getStorage().first();
00244     bm::bvector<>::enumerator en_end = changed->getStorage().end();
00245 
00246     DBGLOG(DBG, "Instantiating nonground nogoods");
00247     while (en < en_end) {
00248 
00249         DBGLOG(DBG, "Instantiating for atom " << *en);
00250         typedef std::pair<ID, int> Pair;
00251         BOOST_FOREACH (Pair p, watchedLiterals) {
00252             DBGLOG(DBG, "Matching nonground nogood " << p.second);
00253 
00254             // 2.
00255             if (std::find(alreadyCompared.begin(), alreadyCompared.end(), std::pair<IDAddress, int>(*en, p.second)) != alreadyCompared.end()) continue;
00256 
00257             const OrdinaryAtom& currentAtom = reg->ogatoms.getByAddress(*en);
00258             const OrdinaryAtom& watchedAtom = reg->onatoms.getByAddress(p.first.address);
00259             // 1.
00260             if (currentAtom.unifiesWith(watchedAtom, reg)) {
00261                 Nogood instantiatedNG;
00262                 watched->getNogood(p.second).match(reg, reg->ogatoms.getIDByAddress(*en), instantiatedNG);
00263                 DBGLOG(DBG, "Instantiated " << instantiatedNG.getStringRepresentation(reg) << " from " << watched->getNogood(p.second).getStringRepresentation(reg));
00264 
00265                 if (instantiatedNG.isGround()) {
00266                     destination->addNogood(instantiatedNG);
00267                 }
00268                 else {
00269                     watched->addNogood(instantiatedNG);
00270                 }
00271             }
00272 
00273             alreadyCompared.insert(std::pair<IDAddress, int>(*en, p.second));
00274         }
00275         en++;
00276     }
00277 }
00278 
00279 
00280 void LazyNogoodGrounder::resetWatched(SimpleNogoodContainerPtr watched)
00281 {
00282     NogoodGrounder::resetWatched(watched);
00283 }
00284 
00285 
00286 DLVHEX_NAMESPACE_END
00287 
00288 // vim:expandtab:ts=4:sw=4:
00289 // mode: C++
00290 // End: