dlvhex  2.5.0
src/CDNLSolver.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 #ifdef HAVE_CONFIG_H
00035 #include "config.h"
00036 #endif
00037 
00038 #include "dlvhex2/CDNLSolver.h"
00039 #include "dlvhex2/ProgramCtx.h"
00040 #include "dlvhex2/GenuineSolver.h"
00041 #include "dlvhex2/Benchmarking.h"
00042 
00043 #include <iostream>
00044 #include <sstream>
00045 #include "dlvhex2/Logger.h"
00046 #include <boost/functional/hash.hpp>
00047 
00048 DLVHEX_NAMESPACE_BEGIN
00049 
00050 #define DBGLOGD(X,Y) DBGLOG(X,Y)
00051 //#define DBGLOGD(X,Y) do{}while(false);
00052 
00053 // ---------- Class CDNLSolver ----------
00054 
00055 bool CDNLSolver::unitPropagation(Nogood& violatedNogood)
00056 {
00057 
00058     DBGLOG(DBG, "Unit propagation starts");
00059     int nogoodNr;
00060     while (unitNogoods.size() > 0) {
00061         nogoodNr = *(unitNogoods.begin());
00062         const Nogood& nextUnitNogood = nogoodset.getNogood(nogoodNr);
00063         unitNogoods.erase(unitNogoods.begin());
00064 
00065         // find propagation DL
00066         int propDL = 0;
00067         BOOST_FOREACH (ID lit, nextUnitNogood) {
00068             if (assigned(lit.address) && decisionlevel[lit.address] > propDL) {
00069                 propDL = decisionlevel[lit.address];
00070             }
00071         }
00072 
00073         // as the nogood is unit, it has a single watched literal
00074         // its negation is the propagated one
00075         ID propagatedLit = negation(*(watchedLiteralsOfNogood[nogoodNr].begin()));
00076         setFact(propagatedLit, propDL, nogoodNr);
00077     }
00078 
00079     if (contradictoryNogoods.size() > 0) {
00080         violatedNogood = nogoodset.getNogood(*(contradictoryNogoods.begin()));
00081         DBGLOG(DBG, "Unit propagation finished with detected contradiction " << violatedNogood);
00082         return false;
00083     }
00084 
00085     DBGLOG(DBG, "Unit propagation finished successfully");
00086     return true;
00087 }
00088 
00089 
00090 void CDNLSolver::loadAddedNogoods()
00091 {
00092     for (int i = 0; i < nogoodsToAdd.getNogoodCount(); ++i) {
00093         addNogoodAndUpdateWatchingStructures(nogoodsToAdd.getNogood(i));
00094 
00095     }
00096     nogoodsToAdd.clear();
00097 }
00098 
00099 
00100 void CDNLSolver::analysis(Nogood& violatedNogood, Nogood& learnedNogood, int& backtrackDL)
00101 {
00102 
00103     DBGLOG(DBG,"Conflict detected, violated nogood: " << violatedNogood);
00104 
00105     #ifndef NDEBUG
00106     ++cntDetectedConflicts;
00107     #endif
00108 
00109     // decision heuristic metric update
00110     touchVarsInNogood(violatedNogood);
00111 
00112     // check how many literals were assigned at top decision level
00113     // if there is more than one, resolve the nogood with the cause of one of the implied literals
00114     learnedNogood = violatedNogood;
00115     int count;
00116     int resSteps = 0;
00117     int latestDL;
00118     IDAddress impliedLit;
00119     long litAssignmentOrderIndex;
00120     ID latestLit;
00121     long latestLitAssignmentOrderIndex;
00122     int bt = 0;
00123     do {
00124         bool foundImpliedLit = false;
00125         count = 0;
00126         impliedLit = ID::ALL_ONES;
00127         latestLit = ID_FAIL;
00128         latestLitAssignmentOrderIndex = -1;
00129         BOOST_FOREACH (ID lit, learnedNogood) {
00130             litAssignmentOrderIndex = getAssignmentOrderIndex(lit.address);
00131             if (litAssignmentOrderIndex > latestLitAssignmentOrderIndex) {
00132                 latestLit = lit;
00133                 latestLitAssignmentOrderIndex = getAssignmentOrderIndex(latestLit.address);
00134             }
00135         }
00136         latestDL = decisionlevel[latestLit.address];
00137 
00138         BOOST_FOREACH (ID lit, learnedNogood) {
00139             // compute number of literals on latest dl
00140             if (decisionlevel[lit.address] == latestDL) {
00141                 count++;
00142                 if (!isDecisionLiteral(lit.address)) {
00143                     impliedLit = lit.address;
00144                     foundImpliedLit = true;
00145                 }
00146             }
00147 
00148             // backtrack to the second-highest decision level
00149             if (decisionlevel[lit.address] > bt && lit.address != latestLit.address && decisionlevel[lit.address] < latestDL) {
00150                 bt = decisionlevel[lit.address];
00151             }
00152         }
00153 
00154         if (count > 1) {
00155             // resolve the clause with multiple literals on top level
00156             // with the cause of one of the implied literals
00157 
00158             // at DL=0 we might have multiple literals without a cause (they are only spurious decision literals, actually they are facts)
00159             if (!foundImpliedLit && latestDL == 0) {
00160                 break;
00161             }
00162             else {
00163                 assert(foundImpliedLit);
00164                 Nogood& c = nogoodset.getNogood(cause[impliedLit]);
00165                 touchVarsInNogood(c);
00166                 learnedNogood = resolve(learnedNogood, c, impliedLit);
00167             }
00168             #ifndef NDEBUG
00169             ++cntResSteps;
00170             #endif
00171             ++resSteps;
00172         }
00173     }while(count > 1);
00174 
00175     if (resSteps > 0) {
00176         // if resSteps == 0, then learnedNogood == violatedNogood, which was already touched
00177         touchVarsInNogood(learnedNogood);
00178     }
00179 
00180     DBGLOG(DBG, "Learned conflict nogood: " << learnedNogood << " (after " << resSteps << " resolution steps)");
00181     DBGLOG(DBG, "Backtrack-DL: " << bt);
00182     backtrackDL = bt;
00183 
00184     // decision heuristic metric update
00185     ++conflicts;
00186     if (conflicts >= 255) {
00187         DBGLOG(DBG, "Maximum conflicts count: dividing all counters by 2");
00188         BOOST_FOREACH (IDAddress litadr, allAtoms) {
00189             varCounterPos[litadr] /= 2;
00190             varCounterNeg[litadr] /= 2;
00191         }
00192         conflicts = 0;
00193     }
00194 }
00195 
00196 
00197 Nogood CDNLSolver::resolve(Nogood& ng1, Nogood& ng2, IDAddress litadr)
00198 {
00199     // resolvent = union of ng1 and ng2 minus both polarities of the resolved literal
00200     Nogood resolvent = ng1;
00201     resolvent.insert(ng2.begin(), ng2.end());
00202     resolvent.erase(createLiteral(litadr));
00203     resolvent.erase(negation(createLiteral(litadr)));
00204     DBGLOG(DBG, "Resolution " << ng1 << " with " << ng2 << ": " << resolvent);
00205 
00206     #ifndef NDEBUG
00207     ++cntResSteps;
00208     #endif
00209     return resolvent;
00210 }
00211 
00212 
00213 void CDNLSolver::setFact(ID fact, int dl, int c = -1)
00214 {
00215 
00216     if (c > -1) {
00217         DBGLOG(DBG, "Assigning " << litToString(fact) << "@" << dl << " with cause " << nogoodset.getNogood(c));
00218     }
00219     else {
00220         DBGLOG(DBG, "Assigning " << litToString(fact) << "@" << dl);
00221     }
00222                                  // fact was set
00223     assignedAtoms->setFact(fact.address);
00224     changedAtoms->setFact(fact.address);
00225                                  // store decision level
00226     decisionlevel[fact.address] = dl;
00227     //if (c > -1)
00228     cause[fact.address] = c;     // store cause
00229     if (fact.isNaf()) {          // store truth value
00230         interpretation->clearFact(fact.address);
00231     }
00232     else {
00233         interpretation->setFact(fact.address);
00234     }
00235     assignmentOrder.insert(fact.address);
00236     factsOnDecisionLevel[dl].push_back(fact.address);
00237 
00238     updateWatchingStructuresAfterSetFact(fact);
00239 
00240     #ifndef NDEBUG
00241     ++cntAssignments;
00242     #endif
00243 }
00244 
00245 
00246 void CDNLSolver::clearFact(IDAddress litadr)
00247 {
00248     DBGLOG(DBG, "Unassigning " << litadr << "@" << decisionlevel[litadr]);
00249     assignedAtoms->clearFact(litadr);
00250     changedAtoms->setFact(litadr);
00251     cause[litadr] = -1;
00252     assignmentOrder.erase(litadr);
00253 
00254     // getFact will return the truth value which was just cleared
00255     // (truth value remains until it is overridden by a new one)
00256     updateWatchingStructuresAfterClearFact(createLiteral(litadr, interpretation->getFact(litadr)));
00257 }
00258 
00259 
00260 void CDNLSolver::backtrack(int dl)
00261 {
00262 
00263     for (uint32_t i = dl + 1; i < factsOnDecisionLevel.size(); ++i) {
00264         BOOST_FOREACH (IDAddress f, factsOnDecisionLevel[i]) {
00265             clearFact(f);
00266         }
00267         factsOnDecisionLevel[i].clear();
00268     }
00269 
00270     #ifndef NDEBUG
00271     ++cntBacktracks;
00272     #endif
00273 }
00274 
00275 
00276 ID CDNLSolver::getGuess()
00277 {
00278 
00279     assert (!complete());
00280 
00281     #ifndef NDEBUG
00282     ++cntGuesses;
00283     #endif
00284 
00285     // simple heuristic: guess the next unassigned literal
00286     /*
00287     for (std::set<IDAddress>::reverse_iterator rit = allAtoms.rbegin(); rit != allAtoms.rend(); ++rit){
00288       if (!assigned(*rit)){
00289         return createLiteral(*rit);
00290       }
00291     }
00292     return ID_FAIL;
00293     */
00294 
00295     /*
00296     BOOST_FOREACH (IDAddress litadr, allAtoms){
00297       if (!assigned(litadr)){
00298         return createLiteral(litadr);
00299       }
00300     }
00301     return ID_FAIL;
00302     */
00303 
00304     DBGLOG(DBG, "Have " << allAtoms.size() << " atoms; " << assignedAtoms->getStorage().count() << " are assigned");
00305 
00306     // iterate over recent conflicts, beginning at the most recent conflict
00307     for (std::vector<int>::reverse_iterator rit = recentConflicts.rbegin(); rit != recentConflicts.rend(); ++rit) {
00308         Nogood& ng = nogoodset.getNogood(*rit);
00309 
00310         // skip satisfied and contraditory nogoods
00311         if (watchedLiteralsOfNogood[*rit].size() == 0) {
00312             continue;
00313         }
00314 
00315         // find most active unassigned variable in this nogood
00316         ID mostActive = ID_FAIL;
00317         BOOST_FOREACH (ID lit, ng) {
00318             if (!assigned(lit.address)) {
00319                 if (mostActive == ID_FAIL ||
00320                 (varCounterPos[lit.address] + varCounterNeg[lit.address]) > (varCounterPos[mostActive.address] + varCounterNeg[mostActive.address])) {
00321                     mostActive = varCounterPos[lit.address] > varCounterNeg[lit.address] ? negation(createLiteral(lit.address)) : createLiteral(lit.address);
00322                 }
00323             }
00324         }
00325 
00326         // if the nogood has no unassigned variable, it must be either satisfied or contradictory and the if above applies
00327         assert(mostActive != ID_FAIL);
00328 
00329         DBGLOG(DBG, "Guessing " << litToString(mostActive) << " because it occurs in recent conflicts");
00330         return mostActive;
00331     }
00332 
00333     // no recent conflicts;
00334     // use alternative heuristic: choose globally most active literal
00335     ID mostActive = ID_FAIL;
00336     BOOST_FOREACH (IDAddress litadr, allAtoms) {
00337         if (!assigned(litadr)) {
00338             if (mostActive == ID_FAIL ||
00339             (varCounterPos[litadr] + varCounterNeg[litadr]) > (varCounterPos[mostActive.address] + varCounterNeg[mostActive.address])) {
00340                 mostActive = varCounterPos[litadr] > varCounterNeg[litadr] ? negation(createLiteral(litadr)) : createLiteral(litadr);
00341             }
00342         }
00343     }
00344 
00345     DBGLOG(DBG, "Guessing " << litToString(mostActive) << " because it is globally active");
00346     return mostActive;
00347 }
00348 
00349 
00350 void CDNLSolver::initWatchingStructures()
00351 {
00352 
00353     // reset lazy data structures
00354     watchedLiteralsOfNogood = std::vector<Set<ID> >(nogoodset.getNogoodCount());
00355     watchingNogoodsOfPosLiteral.clear();
00356     watchingNogoodsOfNegLiteral.clear();
00357     nogoodsOfPosLiteral.clear();
00358     nogoodsOfNegLiteral.clear();
00359 
00360     // reset unit and contradictory nogoods
00361     unitNogoods.clear();
00362     contradictoryNogoods.clear();
00363 
00364     // each nogood watches (at most) two of its literals
00365     for (int nogoodNr = 0; nogoodNr < nogoodset.getNogoodCount(); ++nogoodNr) {
00366         updateWatchingStructuresAfterAddNogood(nogoodNr);
00367     }
00368 }
00369 
00370 
00371 void CDNLSolver::updateWatchingStructuresAfterAddNogood(int index)
00372 {
00373 
00374     DBGLOGD(DBG, "updateWatchingStructuresAfterAddNogood after adding nogood " << index);
00375     const Nogood& ng = nogoodset.getNogood(index);
00376 
00377     // remember for all literals in the nogood that they are contained in this nogood
00378     BOOST_FOREACH (ID lit, ng) {
00379         if (!lit.isNaf()) {
00380             nogoodsOfPosLiteral[lit.address].insert(index);
00381         }
00382         else {
00383             nogoodsOfNegLiteral[lit.address].insert(index);
00384         }
00385     }
00386 
00387     // search for up to two unassigned literals to watch
00388     bool inactive = false;
00389     tmpWatched.clear();
00390     BOOST_FOREACH (ID lit, ng) {
00391         if (!assigned(lit.address) && tmpWatched.size() < 2) {
00392             tmpWatched.insert(createLiteral(lit));
00393         }
00394         else if(falsified(lit)) {
00395             inactive = true;
00396         }
00397     }
00398 
00399     // remember watches
00400     if (!inactive) {
00401         BOOST_FOREACH (ID lit, tmpWatched) {
00402             startWatching(index, createLiteral(lit));
00403         }
00404     }
00405 
00406     if (inactive) {
00407         DBGLOGD(DBG, "Nogood " << index << " is inactive");
00408     }
00409     else if (tmpWatched.size() == 1) {
00410         DBGLOGD(DBG, "Nogood " << index << " is unit");
00411         unitNogoods.insert(index);
00412     }
00413     else if (tmpWatched.size() == 0) {
00414         DBGLOGD(DBG, "Nogood " << index << " is contradictory");
00415         contradictoryNogoods.insert(index);
00416     }
00417 }
00418 
00419 
00420 void CDNLSolver::updateWatchingStructuresAfterRemoveNogood(int index)
00421 {
00422     const Nogood& ng = nogoodset.getNogood(index);
00423 
00424     // remove the nogood from all literal lists
00425     BOOST_FOREACH (ID lit, ng) {
00426         nogoodsOfPosLiteral[lit.address].erase(index);
00427         nogoodsOfNegLiteral[lit.address].erase(index);
00428     }
00429 
00430     // remove all watched literals
00431     Set<ID>& watched = watchedLiteralsOfNogood[index];
00432     BOOST_FOREACH (ID lit, watched) {
00433         stopWatching(index, lit);
00434     }
00435 }
00436 
00437 
00438 void CDNLSolver::updateWatchingStructuresAfterSetFact(ID lit)
00439 {
00440 
00441     DBGLOGD(DBG, "updateWatchingStructuresAfterSetFact after " << litToString(lit) << " was set");
00442     bool changed;
00443 
00444     // go through all nogoods which watch this literal negatively and inactivate them
00445     if ((lit.isNaf() && watchingNogoodsOfPosLiteral.find(lit.address) != watchingNogoodsOfPosLiteral.end()) ||
00446     (!lit.isNaf() && watchingNogoodsOfNegLiteral.find(lit.address) != watchingNogoodsOfNegLiteral.end())) {
00447         do {
00448             changed = false;
00449             BOOST_FOREACH (int nogoodNr, lit.isNaf() ? watchingNogoodsOfPosLiteral[lit.address] : watchingNogoodsOfNegLiteral[lit.address]) {
00450                 inactivateNogood(nogoodNr);
00451                 changed = true;
00452                 break;
00453             }
00454         }while(changed);
00455     }
00456 
00457     // go through all nogoods which watch this literal positively and find a new watched literal
00458     //  if (watchingNogoodsOfPosLiteral.find(lit.address) != watchingNogoodsOfPosLiteral.end()){
00459     if ((!lit.isNaf() && watchingNogoodsOfPosLiteral.find(lit.address) != watchingNogoodsOfPosLiteral.end()) ||
00460     (lit.isNaf() && watchingNogoodsOfNegLiteral.find(lit.address) != watchingNogoodsOfNegLiteral.end())) {
00461         do {
00462             changed = false;
00463 
00464             BOOST_FOREACH (int nogoodNr, lit.isNaf() ? watchingNogoodsOfNegLiteral[lit.address] : watchingNogoodsOfPosLiteral[lit.address]) {
00465                 const Nogood& ng = nogoodset.getNogood(nogoodNr);
00466 
00467                 // stop watching lit
00468                 stopWatching(nogoodNr, lit);
00469 
00470                 // search for a new literal which is
00471                 // 1. not assigned yet
00472                 // 2. currently not watched
00473                 bool inactive = false;
00474                 BOOST_FOREACH (ID nglit, ng) {
00475                     if ((watchedLiteralsOfNogood[nogoodNr].size() < 2) && !assigned(nglit.address) && (watchedLiteralsOfNogood[nogoodNr].count(nglit) == 0)) {
00476                         // watch it
00477                         startWatching(nogoodNr, createLiteral(nglit));
00478                     }
00479                     else if (falsified(nglit)) {
00480                         DBGLOGD(DBG, "Nogood " << nogoodNr << " is now inactive");
00481                         inactivateNogood(nogoodNr);
00482                         inactive = true;
00483                         break;
00484                     }
00485                 }
00486                 if (!inactive) {
00487                     // nogood might have become unit or contradictory
00488                     if (watchedLiteralsOfNogood[nogoodNr].size() == 1) {
00489                         DBGLOGD(DBG, "Nogood " << nogoodNr << " is now unit");
00490                         unitNogoods.insert(nogoodNr);
00491                     }
00492                     else if (watchedLiteralsOfNogood[nogoodNr].size() == 0) {
00493                         DBGLOGD(DBG, "Nogood " << nogoodNr << " is now contradictory");
00494                         contradictoryNogoods.insert(nogoodNr);
00495                         unitNogoods.erase(nogoodNr);
00496                     }
00497                 }
00498 
00499                 changed = true;
00500                 break;
00501             }
00502         }while(changed);
00503     }
00504 }
00505 
00506 
00507 void CDNLSolver::updateWatchingStructuresAfterClearFact(ID literal)
00508 {
00509 
00510     // nogoods which watch the literal negatively were inactive before
00511     //  they can now either (i) still be inactive, or (ii) have at least one unassigned literal
00512 
00513     // nogoods which watch the literal positively were either active or inconsistent before
00514     //  if they were active, they can now (i) have more watched literals (if they had only one before); or
00515     //                   (ii) have as many watched literals as before (if they had already two)
00516     //  if they were inconsistent before, they have at least one watched literal
00517 
00518     DBGLOGD(DBG, "updateWatchingStructuresAfterClearFact after " << litToString(literal) << " was cleared");
00519 
00520     // go through all nogoods which contain this literal either positively or negatively
00521     for (int positiveAndNegativeLiteral = 1; positiveAndNegativeLiteral <= 2; ++positiveAndNegativeLiteral) {
00522 
00523         if ((positiveAndNegativeLiteral == 1 && nogoodsOfPosLiteral.find(literal.address) != nogoodsOfPosLiteral.end()) ||
00524         (positiveAndNegativeLiteral == 2 && nogoodsOfNegLiteral.find(literal.address) != nogoodsOfNegLiteral.end())) {
00525             BOOST_FOREACH (int nogoodNr, positiveAndNegativeLiteral == 1 ? nogoodsOfPosLiteral[literal.address] : nogoodsOfNegLiteral[literal.address]) {
00526                 DBGLOG(DBG, "Updating nogood " << nogoodNr);
00527 
00528                 const Nogood& ng = nogoodset.getNogood(nogoodNr);
00529 
00530                 bool stillInactive = false;
00531 
00532                 // check the number of currently watched literals
00533                 int watchedNum = watchedLiteralsOfNogood[nogoodNr].size();
00534                 switch(watchedNum) {
00535                     case 0:      // nogood was inactive or contradictory before
00536                         // nogood can:
00537                         // 1. still be inactive
00538                         // 2. have one unassigned literal
00539                         // 3. have multiple unassigned literals
00540                         // it cannot be contraditory anymore because at least one literal is unassigned!
00541                         tmpWatched.clear();
00542                         BOOST_FOREACH (ID lit, ng) {
00543                             if (falsified(lit)) {
00544                                 stillInactive = true;
00545                                 break;
00546                             }
00547                             // collect up to 2 watched literals
00548                             if (!assigned(lit.address) && tmpWatched.size() < 2) {
00549                                 tmpWatched.insert(lit);
00550                             }
00551                         }
00552                         if (!stillInactive) {
00553                             DBGLOG(DBG, "Nogood " << nogoodNr << " is reactivated");
00554                             BOOST_FOREACH (ID lit, tmpWatched) {
00555                                 startWatching(nogoodNr, createLiteral(lit));
00556                             }
00557 
00558                             if (tmpWatched.size() == 1) {
00559                                 DBGLOGD(DBG, "Nogood " << nogoodNr << " becomes unit");
00560                                 unitNogoods.insert(nogoodNr);
00561                             }
00562 
00563                             // nogood is (for sure) not contradictory anymore
00564                             contradictoryNogoods.erase(nogoodNr);
00565                         }
00566                         break;
00567                     case 1:      // nogood was unit before
00568                         // watch litadr
00569                         startWatching(nogoodNr, createLiteral(literal));
00570 
00571                         // nogood is not unit anymore
00572                         DBGLOGD(DBG, "Nogood " << nogoodNr << " is not unit anymore");
00573                         unitNogoods.erase(nogoodNr);
00574                         break;
00575                     default:     // nogood has more than one watched literal
00576                         // number of unassigned literals has possibly even increased
00577                         // nothing to do
00578                         break;
00579                 }
00580             }
00581         }
00582     }
00583 }
00584 
00585 
00586 void CDNLSolver::inactivateNogood(int nogoodNr)
00587 {
00588     DBGLOGD(DBG, "Nogood " << nogoodNr << " gets inactive");
00589 
00590     BOOST_FOREACH (ID lit, watchedLiteralsOfNogood[nogoodNr]) {
00591         watchingNogoodsOfPosLiteral[lit.address].erase(nogoodNr);
00592         watchingNogoodsOfNegLiteral[lit.address].erase(nogoodNr);
00593     }
00594     watchedLiteralsOfNogood[nogoodNr].clear();
00595 
00596     unitNogoods.erase(nogoodNr);
00597     contradictoryNogoods.erase(nogoodNr);
00598 }
00599 
00600 
00601 void CDNLSolver::stopWatching(int nogoodNr, ID lit)
00602 {
00603     DBGLOGD(DBG, "Nogood " << nogoodNr << " stops watching " << litToString(lit) << " (" << createLiteral(lit) << ")");
00604     if (!lit.isNaf()) {
00605         watchingNogoodsOfPosLiteral[lit.address].erase(nogoodNr);
00606     }
00607     else {
00608         watchingNogoodsOfNegLiteral[lit.address].erase(nogoodNr);
00609     }
00610     watchedLiteralsOfNogood[nogoodNr].erase(createLiteral(lit));
00611 }
00612 
00613 
00614 void CDNLSolver::startWatching(int nogoodNr, ID lit)
00615 {
00616     DBGLOGD(DBG, "Nogood " << nogoodNr << " starts watching " << litToString(lit) << " (" << createLiteral(lit) << ")");
00617     watchedLiteralsOfNogood[nogoodNr].insert(createLiteral(lit));
00618     if (!lit.isNaf()) {
00619         watchingNogoodsOfPosLiteral[lit.address].insert(nogoodNr);
00620     }
00621     else {
00622         watchingNogoodsOfNegLiteral[lit.address].insert(nogoodNr);
00623     }
00624 }
00625 
00626 
00627 void CDNLSolver::touchVarsInNogood(Nogood& ng)
00628 {
00629     BOOST_FOREACH (ID lit, ng) {
00630         if (lit.isNaf()) {
00631             varCounterNeg[lit.address]++;
00632         }
00633         else {
00634             varCounterPos[lit.address]++;
00635         }
00636     }
00637 }
00638 
00639 
00640 void CDNLSolver::initListOfAllAtoms()
00641 {
00642 
00643     // build a list of all literals which need to be assigned
00644     // go through all nogoods
00645     for (int i = 0; i < nogoodset.getNogoodCount(); ++i) {
00646         const Nogood& ng = nogoodset.getNogood(i);
00647         // go through all literals of the nogood
00648         for (Nogood::const_iterator lIt = ng.begin(); lIt != ng.end(); ++lIt) {
00649             if (lIt->isOrdinaryNongroundAtom()) throw GeneralError("Got nonground atom in SAT instance");
00650             allAtoms.insert(lIt->address);
00651         }
00652     }
00653 }
00654 
00655 
00656 void CDNLSolver::resizeVectors()
00657 {
00658 
00659     unsigned atomNamespaceSize = ctx.registry()->ogatoms.getSize();
00660     DBGLOG(DBG, "Resizing vectors to ground-atom namespace of size: " << atomNamespaceSize);
00661     assignmentOrder.resize(atomNamespaceSize);
00662 }
00663 
00664 
00665 std::string CDNLSolver::litToString(ID lit)
00666 {
00667     std::stringstream ss;
00668     ss << (lit.isNaf() ? std::string("-") : std::string("")) << lit.address;
00669     return ss.str();
00670 }
00671 
00672 
00673 int CDNLSolver::addNogoodAndUpdateWatchingStructures(Nogood ng)
00674 {
00675     assert(ng.isGround());
00676 
00677     // simplify nogood
00678     Nogood ng2;
00679     BOOST_FOREACH (ID lit, ng) {
00680         // do not add nogoods which expand the domain (this is the case if they contain positive atoms which are not in the domain)
00681         if (!lit.isNaf() && !allAtoms.contains(lit.address)) { return 0; }
00682         // keep positive atoms and negated atoms which are in the domain
00683         else if (!lit.isNaf() || allAtoms.contains(lit.address)) { ng2.insert(lit); }
00684         // the only remaining case should be that the literal is negated and the atom is not contained in the domain
00685         else { assert(lit.isNaf() && !allAtoms.contains(lit.address) && "conditions are logically incomplete"); }
00686     }
00687     ng = ng2;
00688 
00689     int index = nogoodset.addNogood(ng);
00690     DBGLOG(DBG, "Adding nogood " << ng << " with index " << index);
00691     if ((int)watchedLiteralsOfNogood.size() <= index) {
00692         watchedLiteralsOfNogood.push_back(Set<ID>(2, 1));
00693     }
00694     updateWatchingStructuresAfterAddNogood(index);
00695 
00696     return index;
00697 }
00698 
00699 
00700 std::string CDNLSolver::getStatistics()
00701 {
00702 
00703     #ifndef NDEBUG
00704     std::stringstream ss;
00705     ss  << "Assignments: " << cntAssignments << std::endl
00706         << "Guesses: " << cntGuesses << std::endl
00707         << "Backtracks: " << cntBacktracks << std::endl
00708         << "Resolution steps: " << cntResSteps << std::endl
00709         << "Conflicts: " << cntDetectedConflicts;
00710     return ss.str();
00711     #else
00712     std::stringstream ss;
00713     ss << "Only available in debug mode";
00714     return ss.str();
00715     #endif
00716 }
00717 
00718 
00719 CDNLSolver::CDNLSolver(ProgramCtx& c, NogoodSet ns) : ctx(c), nogoodset(ns), conflicts(0), cntAssignments(0), cntGuesses(0), cntBacktracks(0), cntResSteps(0), cntDetectedConflicts(0), tmpWatched(2, 1)
00720 {
00721 
00722     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidsolvertime, "Solver time");
00723     resizeVectors();
00724     initListOfAllAtoms();
00725 
00726     // create an interpretation and a storage for assigned facts (we need 3 values)
00727     interpretation.reset(new Interpretation(ctx.registry()));
00728     assignedAtoms.reset(new Interpretation(ctx.registry()));
00729     changedAtoms.reset(new Interpretation(ctx.registry()));
00730     currentDL = 0;
00731     exhaustedDL = 0;
00732 
00733     initWatchingStructures();
00734 };
00735 
00736 void CDNLSolver::restartWithAssumptions(const std::vector<ID>& assumptions)
00737 {
00738 
00739     // reset
00740     DBGLOG(DBG, "Resetting solver");
00741 
00742     interpretation.reset(new Interpretation(ctx.registry()));
00743     assignedAtoms.reset(new Interpretation(ctx.registry()));
00744     changedAtoms.reset(new Interpretation(ctx.registry()));
00745     cause.clear();
00746     assignmentOrder = OrderedSet<IDAddress, SimpleHashIDAddress>();
00747     factsOnDecisionLevel.clear();
00748     decisionLiteralOfDecisionLevel.clear();
00749 
00750     conflicts = 0;
00751     currentDL = 0;
00752     exhaustedDL = 0;
00753 
00754     initWatchingStructures();
00755 
00756     // set assumptions at DL=0
00757     DBGLOG(DBG, "Setting assumptions");
00758     BOOST_FOREACH (ID a, assumptions) {
00759         setFact(createLiteral(a.address, !a.isNaf()), 0);
00760     }
00761 }
00762 
00763 
00764 void CDNLSolver::addPropagator(PropagatorCallback* pb)
00765 {
00766     propagator.insert(pb);
00767 }
00768 
00769 
00770 void CDNLSolver::removePropagator(PropagatorCallback* pb)
00771 {
00772     propagator.erase(pb);
00773 }
00774 
00775 
00776 bool CDNLSolver::handlePreviousModel()
00777 {
00778 
00779     // is there a previous model?
00780     if (complete()) {
00781         if (currentDL == 0) {
00782             return false;
00783         }
00784         else {
00785             // add model as nogood to get another one
00786             // a restriction to the decision literals suffices
00787             Nogood modelNogood;
00788             BOOST_FOREACH (IDAddress fact, allAtoms) {
00789                 if (isDecisionLiteral(fact)) {
00790                     modelNogood.insert(createLiteral(fact, interpretation->getFact(fact)));
00791                 }
00792             }
00793             addNogoodAndUpdateWatchingStructures(modelNogood);
00794             DBGLOG(DBG, "Found previous model. Adding model as nogood " << (nogoodset.getNogoodCount() - 1) << ": " << modelNogood);
00795 
00796             // the new nogood is for sure contraditory
00797             Nogood learnedNogood;
00798             analysis(modelNogood, learnedNogood, currentDL);
00799             recentConflicts.push_back(addNogoodAndUpdateWatchingStructures(learnedNogood));
00800             DBGLOG(DBG, "Backtrack");
00801             backtrack(currentDL);
00802             return true;
00803         }
00804     }
00805     return true;
00806 }
00807 
00808 
00809 void CDNLSolver::flipDecisionLiteral()
00810 {
00811 
00812     // find decision literal dLit of current decision level
00813     ID dLit = decisionLiteralOfDecisionLevel[currentDL];
00814     currentDL--;
00815     exhaustedDL = currentDL;
00816 
00817     // goto previous decision level
00818     DBGLOG(DBG, "Backtrack to DL " << currentDL);
00819     backtrack(currentDL);
00820 
00821     // flip dLit, but now on the previous decision level!
00822     DBGLOG(DBG, "Flipping decision literal: " << litToString(negation(dLit)));
00823     setFact(negation(dLit), currentDL);
00824     flipped[dLit.address] = 1;
00825 }
00826 
00827 
00828 InterpretationPtr CDNLSolver::getNextModel()
00829 {
00830     DLVHEX_BENCHMARK_REGISTER_AND_SCOPE(sidsolvertime, "Solver time");
00831 
00832     Nogood violatedNogood;
00833 
00834     // handle previous model
00835     if (complete()) {
00836         if (currentDL == 0) {
00837             DBGLOG(DBG, "No more models");
00838             return InterpretationPtr();
00839         }
00840         else {
00841             flipDecisionLiteral();
00842         }
00843     }
00844 
00845                                  // if set to true, the loop will run even if the interpretation is already complete
00846     bool anotherIterationEvenIfComplete = false;
00847     // (needed to check if newly added nogood (e.g. by external learners) are satisfied)
00848     while (!complete()) {
00849         anotherIterationEvenIfComplete = false;
00850         DBGLOG(DBG, "Unit propagation");
00851         if (!unitPropagation(violatedNogood)) {
00852             if (currentDL == 0) {
00853                 // no answer set
00854                 return InterpretationPtr();
00855             }
00856             else {
00857                 if (currentDL > exhaustedDL) {
00858                     // backtrack
00859                     Nogood learnedNogood;
00860                     int k = currentDL;
00861                     analysis(violatedNogood, learnedNogood, k);
00862                     recentConflicts.push_back(addNogoodAndUpdateWatchingStructures(learnedNogood));
00863                                  // do not jump below exhausted level, this could lead to regeneration of models
00864                     currentDL = k > exhaustedDL ? k : exhaustedDL;
00865                     backtrack(currentDL);
00866                 }
00867                 else {
00868                     flipDecisionLiteral();
00869                 }
00870             }
00871         }
00872         else {
00873             DBGLOG(DBG, "Calling external learner");
00874             int nogoodCount = nogoodset.getNogoodCount();
00875             BOOST_FOREACH (PropagatorCallback* cb, propagator) {
00876                 DBGLOG(DBG, "Calling external learners with interpretation: " << *interpretation);
00877                 cb->propagate(interpretation, assignedAtoms, changedAtoms);
00878             }
00879             // add new nogoods
00880             int ngc = nogoodset.getNogoodCount();
00881             loadAddedNogoods();
00882             if (ngc != nogoodset.getNogoodCount()) anotherIterationEvenIfComplete = true;
00883             changedAtoms->clear();
00884 
00885             if (nogoodset.getNogoodCount() != nogoodCount) {
00886                 DBGLOG(DBG, "Learned something");
00887             }
00888             else {
00889                 DBGLOG(DBG, "Did not learn anything");
00890 
00891                 if (!complete()) {
00892                     // guess
00893                     currentDL++;
00894                     ID guess = getGuess();
00895                     DBGLOG(DBG, "Guess: " << litToString(guess));
00896                     decisionLiteralOfDecisionLevel[currentDL] = guess;
00897                     setFact(guess, currentDL);
00898                     flipped[guess.address] = 0;
00899                 }
00900             }
00901         }
00902         // add new nogoods
00903         loadAddedNogoods();
00904     }
00905     DBGLOG(DBG, "Got model");
00906 
00907     InterpretationPtr icp(new Interpretation(*interpretation));
00908     return icp;
00909 }
00910 
00911 Nogood CDNLSolver::getInconsistencyCause(InterpretationConstPtr explanationAtoms){
00912     throw GeneralError("Not implemented");
00913 }
00914 
00915 void CDNLSolver::addNogoodSet(const NogoodSet& ns, InterpretationConstPtr frozen)
00916 {
00917     throw GeneralError("Internal CDNL solver does not support incremental extension of the instance");
00918 }
00919 
00920 void CDNLSolver::addNogood(Nogood ng)
00921 {
00922     nogoodsToAdd.addNogood(ng);
00923 }
00924 
00925 
00926 std::vector<Nogood> CDNLSolver::getContradictoryNogoods()
00927 {
00928 
00929     std::vector<Nogood> ngg;
00930     BOOST_FOREACH (int idx, contradictoryNogoods) {
00931         ngg.push_back(nogoodset.getNogood(idx));
00932     }
00933     return ngg;
00934 }
00935 
00936 
00937 Nogood CDNLSolver::getCause(IDAddress adr)
00938 {
00939     return nogoodset.getNogood(cause[adr]);
00940 }
00941 
00942 
00943 DLVHEX_NAMESPACE_END
00944 
00945 // vim:expandtab:ts=4:sw=4:
00946 // mode: C++
00947 // End: