Lane 6 · quantum simulation

QVLASOV

A quantum-computing lane: simulating the collisionless Boltzmann (Vlasov) equation for massive-neutrino large-scale structure on real quantum hardware — reproducing and stress-testing Miyamoto et al. (Phys. Rev. Research 6, 013200, 2024). We linearize the Vlasov equation into i∂t|f⟩ = H|f⟩ (Schrödinger form), Trotterize the evolution, and run it end-to-end: classical solver → statevector → cloud simulator → IonQ trapped-ion QPU.

classical Vlasov reference Trotter emulation (4–6 qubits) SV1 cloud fidelity 0.996 IonQ Forte-1: ran on real QPU

QV-F1 · Neutrino phase space f(x,v) Miyamoto+24 Fig. 2reproduced

🖥 NUMERICAL SIMULATION · classical · scipy matrix-exp eA·T · state dim 4096 (n_gr=64, 1-D x–v phase space) · CPU
∂f/∂t  +  v·∂f/∂x  +  FCDM(t,x)·∂f/∂v  =  0 Miyamoto+24, Eq. 4 — the linearized Vlasov equation. f(t,x,v) = the neutrino distribution in phase space. Neutrinos are <1% of the matter, so their self-gravity is dropped and the CDM force FCDM is an external, known field — that's what makes it linear.

The linearized Vlasov operator is antisymmetriciA is Hermitian, so the evolution is unitary (norm conserved to machine precision). The neutrino distribution shears in phase space under the CDM force F=A sin(Kx).

phase space

QV-F2 · Density perturbation & its spectrum Miyamoto+24 Figs. 3–4reproduced

🖥 NUMERICAL SIMULATION · classical · same Vlasov solver (eA·T) · CPU
ρν(t,x) = ∫ f(t,x,v) d3v   →   δν = (ρν − ρ̄ν)/ρ̄ν   →   Pν(k) = ⟨|δ̃ν(k)|²⟩ Miyamoto+24, Eqs. 6–8 — the observable. Integrate the same f over velocity to get the neutrino density, its fractional perturbation δν, and the power spectrum Pν(k) — the quantity cosmologists compare to data.

The single CDM force mode K drives only the k=K neutrino density mode — every other mode stays at zero. This is the paper's key demonstration, on our classical reference.

density mode

QV-F3 · Trotter convergence quantum algorithm coreverified

QUANTUM SIMULATION · exact statevector emulation (noiseless) · 4–6 qubits (n_gr=4/8) · Trotterized circuit · numpy/CPU
discretize Vlasov  →  df/dt = A(t) f   (A real antisymmetric) ↓  so H ≡ iA is Hermitian — the paper's key move i ∂t|f⟩ = H(t)|f⟩   ⟹   |f(T)⟩ = e−iHT|f(0)⟩ ≈ ( e−iHxτ e−iHvτ )n Miyamoto+24, Eqs. 16, 23, 25 — the Vlasov equation becomes a Schrödinger equation, so a quantum computer can evolve it by Hamiltonian simulation. The last step is the Trotter splitting (τ = T/n) that this chart tests.

The Trotterized Hamiltonian simulation (e-iHxτe-iHvτ)n converges to the exact evolution as 1/n_trotter, at 4-qubit (n_gr=4) and 6-qubit (n_gr=8) scale.

trotter convergence

QV-F4 · Vlasov simulation on a real quantum computer IonQ Forte-1ran on QPU

QUANTUM SIMULATION · REAL HARDWARE — IonQ Forte-1 (trapped-ion QPU, us-east-1) · 4 qubits · circuits depth 62 / 121 / 180 · 40 / 78 / 116 two-qubit gates · 300 shots each · native gates GPI/GPI2/ZZ
|f(T)⟩ = e−iHT|f(0)⟩   with H = iA from the Vlasov equation The same evolution, executed as a gate circuit on trapped ions. Each Trotter factor becomes Pauli-exponential gadgets (basis change → CNOT ladder → Rz), transpiled to IonQ's native GPI/GPI2/ZZ gates; measured shot counts give |f(T)|².

