Skip to main content

lie_groups/representation/
casimir.rs

1//! Casimir operators for Lie algebras.
2//!
3//! The Casimir operators are elements of the center of the universal enveloping
4//! algebra U(𝔤) that commute with all group generators. They provide crucial
5//! invariants for classifying irreducible representations.
6//!
7//! # Mathematical Background
8//!
9//! ## Quadratic Casimir Operator
10//!
11//! The **quadratic Casimir** C₂ is defined as:
12//! ```text
13//! C₂ = Σᵢ Tᵢ²  (sum over orthonormal basis of 𝔤)
14//! ```
15//!
16//! **Key Property**: In any irreducible representation ρ:
17//! ```text
18//! ρ(C₂) = c₂(ρ) · I
19//! ```
20//! where c₂(ρ) is a scalar eigenvalue that labels the representation.
21//!
22//! ## Physical Interpretation
23//!
24//! For different Lie groups, C₂ has different physical meanings:
25//! - **SU(2)**: C₂ = J² (total angular momentum squared)
26//! - **SU(3)**: C₂ labels quark and gluon color representations
27//! - **Lorentz group**: C₂ and C₃ label particle mass and spin
28//!
29//! ## Higher Casimirs
30//!
31//! For Lie algebras of rank r (dimension of Cartan subalgebra),
32//! there are r independent Casimir operators:
33//! - Rank 1 (SU(2), SO(3)): only C₂
34//! - Rank 2 (SU(3), SO(5)): C₂ and C₃
35//! - Rank n (SU(n+1)): C₂, C₃, ..., C_{n+1}
36//!
37//! # Examples
38//!
39//! ## SU(2) Eigenvalues
40//!
41//! For spin-j representation:
42//! ```text
43//! c₂(j) = j(j+1)
44//!
45//! j = 0:     c₂ = 0   (scalar)
46//! j = 1/2:   c₂ = 3/4 (spinor)
47//! j = 1:     c₂ = 2   (vector/adjoint)
48//! j = 3/2:   c₂ = 15/4
49//! ```
50//!
51//! ## SU(3) Eigenvalues
52//!
53//! For representation (p,q):
54//! ```text
55//! c₂(p,q) = (1/3)(p² + q² + pq + 3p + 3q)
56//!
57//! (0,0): c₂ = 0     (trivial/singlet)
58//! (1,0): c₂ = 4/3   (fundamental/quark)
59//! (0,1): c₂ = 4/3   (antifundamental/antiquark)
60//! (1,1): c₂ = 3     (adjoint/gluon)
61//! ```
62//!
63//! # References
64//!
65//! - **Georgi**: "Lie Algebras in Particle Physics" (1999), Chapter 3
66//! - **Cahn**: "Semi-Simple Lie Algebras and Their Representations" (1984), Chapter 7
67//! - **Gilmore**: "Lie Groups, Lie Algebras, and Some of Their Applications" (1974)
68
69/// Casimir operators for Lie algebras.
70///
71/// This trait provides methods for computing eigenvalues of Casimir operators
72/// in different irreducible representations.
73///
74/// # Implementation Notes
75///
76/// For a Lie algebra 𝔤:
77/// 1. Implement `quadratic_casimir_eigenvalue()` using the standard formula
78/// 2. For rank > 1 algebras, optionally implement `higher_casimir_eigenvalues()`
79/// 3. Use exact rational arithmetic where possible (e.g., 4/3 not 1.333...)
80///
81/// # Type Safety
82///
83/// This trait is defined as a standalone trait (not requiring `LieAlgebra`)
84/// to allow flexible implementation strategies. Implementors should ensure
85/// they also implement `LieAlgebra`.
86pub trait Casimir {
87    /// Type representing irreducible representations of this algebra.
88    ///
89    /// # Examples
90    /// - SU(2): `Spin` (half-integer j)
91    /// - SU(3): `Su3Irrep` (Dynkin labels (p,q))
92    /// - SU(N): `YoungTableau` or `DynkinLabels`
93    type Representation;
94
95    /// Eigenvalue of the quadratic Casimir operator in a given irrep.
96    ///
97    /// For an irreducible representation ρ, this computes the scalar c₂(ρ)
98    /// such that ρ(C₂) = c₂(ρ) · I.
99    ///
100    /// # Arguments
101    ///
102    /// * `irrep` - The irreducible representation
103    ///
104    /// # Returns
105    ///
106    /// The eigenvalue c₂(ρ) as a real number.
107    ///
108    /// # Examples
109    ///
110    /// ```ignore
111    /// use lie_groups::{Su2Algebra, Casimir, Spin};
112    ///
113    /// // Spin-1/2 (spinor): c₂ = 3/4
114    /// let c2 = Su2Algebra::quadratic_casimir_eigenvalue(&Spin::HALF);
115    /// assert_eq!(c2, 0.75);
116    /// ```
117    fn quadratic_casimir_eigenvalue(irrep: &Self::Representation) -> f64;
118
119    /// Eigenvalues of higher Casimir operators (optional).
120    ///
121    /// For algebras of rank r > 1, there are r - 1 additional independent
122    /// Casimir operators beyond C₂.
123    ///
124    /// # Returns
125    ///
126    /// A vector of eigenvalues [c₃(ρ), c₄(ρ), ...] for the given irrep.
127    /// Default implementation returns empty vector (no higher Casimirs).
128    ///
129    /// # Examples
130    ///
131    /// For SU(3) with cubic Casimir C₃:
132    /// ```ignore
133    /// let higher = Su3Algebra::higher_casimir_eigenvalues(&irrep);
134    /// let c3 = higher[0]; // Cubic Casimir eigenvalue
135    /// ```
136    fn higher_casimir_eigenvalues(_irrep: &Self::Representation) -> Vec<f64> {
137        vec![]
138    }
139
140    /// Dimension of the Cartan subalgebra (rank of the algebra).
141    ///
142    /// This determines the number of independent Casimir operators:
143    /// - Rank 1: only C₂ (SU(2), SO(3))
144    /// - Rank 2: C₂ and C₃ (SU(3), SO(5))
145    /// - Rank n: C₂, ..., C_{n+1} (SU(n+1))
146    ///
147    /// # Returns
148    ///
149    /// The rank as a positive integer.
150    fn rank() -> usize;
151
152    /// Number of independent Casimir operators.
153    ///
154    /// This equals the rank of the algebra.
155    ///
156    /// # Returns
157    ///
158    /// The number of Casimirs (rank).
159    fn num_casimirs() -> usize {
160        Self::rank()
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    // Placeholder test to ensure module compiles
169    #[test]
170    fn test_trait_compiles() {
171        // This test verifies that the Casimir trait is well-formed
172        // Actual tests are in the implementation modules (su2.rs, su3.rs)
173    }
174
175    /// Test the Casimir identity: ∑_a T^a · T^a = C(R) · I
176    ///
177    /// This is the fundamental identity relating Casimir eigenvalues to
178    /// the sum of squared generators. For a representation R of a Lie algebra:
179    /// ```text
180    /// ∑_a T^a_{ij} T^a_{jk} = C(R) δ_{ik}
181    /// ```
182    ///
183    /// where T^a are the generators in representation R and C(R) is the
184    /// quadratic Casimir eigenvalue.
185    ///
186    /// For SU(2) fundamental (j=1/2):
187    /// - Generators: T^a = σ^a/2 (Pauli matrices / 2)
188    /// - Casimir: C_{1/2} = j(j+1) = 3/4
189    /// - Identity: (σ^1/2)² + (σ^2/2)² + (σ^3/2)² = 3/4 · I
190    #[test]
191    fn test_casimir_identity_su2_fundamental() {
192        use crate::representation::Spin;
193        use crate::su2::Su2Algebra;
194        use ndarray::Array2;
195        use num_complex::Complex64;
196
197        // SU(2) generators in fundamental representation: T^a = σ^a/2
198        // Pauli matrices:
199        // σ^1 = [[0, 1], [1, 0]]
200        // σ^2 = [[0, -i], [i, 0]]
201        // σ^3 = [[1, 0], [0, -1]]
202
203        let sigma1: Array2<Complex64> = Array2::from_shape_vec(
204            (2, 2),
205            vec![
206                Complex64::new(0.0, 0.0),
207                Complex64::new(1.0, 0.0),
208                Complex64::new(1.0, 0.0),
209                Complex64::new(0.0, 0.0),
210            ],
211        )
212        .unwrap();
213
214        let sigma2: Array2<Complex64> = Array2::from_shape_vec(
215            (2, 2),
216            vec![
217                Complex64::new(0.0, 0.0),
218                Complex64::new(0.0, -1.0),
219                Complex64::new(0.0, 1.0),
220                Complex64::new(0.0, 0.0),
221            ],
222        )
223        .unwrap();
224
225        let sigma3: Array2<Complex64> = Array2::from_shape_vec(
226            (2, 2),
227            vec![
228                Complex64::new(1.0, 0.0),
229                Complex64::new(0.0, 0.0),
230                Complex64::new(0.0, 0.0),
231                Complex64::new(-1.0, 0.0),
232            ],
233        )
234        .unwrap();
235
236        // T^a = σ^a / 2
237        let t1 = &sigma1 / Complex64::new(2.0, 0.0);
238        let t2 = &sigma2 / Complex64::new(2.0, 0.0);
239        let t3 = &sigma3 / Complex64::new(2.0, 0.0);
240
241        // Compute ∑_a T^a · T^a
242        let casimir_sum = t1.dot(&t1) + t2.dot(&t2) + t3.dot(&t3);
243
244        // Expected: C_{1/2} · I = (3/4) · I
245        let expected_casimir = Su2Algebra::quadratic_casimir_eigenvalue(&Spin::HALF);
246        let expected_matrix: Array2<Complex64> =
247            Array2::eye(2) * Complex64::new(expected_casimir, 0.0);
248
249        // Verify the identity
250        for i in 0..2 {
251            for j in 0..2 {
252                let diff = (casimir_sum[[i, j]] - expected_matrix[[i, j]]).norm();
253                assert!(
254                    diff < 1e-10,
255                    "Casimir identity violated at ({},{}): got {}, expected {}",
256                    i,
257                    j,
258                    casimir_sum[[i, j]],
259                    expected_matrix[[i, j]]
260                );
261            }
262        }
263
264        // Also verify the Casimir value is 3/4
265        assert!(
266            (expected_casimir - 0.75).abs() < 1e-10,
267            "C_{{1/2}} should be 3/4"
268        );
269    }
270
271    /// Test Casimir identity for SU(2) adjoint representation (j=1).
272    ///
273    /// For the adjoint representation of SU(2):
274    /// - Dimension: 3 (same as dim(su(2)))
275    /// - Casimir: `C_1` = j(j+1) = 2
276    ///
277    /// The generators in the adjoint are related to structure constants.
278    /// Using the physics convention with (T^a)_{bc} = -i f^{abc} (antisymmetric),
279    /// we verify that ∑_a (T^a)_{bc} (T^a)_{cd} is proportional to δ_{bd}.
280    ///
281    /// # Convention Note
282    ///
283    /// The Levi-Civita contraction gives:
284    /// ∑_{a,c} ε_{abc} ε_{acd} = -2 δ_{bd}
285    ///
286    /// The factor of -2 (rather than +2) comes from the antisymmetric
287    /// (real) generator convention. The magnitude |C| = 2 matches the
288    /// formula `C_j` = j(j+1) = 2 for j=1.
289    #[test]
290    fn test_casimir_identity_su2_adjoint() {
291        use crate::representation::Spin;
292        use crate::su2::Su2Algebra;
293
294        // ε tensor (Levi-Civita symbol)
295        let epsilon = |a: usize, b: usize, c: usize| -> f64 {
296            if (a, b, c) == (0, 1, 2) || (a, b, c) == (1, 2, 0) || (a, b, c) == (2, 0, 1) {
297                1.0
298            } else if (a, b, c) == (0, 2, 1) || (a, b, c) == (2, 1, 0) || (a, b, c) == (1, 0, 2) {
299                -1.0
300            } else {
301                0.0
302            }
303        };
304
305        // Build adjoint generators: (t^a)_{bc} = ε_{abc}
306        let mut t_adj: [[[f64; 3]; 3]; 3] = [[[0.0; 3]; 3]; 3];
307        for a in 0..3 {
308            for b in 0..3 {
309                for c in 0..3 {
310                    t_adj[a][b][c] = epsilon(a, b, c);
311                }
312            }
313        }
314
315        // Compute sum: (∑_a T^a T^a)_{bd} = ∑_a ∑_c T^a_{bc} T^a_{cd}
316        let mut casimir_sum = [[0.0; 3]; 3];
317        for b in 0..3 {
318            for d in 0..3 {
319                for a in 0..3 {
320                    for c in 0..3 {
321                        casimir_sum[b][d] += t_adj[a][b][c] * t_adj[a][c][d];
322                    }
323                }
324            }
325        }
326
327        // Result: ∑_{a,c} ε_{abc} ε_{acd} = -2 δ_{bd}
328        // The magnitude matches C_adjoint = 2, sign is negative due to
329        // real antisymmetric generator convention.
330        let expected_casimir = Su2Algebra::quadratic_casimir_eigenvalue(&Spin::ONE);
331
332        for b in 0..3 {
333            for d in 0..3 {
334                // Note: sign is negative for real antisymmetric generators
335                let expected = if b == d { -expected_casimir } else { 0.0 };
336                let diff = (casimir_sum[b][d] - expected).abs();
337                assert!(
338                    diff < 1e-10,
339                    "Adjoint Casimir identity violated at ({},{}): got {}, expected {}",
340                    b,
341                    d,
342                    casimir_sum[b][d],
343                    expected
344                );
345            }
346        }
347
348        // Verify diagonal value is -2 (magnitude matches C_1 = 2)
349        assert!(
350            (casimir_sum[0][0].abs() - expected_casimir).abs() < 1e-10,
351            "|∑_a (T^a T^a)_{{00}}| should equal C_adjoint = 2"
352        );
353    }
354}