/* * CSP Project * Authors: * Jay Bernardo * Matt Rancourt * * File: Decide.java * * Contains the Decide class. Decide is a transition that simply checks for an * unassigned variable name in the formula and chooses it, adding it to M in the * positive state and set to true. * * TODO: Update with coin-flipping in phase 3. */ import java.util.*; import edu.neu.ccs.satsolver.*; class Decide extends Transition{ //HashMap updatePairs; PolynomialI polynomial; boolean doingInitial; /** * Constructor * @param M - Assignment * @param F - Formular */ public Decide(TransitionAssignment M, CSP F){ super(M, F); polynomial = null; } /** * Get the polynomail that we mutate in doTransition * @return - internal private polynomail */ public PolynomialI getPolynomial(){ return polynomial; } /** * Set the polynomial to a given polynomial * @param p - polynomial to set the internal private member to */ public void setPolynomial(PolynomialI p){ polynomial = p; } // TODO: Make stuff like comments later public void doingInitial(boolean value){ doingInitial= value; } /** * This method calculates a dictionary of RelationNumber Instance * pairs. That is, each time we see a relation added, we will add one * to the value for that key. If we remove a relation, we decrement * one value for that given key. * * @param c - CSP to examine * @return - a hashMap of Relation Number / Number of instances pairs * @throws RelationNumberOutOfBoundsException * @throws RankOutOfBoundsException * @throws InvalidVariableNamesLengthException * @throws InvalidVariableValueException */ private HashMap calculateUpdatePairs(CSP c) throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException{ HashMap updatePairs = new HashMap(); int i = 0; for(; i < c.numberOfRelations(); i ++){ Relation currentRelation = c.getRelationAt(i); // We need to "reduce" upwards to get the // relation in terms 3, if it's necessary Relation examineRelation = currentRelation; examineRelation = examineRelation.translateToRankThree(); // We are reducing this relation number, so decrement it in the dict Integer value = updatePairs.get(examineRelation.getRelationNumber()); if(value == null){ updatePairs.put(examineRelation.getRelationNumber(), -1); } else{ updatePairs.put(examineRelation.getRelationNumber(), value - 1); } // Reduce the relation Relation newRelation = currentRelation.reduce(); // We need to "reduce" upwards to get the // relation in terms 3, if it's necessary examineRelation = newRelation; examineRelation = examineRelation.translateToRankThree(); // We have added a new relation, so increment it in the dict value = updatePairs.get(examineRelation.getRelationNumber()); if(value == null){ updatePairs.put(examineRelation.getRelationNumber(), + 1); } else{ updatePairs.put(examineRelation.getRelationNumber(), value + 1); } } return updatePairs; } /** * TODO: Describe what reset does. Waiting for further phase because * this description will change over time. For now, reset just picks * the first unassigned variable and sets it to true * * TODO: Fix the incredibly unDRYness in this function. Much, much too wet. * * @return unused * */ public int doTransition() throws InvalidVariableValueException, RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, VariablePositionOutOfBoundsException{ String unassignedVariableName = F.findUnassignedVariableName(); if(unassignedVariableName == null){ // We will check for failstate FailState f = new FailState(M, F); if(f.doTransition() == 1){ System.out.println("\nFailState =>"); // We have failed System.out.println("Unsolvable"); System.exit(1); } // At this point, we haven't failed, so lets check if we have // a solution SolveState s = new SolveState(M, F); if(s.doTransition() == 1){ System.out.println("\nSolveState =>"); // We have failed System.out.println("Solved"); System.exit(1); } } CSP positive = F.duplicate(); positive.setVariable(unassignedVariableName, 1); HashMap hmPos = calculateUpdatePairs(positive); CSP negative = F.duplicate(); negative.setVariable(unassignedVariableName, 0); HashMap hmNeg = calculateUpdatePairs(negative); OutputI oPos = null; OutputI oNeg = null; if(doingInitial){ // We're doing input initial InputInitial inputPos = new InputInitial(positive.calculateInitialPairs()); InputInitial inputNeg = new InputInitial(negative.calculateInitialPairs()); oPos = edu.neu.ccs.satsolver.SATSolverUtil.calculateBias(inputPos); oNeg = edu.neu.ccs.satsolver.SATSolverUtil.calculateBias(inputNeg); } else{ // We're doing input update InputUpdate inputPos = null; InputUpdate inputNeg = null; int numberOfRelationsPos = positive.numberOfRelations(); int numberOfRelationsNeg = negative.numberOfRelations(); HashSet addedPairsPos = new HashSet(); HashSet removedPairsPos = new HashSet(); HashSet addedPairsNeg = new HashSet(); HashSet removedPairsNeg = new HashSet(); // Calculate pairs for pos Iterator iter = hmPos.keySet().iterator(); while(iter.hasNext()){ Integer relationNumber = (Integer)iter.next(); int value = hmPos.get(relationNumber); if(value > 0){ addedPairsPos.add(new Pair(relationNumber, (double)value/(double)numberOfRelationsPos)); } else if(value < 0){ removedPairsPos.add(new Pair(relationNumber, -1.0 * (double)value/(double)numberOfRelationsPos)); } } // Calculate pairs for neg iter = hmNeg.keySet().iterator(); while(iter.hasNext()){ Integer relationNumber = (Integer)iter.next(); int value = hmNeg.get(relationNumber); if(value > 0){ addedPairsNeg.add(new Pair(relationNumber, (double)value/(double)numberOfRelationsNeg)); } else if(value < 0){ removedPairsNeg.add(new Pair(relationNumber, -1.0 * (double)value/(double)numberOfRelationsNeg)); } } // If there were no added/removed pairs -- assume InputInitial if(addedPairsPos.size() == 0){ // We need to trick the outsourcing into thinking that we're really // doing an input initial. This kind of only really happens if we have one // relation, and its the zero relation. OR, if we have a case where after crazy // reductions we add and then remove the same amount of relations. This is // a border crazy case InputInitial inputPosx = new InputInitial(positive.calculateInitialPairs()); InputInitial inputNegx = new InputInitial(negative.calculateInitialPairs()); oPos = edu.neu.ccs.satsolver.SATSolverUtil.calculateBias(inputPosx); oNeg = edu.neu.ccs.satsolver.SATSolverUtil.calculateBias(inputNegx); } else{ inputPos = new InputUpdate(polynomial, addedPairsPos, removedPairsPos); oPos = edu.neu.ccs.satsolver.SATSolverUtil.updateBias(inputPos); inputNeg = new InputUpdate(polynomial, addedPairsNeg, removedPairsNeg); oNeg = edu.neu.ccs.satsolver.SATSolverUtil.updateBias(inputNeg); } } // Now we need to evaluate which one is better PolynomialI pPos = oPos.getPolynomial(); double biasPos = oPos.getMaxBias(); PolynomialI pNeg = oNeg.getPolynomial(); double biasNeg = oNeg.getMaxBias(); double resultPos = pPos.eval(biasPos); double resultNeg = pNeg.eval(biasNeg); // Add the variable of the appropriate "sign" // depending on what eval returned if(resultPos > resultNeg){ polynomial = pPos; M.add(new TransitionAssignmentVariable(unassignedVariableName, 1, true, true)); } else{ polynomial = pNeg; M.add(new TransitionAssignmentVariable(unassignedVariableName, 0, true, true)); } return -1; } }