Trotter circuits ran on IonQ Forte-1 at 300 shots each. When well-calibrated, the QPU reproduces the neutrino Vlasov-evolution distribution to ~90–95% (nt=2: 0.97), with only ~10% of probability leaking to physically-forbidden states — the mechanism genuinely runs on hardware. But the shallowest circuit (nt=1) reproducibly scored ~0.6, which is counterintuitive and triggered a full root-cause analysis (QV-F5).

IonQ fidelity and leakage

QV-F5 · Root-cause analysis — two NISQ error regimes nt-sweep + noise modelRCA

QUANTUM (REAL HARDWARE) IonQ Forte-1 · 4 qubits · nt-sweep 40→306 two-qubit gates  +  🖥 classical depolarizing-noise model (density-matrix sim) for comparison

To find why the shallowest circuit was worst, we swept the Trotter count at fixed evolution (T=0.2) — so gate count grows (40→306) while per-gate rotation angle shrinks (0.25→0.03 rad) — and compared the hardware to an incoherent depolarizing-noise model.

Result — the cause is resolved. Incoherent depth-noise would make the fewest-gate circuit the best (model: 0.84); hardware reproducibly makes it the worst (0.63, across three runs). So nt=1 is a coherent / systematic error in the shallow, large-angle limit — not gate-count noise (my earlier "calibration drift" guess was refuted by a re-run). Meanwhile nt≥2 (0.97→0.93→0.87) tracks the depth-noise slope. Two regimes, cleanly separated: coherent error dominates shallow, incoherent noise dominates deep, optimum at nt=2.

RCA two regimes

Scorecard — QVLASOV vs Miyamoto et al. 2024

Honest status against the paper's claims. = the quantum algorithm's classical demonstration (Sec. IV); = our extension onto real NISQ hardware.

#Claim / targetOur resultStatus
QV-1Linearized Vlasov → Schrödinger form (A antisymmetric)exact, iA Hermitian
QV-2Norm (particle number) conserved1.0 to 1e-15
QV-3Single CDM mode K drives only k=K density mode (Fig. 4)reproduced
QV-4Hamiltonian simulation via Trotter1/n conv., 4–6 qubits
QV-5Native gate circuit (IonQ GPI/GPI2/ZZ)depth 62, 40×2q, fid 0.998
QV-6Cloud noiseless (SV1)fidelity 0.9957
QV-7Real QPU (IonQ Forte-1)up to 0.97; 2 error regimes (RCA)
QV-8Full FTQC algorithm (QRAM, QAE, 6-D)not feasible on NISQ — honest◐ scoped

Honest limits. The paper's full algorithm targets a fault-tolerant machine (QRAM + deep amplitude estimation + 6-D phase space). That is not runnable on today's NISQ hardware — and we don't claim it is. What runs on IonQ is the core mechanism at toy scale (n_gr=4, 4 qubits): the honest, demonstrable slice.

Implementation

The actual source — validated at every gate/layer before any physics or hardware claim. Fourier pseudospectral split-step; quantum circuits in the Amazon Braket SDK.

"""
QVLASOV lane -- classical reference for Miyamoto et al. (PRResearch 6, 013200, 2024), Sec. IV.

Linearized Vlasov equation for a light species (neutrino) in an external CDM force, in 1D
phase space (x, v). Central-difference discretization -> df/dt = A f with A REAL ANTISYMMETRIC
(paper Eq. 16, 23). Since iA is Hermitian this is the Schroedinger-form the quantum algorithm
simulates; here we integrate it CLASSICALLY (exp(A T) f0) as the ground-truth the quantum
Trotter circuits are benchmarked against.

Toy parameters (paper Sec. IV): L=2, V=1, n_gr=64, F_CDM(x)=A sin(Kx) with A=-1, K=pi,
Maxwell IC f0(x,u) = exp(-u^2/2 sigma^2)/sqrt(2 pi sigma^2), sigma=0.1, evolve to T=0.1, 0.2.
Expected (Figs. 3-4): the CDM force (single mode K) drives ONLY the k=K density mode.
"""
import numpy as np
import scipy.sparse as sp
from scipy.sparse.linalg import expm_multiply


