AntPheromones3/Readme.txt ------------------------- This is an extension of AntPheromones2 that shows * how to use classes from a third-party (ie non-repast, not your) libraries. * how to have ants created/removed during the course of a run. To get a copy of this program: cd YOURDIR mkdir AntPheromones3 cd AntPheromones3 mkdir bin classes Saves cp -r /users/rlr/RePast/Demos-3/AntPheromones3/src . <== note the dot! cp /users/rlr/RePast/Demos-3/AntPheromones3/bin/*.sh bin/ As usual, then edit this line: PROJECTDIR=/users/rlr/RePast/Demos-3/AntPheromones3 ^^^^^^^^^^^^^^^^^^ to have the path to where-ever you put your copy. Also, see the note below about modifying the bin/batchrun.sh so that it knows about the 3rd party commons/math library we use in this program---similar changes had to be made to bin/compile and bin/guirun.sh --- so if you add some other library, be sure to make similar changes to all those files. However, there is a easy way in compile.sh and guirun.sh -- just change this line: # add extra user libraries that should be included here USERDEFINEDLIBS= to this: USERDEFINEDLIBS=/appl/java/commons-math-1.0/commons-math-1.0.jar ========================================================================== Death and birth of Bugs during the run -------------------------------------- Suppose we want bugs to die and be born during the course of each run. For instance, suppose bugs die with a probability increasing as they get closer to the center. Lets see... lets assume: - the world is square and odd sized, with D = max distance (ie center to 0,0) - agents distance from center is d - run-time settable parameter probDieCenterMean/Var (pdcm,pdcv) from which agent is assigned a value when created. - Then prob for agent dying is pdc * ( 1 - d/D ) so that a) at center, d=0, so prob dying is max value, pdc. b) at farthest corner, D=D, so prob dying is pdc*(1-1) = 0. To keep a steady-state population, a new agent is created for each that dies, with new probRandMove drawn from the distribution specified for the run. The agents will be added in one of the 4 "edges", picked randomly. Question: For a non-zero probRandMoveMean and probRandMoveVar, what do we expect to happen to the population average of probRandMove over time? Note that we have to make some decisions: 1) when do agents die? A) we could have them die at the start or end of the Model step() method. That would make things easy, in that they are not dying in the middle of the loop that is activating bugs! B) If we have the Bugs have a chance of dying when the take their step() action, when do we remove them? We can't "naively" remove them from the bugList we are looping over to activate bugs, because the list size would change! - Solution 1: - Loop over the list using an Iterator object. - Have the Bug step() method return true if the agent dies. - Have the Iterator loop check the step() return, and if its true the iterator can remove the bug from the list right then, safely. - Solution 2: - The Bug step() method sets a bug instance variable dead to true if it dies. - After the loop to activate bugs is done, another "grim reaper" Iterator loop goes thru the bugList and removes bugs that return true for their getDead() method value. NB: What about bugs that are dead and still in the world? Do bugs that are active later in the same time step ignore those dead ones? 2) When are agents born? A) If it happens during the loop for activating bugs step() method, where do the new bugs get inserted in the list? If at the end, do they get a chance to step() at the same time they are born? B) Easier: just add enough bugs after all bugs have take a step() and if died, have b een removed. In this program, lets implement 1.B.2 and 2.B . Here is how I proceeded: - add the parameter, add IV to Bugs, assign at creation. add a measure of avgRandMoveProb and write to report file and the graph. test all this. - Add loop to add bugs if any have died, at the start of Model step() Test: add a kludge to remove first bug on list bin/guirun.sh ao=2 D=1 pdcm=0.1 pdcv=0.1 they appear on left edge, wander in. we see the probDieCenterMean change, too, now. hmmm..but eventually the left edge fills up, even tho it doesn't appear so! So the agents placed there are not getting cleared? Oh! when i removed the 0th bug on the list, i didn't remove it from the world! Ok, that is fixed. commment out the two test lines in Model step() - Now lets change the Bug step method to have the bugs maybe die. If they do, they return true from Bug step(). The Model step() must look for that and act accordingly to remove the agent. First: have bugs die at constant probDieCenter, independent of distance to center. We can test the removal of agents that way. Then change Bug methods to have that probability vary with distance to center. OK, that seems to work. Now change Bug checkBugDeath() to use distance to center to vary probDie. Lets create a Bug static variable maxDistanceToCenter, set it from buildModel(). Then we can calculate for each bug: pdc * ( 1 - d/D ) NOTE: I have used "center" but what i mean is location of source! NOTE: do D = distance from 0,0 to location of source. Test like this: bin/guirun.sh ao=2 D=1 pdcm=0.1 pdcv=0.1 Seems to work, and avgProbDieCenter seems to go down. Try for the other ao values. Try for a bigger world/more tants, higher pdcm to start: bin/guirun.sh ao=2 pdcm=0.2 pdcv=0.1 X=100 Y=100 numBugs=100 Interesting--they get lined up on the left wall, until pheromone gets out there! **===> NOTE: Could be a problem if more bugs than room on the wall!! Around 1100 or so steps, they start to stream in, from the center of the wall first, then farther out as pheromone gets to the corners. It would be interesting to also plot/report on the probRandomMove, and start it as > 0, too. So i added that. Test: bin/guirun.sh ao=2 pdcm=0.2 pdcv=0.1 prmm=0.2 prmv=0.1 X=100 Y=100 numBugs=100 My guesses are: - probRandomMove would go down with time -- best to stay near center - probDieCenter would go down -- select for them a little. *** But we need inheritance for this to really work well*** *** Which ants get to be parents?? *** I'll leave that as an exercise for the reader! In any case, an easy way to have "inheritance" is to use values for "genes" (probRandomMove, probDieCenter) take from "selected" parents to set the values of newly born bugs. Try this bin/batchrun.sh ao=2 pdcm=0.2 pdcv=0.1 prmm=0.2 prmv=0.1 X=100 Y=100 nB=100 T=10000 and look at those values at the end: badger: real 0m59.804s battistini: real 1m7.950s ?? [rlr@badger AntPheromones3]$ tail -4 report.00 9997 31.964 31.845 0.115 0.202 9998 31.439 31.723 0.113 0.201 9999 31.500 31.685 0.116 0.198 So the probRandomMove isn't enough of a factor to be selected on, i guess, but the probDieCenter is definitely lower than its starting 0.2 value. Try longer: bin/batchrun.sh ao=2 pdcm=0.2 pdcv=0.1 prmm=0.2 prmv=0.1 X=100 Y=100 nB=100 T=30000 battistini: 3m22.437s That's interesting: probRandMove is up a little! [rlr@battistini AntPheromones3]$ tail -4 report.00 29998 36.608 35.309 0.137 0.226 29999 36.660 35.544 0.143 0.224 30000 36.087 35.761 0.142 0.220 Its worth thinkg about why might randMoveProb change so little, and perhaps even move up. ========================================================================== Let's try this 3rd party library --- the Commons Math library: http://jakarta.apache.org/commons/math/ The API is located here: http://jakarta.apache.org/commons/math/apidocs/index.html The jar file is located here: /appl/java/commons-math-1.0/commons-math-1.0.jar on CSCS machines. For the commons math lib, the top level interface is org.apache.commons.math.stat.* where stat can be various more specific classes and packages, eg univariate.UnivariateStatistics ------------------------------------------------------------------------ To AntPheromones3.java: Let's use the DescriptiveStatistics class, which has a running-average capability. So first we import this: import org.apache.commons.math.stat.descriptive.DescriptiveStatistics; Then we need to declare an IV for an instance: public DescriptiveStatistics avgDStats; // stats on averageDistanceFromSource setup() if ( avgDStats != null ) avgDStats = null; buildModel(): // create the stats object; avgDStats = DescriptiveStatistics.newInstance(); avgDStats.setWindowSize( 10 ); // Ack--a constant!! step() First we move the calculation from stepReport to here, to be sure it happens each step: // calculate these numbers, store in instance variables calcBugStatistics(); Then we add this: // record some stats every step avgDStats.addValue( avgDistanceFromSource ); Modify stepReport() and writeHeaderCommentsToReportFile() We moved the calcBugStatistics() from here, and then changed this line to print the running average: s += String.format(" %6.3f %6.3f", avgDistanceFromSource, avgDStats.getMean() ); -------------------------------------------------------------------------------- Now we have to change bin/*.sh files, too: Put this in after the similar lines for the other libs: COMMONSMATHDIR=/appl/java/commons-math-1.0/ and add this into the java command line: ...:$JUNGDIR/jung-1.1.1.jar:$COMMONSMATHDIR/commons-math-1.0.jar $PACKAGENAME. ... ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Note the colon (:) separates the different jar files. ---------------------------------------------------------------------------------- Now it works, eg: bin/batchrun.sh T=100 I then noticed a problem---i hadn't told it to calc stats after it build the model, but before the first step, so i got this in the report file: # time D 0 0.000 NaN 1 6.925 6.925 So i changed buildModel() so that it does this: // some post-load finishing touches startReportFile(); // for the initial state, calculate these numbers, store in instance variables // record some stats every step calcBugStatistics(); avgDStats.addValue( avgDistanceFromSource ); Now it looks good (or at least plausible): # Avg Avg(10) # time D D 0 8.076 8.076 1 7.935 8.005 2 7.693 7.901 3 7.693 7.901 4 7.652 7.839 5 7.652 7.801 6 7.652 7.777 7 7.652 7.745 8 7.510 7.719 9 7.510 7.719 10 7.369 7.684 ... 33 1.524 2.158 34 1.248 1.873 35 1.166 1.742 36 1.166 1.622 37 1.166 1.622 38 1.166 1.516 39 1.166 1.346 40 1.166 1.346 41 1.166 1.232 42 1.166 1.196 43 1.166 1.196 44 1.166 1.166 45 1.166 1.166 ------------------------------------------------------------------------------ NB: one confusing point which i resolved as follows: I first looked to see what was in the jar file, and under what paths: jar tvf /appl/java/commons-math-1.0-RC1/commons-math-1.0-RC1.jar ... org/apache/commons/math/stat/univariate/DescriptiveStatistics.class ... I guess i still am confused about packages vs paths, as here is what the API gives as the class path: org.apache.commons.math.stat.descriptive.DescriptiveStatistics But I only could get it to work with this import: import org.apache.commons.math.stat.univariate.DescriptiveStatistics; I don't understand why the API doesn't give the same path as we see in the jar file (and we must use to import). Lesson: Use the jar tvf command to find out what the real paths are in the jar file and use those in the import's. Another (maybe better!) lesson: It turns out the above mis-match was because the online doc described a version that was later than the one we had installed, and they had changed the location of things in the meantime. We resolved that by updating to the latest version of the lib jar file /appl/java/commons-math-1.0 which is newer than the -RC1 version. ------------------------------------------------------------------------------