%% Stencil Processing on GPU
%
% This example shows how to generate CUDA(R) kernels for stencil type 
% operations by implementing "Game of Life" by John H. Conway. 
% 
% "Game of Life" is a zero-player _cellular automaton_ game that consists 
% of a collection of cells (_population_) in a rectangular grid 
% (_universe_). The cells evolve at discrete time steps known as 
% _generations_. A set of mathematical rules applied to the cells and its 
% neighbors control their life, death,and reproduction. This "Game of Life" 
% implementation is based on the example provided in the e-book 
% <https://www.mathworks.com/moler/exm _Experiments in MATLAB_> by Cleve Moler.
% The implementation follows these rules:
% 
% * Cells are arranged in a 2-D grid.
% * At each step, the vitality of the eight nearest neighbors of each cell
% determines its fate.
% * Any cell with exactly three live neighbors comes to life at the next
% step.
% * A live cell with exactly two live neighbors remains alive at the next
% step.
% * All other cells (including those with more than three neighbors) die
% at the next step or remain empty.
% 
% Here are some examples of how a cell is updated.
% 
% <<gpucoderdemo_stencil_rules.png>> 
% 
% Many array operations can be expressed as a _stencil_ operation,
% where each element of the output array depends on a small region of the 
% input array. The stencil in this example is the 3-by-3 region around each 
% cell. Finite differences, convolution, median filtering, and 
% finite-element methods are examples of other operations that stencil 
% processing can perform.

% Copyright 2016-2019 The MathWorks, Inc. 

%% Prerequisites
% * CUDA(R) enabled NVIDIA(R) GPU with compute capability 3.2 or higher.
% * NVIDIA CUDA toolkit and driver.
% * Environment variables for the compilers and libraries. For information 
% on the supported versions of the compilers and libraries, see 
% <docid:gpucoder_gs#mw_aa8b0a39-45ea-4295-b244-52d6e6907bff
% Third-Party Products>. For setting up the environment variables, see 
% <docid:gpucoder_gs#mw_453fbbd7-fd08-44a8-9113-a132ed383275
% Environment Variables>.

%% Create a Folder and Copy Relevant Files
% The following line of code creates a folder in your current working 
% folder (pwd) and copies all the relevant files into this folder. If you 
% do not want to perform this operation or if you cannot generate files in 
% this folder, change your current working folder.
gpucoderdemo_setup('gpucoderdemo_stencil');

%% Verify GPU Environment
% To verify that the compilers and libraries necessary for running this example
% are set up correctly, use the <docid:gpucoder_ref#mw_0957d820-192f-400a-8045-0bb746a75278 coder.checkGpuInstall>
% function.
envCfg = coder.gpuEnvConfig('host');
envCfg.BasicCodegen = 1;
envCfg.Quiet = 1;
coder.checkGpuInstall(envCfg);

%% Generate a Random Initial Population
% Being that the game is zero-player, the evolution of the game is 
% determined by its initial state. For this example, an initial population 
% of cells is created on a two-dimensional grid with approximately 25% of 
% the locations being alive.
gridSize = 500;
numGenerations = 100;
initialGrid = (rand(gridSize,gridSize) > .75);

% Draw the initial grid
imagesc(initialGrid);
colormap([1 1 1;0 0.5 0]);
title('Initial Grid');

%% Play the Game of Life
% The
% <matlab:edit(fullfile(matlabroot,'toolbox','gpucoder','gpucoderdemos','gpucoderdemo_stencil','gameoflife_orig.m'))
% gameoflife_orig.m> function is a fully vectorized implementation of 
% "Game of Life". The function updates all cells on the grid in one pass 
% per their generation.
type gameoflife_orig
%%
% Play the game by calling the |gameoflife_orig| function with an 
% initial population. The game iterates through 100 generations and 
% displays the population at each generation.
gameoflife_orig(initialGrid);

%% Convert the Game of Life for GPU Code Generation
% Looking at the calculations in the |updateGrid| function, it is apparent 
% that the same operations are applied at each grid location independently.
% However, each cell must know about its eight neighbors. The modified
% <matlab:edit(fullfile(matlabroot,'toolbox','gpucoder','gpucoderdemos','gpucoderdemo_stencil','gameoflife_stencil.m')) gameoflife_stencil.m>
% function uses the <docid:gpucoder_ref#mw_fd365762-5cf2-41e2-b276-d41338004c92 gpucoder.stencilKernel> 
% pragma to compute a 3-by-3 region around each cell. The GPU Coder(TM) 
% implementation of the stencil kernel computes one element of the grid 
% in each thread and uses shared memory to improve memory bandwidth and 
% data locality. 
type gameoflife_stencil

%% Generate CUDA MEX for the Function
% To generate CUDA MEX for the |gameoflife_stencil| function, create a GPU 
% code configuration object, and then use the <docid:coder_ref#br46oyi-1 codegen> command. 
cfg = coder.gpuConfig('mex');
evalc('codegen -config cfg -args {initialGrid}  gameoflife_stencil');

%% Run the MEX Function
% Run the generated |gameoflife_stencil_mex| with the random initial population.
gridGPU = gameoflife_stencil_mex(initialGrid);
% Draw the grid after 100 generations
imagesc(gridGPU);
colormap([1 1 1;0 0.5 0]);
title('Final Grid - CUDA MEX');

%% Conclusion
% CUDA code was generated for a simple stencil operation,
% Conway's "Game of Life". Implementation was accomplished by using the 
% |gpucoder.stencilKernel| pragma. You can use the technique shown in this 
% example to implement a range of stencil operations, including 
% finite-element algorithms, convolutions, and filters.
%% Cleanup
% Remove the generated files and return to the original folder.
cleanup

displayEndOfDemoMessage(mfilename)
