1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//! Racah–Wigner calculus for compact Lie groups: irreducible representations,
//! Clebsch–Gordan coefficients, and recoupling coefficients (3j / 6j / F / R)
//! for SU(2), SU(N), SO(N), Spin(N) and Sp(2N).
//!
//! Coefficients for any admissible labels are computed on demand — there is no
//! precomputed table and no generation-time label cut. Pure representation
//! mathematics: no fusion-category trait vocabulary, no sector identity types,
//! no tensor-network concepts. Consumers translate the numbers into their own
//! categorical interfaces.
//!
//! # Quick start
//!
//! Exact SU(2) recoupling needs no features. Spins are doubled (`dj = 2j`), so
//! `2` means spin 1; a non-admissible label set returns exact zero, never an
//! error. Here `{1 1 1; 1 1 1} = 1/6`:
//!
//! ```
//! use racah::wigner_6j;
//!
//! let sixj = wigner_6j(2, 2, 2, 2, 2, 2);
//! assert!((sixj.to_f64() - 1.0 / 6.0).abs() < 1e-14);
//! ```
//!
//! # Where to look
//!
//! | You want | Go to |
//! |---|---|
//! | SU(2): 3j, 6j, CG, F, R, Frobenius–Schur — exact, no feature flag | [`su2`] (re-exported at the crate root) |
//! | SU(N), SU(N)/Z_k, PSU(N) — Gelfand–Tsetlin construction | [`sun`] (`cgc-gen`) |
//! | SO(N), Spin(N), Sp(2r) — generator bootstrap, B/C/D series | [`bcd`] (`cgc-gen`) |
//! | Which highest weights a global form admits | [`group`] |
//! | Cache ceilings, budgets, statistics | [`cache`] |
//!
//! # Layers
//!
//! - **base** (no feature): exact SU(2) — closed-form 3j/6j/CGC in
//! big-rational arithmetic with a single final rounding to floating point.
//! - **`cgc-gen`**: runtime coefficient generation for SU(N) (Gelfand–Tsetlin
//! construction), and SO(N)/Sp(2N) (defining-representation seeds plus a
//! family-generic decomposition loop). Dense factorizations and the CGC
//! contractions producing F/R route through the Tenferro traced surface at a
//! single seam, currently executed on the CPU faer backend; no hand-rolled
//! kernels, and no public backend-selection API yet.
//!
//! The boundary is mathematical, not organizational: SU(2) has closed forms and
//! needs no matrix computation, so a consumer needing only SU(2) never pulls a
//! linear-algebra stack.
//!
//! # Exactness contract
//!
//! Combinatorial structure and discrete data are exact; gauge fixing is a
//! deterministic function of the subspace; floating-point stages are
//! verification-gated and versioned. Concretely: labels, dimensions, duals,
//! Frobenius–Schur indicators and fusion multiplicities are exact integer or
//! rational arithmetic, while generated CGC / F / R *values* are `f64` that
//! passed orthogonality, unitarity and pentagon/hexagon gates at generation
//! time. A gate violation is a typed error, never a silently degraded number.
//!
//! # Provider contract
//!
//! Each family publishes an opaque **authority fingerprint** naming the
//! convention set its coefficients are computed in
//! ([`su2_authority_fingerprint`], [`sun::sun_authority_fingerprint`],
//! [`bcd::bcd_authority_fingerprint`]). Persist the bytes next to anything you
//! derive from these coefficients and compare by equality on load; never parse
//! them. The base SU(2) provider adds a checked representation surface
//! ([`su2::Su2Irrep`] and the `*_checked` coefficient functions) and a cache
//! resource contract ([`cache::base_cache_stats`],
//! [`cache::BASE_CACHE_MAX_BYTES`], [`cache::reset`]). The
//! [User Guide][guide-resources] carries the prose.
//!
//! # Documentation
//!
//! - [User Guide] — task-oriented: pick a group, build irreps, fuse, get CGC,
//! get F/R, bound the caches. Start here if you are new.
//! - [`docs/theory.pdf`] — a self-contained note on the objects this API
//! computes (irreps, fusion multiplicities, CGC and gauge, recoupling, the
//! two constructions, the exactness contract).
//! - [`docs/gauge.md`] / [`docs/gauge_soN.md`] — the frozen normative gauge
//! specifications. Reference documents, not tutorials.
//! - [`docs/references.md`] — porting provenance (`file:symbol`-level) and the
//! verified bibliography.
//!
//! [User Guide]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/user-guide/README.md
//! [guide-resources]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/user-guide/resources.md
//! [`docs/theory.pdf`]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/theory.pdf
//! [`docs/references.md`]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/references.md
//! [`docs/gauge.md`]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/gauge.md
//! [`docs/gauge_soN.md`]: https://github.com/Ryo-wtnb11/racah/blob/main/docs/gauge_soN.md
// The audit harness measures only allocations routed through Rust's System
// allocator. Keeping it test-only avoids changing the library allocator
// contract or attributing C/backend allocations to Racah.
static TEST_ALLOCATOR: TrackingAllocator = TrackingAllocator;
/// Which highest weights are genuine representations of *which* group:
/// [`group::RootSystem`], [`group::GlobalForm`], [`group::CenterSubgroup`],
/// [`group::GroupId`] and the central-character admissibility predicate
/// [`group::GroupId::admits`].
///
/// Naming the Lie algebra does not name the group — `so(N)` belongs to both
/// `Spin(N)` and `SO(N)`, `su(N)` to `SU(N)`, every `SU(N)/Z_k` and `PSU(N)` —
/// and the groups differ in exactly one respect: which dominant weights they
/// admit. A global form deletes irreps; it never changes a coefficient value.
/// Pure integer arithmetic, no feature gate.
/// Exact SU(2) recoupling: doubled-spin labels (`dj = 2j`), the infallible
/// closed-form Wigner 3j/6j, Clebsch–Gordan, F/R/Frobenius–Schur functions
/// (exact zero for an inadmissible tuple), and an additive *checked* surface
/// ([`su2::Su2Irrep`], [`su2::wigner_6j_checked`], …) that returns a typed
/// error instead of requiring consumers to infer validity from a zero
/// coefficient. Its items are re-exported at the crate root.
/// SU(N), `SU(N)/Z_k` and `PSU(N)`: irreps from Dynkin labels, exact Weyl
/// dimensions, duals, Littlewood–Richardson products, and the Clebsch–Gordan /
/// F / R coefficients built by the Gelfand–Tsetlin construction.
/// Compilation-gated behind `cgc-gen`.
/// SO(N), Spin(N) and Sp(2r) — the B, C, D Cartan series: irreps from Dynkin
/// labels, exact Weyl dimensions, duals, Frobenius–Schur indicators,
/// Freudenthal weight multiplicities, the exact Brauer–Klimyk/Racah–Speiser
/// tensor-product decomposition $N^c_{ab}$, and the Clebsch–Gordan / F / R
/// coefficients built by the generator bootstrap. Compilation-gated behind
/// `cgc-gen`.
// Family-generic F/R contraction + gates core, shared by `sun::fr` and
// `bcd::fr` (Stage 3 S3.4, issue #27). Private: the public F/R surfaces stay
// per-family; only the block types (`FBlock`/`RBlock`) are re-exported.
pub use SignedSqrtRational;
pub use ;