Skip to content

Commit

Permalink
conway doc+minor fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
virgesmith committed Aug 15, 2021
1 parent 9474805 commit 21a3c9d
Show file tree
Hide file tree
Showing 10 changed files with 50 additions and 27 deletions.
21 changes: 21 additions & 0 deletions docs/examples/conway.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Conway's Game of Life

An implementation of Conway's cellular automata.

![Conway](./img/conway.gif)

{{ include_snippet("./docs/examples/src.md", show_filename=False) }}

## Inputs

The only inputs are the grid size (2d) and the proportion of cells that are alive initially.

## Implementation

This example uses the `StateGrid` class for efficient neighbour counting, requiring only a few lines of code to evolve a generation (see below). The initial alive cells are sampled randomly according to the proportion set. In each new generation, alive cells with less than 2 or more than 3 neighbours die; empty cells with 3 live neighbours come alive. Dead cells are coloured black, live cells are coloured according to how long they have been alive, from white (youngest) to brown (oldest).

{{ include_snippet("examples/conway/conway.py", "step") }}

## Outputs

The sole output is an animation as shown above.
Binary file added docs/examples/img/conway.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/examples/img/schelling.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/examples/neworder-1.0.1-examples-src.tgz
Binary file not shown.
Binary file modified docs/examples/neworder-1.0.1-examples-src.zip
Binary file not shown.
24 changes: 12 additions & 12 deletions docs/examples/schelling.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ An implementation of Schelling's segregation model [[7]](../references.md), whic

## Inputs

In the above example, the similarity threshold is 50% and the cells states are (approximately): 36% empty, 12% red, 12% blue and 39% green, on a 640 x 480 grid. The initial population is randomly constructed using the model's Monte-Carlo engine, the process of moving agents uses randomly swaps unsatisfied agents with empty cells.
In this example, the similarity threshold is 60% and the cells states are: 36% empty, 12% red, 12% blue and 40% green, on a 480 x 360 grid. The initial population is randomly constructed using the model's Monte-Carlo engine, the process of moving agents randomly swaps unsatisfied agents with empty cells. The boundaries are "sinks", i.e. there are no neighbouring cells

## Implementation

The key features that this example uses are the `StateGrid` class for efficient neighbour counting and the use of a conditional halting: an open-ended timeline and a call to the `Model.halt()` method when a certain state is achieved.
The key features used in this example are the `StateGrid` class for efficient neighbour counting and the use of a conditional halting: an open-ended timeline and a call to the `Model.halt()` method when a certain state is achieved.

Since the key output for this model is graphical, the visualisation code sits within the model. The model reaches a steady state when there are no unsatisfied agents remaining and there is nothing to be gained by continuing, so when this happens the `neworder.Model.halt()` method is called, at the end of the `step()` implementation:

Expand All @@ -29,15 +29,15 @@ The `StateGrid.count_neighbours` takes a function argument that filters the stat
The output is an animation as shown above. Log messages also record the timestep and the proportion of the population that remains unsatisfied:

```text
[py 0/1] step 0 42.6660% unsatisfied
[py 0/1] step 1 39.5765% unsatisfied
[py 0/1] step 2 37.5599% unsatisfied
[py 0/1] step 3 36.2454% unsatisfied
[py 0/1] step 4 35.2279% unsatisfied
[py 0/1] step 0 43.1493% unsatisfied
[py 0/1] step 1 39.1400% unsatisfied
[py 0/1] step 2 36.9196% unsatisfied
[py 0/1] step 3 35.3113% unsatisfied
[py 0/1] step 4 33.9259% unsatisfied
...
[py 0/1] step 458 0.0003% unsatisfied
[py 0/1] step 459 0.0003% unsatisfied
[py 0/1] step 460 0.0003% unsatisfied
[py 0/1] step 461 0.0003% unsatisfied
[py 0/1] step 462 0.0000% unsatisfied
[py 0/1] step 133 0.0017% unsatisfied
[py 0/1] step 134 0.0012% unsatisfied
[py 0/1] step 135 0.0012% unsatisfied
[py 0/1] step 136 0.0006% unsatisfied
[py 0/1] step 137 0.0000% unsatisfied
```
18 changes: 10 additions & 8 deletions examples/conway/conway.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,30 @@ def __init__(self, nx, ny, n, edge=no.Domain.WRAP):

self.fig, self.g = self.__init_visualisation()

# !step!
def step(self):

n = self.domain.count_neighbours(lambda x: x > 0)

deaths = np.logical_or(n < 2, n > 3)
births = n == 3

self.domain.state = self.domain.state * ~deaths + births

self.__update_visualisation()
# !step!

def check(self):
# # randomly place a glider (not across edge)
# if self.timeline.index() == 0:
# x = self.mc.raw() % (self.domain.state.shape[0] - 2)
# y = self.mc.raw() % (self.domain.state.shape[1] - 2)
# self.domain.state[x:x+3, y:y+3] = np.rot90(Conway.__glider, self.mc.raw() % 4)

self.__update_visualisation()

def check(self):
return True

def __init_visualisation(self):

plt.ion()
cmap = colors.ListedColormap(['black', 'white', 'purple', 'blue', 'green', 'yellow', 'orange', 'red', 'brown'])
fig = plt.figure(constrained_layout=True, figsize=(12,9))
fig = plt.figure(constrained_layout=True, figsize=(8,6))
g = plt.imshow(self.domain.state, cmap=cmap, vmax=9)
plt.axis("off")

Expand All @@ -60,6 +59,9 @@ def __init_visualisation(self):
return fig, g

def __update_visualisation(self):

self.g.set_data(self.domain.state)
# plt.savefig("/tmp/conway%04d.png" % self.timeline.index(), dpi=80)
# if self.timeline.index() > 100:
# self.halt()

self.fig.canvas.flush_events()
10 changes: 5 additions & 5 deletions examples/schelling/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
#neworder.verbose()

# category 0 is empty
gridsize = [640,480]
categories = np.array([0.56, 0.19, 0.19, 0.6])
# normalise
categories = categories / sum(categories)
similarity = 0.5
gridsize = [480,360]
categories = np.array([0.36, 0.12, 0.12, 0.4])
# normalise if necessary
# categories = categories / sum(categories)
similarity = 0.6

# open-ended timeline with arbitrary timestep
# the model halts when all agents are satisfied, rather than at a specific time
Expand Down
3 changes: 1 addition & 2 deletions examples/schelling/schelling.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,5 @@ def __init_visualisation(self):

def __update_visualisation(self):
self.img.set_array(self.domain.state.T)
# if not self.timeline.index() % 5:
# plt.savefig("/tmp/schelling%04d.png" % (self.timeline.index()//5), dpi=80)
# plt.savefig("/tmp/schelling%04d.png" % self.timeline.index(), dpi=80)
self.fig.canvas.flush_events()
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ nav:
- RiskPaths: examples/riskpaths.md
- People: ./examples/people.md
- Option: examples/option.md
- Conway: examples/conway.md
- Schelling: examples/schelling.md
- Wolf-Sheep: examples/wolf-sheep.md
- N-body: examples/n-body.md
Expand Down

0 comments on commit 21a3c9d

Please sign in to comment.