sábado, 10 de janeiro de 2015

Let´s back to basis and find the steps to build the stupid agent again:

1. We delete the groovy files because we want to build a JAVA model;
2. After creating the first agent - bug - we create a private pointer to the gris - the projection.

Note: Projection vs. Context vs. Agent
Context represent a "soup" where the agents have no concept of space or relation. But it provides the basic infrastructure to define a population and the interactions of the population. A context can have a state with behaviors associated with it (e.g. A crop model for a context representing a framing village). More complex or adaptive behaviors can be applied giving to the context an agent-like quality. Moreover contexts can have sub-contexts. In a farming village a family can be a sub-context. A member of a sub-context is a member of the parent context. 

A Context contains Agents.


Projections are data estrutures designed to define and enfoque relationships between proto-agents within a given context. PRojections are added to a Context to allow the proto-agents to interact with one another. They have a many-to-one relationships with Contexts.  Switching between Projections is simple. No changes are required with  respect to the proto-agent code for a Projection to be able to work with that proto-agent. 

3. To define the Context, the "StupidModelContextBuilder" class is created. It implements the ContextBuilder<Object>. We add an ID to the Context. This class creates the context itself. We just have to define a projection. 
final ContinuousSpace<Object> space = ContinuousSpaceFactoryFinder
                .createContinuousSpaceFactory(null)
                .createContinuousSpace(
                                Constants.SPACE_ID,
                                context,
                                new RandomCartesianAdder<Object>(),
                                new repast.simphony.space.continuous.WrapAroundBorders(),
                                Constants.GRID_SIZE, Constants.GRID_SIZE);

It defines the type of the projection (continuous space) and uses a pointer to the context.

4. When adding an agent to the context, it receives a random value of X and Y because the function used to add the agents is the RandomCartesianAdder. But, additionally, a grid is added (another projection). The agents are not added the Grid automatically. They use the class SimpleGridAdder. 
for (int i = 0; i < Constants.BUG_COUNT; ++i) {
        final Bug bug = new Bug(grid);
        context.add(bug);
        final NdPoint pt = space.getLocation(bug);
        grid.moveTo(bug, (int) pt.getX(), (int) pt.getY());
}
return context;

5. We create a context with two projections: A 2D space and a Grid projections. The visualization is selected only for the Grid. 

quarta-feira, 15 de outubro de 2014

Agents' shape

I created a new class, AgentShape and then I've added some shapes I found in the Internet. Now the agent HabitatCell, when created, passes an instance of the shape which is called in the HabitatStyleOGL2D.

  • The new class

package stupidmodel;

import java.awt.Shape;
import java.awt.geom.GeneralPath;

