schelling2-3.0
Paul Johnson <pauljohn@ku.edu> 2005-02-06

I. Introduction

This is a version of the Thomas Schelling neighborhood segregation
model.  You can read more about it in Chapter 4 of Schelling's book,
Micromotives and Macrobehavior (WW. Norton, 1978) or in his article in
the Journal of Mathematical Sociology called "Dynamic Models of
Segregation" (Vol. 1, 1971, pp. 143-86).

Schelling's model describes two races of individuals that move about
on a flat world. It showed that, even if individuals are rather
tolerant, they end up clustered into homogenous groups.

This simulation model is the Schelling model on steroids.  Its got
just about all of the bells and whistles I can think of. It represents
the traditional two-race segregation model, but it can also allow
additional races. The agents can live in square (Moore) or in
diamond-shaped (von Neumann) neighborhoods of adjustable size. The
world can be a rectangle with "hard edges" or it can be a torus that
has "edge wrapping."  Those features are described below in greater
detail.  This package is intended to facilitate classroom exercises
and research.  It can be used in graphical user interface mode, but it
can also be used in batch mode.  It has complete data-output
facilities.

I have worked on the model on-and-off for about 5 years.  The original
was by Benedikt Stefansson, but the current version bares little
resemblence to the original model.  His was called schelling.  My
first batch of revisions was distributed as schelling2.  That was the
one that added the multi-race capability and fixed up some
calculations.  Then schelling2-2.0 was an "optimization" version.
Below you should find two separate sets of notes that explain the
sequencing of my revisions.  This package, schelling2-3.0, is adding a
lot of functionality for research purposes.

I was recently re-energized after a candidate for a posiiton in the
economics department made a presentation on variants of the Schelling
segregation model. That speaker, Nicolaas Vriend (U. of London),
presented a paper called "Schelling's Spatial Proximity Model of
Segregation Revisited."  I wanted to enable replication and extension
within the Swarm framework.  My current code does not exactly
replicate his work, but it should take researchers within a
stones-throw of it.  Plus I have many more variants built in.

I started with the working model that was distributed as
schelling2-2.0 and began adding the bells and whistles that I now
consider to be necessary for a "full service" Swarm model.  

I began with schelling2-2.0, which already had the multi-race
segregation model with a GUI display, and started working on data
output and the batch mode. The model already had many useful features,
many of which are described in this file.  As I review it, some of the
most interesting features are

1. User choice of neighborhood type, Moore or von Neumann

2. User choice of a torus ('edgeWrapping') or a rectangular world with
hard edges

3. User choice of the size of the neighborhood seen by the agents,
measured by "radius" (described below)

4. I avoid the "createActionForEach" scheduling idioms altogether.
Look in ModelSwarm, where you see I've used a (to me) more obvious,
simpler strategy of looping through all the agents, either 
consecutively or in a random order.


In the step from versions 2.0 to 3.0, the most important changes were
in the creation of a batch processing capability, so I now describe
that change.

II. Enable batch model processing.

That entails

A. Installing the capability for "command line argument processing".
   
That is handled by the Parameters class (the new files
Parameters.h and Parameters.m). The main.m is changed to tell
Swarm to use Parameters to digest command line options. 

Swarm has a global object called "arguments" and when the model
starts, the arguments object is created from the Parameters class.
So, anywhere you need a parameter value, you can ask the arguments
object for it.  Swarm has arguments typed as a generic thing, so the
compiler will warn you that it is not sure arguments can respond to
the messages you want.  You can let it know where to find those
methods--and stop warning you--by casting arguments when you use it.
For example, instead of

[arguments getValueX];

do

[(Parameters *) arguments getValueX];

Note it is necessary to import Parameters.h in order for this to work.

You will note a major departure from the usual Swarm thing when you
study the code.  The ModelSwarm.m is no longer the place where model
parameters live. Instead, the Parameters class is the place.  In
GUI mode, the model initializes itself by asking the arguments object
for values.  If there are no command line arguments, then the system
just retrieves the defaults.  On the other hand, if there are command
line arguments, they will override the defaults. 

For GUI users, there is still the ability to save parameter values to
files and load them.  I'll make sure the command line processing also
allows you to put a parameter file as an option.

