Tag Archives: cellular automata

Preliminary View on Cellular Automata representing neuron interaction.

Brief History
At present time, I have succesfully created a Cellular Automaton in Scilab, which can act as if many different Cellular Automata by the use of variables - allowing for variable rules. The main focus during the development however, was to recreate the Game Of Life, by John Conway. Reason for this being that 'Life' is an axiomatic automaton, which is indirectly why it is so widely known . The code of which, viewable on this blog in the preceding post, is self-explantory for anyone familiar with Cellular Automata and matrix manipulation in scilab. The only major downside was the visualisation of the generations, but the visualisation is, apart from easy on the eye, not an important factor in Cellular Automata, as long as you know how to read your CA you can conduct the necessary research and come to a conclusion. The readout, though simplified by visualisation, can be made faster by saving the state of the CA in serialised form, and only asking, say, every X generation to be drawn - or saved as vector image to a .pdf file.

Abstract

The aim of this program is to imitate a neural network, on a very small scale. For this I use Scilab, the opensource equivalent of Matlab, because I want this code to be easily ran by other people without any cost. There will be a maximum of 1250 neurons at any time during the simulation. This limit was set for computability reasons alone, however, each neuron may have four 'receptors', commonly known as synapses,  at any time.

Neurological explenation

In order for any of the code to make sense, a working understanding of the human nervous system is vital. A few assumptions have to be made, for simplification of the complex processes. First, it should be obvious that prima facie the brain is digital, rather than analog. This was explained in some detail in 'The computer and the brain', by John Von Neumann, so I will keep this discussion short (as the works of Von Neumann are widely available, and should be a priori known to everyone in computerscience).

The digital nature, commonly represented by bits being of either "0" or "1" value. In the human brain, a neuron (nerve cell) either recieves stimulation, or it doesn't. This stimulation however, is of both digital and analog nature. The digital part is prima facie logical and requires no further knowledge, in part due to the clarity of the goal set out by this very post. The analog part however, is not that visible at first sight, thus requires some further explenation. Modelling of the analog part is beyond the extend of my proposed algorithm, due to the problem being tackled is of a different nature than the problem of creating a cellular automaton which acts as the digital part of your brain. The analog part is only visible as soon as we consider neurons with several functions - to illustrate clearly the analog part I will use the simple, and simplified, example of the optic nerve.

In a simplified way, the optic nerve is responsible for what we see - or rather - it sends the data of light hitting our eye to the brain which then interprets this. Imagine the eye tells the brain you are looking at a lamp - how would you know what the brightness is of this lamp? Imagine we have two lamps, lamp A with a brightness of 10, and lamp B, with a brightness of 20. To let the brain know how "bright" the lamp is, the optic nerve has the logical choice to send this as an analog system within a specified timeframe. This means that, when looking at lamp A, the optic nerve might send 50 pulses in 1 millisecond, whilst when looking at lamp B, the optic nerve might send 100 pules in 1 millisecond. Thus explaining the analog nature of our brain.

To keep this preliminary view short, I will only briefly explain how the neurons communicate, before continuing with how we could create logic gates with them.

 

The communication between neurons can be viewed from three different perspectives, there are chemical events, electrical events and mechanical events. Though, most frequently, the communications is shown via transmission of electric pulses from one neuron to another neuron. The "roads" over which these pulses travel are called axons. Each neuron may hold multiple axons, connected via synapses.

When a neuron sends out a pulse, it can also be viewed from a chemical perspective, and a mechanical one, the chemical composition changes allowing for transmission of electrons, or reacting to the recieving of these electrons. Since I am neither interested in the chemics or mechanics part of the neuron, and feel as though my explenation would be unsatisfactory, I will omit these throughout the rest of this discussion.

It is vital to keep in mind that this proposed automaton models the communication between neurons, not the physiological effects on the neuron during this communication.

Logic gating with neurons.

As before mentioned, the brain prima facie digital, and we want thusly to work with this digital data. As mentioned, the way a neuron transmits data, over an axon, to another neuron can be viewed from three separate perspectives. A chemical, electrical, and mechanical perspective can be found, however, on such microscopic levels we can model it as one process – the sending of data from neuron A to neuron B via electrical pulse. The chemical and mechanical events are largely found inside the neuron itself, but the exact way on which this happens need not be implemented, as the implementation considers communication primarily.

