dlvhex
2.5.0
|
00001 /* dlvhex -- Answer-Set Programming with external interfaces. 00002 * Copyright (C) 2005-2007 Roman Schindlauer 00003 * Copyright (C) 2006-2015 Thomas Krennwallner 00004 * Copyright (C) 2009-2016 Peter Schüller 00005 * Copyright (C) 2011-2016 Christoph Redl 00006 * Copyright (C) 2015-2016 Tobias Kaminski 00007 * Copyright (C) 2015-2016 Antonius Weinzierl 00008 * 00009 * This file is part of dlvhex. 00010 * 00011 * dlvhex is free software; you can redistribute it and/or modify it 00012 * under the terms of the GNU Lesser General Public License as 00013 * published by the Free Software Foundation; either version 2.1 of 00014 * the License, or (at your option) any later version. 00015 * 00016 * dlvhex is distributed in the hope that it will be useful, but 00017 * WITHOUT ANY WARRANTY; without even the implied warranty of 00018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00019 * Lesser General Public License for more details. 00020 * 00021 * You should have received a copy of the GNU Lesser General Public 00022 * License along with dlvhex; if not, write to the Free Software 00023 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 00024 * 02110-1301 USA. 00025 */ 00026 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: