import aner.parallel

// Prepare private.repeat.cluster using repeat_cluster.cluster.example.
// Numerical history stays on its producing workers between pipeline stages.
// A consuming task reads its own global iteration; other workers' rows require
// explicit collection and a new ordinary immutable-input submission.
fn simulate(parameters: List, iteration: Int64, seed: Int64,
            output: OutputRegion<Float32>) -> Unit {
    let input = cast<FrozenArray<Float32>>(parameters.get(0))
    var state = input[iteration % input.len()]
    for step in Range(8) {
        state = state + Float32(0.25)
        output[step, 0] = state
        output[step, 1] = Float32(iteration)
    }
}

fn summarize(parameters: List, iteration: Int64, seed: Int64,
             output: OutputRegion<Float32>) -> Unit {
    let history = cast<OutputResults<Float32>>(parameters.get(0))
    output[0] = history[iteration, 7, 0]
    output[1] = history.value(iteration, 15)
}

let execution = parallel.cluster(config: "private.repeat.cluster")
let input = Array<Float32>(64, Float32(1.0)).snapshot()
let history = parallel.repeat(iterations: 100, task: simulate,
    parameters: List(input), output_shape: List(8, 2),
    execution: execution, seed: 2026, resident: true)
let summary = parallel.repeat(iterations: 100, task: summarize,
    parameters: List(history), output_shape: List(2),
    execution: execution, seed: 2026, resident: true)

print(history.is_resident())  // true
print(history.shape())        // List(100, 8, 2)
print(summary.summary())      // Resident input reuse; no numerical collection

// Transfer only the final compact result. Both resident sources stay reusable.
let local = summary.collect()
var correct = true
for iteration in Range(100) {
    if local[iteration, 0] != Float32(3.0) ||
       local[iteration, 1] != Float32(iteration) { correct = false }
}
print(correct)                // true
print(local.is_resident())    // false
print(local[99, 0])           // 3.0
print(local[99, 1])           // 99.0