The most reasonable way of implementing this – considering the neurons communicate via electric pulse – is to consider an ‘energy-threshold’ for each neuron. Let us assume that each neuron can create a pulse of 25mV, to create a gating system with neurons, we can use the threshold the neuron needs to send out a pulse. (We violate the principle here that ‘Absence of a signal should never be used as a signal’, as stated by J. Bigelow, but it makes sense to use this from a neurological point of view)

Assume we have a neuron, which is connected with three axons – two of which he can receive input from and a third which he can send a pulse across. Imagine we want to create the logical ‘AND’ gate – we can do this by setting the threshold to 50mV.

Pulse A Pulse B Result
0 mV 0 mV 0 mV
0 mV 25 mV 25 mV
25 mV 0 mV 25 mV
25 mV 25 mV 50 mV

 

From this, we can see that the only time the threshold value of 50 mV is reached, is when a pulse has come from both neurons. Though a remark has to be made on the simultaneity of the system.

The neuron where the pulse arrives can hold this voltage for a certain period of time, allowing for simultaneity due to containment of energy. This means that, say, pulse A arrives at time t=1ms, and pulse B arrives at t=2ms, the result will still be 50 mV due to the containment. This too, can be modeled rather easily.

Another remark that has to be made, is that a neuron does not necessarily have only 2 synapses (connecting axons), they may very well have 50 of these, in which case some interesting gating tricks could be used – but the threshold system is expandable. (Say, the ‘AND’ gate only works when 10 axons have delivered 225 mV, allowing for 9 out of 10 axons to be needed, instead of all 10, but this, amongst other simplifications, can be left out for the basic model).

The above example should illustrate clearly how one could construct the other gates by using these threshold values, keeping in mind that all complex action which happens on a system can ultimately be brought down to the basic logic gates.

From what is written here, I will construct the cellular automaton - reusing the code base I have created - and posted on this blog. The autamaton, though being limited in size - and clearly efficiency - should show how communication happens between neurons.

Scilab: 4-state Cellular Automata V2.0

UPDATES:
-User input
-Variable rules (Bx/Sy)
- Refactoring of old code
- User can now create the initial field


// The value for a life cell is 2
// The value for a dead cell is 1


// Rules

// live cell surrounded by less than 2 = starvation (die)
// 2 or 3 live neighbours = survive
// exactly 3 = spawn (or stay alive)
// more than 3 = overcrowded (die)

// sieripinski triangle: B1/S12 (applied to one)
function life(rowSize, columnSize)
    
    // alter stacksize for really big fields!
    // default stacksize = 10^8
    
    // create a flexible born / die rule
    born = input('B:') //B2
    survive = input('S:')
    
    
    
    if(rowSize*columnSize>1000000)
        X = input('over 1 million cells! Continue?  Y/N ')
        if(X == 'Y')
            stacksize(168435454)    
        else
           rowSize = input('Enter new rowsize:  ') 
           columnSize = input('Enter new columnsize:   ')
        end
    end
    
    while(rowSize*columnSize > 2500000)
        disp('Too much cells, please stay below 2.5 million cells!')
        rowSize = input('Enter new rowsize:  ') 
        columnSize = input('Enter new columnsize:   ')
    end
    
    // ask if the field should be randomly generated, otherwise, testarea
    
    RGF = input('Generate random field?')
    if(RGF)
        field = generateField(rowSize, columnSize);
    else
        field = enterCustomField(rowSize,columnSize)
    end
isLaunched = %T;

liveCount = 1;
changeCount = 1
arrayOfAlive = [];
arrayOfChange = [];
generation = 0


