maxwalksat.h

00001 /*
00002  * All of the documentation and software included in the
00003  * Alchemy Software is copyrighted by Stanley Kok, Parag
00004  * Singla, Matthew Richardson, Pedro Domingos, Marc
00005  * Sumner and Hoifung Poon.
00006  * 
00007  * Copyright [2004-07] Stanley Kok, Parag Singla, Matthew
00008  * Richardson, Pedro Domingos, Marc Sumner and Hoifung
00009  * Poon. All rights reserved.
00010  * 
00011  * Contact: Pedro Domingos, University of Washington
00012  * (pedrod@cs.washington.edu).
00013  * 
00014  * Redistribution and use in source and binary forms, with
00015  * or without modification, are permitted provided that
00016  * the following conditions are met:
00017  * 
00018  * 1. Redistributions of source code must retain the above
00019  * copyright notice, this list of conditions and the
00020  * following disclaimer.
00021  * 
00022  * 2. Redistributions in binary form must reproduce the
00023  * above copyright notice, this list of conditions and the
00024  * following disclaimer in the documentation and/or other
00025  * materials provided with the distribution.
00026  * 
00027  * 3. All advertising materials mentioning features or use
00028  * of this software must display the following
00029  * acknowledgment: "This product includes software
00030  * developed by Stanley Kok, Parag Singla, Matthew
00031  * Richardson, Pedro Domingos, Marc Sumner and Hoifung
00032  * Poon in the Department of Computer Science and
00033  * Engineering at the University of Washington".
00034  * 
00035  * 4. Your publications acknowledge the use or
00036  * contribution made by the Software to your research
00037  * using the following citation(s): 
00038  * Stanley Kok, Parag Singla, Matthew Richardson and
00039  * Pedro Domingos (2005). "The Alchemy System for
00040  * Statistical Relational AI", Technical Report,
00041  * Department of Computer Science and Engineering,
00042  * University of Washington, Seattle, WA.
00043  * http://www.cs.washington.edu/ai/alchemy.
00044  * 
00045  * 5. Neither the name of the University of Washington nor
00046  * the names of its contributors may be used to endorse or
00047  * promote products derived from this software without
00048  * specific prior written permission.
00049  * 
00050  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY OF WASHINGTON
00051  * AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
00052  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00053  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00054  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE UNIVERSITY
00055  * OF WASHINGTON OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
00056  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00057  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00058  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00059  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
00060  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00061  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00062  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
00063  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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       // User-set parameters
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       // For SampleSat
00118     saRatio_ = params->ssParams->saRatio;
00119     saTemp_ = params->ssParams->saTemp;
00120     lateSa_ = params->ssParams->lateSa;
00121     
00122       // Info from SAT class
00123     if (heuristic_ == TABU || heuristic_ == SS)
00124       changed_.growToSize(numAtoms + 1);
00125     numFlips_ = 0;
00126 
00127       // Info from MaxWalkSat
00128     numerator_ = 50; // User-set?
00129     denominator_ = 100; // User-set?
00130       // We assume we are not in a block
00131     inBlock_ = false;
00132     flipInBlock_ = NOVALUE;
00133 
00134       // Initialize array of function pointers
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       // 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   }
00169   
00173   void infer()
00174   {
00175     int numtry = 0;
00176     int numsuccesstry = 0;
00177     long double lowCost = LDBL_MAX;
00178 
00179       // If keeping track of true clause groundings, then init to zero
00180     if (trackClauseTrueCnts_)
00181       for (int clauseno = 0; clauseno < clauseTrueCnts_->size(); clauseno++)
00182         (*clauseTrueCnts_)[clauseno] = 0;
00183 
00184       // Perform up to maxTries tries or numSolutions successful tries
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         // Make random assigment in subsequent tries
00195         // (for first try, init() should have been called)
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           // If in a block, then another atom was also chosen to flip
00214         if (inBlock_)
00215           flipAtom(flipInBlock_);
00216 
00217           // set in block back to false
00218         inBlock_ = false;
00219         flipInBlock_ = NOVALUE;
00220         
00221         long double costOfFalseClauses = state_->getCostOfFalseClauses();
00222         //long double lowCost = state_->getLowCost();
00223           // If the cost of false clauses is lower than the low cost of all
00224           // tries, then save this as the low state.
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           // If succesful try
00243           // Add 0.0001 to targetCost_ because of double precision error
00244           // This needs to be fixed
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         //cout<< "Active atoms " << state_->getNumActiveAtoms() << endl; 
00260       }
00261     }
00262 
00263       // If keeping track of true clause groundings
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   int getMaxSteps()
00279   {
00280     return maxSteps_;
00281   }
00282   
00283   void setMaxSteps(const int& maxSteps)
00284   {
00285     maxSteps_ = maxSteps;
00286   }
00287   
00288  protected:
00289   
00296   void flipAtom (int toFlip)
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   }
00338 
00345   int pickRandom()
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   }
00399 
00406   int pickBest()
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   }
00493 
00499   int pickTabu()
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   }
00605 
00612   int pickSS()
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   }
00666 
00667 
00683   long double calculateImprovement(const int& atomIdx, Array<int>& canNotFlip,
00684                                    Array<int>& candidateBlockedVars,
00685                                    Array<int>& othersToFlip)
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   }
00765 
00770   void reconstructLowState()
00771   {
00772     assert(lazyLowState_);
00773     if (mwsdebug) cout << "Reconstructing low state ..." << endl;
00774     hash_set<int>::const_iterator it = varsFlippedSinceLowState_.begin();
00775     for (; it != varsFlippedSinceLowState_.end(); it++)
00776     {
00777       if (mwsdebug)
00778       {
00779         cout << "Flipping atom " << (*it) << endl;
00780       }
00781       state_->flipAtomValue(*it);
00782     }
00783     state_->saveLowState();
00784     if (mwsdebug) cout << "Done reconstructing low state ..." << endl;
00785   }
00786 
00787  private:
00788  
00790     // Heuristic to be used to pick an atom
00791   int heuristic_;
00792     // At least this many flips must occur before flipping the same atom
00793   int tabuLength_;
00794   
00795     // BEGIN: SampleSat parameters
00796     // Percent of sim. annealing steps
00797   int saRatio_;
00798     // Sim. annealing temperature
00799   int saTemp_;
00800     // Run sim. annealing only at a plateur
00801   bool lateSa_;
00802     // END: SampleSat parameters
00804 
00805     // Function pointer holds which function is to be used to pick an atom
00806     // = {pickRandom, pickBest, pickTabu, pickSS};
00807   int (MaxWalkSat::*pickcode[15])(void);
00808     // If true, never break a highest cost clause
00809   bool hard_;
00810 
00811     // Make random flip with numerator/denominator probability
00812   int numerator_;
00813   int denominator_;
00814       
00815     // Which other atom to flip in block
00816   bool inBlock_;
00817   int flipInBlock_;
00818   
00819     // If false, the naive way of saving low states (each time a low state is
00820     // found, the whole state is saved) is used; otherwise, a list of variables
00821     // flipped since the last low state is kept and the low state is
00822     // reconstructed. This can be much faster for very large data sets.
00823   bool lazyLowState_;
00824     // List of variables flipped since last low state was found. This is used
00825     // to reconstruct the low state when lazyLowState_ is set.
00826   hash_set<int> varsFlippedSinceLowState_;
00827 };
00828 
00829 #endif

Generated on Wed Feb 14 15:15:17 2007 for Alchemy by  doxygen 1.5.1