/* * CSP Project * Authors: * Jay Bernardo * Matt Rancourt * * File: CSP.java * * This is the main CSP class. * * TODO: * * - Update description once class is fleshed out * * - Currently to find the percentage you have to iterate through *all* * relations. This could be potentially enhanced by changing given percentages * each time a new relation is added to/removed/reduced in the CSP */ import java.util.*; import java.io.*; class CSP { ArrayList relations; /** * Constructor for a CSP * @param relations - ArrayList of relations to assign to this CSP */ public CSP(ArrayList relations){ this.relations = new ArrayList(); Iterator i = relations.iterator(); while(i.hasNext()){ this.relations.add(i.next()); } } /** * Preprocesses the entire CSP to contain only * positive variables * * @throws RelationNumberOutOfBoundsException * @throws RankOutOfBoundsException * @throws InvalidVariableNamesLengthException * @throws InvalidVariableValueException */ public void preprocess() throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException { int i = 0; for(; i < relations.size(); i ++){ Relation r = getRelationAt(i); relations.set(i, r.preprocess()); } } /** * Returns a duplicate of "this" CSP * @return a duplicate of the CSP */ public CSP duplicate() throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException{ ArrayList relationCopies = new ArrayList(); Iterator i = relations.iterator(); while(i.hasNext()){ relationCopies.add(i.next().duplicate()); } return new CSP(relationCopies); } /** * Returns the number of relations in the CSP * @return number of relations in CSP */ public int numberOfRelations(){ return relations.size(); } /** * Returns the relation at the given index * @param index index of relation to return * @return relation at given index */ public Relation getRelationAt(int index){ return relations.get(index); } /** * Adds relation r to the CSP * @param r - relation to add */ public void addRelation(Relation r){ relations.add(r); } /** * Sets all instances of varName in the list of Relations * to the given value * @param varName - name of variable to assign * @param value - value to assign variable to */ public void setVariable(String varName, int value) throws InvalidVariableValueException{ Iterator i = relations.iterator(); while(i.hasNext()){ Relation r = i.next(); r.setVariable(varName, value); } } /** * Calculates a set of Pairs representing the * percentage of each relation in the formula * @return - set of pairs */ public Set calculateInitialPairs() throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException{ int numberOfRelations = numberOfRelations(); double incrementValue = 1.0/(double)numberOfRelations; // We will use a hashmap of relationNumber <-> Pair objects HashMap map = new HashMap(); // Build up the pairs in the dictionary Iterator iter = relations.iterator(); while(iter.hasNext()){ Relation r = iter.next(); int relationNumber = r.translateToRankThree().getRelationNumber(); Pair pair = map.get(relationNumber); if(pair == null){ map.put(relationNumber, new Pair(relationNumber, incrementValue)); } else{ map.put(relationNumber, new Pair(relationNumber, pair.getFraction() + incrementValue)); } } // We now need to create a set of the pairs for return HashSet set = new HashSet(); Iterator keys = map.keySet().iterator(); while(keys.hasNext()){ Integer key = (Integer)keys.next(); set.add(map.get(key)); } return set; } /** * Returns the percentage of a given relation * contained within the CSP * @param relationNumber -relation number to look for * @return percentage of relationNumber in CSP as a float */ public float percentageOfRelation(int relationNumber){ Iterator i = relations.iterator(); int count = 0; while(i.hasNext()){ Relation r = i.next(); if(r.getRelationNumber() == relationNumber){ count ++; } } return (float)count / (float)relations.size(); } /** * Prints out all the relations in a pretty format with newlines (by default) */ public void print(){ print(true); } /** * Overloaded version of print that lets us print without * newlines * @param newLined - true if we want newlines, false otherwise */ public void print(boolean newLined){ Iterator i = relations.iterator(); while(i.hasNext()){ Relation r = i.next(); r.print(); if(newLined == true) System.out.println(); else System.out.print(" "); } } /** * Finds any unassigned variable in a relation that * is contained within this CSP * @return Name of the unassigned variable, * or null if there are no unassigned variables */ public String findUnassignedVariableName(){ Iterator it = relations.iterator(); while(it.hasNext()){ Relation r = it.next(); String unassigned = r.findUnassignedVariableName(); if(unassigned != null){ return unassigned; } } return null; } /** * Parses the input string and returns the CSP representation * @return CSP represented by the string * * TODO : How should this handle parsing errors? Quit? Return null? */ static CSP parse(String input) throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException{ int i = 0; ArrayList relations = new ArrayList(); for(; i < input.length(); i ++){ // We skip all spaces and newlines if(input.charAt(i) != ' ' && input.charAt(i) != '\n'){ // The first thing we should see is capital R if(input.charAt(i) == 'R'){ // We have a valid relation. int relationNumber = -1; String variables[] = null; // Keep reading until we hit a ( String tmp = new String(""); i ++; // We don't want to include the R while(input.charAt(i) != '('){ tmp = String.format("%s%c", tmp, input.charAt(i)); i++; } // We now have the relation number // TODO: Catch the exception this might throw // and give a better output for it relationNumber = Integer.parseInt(tmp); // Next is to grab the variable names. At most // we can have three String var1 = new String(); String var2 = new String(); String var3 = new String(); i ++; // We don't care about the ( int j = 0; while(true){ // We are now after the opening (. If the next character is // a space or a newline, we want to proceed until we find something // that is not a space of a newline while(input.charAt(i) == ' ' || input.charAt(i) == '\n'){ i++; } // Now we've hit something that's not whitspace. If it's our delimiter, then // we're done. if(input.charAt(i) == ')'){ break; } // If it's not the delimiter, we're assuming it's a variable name. // Go through and extract it while there is no whitespace // We can't assume our delimiter (')') is spaced out, so we // have to check for that, too //System.out.println("Getting next chars."); while(input.charAt(i) != ' ' && input.charAt(i) != '\n' && input.charAt(i) != ')'){ char thisChar = input.charAt(i); if(! (String.format("%c", thisChar)).matches("\\w|!")){ System.out.println("Invalid variable name character: " + thisChar); System.exit(1); } if(j == 0){ var1 = String.format("%s%c", var1, thisChar); } else if(j == 1){ var2 = String.format("%s%c", var2, thisChar); } else if(j == 2){ var3 = String.format("%s%c", var3, thisChar); } else{ System.out.println("There are too many variables. Aborting"); System.exit(1); } i ++; } j++; } // If we found no variables, we want to bail out if(j == 0){ System.out.println("No variable names found. Aborting parse."); System.exit(1); } // Now we simply need to construct the proper // data structure for pasisng to the Relation constructor variables = new String[j]; variables[0] = var1; if(j > 1){ variables[1] = var2; if(j>2){ variables[2] = var3; } } relations.add(new Relation(relationNumber, j, variables)); } } } return new CSP(relations); } /** * Overloaded version of the parse method that simply * converts the InputString into a String and calls the * String version of parse * @param input - Input to be parsed (InputString) * @return - representation of the CSP by input */ static CSP parse(InputStream input) throws RelationNumberOutOfBoundsException, RankOutOfBoundsException, InvalidVariableNamesLengthException, InvalidVariableValueException{ return parse(input.toString()); } }