package parameters; import java.util.*; import java.io.*; import java.awt.*; import java.awt.event.*; import main.BetterTokenizer; import main.GeneralInput; import iterators.MultiFloatReturn; public class ParameterSetArray { ParameterSet [] sets; int curSet = 0; private int numSlots; public int totNumSets = 0, numGroups = 0; public Vector tagNames = new Vector(); ParameterSet prototype = null; String curTag = "All"; // Will only return sets matching this tag. 'All' matches everything float lowThreshold = -1000, highThreshold = 1000; // Will only return sets with scores between these thresholds. String filename = ""; // Stores the name of the file where these param sets came from private final static int BLOCK_SIZE = 10; // Sends out action events when significant things happen to it (adding param set, deleting, etc.). private ActionListener actionListener = null; public final static String CLOSING_STRING = "Closing", ADDING_PARAM_SET_STRING = "AddingParamSet", REMOVING_PARAM_SET_STRING = "RemovingParamSet"; public ParameterSetArray() { sets = new ParameterSet[BLOCK_SIZE]; numSlots = BLOCK_SIZE; } public ParameterSetArray(ParameterSet prototype) { sets = new ParameterSet[BLOCK_SIZE]; numSlots = BLOCK_SIZE; this.prototype = prototype; } public void addSet(ParameterSet set) { if(totNumSets == numSlots) { ParameterSet [] temp_sets = sets; sets = new ParameterSet[numSlots + BLOCK_SIZE]; System.arraycopy(temp_sets, 0, sets, 0, numSlots); numSlots += BLOCK_SIZE; } // Find out where this parameter sets group is int i = 0; while(i < totNumSets && sets[i].getGroupNum() < set.getGroupNum()) i++; // Take care of case where this group num was originally skipped if(i < totNumSets && sets[i].getGroupNum() > set.getGroupNum()) i--; // Get to the end of the group while(i + 1 < totNumSets && sets[i + 1].getGroupNum() == set.getGroupNum()) i++; if(i < totNumSets) i++; // So the new one sits at the end of the old ones // Move the sets past here over to make room for(int j = totNumSets; j > i; j--) sets[j] = sets[j - 1]; // Finally, put the set into its spot sets[i] = set; totNumSets++; // Check whether this is a new tag type Enumeration enum = tagNames.elements(); String tag = set.getTag(); String str = ""; while(enum.hasMoreElements() && !tag.equals(str = (String)enum.nextElement())) {} if(!enum.hasMoreElements() && !str.equals(tag)) tagNames.addElement(tag); } public void remove(int set_num) { if(set_num >= totNumSets || set_num < 0) { System.out.println("Tried to remove a parameter set from a set array that was outside of the array"); return; } if(set_num < totNumSets - 1) { System.arraycopy(sets, set_num + 1, sets, set_num, totNumSets - set_num - 1); sets[totNumSets - 1] = null; } totNumSets--; } public void removeAll() { sets = new ParameterSet[BLOCK_SIZE]; numSlots = BLOCK_SIZE; totNumSets = 0; } public void loadParameters(BetterTokenizer tokenizer) throws Exception { int group_num = 0; try { String tag = GeneralInput.findNextIDToken(tokenizer); // Find the first set of par's while(!tag.startsWith("par")) tag = GeneralInput.findNextIDToken(tokenizer); while(true) { // Should throw an exception at the end of the file // Check if the last ID read marks the start of a new pars, and if so get the groupNum if(tag.startsWith("par")) { group_num = (Integer.valueOf(tag.substring(3))).intValue(); // Read the next id, which should be the tag tag = GeneralInput.findNextIDToken(tokenizer); } // Now make a new ParameterSet and let that read in everything else ParameterSet set = new ParameterSet(prototype, group_num, tag); set.loadParameters(tokenizer); addSet(set); tag = GeneralInput.findNextIDToken(tokenizer); } } catch(Exception e) {} // Ignore - it should be eof } public void saveParameters(PrintWriter ps, String indent) throws Exception { for(int set_num = 0; set_num < totNumSets; set_num++) { // Should save out tags here ps.println(indent + "&par" + set_num); ps.println(indent + "&IPARS"); sets[set_num].toString(ps, (indent + "\t")); ps.println(indent + "&endIPARS"); } } public ParameterSet getNextSet() { int set_num = curSet + 1; while(set_num < totNumSets && (sets[set_num].getScore() > highThreshold || sets[set_num].getScore() < lowThreshold || (!curTag.equals("All") && !curTag.equals(sets[set_num].getTag())))) set_num++; if(set_num == totNumSets) return null; curSet = set_num; return sets[curSet]; } public ParameterSet getPreviousSet() { int set_num = curSet - 1; while(set_num >= 0 && (sets[set_num].getScore() > highThreshold || sets[set_num].getScore() < lowThreshold || (!curTag.equals("All") && !curTag.equals(sets[set_num].getTag())))) set_num--; if(set_num < 0) return null; curSet = set_num; return sets[curSet]; } public ParameterSet getCurSet() { return sets[curSet]; } public int getCurSetNum() { return curSet; } public ParameterSet getSetNum(int num) { curSet = num; if(curSet < 0) curSet = 0; else if(curSet > totNumSets - 1) curSet = totNumSets - 1; return sets[curSet]; } public int getCurTagNum() { return tagNames.indexOf(sets[curSet].tag); } public ParameterSet getPrototype() { return prototype; } public ParameterSet goToBeginning() { // This is potentially a dangerous way to do it since it makes assumptions about what // getNextSet does - ie, that a curSet = -1 won't foul it up. curSet = -1; ParameterSet set = getNextSet(); if(curSet == -1) curSet = 0; // Just as protection return set; } public ParameterSet goToSet(int num) { curSet = num; if(curSet < 0) curSet = 0; else if(curSet > totNumSets - 1) curSet = totNumSets - 1; return sets[curSet]; } /** Moves the arrays pointer to the currently selected set to point to the input set. Returns that input set if it finds it in the array, otherwise returns null and moves the pointer to the last set in the array. */ public ParameterSet goToSet(ParameterSet set) { // Find it curSet = 0; while(curSet < getNumSets() && set != sets[curSet]) curSet++; if(curSet > totNumSets - 1) { curSet = totNumSets - 1; return null; } return sets[curSet]; } public boolean atBeginning() { int set_num = curSet; // Just use getPrevious to search back and see if there's something before this one that meets conditions // This is probably a bit dangerous - cause I'm assuming the only thing getPrevious does is change curSet if(getPreviousSet() == null) { curSet = set_num; return false; } else return true; } public boolean atEnd() { int set_num = curSet; // See note in gatBeginning above if(getNextSet() == null) { curSet = set_num; return false; } else return true; } /** Calculated the minimum and maximum distances between parameter sets in this and the input parameter set array. Distances are calculated as the pythagorean distance in n dimensions, where n is the number of parameters. Each parameter is scaled by its range before doing the calculation so that all parameters carry equal weight in the final distance.
This function is safe to use for comparing a paramsetarray with itself. */ public MultiFloatReturn calculateDistancesToSet(ParameterSetArray parray2) { float [] ranges = new float[prototype.getNumParams()]; float min_dist = 1e10f, max_dist = 0; // Precalculate ranges for(int i = 0; i < prototype.getNumParams(); i++) { if(prototype.getUpperBound(i) <= 0 || prototype.getLowerBound(i) <= 0) ranges[i] = 0; else if(prototype.getUpperBound(i) == prototype.getLowerBound(i)) ranges[i] = 0; else ranges[i] = (float)(Math.log(prototype.getUpperBound(i)) - Math.log(prototype.getLowerBound(i))); } ParameterSet set = goToBeginning(); ParameterSet other_set; while(set != null) { if(parray2 == this) // If comparing against ourself, save time by only doing new comparisons other_set = getNextSet(); else other_set = parray2.goToBeginning(); while(other_set != null) { float sum = 0; int num_params = 0; for(int param_num = 0; param_num < prototype.getNumParams(); param_num++) { if(ranges[param_num] > 0) { float num = (float)(Math.log(set.getValue(param_num)) - Math.log(other_set.getValue(param_num))); num /= ranges[param_num]; //if(num > 1) System.out.println("> 1: " + set.getName(param_num) + " " + set.getValue(param_num) + " " + other_set.getValue(param_num) + " " + ranges[param_num] + " " + num); num = num * num; sum += num; } } sum = (float)Math.sqrt(sum); if(sum < min_dist) min_dist = sum; else if(sum > max_dist) max_dist = sum; other_set = parray2.getNextSet(); } // If we are comparing set against itself, curSet would have been changed in inner loop. // So, before moving to next set, reset curSet goToSet(set); set = getNextSet(); } return new MultiFloatReturn(min_dist, max_dist); } public float getHighThreshold() { return highThreshold; } public void setHighThreshold(float threshold) { highThreshold = threshold; } public float getLowThreshold() { return lowThreshold; } public void setLowThreshold(float threshold) { lowThreshold = threshold; } public String getCurTag() { return curTag; } public void setCurTag(String tag) { curTag = tag; } public String getFilename() { return filename; } public void setFilename(String str) { filename = str; } public int getNumSets() { return totNumSets; } /** Call this before deleting the param set array. */ public void deleting() { updateOutput(CLOSING_STRING); } // Stock code for sending out action events public void addActionListener(ActionListener l) { actionListener = AWTEventMulticaster.add(actionListener, l); } public void removeActionListener(ActionListener l) { actionListener = AWTEventMulticaster.remove(actionListener, l); } public void updateOutput(String type) { if(actionListener != null) { actionListener.actionPerformed(new ActionEvent(this, ActionEvent.ACTION_PERFORMED, type)); } } }