I get tired of having to write get methods for every single parameter.
It is boring and tiresome. So I use a shortcut that Marcus Daniels
prepared.  The shortcut uses a Swarm probe to grab a variable by name.
These are used as C functions getInt and getDbl.  You ask the arguments
object for a varible named "worldYSize" like so

getInt(arguments,"worldYSize").

It returns what you want. That trick works for doubles and integers,
and BOOL (since they are treated as 0-1 integers). It does not work
for character variables.

B. Install a BatchSwarm class to act in place of the GUI observer when
run in batchmode (the new files are BatchSwarm.h and BatchSwarm.m).
In order to enable the system to write the raster image showing the
segregation pattern, I added in the classes that allow the creation of
an image in ppm format. These classes were put together originally by
Nelson Minar, then revised by Benedikt Stefansson, and then updated by
me.  I've used these in several projects.  The BatchRaster class
requires the BatchColormap class (see the new files BatchRaster.h,
BatchRaster.m, BatchColormap.h, BatchColormap.m, as well as the
colors.m file)

C. Re-organize the code according to the advice I recently put into
the Swarm tutorial modules simpleBatchBugX.  In the older style, one
writes completely separate output code in ObserverSwarm and
BatchSwarm, usually assuming that the GUI users (with ObserverSwarm)
will only want screen output while the Batch users want output in
files.  In GUI mode, I often want both kinds of output because, when
something interesting happens, I want a record of it.  

So here's the plan. Create a new class Output (Output.h, Output.m),
and in there put all the code related to output to the screen or into
files.  Inside that class, one can use the global variable
swarmGUIMode to tell if we are in batch mode or not. Output can then
be tailored to output the desired information.  The beauty here is
that the same file output can be obtained whether one is in GUI or
batch mode.

If you don't specify a "run" number, the model will use the current time in the file name, so if you run the model a few times, you end up with files like:


output_Tue_Feb__8_09_15_54_2005.data
hdfGraph_Tue_Feb__8_09_15_54_2005.hdf

The first is "raw text" output, which I find convenient, and the
second is an HDF5 data file, which you can view on screen with the
"h5dump" command or you can bring it into a statistical program.  The
HDF5 format preserves real numbers with greater accuracy than a text
file.

The Output class now has a "kitchen sink" flavor.  It creates
text file output.  It creates the same output in HDF5 format.  
As currently configured, in Batch mode it writes out a raster
for every time step.  


D. The GUI has a button to create a screen shot. 

In GUI mode, there's a toggle to turn on the writing of raster images.
If you just want a raster at a particular time, I created a button to
save a screenshot, which will snap the entire screen.


III. More about running batch mode simulations and parameter files.

Type

./schellingSwarm --help

and it will list the parameters I enabled for the command line.  


$ ./schellingSwarm --help
Usage: schellingSwarm [OPTION...]

  -s, --varyseed             Select random number seed from current time
  -S, --seed=INTEGER         Specify seed for random numbers
  -b, --batch                Run in batch mode
  -m, --mode=MODE            Specify mode of use (for archiving)
  -t, --show-current-time    Show current time in control panel
  -I, --inputfile=inputFilename   use parameters in file
      --no-init-file         Inhibit loading of ~/.swarmArchiver
  -r, --run=RunNumber        Run is...
  -v, --verbose              Activate verbose messages
  -x, --worldXSize=worldXSize   worldXSize
  -y, --worldYSize=worldYSize   worldYSize
  -e, --experimentDuration=experimentDuration
                             experimentDuration
  -d, --radius=radius        radius of vision
  -f, --fractionVacant=fractionVacant
                             fraction vacant cells
  -B, --fractionBlue=fractionBlue
                             fraction blue
  -R, --fractionRed=fractionRed   fraction red
  -?, --help                 Give this help list
      --usage                Give a short usage message
  -V, --version              Print program version

You can run models with the short form or long form arguments, e.g., 

short:

./schellingSwarm -B0.1 -R0.1 

long:

./schellingSwarm --fractionBlue=0.1 --fractionRed=0.1

Note, the short form has one dash and no equal sign, the long form
has two dashes with an equal sign.

You should be able to follow the example in Parameter.m and add
more. Generally speaking, you either want to use an input file or
specify parameters individually. Don't do both. The input file will
clobber the command line options.

