Elementary cellular automaton

using EasyABM

Step 1: Create Model

In this model, we work with patches only. We set grid_size to (50,50) and set space_type to NPeriodic.

model = create_2d_model(size = (50,50), space_type=NPeriodic)

Step 2: Initialise the model

We assign two attributes namely color and val to all patches. The patches with val 0 are white while those with val 1 are black. Initially, we set all patches to have val = 0, color = cl"white" except for the patch at position (25,1) which is assigned val = 1, color = cl"black". Since, the color and val attributes are not independent, we tell EasyABM to record only color attribute of the patches through the argument props_to_record to the init_model! function.

function initialiser!(model)
    for j in 1:model.size[2]
        for i in 1:model.size[1]
            model.patches[i,j].color = cl"white"
            model.patches[i,j].val = 0
    model.patches[25,1].color = cl"black"
    model.patches[25,1].val = 1

init_model!(model, initialiser = initialiser!, props_to_record = Dict("patches" => Set([:color])))   

Step 3: Defining the step_rule! and running the model

The dictionary rules defines the update rule. It is known as rule number 30 in the classification of elementary cellular automata. The val property (and hence the color) of jth patch in (i+1)th row is set equal to the value in rules corresponding to the key (a, b, c) where in the ith row a is val of (j-1)th patch, b is val of jth patch and c is the val of (j+1)th patch. Since the size of our space is finite, after a certain number of iterations we have to copy each row to the row below and update the topmost row.

rules = Dict((1,1,1)=>0, (1,1,0)=>0, (1,0,1)=>0, (0,1,1)=>1, 
(1,0,0)=>1, (0,1,0)=>1, (0,0,1)=>1, (0,0,0)=>0) # rule 30

function update_from_row_below(row, model)
    for j in 2:(model.size[1]-1)
        vals = (model.patches[j-1, row-1].val, 
                model.patches[j,   row-1].val, 
                model.patches[j+1, row-1].val)   
        val = rules[vals]
        model.patches[j, row].val = val
        model.patches[j, row].color = val==0 ? cl"white" : cl"black"

function copy_to_row_below(row, model)
    for j in 1:model.size[1]
        model.patches[j, row-1].val = model.patches[j, row].val
        model.patches[j, row-1].color = model.patches[j, row].color

function step_rule!(model)
    if model.tick < model.size[1]
        row = model.tick+1
        update_from_row_below(row, model)      
        for i in 2:model.size[1]
            copy_to_row_below(i, model)
        update_from_row_below(model.size[1], model)

runmodel!(model, steps = 200, steprule = step_rule!)

Step 4: Visualisation

In order to draw the model at a specific frame, say 4th, one can use draw_frame(model, frame = 4 ). If one wants to see the animation of the model run, it can be done as



Step 5: Fetch Data

It is easy to fetch any recorded data after running the model. For example, the numbers of patches with color cl"white" can be got as follows

df = get_nums_patches(model, 
    patch-> patch.color == cl"white", 
    labels=["white"], plot_result=true)