Skip to content

Commit

Permalink
quick doc improvements after another tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
Datseris committed Mar 11, 2021
1 parent 3a9dcb5 commit 365ff87
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "Agents"
uuid = "46ada45e-f475-11e8-01d0-f70cc89e6671"
authors = ["Tim DuBois", "George Datseris", "Ali Vahdati"]
version = "4.1.4"
version = "4.1.5"

[deps]
DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0"
Expand Down
7 changes: 3 additions & 4 deletions docs/src/tutorial.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ In the spirit of simple design, all of this is done by defining simple Julia dat
To set up an ABM simulation in Agents.jl, a user only needs to follow these steps:

1. Choose in what kind of space the agents will live in, for example a graph, a grid, etc. Several spaces are provided by Agents.jl and can be initialized immediately.
1. Define the agent type (or types, for mixed models) that will populate the ABM. This is defined as a standard Julia Type and contains two mandatory fields `id, pos`, with the position field being appropriate for the chosen space.
3. The created agent type, the chosen space, and optional additional model level properties (typically in the form of a dictionary) are provided in our universal structure [`AgentBasedModel`](@ref). This instance defines the model within an Agents.jl simulation.
4. Provide functions that govern the time evolution of the ABM.
A user can provide an agent-stepping function, that acts on each agent one by one, and/or model-stepping function, that steps the entire model as a whole. These functions are standard Julia functions that take advantage of the Agents.jl [API](@ref).
1. Define the agent type (or types, for mixed models) that will populate the ABM. This is defined as a standard Julia `struct` and contains two mandatory fields `id, pos`, with the position field being appropriate for the chosen space.
3. The created agent type, the chosen space, and optional additional model level properties (typically in the form of a dictionary) are provided in our universal structure [`AgentBasedModel`](@ref). This instance defines the model within an Agents.jl simulation. Further options are also available, regarding schedulers and random number generation.
4. Provide functions that govern the time evolution of the ABM. A user can provide an agent-stepping function, that acts on each agent one by one, and/or model-stepping function, that steps the entire model as a whole. These functions are standard Julia functions that take advantage of the Agents.jl [API](@ref).
5. Collect data. To do this, specify which data should be collected, by providing one standard Julia `Vector` of data-to-collect for agents, and another one for the model, for example `[:mood, :wealth]`. The outputted data are in the form of a `DataFrame`.


Expand Down
47 changes: 23 additions & 24 deletions examples/schelling.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,31 +11,38 @@
# the following definition of Schelling's segregation model:

# * Agents belong to one of two groups (0 or 1).
# * The agents live in a two-dimensional Chebyshev grid (8 neighbors per position).
# * If an agent is in the same group with at least three neighbors, then it is happy.
# * The agents live in a two-dimensional grid with a Chebyshev metric.
# This leads to 8 neighboring positions per position (except at the edges of the grid).
# * Each position of the grid can be occupied by at most one agent.
# * If an agent has at least `3` neighbors belonging to the same group, then it is happy.
# * If an agent is unhappy, it keeps moving to new locations until it is happy.

# Schelling's model shows that even small preferences of agents to have neighbors
# belonging to the same group (e.g. preferring that at least 30% of neighbors to
# belonging to the same group (e.g. preferring that at least 3/8 of neighbors to
# be in the same group) could lead to total segregation of neighborhoods.

# This model is also available as [`Models.schelling`](@ref).

# ## Creating a space

# For this example, we will be using a Chebyshev 2D grid, e.g.

space = GridSpace((10, 10); periodic = false)

# Agents belonging in this type of space must have a position field that is a
# `NTuple{2, Int}`. We ensure this below.

# ## Defining the agent type

using Agents
using StatsBase: mean

mutable struct SchellingAgent <: AbstractAgent
id::Int # The identifier number of the agent
pos::Dims{2} # The x, y location of the agent on a 2D grid
mood::Bool # whether the agent is happy in its position. (true = happy)
group::Int # The group of the agent, determines mood as it interacts with neighbors
id::Int # The identifier number of the agent
pos::NTuple{2, Int} # The x, y location of the agent on a 2D grid
mood::Bool # whether the agent is happy in its position. (true = happy)
group::Int # The group of the agent, determines mood as it interacts with neighbors
end

