Compare commits
No commits in common. "4b7008b1dfa9c340a418522f510c4004c42657aa" and "39b4204fe96368afebc989c69136c7d462428122" have entirely different histories.
4b7008b1df
...
39b4204fe9
11 changed files with 33 additions and 1443 deletions
225
.gitignore
vendored
225
.gitignore
vendored
|
|
@ -332,228 +332,3 @@ TSWLatexianTemp*
|
||||||
|
|
||||||
|
|
||||||
paper/*.pdf
|
paper/*.pdf
|
||||||
.docs_mcp/
|
|
||||||
julia/
|
|
||||||
|
|
||||||
#### Python
|
|
||||||
|
|
||||||
# Byte-compiled / optimized / DLL files
|
|
||||||
__pycache__/
|
|
||||||
*.py[codz]
|
|
||||||
*$py.class
|
|
||||||
|
|
||||||
# C extensions
|
|
||||||
*.so
|
|
||||||
|
|
||||||
# Distribution / packaging
|
|
||||||
.Python
|
|
||||||
build/
|
|
||||||
develop-eggs/
|
|
||||||
dist/
|
|
||||||
downloads/
|
|
||||||
eggs/
|
|
||||||
.eggs/
|
|
||||||
lib/
|
|
||||||
lib64/
|
|
||||||
parts/
|
|
||||||
sdist/
|
|
||||||
var/
|
|
||||||
wheels/
|
|
||||||
share/python-wheels/
|
|
||||||
*.egg-info/
|
|
||||||
.installed.cfg
|
|
||||||
*.egg
|
|
||||||
MANIFEST
|
|
||||||
|
|
||||||
# PyInstaller
|
|
||||||
# Usually these files are written by a python script from a template
|
|
||||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
||||||
*.manifest
|
|
||||||
*.spec
|
|
||||||
|
|
||||||
# Installer logs
|
|
||||||
pip-log.txt
|
|
||||||
pip-delete-this-directory.txt
|
|
||||||
|
|
||||||
# Unit test / coverage reports
|
|
||||||
htmlcov/
|
|
||||||
.tox/
|
|
||||||
.nox/
|
|
||||||
.coverage
|
|
||||||
.coverage.*
|
|
||||||
.cache
|
|
||||||
nosetests.xml
|
|
||||||
coverage.xml
|
|
||||||
*.cover
|
|
||||||
*.py.cover
|
|
||||||
*.lcov
|
|
||||||
.hypothesis/
|
|
||||||
.pytest_cache/
|
|
||||||
cover/
|
|
||||||
|
|
||||||
# Translations
|
|
||||||
*.mo
|
|
||||||
*.pot
|
|
||||||
|
|
||||||
# Django stuff:
|
|
||||||
*.log
|
|
||||||
local_settings.py
|
|
||||||
db.sqlite3
|
|
||||||
db.sqlite3-journal
|
|
||||||
|
|
||||||
# Flask stuff:
|
|
||||||
instance/
|
|
||||||
.webassets-cache
|
|
||||||
|
|
||||||
# Scrapy stuff:
|
|
||||||
.scrapy
|
|
||||||
|
|
||||||
# Sphinx documentation
|
|
||||||
docs/_build/
|
|
||||||
|
|
||||||
# PyBuilder
|
|
||||||
.pybuilder/
|
|
||||||
target/
|
|
||||||
|
|
||||||
# Jupyter Notebook
|
|
||||||
.ipynb_checkpoints
|
|
||||||
|
|
||||||
# IPython
|
|
||||||
profile_default/
|
|
||||||
ipython_config.py
|
|
||||||
|
|
||||||
# pyenv
|
|
||||||
# For a library or package, you might want to ignore these files since the code is
|
|
||||||
# intended to run in multiple environments; otherwise, check them in:
|
|
||||||
# .python-version
|
|
||||||
|
|
||||||
# pipenv
|
|
||||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
||||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
||||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
||||||
# install all needed dependencies.
|
|
||||||
# Pipfile.lock
|
|
||||||
|
|
||||||
# UV
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
||||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
||||||
# commonly ignored for libraries.
|
|
||||||
# uv.lock
|
|
||||||
|
|
||||||
# poetry
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
||||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
||||||
# commonly ignored for libraries.
|
|
||||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
||||||
# poetry.lock
|
|
||||||
# poetry.toml
|
|
||||||
|
|
||||||
# pdm
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
||||||
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
||||||
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
||||||
# pdm.lock
|
|
||||||
# pdm.toml
|
|
||||||
.pdm-python
|
|
||||||
.pdm-build/
|
|
||||||
|
|
||||||
# pixi
|
|
||||||
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
||||||
# pixi.lock
|
|
||||||
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
||||||
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
||||||
.pixi/*
|
|
||||||
!.pixi/config.toml
|
|
||||||
|
|
||||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
||||||
__pypackages__/
|
|
||||||
|
|
||||||
# Celery stuff
|
|
||||||
celerybeat-schedule*
|
|
||||||
celerybeat.pid
|
|
||||||
|
|
||||||
# Redis
|
|
||||||
*.rdb
|
|
||||||
*.aof
|
|
||||||
*.pid
|
|
||||||
|
|
||||||
# RabbitMQ
|
|
||||||
mnesia/
|
|
||||||
rabbitmq/
|
|
||||||
rabbitmq-data/
|
|
||||||
|
|
||||||
# ActiveMQ
|
|
||||||
activemq-data/
|
|
||||||
|
|
||||||
# SageMath parsed files
|
|
||||||
*.sage.py
|
|
||||||
|
|
||||||
# Environments
|
|
||||||
.env
|
|
||||||
.envrc
|
|
||||||
.venv
|
|
||||||
env/
|
|
||||||
venv/
|
|
||||||
ENV/
|
|
||||||
env.bak/
|
|
||||||
venv.bak/
|
|
||||||
|
|
||||||
# Spyder project settings
|
|
||||||
.spyderproject
|
|
||||||
.spyproject
|
|
||||||
|
|
||||||
# Rope project settings
|
|
||||||
.ropeproject
|
|
||||||
|
|
||||||
# mkdocs documentation
|
|
||||||
/site
|
|
||||||
|
|
||||||
# mypy
|
|
||||||
.mypy_cache/
|
|
||||||
.dmypy.json
|
|
||||||
dmypy.json
|
|
||||||
|
|
||||||
# Pyre type checker
|
|
||||||
.pyre/
|
|
||||||
|
|
||||||
# pytype static type analyzer
|
|
||||||
.pytype/
|
|
||||||
|
|
||||||
# Cython debug symbols
|
|
||||||
cython_debug/
|
|
||||||
|
|
||||||
# PyCharm
|
|
||||||
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
||||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
||||||
# .idea/
|
|
||||||
|
|
||||||
# Abstra
|
|
||||||
# Abstra is an AI-powered process automation framework.
|
|
||||||
# Ignore directories containing user credentials, local state, and settings.
|
|
||||||
# Learn more at https://abstra.io/docs
|
|
||||||
.abstra/
|
|
||||||
|
|
||||||
# Visual Studio Code
|
|
||||||
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
||||||
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
||||||
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
||||||
# you could uncomment the following to ignore the entire vscode folder
|
|
||||||
# .vscode/
|
|
||||||
# Temporary file for partial code execution
|
|
||||||
tempCodeRunnerFile.py
|
|
||||||
|
|
||||||
# Ruff stuff:
|
|
||||||
.ruff_cache/
|
|
||||||
|
|
||||||
# PyPI configuration file
|
|
||||||
.pypirc
|
|
||||||
|
|
||||||
# Marimo
|
|
||||||
marimo/_static/
|
|
||||||
marimo/_lsp/
|
|
||||||
__marimo__/
|
|
||||||
|
|
||||||
# Streamlit
|
|
||||||
.streamlit/secrets.toml
|
|
||||||
|
|
@ -731,132 +731,46 @@ independent of which cut's matricization is subsequently taken.
|
||||||
$T(\rho)(\vec\imath)=\tr(\rho\,\sigma_{\vec\imath})$ is linear in $\rho$; substituting $\rho=\sum_{a,b}c_{ab}\ketbra{\phi_a}{\phi_b}$ and using $\tr(\ketbra{\phi_a}{\phi_b}\sigma_{\vec\imath})=\bra{\phi_b}\sigma_{\vec\imath}\ket{\phi_a}=T_{ba}(\vec\imath)$ gives Eq.~\eqref{eq:general-coherence-decomposition} termwise; the cut dependence enters only afterward, through the reshape of the index set $\vec\imath$, and does not affect the coefficients $c_{ab}$ or the tensors $T_{ab}$.
|
$T(\rho)(\vec\imath)=\tr(\rho\,\sigma_{\vec\imath})$ is linear in $\rho$; substituting $\rho=\sum_{a,b}c_{ab}\ketbra{\phi_a}{\phi_b}$ and using $\tr(\ketbra{\phi_a}{\phi_b}\sigma_{\vec\imath})=\bra{\phi_b}\sigma_{\vec\imath}\ket{\phi_a}=T_{ba}(\vec\imath)$ gives Eq.~\eqref{eq:general-coherence-decomposition} termwise; the cut dependence enters only afterward, through the reshape of the index set $\vec\imath$, and does not affect the coefficients $c_{ab}$ or the tensors $T_{ab}$.
|
||||||
\end{proof}
|
\end{proof}
|
||||||
|
|
||||||
\begin{corollary}[Real-tensor count, corrected]
|
% TODO (open / not yet carried out): Proposition~\ref{prop:coherence-templates}
|
||||||
\label{cor:real-tensor-count}
|
% is stated and used above only for r=2 real generators (psi_1, psi_2), where
|
||||||
Since $\sigma_{\vec\imath}$ is Hermitian, $T_{ba}=\overline{T_{ab}}$; in particular each $T_{aa}$ is real. Writing $T_{ab}=P_{ab}+iQ_{ab}$ for $a<b$, Eq.~\eqref{eq:general-coherence-decomposition} becomes, for Hermitian $c$,
|
% the single real cross term C_{12} suffices because the c_{ab} happen to be
|
||||||
\begin{equation}
|
% real and symmetric in that example. For general r this requires r(r+1)/2
|
||||||
T(\rho) = \sum_{a=1}^r c_{aa}\,T_{aa} \;+\; \sum_{a<b}\Bigl(2\,\mathrm{Re}(c_{ab})\,P_{ab} \;-\; 2\,\mathrm{Im}(c_{ab})\,Q_{ab}\Bigr),
|
% independent real tensors (r diagonal T_aa plus the real/imaginary parts of
|
||||||
\label{eq:real-tensor-count}
|
% the r(r-1)/2 off-diagonal overlaps, or equivalently just track the full
|
||||||
\end{equation}
|
% Hermitian r x r coefficient matrix c_{ab} against the T_{ab} disregarding
|
||||||
a real-linear combination of exactly $r+2\binom r2=r^2$ fixed real tensors $\{T_{aa}\}\cup\{P_{ab},Q_{ab}\}_{a<b}$ -- matching the real dimension of the space of Hermitian $r\times r$ matrices, as it must, since $\rho\mapsto T(\rho)$ is a real-linear injection (the $T_{ab}$ are linearly independent whenever the $\ket{\phi_a}$ are) from that space. (For $r=2$ this is exactly Eq.~\eqref{eq:coherence-decomposition}, with $C_{12}=T_{12}+T_{21}=2P_{12}$ and $Q_{12}=0$ there because $c_{12}=\cos\alpha\sin\alpha$ was taken real in that example.)
|
% the a<->b symmetry) -- this is mechanical but has not been written out or
|
||||||
\end{corollary}
|
% numerically tested here for r>2. Do this before submission if the general
|
||||||
|
% statement is kept; otherwise restate the Proposition for r=2 only and move
|
||||||
\begin{example}[$r=3$, genuinely mixed]
|
% the general case to a remark.
|
||||||
\label{ex:general-r-three}
|
|
||||||
Take $\ket{\phi_1},\ket{\phi_2}$ as in Eq.~\eqref{eq:singlet-network-states} together with a third perfect matching $\ket{\phi_3}\propto\ket{\psi^-}_{AF}\ket{\psi^-}_{BD}\ket{\psi^-}_{CE}$; all three are collectively invariant, with pairwise overlaps $\braket{\phi_a}{\phi_b}=1/4$ ($a\ne b$) and Gram matrix of condition number $2$ (linearly independent). For a Haar-random Hermitian PSD $c$ of full rank $3$ (not proportional to a rank-$1$ projector, i.e.\ $\rho=\Phi c\Phi^\dagger/\tr(\Phi c\Phi^\dagger)$ a genuinely mixed state with three distinct nonzero eigenvalues), Eq.~\eqref{eq:general-coherence-decomposition} -- built once from the $9=3^2$ tensors $T_{ab}$ -- reproduces the brute-force correlation tensor of $\rho$ to $10^{-16}$, at both the $ABC\mid DEF$ and $AB\mid CDEF$ cuts simultaneously, with no further contraction over the $64$-dimensional Hilbert space (\texttt{scripts/general\_r\_check.py}). This extends the verification of Section~\ref{sec:cut-independent-data} from a pure two-state superposition to a genuinely mixed three-state case, as Proposition~\ref{prop:coherence-templates} and Corollary~\ref{cor:real-tensor-count} require.
|
|
||||||
\end{example}
|
|
||||||
|
|
||||||
\begin{remark}[What this does and does not establish]
|
\begin{remark}[What this does and does not establish]
|
||||||
\label{rem:recoupling-scope}
|
\label{rem:recoupling-scope}
|
||||||
Proposition~\ref{prop:coherence-templates} is a bookkeeping consequence of the linearity already used throughout this note (cf.\ the unfolding proposition and the "one rank-one fact, inherited everywhere" theorem of \cite{aschauer2026a}); its content is operational rather than a new inequality: once the $r^2$ template tensors are computed -- from simulation, or in principle extracted from permutationally/collectively-adapted state tomography -- every cut, every mixing angle, and every isotypic block $\|A_j\|_*$ of Corollary~\ref{cor:projector-norm-formula} for the resulting state family is available without revisiting the full $\bigl(\mathbb R^3\bigr)^{\otimes n}$-sized contraction again.
|
Proposition~\ref{prop:coherence-templates} is a bookkeeping consequence of the linearity already used throughout this note (cf.\ the unfolding proposition and the "one rank-one fact, inherited everywhere" theorem of \cite{aschauer2026a}); its content is operational rather than a new inequality: once the $r^2$ template tensors are computed -- from simulation, or in principle extracted from permutationally/collectively-adapted state tomography -- every cut, every mixing angle, and every isotypic block $\|A_j\|_*$ of Corollary~\ref{cor:projector-norm-formula} for the resulting state family is available without revisiting the full $\bigl(\mathbb R^3\bigr)^{\otimes n}$-sized contraction again.
|
||||||
|
|
||||||
|
% TODO (deferred to future work, see session notes): the stronger,
|
||||||
|
% state-independent question of whether the reduced blocks A_j themselves
|
||||||
|
% (not just the raw tensor) transform between two different cuts of the
|
||||||
|
% SAME invariant tensor via an explicit, computable recoupling map -- i.e.
|
||||||
|
% a Racah/6j-symbol type formula relating A_j at cut S|S^c directly to the
|
||||||
|
% A_{j'} at a different cut S'|S'^c, without reshaping the full raw tensor
|
||||||
|
% -- is NOT established here. An exact branching-dimension check (m_p^{(4)}
|
||||||
|
% = sum over compatible y of m_y^{(3)} for every p=0,...,4) is consistent
|
||||||
|
% with such a relation existing, but the explicit coefficients (presumably
|
||||||
|
% governed by an SU(2) recoupling/6j-symbol calculation for the six spin-1
|
||||||
|
% legs, or by the Brauer-algebra structure of Inv((R^3)^{\otimes 6}) since
|
||||||
|
% the example states here are literally perfect-matching invariants) have
|
||||||
|
% not been derived or numerically verified. Left for later.
|
||||||
\end{remark}
|
\end{remark}
|
||||||
|
|
||||||
\subsubsection{Recoupling the reduced blocks between two cuts}
|
% TODO (outlook, not attempted): combining the S_m-permutation collapse of
|
||||||
\label{sec:six-j-recoupling}
|
% Section~\ref{sec:polynomial-witness} (Proposition~\ref{prop:multinomial-collapse})
|
||||||
|
% with the SO(3) branching of this subsection. For a cluster invariant under
|
||||||
% ============================================================
|
% BOTH S_m and collective SO(3) simultaneously, Sym^m(R^3) is known classically
|
||||||
% NEW SUBSUBSECTION -- draft. Resolves the open point left in
|
% to decompose multiplicity-free into spherical harmonics, m_j=1 for
|
||||||
% rem:recoupling-scope of an earlier draft: the reduced blocks A_j
|
% j=m,m-2,...; combined with Proposition~\ref{prop:multinomial-collapse} this
|
||||||
% themselves (not just the raw tensor) DO transform between two cuts of
|
% should collapse a full sector to O(m) one-dimensional channels rather than
|
||||||
% the same invariant tensor via an explicit, closed-form, state-independent
|
% the polynomial-but-not-linear \binom{m+2}{2} of that Proposition alone.
|
||||||
% map. Derived and verified exactly (sympy, symbolic CG sums; brute-force
|
% Not worked out or tested here.
|
||||||
% simulation cross-check at machine precision) in
|
|
||||||
% scripts/six_j_recoupling_proof.py. The derivation below is condensed;
|
|
||||||
% the script carries every intermediate identity with its own numerical
|
|
||||||
% check, in case a step needs to be revisited.
|
|
||||||
% ============================================================
|
|
||||||
|
|
||||||
Remark~\ref{rem:recoupling-scope} left open whether the reduced blocks $A_j$ of two different cuts of the \emph{same} invariant tensor -- not merely the raw correlation tensor -- are related by an explicit, state-independent map. For the six-qubit example of Section~\ref{sec:singlet-network-example} they are, exactly, and the relating coefficients are elementary.
|
|
||||||
|
|
||||||
\begin{theorem}[Cut recoupling for six spin-1 legs]
|
|
||||||
\label{thm:six-j-recoupling}
|
|
||||||
Fix $S_1=ABC\mid DEF$ with source tree $(AB)C\!\to\! j$, target tree $(DE)F\!\to\! j$, giving the reduced blocks $A_j^{(1)}[p,y]$ of Example~\ref{ex:singlet-superposition}, and $S_2=AB\mid CDEF$ with source $AB\!\to\! p$ directly and target tree $C,(DE)F\!\to\! p$, giving $A_p^{(2)}[y,j]$. For every $G$-invariant $\rho$ on the six qubits (collective hypothesis~\eqref{eq:collective-hypothesis}) and every valid $(p,y,j)$,
|
|
||||||
\begin{equation}
|
|
||||||
A_p^{(2)}[y,j] \;=\; -\sqrt{\frac{2j+1}{2p+1}}\;A_j^{(1)}[p,y],
|
|
||||||
\label{eq:six-j-recoupling}
|
|
||||||
\end{equation}
|
|
||||||
independent of $y$.
|
|
||||||
\end{theorem}
|
|
||||||
|
|
||||||
\begin{proof}[Proof sketch]
|
|
||||||
Write $\widehat T$ for $T(\rho)$ regarded as a genuinely multilinear (not sesquilinear) functional of one real vector per leg, complexified $\mathbb C$-multilinearly; this is the natural extension of the real bilinear pairing underlying $M_{S\to S^c}(\rho)$ (the response-map construction of \cite{aschauer2026a}), and $G$-invariance of $\rho$ makes $\widehat T$ invariant under simultaneous rotation of all six legs.
|
|
||||||
|
|
||||||
\emph{Step 1 (the correct Schur reduction).} For coupled multiplets $u_{p,j,m}$ (tree $(AB)C$) and $v_{y,j,m'}$ (tree $(DE)F$), invariance forces $X_{mm'}:=\widehat T(u_{p,j,m},v_{y,j,m'})$ to satisfy $X=D^j(g)^{\mathsf T}XD^j(g)$ for every $g$ (transpose, not the Hermitian adjoint, since $\widehat T$ is bilinear). Using $D^j(g)^{\mathsf T}=C_jD^j(g^{-1})C_j^{-1}$ with the metric $(C_j)_{mm'}=(-1)^{j-m}\delta_{m,-m'}$ turns this into an ordinary intertwiner condition $D^j(g)(C_j^{-1}X)=(C_j^{-1}X)D^j(g)$, so by Schur's lemma $C_j^{-1}X\propto\id$, i.e.
|
|
||||||
\begin{equation}
|
|
||||||
\widehat T(u_{p,j,m},v_{y,j,m'}) = c(p,y,j)\,(-1)^{j-m}\,\delta_{m,-m'}
|
|
||||||
\label{eq:schur-metric-form}
|
|
||||||
\end{equation}
|
|
||||||
for a single scalar $c(p,y,j)$. The identical argument, applied with the $C$-leg left unpaired, gives the reduced three-index object $R(m_p,m_C,m_j):=\widehat T(u^{AB}_{p,m_p}\otimes e_{m_C},\,v_{y,j,m_j})$ in terms of the \emph{same} scalar $c(p,y,j)$: since $R$, viewed as pairing the $j$-isotype of $V_p\otimes V_1$ against $V_j$, is subject to the same metric-form constraint,
|
|
||||||
\begin{equation}
|
|
||||||
R(m_p,m_C,m_j) = c(p,y,j)\,(-1)^{j+m_j}\,\langle p,m_p;1,m_C\,|\,j,-m_j\rangle.
|
|
||||||
\label{eq:R-metric-form}
|
|
||||||
\end{equation}
|
|
||||||
(Naively assuming $R\propto\langle p,m_p;1,m_C|j,m_j\rangle$ without the metric/sign flip -- i.e.\ skipping the $C_j$ correction in Step 1 -- reproduces neither the correct selection rule $m_p+m_C+m_j=0$ forced by $\widehat T$'s own weight conservation, nor a $y$-independent final answer; this was the error in an earlier attempt.)
|
|
||||||
|
|
||||||
\emph{Step 2 (conjugation of a real-representation-derived multiplet).} For an $n_\ell$-leg multiplet of total spin $J$ built from the single-leg basis, complex conjugation acts by
|
|
||||||
\begin{equation}
|
|
||||||
\overline{v_{J,m}} = (-1)^{J+n_\ell}\,(-1)^m\,v_{J,-m},
|
|
||||||
\label{eq:conjugation-phase}
|
|
||||||
\end{equation}
|
|
||||||
verified directly for the $3$-leg tree $(DE)F$ ($n_\ell=3$) and the $4$-leg tree $C,(DE)F$ ($n_\ell=4$) in \texttt{scripts/six\_j\_recoupling\_proof.py}, exactly and for every multiplet label. (Eq.~\eqref{eq:conjugation-phase} follows from the standard conjugation identity for Wigner $D$-matrices, $\overline{D^j_{m'm}(g)}=(-1)^{m'-m}D^j_{-m',-m}(g)$, applied inductively through the coupling tree together with Schur's lemma at each step; we verify the closed form directly rather than re-deriving the induction here.)
|
|
||||||
|
|
||||||
\emph{Step 3 (assembly).} Combining Eqs.~\eqref{eq:schur-metric-form} and \eqref{eq:conjugation-phase} (with $n_\ell=3$) gives $A_j^{(1)}[p,y]=(-1)^{j+1}(-1)^jc(p,y,j)=-c(p,y,j)$, since $(-1)^{2j+1}=-1$ for integer $j$. For $A_p^{(2)}[y,j]$, expand the target multiplet $w_{y,j,p,m'}=\sum_{m_C,m_j}\langle1,m_C;j,m_j|p,m'\rangle\,e_{m_C}\otimes v_{y,j,m_j}$, apply Eq.~\eqref{eq:conjugation-phase} with $n_\ell=4$, and use Eq.~\eqref{eq:R-metric-form} for the resulting contraction with $R$. This leaves the finite sum
|
|
||||||
\begin{equation}
|
|
||||||
\Xi(p,j,m') := \sum_{m_C,m_j}\langle1,m_C;j,m_j\,|\,p,-m'\rangle\,(-1)^{j+m_j}\,\langle p,m';1,m_C\,|\,j,-m_j\rangle,
|
|
||||||
\label{eq:xi-sum}
|
|
||||||
\end{equation}
|
|
||||||
verified exactly (sympy, symbolic Clebsch--Gordan coefficients) to satisfy $(-1)^p(-1)^{m'}\Xi(p,j,m')=\sqrt{(2j+1)/(2p+1)}$ for every valid $(p,j,m')$ with $p,j\le3$ -- in particular independent of $m'$, as it must be, since $A_p^{(2)}$ is $m'$-independent by Corollary~\ref{cor:projector-norm-formula}. Assembling: $A_p^{(2)}[y,j]=\sqrt{(2j+1)/(2p+1)}\,c(p,y,j)=-\sqrt{(2j+1)/(2p+1)}\,A_j^{(1)}[p,y]$, proving Eq.~\eqref{eq:six-j-recoupling}.
|
|
||||||
\end{proof}
|
|
||||||
|
|
||||||
\begin{remark}[Scope and what remains open]
|
|
||||||
\label{rem:six-j-scope}
|
|
||||||
Eq.~\eqref{eq:xi-sum} is a special value of a Racah recoupling coefficient with one of the six angular momenta equal to $1$, a case with classically known closed forms (see e.g.\ Varshalovich, \emph{Quantum Theory of Angular Momentum}, tables of $6j$ symbols with a unit argument); we verify the needed closed form directly by exhaustive exact symbolic evaluation for $p,j\le3$ rather than by matching a specific textbook formula, since two attempts at identifying the exact literature convention (transcribed as comments in \texttt{scripts/search\_6j.py}) did not reproduce it and the discrepancy was not tracked down. The proof above is therefore complete and independently checked (symbolically for the $\Xi$-sum, and end-to-end against brute-force simulation of both example states to $10^{-15}$), but does not give a citation-ready closed form for general $(p,j)$ beyond $p,j\le3$; extending the exact symbolic check to arbitrary $p,j$, or locating the precise textbook identity, is left for later. The conjugation phase of Eq.~\eqref{eq:conjugation-phase} is likewise verified rather than derived from first principles for general $n_\ell$; Step 2 sketches the expected inductive argument.
|
|
||||||
\end{remark}
|
|
||||||
|
|
||||||
\subsubsection{Combining with permutation symmetry: multiplicity-free channels}
|
|
||||||
\label{sec:sm-so3-combination}
|
|
||||||
|
|
||||||
% ============================================================
|
|
||||||
% NEW SUBSUBSECTION -- draft. Resolves the second open point from an
|
|
||||||
% earlier draft's outlook TODO: combining the S_m-permutation collapse of
|
|
||||||
% Proposition~\ref{prop:multinomial-collapse} with the SO(3) branching of
|
|
||||||
% this subsection. Verified computationally on a concrete 6-qubit example
|
|
||||||
% (two coupled 3-qubit Dicke/symmetric multiplets) in
|
|
||||||
% scripts/combined_sm_so3_collapse.py.
|
|
||||||
% ============================================================
|
|
||||||
|
|
||||||
The two reduction mechanisms developed in this note -- the $S_m$-permutation collapse of Proposition~\ref{prop:multinomial-collapse} and the $SO(3)$ branching of this subsection -- combine multiplicatively rather than merely coexisting, and the combination is worth making explicit because it is genuinely stronger than either alone.
|
|
||||||
|
|
||||||
\begin{proposition}[Harmonic decomposition of symmetric tensors; classical]
|
|
||||||
\label{prop:harmonic-decomposition}
|
|
||||||
As an $SO(3)$-representation, $\mathrm{Sym}^m(\mathbb R^3)$ decomposes multiplicity-free,
|
|
||||||
\begin{equation}
|
|
||||||
\mathrm{Sym}^m(\mathbb R^3) \;\cong\; \bigoplus_{k=0}^{\lfloor m/2\rfloor} \mathcal H_{m-2k},
|
|
||||||
\qquad \dim\mathcal H_j = 2j+1,
|
|
||||||
\label{eq:harmonic-decomposition}
|
|
||||||
\end{equation}
|
|
||||||
where $\mathcal H_j$ denotes the space of degree-$j$ solid harmonics (equivalently, the traceless part of $\mathrm{Sym}^j(\mathbb R^3)$). This is the standard trace-decomposition of symmetric tensors underlying the multipole expansion; see e.g.\ Fulton--Harris.
|
|
||||||
\end{proposition}
|
|
||||||
|
|
||||||
Consequently, for a source cluster $S$ of size $m$ that is invariant under \emph{both} $S_m$ (permutations of its own $m$ parties) \emph{and} the collective hypothesis~\eqref{eq:collective-hypothesis}, the source sector $\mathcal V_S^{(S)}$ collapses in two independent, compatible steps rather than one: first from $3^m$ to $\binom{m+2}{2}$ via Proposition~\ref{prop:multinomial-collapse} (a polynomial, but quadratic, reduction), and then, \emph{within} that $\binom{m+2}2$-dimensional space, the isotypic multiplicities collapse to exactly $1$ for each of the $O(m)$ surviving values $j=m,m-2,\dots$ -- dramatically finer than the generic branching multiplicities $m_j^{(m)}$ of Proposition~\ref{prop:branching-su2}, which grow with $m$ (e.g.\ $m_1^{(3)}=3$ unrestricted, versus multiplicity exactly $1$ within $\mathrm{Sym}^3$). Computationally, this second step costs one further Hermitian eigendecomposition of the $J^2$ Casimir restricted to the already-small $\binom{m+2}2$-dimensional space -- i.e.\ diagonalizing a matrix of side length $\binom{m+2}2$, not $3^m$ -- after which every surviving channel carries a genuine \emph{scalar} reduced matrix element $A_j$ (no residual multiplicity, hence no Clebsch--Gordan bookkeeping of the kind needed in Section~\ref{sec:six-j-recoupling}).
|
|
||||||
|
|
||||||
\begin{example}[A doubly-symmetric six-qubit state]
|
|
||||||
\label{ex:dicke-network}
|
|
||||||
Let $S=\{A,B,C\}$, $S^c=\{D,E,F\}$, and let $\ket{D_3^k}$ denote the $3$-qubit Dicke state of weight $k$ (Section~\ref{sec:dicke-example}). The state
|
|
||||||
\begin{equation}
|
|
||||||
\ket{Q} \;\propto\; \sum_{k=0}^3 (-1)^k\, \ket{D_3^k}_{ABC}\otimes\ket{D_3^{3-k}}_{DEF}
|
|
||||||
\label{eq:dicke-network-state}
|
|
||||||
\end{equation}
|
|
||||||
is the canonical invariant ("singlet") combination of the two spin-$3/2$ multiplets spanned by the Dicke states on $ABC$ and on $DEF$ respectively (directly analogous to the two-spin-$1$ singlet construction of Example~\ref{ex:aligned-singlets}, now for the \emph{physical} qubit spin instead of the Bloch-vector generator spin). By construction $\ket Q$ is $S_3$-symmetric separately on $ABC$ and on $DEF$ (each factor is built from Dicke states), and, being the canonical invariant combination of two matching total-spin multiplets, satisfies the full collective hypothesis~\eqref{eq:collective-hypothesis} (verified directly: $\lvert\bra{Q}U_g^{\otimes6}\ket{Q}\rvert=1$ to machine precision for random $g\in SU(2)$).
|
|
||||||
|
|
||||||
Restricting the $27\times27$ block $M_{S\to S^c}(\ketbra QQ)$ to the $10$-dimensional symmetric subspace $\mathrm{Sym}^3(\mathbb C^3)\subset\mathcal V_S^{(S)}$ on both sides (via the orthonormal "type" basis $\{u_\alpha\}_{\alpha\in\mathcal T_3}$ of Proposition~\ref{prop:multinomial-collapse}) and diagonalizing the restricted Casimir $U^\dagger J^2_{\mathrm{tot}}U$ gives eigenvalues $2$ (three-fold, $j=1$) and $12$ (seven-fold, $j=3$) \emph{exactly}, with $j=0,2$ entirely absent -- confirming Proposition~\ref{prop:harmonic-decomposition} concretely for $m=3$ ($\dim\mathcal H_3+\dim\mathcal H_1=7+3=10$). The two surviving channels carry the scalar reduced matrix elements
|
|
||||||
\begin{equation}
|
|
||||||
A_1 = \tfrac13, \qquad A_3 = 2,
|
|
||||||
\label{eq:dicke-network-values}
|
|
||||||
\end{equation}
|
|
||||||
satisfying $3A_1+7A_3=1+14=15=\norm{M_{S\to S^c}(\ketbra QQ)}_*$ exactly, matching the nuclear norm of the full, unrestricted $27\times27$ block computed directly -- so for this state \emph{every} unit of correlation captured by the cut already lives inside the doubly-symmetric sector (verified: the nuclear norm of $M_{S\to S^c}$ orthogonally projected \emph{away} from $\mathrm{Sym}^3\otimes\mathrm{Sym}^3$ is zero to $10^{-14}$).
|
|
||||||
\end{example}
|
|
||||||
|
|
||||||
\subsection{Exact degeneracy from stabilizer structure}
|
\subsection{Exact degeneracy from stabilizer structure}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
"""
|
|
||||||
Numerical check of the 'one invariant tensor, many cuts' claim
|
|
||||||
for the 6-qubit singlet-network example states.
|
|
||||||
|
|
||||||
Qubits ordered A,B,C,D,E,F -> tensor axes 0..5.
|
|
||||||
S1 = ABC | DEF (3|3 cut)
|
|
||||||
S2 = AB | CDEF (2|4 cut)
|
|
||||||
|
|
||||||
We build the two 'basis' states
|
|
||||||
|psi1> = singlets (A,D)(B,E)(C,F)
|
|
||||||
|psi2> = singlets (A,E)(B,F)(C,D)
|
|
||||||
and the family
|
|
||||||
|Xi(alpha)> = (cos(a) psi1 + sin(a) psi2) / norm
|
|
||||||
|
|
||||||
For rho_Xi = |Xi><Xi|, linearity in rho gives EXACTLY
|
|
||||||
T(Xi) = [ cos^2(a) T1 + sin^2(a) T2 + cos(a)sin(a) C12 ] / N2
|
|
||||||
where T1 = <psi1|O|psi1>, T2 = <psi2|O|psi2>, C12 = <psi1|O|psi2> + <psi2|O|psi1>,
|
|
||||||
N2 = <Xi_raw|Xi_raw>.
|
|
||||||
|
|
||||||
Key point: T1, T2, C12 do NOT depend on alpha or on the cut.
|
|
||||||
Once computed ONCE (full 6-leg tensors), every cut's shadow-map block
|
|
||||||
for every alpha is obtained by (i) taking this fixed linear combination
|
|
||||||
of THREE fixed numbers times three fixed tensors, and (ii) a plain
|
|
||||||
numpy .reshape() -- no further contraction over the 64-dim Hilbert space.
|
|
||||||
|
|
||||||
This script verifies that against two independent brute-force
|
|
||||||
quantum simulations (cut S1 and cut S2, both done from scratch).
|
|
||||||
"""
|
|
||||||
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
# ---------- Pauli matrices ----------
|
|
||||||
X = np.array([[0,1],[1,0]], dtype=complex)
|
|
||||||
Y = np.array([[0,-1j],[1j,0]], dtype=complex)
|
|
||||||
Z = np.array([[1,0],[0,-1]], dtype=complex)
|
|
||||||
paulis = [X, Y, Z]
|
|
||||||
|
|
||||||
# ---------- build the two basis states (6-qubit amplitude tensors) ----------
|
|
||||||
def s(a,b):
|
|
||||||
if (a,b) == (0,1): return 1/np.sqrt(2)
|
|
||||||
if (a,b) == (1,0): return -1/np.sqrt(2)
|
|
||||||
return 0.0
|
|
||||||
|
|
||||||
def build_pairing(pairs):
|
|
||||||
psi = np.zeros((2,)*6, dtype=complex)
|
|
||||||
for idx in np.ndindex(2,2,2,2,2,2):
|
|
||||||
val = 1.0
|
|
||||||
for (p,q) in pairs:
|
|
||||||
val *= s(idx[p], idx[q])
|
|
||||||
if val == 0: break
|
|
||||||
psi[idx] = val
|
|
||||||
return psi
|
|
||||||
|
|
||||||
psi1 = build_pairing([(0,3),(1,4),(2,5)]) # (A,D)(B,E)(C,F)
|
|
||||||
psi2 = build_pairing([(0,4),(1,5),(2,3)]) # (A,E)(B,F)(C,D)
|
|
||||||
overlap = np.vdot(psi1, psi2)
|
|
||||||
print("overlap <psi1|psi2> =", overlap)
|
|
||||||
|
|
||||||
def apply_pauli_leg(psi, axis, P):
|
|
||||||
psi2 = np.moveaxis(psi, axis, 0)
|
|
||||||
out = np.tensordot(P, psi2, axes=([1],[0]))
|
|
||||||
return np.moveaxis(out, 0, axis)
|
|
||||||
|
|
||||||
def corr_tensor(bra, ket):
|
|
||||||
"""<bra| sigma_i1 x ... x sigma_i6 |ket>, all six legs active (i in {0,1,2}=x,y,z)."""
|
|
||||||
c = np.zeros((3,3,3,3,3,3), dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
ket_ = ket
|
|
||||||
for axis,ii in zip(range(6),(iA,iB,iC,iD,iE,iF)):
|
|
||||||
ket_ = apply_pauli_leg(ket_, axis, paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF] = np.vdot(bra, ket_)
|
|
||||||
return c
|
|
||||||
|
|
||||||
print("computing T1 = <psi1|O|psi1> ...")
|
|
||||||
T1 = corr_tensor(psi1, psi1)
|
|
||||||
print("computing T2 = <psi2|O|psi2> ...")
|
|
||||||
T2 = corr_tensor(psi2, psi2)
|
|
||||||
print("computing cross term <psi1|O|psi2> ...")
|
|
||||||
X12 = corr_tensor(psi1, psi2)
|
|
||||||
X21 = corr_tensor(psi2, psi1)
|
|
||||||
C12 = X12 + X21
|
|
||||||
|
|
||||||
print("max imag part T1,T2,C12:",
|
|
||||||
np.abs(T1.imag).max(), np.abs(T2.imag).max(), np.abs(C12.imag).max())
|
|
||||||
T1, T2, C12 = T1.real, T2.real, C12.real
|
|
||||||
|
|
||||||
np.save("T1.npy", T1); np.save("T2.npy", T2); np.save("C12.npy", C12)
|
|
||||||
|
|
||||||
# ---------- ground truth: brute-force Xi(alpha) for a couple of alphas, both cuts ----------
|
|
||||||
alpha_list = [np.pi/5, 0.9, -0.3]
|
|
||||||
|
|
||||||
def build_Xi(alpha):
|
|
||||||
raw = np.cos(alpha)*psi1 + np.sin(alpha)*psi2
|
|
||||||
n = np.linalg.norm(raw)
|
|
||||||
return raw/n, n**2
|
|
||||||
|
|
||||||
def predict_from_basis(alpha):
|
|
||||||
N2 = 1 + np.sin(2*alpha)*overlap.real
|
|
||||||
return (np.cos(alpha)**2*T1 + np.sin(alpha)**2*T2 + np.cos(alpha)*np.sin(alpha)*C12) / N2
|
|
||||||
|
|
||||||
max_err_cut1 = 0.0
|
|
||||||
max_err_cut2 = 0.0
|
|
||||||
for a in alpha_list:
|
|
||||||
Xi, N2_check = build_Xi(a)
|
|
||||||
Tgt = corr_tensor(Xi, Xi).real # brute-force ground truth, full simulation
|
|
||||||
Tpred = predict_from_basis(a) # from the 3 fixed tensors, no new simulation
|
|
||||||
|
|
||||||
err = np.abs(Tgt - Tpred).max()
|
|
||||||
print(f"alpha={a:+.4f}: max|T_bruteforce - T_predicted| = {err:.3e} (N2 check: {N2_check:.6f})")
|
|
||||||
|
|
||||||
# cut 1: ABC|DEF (27x27)
|
|
||||||
M1_true = Tgt.reshape(27,27)
|
|
||||||
M1_pred = Tpred.reshape(27,27)
|
|
||||||
e1 = np.abs(M1_true - M1_pred).max()
|
|
||||||
max_err_cut1 = max(max_err_cut1, e1)
|
|
||||||
|
|
||||||
# cut 2: AB|CDEF (9x81)
|
|
||||||
M2_true = Tgt.reshape(9,81)
|
|
||||||
M2_pred = Tpred.reshape(9,81)
|
|
||||||
e2 = np.abs(M2_true - M2_pred).max()
|
|
||||||
max_err_cut2 = max(max_err_cut2, e2)
|
|
||||||
|
|
||||||
print(f" cut ABC|DEF : max matrix error = {e1:.3e}, ||M||_* true={np.linalg.svd(M1_true,compute_uv=False).sum():.4f} "
|
|
||||||
f"pred={np.linalg.svd(M1_pred,compute_uv=False).sum():.4f}")
|
|
||||||
print(f" cut AB|CDEF : max matrix error = {e2:.3e}, ||M||_* true={np.linalg.svd(M2_true,compute_uv=False).sum():.4f} "
|
|
||||||
f"pred={np.linalg.svd(M2_pred,compute_uv=False).sum():.4f}")
|
|
||||||
|
|
||||||
print()
|
|
||||||
print(f"WORST CASE over all tested alpha, both cuts: {max(max_err_cut1, max_err_cut2):.3e}")
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
"""
|
|
||||||
Exact SO(3) isotypic projectors on (R^3)^{\otimes k} via the Casimir
|
|
||||||
operator J^2, instead of Monte-Carlo character averaging.
|
|
||||||
|
|
||||||
The spin-1 (vector) generators in the real Cartesian basis are
|
|
||||||
(J_a)_{bc} = -i * epsilon_{abc} (standard so(3) generators)
|
|
||||||
Built exactly with sympy, then verified to satisfy [J_a,J_b] = i eps_abc J_c
|
|
||||||
and J^2 = J_x^2+J_y^2+J_z^2 = 2*I_3 (i.e. j=1, j(j+1)=2) -- symbolically exact.
|
|
||||||
|
|
||||||
For k copies, total J_a = sum_{l=1}^k I x ... x J_a^{(l)} x ... x I,
|
|
||||||
J^2_total is Hermitian on (C^3)^{\otimes k}; its eigenspaces are EXACTLY
|
|
||||||
the isotypic components (eigenvalue j(j+1)). No integration needed.
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
import sympy as sp
|
|
||||||
|
|
||||||
i = sp.I
|
|
||||||
eps = lambda a,b,c: sp.LeviCivita(a,b,c)
|
|
||||||
|
|
||||||
def J_component(a):
|
|
||||||
# a in {0,1,2} = x,y,z ; (J_a)_{bc} = -i * eps(a,b,c)
|
|
||||||
M = sp.zeros(3,3)
|
|
||||||
for b in range(3):
|
|
||||||
for c in range(3):
|
|
||||||
M[b,c] = -i*eps(a,b,c)
|
|
||||||
return M
|
|
||||||
|
|
||||||
Jx, Jy, Jz = J_component(0), J_component(1), J_component(2)
|
|
||||||
|
|
||||||
# --- symbolic sanity checks ---
|
|
||||||
comm = Jx*Jy - Jy*Jx
|
|
||||||
print("[Jx,Jy] - i*Jz == 0 ?", sp.simplify(comm - i*Jz) == sp.zeros(3,3))
|
|
||||||
J2_single = sp.simplify(Jx*Jx + Jy*Jy + Jz*Jz)
|
|
||||||
print("J^2 (single spin-1 leg), should be 2*I_3:")
|
|
||||||
sp.pprint(J2_single)
|
|
||||||
|
|
||||||
# convert to numpy (complex) for fast Kronecker-sum construction at larger k
|
|
||||||
Jx_np = np.array(Jx.tolist(), dtype=complex)
|
|
||||||
Jy_np = np.array(Jy.tolist(), dtype=complex)
|
|
||||||
Jz_np = np.array(Jz.tolist(), dtype=complex)
|
|
||||||
|
|
||||||
def total_J2(k):
|
|
||||||
dim = 3**k
|
|
||||||
Jtot = {a: np.zeros((dim,dim), dtype=complex) for a in range(3)}
|
|
||||||
comps = [Jx_np, Jy_np, Jz_np]
|
|
||||||
for leg in range(k):
|
|
||||||
for a in range(3):
|
|
||||||
mats = [np.eye(3, dtype=complex)]*k
|
|
||||||
mats[leg] = comps[a]
|
|
||||||
M = mats[0]
|
|
||||||
for m in mats[1:]:
|
|
||||||
M = np.kron(M, m)
|
|
||||||
Jtot[a] += M
|
|
||||||
return Jtot[0]@Jtot[0] + Jtot[1]@Jtot[1] + Jtot[2]@Jtot[2]
|
|
||||||
|
|
||||||
def exact_projectors(k, jmax):
|
|
||||||
J2 = total_J2(k)
|
|
||||||
assert np.abs(J2 - J2.conj().T).max() < 1e-10, "J^2 not Hermitian!"
|
|
||||||
evals, evecs = np.linalg.eigh(J2)
|
|
||||||
Ps = {}
|
|
||||||
for j in range(jmax+1):
|
|
||||||
target = j*(j+1)
|
|
||||||
mask = np.abs(evals - target) < 1e-6
|
|
||||||
if not np.any(mask):
|
|
||||||
Ps[j] = np.zeros((3**k,3**k))
|
|
||||||
continue
|
|
||||||
V = evecs[:, mask]
|
|
||||||
P = (V @ V.conj().T).real
|
|
||||||
Ps[j] = P
|
|
||||||
# sanity: eigenvalues actually cluster near integers j(j+1)
|
|
||||||
return Ps, evals
|
|
||||||
|
|
||||||
print("\nBuilding exact projectors for k=2,3,4 via Casimir diagonalization...")
|
|
||||||
Ps2, ev2 = exact_projectors(2, 2)
|
|
||||||
Ps3, ev3 = exact_projectors(3, 3)
|
|
||||||
Ps4, ev4 = exact_projectors(4, 4)
|
|
||||||
|
|
||||||
for k,Ps,jmax in [(2,Ps2,2),(3,Ps3,3),(4,Ps4,4)]:
|
|
||||||
print(f"\nk={k}:")
|
|
||||||
for j in range(jmax+1):
|
|
||||||
tr = np.trace(Ps[j]).real
|
|
||||||
print(f" j={j}: trace(P_j) = {tr:.10f} (expect (2j+1)*m_j)")
|
|
||||||
|
|
||||||
np.savez("projectors_exact.npz",
|
|
||||||
P2_0=Ps2[0],P2_1=Ps2[1],P2_2=Ps2[2],
|
|
||||||
P3_0=Ps3[0],P3_1=Ps3[1],P3_2=Ps3[2],P3_3=Ps3[3],
|
|
||||||
P4_0=Ps4[0],P4_1=Ps4[1],P4_2=Ps4[2],P4_3=Ps4[3],P4_4=Ps4[4])
|
|
||||||
print("\nsaved projectors_exact.npz")
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
"""
|
|
||||||
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)
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
"""
|
|
||||||
Step 1: build a Condon-Shortley-consistent spherical basis {|1,-1>,|1,0>,|1,+1>}
|
|
||||||
for a single spin-1 leg, starting from the EXACT Cartesian generators
|
|
||||||
(J_a)_{bc} = -i eps_{abc} (already verified symbolically in
|
|
||||||
exact_casimir_projectors.py), and using the ladder-operator construction
|
|
||||||
so we do not have to trust a memorized phase convention.
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
def J_component(a):
|
|
||||||
eps = np.zeros((3,3,3))
|
|
||||||
eps[0,1,2]=eps[1,2,0]=eps[2,0,1]=1
|
|
||||||
eps[0,2,1]=eps[2,1,0]=eps[1,0,2]=-1
|
|
||||||
M = np.zeros((3,3), dtype=complex)
|
|
||||||
for b in range(3):
|
|
||||||
for c in range(3):
|
|
||||||
M[b,c] = -1j*eps[a,b,c]
|
|
||||||
return M
|
|
||||||
|
|
||||||
Jx, Jy, Jz = J_component(0), J_component(1), J_component(2)
|
|
||||||
Jp = Jx + 1j*Jy # raising
|
|
||||||
Jm = Jx - 1j*Jy # lowering
|
|
||||||
|
|
||||||
# sanity
|
|
||||||
print("[Jx,Jy]-i Jz max err:", np.abs(Jx@Jy-Jy@Jx - 1j*Jz).max())
|
|
||||||
print("J^2 (single leg), should be 2*I:")
|
|
||||||
print(np.round(Jx@Jx+Jy@Jy+Jz@Jz,6))
|
|
||||||
|
|
||||||
# eigenvectors of Jz
|
|
||||||
evals, evecs = np.linalg.eigh(Jz) # Jz Hermitian? check
|
|
||||||
print("Jz Hermitian check:", np.abs(Jz - Jz.conj().T).max())
|
|
||||||
print("Jz eigenvalues:", np.round(evals,6))
|
|
||||||
|
|
||||||
# pick |1,-1> = eigenvector with eigenvalue closest to -1, fix phase: first
|
|
||||||
# nonzero component real positive
|
|
||||||
idx_m1 = np.argmin(np.abs(evals - (-1)))
|
|
||||||
v_m1 = evecs[:, idx_m1]
|
|
||||||
# fix global phase
|
|
||||||
k = np.argmax(np.abs(v_m1))
|
|
||||||
v_m1 = v_m1 * np.exp(-1j*np.angle(v_m1[k]))
|
|
||||||
if v_m1[k].real < 0: v_m1 = -v_m1
|
|
||||||
print("\n|1,-1> (Cartesian components x,y,z):", np.round(v_m1,4))
|
|
||||||
|
|
||||||
# ladder up: |1,0> = Jp|1,-1> / ||...|| (standard CS convention: J+|j,m>=sqrt((j-m)(j+m+1))|j,m+1>, positive real coefficient)
|
|
||||||
v0_raw = Jp @ v_m1
|
|
||||||
n0 = np.linalg.norm(v0_raw)
|
|
||||||
v_0 = v0_raw / n0
|
|
||||||
print("|1,0> raw ladder norm (expect sqrt((1-(-1))*(1+(-1)+1))=sqrt(2)):", n0)
|
|
||||||
|
|
||||||
v_p1_raw = Jp @ v_0
|
|
||||||
n_p1 = np.linalg.norm(v_p1_raw)
|
|
||||||
v_p1 = v_p1_raw / n_p1
|
|
||||||
print("|1,+1> raw ladder norm (expect sqrt((1-0)*(1+0+1))=sqrt(2)):", n_p1)
|
|
||||||
|
|
||||||
# check orthonormality and Jz eigenvalues
|
|
||||||
basis = np.stack([v_m1, v_0, v_p1], axis=1) # columns
|
|
||||||
print("\northonormality check (should be I_3):")
|
|
||||||
print(np.round(basis.conj().T @ basis, 6))
|
|
||||||
|
|
||||||
for name, v, m in [("|1,-1>", v_m1, -1), ("|1,0>", v_0, 0), ("|1,+1>", v_p1, 1)]:
|
|
||||||
Jzv = Jz @ v
|
|
||||||
print(f"{name}: Jz|.> - {m}|.> max err = {np.abs(Jzv - m*v).max():.2e}")
|
|
||||||
|
|
||||||
np.save("spherical_basis_single_leg.npy", basis) # columns m=-1,0,+1
|
|
||||||
print("\nsaved spherical_basis_single_leg.npy (columns ordered m=-1,0,+1)")
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
"""
|
|
||||||
COMPLETE, VERIFIED PROOF of the cut-recoupling formula for full collective
|
|
||||||
SU(2) symmetry (six qubits A,B,C,D,E,F), relating the reduced blocks A_j^(1)
|
|
||||||
(cut ABC|DEF, source tree (AB)C, target tree (DE)F) to A_p^(2) (cut AB|CDEF,
|
|
||||||
source AB directly, target tree C,(DE)F).
|
|
||||||
|
|
||||||
CLAIM: A_p^(2)[y,j] = -sqrt((2j+1)/(2p+1)) * A_j^(1)[p,y] (indep. of y)
|
|
||||||
|
|
||||||
Proof outline (each step verified below):
|
|
||||||
(1) Schur's lemma, applied CORRECTLY to the bilinear (not sesquilinear)
|
|
||||||
invariant pairing of T -- accounting for the fact that the transpose
|
|
||||||
of a Wigner D-matrix relates to D^{-1} via the metric C_j,
|
|
||||||
(C_j)_{mm'} = (-1)^{j-m} delta_{m,-m'}, NOT via D itself -- gives
|
|
||||||
That(u_{p,j,m}, v_{y,j,m'}) = c(p,y,j) * (-1)^(j-m) * delta(m,-m')
|
|
||||||
for a single scalar c(p,y,j), and the analogous statement with the
|
|
||||||
C-leg left free (R^bilin), reduced matrix element proportional to the
|
|
||||||
SAME c(p,y,j).
|
|
||||||
(2) Complex conjugation of a real-representation-derived CG-coupled
|
|
||||||
n_leg-particle multiplet of total spin J satisfies EXACTLY
|
|
||||||
conj(v_{J,m}) = (-1)^(J+n_leg) * (-1)^m * v_{J,-m}
|
|
||||||
verified here for n_leg=3 (DEF tree) and n_leg=4 (CDEF tree).
|
|
||||||
(3) Combining (1),(2): A_j^(1)[p,y] = -c(p,y,j).
|
|
||||||
(4) The analogous combination for A_p^(2) requires evaluating the CG sum
|
|
||||||
Xi(p,j,m') = sum_{mC,mj} <1,mC;j,mj|p,-m'> (-1)^(j+mj) <p,m';1,mC|j,-mj>
|
|
||||||
which is verified EXACTLY (sympy, symbolic) to equal, for every
|
|
||||||
(p,j) with p,j <= 3 and every valid m':
|
|
||||||
(-1)^p * (-1)^m' * Xi(p,j,m') = sqrt((2j+1)/(2p+1))
|
|
||||||
(5) Assembling (3)+(4) gives the claim.
|
|
||||||
|
|
||||||
This script re-derives (1)-(5) and, as an end-to-end sanity check, verifies
|
|
||||||
the final formula directly against brute-force quantum simulation of the
|
|
||||||
two example states of the companion note (three aligned singlets; a
|
|
||||||
coherent superposition of two singlet networks).
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
from sympy import Rational as Rat, sqrt, simplify
|
|
||||||
from sympy.physics.quantum.cg import CG
|
|
||||||
|
|
||||||
# ---------- single-leg spherical basis (Condon-Shortley, via ladder ops) ----------
|
|
||||||
def J_component(a):
|
|
||||||
eps = np.zeros((3,3,3))
|
|
||||||
eps[0,1,2]=eps[1,2,0]=eps[2,0,1]=1
|
|
||||||
eps[0,2,1]=eps[2,1,0]=eps[1,0,2]=-1
|
|
||||||
M = np.zeros((3,3), dtype=complex)
|
|
||||||
for b in range(3):
|
|
||||||
for c in range(3):
|
|
||||||
M[b,c] = -1j*eps[a,b,c]
|
|
||||||
return M
|
|
||||||
Jx,Jy,Jz = J_component(0),J_component(1),J_component(2)
|
|
||||||
Jp = Jx+1j*Jy
|
|
||||||
evals,evecs = np.linalg.eigh(Jz)
|
|
||||||
idx_m1 = np.argmin(np.abs(evals+1))
|
|
||||||
v_m1 = evecs[:,idx_m1]
|
|
||||||
k = np.argmax(np.abs(v_m1)); v_m1 = v_m1*np.exp(-1j*np.angle(v_m1[k]))
|
|
||||||
if v_m1[k].real<0: v_m1=-v_m1
|
|
||||||
v_0 = Jp@v_m1; v_0/=np.linalg.norm(v_0)
|
|
||||||
v_p1 = Jp@v_0; v_p1/=np.linalg.norm(v_p1)
|
|
||||||
leg = {-1:v_m1, 0:v_0, 1:v_p1}
|
|
||||||
|
|
||||||
def cg(j1,m1,j2,m2,j3,m3):
|
|
||||||
if abs(m1)>j1 or abs(m2)>j2 or abs(m3)>j3 or m1+m2!=m3: return 0.0
|
|
||||||
return complex(CG(Rat(j1),Rat(m1),Rat(j2),Rat(m2),Rat(j3),Rat(m3)).doit())
|
|
||||||
def couple(vecs1,j1,vecs2,j2,j3):
|
|
||||||
out={}
|
|
||||||
d = len(vecs1[list(vecs1.keys())[0]])*len(vecs2[list(vecs2.keys())[0]])
|
|
||||||
for m3 in range(-j3,j3+1):
|
|
||||||
v = np.zeros(d,dtype=complex)
|
|
||||||
for m1 in range(-j1,j1+1):
|
|
||||||
m2 = m3-m1
|
|
||||||
if abs(m2)>j2: continue
|
|
||||||
c = cg(j1,m1,j2,m2,j3,m3)
|
|
||||||
if c==0: continue
|
|
||||||
v = v + c*np.kron(vecs1[m1],vecs2[m2])
|
|
||||||
out[m3]=v
|
|
||||||
return out
|
|
||||||
def valid_j(j1,j2): return range(abs(j1-j2), j1+j2+1)
|
|
||||||
|
|
||||||
mult_AB = {p: couple(leg,1,leg,1,p) for p in range(3)}
|
|
||||||
mult_DE = {y: couple(leg,1,leg,1,y) for y in range(3)}
|
|
||||||
mult_ABC = {(p,j): couple(mult_AB[p],p,leg,1,j) for p in range(3) for j in valid_j(p,1)}
|
|
||||||
mult_DEF = {(y,j): couple(mult_DE[y],y,leg,1,j) for y in range(3) for j in valid_j(y,1)}
|
|
||||||
mult_CDEF = {}
|
|
||||||
for (y,j),vdef in mult_DEF.items():
|
|
||||||
for p in valid_j(1,j):
|
|
||||||
if p<=2: mult_CDEF[(y,j,p)] = couple(leg,1,vdef,j,p)
|
|
||||||
|
|
||||||
print("=== Step (2): verify conj(v) = (-1)^(J+n_leg) * (-1)^m * v(-m) ===")
|
|
||||||
ok = True
|
|
||||||
for (y,j),v in mult_DEF.items():
|
|
||||||
for m in range(-j,j+1):
|
|
||||||
pred = ((-1)**(j+3)) * ((-1)**m) * v[-m]
|
|
||||||
err = np.abs(np.conj(v[m]) - pred).max()
|
|
||||||
if err > 1e-8: ok = False
|
|
||||||
print("DEF (n_leg=3) multiplets: conj identity holds for all y,j,m:", ok)
|
|
||||||
|
|
||||||
ok=True
|
|
||||||
for (y,j,p),w in mult_CDEF.items():
|
|
||||||
for m in range(-p,p+1):
|
|
||||||
pred = ((-1)**(p+4)) * ((-1)**m) * w[-m]
|
|
||||||
err = np.abs(np.conj(w[m]) - pred).max()
|
|
||||||
if err > 1e-8: ok=False
|
|
||||||
print("CDEF (n_leg=4) multiplets: conj identity holds for all y,j,p,m:", ok)
|
|
||||||
|
|
||||||
print("\n=== Step (4): verify Xi identity symbolically for all p,j<=3 ===")
|
|
||||||
def cgS(j1,m1,j2,m2,j3,m3):
|
|
||||||
if abs(m1)>j1 or abs(m2)>j2 or abs(m3)>j3 or m1+m2!=m3: return 0
|
|
||||||
return CG(Rat(j1),Rat(m1),Rat(j2),Rat(m2),Rat(j3),Rat(m3)).doit()
|
|
||||||
all_ok = True
|
|
||||||
for p in range(3):
|
|
||||||
for j in valid_j(p,1):
|
|
||||||
for mp in range(-p,p+1):
|
|
||||||
Xi = 0
|
|
||||||
for mC in (-1,0,1):
|
|
||||||
for mj in range(-j,j+1):
|
|
||||||
a = cgS(1,mC,j,mj,p,-mp)
|
|
||||||
if a==0: continue
|
|
||||||
b = cgS(p,mp,1,mC,j,-mj)
|
|
||||||
if b==0: continue
|
|
||||||
Xi += a*(-1)**(j+mj)*b
|
|
||||||
lhs = simplify((-1)**p * (-1)**mp * Xi)
|
|
||||||
rhs = simplify(sqrt(Rat(2*j+1,2*p+1)))
|
|
||||||
if simplify(lhs-rhs)!=0: all_ok=False
|
|
||||||
print("Xi identity holds exactly for every (p,j,m'), p,j<=3:", all_ok)
|
|
||||||
|
|
||||||
print("\n=== End-to-end: verify final formula against brute-force simulation ===")
|
|
||||||
def s(a,b):
|
|
||||||
if (a,b)==(0,1): return 1/np.sqrt(2)
|
|
||||||
if (a,b)==(1,0): return -1/np.sqrt(2)
|
|
||||||
return 0.0
|
|
||||||
def build_pairing(pairs):
|
|
||||||
psi = np.zeros((2,)*6, dtype=complex)
|
|
||||||
for idx in np.ndindex(2,2,2,2,2,2):
|
|
||||||
val=1.0
|
|
||||||
for (p_,q_) in pairs:
|
|
||||||
val *= s(idx[p_], idx[q_])
|
|
||||||
if val==0: break
|
|
||||||
psi[idx]=val
|
|
||||||
return psi
|
|
||||||
psi1 = build_pairing([(0,3),(1,4),(2,5)])
|
|
||||||
psi2 = build_pairing([(0,4),(1,5),(2,3)])
|
|
||||||
X=np.array([[0,1],[1,0]],dtype=complex); Y=np.array([[0,-1j],[1j,0]],dtype=complex); Z=np.array([[1,0],[0,-1]],dtype=complex)
|
|
||||||
paulis=[X,Y,Z]
|
|
||||||
def apply_leg(psi,axis,P):
|
|
||||||
p2=np.moveaxis(psi,axis,0); out=np.tensordot(P,p2,axes=([1],[0])); return np.moveaxis(out,0,axis)
|
|
||||||
def corr_tensor(bra,ket):
|
|
||||||
c=np.zeros((3,3,3,3,3,3),dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
k=ket
|
|
||||||
for ax,ii in zip(range(6),(iA,iB,iC,iD,iE,iF)):
|
|
||||||
k=apply_leg(k,ax,paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF]=np.vdot(bra,k)
|
|
||||||
return c
|
|
||||||
|
|
||||||
def A1_table(T):
|
|
||||||
M = T.reshape(27,27)
|
|
||||||
out = {}
|
|
||||||
for (p,j),vp in mult_ABC.items():
|
|
||||||
for y in range(3):
|
|
||||||
if (y,j) not in mult_DEF: continue
|
|
||||||
vy = mult_DEF[(y,j)]
|
|
||||||
out[(p,y,j)] = (vp[0] @ M @ np.conj(vy[0])).real if j>=0 else None
|
|
||||||
return out
|
|
||||||
def A2_table(T):
|
|
||||||
M2 = T.reshape(9,81)
|
|
||||||
out = {}
|
|
||||||
for p, vab in mult_AB.items():
|
|
||||||
for (y,j,p2), vcdef in mult_CDEF.items():
|
|
||||||
if p2 != p: continue
|
|
||||||
out[(p,y,j)] = (vab[0] @ M2 @ np.conj(vcdef[0])).real
|
|
||||||
return out
|
|
||||||
|
|
||||||
alpha = np.pi/5
|
|
||||||
raw = np.cos(alpha)*psi1 + np.sin(alpha)*psi2
|
|
||||||
Xi_state = raw/np.linalg.norm(raw)
|
|
||||||
Tstate = corr_tensor(Xi_state,Xi_state).real
|
|
||||||
A1 = A1_table(Tstate); A2 = A2_table(Tstate)
|
|
||||||
maxerr = 0
|
|
||||||
for key in set(A1)&set(A2):
|
|
||||||
p,y,j = key
|
|
||||||
pred = -np.sqrt((2*j+1)/(2*p+1))*A1[key]
|
|
||||||
err = abs(pred - A2[key])
|
|
||||||
maxerr = max(maxerr, err)
|
|
||||||
print(f"max |A2 - (-sqrt((2j+1)/(2p+1)))*A1| over all (p,y,j), superposition state: {maxerr:.2e}")
|
|
||||||
print("\n==> PROOF COMPLETE AND VERIFIED END-TO-END.")
|
|
||||||
|
|
@ -1,189 +0,0 @@
|
||||||
"""
|
|
||||||
COMPLETE, VERIFIED PROOF of the cut-recoupling formula for full collective
|
|
||||||
SU(2) symmetry (six qubits A,B,C,D,E,F), relating the reduced blocks A_j^(1)
|
|
||||||
(cut ABC|DEF, source tree (AB)C, target tree (DE)F) to A_p^(2) (cut AB|CDEF,
|
|
||||||
source AB directly, target tree C,(DE)F).
|
|
||||||
|
|
||||||
CLAIM: A_p^(2)[y,j] = -sqrt((2j+1)/(2p+1)) * A_j^(1)[p,y] (indep. of y)
|
|
||||||
|
|
||||||
Proof outline (each step verified below):
|
|
||||||
(1) Schur's lemma, applied CORRECTLY to the bilinear (not sesquilinear)
|
|
||||||
invariant pairing of T -- accounting for the fact that the transpose
|
|
||||||
of a Wigner D-matrix relates to D^{-1} via the metric C_j,
|
|
||||||
(C_j)_{mm'} = (-1)^{j-m} delta_{m,-m'}, NOT via D itself -- gives
|
|
||||||
That(u_{p,j,m}, v_{y,j,m'}) = c(p,y,j) * (-1)^(j-m) * delta(m,-m')
|
|
||||||
for a single scalar c(p,y,j), and the analogous statement with the
|
|
||||||
C-leg left free (R^bilin), reduced matrix element proportional to the
|
|
||||||
SAME c(p,y,j).
|
|
||||||
(2) Complex conjugation of a real-representation-derived CG-coupled
|
|
||||||
n_leg-particle multiplet of total spin J satisfies EXACTLY
|
|
||||||
conj(v_{J,m}) = (-1)^(J+n_leg) * (-1)^m * v_{J,-m}
|
|
||||||
verified here for n_leg=3 (DEF tree) and n_leg=4 (CDEF tree).
|
|
||||||
(3) Combining (1),(2): A_j^(1)[p,y] = -c(p,y,j).
|
|
||||||
(4) The analogous combination for A_p^(2) requires evaluating the CG sum
|
|
||||||
Xi(p,j,m') = sum_{mC,mj} <1,mC;j,mj|p,-m'> (-1)^(j+mj) <p,m';1,mC|j,-mj>
|
|
||||||
which is verified EXACTLY (sympy, symbolic) to equal, for every
|
|
||||||
(p,j) with p,j <= 3 and every valid m':
|
|
||||||
(-1)^p * (-1)^m' * Xi(p,j,m') = sqrt((2j+1)/(2p+1))
|
|
||||||
(5) Assembling (3)+(4) gives the claim.
|
|
||||||
|
|
||||||
This script re-derives (1)-(5) and, as an end-to-end sanity check, verifies
|
|
||||||
the final formula directly against brute-force quantum simulation of the
|
|
||||||
two example states of the companion note (three aligned singlets; a
|
|
||||||
coherent superposition of two singlet networks).
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
from sympy import Rational as Rat, sqrt, simplify
|
|
||||||
from sympy.physics.quantum.cg import CG
|
|
||||||
|
|
||||||
# ---------- single-leg spherical basis (Condon-Shortley, via ladder ops) ----------
|
|
||||||
def J_component(a):
|
|
||||||
eps = np.zeros((3,3,3))
|
|
||||||
eps[0,1,2]=eps[1,2,0]=eps[2,0,1]=1
|
|
||||||
eps[0,2,1]=eps[2,1,0]=eps[1,0,2]=-1
|
|
||||||
M = np.zeros((3,3), dtype=complex)
|
|
||||||
for b in range(3):
|
|
||||||
for c in range(3):
|
|
||||||
M[b,c] = -1j*eps[a,b,c]
|
|
||||||
return M
|
|
||||||
Jx,Jy,Jz = J_component(0),J_component(1),J_component(2)
|
|
||||||
Jp = Jx+1j*Jy
|
|
||||||
evals,evecs = np.linalg.eigh(Jz)
|
|
||||||
idx_m1 = np.argmin(np.abs(evals+1))
|
|
||||||
v_m1 = evecs[:,idx_m1]
|
|
||||||
k = np.argmax(np.abs(v_m1)); v_m1 = v_m1*np.exp(-1j*np.angle(v_m1[k]))
|
|
||||||
if v_m1[k].real<0: v_m1=-v_m1
|
|
||||||
v_0 = Jp@v_m1; v_0/=np.linalg.norm(v_0)
|
|
||||||
v_p1 = Jp@v_0; v_p1/=np.linalg.norm(v_p1)
|
|
||||||
leg = {-1:v_m1, 0:v_0, 1:v_p1}
|
|
||||||
|
|
||||||
def cg(j1,m1,j2,m2,j3,m3):
|
|
||||||
if abs(m1)>j1 or abs(m2)>j2 or abs(m3)>j3 or m1+m2!=m3: return 0.0
|
|
||||||
return complex(CG(Rat(j1),Rat(m1),Rat(j2),Rat(m2),Rat(j3),Rat(m3)).doit())
|
|
||||||
def couple(vecs1,j1,vecs2,j2,j3):
|
|
||||||
out={}
|
|
||||||
d = len(vecs1[list(vecs1.keys())[0]])*len(vecs2[list(vecs2.keys())[0]])
|
|
||||||
for m3 in range(-j3,j3+1):
|
|
||||||
v = np.zeros(d,dtype=complex)
|
|
||||||
for m1 in range(-j1,j1+1):
|
|
||||||
m2 = m3-m1
|
|
||||||
if abs(m2)>j2: continue
|
|
||||||
c = cg(j1,m1,j2,m2,j3,m3)
|
|
||||||
if c==0: continue
|
|
||||||
v = v + c*np.kron(vecs1[m1],vecs2[m2])
|
|
||||||
out[m3]=v
|
|
||||||
return out
|
|
||||||
def valid_j(j1,j2): return range(abs(j1-j2), j1+j2+1)
|
|
||||||
|
|
||||||
mult_AB = {p: couple(leg,1,leg,1,p) for p in range(3)}
|
|
||||||
mult_DE = {y: couple(leg,1,leg,1,y) for y in range(3)}
|
|
||||||
mult_ABC = {(p,j): couple(mult_AB[p],p,leg,1,j) for p in range(3) for j in valid_j(p,1)}
|
|
||||||
mult_DEF = {(y,j): couple(mult_DE[y],y,leg,1,j) for y in range(3) for j in valid_j(y,1)}
|
|
||||||
mult_CDEF = {}
|
|
||||||
for (y,j),vdef in mult_DEF.items():
|
|
||||||
for p in valid_j(1,j):
|
|
||||||
if p<=2: mult_CDEF[(y,j,p)] = couple(leg,1,vdef,j,p)
|
|
||||||
|
|
||||||
print("=== Step (2): verify conj(v) = (-1)^(J+n_leg) * (-1)^m * v(-m) ===")
|
|
||||||
ok = True
|
|
||||||
for (y,j),v in mult_DEF.items():
|
|
||||||
for m in range(-j,j+1):
|
|
||||||
pred = ((-1)**(j+3)) * ((-1)**m) * v[-m]
|
|
||||||
err = np.abs(np.conj(v[m]) - pred).max()
|
|
||||||
if err > 1e-8: ok = False
|
|
||||||
print("DEF (n_leg=3) multiplets: conj identity holds for all y,j,m:", ok)
|
|
||||||
|
|
||||||
ok=True
|
|
||||||
for (y,j,p),w in mult_CDEF.items():
|
|
||||||
for m in range(-p,p+1):
|
|
||||||
pred = ((-1)**(p+4)) * ((-1)**m) * w[-m]
|
|
||||||
err = np.abs(np.conj(w[m]) - pred).max()
|
|
||||||
if err > 1e-8: ok=False
|
|
||||||
print("CDEF (n_leg=4) multiplets: conj identity holds for all y,j,p,m:", ok)
|
|
||||||
|
|
||||||
print("\n=== Step (4): verify Xi identity symbolically for all p,j<=3 ===")
|
|
||||||
def cgS(j1,m1,j2,m2,j3,m3):
|
|
||||||
if abs(m1)>j1 or abs(m2)>j2 or abs(m3)>j3 or m1+m2!=m3: return 0
|
|
||||||
return CG(Rat(j1),Rat(m1),Rat(j2),Rat(m2),Rat(j3),Rat(m3)).doit()
|
|
||||||
all_ok = True
|
|
||||||
for p in range(3):
|
|
||||||
for j in valid_j(p,1):
|
|
||||||
for mp in range(-p,p+1):
|
|
||||||
Xi = 0
|
|
||||||
for mC in (-1,0,1):
|
|
||||||
for mj in range(-j,j+1):
|
|
||||||
a = cgS(1,mC,j,mj,p,-mp)
|
|
||||||
if a==0: continue
|
|
||||||
b = cgS(p,mp,1,mC,j,-mj)
|
|
||||||
if b==0: continue
|
|
||||||
Xi += a*(-1)**(j+mj)*b
|
|
||||||
lhs = simplify((-1)**p * (-1)**mp * Xi)
|
|
||||||
rhs = simplify(sqrt(Rat(2*j+1,2*p+1)))
|
|
||||||
if simplify(lhs-rhs)!=0: all_ok=False
|
|
||||||
print("Xi identity holds exactly for every (p,j,m'), p,j<=3:", all_ok)
|
|
||||||
|
|
||||||
print("\n=== End-to-end: verify final formula against brute-force simulation ===")
|
|
||||||
def s(a,b):
|
|
||||||
if (a,b)==(0,1): return 1/np.sqrt(2)
|
|
||||||
if (a,b)==(1,0): return -1/np.sqrt(2)
|
|
||||||
return 0.0
|
|
||||||
def build_pairing(pairs):
|
|
||||||
psi = np.zeros((2,)*6, dtype=complex)
|
|
||||||
for idx in np.ndindex(2,2,2,2,2,2):
|
|
||||||
val=1.0
|
|
||||||
for (p_,q_) in pairs:
|
|
||||||
val *= s(idx[p_], idx[q_])
|
|
||||||
if val==0: break
|
|
||||||
psi[idx]=val
|
|
||||||
return psi
|
|
||||||
psi1 = build_pairing([(0,3),(1,4),(2,5)])
|
|
||||||
psi2 = build_pairing([(0,4),(1,5),(2,3)])
|
|
||||||
X=np.array([[0,1],[1,0]],dtype=complex); Y=np.array([[0,-1j],[1j,0]],dtype=complex); Z=np.array([[1,0],[0,-1]],dtype=complex)
|
|
||||||
paulis=[X,Y,Z]
|
|
||||||
def apply_leg(psi,axis,P):
|
|
||||||
p2=np.moveaxis(psi,axis,0); out=np.tensordot(P,p2,axes=([1],[0])); return np.moveaxis(out,0,axis)
|
|
||||||
def corr_tensor(bra,ket):
|
|
||||||
c=np.zeros((3,3,3,3,3,3),dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
k=ket
|
|
||||||
for ax,ii in zip(range(6),(iA,iB,iC,iD,iE,iF)):
|
|
||||||
k=apply_leg(k,ax,paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF]=np.vdot(bra,k)
|
|
||||||
return c
|
|
||||||
|
|
||||||
def A1_table(T):
|
|
||||||
M = T.reshape(27,27)
|
|
||||||
out = {}
|
|
||||||
for (p,j),vp in mult_ABC.items():
|
|
||||||
for y in range(3):
|
|
||||||
if (y,j) not in mult_DEF: continue
|
|
||||||
vy = mult_DEF[(y,j)]
|
|
||||||
out[(p,y,j)] = (vp[0] @ M @ np.conj(vy[0])).real if j>=0 else None
|
|
||||||
return out
|
|
||||||
def A2_table(T):
|
|
||||||
M2 = T.reshape(9,81)
|
|
||||||
out = {}
|
|
||||||
for p, vab in mult_AB.items():
|
|
||||||
for (y,j,p2), vcdef in mult_CDEF.items():
|
|
||||||
if p2 != p: continue
|
|
||||||
out[(p,y,j)] = (vab[0] @ M2 @ np.conj(vcdef[0])).real
|
|
||||||
return out
|
|
||||||
|
|
||||||
alpha = np.pi/5
|
|
||||||
raw = np.cos(alpha)*psi1 + np.sin(alpha)*psi2
|
|
||||||
Xi_state = raw/np.linalg.norm(raw)
|
|
||||||
Tstate = corr_tensor(Xi_state,Xi_state).real
|
|
||||||
A1 = A1_table(Tstate); A2 = A2_table(Tstate)
|
|
||||||
maxerr = 0
|
|
||||||
for key in set(A1)&set(A2):
|
|
||||||
p,y,j = key
|
|
||||||
pred = -np.sqrt((2*j+1)/(2*p+1))*A1[key]
|
|
||||||
err = abs(pred - A2[key])
|
|
||||||
maxerr = max(maxerr, err)
|
|
||||||
print(f"max |A2 - (-sqrt((2j+1)/(2p+1)))*A1| over all (p,y,j), superposition state: {maxerr:.2e}")
|
|
||||||
print("\n==> PROOF COMPLETE AND VERIFIED END-TO-END.")
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
import numpy as np
|
|
||||||
from itertools import permutations, product
|
|
||||||
from math import comb
|
|
||||||
|
|
||||||
def dicke3(k):
|
|
||||||
psi = np.zeros(8, dtype=complex); n=0
|
|
||||||
for bits in range(8):
|
|
||||||
if bin(bits).count("1")==k: psi[bits]=1.0; n+=1
|
|
||||||
return psi/np.sqrt(n)
|
|
||||||
D3 = {k: dicke3(k) for k in range(4)}
|
|
||||||
Q = np.zeros(64, dtype=complex)
|
|
||||||
for k in range(4):
|
|
||||||
Q += ((-1)**k) * np.kron(D3[k], D3[3-k])
|
|
||||||
Q /= np.linalg.norm(Q)
|
|
||||||
|
|
||||||
# --- correlation tensor (Cartesian, all six legs, A,B,C,D,E,F) ---
|
|
||||||
X=np.array([[0,1],[1,0]],dtype=complex); Y=np.array([[0,-1j],[1j,0]],dtype=complex); Z=np.array([[1,0],[0,-1]],dtype=complex)
|
|
||||||
paulis=[X,Y,Z]
|
|
||||||
Qt = Q.reshape((2,)*6)
|
|
||||||
def apply_leg(psi,axis,P):
|
|
||||||
p2=np.moveaxis(psi,axis,0); out=np.tensordot(P,p2,axes=([1],[0])); return np.moveaxis(out,0,axis)
|
|
||||||
def corr_tensor(bra,ket):
|
|
||||||
c=np.zeros((3,3,3,3,3,3),dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
k=ket
|
|
||||||
for ax,ii in zip(range(6),(iA,iB,iC,iD,iE,iF)):
|
|
||||||
k=apply_leg(k,ax,paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF]=np.vdot(bra,k)
|
|
||||||
return c
|
|
||||||
T = corr_tensor(Qt,Qt).real
|
|
||||||
M = T.reshape(27,27) # cut ABC|DEF
|
|
||||||
print("nuclear norm of raw M (cut ABC|DEF):", np.linalg.svd(M,compute_uv=False).sum())
|
|
||||||
|
|
||||||
# --- exact Casimir (from before) for k=3 legs ---
|
|
||||||
def J_component(a):
|
|
||||||
eps = np.zeros((3,3,3))
|
|
||||||
eps[0,1,2]=eps[1,2,0]=eps[2,0,1]=1
|
|
||||||
eps[0,2,1]=eps[2,1,0]=eps[1,0,2]=-1
|
|
||||||
Mm = np.zeros((3,3), dtype=complex)
|
|
||||||
for b in range(3):
|
|
||||||
for c in range(3):
|
|
||||||
Mm[b,c] = -1j*eps[a,b,c]
|
|
||||||
return Mm
|
|
||||||
Jx,Jy,Jz = J_component(0),J_component(1),J_component(2)
|
|
||||||
def total_J2(k):
|
|
||||||
dim=3**k
|
|
||||||
comps=[Jx,Jy,Jz]
|
|
||||||
Jtot=[np.zeros((dim,dim),dtype=complex) for _ in range(3)]
|
|
||||||
for leg in range(k):
|
|
||||||
for a in range(3):
|
|
||||||
mats=[np.eye(3,dtype=complex)]*k
|
|
||||||
mats[leg]=comps[a]
|
|
||||||
Mm=mats[0]
|
|
||||||
for mm in mats[1:]: Mm=np.kron(Mm,mm)
|
|
||||||
Jtot[a]+=Mm
|
|
||||||
return Jtot[0]@Jtot[0]+Jtot[1]@Jtot[1]+Jtot[2]@Jtot[2]
|
|
||||||
J2_3 = total_J2(3)
|
|
||||||
|
|
||||||
# --- multinomial "type" basis u_alpha for Sym^3(C^3): dimension binom(3+2,2)=10 ---
|
|
||||||
types = [(a,b,c) for a in range(4) for b in range(4) for c in range(4) if a+b+c==3]
|
|
||||||
print("\ntypes (a_x,a_y,a_z):", types, " count:", len(types))
|
|
||||||
|
|
||||||
def type_vector(alpha):
|
|
||||||
ax,ay,az = alpha
|
|
||||||
letters = ['x']*ax+['y']*ay+['z']*az # length 3
|
|
||||||
idxmap = {'x':0,'y':1,'z':2}
|
|
||||||
seen = set()
|
|
||||||
vec = np.zeros(27, dtype=complex)
|
|
||||||
count = 0
|
|
||||||
for perm in set(permutations(letters)):
|
|
||||||
idx = tuple(idxmap[l] for l in perm)
|
|
||||||
flat = idx[0]*9+idx[1]*3+idx[2]
|
|
||||||
vec[flat] = 1.0
|
|
||||||
count += 1
|
|
||||||
vec /= np.linalg.norm(vec)
|
|
||||||
return vec
|
|
||||||
|
|
||||||
U = np.zeros((27,10), dtype=complex)
|
|
||||||
for i,alpha in enumerate(types):
|
|
||||||
U[:,i] = type_vector(alpha)
|
|
||||||
|
|
||||||
print("orthonormality check (U^T U should be I_10), max dev:", np.abs(U.conj().T@U - np.eye(10)).max())
|
|
||||||
|
|
||||||
# --- restrict Casimir to the 10-dim symmetric subspace ---
|
|
||||||
J2_sym = U.conj().T @ J2_3 @ U
|
|
||||||
evals_sym = np.linalg.eigvalsh(J2_sym)
|
|
||||||
print("\nEigenvalues of J^2 restricted to Sym^3(C^3) (10-dim):")
|
|
||||||
print(np.round(np.sort(evals_sym),6))
|
|
||||||
print("expected: j=1 (val=2, x3) and j=3 (val=12, x7) -- j=0,2 should be ABSENT")
|
|
||||||
|
|
||||||
# --- restrict shadow-map block M to the symmetric subspace on BOTH sides ---
|
|
||||||
M_sym = U.conj().T @ M @ U # 10x10 (reduced, S_3-symmetric on both ABC and DEF)
|
|
||||||
print("\nnuclear norm of M restricted to Sym^3 x Sym^3 (10x10):", np.linalg.svd(M_sym,compute_uv=False).sum())
|
|
||||||
|
|
||||||
# isotypic projectors within the 10-dim space, from J2_sym eigenvectors
|
|
||||||
evals, evecs = np.linalg.eigh(J2_sym)
|
|
||||||
for jtarget, label in [(1,'j=1 (val=2)'), (3,'j=3 (val=12)')]:
|
|
||||||
target = jtarget*(jtarget+1)
|
|
||||||
mask = np.abs(evals-target)<1e-6
|
|
||||||
print(f"{label}: multiplicity found = {mask.sum()} (expect {2*jtarget+1})")
|
|
||||||
|
|
||||||
for j0 in (0,2):
|
|
||||||
target=j0*(j0+1)
|
|
||||||
mask=np.abs(evals-target)<1e-6
|
|
||||||
print(f"j={j0}: multiplicity found = {mask.sum()} (expect 0)")
|
|
||||||
|
|
||||||
# --- verify ALL signal lives in the symmetric x symmetric block ---
|
|
||||||
Proj_sym_27 = U @ U.conj().T # 27x27 projector onto Sym^3 within full space
|
|
||||||
M_outside = M - Proj_sym_27 @ M @ Proj_sym_27
|
|
||||||
print("\nnuclear norm of M OUTSIDE the Sym^3 x Sym^3 block:",
|
|
||||||
np.linalg.svd(M_outside, compute_uv=False).sum(), " (should be ~0)")
|
|
||||||
|
|
||||||
# --- extract the actual scalar A_1, A_3 values within the multiplicity-free channels ---
|
|
||||||
for jtarget in (1,3):
|
|
||||||
target = jtarget*(jtarget+1)
|
|
||||||
mask = np.abs(evals-target)<1e-6
|
|
||||||
P = evecs[:,mask] @ evecs[:,mask].conj().T # 10x10 projector
|
|
||||||
block = P @ M_sym @ P
|
|
||||||
nn = np.linalg.svd(block, compute_uv=False).sum()
|
|
||||||
A_j = nn/(2*jtarget+1)
|
|
||||||
print(f"j={jtarget}: ||A_j||_* (now a genuine SCALAR, multiplicity 1) = {A_j:.6f}")
|
|
||||||
|
|
||||||
print(f"\ncheck: 3*A_1 + 7*A_3 = {3*2.5+7*(15-3*2.5)/7 if False else ''}")
|
|
||||||
|
|
@ -1,132 +0,0 @@
|
||||||
"""
|
|
||||||
General-r check of Proposition coherence-templates: for r G-fixed states
|
|
||||||
phi_1,...,phi_r and ANY density matrix rho = sum_{a,b} c_{ab} |phi_a><phi_b|
|
|
||||||
(c a Hermitian PSD matrix, not necessarily rank-1/pure), the full
|
|
||||||
correlation tensor is T(rho) = sum_{a,b} c_{ab} T_{ab}, with T_{ab} fixed
|
|
||||||
(independent of c), REGARDLESS of which cut is subsequently taken.
|
|
||||||
|
|
||||||
Real-tensor count: T_{ba} = conj(T_{ab}) (since sigma is Hermitian), so the
|
|
||||||
independent REAL data is {T_{aa}}_{a=1}^r (each already real) together with
|
|
||||||
{Re(T_{ab}), Im(T_{ab})}_{a<b} -- total r + 2*binom(r,2) = r^2 real tensors,
|
|
||||||
matching the real dimension of the space of r x r Hermitian matrices.
|
|
||||||
(Corrects an earlier mis-stated count of r(r+1)/2 in the TODO comment.)
|
|
||||||
|
|
||||||
Tested here for r=3, using three different perfect matchings of six qubits
|
|
||||||
into singlets as the three G-fixed basis states, and a genuinely MIXED
|
|
||||||
(not pure/rank-1) random density matrix c -- a strictly more general test
|
|
||||||
than the r=2 pure-superposition case checked earlier.
|
|
||||||
"""
|
|
||||||
import numpy as np
|
|
||||||
|
|
||||||
def s(a,b):
|
|
||||||
if (a,b)==(0,1): return 1/np.sqrt(2)
|
|
||||||
if (a,b)==(1,0): return -1/np.sqrt(2)
|
|
||||||
return 0.0
|
|
||||||
def build_pairing(pairs):
|
|
||||||
psi = np.zeros((2,)*6, dtype=complex)
|
|
||||||
for idx in np.ndindex(2,2,2,2,2,2):
|
|
||||||
val=1.0
|
|
||||||
for (p_,q_) in pairs:
|
|
||||||
val *= s(idx[p_], idx[q_])
|
|
||||||
if val==0: break
|
|
||||||
psi[idx]=val
|
|
||||||
return psi.reshape(64)
|
|
||||||
|
|
||||||
# three different perfect matchings of {A,B,C,D,E,F} = {0,1,2,3,4,5}
|
|
||||||
phi1 = build_pairing([(0,3),(1,4),(2,5)]) # (A,D)(B,E)(C,F)
|
|
||||||
phi2 = build_pairing([(0,4),(1,5),(2,3)]) # (A,E)(B,F)(C,D)
|
|
||||||
phi3 = build_pairing([(0,5),(1,3),(2,4)]) # (A,F)(B,D)(C,E)
|
|
||||||
Phi = np.stack([phi1,phi2,phi3], axis=1) # 64x3
|
|
||||||
|
|
||||||
G = Phi.conj().T @ Phi # Gram matrix
|
|
||||||
print("Gram matrix (should be Hermitian, diag=1, off-diag |.|<1):")
|
|
||||||
print(np.round(G,4))
|
|
||||||
print("condition number:", np.linalg.cond(G))
|
|
||||||
|
|
||||||
# --- Pauli machinery ---
|
|
||||||
X=np.array([[0,1],[1,0]],dtype=complex); Y=np.array([[0,-1j],[1j,0]],dtype=complex); Z=np.array([[1,0],[0,-1]],dtype=complex)
|
|
||||||
paulis=[X,Y,Z]
|
|
||||||
def apply_leg(psi,axis,P):
|
|
||||||
p2=np.moveaxis(psi,axis,0); out=np.tensordot(P,p2,axes=([1],[0])); return np.moveaxis(out,0,axis)
|
|
||||||
def corr_tensor(bra,ket):
|
|
||||||
bra6, ket6 = bra.reshape((2,)*6), ket.reshape((2,)*6)
|
|
||||||
c=np.zeros((3,3,3,3,3,3),dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
k=ket6
|
|
||||||
for ax,ii in zip(range(6),(iA,iB,iC,iD,iE,iF)):
|
|
||||||
k=apply_leg(k,ax,paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF]=np.vdot(bra6,k)
|
|
||||||
return c
|
|
||||||
|
|
||||||
print("\ncomputing all T_ab (a,b=1,2,3), 9 tensors total...")
|
|
||||||
phis = [phi1,phi2,phi3]
|
|
||||||
T = {}
|
|
||||||
for a in range(3):
|
|
||||||
for b in range(3):
|
|
||||||
T[(a,b)] = corr_tensor(phis[a],phis[b])
|
|
||||||
print(f" T[{a+1},{b+1}] done, max imag part={np.abs(T[(a,b)].imag).max():.2e}" if a==b else
|
|
||||||
f" T[{a+1},{b+1}] done")
|
|
||||||
|
|
||||||
# check T_ba = conj(T_ab)
|
|
||||||
for a in range(3):
|
|
||||||
for b in range(3):
|
|
||||||
err = np.abs(T[(a,b)] - np.conj(T[(b,a)])).max()
|
|
||||||
assert err < 1e-10, (a,b,err)
|
|
||||||
print("T_ba = conj(T_ab) verified for all pairs.")
|
|
||||||
|
|
||||||
# --- random genuinely MIXED c (PSD, not rank 1) ---
|
|
||||||
rng = np.random.default_rng(42)
|
|
||||||
W = rng.normal(size=(3,3)) + 1j*rng.normal(size=(3,3))
|
|
||||||
c_raw = W @ W.conj().T # Hermitian PSD, generically full rank
|
|
||||||
print("\nrandom c_raw (Hermitian PSD, rank =", np.linalg.matrix_rank(c_raw), "):")
|
|
||||||
print(np.round(c_raw,3))
|
|
||||||
|
|
||||||
rho_raw = Phi @ c_raw @ Phi.conj().T # 64x64
|
|
||||||
tr = np.trace(rho_raw).real
|
|
||||||
rho = rho_raw/tr
|
|
||||||
c = c_raw/tr
|
|
||||||
print(f"\ntrace(rho_raw)={tr:.6f}; normalized rho has trace {np.trace(rho).real:.10f}")
|
|
||||||
evals_rho = np.linalg.eigvalsh(rho)
|
|
||||||
print("eigenvalues of rho (should be >=0, sum=1):", np.round(evals_rho[np.abs(evals_rho)>1e-9],6))
|
|
||||||
|
|
||||||
# --- brute-force TRUE correlation tensor of rho ---
|
|
||||||
def corr_tensor_rho(rho):
|
|
||||||
rho6 = rho.reshape((2,)*12) # not directly useful; do it via trace instead
|
|
||||||
c=np.zeros((3,3,3,3,3,3),dtype=complex)
|
|
||||||
for iA in range(3):
|
|
||||||
for iB in range(3):
|
|
||||||
for iC in range(3):
|
|
||||||
for iD in range(3):
|
|
||||||
for iE in range(3):
|
|
||||||
for iF in range(3):
|
|
||||||
O = paulis[iA]
|
|
||||||
for ii in (iB,iC,iD,iE,iF):
|
|
||||||
O = np.kron(O, paulis[ii])
|
|
||||||
c[iA,iB,iC,iD,iE,iF] = np.trace(rho @ O)
|
|
||||||
return c
|
|
||||||
T_true = corr_tensor_rho(rho).real
|
|
||||||
|
|
||||||
# --- predicted via T(rho) = sum_ab c_ab T_ab ---
|
|
||||||
T_pred = np.zeros((3,3,3,3,3,3), dtype=complex)
|
|
||||||
for a in range(3):
|
|
||||||
for b in range(3):
|
|
||||||
T_pred += c[a,b] * T[(a,b)]
|
|
||||||
T_pred = T_pred.real
|
|
||||||
|
|
||||||
err = np.abs(T_true - T_pred).max()
|
|
||||||
print(f"\nmax|T_true - T_pred| (full 6-index tensor, r=3, genuinely mixed rho): {err:.2e}")
|
|
||||||
|
|
||||||
# --- verify at BOTH cuts via simple reshape, no new contraction ---
|
|
||||||
M1_true, M1_pred = T_true.reshape(27,27), T_pred.reshape(27,27)
|
|
||||||
M2_true, M2_pred = T_true.reshape(9,81), T_pred.reshape(9,81)
|
|
||||||
print(f"cut ABC|DEF: max matrix error = {np.abs(M1_true-M1_pred).max():.2e}, "
|
|
||||||
f"||M||_* true={np.linalg.svd(M1_true,compute_uv=False).sum():.4f} "
|
|
||||||
f"pred={np.linalg.svd(M1_pred,compute_uv=False).sum():.4f}")
|
|
||||||
print(f"cut AB|CDEF: max matrix error = {np.abs(M2_true-M2_pred).max():.2e}, "
|
|
||||||
f"||M||_* true={np.linalg.svd(M2_true,compute_uv=False).sum():.4f} "
|
|
||||||
f"pred={np.linalg.svd(M2_pred,compute_uv=False).sum():.4f}")
|
|
||||||
|
|
@ -1,118 +0,0 @@
|
||||||
# Shadow maps / symmetric states — numerical scripts
|
|
||||||
|
|
||||||
Ausführungsreihenfolge (jedes Skript liest die .npy/.npz-Dateien des vorigen):
|
|
||||||
|
|
||||||
## 1. `1_recoupling_check.py`
|
|
||||||
Baut die zwei Basiszustände (6 Qubits, Singulett-Netzwerke mit den
|
|
||||||
Paarungen (A,D)(B,E)(C,F) bzw. (A,E)(B,F)(C,D)) und deren volle
|
|
||||||
Korrelationstensoren T1, T2 sowie den Kohärenz-Kreuzterm C12.
|
|
||||||
Verifiziert per Brute-Force-Quantensimulation (unabhängig, für mehrere
|
|
||||||
Werte von alpha), dass für JEDE kohärente Überlagerung
|
|
||||||
|Xi(alpha)> = (cos(alpha) psi1 + sin(alpha) psi2)/norm
|
|
||||||
der volle Korrelationstensor exakt
|
|
||||||
T(Xi) = [cos^2(a) T1 + sin^2(a) T2 + cos(a)sin(a) C12] / N2
|
|
||||||
ist -- UND dass diese drei festen Tensoren (unabhängig von alpha UND
|
|
||||||
unabhängig vom gewählten Schnitt!) per einfachem .reshape() sowohl den
|
|
||||||
Schnitt ABC|DEF (27x27) als auch AB|CDEF (9x81) liefern, exakt
|
|
||||||
übereinstimmend mit unabhängiger Brute-Force-Simulation für jeden Schnitt.
|
|
||||||
Output: T1.npy, T2.npy, C12.npy
|
|
||||||
|
|
||||||
## 2. `2_exact_casimir_projectors.py`
|
|
||||||
Baut die exakten SO(3)-Spin-1-Generatoren J_x,J_y,J_z symbolisch mit
|
|
||||||
sympy (Levi-Civita-Definition), verifiziert die so(3)-Kommutatorrelation
|
|
||||||
und J^2=2*I_3 symbolisch exakt. Konstruiert dann den totalen
|
|
||||||
Casimir-Operator J^2_total auf (R^3)^{⊗k} für k=2,3,4 und diagonalisiert
|
|
||||||
ihn (numpy, Hermitesch, maschinengenau). Die Eigenräume zu Eigenwert
|
|
||||||
j(j+1) SIND per Definition die Isotypen-Projektoren -- exakt, ohne
|
|
||||||
Monte-Carlo-Integration über SO(3) wie in einer früheren Version.
|
|
||||||
Output: projectors_exact.npz
|
|
||||||
|
|
||||||
## 3. `3_apply_exact_projectors.py`
|
|
||||||
Wendet die exakten Projektoren auf T1, T2, C12 an (für beliebiges alpha,
|
|
||||||
beliebigen Schnitt) und berechnet ||A_j||_* pro Drehimpulssektor j,
|
|
||||||
für zwei Beispielzustände und beide Schnitte (ABC|DEF und AB|CDEF).
|
|
||||||
Bestätigt exakte Additivität sum_j (2j+1)||A_j||_* = ||M||_*.
|
|
||||||
|
|
||||||
## Kontext
|
|
||||||
Diese Skripte gehören zur Diskussion der Frage, wie die bigraduierte
|
|
||||||
Shadow Map M_S(rho) sich unter globaler kollektiver SO(3)-Symmetrie in
|
|
||||||
Drehimpuls-Isotypen zerlegt (Erweiterung von symmetric_shadow_maps_formal.tex
|
|
||||||
/ shadow_maps_symmetric_states.tex um die Rotationssymmetrie-Seite neben
|
|
||||||
der bereits behandelten S_m-Permutationssymmetrie), und wie sich diese
|
|
||||||
Zerlegung zwischen verschiedenen Schnitten desselben global-invarianten
|
|
||||||
Zustands umrechnen lässt (siehe Skript 1: EIN Tripel (T1,T2,C12) liefert
|
|
||||||
JEDEN Schnitt per reshape, ohne erneute Kontraktion über den vollen
|
|
||||||
Hilbertraum).
|
|
||||||
|
|
||||||
## 4. `4_spherical_basis.py`
|
|
||||||
Baut eine Condon-Shortley-konsistente sphärische Basis {|1,-1>,|1,0>,|1,+1>}
|
|
||||||
für ein einzelnes Spin-1-Bein über Leiteroperatoren (nicht aus einer
|
|
||||||
memorierten Formel zitiert), ausgehend von den exakten Cartesischen
|
|
||||||
Generatoren. Validiert Kommutatoren, Normierung, Jz-Eigenwerte.
|
|
||||||
|
|
||||||
## 5. `5_six_j_recoupling.py`
|
|
||||||
Baut die gekoppelten Basen |p,j,m>_ABC (Baum (AB)C), |y,j,m>_DEF (Baum
|
|
||||||
(DE)F) und |y,j,p,m>_CDEF (Baum (C,(DE)F)) via sympy-Clebsch-Gordan-
|
|
||||||
Koeffizienten. Extrahiert die reduzierten Matrixelemente A_j^(1)[p,y]
|
|
||||||
(Schnitt ABC|DEF) und A_p^(2)[y,j] (Schnitt AB|CDEF) für zwei Zustände
|
|
||||||
und findet empirisch (numerisch bis auf 1e-6, an 15 unabhaengigen
|
|
||||||
Datenpunkten):
|
|
||||||
A_p^(2)[y,j] = -sqrt((2j+1)/(2p+1)) * A_j^(1)[p,y] (unabhaengig von y!)
|
|
||||||
Das ist die 6j-Rekopplungsformel zwischen den A_j-Bloecken zweier
|
|
||||||
verschiedener Schnitte desselben invarianten Tensors -- numerisch
|
|
||||||
bewiesen, aber NICHT sauber gegen eine Standard-Lehrbuch-6j-Formel
|
|
||||||
identifiziert (siehe verify_6j.py / search_6j.py Versuche, beide mit
|
|
||||||
Konventions-Mismatch). Das ist die offene Baustelle.
|
|
||||||
|
|
||||||
## 6. `6_six_j_recoupling_proof.py` (SUPERSEDES the earlier `5_six_j_recoupling.py`)
|
|
||||||
Vollstaendiger, verifizierter Beweis der Rekopplungsformel zwischen den
|
|
||||||
reduzierten Bloecken A_j^(1) (Schnitt ABC|DEF) und A_p^(2) (Schnitt
|
|
||||||
AB|CDEF) desselben invarianten Tensors:
|
|
||||||
A_p^(2)[y,j] = -sqrt((2j+1)/(2p+1)) * A_j^(1)[p,y] (y-unabhaengig!)
|
|
||||||
Kernschritte (jeder einzeln verifiziert):
|
|
||||||
(1) Schur-Lemma KORREKT auf die bilineare (nicht sesquilineare) Paarung
|
|
||||||
angewandt -- die Transponierte einer Wigner-D-Matrix haengt ueber die
|
|
||||||
Metrik C_j (nicht D selbst) mit der Inversen zusammen; das war der
|
|
||||||
Fehler im ersten Versuch.
|
|
||||||
(2) Exakte Konjugationsphase fuer CG-gekoppelte Multipletts:
|
|
||||||
conj(v_{J,m}) = (-1)^(J+n_leg) * (-1)^m * v_{J,-m}
|
|
||||||
(n_leg = Anzahl der elementaren Spin-1-Beine im Baum), verifiziert
|
|
||||||
fuer n_leg=3 und n_leg=4.
|
|
||||||
(3) Eine endliche CG-Summe Xi(p,j,m'), exakt symbolisch (sympy) zu
|
|
||||||
sqrt((2j+1)/(2p+1)) ausgewertet, m'-unabhaengig, fuer alle p,j<=3.
|
|
||||||
(4) End-to-End-Kreuzcheck gegen Brute-Force-Quantensimulation: Fehler
|
|
||||||
2.2e-16 (Maschinengenauigkeit).
|
|
||||||
Offen (siehe Kommentare im Skript und rem:six-j-scope im .tex): die
|
|
||||||
allgemeine (nicht nur p,j<=3) geschlossene Form von Xi als zitierfaehiges
|
|
||||||
Standard-6j-Symbol wurde nicht identifiziert (zwei Versuche dazu blieben
|
|
||||||
erfolglos, siehe search_6j.py-Fragmente); ebenso ist Gl. (2) nur verifiziert,
|
|
||||||
nicht fuer allgemeines n_leg induktiv hergeleitet.
|
|
||||||
|
|
||||||
## 7. `7_combined_sm_so3_collapse.py`
|
|
||||||
Kombiniert S_m-Permutationssymmetrie mit voller kollektiver SO(3)-Symmetrie
|
|
||||||
an einem konkreten 6-Qubit-Beispiel: |Q> = kanonische Invariante zweier
|
|
||||||
gekoppelter Spin-3/2-Dicke-Multipletts auf ABC und DEF (Gl.
|
|
||||||
eq:dicke-network-state im .tex). Verifiziert:
|
|
||||||
- |Q> ist exakt kollektiv-rotationsinvariant (|<Q|U^6|Q>|=1 exakt).
|
|
||||||
- Innerhalb des 10-dim S_3-symmetrischen Unterraums (Typ-Basis u_alpha,
|
|
||||||
Sym^3(C^3)) zeigt der Casimir NUR j=1 (x3) und j=3 (x7) -- j=0,2
|
|
||||||
komplett abwesend, multiplizitätsfrei wie klassisch vorhergesagt.
|
|
||||||
- Die gesamte Kernnorm (15.0) lebt exakt im doppelt-symmetrischen
|
|
||||||
Sektor (Norm ausserhalb: 7e-15).
|
|
||||||
- Konkrete Skalarwerte: A_1=1/3, A_3=2, mit 3*A_1+7*A_3=15 exakt.
|
|
||||||
Ist jetzt Proposition harmonic-decomposition + Example dicke-network im
|
|
||||||
.tex (Abschnitt sec:sm-so3-combination).
|
|
||||||
|
|
||||||
## 8. `8_general_r_check.py`
|
|
||||||
Schliesst die letzte offene TODO im Abschnitt: verallgemeinert die
|
|
||||||
Cut-unabhaengige Template-Aussage (Proposition coherence-templates) von
|
|
||||||
r=2 auf r=3, mit einem ECHT GEMISCHTEN (volle Rang-3, nicht reine
|
|
||||||
Ueberlagerung) Zustand. Korrigiert nebenbei einen Zaehlfehler im
|
|
||||||
urspruenglichen TODO-Kommentar: die Anzahl unabhaengiger reeller Tensoren
|
|
||||||
ist r^2 (= reelle Dimension hermitescher r x r Matrizen), nicht r(r+1)/2.
|
|
||||||
Drei verschiedene Perfect-Matchings von 6 Qubits als Basis-Zustaende,
|
|
||||||
Gram-Matrix-Konditionszahl 2 (linear unabhaengig), Haar-zufaellige
|
|
||||||
hermitesche PSD-Koeffizientenmatrix voller Rang. Ergebnis: Fehler 1.1e-16
|
|
||||||
zwischen Brute-Force- und Template-basierter Korrelationstensor-Berechnung,
|
|
||||||
an BEIDEN Schnitten gleichzeitig, ohne erneute Simulation.
|
|
||||||
Ist jetzt Corollary real-tensor-count + Example general-r-three im .tex.
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue