> ⚠️ **Heads up:** The remaining chapters dive into the compiler internals that power Reefer. If you’re here for day-to-day algebra usage, you can safely skip what's ahead or come back later when you’re ready for the gory details.
# Optimization Pipeline
Reefer behaves like a tiny compiler that runs entirely during macro expansion. The input is the Rust module annotated with `#[reefer::algebra]` plus any later calls to the generated `expr!` macro; the output is more Rust code that Rustc can type-check and inline. This chapter walks through the pipeline end to end so you can reason about where behaviours or diagnostics originate.
## Stage 1 - Attribute parsing (front end)
- **Responsibilities:** Decode the attribute payload and gather `basis!` / `shape!` invocations.
- **Key modules:** `src/spec.rs`, `src/algebra.rs`.
- **Inputs & outputs:** The procedural macro receives a module annotated with `#[reefer::algebra(scalar, p, q)]`. It lowers the arguments into `AlgebraAttr`, then aggregates basis and shape declarations into an `AlgebraSpec`.
- **Failure surface:** Any syntactic issue (unknown argument, missing module body, malformed `basis!`) is surfaced immediately via `syn::Error` tied to the offending span.
At the end of this stage we have a structured description of the algebra, no code has been emitted yet, but the spec contains everything downstream passes need.
## Stage 2 - Module elaboration
- **Responsibilities:** Turn the declarative spec into concrete Rust items.
- **Key modules:** `src/algebra.rs` (`build_algebra`), `src/spec.rs` (`ShapeItem`).
- **What happens:**
- Every `basis!` block is recorded and removed from the expanded module.
- Each `shape!` block desugars into a public struct with scalar fields, constructors, and basic trait impls.
- The module receives an `expr!` helper backed by `reefer::build_expr!` so user crates can author symbolic closures.
If anything goes wrong here, such as the module being empty, the macro emits a compile-time error and stops.
## Stage 3 - Alias rewrite
- **Responsibilities:** Normalise user-friendly aliases (`e12`, `rotorA`) to canonical basis masks.
- **Key modules:** `src/build_expr/rewrite.rs`, `src/optimizer.rs` (`Optimizer::alias_mapping`).
- **Inputs & outputs:** When a user invokes `ga::expr!(...)`, the macro captures the closure and builds a `BuildExpr` record. Alias mapping produces a deterministic table from strings to basis masks; the rewrite pass walks the syntax tree, replacing identifiers so the rest of the pipeline only sees canonical names.
- **Failure surface:** Rewriting is designed to be total. If an identifier cannot be mapped, the optimiser records a diagnostic that materialises as a compile-time error attached to the original token.
This stage keeps the symbolic IR free from any naming quirks and enables deterministic simplifications.
## Stage 4 - IR construction
- **Responsibilities:** Interpret the rewritten closure into a Clifford-aware intermediate representation.
- **Key modules:** `src/optimizer/parser.rs`, `src/clifford/multivector.rs`, `src/clifford/mod.rs`.
- **Inputs & outputs:** The parser walks the `syn::Expr` tree, calling algebraic helpers to produce a `SymbolMultivector` (backed by `SynField` coefficients). Each node records the blade mask and the coefficient expression, preserving structure like wedges, inner products, involutions, and exponentials.
- **Failure surface:** If the expression uses unsupported syntax (for example a method call the parser does not recognise), `analysis_error` is set on `BuildExpr`. Expansion continues with a fallback closure so compilation succeeds, but later optimisation steps are skipped.
Think of this stage as turning syntax into a typed, algebra-specific IR; much like translating Rust HIR into MIR.
## Stage 5 - Optimisation passes
- **Responsibilities:** Simplify the multivector and prepare literals.
- **Key modules:** `src/build_expr.rs` (`BuildExpr::optimise`, `constant_shape_literal`), `src/clifford/multivector.rs` (algebraic helpers).
- **Pass highlights:**
- **Zero pruning:** Any blade whose coefficient evaluates to zero is dropped immediately, keeping the representation sparse.
- **Term merging:** Like-grade blades with compatible masks are merged via `accumulate_term`, reducing redundant arithmetic.
Feature flags (`backend_cas`, `backend_egg`) control which scalar backend drives simplification. The default CAS stack works quite well. Egg is an alternative that is being explored but is not yet functional and thus is behind a feature flag.
## Stage 6 - Backend emission
- **Responsibilities:** Convert the final IR back into Rust tokens.
- **Key modules:** `src/build_expr.rs` (`BuildExpr::into_stream`), `src/algebra.rs` (module generation).
- **What happens:**
- Successful constant folding swaps the closure body for a literal shape struct value.
- The closure is rehydrated into tokens using `quote!`, referencing the generated shape/basis types.
- The resulting `TokenStream` is emitted to Rustc, which then performs its normal type checking and optimisation pipeline.
## Cross-cutting behaviours
- **Diagnostics:** Every stage propagates `syn::Error` or human-friendly messages. Front-end issues halt expansion; middle-end failures record context on `BuildExpr` so users receive actionable compiler notes. There are still some `todo!()`s sprinkled in (eg `div` still needs implemented) but every other path should not panic.
- **Testing hooks:** Unit tests in `src/algebra.rs` validate attribute handling, `optimizer::parser::tests` cover IR construction, and integration suites in `tests/smoke.rs` exercise the complete pipeline.
- **Extensibility:** New passes should slot naturally into Stage 5. They operate in place on `SymbolMultivector`.
Understanding these stages makes it easier to diagnose compile-time errors and to extend Reefer with new algebraic tricks. When you add a feature, ask which stage owns the logic, wire a couple tests into the matching module, and verify that the emitted tokens still type-check under both backends.