Note in the GUI mode you have the options to load and save parameter
files.  You can use that mode to get a "first draft" of an input file
for use in the batch mode.  All you have to do is type a file name in,
hit enter, and then hit the button.  Then if you re-start in GUI mode,
you can type in the same name, hit enter, and the values are
re-loaded.  If you do that, and look at the parameter file, you see it
has lots of variables in it that the Parameters class inherits from
Swarm's Arguments class.

-------------------------------------
#Machine Generated Object-IVAR-Dump
@begin
zbits   135750962
argc    1
applicationName schellingSwarm
executablePath  /home/pauljohn/swarm/MySwarmCode/schelling2-3.0-Swarm-2.1/schellingSwarm
appModeString   default
version [no application version]
bugAddress      <NULL>
inhibitArchiverLoadFlag 0 '
inhibitExecutableSearchFlag     0 '
batchModeFlag   0 '
varySeedFlag    0 '
fixedSeedFlag   0 '
fixedSeed       0
verboseFlag     0 '
showCurrentTimeFlag     0 '
swarmHome       /usr/
defaultAppConfigPath    ./
defaultAppDataPath      ./
ignoringEnvFlag 1 '^A'
lastArgIndex    1
inputFilename   <NULL>
run     -1
experimentDuration      1000
worldXSize      80
[and so forth]
-----------------------------------

In GUI mode, it works fine to save a file and load it back in without
any fussing about.  In batch mode, however, those extra variables
create a little problem.  Some of the variables obliterate instance
variables that the system needs.  So if you create a parameter file,
say "test.setup", and then try to load it as the input file,

./schellingSwarm -b --inputfile="test.setup"

a segmentation fault results.  The fix is to manually edit the
"test.setup" file and cut out all of the variables that you don't want
or need, so it should look like this at the top:

-------------------------------------
#Machine Generated Object-IVAR-Dump
@begin
experimentDuration      1000
worldXSize      80
[and so forth]
-----------------------------------

With this package, I've included a cleaned up input file,
"cleaned.setup" that shows how it should work.
 

I am not a big fan of the input file idea when running in batch mode.
Generally, I prefer to run models over and over by using a script, and
in the script it will specify command line options.  So, I like to
have the default parameters set in Parameters.m itself, and then run
variations, as in

./schellingSwarm -b --worldXSize=100 --worldYSize=100 --seed=342342

I specify a different seed for each run, so I get variety but also keep
replicability.  I have a script (distributed separately) called
replicator that can manage this. There is also a nice program called
Drone that I've used for running in batch mode.

IV. Movement algorithms

I've recently been adding alternative "search algorithms" for the
agents to use as they try to find new places to live. In the original
version of this Schelling model, the agents moved at random to an open
space.  That method had this declaration:

- (BOOL)findEmptyLocationX: (int*)newX Y: (int*)newY

It does not search randomly in all directions, however. It mainly
looks to the right from a randomly chosen starting point.  I think
Benedikt did that because it was easy and to give students a problem
to work on. 

I believe Schelling's original paper said they move to the closest
spot where they find an improvement.  I wanted that search to be
patterened according to the type of network that is used.  But more
recently I've heard that some people think it is more interesting to
have the agents search only in perpendicular directions (left, right,
up, down), so I wrote that in.  I did not yet write a method where the
agents search for global optima.

The algorithms for finding open spots are in SchellingWorld, and the
agents themselves tell the world which algorithm to use.  For example,
to search in the vicinity of the current position in bands of
increasingly greater radius, the method in SchllingWorld:


- (BOOL)findNearestAcceptableColor: (int)col Tolerance:(double)tol X:
  (int*)newX Y: (int*)newY

The agent asks the world to find it the nearest space that is
tolerable.  Note, the algorithm could no doubt be accelerated and
optimized, but it is not too bad.  It respects the parameters for
the neighborhood type as well as edgeWrapping in the overall model.

I have written this so that the agent's search for a better position reaches
out in progressively larger neighborhoods OF THE SAME TYPE as the one
that the agent uses to measure racial compositionin the neighborhood.


For example, in a model with VN neighborhoods, the agent first searches


                  1
                1   1
                  1

and then

                  1
                1   1
              1       1
                1   1
                  1

and then

                  1
                1   1
              1       1
            1           1
              1       1
                1   1
                  1

The agent will take the first improvement found, and the algorithm starts at a random position
within this diamond shape each time.

