package edu.neu.ccs.evergreen.model; import java.util.List; import java.util.Set; import java.util.TreeSet; import org.apache.log4j.Logger; import edu.neu.ccs.evergreen.exception.ContradictionException; import edu.neu.ccs.evergreen.ir.Relation; import edu.neu.ccs.evergreen.util.Polynomial; /** * Tracks the overall state of the system. */ public class State { private static final Logger LOGGER = Logger.getLogger(State.class); private Variables variables; private Weights weights; private Reductions reductions; private Assignments assignments; /** * Create a new state which is based off of the given information. * * @param variables * Variables in the system * @param weights * Weight of the system * @param reductions * Active reductions * @param assignments * Active assignments */ public State(Variables variables, Weights weights, Reductions reductions, Assignments assignments) { this.variables = variables; this.weights = weights.clone(); this.reductions = reductions.clone(); this.assignments = assignments.clone(); } /** * @see java.lang.Object#clone() */ public State clone() { return new State(variables, weights, reductions, assignments); } /** * Add an assignment to the state. * * @param assignment * New assignment */ public void addAssignment(Assignment assignment) { assignments.addAssignment(assignment); propagate(assignment); } /** * Propagate the given assignment through the system. * * @param assignment * Assignment to propagate */ private void propagate(Assignment assignment) { List constraints = variables.getConstraints(assignment .getVariable()); for (Constraint constraint : constraints) { int relationNumber = reductions.getRelationNumber(constraint); if (Constraint.reducable(relationNumber)) { int variablePosition = constraint.getPosition(assignment .getVariable()); int newRelationNumber = Relation.reduce(relationNumber, variablePosition, assignment.getValue()); if (relationNumber != newRelationNumber) { if (newRelationNumber == 0) { throw new ContradictionException("Contradiction", constraint); } reductions.addReduction(constraint, newRelationNumber); weights.switchWeight(relationNumber, newRelationNumber, constraint.getWeight()); findForcedAssignments(constraint, newRelationNumber, variablePosition); } } } } /** * Determine what variables are forced in the constraint which now has the * given relation number. * * @param constraint * Constraint to check * @param relationNumber * Constraint's current relation number * @param ignorePosition * Optional position to ignore in check; -1 is ignore nothing */ private void findForcedAssignments(Constraint constraint, int relationNumber, int ignorePosition) { if (Constraint.reducable(relationNumber)) { for (int position = 0; position < constraint.getRank(); position++) { if ((ignorePosition == -1) || (position != ignorePosition)) { int forcedValue = Relation.forcedValue(relationNumber, position); if (forcedValue != -1) { int forcedVariable = constraint.getVariable(position); LOGGER.trace(forcedVariable + "=" + forcedValue + " was forced by " + constraint); addAssignment(new Assignment(forcedVariable, forcedValue, extractForcedBy(constraint, relationNumber, position), constraint)); } } } } } private Set extractForcedBy(Constraint constraint, int relationNumber, int ignorePosition) { Set result = new TreeSet(); int index = 0; for (int position = 0; position < constraint.getRank(); position++) { if (position != ignorePosition) { result.add(constraint.getVariable(position)); index++; } } return result; } /** * Based on the starting state of the system, determine if any variables are * forced to begin with. */ public void unitPropagate() { for (Constraint constraint : getConstraints()) { int relationNumber = reductions.getRelationNumber(constraint); findForcedAssignments(constraint, relationNumber, -1); } } /** * Negate a variable and change all of the constraints it is in. * @param variable Variable to map */ public void nMap(int variable) { for (Constraint constraint : variables.getConstraints(variable)) { int relationNumber = reductions.getRelationNumber(constraint); int variablePosition = constraint.getPosition(variable); int newRelationNumber = Relation.rename(relationNumber, variablePosition); if (relationNumber != newRelationNumber) { reductions.addReduction(constraint, newRelationNumber); weights.switchWeight(relationNumber, newRelationNumber, constraint.getWeight()); } } } /** * Return an ordered list of decisions that were made. * * @return Decision assignments */ public List getDecisions() { return assignments.getDecisions(); } /** * How many variables have been given an assignment. * * @return # of variables assigned */ public int assignmentCount() { return assignments.size(); } /** * Does the given variable have an assignment? * * @param variable * Variable to check * @return True if it is unassigned. */ public boolean unassigned(int variable) { return !assignments.assigned(variable); } /** * Calculate the appMean of the system. * * @return appMean */ public double appMean() { // TODO: Convert to aspect Stats.biasCount++; return weights.solve(); } /** * Calculate the max bias of the system. * * @return Max bias */ public double maxBias() { // TODO: Convert to aspect Stats.biasCount++; return weights.maxBias(); } /** * For the given bias, determine how many are satisfied. * * @param bias * Bias * @return Percentage satisfied */ public double satisfiedPercentage(double bias) { return weights.satisfiedPercentage(bias); } /** * Generate the assignment this instance represents in the standard output * format. * * @param maxVariable * Maximum variable to include in output * @return Assignment string */ public String solutionString(int maxVariable) { return assignments.solutionString(maxVariable); } /** * Return the last decision that was made. * * @return Last decision assignment */ public Assignment getLastDecision() { return assignments.getLastDecision(); } /** * Return the assignment for the given variable. * * @param variable * Variable * @return Assignment */ public Assignment getAssignment(int variable) { return assignments.getAssignment(variable); } /** * Return the maximum variable in the system. * @return Maximum variable */ public int getMaximumVariable() { return variables.getMaximumVariable(); } /** * Return all of the constraints in the system. * @return List of constraints */ public List getConstraints() { return variables.getConstraints(); } /** * Return the raw polynomial that represents this state. * @return Polynomial */ public Polynomial getPolynomial() { return weights.getPolynomial(); } }