00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066 #ifndef MAXWALKSAT_H
00067 #define MAXWALKSAT_H
00068
00069 #include <cfloat>
00070 #include <unistd.h>
00071 #include <sys/time.h>
00072 #include <sys/resource.h>
00073 #include <cstring>
00074 #include <sstream>
00075 #include <fstream>
00076 #include "array.h"
00077 #include "timer.h"
00078 #include "util.h"
00079 #include "sat.h"
00080 #include "maxwalksatparams.h"
00081
00082 const bool mwsdebug = false;
00083
00094 class MaxWalkSat : public SAT
00095 {
00096 public:
00097
00101 MaxWalkSat(VariableState* state, int seed, const bool& trackClauseTrueCnts,
00102 MaxWalksatParams* params)
00103 : SAT(state, seed, trackClauseTrueCnts), printInfo_(true)
00104 {
00105 int numAtoms = state_->getNumAtoms();
00106
00107
00108 maxSteps_ = params->maxSteps;
00109 maxTries_ = params->maxTries;
00110 targetCost_ = params->targetCost;
00111 hard_ = params->hard;
00112
00113 state_->setBreakHardClauses(hard_);
00114 numSolutions_ = params->numSolutions;
00115 heuristic_ = params->heuristic;
00116 tabuLength_ = params->tabuLength;
00117 lazyLowState_ = params->lazyLowState;
00118
00119 saRatio_ = params->ssParams->saRatio;
00120 saTemp_ = params->ssParams->saTemp;
00121 lateSa_ = params->ssParams->lateSa;
00122
00123
00124 if (heuristic_ == TABU || heuristic_ == SS)
00125 changed_.growToSize(numAtoms + 1);
00126 numFlips_ = 0;
00127
00128
00129 numerator_ = 50;
00130 denominator_ = 100;
00131
00132 inBlock_ = -1;
00133 flipInBlock_ = NOVALUE;
00134
00135
00136 int idx = 0;
00137 pickcode[idx++] = &MaxWalkSat::pickRandom;
00138 pickcode[idx++] = &MaxWalkSat::pickBest;
00139 pickcode[idx++] = &MaxWalkSat::pickTabu;
00140 pickcode[idx++] = &MaxWalkSat::pickSS;
00141 }
00142
00146 ~MaxWalkSat()
00147 {
00148
00149
00150
00151
00152
00153
00154
00155 }
00156
00161 void init()
00162 {
00163
00164 if (heuristic_ == TABU || heuristic_ == SS)
00165 {
00166 int numAtoms = state_->getNumAtoms();
00167 if (changed_.size() != numAtoms + 1)
00168 {
00169 if (changed_.size() < numAtoms + 1)
00170 changed_.growToSize(numAtoms + 1);
00171 else
00172 changed_.shrinkToSize(numAtoms + 1);
00173 }
00174 for (int i = 1; i <= numAtoms; i++)
00175 changed_[i] = -(tabuLength_ + 1);
00176 }
00177 state_->initRandom();
00178 }
00179
00183 void infer()
00184 {
00185 int numtry = 0;
00186 int numsuccesstry = 0;
00187 long double lowCost = LDBL_MAX;
00188
00189
00190
00191
00192
00193
00194
00195
00196 while (numsuccesstry < numSolutions_ && numtry < maxTries_)
00197 {
00198 numtry++;
00199 numFlips_ = 0;
00200 long double tryLowCost = LDBL_MAX;
00201 int tryLowBad = INT_MAX;
00202 bool lowStateInThisTry = false;
00203 if (lazyLowState_)
00204 varsFlippedSinceLowState_.clear();
00205
00206
00207
00208 if (numtry > 1 && numsuccesstry == 0) init();
00209
00210 if (printInfo_ || mwsdebug)
00211 {
00212 cout << "\nIn the beginning of try " << numtry << ": " << endl;
00213 cout << "Number of clauses: " << state_->getNumClauses() << endl;
00214 cout << "Number of false clauses: " << state_->getNumFalseClauses()
00215 << endl;
00216 cout << "Cost of false clauses: " << state_->getCostOfFalseClauses()
00217 << endl;
00218 cout << "Target cost: " << targetCost_ << endl;
00219 }
00220
00221 while (numFlips_ < maxSteps_ && numsuccesstry < numSolutions_)
00222 {
00223 numFlips_++;
00224 flipAtom((this->*(pickcode[heuristic_]))());
00225
00226 if (inBlock_ > -1)
00227 {
00228 if (mwsdebug)
00229 {
00230 cout << "In block " << inBlock_ << ": flip atom " << flipInBlock_
00231 << endl;
00232 }
00233 flipAtom(flipInBlock_);
00234 }
00235
00236
00237 inBlock_ = -1;
00238 flipInBlock_ = NOVALUE;
00239
00240 long double costOfFalseClauses = state_->getCostOfFalseClauses();
00241
00242 if (costOfFalseClauses < tryLowCost)
00243 {
00244 tryLowCost = costOfFalseClauses;
00245 tryLowBad = state_->getNumFalseClauses();
00246 }
00247
00248
00249
00250
00251 if ((costOfFalseClauses <= targetCost_ + 0.0001 &&
00252 costOfFalseClauses <= lowCost) || (costOfFalseClauses < lowCost))
00253 {
00254 if (mwsdebug)
00255 {
00256 cout << "Cost of false clauses: " << costOfFalseClauses
00257 << " less than lowest cost: " << lowCost << endl;
00258 }
00259 lowCost = costOfFalseClauses;
00260 if (!lazyLowState_)
00261 state_->saveLowState();
00262 else
00263 {
00264 varsFlippedSinceLowState_.clear();
00265 lowStateInThisTry = true;
00266 }
00267 }
00268
00269
00270
00271
00272 if (costOfFalseClauses <= targetCost_ + 0.0001)
00273 numsuccesstry++;
00274 }
00275
00276 if (lowStateInThisTry)
00277 reconstructLowState();
00278 state_->saveLowStateToDB();
00279
00280 if (printInfo_ || mwsdebug)
00281 {
00282 cout<< "In the end of try " << numtry << ": " << endl;
00283 cout<< "Lowest num. of false clauses: " << tryLowBad << endl;
00284 cout<< "Lowest cost of false clauses: " << tryLowCost << endl;
00285 cout<< "Number of flips: " << numFlips_ << endl;
00286
00287 }
00288 }
00289
00290
00291 if (trackClauseTrueCnts_)
00292 tallyCntsFromState();
00293 }
00294
00295 const int getHeuristic()
00296 {
00297 return heuristic_;
00298 }
00299
00300 void setHeuristic(const int& heuristic)
00301 {
00302 heuristic_ = heuristic;
00303 }
00304
00305 int getMaxSteps()
00306 {
00307 return maxSteps_;
00308 }
00309
00310 void setMaxSteps(const int& maxSteps)
00311 {
00312 maxSteps_ = maxSteps;
00313 }
00314
00315 void setPrintInfo(const bool& printInfo)
00316 {
00317 printInfo_ = printInfo;
00318 }
00319
00320 const bool getPrintInfo()
00321 {
00322 return printInfo_;
00323 }
00324
00325 protected:
00326
00333 void flipAtom(int toFlip)
00334 {
00335
00336 if (toFlip == NOVALUE)
00337 return;
00338
00339
00340 state_->flipAtom(toFlip, inBlock_);
00341
00342 if (heuristic_ == TABU || heuristic_ == SS)
00343 {
00344 changed_.growToSize(state_->getNumAtoms() + 1, -(tabuLength_ + 1));
00345 changed_[toFlip] = numFlips_;
00346 }
00347
00348 if (lazyLowState_)
00349 {
00350
00351
00352
00353 if (varsFlippedSinceLowState_.find(toFlip) !=
00354 varsFlippedSinceLowState_.end())
00355 {
00356 if (mwsdebug)
00357 {
00358
00359
00360 }
00361 varsFlippedSinceLowState_.erase(toFlip);
00362 }
00363 else
00364 {
00365 if (mwsdebug)
00366 {
00367
00368
00369 }
00370 varsFlippedSinceLowState_.insert(toFlip);
00371 }
00372 }
00373
00374 }
00375
00382 int pickRandom()
00383 {
00384
00385 assert(inBlock_ == -1);
00386 int atomIdx = state_->getIndexOfAtomInRandomFalseClause();
00387 if (atomIdx == NOVALUE) return NOVALUE;
00388 if (state_->getImprovementByFlipping(atomIdx) == -LDBL_MAX) return NOVALUE;
00389
00390
00391 bool ignoreActivePreds = false;
00392 bool groundOnly = false;
00393 if (!state_->activateAtom(atomIdx, ignoreActivePreds, groundOnly))
00394 return NOVALUE;
00395
00396
00397 int blockIdx = state_->getBlockIndex(atomIdx - 1);
00398 if (blockIdx >= 0)
00399 {
00400
00401
00402 if (state_->getDomain()->getBlockEvidence(blockIdx) ||
00403 state_->getDomain()->getBlockSize(blockIdx) == 1)
00404 return NOVALUE;
00405 else
00406 {
00407
00408 int blockSize = state_->getDomain()->getBlockSize(blockIdx);
00409
00410 if (state_->getValueOfAtom(atomIdx) == 0)
00411 {
00412 for (int i = 0; i < blockSize; i++)
00413 {
00414 const Predicate* pred =
00415 state_->getDomain()->getPredInBlock(i, blockIdx);
00416 GroundPredicate* gndPred = new GroundPredicate((Predicate*)pred);
00417
00418 int idx = state_->getIndexOfGroundPredicate(gndPred);
00419
00420 delete gndPred;
00421 delete pred;
00422
00423
00424 if (idx >= 0)
00425 {
00426 if (state_->getValueOfAtom(idx + 1) == 1)
00427 {
00428 inBlock_ = blockIdx;
00429 flipInBlock_ = idx + 1;
00430 return atomIdx;
00431 }
00432 }
00433 }
00434 }
00435
00436 else
00437 {
00438 bool ok = false;
00439 while (!ok)
00440 {
00441 const Predicate* pred =
00442 state_->getDomain()->getRandomPredInBlock(blockIdx);
00443 GroundPredicate* gndPred = new GroundPredicate((Predicate*)pred);
00444
00445 int idx = state_->getIndexOfGroundPredicate(gndPred);
00446
00447 delete gndPred;
00448 delete pred;
00449
00450 if (idx + 1 != atomIdx)
00451 {
00452 inBlock_ = blockIdx;
00453 flipInBlock_ = idx + 1;
00454 return atomIdx;
00455 }
00456 }
00457 }
00458 }
00459 }
00460
00461 return atomIdx;
00462 }
00463
00470 int pickBest()
00471 {
00472
00473
00474 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00475 if (noisyPick)
00476 return pickRandom();
00477
00478 assert(inBlock_ == -1);
00479
00480 int toFix = state_->getRandomFalseClauseIndex();
00481 if (toFix == NOVALUE) return NOVALUE;
00482
00483 if (mwsdebug) cout << "Looking to fix clause " << toFix << endl;
00484
00485 int clauseSize = state_->getClauseSize(toFix);
00486 long double cost = state_->getClauseCost(toFix);
00487
00488 long double improvement;
00489
00490 Array<Array<int> > canNotFlip;
00491
00492
00493 Array<Array<int> > candidateBlockedVars;
00494 Array<Array<int> > othersToFlip;
00495 Array<int> blockIdx;
00496
00497 canNotFlip.growToSize(clauseSize);
00498 candidateBlockedVars.growToSize(clauseSize);
00499 othersToFlip.growToSize(clauseSize);
00500 blockIdx.growToSize(clauseSize);
00501
00502
00503 Array<int> best;
00504
00505 register int numbest = 0;
00506
00507 long double bestvalue = -LDBL_MAX;
00508
00509
00510 for (int i = 0; i < clauseSize; i++)
00511 {
00512 register int lit = state_->getAtomInClause(i, toFix);
00513
00514 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00515
00516 register int var = abs(lit);
00517
00518 if (state_->isFixedAtom(var)) continue;
00519 bool ignoreActivePreds = false;
00520 bool groundOnly = false;
00521 if (!state_->activateAtom(var, ignoreActivePreds, groundOnly))
00522 return NOVALUE;
00523
00524 improvement = calculateImprovement(var, canNotFlip[i],
00525 candidateBlockedVars[i],
00526 othersToFlip[i], blockIdx[i]);
00527 if (mwsdebug)
00528 cout << "Improvement of var " << var << " is: " << improvement << endl;
00529
00530 if (improvement > -LDBL_MAX && improvement >= bestvalue)
00531 {
00532 if (improvement > bestvalue)
00533 {
00534 numbest = 0;
00535 best.clear();
00536 }
00537 bestvalue = improvement;
00538 best.append(i);
00539 numbest++;
00540 }
00541 }
00542
00543
00544 if (numbest == 0) return NOVALUE;
00545
00546
00547 int toFlip = best[random()%numbest];
00548
00549
00550 if (numbest == 1)
00551 toFlip = best[0];
00552 int toFlipAtom = abs(state_->getAtomInClause(toFlip, toFix));
00553
00554 if (blockIdx[toFlip] > -1)
00555 {
00556
00557 if (canNotFlip[toFlip].contains(toFlipAtom))
00558 toFlipAtom = NOVALUE;
00559 else
00560 {
00561 int idx = candidateBlockedVars[toFlip].find(toFlipAtom);
00562 if (idx >= 0)
00563 {
00564 inBlock_ = blockIdx[toFlip];
00565 flipInBlock_ = othersToFlip[toFlip][idx];
00566 }
00567 }
00568 }
00569
00570
00571 return toFlipAtom;
00572 }
00573
00579 int pickTabu()
00580 {
00581
00582 assert(inBlock_ == -1);
00583
00584 int toFix = state_->getRandomFalseClauseIndex();
00585 if (toFix == NOVALUE)
00586 {
00587
00588 return NOVALUE;
00589 }
00590 if (mwsdebug) cout << "Looking to fix clause " << toFix << endl;
00591
00592 int clauseSize = state_->getClauseSize(toFix);
00593 long double cost = state_->getClauseCost(toFix);
00594
00595 long double improvement;
00596
00597 Array<Array<int> > canNotFlip;
00598
00599
00600 Array<Array<int> > candidateBlockedVars;
00601 Array<Array<int> > othersToFlip;
00602 Array<int> blockIdx;
00603
00604 canNotFlip.growToSize(clauseSize);
00605 candidateBlockedVars.growToSize(clauseSize);
00606 othersToFlip.growToSize(clauseSize);
00607 blockIdx.growToSize(clauseSize);
00608
00609
00610 Array<int> best;
00611
00612 register int numbest = 0;
00613
00614 long double bestvalue = -LDBL_MAX;
00615
00616
00617 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00618
00619
00620 if (noisyPick)
00621 {
00622 for (int i = 0; i < clauseSize; i++)
00623 {
00624 register int lit = state_->getAtomInClause(i, toFix);
00625
00626 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00627
00628 register int var = abs(lit);
00629
00630 if (state_->isFixedAtom(var)) continue;
00631 bool ignoreActivePreds = false;
00632 bool groundOnly = false;
00633 if (!state_->activateAtom(var, ignoreActivePreds, groundOnly))
00634 return NOVALUE;
00635
00636
00637 calculateImprovement(var, canNotFlip[i],
00638 candidateBlockedVars[i],
00639 othersToFlip[i], blockIdx[i]);
00640
00641 best.append(i);
00642 numbest++;
00643 }
00644 }
00645
00646 else for (int i = 0; i < clauseSize; i++)
00647 {
00648 register int lit = state_->getAtomInClause(i, toFix);
00649
00650 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00651
00652 register int var = abs(lit);
00653
00654 if (state_->isFixedAtom(var)) continue;
00655 bool ignoreActivePreds = false;
00656 bool groundOnly = false;
00657 if (!state_->activateAtom(var, ignoreActivePreds, groundOnly))
00658 return NOVALUE;
00659
00660 improvement = calculateImprovement(var, canNotFlip[i],
00661 candidateBlockedVars[i],
00662 othersToFlip[i], blockIdx[i]);
00663 if (mwsdebug)
00664 cout << "Improvement of var " << var << " is: " << improvement << endl;
00665
00666
00667 if (improvement > 0 && improvement >= bestvalue)
00668 {
00669 if (improvement > bestvalue)
00670 {
00671 numbest = 0;
00672 best.clear();
00673 }
00674 bestvalue = improvement;
00675 best.append(i);
00676 numbest++;
00677 }
00678 else if (improvement > -LDBL_MAX &&
00679 tabuLength_ < numFlips_ - changed_[var])
00680 {
00681 if (improvement >= bestvalue)
00682 {
00683 if (improvement > bestvalue)
00684 {
00685 numbest = 0;
00686 best.clear();
00687 }
00688 bestvalue = improvement;
00689 best.append(i);
00690 numbest++;
00691 }
00692 }
00693 }
00694
00695 if (numbest == 0)
00696 {
00697
00698 return NOVALUE;
00699 }
00700
00701 int toFlip = NOVALUE;
00702
00703 if (numbest == 1)
00704 toFlip = best[0];
00705 else
00706
00707 toFlip = best[random()%numbest];
00708 int toFlipAtom = abs(state_->getAtomInClause(toFlip, toFix));
00709
00710 if (blockIdx[toFlip] > -1)
00711 {
00712
00713 if (canNotFlip[toFlip].contains(toFlipAtom))
00714 toFlipAtom = NOVALUE;
00715 else
00716 {
00717 int idx = candidateBlockedVars[toFlip].find(toFlipAtom);
00718 if (idx >= 0)
00719 {
00720 inBlock_ = blockIdx[toFlip];
00721 flipInBlock_ = othersToFlip[toFlip][idx];
00722 }
00723 }
00724 }
00725
00726
00727 return toFlipAtom;
00728 }
00729
00736 int pickSS()
00737 {
00738
00739 assert(inBlock_ == -1);
00740 Array<int> canNotFlip;
00741
00742
00743 Array<int> candidateBlockedVars;
00744 Array<int> othersToFlip;
00745 int blockIdx;
00746
00747 long double costOfFalseClauses = state_->getCostOfFalseClauses();
00748
00749
00750
00751
00752
00753 if (costOfFalseClauses <= targetCost_ + 0.0001 ||
00754 (!lateSa_ && random() % 100 < saRatio_ ))
00755 {
00756
00757 int toFlip = state_->getIndexOfRandomAtom();
00758 if (toFlip == NOVALUE) return NOVALUE;
00759
00760 if (state_->isFixedAtom(toFlip)) return NOVALUE;
00761 bool ignoreActivePreds = false;
00762
00763 bool groundOnly = true;
00764 if (!state_->activateAtom(toFlip, ignoreActivePreds, groundOnly))
00765 return NOVALUE;
00766 long double improvement = calculateImprovement(toFlip, canNotFlip,
00767 candidateBlockedVars,
00768 othersToFlip, blockIdx);
00769 if (mwsdebug) cout << "Total improvement: " << improvement << endl;
00770
00771
00772
00773 if (improvement > -LDBL_MAX &&
00774 ((improvement >= 0) ||
00775 (random() <= exp(improvement/(saTemp_/100.0)) * RAND_MAX)))
00776 {
00777
00778 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00779 else
00780 {
00781 int idx = candidateBlockedVars.find(toFlip);
00782 if (idx >= 0)
00783 {
00784 inBlock_ = blockIdx;
00785 flipInBlock_ = othersToFlip[idx];
00786 }
00787 }
00788
00789
00790 if (toFlip != NOVALUE)
00791 {
00792 state_->setActive(toFlip);
00793 }
00794 return toFlip;
00795 }
00796 else
00797 {
00798 return NOVALUE;
00799 }
00800 }
00801
00802 else
00803 {
00804 return pickTabu();
00805 }
00806 }
00807
00808
00826 long double calculateImprovement(const int& atomIdx, Array<int>& canNotFlip,
00827 Array<int>& candidateBlockedVars,
00828 Array<int>& othersToFlip, int& blockIdx)
00829 {
00830 blockIdx = state_->getBlockIndex(atomIdx - 1);
00831 if (blockIdx == -1)
00832 {
00833
00834 return state_->getImprovementByFlipping(atomIdx);
00835 }
00836 else
00837 {
00838
00839
00840 if (state_->getDomain()->getBlockEvidence(blockIdx) ||
00841 state_->getDomain()->getBlockSize(blockIdx) == 1)
00842 {
00843 canNotFlip.append(atomIdx);
00844 return -LDBL_MAX;
00845 }
00846 else
00847 {
00848
00849 int blockSize = state_->getDomain()->getBlockSize(blockIdx);
00850 int chosen = -1;
00851 int otherToFlip = -1;
00852
00853
00854 if (state_->getValueOfAtom(atomIdx) == 0)
00855 {
00856 for (int i = 0; i < blockSize; i++)
00857 {
00858 const Predicate* pred =
00859 state_->getDomain()->getPredInBlock(i, blockIdx);
00860 GroundPredicate* gndPred = new GroundPredicate((Predicate*)pred);
00861
00862 int idx = state_->getIndexOfGroundPredicate(gndPred);
00863
00864 delete gndPred;
00865 delete pred;
00866
00867
00868 if (idx >= 0)
00869 {
00870 if (state_->getValueOfAtom(idx + 1) == 1)
00871 {
00872 chosen = idx + 1;
00873 break;
00874 }
00875 }
00876 }
00877 }
00878
00879
00880 else
00881 {
00882 bool ok = false;
00883 while (!ok)
00884 {
00885 const Predicate* pred =
00886 state_->getDomain()->getRandomPredInBlock(blockIdx);
00887 GroundPredicate* gndPred = new GroundPredicate((Predicate*)pred);
00888
00889 int idx = state_->getIndexOfGroundPredicate(gndPred);
00890 if (idx == -1)
00891 {
00892 delete gndPred;
00893 delete pred;
00894 continue;
00895
00896 }
00897 chosen = idx + 1;
00898
00899 delete gndPred;
00900 delete pred;
00901
00902 if (chosen != atomIdx)
00903 ok = true;
00904 }
00905 }
00906
00907 assert(chosen >= 0);
00908 candidateBlockedVars.append(atomIdx);
00909 otherToFlip = chosen;
00910 othersToFlip.append(otherToFlip);
00911 return (state_->getImprovementByFlipping(atomIdx) +
00912 state_->getImprovementByFlipping(otherToFlip));
00913 }
00914 }
00915 }
00916
00921 void reconstructLowState()
00922 {
00923 assert(lazyLowState_);
00924 if (mwsdebug) cout << "Reconstructing low state ..." << endl;
00925 hash_set<int>::const_iterator it = varsFlippedSinceLowState_.begin();
00926 for (; it != varsFlippedSinceLowState_.end(); it++)
00927 {
00928 if (mwsdebug)
00929 {
00930 cout << "Flipping atom " << (*it) << endl;
00931 }
00932 state_->flipAtomValue(*it, -1);
00933 }
00934 state_->saveLowState();
00935 if (mwsdebug) cout << "Done reconstructing low state ..." << endl;
00936 }
00937
00938 private:
00939
00941
00942 int heuristic_;
00943
00944 int tabuLength_;
00945
00946
00947
00948 int saRatio_;
00949
00950 int saTemp_;
00951
00952 bool lateSa_;
00953
00955
00956
00957
00958 int (MaxWalkSat::*pickcode[15])(void);
00959
00960 bool hard_;
00961
00962
00963 int numerator_;
00964 int denominator_;
00965
00966
00967 int inBlock_;
00968 int flipInBlock_;
00969
00970
00971
00972
00973
00974 bool lazyLowState_;
00975
00976
00977 hash_set<int> varsFlippedSinceLowState_;
00978
00979
00980 bool printInfo_;
00981 };
00982
00983 #endif