On the other hand, a Moore neighborhood is just progressively larger squares

                1 1 1
                1   1
                1 1 1

                1 1 1 1 1
                1       1
                1       1
                1       1
                1 1 1 1 1

I have no idea if anybody else in the world wants it that way, but I did.
I did it this way because I'm stubborn.

I also have written a method that searches for the nearest open spot
in perpendicular directions and it does truly randomize the direction
of movement.  That one is called:

- (BOOL)findEmptyPerpendicularX: (int*)newX Y: (int*)newY

If you look in Person.m, you will see an if-then-else thing where I
tell the agent which method to use.  So far, I've just been hard
coding the selection and did not create a model parameter for it. But
students ought to be able to follow the example of the way I put in
other parameters to implement that enhancement.


V. TODO list

It seems to me that the most important next step is the development of
really nice indicators of segregation & clustering.  I'd first create
summary indicator of the diversity perceived by the agents.  I'd
consider making an average and also try to calculate some kind of
baseline perceived diversity that would occur with random placement.
I'd also try to calculate something like the average number of cells
an agent must move in order to find someone of the other type.  


---------------------------------------------------------
schelling2-2.0
Paul Johnson <pauljohn@ku.edu> 2003-04-16

I have a new class, Nhood2dCounter ("Neighborhood 2d Counter"), and I
want to facilitate its use in other projects.  So this new edition of
the Schelling model demonstrates what it does and how it works.

This edition of schelling2 is just a little polished and reorganized,
not substantively changed.  It shows off Nhood2dCounter.

Nhood2dCounter is now an abstracted class that anybody can use if they need to
have their agents ask a grid "how many visible things are there within
my neighborhood?"  The shape of the neighborhood is customizable. The
SchellingWorld has a set of those Nhood2dCounters, one for each race
in the model, so when an agent wants to know "how many people are like
me around here," the SchellingWorld has a quick answer.  There is a
verbose discussion of this in the Nhood2dCounter.h file.

In this edition, there is also some trivial
clarification/reorganization of the interface between the agents and
the SchellingWorld.  The Schelling world has several
collections/spaces in it. It has an "objectGrid", a Swarm Discrete2d
that records the positions of the agents. It also has the array of
Nhood2dCounters, each of which tells how many of a color are visible.
Now, when agents want to move, they no longer do the usual Swarm thing
of putting a "nil" at the current location and then adding self to
another location. Instead, when an agent moves, he just tells
SchellingWorld to remove it, or add itself. In Person.m, for example:

      [myWorld removeObject: self atX: x Y: y];
      [myWorld addObject: self atX: newX Y: newY];

The SchellingWorld does the bookwork of putting agents in and out of
objectGrid and also updating the Nhood2dCounter objects. I verified
that this does give the right numbers.

When one does actually need to use the objectGrid for something,
such as in the ObserverSwarm's display commands, just ask for
that grid from the SchellingWorld with "getObjectGrid". 

Please note: Concerning the search for empty spaces to which they
might move, I have left in this peculiar specification that the
original model had.  That searches globally and takes the first open
spot it finds.  The nifty new Nhood2dCounter could be used to just
scan for openings in the local neighborhood, but that is a substative
change I don't want to introduce when I'm trying to feature the
Nhood2dCounter itself.

Following is the README from the Schelling2, it
still holds.  I've not changed the interface or features, I just
abstracted Nhood2dCounter.  I wish to add it to the Swarm space
library, if I can get a show of hands.

-----------------------------------------------
Paul Johnson <pauljohn@ku.edu> 2003-02-16
Assoc Prof, Political Science
University of Kansas
Swarm Development Group

Thomas Schelling's model of racial segregation is a classic
in social science and it is one of the first agent-based
models (J. Mathematical Sociology, 1971).

I found Benedikt Stefansson's old Schelling model.  Benedikt was one
of the early Swarm users/educators and there were several times during
my Swarm break-in period when he supplied me with pivotal help.
(After that, I made a vow to always try to help the new guys.) I
believe Benedikt's code was updated by Lars-Erik Cederman, and
possibly some students, who also were at UCLA at the time.

Files in the most recent version I found had this mark at the top.

// Schellings Segregation Model
// Code by Benedikt Stefansson, <benedikt@ucla.edu>. 
// First version July 1997
// Second version February 1998