while(isLaunched) // infinite loop
    for row = 1:rowSize 
        for column = 1:columnSize
            
            count = 0 // set count to zero for every 'cell'
            
            
            
            if(row<rowSize & column < columnSize & row > 1 & column > 1) // check boundary conditions
               if(field(row,column+1) == 2 | field(row,column+1) == 10)
                    count = count + 1
               end 
               
               if(field(row,column-1) == 2 | field(row,column-1) == 10)
                    count = count + 1
               end
               
               if(field(row-1,column-1) == 2 | field(row-1,column-1) == 10)
                    count = count + 1    
               end
               
               if(field(row-1,column)==2 | field(row-1,column) == 10)
                   count = count + 1    
               end
               
               if(field(row-1,column+1)==2 |field(row-1,column+1) == 10)
                    count = count + 1;    
               end
               
               if(field(row+1,column)==2 | field(row+1,column) == 10)
                    count = count + 1
               end
               
               if(field(row+1,column-1)==2 | field(row+1,column-1) == 10)
                   count = count + 1
               end
               
               if(field(row+1,column+1)==2 | field(row+1,column+1) == 10) // 10 signals that it was ALIVE (2) in this generation, but will DIE in the next generation!!!!!!
                   count = count + 1
               end
               
               
               
          else // WHAT IF THE ALL BOUNDARY CHECK IS FALSE
              
          end // end the -ALL BOUNDARY- check
          
          
          

  
                // Now we see what the count equals, and decide what the cell has to do accordingly
                
                // I'll have to flag them for change. 
                // Probably Von Neumans way.
                if(count==born)
                   if(field(row,column) == 1)
                        field(row,column) = 20 // flagged to be alive
                   end
                else // Check if they survive - if they don't, they'll die.
                    
                    willSurvive=%F // OUTSIDE THE IF, OTHERWISE IF 2 = %T, RESET TO %F FOR 3 & STAY AT %F.
                    for inVector=1:length(survive)
                        if(count == survive(inVector)) 
                            willSurvive=%T
                        end
                    end
                    if(~willSurvive)
                       if(field(row,column)==2)
                          field(row,column)=10 
                       end
                    end
                end
                
            
            
        end // end the for column
    end // end the for row
       
    generation = generation +1 // we have gone through one generation
   // disp(generation)
   

   changing = 0
   
    // Update the graph matrix by changing those that have to be changed!
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns) == 10)
               field(rows,columns)=1
               changing = changing + 1
            end
                      
            if(field(rows,columns) == 20)
                field(rows,columns)=2
                changing = changing + 1
            end
        end
    end // end for ROWS
    
    //clf
    
    
    // COUNT THE LIVE ONES
       
      liveOnes = 0
      
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns)==2)
                liveOnes = liveOnes + 1;
            end
        end
    end    
    
    arrayOfAlive(liveCount) = liveOnes;
    arrayOfChange(changeCount) = (changing)
    liveCount = liveCount + 1;
    changeCount = changeCount + 1
    
    
    if(modulo(generation,10)==0)
       subplot(222)

       plot(arrayOfAlive)
       livePlot = gca()
       xtitle('Generation vs Live Cells')
       
       // also create another graph with percentages?
       subplot(223)
       plot(arrayOfChange)
       AOC = gca()
       xtitle('Change in Life')
    end
    
    graph = gca()
    subplot(221)

    Matplot(field)
    xtitle('generation: ' + string(generation))
end


endfunction



function M=generateField(rows,columns)
        M=[]
    for i=1:rows
        for j=1:columns
            M(i,j) = 1+round(rand())
        end
    end
    
   
endfunction

function NRF=enterCustomField(rows,columns)
    NRF = [] // non Random field
    for i=1:rows
        for j=1:columns
            NRF(i,j) = 1
        end
    end
    
    // ask user for input on NRF creation. 
    
    userInput = 'input'
    while(~(userInput=='EOI'))//end of input
        userInput = input('Enter a location to be set alive:')
        if(userInput=='EOI')
            break
        end
        disp(userInput(1))
        NRF(userInput(1),userInput(2))=2
    end
endfunction




Scilab: 4-state Cellular Automata v1.1

Added: - Warnings when cell count exceeds 1 million
- Altering stacksize when cell count > 1 million

// The value for a life cell is 2
// The value for a dead cell is 1


// Rules

