// Case E: cluster native RNG. Run from the project root.
// For warmed, balanced repeated measurements and exact parity, use the benchmark.
import aner.parallel
import aner.random

// The root seed and global draw index select each observation independently
// of task scheduling. Retain ten counts per block, without transferring draws.
fn count_block(parameters: List, block: Int64, task_seed: Int64) -> List {
    let count = cast<Int64>(parameters.get(0))
    let size = cast<Int64>(parameters.get(1))
    let seed = cast<Int64>(parameters.get(2))
    let counts = Array<Int64>(10, 0)
    for offset in Range(size) {
        let draw = block * size + offset
        if draw < count {
            let choice = random.integer(low: 1, high: 10, seed: seed, draw: draw)
            counts[choice - 1] += 1
        }
    }
    let output = List()
    for face in Range(10) { output.append(counts[face]) }
    return output
}

let draw_count = 100_000_003
let block_size = 10_000
let root_seed = 20_261_019
let blocks = integer_div(draw_count + block_size - 1, block_size)
let execution = parallel.cluster(config: "config/cluster.private")

let started = Duration.monotonic()
let results = parallel.repeat(iterations: blocks, task: count_block,
    parameters: List(draw_count, block_size, root_seed), execution: execution,
    seed: root_seed, max_bytes: 67_108_864)
let elapsed_ns = Duration.monotonic().subtract(started).nanoseconds()

let histogram = Array<Int64>(10, 0)
for block in Range(blocks) {
    for face in Range(10) { histogram[face] += Int64(results.value(block, face)) }
}
var total = 0
for face in Range(10) { total += histogram[face] }
if total != draw_count { print(integer_div(1, 0)) }
print("Case E: cluster; seed=" + String(root_seed) + "; engine=" + random.engine())
print("repeat_elapsed_ns=" + String(elapsed_ns))
print(histogram)
print(results.summary())
