cpsc-qft / src /cpsc /compiler.py
SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
eef9104 verified
Raw History Blame Contribute Delete
3.44 kB
# *******************************************************************************
# Copyright (c) 2026 Ahmad Ali Parr and others.
#
# This program and the accompanying materials are made available under the
# terms of the CPSC Eclipse Strict Copyleft License, Version 1.0, which is
# available in LICENSES/CPSC-ESCL-1.0.txt, or, at your option, under the
# GNU Affero General Public License, Version 3 only, which is available in
# LICENSES/AGPL-3.0.txt. Both options are strict copyleft. There is no
# classpath exception and no permissive relicensing.
#
# SPDX-License-Identifier: LicenseRef-CPSC-ESCL-1.0 OR AGPL-3.0-only
# *******************************************************************************
"""Proof-carrying scattering synthesis.
The compiler admits a gate list, checks the translation orbit, exponentiates
only the admitted local terms, and binds a certificate to the admitted list.
"""
from __future__ import annotations
import numpy as np
from cpsc.analyzer import CompilationRejected, Gate, SymmetryAnalyzer, SymmetryMode
from cpsc.certificate import Certificate, bind_certificate
from cpsc.channel import evolve_trotter, x_parity_leakage, z_parity_leakage
from cpsc.hamiltonian import magnetization_of, parity_of
def translation_orbit_closed(gates: list[Gate], n: int) -> str | None:
"""A translation-invariant schedule must include every cyclic image.
ZZ[i, i+1] is closed only if every bond appears. A lone transverse flip
is closed only if every site appears with the same kind. Global gates
with empty support are already invariant.
"""
names = {(g.kind, g.qubits) for g in gates}
for kind, qubits in list(names):
if not qubits:
continue
for shift in range(n):
image = tuple((q + shift) % n for q in qubits)
if (kind, image) not in names and (kind, image[::-1]) not in names:
return (
f"{kind}{qubits} is not closed under translation; "
f"missing image {image}"
)
return None
def compile_scattering(
n: int,
initial_basis: int,
gates: list[Gate],
*,
time: float,
steps: int = 8,
j: float = 1.0,
lam: float = 0.0,
require_translation: bool = True,
) -> dict:
if steps < 1:
raise ValueError("steps must be positive")
mode = SymmetryMode.ISING if lam == 0.0 else SymmetryMode.SPIN_FLIP
analyzer = SymmetryAnalyzer(n, mode=mode)
admitted = analyzer.admit(gates)
if require_translation:
reason = translation_orbit_closed(admitted, n)
if reason is not None:
raise CompilationRejected(reason)
conserve_mag = mode is SymmetryMode.ISING
state = evolve_trotter(
n,
initial_basis,
admitted,
time=time,
steps=steps,
j=j,
lam=lam,
conserve_magnetization=conserve_mag,
)
certificate = bind_certificate(admitted, mode=mode.value, n=n, lam=lam, j=j, time=time, steps=steps)
z_leak = z_parity_leakage(state, n, parity_of(initial_basis, n))
x_leak = x_parity_leakage(state, n, initial_basis)
return {
"mode": mode.value,
"admitted": admitted,
"state": state,
"certificate": certificate,
"z_parity_leakage": z_leak,
"x_parity_leakage": x_leak,
"magnetization": magnetization_of(initial_basis, n) if conserve_mag else None,
}