# 1. The Pipeline ## Physics statement Deriving Feynman rules for a BSM Lagrangian is a fixed sequence of physics operations, regardless of the model: write down the symmetric Lagrangian, verify it really is symmetric, break the symmetry spontaneously, find the mass eigenstates, and read off the interaction vertices in the mass basis. `feynlag` takes that sequence literally and gives each step its own module. ## The seven stages ```{mermaid} flowchart LR A["1. Declare
fields, params, groups"] --> B["2. Write
Lagrangian terms"] B --> C["3. Check
invariance, hermiticity, dimension"] C --> D["4. Break
VEV shift + tadpoles"] D --> E["5. Diagonalize
mass matrices -> rotations"] E --> F["6. Extract
vertices"] F --> G["7. Export
LaTeX / UFO"] ``` | # | Stage | Module(s) | Manual chapter | |---|-------|-----------|-----------------| | 1 | Declare | `parameters.py`, `fields.py`, `groups/gauge.py`, `groups/discrete.py` | {doc}`declaration` | | 2 | Write | `lagrangian.py`, `operators.py` | {doc}`lagrangian` | | 3 | Check | `invariance.py` | {doc}`invariance` | | 4 | Break | `vacuum/ewsb.py`, `vacuum/tadpoles.py` | {doc}`ssb` | | 4b| Masses | `vacuum/masses.py` | {doc}`masses` | | 5 | Diagonalize | `vacuum/diagonalize.py` | {doc}`diagonalization` | | 6 | Extract | `vertices/extract.py`, `vertices/bilinear.py`, `vertices/yangmills.py`, `vertices/vertex.py` | {doc}`vertices` | | 7 | Export | `export/latex.py`, `export/ufo/` | {doc}`export` | `dirac.py` (Clifford algebra) and `verify/checks.py` (the dual symbolic+numeric verification toolkit, {doc}`verification`) are used across every stage rather than owning one. Sitting *before* stage 2 is an optional exploration-branch helper, {doc}`suggest` — instead of hand-writing the Lagrangian, it enumerates every gauge/discrete-invariant term the declared field content admits, using the stage-3 invariance machinery as an oracle. ## Orchestration: `Model` is a lazy pipeline Every stage above is exposed as a method or cached property on {class}`~feynlag.lagrangian.Model`, and **nothing is computed at construction or at import time**. `Model.__init__` just stores its arguments; `Model.vacuum`, `Model.tadpoles()`, `Model.mass_matrix(...)`, `Model.physical_lagrangian()` and `Model.feynman_rules(...)` each compute on first call and memoize in `Model._cache`, a plain dict cleared by `Model._invalidate()`. The two state-mutating calls — `Model.solve_tadpoles` and `Model.rotate` — both call `_invalidate()` before returning, so any later `physical_lagrangian()` call recomputes downstream of the new tadpole solution or rotation rather than serving a stale memoized result. This is a deliberate reaction to a **known flaw in the DLRSM1 reference implementation** `feynlag` was built from: DLRSM1 computed pipeline results as a side effect of module import, which made partial or reordered pipelines silently return inconsistent state. Laziness plus explicit invalidation means the `Model` object can always be inspected mid-pipeline (e.g. call `check_invariance()` before ever touching EWSB) with no risk of a stale cache masking a later change. ```python m = Model("SM", ...) m.check_invariance() # stage 3, no caching needed m.solve_tadpoles([mu2]) # stage 4 -- invalidates any cached # physical_lagrangian m.mass_matrix([...]) # stage 4b, computed on demand m.rotate(weinberg_rotation) # stage 5 -- invalidates again m.feynman_rules([...]) # stage 6, built from the now-current # physical_lagrangian ``` ## Two representations, two tracks Bosonic fields (scalars, gauge bosons) are plain commuting `sympy.Symbol`s. Fermion fields are `sympy.IndexedBase`-typed (one flavor-indexed component per gauge component) and every fermion bilinear `psibar Gamma psi` is wrapped in the opaque `Bilinear(bar, gamma, field)` atom, which never enters the commuting-symbol machinery. This split runs through every stage from declaration (`fields.py`) to extraction (`vertices/extract.py` vs. `vertices/bilinear.py`) and is covered in detail in {doc}`declaration` and {doc}`vertices`. ## Validation There is no single test for "the pipeline" -- `test_scalar_pipeline_sm.py` (`test_lazy_pipeline_no_state_leak`) specifically pins the laziness/cache invalidation contract described above.