Banner
Aggregation and Flocking


Aggregation and Coordination

Winter 2017

Psychology 120


Introduction

Our goal this quarter is to learn the basics of how to build agent-based models and how to use them to better understand, explain, and predict behavior by creating virtual experiments.  So far, we have learned how to create agents that move around in space.  Spatiotemporal movement is one of the fundamental characteristics organisms.  For social organisms, aggregation and coordination is a universal property of social behavior.  Today we will learn the basics of creating agents that aggregate and coordinate their behavior.  We will then have the basic ingredients to model just about any social behaviors and systems we can imagine.

Let’s begin by creating a new project “aggregate and coordinate” and create a more efficient move method.

	public void move(Environment state){
		if(state.random.nextBoolean(probMove)){
			xdir = state.random.nextInt(3)-1;
			ydir =  state.random.nextInt(3)-1;
		}
		int tempx = x;
		int tempy = y;
		x += xdir;
		y += ydir;
		if(collisions){
			Bag b = state.space.getObjectsAtLocation(x, y);
			if(b != null){
				xdir = state.random.nextInt(3)-1;
				ydir =  state.random.nextInt(3)-1;
				x = tempx + xdir;
				y = tempy + ydir;
			}
		}
		if(bounded){
			x = bx(state,x);
			y = by(state,y);
		}
		else{
			x = state.space.stx(x);
			y = state.space.sty(y);
		}
		state.space.setObjectLocation(this, x, y);
	}
	
	public int bx(Environment state, int x){
		if(x < 0 || x > state.space.getWidth()-1){
			xdir = -xdir;
			return x + xdir;
		}
		return x;
	}
	
	public int by(Environment state, int y){
		if(y < 0 || y > state.space.getHeight()-1){
			ydir = -ydir;
			return y + ydir;
		}
		return y;
	}

Aggregation

What rules would allow agents to aggregate together? There are a number of ways to specify rules for how agents aggregate, but let’s first think about the problem and then come up with a solution.

One thing we know is that for agents to aggregate, they move move towards each other.  Let’s look at Dictyostelium discoideum aggregate.

[youtube tpdIvlSochk]

It is clear from watching Dictyostelium discoideum move that they are moving towards each other but in a way that leads to aggregation into a single clump and perhaps more if we had a larger view.

Here is a video of an agent-based model of Dictyostelium discoideum aggregation:

[youtube lI33shsCxmg]

Spider crabs:

[youtube iQSHfutIzh8]

Human crowds:

[youtube Psvk1UjTang]

One way to implement aggregation is to introduce a majority rule. Roughly speaking, move in the direction when you “see” the most other agents. There are two problems here: (1) What does it mean to “see” and how far can an agent “see”? (2) How do you move towards the majority of other agents in your view?

Let’s call the “view” of an agent the area around an agent that is defined by its search radius.

View of Agent x

View of Agent x

So, let’s begin by adding two variables. One a Boolean variable for whether to aggregate or not and the second, a search radius, which is the view of an agent. We will also add the appropriate set and get methods and pass these values from the Envrionment to Agent agents we create.

Next, in Agents, we should add majority decision rules for each dimension in space.

 


 

       public int decidex(Environment state, Bag neighbors){
		int posx = 0, negx = 0;
		for(int i=0; i < neighbors.numObjs;i++){ 
                    Agent a = (Agent) neighbors.objs[i]; 
                    if(a.x > x)
		        posx++;
		    if(a.x < x) negx++; 
                 } 
                if(posx > negx){
		     return 1;
		}
		if(negx > posx){
		    return -1;
		}
		return state.random.nextInt(3)-1;
	}
	
	public int decidey(Environment state, Bag neighbors){
		int posy = 0, negy = 0;
		for(int i=0; i < neighbors.numObjs;i++){ 
                    Agent a = (Agent) neighbors.objs[i]; 
                    if(a.y > y)
		         posy++;
		    if(a.y < y) 
                         negy++; 
                } 
                if(posy > negy){
			return 1;
		}
		if(negy > posy){
			return -1;
		}
		return state.random.nextInt(3)-1;
	}

 


 

We can then introduce our aggregation method and add it to our step method and we are about done!

 


 

        public void aggregate(Environment state, int searchRadius){
		Bag neighbors = state.space.getMooreNeighbors(x, y, searchRadius, mode, true);
		if(neighbors.numObjs > 1){
			xdir = decidex(state,neighbors);
			ydir = decidey(state,neighbors);
			x+=xdir;
			y+=ydir;
			if(bounded){
				x = bx(state,x);
				y = by(state,y);
			}
			else{
				x = state.space.stx(x);
				y = state.space.sty(y);
			}
			state.space.setObjectLocation(this, x, y);
		}
		else{
			move(state);
		}
	}

 


 

	public void step(SimState state) {
		if(aggregate){
			aggregate((Environment)state);
		}
		else {
			move((Environment)state);
		}
          }

 


