All examples
Scientific computing

Process independent images on CPU

Apply three blur passes to 64 synthetic grayscale images with one checked parallel.repeat call, private pixel buffers and ordered numeric results.

cpu_image_blur_intro.aner
// Batch image preprocessing on four local CPU workers.
// Synthetic grayscale images; requires at least four admitted CPU slots.
// Run: aner run examples/parallel/cpu_image_blur_intro.aner --max-steps 500000000
import aner.parallel
// Batch preprocessing: one independent grayscale camera image per task.
// The fixture is synthetic: a lighting gradient, a bright central object and
// reproducible sensor texture. Each image varies exposure; no file I/O is timed.
import aner.math

fn process_image(parameters: List, iteration: Int64, seed: Int64) -> List {
    let width = cast<Int64>(parameters.get(0))
    let height = cast<Int64>(parameters.get(1))
    let passes = cast<Int64>(parameters.get(2))
    let pixels = width * height
    var source = Array<Float64>(pixels, 0.0)
    var destination = Array<Float64>(pixels, 0.0)
    let exposure = 0.85 + Float64(iteration % 15) * 0.02

    // Both buffers start with the same boundary pixels. The blur updates only
    // interior pixels, so every pass preserves the original one-pixel border.
    var y = 0
    while y < height {
        var x = 0
        while x < width {
            let texture = Float64((x * 17 + y * 13 + iteration * 3) % 23) - 11.0
            var intensity = 20.0 + 140.0 * Float64(x) / Float64(width - 1) + texture
            if x >= width / 4 && x < 3 * width / 4 &&
               y >= height / 4 && y < 3 * height / 4 {
                intensity = intensity + 65.0
            }
            intensity = intensity * exposure
            if intensity < 0.0 { intensity = 0.0 }
            if intensity > 255.0 { intensity = 255.0 }
            let index = y * width + x
            source.set(index, intensity)
            destination.set(index, intensity)
            x = x + 1
        }
        y = y + 1
    }

    var pass = 0
    while pass < passes {
        y = 1
        while y < height - 1 {
            var x = 1
            while x < width - 1 {
                let index = y * width + x
                let neighborhood = source.get(index - width - 1) + source.get(index - width) +
                    source.get(index - width + 1) + source.get(index - 1) + source.get(index) +
                    source.get(index + 1) + source.get(index + width - 1) +
                    source.get(index + width) + source.get(index + width + 1)
                destination.set(index, neighborhood / 9.0)
                x = x + 1
            }
            y = y + 1
        }
        // Read the old image throughout one pass; swap after the full pass.
        let previous = source
        source = destination
        destination = previous
        pass = pass + 1
    }

    var pixel_sum = 0.0
    var square_sum = 0.0
    var index = 0
    while index < pixels {
        let value = source.get(index)
        pixel_sum = pixel_sum + value
        square_sum = square_sum + value * value
        index = index + 1
    }
    // Deterministic output columns: mean gray level, RMS gray level, center pixel.
    return List(pixel_sum / Float64(pixels), math.sqrt(square_sum / Float64(pixels)),
        source.get((height / 2) * width + width / 2))
}

// Each image gets its own buffers.
let parameters = List(64, 64, 3)
let results = parallel.repeat(
    iterations: 64,
    task: process_image,
    parameters: parameters,
    execution: parallel.local(workers: 4),
    seed: 2026)

print(results.rows())
print(results.mean(column: 0))

Make it your experiment.

With a compatible development runtime installed, save this program as examples/parallel/cpu_image_blur_intro.aner inside a folder for your experiment. Open a terminal in that folder, then check and run the program.

Terminal
aner check examples/parallel/cpu_image_blur_intro.aner
aner run examples/parallel/cpu_image_blur_intro.aner --max-steps 500000000

The aner command must be on your PATH. Follow the installation guide if your terminal cannot find it.

Use a compatible current native Aner development engine with aner.parallel, checked parallel.repeat tasks, SimulationResults and Duration.monotonic. This synthetic CPU image workload needs no input files, image library, accelerator, network, service or credential. The published command sets --max-steps 500000000 as an explicit interpreter budget. Checking processes no images; running prints numeric results and creates no file. This compact program explicitly requests four local workers and requires at least four admitted CPU slots. Use workers: 0 for automatic admitted allocation when adapting the example.

This example uses synthetic images. Measured timings describe the documented workload, runtime build and CPU allocation.

Read the comparison and measurement method
Install Aner