Run the model forward a number of steps to see if you can tell the difference. You can always check to verify that non-uniform neighborhoods are being used by setting the strategies of all neighbors of several randomly chosen people to certain distinct values.bsh% mixed_nbhd = new NeighborhoodConstructor() {
NeighborhoodConstructor n1 = new SquareNeighborhood(1);
NeighborhoodConstructor n2 = new RoundNeighborhood(2);
NeighborhoodConstructor n3 = new SquareNeighborhood(3);
LinkedList getNeighborhood(int i, int j, int w, int h, Agent[][] world, boolean b) {
double r = Math.random();
if (r < 0.333)
return n1.getNeighborhood(i,j,w,h,world,b);
else if (r < 0.666)
return n2.getNeighborhood(i,j,w,h,world,b);
else
return n3.getNeighborhood(i,j,w,h,world,b);
}
};
bsh% SetDefaultNeighborhood( mixed_nbhd );
SetStrategies(ExpandedNeighborhood(RandomSubset(population, 5), 1), 4);
Before the above command |
After the above command |
This is easier than it sounds. The following will guide you through the process of creating a new neighborhood, installing it, and using it in your model. It is assumed that you have a working version of the Java compiler installed. If not, go to Sun's web site and download a Java compiler for your computer (it's free).
Suppose you want X-shaped neighborhoods. One solution is the following:
public class XNeighborhood implements NeighborhoodConstructor {
int length;
public XNeighborhood(int length) {
this.length = length;
}
public LinkedList getNeighborhood(int i,
int j,
int width,
int height,
Agent[][] world,
boolean wrap)
{
LinkedList nbhd = new LinkedList();
int offset;
for (offset=1; offset<=length; offset++) {
nbhd.add( world[ (i+offset+width) % width ][ (j+offset+height) % height] );
nbhd.add( world[ (i+offset+width) % width ][ (j-offset+height) % height] );
nbhd.add( world[ (i-offset+width) % width ][ (j+offset+height) % height] );
nbhd.add( world[ (i-offset+width) % width ][ (j-offset+height) % height] );
}
return nbhd;
}
}
That's it. Compiling this and loading it into the model will give you X-shaped neighborhoods of any size. If you don't have a Java compiler installed but want to see how loading an extension class works, you can download a copy of XNeighborhood.class and follow the instructions on loading an extension class.
public class XNeighborhood implements NeighborhoodConstructor {This says we are defining a new class named "XNeighborhood" which implements the interface "NeighborhoodConstructor". In Java, implementing an interface is a promise that certain functions of the right kind are defined. The NeighborhoodConstructor interface only requires one function to be defined: getNeighborhood. It must return a linked list containing the neighbors.
int length;
There's no reason why we have to fix the size of the X. The member variable "length" is the length of one of the stems of the X.
public XNeighborhood(int length) {When creating a new instance of the XNeighborhood, we have to pass in the length of a stem. This value is stored in the variable "length". When we are done, the following command will create a new X-shaped neighborhood with a stem size of 3:
this.length = length;
}
bsh% x_nbhd = new XNeighborhood(3);
i | The x-coordinate of the agent whose neighborhood we are creating. |
j | The y-coordinate of the agent whose neighborhood we are creating. |
width | The width of the lattice. |
height | The height of the lattice. |
world | A two-dimensional array of agents. This provides direct access to the lattice (and hence the entire population). |
wrap | If "true", then the user has requested that neighborhoods wrap at the edge of the lattice; if "false," then the user has requested that neighborhoods do not wrap --- i.e., that the lattice has definite bounds. This value can be ignored (as this example does). |
Constructing the X-shaped neighborhood is straightforward: add agents in the northwest, northeast, southwest, and southeast corners, moving out from the starting position at (i,j). If you haven't seen "(i+offset+width) % width" before, its meaning probably isn't clear. That bit of code addsoffset to i, taking care to wrap around the edges of the lattice. ("N % M" returns the value of N modulo M.) With this code we are explicitly ignoring the user's request to wrap or not wrap at the edge of the lattice. Modifying this example so that it respects the user's request is left as an exercise.
The linked list of neighbors that will be returned is created in the line
LinkedList nbhd = new LinkedList();Neighbors are added to the list by calling the "add(...)" method. The majority of the getNeighborhood method consists of a for-loop that picks the right neighbors out of the lattice and adds them to the list.
public LinkedList getNeighborhood(int i,
int j,
int width,
int height,
Agent[][] world,
boolean wrap)
{
LinkedList nbhd = new LinkedList();
int offset;
for (offset=1; offset<=length; offset++) {
nbhd.add( world[ (i+offset+width) % width ][ (j+offset+height) % height] );
nbhd.add( world[ (i+offset+width) % width ][ (j-offset+height) % height] );
nbhd.add( world[ (i-offset+width) % width ][ (j+offset+height) % height] );
nbhd.add( world[ (i-offset+width) % width ][ (j-offset+height) % height] );
}
return nbhd;
}
import java.util.*;to the start of the file. If you like, you can download a copy of XNeighborhood.java. Save it in the same directory where net.jar is located.
From your operating system's command line (not the BeanShell command line), switch to the directory containing XNeighborhood.java and type:
javac -classpath "./net.jar" XNeighborhood.javaIf the gods of computation favor you, your machine should whir and chunk away for a few seconds and then stop. A new file named "XNeighborhood.class" has been created.
Move "XNeighborhood.class" into the same directory as net.jar.
Type addClassPath("."); at the BeanShell prompt. Once you have done this, the new class is available to the model. If you quit the model and restart, you will need to type addClassPath(".") each time to load the extension classes. This minor headache will be fixed in future versions.
bsh% x_nbhd = new XNeighborhood(3);and then create a new model.
bsh% SetDefaultNeighborhood(x_nbhd);