Tutorial Three


This next iteration of our simple simulation will add more complicated agent behavoir as well as a display. In this version of the simulation, each agent will have some integer amount of wealth. Each iteration each agent (the "self" agent) will attempt a "transaction" with another agent that it is linked to. This other agent will be chosen at random from all the other agents that this agent is linked to. The "transaction" works as follows. If the other agent has more wealth than self, and that agent's wealth is greater than two, then two units of wealth will be taken from the other agent and given to self. If the other agent has less wealth than self, then self removes the link to the other agent, and creates a new one with an an agent chosen at random.

  1. Open RepastPy, if you don't already have it open. and load the Tutorial 2 project.

  2. Rename the model display name, model name and agent name and agent group name to Tutorial 3, TutorialThreeModel, TutorialThreeAgent and tutorialThreeNodes respectively. At this point you should know how to do this. If not, follow the beginning steps for tutorial 2.

  3. Save your project as tutorial3.sbp.




  4. Click on the Network Display component in the network component palette. Click on TutorialThreeModel.

    You should see a new component added to the project tree. This component will be labeled Network Display. Most components are added the model component, although some may be added to the agent. See the SimBuilder Component reference for what can be added to what.

  5. Click on Network Display if it is not already highlighted to display its properties.




  6. Choose circular from the Layout property.

    The layout property defines how the network will be laid out on the display. Circular will layout the nodes in a circle; Fruchman-Reingold will layout the nodes according to the Fruchman-Reingold algorithm (a "simulated annealing" type graph layout); Kamada-Kawai will layout the nodes according to the Kamada-Kawai algorithm; and Random will layout the nodes randomly. The Edit button can be used to set properties specific to each type of graph layout.

    That's it for adding a display. We'll now add some more complicated agent behavior.

  7. Save your project. Its okay to overwrite your current save file.

  8. Click on TutorialThreeAgent.

  9. Add a new field to TutorialThreeAgent called wealth. It should be of int type with a default value of 0, accessible but not a parameter. By accessible, you are creating the get/set accessor methods for the field, but not making it "probeable" via Repast.




  10. Click on the edit button of the actions property in TutorialThreeAgent, and select the step method if it is not already selected.

  11. Delete all the source code from the step action.

  12. Add the following to the step action.

    if (self.getNumOutEdges()):
      otherAgent = (TutorialThreeAgent)self.getRandomNodeOut()
      otherWealth = otherAgent.getWealth()
      if (otherWealth > self.wealth and otherWealth > 2):
        self.wealth = self.wealth + 2
        otherAgent.setWealth(otherWealth - 2)
      else:
        self.removeEdgesTo(otherAgent)
        otherAgent.removeEdgesFrom(self)
        self.makeRandomOutEdge(self.model.getAgentList(), DefaultDrawableEdge(), false)

    else:
      self.makeRandomOutEdge(self.model.getAgentList(), DefaultDrawableEdge(), false)

    self.setNodeLabel(String.valueOf(self.wealth))

    Make sure that the code is indented exactly as it is above. Here's the same code with line numbers added for reference.

    1. if (self.getNumOutEdges()):
    2.   otherAgent = (TutorialThreeAgent)self.getRandomNodeOut()
    3.   otherWealth = otherAgent.getWealth()
    4.   if (otherWealth > self.wealth and otherWealth > 2):
    5.     self.wealth = self.wealth + 2
    6.     otherAgent.setWealth(otherWealth - 2)
    7.   else:
    8.     self.removeEdgesTo(otherAgent)
    9.     otherAgent.removeEdgesFrom(self)
    10.     self.makeRandomOutEdge(self.model.getAgentList(), DefaultDrawableEdge(), false)
    11.
    12. else:
    13.   self.makeRandomOutEdge(self.model.getAgentList(), DefaultDrawableEdge(), false)
    14.
    15. self.setNodeLabel(String.valueOf(self.wealth))

    Line one here checks that the current agent (the "self" agent) has out edges. If so, then the indented code under the if statement is executed. Line 2 gets another agent at the other end of one of self's out edges, and stores that agent in a variable called otherAgent. The "(TutorialThreeAgent)" is called a cast, and ensures that the node returned from getRandomNodeOut will be treated by the compiler as a TutorialThreeAgent. Line 3 gets the amount of wealth this other agent has and stores that number in a variable called otherWealth. Line 4 tests that the other agent has more wealth than self and that this amount of wealth is greater than 2. We test that the amount is greater than two, so that wealth never falls below 0. If this test is true, then line 5 and line 6 add two units of wealth to self, and remove 2 units from the other agent. Lines 8, 9 and 10 are executed if the test on line 4 fails. Line 8 removes the edge to the other agent, and line 9 remove the edge from the other agent to self. Line 10 makes an edge at random between self and an agent in the list of all the agents. self.model contains this list and we get it by calling the getAgentList method. The false argument ensures that we do not get any self loops as the result. Line 13 gets executed if the test in line 1 fails. Line 13 is identical to line 10. The last line ensures that the displayed label for self is updated to self's current wealth amount. String.valueOf(...) returns the value of the self.wealth parameter as a String (a list of text characters) suitable for a label.

  13. Click OK to save your changes.

  14. Rename the labelMin and labelMax parameters in TutorialThreeModel to wealthMin and wealthMax and set their respective default values to 10 and 20. You can do this directly in the fields table itself.




    Recall that you edit fields by bringing up the fields editor and then clicking on the field you want to edit in the fields table. For example, to edit the name of the labelMax parameter, click on labelMax in the fields table, delete the text and type in wealthMax. Do the same to edit the default value.

    We now have a range of wealth from a minimum of 10 to a maximum of 20. What we want to do now is assign some value from this range to the wealth parameter of each agent. This kind of assignment is done is the model's initAgent's method. So,

  15. Bring up the actions editor to edit the initAgents action. (Click on the edit button for TutorialThreeModel's action property, and select the initAgents action if it is not already selected.)

  16. Replace the references to labelMin, labelMax and the variable i in the line

    i = Random.uniform.nextIntFromTo(self.labelMin, self.labelMax)

    with wealthMin, wealthMax and wealth respectively. The line should now look like

    wealth = Random.uniform.nextIntFromTo(self.wealthMin, self.wealthMax)

    This will assign a random integer from the range defined by self.wealthMin and self.wealthMax to the variable wealth. Replacing i with wealth is not necessary here, but it does give a clearer idea of what this random integer will be used for.

    Beneath this newly edited line, add

    agent.setWealth(wealth)

    This will set the agent's wealth to the value of the wealth variable. When you created the wealth field for TutorialThreeAgent and marked it as accessible, RepastPy silently created getWealth and setWealth accessor methods for you. You use the setWeath method to set the wealth value and the getWealth value to get the value.

    Edit the line

    agent.setNodeLabel("id - " + i)

    to read

    agent.setNodeLabel(String.valueOf(wealth))

    This sets the label of the node to the text value of the value of the wealth variable.

    Lastly replace the reference to TutorialTwoAgent in the for loop header to TutorialThreeAgent and tutorialTwoNodes with tutorialThreeNodes, just as you did in the second iteration of the tutorial. The entire action source should now read:


    for agent as TutorialThreeAgent in self.tutorialThreeNodes:
      wealth = Random.uniform.nextIntFromTo(self.wealthMin, self.wealthMax)
      agent.setWealth(wealth)
      agent.setNodeLabel(String.valueOf(wealth))

    Click OK to save your changes.

  17. Save and compile.

  18. Run the simulation.

    When you click the run button on the RePast toolbar, you should see a circular display of the network with the wealth displayed on each node. However, the wealth label and the links do not change while the simluation is running, although given the code you have just written, they should.

    In this case, the simulation is running correctly, wealth is being altered and links are being created a destroyed, but the display is not updating to show the changes. We need to edit the Network Display Component for this to work.

  19. Exit the RePast simulation and click on the Network Display component. Then click on the schedule property's edit button. This will bring up the schedule editor.






    RepastPy allows you to schedule components actions to execute at certain times in the simulation. Recall that when you run a RePast simulation the tick count on the toolbar increase by one for each iteration of the simulation. You can schedule component actions against these ticks with the schedule editor.

    In our case, we'd like to update the display every iteration of the simulation, that is, at every tick. So,

  20. Select the update_display action from the combo box of actions in the schedule editor.

    The actions box lists the actions available for scheduling, some of these may be user defined via the actions property and some may be internally defined by the component. The two listed here are internally defined by the Network Display component.

  21. Select EVERY_TICK from the execution combo box and make sure that the tick text area reads 1.

    The execution combo box lists the types of execution you can use to schedule your action. These types are

    1. EVERY_TICK -- the specified action executes every tick beginning at the tick specificed in the tick box.

    2. AT A SINGLE TICK -- the specified action executes once at the tick specificed in the tick box.

    3. AT INTERVAL -- the specified action executes at the interval specified by the tick box (e.g. every three ticks).

    4. AT END -- the specified action executes at the end of the RePast simulation, that is, when the stop button is pressed. The tick box is ignored in this case.

    5. AT PAUSE -- the specified action executes at a pause in the RePast simulation, that is, when the pause button is pressed, or when the step button is pressed (step runs a single iteration and then pauses). The tick box is ignored in this case.

    The execute last check box is available for the AT INTERVAL and AT A SINGLE TICK types. Checking execute last check box ensures that the specified action will execute after any regularly scheduled actions. So for example, if action x is scheduled to execute every tick beginning at 1, and action y is scheduled to execute only at tick 3, and has execute last checked then y will execute after x at tick 3.

    The master schedule property in the model component gives you a view of all the scheduled actions in relation to each other. You can edit their relative order there.

  22. Click the add button to add the action execution to the table.

    To delete an action execution click on it in the table and click the delete button.

    < There is no way to edit actions other than deleting them and re-adding them.

  23. Click OK to register your changes with the component.

  24. Save and compile.

  25. Run the RePast simulation.

    The wealth of each node will change a bit a first and then settle down as nodes begin to swap wealth back and forth. The projects directory contains several more sample models. They are good examples of how to create more complicated RepsatPy models.