AntPheromones2/Readme.txt
-------------------------
This adds some features to AntPheromones1:
- bugs are "smarter" -- they move to the best open neighbor cell,
unless they move randomly. Each has a probablity of moving
randomly, initially assigned at random from a Normal distribution.
The mean,var of that distribution are model parameters:
probRandMoveMean (prmm)
probRandMoveVar (prmv)
- Bugs color = function of their probablilty of moving randomly.
More blue -> less random, but s.t. probRandMove > 0.5 is colored minimally.
But the differences are still hard to see for low variance and many small cells.
Note: its worth thinking about what to do with things like bug color,
which are (usually) only relevant when in GUI mode.
Also, how to handle changes to the probRandMove via the GUI?
- Add custom buttons, to print the bugList, and to reset
the bug's probRandMove values.
- Add a graph that shows the mean distance to the pheromone source.
See the RePast HowTo pages on graphs, histograms, etc.
- Include alternative activation orders:
ao method
-- ------
0 step() -- as before, in fixed order
1 stepRWR() -- random-with-replacement (numBugs move each t step)
2 stepRWOR() -- random-without-replacement
(shuffle the arraylist, then process in that order)
- Add a randomMoveMethod (rmm) parameter:
0 move to random open neighbor cell from all open found
1 move to first open neighbor cell found ---> NOTE BIAS
To get a copy:
mkdir AntPheromones2
cd AntPheromones2
mkdir classes Saves
cp -r /users/rlr/RePast/Demos-3/AntPheromones2/src . <=== note the dot!
cp -r /users/rlr/RePast/Demos-3/AntPheromones2/bin . <=== note the dot!
cp -r /users/rlr/RePast/Demos-3/AntPheromones2/build.xml . <=== note the dot!
and then edit this line in the bin/*.sh files:
bin/compile.sh bin/guirun.sh bin/batchrun.sh
to set the PROJECTDIR path to where-ever you put your copy.
Then compile
bin/compile.sh
and test.
Example run commands (each using guirun.sh):
bin/guirun.sh ao=0 prmm=0.0 prmv=.0 rmm=0 numBugs=100 X=100 Y=100
step,step...for a while; note the behavior! run for a bit. pause.
custom-actions->print bugs
bin/guirun.sh ao=0 prmm=0.1 prmv=.1 rmm=0 numBugs=100 X=100 Y=100
run until they reach the center; change to rmm=1; can you see the difference?
do the aggregate measures show the difference?
bin/guirun.sh ao=0 prmm=0.01 prmv=.01 rmm=1 numBugs=100 X=100 Y=100
now can you see the difference in the pre "equilibrium" behavior?
note this is with a tiny amount of random movement...
bin/guirun.sh ao=0 prmm=0.3 prmv=.3 rmm=0 numBugs=100 X=100 Y=100
very heterogenous crowd of bugs -- some random, some not much.
it would be interesting to see if we could see a correlation
of probRandMove with agent location (ie, less random near center).
Run for a while, probe some agents and see.
(Note: the probe shows all the digits of double values, so put
cursor in the ProbRandMove slot and move left to see signif. digits)
Test replication:
bin/batchrun.sh ao=0 prmm=0.3 prmv=.3 rmm=0 numBugs=100 X=100 Y=100 T=500
bin/batchrun.sh iPFN=report.xml.00 rFN=report-x
diff report.00 report-x.00
========================================================================
Assignment:
0. Print the averageBugNbor1Count and averageBugNbor2Count
in the report file each time step.
1. Calculate the average distance to pSource for agents with
different randomMoveProbablities. For instance, one quick method:
Calculate the averages for agents in each quartile of
randomMoveProbability. Print these values out each step in the
report file.
2. Create and use a Comparator to sort the bugs on some other
feature, e.g., the amount of pheromone at the site they occupy.
3. Define a custom slider for probRandMoveMean.
When it is changed, re-assign probRandMove to all bugs,
using the distribution defined by that new mean.
4. Devise another measure (or more than one!) of the extent
of clustering. Calculate it each step, write to the report file.
5. Define two types of bugs:
type0: move as before, to pheromone
type1: move to lower pheromone!
fractionType0 parameter specifies what fraction of the
bugs are type 0 (and therefore how many are type1, too).
6. Define a bug happiness: e.g., pheromone where it is.
Have each bug calculate some kind of running average
of its recent happiness, e.g., averaged over the last
10 time steps.
Then average that over all bugs, and write the the report file.
=======================================================================
Extracts:
A. Activation Order in AntPheromones2.java:
// final means its a "constant" -- can't be changed during the run.
// Thus these become "symbolic constants" that make your program easier to read
// as seen in the if ... tests in step().
public int activationOrder; // control how bug-activation is done
public static final int fixedActivationOrder = 0;
public static final int rwrActivationOrder = 1; // random with replacement
public static final int rworActivationOrder = 2; // random without replacement
step()
if ( activationOrder == fixedActivationOrder ) {
// now the bugs get a chance to move around
for ( int i = 0; i < bugList.size(); i++ ) {
Bug aBug = bugList.get (i);
aBug.step ();
}
}
else if ( activationOrder == rwrActivationOrder ) {
int blsize = bugList.size();
int r;
for ( int i = 0; i < blsize; i++ ) {
r = getUniformIntFromTo( 0, blsize-1 );
Bug aBug = bugList.get ( r );
aBug.step ();
}
}
else if ( activationOrder == rworActivationOrder ) {
// here we shuffle the list, then process in order
SimUtilities.shuffle( bugList, uchicago.src.sim.util.Random.uniform );
for ( int i = 0; i < bugList.size(); i++ ) {
Bug aBug = bugList.get (i);
aBug.step ();
}
}
---------------------------------------------------------------------------
B. Add custom actions. Sorting an ArrayList
GUIModel - setup()
// init, setup and turn on the modelMinipulator stuff (in custom actions)
modelManipulator.init();
modelManipulator.addButton( "Print Bugs",
new ActionListener() {
public void actionPerformed(ActionEvent evt) {
printBugs();
}
}
);
modelManipulator.addButton( "Reset Bug probRandMove",
new ActionListener() {
public void actionPerformed(ActionEvent evt) {
resetBugProbRandMove();
}
}
);
AntPheromones2.java:
public void resetBugProbRandMove () {
for ( Bug aBug : bugList ) {
double r = getNormalDoubleProb( probRandMoveMean, probRandMoveVar );
aBug.setProbRandMove( r );
}
}
public void printBugs ( ) {
// sort the bugs based on distance to source
Collections.sort( bugList, new BugDistanceToSourceComparator() );
System.out.printf( "\nbugList:\n" );
System.out.printf( " ID X Y DistToSource\n" );
for ( Bug aBug: bugList ) {
System.out.printf( " %3d %3d %3d %.3f\n",
aBug.getID(), aBug.getX(), aBug.getY(), calcDistanceToSource(aBug));
}
calcBugStatistics(); // just in case...
System.out.printf( " avgDistToSource: %.3f\n", avgDistanceFromSource );
System.out.printf( "\n" );
}
We need this Comparator "inner class" -- it has one method compare(object1,object2)
which, by the value it returns, defines how any two objects in the list sort
when you use this comparator in the Collections.sort() call:
// BugDistanceToSourceComparator
// Callback for sort, to order by ascending distance to source of pheromone
// return +1 if a after b, 0 if a == b, -1 if a before b
// where a and b are values from the two objects to be sorted.
private class BugDistanceToSourceComparator implements Comparator {
public final int compare ( Object bug1, Object bug2 ) {
double d1 = ( (Bug) bug1 ).getDistanceToSource();
double d2 = ( (Bug) bug2 ).getDistanceToSource();
if ( d1 > d2 )
return 1;
else if ( d1 < d2 )
return -1;
return 0;
}
}
---------------------------------------------------------------------------
C. Graph the average across bugs of the number of neighbors each has
AntPheromones2.java -- collect and store the numbers to graph
public double averageBugNbor1Count; // avg of #bugs d=1 away from each bug
public double averageBugNbor2Count; // d=2 away
stepReport() -- calls calcBugStatistics();
public void calcBugStatistics() {
double totalNbor1Count = 0.0;
double totalNbor2Count = 0.0;
avgDistanceFromSource = 0.0;
for ( Bug aBug : bugList ) {
totalNbor1Count += aBug.getNumberOfNeighbors( 1 );
totalNbor2Count += aBug.getNumberOfNeighbors( 2 );
avgDistanceFromSource += calcDistanceToSource( bug );
}
if ( bugList.size() > 0 ) {
averageBugNbor1Count = totalNbor1Count / bugList.size();
averageBugNbor2Count = totalNbor2Count / bugList.size();
avgDistanceFromSource /= bugList.size();
}
}
Bug.java --
// return the number of neighbors the bug has, at distance d
public int getNumberOfNeighbors( int d ) {
Vector nbors = bugsWorld.getMooreNeighbors( x, y, d, d, false );
return nbors.size();
}
GUIModel.java -- create the graph, update it each step
import uchicago.src.sim.analysis.*;
private OpenSequenceGraph avgGraph; // grapher
buildDisplay()
// lets create a graph for average bug number of neighbors at 1,2 cells away.
avgGraph = new OpenSequenceGraph("Bug Stats", this);
avgGraph.setXRange( 0, 200 );
avgGraph.setYRange( 0, 8 );
avgGraph.setAxisTitles("time", "bug averages");
// now add the sequences (line plots of values) the graph will include
// note these sequences depend on calcBugStatistics being called first!
// each of these little wrapper classes has one method that
// returns the value we want plotted at each tick count.
class AverageBugNbor1Count implements Sequence {
public double getSValue() {
return averageBugNbor1Count;
}
}
class AverageBugNbor2Count implements Sequence {
public double getSValue() {
return averageBugNbor2Count;
}
}
avgGraph.addSequence("Avg. Bug 1-Nbor Count", new AverageBugNbor1Count());
avgGraph.addSequence("Avg. Bug 2-Nbor Count", new AverageBugNbor2Count());
// now actually display the graph on the screen.
avgGraph.display();
step() calls avgGraph.step();
public void step() {
super.step(); // the model does whatever it does
// add things after this for all displays (graphs, etc)
dsurf.updateDisplay();
avgGraph.step();
}
-----------------------------------------------------------------------------
D. Bugs -- smarter, change color based on probRandMove
We want to create bugs with heterogenous randMoveProb values.
We assign values from a normal distribution, with mean,var
set by model parameters.
AntPheromones2.java -- parameters defined, used to create bugs
public double probRandMoveMean; // mean,var of probRandMove
public double probRandMoveVar; // assigned to bugs as created
buildModel(): -- for each bug we create:
double r = getNormalDoubleProb( probRandMoveMean, probRandMoveVar );
aBug.setProbRandMove( r );
Bug.java
step() -- maybe move randomly, otherwise move steepest direction up:
// see if we move randomly...
if ( probRandMove >= model.getUniformDoubleFromTo( 0, 1 ) ) {
pt = findRandomOpenNeighborCell ();
if ( pt != null ) {
moved = moveTo( (int) pt.getX(), (int) pt.getY() );
if ( model.getRDebug() > 1 )
System.out.printf(" -- moved to random cell %d,%d.\n",x,y);
}
}
else { // try to move to a neighbor cell with more pheromone
pt = findMostPheromoneOpenNeighborCell ( neighborhoodRadius );
if ( pt != null ) { // we got one!
int newX = (int) pt.getX();
int newY = (int) pt.getY();
if ( pSpace.getValueAt( x, y ) < pSpace.getValueAt( newX, newY ) ) {
moved = moveTo( newX, newY );
if ( model.getRDebug() > 1 )
System.out.printf(" -- moved to better cell at %d,%d.\n",
x, y );
}
}
}
findRandomOpenNeighborCell()
random (rmm=0): pick randomly from list of open cells
biased (rmm=1): pick first one from list of open cells
==> Color the bugs based on randomMoveProb:
setup colorMap for bug colors and drawing
public static GUIModel guiModel = null;
public static ColorMap probRandMoveColorMap;
public static final int colorMapSize = 64;
public static final double colorMapMax = colorMapSize - 1.0;
// NOTE: more color at low end of map!
public static void setupBugDrawing ( GUIModel m ) {
guiModel = m;
probRandMoveColorMap = new ColorMap ();
for ( int i = 0; i < colorMapSize; i++ ) {
probRandMoveColorMap.mapColor ( (int) colorMapMax - i,
0.0, 0.0, i / colorMapMax );
}
}
When we set the probRandMove, set myColor
public void setProbRandMove( double d ) {
if ( d < 0.0 || d > 1.0 )
System.err.printf("\nsetProbRandMove(%.3f): out of [0,1]!\n", d );
else {
probRandMove = d;
if ( guiModel != null )
setBugColorFromPRM();
}
}
// setBugColorFromPRM
// use the probRandMove to set the color
// But note we want to the to map from [0,0.5] to full range of colors
public void setBugColorFromPRM () {
int i = (int) Math.round( 2.0 * probRandMove * colorMapMax );
i = (int) Math.min( i, colorMapMax );
myColor = probRandMoveColorMap.getColor( i );
if ( model.getRDebug() > 2 )
System.out.printf( "setBugColorFromPRM: probRandMove %.3f -> i %d.\n",
probRandMove, i );
}
When we draw, use myColor and draw the edge:
public void draw( SimGraphics g ) {
g.drawFastRoundRect( myColor );
g.drawRectBorder( bugEdgeStroke, Color.cyan );
}
==========================================================================
==========================================================================
==========================================================================
Let's test how activationOrder affects variability of runs.
activationOrder value
fixed 0
randomWithReplacement 1
randomWithoutReplacement 2
Try these repeats with different seeds:
bin/batchrun.sh T=200 ao=0 rFN=report-ao0 rN=00
bin/batchrun.sh T=200 ao=0 rFN=report-ao0 rN=01
There are big differences for the first 24 steps,
< 0 6.342
< 1 6.200
< 2 6.200
< 3 6.200
vs
> 0 8.028
> 1 7.904
> 2 7.688
> 3 7.688
But then it gets to the same state, as they all crowd around:
22 1.483
23 1.324
24 1.324
25 1.166
26 1.166
Lets try this again with some random movement:
bin/batchrun.sh T=200 ao=0 prmm=0.1 rFN=report-ao0-r rN=00
bin/batchrun.sh T=200 ao=0 prmm=0.1 rFN=report-ao0-r rN=01
Here is from report-ao0-r.00
# Avg
# time D
0 7.282
1 7.184
2 7.037
3 7.037
4 6.865
and from 01
# Avg
# time D
0 8.802
1 8.713
2 8.710
3 8.710
4 8.640
These are different all the way, with occassional
steps where they happen to be the same.
Lets see if it still runs identically if we start with
the same seed:
bin/batchrun.sh T=200 iPFN=report-ao0-r.xml.00 rFN=report-ao0-r-x rN=00
[rlr@badger AntPheromones2]$ grep seed report-ao0-r.xml.00 report-ao0-r-x.xml.00
report-ao0-r.xml.00: 1110030643172
report-ao0-r-x.xml.00: 1110030643172
[rlr@badger AntPheromones2]$ diff report-ao0-r.xml.00 report-ao0-r-x.xml.00
14c14
<
---
> report-ao0-r.xml.00
20c20
< report-ao0-r
---
> report-ao0-r-x
So...that all looks fine.
==================================================================================