diff --git a/paper/symmetric_shadow_maps_formal.tex b/paper/symmetric_shadow_maps_formal.tex index 2c52506..fff9afd 100644 --- a/paper/symmetric_shadow_maps_formal.tex +++ b/paper/symmetric_shadow_maps_formal.tex @@ -1215,7 +1215,8 @@ i.e.\ that the $2\times2$ array of blocks is circulant --- a prediction that fol A direct check against the stabilizer group $H=\langle K_1,K_2,K_3,K_4\rangle$ of $\rho_\square$ (Lemma~\ref{lem:code-support}) confirms this: in the raw Pauli-string basis, $X_1X_3\in H$ and $X_2X_4\in H$, while $X_1X_4\notin H$ and $X_2X_3\notin H$, so \begin{equation*} M_{\{1\}\to\{3\}}(\rho_\square)=M_{\{2\}\to\{4\}}(\rho_\square)=1\ (\text{support on the }xx\text{ direction only}), -\qquad +\end{equation*} +\begin{equation*} M_{\{1\}\to\{4\}}(\rho_\square)=M_{\{2\}\to\{3\}}(\rho_\square)=0, \end{equation*} matching Eq.~\eqref{eq:ring-circulant-prediction} exactly. This is a case where the weak, cut-factorizing symmetry and the combinatorial stabilizer mechanism of Lemma~\ref{lem:stabilizer-degeneracy} operate on the same numbers from two independent directions: the stabilizer mechanism explains \emph{why} the entries are $0$ or $\pm1$ at all, while the swap-equivariance of Proposition~\ref{prop:block-diagonal} explains, without reference to the stabilizer formalism, why the two nonzero entries must coincide and the two zero entries must coincide. Diagonalizing this $2\times2$ circulant block in the symmetric/antisymmetric basis $(\,e_x^{(1)}\pm e_x^{(2)})/\sqrt2$ gives eigenvalues $1\pm0=1$ in this instance --- here the two channels happen to be degenerate, since the off-diagonal entry vanishes, but the circulant form Eq.~\eqref{eq:ring-circulant-prediction} would hold with generically distinct symmetric/antisymmetric eigenvalues $a\pm b$ for any $\rho$ merely invariant under this same reflection, stabilizer or not. @@ -1412,6 +1413,208 @@ The $y$-parity grading occasionally useful for real-in-the-computational-basis s Proposition~\ref{prop:block-diagonal} and Lemma~\ref{lem:stabilizer-degeneracy} are complementary, not competing, and apply under disjoint hypotheses. The representation-theoretic mechanism applies whenever $\rho$ is genuinely $G$-invariant under some compact group $G$ acting by local unitaries and preserving the cut, regardless of whether $\rho$ is Pauli-diagonal; it says nothing about states, such as a generic finite-group-symmetric state built from a permutation representation, that are not Pauli-diagonal. The stabilizer mechanism applies whenever $\rho$ is (a uniform mixture over) a stabilizer code state, regardless of whether it possesses any continuous symmetry at all --- as is the case for $\GHZ_n$, the Smolin state, and every graph state used elsewhere in this note, none of which is invariant under a nontrivial continuous collective symmetry. In the (comparatively narrow) overlap where a state is both $G$-invariant for some continuous $G$ and Pauli-diagonal, both mechanisms apply and constrain the same block structure from different directions; outside that overlap, exactly one of the two is available, and it is this Lemma, not Proposition~\ref{prop:block-diagonal}, that accounts for every numerically observed degeneracy reported so far in this note. \end{remark} +\subsection*{A polynomial-size witness for permutation-symmetric cluster sources} +\label{sec:multinomial-collapse} + +Remark~\ref{rem:computational-cost} raised the cost of evaluating $\mathcal M_S(\rho)$ +as a genuine obstruction once $|S|$ or $|S^c|$ grows. We now show that this +obstruction disappears entirely for a natural and large class of states: those +invariant under permuting the parties \emph{within} $S$ and \emph{within} $S^c$ +separately. This is an instance of the weak, cut-factorizing hypothesis of +Proposition~\ref{prop:block-diagonal} --- not the strong, party-local one, since a +transposition of two parties inside $S$ is not of the form $U^{(a)}\otimes U^{(b)}$ +(compare Remark~\ref{rem:permutation-separating-example}) --- specialized to the +full symmetric group, whose isotypic decomposition on a Pauli-string alphabet +collapses to an elementary orbit-counting argument. + +\paragraph{Setup.} Fix qubits ($d_a=2$) for concreteness (Remark~\ref{rem:qudit-collapse} +below records the general-$d$ statement). Fix a source cluster $S$ with $|S|=m$ +and let $S^c$ be its complement, $|S^c|=l:=n-m$. Consider the single bigraduated +block $M_{S\to S^c}(\rho)$ of Definition~\ref{def:bigraduated} with $V=S$, $T=S^c$ +--- the ``fully active'' block already singled out after +Corollary~\ref{cor:sub-block} as the witness for genuine joint $S$-cluster +correlation. In the orthonormal Pauli-string basis this is the +$3^m\times 3^l$ matrix +\begin{equation*} +c(\vec\imath,\vec\jmath):=\tr\bigl(\rho\,\sigma_{\vec\imath}\otimes\sigma_{\vec\jmath}\bigr), +\qquad +\vec\imath\in\{x,y,z\}^m,\ \vec\jmath\in\{x,y,z\}^l. +\end{equation*} +For $\vec\imath\in\{x,y,z\}^m$ let $\mathrm{type}(\vec\imath)=(a_x,a_y,a_z)\in\mathcal T_m$, +$\mathcal T_m:=\{(a_x,a_y,a_z)\in\mathbb Z_{\ge0}^3: a_x+a_y+a_z=m\}$, record how +often each label occurs; the symmetric group $S_m$ acts on $\{x,y,z\}^m$ by +permuting positions, with orbits exactly the level sets of $\mathrm{type}$, and the +orbit of type $\alpha$ has size the multinomial coefficient $\binom m\alpha:=\frac{m!}{a_x!a_y!a_z!}$. +Note $|\mathcal T_m|=\binom{m+2}{2}$, polynomial in $m$, against the ambient $3^m$. + +\begin{proposition}[Multinomial block collapse] +\label{prop:multinomial-collapse} +Suppose $\rho$ is invariant under $U_\pi\otimes U_{\pi'}$ for every $\pi\in S_m$ +acting by the permutation unitary on $\mathcal H^{(S)}$ and every $\pi'\in S_l$ +acting by the permutation unitary on $\mathcal H^{(S^c)}$. Then $c(\vec\imath,\vec\jmath)$ +depends on $(\vec\imath,\vec\jmath)$ only through $(\mathrm{type}(\vec\imath),\mathrm{type}(\vec\jmath))\in\mathcal T_m\times\mathcal T_l$; +write $\tilde c(\alpha,\beta)$ for this common value, and define the +multinomial-weighted reduced matrix $\hat C\in\mathbb C^{|\mathcal T_m|\times|\mathcal T_l|}$ by +\begin{equation} +\hat C_{\alpha,\beta}:=\sqrt{\binom m\alpha\binom l\beta}\;\tilde c(\alpha,\beta). +\label{eq:reduced-dicke-matrix} +\end{equation} +Then $M_{S\to S^c}(\rho)$ and $\hat C$ have identical nonzero singular values +(the smaller matrix effectively zero-padded), so in particular +\begin{equation*} +\norm{M_{S\to S^c}(\rho)}_*=\norm{\hat C}_*, +\qquad +\norm{M_{S\to S^c}(\rho)}_{\fro}=\norm{\hat C}_{\fro}. +\end{equation*} +\end{proposition} + +\begin{proof} +$U_\pi$-invariance of $\rho$ gives $\tr(\rho\,\sigma_{\pi\vec\imath}\otimes\sigma_{\vec\jmath}) +=\tr(U_\pi^\dagger\rho U_\pi\,\sigma_{\vec\imath}\otimes\sigma_{\vec\jmath})=c(\vec\imath,\vec\jmath)$ +for every $\pi\in S_m$, since conjugating $\rho$ by $U_\pi$ permutes the legs of +the Pauli string in the trace exactly as $\pi$ permutes $\vec\imath$; the analogous +identity on the target side follows from $U_{\pi'}$-invariance. Hence $c$ is +constant on $S_m$-orbit $\times$ $S_l$-orbit classes, proving the first claim. + +For the matrix identity, let $u_\alpha\in\mathbb R^{3^m}$ be the normalized +indicator vector of the orbit of type $\alpha$ (equal to $1/\sqrt{\binom m\alpha}$ +on that orbit and $0$ elsewhere), and $v_\beta\in\mathbb R^{3^l}$ analogously. +Since distinct orbits partition the index set, $U:=(u_\alpha)_{\alpha\in\mathcal T_m}$ +and $V:=(v_\beta)_{\beta\in\mathcal T_l}$ have orthonormal columns. For +$\vec\imath$ of type $\alpha$ and $\vec\jmath$ of type $\beta$, +\begin{equation*} +(U\hat C V^T)_{\vec\imath,\vec\jmath} +=\frac{1}{\sqrt{\binom m\alpha}}\,\hat C_{\alpha,\beta}\,\frac1{\sqrt{\binom l\beta}} +=\tilde c(\alpha,\beta)=c(\vec\imath,\vec\jmath), +\end{equation*} +so $M_{S\to S^c}(\rho)=U\hat C\,V^T$. Left and right multiplication by +matrices with orthonormal columns preserves singular values up to zero-padding +(e.g.\ $M^TM=V\hat C^T\hat C V^T$ has the same nonzero eigenvalues as $\hat C^T\hat C$, +since $V^TV=\id$), giving the claim. +\end{proof} + +\begin{corollary}[Normalized witness] +\label{cor:dicke-normalized} +If $\rho$ is separable across $S\mid S^c$, then, in the normalization of +Corollary~\ref{cor:sub-block} applied with $\mathcal V=\{S\}$, $\mathcal T=\{S^c\}$, +\begin{equation*} +\frac{\norm{\hat C}_*}{\sqrt{(2^m-1)(2^l-1)}} +=\norm{\widehat M_{S\to S^c}(\rho)}_* +\le\norm{\mathcal M_S(\rho)}_*\le1. +\end{equation*} +\end{corollary} + +The point of Proposition~\ref{prop:multinomial-collapse} is computational, not a +sharper bound: it lets one evaluate $\norm{M_{S\to S^c}(\rho)}_*$ exactly via an +SVD of size $\binom{m+2}{2}\times\binom{l+2}{2}$ rather than $3^m\times3^l$, for +\emph{any} state with the stated permutation symmetry, with no approximation. + +\begin{remark}[General local dimension] +\label{rem:qudit-collapse} +For general finite $d_a\equiv d$ on $S$ (and possibly different $d$ on $S^c$), +the same argument replaces $\{x,y,z\}$ by any fixed orthonormal generator set +of size $d^2-1$; orbits of $S_m$ on $(d^2-1)$-letter strings of length $m$ are +again indexed by compositions $\mathcal T_m^{(d)}=\{\alpha\in\mathbb Z_{\ge0}^{d^2-1}:\sum\alpha_i=m\}$, +of cardinality $\binom{m+d^2-2}{d^2-2}$ --- polynomial in $m$ for fixed $d$, +exponential in $d$ but that dependence is orthogonal to the point made here. +\end{remark} + +\subsection*{Worked example: Dicke states} +\label{sec:dicke-example} + +\begin{lemma}[Closed-form Dicke correlator] +\label{lem:dicke-correlator} +Let $\lvert D_n^k\rangle:=\binom nk^{-1/2}\sum_{\lvert w\rvert=k}\lvert w\rangle$ +be the $n$-qubit Dicke state of weight $k$, and let $P$ be a Pauli string of type +$(n_I,n_X,n_Y,n_Z)$ ($n_I+n_X+n_Y+n_Z=n$, no reference to which positions carry +which label needed, by Proposition~\ref{prop:multinomial-collapse}-type symmetry +applied to the full state). Then, if $n_X+n_Y$ is even, +\begin{equation} +\langle D_n^k\rvert P\lvert D_n^k\rangle +=\frac{i^{\,n_Y}}{\binom nk} +\sum_{\substack{a_X+a_Y=(n_X+n_Y)/2\\ a_I+a_Z=k-(n_X+n_Y)/2}} +\binom{n_X}{a_X}\binom{n_Y}{a_Y}\binom{n_I}{a_I}\binom{n_Z}{a_Z}(-1)^{a_Y+a_Z}, +\label{eq:dicke-correlator} +\end{equation} +and $=0$ if $n_X+n_Y$ is odd. +\end{lemma} + +\begin{proof} +Write $P\lvert w\rangle=\phi(w)\lvert w'\rangle$ where $w'$ flips the bits of $w$ +at the $X$- and $Y$-labeled positions and leaves the rest unchanged, and +$\phi(w)=\prod_{Z\text{-pos}}(-1)^{w_i}\prod_{Y\text{-pos}}i(1-2w_i)$ (the $X$- +factors carry no phase). Since $\lvert D_n^k\rangle$ has support only on weight-$k$ +strings, $\langle D_n^k\rvert P\lvert D_n^k\rangle=\binom nk^{-1}\sum_{\lvert w\rvert=k,\,\lvert w'\rvert=k}\phi(w)$. +The weight-preservation condition $\lvert w'\rvert=\lvert w\rvert$ forces exactly +half of the $n_X+n_Y$ flipped positions to hold a $1$ in $w$, i.e.\ $a_X+a_Y=(n_X+n_Y)/2$ +if $w$ has $a_X$ ones among the $X$-positions and $a_Y$ ones among the +$Y$-positions (impossible if $n_X+n_Y$ is odd); the total-weight condition +$a_I+a_X+a_Y+a_Z=k$ then gives $a_I+a_Z=k-(n_X+n_Y)/2$. Summing $\phi(w)=(-1)^{a_Z}\cdot i^{\,n_Y-a_Y}(-i)^{a_Y}=(-1)^{a_Z+a_Y}i^{\,n_Y}$ +over all $w$ with prescribed $(a_I,a_X,a_Y,a_Z)$, weighted by the number +$\binom{n_I}{a_I}\binom{n_X}{a_X}\binom{n_Y}{a_Y}\binom{n_Z}{a_Z}$ of such $w$, gives +Eq.~\eqref{eq:dicke-correlator}. +\end{proof} + +Dicke states are invariant under the full party-permutation group $S_n$, hence +in particular under $S_m\times S_l$ for any cut $S\mid S^c$, so +Proposition~\ref{prop:multinomial-collapse} applies with $\tilde c(\alpha,\beta)$ +given directly by Eq.~\eqref{eq:dicke-correlator} at $(n_I,n_X,n_Y,n_Z)=(n-m-l,\alpha_x+\beta_x,\alpha_y+\beta_y,\alpha_z+\beta_z)$. + +\begin{example} +\label{ex:dicke-scaling} +For $n=9$, $k=4$, $S,S^c$ of size $m=4$, $l=3$, direct construction of the full +$81\times27$ matrix $M_{S\to S^c}(\rho)$ and of the reduced $15\times10$ matrix +$\hat C$ of Eq.~\eqref{eq:reduced-dicke-matrix} give identical singular-value +spectra to $10$ decimal digits, with $\norm{M_{S\to S^c}}_*=\norm{\hat C}_*=3.0972760203\ldots$, +confirming Proposition~\ref{prop:multinomial-collapse} numerically as well as +algebraically. + +The practical payoff is in scaling $m,l$ far beyond what the ambient +$3^m\times3^l$ matrix could ever accommodate. Table~\ref{tab:dicke-scaling} +reports $\norm{\hat C}_*$ and wall-clock time for a fixed weight $k=3$ Dicke +state as $n,m,l$ grow; the reduced matrix and its exact SVD remain cheap +throughout, while the corresponding ambient matrix size is astronomically +out of reach already by $n\approx60$. + +\begin{table}[h] +\centering +\small +\begin{tabular}{@{}rrrrrr@{}} +\toprule +$n$ & $m$ & $l$ & $\hat C$ size & ambient $3^m\times3^l$ & $\norm{\hat C}_*$ \\ +\midrule +10 & 4 & 4 & $15\times15$ & $8.1\times10^{1}\times8.1\times10^{1}$ & $5.66$ \\ +30 & 10 & 8 & $66\times45$ & $5.9\times10^{4}\times6.6\times10^{3}$ & $4.33$ \\ +60 & 20 & 15 & $231\times136$ & $3.5\times10^{9}\times1.4\times10^{7}$ & $4.93$ \\ +100 & 30 & 25 & $496\times351$ & $2.1\times10^{14}\times8.5\times10^{11}$ & $4.42$ \\ +200 & 40 & 35 & $861\times666$ & $1.2\times10^{19}\times5.0\times10^{16}$ & $1.85$ \\ +\bottomrule +\end{tabular} +\caption{Exact evaluation of $\norm{M_{S\to S^c}(\rho)}_*$ for the $k=3$ Dicke +state via the reduced matrix $\hat C$, Eq.~\eqref{eq:reduced-dicke-matrix}. +The rightmost ambient-matrix sizes are the dimensions an unreduced computation +would require; already at $n=200$ this is about $6\times10^{35}$ entries, versus +$861\times666\approx5.7\times10^{5}$ for $\hat C$ (computed, with full SVD, in +about $1.3$ seconds on a single core). The script +\texttt{scripts/dicke\_block\_collapse.py} reproduces this table and the exact +match with the ambient matrix at small $n$.} +\label{tab:dicke-scaling} +\end{table} + +Two caveats keep this example honest. First, Table~\ref{tab:dicke-scaling} +reports the \emph{unnormalized} block $\norm{M_{S\to S^c}}_*$, not the +cut-separable witness $\norm{\widehat M_{S\to S^c}}_*$ of +Corollary~\ref{cor:dicke-normalized}; the latter divides by +$\sqrt{(2^m-1)(2^l-1)}$, which grows so quickly with $m,l$ that the normalized +witness is far below the separable threshold $1$ at the larger table entries --- +the large-$n$ rows demonstrate tractability of the computation, not entanglement +detection at that scale. Second, at half filling $k=n/2$ the unnormalized +correlator itself decays with $n$ (a genuine physical effect, not a numerical +artifact); Table~\ref{tab:dicke-scaling} therefore fixes a small $k=3$ so the +signal stays $O(1)$ throughout the range shown. +\end{example} + + \section{Outlook} The combined shadow map should be viewed as a structured refinement of the older correlation strengths $L_S$ introduced by Aschauer \emph{et al.} \cite{aschauer}. Those quantities keep one Frobenius norm per tensor block; the present construction keeps the common one-vs-rest channel structure across all orthogonal sectors on the complement. In that sense it preserves the geometric spirit of that local-invariant sector decomposition while extracting more information from the same correlation data. diff --git a/scripts/dicker_block_collapse.py b/scripts/dicker_block_collapse.py new file mode 100644 index 0000000..80ca28e --- /dev/null +++ b/scripts/dicker_block_collapse.py @@ -0,0 +1,208 @@ +""" +dicke_block_collapse.py + +Reproduces the numerical claims of Proposition (multinomial block collapse) +and Example (Dicke-state scaling): for a Dicke state |D_n^k>, the ambient +3^m x 3^l shadow-map block M_{S->S^c}(rho) has EXACTLY the same singular +values (hence the same nuclear norm) as a much smaller multinomial-weighted +matrix C_hat of size C(m+2,2) x C(l+2,2). This lets ||M_{S->S^c}||_* be +computed exactly for cluster sizes far beyond what the ambient matrix could +ever be built at. + +Two things are verified/produced: + (1) Exact-arithmetic closed-form Dicke correlator, checked against + brute-force dense simulation for small n. + (2) Exact match between the ambient matrix M and the reduced matrix C_hat + (singular values, nuclear norm), then a scaling table pushing m, l, n + far beyond brute-force reach. + +Run: python3 dicke_block_collapse.py +""" + +import time +from itertools import combinations, product +from math import comb, factorial + +import numpy as np + +# ---------------------------------------------------------------------- +# Part 0: brute-force reference (only used for small-n sanity checks) +# ---------------------------------------------------------------------- + +_I = np.eye(2, dtype=complex) +_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) +_PAULI = {"i": _I, "x": _X, "y": _Y, "z": _Z} + + +def _kron_list(ops): + out = ops[0] + for o in ops[1:]: + out = np.kron(out, o) + return out + + +def dicke_state_vector(n, k): + """Dense state vector of the n-qubit weight-k Dicke state (small n only).""" + dim = 2 ** n + psi = np.zeros(dim, dtype=complex) + for bits in combinations(range(n), k): + idx = 0 + for b in bits: + idx |= 1 << (n - 1 - b) + psi[idx] = 1.0 + psi /= np.linalg.norm(psi) + return psi + + +def brute_force_expectation(n, k, labels): + """ by dense simulation. labels: length-n tuple in 'ixyz'.""" + psi = dicke_state_vector(n, k) + op = _kron_list([_PAULI[c] for c in labels]) + return psi.conj() @ op @ psi + + +# ---------------------------------------------------------------------- +# Part 1: closed-form Dicke correlator (Lemma: closed-form Dicke correlator) +# ---------------------------------------------------------------------- + +def dicke_correlator(n, k, n_I, n_X, n_Y, n_Z): + """ + for a Pauli-string TYPE (n_I identities, n_X X's, + n_Y Y's, n_Z Z's; n_I+n_X+n_Y+n_Z = n), via Eq. (dicke-correlator). + + All intermediate sums are kept as exact Python integers to avoid + catastrophic cancellation between huge binomial coefficients; only the + final division by C(n,k) is converted to a float (Python performs a + correctly-rounded true division even for arbitrary-size integers). + """ + assert n_I + n_X + n_Y + n_Z == n + m_xy = n_X + n_Y + if m_xy % 2 != 0: + return 0.0 + half = m_xy // 2 + target_iz = k - half + if target_iz < 0 or target_iz > n_I + n_Z: + return 0.0 + + total = 0 # exact integer accumulator + for a_x in range(max(0, half - n_Y), min(n_X, half) + 1): + a_y = half - a_x + w_xy = comb(n_X, a_x) * comb(n_Y, a_y) * (-1) ** a_y + for a_i in range(max(0, target_iz - n_Z), min(n_I, target_iz) + 1): + a_z = target_iz - a_i + w_iz = comb(n_I, a_i) * comb(n_Z, a_z) * (-1) ** a_z + total += w_xy * w_iz + + denom = comb(n, k) + return (1j ** n_Y) * (total / denom) + + +# ---------------------------------------------------------------------- +# Part 2: ambient block matrix vs. multinomial-reduced matrix +# ---------------------------------------------------------------------- + +def multinomial(n, counts): + r = factorial(n) + for c in counts: + r //= factorial(c) + return r + + +def active_types(size): + """All (a_x, a_y, a_z) with a_x+a_y+a_z == size (the 'fully active' sector).""" + return [ + (ax, ay, size - ax - ay) + for ax in range(size + 1) + for ay in range(size + 1 - ax) + ] + + +def ambient_block_matrix(n, k, m, l): + """The full 3^m x 3^l block M_{S->S^c}(rho) in the raw Pauli-string basis.""" + labels_s = list(product("xyz", repeat=m)) + labels_t = list(product("xyz", repeat=l)) + rest = n - m - l + M = np.zeros((len(labels_s), len(labels_t)), dtype=complex) + for i, ls in enumerate(labels_s): + cs = {c: ls.count(c) for c in "xyz"} + for j, lt in enumerate(labels_t): + ct = {c: lt.count(c) for c in "xyz"} + M[i, j] = dicke_correlator( + n, k, rest, cs["x"] + ct["x"], cs["y"] + ct["y"], cs["z"] + ct["z"] + ) + return M + + +def reduced_block_matrix(n, k, m, l): + """ + The multinomial-weighted reduced matrix C_hat of Eq. (reduced-dicke-matrix), + size C(m+2,2) x C(l+2,2), with the SAME singular values as the ambient + 3^m x 3^l block (Proposition: multinomial block collapse). + """ + src_types = active_types(m) + tgt_types = active_types(l) + rest = n - m - l + C = np.zeros((len(src_types), len(tgt_types)), dtype=complex) + for i, (sx, sy, sz) in enumerate(src_types): + w_s = multinomial(m, [sx, sy, sz]) + for j, (tx, ty, tz) in enumerate(tgt_types): + w_t = multinomial(l, [tx, ty, tz]) + val = dicke_correlator(n, k, rest, sx + tx, sy + ty, sz + tz) + C[i, j] = float(np.sqrt(float(w_s * w_t))) * val + return C + + +# ---------------------------------------------------------------------- +# Part 3: checks and scaling table +# ---------------------------------------------------------------------- + +def check_formula_against_brute_force(n=8, k=3, trials=30, seed=0): + rng = np.random.default_rng(seed) + max_err = 0.0 + for _ in range(trials): + labels = rng.choice(list("ixyz"), size=n) + counts = {c: int((labels == c).sum()) for c in "ixyz"} + ref = brute_force_expectation(n, k, tuple(labels)) + val = dicke_correlator(n, k, counts["i"], counts["x"], counts["y"], counts["z"]) + max_err = max(max_err, abs(ref - val)) + print(f"[check 1] closed-form vs. brute force (n={n}, k={k}, {trials} random " + f"Pauli strings): max error = {max_err:.2e}") + + +def check_ambient_vs_reduced(n=9, k=4, m=4, l=3): + M = ambient_block_matrix(n, k, m, l) + C = reduced_block_matrix(n, k, m, l) + sv_full = np.sort(np.linalg.svd(M, compute_uv=False))[::-1] + sv_red = np.sort(np.linalg.svd(C, compute_uv=False))[::-1] + print(f"[check 2] ambient {M.shape} vs. reduced {C.shape} (n={n}, k={k}, " + f"m={m}, l={l})") + print(f" ||M||_* = {sv_full.sum().real:.10f}") + print(f" ||C||_* = {sv_red.sum().real:.10f}") + print(f" max |sv_full - sv_red| (top {min(6, len(sv_red))}) = " + f"{np.max(np.abs(sv_full[:len(sv_red)][:6] - sv_red[:6])):.2e}") + + +def scaling_table(k=3, cases=((10, 4, 4), (30, 10, 8), (60, 20, 15), + (100, 30, 25), (200, 40, 35))): + print(f"[scaling table] fixed weight k={k}, reduced matrix only " + f"(ambient matrix is never built)") + header = f"{'n':>5}{'m':>5}{'l':>5} {'C_hat shape':>14} {'ambient 3^m x 3^l':>26} {'||C_hat||_*':>13} {'time':>8}" + print(header) + for n, m, l in cases: + t0 = time.time() + C = reduced_block_matrix(n, k, m, l) + sv = np.linalg.svd(C, compute_uv=False) + dt = time.time() - t0 + ambient = f"{3.0**m:.2e} x {3.0**l:.2e}" + print(f"{n:>5}{m:>5}{l:>5} {str(C.shape):>14} {ambient:>26} " + f"{sv.sum().real:>13.6f} {dt:>7.3f}s") + + +if __name__ == "__main__": + check_formula_against_brute_force() + print() + check_ambient_vs_reduced() + print() + scaling_table() \ No newline at end of file