# Notice that the position of this Agent type is a `Dims{2}`, equivalent to
# `NTuple{2,Int}`, because we will use a 2-dimensional `GridSpace`.

# We added two more fields for this model, namely a `mood` field which will
# store `true` for a happy agent and `false` for an unhappy one, and an `group`
# field which stores `0` or `1` representing two groups.
Expand All @@ -49,12 +56,6 @@ end
# end
# ```

# ## Creating a space

# For this example, we will be using a Chebyshev 2D grid, e.g.

space = GridSpace((10, 10), periodic = false)

# ## Creating an ABM

# To make our model we follow the instructions of [`AgentBasedModel`](@ref).
Expand Down Expand Up @@ -106,7 +107,6 @@ function initialize(; numagents = 320, griddims = (20, 20), min_to_be_happy = 3,
end
return model
end
nothing # hide

# Notice that the position that an agent is initialized does not matter
# in this example.
Expand All @@ -120,10 +120,11 @@ nothing # hide

function agent_step!(agent, model)
minhappy = model.min_to_be_happy
neighbor_positions = nearby_positions(agent, model)
count_neighbors_same_group = 0
## For each neighbor, get group and compare to current agent's group
## and increment count_neighbors_same_group as appropriately.
## Here `nearby_agents` (with default arguments) will provide an iterator
## over the nearby agents one grid point away, which are at most 8.
for neighbor in nearby_agents(agent, model)
if agent.group == neighbor.group
count_neighbors_same_group += 1
Expand All @@ -139,7 +140,6 @@ function agent_step!(agent, model)
end
return
end
nothing # hide

# For the purpose of this implementation of Schelling's segregation model,
# we only need an agent step function.
Expand Down Expand Up @@ -226,7 +226,7 @@ abm_video(
framerate = 4, frames = 20,
title = "Schelling's segregation model"
)
nothing # hide

# ```@raw html
# <video width="auto" controls autoplay loop>
# <source src="../schelling.mp4" type="video/mp4">
Expand Down Expand Up @@ -337,9 +337,8 @@ data[(end - 10):end, :]
# the `groupby` and `combine` functions from the `DataFrames` package:

using DataFrames
using Statistics: mean
gd = groupby(data,[:step, :min_to_be_happy, :numagents])
data_mean = combine(gd,[:happyperc_mood,:replicate] .=> mean)
gd = groupby(data, [:step, :min_to_be_happy, :numagents])
data_mean = combine(gd, [:happyperc_mood, :replicate] .=> mean)

out = select(data_mean, Not(:replicate_mean))

Expand Down
2 changes: 1 addition & 1 deletion src/core/agents.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export AbstractAgent, @agent, GraphAgent, GridAgent, ContinuousAgent, OSMAgent
YourAgentType <: AbstractAgent
Agents participating in Agents.jl simulations are instances of user-defined Types that
are subtypes of `AbstractAgent`. It is almost always the case that mutable Types make
for a simpler modellign experience.
for a simpler modelling experience.
Your agent type(s) **must have** the `id` field as first field.
Depending on the space structure there might be a `pos` field of appropriate type
Expand Down
7 changes: 5 additions & 2 deletions src/simulations/step.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ export step!, dummystep

"""
step!(model, agent_step!, n::Int = 1)
step!(model, agent_step!, model_step!, n::Int = 1, agents_first::Bool=true)
step!(model, agent_step!, model_step!, n::Int = 1, agents_first::Bool = true)
Update agents `n` steps according to the stepping function `agent_step!`.
Agents will be activated as specified by the `model.scheduler`.
Expand All @@ -13,13 +13,16 @@ activates the agents).
`step!` ignores scheduled IDs that do not exist within the model, allowing
you to safely kill agents dynamically.
step!(model, agent_step!, model_step!, n::Function, agents_first::Bool=true)
step!(model, agent_step!, model_step!, n::Function, agents_first::Bool = true)
In this version `n` is a function.
Then `step!` runs the model until `n(model, s)` returns `true`, where `s` is the
current amount of steps taken, starting from 0.
For this method of `step!`, `model_step!` must be provided always (use [`dummystep`](@ref)
if you have no model stepping dynamics).
See also [Advanced stepping](@ref) for stepping complex models where `agent_step!` might
not be convenient.
"""
function step! end

Expand Down

0 comments on commit 365ff87

Please sign in to comment.