1

I'm currently working on a code that makes use of a 2D cellular automata as an epidemic simulator in MATLAB. The main basic rule I'm trying to implement is that if any neighbour within a Moore Neighbourhood with a 1-cell radius is infected, the cell will become infected. But I can't seem to get a good code working for it.

Basically what I'm trying to do is say with for a cell with a one cell radius Moore neighbourhood, if any values in this neighbourhood = 2, then the initial cell will become 2.

I've tried using the forest fire code on the rosetta code as a basis for my code behaviour but it doesnt work very well. The rules don't really work that well when applying it to mine. I've tried using the mod function and a series of if loops to attach. I'll put in some code of each to give context.

This example doesn't really function well as an epidemic simulator to be honest.

    matlab
    clear; clc;
    n = 200;
    N = n/2;
    E = 0.001; % Creating an arbitrary number for population exposed to                 
                 the disease but not infected
    p = 1 + (rand(n,n)<E);
    %p = ceil(rand(n,n)*2.12) - 1;
    % ratio0 = sum(p(:)==0)/n^2;
    % ratio1 = sum(p(:)==1)/n^2;
    % ratio2 = sum(p(:)==2)/n^2;
    % ratio3 = sum(p(:)==3)/n^2;
    S = ones(3); S(2,2) = 0;
    ff = 0.00000000002;
    p(N,N) = 3;
    %% Running the simulation for a set number of loops
    colormap([1,1,1;1,0,1;1,0,0]); %Setting colourmap to Green, red and 
    grey
    count = 0;
    while(count<365) % Running the simulation with limited number of runs
    count = count + 1;
    image(p); pause(0.1); % Creating an image of the model
    P = (p==1); % Adding empty cells to new array
    P = P + (p==2).*((filter2(S,p==3)>0) + (rand(n,n)<ff) + 2); % Setting         
              2 as a tree, ignites based on proximity of trees and random 
              chance ff
    P = P + (p==3); % Setting 3 as a burning tree, that becomes 1,
    p = P;
    end

second idea. this basically returns nothing

    matlab
    clear;clf;clc;
    n = 200;
    pos = mod((1:n),n) + 1; neg = mod((1:n)-2,n) + 1;
    p = (ceil(rand(n,n)*1.0005));
    for t = 1:365
        if p(neg,neg) ==2 
           p(:,:) = 2;
        end
        if p(:,neg)==2 
           p(:,:) = 2;
        end
        if p(pos,neg)==2
           p(:,:) = 2;
        end
        if p(neg,:)==2
           p(:,:) = 2;
        end   
        if p(pos,:)==2
           p(:,:) = 2;
        end
        if p(neg,pos)==2
           p(:,:) = 2;
        end
        if p(:,pos)==2
           p(:,:) = 2;
        end
        if p(pos,pos)== 2
           p(:,:) = 2;
        end
        image(p)
        colormap([1,1,1;1,0,1])
    end

third I tried using logic gates to see if that would work. I don't know if commas would work instead.

    matlab
    clear;clf;clc;
    n = 200;
    pos = mod((1:n),n) + 1; neg = mod((1:n)-2,n) + 1;
    p = (ceil(rand(n,n)*1.0005));
    %P = p(neg,neg) + p(:,neg) + p(pos,neg) + p(neg,:) + p(:,:) + p(pos,:)         
       + p(neg,pos) + p(:,pos) + p(pos,pos)

    for t=1:365
        if p(neg,neg)|| p(:,neg) || p(pos,neg) || p(neg,:) ||  p(pos,:) ||         
           p(neg,pos) || p(:,pos) || p(pos,pos) == 2
           p(:,:) = 2;
        end
        image(p)
        colormap([1,1,1;1,0,1])
    end

I expected the matrix to just gradually become more magenta but nothing happens in the second one. I get this error for the third.

"Operands to the || and && operators must be convertible to logical scalar values."

