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)

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

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

Returns:
Index of atom picked.

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.

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


The documentation for this class was generated from the following file:
Generated on Tue Jan 16 05:30:06 2007 for Alchemy by  doxygen 1.5.1