In Benedikt's model, there are 2 races, and the agents have a pre-set
tolerance coefficient. If the fraction of neighbors (in a Von Neumann
neighborhood) who have the same color as the agent is not as high as
the tolerance parameter, then the agent moves to a new location. The
new location is chosen completely at random, subject only to the 
requirement that the targeted space is not occupied.  The model showed
the famous result that Schelling emphasized, which held that even
a mild individual desire for same-ness in its environment can drive
a massive trend toward racial segregation.

I started updating, cutting out old fashioned stuff, adding features,
improving the display. I've removed some clases, significantly beefed
up record keeping in the SchellingWorld, added lots and lots of
options.

So, here you go.

I'm not responsible for any mistakes, but claim credit for
all success.

To tantalize you, I refer you to 2 pictures of the model.

The "standard" two race Schelling neighborhood model:

http://lark.cc.ku.edu/~pauljohn/Swarm/MySwarmCode/Schelling/schellingSnap1.jpg

A model with 6 races and an intolerant "majority" race, Moore
neighborhood with radius 4 (you can replicate by loading parameter
file flight1.setup):

http://lark.cc.ku.edu/~pauljohn/Swarm/MySwarmCode/Schelling/schellingSnap2.jpg

Same model as previous, except with VonNeumann neighborhood.

http://lark.cc.ku.edu/~pauljohn/Swarm/MySwarmCode/Schelling/schellingSnap3.jpg


In this version of the Schelling model, there are many new features. Here
are the most interesting ones.


1. The number of races can be 2 or higher.  
Different races show as different colors.  I only put in
color assignments for 20 races, but there is no reason a person
must stop there. (Look in ObserverSwarm.m, where you see I
had fun browsing the rgb.txt file for names of colors.)

In the original version, there were 2 races, RED and BLUE.  The user
could set the percentage of agents that were BLUE and also could
adjust tolerance parameters for both BLUE and RED.  When I added the
possibility of more races, it made it more confusing to set the
parameters for the individual classes.  I don't know how I could allow
the GUI to change the parameters for each race when the number of
races is variable, so here is what I have done.

The first two races are always BLUE and RED.  Users can set the
pfraction of agents that are BLUE and RED.  If there are only two
races, this exhausts the possiblities.  If there are 3 or more races,
then I have assumed that all the "extras" after RED and BLUE are all
equally likely. Thus, after taking out the fractions allocated by the
user for BLUE and RED, the remaining fraction is equally divided. So,
for example, if the user specifies that there are 7 races altogether,
and 30% of the agents are BLUE and 25% are RED, then that means that
45% of the agents are equally divided between 5 races.  That detail is
pretty easy to customize in the ModelSwarm.m file, if you want
something different.  Similarly, in the GUI, users can specify the
tolerance ranges for BLUE, RED, and OTHER types.


2. The user can decide whether or not the agents update their
information in an ASYNCHRONOUS or SYNCHRONOUS manner.  Each agent in
the list is given a chance to move at each time step.  What
information is available when they decide?  ASYCHRONOUS is the
standard and probably more desirable. If updating is ASYNCHRONOUS,
that means that the agents view their world, and move, and their new
position is instantly available to the next agent that decides whether
to move.  In a SYNCHRONOUS world, we want to represent the idea that
agents are moving simultaneously, so the impacts of agent moves are
not registered on the world until the whole set of agents is
processed.  The model is SYNCHRONOUS in the sense that, when an agent
is deciding whether to move, then that agent does so in light of the
state of the world at the beginning of the time step.  There is a
little wrinkle in this, however, because once an agent decides to
move, then that agent must look about for open positions.  A position
is open if no agent has yet moved there, and so there is a possibility
that, during a time step, one agent will move and take a position that
another one might like.  So the model is not in fact entirely
SYNCHRONOUS. Rather, the information agents have about the racial
composition of their neighborhood is updated SYNCHRONOUSLY.

3. This version can investigate edge effects.  The grid on which the
agents move can be either an edge-wrapping torus or a flat grid. If
the world is seen as a grid with edges, then the agents near the edge 
simply act as if there is nothing beyond the last cell, and their 
decisions are based only on the agents they can see from their position
as they look into the center of the grid. 

Benedikt's original model assumed the torus. I wanted the user to
choose at run time.  Implementing this required the elimination of the
DiscreteToroid class that was used in Benedikt's original model.  Now
allow SchellingWorld can be set to allow edge-wrapping to make the
space like a torus or to treat the space as a flat grid.


