├── Schelling
├── Mesa
│ ├── __init__.py
│ ├── benchmark_schelling.py
│ └── Schelling.py
├── Agents
│ ├── benchmark_schelling.jl
│ └── Schelling.jl
├── Mason
│ ├── benchmark_schelling.sh
│ ├── Agent_large.java
│ ├── Agent_small.java
│ ├── Schelling_small.java
│ └── Schelling_large.java
├── NetLogo
│ ├── benchmark_schelling.sh
│ ├── parameters_schelling.xml
│ └── Schelling.nlogo
└── DECLARATION.md
├── WolfSheep
├── Mesa
│ ├── __init__.py
│ ├── benchmark_wolfsheep.py
│ ├── WolfSheep.py
│ └── agents.py
├── Agents
│ ├── benchmark_wolfsheep.jl
│ └── WolfSheep.jl
├── Mason
│ ├── benchmark_wolfsheep.sh
│ ├── Sheep_large.java
│ ├── Sheep_small.java
│ ├── Wolf_large.java
│ ├── Wolf_small.java
│ ├── Wsg_small.java
│ └── Wsg_large.java
├── NetLogo
│ ├── benchmark_wolfsheep.sh
│ ├── parameters_wolfsheep.xml
│ └── WolfSheep.nlogo
└── DECLARATION.md
├── mason.22.jar
├── .gitignore
├── Project.toml
├── .github
├── run-flocking.sh
├── run-wolfsheep.sh
├── run-schelling.sh
├── run-forestfire.sh
├── setup.sh
└── workflows
│ └── run-benchmarks.yml
├── seed_netlogo.jl
├── runall.sh
├── Flocking
├── Agents
│ ├── benchmark_flocking.jl
│ └── Flocking.jl
├── Mesa
│ ├── benchmark_flocking.py
│ ├── Flocking.py
│ └── boid.py
├── Mason
│ ├── benchmark_flocking.sh
│ ├── Flocking_large.java
│ ├── Flocking_small.java
│ ├── Flocker_large.java
│ └── Flocker_small.java
├── NetLogo
│ ├── benchmark_flocking.sh
│ ├── parameters_flocking.xml
│ └── Flocking.nlogo
└── DECLARATION.md
├── create_benchmark_table.jl
├── LICENSE.md
└── README.md
/Schelling/Mesa/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/WolfSheep/Mesa/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/mason.22.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JuliaDynamics/ABMFrameworksComparison/HEAD/mason.22.jar
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Manifest.toml
2 | *.pyc
3 | *.code-workspace
4 | *.class
5 | .*.tmp.nlogo
6 | netlogo
7 | benchmark_results.txt
8 | __pycache__
9 |
--------------------------------------------------------------------------------
/Project.toml:
--------------------------------------------------------------------------------
1 | [deps]
2 | Agents = "46ada45e-f475-11e8-01d0-f70cc89e6671"
3 | BenchmarkTools = "6e4b80f9-dd63-53aa-95a3-0cdb28fa8baf"
4 | LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179"
5 | PrettyTables = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d"
6 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
7 |
--------------------------------------------------------------------------------
/.github/run-flocking.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | (
4 |
5 | echo "Benchmarking Agents.jl"
6 | julia --project=@. ./Flocking/Agents/benchmark_flocking.jl
7 |
8 | echo "Benchmarking Mason"
9 | bash ./Flocking/Mason/benchmark_flocking.sh
10 |
11 | echo "Benchmarking Mesa"
12 | python3 ./Flocking/Mesa/benchmark_flocking.py
13 |
14 | echo "Benchmarking NetLogo"
15 | bash Flocking/NetLogo/benchmark_flocking.sh
16 |
17 | ) | tee benchmark_results.txt
18 |
19 | julia --project=@. create_benchmark_table.jl
20 |
--------------------------------------------------------------------------------
/.github/run-wolfsheep.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | (
4 |
5 | echo "Benchmarking Agents.jl"
6 | julia --project=@. ./WolfSheep/Agents/benchmark_wolfsheep.jl
7 |
8 | echo "Benchmarking Mason"
9 | bash ./WolfSheep/Mason/benchmark_wolfsheep.sh
10 |
11 | echo "Benchmarking Mesa"
12 | python3 ./WolfSheep/Mesa/benchmark_wolfsheep.py
13 |
14 | echo "Benchmarking NetLogo"
15 | bash ./WolfSheep/NetLogo/benchmark_wolfsheep.sh
16 |
17 | ) | tee benchmark_results.txt
18 |
19 | julia --project=@. create_benchmark_table.jl
--------------------------------------------------------------------------------
/.github/run-schelling.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | (
4 |
5 | echo "Benchmarking Agents.jl"
6 | julia --project=@. ./Schelling/Agents/benchmark_schelling.jl
7 |
8 | echo "Benchmarking Mason"
9 | bash ./Schelling/Mason/benchmark_schelling.sh
10 |
11 | echo "Benchmarking Mesa"
12 | python3 ./Schelling/Mesa/benchmark_schelling.py
13 |
14 | echo "Benchmarking NetLogo"
15 | bash Schelling/NetLogo/benchmark_schelling.sh
16 |
17 | ) | tee benchmark_results.txt
18 |
19 | julia --project=@. create_benchmark_table.jl
20 |
--------------------------------------------------------------------------------
/.github/run-forestfire.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | (
4 |
5 | echo "Benchmarking Agents.jl"
6 | julia --project=@. ./ForestFire/Agents/benchmark_forestfire.jl
7 |
8 | echo "Benchmarking Mason"
9 | bash ./ForestFire/Mason/benchmark_forestfire.sh
10 |
11 | echo "Benchmarking Mesa"
12 | python3 ./ForestFire/Mesa/benchmark_forestfire.py
13 |
14 | echo "Benchmarking NetLogo"
15 | bash ./ForestFire/NetLogo/benchmark_forestfire.sh
16 |
17 | ) | tee benchmark_results.txt
18 |
19 | julia --project=@. create_benchmark_table.jl
20 |
--------------------------------------------------------------------------------
/seed_netlogo.jl:
--------------------------------------------------------------------------------
1 | using LightXML, Random
2 |
3 | n_run = parse(Int, ARGS[2])
4 | rng_seed = MersenneTwister(42)
5 |
6 | xdoc = parse_file(ARGS[1])
7 | xroot = root(xdoc)
8 |
9 | found = false
10 |
11 | for c in child_elements(xroot)
12 | global found
13 | for cc in child_elements(c)
14 | if attribute(cc, "variable"; required=false) == "seed"
15 | for _ in 1:n_run
16 | seed = rand(rng_seed, 1:10000)
17 | e = new_child(cc, "value")
18 | set_attribute(e, "value", seed)
19 | end
20 | found = true
21 | end
22 | end
23 | end
24 |
25 | !found && error("No seed was found in XML!")
26 | save_file(xdoc, ARGS[1])
27 | free(xdoc)
28 |
--------------------------------------------------------------------------------
/runall.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | (
4 |
5 | echo "Benchmarking Agents.jl"
6 | julia --project=@. WolfSheep/Agents/benchmark_wolfsheep.jl
7 | julia --project=@. Flocking/Agents/benchmark_flocking.jl
8 | julia --project=@. Schelling/Agents/benchmark_schelling.jl
9 |
10 | echo "Benchmarking Mason"
11 | bash WolfSheep/Mason/benchmark_wolfsheep.sh
12 | bash Flocking/Mason/benchmark_flocking.sh
13 | bash Schelling/Mason/benchmark_schelling.sh
14 |
15 | echo "Benchmarking Mesa"
16 | python3 WolfSheep/Mesa/benchmark_wolfsheep.py
17 | python3 Flocking/Mesa/benchmark_flocking.py
18 | python3 Schelling/Mesa/benchmark_schelling.py
19 |
20 | echo "Benchmarking NetLogo"
21 | bash WolfSheep/NetLogo/benchmark_wolfsheep.sh
22 | bash Flocking/NetLogo/benchmark_flocking.sh
23 | bash Schelling/NetLogo/benchmark_schelling.sh
24 |
25 | ) | tee benchmark_results.txt
26 |
27 | julia --project=@. create_benchmark_table.jl
--------------------------------------------------------------------------------
/Flocking/Agents/benchmark_flocking.jl:
--------------------------------------------------------------------------------
1 | using Agents
2 | using BenchmarkTools
3 | using Random
4 |
5 | include("Flocking.jl")
6 |
7 | rng_seed = MersenneTwister(42)
8 |
9 | rng_model() = Xoshiro(rand(rng_seed, 1:10000))
10 |
11 | function run_model(rng, extent, n_birds, visual_distance)
12 | model = flocking_model(rng, extent, n_birds, visual_distance)
13 | step!(model, 100)
14 | end
15 |
16 | n_run = 100
17 |
18 | a = @benchmark run_model(rng, (100, 100), 200, 5.0) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
19 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
20 | println("Agents.jl Flocking-small (ms): ", median_time * 1e-6)
21 |
22 | a = @benchmark run_model(rng, (150, 150), 400, 15.0) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
23 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
24 | println("Agents.jl Flocking-large (ms): ", median_time * 1e-6)
25 |
--------------------------------------------------------------------------------
/Schelling/Agents/benchmark_schelling.jl:
--------------------------------------------------------------------------------
1 | using Agents
2 | using BenchmarkTools
3 | using Random
4 |
5 | include("Schelling.jl")
6 |
7 | rng_seed = MersenneTwister(42)
8 |
9 | rng_model() = Xoshiro(rand(rng_seed, 1:10000))
10 |
11 | function run_model(rng, numagents, griddims, min_to_be_happy, radius)
12 | model = schelling_model(rng, numagents, griddims, min_to_be_happy, radius)
13 | step!(model, 20)
14 | end
15 |
16 | n_run = 100
17 |
18 | a = @benchmark run_model(rng, 1000, (40, 40), 3, 1) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
19 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
20 | println("Agents.jl Schelling-small (ms): ", median_time * 1e-6)
21 |
22 | a = @benchmark run_model(rng, 8000, (100, 100), 8, 2) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
23 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
24 | println("Agents.jl Schelling-large (ms): ", median_time * 1e-6)
25 |
--------------------------------------------------------------------------------
/.github/setup.sh:
--------------------------------------------------------------------------------
1 | # fetch update software list
2 | sudo apt-get update
3 |
4 | # give permissions
5 | sudo chmod a+rwx ./
6 | sudo chmod -R 777 ./
7 |
8 | # install java
9 | sudo apt install default-jre-headless
10 | sudo apt install default-jdk-headless
11 |
12 | # install julia
13 | sudo wget https://julialang-s3.julialang.org/bin/linux/x64/1.10/julia-1.11.5-linux-x86_64.tar.gz
14 | sudo tar zxvf julia-1.11.5-linux-x86_64.tar.gz
15 | export PATH=$PATH:$(pwd)"/julia-1.11.5/bin"
16 | printf "\nexport PATH=\"\$PATH:"$(pwd)"/julia-1.11.5/bin\"" >> ~/.bashrc
17 |
18 | # install agents
19 | julia --project=@. -e 'using Pkg; Pkg.instantiate()'
20 |
21 | # install mesa
22 | sudo apt install python3-pip
23 | pip install mesa==3.2.0
24 |
25 | # install netlogo
26 | sudo wget http://ccl.northwestern.edu/netlogo/6.4.0/NetLogo-6.4.0-64.tgz
27 | sudo tar -xzf NetLogo-6.4.0-64.tgz
28 | sudo mv "NetLogo-6.4.0-64" netlogo
29 |
30 | # install bc tool
31 | sudo apt install bc
32 |
--------------------------------------------------------------------------------
/WolfSheep/Agents/benchmark_wolfsheep.jl:
--------------------------------------------------------------------------------
1 | using Agents
2 | using BenchmarkTools
3 | using Random
4 |
5 | include("WolfSheep.jl")
6 |
7 | rng_seed = MersenneTwister(42)
8 |
9 | rng_model() = Xoshiro(rand(rng_seed, 1:10000))
10 |
11 | function run_model(rng, n_sheep, n_wolves, dims, regrowth_time,
12 | sheep_reproduce, wolf_reproduce)
13 | model = predator_prey_model(rng, n_sheep, n_wolves, dims, regrowth_time,
14 | sheep_reproduce, wolf_reproduce)
15 | step!(model, 100)
16 | end
17 |
18 | n_run = 100
19 |
20 | a = @benchmark run_model(rng, 60, 40, (25, 25), 20, 0.2, 0.1) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
21 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
22 | println("Agents.jl WolfSheep-small (ms): ", median_time * 1e-6)
23 |
24 | a = @benchmark run_model(rng, 1000, 500, (100, 100), 10, 0.4, 0.2) setup=(rng = rng_model()) evals=1 samples=n_run seconds=1e6
25 | median_time = sort(a.times)[n_run ÷ 2 + n_run % 2]
26 | println("Agents.jl WolfSheep-large (ms): ", median_time * 1e-6)
27 |
--------------------------------------------------------------------------------
/Schelling/Agents/Schelling.jl:
--------------------------------------------------------------------------------
1 | using Agents
2 |
3 | @agent struct SchellingAgent(GridAgent{2})
4 | const group::Int # The group of the agent
5 | end
6 |
7 | function schelling_model(rng, numagents, griddims, min_to_be_happy, radius)
8 | space = GridSpaceSingle(griddims, periodic = false)
9 | properties = (min_to_be_happy = min_to_be_happy, radius = radius)
10 | model = StandardABM(SchellingAgent, space; agent_step!, properties, rng,
11 | container = Vector, scheduler = Schedulers.Randomly())
12 | for n in 1:numagents
13 | add_agent_single!(model, n < numagents / 2 ? 1 : 2)
14 | end
15 | return model
16 | end
17 |
18 | function agent_step!(agent, model)
19 | count_neighbors_same_group = 0
20 | for neighbor in nearby_agents(agent, model, model.radius)
21 | if agent.group == neighbor.group
22 | count_neighbors_same_group += 1
23 | end
24 | end
25 | if count_neighbors_same_group ≥ model.min_to_be_happy
26 | move_agent_single!(agent, model)
27 | end
28 | return
29 | end
30 |
--------------------------------------------------------------------------------
/Flocking/Mesa/benchmark_flocking.py:
--------------------------------------------------------------------------------
1 | # Use Python 3
2 |
3 | # Only collect the number of wolves and sheeps per step.
4 |
5 | import timeit
6 | import gc
7 |
8 | setup = """
9 | gc.enable()
10 | import os, sys
11 | sys.path.insert(0, os.path.abspath("."))
12 |
13 | from Flocking import BoidFlockers
14 |
15 | import random
16 | random.seed(42)
17 |
18 | def runthemodel(seed, population, width, height, vision):
19 | flock = BoidFlockers(seed, population, width, height, vision)
20 | for i in range(0, 100):
21 | flock.step()
22 |
23 | seed = random.randint(1, 10000)
24 | population={}
25 | width={}
26 | height={}
27 | vision={}
28 | """
29 |
30 | n_run = 100
31 |
32 | tt = timeit.Timer('runthemodel(seed, population, width, height, vision)', setup=setup.format(200, 100, 100, 5))
33 | a = tt.repeat(n_run, 1)
34 | median_time = sorted(a)[n_run // 2 + n_run % 2]
35 | print("Mesa Flocking-small (ms):", median_time*1e3)
36 |
37 | tt = timeit.Timer('runthemodel(seed, population, width, height, vision)', setup=setup.format(400, 150, 150, 15))
38 | a = tt.repeat(n_run, 1)
39 | median_time = sorted(a)[n_run // 2 + n_run % 2]
40 | print("Mesa Flocking-large (ms):", median_time*1e3)
41 |
--------------------------------------------------------------------------------
/Schelling/Mesa/benchmark_schelling.py:
--------------------------------------------------------------------------------
1 | # Use Python 3
2 |
3 | import timeit
4 | import gc
5 |
6 | setup = """
7 | gc.enable()
8 | import os, sys
9 | sys.path.insert(0, os.path.abspath("."))
10 |
11 | from Schelling import SchellingModel
12 |
13 | import random
14 | random.seed(42)
15 |
16 | def runthemodel(seed, height, width, homophily, radius, density,):
17 | schelling = SchellingModel(seed, height, width, homophily, radius, density,)
18 | for i in range(0, 20):
19 | schelling.step()
20 |
21 | seed = random.randint(1, 10000)
22 | height = {}
23 | width = {}
24 | homophily = {}
25 | radius = {}
26 | density = {}
27 | """
28 |
29 | n_run = 100
30 |
31 | tt = timeit.Timer('runthemodel(seed, height, width, homophily, radius, density)',
32 | setup=setup.format(40, 40, 3, 1, 0.625))
33 | a = tt.repeat(n_run, 1)
34 | median_time = sorted(a)[n_run // 2 + n_run % 2]
35 | print("Mesa Schelling-small (ms):", median_time*1e3)
36 |
37 | tt = timeit.Timer('runthemodel(seed, height, width, homophily, radius, density)',
38 | setup=setup.format(100, 100, 8, 2, 0.8))
39 | a = tt.repeat(n_run, 1)
40 | median_time = sorted(a)[n_run // 2 + n_run % 2]
41 | print("Mesa Schelling-large (ms):", median_time*1e3)
42 |
43 |
--------------------------------------------------------------------------------
/Flocking/Mason/benchmark_flocking.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SEED=42
4 | RANDOM=$SEED
5 | N_RUN=100
6 |
7 | export CLASSPATH=Flocking/Mason:./mason.22.jar
8 | javac Flocking/Mason/Flocking_small.java Flocking/Mason/Flocker_small.java
9 | javac Flocking/Mason/Flocking_large.java Flocking/Mason/Flocker_large.java
10 |
11 | n_run_model_small () {
12 | times=()
13 | for i in $( seq 1 $N_RUN )
14 | do
15 | startt=`date +%s%N`
16 | java Flocking_small -seed $((RANDOM % 10000 + 1)) -for 100 -quiet
17 | endt=`date +%s%N`
18 | times+=(`expr $endt - $startt`)
19 | done
20 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
21 | echo -n "Mason Flocking-small (ms): "
22 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
23 | }
24 |
25 | n_run_model_large () {
26 | times=()
27 | for i in $( seq 1 $N_RUN )
28 | do
29 | startt=`date +%s%N`
30 | java Flocking_large -seed $((RANDOM % 10000 + 1)) -for 100 -quiet
31 | endt=`date +%s%N`
32 | times+=(`expr $endt - $startt`)
33 | done
34 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
35 | echo -n "Mason Flocking-large (ms): "
36 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
37 | }
38 |
39 | n_run_model_small
40 | n_run_model_large
41 |
--------------------------------------------------------------------------------
/Schelling/Mason/benchmark_schelling.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SEED=42
4 | RANDOM=$SEED
5 | N_RUN=100
6 |
7 | export CLASSPATH=Schelling/Mason:./mason.22.jar
8 | javac Schelling/Mason/Schelling_small.java Schelling/Mason/Agent_small.java
9 | javac Schelling/Mason/Schelling_large.java Schelling/Mason/Agent_large.java
10 |
11 | n_run_model_small () {
12 | times=()
13 | for i in $( seq 1 $N_RUN )
14 | do
15 | startt=`date +%s%N`
16 | java Schelling_small -seed $((RANDOM % 10000 + 1)) -for 20 -quiet
17 | endt=`date +%s%N`
18 | times+=(`expr $endt - $startt`)
19 | done
20 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
21 | echo -n "Mason Schelling-small (ms): "
22 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
23 | }
24 |
25 | n_run_model_large () {
26 | times=()
27 | for i in $( seq 1 $N_RUN )
28 | do
29 | startt=`date +%s%N`
30 | java Schelling_large -seed $((RANDOM % 10000 + 1)) -for 20 -quiet
31 | endt=`date +%s%N`
32 | times+=(`expr $endt - $startt`)
33 | done
34 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
35 | echo -n "Mason Schelling-large (ms): "
36 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
37 | }
38 |
39 | n_run_model_small
40 | n_run_model_large
41 |
42 |
--------------------------------------------------------------------------------
/WolfSheep/Mason/benchmark_wolfsheep.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | SEED=42
4 | RANDOM=$SEED
5 | N_RUN=100
6 |
7 | export CLASSPATH=WolfSheep/Mason:./mason.22.jar
8 | javac WolfSheep/Mason/Wsg_small.java WolfSheep/Mason/Wolf_small.java WolfSheep/Mason/Sheep_small.java
9 | javac WolfSheep/Mason/Wsg_large.java WolfSheep/Mason/Wolf_large.java WolfSheep/Mason/Sheep_large.java
10 |
11 | n_run_model_small () {
12 | times=()
13 | for i in $( seq 1 $N_RUN )
14 | do
15 | startt=`date +%s%N`
16 | java Wsg_small -seed $((RANDOM % 10000 + 1)) -for 100 -quiet
17 | endt=`date +%s%N`
18 | times+=(`expr $endt - $startt`)
19 | done
20 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
21 | echo -n "Mason WolfSheep-small (ms): "
22 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
23 | }
24 |
25 | n_run_model_large () {
26 | times=()
27 | for i in $( seq 1 $N_RUN )
28 | do
29 | startt=`date +%s%N`
30 | java Wsg_large -seed $((RANDOM % 10000 + 1)) -for 100 -quiet
31 | endt=`date +%s%N`
32 | times+=(`expr $endt - $startt`)
33 | done
34 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
35 | echo -n "Mason WolfSheep-large (ms): "
36 | echo "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]} * 0.000001" | bc
37 | }
38 |
39 | n_run_model_small
40 | n_run_model_large
41 |
--------------------------------------------------------------------------------
/.github/workflows/run-benchmarks.yml:
--------------------------------------------------------------------------------
1 | name: run-benchmarks
2 | on:
3 | pull_request:
4 | branches:
5 | - main
6 | push:
7 | branches:
8 | - main
9 | tags: '*'
10 |
11 | jobs:
12 | Run-benchmark-flocking:
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Cancel ongoing test runs for previous commits
16 | uses: styfle/cancel-workflow-action@0.11.0
17 | - uses: actions/checkout@v3
18 | - name: setup-benchmarks
19 | run: bash ./.github/setup.sh
20 | - name: run-benchmarks
21 | run: bash ./.github/run-flocking.sh
22 | Run-benchmark-wolfsheep:
23 | runs-on: ubuntu-latest
24 | steps:
25 | - name: Cancel ongoing test runs for previous commits
26 | uses: styfle/cancel-workflow-action@0.11.0
27 | - uses: actions/checkout@v3
28 | - name: setup-benchmarks
29 | run: bash ./.github/setup.sh
30 | - name: run-benchmarks
31 | run: bash ./.github/run-wolfsheep.sh
32 | Run-benchmark-schelling:
33 | runs-on: ubuntu-latest
34 | steps:
35 | - name: Cancel ongoing test runs for previous commits
36 | uses: styfle/cancel-workflow-action@0.11.0
37 | - uses: actions/checkout@v3
38 | - name: setup-benchmarks
39 | run: bash ./.github/setup.sh
40 | - name: run-benchmarks
41 | run: bash ./.github/run-schelling.sh
42 |
--------------------------------------------------------------------------------
/create_benchmark_table.jl:
--------------------------------------------------------------------------------
1 | using PrettyTables
2 |
3 | frameworks = ["Agents.jl", "Mason", "NetLogo", "Mesa"]
4 |
5 | models = ["WolfSheep-small", "WolfSheep-large",
6 | "Flocking-small", "Flocking-large",
7 | "Schelling-small", "Schelling-large",
8 | "ForestFire-small", "ForestFire-large"]
9 |
10 | frameworks_times = Dict(m => Dict(f => 0.0 for f in frameworks) for m in models)
11 |
12 | open("benchmark_results.txt", "r") do f
13 | for line in readlines(f)
14 | !occursin("(ms)", line) && continue
15 | s_line = split(line)
16 | !in(s_line[1], frameworks) && continue
17 | frameworks_times[String(s_line[2])][String(s_line[1])] = parse(Float64, s_line[4])
18 | end
19 | end
20 |
21 | frameworks_comparison = Dict(m => Dict(f => 0.0 for f in frameworks) for m in models)
22 | for m in models
23 | for f in frameworks
24 | if f == "Agents.jl"
25 | frameworks_comparison[m][f] = 1
26 | else
27 | frameworks_times[m][f] == 0.0 && continue
28 | v = round(frameworks_times[m][f]/frameworks_times[m]["Agents.jl"], digits=1)
29 | frameworks_comparison[m][f] = v
30 | end
31 | end
32 | end
33 |
34 | columns = ["Model/Framework", "Agents.jl 6.2.10", "MASON 22.0", "Netlogo 6.4.0", "Mesa 3.2.0"]
35 | results = mapreduce(permutedims, vcat, [vcat([m], [ifelse(frameworks_comparison[m][f] != 0, frameworks_comparison[m][f], ".") for f in frameworks]) for m in models])
36 | conf = set_pt_conf(tf = tf_markdown, alignment = :c)
37 | table = pretty_table_with_conf(conf, results; header = columns)
38 |
--------------------------------------------------------------------------------
/WolfSheep/Mesa/benchmark_wolfsheep.py:
--------------------------------------------------------------------------------
1 | # Use Python 3
2 |
3 | # Only collect the number of wolves and sheeps per step.
4 |
5 | import timeit
6 | import gc
7 |
8 | setup = """
9 | gc.enable()
10 | import os, sys
11 | sys.path.insert(0, os.path.abspath("."))
12 |
13 | from agents import Sheep, Wolf, GrassPatch
14 | from WolfSheep import WolfSheep
15 |
16 | import random
17 | random.seed(42)
18 |
19 | def runthemodel(seed, height, width, initial_sheep, initial_wolves, sheep_reproduce, wolf_reproduce, grass_regrowth_time):
20 | wolfsheep = WolfSheep(seed, height, width, initial_sheep, initial_wolves, sheep_reproduce, wolf_reproduce, grass_regrowth_time)
21 | for i in range(0, 100):
22 | wolfsheep.step()
23 |
24 | seed = random.randint(1, 10000)
25 | height = {}
26 | width = {}
27 | initial_sheep = {}
28 | initial_wolves = {}
29 | sheep_reproduce = {}
30 | wolf_reproduce = {}
31 | grass_regrowth_time = {}
32 | """
33 |
34 | n_run = 100
35 |
36 | tt = timeit.Timer('runthemodel(seed, height, width, initial_sheep, initial_wolves, sheep_reproduce, wolf_reproduce, grass_regrowth_time)',
37 | setup=setup.format(25, 25, 60, 40, 0.2, 0.1, 20))
38 | a = tt.repeat(n_run, 1)
39 | median_time = sorted(a)[n_run // 2 + n_run % 2]
40 | print("Mesa WolfSheep-small (ms):", median_time*1e3)
41 |
42 | tt = timeit.Timer('runthemodel(seed, height, width, initial_sheep, initial_wolves, sheep_reproduce, wolf_reproduce, grass_regrowth_time)',
43 | setup=setup.format(100, 100, 1000, 500, 0.4, 0.2, 10))
44 | a = tt.repeat(n_run, 1)
45 | median_time = sorted(a)[n_run // 2 + n_run % 2]
46 | print("Mesa WolfSheep-large (ms):", median_time*1e3)
--------------------------------------------------------------------------------
/Flocking/NetLogo/benchmark_flocking.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # NetLogo's profiler sucks in the sense that it times one run, then spits out a bunch of junk
4 | # to either a file or stdout. There's no easy abilitiy to parse it.
5 |
6 | # the netlogo folder is assumed to be inside the NetLogo folder of this repository, which contains the models
7 |
8 | N_RUN=100
9 |
10 | NAME_LAUNCHER="./netlogo/netlogo-headless.sh"
11 | NAME_MODEL="Flocking/NetLogo/Flocking.nlogo"
12 | NAME_PARAM="Flocking/NetLogo/parameters_flocking.xml"
13 | NAME_TIMES="Flocking/NetLogo/times.txt"
14 |
15 | julia --project=@. seed_netlogo.jl $NAME_PARAM $N_RUN
16 |
17 | n_run_model_small () {
18 | sed -i '1d' $NAME_PARAM
19 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_small \
20 | --min-pxcor 0 --max-pxcor 99 --min-pycor 0 --max-pycor 99 --threads 1)
21 | times=()
22 | while IFS= read -r line; do
23 | times+=(`expr $line`)
24 | done < $NAME_TIMES
25 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
26 | printf "NetLogo Flocking-small (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
27 | rm $NAME_TIMES
28 | }
29 |
30 | n_run_model_large () {
31 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_large \
32 | --min-pxcor 0 --max-pxcor 149 --min-pycor 0 --max-pycor 149 --threads 1)
33 | times=()
34 | while IFS= read -r line; do
35 | times+=(`expr $line`)
36 | done < $NAME_TIMES
37 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
38 | printf "NetLogo Flocking-large (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
39 | rm $NAME_TIMES
40 | }
41 |
42 | n_run_model_small
43 | n_run_model_large
44 |
--------------------------------------------------------------------------------
/Schelling/NetLogo/benchmark_schelling.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # NetLogo's profiler sucks in the sense that it times one run, then spits out a bunch of junk
4 | # to either a file or stdout. There's no easy abilitiy to parse it.
5 |
6 | # the netlogo folder is assumed to be inside the NetLogo folder of this repository, which contains the models
7 |
8 | N_RUN=100
9 |
10 | NAME_LAUNCHER="./netlogo/netlogo-headless.sh"
11 | NAME_MODEL="Schelling/NetLogo/Schelling.nlogo"
12 | NAME_PARAM="Schelling/NetLogo/parameters_schelling.xml"
13 | NAME_TIMES="Schelling/NetLogo/times.txt"
14 |
15 | julia --project=@. seed_netlogo.jl $NAME_PARAM $N_RUN
16 |
17 | n_run_model_small () {
18 | sed -i '1d' $NAME_PARAM
19 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_small \
20 | --min-pxcor 0 --max-pxcor 39 --min-pycor 0 --max-pycor 39 --threads 1)
21 | times=()
22 | while IFS= read -r line; do
23 | times+=(`expr $line`)
24 | done < $NAME_TIMES
25 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
26 | printf "NetLogo Schelling-small (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
27 | rm $NAME_TIMES
28 | }
29 |
30 | n_run_model_large () {
31 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_large \
32 | --min-pxcor 0 --max-pxcor 99 --min-pycor 0 --max-pycor 99 --threads 1)
33 | times=()
34 | while IFS= read -r line; do
35 | times+=(`expr $line`)
36 | done < $NAME_TIMES
37 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
38 | printf "NetLogo Schelling-large (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
39 | rm $NAME_TIMES
40 | }
41 |
42 | n_run_model_small
43 | n_run_model_large
44 |
--------------------------------------------------------------------------------
/Flocking/Agents/Flocking.jl:
--------------------------------------------------------------------------------
1 | using Agents, LinearAlgebra
2 |
3 | @agent struct Bird(ContinuousAgent{2, Float64})
4 | const speed::Float64
5 | const cohere_factor::Float64
6 | const separation::Float64
7 | const separate_factor::Float64
8 | const match_factor::Float64
9 | const visual_distance::Float64
10 | end
11 |
12 | function flocking_model(rng, extent, n_birds, visual_distance;
13 | speed = 1.0, cohere_factor = 0.03, separation = 1.0, separate_factor = 0.015,
14 | match_factor = 0.05, spacing = visual_distance / 1.5,)
15 | space2d = ContinuousSpace(extent; spacing)
16 | model = StandardABM(Bird, space2d; agent_step!, rng, container = Vector,
17 | scheduler = Schedulers.Randomly())
18 | for n in 1:n_birds
19 | vel = SVector{2}(rand(abmrng(model)) * 2 - 1 for _ in 1:2)
20 | add_agent!(model, vel, speed, cohere_factor, separation,
21 | separate_factor, match_factor, visual_distance)
22 | end
23 | return model
24 | end
25 |
26 | function agent_step!(bird, model)
27 | neighbor_agents = nearby_agents(bird, model, bird.visual_distance)
28 | N = 0
29 | match = separate = cohere = SVector{2}(0.0, 0.0)
30 | for neighbor in neighbor_agents
31 | N += 1
32 | heading = get_direction(bird.pos, neighbor.pos, model)
33 | cohere += heading
34 | match += neighbor.vel
35 | if sum(heading .^ 2) < bird.separation^2
36 | separate -= heading
37 | end
38 | end
39 | cohere *= bird.cohere_factor
40 | separate *= bird.separate_factor
41 | match *= bird.match_factor
42 | bird.vel += (cohere + separate + match) / max(N, 1)
43 | bird.vel /= norm(bird.vel)
44 | move_agent!(bird, model, bird.speed)
45 | end
46 |
--------------------------------------------------------------------------------
/WolfSheep/NetLogo/benchmark_wolfsheep.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # NetLogo's profiler sucks in the sense that it times one run, then spits out a bunch of junk
4 | # to either a file or stdout. There's no easy abilitiy to parse it.
5 |
6 | # the netlogo folder is assumed to be inside the NetLogo folder of this repository, which contains the models
7 |
8 | N_RUN=100
9 |
10 | NAME_LAUNCHER="./netlogo/netlogo-headless.sh"
11 | NAME_MODEL="WolfSheep/NetLogo/WolfSheep.nlogo"
12 | NAME_PARAM="WolfSheep/NetLogo/parameters_wolfsheep.xml"
13 | NAME_TIMES="WolfSheep/NetLogo/times.txt"
14 |
15 | julia --project=@. seed_netlogo.jl $NAME_PARAM $N_RUN
16 |
17 | n_run_model_small () {
18 | sed -i '1d' $NAME_PARAM
19 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_small \
20 | --min-pxcor 0 --max-pxcor 24 --min-pycor 0 --max-pycor 24 --threads 1)
21 | times=()
22 | while IFS= read -r line; do
23 | times+=(`expr $line`)
24 | done < $NAME_TIMES
25 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
26 | printf "NetLogo WolfSheep-small (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
27 | rm $NAME_TIMES
28 | }
29 |
30 | n_run_model_large () {
31 | (bash $NAME_LAUNCHER --model $NAME_MODEL --setup-file $NAME_PARAM --experiment benchmark_large \
32 | --min-pxcor 0 --max-pxcor 99 --min-pycor 0 --max-pycor 99 --threads 1)
33 | times=()
34 | while IFS= read -r line; do
35 | times+=(`expr $line`)
36 | done < $NAME_TIMES
37 | readarray -t sorted < <(printf '%s\n' "${times[@]}" | sort)
38 | printf "NetLogo WolfSheep-large (ms): "${sorted[(`expr $N_RUN / 2 + $N_RUN % 2`)]}"\n"
39 | rm $NAME_TIMES
40 | }
41 |
42 | n_run_model_small
43 | n_run_model_large
44 |
45 |
--------------------------------------------------------------------------------
/Schelling/NetLogo/parameters_schelling.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | setup
4 | benchmark
5 | ticks = 20
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | setup
26 | benchmark
27 | ticks = 20
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Schelling/Mason/Agent_large.java:
--------------------------------------------------------------------------------
1 | import sim.field.grid.ObjectGrid2D;
2 | import sim.engine.SimState;
3 | import sim.util.IntBag;
4 | import sim.util.Int2D;
5 | import sim.engine.Steppable;
6 |
7 | public class Agent_large implements Steppable
8 | {
9 | Int2D loc;
10 | public ObjectGrid2D neighbors;
11 | public int group;
12 | IntBag neighborsX;
13 | IntBag neighborsY;
14 |
15 | public Agent_large(final int x, final int y, final int group) {
16 | this.loc = new Int2D(x, y);
17 | this.group = group;
18 | this.neighborsX = new IntBag(25);
19 | this.neighborsY = new IntBag(25);
20 | }
21 |
22 | public void step(final SimState state) {
23 | final Schelling_large sch = (Schelling_large)state;
24 | final int x = this.loc.x;
25 | final int y = this.loc.y;
26 | final int neighborhood = sch.neighborhood;
27 | final ObjectGrid2D neighbors2 = sch.neighbors;
28 | neighbors2.getMooreLocations(x, y, neighborhood, 0, true, this.neighborsX, this.neighborsY);
29 | double val = 0.0;
30 | final int threshold = sch.threshold;
31 | final int numObjs = this.neighborsX.numObjs;
32 | final int[] objsX = this.neighborsX.objs;
33 | final int[] objsY = this.neighborsY.objs;
34 | for (int i = 0; i < numObjs; ++i) {
35 | Object o = neighbors2.field[objsX[i]][objsY[i]];
36 | if (o != null) {
37 | Agent_large neigh = (Agent_large)o;
38 | if (neigh.group == this.group && (objsX[i] != x || objsY[i] != y)) {
39 | val += 1.0;
40 | }
41 | }
42 | }
43 | if (val < threshold) {
44 | final int newLocIndex = state.random.nextInt(sch.emptySpaces.numObjs);
45 | final Int2D newLoc = (Int2D)sch.emptySpaces.objs[newLocIndex];
46 | sch.emptySpaces.objs[newLocIndex] = this.loc;
47 | this.loc = newLoc;
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/Schelling/Mason/Agent_small.java:
--------------------------------------------------------------------------------
1 | import sim.field.grid.ObjectGrid2D;
2 | import sim.engine.SimState;
3 | import sim.util.IntBag;
4 | import sim.util.Int2D;
5 | import sim.engine.Steppable;
6 |
7 | public class Agent_small implements Steppable
8 | {
9 | Int2D loc;
10 | public ObjectGrid2D neighbors;
11 | public int group;
12 | IntBag neighborsX;
13 | IntBag neighborsY;
14 |
15 | public Agent_small(final int x, final int y, final int group) {
16 | this.loc = new Int2D(x, y);
17 | this.group = group;
18 | this.neighborsX = new IntBag(9);
19 | this.neighborsY = new IntBag(9);
20 | }
21 |
22 | public void step(final SimState state) {
23 | final Schelling_small sch = (Schelling_small)state;
24 | final int x = this.loc.x;
25 | final int y = this.loc.y;
26 | final int neighborhood = sch.neighborhood;
27 | final ObjectGrid2D neighbors2 = sch.neighbors;
28 | neighbors2.getMooreLocations(x, y, neighborhood, 0, true, this.neighborsX, this.neighborsY);
29 | double val = 0.0;
30 | final int threshold = sch.threshold;
31 | final int numObjs = this.neighborsX.numObjs;
32 | final int[] objsX = this.neighborsX.objs;
33 | final int[] objsY = this.neighborsY.objs;
34 | for (int i = 0; i < numObjs; ++i) {
35 | Object o = neighbors2.field[objsX[i]][objsY[i]];
36 | if (o != null) {
37 | Agent_small neigh = (Agent_small)o;
38 | if (neigh.group == this.group && (objsX[i] != x || objsY[i] != y)) {
39 | val += 1.0;
40 | }
41 | }
42 | }
43 |
44 | if (val < threshold) {
45 | final int newLocIndex = state.random.nextInt(sch.emptySpaces.numObjs);
46 | final Int2D newLoc = (Int2D)sch.emptySpaces.objs[newLocIndex];
47 | sch.emptySpaces.objs[newLocIndex] = this.loc;
48 | this.loc = newLoc;
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Flocking/Mason/Flocking_large.java:
--------------------------------------------------------------------------------
1 | import sim.engine.Steppable;
2 | import sim.util.Bag;
3 | import sim.util.Double2D;
4 | import sim.field.continuous.Continuous2D;
5 | import sim.engine.SimState;
6 | import sim.engine.RandomSequence;
7 |
8 | public class Flocking_large extends SimState
9 | {
10 | public Continuous2D flockers;
11 | public double width;
12 | public double height;
13 | public int numFlockers;
14 | public double cohesion;
15 | public double avoidance;
16 | public double consistency;
17 | public double momentum;
18 | public double neighborhood;
19 |
20 | public Flocking_large(final long seed) {
21 | super(seed);
22 | this.width = 150.0;
23 | this.height = 150.0;
24 | this.numFlockers = 400;
25 | this.neighborhood = 15.0;
26 | this.cohesion = 0.03;
27 | this.avoidance = 0.015;
28 | this.consistency = 0.05;
29 | this.momentum = 1.0;
30 | }
31 |
32 | public void start() {
33 | super.start();
34 | Steppable[] array_agents = new Steppable[numFlockers];
35 | int count = 0;
36 | this.flockers = new Continuous2D(this.neighborhood / 1.5, this.width, this.height);
37 | for (int x = 0; x < this.numFlockers; ++x) {
38 | final Double2D location = new Double2D(this.random.nextDouble() * this.width, this.random.nextDouble() * this.height);
39 | final Double2D vel = new Double2D(this.random.nextDouble()*2-1, this.random.nextDouble()*2-1);
40 | final Flocker_large flocker = new Flocker_large(location, vel);
41 | this.flockers.setObjectLocation((Object)flocker, location);
42 | flocker.flockers = this.flockers;
43 | flocker.theFlock = this;
44 | array_agents[count] = flocker;
45 | ++count;
46 | }
47 | this.schedule.scheduleRepeating(new RandomSequence(array_agents));
48 | }
49 |
50 | public static void main(final String[] args) {
51 | doLoop((Class)Flocking_large.class, args);
52 | System.exit(0);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Flocking/Mason/Flocking_small.java:
--------------------------------------------------------------------------------
1 | import sim.engine.Steppable;
2 | import sim.util.Bag;
3 | import sim.util.Double2D;
4 | import sim.field.continuous.Continuous2D;
5 | import sim.engine.SimState;
6 | import sim.engine.RandomSequence;
7 |
8 | public class Flocking_small extends SimState
9 | {
10 | public Continuous2D flockers;
11 | public double width;
12 | public double height;
13 | public int numFlockers;
14 | public double cohesion;
15 | public double avoidance;
16 | public double consistency;
17 | public double momentum;
18 | public double neighborhood;
19 |
20 | public Flocking_small(final long seed) {
21 | super(seed);
22 | this.width = 100.0;
23 | this.height = 100.0;
24 | this.numFlockers = 200;
25 | this.neighborhood = 5.0;
26 | this.cohesion = 0.03;
27 | this.avoidance = 0.015;
28 | this.consistency = 0.05;
29 | this.momentum = 1.0;
30 | }
31 |
32 | public void start() {
33 | super.start();
34 | Steppable[] array_agents = new Steppable[numFlockers];
35 | int count = 0;
36 | this.flockers = new Continuous2D(this.neighborhood / 1.5, this.width, this.height);
37 | for (int x = 0; x < this.numFlockers; ++x) {
38 | final Double2D location = new Double2D(this.random.nextDouble() * this.width, this.random.nextDouble() * this.height);
39 | final Double2D vel = new Double2D(this.random.nextDouble()*2-1, this.random.nextDouble()*2-1);
40 | final Flocker_small flocker = new Flocker_small(location, vel);
41 | this.flockers.setObjectLocation((Object)flocker, location);
42 | flocker.flockers = this.flockers;
43 | flocker.theFlock = this;
44 | array_agents[count] = flocker;
45 | ++count;
46 | }
47 | this.schedule.scheduleRepeating(new RandomSequence(array_agents));
48 | }
49 |
50 | public static void main(final String[] args) {
51 | doLoop((Class)Flocking_small.class, args);
52 | System.exit(0);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/Schelling/Mesa/Schelling.py:
--------------------------------------------------------------------------------
1 | import random
2 |
3 | import mesa
4 | from mesa import Model
5 | from mesa.discrete_space import CellAgent, OrthogonalMooreGrid
6 |
7 | class SchellingAgent(CellAgent):
8 | '''
9 | Schelling segregation agent
10 | '''
11 | def __init__(self, model, cell, agent_type):
12 | '''
13 | Create a new Schelling agent.
14 | Args:
15 | unique_id: Unique identifier for the agent.
16 | x, y: Agent initial location.
17 | agent_type: Indicator for the agent's type (minority=1, majority=0)
18 | '''
19 | super().__init__(model)
20 | self.cell = cell
21 | self.type = agent_type
22 |
23 | def step(self):
24 | similar = 0
25 | r = self.model.radius
26 | for neighbor in self.cell.get_neighborhood(radius=self.model.radius).agents:
27 | if neighbor.type == self.type:
28 | similar += 1
29 |
30 | # If unhappy, move:
31 | if similar < self.model.homophily:
32 | self.cell = self.model.grid.select_random_empty_cell()
33 |
34 | class SchellingModel(Model):
35 | '''
36 | Model class for the Schelling segregation model.
37 | '''
38 |
39 | def __init__(self, seed, height, width, homophily, radius, density, minority_pc=0.5):
40 | '''
41 | '''
42 | super().__init__(seed=seed)
43 | self.height = height
44 | self.width = width
45 | self.density = density
46 | self.minority_pc = minority_pc
47 | self.homophily = homophily
48 | self.radius = radius
49 | self.grid = OrthogonalMooreGrid((width, height), random=self.random, capacity=1)
50 |
51 | for cell in self.grid.all_cells:
52 | if self.random.random() < self.density:
53 | agent_type = 1 if self.random.random() < minority_pc else 0
54 | SchellingAgent(self, cell, agent_type)
55 |
56 | def step(self):
57 | '''
58 | Run one step of the model.
59 | '''
60 | self.agents.shuffle_do("step")
61 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The Agents.jl package is licensed under the MIT "Expat" License:
2 |
3 | > The MIT License (MIT)
4 | >
5 | > Copyright (c) 2019-present, George Datseris, Tim DuBois, Ali R. Vahdati, Aayush Sabharwal, Adriano Meligrana and other open source contributors
6 | >
7 | > Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8 | >
9 | >The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 | >
11 | >THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A >PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12 |
13 |
14 | This repository includes code for benchmarking purposes from the following projects, which have their own licenses:
15 | - [Mesa](https://github.com/projectmesa/mesa/blob/master/LICENSE) [Apache2]
16 | - [MASON](https://github.com/eclab/mason/blob/master/LICENSE) [AFL]
17 | - [NetLogo, Flocking](http://ccl.northwestern.edu/netlogo/models/Flocking) [Creative Commons Attribution-NonCommercial-ShareAlike 3.0]
18 | - [NetLogo, Wolf Sheep Predation](http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation) [Creative Commons Attribution-NonCommercial-ShareAlike 3.0]
19 | - [NetLogo, Fire](http://ccl.northwestern.edu/netlogo/models/Fire) [Creative Commons Attribution-NonCommercial-ShareAlike 3.0]
20 | - [NetLogo, Segregation](http://ccl.northwestern.edu/netlogo/models/Segregation) [Creative Commons Attribution-NonCommercial-ShareAlike 3.0]
21 |
--------------------------------------------------------------------------------
/Flocking/NetLogo/parameters_flocking.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | setup
4 | benchmark
5 | ticks = 100
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | setup
32 | benchmark
33 | ticks = 100
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/WolfSheep/Mason/Sheep_large.java:
--------------------------------------------------------------------------------
1 | import sim.engine.*;
2 | import sim.field.continuous.*;
3 | import sim.field.grid.IntGrid2D;
4 | import sim.field.grid.SparseGrid2D;
5 | import sim.util.*;
6 |
7 | public class Sheep_large implements Steppable
8 | {
9 | public Int2D loc = new Int2D(0,0);
10 | public SparseGrid2D fieldSheeps;
11 | public IntGrid2D fieldGrass;
12 | public Wsg_large theWsg;
13 | public boolean dead = false;
14 | public int energy = 0;
15 | public Sheep_large(Int2D location) { loc = location; }
16 |
17 | public boolean isDead() { return dead; }
18 | public void setDead(boolean val) { dead = val; }
19 |
20 | public void step(SimState state)
21 | {
22 | if (dead) return;
23 |
24 | final Wsg_large wsg = (Wsg_large)state;
25 |
26 | boolean moved = false;
27 | int x = loc.x;
28 | int y = loc.y;
29 |
30 | int xmin = (x>0) ? -1 : 0;
31 | int xmax = (x0) ? -1 : 0;
33 | int ymax = (y0) ? -1 : 0;
31 | int xmax = (x0) ? -1 : 0;
33 | int ymax = (y0) ? -1 : 0;
29 | int xmax = (x0) ? -1 : 0;
31 | int ymax = (y 0){
42 | for (int k = 0; k < a.numObjs; k++) {
43 | Sheep_large s = (Sheep_large) a.objs[k];
44 | if (!s.isDead())
45 | {
46 | b.add(s);
47 | }
48 | }
49 | }
50 |
51 | if (b != null && b.numObjs > 0){
52 | int q = wsg.random.nextInt(b.numObjs);
53 | Sheep_large s = (Sheep_large) b.objs[q];
54 | s.setDead(true);
55 | energy += 13;
56 | }
57 |
58 | energy -= 1;
59 |
60 | if (energy <= 0) {
61 | dead = true;
62 | state.schedule.scheduleOnce(this);
63 | return;
64 | }
65 | if (wsg.random.nextDouble() < 0.2) {
66 | energy /= 2;
67 | Int2D location = new Int2D(loc.x, loc.y);
68 |
69 | Wolf_large w = new Wolf_large(location);
70 | w.energy = energy;
71 |
72 | wsg.fieldWolves.setObjectLocation(w, location);
73 | Schedule schedule = state.schedule;
74 | schedule.scheduleRepeating(w, 2, 1.0);
75 | }
76 |
77 | }
78 |
79 | }
--------------------------------------------------------------------------------
/WolfSheep/Agents/WolfSheep.jl:
--------------------------------------------------------------------------------
1 | using Agents
2 |
3 | @agent struct Wolf(GridAgent{2})
4 | energy::Float64
5 | const reproduction_prob::Float64
6 | const Δenergy::Float64
7 | end
8 |
9 | @agent struct Sheep(GridAgent{2})
10 | energy::Float64
11 | const reproduction_prob::Float64
12 | const Δenergy::Float64
13 | end
14 |
15 | function predator_prey_model(rng, n_sheep, n_wolves, dims,
16 | regrowth_time, sheep_reproduce, wolf_reproduce;
17 | Δenergy_sheep = 5, Δenergy_wolf = 13,)
18 | space = GridSpace(dims, periodic = false)
19 | properties = (fully_grown = falses(dims), countdown = zeros(Int, dims),
20 | regrowth_time = regrowth_time)
21 | scheduler = Schedulers.ByType(true, true, Union{Wolf, Sheep})
22 | model = ABM(Union{Wolf, Sheep}, space; agent_step!, model_step!, scheduler,
23 | properties, rng, warn = false)
24 | for _ in 1:n_sheep
25 | energy = rand(abmrng(model), 0:(Δenergy_sheep * 2 - 1))
26 | add_agent!(Sheep, model, energy, sheep_reproduce, Δenergy_sheep)
27 | end
28 | for _ in 1:n_wolves
29 | energy = rand(abmrng(model), 0:(Δenergy_wolf * 2 - 1))
30 | add_agent!(Wolf, model, energy, wolf_reproduce, Δenergy_wolf)
31 | end
32 | @inbounds for p in positions(model)
33 | fully_grown = rand(abmrng(model), Bool)
34 | countdown = fully_grown ? regrowth_time : rand(abmrng(model), 0:(regrowth_time - 1))
35 | model.countdown[p...] = countdown
36 | model.fully_grown[p...] = fully_grown
37 | end
38 | return model
39 | end
40 |
41 | function agent_step!(agent, model)
42 | randomwalk!(agent, model; ifempty = false)
43 | agent.energy -= 1
44 | eat!(agent, model)
45 | if agent.energy < 0
46 | remove_agent!(agent, model)
47 | elseif rand(abmrng(model)) <= agent.reproduction_prob
48 | agent.energy /= 2
49 | replicate!(agent, model)
50 | end
51 | end
52 |
53 | function eat!(sheep::Sheep, model)
54 | if model.fully_grown[sheep.pos...]
55 | sheep.energy += sheep.Δenergy
56 | model.fully_grown[sheep.pos...] = false
57 | end
58 | end
59 |
60 | function eat!(wolf::Wolf, model)
61 | dinner = random_agent_in_position(wolf.pos, model, is_sheep)
62 | if !isnothing(dinner)
63 | remove_agent!(dinner, model)
64 | wolf.energy += wolf.Δenergy
65 | end
66 | end
67 |
68 | is_sheep(agent) = agent isa Sheep
69 |
70 | function model_step!(model)
71 | @inbounds for p in positions(model)
72 | if !(model.fully_grown[p...])
73 | if model.countdown[p...] ≤ 0
74 | model.fully_grown[p...] = true
75 | model.countdown[p...] = model.regrowth_time
76 | else
77 | model.countdown[p...] -= 1
78 | end
79 | end
80 | end
81 | end
82 |
--------------------------------------------------------------------------------
/WolfSheep/Mason/Wolf_small.java:
--------------------------------------------------------------------------------
1 | import sim.engine.*;
2 | import sim.field.continuous.*;
3 | import sim.field.grid.IntGrid2D;
4 | import sim.field.grid.SparseGrid2D;
5 | import sim.util.*;
6 |
7 | public class Wolf_small implements Steppable
8 | {
9 | public Int2D loc = new Int2D(0,0);
10 | public Int2D lastd = new Int2D(0,0);
11 | public SparseGrid2D fieldWolves;
12 | public SparseGrid2D fieldSheeps;
13 | public Wsg_small theWsg;
14 | public boolean dead = false;
15 | public int energy = 0;
16 | public Wolf_small(Int2D location) { loc = location; }
17 |
18 | public boolean isDead() { return dead; }
19 | public void setDead(boolean val) { dead = val; }
20 |
21 | public void step(SimState state)
22 | {
23 | if (dead) return;
24 |
25 | final Wsg_small wsg = (Wsg_small)state;
26 |
27 | int x = loc.x;
28 | int y = loc.y;
29 |
30 | int xmin = (x>0) ? -1 : 0;
31 | int xmax = (x0) ? -1 : 0;
33 | int ymax = (y 0){
46 | for (int k = 0; k < a.numObjs; k++) {
47 | Sheep_small s = (Sheep_small) a.objs[k];
48 | if (!s.isDead())
49 | {
50 | b.add(s);
51 | }
52 | }
53 | }
54 | if (b != null && b.numObjs > 0){
55 | int q = wsg.random.nextInt(b.numObjs);
56 | Sheep_small s = (Sheep_small) b.objs[q];
57 | s.setDead(true);
58 | energy += 13;
59 | }
60 |
61 | energy -= 1;
62 | if (energy <= 0) {
63 | dead = true;
64 | state.schedule.scheduleOnce(this);
65 | return;
66 | }
67 |
68 | //reproduce
69 | if (wsg.random.nextDouble() < 0.1) {
70 | energy /= 2;
71 | Int2D location = new Int2D(loc.x, loc.y);
72 |
73 | Wolf_small w = new Wolf_small(location);
74 | w.energy = energy;
75 |
76 | wsg.fieldWolves.setObjectLocation(w, location);
77 | Schedule schedule = state.schedule;
78 | schedule.scheduleRepeating(w, 2, 1.0);
79 | }
80 |
81 | }
82 | }
--------------------------------------------------------------------------------
/Schelling/Mason/Schelling_small.java:
--------------------------------------------------------------------------------
1 | import sim.engine.Steppable;
2 | import sim.util.Int2D;
3 | import sim.util.Bag;
4 | import sim.field.grid.ObjectGrid2D;
5 | import sim.engine.SimState;
6 | import sim.engine.RandomSequence;
7 |
8 | public class Schelling_small extends SimState
9 | {
10 | public int gridHeight;
11 | public int gridWidth;
12 | public int neighborhood;
13 | public int threshold;
14 | public double redProbability;
15 | public double blueProbability;
16 | public double emptyProbability;
17 | public double unavailableProbability;
18 | public ObjectGrid2D neighbors;
19 | public Bag emptySpaces;
20 | public Bag fillSpaces;
21 |
22 | public Schelling_small(final long seed) {
23 | this(seed, 40, 40);
24 | }
25 |
26 | public Schelling_small(final long seed, final int width, final int height) {
27 | super(seed);
28 | this.neighborhood = 1;
29 | this.threshold = 3;
30 | this.redProbability = 0.3125;
31 | this.blueProbability = 0.3125;
32 | this.emptyProbability = 0.375;
33 | this.emptySpaces = new Bag();
34 | this.fillSpaces = new Bag();
35 | this.gridWidth = width;
36 | this.gridHeight = height;
37 | }
38 |
39 | public void start() {
40 | super.start();
41 | for (int x = 0; x < this.gridWidth; ++x) {
42 | for (int y = 0; y < this.gridHeight; ++y) {
43 | final double d = this.random.nextDouble();
44 | if (d < this.redProbability + this.blueProbability) {
45 | this.fillSpaces.add((Object)new Int2D(x, y));
46 | }
47 | else {
48 | this.emptySpaces.add((Object)new Int2D(x, y));
49 | }
50 | }
51 | }
52 |
53 | this.neighbors = new ObjectGrid2D(this.gridWidth, this.gridHeight);
54 |
55 | Steppable[] array_agents = new Steppable[this.fillSpaces.numObjs];
56 | int count = 0;
57 |
58 | for (int i = 0; i < this.fillSpaces.numObjs; ++i) {
59 | double d = this.random.nextDouble();
60 | Int2D pos = (Int2D)this.fillSpaces.objs[i];
61 | if (d < 0.5) {
62 | Agent_small agent = new Agent_small(pos.x, pos.y, 1);
63 | this.neighbors.field[pos.x][pos.y] = agent;
64 | array_agents[count] = agent;
65 | }
66 | else {
67 | Agent_small agent = new Agent_small(pos.x, pos.y, 2);
68 | this.neighbors.field[pos.x][pos.y] = agent;
69 | array_agents[count] = agent;
70 | }
71 | ++count;
72 | }
73 |
74 | this.schedule.scheduleRepeating(new RandomSequence(array_agents));
75 | }
76 |
77 | public static void main(final String[] args) {
78 | doLoop((Class)Schelling_small.class, args);
79 | System.exit(0);
80 | }
81 | }
82 |
83 |
--------------------------------------------------------------------------------
/Schelling/Mason/Schelling_large.java:
--------------------------------------------------------------------------------
1 | import sim.engine.Steppable;
2 | import sim.util.Int2D;
3 | import sim.util.Bag;
4 | import sim.field.grid.ObjectGrid2D;
5 | import sim.engine.SimState;
6 | import sim.engine.RandomSequence;
7 |
8 | public class Schelling_large extends SimState
9 | {
10 | public int gridHeight;
11 | public int gridWidth;
12 | public int neighborhood;
13 | public int threshold;
14 | public double redProbability;
15 | public double blueProbability;
16 | public double emptyProbability;
17 | public double unavailableProbability;
18 | public ObjectGrid2D neighbors;
19 | public Bag emptySpaces;
20 | public Bag fillSpaces;
21 |
22 | public Schelling_large(final long seed) {
23 | this(seed, 100, 100);
24 | }
25 |
26 | public Schelling_large(final long seed, final int width, final int height) {
27 | super(seed);
28 | this.neighborhood = 2;
29 | this.threshold = 8;
30 | this.redProbability = 0.4;
31 | this.blueProbability = 0.4;
32 | this.emptyProbability = 0.2;
33 | this.emptySpaces = new Bag();
34 | this.fillSpaces = new Bag();
35 | this.gridWidth = width;
36 | this.gridHeight = height;
37 | }
38 |
39 | public void start() {
40 | super.start();
41 | for (int x = 0; x < this.gridWidth; ++x) {
42 | for (int y = 0; y < this.gridHeight; ++y) {
43 | final double d = this.random.nextDouble();
44 | if (d < this.redProbability + this.blueProbability) {
45 | this.fillSpaces.add((Object)new Int2D(x, y));
46 | }
47 | else {
48 | this.emptySpaces.add((Object)new Int2D(x, y));
49 | }
50 | }
51 | }
52 |
53 | this.neighbors = new ObjectGrid2D(this.gridWidth, this.gridHeight);
54 |
55 | Steppable[] array_agents = new Steppable[this.fillSpaces.numObjs];
56 | int count = 0;
57 |
58 | for (int i = 0; i < this.fillSpaces.numObjs; ++i) {
59 | double d = this.random.nextDouble();
60 | Int2D pos = (Int2D)this.fillSpaces.objs[i];
61 | if (d < 0.5) {
62 | Agent_large agent = new Agent_large(pos.x, pos.y, 1);
63 | this.neighbors.field[pos.x][pos.y] = agent;
64 | array_agents[count] = agent;
65 | }
66 | else {
67 | Agent_large agent = new Agent_large(pos.x, pos.y, 2);
68 | this.neighbors.field[pos.x][pos.y] = agent;
69 | array_agents[count] = agent;
70 | }
71 | ++count;
72 | }
73 |
74 | this.schedule.scheduleRepeating(new RandomSequence(array_agents));
75 | }
76 |
77 | public static void main(final String[] args) {
78 | doLoop((Class)Schelling_large.class, args);
79 | System.exit(0);
80 | }
81 | }
82 |
83 |
84 |
--------------------------------------------------------------------------------
/WolfSheep/NetLogo/parameters_wolfsheep.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | setup
4 | benchmark
5 | ticks = 100
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | setup
41 | benchmark
42 | ticks = 100
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/Flocking/Mesa/Flocking.py:
--------------------------------------------------------------------------------
1 | """
2 | Flockers
3 | =============================================================
4 | A Mesa implementation of Craig Reynolds's Boids flocker model.
5 | Uses numpy arrays to represent vectors.
6 | """
7 |
8 | import numpy as np
9 |
10 | from mesa import Model
11 | from mesa.experimental.continuous_space import ContinuousSpace
12 |
13 | from boid import Boid
14 |
15 | class BoidFlockers(Model):
16 | """
17 | Flocker model class. Handles agent creation, placement and scheduling.
18 | """
19 |
20 | def __init__(
21 | self,
22 | seed,
23 | population_size,
24 | width,
25 | height,
26 | vision,
27 | speed=1,
28 | separation=1,
29 | cohere=0.03,
30 | separate=0.015,
31 | match=0.05,
32 | ):
33 | """
34 | Create a new Flockers model.
35 |
36 | Args:
37 | population: Number of Boids
38 | width, height: Size of the space.
39 | speed: How fast should the Boids move.
40 | vision: How far around should each Boid look for its neighbors
41 | separation: What's the minimum distance each Boid will attempt to
42 | keep from any other
43 | cohere, separate, match: factors for the relative importance of
44 | the three drives. """
45 | super().__init__(seed=seed)
46 |
47 | # Set up the space
48 | self.space = ContinuousSpace(
49 | [[0, width], [0, height]],
50 | torus=True,
51 | random=self.random,
52 | n_agents=population_size,
53 | )
54 |
55 | # Create and place the Boid agents
56 | positions = self.rng.random(size=(population_size, 2)) * self.space.size
57 | directions = self.rng.uniform(-1, 1, size=(population_size, 2))
58 | Boid.create_agents(
59 | self,
60 | population_size,
61 | self.space,
62 | position=positions,
63 | direction=directions,
64 | cohere=cohere,
65 | separate=separate,
66 | match=match,
67 | speed=speed,
68 | vision=vision,
69 | separation=separation,
70 | )
71 |
72 | # For tracking statistics
73 | self.average_heading = None
74 | self.update_average_heading()
75 |
76 | def update_average_heading(self):
77 | """Calculate the average heading (direction) of all Boids."""
78 | if not self.agents:
79 | self.average_heading = 0
80 | return
81 |
82 | headings = np.array([agent.direction for agent in self.agents])
83 | mean_heading = np.mean(headings, axis=0)
84 | self.average_heading = np.arctan2(mean_heading[1], mean_heading[0])
85 |
86 | def step(self):
87 | """Run one step of the model.
88 |
89 | All agents are activated in random order using the AgentSet shuffle_do method.
90 | """
91 | self.agents.shuffle_do("step")
92 | self.update_average_heading()
93 |
--------------------------------------------------------------------------------
/Flocking/Mesa/boid.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 |
3 | from mesa.experimental.continuous_space import ContinuousSpaceAgent
4 |
5 | class Boid(ContinuousSpaceAgent):
6 | """
7 | A Boid-style flocker agent.
8 |
9 | The agent follows three behaviors to flock:
10 | - Cohesion: steering towards neighboring agents.
11 | - Separation: avoiding getting too close to any other agent.
12 | - Alignment: try to fly in the same direction as the neighbors.
13 |
14 | Boids have a vision that defines the radius in which they look for their
15 | neighbors to flock with. Their speed (a scalar) and velocity (a vector)
16 | define their movement. Separation is their desired minimum distance from
17 | any other Boid.
18 | """
19 |
20 | def __init__(
21 | self,
22 | model,
23 | space,
24 | position,
25 | speed,
26 | direction,
27 | vision,
28 | separation,
29 | cohere=0.03,
30 | separate=0.015,
31 | match=0.05,
32 | ):
33 | """
34 | Create a new Boid flocker agent.
35 |
36 | Args:
37 | unique_id: Unique agent identifyer.
38 | pos: Starting position
39 | speed: Distance to move per step.
40 | heading: numpy vector for the Boid's direction of movement.
41 | vision: Radius to look around for nearby Boids.
42 | separation: Minimum distance to maintain from other Boids.
43 | cohere: the relative importance of matching neighbors' positions
44 | separate: the relative importance of avoiding close neighbors
45 | match: the relative importance of matching neighbors' headings
46 |
47 | """
48 | super().__init__(space, model)
49 | self.position = position
50 | self.speed = speed
51 | self.direction = direction
52 | self.vision = vision
53 | self.separation = separation
54 | self.cohere_factor = cohere
55 | self.separate_factor = separate
56 | self.match_factor = match
57 | self.neighbors = []
58 |
59 | def step(self):
60 | """
61 | Get the Boid's neighbors, compute the new vector, and move accordingly.
62 | """
63 |
64 | neighbors, distances = self.get_neighbors_in_radius(radius=self.vision)
65 | self.neighbors = [n for n in neighbors if n is not self]
66 |
67 | # If no neighbors, maintain current direction
68 | if not neighbors:
69 | self.position += self.direction * self.speed
70 | return
71 |
72 | delta = self.space.calculate_difference_vector(self.position, agents=neighbors)
73 |
74 | cohere_vector = delta.sum(axis=0) * self.cohere_factor
75 | separation_vector = (
76 | -1 * delta[distances < self.separation].sum(axis=0) * self.separate_factor
77 | )
78 | match_vector = (
79 | np.asarray([n.direction for n in neighbors]).sum(axis=0) * self.match_factor
80 | )
81 |
82 | # Update direction based on the three behaviors
83 | self.direction += (cohere_vector + separation_vector + match_vector) / len(
84 | neighbors
85 | )
86 |
87 | # Normalize direction vector
88 | self.direction /= np.linalg.norm(self.direction)
89 |
90 | # Move boid
91 | self.position += self.direction * self.speed
92 |
93 |
--------------------------------------------------------------------------------
/WolfSheep/Mason/Wsg_small.java:
--------------------------------------------------------------------------------
1 | import sim.engine.*;
2 | import sim.util.*;
3 | import sim.field.grid.IntGrid2D;
4 | import sim.field.grid.SparseGrid2D;
5 |
6 | public class Wsg_small extends SimState
7 | {
8 | public static final int GRID_HEIGHT = 25;
9 | public static final int GRID_WIDTH = 25;
10 | public SparseGrid2D fieldSheeps = new SparseGrid2D(GRID_WIDTH, GRID_HEIGHT);
11 | public SparseGrid2D fieldWolves = new SparseGrid2D(GRID_WIDTH, GRID_HEIGHT);
12 | public IntGrid2D fieldGrass = new IntGrid2D(GRID_WIDTH, GRID_HEIGHT);
13 | public IntGrid2D fieldFullyGrown = new IntGrid2D(GRID_WIDTH, GRID_HEIGHT);
14 |
15 | public int numWS = 100;
16 | public int numSheep = 60;
17 | public int numWolves = 40;
18 |
19 | public Wsg_small(long seed)
20 | {
21 | super(seed);
22 | }
23 |
24 | public void start()
25 | {
26 | super.start();
27 |
28 | for (int i = 0; i < GRID_WIDTH; i++) {
29 | for (int j = 0; j < GRID_HEIGHT; j++) {
30 | if (random.nextDouble() < 0.5) {
31 | fieldGrass.set(i, j, random.nextInt(20));
32 | fieldFullyGrown.set(i, j, 1);
33 | } else {
34 | fieldGrass.set(i, j, 0);
35 | fieldFullyGrown.set(i, j, 0);
36 | }
37 | }
38 | }
39 |
40 | for(int x=0;x None:
85 | """Set grass growth state and schedule regrowth if eaten."""
86 | self._fully_grown = value
87 |
88 | if not value: # If grass was just eaten
89 | self.model.simulator.schedule_event_relative(
90 | setattr,
91 | self.grass_regrowth_time,
92 | function_args=[self, "fully_grown", True],
93 | )
94 |
95 | def __init__(self, model, countdown, grass_regrowth_time, cell):
96 | """Create a new patch of grass.
97 |
98 | Args:
99 | model: Model instance
100 | countdown: Time until grass is fully grown again
101 | grass_regrowth_time: Time needed to regrow after being eaten
102 | cell: Cell to which this grass patch belongs
103 | """
104 | super().__init__(model)
105 | self._fully_grown = countdown == 0
106 | self.grass_regrowth_time = grass_regrowth_time
107 | self.cell = cell
108 |
109 | # Schedule initial growth if not fully grown
110 | if not self.fully_grown:
111 | self.model.simulator.schedule_event_relative(
112 | setattr, countdown, function_args=[self, "fully_grown", True]
113 | )
114 |
--------------------------------------------------------------------------------
/Flocking/Mason/Flocker_large.java:
--------------------------------------------------------------------------------
1 | import sim.engine.SimState;
2 | import sim.util.Bag;
3 | import sim.field.continuous.Continuous2D;
4 | import sim.util.Double2D;
5 | import sim.engine.Steppable;
6 |
7 | public class Flocker_large implements Steppable
8 | {
9 | public Double2D loc;
10 | public Double2D lastd;
11 | public Continuous2D flockers;
12 | public Flocking_large theFlock;
13 |
14 | public Flocker_large(final Double2D location, final Double2D lastd) {
15 | this.lastd = lastd;
16 | this.loc = location;
17 | }
18 |
19 | public Bag getNeighbors() {
20 | return this.flockers.getNeighborsWithinDistance(this.loc, this.theFlock.neighborhood, true);
21 | }
22 |
23 | public Double2D momentum() {
24 | return this.lastd;
25 | }
26 |
27 | public Double2D consistency(final Bag b, final Continuous2D flockers) {
28 | double x = 0.0;
29 | double y = 0.0;
30 | int i = 0;
31 | int count = 0;
32 | for (i = 0; i < b.numObjs; ++i) {
33 | final Flocker_large other = (Flocker_large)b.objs[i];
34 | if (other != this) {
35 | final Double2D m = ((Flocker_large)b.objs[i]).momentum();
36 | x += m.x;
37 | y += m.y;
38 | ++count;
39 | }
40 | }
41 | if (count > 0) {
42 | x /= count;
43 | y /= count;
44 | }
45 | return new Double2D(x, y);
46 | }
47 |
48 | public Double2D cohesion(final Bag b, final Continuous2D flockers) {
49 | double x = 0.0;
50 | double y = 0.0;
51 | int count = 0;
52 | int i;
53 | Flocker_large other;
54 | double dx;
55 | double dy;
56 | for (i = 0; i < b.numObjs; ++i) {
57 | other = (Flocker_large)b.objs[i];
58 | if (other != this) {
59 | dx = other.loc.x - this.loc.x;
60 | dy = other.loc.y - this.loc.y;
61 | x += dx;
62 | y += dy;
63 | ++count;
64 | }
65 | }
66 | if (count > 0) {
67 | x /= count;
68 | y /= count;
69 | }
70 | return new Double2D(x, y);
71 | }
72 |
73 | public Double2D avoidance(final Bag b, final Continuous2D flockers) {
74 | double x = 0.0;
75 | double y = 0.0;
76 | int i = 0;
77 | int count = 0;
78 | for (i = 0; i < b.numObjs; ++i) {
79 | final Flocker_large other = (Flocker_large)b.objs[i];
80 | if (other != this) {
81 | final double dx = other.loc.x - this.loc.x;
82 | final double dy = other.loc.y - this.loc.y;
83 | final double lensquared = dx * dx + dy * dy;
84 | ++count;
85 | if (lensquared < 1.0) {
86 | x -= dx;
87 | y -= dy;
88 | }
89 | }
90 | }
91 | if (count > 0) {
92 | x /= count;
93 | y /= count;
94 | }
95 | return new Double2D(x, y);
96 | }
97 |
98 | public void step(final SimState state) {
99 | final Flocking_large flock = (Flocking_large)state;
100 | this.loc = flock.flockers.getObjectLocation((Object)this);
101 | final Bag b = this.getNeighbors();
102 | final Double2D avoid = this.avoidance(b, flock.flockers);
103 | final Double2D cohe = this.cohesion(b, flock.flockers);
104 | final Double2D cons = this.consistency(b, flock.flockers);
105 | final Double2D mome = this.momentum();
106 | double dx = flock.cohesion * cohe.x + flock.avoidance * avoid.x + flock.consistency * cons.x + mome.x;
107 | double dy = flock.cohesion * cohe.y + flock.avoidance * avoid.y + flock.consistency * cons.y + mome.y;
108 | final double dis = Math.sqrt(dx * dx + dy * dy);
109 | if (dis > 0.0) {
110 | dx = dx / dis;
111 | dy = dy / dis;
112 | }
113 | this.lastd = new Double2D(dx, dy);
114 | this.loc = new Double2D(flock.flockers.stx(this.loc.x + dx), flock.flockers.sty(this.loc.y + dy));
115 | flock.flockers.setObjectLocation((Object)this, this.loc);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Flocking/Mason/Flocker_small.java:
--------------------------------------------------------------------------------
1 | import sim.engine.SimState;
2 | import sim.util.Bag;
3 | import sim.field.continuous.Continuous2D;
4 | import sim.util.Double2D;
5 | import sim.engine.Steppable;
6 |
7 | public class Flocker_small implements Steppable
8 | {
9 | public Double2D loc;
10 | public Double2D lastd;
11 | public Continuous2D flockers;
12 | public Flocking_small theFlock;
13 |
14 | public Flocker_small(final Double2D location, final Double2D lastd) {
15 | this.lastd = lastd;
16 | this.loc = location;
17 | }
18 |
19 | public Bag getNeighbors() {
20 | return this.flockers.getNeighborsWithinDistance(this.loc, this.theFlock.neighborhood, true);
21 | }
22 |
23 | public Double2D momentum() {
24 | return this.lastd;
25 | }
26 |
27 | public Double2D consistency(final Bag b, final Continuous2D flockers) {
28 | double x = 0.0;
29 | double y = 0.0;
30 | int i = 0;
31 | int count = 0;
32 | for (i = 0; i < b.numObjs; ++i) {
33 | final Flocker_small other = (Flocker_small)b.objs[i];
34 | if (other != this) {
35 | final Double2D m = ((Flocker_small)b.objs[i]).momentum();
36 | x += m.x;
37 | y += m.y;
38 | ++count;
39 | }
40 | }
41 | if (count > 0) {
42 | x /= count;
43 | y /= count;
44 | }
45 | return new Double2D(x, y);
46 | }
47 |
48 | public Double2D cohesion(final Bag b, final Continuous2D flockers) {
49 | double x = 0.0;
50 | double y = 0.0;
51 | int count = 0;
52 | int i;
53 | Flocker_small other;
54 | double dx;
55 | double dy;
56 | for (i = 0; i < b.numObjs; ++i) {
57 | other = (Flocker_small)b.objs[i];
58 | if (other != this) {
59 | dx = other.loc.x - this.loc.x;
60 | dy = other.loc.y - this.loc.y;
61 | x += dx;
62 | y += dy;
63 | ++count;
64 | }
65 | }
66 | if (count > 0) {
67 | x /= count;
68 | y /= count;
69 | }
70 | return new Double2D(x, y);
71 | }
72 |
73 | public Double2D avoidance(final Bag b, final Continuous2D flockers) {
74 | double x = 0.0;
75 | double y = 0.0;
76 | int i = 0;
77 | int count = 0;
78 | for (i = 0; i < b.numObjs; ++i) {
79 | final Flocker_small other = (Flocker_small)b.objs[i];
80 | if (other != this) {
81 | final double dx = other.loc.x - this.loc.x;
82 | final double dy = other.loc.y - this.loc.y;
83 | final double lensquared = dx * dx + dy * dy;
84 | ++count;
85 | if (lensquared < 1.0) {
86 | x -= dx;
87 | y -= dy;
88 | }
89 | }
90 | }
91 | if (count > 0) {
92 | x /= count;
93 | y /= count;
94 | }
95 | return new Double2D(x, y);
96 | }
97 |
98 | public void step(final SimState state) {
99 | final Flocking_small flock = (Flocking_small)state;
100 | this.loc = flock.flockers.getObjectLocation((Object)this);
101 | final Bag b = this.getNeighbors();
102 | final Double2D avoid = this.avoidance(b, flock.flockers);
103 | final Double2D cohe = this.cohesion(b, flock.flockers);
104 | final Double2D cons = this.consistency(b, flock.flockers);
105 | final Double2D mome = this.momentum();
106 | double dx = flock.cohesion * cohe.x + flock.avoidance * avoid.x + flock.consistency * cons.x + mome.x;
107 | double dy = flock.cohesion * cohe.y + flock.avoidance * avoid.y + flock.consistency * cons.y + mome.y;
108 | final double dis = Math.sqrt(dx * dx + dy * dy);
109 | if (dis > 0.0) {
110 | dx = dx / dis;
111 | dy = dy / dis;
112 | }
113 | this.lastd = new Double2D(dx, dy);
114 | this.loc = new Double2D(flock.flockers.stx(this.loc.x + dx), flock.flockers.sty(this.loc.y + dy));
115 | flock.flockers.setObjectLocation((Object)this, this.loc);
116 | }
117 | }
118 |
--------------------------------------------------------------------------------
/Flocking/DECLARATION.md:
--------------------------------------------------------------------------------
1 | # Flocking model
2 |
3 | An archetypical model of flocking behaviour of animals in continuous space. It is meant to test the performance of the software in continuous space: handling 64-bit floats, moving agents, searching for nearby agents.
4 |
5 | Note that there are two versions of this model, a small one and a large one. The difference in the large is that the space extent, visual distance, and number of agents, are larger.
6 |
7 | The flock model illustrates how flocking behaviour can emerge when each bird follows three simple rules:
8 |
9 | * maintain a minimum distance from other birds to avoid collision.
10 | * fly towards the average position of neighbors.
11 | * fly in the average direction of neighbors.
12 |
13 | ## Rules of the ABM
14 |
15 | - Agents live in a 2 dimensional continuous space. This means that the agent position is a 64 bit float and that the extent of the space the agents live in is also a 64 bit float.
16 | - The space is periodic in both directions: if an agent moves outside the space extent, the agent wraps back to the other side. Additionally, when searching for nearby agents, the periodicity of the space must be respected.
17 | - Agents represent birds trying to flock. They have many properties that are listed below, including the type each property should have. See the technical implementation below for default values (the properties may be named arbitrarily by each implementation):
18 | - `ID`, integer, a unique identifier for each agent.
19 | - `pos`, a tuple/vector of 2 64-bit floats, the position of the agent.
20 | - `vel`, a tuple/vector of 2 64-bit floats, the velocity of the agent. The rules of the ABM enforce `vel` to always be a unit vector.
21 | - `speed`, 64-bit number, the speed of the agent (magnitude of velocity). Defines how much an agent will move in one simulation step.
22 | - `separation`, 64-bit real, defines the minimum distance a bird must maintain from its neighbors.
23 | - `visual_distance` refers to the distance a bird can see and defines a radius of neighboring birds.
24 | - `cohere_factor`, 64-bit number, is the importance of maintaining the average position of neighbors.
25 | - `match_factor`, 64bit real, is the importance of matching the average trajectory of neighboring birds.
26 | - `separate_factor`, 64bit float, is the importance of maintaining the minimum distance from neighboring birds.
27 | - Agents are activated in sequence one by one in a random order (a new random order must be generated at each step of the simulation). Once activated, each agent does the following:
28 | - Finds all neighbors within its visual distance (i.e. finds all neighbors with euclidean distance less or equal to the value of `visual_distance`).
29 | - Three orientation vectors are generated from the neighbors: a coherence, a matching, and a separation vector. How these vectors are generated is actually simpler to show in code, see technical implementation below.
30 | - The agent updates its velocity based on the three orientation vectors and its own velocity as the average of the four vectors. The velocity vector is then normalized to unit length.
31 | - The agent moves according to the direction of its velocity vector for a length given by the `speed` agent property.
32 | - The simulation is performed for a fixed amount of steps.
33 |
34 | ## Technical implementation
35 |
36 | The simulation is performed for exactly 100 steps.
37 |
38 | Defaults that are the same for the small and large version of simulation:
39 |
40 | - speed of birds: 1.0
41 | - cohere factor of birds: 0.03
42 | - separation of birds: 1.0
43 | - separate factor of birds: 0.015
44 | - match factor of birds: 0.05
45 |
46 | Defaults for the small version:
47 |
48 | - dimensions of the space: (100, 100)
49 | - number of birds: 200
50 | - visual distance of birds: 5.0
51 |
52 | Defaults for the large version:
53 |
54 | - dimensions of the space: (150, 150)
55 | - number of birds: 400
56 | - visual distance of birds: 15.0
57 |
58 | Here is the code for the update rule of the flocking behaviour in Agents.jl:
59 | ```julia
60 | function flocking_agent_step!(bird, model)
61 | neighbor_ids = nearby_ids(bird, model, bird.visual_distance)
62 | N = 0
63 | match = separate = cohere = (0.0, 0.0)
64 | for id in neighbor_ids
65 | N += 1
66 | neighbor = model[id].pos
67 | heading = neighbor .- bird.pos
68 | cohere = cohere .+ heading
69 | if euclidean_distance(bird.pos, neighbor, model) < bird.separation
70 | separate = separate .- heading
71 | end
72 | match = match .+ model[id].vel
73 | end
74 | N = max(N, 1)
75 | cohere = cohere ./ N .* bird.cohere_factor
76 | separate = separate ./ N .* bird.separate_factor
77 | match = match ./ N .* bird.match_factor
78 | bird.vel = (bird.vel .+ cohere .+ separate .+ match) ./ 2
79 | bird.vel = bird.vel ./ norm(bird.vel)
80 | move_agent!(bird, model, bird.speed)
81 | end
82 | ```
83 |
84 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Agent based modelling frameworks comparison
2 |
3 |
4 | [](https://doi.org/10.5281/zenodo.8016506)
5 |
6 |
7 |
8 | This repository contains code used to compare performance and features between various agent based modelling **(ABM)** frameworks. Currently, frameworks compared are [Agents.jl](https://github.com/JuliaDynamics/Agents.jl), [NetLogo](https://github.com/NetLogo/NetLogo), [MASON](https://github.com/eclab/mason) and [Mesa](https://github.com/projectmesa/mesa). We happily welcome more frameworks to join the comparison.
9 |
10 | **The performance benchmark comparison is run automatically during continuous integration, and hence the comparison is updated after every pull request to this repo.**
11 |
12 | This repository has been initiated and maintained by the developers of Agents.jl. However, it strongly welcomes contributions (in the form of Pull Requests) from developers or users of other modelling frameworks. Contributions may improve performance of a model implementation, or simplify the code of the implementation, provided that they still abide the model declaration, see below for more information. Furthermore, we also welcome contributions that may implement a comparison across a new agent based model not yet considered in this comparison.
13 |
14 | ## Latest results
15 |
16 | These are the results of the latest comparison:
17 |
18 | | Model/Framework | Agents.jl 6.2.10 | MASON 22.0 | Netlogo 6.4.0 | Mesa 3.2.0 |
19 | |:------------------|:---------------:|:------------:|:------------:|:---------------:|
20 | | WolfSheep (Time-Ratio, Small-Version) | 1 | 73.3x | 12.8x | 12.4x |
21 | | WolfSheep (Time-Ratio, Large-Version) | 1 | 17.1x | 6.1x | 4.9x |
22 | | WolfSheep (Lines of Code) | 73 | 202 | 137 (871) | 118 |
23 | | Flocking (Time-Ratio, Small-Version) | 1 | 17.7x | 17.1x | 184.1x |
24 | | Flocking (Time-Ratio, Large-Version) | 1 | 2.8x | 19.0x | 62.7x |
25 | | Flocking (Lines of Code) | 42 | 159 | 82 (689) | 94 |
26 | | Schelling (Time-Ratio, Small-Version) | 1 | 43.3x | 12.5x | 32.3x |
27 | | Schelling (Time-Ratio, Large-Version) | 1 | 3.7x | 13.5x | 23.4x |
28 | | Schelling (Lines of Code) | 26 | 129 | 54 (739) | 33 |
29 |
30 | ## How it works
31 |
32 | Various agent based models have been selected to compare performance, such as the Schelling model for example. This repository is structured as follows
33 |
34 | 1. Each selected ABM is contained in a dedicated folder of this repo.
35 | 1. Inside the ABM folder there is a DECLARATION.md markdown file. In declares both the scientific as well as technical implementation of the ABM. We tried our best to make the declaration as clear and as specific as possible, but we welcome Pull Requests that may clarify the declaration even more.
36 | 1. In the same folder there are subfolders named after the frameworks. Each contains the files that implement and benchmark the ABM implementation.
37 | 1. The implementation must be written in the same way a typical user will use the respective software. The implementations must only use the documented API of the respective software.
38 | 1. The benchmark step operates as follows: all models must be seeded with a given random number generator seed. At the start of the process, _`S` random seeds are generated in a reproducible way (or, alternatively, a random number generator that generates seeds is initialized with a specified seed)_. `S` is the amount of random seeds and hence also the amount of simulations performed for a given model. Unless stated otherwise in the declaration file of an ABM, `S` has been arbitrarily decided to be `100`.
39 | 1. From these `100` random (but reproducibly random) model runs, the median is used as the performance of each software.
40 | 1. The benchmarks are run during continuous integration. The benchmark timings are collected among ABMs and among the different ABM software during continuous integration. The timings are printed in the CI log, and also stored in a csv file (not yet, TODO) to be accessed later.
41 |
42 | ## How to run the benchmarks locally
43 |
44 | To reproduce the results you can run the `runall.sh` file with `bash runall.sh`. It is easier to run the file with a Linux OS, but you can emulate the same behaviour on Windows using WSL.
45 |
46 | The requirements to run the benchmark file are:
47 |
48 | 1. To run the file on a bash shell;
49 | 1. To install the tested frameworks (except for Mason which is already provided);
50 | 1. To make the commands `julia`, `python`, `java` and `javac` available from the shell and to have the bc tool available;
51 | 1. To move the folder where NetLogo is installed, rename it as `netlogo` and put it inside the main folder.
52 |
53 | This snippet was tested on an Ubuntu 22.04 LTS x86_64, but it should work also on other similar environments, copy-paste it on a bash shell to set up everything automatically for the benchmark:
54 |
55 | ```bash
56 | # fetch update software list
57 | sudo apt-get update
58 |
59 | # clone the repository and give permissions
60 | sudo git clone https://github.com/JuliaDynamics/ABM_Framework_Comparisons.git
61 | sudo chmod a+rwx ABM_Framework_Comparisons
62 | sudo chmod -R 777 ABM_Framework_Comparisons
63 |
64 | # install julia
65 | sudo wget https://julialang-s3.julialang.org/bin/linux/x64/1.9/julia-1.11.5-linux-x86_64.tar.gz
66 | sudo tar zxvf julia-1.9.4-linux-x86_64.tar.gz
67 | export PATH=$PATH:$(pwd)"/julia-1.11.5/bin"
68 | printf "\nexport PATH=\"\$PATH:"$(pwd)"/julia-1.11.5/bin\"" >> ~/.bashrc
69 |
70 | # install agents
71 | julia --project=ABM_Framework_Comparisons -e 'using Pkg; Pkg.instantiate()'
72 |
73 | # install java
74 | sudo apt install default-jre-headless
75 | sudo apt install default-jdk-headless
76 |
77 | # install mesa
78 | sudo apt install python3-pip
79 | pip install mesa==3.2.0
80 |
81 | # install netlogo
82 | sudo wget http://ccl.northwestern.edu/netlogo/6.4.0/NetLogo-6.4.0-64.tgz
83 | sudo tar -xzf NetLogo-6.4.0-64.tgz
84 |
85 | # move netlogo inside repository
86 | sudo mv "NetLogo-6.4.0-64" netlogo
87 | sudo mv netlogo ABM_Framework_Comparisons
88 |
89 | # install bc tools
90 | sudo apt install bc
91 |
92 | # move to repo folder
93 | cd ABM_Framework_Comparisons
94 | ```
95 |
96 | If you are using WSL make sure that you move to a folder inside the subsystem before running these commands.
97 |
98 |
--------------------------------------------------------------------------------
/Flocking/NetLogo/Flocking.nlogo:
--------------------------------------------------------------------------------
1 | extensions [ profiler ]
2 |
3 | globals [
4 | time-tot
5 | ]
6 |
7 | turtles-own [
8 | flockmates ;; agentset of nearby turtles
9 | nearest-neighbor ;; closest one of our flockmates
10 | ]
11 |
12 | to benchmark
13 | profiler:reset ;; clear the data
14 | profiler:start ;; start profiling
15 | setup
16 | repeat n_ticks [go] ;; run for n_ticks steps
17 | profiler:stop ;; stop profiling
18 | set time-tot profiler:inclusive-time "go" + profiler:inclusive-time "setup"
19 | file-open "times.txt"
20 | file-print time-tot
21 | file-close
22 | end
23 |
24 | to setup
25 | clear-all
26 | random-seed seed
27 | create-turtles population
28 | [ set color yellow - 2 + random 7 ;; random shades look nice
29 | set size 2 ;; easier to see
30 | setxy random-xcor random-ycor
31 | set flockmates no-turtles ]
32 | set time-tot 0
33 | reset-ticks
34 | end
35 |
36 | to go
37 | ask turtles [ flock ]
38 | ;; the following line is used to make the turtles
39 | ;; animate more smoothly.
40 | ;repeat 5 [ ask turtles [ fd 0.2 ] display ]
41 | ;; for greater efficiency, at the expense of smooth
42 | ;; animation, substitute the following line instead:
43 | ask turtles [ fd 1 ]
44 | tick
45 | end
46 |
47 | to flock ;; turtle procedure
48 | find-flockmates
49 | if any? flockmates
50 | [ find-nearest-neighbor
51 | ifelse distance nearest-neighbor < minimum-separation
52 | [ separate ]
53 | [ align
54 | cohere ] ]
55 | end
56 |
57 | to find-flockmates ;; turtle procedure
58 | set flockmates other turtles in-radius vision
59 | end
60 |
61 | to find-nearest-neighbor ;; turtle procedure
62 | set nearest-neighbor min-one-of flockmates [distance myself]
63 | end
64 |
65 | ;;; SEPARATE
66 |
67 | to separate ;; turtle procedure
68 | turn-away ([heading] of nearest-neighbor) max-separate-turn
69 | end
70 |
71 | ;;; ALIGN
72 |
73 | to align ;; turtle procedure
74 | turn-towards average-flockmate-heading max-align-turn
75 | end
76 |
77 | to-report average-flockmate-heading ;; turtle procedure
78 | ;; We can't just average the heading variables here.
79 | ;; For example, the average of 1 and 359 should be 0,
80 | ;; not 180. So we have to use trigonometry.
81 | let x-component sum [dx] of flockmates
82 | let y-component sum [dy] of flockmates
83 | ifelse x-component = 0 and y-component = 0
84 | [ report heading ]
85 | [ report atan x-component y-component ]
86 | end
87 |
88 | ;;; COHERE
89 |
90 | to cohere ;; turtle procedure
91 | turn-towards average-heading-towards-flockmates max-cohere-turn
92 | end
93 |
94 | to-report average-heading-towards-flockmates ;; turtle procedure
95 | ;; "towards myself" gives us the heading from the other turtle
96 | ;; to me, but we want the heading from me to the other turtle,
97 | ;; so we add 180
98 | let x-component mean [sin (towards myself + 180)] of flockmates
99 | let y-component mean [cos (towards myself + 180)] of flockmates
100 | ifelse x-component = 0 and y-component = 0
101 | [ report heading ]
102 | [ report atan x-component y-component ]
103 | end
104 |
105 | ;;; HELPER PROCEDURES
106 |
107 | to turn-towards [new-heading max-turn] ;; turtle procedure
108 | turn-at-most (subtract-headings new-heading heading) max-turn
109 | end
110 |
111 | to turn-away [new-heading max-turn] ;; turtle procedure
112 | turn-at-most (subtract-headings heading new-heading) max-turn
113 | end
114 |
115 | ;; turn right by "turn" degrees (or left if "turn" is negative),
116 | ;; but never turn more than "max-turn" degrees
117 | to turn-at-most [turn max-turn] ;; turtle procedure
118 | ifelse abs turn > max-turn
119 | [ ifelse turn > 0
120 | [ rt max-turn ]
121 | [ lt max-turn ] ]
122 | [ rt turn ]
123 | end
124 |
125 |
126 | ; Copyright 1998 Uri Wilensky.
127 | ; See Info tab for full copyright and license.
128 | @#$#@#$#@
129 | GRAPHICS-WINDOW
130 | 250
131 | 10
132 | 1058
133 | 819
134 | -1
135 | -1
136 | 8.0
137 | 1
138 | 10
139 | 1
140 | 1
141 | 1
142 | 0
143 | 1
144 | 1
145 | 1
146 | 0
147 | 99
148 | 0
149 | 99
150 | 1
151 | 1
152 | 1
153 | ticks
154 | 30.0
155 |
156 | BUTTON
157 | 39
158 | 93
159 | 116
160 | 126
161 | NIL
162 | setup
163 | NIL
164 | 1
165 | T
166 | OBSERVER
167 | NIL
168 | NIL
169 | NIL
170 | NIL
171 | 1
172 |
173 | BUTTON
174 | 122
175 | 93
176 | 203
177 | 126
178 | NIL
179 | go
180 | T
181 | 1
182 | T
183 | OBSERVER
184 | NIL
185 | NIL
186 | NIL
187 | NIL
188 | 0
189 |
190 | SLIDER
191 | 9
192 | 51
193 | 232
194 | 84
195 | population
196 | population
197 | 1.0
198 | 1000.0
199 | 300.0
200 | 1.0
201 | 1
202 | NIL
203 | HORIZONTAL
204 |
205 | SLIDER
206 | 5
207 | 196
208 | 179
209 | 229
210 | seed
211 | seed
212 | 0.0
213 | 50000.0
214 | 1.0
215 | 1.0
216 | 1
217 | NIL
218 | HORIZONTAL
219 |
220 | SLIDER
221 | 5
222 | 196
223 | 179
224 | 229
225 | n_ticks
226 | n_ticks
227 | 0.0
228 | 50000.0
229 | 1.0
230 | 1.0
231 | 1
232 | NIL
233 | HORIZONTAL
234 |
235 | SLIDER
236 | 4
237 | 217
238 | 237
239 | 250
240 | max-align-turn
241 | max-align-turn
242 | 0.0
243 | 20.0
244 | 5.0
245 | 0.25
246 | 1
247 | degrees
248 | HORIZONTAL
249 |
250 | SLIDER
251 | 4
252 | 251
253 | 237
254 | 284
255 | max-cohere-turn
256 | max-cohere-turn
257 | 0.0
258 | 20.0
259 | 3.0
260 | 0.25
261 | 1
262 | degrees
263 | HORIZONTAL
264 |
265 | SLIDER
266 | 4
267 | 285
268 | 237
269 | 318
270 | max-separate-turn
271 | max-separate-turn
272 | 0.0
273 | 20.0
274 | 1.5
275 | 0.25
276 | 1
277 | degrees
278 | HORIZONTAL
279 |
280 | SLIDER
281 | 9
282 | 135
283 | 232
284 | 168
285 | vision
286 | vision
287 | 0.0
288 | 10.0
289 | 5.0
290 | 0.5
291 | 1
292 | patches
293 | HORIZONTAL
294 |
295 | SLIDER
296 | 9
297 | 169
298 | 232
299 | 202
300 | minimum-separation
301 | minimum-separation
302 | 0.0
303 | 5.0
304 | 1.0
305 | 0.25
306 | 1
307 | patches
308 | HORIZONTAL
309 |
310 | BUTTON
311 | 49
312 | 12
313 | 161
314 | 45
315 | benchmark
316 | benchmark
317 | NIL
318 | 1
319 | T
320 | OBSERVER
321 | NIL
322 | NIL
323 | NIL
324 | NIL
325 | 1
326 |
327 | @#$#@#$#@
328 | ## WHAT IS IT?
329 |
330 | This model is an attempt to mimic the flocking of birds. (The resulting motion also resembles schools of fish.) The flocks that appear in this model are not created or led in any way by special leader birds. Rather, each bird is following exactly the same set of rules, from which flocks emerge.
331 |
332 | ## HOW IT WORKS
333 |
334 | The birds follow three rules: "alignment", "separation", and "cohesion".
335 |
336 | "Alignment" means that a bird tends to turn so that it is moving in the same direction that nearby birds are moving.
337 |
338 | "Separation" means that a bird will turn to avoid another bird which gets too close.
339 |
340 | "Cohesion" means that a bird will move towards other nearby birds (unless another bird is too close).
341 |
342 | When two birds are too close, the "separation" rule overrides the other two, which are deactivated until the minimum separation is achieved.
343 |
344 | The three rules affect only the bird's heading. Each bird always moves forward at the same constant speed.
345 |
346 | ## HOW TO USE IT
347 |
348 | First, determine the number of birds you want in the simulation and set the POPULATION slider to that value. Press SETUP to create the birds, and press GO to have them start flying around.
349 |
350 | The default settings for the sliders will produce reasonably good flocking behavior. However, you can play with them to get variations:
351 |
352 | Three TURN-ANGLE sliders control the maximum angle a bird can turn as a result of each rule.
353 |
354 | VISION is the distance that each bird can see 360 degrees around it.
355 |
356 | ## THINGS TO NOTICE
357 |
358 | Central to the model is the observation that flocks form without a leader.
359 |
360 | There are no random numbers used in this model, except to position the birds initially. The fluid, lifelike behavior of the birds is produced entirely by deterministic rules.
361 |
362 | Also, notice that each flock is dynamic. A flock, once together, is not guaranteed to keep all of its members. Why do you think this is?
363 |
364 | After running the model for a while, all of the birds have approximately the same heading. Why?
365 |
366 | Sometimes a bird breaks away from its flock. How does this happen? You may need to slow down the model or run it step by step in order to observe this phenomenon.
367 |
368 | ## THINGS TO TRY
369 |
370 | Play with the sliders to see if you can get tighter flocks, looser flocks, fewer flocks, more flocks, more or less splitting and joining of flocks, more or less rearranging of birds within flocks, etc.
371 |
372 | You can turn off a rule entirely by setting that rule's angle slider to zero. Is one rule by itself enough to produce at least some flocking? What about two rules? What's missing from the resulting behavior when you leave out each rule?
373 |
374 | Will running the model for a long time produce a static flock? Or will the birds never settle down to an unchanging formation? Remember, there are no random numbers used in this model.
375 |
376 | ## EXTENDING THE MODEL
377 |
378 | Currently the birds can "see" all around them. What happens if birds can only see in front of them? The `in-cone` primitive can be used for this.
379 |
380 | Is there some way to get V-shaped flocks, like migrating geese?
381 |
382 | What happens if you put walls around the edges of the world that the birds can't fly into?
383 |
384 | Can you get the birds to fly around obstacles in the middle of the world?
385 |
386 | What would happen if you gave the birds different velocities? For example, you could make birds that are not near other birds fly faster to catch up to the flock. Or, you could simulate the diminished air resistance that birds experience when flying together by making them fly faster when in a group.
387 |
388 | Are there other interesting ways you can make the birds different from each other? There could be random variation in the population, or you could have distinct "species" of bird.
389 |
390 | ## NETLOGO FEATURES
391 |
392 | Notice the need for the `subtract-headings` primitive and special procedure for averaging groups of headings. Just subtracting the numbers, or averaging the numbers, doesn't give you the results you'd expect, because of the discontinuity where headings wrap back to 0 once they reach 360.
393 |
394 | ## RELATED MODELS
395 |
396 | * Moths
397 | * Flocking Vee Formation
398 | * Flocking - Alternative Visualizations
399 |
400 | ## CREDITS AND REFERENCES
401 |
402 | This model is inspired by the Boids simulation invented by Craig Reynolds. The algorithm we use here is roughly similar to the original Boids algorithm, but it is not the same. The exact details of the algorithm tend not to matter very much -- as long as you have alignment, separation, and cohesion, you will usually get flocking behavior resembling that produced by Reynolds' original model. Information on Boids is available at http://www.red3d.com/cwr/boids/.
403 |
404 | ## HOW TO CITE
405 |
406 | If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.
407 |
408 | For the model itself:
409 |
410 | * Wilensky, U. (1998). NetLogo Flocking model. http://ccl.northwestern.edu/netlogo/models/Flocking. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
411 |
412 | Please cite the NetLogo software as:
413 |
414 | * Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
415 |
416 | ## COPYRIGHT AND LICENSE
417 |
418 | Copyright 1998 Uri Wilensky.
419 |
420 | 
421 |
422 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
423 |
424 | Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.
425 |
426 | This model was created as part of the project: CONNECTED MATHEMATICS: MAKING SENSE OF COMPLEX PHENOMENA THROUGH BUILDING OBJECT-BASED PARALLEL MODELS (OBPML). The project gratefully acknowledges the support of the National Science Foundation (Applications of Advanced Technologies Program) -- grant numbers RED #9552950 and REC #9632612.
427 |
428 | This model was converted to NetLogo as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227. Converted from StarLogoT to NetLogo, 2002.
429 |
430 |
431 | @#$#@#$#@
432 | default
433 | true
434 | 0
435 | Polygon -7500403 true true 150 5 40 250 150 205 260 250
436 |
437 | airplane
438 | true
439 | 0
440 | Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15
441 |
442 | arrow
443 | true
444 | 0
445 | Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150
446 |
447 | box
448 | false
449 | 0
450 | Polygon -7500403 true true 150 285 285 225 285 75 150 135
451 | Polygon -7500403 true true 150 135 15 75 150 15 285 75
452 | Polygon -7500403 true true 15 75 15 225 150 285 150 135
453 | Line -16777216 false 150 285 150 135
454 | Line -16777216 false 150 135 15 75
455 | Line -16777216 false 150 135 285 75
456 |
457 | bug
458 | true
459 | 0
460 | Circle -7500403 true true 96 182 108
461 | Circle -7500403 true true 110 127 80
462 | Circle -7500403 true true 110 75 80
463 | Line -7500403 true 150 100 80 30
464 | Line -7500403 true 150 100 220 30
465 |
466 | butterfly
467 | true
468 | 0
469 | Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
470 | Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
471 | Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
472 | Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
473 | Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
474 | Circle -16777216 true false 135 90 30
475 | Line -16777216 false 150 105 195 60
476 | Line -16777216 false 150 105 105 60
477 |
478 | car
479 | false
480 | 0
481 | Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
482 | Circle -16777216 true false 180 180 90
483 | Circle -16777216 true false 30 180 90
484 | Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
485 | Circle -7500403 true true 47 195 58
486 | Circle -7500403 true true 195 195 58
487 |
488 | circle
489 | false
490 | 0
491 | Circle -7500403 true true 0 0 300
492 |
493 | circle 2
494 | false
495 | 0
496 | Circle -7500403 true true 0 0 300
497 | Circle -16777216 true false 30 30 240
498 |
499 | cow
500 | false
501 | 0
502 | Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
503 | Polygon -7500403 true true 73 210 86 251 62 249 48 208
504 | Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123
505 |
506 | cylinder
507 | false
508 | 0
509 | Circle -7500403 true true 0 0 300
510 |
511 | dot
512 | false
513 | 0
514 | Circle -7500403 true true 90 90 120
515 |
516 | face happy
517 | false
518 | 0
519 | Circle -7500403 true true 8 8 285
520 | Circle -16777216 true false 60 75 60
521 | Circle -16777216 true false 180 75 60
522 | Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
523 |
524 | face neutral
525 | false
526 | 0
527 | Circle -7500403 true true 8 7 285
528 | Circle -16777216 true false 60 75 60
529 | Circle -16777216 true false 180 75 60
530 | Rectangle -16777216 true false 60 195 240 225
531 |
532 | face sad
533 | false
534 | 0
535 | Circle -7500403 true true 8 8 285
536 | Circle -16777216 true false 60 75 60
537 | Circle -16777216 true false 180 75 60
538 | Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183
539 |
540 | fish
541 | false
542 | 0
543 | Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
544 | Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
545 | Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
546 | Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
547 | Circle -16777216 true false 215 106 30
548 |
549 | flag
550 | false
551 | 0
552 | Rectangle -7500403 true true 60 15 75 300
553 | Polygon -7500403 true true 90 150 270 90 90 30
554 | Line -7500403 true 75 135 90 135
555 | Line -7500403 true 75 45 90 45
556 |
557 | flower
558 | false
559 | 0
560 | Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
561 | Circle -7500403 true true 85 132 38
562 | Circle -7500403 true true 130 147 38
563 | Circle -7500403 true true 192 85 38
564 | Circle -7500403 true true 85 40 38
565 | Circle -7500403 true true 177 40 38
566 | Circle -7500403 true true 177 132 38
567 | Circle -7500403 true true 70 85 38
568 | Circle -7500403 true true 130 25 38
569 | Circle -7500403 true true 96 51 108
570 | Circle -16777216 true false 113 68 74
571 | Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
572 | Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240
573 |
574 | house
575 | false
576 | 0
577 | Rectangle -7500403 true true 45 120 255 285
578 | Rectangle -16777216 true false 120 210 180 285
579 | Polygon -7500403 true true 15 120 150 15 285 120
580 | Line -16777216 false 30 120 270 120
581 |
582 | leaf
583 | false
584 | 0
585 | Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
586 | Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195
587 |
588 | line
589 | true
590 | 0
591 | Line -7500403 true 150 0 150 300
592 |
593 | line half
594 | true
595 | 0
596 | Line -7500403 true 150 0 150 150
597 |
598 | pentagon
599 | false
600 | 0
601 | Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120
602 |
603 | person
604 | false
605 | 0
606 | Circle -7500403 true true 110 5 80
607 | Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
608 | Rectangle -7500403 true true 127 79 172 94
609 | Polygon -7500403 true true 195 90 240 150 225 180 165 105
610 | Polygon -7500403 true true 105 90 60 150 75 180 135 105
611 |
612 | plant
613 | false
614 | 0
615 | Rectangle -7500403 true true 135 90 165 300
616 | Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
617 | Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
618 | Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
619 | Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
620 | Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
621 | Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
622 | Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90
623 |
624 | square
625 | false
626 | 0
627 | Rectangle -7500403 true true 30 30 270 270
628 |
629 | square 2
630 | false
631 | 0
632 | Rectangle -7500403 true true 30 30 270 270
633 | Rectangle -16777216 true false 60 60 240 240
634 |
635 | star
636 | false
637 | 0
638 | Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108
639 |
640 | target
641 | false
642 | 0
643 | Circle -7500403 true true 0 0 300
644 | Circle -16777216 true false 30 30 240
645 | Circle -7500403 true true 60 60 180
646 | Circle -16777216 true false 90 90 120
647 | Circle -7500403 true true 120 120 60
648 |
649 | tree
650 | false
651 | 0
652 | Circle -7500403 true true 118 3 94
653 | Rectangle -6459832 true false 120 195 180 300
654 | Circle -7500403 true true 65 21 108
655 | Circle -7500403 true true 116 41 127
656 | Circle -7500403 true true 45 90 120
657 | Circle -7500403 true true 104 74 152
658 |
659 | triangle
660 | false
661 | 0
662 | Polygon -7500403 true true 150 30 15 255 285 255
663 |
664 | triangle 2
665 | false
666 | 0
667 | Polygon -7500403 true true 150 30 15 255 285 255
668 | Polygon -16777216 true false 151 99 225 223 75 224
669 |
670 | truck
671 | false
672 | 0
673 | Rectangle -7500403 true true 4 45 195 187
674 | Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
675 | Rectangle -1 true false 195 60 195 105
676 | Polygon -16777216 true false 238 112 252 141 219 141 218 112
677 | Circle -16777216 true false 234 174 42
678 | Rectangle -7500403 true true 181 185 214 194
679 | Circle -16777216 true false 144 174 42
680 | Circle -16777216 true false 24 174 42
681 | Circle -7500403 false true 24 174 42
682 | Circle -7500403 false true 144 174 42
683 | Circle -7500403 false true 234 174 42
684 |
685 | turtle
686 | true
687 | 0
688 | Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
689 | Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
690 | Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
691 | Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
692 | Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
693 | Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99
694 |
695 | wheel
696 | false
697 | 0
698 | Circle -7500403 true true 3 3 294
699 | Circle -16777216 true false 30 30 240
700 | Line -7500403 true 150 285 150 15
701 | Line -7500403 true 15 150 285 150
702 | Circle -7500403 true true 120 120 60
703 | Line -7500403 true 216 40 79 269
704 | Line -7500403 true 40 84 269 221
705 | Line -7500403 true 40 216 269 79
706 | Line -7500403 true 84 40 221 269
707 |
708 | x
709 | false
710 | 0
711 | Polygon -7500403 true true 270 75 225 30 30 225 75 270
712 | Polygon -7500403 true true 30 75 75 30 270 225 225 270
713 | @#$#@#$#@
714 | NetLogo 6.1.1
715 | @#$#@#$#@
716 | set population 200
717 | setup
718 | repeat 200 [ go ]
719 | @#$#@#$#@
720 | @#$#@#$#@
721 | @#$#@#$#@
722 | @#$#@#$#@
723 | default
724 | 0.0
725 | -0.2 0 0.0 1.0
726 | 0.0 1 1.0 0.0
727 | 0.2 0 0.0 1.0
728 | link direction
729 | true
730 | 0
731 | Line -7500403 true 150 150 90 180
732 | Line -7500403 true 150 150 210 180
733 | @#$#@#$#@
734 | 0
735 | @#$#@#$#@
736 |
--------------------------------------------------------------------------------
/Schelling/NetLogo/Schelling.nlogo:
--------------------------------------------------------------------------------
1 | extensions [profiler]
2 |
3 | globals [
4 | time-tot
5 | ]
6 |
7 | turtles-own [
8 | happy? ; for each turtle, indicates whether at least %-similar-wanted percent of that turtle's neighbors are the same color as the turtle
9 | similar-nearby ; how many neighboring patches have a turtle with my color?
10 | other-nearby ; how many have a turtle of another color?
11 | total-nearby ; sum of previous two variables
12 | ]
13 |
14 | to setup
15 | clear-all
16 | random-seed seed
17 | ; create turtles on random patches.
18 | ask patches [ set pcolor white ]
19 | create-turtles agents [
20 | ; 105 is the color number for "blue"
21 | ; 27 is the color number for "orange"
22 | set color one-of [105 27]
23 | set size 1
24 | setxy random-pxcor random-pycor
25 | ]
26 | update-turtles
27 | set time-tot 0
28 | reset-ticks
29 | end
30 |
31 | to benchmark
32 | profiler:reset ;; clear the data
33 | profiler:start ;; start profiling
34 | setup
35 | repeat n_ticks [go] ;; run for n_ticks steps
36 | profiler:stop ;; stop profiling
37 | set time-tot profiler:inclusive-time "go" + profiler:inclusive-time "setup"
38 | file-open "times.txt"
39 | file-print time-tot
40 | file-close
41 | end
42 |
43 | ; run the model for one tick
44 | to go
45 | update-turtles
46 | tick
47 | end
48 |
49 | ; unhappy turtles try a new spot
50 | to move-unhappy-turtles
51 | ask turtles
52 | [ find-new-spot ]
53 | end
54 |
55 | to find-new-spot
56 | move-to one-of patches with [not any? turtles-here]
57 | end
58 |
59 | to update-turtles
60 | ask turtles [
61 | ; in next two lines, we use "neighbors" to test the eight patches
62 | ; surrounding the current patch
63 | set similar-nearby count (other turtles-on patches in-radius r) with [ color = [ color ] of myself ]
64 | set other-nearby count (other turtles-on patches in-radius r) with [ color != [ color ] of myself ]
65 | set total-nearby similar-nearby + other-nearby
66 | set happy? similar-nearby >= (%-similar-wanted * total-nearby / 100)
67 | if not happy? [ find-new-spot ]
68 | ]
69 | end
70 |
71 | ; Copyright 1997 Uri Wilensky.
72 | ; See Info tab for full copyright and license.
73 | @#$#@#$#@
74 | GRAPHICS-WINDOW
75 | 375
76 | 10
77 | 783
78 | 419
79 | -1
80 | -1
81 | 8.0
82 | 1
83 | 10
84 | 1
85 | 1
86 | 1
87 | 0
88 | 1
89 | 1
90 | 1
91 | 0
92 | 49
93 | 0
94 | 49
95 | 1
96 | 1
97 | 1
98 | ticks
99 | 30.0
100 |
101 | SLIDER
102 | 10
103 | 95
104 | 285
105 | 128
106 | %-similar-wanted
107 | %-similar-wanted
108 | 0
109 | 100
110 | 30.0
111 | 1
112 | 1
113 | %
114 | HORIZONTAL
115 |
116 | SLIDER
117 | 5
118 | 196
119 | 179
120 | 229
121 | r
122 | r
123 | 0.0
124 | 50000.0
125 | 1.0
126 | 1.0
127 | 1
128 | NIL
129 | HORIZONTAL
130 |
131 | BUTTON
132 | 10
133 | 55
134 | 90
135 | 88
136 | setup
137 | setup
138 | NIL
139 | 1
140 | T
141 | OBSERVER
142 | NIL
143 | NIL
144 | NIL
145 | NIL
146 | 1
147 |
148 | BUTTON
149 | 200
150 | 55
151 | 285
152 | 88
153 | go
154 | go
155 | T
156 | 1
157 | T
158 | OBSERVER
159 | NIL
160 | NIL
161 | NIL
162 | NIL
163 | 0
164 |
165 | BUTTON
166 | 100
167 | 55
168 | 190
169 | 88
170 | go once
171 | go
172 | NIL
173 | 1
174 | T
175 | OBSERVER
176 | NIL
177 | NIL
178 | NIL
179 | NIL
180 | 0
181 |
182 | CHOOSER
183 | 801
184 | 380
185 | 950
186 | 425
187 | visualization
188 | visualization
189 | "old" "square-x"
190 | 1
191 |
192 | SLIDER
193 | 5
194 | 196
195 | 179
196 | 229
197 | seed
198 | seed
199 | 0.0
200 | 50000.0
201 | 1.0
202 | 1.0
203 | 1
204 | NIL
205 | HORIZONTAL
206 |
207 | SLIDER
208 | 5
209 | 196
210 | 179
211 | 229
212 | n_ticks
213 | n_ticks
214 | 0.0
215 | 50000.0
216 | 1.0
217 | 1.0
218 | 1
219 | NIL
220 | HORIZONTAL
221 |
222 | SLIDER
223 | 10
224 | 10
225 | 285
226 | 43
227 | agents
228 | agents
229 | 50
230 | 5000
231 | 2000.0
232 | 1
233 | 1
234 | NIL
235 | HORIZONTAL
236 |
237 | PLOT
238 | 10
239 | 295
240 | 260
241 | 445
242 | Number-unhappy
243 | NIL
244 | NIL
245 | 0.0
246 | 10.0
247 | 0.0
248 | 100.0
249 | true
250 | false
251 | "" ""
252 | PENS
253 | "default" 1.0 0 -16777216 true "" "plot count turtles with [not happy?]"
254 |
255 | MONITOR
256 | 265
257 | 315
258 | 355
259 | 360
260 | num-unhappy
261 | count turtles with [not happy?]
262 | 1
263 | 1
264 | 11
265 |
266 | MONITOR
267 | 265
268 | 170
269 | 355
270 | 215
271 | # agents
272 | count turtles
273 | 1
274 | 1
275 | 11
276 |
277 | BUTTON
278 | 820
279 | 30
280 | 932
281 | 63
282 | benchmark
283 | benchmark
284 | NIL
285 | 1
286 | T
287 | OBSERVER
288 | NIL
289 | NIL
290 | NIL
291 | NIL
292 | 1
293 |
294 | @#$#@#$#@
295 | ## WHAT IS IT?
296 |
297 | This project models the behavior of two types of agents in a neighborhood. The orange agents and blue agents get along with one another. But each agent wants to make sure that it lives near some of "its own." That is, each orange agent wants to live near at least some orange agents, and each blue agent wants to live near at least some blue agents. The simulation shows how these individual preferences ripple through the neighborhood, leading to large-scale patterns.
298 |
299 | This project was inspired by Thomas Schelling's writings about social systems (such as housing patterns in cities).
300 |
301 | ## HOW TO USE IT
302 |
303 | Click the SETUP button to set up the agents. There are approximately equal numbers of orange and blue agents. The agents are set up so no patch has more than one agent. Click GO to start the simulation. If agents don't have enough same-color neighbors, they move to a nearby patch. (The topology is wrapping, so that patches on the bottom edge are neighbors with patches on the top and similar for left and right).
304 |
305 | The DENSITY slider controls the occupancy density of the neighborhood (and thus the total number of agents). (It takes effect the next time you click SETUP.) The %-SIMILAR-WANTED slider controls the percentage of same-color agents that each agent wants among its neighbors. For example, if the slider is set at 30, each blue agent wants at least 30% of its neighbors to be blue agents.
306 |
307 | The % SIMILAR monitor shows the average percentage of same-color neighbors for each agent. It starts at about 50%, since each agent starts (on average) with an equal number of orange and blue agents as neighbors. The NUM-UNHAPPY monitor shows the number of unhappy agents, and the % UNHAPPY monitor shows the percent of agents that have fewer same-color neighbors than they want (and thus want to move). The % SIMILAR and the NUM-UNHAPPY monitors are also plotted.
308 |
309 | The VISUALIZATION chooser gives two options for visualizing the agents. The OLD option uses the visualization that was used by the segregation model in the past. The SQUARE-X option visualizes the agents as squares. Unhappy agents are visualized as Xs.
310 |
311 | ## THINGS TO NOTICE
312 |
313 | When you execute SETUP, the orange and blue agents are randomly distributed throughout the neighborhood. But many agents are "unhappy" since they don't have enough same-color neighbors. The unhappy agents move to new locations in the vicinity. But in the new locations, they might tip the balance of the local population, prompting other agents to leave. If a few agents move into an area, the local blue agents might leave. But when the blue agents move to a new area, they might prompt orange agents to leave that area.
314 |
315 | Over time, the number of unhappy agents decreases. But the neighborhood becomes more segregated, with clusters of orange agents and clusters of blue agents.
316 |
317 | In the case where each agent wants at least 30% same-color neighbors, the agents end up with (on average) 70% same-color neighbors. So relatively small individual preferences can lead to significant overall segregation.
318 |
319 | ## THINGS TO TRY
320 |
321 | Try different values for %-SIMILAR-WANTED. How does the overall degree of segregation change?
322 |
323 | If each agent wants at least 40% same-color neighbors, what percentage (on average) do they end up with?
324 |
325 | Try different values of DENSITY. How does the initial occupancy density affect the percentage of unhappy agents? How does it affect the time it takes for the model to finish?
326 |
327 | Can you set sliders so that the model never finishes running, and agents keep looking for new locations?
328 |
329 | ## EXTENDING THE MODEL
330 |
331 | The `find-new-spot` procedure has the agents move locally till they find a spot. Can you rewrite this procedure so the agents move directly to an appropriate new spot?
332 |
333 | Incorporate social networks into this model. For instance, have unhappy agents decide on a new location based on information about what a neighborhood is like from other agents in their network.
334 |
335 | Change the rules for agent happiness. One idea: suppose that the agents need some minimum threshold of "good neighbors" to be happy with their location. Suppose further that they don't always know if someone makes a good neighbor. When they do, they use that information. When they don't, they use color as a proxy -- i.e., they assume that agents of the same color make good neighbors.
336 |
337 | The two different visualizations emphasize different aspects of the model. The SQUARE-X visualization shows whether an agent is happy or not. Can you design a different visualization that emphasizes different aspects?
338 |
339 | ## NETLOGO FEATURES
340 |
341 | `sprout` is used to create agents while ensuring no patch has more than one agent on it.
342 |
343 | When an agent moves, `move-to` is used to move the agent to the center of the patch it eventually finds.
344 |
345 | Note two different methods that can be used for find-new-spot, one of them (the one we use) is recursive.
346 |
347 | ## CREDITS AND REFERENCES
348 |
349 | Schelling, T. (1978). Micromotives and Macrobehavior. New York: Norton.
350 |
351 | See also: Rauch, J. (2002). Seeing Around Corners; The Atlantic Monthly; April 2002;Volume 289, No. 4; 35-48. https://www.theatlantic.com/magazine/archive/2002/04/seeing-around-corners/302471/
352 |
353 | ## HOW TO CITE
354 |
355 | If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.
356 |
357 | For the model itself:
358 |
359 | * Wilensky, U. (1997). NetLogo Segregation model. http://ccl.northwestern.edu/netlogo/models/Segregation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
360 |
361 | Please cite the NetLogo software as:
362 |
363 | * Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
364 |
365 | ## COPYRIGHT AND LICENSE
366 |
367 | Copyright 1997 Uri Wilensky.
368 |
369 | 
370 |
371 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
372 |
373 | Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.
374 |
375 | This model was created as part of the project: CONNECTED MATHEMATICS: MAKING SENSE OF COMPLEX PHENOMENA THROUGH BUILDING OBJECT-BASED PARALLEL MODELS (OBPML). The project gratefully acknowledges the support of the National Science Foundation (Applications of Advanced Technologies Program) -- grant numbers RED #9552950 and REC #9632612.
376 |
377 | This model was converted to NetLogo as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227. Converted from StarLogoT to NetLogo, 2001.
378 |
379 |
380 | @#$#@#$#@
381 | default
382 | true
383 | 0
384 | Polygon -7500403 true true 150 5 40 250 150 205 260 250
385 |
386 | airplane
387 | true
388 | 0
389 | Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15
390 |
391 | arrow
392 | true
393 | 0
394 | Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150
395 |
396 | box
397 | false
398 | 0
399 | Polygon -7500403 true true 150 285 285 225 285 75 150 135
400 | Polygon -7500403 true true 150 135 15 75 150 15 285 75
401 | Polygon -7500403 true true 15 75 15 225 150 285 150 135
402 | Line -16777216 false 150 285 150 135
403 | Line -16777216 false 150 135 15 75
404 | Line -16777216 false 150 135 285 75
405 |
406 | bug
407 | true
408 | 0
409 | Circle -7500403 true true 96 182 108
410 | Circle -7500403 true true 110 127 80
411 | Circle -7500403 true true 110 75 80
412 | Line -7500403 true 150 100 80 30
413 | Line -7500403 true 150 100 220 30
414 |
415 | butterfly
416 | true
417 | 0
418 | Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
419 | Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
420 | Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
421 | Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
422 | Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
423 | Circle -16777216 true false 135 90 30
424 | Line -16777216 false 150 105 195 60
425 | Line -16777216 false 150 105 105 60
426 |
427 | car
428 | false
429 | 0
430 | Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
431 | Circle -16777216 true false 180 180 90
432 | Circle -16777216 true false 30 180 90
433 | Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
434 | Circle -7500403 true true 47 195 58
435 | Circle -7500403 true true 195 195 58
436 |
437 | circle
438 | false
439 | 0
440 | Circle -7500403 true true 0 0 300
441 |
442 | circle 2
443 | false
444 | 0
445 | Circle -7500403 true true 0 0 300
446 | Circle -16777216 true false 30 30 240
447 |
448 | cow
449 | false
450 | 0
451 | Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
452 | Polygon -7500403 true true 73 210 86 251 62 249 48 208
453 | Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123
454 |
455 | cylinder
456 | false
457 | 0
458 | Circle -7500403 true true 0 0 300
459 |
460 | face happy
461 | false
462 | 0
463 | Circle -7500403 true true 8 8 285
464 | Circle -16777216 true false 60 75 60
465 | Circle -16777216 true false 180 75 60
466 | Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
467 |
468 | face neutral
469 | false
470 | 0
471 | Circle -7500403 true true 8 7 285
472 | Circle -16777216 true false 60 75 60
473 | Circle -16777216 true false 180 75 60
474 | Rectangle -16777216 true false 60 195 240 225
475 |
476 | face sad
477 | false
478 | 0
479 | Circle -7500403 true true 8 8 285
480 | Circle -16777216 true false 60 75 60
481 | Circle -16777216 true false 180 75 60
482 | Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183
483 |
484 | face-happy
485 | false
486 | 0
487 | Circle -7500403 true true 8 8 285
488 | Circle -16777216 true false 60 75 60
489 | Circle -16777216 true false 180 75 60
490 | Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
491 |
492 | fish
493 | false
494 | 0
495 | Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
496 | Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
497 | Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
498 | Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
499 | Circle -16777216 true false 215 106 30
500 |
501 | flag
502 | false
503 | 0
504 | Rectangle -7500403 true true 60 15 75 300
505 | Polygon -7500403 true true 90 150 270 90 90 30
506 | Line -7500403 true 75 135 90 135
507 | Line -7500403 true 75 45 90 45
508 |
509 | flower
510 | false
511 | 0
512 | Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
513 | Circle -7500403 true true 85 132 38
514 | Circle -7500403 true true 130 147 38
515 | Circle -7500403 true true 192 85 38
516 | Circle -7500403 true true 85 40 38
517 | Circle -7500403 true true 177 40 38
518 | Circle -7500403 true true 177 132 38
519 | Circle -7500403 true true 70 85 38
520 | Circle -7500403 true true 130 25 38
521 | Circle -7500403 true true 96 51 108
522 | Circle -16777216 true false 113 68 74
523 | Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
524 | Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240
525 |
526 | house
527 | false
528 | 0
529 | Rectangle -7500403 true true 45 120 255 285
530 | Rectangle -16777216 true false 120 210 180 285
531 | Polygon -7500403 true true 15 120 150 15 285 120
532 | Line -16777216 false 30 120 270 120
533 |
534 | leaf
535 | false
536 | 0
537 | Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
538 | Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195
539 |
540 | line
541 | true
542 | 0
543 | Line -7500403 true 150 0 150 300
544 |
545 | line half
546 | true
547 | 0
548 | Line -7500403 true 150 0 150 150
549 |
550 | pentagon
551 | false
552 | 0
553 | Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120
554 |
555 | person
556 | false
557 | 0
558 | Circle -7500403 true true 110 5 80
559 | Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
560 | Rectangle -7500403 true true 127 79 172 94
561 | Polygon -7500403 true true 195 90 240 150 225 180 165 105
562 | Polygon -7500403 true true 105 90 60 150 75 180 135 105
563 |
564 | person2
565 | false
566 | 0
567 | Circle -7500403 true true 105 0 90
568 | Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
569 | Rectangle -7500403 true true 127 79 172 94
570 | Polygon -7500403 true true 195 90 285 180 255 210 165 105
571 | Polygon -7500403 true true 105 90 15 180 60 195 135 105
572 |
573 | plant
574 | false
575 | 0
576 | Rectangle -7500403 true true 135 90 165 300
577 | Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
578 | Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
579 | Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
580 | Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
581 | Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
582 | Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
583 | Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90
584 |
585 | square
586 | false
587 | 0
588 | Rectangle -7500403 true true 30 30 270 270
589 |
590 | square - happy
591 | false
592 | 0
593 | Rectangle -7500403 true true 30 30 270 270
594 | Polygon -16777216 false false 75 195 105 240 180 240 210 195 75 195
595 |
596 | square - unhappy
597 | false
598 | 0
599 | Rectangle -7500403 true true 30 30 270 270
600 | Polygon -16777216 false false 60 225 105 180 195 180 240 225 75 225
601 |
602 | square 2
603 | false
604 | 0
605 | Rectangle -7500403 true true 30 30 270 270
606 | Rectangle -16777216 true false 60 60 240 240
607 |
608 | square-small
609 | false
610 | 0
611 | Rectangle -7500403 true true 45 45 255 255
612 |
613 | square-x
614 | false
615 | 0
616 | Rectangle -7500403 true true 30 30 270 270
617 | Line -16777216 false 75 90 210 210
618 | Line -16777216 false 210 90 75 210
619 |
620 | star
621 | false
622 | 0
623 | Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108
624 |
625 | target
626 | false
627 | 0
628 | Circle -7500403 true true 0 0 300
629 | Circle -16777216 true false 30 30 240
630 | Circle -7500403 true true 60 60 180
631 | Circle -16777216 true false 90 90 120
632 | Circle -7500403 true true 120 120 60
633 |
634 | tree
635 | false
636 | 0
637 | Circle -7500403 true true 118 3 94
638 | Rectangle -6459832 true false 120 195 180 300
639 | Circle -7500403 true true 65 21 108
640 | Circle -7500403 true true 116 41 127
641 | Circle -7500403 true true 45 90 120
642 | Circle -7500403 true true 104 74 152
643 |
644 | triangle
645 | false
646 | 0
647 | Polygon -7500403 true true 150 30 15 255 285 255
648 |
649 | triangle 2
650 | false
651 | 0
652 | Polygon -7500403 true true 0 0 0 300 300 300 30 30
653 |
654 | triangle2
655 | false
656 | 0
657 | Polygon -7500403 true true 150 0 0 300 300 300
658 |
659 | truck
660 | false
661 | 0
662 | Rectangle -7500403 true true 4 45 195 187
663 | Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
664 | Rectangle -1 true false 195 60 195 105
665 | Polygon -16777216 true false 238 112 252 141 219 141 218 112
666 | Circle -16777216 true false 234 174 42
667 | Rectangle -7500403 true true 181 185 214 194
668 | Circle -16777216 true false 144 174 42
669 | Circle -16777216 true false 24 174 42
670 | Circle -7500403 false true 24 174 42
671 | Circle -7500403 false true 144 174 42
672 | Circle -7500403 false true 234 174 42
673 |
674 | turtle
675 | true
676 | 0
677 | Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
678 | Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
679 | Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
680 | Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
681 | Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
682 | Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99
683 |
684 | wheel
685 | false
686 | 0
687 | Circle -7500403 true true 3 3 294
688 | Circle -16777216 true false 30 30 240
689 | Line -7500403 true 150 285 150 15
690 | Line -7500403 true 15 150 285 150
691 | Circle -7500403 true true 120 120 60
692 | Line -7500403 true 216 40 79 269
693 | Line -7500403 true 40 84 269 221
694 | Line -7500403 true 40 216 269 79
695 | Line -7500403 true 84 40 221 269
696 |
697 | x
698 | false
699 | 0
700 | Polygon -7500403 true true 300 60 225 0 0 225 60 300
701 | Polygon -7500403 true true 0 60 75 0 300 240 225 300
702 | @#$#@#$#@
703 | NetLogo 6.3.0
704 | @#$#@#$#@
705 | @#$#@#$#@
706 | @#$#@#$#@
707 | @#$#@#$#@
708 | @#$#@#$#@
709 | default
710 | 0.0
711 | -0.2 0 0.0 1.0
712 | 0.0 1 1.0 0.0
713 | 0.2 0 0.0 1.0
714 | link direction
715 | true
716 | 0
717 | Line -7500403 true 150 150 90 180
718 | Line -7500403 true 150 150 210 180
719 | @#$#@#$#@
720 | 1
721 | @#$#@#$#@
722 |
723 |
--------------------------------------------------------------------------------
/WolfSheep/NetLogo/WolfSheep.nlogo:
--------------------------------------------------------------------------------
1 | extensions [profiler]
2 |
3 | globals [
4 | max-sheep ; don't let the sheep population grow too large
5 | time-tot
6 | ]
7 |
8 | ; Sheep and wolves are both breeds of turtles
9 | breed [ sheep a-sheep ] ; sheep is its own plural, so we use "a-sheep" as the singular
10 | breed [ wolves wolf ]
11 |
12 | turtles-own [ energy ] ; both wolves and sheep have energy
13 |
14 | patches-own [ countdown ] ; this is for the sheep-wolves-grass model version
15 |
16 | to setup
17 | clear-all
18 | random-seed seed
19 | ifelse netlogo-web? [ set max-sheep 10000 ] [ set max-sheep 30000 ]
20 |
21 | ; Check model-version switch
22 | ; if we're not modeling grass, then the sheep don't need to eat to survive
23 | ; otherwise each grass' state of growth and growing logic need to be set up
24 | ifelse model-version = "sheep-wolves-grass" [
25 | ask patches [
26 | set pcolor one-of [ green brown ]
27 | ifelse pcolor = green
28 | [ set countdown grass-regrowth-time ]
29 | [ set countdown random grass-regrowth-time ] ; initialize grass regrowth clocks randomly for brown patches
30 | ]
31 | ]
32 | [
33 | ask patches [ set pcolor green ]
34 | ]
35 |
36 | create-sheep initial-number-sheep ; create the sheep, then initialize their variables
37 | [
38 | set shape "sheep"
39 | set color white
40 | set size 1 ; easier to see
41 | set label-color blue - 2
42 | set energy random (2 * sheep-gain-from-food)
43 | setxy random-pxcor random-pycor
44 | ]
45 |
46 | create-wolves initial-number-wolves ; create the wolves, then initialize their variables
47 | [
48 | set shape "wolf"
49 | set color black
50 | set size 1 ; easier to see
51 | set energy random (2 * wolf-gain-from-food)
52 | setxy random-pxcor random-pycor
53 | ]
54 | display-labels
55 | set time-tot 0
56 | reset-ticks
57 | end
58 |
59 | to benchmark
60 | profiler:reset ;; clear the data
61 | profiler:start ;; start profiling
62 | setup
63 | repeat n_ticks [go] ;; run for n_ticks steps
64 | profiler:stop ;; stop profiling
65 | set time-tot profiler:inclusive-time "go" + profiler:inclusive-time "setup"
66 | file-open "times.txt"
67 | file-print time-tot
68 | file-close
69 | end
70 |
71 | to go
72 | ask sheep [
73 | move
74 |
75 | ; in this version, sheep eat grass, grass grows, and it costs sheep energy to move
76 | if model-version = "sheep-wolves-grass" [
77 | set energy energy - 1 ; deduct energy for sheep only if running sheep-wolves-grass model version
78 | eat-grass ; sheep eat grass only if running the sheep-wolves-grass model version
79 | death ; sheep die from starvation only if running the sheep-wolves-grass model version
80 | ]
81 |
82 | reproduce-sheep ; sheep reproduce at a random rate governed by a slider
83 | ]
84 | ask wolves [
85 | move
86 | set energy energy - 1 ; wolves lose energy as they move
87 | eat-sheep ; wolves eat a sheep on their patch
88 | death ; wolves die if they run out of energy
89 | reproduce-wolves ; wolves reproduce at a random rate governed by a slider
90 | ]
91 |
92 | if model-version = "sheep-wolves-grass" [ ask patches [ grow-grass ] ]
93 |
94 | tick
95 | display-labels
96 | end
97 |
98 | to move ; turtle procedure
99 | rt random 50
100 | lt random 50
101 | fd 1
102 | end
103 |
104 | to eat-grass ; sheep procedure
105 | ; sheep eat grass and turn the patch brown
106 | if pcolor = green [
107 | set pcolor brown
108 | set energy energy + sheep-gain-from-food ; sheep gain energy by eating
109 | ]
110 | end
111 |
112 | to reproduce-sheep ; sheep procedure
113 | if random-float 100 < sheep-reproduce [ ; throw "dice" to see if you will reproduce
114 | set energy (energy / 2) ; divide energy between parent and offspring
115 | hatch 1 [ rt random-float 360 fd 1 ] ; hatch an offspring and move it forward 1 step
116 | ]
117 | end
118 |
119 | to reproduce-wolves ; wolf procedure
120 | if random-float 100 < wolf-reproduce [ ; throw "dice" to see if you will reproduce
121 | set energy (energy / 2) ; divide energy between parent and offspring
122 | hatch 1 [ rt random-float 360 fd 1 ] ; hatch an offspring and move it forward 1 step
123 | ]
124 | end
125 |
126 | to eat-sheep ; wolf procedure
127 | let prey one-of sheep-here ; grab a random sheep
128 | if prey != nobody [ ; did we get one? if so,
129 | ask prey [ die ] ; kill it, and...
130 | set energy energy + wolf-gain-from-food ; get energy from eating
131 | ]
132 | end
133 |
134 | to death ; turtle procedure (i.e. both wolf and sheep procedure)
135 | ; when energy dips below zero, die
136 | if energy < 0 [ die ]
137 | end
138 |
139 | to grow-grass ; patch procedure
140 | ; countdown on brown patches: if you reach 0, grow some grass
141 | if pcolor = brown [
142 | ifelse countdown <= 0
143 | [ set pcolor green
144 | set countdown grass-regrowth-time ]
145 | [ set countdown countdown - 1 ]
146 | ]
147 | end
148 |
149 | to-report grass
150 | ifelse model-version = "sheep-wolves-grass" [
151 | report patches with [pcolor = green]
152 | ]
153 | [ report 0 ]
154 | end
155 |
156 |
157 | to display-labels
158 | ask turtles [ set label "" ]
159 | if show-energy? [
160 | ask wolves [ set label round energy ]
161 | if model-version = "sheep-wolves-grass" [ ask sheep [ set label round energy ] ]
162 | ]
163 | end
164 |
165 |
166 | ; Copyright 1997 Uri Wilensky.
167 | ; See Info tab for full copyright and license.
168 | @#$#@#$#@
169 | GRAPHICS-WINDOW
170 | 355
171 | 10
172 | 863
173 | 519
174 | -1
175 | -1
176 | 20.0
177 | 1
178 | 14
179 | 1
180 | 1
181 | 1
182 | 0
183 | 1
184 | 1
185 | 1
186 | 0
187 | 24
188 | 0
189 | 24
190 | 0
191 | 0
192 | 1
193 | ticks
194 | 30.0
195 |
196 | SLIDER
197 | 5
198 | 60
199 | 179
200 | 93
201 | initial-number-sheep
202 | initial-number-sheep
203 | 0
204 | 250
205 | 60.0
206 | 1
207 | 1
208 | NIL
209 | HORIZONTAL
210 |
211 | SLIDER
212 | 5
213 | 196
214 | 179
215 | 229
216 | seed
217 | seed
218 | 0.0
219 | 50000.0
220 | 1.0
221 | 1.0
222 | 1
223 | NIL
224 | HORIZONTAL
225 |
226 | SLIDER
227 | 5
228 | 196
229 | 179
230 | 229
231 | n_ticks
232 | n_ticks
233 | 0.0
234 | 50000.0
235 | 1.0
236 | 1.0
237 | 1
238 | NIL
239 | HORIZONTAL
240 |
241 | SLIDER
242 | 5
243 | 196
244 | 179
245 | 229
246 | sheep-gain-from-food
247 | sheep-gain-from-food
248 | 0.0
249 | 50.0
250 | 5.0
251 | 1.0
252 | 1
253 | NIL
254 | HORIZONTAL
255 |
256 | SLIDER
257 | 5
258 | 231
259 | 179
260 | 264
261 | sheep-reproduce
262 | sheep-reproduce
263 | 1.0
264 | 20.0
265 | 20.0
266 | 1.0
267 | 1
268 | %
269 | HORIZONTAL
270 |
271 | SLIDER
272 | 185
273 | 60
274 | 350
275 | 93
276 | initial-number-wolves
277 | initial-number-wolves
278 | 0
279 | 250
280 | 40.0
281 | 1
282 | 1
283 | NIL
284 | HORIZONTAL
285 |
286 | SLIDER
287 | 183
288 | 195
289 | 348
290 | 228
291 | wolf-gain-from-food
292 | wolf-gain-from-food
293 | 0.0
294 | 100.0
295 | 13.0
296 | 1.0
297 | 1
298 | NIL
299 | HORIZONTAL
300 |
301 | SLIDER
302 | 183
303 | 231
304 | 348
305 | 264
306 | wolf-reproduce
307 | wolf-reproduce
308 | 0.0
309 | 20.0
310 | 10.0
311 | 1.0
312 | 1
313 | %
314 | HORIZONTAL
315 |
316 | SLIDER
317 | 40
318 | 100
319 | 252
320 | 133
321 | grass-regrowth-time
322 | grass-regrowth-time
323 | 0
324 | 100
325 | 20.0
326 | 1
327 | 1
328 | NIL
329 | HORIZONTAL
330 |
331 | BUTTON
332 | 40
333 | 140
334 | 109
335 | 173
336 | setup
337 | setup
338 | NIL
339 | 1
340 | T
341 | OBSERVER
342 | NIL
343 | NIL
344 | NIL
345 | NIL
346 | 1
347 |
348 | BUTTON
349 | 115
350 | 140
351 | 190
352 | 173
353 | go
354 | go
355 | T
356 | 1
357 | T
358 | OBSERVER
359 | NIL
360 | NIL
361 | NIL
362 | NIL
363 | 0
364 |
365 | TEXTBOX
366 | 20
367 | 178
368 | 160
369 | 196
370 | Sheep settings
371 | 11
372 | 0.0
373 | 0
374 |
375 | TEXTBOX
376 | 198
377 | 176
378 | 311
379 | 194
380 | Wolf settings
381 | 11
382 | 0.0
383 | 0
384 |
385 | SWITCH
386 | 105
387 | 270
388 | 241
389 | 303
390 | show-energy?
391 | show-energy?
392 | 1
393 | 1
394 | -1000
395 |
396 | CHOOSER
397 | 5
398 | 10
399 | 350
400 | 55
401 | model-version
402 | model-version
403 | "sheep-wolves" "sheep-wolves-grass"
404 | 1
405 |
406 | BUTTON
407 | 210
408 | 145
409 | 322
410 | 178
411 | benchmark
412 | benchmark
413 | NIL
414 | 1
415 | T
416 | OBSERVER
417 | NIL
418 | NIL
419 | NIL
420 | NIL
421 | 1
422 |
423 | PLOT
424 | 30
425 | 380
426 | 330
427 | 615
428 | plot 1
429 | NIL
430 | NIL
431 | 0.0
432 | 10.0
433 | 0.0
434 | 10.0
435 | true
436 | false
437 | "" ""
438 | PENS
439 | "default" 1.0 0 -2674135 true "" "plot count wolves"
440 | "pen-1" 1.0 0 -13345367 true "" "plot count sheep"
441 | "pen-2" 1.0 0 -10899396 true "" "plot count grass"
442 |
443 | @#$#@#$#@
444 | ## WHAT IS IT?
445 |
446 | This model explores the stability of predator-prey ecosystems. Such a system is called unstable if it tends to result in extinction for one or more species involved. In contrast, a system is stable if it tends to maintain itself over time, despite fluctuations in population sizes.
447 |
448 | ## HOW IT WORKS
449 |
450 | There are two main variations to this model.
451 |
452 | In the first variation, the "sheep-wolves" version, wolves and sheep wander randomly around the landscape, while the wolves look for sheep to prey on. Each step costs the wolves energy, and they must eat sheep in order to replenish their energy - when they run out of energy they die. To allow the population to continue, each wolf or sheep has a fixed probability of reproducing at each time step. In this variation, we model the grass as "infinite" so that sheep always have enough to eat, and we don't explicitly model the eating or growing of grass. As such, sheep don't either gain or lose energy by eating or moving. This variation produces interesting population dynamics, but is ultimately unstable. This variation of the model is particularly well-suited to interacting species in a rich nutrient environment, such as two strains of bacteria in a petri dish (Gause, 1934).
453 |
454 | The second variation, the "sheep-wolves-grass" version explictly models grass (green) in addition to wolves and sheep. The behavior of the wolves is identical to the first variation, however this time the sheep must eat grass in order to maintain their energy - when they run out of energy they die. Once grass is eaten it will only regrow after a fixed amount of time. This variation is more complex than the first, but it is generally stable. It is a closer match to the classic Lotka Volterra population oscillation models. The classic LV models though assume the populations can take on real values, but in small populations these models underestimate extinctions and agent-based models such as the ones here, provide more realistic results. (See Wilensky & Rand, 2015; chapter 4).
455 |
456 | The construction of this model is described in two papers by Wilensky & Reisman (1998; 2006) referenced below.
457 |
458 | ## HOW TO USE IT
459 |
460 | 1. Set the model-version chooser to "sheep-wolves-grass" to include grass eating and growth in the model, or to "sheep-wolves" to only include wolves (black) and sheep (white).
461 | 2. Adjust the slider parameters (see below), or use the default settings.
462 | 3. Press the SETUP button.
463 | 4. Press the GO button to begin the simulation.
464 | 5. Look at the monitors to see the current population sizes
465 | 6. Look at the POPULATIONS plot to watch the populations fluctuate over time
466 |
467 | Parameters:
468 | MODEL-VERSION: Whether we model sheep wolves and grass or just sheep and wolves
469 | INITIAL-NUMBER-SHEEP: The initial size of sheep population
470 | INITIAL-NUMBER-WOLVES: The initial size of wolf population
471 | SHEEP-GAIN-FROM-FOOD: The amount of energy sheep get for every grass patch eaten (Note this is not used in the sheep-wolves model version)
472 | WOLF-GAIN-FROM-FOOD: The amount of energy wolves get for every sheep eaten
473 | SHEEP-REPRODUCE: The probability of a sheep reproducing at each time step
474 | WOLF-REPRODUCE: The probability of a wolf reproducing at each time step
475 | GRASS-REGROWTH-TIME: How long it takes for grass to regrow once it is eaten (Note this is not used in the sheep-wolves model version)
476 | SHOW-ENERGY?: Whether or not to show the energy of each animal as a number
477 |
478 | Notes:
479 | - one unit of energy is deducted for every step a wolf takes
480 | - when running the sheep-wolves-grass model version, one unit of energy is deducted for every step a sheep takes
481 |
482 | There are three monitors to show the populations of the wolves, sheep and grass and a populations plot to display the population values over time.
483 |
484 | If there are no wolves left and too many sheep, the model run stops.
485 |
486 | ## THINGS TO NOTICE
487 |
488 | When running the sheep-wolves model variation, watch as the sheep and wolf populations fluctuate. Notice that increases and decreases in the sizes of each population are related. In what way are they related? What eventually happens?
489 |
490 | In the sheep-wolves-grass model variation, notice the green line added to the population plot representing fluctuations in the amount of grass. How do the sizes of the three populations appear to relate now? What is the explanation for this?
491 |
492 | Why do you suppose that some variations of the model might be stable while others are not?
493 |
494 | ## THINGS TO TRY
495 |
496 | Try adjusting the parameters under various settings. How sensitive is the stability of the model to the particular parameters?
497 |
498 | Can you find any parameters that generate a stable ecosystem in the sheep-wolves model variation?
499 |
500 | Try running the sheep-wolves-grass model variation, but setting INITIAL-NUMBER-WOLVES to 0. This gives a stable ecosystem with only sheep and grass. Why might this be stable while the variation with only sheep and wolves is not?
501 |
502 | Notice that under stable settings, the populations tend to fluctuate at a predictable pace. Can you find any parameters that will speed this up or slow it down?
503 |
504 | ## EXTENDING THE MODEL
505 |
506 | There are a number ways to alter the model so that it will be stable with only wolves and sheep (no grass). Some will require new elements to be coded in or existing behaviors to be changed. Can you develop such a version?
507 |
508 | Try changing the reproduction rules -- for example, what would happen if reproduction depended on energy rather than being determined by a fixed probability?
509 |
510 | Can you modify the model so the sheep will flock?
511 |
512 | Can you modify the model so that wolves actively chase sheep?
513 |
514 | ## NETLOGO FEATURES
515 |
516 | Note the use of breeds to model two different kinds of "turtles": wolves and sheep. Note the use of patches to model grass.
517 |
518 | Note use of the ONE-OF agentset reporter to select a random sheep to be eaten by a wolf.
519 |
520 | ## RELATED MODELS
521 |
522 | Look at Rabbits Grass Weeds for another model of interacting populations with different rules.
523 |
524 | ## CREDITS AND REFERENCES
525 |
526 | Wilensky, U. & Reisman, K. (1998). Connected Science: Learning Biology through Constructing and Testing Computational Theories -- an Embodied Modeling Approach. International Journal of Complex Systems, M. 234, pp. 1 - 12. (The Wolf-Sheep-Predation model is a slightly extended version of the model described in the paper.)
527 |
528 | Wilensky, U. & Reisman, K. (2006). Thinking like a Wolf, a Sheep or a Firefly: Learning Biology through Constructing and Testing Computational Theories -- an Embodied Modeling Approach. Cognition & Instruction, 24(2), pp. 171-209. http://ccl.northwestern.edu/papers/wolfsheep.pdf .
529 |
530 | Wilensky, U., & Rand, W. (2015). An introduction to agent-based modeling: Modeling natural, social and engineered complex systems with NetLogo. Cambridge, MA: MIT Press.
531 |
532 | Lotka, A. J. (1925). Elements of physical biology. New York: Dover.
533 |
534 | Volterra, V. (1926, October 16). Fluctuations in the abundance of a species considered mathematically. Nature, 118, 558–560.
535 |
536 | Gause, G. F. (1934). The struggle for existence. Baltimore: Williams & Wilkins.
537 |
538 | ## HOW TO CITE
539 |
540 | If you mention this model or the NetLogo software in a publication, we ask that you include the citations below.
541 |
542 | For the model itself:
543 |
544 | * Wilensky, U. (1997). NetLogo Wolf Sheep Predation model. http://ccl.northwestern.edu/netlogo/models/WolfSheepPredation. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
545 |
546 | Please cite the NetLogo software as:
547 |
548 | * Wilensky, U. (1999). NetLogo. http://ccl.northwestern.edu/netlogo/. Center for Connected Learning and Computer-Based Modeling, Northwestern University, Evanston, IL.
549 |
550 | ## COPYRIGHT AND LICENSE
551 |
552 | Copyright 1997 Uri Wilensky.
553 |
554 | 
555 |
556 | This work is licensed under the Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License. To view a copy of this license, visit https://creativecommons.org/licenses/by-nc-sa/3.0/ or send a letter to Creative Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA.
557 |
558 | Commercial licenses are also available. To inquire about commercial licenses, please contact Uri Wilensky at uri@northwestern.edu.
559 |
560 | This model was created as part of the project: CONNECTED MATHEMATICS: MAKING SENSE OF COMPLEX PHENOMENA THROUGH BUILDING OBJECT-BASED PARALLEL MODELS (OBPML). The project gratefully acknowledges the support of the National Science Foundation (Applications of Advanced Technologies Program) -- grant numbers RED #9552950 and REC #9632612.
561 |
562 | This model was converted to NetLogo as part of the projects: PARTICIPATORY SIMULATIONS: NETWORK-BASED DESIGN FOR SYSTEMS LEARNING IN CLASSROOMS and/or INTEGRATED SIMULATION AND MODELING ENVIRONMENT. The project gratefully acknowledges the support of the National Science Foundation (REPP & ROLE programs) -- grant numbers REC #9814682 and REC-0126227. Converted from StarLogoT to NetLogo, 2000.
563 |
564 |
565 | @#$#@#$#@
566 | default
567 | true
568 | 0
569 | Polygon -7500403 true true 150 5 40 250 150 205 260 250
570 |
571 | airplane
572 | true
573 | 0
574 | Polygon -7500403 true true 150 0 135 15 120 60 120 105 15 165 15 195 120 180 135 240 105 270 120 285 150 270 180 285 210 270 165 240 180 180 285 195 285 165 180 105 180 60 165 15
575 |
576 | arrow
577 | true
578 | 0
579 | Polygon -7500403 true true 150 0 0 150 105 150 105 293 195 293 195 150 300 150
580 |
581 | box
582 | true
583 | 0
584 | Polygon -7500403 true true 150 285 285 225 285 75 150 135
585 | Polygon -7500403 true true 150 135 15 75 150 15 285 75
586 | Polygon -7500403 true true 15 75 15 225 150 285 150 135
587 | Line -16777216 false 150 285 150 135
588 | Line -16777216 false 150 135 15 75
589 | Line -16777216 false 150 135 285 75
590 |
591 | bug
592 | true
593 | 0
594 | Circle -7500403 true true 96 182 108
595 | Circle -7500403 true true 110 127 80
596 | Circle -7500403 true true 110 75 80
597 | Line -7500403 true 150 100 80 30
598 | Line -7500403 true 150 100 220 30
599 |
600 | butterfly
601 | true
602 | 0
603 | Polygon -7500403 true true 150 165 209 199 225 225 225 255 195 270 165 255 150 240
604 | Polygon -7500403 true true 150 165 89 198 75 225 75 255 105 270 135 255 150 240
605 | Polygon -7500403 true true 139 148 100 105 55 90 25 90 10 105 10 135 25 180 40 195 85 194 139 163
606 | Polygon -7500403 true true 162 150 200 105 245 90 275 90 290 105 290 135 275 180 260 195 215 195 162 165
607 | Polygon -16777216 true false 150 255 135 225 120 150 135 120 150 105 165 120 180 150 165 225
608 | Circle -16777216 true false 135 90 30
609 | Line -16777216 false 150 105 195 60
610 | Line -16777216 false 150 105 105 60
611 |
612 | car
613 | false
614 | 0
615 | Polygon -7500403 true true 300 180 279 164 261 144 240 135 226 132 213 106 203 84 185 63 159 50 135 50 75 60 0 150 0 165 0 225 300 225 300 180
616 | Circle -16777216 true false 180 180 90
617 | Circle -16777216 true false 30 180 90
618 | Polygon -16777216 true false 162 80 132 78 134 135 209 135 194 105 189 96 180 89
619 | Circle -7500403 true true 47 195 58
620 | Circle -7500403 true true 195 195 58
621 |
622 | circle
623 | false
624 | 0
625 | Circle -7500403 true true 0 0 300
626 |
627 | circle 2
628 | false
629 | 0
630 | Circle -7500403 true true 0 0 300
631 | Circle -16777216 true false 30 30 240
632 |
633 | cow
634 | false
635 | 0
636 | Polygon -7500403 true true 200 193 197 249 179 249 177 196 166 187 140 189 93 191 78 179 72 211 49 209 48 181 37 149 25 120 25 89 45 72 103 84 179 75 198 76 252 64 272 81 293 103 285 121 255 121 242 118 224 167
637 | Polygon -7500403 true true 73 210 86 251 62 249 48 208
638 | Polygon -7500403 true true 25 114 16 195 9 204 23 213 25 200 39 123
639 |
640 | cylinder
641 | false
642 | 0
643 | Circle -7500403 true true 0 0 300
644 |
645 | dot
646 | false
647 | 0
648 | Circle -7500403 true true 90 90 120
649 |
650 | face happy
651 | false
652 | 0
653 | Circle -7500403 true true 8 8 285
654 | Circle -16777216 true false 60 75 60
655 | Circle -16777216 true false 180 75 60
656 | Polygon -16777216 true false 150 255 90 239 62 213 47 191 67 179 90 203 109 218 150 225 192 218 210 203 227 181 251 194 236 217 212 240
657 |
658 | face neutral
659 | false
660 | 0
661 | Circle -7500403 true true 8 7 285
662 | Circle -16777216 true false 60 75 60
663 | Circle -16777216 true false 180 75 60
664 | Rectangle -16777216 true false 60 195 240 225
665 |
666 | face sad
667 | false
668 | 0
669 | Circle -7500403 true true 8 8 285
670 | Circle -16777216 true false 60 75 60
671 | Circle -16777216 true false 180 75 60
672 | Polygon -16777216 true false 150 168 90 184 62 210 47 232 67 244 90 220 109 205 150 198 192 205 210 220 227 242 251 229 236 206 212 183
673 |
674 | fish
675 | false
676 | 0
677 | Polygon -1 true false 44 131 21 87 15 86 0 120 15 150 0 180 13 214 20 212 45 166
678 | Polygon -1 true false 135 195 119 235 95 218 76 210 46 204 60 165
679 | Polygon -1 true false 75 45 83 77 71 103 86 114 166 78 135 60
680 | Polygon -7500403 true true 30 136 151 77 226 81 280 119 292 146 292 160 287 170 270 195 195 210 151 212 30 166
681 | Circle -16777216 true false 215 106 30
682 |
683 | flag
684 | false
685 | 0
686 | Rectangle -7500403 true true 60 15 75 300
687 | Polygon -7500403 true true 90 150 270 90 90 30
688 | Line -7500403 true 75 135 90 135
689 | Line -7500403 true 75 45 90 45
690 |
691 | flower
692 | false
693 | 0
694 | Polygon -10899396 true false 135 120 165 165 180 210 180 240 150 300 165 300 195 240 195 195 165 135
695 | Circle -7500403 true true 85 132 38
696 | Circle -7500403 true true 130 147 38
697 | Circle -7500403 true true 192 85 38
698 | Circle -7500403 true true 85 40 38
699 | Circle -7500403 true true 177 40 38
700 | Circle -7500403 true true 177 132 38
701 | Circle -7500403 true true 70 85 38
702 | Circle -7500403 true true 130 25 38
703 | Circle -7500403 true true 96 51 108
704 | Circle -16777216 true false 113 68 74
705 | Polygon -10899396 true false 189 233 219 188 249 173 279 188 234 218
706 | Polygon -10899396 true false 180 255 150 210 105 210 75 240 135 240
707 |
708 | house
709 | false
710 | 0
711 | Rectangle -7500403 true true 45 120 255 285
712 | Rectangle -16777216 true false 120 210 180 285
713 | Polygon -7500403 true true 15 120 150 15 285 120
714 | Line -16777216 false 30 120 270 120
715 |
716 | leaf
717 | false
718 | 0
719 | Polygon -7500403 true true 150 210 135 195 120 210 60 210 30 195 60 180 60 165 15 135 30 120 15 105 40 104 45 90 60 90 90 105 105 120 120 120 105 60 120 60 135 30 150 15 165 30 180 60 195 60 180 120 195 120 210 105 240 90 255 90 263 104 285 105 270 120 285 135 240 165 240 180 270 195 240 210 180 210 165 195
720 | Polygon -7500403 true true 135 195 135 240 120 255 105 255 105 285 135 285 165 240 165 195
721 |
722 | line
723 | true
724 | 0
725 | Line -7500403 true 150 0 150 300
726 |
727 | line half
728 | true
729 | 0
730 | Line -7500403 true 150 0 150 150
731 |
732 | pentagon
733 | false
734 | 0
735 | Polygon -7500403 true true 150 15 15 120 60 285 240 285 285 120
736 |
737 | person
738 | false
739 | 0
740 | Circle -7500403 true true 110 5 80
741 | Polygon -7500403 true true 105 90 120 195 90 285 105 300 135 300 150 225 165 300 195 300 210 285 180 195 195 90
742 | Rectangle -7500403 true true 127 79 172 94
743 | Polygon -7500403 true true 195 90 240 150 225 180 165 105
744 | Polygon -7500403 true true 105 90 60 150 75 180 135 105
745 |
746 | plant
747 | false
748 | 0
749 | Rectangle -7500403 true true 135 90 165 300
750 | Polygon -7500403 true true 135 255 90 210 45 195 75 255 135 285
751 | Polygon -7500403 true true 165 255 210 210 255 195 225 255 165 285
752 | Polygon -7500403 true true 135 180 90 135 45 120 75 180 135 210
753 | Polygon -7500403 true true 165 180 165 210 225 180 255 120 210 135
754 | Polygon -7500403 true true 135 105 90 60 45 45 75 105 135 135
755 | Polygon -7500403 true true 165 105 165 135 225 105 255 45 210 60
756 | Polygon -7500403 true true 135 90 120 45 150 15 180 45 165 90
757 |
758 | sheep
759 | false
760 | 15
761 | Circle -1 true true 203 65 88
762 | Circle -1 true true 70 65 162
763 | Circle -1 true true 150 105 120
764 | Polygon -7500403 true false 218 120 240 165 255 165 278 120
765 | Circle -7500403 true false 214 72 67
766 | Rectangle -1 true true 164 223 179 298
767 | Polygon -1 true true 45 285 30 285 30 240 15 195 45 210
768 | Circle -1 true true 3 83 150
769 | Rectangle -1 true true 65 221 80 296
770 | Polygon -1 true true 195 285 210 285 210 240 240 210 195 210
771 | Polygon -7500403 true false 276 85 285 105 302 99 294 83
772 | Polygon -7500403 true false 219 85 210 105 193 99 201 83
773 |
774 | square
775 | false
776 | 0
777 | Rectangle -7500403 true true 30 30 270 270
778 |
779 | square 2
780 | false
781 | 0
782 | Rectangle -7500403 true true 30 30 270 270
783 | Rectangle -16777216 true false 60 60 240 240
784 |
785 | star
786 | false
787 | 0
788 | Polygon -7500403 true true 151 1 185 108 298 108 207 175 242 282 151 216 59 282 94 175 3 108 116 108
789 |
790 | target
791 | false
792 | 0
793 | Circle -7500403 true true 0 0 300
794 | Circle -16777216 true false 30 30 240
795 | Circle -7500403 true true 60 60 180
796 | Circle -16777216 true false 90 90 120
797 | Circle -7500403 true true 120 120 60
798 |
799 | tree
800 | false
801 | 0
802 | Circle -7500403 true true 118 3 94
803 | Rectangle -6459832 true false 120 195 180 300
804 | Circle -7500403 true true 65 21 108
805 | Circle -7500403 true true 116 41 127
806 | Circle -7500403 true true 45 90 120
807 | Circle -7500403 true true 104 74 152
808 |
809 | triangle
810 | false
811 | 0
812 | Polygon -7500403 true true 150 30 15 255 285 255
813 |
814 | triangle 2
815 | false
816 | 0
817 | Polygon -7500403 true true 150 30 15 255 285 255
818 | Polygon -16777216 true false 151 99 225 223 75 224
819 |
820 | truck
821 | false
822 | 0
823 | Rectangle -7500403 true true 4 45 195 187
824 | Polygon -7500403 true true 296 193 296 150 259 134 244 104 208 104 207 194
825 | Rectangle -1 true false 195 60 195 105
826 | Polygon -16777216 true false 238 112 252 141 219 141 218 112
827 | Circle -16777216 true false 234 174 42
828 | Rectangle -7500403 true true 181 185 214 194
829 | Circle -16777216 true false 144 174 42
830 | Circle -16777216 true false 24 174 42
831 | Circle -7500403 false true 24 174 42
832 | Circle -7500403 false true 144 174 42
833 | Circle -7500403 false true 234 174 42
834 |
835 | turtle
836 | true
837 | 0
838 | Polygon -10899396 true false 215 204 240 233 246 254 228 266 215 252 193 210
839 | Polygon -10899396 true false 195 90 225 75 245 75 260 89 269 108 261 124 240 105 225 105 210 105
840 | Polygon -10899396 true false 105 90 75 75 55 75 40 89 31 108 39 124 60 105 75 105 90 105
841 | Polygon -10899396 true false 132 85 134 64 107 51 108 17 150 2 192 18 192 52 169 65 172 87
842 | Polygon -10899396 true false 85 204 60 233 54 254 72 266 85 252 107 210
843 | Polygon -7500403 true true 119 75 179 75 209 101 224 135 220 225 175 261 128 261 81 224 74 135 88 99
844 |
845 | wheel
846 | false
847 | 0
848 | Circle -7500403 true true 3 3 294
849 | Circle -16777216 true false 30 30 240
850 | Line -7500403 true 150 285 150 15
851 | Line -7500403 true 15 150 285 150
852 | Circle -7500403 true true 120 120 60
853 | Line -7500403 true 216 40 79 269
854 | Line -7500403 true 40 84 269 221
855 | Line -7500403 true 40 216 269 79
856 | Line -7500403 true 84 40 221 269
857 |
858 | wolf
859 | false
860 | 0
861 | Polygon -16777216 true false 253 133 245 131 245 133
862 | Polygon -7500403 true true 2 194 13 197 30 191 38 193 38 205 20 226 20 257 27 265 38 266 40 260 31 253 31 230 60 206 68 198 75 209 66 228 65 243 82 261 84 268 100 267 103 261 77 239 79 231 100 207 98 196 119 201 143 202 160 195 166 210 172 213 173 238 167 251 160 248 154 265 169 264 178 247 186 240 198 260 200 271 217 271 219 262 207 258 195 230 192 198 210 184 227 164 242 144 259 145 284 151 277 141 293 140 299 134 297 127 273 119 270 105
863 | Polygon -7500403 true true -1 195 14 180 36 166 40 153 53 140 82 131 134 133 159 126 188 115 227 108 236 102 238 98 268 86 269 92 281 87 269 103 269 113
864 |
865 | x
866 | false
867 | 0
868 | Polygon -7500403 true true 270 75 225 30 30 225 75 270
869 | Polygon -7500403 true true 30 75 75 30 270 225 225 270
870 | @#$#@#$#@
871 | NetLogo 6.1.1
872 | @#$#@#$#@
873 | set model-version "sheep-wolves-grass"
874 | set show-energy? false
875 | setup
876 | repeat 75 [ go ]
877 | @#$#@#$#@
878 | @#$#@#$#@
879 | @#$#@#$#@
880 | @#$#@#$#@
881 | default
882 | 0.0
883 | -0.2 0 0.0 1.0
884 | 0.0 1 1.0 0.0
885 | 0.2 0 0.0 1.0
886 | link direction
887 | true
888 | 0
889 | Line -7500403 true 150 150 90 180
890 | Line -7500403 true 150 150 210 180
891 | @#$#@#$#@
892 | 1
893 | @#$#@#$#@
894 |
--------------------------------------------------------------------------------