def build_operator(n=64, L=2.0, V=1.0, A=-1.0, K=np.pi):
    """Return (A_matrix, x, v). f indexed as flat[i*n + j], i=x, j=v.
    Streaming -v d/dx (periodic in x); force -F(x) d/dv (Dirichlet f=0 outside v-grid)."""
    dx = L / n
    x = np.arange(n) * dx
    dv = 2.0 * V / (n + 1)
    v = -V + (np.arange(n) + 1) * dv          # Dirichlet grid, excludes +/-V (Eq. 11)
    F = A * np.sin(K * x)                      # CDM force (Eq. 68)

    rows, cols, vals = [], [], []

    def add(r, c, val):
        rows.append(r); cols.append(c); vals.append(val)

    for i in range(n):
        ip, im = (i + 1) % n, (i - 1) % n      # periodic in x
        for j in range(n):
            r = i * n + j
            # streaming: -v_j (f[i+1,j] - f[i-1,j]) / (2 dx)
            add(r, ip * n + j, -v[j] / (2 * dx))
            add(r, im * n + j, +v[j] / (2 * dx))
            # force: -F_i (f[i,j+1] - f[i,j-1]) / (2 dv), Dirichlet
            if j + 1 < n:
                add(r, i * n + (j + 1), -F[i] / (2 * dv))
            if j - 1 >= 0:
                add(r, i * n + (j - 1), +F[i] / (2 * dv))

    Amat = sp.csr_matrix((vals, (rows, cols)), shape=(n * n, n * n))
    return Amat, x, v


def maxwell_ic(n, v, sigma=0.1):
    """f0 constant in x, Maxwell in v (Eq. 70). Returns flat vector (n*n,)."""
    fv = np.exp(-v ** 2 / (2 * sigma ** 2)) / np.sqrt(2 * np.pi * sigma ** 2)
    f0 = np.tile(fv, (n, 1))                   # (n_x, n_v), constant in x
    return f0.reshape(-1)


def density(f_flat, n, dv):
    """rho(x) = sum_v f dv  ->  delta(x) = (rho - mean)/mean."""
    f = f_flat.reshape(n, n)
    rho = f.sum(axis=1) * dv
    return rho, (rho - rho.mean()) / rho.mean()


def evolve(Amat, f0, T):
    """f(T) = exp(A T) f0  (A antisymmetric -> orthogonal -> norm preserving)."""
    return expm_multiply(Amat * T, f0)


def run():
    n, L, V, K = 64, 2.0, 1.0, np.pi
    Amat, x, v = build_operator(n=n, L=L, V=V, A=-1.0, K=K)
    dv = 2.0 * V / (n + 1)
    f0 = maxwell_ic(n, v, sigma=0.1)

    print(f"QVLASOV classical: n_gr={n} (dim {n*n}), L={L} V={V} K=pi, A antisymmetric="
          f"{np.allclose((Amat + Amat.T).toarray(), 0, atol=1e-12)}")
    results = {}
    for T in (0.0, 0.1, 0.2):
        fT = evolve(Amat, f0, T) if T > 0 else f0.copy()
        rho, delta = density(fT, n, dv)
        norm = np.linalg.norm(fT) / np.linalg.norm(f0)
        dk = np.abs(np.fft.rfft(delta))
        kmode = np.argmax(dk[1:]) + 1  # dominant nonzero mode
        results[T] = dict(delta=delta, dk=dk, norm=norm, kmode=int(kmode))
        print(f"T={T:.1f}: |f|/|f0|={norm:.6f} (orthogonal->1)  dominant density mode k_index={kmode} "
              f"(K=pi -> index {int(round(K*L/(2*np.pi)))})  max|delta|={np.abs(delta).max():.3e}")
    np.savez("data/vlasov_classical.npz",
             **{f"delta_T{int(T*10)}": results[T]["delta"] for T in results},
             **{f"dk_T{int(T*10)}": results[T]["dk"] for T in results}, x=x)
    # check: at T>0 the dominant mode is k-index 1 (= K=pi over L=2 -> one wavelength)
    kexpect = int(round(K * L / (2 * np.pi)))  # = 1
    ok = all(results[T]["kmode"] == kexpect for T in (0.1, 0.2)) and \
         all(abs(results[T]["norm"] - 1) < 1e-6 for T in results)
    print("QVLASOV classical:", "PASS" if ok else "CHECK",
          f"(single mode k={kexpect} driven, norm conserved)")
    return results, x


