#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) |
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 286 of file maxwalksat.h.
References SAT::changed_, VariableState::flipAtom(), VariableState::getNumAtoms(), Array< Type >::growToSize(), SAT::numFlips_, and Inference::state_.
Referenced by infer().
00287 { 00288 //if (mwsdebug) cout << "Entering MaxWalkSat::flipAtom" << endl; 00289 if (toFlip == NOVALUE) 00290 return; 00291 00292 // Flip the atom in the state 00293 state_->flipAtom(toFlip); 00294 // Mark this flip as last time atom was changed if tabu is used 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 // Mark this variable as flipped since last low state. If already 00304 // present, then it has been flipped back to its value in the low 00305 // state and we can remove it. 00306 if (varsFlippedSinceLowState_.find(toFlip) != 00307 varsFlippedSinceLowState_.end()) 00308 { 00309 if (mwsdebug) 00310 { 00311 //cout << "Atom " << toFlip << " has been flipped since low state, " 00312 // << "so removing it" << endl; 00313 } 00314 varsFlippedSinceLowState_.erase(toFlip); 00315 } 00316 else 00317 { 00318 if (mwsdebug) 00319 { 00320 //cout << "Atom " << toFlip << " not flipped since low state, " 00321 // << "so adding it" << endl; 00322 } 00323 varsFlippedSinceLowState_.insert(toFlip); 00324 } 00325 } 00326 //if (mwsdebug) cout << "Leaving MaxWalkSat::flipAtom" << endl; 00327 }
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 335 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().
00336 { 00337 //if (mwsdebug) cout << "Entering MaxWalkSat::pickRandom" << endl; 00338 assert(!inBlock_); 00339 int atomIdx = state_->getIndexOfAtomInRandomFalseClause(); 00340 assert(atomIdx > 0); 00341 00342 // If atom is in a block, then another one has to be picked 00343 int blockIdx = state_->getBlockIndex(atomIdx - 1); 00344 if (blockIdx >= 0) 00345 { 00346 // Atom is in a block 00347 // If evidence atom exists or in block of size 1, then can not flip 00348 if (state_->isBlockEvidence(blockIdx) || 00349 state_->getBlockSize(blockIdx) == 1) 00350 return NOVALUE; 00351 else 00352 { 00353 //Dealing with atom in a block 00354 Array<int>& block = state_->getBlockArray(blockIdx); 00355 // 0->1: choose atom in block which is already 1 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 // 1->0: choose to flip the other randomly 00369 // TODO: choose to flip the other with best improvement 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 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickRandom" << endl; 00387 return atomIdx; 00388 }
int MaxWalkSat::pickBest | ( | ) | [inline, protected] |
Pick the best atom (clauses made satisfied - clauses made unsatisfied) in a random unsatisfied clause.
Definition at line 396 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().
00397 { 00398 //if (mwsdebug) cout << "Entering MaxWalkSat::pickBest" << endl; 00399 assert(!inBlock_); 00400 // Clause to fix picked at random 00401 int toFix = state_->getRandomFalseClauseIndex(); 00402 if (toFix == NOVALUE) return NOVALUE; 00403 00404 long double improvement; 00405 00406 Array<int> canNotFlip; 00407 // If var in candidateBlockedVars is chosen, then 00408 // corresponding var in othersToFlip is flipped as well 00409 Array<int> candidateBlockedVars; 00410 Array<int> othersToFlip; 00411 00412 int clauseSize = state_->getClauseSize(toFix); 00413 long double cost = state_->getClauseCost(toFix); 00414 // Holds the best atoms so far 00415 Array<int> best; 00416 // How many are tied for best 00417 register int numbest = 0; 00418 // Best value so far 00419 long double bestvalue = -LDBL_MAX; 00420 // With prob. do a noisy pick 00421 bool noisyPick = (numerator_ > 0 && random()%denominator_ < numerator_); 00422 00423 // Look at each atom and pick best ones 00424 for (int i = 0; i < clauseSize; i++) 00425 { 00426 register int lit = state_->getAtomInClause(i, toFix); 00427 // Neg. clause: Only look at true literals 00428 if (cost < 0 && !state_->isTrueLiteral(lit)) continue; 00429 // var is the index of the atom 00430 register int var = abs(lit); 00431 00432 improvement = calculateImprovement(var, canNotFlip, 00433 candidateBlockedVars, 00434 othersToFlip); 00435 00436 if (improvement >= bestvalue) 00437 { // Tied or better than previous best 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 // If only false literals in a neg. clause, then numbest is 0 00450 if (numbest == 0) return NOVALUE; 00451 // Choose one of the best at random 00452 // (default if none of the following 2 cases occur) 00453 int toFlip = best[random()%numbest]; 00454 00455 // 1. If no improvement by best, 00456 // then with prob. choose a random atom 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 // 2. Exactly one best atom 00465 else if (numbest == 1) 00466 toFlip = best[0]; 00467 00468 // If atom can not be flipped, then null flip 00469 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00470 else 00471 { // If toFlip is in block, then set other to flip 00472 int idx = candidateBlockedVars.find(toFlip); 00473 if (idx >= 0) 00474 { 00475 inBlock_ = true; 00476 flipInBlock_ = othersToFlip[idx]; 00477 } 00478 } 00479 00480 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickBest" << endl; 00481 return toFlip; 00482 }
int MaxWalkSat::pickTabu | ( | ) | [inline, protected] |
Pick an atom from a random unsatisfied clause based on the tabu heuristic.
Definition at line 489 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().
00490 { 00491 //if (mwsdebug) cout << "Entering MaxWalkSat::pickTabu" << endl; 00492 assert(!inBlock_); 00493 // Clause to fix picked at random 00494 int toFix = state_->getRandomFalseClauseIndex(); 00495 if (toFix == NOVALUE) 00496 { 00497 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu (NOVALUE)" << endl; 00498 return NOVALUE; 00499 } 00500 00501 long double improvement; 00502 Array<int> canNotFlip; 00503 // If var in candidateBlockedVars is chosen, then 00504 // corresponding var in othersToFlip is flipped as well 00505 Array<int> candidateBlockedVars; 00506 Array<int> othersToFlip; 00507 00508 int clauseSize = state_->getClauseSize(toFix); 00509 long double cost = state_->getClauseCost(toFix); 00510 00511 // Holds the best atoms so far 00512 Array<int> best; 00513 // How many are tied for best 00514 register int numbest = 0; 00515 // Best value so far 00516 long double bestvalue = -LDBL_MAX; 00517 00518 // With prob. do a noisy pick 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 // Neg. clause: Only look at true literals 00525 if (cost < 0 && !state_->isTrueLiteral(lit)) continue; 00526 // var is the index of the atom 00527 register int var = abs(lit); 00528 00529 improvement = calculateImprovement(var, canNotFlip, candidateBlockedVars, 00530 othersToFlip); 00531 00532 // TABU: If pos. improvement, then always add it to best 00533 if (improvement > 0 && improvement >= bestvalue) 00534 { // Tied or better than previous best 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 { // Tied or better than previous best 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 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu (NOVALUE)" << endl; 00568 return NOVALUE; 00569 } 00570 00571 int toFlip = NOVALUE; 00572 // Exactly one best atom 00573 if (numbest == 1) 00574 toFlip = best[0]; 00575 else 00576 // Choose one of the best at random 00577 toFlip = best[random()%numbest]; 00578 00579 00580 // If atom can not be flipped, then null flip 00581 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00582 else 00583 { // If toflip is in block, then set other to flip 00584 int idx = candidateBlockedVars.find(toFlip); 00585 if (idx >= 0) 00586 { 00587 inBlock_ = true; 00588 flipInBlock_ = othersToFlip[idx]; 00589 } 00590 } 00591 00592 //if (mwsdebug) cout << "Leaving MaxWalkSat::pickTabu" << endl; 00593 return toFlip; 00594 }
int MaxWalkSat::pickSS | ( | ) | [inline, protected] |
Pick an atom according to the SampleSat heuristic.
This means sometimes sim. annealing, sometimes MaxWalkSat.
Definition at line 602 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().
00603 { 00604 //if (mwsdebug) cout << "Entering MaxWalkSat::pickSS" << endl; 00605 assert(!inBlock_); 00606 Array<int> canNotFlip; 00607 // If var in candidateBlockedVars is chosen, then 00608 // corresponding var in othersToFlip is flipped as well 00609 Array<int> candidateBlockedVars; 00610 Array<int> othersToFlip; 00611 long double costOfFalseClauses = state_->getCostOfFalseClauses(); 00612 00613 // If we have already reached a solution or if in an SA step, 00614 // then perform SA 00615 // Add 0.0001 to targetCost_ because of double precision error 00616 // This needs to be fixed 00617 if (costOfFalseClauses <= targetCost_ + 0.0001 || 00618 (random() % 100 < saRatio_ && !lateSa_)) 00619 { 00620 // Choose a random atom to flip 00621 int toFlip = state_->getIndexOfRandomAtom(); 00622 if (toFlip == NOVALUE) return NOVALUE; 00623 long double improvement = calculateImprovement(toFlip, canNotFlip, 00624 candidateBlockedVars, 00625 othersToFlip); 00626 00627 // If pos. or no improvement, then the atom will be flipped 00628 // Or neg. improvement: According to temp. flip atom anyway 00629 if ((improvement >= 0) || 00630 (random() <= exp(improvement/(saTemp_/100.0)) * RAND_MAX)) 00631 { 00632 // If atom can not be flipped, then null flip 00633 if (canNotFlip.contains(toFlip)) toFlip = NOVALUE; 00634 else 00635 { // If toflip is in block, then set other to flip 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 // Not in a solution or SA step: perform normal MWS step 00651 else 00652 { 00653 return pickTabu(); 00654 } 00655 }
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 673 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().
00676 { 00677 int blockIdx = state_->getBlockIndex(atomIdx - 1); 00678 if (blockIdx == -1) 00679 { 00680 // Atom not in a block 00681 return state_->getImprovementByFlipping(atomIdx); 00682 } 00683 00684 else 00685 { 00686 // Atom is in a block 00687 // If evidence atom exists or in block of size 1, then can not flip 00688 if (state_->isBlockEvidence(blockIdx) || 00689 state_->getBlockSize(blockIdx) == 1) 00690 { 00691 canNotFlip.append(atomIdx); 00692 return -LDBL_MAX; 00693 } 00694 else 00695 { 00696 //Dealing with atom in a block 00697 Array<int>& block = state_->getBlockArray(blockIdx); 00698 int chosen = -1; 00699 int otherToFlip = -1; 00700 00701 // 0->1: choose atom in block which is already 1 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 // 1->0: choose to flip the other randomly 00724 // TODO: choose to flip the other with best improvement 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 }