Another basic property of social organisms is that they can coordinate their behaviors with others. A relatively simple mechanism of coordination are flocking in which agents adjust their movement relative to their neighbors in their local neighborhood.

[youtube eakKfY5aHmY]

 

[youtube LlSPOnQw86A]

We can implement a very simple version of coordination by having our particles/agents adjust their direction of movement on both the x- and y-coordinates based on the direction of movement of their neighbors.


	public int decideCx(Environment state, Bag neighbors){
		int xdirp = 0, xdirn=0, xdir0 = 0;
		for(int i=0;i<neighbors.numObjs;i++){
			Agent a = (Agent)neighbors.objs[i];
			if(a.xdir < 0){ 
                              xdirn++; 
                        } else if(a.xdir > 0){
			      xdirp++;
			}
			else{
			      xdir0++;
			}
		}
		if(xdirp > xdirn && xdirp> xdir0){
			return 1;
		}
		if(xdirn > xdirp && xdirn> xdir0){
			return -1;
		}
		if(xdir0 > xdirp && xdir0> xdirn){
			return 0;
		}
		return xdir;
	}
	
	public int decideCy(Environment state, Bag neighbors){
		int ydirp = 0, ydirn=0, ydir0 = 0;
		for(int i=0;i<neighbors.numObjs;i++){
			Agent a = (Agent)neighbors.objs[i];
			if(a.ydir < 0){ 
                            ydirn++; } 
                        else if(a.ydir > 0){
			    ydirp++;
			}
			else{
			     ydir0++;
			}
		}
		if(ydirp > ydirn && ydirp> ydir0){
			return 1;
		}
		if(ydirn > ydirp && ydirn> ydir0){
			return -1;
		}
		if(ydir0 > ydirp && ydir0> ydirn){
			return 0;
		}
		return ydir;
	}

Our coordination method below is similar to the aggregate method above. Of course, their are many ways that agents can coordinate their behavior via individual decisions and this is one of the simpler examples.


	public void coordinate(Environment state, int searchRadius){
		Bag neighbors = state.space.getMooreNeighbors(x, y, searchRadius, mode, true);
		if(neighbors.numObjs > 1){
			xdir = decideCx(state,neighbors);
			ydir = decideCy(state,neighbors);
			x+=xdir;
			y+=ydir;
			if(bounded){
				x = bx(state,x);
				y = by(state,y);
			}
			else{
				x = state.space.stx(x);
				y = state.space.sty(y);
			}
			state.space.setObjectLocation(this, x, y);
		}
		else{
			move(state);
		}
	}

And our step method with the various options available.


public void step(SimState state) {
	if(aggregate && !coordinate){
		aggregate((Environment)state);
	}
	else if(coordinate && !aggregate){
		coordinate((Environment)state);
	}
	else if(coordinate && aggregate){
		coordinate((Environment)state);
		aggregate((Environment)state);
	}
	else {
		move((Environment)state);
	}
}

Finally, let’s develop some methods for uniquely placing agents in space.  First, in the initial conditions, we can introduce a method for uniquely and randomly placing agents in space.


	public void place(Agent a){
		boolean notPlaced = true;
		while(notPlaced){
			Bag b = space.getObjectsAtLocation(a.x, a.y);
			if(b == null){
				space.setObjectLocation(a, a.x, a.y);
				notPlaced = false;
			}
			else{
				a.x = random.nextInt(gridWidth);
				a.y = random.nextInt(gridHeight);
			}
		}
	}

Then we can rewrite our place agents method in Envirionment:

	public void placeAgents(){
		for(int i=0;i<n;i++){
			int x = random.nextInt(gridWidth);
			int y = random.nextInt(gridHeight);
			Agent a = new Agent(this,x,y);
			if(unique){
				if(i < gridWidth*gridHeight){
					place(a);
				}
				else{
					System.out.println("Too many agents for the dimensions of this space.");
					break;
				}
			}
			else{
				space.setObjectLocation(a, x, y);
			}
			schedule.scheduleRepeating(a);
		}
	}

In the Agent class, we need to introduce a place agent method that also resets an agents location back to where it was if it does not move.

	int tx;
	int ty;

	public Agent(Environment state, int x, int y) {
		super();
		this.x = x;
		this.y = y;
		this.tx = x; //these statements to the constructor method
		this.ty = y;

	public boolean placeAgent(Environment state){
		if(unique){
			Bag b = state.space.getObjectsAtLocation(x, y);
			if(b == null){
				state.space.setObjectLocation(this, x, y);
				tx = x;
				ty = y;
				return true;
			}
			else{
				x = tx;
				y = ty;
				return false;
			}
			
		}
		else{
			state.space.setObjectLocation(this, x, y);
			tx = x;
			ty = y;
			return true;
		}
	}

aggregate and coordinate.zip