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  protected:
00279   
00286   void flipAtom (int toFlip)
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   }
00328 
00335   int pickRandom()
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   }
00389 
00396   int pickBest()
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   }
00483 
00489   int pickTabu()
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   }
00595 
00602   int pickSS()
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   }
00656 
00657 
00673   long double calculateImprovement(const int& atomIdx, Array<int>& canNotFlip,
00674                                    Array<int>& candidateBlockedVars,
00675                                    Array<int>& othersToFlip)
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   }
00755 
00760   void reconstructLowState()
00761   {
00762     assert(lazyLowState_);
00763     if (mwsdebug) cout << "Reconstructing low state ..." << endl;
00764     hash_set<int>::const_iterator it = varsFlippedSinceLowState_.begin();
00765     for (; it != varsFlippedSinceLowState_.end(); it++)
00766     {
00767       if (mwsdebug)
00768       {
00769         cout << "Flipping atom " << (*it) << endl;
00770       }
00771       state_->flipAtomValue(*it);
00772     }
00773     state_->saveLowState();
00774     if (mwsdebug) cout << "Done reconstructing low state ..." << endl;
00775   }
00776 
00777  private:
00778  
00780     // Heuristic to be used to pick an atom
00781   int heuristic_;
00782     // At least this many flips must occur before flipping the same atom
00783   int tabuLength_;
00784   
00785     // BEGIN: SampleSat parameters
00786     // Percent of sim. annealing steps
00787   int saRatio_;
00788     // Sim. annealing temperature
00789   int saTemp_;
00790     // Run sim. annealing only at a plateur
00791   bool lateSa_;
00792     // END: SampleSat parameters
00794 
00795     // Function pointer holds which function is to be used to pick an atom
00796     // = {pickRandom, pickBest, pickTabu, pickSS};
00797   int (MaxWalkSat::*pickcode[15])(void);
00798     // If true, never break a highest cost clause
00799   bool hard_;
00800 
00801     // Make random flip with numerator/denominator probability
00802   int numerator_;
00803   int denominator_;
00804       
00805     // Which other atom to flip in block
00806   bool inBlock_;
00807   int flipInBlock_;
00808   
00809     // If false, the naive way of saving low states (each time a low state is
00810     // found, the whole state is saved) is used; otherwise, a list of variables
00811     // flipped since the last low state is kept and the low state is
00812     // reconstructed. This can be much faster for very large data sets.
00813   bool lazyLowState_;
00814     // List of variables flipped since last low state was found. This is used
00815     // to reconstruct the low state when lazyLowState_ is set.
00816   hash_set<int> varsFlippedSinceLowState_;
00817 };
00818 
00819 #endif

Generated on Tue Jan 16 05:30:03 2007 for Alchemy by  doxygen 1.5.1