4. Neighborhoods, Neighborhoods!  Here you get fully adjustable size
(via radius parameter) and type (Von Neumann or Moore).  Now the
agent's neighborhood can have any radius you want.  If you choose a
Von Neumann neighborhood with radius 1, then the neighborhood over
which the agent is seen is like the 1's in here:

0 1 0 
1 1 1       vn radius 1
0 1 0 

0 0 1 0 0 
0 1 1 1 0 
1 1 1 1 1   vn radius 2
0 1 1 1 0 
0 0 1 0 0 


0 0 0 1 0 0 0 
0 0 1 1 1 0 0 
0 1 1 1 1 1 0 
1 1 1 1 1 1 1 vn radius 3 
0 1 1 1 1 1 0 
0 0 1 1 1 0 0 
0 0 0 1 0 0 0 


etc...

1 1 1 
1 1 1       moore radius 1
1 1 1 



Set the neighborhood by typing in a value in the probe display. The
default is
 
vonneuman

to get the standard "up down left right" neighborhood.  Actually,
anything starting with a "v" will do.

If you put anything else, it uses the other type of
neighborhood, which is a Moore neighborhood.

Benedikt had designed the neighborhood type input in that way.  I was
surprised to see it, I'm not sure I would have thought of it.  And I
kinda like it, now I see how it is done. See for yourself in
ModelSwarm.m. It treats the string that the user types in as an
array, basically, and it scans just the first letter to decide the
neighborhood type.



5. I added lots of record keeping in SchellingWorld. This is designed
to speed up the model.

Suppose each agent has to calculate the proportion of "like" agents
there are in the neighborhood.  If we have each agent cycle over the
whole neighborhood, that can make the model really slow.  There are
a lot of redundant calculations, as various neighboring agents will be 
making calculations about the same cells.  Furthermore, even if 
nobody moves from one time to the next, each agent has to go recalculate
from its neighborhood.

I wanted to save the time/cost of all those calculations.

If all agents have the same neighborhood type & radius, then the
agents need not cycle through their neighboring cells and
calculate. Instead, the SchellingWorld is automatically making those
calcualtions and any agent can just ask the SchellingWorld for the
"Visible Number" of a given race from a particular point in the grid.
This significantly accelerates the neighborhood analysis by the
agents. It is faster because agents who do not move do not have any
impact to change the environment of other agents, and the world needs
not make any new calculations.  So as the model approaches
equilibrium, the number of calculations required is dramatically
reduced.  I got the idea of using this accelerated grid while working
on a project with Dave Brochoux about political protest, which was
eventually published in Journal of Artificial Societies and Social
Simulation (2002).  I've since then adapted the same thing for my
Swarm version of the Nowak/Latane SocialImpact model (which I have
also available for download).  So, by the time I adapted that approach
for this model, the code is getting pretty clean. I'm thinking that
this scheme would be a nice addition to the Swarm library as a subset
of Discrete2d and I may take care of that.


6. In case you compare against the old version, you will see I have
eliminated the Neighborhood class.  In that version, the agent had a
Neighborhood object that listed its neighbors.  When the agent moved,
the Neighborhood object had to be recalculated.  This irritated me. In
this new version, the agents view their surroundings in the grid and
decide according to their wishes.  This means that one can easily
customize the sort of neighborhood that each agent uses, or, if the
agent is using the standard radius/type that is used in
SchellingWorld, then the agent can just ask the world for the
information it needs. The old Neighborhood class was always a
distraction to me and now, if we want, each individual agent can use
its own kind of neighborhood.

In case you want to know how you might implement the different
neighborhoods for agents, please look in Person.m for the method
"verifyNhoodData:". That method shows how you can iterate over 
neighboring cells and figure out the racial composition of a
neighborhood. I originally wrote that to double-check the data
I was getting from the SchellingWorld, but now it stands as an
example of how you can customize neighborhoods.


7. There is a new Toggle button to determine whether the agents are
processed in the same order every time or they are randomized at each
time step. The randomization makes the model run slower.




Interesting things to note.  