// live cell surrounded by less than 2 = starvation (die)
// 2 or 3 live neighbours = survive
// exactly 3 = spawn (or stay alive)
// more than 3 = overcrowded (die)
function life(rowSize, columnSize)
    
    // alter stacksize for really big fields!
    // default stacksize = 10^8
    
    if(rowSize*columnSize>1000000)
        x = input('You re creating a big field. Continue: Y / N:   ')
        if(x=='Y')
        stacksize(168435454)    // arbitrary limit working on most sizes and enough to calculate reasonably big (2.5*10^7) cells - though plotting can become 'unstable'
        else
            rowSize = 10; columnSize = 10;
        end
    end
field = generateField(rowSize, columnSize);
isLaunched = %T;

liveCount = 1;
changeCount = 1
arrayOfAlive = [];
arrayOfChange = [];
generation = 0


while(isLaunched) // infinite loop
    for row = 1:rowSize 
        for column = 1:columnSize
            
            count = 0 // set count to zero for every 'cell'
            if(row<rowSize & column < columnSize & row > 1 & column > 1) // check boundary conditions
               if(field(row,column+1) == 2 | field(row,column+1) == 10)
                    count = count + 1
               end 
               
               if(field(row,column-1) == 2 | field(row,column-1) == 10)
                    count = count + 1
               end
               
               if(field(row-1,column-1) == 2 | field(row-1,column-1) == 10)
                    count = count + 1    
               end
               
               if(field(row-1,column)==2 | field(row-1,column) == 10)
                   count = count + 1    
               end
               
               if(field(row-1,column+1)==2 |field(row-1,column+1) == 10)
                    count = count + 1;    
               end
               
               if(field(row+1,column)==2 | field(row+1,column) == 10)
                    count = count + 1
               end
               
               if(field(row+1,column-1)==2 | field(row+1,column-1) == 10)
                   count = count + 1
               end
               
               if(field(row+1,column+1)==2 | field(row+1,column+1) == 10) // 10 signals that it was ALIVE (2) in this generation, but will DIE in the next generation!!!!!!
                   count = count + 1
               end
               
               

  
                // Now we see what the count equals, and decide what the cell has to do accordingly
                
                // I'll have to flag them for change. 
                // Probably Von Neumans way.
                if(count==3)
                   if(field(row,column) == 1)
                        field(row,column) = 20 // flagged to be alive
                   end
                elseif(count<2)
                    if(field(row,column) == 2)
                        field(row,column)= 10 // flagged to be dead
                     end
                elseif(count>3)
                    if(field(row,column)==2)
                        field(row,column)= 10 // flagged to be dead
                    end
                end
                
            end // end the big if
            
        end // end the for column
    end // end the for row
       
    generation = generation +1 // we have gone through one generation
   // disp(generation)
   

   changing = 0
   
    // Update the graph matrix by changing those that have to be changed!
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns) == 10)
               field(rows,columns)=1
               changing = changing + 1
            end
                      
            if(field(rows,columns) == 20)
                field(rows,columns)=2
                changing = changing + 1
            end
        end
    end // end for ROWS
    
    //clf
    
    
    // COUNT THE LIVE ONES
       
      liveOnes = 0
      
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns)==2)
                liveOnes = liveOnes + 1;
            end
        end
    end    
    
    arrayOfAlive(liveCount) = liveOnes;
    arrayOfChange(changeCount) = (changing)
    liveCount = liveCount + 1;
    changeCount = changeCount + 1
    
    
    if(modulo(generation,10)==0)
       subplot(222)

       plot(arrayOfAlive)
       livePlot = gca()
       xtitle('Generation vs Live Cells')
       
       // also create another graph with percentages?
       subplot(223)
       plot(arrayOfChange)
       AOC = gca()
       xtitle('Change in Life')
    end
    
    graph = gca()
    subplot(221)

    Matplot(field)
    xtitle('generation: ' + string(generation))
end


endfunction



function M=generateField(rows,columns)
        M=[]
    for i=1:rows
        for j=1:columns
            M(i,j) = 1+round(rand())
        end
    end
    
   
endfunction

Scilab: 4-state Cellular Automaton

This code has some "optimalisation" issues at first glance, but this is due to the fact I've written a 4-state CA when a 3-state CA would reach the same outcome. I have chosen to do this, because I plan to implement "Barricelli's parasites", as first done by Barricelli in 1953 on the MANIAC, based on theories by himself and John Von Neumann. My primary goal is to illustrate that parasites, giving the power they had in 1953, will always dominate the universe.

