aima.core.logic.propositional.inference.WalkSAT Maven / Gradle / Ivy
package aima.core.logic.propositional.inference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import aima.core.logic.propositional.kb.data.Clause;
import aima.core.logic.propositional.kb.data.Model;
import aima.core.logic.propositional.parsing.ast.PropositionSymbol;
/**
* Artificial Intelligence A Modern Approach (3rd Edition): page 263.
*
*
*
*
* function WALKSAT(clauses, p, max_flips) returns a satisfying model or failure
* inputs: clauses, a set of clauses in propositional logic
* p, the probability of choosing to do a "random walk" move, typically around 0.5
* max_flips, number of flips allowed before giving up
*
* model <- a random assignment of true/false to the symbols in clauses
* for i = 1 to max_flips do
* if model satisfies clauses then return model
* clause <- a randomly selected clause from clauses that is false in model
* with probability p flip the value in model of a randomly selected symbol from clause
* else flip whichever symbol in clause maximizes the number of satisfied clauses
* return failure
*
*
*
* Figure 7.18 The WALKSAT algorithm for checking satisfiability by randomly
* flipping the values of variables. Many versions of the algorithm exist.
*
* @author Ciaran O'Reilly
* @author Ravi Mohan
* @author Mike Stampone
*/
public class WalkSAT {
/**
* WALKSAT(clauses, p, max_flips)
*
* @param clauses
* a set of clauses in propositional logic
* @param p
* the probability of choosing to do a "random walk" move,
* typically around 0.5
* @param maxFlips
* number of flips allowed before giving up. Note: a value < 0 is
* interpreted as infinity.
*
* @return a satisfying model or failure (null).
*/
public Model walkSAT(Set clauses, double p, int maxFlips) {
assertLegalProbability(p);
// model <- a random assignment of true/false to the symbols in clauses
Model model = randomAssignmentToSymbolsInClauses(clauses);
// for i = 1 to max_flips do (Note: maxFlips < 0 means infinity)
for (int i = 0; i < maxFlips || maxFlips < 0; i++) {
// if model satisfies clauses then return model
if (model.satisfies(clauses)) {
return model;
}
// clause <- a randomly selected clause from clauses that is false
// in model
Clause clause = randomlySelectFalseClause(clauses, model);
// with probability p flip the value in model of a randomly selected
// symbol from clause
if (random.nextDouble() < p) {
model = model.flip(randomlySelectSymbolFromClause(clause));
} else {
// else flip whichever symbol in clause maximizes the number of
// satisfied clauses
model = flipSymbolInClauseMaximizesNumberSatisfiedClauses(
clause, clauses, model);
}
}
// return failure
return null;
}
//
// SUPPORTING CODE
//
private Random random = new Random();
/**
* Default Constructor.
*/
public WalkSAT() {
}
/**
* Constructor.
*
* @param random
* the random generator to be used by the algorithm.
*/
public WalkSAT(Random random) {
this.random = random;
}
//
// PROTECTED
//
protected void assertLegalProbability(double p) {
if (p < 0 || p > 1) {
throw new IllegalArgumentException("p is not a legal propbability value [0-1]: "+p);
}
}
protected Model randomAssignmentToSymbolsInClauses(Set clauses) {
// Collect the symbols in clauses
Set symbols = new LinkedHashSet();
for (Clause c : clauses) {
symbols.addAll(c.getSymbols());
}
// Make initial set of assignments
Map values = new HashMap();
for (PropositionSymbol symbol : symbols) {
// a random assignment of true/false to the symbols in clauses
values.put(symbol, random.nextBoolean());
}
Model result = new Model(values);
return result;
}
protected Clause randomlySelectFalseClause(Set clauses, Model model) {
// Collect the clauses that are false in the model
List falseClauses = new ArrayList();
for (Clause c : clauses) {
if (Boolean.FALSE.equals(model.determineValue(c))) {
falseClauses.add(c);
}
}
// a randomly selected clause from clauses that is false
Clause result = falseClauses.get(random.nextInt(falseClauses.size()));
return result;
}
protected PropositionSymbol randomlySelectSymbolFromClause(Clause clause) {
// all the symbols in clause
Set symbols = clause.getSymbols();
// a randomly selected symbol from clause
PropositionSymbol result = (new ArrayList(symbols))
.get(random.nextInt(symbols.size()));
return result;
}
protected Model flipSymbolInClauseMaximizesNumberSatisfiedClauses(
Clause clause, Set clauses, Model model) {
Model result = model;
// all the symbols in clause
Set symbols = clause.getSymbols();
int maxClausesSatisfied = -1;
for (PropositionSymbol symbol : symbols) {
Model flippedModel = result.flip(symbol);
int numberClausesSatisfied = 0;
for (Clause c : clauses) {
if (Boolean.TRUE.equals(flippedModel.determineValue(c))) {
numberClausesSatisfied++;
}
}
// test if this symbol flip is the new maximum
if (numberClausesSatisfied > maxClausesSatisfied) {
result = flippedModel;
maxClausesSatisfied = numberClausesSatisfied;
if (numberClausesSatisfied == clauses.size()) {
// i.e. satisfies all clauses
break; // this is our goal.
}
}
}
return result;
}
}