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 enum heuristics {RANDOM = 0, BEST = 1, TABU = 2, SS = 3};
00083 const bool mwsdebug = false;
00084
00095 class MaxWalkSat : public SAT
00096 {
00097 public:
00098
00102 MaxWalkSat(VariableState* state, int seed, const bool& trackClauseTrueCnts,
00103 MaxWalksatParams* params)
00104 : SAT(state, seed, trackClauseTrueCnts)
00105 {
00106 int numAtoms = state_->getNumAtoms();
00107
00108
00109 maxSteps_ = params->maxSteps;
00110 maxTries_ = params->maxTries;
00111 targetCost_ = params->targetCost;
00112 hard_ = params->hard;
00113 numSolutions_ = params->numSolutions;
00114 heuristic_ = params->heuristic;
00115 tabuLength_ = params->tabuLength;
00116 lazyLowState_ = params->lazyLowState;
00117
00118 saRatio_ = params->ssParams->saRatio;
00119 saTemp_ = params->ssParams->saTemp;
00120 lateSa_ = params->ssParams->lateSa;
00121
00122
00123 if (heuristic_ == TABU || heuristic_ == SS)
00124 changed_.growToSize(numAtoms + 1);
00125 numFlips_ = 0;
00126
00127
00128 numerator_ = 50;
00129 denominator_ = 100;
00130
00131 inBlock_ = false;
00132 flipInBlock_ = NOVALUE;
00133
00134
00135 int idx = 0;
00136 pickcode[idx++] = &MaxWalkSat::pickRandom;
00137 pickcode[idx++] = &MaxWalkSat::pickBest;
00138 pickcode[idx++] = &MaxWalkSat::pickTabu;
00139 pickcode[idx++] = &MaxWalkSat::pickSS;
00140 }
00141
00145 ~MaxWalkSat() { }
00146
00151 void init()
00152 {
00153
00154 if (heuristic_ == TABU || heuristic_ == SS)
00155 {
00156 int numAtoms = state_->getNumAtoms();
00157 if (changed_.size() != numAtoms + 1)
00158 {
00159 if (changed_.size() < numAtoms + 1)
00160 changed_.growToSize(numAtoms + 1);
00161 else
00162 changed_.shrinkToSize(numAtoms + 1);
00163 }
00164 for (int i = 1; i <= numAtoms; i++)
00165 changed_[i] = -(tabuLength_ + 1);
00166 }
00167 state_->initRandom();
00168 }
00169
00173 void infer()
00174 {
00175 int numtry = 0;
00176 int numsuccesstry = 0;
00177 long double lowCost = LDBL_MAX;
00178
00179
00180 if (trackClauseTrueCnts_)
00181 for (int clauseno = 0; clauseno < clauseTrueCnts_->size(); clauseno++)
00182 (*clauseTrueCnts_)[clauseno] = 0;
00183
00184
00185 while (numsuccesstry < numSolutions_ &&
00186 numtry < maxTries_*numSolutions_)
00187 {
00188 numtry++;
00189 numFlips_ = 0;
00190 bool lowStateInThisTry = false;
00191 if (lazyLowState_)
00192 varsFlippedSinceLowState_.clear();
00193
00194
00195
00196 if (numtry > 1 && numsuccesstry == 0) init();
00197
00198 if (mwsdebug)
00199 {
00200 cout << "\nIn the beginning of try " << numtry << ": " << endl;
00201 cout << "Number of clauses: " << state_->getNumClauses() << endl;
00202 cout << "Number of false clauses: " << state_->getNumFalseClauses()
00203 << endl;
00204 cout << "Cost of false clauses: " << state_->getCostOfFalseClauses()
00205 << endl;
00206 cout << "Target cost: " << targetCost_ << endl;
00207 }
00208
00209 while (numFlips_ < maxSteps_ && numsuccesstry < numSolutions_)
00210 {
00211 numFlips_++;
00212 flipAtom((this->*(pickcode[heuristic_]))());
00213
00214 if (inBlock_)
00215 flipAtom(flipInBlock_);
00216
00217
00218 inBlock_ = false;
00219 flipInBlock_ = NOVALUE;
00220
00221 long double costOfFalseClauses = state_->getCostOfFalseClauses();
00222
00223
00224
00225 if (costOfFalseClauses < lowCost)
00226 {
00227 if (mwsdebug)
00228 {
00229 cout << "Cost of false clauses: " << costOfFalseClauses
00230 << " less than lowest cost: " << lowCost << endl;
00231 }
00232 lowCost = costOfFalseClauses;
00233 if (!lazyLowState_)
00234 state_->saveLowState();
00235 else
00236 {
00237 varsFlippedSinceLowState_.clear();
00238 lowStateInThisTry = true;
00239 }
00240 }
00241
00242
00243
00244
00245 if (costOfFalseClauses <= targetCost_ + 0.0001)
00246 numsuccesstry++;
00247 }
00248
00249 if (lowStateInThisTry)
00250 reconstructLowState();
00251 state_->saveLowStateToDB();
00252
00253 if (mwsdebug)
00254 {
00255 cout<< "In the end of try " << numtry << ": " << endl;
00256 cout<< "Lowest num. of false clauses: " << state_->getLowBad() << endl;
00257 cout<< "Lowest cost of false clauses: " << state_->getLowCost() << endl;
00258 cout<< "Number of flips: " << numFlips_ << endl;
00259
00260 }
00261 }
00262
00263
00264 if (trackClauseTrueCnts_)
00265 state_->getNumClauseGndings(clauseTrueCnts_, true);
00266 }
00267
00268 const int getHeuristic()
00269 {
00270 return heuristic_;
00271 }
00272
00273 void setHeuristic(const int& heuristic)
00274 {
00275 heuristic_ = heuristic;
00276 }
00277
00278 int getMaxSteps()
00279 {
00280 return maxSteps_;
00281 }
00282
00283 void setMaxSteps(const int& maxSteps)
00284 {
00285 maxSteps_ = maxSteps;
00286 }
00287
00288 protected:
00289
00296 void flipAtom (int toFlip)
00297 {
00298
00299 if (toFlip == NOVALUE)
00300 return;
00301
00302
00303 state_->flipAtom(toFlip);
00304
00305 if (heuristic_ == TABU || heuristic_ == SS)
00306 {
00307 changed_[toFlip] = numFlips_;
00308 changed_.growToSize(state_->getNumAtoms(), -(tabuLength_ + 1));
00309 }
00310
00311 if (lazyLowState_)
00312 {
00313
00314
00315
00316 if (varsFlippedSinceLowState_.find(toFlip) !=
00317 varsFlippedSinceLowState_.end())
00318 {
00319 if (mwsdebug)
00320 {
00321
00322
00323 }
00324 varsFlippedSinceLowState_.erase(toFlip);
00325 }
00326 else
00327 {
00328 if (mwsdebug)
00329 {
00330
00331
00332 }
00333 varsFlippedSinceLowState_.insert(toFlip);
00334 }
00335 }
00336
00337 }
00338
00345 int pickRandom()
00346 {
00347
00348 assert(!inBlock_);
00349 int atomIdx = state_->getIndexOfAtomInRandomFalseClause();
00350 assert(atomIdx > 0);
00351
00352
00353 int blockIdx = state_->getBlockIndex(atomIdx - 1);
00354 if (blockIdx >= 0)
00355 {
00356
00357
00358 if (state_->isBlockEvidence(blockIdx) ||
00359 state_->getBlockSize(blockIdx) == 1)
00360 return NOVALUE;
00361 else
00362 {
00363
00364 Array<int>& block = state_->getBlockArray(blockIdx);
00365
00366 if (state_->getValueOfAtom(atomIdx) == 0)
00367 {
00368 for (int i = 0; i < block.size(); i++)
00369 {
00370 if (state_->getValueOfAtom(block[i] + 1) == 1)
00371 {
00372 inBlock_ = true;
00373 flipInBlock_ = block[i] + 1;
00374 return atomIdx;
00375 }
00376 }
00377 }
00378
00379
00380 else
00381 {
00382 bool ok = false;
00383 while (!ok)
00384 {
00385 int chosen = random() % block.size();
00386 if (block[chosen] + 1 != atomIdx)
00387 {
00388 inBlock_ = true;
00389 flipInBlock_ = block[chosen] + 1;
00390 return atomIdx;
00391 }
00392 }
00393 }
00394 }
00395 }
00396
00397 return atomIdx;
00398 }
00399
00406 int pickBest()
00407 {
00408
00409 assert(!inBlock_);
00410
00411 int toFix = state_->getRandomFalseClauseIndex();
00412 if (toFix == NOVALUE) return NOVALUE;
00413
00414 long double improvement;
00415
00416 Array<int> canNotFlip;
00417
00418
00419 Array<int> candidateBlockedVars;
00420 Array<int> othersToFlip;
00421
00422 int clauseSize = state_->getClauseSize(toFix);
00423 long double cost = state_->getClauseCost(toFix);
00424
00425 Array<int> best;
00426
00427 register int numbest = 0;
00428
00429 long double bestvalue = -LDBL_MAX;
00430
00431 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00432
00433
00434 for (int i = 0; i < clauseSize; i++)
00435 {
00436 register int lit = state_->getAtomInClause(i, toFix);
00437
00438 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00439
00440 register int var = abs(lit);
00441
00442 improvement = calculateImprovement(var, canNotFlip,
00443 candidateBlockedVars,
00444 othersToFlip);
00445
00446 if (improvement >= bestvalue)
00447 {
00448 if (improvement > bestvalue)
00449 {
00450 numbest = 0;
00451 best.clear();
00452 }
00453 bestvalue = improvement;
00454 best.append(var);
00455 numbest++;
00456 }
00457 }
00458
00459
00460 if (numbest == 0) return NOVALUE;
00461
00462
00463 int toFlip = best[random()%numbest];
00464
00465
00466
00467 if (bestvalue <= 0 && noisyPick)
00468 {
00469 if (cost > 0)
00470 toFlip = abs(state_->getRandomAtomInClause(toFix));
00471 else
00472 toFlip = state_->getRandomTrueLitInClause(toFix);
00473 }
00474
00475 else if (numbest == 1)
00476 toFlip = best[0];
00477
00478
00479 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00480 else
00481 {
00482 int idx = candidateBlockedVars.find(toFlip);
00483 if (idx >= 0)
00484 {
00485 inBlock_ = true;
00486 flipInBlock_ = othersToFlip[idx];
00487 }
00488 }
00489
00490
00491 return toFlip;
00492 }
00493
00499 int pickTabu()
00500 {
00501
00502 assert(!inBlock_);
00503
00504 int toFix = state_->getRandomFalseClauseIndex();
00505 if (toFix == NOVALUE)
00506 {
00507
00508 return NOVALUE;
00509 }
00510
00511 long double improvement;
00512 Array<int> canNotFlip;
00513
00514
00515 Array<int> candidateBlockedVars;
00516 Array<int> othersToFlip;
00517
00518 int clauseSize = state_->getClauseSize(toFix);
00519 long double cost = state_->getClauseCost(toFix);
00520
00521
00522 Array<int> best;
00523
00524 register int numbest = 0;
00525
00526 long double bestvalue = -LDBL_MAX;
00527
00528
00529 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00530
00531 for (int i = 0; i < clauseSize; i++)
00532 {
00533 register int lit = state_->getAtomInClause(i, toFix);
00534
00535 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00536
00537 register int var = abs(lit);
00538
00539 improvement = calculateImprovement(var, canNotFlip, candidateBlockedVars,
00540 othersToFlip);
00541
00542
00543 if (improvement > 0 && improvement >= bestvalue)
00544 {
00545 if (improvement > bestvalue)
00546 {
00547 numbest = 0;
00548 best.clear();
00549 }
00550 bestvalue = improvement;
00551 best.append(var);
00552 numbest++;
00553 }
00554 else if (tabuLength_ < numFlips_ - changed_[var])
00555 {
00556 if (noisyPick && bestvalue <= 0)
00557 {
00558 best.append(var);
00559 numbest++;
00560 }
00561 else if (improvement >= bestvalue)
00562 {
00563 if (improvement > bestvalue)
00564 {
00565 numbest = 0;
00566 best.clear();
00567 }
00568 bestvalue = improvement;
00569 best.append(var);
00570 numbest++;
00571 }
00572 }
00573 }
00574
00575 if (numbest == 0)
00576 {
00577
00578 return NOVALUE;
00579 }
00580
00581 int toFlip = NOVALUE;
00582
00583 if (numbest == 1)
00584 toFlip = best[0];
00585 else
00586
00587 toFlip = best[random()%numbest];
00588
00589
00590
00591 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00592 else
00593 {
00594 int idx = candidateBlockedVars.find(toFlip);
00595 if (idx >= 0)
00596 {
00597 inBlock_ = true;
00598 flipInBlock_ = othersToFlip[idx];
00599 }
00600 }
00601
00602
00603 return toFlip;
00604 }
00605
00612 int pickSS()
00613 {
00614
00615 assert(!inBlock_);
00616 Array<int> canNotFlip;
00617
00618
00619 Array<int> candidateBlockedVars;
00620 Array<int> othersToFlip;
00621 long double costOfFalseClauses = state_->getCostOfFalseClauses();
00622
00623
00624
00625
00626
00627 if (costOfFalseClauses <= targetCost_ + 0.0001 ||
00628 (random() % 100 < saRatio_ && !lateSa_))
00629 {
00630
00631 int toFlip = state_->getIndexOfRandomAtom();
00632 if (toFlip == NOVALUE) return NOVALUE;
00633 long double improvement = calculateImprovement(toFlip, canNotFlip,
00634 candidateBlockedVars,
00635 othersToFlip);
00636
00637
00638
00639 if ((improvement >= 0) ||
00640 (random() <= exp(improvement/(saTemp_/100.0)) * RAND_MAX))
00641 {
00642
00643 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00644 else
00645 {
00646 int idx = candidateBlockedVars.find(toFlip);
00647 if (idx >= 0)
00648 {
00649 inBlock_ = true;
00650 flipInBlock_ = othersToFlip[idx];
00651 }
00652 }
00653 return toFlip;
00654 }
00655 else
00656 {
00657 return NOVALUE;
00658 }
00659 }
00660
00661 else
00662 {
00663 return pickTabu();
00664 }
00665 }
00666
00667
00683 long double calculateImprovement(const int& atomIdx, Array<int>& canNotFlip,
00684 Array<int>& candidateBlockedVars,
00685 Array<int>& othersToFlip)
00686 {
00687 int blockIdx = state_->getBlockIndex(atomIdx - 1);
00688 if (blockIdx == -1)
00689 {
00690
00691 return state_->getImprovementByFlipping(atomIdx);
00692 }
00693
00694 else
00695 {
00696
00697
00698 if (state_->isBlockEvidence(blockIdx) ||
00699 state_->getBlockSize(blockIdx) == 1)
00700 {
00701 canNotFlip.append(atomIdx);
00702 return -LDBL_MAX;
00703 }
00704 else
00705 {
00706
00707 Array<int>& block = state_->getBlockArray(blockIdx);
00708 int chosen = -1;
00709 int otherToFlip = -1;
00710
00711
00712 if (state_->getValueOfAtom(atomIdx) == 0)
00713 {
00714 if (mwsdebug)
00715 {
00716 cout << "0->1 atom " << atomIdx << endl;
00717 for (int i = 0; i < block.size(); i++)
00718 {
00719 cout << "Atom in block " << block[i] + 1 << " ";
00720 cout << state_->getValueOfAtom(block[i] + 1) << endl;
00721 }
00722 }
00723
00724 for (int i = 0; i < block.size(); i++)
00725 {
00726 if (state_->getValueOfAtom(block[i] + 1) == 1)
00727 {
00728 chosen = i;
00729 break;
00730 }
00731 }
00732 }
00733
00734
00735 else
00736 {
00737 if (mwsdebug)
00738 {
00739 cout << "1->0 atom " << atomIdx << endl;
00740 for (int i = 0; i < block.size(); i++)
00741 {
00742 cout << "Atom in block " << block[i] + 1 << " ";
00743 cout << state_->getValueOfAtom(block[i] + 1) << endl;
00744 }
00745 }
00746 bool ok = false;
00747 while (!ok)
00748 {
00749 chosen = random() % block.size();
00750 if (block[chosen] + 1 != atomIdx)
00751 ok = true;
00752 }
00753 }
00754
00755 assert(chosen >= 0);
00756 candidateBlockedVars.append(atomIdx);
00757 otherToFlip = block[chosen] + 1;
00758 othersToFlip.append(otherToFlip);
00759 return (state_->getImprovementByFlipping(atomIdx) +
00760 state_->getImprovementByFlipping(otherToFlip));
00761
00762 }
00763 }
00764 }
00765
00770 void reconstructLowState()
00771 {
00772 assert(lazyLowState_);
00773 if (mwsdebug) cout << "Reconstructing low state ..." << endl;
00774 hash_set<int>::const_iterator it = varsFlippedSinceLowState_.begin();
00775 for (; it != varsFlippedSinceLowState_.end(); it++)
00776 {
00777 if (mwsdebug)
00778 {
00779 cout << "Flipping atom " << (*it) << endl;
00780 }
00781 state_->flipAtomValue(*it);
00782 }
00783 state_->saveLowState();
00784 if (mwsdebug) cout << "Done reconstructing low state ..." << endl;
00785 }
00786
00787 private:
00788
00790
00791 int heuristic_;
00792
00793 int tabuLength_;
00794
00795
00796
00797 int saRatio_;
00798
00799 int saTemp_;
00800
00801 bool lateSa_;
00802
00804
00805
00806
00807 int (MaxWalkSat::*pickcode[15])(void);
00808
00809 bool hard_;
00810
00811
00812 int numerator_;
00813 int denominator_;
00814
00815
00816 bool inBlock_;
00817 int flipInBlock_;
00818
00819
00820
00821
00822
00823 bool lazyLowState_;
00824
00825
00826 hash_set<int> varsFlippedSinceLowState_;
00827 };
00828
00829 #endif