package iterators; import java.io.*; import main.BetterTokenizer; import main.Cell; import main.Node; import main.Network; import main.Model; import stoppers.SimpleStop; import main.ModelRunner; import main.GeneralInput; import affectors.Affector; import parameters.ParameterSet; import main.MoreMath; import java.util.Calendar; import java.util.GregorianCalendar; import genegui.*; public class ModelIterator extends Object implements Runnable { protected Network network = null; protected Model model = null; /** The general purpose output file from an iterator. This is also the output file used by UberIterator. */ protected PrintWriter ps = null; protected String outFileName = "IteratorOut.txt"; public SimpleStop origStopper = new SimpleStop(200); public Cell[] cells; public int numCells; protected Thread runThread = null; protected boolean running = false; public Function theFunction; private String FunctionName = "Function"; protected float finalScore = 1f; /** Local copy of Parameters.nParsTV */ protected ParameterSet parsTV = new ParameterSet(); protected int nParsTV = 0; /** local copy of Parameters. */ protected float [] p; /** This is here to say whether the iterator should be saving stuff out to a file or not. */ protected boolean verbose = false; /** If true, and if verbose is true, opens outFileName and saves any output there. If false, assume that outfile is being set from somewhere else (like uberIterator). */ private boolean useOwnFile = true; private boolean bombed = false; private boolean varyAllParams = false; public int numFunctionCalls = 0; /** Pointer the the viewer that displays results for this iterator */ protected IteratorViewer TheIteratorViewer; // The first constructor is here only so that we can construct by name. // Need to call init right away, otherwise there will be all kinds of problems public ModelIterator() {} // Note - this init function may be called more than once - its called each time // a new model is loaded. public void init(Network network, Model model) { this.network = network; this.model = model; this.cells = model.cells; this.numCells = model.numCells; // parsTV = new ParameterSet(); // by default an iterator initializes itself with a plain-vanilla // Function object (see initial value of FunctionName) but if one is loaded from the init // file the name is stored and used in this step try { Class c = Class.forName("iterators." + FunctionName); theFunction = (Function)c.newInstance(); } catch(Exception e) { System.out.println(e.toString()); return; } theFunction.init(new ModelRunner(model, new SimpleStop())); theFunction.setStopper(origStopper); if (varyAllParams && model != null) parsTV = model.getModelParameterSet().copy(); } /** Called before each run of an iterator. This reset contains code that all iterators should do when they are reset. Subclasses should override to perform any additional operations they need to do when reset, but they should also call super.reset(). */ public void reset() { if(verbose && useOwnFile) { try { ps = new PrintWriter(new FileOutputStream(outFileName), true); } catch(IOException e) { ps = null; } } nParsTV = parsTV.getNumParams(); // set local values of nParsTV p = parsTV.getParVals(); // and p from parsTV bombed = false; numFunctionCalls = 0; } public ModelIterator copy() throws Exception { throw new Exception("Uh Oh: copy not implemented by this iterator"); } /** Returns the name of the iterator output file. @result String - Output file name. @author WJS */ public String getOutputFileName() { return(outFileName); } /** Returns the current ParameterSet for the Iterator @return ParameterSet @author WJS */ public ParameterSet getParameterSet() { return(parsTV); } /** Called when the output file is changed. @param String fileName - The new file name. @author WJS */ public void setOutputFile(String fileName) throws Exception { // Over-ride } public void setStopper(SimpleStop stop) { theFunction.setStopper(stop); } public SimpleStop getStopper() { return theFunction.getStopper(); } public void resetStopper() { theFunction.setStopper(origStopper); } public void setFunction(Function fun) { theFunction = fun; } public void setPrint(boolean m) { verbose = m; } public void print(String outString) { if(verbose) ps.print(outString); } public void println(String outString) { if(verbose) ps.println(outString); } public void println() { if(verbose) ps.println(); } public void setPrintStream(PrintWriter ps) { useOwnFile = false; // So we don't try to open or close the file this.ps = ps; } /** This is called when a cam file is being set up. It should print a list of the tags which this iterator will be outputting for each parameter set saved in the file. Following each tag should be either the string "number" or the string "flag", indicating whether the output will be numerical or text. Most iterators will not need to implement this function since they have no extra information to save beyond score, num function calls, and the parameters themselves */ public void saveOutputTags(PrintWriter ps, String inset) { origStopper.saveOutputTags(ps, inset); ps.println(inset + "&NumFunctionCalls\tnumber"); ps.println(inset + "&IteratorScore\tnumber"); } /** Saves tagged output from this iterator to a cam file. This is called by the UberIteratorFunction whenever it gets a good score. This function should save any useful information the iterator possesses about the set of parameters using the standard &tag format. The data should be either a number or a string. The cam file can't handle more complex data objects currently. Note that the Score is saved directly by the UberIteratorFunction. Other Iterators should call super.saveOutput() to get things that are general to all iterators saved (i.e. NumFunctionCalls).

Most iterators will not need to implement this function since they have no extra information to save beyond score, num function calls, and the parameters themselves*/ public void saveOutput(PrintWriter ps, String inset) { origStopper.saveOutput(ps, inset); ps.println(inset + "&NumFunctionCalls\t" + numFunctionCalls); ps.println(inset + "&IteratorScore\t" + finalScore); } /** If an iterator wants to save large amounts of information that doesn't fit into the tag format above, then it should return true in this method. If its running in an UberIterator, it will then get its 'ps' variable set to an appropriate file for dumping data. */ public boolean isSaveExtra() { return false; } /** Called when the iterator finishes running if isSaveExtra returns true. */ public void saveExtra(PrintWriter ps) {} public void loadParameters(BetterTokenizer tokenizer) throws Exception { // Go through looking for parameters, and read in each one GeneralInput.indent++; String info = ""; try { info = GeneralInput.findNextIDToken(tokenizer); while(!info.equals("endIterator")) { loadParameter(info, tokenizer); info = GeneralInput.findNextIDToken(tokenizer); } } catch(Exception e) { throw new Exception("Problem loading " + info + " : " + e.toString()); } GeneralInput.indent--; } protected void loadParameter(String info, BetterTokenizer tokenizer) throws Exception { Calendar calendar = new GregorianCalendar(); // If FixedPoint, specifies the fixed point iteration. Otherwise Adaptive stepsize integration if(info.equals("IntegrationMode")) { GeneralInput.nextToken(tokenizer); theFunction.runner.setRunMode(tokenizer.sval); } /* if(info.equals("FPStabilizer")) { if(GeneralInput.nextToken(tokenizer) != BetterTokenizer.TT_NUMBER) System.out.println("Warning: Bad or no FPStabilizer specified"); else theFunction.runner.setFPStabilizer((float) tokenizer.nval); } */ if(info.equals("VaryAllParams")) { parsTV = model.getModelParameterSet().copy(); varyAllParams = true; } else if(info.equals("ParamsToVary")) { parsTV.loadParameterValues(tokenizer,false); } else if(info.equals("ParamsToExclude")) { GeneralInput.indent++; String param_name = ""; try { param_name = GeneralInput.findNextIDToken(tokenizer); while(!param_name.equals("endParamsToExclude")) { parsTV.removeParameter(param_name); param_name = GeneralInput.findNextIDToken(tokenizer); } } catch(Exception e) { throw new Exception("Problem removing parameter " + param_name + " : " + e.toString()); } GeneralInput.indent--; } else if(info.equals("Stopper")) { GeneralInput.nextToken(tokenizer); String stopper_name = tokenizer.sval; Class c = Class.forName("stoppers." + stopper_name); SimpleStop stopper = (SimpleStop)c.newInstance(); stopper.init(model); origStopper = stopper; stopper.loadParameters(tokenizer); theFunction.setStopper(stopper); } else if(info.equals("Function")) { GeneralInput.nextToken(tokenizer); FunctionName = tokenizer.sval; Class c = Class.forName("iterators." + FunctionName); Function new_function = (Function)c.newInstance(); new_function.init(theFunction.runner); theFunction = new_function; theFunction.loadParameters(tokenizer); theFunction.setStopper(origStopper); } else if(info.equals("OutfileName") || info.equals("OutpathName")) { GeneralInput.nextToken(tokenizer); outFileName = tokenizer.sval; outFileName = outFileName + "/" + model.getName() +"_" + (calendar.get(Calendar.MONTH) + 1) + "_" + calendar.get(Calendar.DAY_OF_MONTH) + "_" + calendar.get(Calendar.HOUR_OF_DAY) + "_" + calendar.get(Calendar.MINUTE) + "_" + calendar.get(Calendar.SECOND); outFileName = outFileName + "_" + MoreMath.randomInt(100,9999); } else { System.out.println("Unrecognized parameter while loading iterator : " + info); } } /** Sets the IteratorViewer that this iterator reports to. @param IteratorViewer viewer @author WJS */ public void setIteratorViewer(IteratorViewer viewer) { TheIteratorViewer = viewer; } // The start() function is called to start the iterator searching. public void startRun() { doStartRun(); runThread = new Thread(this); runThread.setPriority(Thread.NORM_PRIORITY-1); runThread.start(); if (TheIteratorViewer!=null) { TheIteratorViewer.runStarted(); TheIteratorViewer.setMessagesText("Run started"); } } public void doStartRun() { running = true; } public void run() { doRun(); runThread = null; } public void doRun() { // Override this function for each particular iterator // Added this so that I could use the iterator base class // to do a single evaluation of a particular function reset(); finalScore = F(p); this.stopRun(); } public void stopRun() { if (theFunction != null) theFunction.stopRun(); if (p != null) parsTV.setFrom(p); // parsTV now holds the final pars - won't work if its an uberiterator or something else strange running = false; try { runThread.join(5000); } catch (Exception ex) { System.out.println(ex); } runThread = null; if (verbose && useOwnFile) ps.close(); if (TheIteratorViewer!=null) { TheIteratorViewer.runStopped(); TheIteratorViewer.setMessagesText("Run stopped"); } } public boolean didPass() { return theFunction.runner.stopper.didPass(finalScore); } public boolean isRunning() { return running; } public boolean didBomb() { return(bombed); } public float getValue() { return finalScore; } public void setState(ParameterSet state) { parsTV.setFrom(state); } public void getState(ParameterSet state) { state.setFrom(parsTV); } // override this to give an iterator a quit method public void quit() { System.out.println("Sorry, quit not implemented in this iterator"); } public void iterError(String err) { System.out.println("Iterator bombed: " + err); bombed = true; stopRun(); } public float F(float [] thePoint) { parsTV.setFrom(thePoint); try { numFunctionCalls++; float theVal = theFunction.evaluate(parsTV); return theVal; } catch (Exception e) { iterError(e.toString()); } return 0f; } /** //ELI 7/7/99 This method calls Function.continueEvaluate() to continue evaluating whatever function was running before. Before calling this, you should call F(). If F() returns and you then want to continue running the function (for instance to continue running a model with the default function) then call continueF(). continueF() will not reset the model before continuing the run. It also does not increment the numFunctionCalls variable. */ public float continueF(float [] thePoint) { parsTV.setFrom(thePoint); try { float theVal = theFunction.continueEvaluate(parsTV); return theVal; } catch(Exception e) { iterError(e.toString()); } return 0f; } }