Skip to main content

rlx/
lib.rs

1// RLX — versatile ML compiler + runtime.
2// Copyright (C) 2026 Eugene Hauptmann, Nataliya Kosmyna.
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, version 3.
7//
8// This program is distributed in the hope that it will be useful,
9// but WITHOUT ANY WARRANTY; without even the implied warranty of
10// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11// GNU General Public License for more details.
12//
13// You should have received a copy of the GNU General Public License
14// along with this program. If not, see <https://www.gnu.org/licenses/>.
15
16//! # RLX
17//!
18//! A small ML compiler + runtime for transformer inference and training,
19//! with a JAX-shaped IR + autodiff + transforms (`jvp`, `hvp`, `vmap`)
20//! on top of CPU / Apple Silicon (Metal / MLX) / NVIDIA (CUDA) / AMD
21//! (ROCm) / Google TPU / cross-platform GPU (wgpu) / FPGA / Cortex-M
22//! backends.
23//!
24//! This is the **prelude crate** — pulls in the framework-level
25//! workspace members and re-exports the common types so a one-line
26//! `use rlx::prelude::*;` covers most usage.
27//!
28//! ## Three usage patterns
29//!
30//! ### 1. Build + run a graph by hand
31//!
32//! ```ignore
33//! use rlx::prelude::*;
34//!
35//! let mut g = Graph::new("hello");
36//! let x = g.input("x", Shape::new(&[1, 4], DType::F32));
37//! let w = g.param("w", Shape::new(&[4, 2], DType::F32));
38//! let y = g.matmul(x, w, Shape::new(&[1, 2], DType::F32));
39//! let scaled = g.mul(x, g.constant(2.0, DType::F32)); // GraphExt literal
40//! g.set_outputs(vec![y, scaled]);
41//!
42//! let mut compiled = Session::new(Device::Cpu).compile(g);
43//! compiled.set_param("w", &[1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0]);
44//! let out = compiled.run(&[("x", &[1.0, 2.0, 3.0, 4.0])]);
45//! ```
46//!
47//! ## Module map
48//!
49//! Every workspace crate is reachable as a module on `rlx`:
50//!
51//! | path            | crate           | what                                                                            |
52//! |-----------------|-----------------|---------------------------------------------------------------------------------|
53//! | `rlx::ir`       | `rlx-ir`        | IR types, ops, graph builder                                                    |
54//! | `rlx::opt`      | `rlx-opt`       | facade: `rlx-fusion` + `rlx-autodiff` + `rlx-compile`                           |
55//! | `rlx::driver`   | `rlx-driver`    | `Device` enum, registries                                                       |
56//! | `rlx::runtime`  | `rlx-runtime`   | `Session`, `CompiledGraph`                                                      |
57//! | `rlx::macros`   | `rlx-macros`    | `#[rlx_model]` proc macro                                                       |
58//! | `rlx::gguf`     | `rlx-gguf`      | GGUF parser + dequant *(feature `gguf`)*                                        |
59//! | `rlx::onnx`     | `rlx-onnx`      | ONNX Runtime `.onnx` inference *(feature `onnx`)*                               |
60//! | `rlx::bench`    | `rlx-bench`     | benchmark harness *(feature `bench`)*                                           |
61//! | `rlx::sparse`   | `rlx-sparse`    | downstream: sparse linalg *(feature `sparse`)*                                  |
62//! | `rlx::splat`    | `rlx-splat`     | 3D Gaussian splatting *(feature `splat`)* — `register()`, decomposed IR ops      |
63//! | `rlx::linalg`   | `rlx-linalg`    | downstream: dense linalg via LAPACK *(feature `linalg`)*                        |
64//! | `rlx::cortexm`  | `rlx-cortexm`   | INT8 ARMv7E-M kernels *(feature `cortexm`)* — no `Backend` impl, kernels only   |
65//! | `rlx::fpga`     | `rlx-fpga`      | IR → SystemVerilog datapath synthesis *(feature `fpga`)* — no `Backend` impl    |
66//!
67//! ## Convenience namespaces
68//!
69//! Grouped re-exports for related concerns — use these when you want
70//! one focused subset without star-importing the whole prelude:
71//!
72//! | namespace            | what                                                                          |
73//! |----------------------|-------------------------------------------------------------------------------|
74//! | [`rlx::quant`]       | `QuantScheme`, `QuantMap` (IR quantization metadata)                          |
75//! | [`rlx::ops`]         | `Activation`, `BinaryOp`, `CmpOp`, `MaskKind`, `ChainStep`, `ChainOperand`    |
76//! | [`rlx::autodiff`]    | `jvp`, `hvp`, `vmap` + the autodiff entry points                              |
77//! | [`rlx::prelude`]     | star-import target covering the 95% case                                      |
78//!
79//! ## Backend feature gates
80//!
81//! Pick the ones that match your hardware. Multiple backends can be
82//! enabled at once; the runtime picks one per `Session`.
83//!
84//! | feature             | backend                              | platform                  |
85//! |---------------------|--------------------------------------|---------------------------|
86//! | `cpu` *(default)*   | NEON / AVX + Accelerate / OpenBLAS   | every host                |
87//! | `metal`             | Metal Performance Shaders + MSL      | macOS (Apple Silicon)     |
88//! | `mlx`               | Apple MLX (vendored)                 | macOS (Apple Silicon)     |
89//! | `gpu`               | wgpu (Vulkan / DX12 / WebGPU / Metal)| cross-platform            |
90//! | `cuda`              | cuBLAS / cuDNN / NVRTC               | Linux / Windows + NVIDIA  |
91//! | `rocm`              | hipBLAS / MIOpen                     | Linux + AMD               |
92//! | `tpu`               | libtpu PJRT plugin                   | Linux + GCP TPU           |
93//! | `blas-accelerate`   | macOS Accelerate                     | macOS                     |
94//! | `blas-mkl`          | Intel MKL                            | Intel / AMD CPUs          |
95//! | `blas-openblas`     | OpenBLAS                             | cross-platform CPU        |
96//!
97//! ## Convenience aggregates
98//!
99//! Single-flag setups for common platforms. Each composes the
100//! fragments most users want for that target.
101//!
102//! | feature           | expands to                                  |
103//! |-------------------|---------------------------------------------|
104//! | `apple-silicon`   | `cpu` + `metal` + `blas-accelerate`         |
105//! | `nvidia`          | `cpu` + `cuda`                              |
106//! | `edge`            | `cpu` + `cortexm`                           |
107//! | `all-cpu`         | `cpu` + `gguf` + `linalg`                   |
108//!
109//! `mlx` and `rocm` aren't in any aggregate because their crates
110//! aren't on crates.io (vendor-bundled submodule / workspace-
111//! relative kernel sources). To opt in, depend on the workspace via
112//! git and add the feature explicitly:
113//!
114//! ```toml
115//! rlx = { git = "https://github.com/MIT-RLX/rlx", features = ["apple-silicon", "mlx"] }
116//! ```
117
118#![doc(html_root_url = "https://docs.rs/rlx/0.2.1")]
119
120// ── Module re-exports ───────────────────────────────────────────
121
122/// Tensor IR — types, shapes, ops, graph builder.
123/// See [`rlx-ir`](https://crates.io/crates/rlx-ir).
124pub use rlx_ir as ir;
125
126/// Symbolic tensor DSL — operator-overloaded graph building.
127/// Available with the `tensor` feature (on by default).
128#[cfg(feature = "tensor")]
129pub use rlx_tensor as tensor;
130
131/// Graph rewrites + autodiff + vmap.
132/// See [`rlx-opt`](https://crates.io/crates/rlx-opt).
133pub use rlx_opt as opt;
134
135/// Device enum + cross-cutting types.
136/// See [`rlx-driver`](https://crates.io/crates/rlx-driver).
137pub use rlx_driver as driver;
138
139/// User-facing `Session` / `CompiledGraph`.
140/// See [`rlx-runtime`](https://crates.io/crates/rlx-runtime).
141pub use rlx_runtime as runtime;
142
143/// Procedural macros (`#[rlx_model]`, `pipeline_schedule!`).
144/// See [`rlx-macros`](https://crates.io/crates/rlx-macros).
145pub use rlx_macros as macros;
146
147#[cfg(feature = "gguf")]
148/// GGUF v1 / v2 / v3 parser + dequant + quant encoders + writer.
149/// See [`rlx-gguf`](https://crates.io/crates/rlx-gguf).
150pub use rlx_gguf as gguf;
151
152#[cfg(feature = "gguf-convert")]
153/// safetensors / ONNX → GGUF conversion with per-tensor quantization.
154/// Useful at first inference load to shrink memory + disk footprint.
155/// See [`rlx-gguf-convert`](https://crates.io/crates/rlx-gguf-convert).
156pub use rlx_gguf_convert as gguf_convert;
157
158#[cfg(feature = "bench")]
159/// Uniform benchmark harness.
160/// See [`rlx-bench`](https://crates.io/crates/rlx-bench).
161pub use rlx_bench as bench;
162
163#[cfg(feature = "sparse")]
164/// Downstream: sparse linear algebra (custom-op scaffold).
165/// See [`rlx-sparse`](https://crates.io/crates/rlx-sparse).
166pub use rlx_sparse as sparse;
167
168#[cfg(feature = "linalg")]
169/// Downstream: dense linalg via LAPACK (custom-op scaffold).
170/// See [`rlx-linalg`](https://crates.io/crates/rlx-linalg).
171pub use rlx_linalg as linalg;
172
173#[cfg(feature = "splat")]
174/// Downstream: 3D Gaussian splatting (CPU reference render custom op).
175/// See [`rlx-splat`](https://crates.io/crates/rlx-splat).
176pub use rlx_splat as splat;
177
178#[cfg(feature = "umap")]
179/// Downstream: UMAP / fast-umap custom ops (k-NN from pairwise distances).
180pub use rlx_umap as umap;
181
182#[cfg(feature = "optim")]
183/// Training-step optimizers (Adam, AdamW, NAdamW, RAdam, QHAdamW,
184/// LAMB, Adafactor, Lion, SOAP, Kron-PSGD, Muon, Sophia, MARS). See
185/// [`rlx-optim`](https://crates.io/crates/rlx-optim).
186pub use rlx_optim as optim;
187
188#[cfg(feature = "cortexm")]
189/// `no_std` ARMv7E-M INT8 kernels (Cortex-M4F / M7). Doesn't
190/// implement `Backend` — call the kernels (`dense`, `conv2d`,
191/// `maxpool`, `relu`, `argmax`) directly.
192/// See [`rlx-cortexm`](https://crates.io/crates/rlx-cortexm).
193pub use rlx_cortexm as cortexm;
194
195#[cfg(feature = "fpga")]
196/// IR → SystemVerilog datapath synthesis. Doesn't implement
197/// `Backend` — synth + P&R takes minutes; the entry point is
198/// `rlx::fpga::codegen::emit_model`.
199/// See [`rlx-fpga`](https://crates.io/crates/rlx-fpga).
200pub use rlx_fpga as fpga;
201
202#[cfg(feature = "onnx")]
203/// ONNX Runtime inference for `.onnx` files on RLX [`Device`] backends.
204/// See [`rlx-onnx`](https://crates.io/crates/rlx-onnx).
205pub use rlx_onnx as onnx;
206
207// ── Error types ─────────────────────────────────────────────────
208//
209// The whole stack returns `anyhow::Result<T>` — `rlx::Result` /
210// `rlx::Error` make that the obvious choice for downstream code
211// without forcing an explicit `anyhow` dep at the call site.
212
213/// Crate-wide result type — alias of `anyhow::Result<T>`. Use this
214/// in `main()` and library boundaries.
215pub type Result<T, E = anyhow::Error> = std::result::Result<T, E>;
216
217/// Crate-wide error type — alias of `anyhow::Error`.
218pub type Error = anyhow::Error;
219
220// ── Flat re-exports for the most-common types ───────────────────
221//
222// These cover ~90% of user code: build a graph with rlx_ir types,
223// compile + run it through Session, then read back outputs. Less
224// common types stay reachable via the module re-exports above.
225
226pub use rlx_driver::Device;
227pub use rlx_ir::quant::QuantScheme;
228pub use rlx_ir::{
229    DType, Element, FusionPolicy, Graph, GraphExt, GraphModule, GraphStage, HirModule, HirOp,
230    LirModule, MirModule, Node, NodeId, Op, OpKind, Shape, Tick, scalar_constant_bytes,
231};
232pub use rlx_ir::{
233    NodeOrigin, inspect_graph, inspect_graph_diff, inspect_hir, inspect_hir_stats, inspect_lir,
234    inspect_mir, inspect_mir_diff, inspect_mir_stats, node_label,
235};
236pub use rlx_opt::{
237    CalibrationRecord, CompilePipeline, CompileResult, FusionOptions, FusionReport, FusionTarget,
238    MissReason, MissedFusion, Pass, PipelineInspect, Precision, PrecisionPolicy, fusion_passes,
239    fusion_passes_for_supported, hvp, inspect_pipeline, jvp, maybe_dump_pipeline,
240    supported_for_target, supports_op, vmap,
241};
242pub use rlx_runtime::{
243    BackendsManifest, CompiledGraph, DeviceBenchResult, DeviceCandidate, DeviceFallbackError,
244    DevicePickStrategy, DevicePolicy, DeviceRouter, FlexibleSession, GraphDevices,
245    ParseDeviceError, Session, available_devices, benchmark_devices, device_chain_from_env,
246    device_from_env, device_label, device_report, devices_for, devices_for_with_policy,
247    fastest_device, fastest_device_for, graph_param_names, is_available, parse_device,
248    parse_device_list, resolve_device, resolve_device_chain, run_with_fallback,
249};
250
251// ── Grouped namespaces ──────────────────────────────────────────
252
253/// Quantization metadata — schemes the IR carries per-tensor, plus
254/// the `QuantMap` graph-level annotation. Use these when wiring
255/// `Op::DequantMatMul` or attaching quant info to your own ops.
256///
257/// ```ignore
258/// use rlx::quant::QuantScheme;
259///
260/// let scheme = QuantScheme::GgufQ4K;   // GGUF Q4_K super-block
261/// assert!(scheme.is_gguf());
262/// assert_eq!(scheme.gguf_block_bytes(), 144);
263/// ```
264pub mod quant {
265    pub use rlx_ir::quant::{QuantMap, QuantScheme};
266}
267
268/// Op-builder helper enums — the variants the graph builder methods
269/// (`g.binary`, `g.compare`, `g.activation`, `g.attention_kind`, …)
270/// take as their first argument, plus the fused-chain primitives
271/// used by `Op::ElementwiseRegion`.
272///
273/// ```ignore
274/// use rlx::{Graph, GraphExt, Shape, DType};
275/// use rlx::ops::{Activation, BinaryOp};
276///
277/// let mut g = Graph::new("ex");
278/// let x = g.input("x", Shape::new(&[4], DType::F32));
279/// let y = g.input("y", Shape::new(&[4], DType::F32));
280/// let s = g.binary(BinaryOp::Add, x, y, Shape::new(&[4], DType::F32));
281/// let r = g.activation(Activation::Silu, s, Shape::new(&[4], DType::F32));
282/// let scaled = g.mul(x, g.constant(2.0, DType::F32));
283/// g.set_outputs(vec![r, scaled]);
284/// ```
285pub mod ops {
286    pub use rlx_ir::op::{Activation, BinaryOp, ChainOperand, ChainStep, CmpOp, MaskKind};
287}
288
289/// Autodiff + transforms — re-exports the public entry points from
290/// `rlx_opt`. Use these when computing gradients or doing
291/// `vmap` / `jvp` / `hvp` over a graph.
292///
293/// ```ignore
294/// use rlx::autodiff::{jvp, vmap};
295/// ```
296pub mod autodiff {
297    pub use rlx_opt::{hvp, jvp, vmap};
298}
299
300// ── Prelude — single `use rlx::prelude::*;` for the 95% case ────
301//
302// Includes the graph-building / runtime types, common IR helper
303// enums, and autodiff entry points. Skips less-common
304// types — those stay reachable via the module re-exports above.
305
306/// Star-import target covering the 95% case:
307///
308/// ```ignore
309/// use rlx::prelude::*;
310///
311/// // graph building
312/// let mut g = Graph::new("ex");
313/// let x = g.input("x", Shape::new(&[1, 4], DType::F32));
314/// let y = g.mul(x, g.constant(2.0, DType::F32));
315/// g.set_outputs(vec![y]);
316///
317/// // compile + run (auto-pick fastest, or choose any compatible backend)
318/// let mut runner = GraphDevices::new(g);
319/// let device = runner.fastest(); // or pick from runner.devices()
320/// let out = runner.run(device, &[("x", &[1.0; 4])]).unwrap();
321///
322/// ```
323pub mod prelude {
324    // Tensor DSL (expression-style graph building) — feature `tensor`.
325    #[cfg(feature = "tensor")]
326    pub use crate::tensor::{GraphScope, Tensor, ax, graph, graph_with, ix, rg, s, shape, tail};
327    // Core graph + runtime
328    pub use crate::{
329        BackendsManifest, CompiledGraph, DType, Device, DeviceBenchResult, DeviceCandidate,
330        DeviceFallbackError, DevicePickStrategy, DevicePolicy, DeviceRouter, Element, Error,
331        FlexibleSession, Graph, GraphDevices, GraphExt, GraphModule, GraphStage, Node, NodeId, Op,
332        OpKind, ParseDeviceError, Result, Session, Shape, Tick, available_devices,
333        benchmark_devices, device_chain_from_env, device_from_env, device_label, device_report,
334        devices_for, devices_for_with_policy, fastest_device, fastest_device_for,
335        graph_param_names, is_available, parse_device, parse_device_list, resolve_device,
336        resolve_device_chain, run_with_fallback, scalar_constant_bytes,
337    };
338    // IR builder helpers
339    pub use crate::ops::{Activation, BinaryOp, CmpOp, MaskKind};
340    // Quant metadata
341    pub use crate::QuantScheme;
342    // Autodiff
343    pub use crate::{hvp, jvp, vmap};
344    // Optimizer types — useful when configuring passes / precision
345    pub use crate::ir::env::{self, RlxEnv, RuntimeOverrides, flag, set, unset, var};
346    pub use crate::{CalibrationRecord, Pass, Precision, PrecisionPolicy};
347
348    // 3D Gaussian splatting (`rlx-splat` — call `register()` once per process)
349    #[cfg(feature = "splat")]
350    pub use crate::splat::{
351        gaussian_splat_render_common_ir, gaussian_splat_render_decomposed,
352        gaussian_splat_render_reference, register,
353    };
354    #[cfg(feature = "splat")]
355    pub use rlx_ir::ops::splat::{
356        GaussianSplatInputs, GaussianSplatRenderParams, gaussian_splat_prep_packed_len,
357        gaussian_splat_tile_count,
358    };
359    #[cfg(feature = "splat")]
360    pub use rlx_splat::prep_layout::{prep_packed_len, tile_count};
361}
362
363/// Register optional custom backends and companion custom-op crates.
364///
365/// Builtins (CPU, Metal, CUDA, …) register automatically on first
366/// [`Session`] use. Call this at process startup when you ship extra
367/// backends or custom-op libraries:
368///
369/// ```ignore
370/// rlx::register_backends! {
371///     splat => rlx::splat::register,
372///     sparse => rlx::sparse::register,
373/// }
374/// ```
375#[macro_export]
376macro_rules! register_backends {
377    () => {};
378    ( $( $name:ident => $register:path ),* $(,)? ) => {
379        $( $register(); )*
380    };
381}