Gameoflife

Python Numpy

from __future__ import print_function
"""
Game of Life
------------

So what does this code example illustrate?
"""
from benchpress import util
from gameoflife_utils import pattern_paths, insert_cells, cells_from_file
import numpy as np

SURVIVE_LOW     = 2
SURVIVE_HIGH    = 3
SPAWN           = 3

def world(height, width, B):
    state = np.ones((height+2, width+2), dtype=B.dtype)
    state[2:-2, 2:-2] = B.dtype(0)
    return state

def world_zeros(height, width, B):
    state = np.zeros((height+2, width+2), dtype=B.dtype)
    return state

def play(state, iterations, version=1, visualize=False):

    cells = state[1:-1,1:-1]
    ul = state[0:-2, 0:-2]
    um = state[0:-2, 1:-1]
    ur = state[0:-2, 2:  ]
    ml = state[1:-1, 0:-2]
    mr = state[1:-1, 2:  ]
    ll = state[2:  , 0:-2]
    lm = state[2:  , 1:-1]
    lr = state[2:  , 2:  ]

    def update():
        """
        This is the first implementation of the game rules.
        """
        neighbors = ul + um + ur + ml + mr + ll + lm + lr       # count neighbors
        live = neighbors * cells                                # extract live cells neighbors
        stay = (live >= SURVIVE_LOW) & (live <= SURVIVE_HIGH)   # find cells the stay alive
        dead = neighbors * (cells == 0)                         # extract dead cell neighbors
        spawn = dead == SPAWN                                   # find cells that spaw new life

        cells[:] = stay | spawn                                 # save result for next iteration

    def update_optimized():
        """
        This is an optimized implementation of the game rules.
        """
        neighbors = ul + um + ur + ml + mr + ll + lm + lr       # Count neighbors

        c1 = (neighbors == SURVIVE_LOW)                         # Life conditions
        c2 = (neighbors == SPAWN)

        cells[:] = cells * c1 + c2                              # Update

    if version == 1:                # Select the update function
        update_func = update
    elif version == 2:
        update_func = update_optimized

    for i in range(iterations):    # Run the game
        if visualize:
            util.plot_surface(state, "3d", 16, 1, 0)
        update_func()
        util.Benchmark().flush()

    return state

def main():

    B = util.Benchmark()
    (H, W, I, V) = B.size

    if V not in [1, 2]:
        raise Exception("Unsupported rule-implementation.")
    if B.inputfn:
        if "LIF" in B.inputfn:
            paths = pattern_paths("cells")
            S = world_zeros(H, W, B)
            cells = cells_from_file(B.inputfn)
            insert_cells(S, cells)
        else:
            S = B.load_array()
    else:
        S = world(H, W, B)

    B.start()
    R = play(S, I, V, B.visualize)
    B.stop()

    B.pprint()
    if B.outputfn:
        B.tofile(B.outputfn, {'res': R})
    if B.visualize:
        util.confirm_exit()

if __name__ == "__main__":
    main()

C99 Seq

Error

There are issues with the implementation.

In progress...

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <bp_util.h>

void world(double* state, int height, int width)
{
    for (int h=0; h<height; ++h) {
        for (int w=0; w<width; ++w) {
            state[h*width + w] = (((h < 2) && (h > (height-3))) ||
                                 ((w < 2) && (w > (width-3))));
        }
    }
}

void play(double* state, int height, int width, int iterations, int version)
{
    printf("%p %d %d %d %d\n", state, height, width, iterations, version);
}

int main (int argc, char **argv)
{
    bp_util_type bp = bp_util_create(argc, argv, 4); // Grab arguments
    if (bp.args.has_error) {
        return 1;
    }

    const int height    = bp.args.sizes[0];
    const int width     = bp.args.sizes[1];
    const int iter      = bp.args.sizes[2];
    const int version   = bp.args.sizes[3];

    size_t grid_size = height*width*sizeof(double);
    double *state = (double*)malloc(grid_size);

    world(state, height, width);

    bp.timer_start();
    play(state, height, width, iter, version);
    bp.timer_stop();

    bp.print("gameoflife(c99_seq)");

    free(state);
    return 0;
}

Cpp11 Bxx

#include <iostream>
#include <iomanip>
#include <bxx/bohrium.hpp>
#include <bp_util.h>

static double SURVIVE_LOW  = 2.0;
static double SURVIVE_HIGH = 3.0;
static double SPAWN        = 3.0;

using namespace std;
using namespace bxx;

template <typename T>
void world(int height, int width, multi_array<T>& state)
{
    state = ones<T>(height+2, width+2);
    state[_(2,-3)][_(2,-3)] = (T)0;
}

