Add scripts for exact Casimir projectors and recoupling proof

- Implemented `2_exact_casimir_projectors.py` to construct exact SO(3) isotypic projectors using the Casimir operator, replacing Monte-Carlo methods.
- Created `3_apply_exact_projectors.py` to apply the exact projectors to example states, calculating ||A_j||_* estimates with improved precision.
- Developed `4_spherical_basis.py` to build a Condon-Shortley-consistent spherical basis for a single spin-1 leg using ladder operators.
- Introduced `6_six_j_recoupling_proof.py` to provide a complete proof of the cut-recoupling formula for full collective SU(2) symmetry, verifying the relationship between reduced blocks A_j^(1) and A_p^(2).
- Added a README file to document the execution order and purpose of each script in the symmetric states project.
This commit is contained in:
Hans Aschauer 2026-08-08 00:00:41 +02:00
parent 39b4204fe9
commit bc6f58b2c4
9 changed files with 1097 additions and 13 deletions

View file

@ -0,0 +1,56 @@
"""
Apply the EXACT Casimir-based isotypic projectors (projectors_exact.npz)
to the two example states, at both cuts, replacing the earlier
Monte-Carlo-based ||A_j||_* estimates with machine-precision values.
Uses T1, T2, C12 (saved by recoupling_check.py) so that "Example 1"
(pure psi1) and "Example 2" (Xi at alpha) are both obtained from the
SAME three fixed tensors, no new quantum simulation.
"""
import numpy as np
T1 = np.load("T1.npy")
T2 = np.load("T2.npy")
C12 = np.load("C12.npy")
overlap = 0.25 # <psi1|psi2>, real (checked earlier)
P = np.load("projectors_exact.npz")
def state_tensor(alpha):
N2 = 1 + np.sin(2*alpha)*overlap
return (np.cos(alpha)**2*T1 + np.sin(alpha)**2*T2
+ np.cos(alpha)*np.sin(alpha)*C12) / N2
def report(label, alpha):
T = state_tensor(alpha)
M_c1 = T.reshape(27,27) # cut ABC|DEF
M_c2 = T.reshape(9,81) # cut AB|CDEF
print(f"\n=== {label} (alpha={alpha}) ===")
print("-- cut ABC|DEF --")
tot = 0.0
for j in range(4):
Pj = P[f"P3_{j}"]
block = Pj @ M_c1 @ Pj
nn = np.linalg.svd(block, compute_uv=False).sum()
Aj = nn/(2*j+1)
tot += (2*j+1)*Aj
print(f" j={j}: ||A_j||_* = {Aj:.6f}")
raw_nn = np.linalg.svd(M_c1, compute_uv=False).sum()
print(f" sum_j (2j+1)||A_j||_* = {tot:.6f} vs. ||M||_* direct = {raw_nn:.6f}")
print("-- cut AB|CDEF --")
tot = 0.0
for j in range(3):
Pj_src = P[f"P2_{j}"]
Pj_tgt = P[f"P4_{j}"]
block = Pj_src @ M_c2 @ Pj_tgt
nn = np.linalg.svd(block, compute_uv=False).sum()
Aj = nn/(2*j+1)
tot += (2*j+1)*Aj
print(f" j={j}: ||A_j||_* = {Aj:.6f}")
raw_nn = np.linalg.svd(M_c2, compute_uv=False).sum()
print(f" sum_j (2j+1)||A_j||_* = {tot:.6f} vs. ||M||_* direct = {raw_nn:.6f}")
report("Example 1 (pure psi1, three aligned singlets)", 0.0)
report("Example 2 (superposition)", np.pi/5)