package splar.plugins.reasoners.bdd.javabdd; import java.io.FileOutputStream; import java.io.FileReader; import java.io.LineNumberReader; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import javax.naming.OperationNotSupportedException; import net.sf.javabdd.BDD; import net.sf.javabdd.BDDFactory; import net.sf.javabdd.JFactory; import net.sf.javabdd.BDDFactory.ReorderMethod; import splar.core.constraints.Assignment; import splar.core.constraints.BooleanVariable; import splar.core.constraints.BooleanVariableInterface; import splar.core.fm.FeatureTreeNode; import splar.core.fm.reasoning.FMReasoningException; import splar.core.fm.reasoning.FMReasoningInterface; import splar.core.heuristics.VariableOrderingHeuristic; public abstract class ReasoningWithBDD extends FMReasoningInterface { protected BDDFactory bddFactory; protected BDD theOriginalBDD; protected BDD theWorkingBDD; protected int nodeNum; protected int cacheSize; protected ReorderMethod reorderMethod; protected VariableOrderingHeuristic variableOrderingHeuristic; protected long maxBuildingTime; // in milliseconds protected long heuristicRunningTime; protected long bddBuildingTime; // allows multiples BDD states to be saved and recovered protected Map<String,ReasoningWithBDDState> states; protected int[] variables = null; protected boolean newAssignmentsMade = false; protected String orderingFormulasStrategy; public ReasoningWithBDD(VariableOrderingHeuristic voHeuristic, int nodeNum, int cacheSize, long maxBuildingTime, ReorderMethod reorderMethod, String orderingFormulasStrategy) { super(); this.variableOrderingHeuristic = voHeuristic; this.nodeNum = nodeNum; this.cacheSize = cacheSize; this.reorderMethod = reorderMethod; states = new LinkedHashMap<String,ReasoningWithBDDState>(); this.maxBuildingTime = maxBuildingTime; this.heuristicRunningTime = -1; this.bddBuildingTime = -1; this.orderingFormulasStrategy = orderingFormulasStrategy; bddFactory = JFactory.init(nodeNum,cacheSize); } public ReasoningWithBDD(VariableOrderingHeuristic voHeuristic, int nodeNum, int cacheSize, long maxBuildingTime, ReorderMethod reorderMethod) { this(voHeuristic, nodeNum, cacheSize, maxBuildingTime, reorderMethod, "undefined"); } protected void initBDDReorder(int countNodes) { if ( reorderMethod != BDDFactory.REORDER_NONE ) { bddFactory.enableReorder(); bddFactory.autoReorder(reorderMethod); // define each level of the BDD as an eligible SIFTING block if ( reorderMethod == BDDFactory.REORDER_SIFT || reorderMethod == BDDFactory.REORDER_SIFTITE || reorderMethod == BDDFactory.REORDER_RANDOM ){ for( int i = 0 ; i < countNodes ; i++ ) { bddFactory.addVarBlock(bddFactory.ithVar(i), false); } } } } public void init() throws Exception { clearStates(); theOriginalBDD = createBDD(bddFactory, orderingFormulasStrategy); theWorkingBDD = theOriginalBDD.id(); if ( variables == null ) { variables = initVars(theOriginalBDD.getFactory().varNum()); } } public void init(String stateFilePath, String stateFileName) throws Exception { long start = System.currentTimeMillis(); // clear states clearStates(); // load the BDD theOriginalBDD = bddFactory.load(stateFilePath + stateFileName + ".bdd"); theWorkingBDD = theOriginalBDD.id(); // load the Map: BDD nodes <-> variable names LineNumberReader reader = new LineNumberReader(new FileReader(stateFilePath + stateFileName + ".keys")); int lineNum = 0; String line = reader.readLine(); // Variable -> Index Map varName2IndexMap = new HashMap<String, Integer>(); while( line != null ) { varName2IndexMap.put(line, lineNum++); line = reader.readLine(); } reader.close(); // Index -> Variable Map varIndex2NameMap = new String[varName2IndexMap.size()]; for( String varName : varName2IndexMap.keySet() ) { varIndex2NameMap[varName2IndexMap.get(varName)] = varName; } variables = initVars(theOriginalBDD.getFactory().varNum()); bddBuildingTime = System.currentTimeMillis() - start; } public void restoreFromFile(String stateFilePath, String stateFileName) throws Exception { init(stateFilePath, stateFileName); } public void saveToFile(String stateFilePath, String stateFileName) throws Exception { // Save BDD bddFactory.save(stateFilePath + stateFileName + ".bdd", theOriginalBDD); // Save the Mapping PrintWriter writer = new PrintWriter(new FileOutputStream(stateFilePath + stateFileName + ".keys")); for( int i = 0 ; i < varIndex2NameMap.length ; i++ ) { writer.println(varIndex2NameMap[i]); } writer.close(); } public void clearStates() { for( ReasoningWithBDDState state : states.values() ) { state.discard(); } states.clear(); } public void end() { } public double getHeuristicRunningTime() { return variableOrderingHeuristic.getRunningTime(); } public long getBDDBuildingTime() { return bddBuildingTime; } public void restrict(String variableID, boolean value) { BDD varBDD = value ? bddFactory.ithVar(getVariableIndex(variableID)).id() : bddFactory.nithVar(getVariableIndex(variableID)).id(); theWorkingBDD.restrictWith(varBDD); } protected int[] initVars(int numVars) { int vars[] = new int[numVars]; for( int i = 0 ; i < numVars ; i++ ) { vars[i] = -1; } return vars; } protected abstract BDD createBDD(BDDFactory bddFactory, String orderingFormulasStrategy) throws Exception; public void saveState(String stateID) { ReasoningWithBDDState state = new ReasoningWithBDDState(this); state.save(); states.put(stateID, state); } public void restoreState(String stateID) { ReasoningWithBDDState state = states.get(stateID); state.restore(); states.remove(stateID); } public void discardState(String stateID) { ReasoningWithBDDState state = states.get(stateID); state.discard(); states.remove(stateID); } public BDD getBDD() { return theWorkingBDD; } public BDDFactory getBDDFactory() { return bddFactory; } /**************************************************************************************************************** * REASONING OPERATIONS ****************************************************************************************************************/ @Override public boolean isConsistent() throws OperationNotSupportedException { return !theWorkingBDD.isZero(); } @Override public double countValidConfigurations() throws OperationNotSupportedException { return theWorkingBDD.satCount(); } @Override public Iterator<Assignment> iterateOverValidConfigurations() throws OperationNotSupportedException { return new BDDSolutionsIterator<Assignment>(theWorkingBDD,varIndex2NameMap); } } class ReasoningWithBDDState { private ReasoningWithBDD rBDD; protected int savedVariables[]; protected BDD savedBDD; protected boolean savednewAssignmentsMade = false; public ReasoningWithBDDState(ReasoningWithBDD rBDD) { this.rBDD = rBDD; } public void save() { savedBDD = rBDD.getBDD().id(); savedVariables = new int[rBDD.variables.length]; System.arraycopy(rBDD.variables, 0, savedVariables, 0, rBDD.variables.length); savednewAssignmentsMade = rBDD.newAssignmentsMade; } public void restore() { rBDD.theWorkingBDD.free(); rBDD.theWorkingBDD = savedBDD; System.arraycopy(savedVariables, 0, rBDD.variables, 0, savedVariables.length); rBDD.newAssignmentsMade = savednewAssignmentsMade; } public void discard() { savedBDD.free(); savedVariables = null; rBDD = null; } }