if __name__ == "__main__":
    run()
"""
QVLASOV quantum stage 1 -- Trotterized Hamiltonian simulation of the linearized Vlasov
operator, emulated EXACTLY on a statevector (numpy). This is the algorithm the paper runs
on an FTQC; here we verify at TOY scale that:
  (a) H = iA is Hermitian (A antisymmetric) -> exp(-iHt) is a genuine quantum evolution;
  (b) Trotter(exp(-iH_x t/n) exp(-iH_v t/n))^n -> exact exp(-iHt) as n grows (2nd-order);
  (c) the encoded state reproduces the CLASSICAL neutrino density mode (Fig. 4).

n_gr in {4, 8}: state dimension n_gr^2 = 16 (4 qubits) or 64 (6 qubits) -- QPU-scale.
"""
import numpy as np
from scipy.linalg import expm


def build_parts(n, L=2.0, V=1.0, A=-1.0, K=np.pi):
    """Dense A_stream (-v d/dx) and A_force (-F d/dv); flat index i*n+j (i=x, j=v)."""
    dx, dv = L / n, 2.0 * V / (n + 1)
    x = np.arange(n) * dx
    v = -V + (np.arange(n) + 1) * dv
    F = A * np.sin(K * x)
    As = np.zeros((n * n, n * n)); Af = np.zeros((n * n, n * n))
    for i in range(n):
        ip, im = (i + 1) % n, (i - 1) % n
        for j in range(n):
            r = i * n + j
            As[r, ip * n + j] += -v[j] / (2 * dx)
            As[r, im * n + j] += +v[j] / (2 * dx)
            if j + 1 < n:
                Af[r, i * n + (j + 1)] += -F[i] / (2 * dv)
            if j - 1 >= 0:
                Af[r, i * n + (j - 1)] += +F[i] / (2 * dv)
    return As, Af, x, v, dv


def maxwell(n, v, sigma=0.1):
    fv = np.exp(-v ** 2 / (2 * sigma ** 2)) / np.sqrt(2 * np.pi * sigma ** 2)
    return np.tile(fv, (n, 1)).reshape(-1)


def density_mode(state, n, dv, kidx=1):
    rho = state.reshape(n, n).real.sum(axis=1) * dv
    delta = (rho - rho.mean()) / rho.mean()
    return np.abs(np.fft.rfft(delta))[kidx]


def main():
    for n in (4, 8):
        As, Af, x, v, dv = build_parts(n)
        A = As + Af
        H = 1j * A
        herm = np.allclose(H, H.conj().T, atol=1e-12)
        f0 = maxwell(n, v); f0 = f0 / np.linalg.norm(f0)
        T = 0.2
        exact = expm(-1j * H * T) @ f0      # = expm(A T) f0
        # (b) Trotter convergence
        print(f"--- n_gr={n} (dim {n*n} = {int(np.log2(n*n))} qubits) | H Hermitian={herm}")
        Hx, Hv = 1j * As, 1j * Af
        for nt in (1, 2, 4, 8, 16, 32):
            Ux = expm(-1j * Hx * (T / nt))
            Uv = expm(-1j * Hv * (T / nt))
            state = f0.copy()
            for _ in range(nt):
                state = Uv @ (Ux @ state)
            err = np.linalg.norm(state - exact)
            print(f"   Trotter steps={nt:2d}: |psi_trot - psi_exact| = {err:.2e}")
        # (c) density mode matches classical
        km_exact = density_mode(exact, n, dv)
        km_f0 = density_mode(f0, n, dv)
        print(f"   density k=1 mode: t=0 -> {km_f0:.2e},  T={T} -> {km_exact:.2e} "
              f"(enhanced, cf. classical Fig. 4)")


