qnmlab
Black-hole quasinormal modes with quantum algorithms.
qnmlab computes the ringing frequencies of black holes with variational quantum
algorithms. You choose a black hole, a size in qubits, a representation, and a simulated
or real quantum backend, and compare the result with trusted reference values.
The two ideas behind it:
- Phase readout. On hyperboloidal slices the modes are eigenvalues of one linear
operator, so a mode's frequency is two measured averages,
Re ω = −⟨H₂⟩,Im ω = ⟨H₁⟩. That costs about 130 times fewer shots than detecting where a matrix becomes singular. - Seedless search. A thresholded scan of the complex frequency plane produces a shortlist of candidates, and the phase readout verifies each one. No starting guess is needed.
Classical methods compute these modes faster; qnmlab is for studying, benchmarking and
running the quantum formulation, not for replacing them.
Install
pip install qnmlab # core: numpy, scipy, sympy
pip install "qnmlab[hardware]" # + Qiskit, to export circuits for real devices
Latest development version:
pip install git+https://github.com/abir-tech/qnmlab.git
Quick start
import qnmlab as ql
bh = ql.KazakovSolodukhin(a=0.5) # or ql.Schwarzschild(), ql.ReissnerNordstrom(Q), ql.Hayward(l)
ql.reference_modes(bh, ell=2, n_modes=2) # classical ground truth
# read the fundamental on a simulated noisy 3-qubit device
r = ql.measure_mode(bh, qubits=3, noise=ql.NoiseModel.emerald_random(), shots=800)
print(r.omega, r.meta["error_vs_reference"])
# find modes with no starting guess (Schwarzschild, 4 qubits)
res = ql.find_modes(ql.Schwarzschild(), qubits=4)
print(res.modes) # the fundamental and the first overtone
From the command line:
qnmlab modes --model kazakov-solodukhin --parameter 0.5
qnmlab readout --model schwarzschild --qubits 3 --noise emerald-random --shots 800
qnmlab search --model schwarzschild --qubits 4
What you can choose
| choice | options |
|---|---|
| black hole | Schwarzschild(), KazakovSolodukhin(a) — validated against published frequencies; ReissnerNordstrom(Q), Hayward(l) — experimental (cross-checked against an independent method, not against published values) |
| size | qubits; operator dimension 2**qubits |
| readout representation | "hyperboloidal" (any model), "ultraspherical" (banded generalised pencil, Schwarzschild) |
| search representation | "leaver" (tridiagonal, Schwarzschild), "frobenius" (any model) |
| search solver | "exact" (fast) or "variational" (a variational solver at every grid point) |
| noise | NoiseModel.ideal(), .emerald_random(), .emerald_coherent(), or your own NoiseModel(p2, eps, readout) |
Real hardware
op = ql.readout_operator(ql.Schwarzschild(), qubits=3)
state = ql.prepare_state(op, lead=0.48 - 0.097j, layers=2)
job = ql.hardware.build_job(op, state) # 11 circuits
ok = ql.hardware.verify(job) # Qiskit export matches the simulation
circuits = [ql.hardware.to_qiskit(c, 3) for c in job["circuits"]]
# ... run them with your provider, collect raw counts by circuit name ...
result = ql.hardware.analyse_counts(job, raw_counts) # measures bit order, mitigates readout
analyse_counts measures the provider's bit order from two calibration circuits and stops
if a qubit is stuck — both happened on real devices while this package was developed.
The raw counts of the 2026 IQM Emerald run ship with the package:
ql.benchmarks.reanalyse_emerald_2026() # (0.43919 - 0.10430i), exact 0.48186 - 0.09674i
Scope and honesty
- The end-to-end search ran in simulation; on hardware only the readout was run, from a classically prepared state.
- The search costs about 10^13 measurement shots at 4 qubits.
- The hardware error (~0.04) is dominated by gate noise; more qubits help only once it falls.
Citing
If you use qnmlab, please cite the accompanying paper (see CITATION.cff):
A. Chekroun, H. Al-Yoorby, M. A. Assal, Z. Lourghi, A. Boussahi,
Phase Readout and Seedless Search for Black-Hole Quasinormal Modes on Quantum Processors (2026).
Development
pip install -e ".[dev]"
pytest -m "not slow" # ~5 minutes
pytest # includes the ~40-minute end-to-end search
MIT licence.
Metadata
Release files for qnmlab 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| qnmlab-0.1.0.tar.gz | 82.4 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qnmlab-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 164.4 kB
Release files / qnmlab-0.1.0.tar.gz
| Download URL | qnmlab-0.1.0.tar.gz |
|---|---|
| Size | 82.4 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
ffe6149ce2e90cf9780e81b3ddca3d7c4026c4e17cd8ec5dd41115145f9202aa
|
|
BLAKE2b-256 checksum How to use checksums |
abe8da7f9f671af6d5966839b49f2adbb629acc60c36849db9444280b89ecd92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Release files / qnmlab-0.1.0-py3-none-any.whl
| Download URL | qnmlab-0.1.0-py3-none-any.whl |
|---|---|
| Size | 81.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
12e1f2c237ffa075ed3cfdf60bc1ea99d56e65a8ed5cfc9149a4949f617f5f23
|
|
BLAKE2b-256 checksum How to use checksums |
6c0314b07a401e719da6131f307fc5bf2c430a1ed7cdacc44169542792f7f74d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Security for qnmlab 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.