# Entanglement-detection scripts from this chat This is the code from a conversation that started with the "symmetric shadow maps" paper (`symmetric_shadow_maps_formal.tex`) and worked outward through a chain of entanglement-detection techniques on the two-qutrit **Tiles** bound-entangled state (Bennett-DiVincenzo-Mor-Shor-Smolin-Terhal UPB state, already used as a benchmark in the paper): symmetric-state sanity checks, DPS symmetric-extension SDPs, noise-robustness thresholds, local filtering, and (in progress) a third DPS extension level. **Note: none of this has been re-run/verified after being assembled into this package** (per your request) -- it's a straight extraction of the code from the chat. The numbers quoted in each docstring/comment are what the sandbox actually produced during the conversation; treat them as "expected results to check against" rather than guaranteed. ## Setup ``` pip install -r requirements.txt ``` `scs` is the default (open-source, first-order) SDP solver used throughout. If you have a MOSEK license (free for academics), it is very likely much faster for these problem sizes -- just change `SOLVER = cp.SCS` to `SOLVER = cp.MOSEK` near the top of scripts 03, 04, 06, 07, 08. ## Files, in the order they came up in the conversation | File | What it does | Expected result | Rough runtime | |---|---|---|---| | `common.py` | Shared utilities: Gell-Mann generators (paper convention), Tiles state, qutrit Werner state, correlation-matrix/shadow-map criterion, plain PPT check, operator-Sinkhorn filter. Imported by scripts 03-06. | -- | -- | | `dps_hierarchy.py` | General, level-`k`-parametrized DPS symmetric-extension SDP builder (used for levels 2 and 3, and usable for higher `k`). | -- | -- | | `01_werner_qubit_symbolic.py` | Exact (sympy) check: 2-qubit Werner state, `SU(2)` symmetry forces the correlation matrix `∝ I`. | Shadow-map threshold *exactly* matches PPT: **p_c = 1/3** both ways. | seconds | | `02_werner_qutrit_symbolic.py` | Same, generalized to qutrits (antisymmetric-subspace Werner state). | Shadow-map threshold **p_c = 1/2**, but true threshold (Werner 1989) is **p_c = 1/4** -- the order-1 criterion is valid but NOT tight in d=3 (unlike d=2). | under a minute | | `03_dps_level2_demo.py` | DPS level 2 via `dps_hierarchy`. Sanity check on Werner qutrit; then the interesting case: Tiles state, where plain PPT is exactly blind (min eigenvalue ≈ 0) but DPS-2 detects it. | Werner: consistent with p=1/4 away from the boundary. Tiles: PPT feasible=True, DPS-2 feasible=False (detected). Robust across solver tolerances 1e-5..1e-8. | under a minute | | `04_tiles_noise_scan.py` | Noise-threshold bisection for (a) the plain shadow-map criterion and (b) DPS level 2, on the noisy Tiles family. | Shadow-map **p_c ≈ 0.9493** (5.07% tolerance); DPS-2 **p_c ≈ 0.951** (4.9%) -- i.e. DPS-2 barely improves on the much cheaper order-1 criterion for this state. | a few minutes (DPS-2 bisection) | | `05_local_filtering.py` | Operator-Sinkhorn local filtering (SLOCC normal form) + the plain shadow-map criterion on the filtered state. | **p_c ≈ 0.8722** (12.78% tolerance) -- matches the literature's "Filter Covariance Matrix Criterion" (Gittsovich, Gühne, Hyllus, Eisert, arXiv:0803.0757, Prop. IV.13: p_c = 0.8723, 12.77%) to ~4 decimal places. | seconds | | `06_dps_level2_filtered.py` | DPS level 2 applied to the *filtered* state (combining both levers). | **p_c ≈ 0.9426** (5.74%) -- filtering helps DPS-2 only marginally, much less than it helps the plain shadow-map (05). Filtering and DPS-extension-order are not equally powerful levers here, and don't simply stack. | a few minutes | | `07_dps_level3_single.py` | A single DPS level-3 feasibility check on the pure Tiles state, to confirm level 3 is tractable at all. | status = infeasible (detected). Took **~137s** with SCS in the original sandbox. | ~1-3 minutes | | `08_dps_level_k_bisection.py` | General, **resumable** bisection for the DPS level-`k` noise threshold, one step per invocation, progress saved to JSON. Defaults to `LEVEL=3`. | See below -- **in progress**. | ~2-4 min per step with SCS (k=3) | | `dps_level3_bisection_state.json` | Saved progress for the level-3 bisection from the original session (8 SCS solves already spent). | Current bracket: **[0.90982, 0.91080]**, i.e. `p_c ≈ 0.910-0.911`. | -- | | `09_dps_level3_filtered_bisection.py` | Combines local filtering (05) with DPS level 3 (07/08): filter the state, then run the level-3 SDP on it. Resumable, same pattern as 08. | Untested/in progress -- based on the level-2 precedent (06), expect only a modest improvement over plain level 3, not a jump to ~13%. Starting bracket is an educated guess, not a proven bound (see the script's docstring). | most expensive script here: ~85-140s per solve, ~12-16 solves for a full bisection | ## Where the level-3 bisection currently stands ```json {"lo": 0.90982, "hi": 0.91080, "iter": 8} ``` So DPS level 3 detects entanglement for `p ≳ 0.910`, i.e. roughly **9.0% noise tolerance** -- already better than level 2's 4.9-5.7%, but still well short of the 12.77-12.78% that local filtering alone achieves. Just re-run `08_dps_level_k_bisection.py` (it picks up the saved state automatically) to narrow this further. ## The overall picture that emerged (for reference) | Method | p_c | Noise tolerance | |---|---|---| | plain PPT | ~1.0 | ~0% (knife-edge) | | shadow-map / de Vicente Bloch criterion (order 1) | 0.9493 | 5.07% | | DPS level 2 | 0.9510 | 4.90% | | DPS level 2 + filtering | 0.9426 | 5.74% | | DPS level 3 (partial result so far) | ~0.910 | ~9.0% (narrowing) | | **local filtering + shadow-map (order 1)** | **0.8722** | **12.78%** | | literature: Filter-CMC (Prop. IV.13) | 0.8723 | 12.77% | | literature: best known positive map | 0.8744 | 12.56% | Headline takeaway: for this particular state, **local filtering (a SLOCC pre-processing step) is a far bigger lever than increasing the DPS extension order**, and the two don't stack additively -- filtering the state and then applying the cheapest possible (order-1) criterion already matches a specialized literature result almost exactly, while adding DPS levels on top gives comparatively little. ## A performance note on why level 3+ gets slow The DPS SDP *variable* is parametrized on `A ⊗ Sym^k(B)`, dimension `d · C(d+k-1, k)` -- polynomial in `k` (this is the "exploit the built-in Bose symmetry of the extension copies" trick). But the **PPT constraint** itself has to be checked on the full, unsymmetrized embedding `A ⊗ B_1 ⊗ ... ⊗ B_k`, dimension `d^(k+1)` -- exponential in `k`. Since SDP solver cost is governed by the size of the PSD cone (the PPT constraint), not by the number of free variables, this is why level 3 (81×81 cone) is already much slower than level 2 (27×27 cone), and level 4 (243×243) would be slower still. A proper fix would exploit representation-theoretic structure of the PPT constraint itself, not just of the extension -- that's a bigger undertaking than what's implemented here. If you have MOSEK (or another interior-point solver): try it first for levels 3-4. Interior-point methods are usually much faster than SCS on small/medium, dense SDPs like these -- SCS is tuned for large sparse problems and is likely the main reason level 3 took ~137s-227s per solve here rather than a fraction of a second.