MaxWalkSat Class Reference

The MaxWalkSat algorithm. More...

#include <maxwalksat.h>

Inheritance diagram for MaxWalkSat:

SAT Inference List of all members.

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.

Detailed Description

The MaxWalkSat algorithm.

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.


Member Function Documentation

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.

Parameters:
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.

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

Parameters:
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   }


The documentation for this class was generated from the following file:
Generated on Wed Feb 14 15:15:21 2007 for Alchemy by  doxygen 1.5.1