I just have no idea what to do!

  • So cells can be `1` or `2`. If a neighbour is `2` the cell becomes `2`. Does it ever become `1`? Does the own cell's state matter? Do `2` cells always remain as `2`? – Luis Mendo Jun 13 '19 at 16:21
  • Hi Luis, you're correct, there are 2 states and if a neighbour is 2, the cell becomes 2. The cell will become recovered (3) after a few iterations but I'm not yet sure as how to code this. Once the cell becomes (3) there should be no way of it becoming 2 again. – kashmoney505 Jun 13 '19 at 16:57
  • Recovery is a different matter, and should probably be posted as a different question, as it completely changes the problem. What I would do is: define cells as `0 for non-infected and positive integer for infected, and keep a counter in each cell, which is increased at each iteration. When a cell reaches a given value it becomes cured – Luis Mendo Jun 13 '19 at 17:01
  • "*Operands to the || and && operators must be convertible to logical scalar values.*" This is addressed [here](https://stackoverflow.com/questions/16080143/operands-to-the-and-operators-must-be-convertible-to-logical-scalar-values) and [here](https://stackoverflow.com/questions/9172789/how-to-solve-operands-to-logical-scalar). – SecretAgentMan Jun 13 '19 at 17:14
  • @Luis Mendo When you say to keep a counter in each cell, do you mean to use 1s and 0s to then to add up the number of 1s in surrounding cells? for example, using my code, `P = p(neg,neg) + p(:,neg) + p(pos,neg) + p(neg,:) + p(:,:) + p(pos,:) + p(neg,pos) + p(:,pos) + p(pos,pos) p =' P==3 | P==4` or something along those lines? – kashmoney505 Jun 13 '19 at 17:19
  • No, adding the number if neighbors is not useful. It only matter whether there is some neighbor infected or none infected. What I meant is increase the value for infected cells in each iteration – Luis Mendo Jun 13 '19 at 18:20

1 Answers1

1

Cells do not heal

I assume that

  • Infected is 2, non-infected is 1;
  • An infected cell remains infected;
  • A non-infected cell becomes infected if any neighbour is.

A simple way to achieve this is using 2-D convolution:

n = 200;
p = (ceil(rand(n,n)*1.0005));
neighbourhood = [1 1 1; 1 1 1; 1 1 1]; % Moore plus own cell
for t = 1:356
    p = (conv2(p-1, neighbourhood, 'same')>0) + 1; % update
    image(p), axis equal, axis tight, colormap([.4 .4 .5; .8 0 0]), pause(.1) % plot
end

enter image description here

Cells heal after a specified time

  • To model this, it is better to use 0 for a non-infected cell and a positive integer for an infected cell, which indicated how long it has been infected.
  • A cell heals after it has been infected for a specified number of iterations (but can immediately become infeced again...)

The code uses convolution, as the previous one, but now already infected cells need to be dealt with separately from newly infected cells, and so a true Moore neighbourhood is used.

n = 200;
p = (ceil(rand(n,n)*1.0005))-1; % 0: non-infected. 1: just infected
T = 20; % time to heal
neighbourhood = [1 1 1; 1 0 1; 1 1 1]; % Moore
for t = 1:356    
    already_infected = p>0; % logical index
    p(already_infected) = p(already_infected)+1; % increase time count for infected
    newly_infected = conv2(p>0, neighbourhood, 'same')>0; % logical index
    p(newly_infected & ~already_infected) = 1; % these just became infected
    newly_healed = p==T; % logical index
    p(newly_healed) = 0; % these are just healed
    image(p>0), axis equal, axis tight, colormap([.4 .4 .5; .8 0 0]), pause(.1) % plot
    % infected / non-infected state
end

enter image description here

Luis Mendo
  • 110,752
  • 13
  • 76
  • 147
  • Wow this is great! I sort of understand how the conv2 function works, it's like image convolution right? can you explain to me why in p = (conv2(p-1, neighbourhood, 'same')>0) + 1; you use p-1 and then + 1 at the end? is the plus 1 there so you have a final matrix with 1 and 2 values? – kashmoney505 Jun 13 '19 at 16:59
  • Yes, that's convolution, as is used in image processing. I use `p-1` so non-infected is `0` instead of `1`. That way, if the convolution result is any positive number it means the cell is now infected. To convert from "any positive positive number" to `1` I'm using `>0`. And then, as you said, I'm add 1 to convert 0,1 to 1,2 – Luis Mendo Jun 13 '19 at 17:03
  • Cool, one more question. Why do you use [1 1 1; 1 1 1; 1 1 1] for the neighbourhood? When doing convolution for the neighbourhood, isn't it better to leave out the own cell? – kashmoney505 Jun 13 '19 at 17:21
  • I included the center cell to mean “if the cell is infected it stays infected”. It makes the code more compact. Alternatively you could leave that as 0 and then apply logical OR between the convolution output and the input – Luis Mendo Jun 13 '19 at 18:21
  • @kashmoney505 I included a version in which cells heal after some time – Luis Mendo Jun 13 '19 at 21:31
  • 1
    Thank you so much for all your assistance! – kashmoney505 Jun 14 '19 at 02:02