Skip to content

Architecture

Lucen is a single pipeline from a comment pragma to parallel execution. This page is the map; the engineering guide walks the code, and the technical specification is the authority on every semantic.

The compile-time pipeline

Activation installs an import hook. When a marked module is imported, the hook runs it through five stages, each producing a written decision record before the next begins.

flowchart LR
    src[Marked source] --> scanner
    scanner[Scanner\nfind pragmas, parse clauses] --> rewriter
    rewriter[Rewriter\nclassify every name] --> analyzer
    analyzer[Analyzer\nrecognize dependency shape] --> selector
    selector[Selector\nroute to backend or sequential] --> codegen
    codegen[Codegen\nchunk function + sequential twin] --> rewritten[Rewritten module]

The rewriter classifies each name in the block as loop-local, read-only, reduction accumulator, indexed write, or cross-iteration read. The analyzer recognizes dependency shapes analytically (self-contained, monotonic offset, recognized DAG). The selector routes each block, and codegen emits two functions per block: a chunk function for workers and a sequential twin that is also the fallback path, so the sequential behavior is the original loop by construction.

The runtime dispatch flow

At call time, dispatch decides whether parallelism pays, runs chunks over a persistent pool, and commits their results in order under an audit.

flowchart TD
    call[Marked loop reached] --> probe[Probe chunk 0\nas a sequential prefix]
    probe --> gate{Projected parallel\nbeats sequential?}
    gate -- no --> seq[Finish sequentially\nreport UNPROFITABLE]
    gate -- yes --> route{Backend}
    route -- map/reduction --> process[Process workers]
    route -- by-reference / FT heavy --> thread[Thread workers]
    route -- recognized DAG --> wavefront[Level-synchronous wavefront]
    process --> audit
    thread --> audit
    wavefront --> audit[Write-set audit\nat join]
    audit -- disjoint --> commit[Commit slabs in chunk order\nfold reductions in element order]
    audit -- conflict --> fallback[Discard, re-run sequentially]
    commit --> result[Bit-identical result]
    fallback --> result

Every path ends at a result bit-identical to sequential Python. A conflict, a serialization failure, or anything unprovable discards the parallel attempt and re-runs the block as the sequential twin; the two concurrency protocols behind the audit and the wavefront are model-checked.

Backend selection

Selection is static and interpreter-independent. Maps and reductions run on the process backend on both locked and free-threaded builds, because shared-object reference counting makes threads lose on shared-container workloads even without a global lock (ADR 0013). The thread backend serves by-reference blocks and free-threaded heavy compute; the recognized-DAG wavefront runs sequentially by default and in parallel only under an explicit backend=thread on a free-threaded build.

The optional native core

Two orchestration loops, the write-set audit and the reduction fold, run in a Rust core when the compiled extension is present. Every native operation has an identical-semantics pure-Python twin, so the library is correct with the extension absent, and the two paths are proven to agree.