template <typename T>
void play(multi_array<T>& state, int iterations, int version, int visualize)
{
    multi_array<T> cells, ul, um, ur, ml, mr, ll, lm, lr;
    cells   = state[_(1,-2)][_(1,-2)];
    ul      = state[_(0,-3)][_(0,-3)];
    um      = state[_(0,-3)][_(1,-2)];
    ur      = state[_(0,-3)][_(2,-1)];
    ml      = state[_(1,-2)][_(0,-3)];
    mr      = state[_(1,-2)][_(2,-1)];
    ll      = state[_(2,-1)][_(0,-3)];
    lm      = state[_(2,-1)][_(1,-2)];
    lr      = state[_(2,-1)][_(2,-1)];

    multi_array<T> neighbors;
    if (1 == version) {             //  This is the first implementation of the game rules.
        multi_array<T> live, dead;
        multi_array<bool> stay, spawn;
        for (int i=0; i<iterations; ++i) {
            neighbors   = ul + um + ur + ml + mr + ll + lm + lr;// Count neighbors
            live        = neighbors * cells;                    // Extract live cells neighbors
                                                                // Find cells that stay alive
            stay        = (SURVIVE_LOW <= live) && 
                          (live <= SURVIVE_HIGH);  
            dead        = neighbors * as<T>(cells == (T)0);     // Extract dead cell neighbors
            spawn       = dead == SPAWN;                        // Find spawning cells
            
            cells(as<T>(stay || spawn));                        // Update state

            if (visualize) {
                plot_surface(state, 1, 16, 1, 0);
            }
        }
    } else if (2 == version) {      // This is an optimized version of the game rules
        multi_array<T> c1, c2;
        for (int i=0; i<iterations; ++i) {
            neighbors = ul + um + ur + ml + mr + ll + lm + lr;  // Count neighbors

            c1 = as<T>(neighbors == SURVIVE_LOW);               // Life conditions
            c2 = as<T>(neighbors == SPAWN);

            cells(cells * c1 + c2);                             // Update

            if (visualize) {
                plot_surface(state, 1, 16, 1, 0);
            }
        }
    } else {
        throw std::runtime_error("Unsupported version.");
    }
}

template <typename T>
void bench(bp_util_type& bp, const int W, const int H, const int I, const int V)
{
    multi_array<T> state;                           // Construct matrices
    world(H, W, state);

    Runtime::instance().flush();
    bp.timer_start();                               // Start timer

    play(state, I, V, bp.args.visualize);

    Runtime::instance().flush();
    bp.timer_stop();                                // Stop timer

    bp.print("gameoflife(cpp11_bxx)");				// Print results..
    if (bp.args.verbose) {                          // ..and value.
        cout << fixed << setprecision(10)
             << "Result = " << scalar(sum(state)) << endl;
    }
}

int main(int argc, char* argv[])
{
    bp_util_type bp = bp_util_create(argc, argv, 4);// Grab arguments
    if (bp.args.has_error) {
        return 1;
    }
    const int W = bp.args.sizes[0];
    const int H = bp.args.sizes[1];
    const int I = bp.args.sizes[2];
    const int V = bp.args.sizes[3];

    bench<double>(bp, W, H, I, V);

    return 0;
}

Cpp11 Omp

Error

There are issues with the implementation.

In progress...

#include <iostream>
#include <iomanip>
#include <bp_util.h>

#define HEIGHT 1000
#define WIDTH  1000

static double SURVIVE_LOW  = 2.0;
static double SURVIVE_HIGH = 3.0;
static double SPAWN        = 3.0;

using namespace std;

template <typename T>
void world(T state)
{
    #pragma omp parallel for collapse(2)
    for(int h=0; h<HEIGHT+2; ++h) {
        for(int w=0; w<WIDTH+2; ++w) {
            state[h][w] = (((h<2) and (h>WIDTH-3)) &&
                           ((w<2) and (w>HEIGHT-3)));
        }
    }
}

template <typename T>
void play(T state, int iterations, int version, int visualize)
{
    cout << state << SURVIVE_LOW << SURVIVE_HIGH << SPAWN << endl;
    cout << state << iterations << version << visualize << endl;
    
    T* cells, ul, um, ur, ml, mr, ll, lm, lr;
}

template <typename T>
void bench(bp_util_type& bp, const int I, const int V)
{
    auto state = new T[HEIGHT][WIDTH];              // Construct matrices
    world(state);

    bp.timer_start();                               // Start timer

    play(state, I, V, bp.args.visualize);

    bp.timer_stop();                                // Stop timer

    bp.print("gameoflife(cpp11_omp)");				// Print results..
    if (bp.args.verbose) {                          // ..and value.
        cout << fixed << setprecision(10)
             << "Result = " << endl;
    }
}

int main(int argc, char* argv[])
{
    bp_util_type bp = bp_util_create(argc, argv, 4);// Grab arguments
    if (bp.args.has_error) {
        return 1;
    }
    const int W = bp.args.sizes[0];
    const int H = bp.args.sizes[1];
    const int I = bp.args.sizes[2];
    const int V = bp.args.sizes[3];

    if (HEIGHT != H) {
        cout << "Multidimensional arrays in C11 does not support dynamic size, so it has to be: " << H << "." << endl;
        return 0;
    }
    if (WIDTH != W) {
        cout << "Multidimensional arrays in C11 does not support dynamic size, so it has to be: " << W << "." << endl;
        return 0;
    }

    bench<double>(bp, I, V);

    return 0;
}