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 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.
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:
The Sugarscape model (ss.nlogo) is a good introduction to the NetLogo language. It is further analyzed in overview3.html.
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
]
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
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
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.
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
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
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