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 protected:
00279
00286 void flipAtom (int toFlip)
00287 {
00288
00289 if (toFlip == NOVALUE)
00290 return;
00291
00292
00293 state_->flipAtom(toFlip);
00294
00295 if (heuristic_ == TABU || heuristic_ == SS)
00296 {
00297 changed_[toFlip] = numFlips_;
00298 changed_.growToSize(state_->getNumAtoms(), -(tabuLength_ + 1));
00299 }
00300
00301 if (lazyLowState_)
00302 {
00303
00304
00305
00306 if (varsFlippedSinceLowState_.find(toFlip) !=
00307 varsFlippedSinceLowState_.end())
00308 {
00309 if (mwsdebug)
00310 {
00311
00312
00313 }
00314 varsFlippedSinceLowState_.erase(toFlip);
00315 }
00316 else
00317 {
00318 if (mwsdebug)
00319 {
00320
00321
00322 }
00323 varsFlippedSinceLowState_.insert(toFlip);
00324 }
00325 }
00326
00327 }
00328
00335 int pickRandom()
00336 {
00337
00338 assert(!inBlock_);
00339 int atomIdx = state_->getIndexOfAtomInRandomFalseClause();
00340 assert(atomIdx > 0);
00341
00342
00343 int blockIdx = state_->getBlockIndex(atomIdx - 1);
00344 if (blockIdx >= 0)
00345 {
00346
00347
00348 if (state_->isBlockEvidence(blockIdx) ||
00349 state_->getBlockSize(blockIdx) == 1)
00350 return NOVALUE;
00351 else
00352 {
00353
00354 Array<int>& block = state_->getBlockArray(blockIdx);
00355
00356 if (state_->getValueOfAtom(atomIdx) == 0)
00357 {
00358 for (int i = 0; i < block.size(); i++)
00359 {
00360 if (state_->getValueOfAtom(block[i] + 1) == 1)
00361 {
00362 inBlock_ = true;
00363 flipInBlock_ = block[i] + 1;
00364 return atomIdx;
00365 }
00366 }
00367 }
00368
00369
00370 else
00371 {
00372 bool ok = false;
00373 while (!ok)
00374 {
00375 int chosen = random() % block.size();
00376 if (block[chosen] + 1 != atomIdx)
00377 {
00378 inBlock_ = true;
00379 flipInBlock_ = block[chosen] + 1;
00380 return atomIdx;
00381 }
00382 }
00383 }
00384 }
00385 }
00386
00387 return atomIdx;
00388 }
00389
00396 int pickBest()
00397 {
00398
00399 assert(!inBlock_);
00400
00401 int toFix = state_->getRandomFalseClauseIndex();
00402 if (toFix == NOVALUE) return NOVALUE;
00403
00404 long double improvement;
00405
00406 Array<int> canNotFlip;
00407
00408
00409 Array<int> candidateBlockedVars;
00410 Array<int> othersToFlip;
00411
00412 int clauseSize = state_->getClauseSize(toFix);
00413 long double cost = state_->getClauseCost(toFix);
00414
00415 Array<int> best;
00416
00417 register int numbest = 0;
00418
00419 long double bestvalue = -LDBL_MAX;
00420
00421 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00422
00423
00424 for (int i = 0; i < clauseSize; i++)
00425 {
00426 register int lit = state_->getAtomInClause(i, toFix);
00427
00428 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00429
00430 register int var = abs(lit);
00431
00432 improvement = calculateImprovement(var, canNotFlip,
00433 candidateBlockedVars,
00434 othersToFlip);
00435
00436 if (improvement >= bestvalue)
00437 {
00438 if (improvement > bestvalue)
00439 {
00440 numbest = 0;
00441 best.clear();
00442 }
00443 bestvalue = improvement;
00444 best.append(var);
00445 numbest++;
00446 }
00447 }
00448
00449
00450 if (numbest == 0) return NOVALUE;
00451
00452
00453 int toFlip = best[random()%numbest];
00454
00455
00456
00457 if (bestvalue <= 0 && noisyPick)
00458 {
00459 if (cost > 0)
00460 toFlip = abs(state_->getRandomAtomInClause(toFix));
00461 else
00462 toFlip = state_->getRandomTrueLitInClause(toFix);
00463 }
00464
00465 else if (numbest == 1)
00466 toFlip = best[0];
00467
00468
00469 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00470 else
00471 {
00472 int idx = candidateBlockedVars.find(toFlip);
00473 if (idx >= 0)
00474 {
00475 inBlock_ = true;
00476 flipInBlock_ = othersToFlip[idx];
00477 }
00478 }
00479
00480
00481 return toFlip;
00482 }
00483
00489 int pickTabu()
00490 {
00491
00492 assert(!inBlock_);
00493
00494 int toFix = state_->getRandomFalseClauseIndex();
00495 if (toFix == NOVALUE)
00496 {
00497
00498 return NOVALUE;
00499 }
00500
00501 long double improvement;
00502 Array<int> canNotFlip;
00503
00504
00505 Array<int> candidateBlockedVars;
00506 Array<int> othersToFlip;
00507
00508 int clauseSize = state_->getClauseSize(toFix);
00509 long double cost = state_->getClauseCost(toFix);
00510
00511
00512 Array<int> best;
00513
00514 register int numbest = 0;
00515
00516 long double bestvalue = -LDBL_MAX;
00517
00518
00519 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_);
00520
00521 for (int i = 0; i < clauseSize; i++)
00522 {
00523 register int lit = state_->getAtomInClause(i, toFix);
00524
00525 if (cost < 0 && !state_->isTrueLiteral(lit)) continue;
00526
00527 register int var = abs(lit);
00528
00529 improvement = calculateImprovement(var, canNotFlip, candidateBlockedVars,
00530 othersToFlip);
00531
00532
00533 if (improvement > 0 && improvement >= bestvalue)
00534 {
00535 if (improvement > bestvalue)
00536 {
00537 numbest = 0;
00538 best.clear();
00539 }
00540 bestvalue = improvement;
00541 best.append(var);
00542 numbest++;
00543 }
00544 else if (tabuLength_ < numFlips_ - changed_[var])
00545 {
00546 if (noisyPick && bestvalue <= 0)
00547 {
00548 best.append(var);
00549 numbest++;
00550 }
00551 else if (improvement >= bestvalue)
00552 {
00553 if (improvement > bestvalue)
00554 {
00555 numbest = 0;
00556 best.clear();
00557 }
00558 bestvalue = improvement;
00559 best.append(var);
00560 numbest++;
00561 }
00562 }
00563 }
00564
00565 if (numbest == 0)
00566 {
00567
00568 return NOVALUE;
00569 }
00570
00571 int toFlip = NOVALUE;
00572
00573 if (numbest == 1)
00574 toFlip = best[0];
00575 else
00576
00577 toFlip = best[random()%numbest];
00578
00579
00580
00581 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00582 else
00583 {
00584 int idx = candidateBlockedVars.find(toFlip);
00585 if (idx >= 0)
00586 {
00587 inBlock_ = true;
00588 flipInBlock_ = othersToFlip[idx];
00589 }
00590 }
00591
00592
00593 return toFlip;
00594 }
00595
00602 int pickSS()
00603 {
00604
00605 assert(!inBlock_);
00606 Array<int> canNotFlip;
00607
00608
00609 Array<int> candidateBlockedVars;
00610 Array<int> othersToFlip;
00611 long double costOfFalseClauses = state_->getCostOfFalseClauses();
00612
00613
00614
00615
00616
00617 if (costOfFalseClauses <= targetCost_ + 0.0001 ||
00618 (random() % 100 < saRatio_ && !lateSa_))
00619 {
00620
00621 int toFlip = state_->getIndexOfRandomAtom();
00622 if (toFlip == NOVALUE) return NOVALUE;
00623 long double improvement = calculateImprovement(toFlip, canNotFlip,
00624 candidateBlockedVars,
00625 othersToFlip);
00626
00627
00628
00629 if ((improvement >= 0) ||
00630 (random() <= exp(improvement/(saTemp_/100.0)) * RAND_MAX))
00631 {
00632
00633 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE;
00634 else
00635 {
00636 int idx = candidateBlockedVars.find(toFlip);
00637 if (idx >= 0)
00638 {
00639 inBlock_ = true;
00640 flipInBlock_ = othersToFlip[idx];
00641 }
00642 }
00643 return toFlip;
00644 }
00645 else
00646 {
00647 return NOVALUE;
00648 }
00649 }
00650
00651 else
00652 {
00653 return pickTabu();
00654 }
00655 }
00656
00657
00673 long double calculateImprovement(const int& atomIdx, Array<int>& canNotFlip,
00674 Array<int>& candidateBlockedVars,
00675 Array<int>& othersToFlip)
00676 {
00677 int blockIdx = state_->getBlockIndex(atomIdx - 1);
00678 if (blockIdx == -1)
00679 {
00680
00681 return state_->getImprovementByFlipping(atomIdx);
00682 }
00683
00684 else
00685 {
00686
00687
00688 if (state_->isBlockEvidence(blockIdx) ||
00689 state_->getBlockSize(blockIdx) == 1)
00690 {
00691 canNotFlip.append(atomIdx);
00692 return -LDBL_MAX;
00693 }
00694 else
00695 {
00696
00697 Array<int>& block = state_->getBlockArray(blockIdx);
00698 int chosen = -1;
00699 int otherToFlip = -1;
00700
00701
00702 if (state_->getValueOfAtom(atomIdx) == 0)
00703 {
00704 if (mwsdebug)
00705 {
00706 cout << "0->1 atom " << atomIdx << endl;
00707 for (int i = 0; i < block.size(); i++)
00708 {
00709 cout << "Atom in block " << block[i] + 1 << " ";
00710 cout << state_->getValueOfAtom(block[i] + 1) << endl;
00711 }
00712 }
00713
00714 for (int i = 0; i < block.size(); i++)
00715 {
00716 if (state_->getValueOfAtom(block[i] + 1) == 1)
00717 {
00718 chosen = i;
00719 break;
00720 }
00721 }
00722 }
00723
00724
00725 else
00726 {
00727 if (mwsdebug)
00728 {
00729 cout << "1->0 atom " << atomIdx << endl;
00730 for (int i = 0; i < block.size(); i++)
00731 {
00732 cout << "Atom in block " << block[i] + 1 << " ";
00733 cout << state_->getValueOfAtom(block[i] + 1) << endl;
00734 }
00735 }
00736 bool ok = false;
00737 while (!ok)
00738 {
00739 chosen = random() % block.size();
00740 if (block[chosen] + 1 != atomIdx)
00741 ok = true;
00742 }
00743 }
00744
00745 assert(chosen >= 0);
00746 candidateBlockedVars.append(atomIdx);
00747 otherToFlip = block[chosen] + 1;
00748 othersToFlip.append(otherToFlip);
00749 return (state_->getImprovementByFlipping(atomIdx) +
00750 state_->getImprovementByFlipping(otherToFlip));
00751
00752 }
00753 }
00754 }
00755
00760 void reconstructLowState()
00761 {
00762 assert(lazyLowState_);
00763 if (mwsdebug) cout << "Reconstructing low state ..." << endl;
00764 hash_set<int>::const_iterator it = varsFlippedSinceLowState_.begin();
00765 for (; it != varsFlippedSinceLowState_.end(); it++)
00766 {
00767 if (mwsdebug)
00768 {
00769 cout << "Flipping atom " << (*it) << endl;
00770 }
00771 state_->flipAtomValue(*it);
00772 }
00773 state_->saveLowState();
00774 if (mwsdebug) cout << "Done reconstructing low state ..." << endl;
00775 }
00776
00777 private:
00778
00780
00781 int heuristic_;
00782
00783 int tabuLength_;
00784
00785
00786
00787 int saRatio_;
00788
00789 int saTemp_;
00790
00791 bool lateSa_;
00792
00794
00795
00796
00797 int (MaxWalkSat::*pickcode[15])(void);
00798
00799 bool hard_;
00800
00801
00802 int numerator_;
00803 int denominator_;
00804
00805
00806 bool inBlock_;
00807 int flipInBlock_;
00808
00809
00810
00811
00812
00813 bool lazyLowState_;
00814
00815
00816 hash_set<int> varsFlippedSinceLowState_;
00817 };
00818
00819 #endif