1. In this ModelSwarm, there are statistical distributions
"uniformDouble" and "uniformInteger".  I considered cutting those
because there are built in Swarm distributions for them. But I left
them as an example of how a user might want to create distributions
that draw from separate random number streams.  Since a simulation
will run the same way every time--using the same random number
streams--sometimes it is useful to make sure that one part of the
model always uses the exact same same random numbers while allowing a
specific part of the model to have random numbers that vary across
runs.  So I'm leaving these distributions to give some hints about how
that might be done.

2. I have tried my best to put in a standard format for the code. The
spacing and use of braces is in the Objective-C style.  So when you see
a method declared like so:

- (double)getRandomDoubleMin: (double)min Max: (double)max;

please be aware of the fact that the spacing is not an accident.
There is supposed to be a space after the dash at the beginning, and
there is not supposed to be a space between a type declaration and a
variable name.

Also, the style of the braces is like this

if (whatever)
{
   some stuff;
}

rather than this

if (whatever){
   some stuff
}

3. Many Swarm users do not realize that they can put a C function into
an Objective-C method.  To show how it can be done, in
SchellingWorld.m, I've put in an absolute value function into the
createEnd method.  Because the function is inside the method, the
function can ONLY be used inside the method.  It is a good way of
keeping the scope as small as possible.

4. Note that when I want output to the terminal, I often 

  fprintf(stderr, " blah ");

rather than

  printf( "blah");

This is a trick that Rick Riolo (U Mich) taught me. 
The fprintf has the advantage that it prints the information right
away. printf output is cached by the operating system until there is 
a bunch of it to write to the terminal.

5. If you are interested in learning about dynamic allocation of
memory, pointers, and macros, the SchellingWorld class has some
interesting and fairly clear example material.  It shows the dynamic
allocation of both one and two dimensional arrays.

6. I was unsure, after looking at Benedikt's model, whether the agent
was supposed to count itself in calculating the neighborhood
figures. It appeared to me that in the original model, the agents who
used a Von Neumann neighborhood did not count themselves, but the
agents in the Moore neighborhood did count themselves. 

If you look in Person.m's method

- (double)getFractionOf: (int)t 

You see I've elected to not count self in the neighborhood
tally , but as the comments indicate, it would be
simple/easy/uncontroversial/fun/convenient to change that.

7. At the last minute, I've become concerned about the way agents make
calculations about when to move.  I don't think this really is a
problem, but I'm meditating on it.

Benedikt originally wrote it like this:

 if((myTolerance<[myNeighborhood getFractionOf: (myColor==10)? 11 : 10]))
        [self moveToNewLocation];

There are two types, "10" and "11". This means that, if an agent is
type "10", then the agent would look to see the fraction of neighbors
that are the other kind, "11", and then move if it exceeds a threshold.

The problem is this: should "empty" cells be counted?  In Benedikt's
original model, if a cell is empty, it is still included in the
calculations, because the Neighborhood.m file's getFractionOf: method
assumes that if a cell is not a particular color, then it is the other
color.  Consequently, an empty cell has the same impact on an agent as
a neighbor of the same color.

I did not realize that implication when I first started revising.

When I generalized the model to allow many more races, I changed it so
that the agent finds the number of neighbors like it, and also it
finds out the number of occupied cells in the neighborhood, and then
they are divided to calculate "fracMyColor." Then 1-fracMyColor is the
fraction of "other types" in the neighborhood.

  double fracMyColor = [self getFractionOf: myColor];	
  if( myTolerance < 1.0 - fracMyColor  )
         [self moveToNewLocation];

The thing that concerns me is the treatment of blank spaces in the grid.
Benedikt's model assumed they were friends, whereas I'm not counting
them at all.

TODO list:


1. Summary indicator!

This model needs a segregation index. Badly. We want to use it to
compare outcomes. We need both an aggregate "objective" index of
segregation as well as an subjective agent-level indicator.  I suggest
summarizing agent observations of "diversity" by calculating "entropy"
from each spot in the grid.

2. Note this model uses the deprecated Swarm ObjectSaver to save
parameter snaps.  I don't think I've ever understood why the Swarm
team wanted to get rid of this simple/easy to use feature in favor of
the Lisp and hdf5 archiving, but there must have been good reasons.  I
think one reason was error-checking.  Anyway, that feature has been on
the endagered list for a long time, so it would be virtous to swap it
out for one of the other approaches. I've not done it, however.  In
fact, I've allowed the user to put in the file name for saved objects
in the GUI.