if __name__ == "__main__":
    main()
"""
QVLASOV quantum stage 2 -- gate-level circuit for real hardware (IonQ via Braket).

We Pauli-decompose H_x=iA_stream and H_v=iA_force (n_gr=4 -> 4 qubits), build a Trotter
circuit of Pauli-exponential gadgets (exp(-i c_k P_k tau) = basis-change + CNOT-ladder +
Rz), and VALIDATE it (numpy) against the exact evolution before any hardware.
This native-gate circuit is what Braket transpiles for IonQ.
"""
import numpy as np
from itertools import product
from trotter_emulation import build_parts, maxwell

I2 = 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": I2, "X": X, "Y": Y, "Z": Z}


def kron_string(s):
    M = np.array([[1]], dtype=complex)
    for ch in s:
        M = np.kron(M, PAULI[ch])
    return M


def pauli_decompose(H, nq, tol=1e-9):
    """H (2^nq x 2^nq Hermitian) -> {pauli_string: real_coeff}."""
    d = 2 ** nq
    terms = {}
    for combo in product("IXYZ", repeat=nq):
        s = "".join(combo)
        c = np.trace(kron_string(s).conj().T @ H) / d
        if abs(c) > tol:
            terms[s] = float(np.real(c))
    return terms


def exp_pauli_matrix(s, theta, nq):
    """exp(-i theta P) as a full matrix (for validation)."""
    P = kron_string(s)
    return np.cos(theta) * np.eye(2 ** nq) - 1j * np.sin(theta) * P


def trotter_unitary(terms_x, terms_v, T, n_trotter, nq):
    """(prod exp(-i c P tau) over v-terms, then x-terms)^n_trotter, tau=T/n_trotter."""
    tau = T / n_trotter
    U = np.eye(2 ** nq, dtype=complex)
    for _ in range(n_trotter):
        for s, c in terms_x.items():
            U = exp_pauli_matrix(s, c * tau, nq) @ U
        for s, c in terms_v.items():
            U = exp_pauli_matrix(s, c * tau, nq) @ U
    return U


def validate(n_gr=4):
    from scipy.linalg import expm
    nq = int(np.log2(n_gr * n_gr))
    As, Af, x, v, dv = build_parts(n_gr)
    Hx, Hv = 1j * As, 1j * Af
    H = Hx + Hv
    tx = pauli_decompose(Hx, nq)
    tv = pauli_decompose(Hv, nq)
    print(f"n_gr={n_gr} -> {nq} qubits | Pauli terms: H_x={len(tx)}, H_v={len(tv)}")
    # (a) decomposition exact
    Hx_rec = sum(c * kron_string(s) for s, c in tx.items())
    print(f"  decomposition error |H_x - sum c P| = {np.abs(Hx - Hx_rec).max():.2e}")
    # (b) Trotter circuit unitary -> exact evolution
    T = 0.2
    exact = expm(-1j * H * T)
    for nt in (1, 2, 4, 8):
        U = trotter_unitary(tx, tv, T, nt, nq)
        err = np.abs(U - exact).max()
        print(f"  Trotter steps={nt}: |U_circuit - U_exact|_max = {err:.2e}")
    # (c) act on Maxwell IC, check density mode grows
    f0 = maxwell(n_gr, v); f0 = f0 / np.linalg.norm(f0)
    psi = trotter_unitary(tx, tv, T, 8, nq) @ f0
    rho = psi.reshape(n_gr, n_gr).real.sum(axis=1) * dv
    delta = (rho - rho.mean()) / rho.mean()
    print(f"  density k=1 mode after circuit: {np.abs(np.fft.rfft(delta))[1]:.3e} (grows from 0)")
    return tx, tv


