Skip to content

Engine overview

Ren's engine is the path from user-facing polynomial or CKKS code to backend work. Use this page as the map before reading the more detailed engine pages.

flowchart LR subgraph Frontend["User-facing layer"] A["CKKS objects"] B["Poly values"] end subgraph IR["Lazy IR"] C["Node DAG<br/>ops, sources, ring/domain metadata"] end subgraph Planning["Planning"] E["Scheduler"] F["Memory planner"] end subgraph Runtime["Runtime"] G["ExecUnits"] H["Python backend"] I["CUDA backend"] end A --> B --> C C --> E --> F --> G G --> H G --> I J["ren.jit"] -. "captures and replays ExecUnits" .-> G

Frontend values

User code starts with Poly values or higher-level CKKS objects. CKKS Plaintext and Ciphertext values contain Poly fields, so CKKS arithmetic eventually enters the same polynomial graph path.

Poly wraps a lazy Node graph. Arithmetic, domain conversions, ring changes, copies, and constants add nodes. They do not launch backend work until a concrete result is needed.

Realization boundary

Realization is the boundary between symbolic graph construction and execution. Calls such as realize(), tolist(), tobytes(), serialization, decryption, and JIT capture force Ren to schedule the requested outputs.

Ren gathers requested outputs under one SINK so shared intermediates can be scheduled together. That is why realizing multiple outputs in one call can produce a better schedule than realizing them one at a time.

Scheduler and memory planner

The scheduler rewrites the Node DAG into scheduled work. It lowers high-level ring operations, inserts required domain conversions, chooses materialization boundaries, turns stores into kernel roots, and records how lazy outputs become realized buffers.

The memory planner then packs temporary buffers whose identity does not matter. Final outputs, allocated buffers, copies, views, and explicit no-opt buffers keep stable identity.

Backends and replay

Backend lowering turns scheduled work into executable units. Compute units run through the selected backend; copies and buffer views lower to their own lightweight execution units.

ren.jit sits at the executable-unit boundary. It records units during a first realization, then later calls with matching Poly specs and top-level scalar arguments bind new input buffers into the captured plan.

Need Page
Ring, RNS, domain, node, constant, and view semantics Polynomial engine
Full realization path from lazy graph to execution Execution pipeline
Scheduler pass order and rewrite tracing Scheduling
Memory planning, executable units, copies, views, and backends Runtime
Capture, cache keys, replay, and failure modes ren.jit replay

Source map