henad-models 0.3.0

Example models for Henad, a parallel agent-based modelling engine.
Documentation
// Refills the grid at the density the model was built with, one invocation per packed word.
//
// Draws per cell as `GameOfLifeModel::init` does, but from `pcg_hash` over the cell index rather
// than a walked xorshift64 stream. An action is not part of the tick-0 oracle, so the two backends
// need not produce the same grid here.

#import henad::rng::{pcg_hash, below}

struct Params {
    width: u32,
    height: u32,
    threshold: u32,
    seed: u32,
}

@group(0) @binding(0) var<storage, read_write> state_out: array<u32>;
@group(0) @binding(1) var<uniform> params: Params;

@compute
@workgroup_size(16, 16)
fn main(@builtin(global_invocation_id) global_id: vec3<u32>) {
    let width = params.width;
    let stride = (width + 31u) / 32u;
    let word = global_id.x;
    let y = global_id.y;
    if word >= stride || y >= params.height {
        return;
    }

    // Trailing bits of a ragged last word hold no cell and must stay zero, so the loop stops at
    // the last real cell rather than filling all 32 bits.
    let first = word * 32u;
    let cells_here = min(width - first, 32u);
    var bits = 0u;
    for (var j = 0u; j < cells_here; j = j + 1u) {
        // Each cell has its own draw. Two cells sharing one draw would correlate.
        let draw = pcg_hash(params.seed ^ pcg_hash(y * width + first + j));
        if below(draw, params.threshold) {
            bits = bits | (1u << j);
        }
    }
    state_out[y * stride + word] = bits;
}