package splar.core.heuristics;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import splar.core.constraints.BooleanVariableInterface;
import splar.core.constraints.CNFClause;
import splar.core.constraints.CNFFormula;
public class FORCEVariableOrderingHeuristic extends VariableOrderingHeuristic {
private final boolean DEBUG = false;
private static final int maxSpanReductionAttempts = 2;
private BooleanVariableInterface initialVariableOrdering[];
private int numReruns;
public FORCEVariableOrderingHeuristic(String name, int numReRuns) {
this(name,null,numReRuns);
}
public FORCEVariableOrderingHeuristic(String name, BooleanVariableInterface initialVariableOrdering[], int numReRuns) {
super(name);
this.initialVariableOrdering = initialVariableOrdering;
this.numReruns = numReRuns;
}
public void setParameter(String name, Object value) {
if ( name.compareToIgnoreCase("variable_ordering_list") == 0 ) {
if ( value != null && (value instanceof String ) ) {
String voList = (String)value;
initialVariableOrdering = VariableOrderingHeuristic.variableOrderingAsBooleanVariableArray(voList);
}
}
else if (name.compareToIgnoreCase("num_reruns") == 0 ) {
numReruns = Integer.parseInt((String)parameters.get("num_reruns"));
}
super.setParameter(name, value);
}
private BooleanVariableInterface[] getInitialVariableOrdering(CNFFormula cnf) {
// if an initial variable ordering has been specified, returns it
if ( initialVariableOrdering != null ) {
return initialVariableOrdering;
}
// else, generates a random variable ordering
List<BooleanVariableInterface> scrambledVariables = new ArrayList<BooleanVariableInterface>();
scrambledVariables.addAll(cnf.getVariables());
if ( DEBUG ) System.out.println("FORCE: Shuffling...");
java.util.Collections.shuffle(scrambledVariables);
return scrambledVariables.toArray(new BooleanVariableInterface[0]);
}
// algorithm based on paper: "FORCE: A Fast and Easy-To-Implement Variable-Ordering Heuristic"
// By Fadi Aloul, Igor Markov, Karem Sakallah
// ACM GLSVLSI 2003, April 28-29, 2003
public String[] runHeuristic(CNFFormula cnf) {
String varOrder[] = null;
int runsMinSpan = Integer.MAX_VALUE;
int numLoops = (initialVariableOrdering != null) ? 1 : numReruns;
if (DEBUG) System.out.println("num loops: " + numLoops);
for( int runIndex = 1 ; runIndex <= numLoops ; runIndex++ ) {
if ( numLoops > 1 ) {
System.out.println(">> FORCE: run #" + runIndex);
}
int countUnsuccessfulSpanReductions = 0;
BooleanVariableInterface outputVariableOrdering[] = null;
// set initial variable ordering
BooleanVariableInterface variables[] = getInitialVariableOrdering(cnf);
Set<CNFClause> clauses = cnf.getClauses();
Map<String,Integer> variableMap = VariableOrderingHeuristic.variableOrderingAsHashMap(variables);
variableMap = VariableOrderingHeuristic.variableOrderingAsHashMap(variables);
int countVars = variables.length;
int countClauses = clauses.size();
outputVariableOrdering = new BooleanVariableInterface[countVars];
System.arraycopy(variables,0,outputVariableOrdering,0,countVars);
int span = cnf.calculateClauseSpan(variableMap);
int minSpan = span;
if ( DEBUG ) System.out.println("Span: " + span);
int countSteps = 0;
// repeat limit times or until total span stops decreasing
while( countUnsuccessfulSpanReductions < maxSpanReductionAttempts ) {
// compute center of gravity of each clause
double COG[] = new double[countClauses];
int i = 0;
for( CNFClause clause : clauses ) {
double orderSum = 0;
for( BooleanVariableInterface var : clause.getVariables() ) {
try {
orderSum += variableMap.get(var.getID()).intValue();
}
catch( Exception e ) {
System.out.println("Var not found: " + var.getID());
e.printStackTrace();
}
}
COG[i++] = orderSum / clause.countVariables();
}
// for each vertex compute tentative new location of v based on centers of gravity of clauses
for( BooleanVariableInterface var : variables ) {
double sumCOG = 0;
int countVarClauses = 0;
int clauseIndex = 0;
for( CNFClause clause : clauses ) {
if ( clause.getVariables().contains(var) ) {
sumCOG += COG[clauseIndex];
countVarClauses++;
}
clauseIndex++;
}
double varCOG = new Double(sumCOG / countVarClauses);
var.attachData(varCOG);
}
// sort tentative vertex locations and assign integer indices to the variables
Comparator<BooleanVariableInterface> comparator = new Comparator<BooleanVariableInterface>() {
public int compare(BooleanVariableInterface var1, BooleanVariableInterface var2) {
Double var1Score = (Double)var1.getAttachedData();
Double var2Score = (Double)var2.getAttachedData();
if ( var1Score.doubleValue() > var2Score.doubleValue() ) {
return 1;
}
else if ( var1Score.doubleValue() < var2Score.doubleValue() ) {
return -1;
}
return 0;
}
public boolean equals(Comparator<BooleanVariableInterface> comparator) {
if ( comparator == null ) {
return false;
}
return (comparator == this);
}
};
java.util.Arrays.sort(variables, comparator);
// variable to index mapping updated with new variable locations
variableMap = VariableOrderingHeuristic.variableOrderingAsHashMap(variables);
span = cnf.calculateClauseSpan(variableMap);
countSteps++;
if ( span < minSpan ) {
minSpan = span;
// outputVariableOrdering = new BooleanVariableInterface[countVars];
System.arraycopy(variables,0,outputVariableOrdering,0,countVars);
countUnsuccessfulSpanReductions = 0;
if ( DEBUG ) System.out.println(countSteps + ": REDUCTION" + (runIndex+1) + "(" + countUnsuccessfulSpanReductions + ") Span: " + span);
}
else {
countUnsuccessfulSpanReductions++;
if ( DEBUG ) System.out.println(countSteps + ": NO REDUCTION " + (runIndex+1) + "(" + countUnsuccessfulSpanReductions + ") Span: " + span);
}
}
if ( minSpan < runsMinSpan ) {
if ( outputVariableOrdering != null ) {
varOrder = VariableOrderingHeuristic.variableOrderingAsStringVariableArray(outputVariableOrdering);
}
runsMinSpan = minSpan;
}
}
return varOrder;
}
}