Cellular automata library - CuCCAl

What is it?

A GPGPU CUDA powered cellular automata library , capable of hiding all the complexity behind the GPU programming of classica/complex and macroscopic cellular automata. The aim of this library is to make life easier to researchers that need to write and execute big cellular automata model.

Belousov-Zhabotinsky reaction cellular automaton.

Figure 1. Dewdney's Belousov-Zhabotinsky reaction cellular automaton.

The programmer has only to write the elementary processes that compose the transition function, register the substates and set up the automaton parameters (for example, the number of steps and cellular space size). The Memory management is completely behind the scene, letting the programmer concentrate only on the model he needs to write.

This library is open source. Help make it better!

 Library Usage Overview

Two main files are involed in the Cellular automaton specification: main.c and config.c.

Config.c contains transition function (the core of the model) and the substate enum that defines the substate names and the so called stoop condition that simply defines the execution stop criteria. The subsequent example shows
an example of the famous Conway's Game of Life Cellular Automaton.

#include "config.h"
#include "CA.cuh"
extern CA CA;

__global__ void gpuEvolve(CA_GPU* d_CA){
 unsigned int col=threadIdx.x+blockIdx.x*blockDim.x);
 unsigned int row=threadIdx.y+blockIdx.y*blockDim.y);
 unsigned int totRows=d_CA->scalars->rows;
 unsigned int totCols=d_CA->scalars->cols;
 if(row<totRows && col<totCols){
 short unsigned int count=0;
 unsigned int linNeighIdx=0;
 bool alive=d_CA->getSubstateValue_BOOL(Q,row,col);
 for (int neigh = 1; neigh < 9; neigh++) {
   linNeighIdx=d_CA->getNeighborIndex_MOORE_Toroidal(row,col,neigh,totRows,totCols);
   if(d_CA->getSubstateValue_BOOL(Q,linNeighIdx)==true) {
     count++;
    }
 }
  alive=( (!alive && count==3) || (alive && ( count==2 || count==3))) ? true : false;
  d_CA->setSubstateValue_BOOL(Q_NEW,row,col,alive);
 }
}
void __global__ copyBoard(CA_GPU* d_CA){
int col=(threadIdx.x+blockIdx.x*blockDim.x);
int row=(threadIdx.y+blockIdx.y*blockDim.y);
if(row<d_CA->scalars->rows && col<d_CA->scalars->cols){
d_CA->setSubstateValue_BOOL(Q,row,col,d_CA->getSubstateValue_BOOL(Q_NEW,row,col));
}
}
//true means --> STOP THE AUTOMATA
bool stopCondition(){
if(CA.getSteps() > 100){
return true;
}
return false;
}

Now that we have defined the global elementary processes we're ready to define the other pieces of a CA, namely substates and order of execution of elementary processes withing the global transition function.


int main() {
/*--------START CONFIGURATION AND INITIALIZATION PHASE--------*/

CA.setInitialParameters(2,2);
CA.initialize();

CA.addSubstate(Q,BOOL);
CA.addSubstate(Q_NEW,BOOL);

CA.registerElementaryProcess(gpuEvolve);
CA.registerElementaryProcess(copyBoard);
CA.registerStopCondictionCallback(stopCondition);

CA.setBlockDimY(16);
CA.setBlockdimX(16);

CA.initializeGPUAutomata();

/*--------END CONFIGURATION AND INITIALIZATION PHASE--------*/
CA.globalTransitionFunction();
CA.copyBuffersFromGPU();
CA.cleanUpGPUAutomata();

CA.cleanup();
printf("Elapsed Time = %.5f",CA.elapsedTime);
return 0;
}

That is all you need to exploit the computational power of your GPU. For instance this model runs 40x times faster that my serial version running on a intel i7 4460 CPU.

This library is open source. Help make it better!

 

Figure 1 shows an example image of the the famous Belousov-Zhabotinsky cellular automaton which rules are:

  1. A cell can have any of n discrete state [0,n-1].
  2.  if state is healthy(0) n'=a/k1 + b/k2;
  3. if state is ill(n-1) n'=0, the cell becomes healthy;
  4. if state is infected([1,n-2]), n'=(s/a+b+1) + g ;

where a = number of infected neighbors,b = number of ill neighbors, k1, k2, and g are constants, s is the sum of states of the cell and all of its neighbors.

You have no excuses to write it with the library!

Leave a Reply

Your email address will not be published. Required fields are marked *