Flaws in this 'beta' version are:
- limited universe, causing the CA to hit 'the edge of the universe'.
- A time-complexity of n² (which is not in itself a flaw, but hashlife is significantly better)

Features:
- A working CA with rules on Conway's game of life (B3/S23)
- A plot showing the current count of live cells
- A plot showing the change in life (the 3th and 4th state count)

// The value for a life cell is 2
// The value for a dead cell is 1


// Rules

// live cell surrounded by less than 2 = starvation (die)
// 2 or 3 live neighbours = survive
// exactly 3 = spawn (or stay alive)
// more than 3 = overcrowded (die)
function life(rowSize, columnSize)
field = generateField(rowSize, columnSize);
isLaunched = %T;

liveCount = 1;
changeCount = 1
arrayOfAlive = [];
arrayOfChange = [];
generation = 0


while(isLaunched) // infinite loop
    for row = 1:rowSize 
        for column = 1:columnSize
            
            count = 0 // set count to zero for every 'cell'
            if(row<rowSize & column < columnSize & row > 1 & column > 1) // check boundary conditions
               if(field(row,column+1) == 2 | field(row,column+1) == 10)
                    count = count + 1
               end 
               
               if(field(row,column-1) == 2 | field(row,column-1) == 10)
                    count = count + 1
               end
               
               if(field(row-1,column-1) == 2 | field(row-1,column-1) == 10)
                    count = count + 1    
               end
               
               if(field(row-1,column)==2 | field(row-1,column) == 10)
                   count = count + 1    
               end
               
               if(field(row-1,column+1)==2 |field(row-1,column+1) == 10)
                    count = count + 1;    
               end
               
               if(field(row+1,column)==2 | field(row+1,column) == 10)
                    count = count + 1
               end
               
               if(field(row+1,column-1)==2 | field(row+1,column-1) == 10)
                   count = count + 1
               end
               
               if(field(row+1,column+1)==2 | field(row+1,column+1) == 10) // 10 signals that it was ALIVE (2) in this generation, but will DIE in the next generation!!!!!!
                   count = count + 1
               end
               
               

  
                // Now we see what the count equals, and decide what the cell has to do accordingly
                
                // I'll have to flag them for change. 
                // Probably Von Neumans way.
                if(count==3)
                   if(field(row,column) == 1)
                        field(row,column) = 20 // flagged to be alive
                   end
                elseif(count<2)
                    if(field(row,column) == 2)
                        field(row,column)= 10 // flagged to be dead
                     end
                elseif(count>3)
                    if(field(row,column)==2)
                        field(row,column)= 10 // flagged to be dead
                    end
                end
                
            end // end the big if
            
        end // end the for column
    end // end the for row
       
    generation = generation +1 // we have gone through one generation
   // disp(generation)
   

   changing = 0
   
    // Update the graph matrix by changing those that have to be changed!
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns) == 10)
               field(rows,columns)=1
               changing = changing + 1
            end
                      
            if(field(rows,columns) == 20)
                field(rows,columns)=2
                changing = changing + 1
            end
        end
    end // end for ROWS
    
    //clf
    
    
    // COUNT THE LIVE ONES
       
      liveOnes = 0
      
       for rows=1:rowSize
        for columns = 1:columnSize
            if(field(rows,columns)==2)
                liveOnes = liveOnes + 1;
            end
        end
    end    
    
    arrayOfAlive(liveCount) = liveOnes;
    arrayOfChange(changeCount) = (changing)
    liveCount = liveCount + 1;
    changeCount = changeCount + 1
    
    
    if(modulo(generation,10)==0)
       subplot(222)

       plot(arrayOfAlive)
       livePlot = gca()
       xtitle('Generation vs Live Cells')
       
       // also create another graph with percentages?
       subplot(223)
       plot(arrayOfChange)
       AOC = gca()
       xtitle('Change in Life')
    end
    
    graph = gca()
    subplot(221)

    Matplot(field)
    xtitle('generation: ' + string(generation))
end


endfunction



function M=generateField(rows,columns)
        M=[]
    for i=1:rows
        for j=1:columns
            M(i,j) = 1+round(rand())
        end
    end
    
   
endfunction