Author: Adriano Pinto Claro da Fonseca
Email: apcf@topfonseca.com
Institutional email: adriano.fonseca@tecnico.ulisboa.pt
Affiliation: Student at Instituto Superior Técnico, Universidade de Lisboa
Supervisor: Pedrame Bargassa, Ruđer Bošković Institute (RBI)
This repository implements a Parametrized Quantum Circuit (PQC) binary classifier for high-energy physics (HEP) event classification — distinguishing signal from background events using 12 input features per event. Training is performed on classical hardware (or optionally on real quantum hardware) via mini-batch gradient descent, with quantum circuit gradients computed exactly using the parameter shift rule.
Four implementations are provided across two quantum computing frameworks:
| Implementation | Framework | Embedding method | Real hardware |
|---|---|---|---|
| Qiskit (primary) | Qiskit [6] / IBM | StatePreparation |
✓ IBM Quantum (via IBM_BACKEND) |
| Gram-Schmidt | PyQuil [8] / Rigetti | Custom 16×16 unitary (Gram-Schmidt) | ✗ |
| QR decomposition | PyQuil [8] / Rigetti | Custom 16×16 unitary (QR) | ✗ |
| Pytket [7] | PyQuil [8] / Rigetti | Qiskit → Pytket → PyQuil (native gates) | ✓ Rigetti QPU (via QUANTUM_COMPUTER) |
PQC_HEP_Code/
│
├── README.md ← this file
├── CITATION.cff ← citation metadata
├── LICENSE ← MIT licence
├── circuits_light.svg ← visualisation of all 19 circuits (light background)
├── circuits_dark.svg ← visualisation of all 19 circuits (dark background)
│
├── Qiskit implementation/
│ ├── PQC_HEP_training_file_Qiskit.py ← primary training script
│ └── circuits_library_Qiskit.py ← 19 variational form circuits (Qiskit)
│
└── Pyquil implementations/
├── circuits_library_PyQuil.py ← 19 variational form circuits (PyQuil)
├── Gram-Schmidt implementation/
│ └── PQC_HEP_training_file_Gram-Schmidt.py
├── QR implementation/
│ └── PQC_HEP_training_file_QR.py
└── Pytket implementation/
└── PQC_HEP_training_file_pytket.py
The data files (train_sig.csv, train_bkg.csv) are expected in a Data/ folder at the
same level as the implementation folders, or the path can be configured in USER SETTINGS.
The Qiskit implementation is recommended as the main version for the following reasons:
-
Exact simulation mode (
USE_STATEVECTOR=True): Qiskit'sAerSimulatorand theStatevectorclass allow exact, deterministic computation of P(|1⟩) without shot noise. This gives perfectly clean gradient estimates and smooth, reproducible loss curves — ideal for studying convergence behaviour. -
Real IBM Quantum hardware support: By setting
IBM_BACKENDto an IBM QPU name (e.g."ibm_brisbane"), the same code can run on real quantum hardware without modification. Qiskit'sStatePreparationgate is natively supported and can be transpiled to hardware-native gate sets. -
Computational efficiency: AerSimulator supports parallel multi-circuit evaluation via
max_parallel_experiments=0, exploiting all available CPU cores. The training loop submits entire batches of circuits in a singlebackend.run()call, eliminating per-circuit Python overhead. -
Ecosystem maturity: Qiskit [6] is the most actively developed and widely used quantum computing framework, with extensive documentation, hardware support, and community resources.
The three PyQuil implementations are included for the following reasons:
-
Exploration of amplitude embedding strategies: The Gram-Schmidt and QR implementations construct the amplitude embedding as an explicit 16×16 unitary matrix. These were developed to explore whether the choice of unitary construction method affects training behaviour, providing a direct comparison against the Qiskit StatePreparation approach.
-
Cross-framework portability: The Pytket [7] implementation demonstrates that the same PQC algorithm can be expressed across multiple quantum computing frameworks by using Pytket as a transpilation layer (Qiskit → Pytket → PyQuil [8]), rebasing the embedding to native Rigetti gates {Rx, Rz, CZ}.
-
Rigetti hardware support (Pytket only): The Pytket implementation can run on real Rigetti quantum hardware by changing the
QUANTUM_COMPUTERsetting to a QPU name (e.g."Ankaa-2"), since the native-gate rebase makes the circuit hardware-compatible. -
Completeness: All four implementations share the same mathematical framework (identical loss function, weight normalisation, parameter shift rule, and Adam optimiser), providing a basis for cross-provider hardware comparisons.
Note: The Gram-Schmidt and QR implementations use a custom
DefGateto apply the 16×16 embedding unitary. This construct is only supported by the PyQuil QVM simulator and cannot be executed on real quantum hardware without additional native-gate decomposition.
Each circuit consists of two parts applied sequentially to a 4-qubit register:
- Amplitude embedding: The 12 input features are zero-padded to 16 dimensions and normalised to unit L2 norm, encoding them as the amplitudes of a quantum state |ψ⟩.
- Variational form W(θ): A parameterised circuit of rotation gates (Rx, Ry, Rz and optionally CRx, CRy, CRz) with trainable parameters θ. 19 circuit templates are available, numbered following Figure 2 of Sim et al. (2019) [5].
The classifier output is the measurement probability P(qubit 0 = |1⟩).
Training uses mini-batch gradient descent with one Adam optimiser step per batch:
- Forward pass: evaluate P(|1⟩) for all events in the batch at the current θ.
- Batch loss: weighted binary cross-entropy over the current batch
$K$ :
where
- Gradient: computed exactly via the parameter shift rule, where
$f(\boldsymbol{\theta}) \equiv y_i(\boldsymbol{\theta}) = P_0(|1\rangle)$ is the circuit output for event$i$ at parameters$\boldsymbol{\theta}$ (the quantity evaluated in step 1):
- Four-term rule for CRx(θ), CRy(θ), CRz(θ) (generator eigenvalues {−1, 0, +1}) (see [3]):
where
The batch gradient of the loss then follows from the chain rule:
where
- Optimiser update: Adam [4] (Kingma & Ba 2014, standard constant-β₁/β₂ formulation,
implemented via
sklearn.neural_network._stochastic_optimizers.AdamOptimizer).
Physics event weights are normalised after event selection so that the total signal weight equals the total background weight:
where MAX_EVENTS or BALANCE_CLASSES settings.
Before training begins, each parameter θₖ is automatically classified by the gate type it
feeds, and the correct gradient rule is applied per parameter. Each circuit function directly
reports the gate name for every parameter it consumes via a parameterized_gate_names list,
so classification is backend-independent: all 19 circuits produce exact gradients on both
local simulation and real IBM or Rigetti quantum hardware.
Supported parameterised gate types and their rules:
| Gate | Rule | Generator eigenvalues |
|---|---|---|
| Rx(θ), Ry(θ), Rz(θ) | Two-term | {+1, −1} |
| CRx(θ), CRy(θ), CRz(θ) | Four-term | {−1, 0, +1} |
An unrecognised gate type raises a ValueError immediately with a clear message — there is
no silent failure.
If you add a new circuit: two rules apply.
Scaled parameters: each trainable parameter must appear directly as a gate angle, not as a scaled expression. Writing
rx(theta[k], q)is correct; writingrx(2*theta[k], q)causes the shift size to be wrong and gives silently incorrect gradients without triggering any error. All 19 existing circuits follow this convention.New gate types: if your circuit uses a parameterised gate not in the table above, you must add it in two places: (a) add its name and a rule label to
gate_names_to_shift_rulesin each training file you use, and (b) if its generator eigenvalue structure does not match any existing rule, also add the corresponding gradient formula incompute_batch_gradient_and_lossin each training file. If the new gate fits an existing rule (e.g. another single-qubit rotation), only step (a) is needed.
The Qiskit implementation supports two simulation modes controlled by USE_STATEVECTOR:
-
USE_STATEVECTOR = True: Computes P(|1⟩) exactly using the full quantum state vector. No measurement shot noise — gradients are exact and training curves are perfectly smooth. Recommended for studying convergence behaviour and producing clean loss curves. -
USE_STATEVECTOR = False: Estimates P(|1⟩) fromNmmeasurement shots. Introduces statistical shot noise in each gradient estimate, simulating what would occur on real quantum hardware. SetNm ≥ 1000for reasonable gradient estimates.
All 19 variational circuit architectures (Sim et al. 2019 [5]) — click to expand
Python >= 3.9
qiskit
qiskit-aer
scikit-learn
numpy
tqdm
Optional (for real IBM hardware):
qiskit-ibm-runtime
Python >= 3.9
pyquil
scikit-learn
numpy
scipy (QR implementation only)
tqdm
Docker (to run the QVM and Quilc containers)
Additional dependencies for the Pytket implementation:
pytket
pytket-qiskit
pytket-pyquil
The data files are not included in this repository and must be provided by the user.
The signal and background CSV paths are set via SIG_FILE, BKG_FILE, and DATA_FOLDER
in USER SETTINGS. The expected CSV format (one event per line) is fixed:
col 0–11 : 12 floating-point feature values
col 12 : event weight (float)
col 13 : process name (string, ignored during training)
Clone the repository and install dependencies. Each implementation requires a different set of packages — install only what you need:
# --- Qiskit implementation ---
pip install qiskit qiskit-aer scikit-learn numpy tqdm
# --- PyQuil implementations (Gram-Schmidt or QR) ---
pip install pyquil scikit-learn numpy tqdm
pip install scipy # QR implementation only; not needed for Gram-Schmidt
# --- Pytket implementation ---
# Requires both the PyQuil dependencies above AND the Pytket packages below.
pip install pyquil scikit-learn numpy tqdm
pip install pytket pytket-qiskit pytket-pyquil
# --- Optional: real IBM hardware (Qiskit only) ---
pip install qiskit-ibm-runtimeThe PyQuil implementations require the Rigetti QVM simulator and Quilc compiler to be
running as Docker containers before training is started. The port numbers must match the
QVM_PORT and QUILC_PORT settings in USER SETTINGS (defaults: 5001 and 5555).
docker run --rm -p 5001:5000 rigetti/qvm -S
docker run --rm -p 5555:5555 rigetti/quilc -RAll hyperparameters are controlled via the USER SETTINGS section at the top of each training file. No other section of the file needs to be modified between runs.
cd "Qiskit implementation"
python3 PQC_HEP_training_file_Qiskit.pyCommand-line arguments are also available and override USER SETTINGS:
python3 PQC_HEP_training_file_Qiskit.py \
--circuit-number 2 \
--n-layers 1 \
--n-iter 100 \
--batch-size 100 \
--max-events 2000Note:
--batch-sizealways takes an integer event count.BATCH_SIZE_IS_FRACTIONis ignored when--batch-sizeis given on the command line.
# Gram-Schmidt
cd "Pyquil implementations/Gram-Schmidt implementation"
python3 PQC_HEP_training_file_Gram-Schmidt.py
# QR decomposition
cd "Pyquil implementations/QR implementation"
python3 PQC_HEP_training_file_QR.py
# Pytket
cd "Pyquil implementations/Pytket implementation"
python3 PQC_HEP_training_file_pytket.pyIf training fails with a connection error, the QVM or Quilc container is not running.
Check with docker ps and restart if needed using the commands in the Installation section.
If ports 5001 or 5555 are already in use on your system, change the -p mapping in the
docker run command and update QVM_PORT / QUILC_PORT in USER SETTINGS to match.
If IBM_BACKEND is set, qiskit-ibm-runtime must be installed and a valid IBM_TOKEN
must be provided. Setting IBM_BACKEND = None always uses local simulation with no account
required.
The following settings have the most significant impact on training. All settings are documented in full detail within each training file.
| Setting | Description |
|---|---|
CIRCUIT_NUMBER |
Variational form template (1–19, see circuit selection below) |
N_LAYERS |
Number of variational block repetitions per pass |
MAX_EVENTS |
Total training events; None uses all available |
BALANCE_CLASSES |
Use equal signal and background event counts; no effect when MAX_EVENTS=None |
N_ITER |
Full passes over all training events (epochs) (default: 10) |
BATCH_SIZE |
Events per mini-batch gradient update; see BATCH_SIZE_IS_FRACTION |
BATCH_SIZE_IS_FRACTION |
If True, BATCH_SIZE is a fraction of total events (e.g. 0.1); if False, it is an exact integer count |
ALPHA |
Adam learning rate |
USE_STATEVECTOR |
Exact P(|1⟩) without shot noise — Qiskit only |
Nm |
Shots per evaluation when USE_STATEVECTOR=False — Qiskit only |
GLOBAL_EVAL_STEP |
Evaluate global loss every N passes |
RUN_TAG |
Optional string prepended to the output folder name |
Circuits 1–19 are numbered following Figure 2 of Sim et al. (2019) [5]. All circuits use 4 qubits and between 4 and 28 trainable parameters per layer application. Key properties:
- Circuits 1, 2, 9–12, 15: Only Rx/Ry/Rz gates — all parameters use the two-term rule.
- Circuits 3–8, 13–14, 16–19: Include CRx or CRz gates — some parameters use the four-term rule.
Each run creates a timestamped output folder:
[RUN_TAG_]circuit{N}_layers{L}_{iter}iter_batch{B}_{YYYY-MM-DD_HH-MM-SS}/
├── results.json ← full training record (all settings, loss history, final θ)
└── classifier.py ← standalone classifier with trained parameters baked in
The results.json file records all USER SETTINGS, the loss at each checkpoint, and
theta_final (the trained parameter vector). It can be loaded with Python's json.load().
The classifier.py file is a self-contained script that applies the trained circuit to new
events without requiring the training file. It supports two modes:
- Single event (default): edit
your_event_featuresinside the file and run it directly. - Batch CSV: pass a data file as a command-line argument to classify every event in it:
The CSV must have the same column format as the training data (col 0–11: features; col 12+: ignored). One result line is printed per event.
python classifier.py path/to/events.csv
If you use this code, please cite it as:
APA: Fonseca, A. (2026). PQC-HEP-Binary_Classification (Version 1.0.0) [Computer software]. https://github.com/APCF-git/PQC-HEP-Binary_Classification
BibTeX:
@software{fonseca2026pqchep,
author = {Fonseca, Adriano},
title = {PQC-HEP-Binary\_Classification},
year = {2026},
version = {1.0.0},
url = {https://github.com/APCF-git/PQC-HEP-Binary\_Classification},
license = {MIT}
}You can also use the "Cite this repository" button in the GitHub sidebar (generated automatically from CITATION.cff).
1. Mitarai, K., Negoro, M., Kitagawa, M., & Fujii, K. (2018).
Quantum circuit learning.
Physical Review A, 98, 032309.
arXiv:1803.00745
— Two-term parameter shift rule for exact quantum gradients; used in
compute_batch_gradient_and_loss for Rx/Ry/Rz gates in all four implementations.
2. Schuld, M., Bergholm, V., Gogolin, C., Izaac, J., & Killoran, N. (2019). Evaluating analytic gradients on quantum hardware. Physical Review A, 99, 032331. arXiv:1811.11184 — Proof of exactness of the two-term parameter shift rule for gates of the form exp(−iθ/2·P) where P is a Pauli operator.
3. Anselmetti, G.-L. R., Wierichs, D., Gogolin, C., & Parrish, R. M. (2021). Local, expressive, quantum-number-preserving VQE ansätze for fermionic systems. New Journal of Physics, 23, 113010. arXiv:2104.05695 — Four-term parameter shift rule for controlled-Pauli-rotation gates with generator eigenvalues {−1, 0, +1} (Appendix F.2, Eq. F15); used for CRx/CRy/CRz gates.
4. Kingma, D. P., & Ba, J. (2014).
Adam: A method for stochastic optimization.
arXiv:1412.6980
— Standard Adam optimiser (constant-β₁/β₂ formulation); the specific
implementation used is sklearn.neural_network._stochastic_optimizers.AdamOptimizer
in all four training files.
5. Sim, S., Johnson, P. D., & Aspuru-Guzik, A. (2019).
Expressibility and entangling capability of parameterized quantum circuits
for hybrid quantum-classical algorithms.
Advanced Quantum Technologies, 2(12), 1900070.
DOI: 10.1002/qute.201900070
— Circuit templates 1–19 in circuits_library_Qiskit.py and
circuits_library_PyQuil.py follow Figure 2 of this work.
6. Qiskit contributors (2023).
Qiskit: An open-source framework for quantum computing.
DOI: 10.5281/zenodo.2573505 (accessed 2026)
— Quantum computing framework used by the primary Qiskit implementation
(qiskit, qiskit-aer). The Zenodo record reflects the last archived version (2023);
the framework was used in its current 2026 release.
7. Sivarajah, S., Dilkes, S., Cowtan, A., Sherwood, W., Misra, A., & Duncan, R. (2021). t|ket⟩: a retargetable compiler for NISQ devices. Quantum Science and Technology, 6(1), 014003. DOI: 10.1088/2058-9565/ab8e92 — Pytket is used in the Pytket implementation as the transpilation layer (Qiskit → Pytket → PyQuil), rebasing the amplitude embedding to native Rigetti gates {Rx, Rz, CZ}.
8. Smith, R. S., Curtis, M. J., & Zeng, W. J. (2017). A practical quantum instruction set architecture. arXiv:1608.03355 — Describes the Quil quantum instruction language, the basis of the PyQuil framework used in the Gram-Schmidt, QR, and Pytket implementations.