if __name__ == "__main__":
    validate(4)
"""
QVLASOV -- Braket gate circuit (n_gr=4, 4 qubits) for IonQ.
Circuit = state-prep(Maxwell f0, a product state: uniform in x, Gaussian in v)
          + Trotter( exp(-i H_x tau) exp(-i H_v tau) ) via native Pauli-exponential gadgets.
Validated on the LOCAL simulator against the classical evolution BEFORE any cloud/QPU cost.
"""
import numpy as np
from braket.circuits import Circuit
from braket.devices import LocalSimulator
from trotter_emulation import build_parts, maxwell
from quantum_circuit import pauli_decompose, trotter_unitary

N_GR = 4
NQ = 4  # qubits 0,1 = x (MSB), qubits 2,3 = v (LSB)


def gaussian_prep_angles(n_gr=4, sigma=0.1, V=1.0):
    """4-amplitude Gaussian (v-grid) -> angles for a 2-qubit real state prep."""
    dv = 2 * V / (n_gr + 1)
    v = -V + (np.arange(n_gr) + 1) * dv
    a = np.exp(-v ** 2 / (2 * sigma ** 2)); a = a / np.linalg.norm(a)  # a[j], j=2*q2+q3
    r0 = np.hypot(a[0], a[1]); r1 = np.hypot(a[2], a[3])
    beta = 2 * np.arctan2(r1, r0)
    g0 = 2 * np.arctan2(a[1], a[0])
    g1 = 2 * np.arctan2(a[3], a[2])
    return beta, g0, g1, a


def add_state_prep(circ):
    """|0000> -> f0 = (uniform on x-qubits 0,1) (x) (Gaussian on v-qubits 2,3)."""
    circ.h(0); circ.h(1)                       # uniform in x
    beta, g0, g1, _ = gaussian_prep_angles()
    circ.ry(2, beta)                            # split between v-halves
    # uniformly-controlled Ry on qubit 3 controlled by qubit 2
    circ.ry(3, (g0 + g1) / 2)
    circ.cnot(2, 3)
    circ.ry(3, (g0 - g1) / 2)
    circ.cnot(2, 3)
    return circ


def add_pauli_exp(circ, s, theta):
    """exp(-i theta P): basis-change + CNOT ladder + Rz(2 theta) + uncompute."""
    active = [q for q, ch in enumerate(s) if ch != "I"]
    if not active or abs(theta) < 1e-12:
        return
    for q in active:            # basis change: map Pauli -> Z
        if s[q] == "X":
            circ.h(q)
        elif s[q] == "Y":
            circ.rx(q, np.pi / 2)
    for a, b in zip(active[:-1], active[1:]):
        circ.cnot(a, b)
    circ.rz(active[-1], 2 * theta)
    for a, b in zip(active[:-1][::-1], active[1:][::-1]):
        circ.cnot(a, b)
    for q in active:            # uncompute basis change
        if s[q] == "X":
            circ.h(q)
        elif s[q] == "Y":
            circ.rx(q, -np.pi / 2)


def build_circuit(T=0.2, n_trotter=4, prep=True):
    As, Af, x, v, dv = build_parts(N_GR)
    tx = pauli_decompose(1j * As, NQ)
    tv = pauli_decompose(1j * Af, NQ)
    tau = T / n_trotter
    circ = Circuit()
    if prep:
        add_state_prep(circ)
    for _ in range(n_trotter):
        for s, c in tx.items():
            add_pauli_exp(circ, s, c * tau)
        for s, c in tv.items():
            add_pauli_exp(circ, s, c * tau)
    return circ, (As, Af, x, v, dv)


