// Native CPU cluster example. Setup: docs/CLUSTER.md.
// Run from the project root with an updated compatible development runtime.
import aner.parallel
import aner.random

let draw_count = 100_000
let block_size = 1_000
let root_seed = 20_261_019
let verify = true

let execution = parallel.cluster(config: "private.repeat.cluster")
// For a local baseline, replace the preceding declaration with this one:
// let execution = parallel.local(workers: 1)

fn count_block(parameters: List, block: Int64, task_seed: Int64) -> List {
    let total = 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 < total {
            let face = random.integer(low: 1, high: 10, seed: seed, draw: draw)
            counts[face - 1] += 1
        }
    }
    let output = List()
    for face in Range(10) { output.append(counts[face]) }
    return output
}

let blocks = integer_div(draw_count + block_size - 1, block_size)
let parameters = List(draw_count, block_size, root_seed)
let results = parallel.repeat(iterations: blocks, task: count_block,
    parameters: parameters, execution: execution, seed: root_seed,
    max_bytes: 67_108_864)

if verify {
    let reference = parallel.repeat(iterations: blocks, task: count_block,
        parameters: parameters, execution: parallel.local(workers: 1),
        seed: root_seed, max_bytes: 67_108_864)
    for block in Range(blocks) {
        for face in Range(10) {
            if results.value(block, face) != reference.value(block, face) {
                print("FAILED: cluster and local block counts differ")
                print(integer_div(1, 0))
            }
        }
    }
    print("Verified: every block and bin matches the one-worker calculation")
}

let histogram = Array<Int64>(10, 0)
for block in Range(blocks) {
    for face in Range(10) { histogram[face] += Int64(results.value(block, face)) }
}
var counted = 0
var encoded = "["
for face in Range(10) {
    counted += histogram[face]
    if face > 0 { encoded = encoded + "," }
    encoded = encoded + String(histogram[face])
}
encoded = encoded + "]"
if counted != draw_count {
    print("FAILED: histogram does not account for every requested draw")
    print(integer_div(1, 0))
}
print("Completed draws: " + String(counted))
print("Counts for outcomes 1 through 10: " + encoded)
print(results.summary())
