#include <maxwalksat.h>
Inheritance diagram for MaxWalkSat:
Public Member Functions | |
MaxWalkSat (VariableState *state, int seed, const bool &trackClauseTrueCnts, MaxWalksatParams *params) | |
Constructor: user-set parameters are set. | |
~MaxWalkSat () | |
Destructor (destructors from superclasses are called). | |
void | init () |
Initializes the MaxWalkSat algorithm. | |
void | infer () |
Performs the given number of MaxWalkSat inference tries. | |
const int | getHeuristic () |
void | setHeuristic (const int &heuristic) |
int | getMaxSteps () |
void | setMaxSteps (const int &maxSteps) |
Protected Member Functions | |
void | flipAtom (int toFlip) |
Flips the truth value of an atom and marks this iteration as the last time it was flipped. | |
int | pickRandom () |
Pick a random atom in a random unsatisfied pos. | |
int | pickBest () |
Pick the best atom (clauses made satisfied - clauses made unsatisfied) in a random unsatisfied clause. | |
int | pickTabu () |
Pick an atom from a random unsatisfied clause based on the tabu heuristic. | |
int | pickSS () |
Pick an atom according to the SampleSat heuristic. | |
long double | calculateImprovement (const int &atomIdx, Array< int > &canNotFlip, Array< int > &candidateBlockedVars, Array< int > &othersToFlip) |
Calculates the improvement (makecost - breakcost) by flipping an atom. | |
void | reconstructLowState () |
Reconstructs the state with the lowest cost by flipping atoms back to their value in this state. |
This code is based on the MaxWalkSat package of Kautz et al. and SampleSat by Wei et al.
Walksat is achieved by using unit weights (1 and -1) in the clauses in the state and setting the target cost to 0.
SampleSat is achieved by using unit weights (1 and -1) in the clauses in the state and setting the target cost to 0 and the heuristic to SS.
Definition at line 95 of file maxwalksat.h.
void MaxWalkSat::init | ( | ) | [inline, virtual] |
Initializes the MaxWalkSat algorithm.
A random assignment is given to the atoms and the state is initialized.
Implements Inference.
Definition at line 151 of file maxwalksat.h.
References SAT::changed_, VariableState::getNumAtoms(), Array< Type >::growToSize(), VariableState::initRandom(), Array< Type >::shrinkToSize(), Array< Type >::size(), and Inference::state_.
Referenced by infer(), SimulatedTempering::init(), MCSAT::init(), and GibbsSampler::init().
00152 { 00153 // Init changed array if using tabu 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 }
void MaxWalkSat::flipAtom | ( | int | toFlip | ) | [inline, protected] |
Flips the truth value of an atom and marks this iteration as the last time it was flipped.
toFlip | Index of atom to flip. |
Definition at line 296 of file maxwalksat.h.
References SAT::changed_, VariableState::flipAtom(), VariableState::getNumAtoms(), Array< Type >::growToSize(), SAT::numFlips_, and Inference::state_.
Referenced by infer().
00297 { 00298 //if (mwsdebug) cout << "Entering MaxWalkSat::flipAtom" << endl; 00299 if (toFlip == NOVALUE) 00300 return; 00301 00302 // Flip the atom in the state 00303 state_->flipAtom(toFlip); 00304 // Mark this flip as last time atom was changed if tabu is used 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 // Mark this variable as flipped since last low state. If already 00314 // present, then it has been flipped back to its value in the low 00315 // state and we can remove it. 00316 if (varsFlippedSinceLowState_.find(toFlip) != 00317 varsFlippedSinceLowState_.end()) 00318 { 00319 if (mwsdebug) 00320 { 00321 //cout << "Atom " << toFlip << " has been flipped since low state, " 00322 // << "so removing it" << endl; 00323 } 00324 varsFlippedSinceLowState_.erase(toFlip); 00325 } 00326 else 00327 { 00328 if (mwsdebug) 00329 { 00330 //cout << "Atom " << toFlip << " not flipped since low state, " 00331 // << "so adding it" << endl; 00332 } 00333 varsFlippedSinceLowState_.insert(toFlip); 00334 } 00335 } 00336 //if (mwsdebug) cout << "Leaving MaxWalkSat::flipAtom" << endl; 00337 }
int MaxWalkSat::pickRandom | ( | ) | [inline, protected] |
Pick a random atom in a random unsatisfied pos.
clause or a random true literal in a random satsified neg. clause to flip.
Definition at line 345 of file maxwalksat.h.
References VariableState::getBlockArray(), VariableState::getBlockIndex(), VariableState::getBlockSize(), VariableState::getIndexOfAtomInRandomFalseClause(), VariableState::getValueOfAtom(), VariableState::isBlockEvidence(), Array< Type >::size(), and Inference::state_.
Referenced by MaxWalkSat().
00346 { 00347 //if (mwsdebug) cout << "Entering MaxWalkSat::pickRandom" << endl; 00348 assert(!inBlock_); 00349 int atomIdx = state_->getIndexOfAtomInRandomFalseClause(); 00350 assert(atomIdx > 0); 00351 00352 // If atom is in a block, then another one has to be picked 00353 int blockIdx = state_->getBlockIndex(atomIdx - 1); 00354 if (blockIdx >= 0) 00355 { 00356 // Atom is in a block 00357 // If evidence atom exists or in block of size 1, then can not flip 00358 if (state_->isBlockEvidence(blockIdx) || 00359 state_->getBlockSize(blockIdx) == 1) 00360 return NOVALUE; 00361 else 00362 { 00363 //Dealing with atom in a block 00364 Array<int>& block = state_->getBlockArray(blockIdx); 00365 // 0->1: choose atom in block which is already 1 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 // 1->0: choose to flip the other randomly 00379 // TODO: choose to flip the other with best improvement 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 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickRandom" << endl; 00397 return atomIdx; 00398 }
int MaxWalkSat::pickBest | ( | ) | [inline, protected] |
Pick the best atom (clauses made satisfied - clauses made unsatisfied) in a random unsatisfied clause.
Definition at line 406 of file maxwalksat.h.
References Array< Type >::append(), calculateImprovement(), Array< Type >::clear(), Array< Type >::contains(), Array< Type >::find(), VariableState::getAtomInClause(), VariableState::getClauseCost(), VariableState::getClauseSize(), VariableState::getRandomAtomInClause(), VariableState::getRandomFalseClauseIndex(), VariableState::getRandomTrueLitInClause(), and Inference::state_.
Referenced by MaxWalkSat().
00407 { 00408 //if (mwsdebug) cout << "Entering MaxWalkSat::pickBest" << endl; 00409 assert(!inBlock_); 00410 // Clause to fix picked at random 00411 int toFix = state_->getRandomFalseClauseIndex(); 00412 if (toFix == NOVALUE) return NOVALUE; 00413 00414 long double improvement; 00415 00416 Array<int> canNotFlip; 00417 // If var in candidateBlockedVars is chosen, then 00418 // corresponding var in othersToFlip is flipped as well 00419 Array<int> candidateBlockedVars; 00420 Array<int> othersToFlip; 00421 00422 int clauseSize = state_->getClauseSize(toFix); 00423 long double cost = state_->getClauseCost(toFix); 00424 // Holds the best atoms so far 00425 Array<int> best; 00426 // How many are tied for best 00427 register int numbest = 0; 00428 // Best value so far 00429 long double bestvalue = -LDBL_MAX; 00430 // With prob. do a noisy pick 00431 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_); 00432 00433 // Look at each atom and pick best ones 00434 for (int i = 0; i < clauseSize; i++) 00435 { 00436 register int lit = state_->getAtomInClause(i, toFix); 00437 // Neg. clause: Only look at true literals 00438 if (cost < 0 && !state_->isTrueLiteral(lit)) continue; 00439 // var is the index of the atom 00440 register int var = abs(lit); 00441 00442 improvement = calculateImprovement(var, canNotFlip, 00443 candidateBlockedVars, 00444 othersToFlip); 00445 00446 if (improvement >= bestvalue) 00447 { // Tied or better than previous best 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 // If only false literals in a neg. clause, then numbest is 0 00460 if (numbest == 0) return NOVALUE; 00461 // Choose one of the best at random 00462 // (default if none of the following 2 cases occur) 00463 int toFlip = best[random()%numbest]; 00464 00465 // 1. If no improvement by best, 00466 // then with prob. choose a random atom 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 // 2. Exactly one best atom 00475 else if (numbest == 1) 00476 toFlip = best[0]; 00477 00478 // If atom can not be flipped, then null flip 00479 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00480 else 00481 { // If toFlip is in block, then set other to flip 00482 int idx = candidateBlockedVars.find(toFlip); 00483 if (idx >= 0) 00484 { 00485 inBlock_ = true; 00486 flipInBlock_ = othersToFlip[idx]; 00487 } 00488 } 00489 00490 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickBest" << endl; 00491 return toFlip; 00492 }
int MaxWalkSat::pickTabu | ( | ) | [inline, protected] |
Pick an atom from a random unsatisfied clause based on the tabu heuristic.
Definition at line 499 of file maxwalksat.h.
References Array< Type >::append(), calculateImprovement(), SAT::changed_, Array< Type >::clear(), Array< Type >::contains(), Array< Type >::find(), VariableState::getAtomInClause(), VariableState::getClauseCost(), VariableState::getClauseSize(), VariableState::getRandomFalseClauseIndex(), SAT::numFlips_, and Inference::state_.
Referenced by MaxWalkSat(), and pickSS().
00500 { 00501 //if (mwsdebug) cout << "Entering MaxWalkSat::pickTabu" << endl; 00502 assert(!inBlock_); 00503 // Clause to fix picked at random 00504 int toFix = state_->getRandomFalseClauseIndex(); 00505 if (toFix == NOVALUE) 00506 { 00507 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu (NOVALUE)" << endl; 00508 return NOVALUE; 00509 } 00510 00511 long double improvement; 00512 Array<int> canNotFlip; 00513 // If var in candidateBlockedVars is chosen, then 00514 // corresponding var in othersToFlip is flipped as well 00515 Array<int> candidateBlockedVars; 00516 Array<int> othersToFlip; 00517 00518 int clauseSize = state_->getClauseSize(toFix); 00519 long double cost = state_->getClauseCost(toFix); 00520 00521 // Holds the best atoms so far 00522 Array<int> best; 00523 // How many are tied for best 00524 register int numbest = 0; 00525 // Best value so far 00526 long double bestvalue = -LDBL_MAX; 00527 00528 // With prob. do a noisy pick 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 // Neg. clause: Only look at true literals 00535 if (cost < 0 && !state_->isTrueLiteral(lit)) continue; 00536 // var is the index of the atom 00537 register int var = abs(lit); 00538 00539 improvement = calculateImprovement(var, canNotFlip, candidateBlockedVars, 00540 othersToFlip); 00541 00542 // TABU: If pos. improvement, then always add it to best 00543 if (improvement > 0 && improvement >= bestvalue) 00544 { // Tied or better than previous best 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 { // Tied or better than previous best 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 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu (NOVALUE)" << endl; 00578 return NOVALUE; 00579 } 00580 00581 int toFlip = NOVALUE; 00582 // Exactly one best atom 00583 if (numbest == 1) 00584 toFlip = best[0]; 00585 else 00586 // Choose one of the best at random 00587 toFlip = best[random()%numbest]; 00588 00589 00590 // If atom can not be flipped, then null flip 00591 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00592 else 00593 { // If toflip is in block, then set other to flip 00594 int idx = candidateBlockedVars.find(toFlip); 00595 if (idx >= 0) 00596 { 00597 inBlock_ = true; 00598 flipInBlock_ = othersToFlip[idx]; 00599 } 00600 } 00601 00602 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu" << endl; 00603 return toFlip; 00604 }
int MaxWalkSat::pickSS | ( | ) | [inline, protected] |
Pick an atom according to the SampleSat heuristic.
This means sometimes sim. annealing, sometimes MaxWalkSat.
Definition at line 612 of file maxwalksat.h.
References calculateImprovement(), Array< Type >::contains(), Array< Type >::find(), VariableState::getCostOfFalseClauses(), VariableState::getIndexOfRandomAtom(), pickTabu(), Inference::state_, and SAT::targetCost_.
Referenced by MaxWalkSat().
00613 { 00614 //if (mwsdebug) cout << "Entering MaxWalkSat::pickSS" << endl; 00615 assert(!inBlock_); 00616 Array<int> canNotFlip; 00617 // If var in candidateBlockedVars is chosen, then 00618 // corresponding var in othersToFlip is flipped as well 00619 Array<int> candidateBlockedVars; 00620 Array<int> othersToFlip; 00621 long double costOfFalseClauses = state_->getCostOfFalseClauses(); 00622 00623 // If we have already reached a solution or if in an SA step, 00624 // then perform SA 00625 // Add 0.0001 to targetCost_ because of double precision error 00626 // This needs to be fixed 00627 if (costOfFalseClauses <= targetCost_ + 0.0001 || 00628 (random() % 100 < saRatio_ && !lateSa_)) 00629 { 00630 // Choose a random atom to flip 00631 int toFlip = state_->getIndexOfRandomAtom(); 00632 if (toFlip == NOVALUE) return NOVALUE; 00633 long double improvement = calculateImprovement(toFlip, canNotFlip, 00634 candidateBlockedVars, 00635 othersToFlip); 00636 00637 // If pos. or no improvement, then the atom will be flipped 00638 // Or neg. improvement: According to temp. flip atom anyway 00639 if ((improvement >= 0) || 00640 (random() <= exp(improvement/(saTemp_/100.0)) * RAND_MAX)) 00641 { 00642 // If atom can not be flipped, then null flip 00643 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00644 else 00645 { // If toflip is in block, then set other to flip 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 // Not in a solution or SA step: perform normal MWS step 00661 else 00662 { 00663 return pickTabu(); 00664 } 00665 }
long double MaxWalkSat::calculateImprovement | ( | const int & | atomIdx, | |
Array< int > & | canNotFlip, | |||
Array< int > & | candidateBlockedVars, | |||
Array< int > & | othersToFlip | |||
) | [inline, protected] |
Calculates the improvement (makecost - breakcost) by flipping an atom.
If the atom is in a block, then its index is saved in candidateBlockedVars and the index of another atom chosen to be flipped in the block is appended to othersToFlip. If the atom is in a block with evidence, then its index is appended to canNotFlip.
atomIdx | Index of atom for which the improvement is calculated. | |
canNotFlip | Holds indices of atoms which can not be flipped due to evidence in a block. | |
candidateBlockedVars | If dealing with an atom in a block, then its index is appended here. | |
othersToFlip | If dealing with an atom in a block, then the index of the other atom chosen to be flipped is appended here. |
Definition at line 683 of file maxwalksat.h.
References Array< Type >::append(), VariableState::getBlockArray(), VariableState::getBlockIndex(), VariableState::getBlockSize(), VariableState::getImprovementByFlipping(), VariableState::getValueOfAtom(), VariableState::isBlockEvidence(), Array< Type >::size(), and Inference::state_.
Referenced by pickBest(), pickSS(), and pickTabu().
00686 { 00687 int blockIdx = state_->getBlockIndex(atomIdx - 1); 00688 if (blockIdx == -1) 00689 { 00690 // Atom not in a block 00691 return state_->getImprovementByFlipping(atomIdx); 00692 } 00693 00694 else 00695 { 00696 // Atom is in a block 00697 // If evidence atom exists or in block of size 1, then can not flip 00698 if (state_->isBlockEvidence(blockIdx) || 00699 state_->getBlockSize(blockIdx) == 1) 00700 { 00701 canNotFlip.append(atomIdx); 00702 return -LDBL_MAX; 00703 } 00704 else 00705 { 00706 //Dealing with atom in a block 00707 Array<int>& block = state_->getBlockArray(blockIdx); 00708 int chosen = -1; 00709 int otherToFlip = -1; 00710 00711 // 0->1: choose atom in block which is already 1 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 // 1->0: choose to flip the other randomly 00734 // TODO: choose to flip the other with best improvement 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 }