def density_mode_from_state(state, n_gr, dv):
    rho = np.abs(state.reshape(n_gr, n_gr)).real
    # state amplitudes are real up to global phase; use real part with sign from phase
    amp = state.reshape(n_gr, n_gr)
    rho = amp.real.sum(axis=1) * dv
    delta = (rho - rho.mean()) / rho.mean()
    return np.abs(np.fft.rfft(delta))[1], delta


def validate():
    from scipy.linalg import expm
    T = 0.2
    As, Af, x, v, dv = build_parts(N_GR)
    f0 = maxwell(N_GR, v); f0 = f0 / np.linalg.norm(f0)
    exact = expm((As + Af) * T) @ f0
    exact_n = exact / np.linalg.norm(exact)
    dev = LocalSimulator()
    print(f"{'n_trot':>6} {'depth':>6} {'gates':>6} {'2q-gates':>8} {'fidelity':>10}")
    for nt in (1, 2, 3, 4):
        circ, _ = build_circuit(T=T, n_trotter=nt, prep=True)
        n2q = sum(1 for ins in circ.instructions if ins.operator.qubit_count == 2)
        sv = np.asarray(dev.run(circ.state_vector(), shots=0).result().values[0])
        fid = abs(np.vdot(sv, exact_n)) ** 2
        print(f"{nt:6d} {circ.depth:6d} {len(circ.instructions):6d} {n2q:8d} {fid:10.5f}")
    return None


if __name__ == "__main__":
    validate()
"""
Run the QVLASOV circuit on Braket devices and compare the measured phase-space distribution
to the classical ground truth. SV1 (noiseless cloud) validates the pipeline; IonQ Forte-1
(real QPU) is the hardware demo -- benchmarked classical <-> noiseless <-> real.

The hardware observable is the computational-basis probability P(bitstring) = |amplitude|^2
over the 16 phase-space grid points; classical target = |exp(A T) f0|^2. Distribution
fidelity F = (sum sqrt(p_i q_i))^2 quantifies how well the device reproduces the physics.
"""
import sys
import numpy as np
from scipy.linalg import expm
from braket.aws import AwsDevice
from braket.devices import LocalSimulator
from trotter_emulation import build_parts, maxwell
from braket_run import build_circuit, N_GR

S3 = ("amazon-braket-us-east-1-297904677595", "qvlasov")
SV1 = "arn:aws:braket:::device/quantum-simulator/amazon/sv1"
IONQ = "arn:aws:braket:us-east-1::device/qpu/ionq/Forte-1"


def classical_distribution(T=0.2):
    As, Af, x, v, dv = build_parts(N_GR)
    f0 = maxwell(N_GR, v); f0 = f0 / np.linalg.norm(f0)
    psi = expm((As + Af) * T) @ f0
    return np.abs(psi) ** 2 / np.sum(np.abs(psi) ** 2)


def counts_to_dist(counts, nq=4):
    d = np.zeros(2 ** nq)
    tot = sum(counts.values())
    for bstr, c in counts.items():
        d[int(bstr, 2)] = c / tot
    return d


def fidelity(p, q):
    return float(np.sum(np.sqrt(np.clip(p, 0, None) * np.clip(q, 0, None))) ** 2)