public class AgentShape {
private boolean fillshape;
public AgentShape(){
}
/**
* Adapted From 'http://www.gailer-net.de/tutorials/java3/Notes/chap74/ch74_9.html'
* @param size
* @return path shape
*/
public final Shape getStar(int size )
  {
  int endX,endY;
  fillshape = false;
  GeneralPath path = new GeneralPath();
    // Six lines radiating from (x,y)
  path.moveTo(0, 0);
    for ( int i = 0; i<6; i++ )
    {
      endX = (int)(size*Math.cos( (2*Math.PI/6)*i ));
      endY = (int)(size*Math.sin( (2*Math.PI/6)*i ));
      path.lineTo(endX, endY); 
      path.moveTo(0,0);
    }
    return path;
  }
/**
* Creating another star
* Adapted From 'http://zetcode.com/gfx/java2d/shapesandfills/'
* Size multiplies by the fixed distance between the points.
* Higher values of size_rate means a smaller figure.
* @param size_rate
* @return path shape
*/
/* First, I divided by 85, then I move the star to the center...*/
private static double points[][] = { 
    { -1.7647/2, 0+0.47059/2 }, { 0.88235-1.7647/2, 1-0.88235+0.47059/2 }, { 1.17647-1.7647/2, 1-0.117647+0.47059/2 }, { 1.47059-1.7647/2, 1-0.88235+0.47059/2}, 
    { 2.35294-1.7647/2, 1-1+0.47059/2 }, { 1.76471-1.7647/2, 1-1.47059+0.47059/2 }, { 1.88235-1.7647/2, 1-2.23530+0.47059/2 }, { 1.17647-1.7647/2, 1-1.7647+0.47059/2 }, 
    { 0.47059-1.7647/2, 1-2.3530+0.47059/2 }, { 0.58824-1.7647/2, 1-1.47059+0.47059/2 }, { -1.7647/2, 0+0.47059/2} 
  /* original: 
    { 0, 85 }, { 75, 75 }, { 100, 10 }, { 125, 75 }, 
    { 200, 85 }, { 150, 125 }, { 160, 190 }, { 100, 150 }, 
    { 40, 190 }, { 50, 125 }, { 0, 85 } 
   
   
   
    */
};
public final boolean isFilledShape()
{
return fillshape;
}
public final Shape getFilledStar(double size ){
fillshape = true;
GeneralPath path = new GeneralPath();
path.moveTo(points[0][0]*size, points[0][1]*size);
for (int k = 1; k < points.length; k++)
    path.lineTo(points[k][0]*size, points[k][1]*size);
path.closePath();
return path;
}
/**
* Adapted from ''
* It apparently doesn't work because it doesn't accept Quadratic Curves.
* @return
*/
public final Shape getQuadArrow(){
GeneralPath path = new GeneralPath();
        float p1x = 10, p1y = 10;   // P1
        float p2x = 100, p2y = 10;  // P2
        float cx = 55, cy = 50;     // Control point of the curve
        float arrSize = 5;          // Size of the arrow segments

        float adjSize = (float)(arrSize/Math.sqrt(2));
        float ex = p2x - cx;
        float ey = p2y - cy;
        float abs_e = (float)Math.sqrt(ex*ex + ey*ey);
        ex /= abs_e;
        ey /= abs_e;


        // Creating quad arrow
        path.moveTo(p1x, p1y);
        path.quadTo(cx, cy, p2x, p2y);
        path.lineTo(p2x + (ey-ex)*adjSize, p2y - (ex + ey)*adjSize);
        path.moveTo(p2x, p2y);
        path.lineTo(p2x - (ey + ex)*adjSize, p2y + (ex - ey)*adjSize);
return path;
}
/**
* Adapted from 'http://www.java-forums.org/awt-swing/5842-how-draw-arrow-mark-using-java-swing.html'
* @param length
* @param barb
* @return
*/
public final Shape getArrow(int length,int barb){
  double angle = Math.toRadians(20);
      GeneralPath path = new GeneralPath();
      path.moveTo(-length/2, 0);
      path.lineTo(length/2, 0);
      double x = length/2 - barb*Math.cos(angle);
      double y = barb*Math.sin(angle);
      path.lineTo(x, y);
      x = length/2 - barb*Math.cos(-angle);
      y = barb*Math.sin(-angle);
      path.moveTo(length/2, 0);
      path.lineTo(x, y);
      return path;
}

}

  • The new constructor for the HabitatCell with the new variable shape:
public class HabitatCell {
        private static final double maximumFoodProductionRate = 0.01;
        private final int x, y;
        private double foodAvailability = 0.0;
        private Shape shape;
       

        public HabitatCell(final int x, final int y, Shape shape) {
                this.x = x;
                this.y = y;
                this.shape = shape;
               
        }
...


