SugarScape

SugarScape is a model developed by Joshua Epstein and Robert Axtell (see references.)

In the first version hungry agents roam the countryside looking for sugar. As they roam, they burn sugar at a rate determined by their metabolism. If an agent burns up all of his sugar before he finds more, he dies. An agent's ability to spot sugar is determined by how far it can see. This is controlled by its vision attribute.

When an agent discovers a patch of sugar, he consumes it and resumes his search for more sugar. Eventually, the patch will grow more sugar at a rate determined by its growBack attribute.

By playing with these parameters-- metabolism, vision, and growBack-- users can gain insight into phenomena such as carrying capacity, distribution of wealth, seasonal migration, and resource consumption.

In version 2 agents have finite life times and the ability to mate. In this version users can also gain  insight into phenomena such as fertility, cultural dynamics, proto-history, even combat.

In version 3 a second commodity is introduced: spice. An agent rich in sugar but poor in spice can trade with an agent in the opposite situation. The number of units of spice equivalent to a unit of sugar fluctuates according to supply and demand. The model provides interesting insights into the performance of markets populated by rational agents versus markets populated by evolving agents.

In version 4, disease is added to the model. Users can study the transmission of disease, the effects on the economy, and disease control policies.

CNP SugarScape

CNP SugarScape is a version of SugarScape 1.0 described above, but with a twist. Instead of vision, turtles have a broadcast range. Following the Contract Net Protocol (CNP), turtles broadcast requests for proposals (rfp's). Patches that receive these requests may send proposals back to the turtle. The turtle selects the best proposal, and moves toward the patch to pick up the sugar.

Here is CNP SugarScape at initialization. Note that there are 100 turtles. Each has a random broadcast range (0 – 5 patches), a random metabolism (0 – 0.3), and a random initial endowment of energy (0% – 100%). The average energy is 50.29%.

After a short amount of time the population stabilizes at 39 turtles with an average energy of 26.53%. This is the environment's carrying capacity.

Design

Every turtle in SugarScape has a proposal queue, every patch has an rfp queue. Turtles place rfps in the rfp queues of nearby patches. An rfp contains a reference to the turtle that created it.

If a patch decides to respond to an rfp in its queue, it places a proposal in the proposal queue of the turtle that sent the original rfp. The proposal contains a reference back to the patch that created it.

Here it is as a class diagram:

Implementation

The Sugarscape model (ss.nlogo) is a good introduction to the NetLogo language. It is further analyzed in overview3.html.

 

 

 

 

Agent Attributes

Including the proposal queue, a turtle has six attributes:

turtles-own [
   energy            ; dead = 0% <= energy <= 100%
   metabolism        ; rate sugar is burned by moving <= 0.3
   proposal-queue    ; patches put proposals here
   broadcast-range   ; how far can rfps be transmitted <= 5
   hasProposal       ; = true if turtle has accepted a proposal
   target            ; = the patch that made the accepted proposal
]

A patch has three attributes:

patches-own [
   sugar             ; = amount of sugar here <= 100%
   grow-back         ; how fast sugar is replenished <= 5
   rfp-queue         ; turtles put rfp's here
]

Agent Initialization

We begin with the standard initialization procedures:

to init-agents
   ca
   init-turtles
   init-patches
   repeat 5 [diffuse sugar .1]
end

to init-turtles
   crt 100
   ask turtles [init-turtle]
end

to init-patches
   ask patches [init-patch]
end

A turtle is initialized with a random energy, metabolism, position, and broadcast range. The redness of the turtle reflects its energy level.

to init-turtle
   set energy random 100
   set metabolism random-float 0.3
   set broadcast-range 5
   set hasProposal false
   set proposal-queue []
   setxy random-xcor random-ycor
   set color scale-color red energy 140 0
end

A patch is initialized with a random amount of sugar and a random grow back rate. The greenness of a patch reflects how much sugar is present.

to init-patch
   set sugar random 100
   set grow-back random 5
   set rfp-queue []
   set pcolor scale-color green sugar 140 0
end

Updating Agents

We begin with the usual machinery for updating agents:

to update-agents
   update-turtles
   update-patches
end

to update-patches
   ask patches [update-patch]
end

to update-turtles
   ask turtles [update-turtle]
end

A patch goes through cycles of making proposals and growing sugar:

to update-patch
   make-proposals
   grow-sugar
end

A turtle goes through cycles of making rfp's and seeking sugar:

to update-turtle
   make-rfps
   seek-sugar
end

Requesting and selecting proposals from patches

If a turtle has no proposal, it selects a proposal from its queue. If the queue is empty, the turtle broadcasts an rfp:

to make-rfps
   if not hasProposal
      [
         ifelse empty? proposal-queue
            [make-rfp]
            [select-proposal]
      ]
end

A turtle sorts its proposal queue by distance and awards the contract to the nearest patch:

to select-proposal
   set proposal-queue
      sort-by [distance ?1 < distance ?2] proposal-queue
   set target first proposal-queue
   set hasProposal true
   set proposal-queue []
end

A turtle "makes" and rfp simply by putting a reference to itself into the rfp queues of all nearby patches.

to make-rfp
   locals [near]
   set near patches in-radius broadcast-range
   ask near [set rfp-queue lput myself rfp-queue]
end

Note the use of myself instead of self. In NetLogo self always refers to the agent executing a command, while myself refers to the agent asking for a command to be executed.

Seeking and consuming sugar

Each cycle a turtle advances one step toward its target. When it arrives, it consumes sugar. If a turtle has no target, it moves twice the distance of its broadcast range looking for new sources of sugar:

to seek-sugar
   ifelse hasProposal
      [
         ifelse target = patch-here
            [consume-sugar target]
            [move-toward target 1]
      ]
      [move-toward one-of patches broadcast-range * 2]

end

A turtle converts sugar into equal amounts of energy:

to consume-sugar [p]
   locals [old-energy]
   set old-energy energy
   set energy max (list (value-from p [sugar]) 100)
   ask p [set sugar
              sugar - ((value-from myself [energy]) - old-energy)]
   set hasProposal false
   move-toward one-of patches 2 * broadcast-range
   type self
   print " has consumed sugar"
end

As a turtle moves, it consumes energy according to its metabolism rate:

to move-toward [goal steps]
   face goal
   fd steps
   set energy (energy - energy * metabolism * steps)
   set color scale-color red energy 140 0
   if (energy <= 0)
   [
      type self
      print " is dying"
      die
   ]
end

Making proposals and sugar

If a patch has sugar, it places a proposal, which is simply a reference to itself, into the proposal queue of every agent in its rfp queue provided that 1. the agent hasn't died and 2. the agent hasn't accepted a proposal from another patch:

to make-proposals
   locals [candidate]
   if (0 < sugar)
   [
      if (not empty? rfp-queue)
         [set candidate (first rfp-queue)]
      while [not empty? rfp-queue and
                        ((candidate = nobody) or
                        (value-from candidate [hasProposal]))]
      [
         set rfp-queue bf rfp-queue
         if (not empty? rfp-queue) [set candidate (first rfp-queue)]
      ]
      if not empty? rfp-queue
      [
         ask candidate
            [set proposal-queue (lput myself proposal-queue)]
         set rfp-queue bf rfp-queue
      ]
    ]
end

If sugar level is below 50, a patch incrementally adds a tiny bit of sugar on every cycle. Note the color being restored:

to grow-sugar
   if sugar < 50
      [ set sugar min (list 100 (sugar + grow-back)) ]
   set pcolor scale-color green sugar 140 0
end

Gathering statistics

Here are a few simple statistics:

to-report avg-energy
   locals [result]
   ask turtles [set result result + energy]
   report result / (count turtles)
end

to-report population
   report count turtles
end