def run(device_name, n_trotter=1, shots=1000, T=0.2):
    circ, _ = build_circuit(T=T, n_trotter=n_trotter, prep=True)
    cls = classical_distribution(T)
    # noiseless local reference
    loc = LocalSimulator().run(circ, shots=shots).result().measurement_counts
    loc_d = counts_to_dist(loc)
    print(f"[local noiseless] n_trotter={n_trotter} shots={shots} "
          f"fidelity vs classical = {fidelity(loc_d, cls):.4f}", flush=True)
    if device_name == "local":
        return
    arn = SV1 if device_name == "sv1" else IONQ
    dev = AwsDevice(arn)
    print(f"submitting to {device_name} ({arn.split('/')[-1]}) ...", flush=True)
    task = dev.run(circ, shots=shots, s3_destination_folder=S3)
    print(f"  task id: {task.id}", flush=True)
    if device_name == "sv1":
        res = task.result()  # SV1 returns quickly
        dev_d = counts_to_dist(res.measurement_counts)
        print(f"[SV1] fidelity vs classical = {fidelity(dev_d, cls):.4f}", flush=True)
    else:
        print(f"  IonQ task QUEUED -- poll with: {task.id}", flush=True)
        print(f"  status: {task.state()}", flush=True)
    return task


if __name__ == "__main__":
    dev = sys.argv[1] if len(sys.argv) > 1 else "local"
    nt = int(sys.argv[2]) if len(sys.argv) > 2 else 1
    run(dev, n_trotter=nt)
"""
Submit the QVLASOV Trotter circuits (n_trotter=1,2,3) to IonQ Forte-1 for the
classical <-> noiseless <-> real-QPU breaking-point curve. Saves task ARNs for polling.
"""
import json
import numpy as np
from braket.aws import AwsDevice
from braket_run import build_circuit
from run_cloud import S3, IONQ, classical_distribution, counts_to_dist, fidelity
from braket.devices import LocalSimulator

SHOTS = 300
NTS = [1, 2, 3]

dev = AwsDevice(IONQ)
cls = classical_distribution()
tasks = {}
print(f"IonQ Forte-1 -- submitting n_trotter={NTS} at {SHOTS} shots "
      f"(est ${len(NTS)*(SHOTS*0.08+0.30):.2f})", flush=True)
for nt in NTS:
    circ, _ = build_circuit(T=0.2, n_trotter=nt, prep=True)
    n2q = sum(1 for ins in circ.instructions if ins.operator.qubit_count == 2)
    loc = counts_to_dist(LocalSimulator().run(circ, shots=2000).result().measurement_counts)
    task = dev.run(circ, shots=SHOTS, s3_destination_folder=S3)
    tasks[nt] = {"arn": task.id, "depth": circ.depth, "n2q": n2q,
                 "noiseless_fidelity": fidelity(loc, cls)}
    print(f"  nt={nt}: depth={circ.depth} 2q={n2q} noiseless_fid={fidelity(loc, cls):.4f} "
          f"-> {task.id}  [{task.state()}]", flush=True)

with open("data/ionq_tasks.json", "w") as f:
    json.dump({"shots": SHOTS, "cls_dist": cls.tolist(), "tasks": tasks}, f, indent=2)
print("saved data/ionq_tasks.json -- poll with poll_ionq.py", flush=True)

Why this lane — and how it relates to the FDM program

Miyamoto et al. is one of two frontier "quantum simulation" papers. Its key move — linearized Vlasov → Schrödinger equation → Hamiltonian simulation — is the same mathematical structure as our wave-dark-matter solvers. Fuzzy dark matter is a Schrödinger–Poisson system; this neutrino Vlasov problem becomes one by construction. Both reduce to Hamiltonian evolution on a grid.

Two faces of quantum simulation sit side by side in this program: the analog route (the VACUA lane — a cold-atom BEC that is the physics) and the digital route here (a gate-based quantum algorithm). Both are underwritten by the same differentiable spectral machinery we built for the FDM campaign.

The honest arc. The full fault-tolerant algorithm is years of hardware away. But its core kernel — Trotterized Hamiltonian simulation of the Vlasov state — runs today. We take it as far as NISQ allows: classical ↔ noiseless simulator ↔ real IonQ QPU, and we measure where it breaks. That breaking point, not an over-claimed "we simulated cosmology on a quantum computer," is the result.

fdmsim · QVLASOV lane · reproduction + real-hardware extension of Miyamoto et al. 2024 · classical ↔ SV1 ↔ IonQ Forte-1 · blind, provenance-tracked, no goal-seeking