  • It is in the class  StupidModelContextBuilder that the shape is decided. Nevertheless, the shape can always change if we set a new shape for the agent while running.  I add this lines before the  agents are created.
Arrow:

final Shape sh = new AgentShape().getArrow(10,5);

Or FilledStar:


final Shape sh = new AgentShape().getFilledStar(8.0);

And then, creating the agents with the predefined shape:

for (int i = 0; i < Constants.GRID_SIZE; ++i) {
for (int j = 0; j < Constants.GRID_SIZE; j++){
final HabitatCell cell = new HabitatCell(i,j,sh);
context.add(cell);
grid.moveTo(cell, i, j);

terça-feira, 14 de outubro de 2014

Still the Stupidmodel

Now I wonder if I could modify the agents "HabitatCell" to become normal agents and forget the idea of cell versus agents.


What I did:
I decided to consider each HabitatCell as an agent that shares the grid with the other agents.

1- I've created a new class which extends DefaultStyleOGL2D (I had to look for a way to exchange the shape of the agents (http://repast.10935.n7.nabble.com/Changing-agent-shape-on-the-fly-using-extending-DefaultStyleOGL2D-td9543.html) to the folder 'observer':

package stupidmodel.observer;


import java.awt.Color;

import repast.simphony.visualizationOGL2D.DefaultStyleOGL2D;
import saf.v3d.scene.VSpatial;
import stupidmodel.HabitatCell;

/**
 * A simple custom color implementation for {@link HabitatStyle} agents.
 * 
 * <p>
 * The color of each agent depends on the food quantity.
 * Dark green means more food
 * </p>
 * 
 * @authorJosé  Cascalho (jose.cascalho)
 * @since 2014
 * @version $Id$
 */
public class HabitatStyleOGL2D extends DefaultStyleOGL2D {

/**
* @return a circle of radius 4.
*/
  public VSpatial getVSpatial(Object agent, VSpatial spatial) {
  //if (spatial == null) {
      spatial = shapeFactory.createRectangle(10, 10);
   
  //}
    return spatial;
  }


/**
* Returns a modified color value for an agent. Bit tricky, though.
* @see repast.simphony.visualizationOGL2D.DefaultStyleOGL2D#getColor(java.lang.Object)
*/
@Override
    public Color getColor(final Object agent) {
if (agent instanceof HabitatCell) {
final HabitatCell cell = (HabitatCell) agent;
            final double food = cell.getFoodAvailability();
            //System.out.println("Food availability:"+ food);
            final int strength = (int) Math.min(200 * food, 255);
            return new Color(0, strength, 0); // 0x000000 - black,
                                              // 0x00FF00 - green
    }
return super.getColor(agent);

}

2- At the StupidModelContextBuilder class I've added the following lines (and removed all the lines related to 'ValueLayer':



/** In the same grid, HabitatCell agents are added: */

for (int i = 0; i < Constants.GRID_SIZE; ++i) {
for (int j = 0; j < Constants.GRID_SIZE; j++){
final HabitatCell cell = new HabitatCell(i,j);
context.add(cell);
grid.moveTo(cell, i, j);
}

}
3- At the HabitatCell class the following method is simplified:

       @ScheduledMethod(start = 1, interval = 1, priority = 1)
        public void growFood() {
                foodAvailability += RandomHelper.nextDoubleFromTo(0.0,
                                maximumFoodProductionRate);

               

              

        }

4- Finally at the Agent Selection of the Options Editor, I've added the agent HabitatCell and at the grid style, selected the 'stupidmodel.observer.HabitatStyleOGL2D'.

Stupidmodel

I have been using the Stupidmodel (https://code.google.com/p/repast-demos/wiki/StupidModel) to learning how to create a Repast model.


I already found two problems, one which I didn't solve yet. Other I found the solution in the Internet. Rembering all, I'm using Repast S, the 2.2 version and the Stupidmodel was implemented using the version 2.0.

The two problems:

  • GetLabel() in the DefaultStyleOGL2D.

The suggestion made to add a visible label to each Bug agent doesn't work. I read that there was a 'bug' related to this problem. But I only found a correction made for the 2.1 version, which I tried in the version I use, the 2.2., and it didn't work. Although I've added the following method to the BugStyleOGL2D class, I never got as output the value of the label (even if it is just "bla bla");
@Override
public String getLabel(final Object agent) {
//System.out.print(bug.getSize());
if (agent instanceof Bug){
final Bug bug = (Bug) agent;
  // System.out.println(label); 
    return new String("bla bla"); 
}
return super.getLabel(agent);

}

  • Adding a value layer, to get the cells in the environment, each one an agent, and each one with an attribute. 
The problem is described in http://sourceforge.net/p/repast/mailman/message/29342013/. 

The window in the 'options editor' doesn't show the Value editor as it should. I fixed it modifying the xml file repast.simphony.action.display_1.xml, removing 

<valueLayers/>

and adding the following lines:

   <valueLayers>
     <string>foodValueLayer</string>
  </valueLayers>


segunda-feira, 29 de setembro de 2014

Scheduler

One of the most important classes in REPAST is the scheduler which, apparently, determines the action in a simulation. It is possible to define it with annotations. Is it the only way to put it running? Let's see.

Starting...

Reading "REPAST JAVA GETTING STARTED".
My goal: to adapt the model "zombies". As usual, trying to create new models based on previous examples.
The first link I discovered which is essential for every one learning how to use Repast: https://code.google.com/p/cscs-repast-demos/


J.