C++ accelerated FPM quantum simulation primitives with Python bindings
Project description
fpm-cpp-port — C++ Accelerated FPM (Finite Possibility Mechanics)
Install from PyPI:
pip install fpm-qsim
Use the C++ extension module:
import fpm_cpp as fpm
A 540-line C++17 port of fpm-qsim 0.1.8's core simulation primitives, bit-exact verified against the Python reference, delivering up to 332× speedup at 1 qubit and 409× speedup vs the general matrix-exp baseline at 6 qubits.
Headline result
On the canonical 1-qubit pure-dephasing benchmark (γ=0.02, dt=1.0, 1000 steps):
| Method | Wall time | Max abs error |
|---|---|---|
| C++ FPM (serial) | 0.06 ms | 4.86 × 10⁻¹⁶ |
| C++ FPM (OpenMP) | 2.04 ms | 4.86 × 10⁻¹⁶ |
| Python FPM (NumPy) | 19.92 ms | 4.86 × 10⁻¹⁶ |
| matrix-exp (general) | 6.13 ms | 4.86 × 10⁻¹⁶ |
| matrix-exp (specialized) | 6.87 ms | 4.86 × 10⁻¹⁶ |
| QuTiP 5.3.0 | 54.25 ms | 8.66 × 10⁻⁹ |
| scipy.solve_ivp | 25.80 ms | 1.61 × 10⁻⁹ |
| Qiskit Aer 0.17.2 | 151.37 ms | 5.55 × 10⁻¹⁴ |
C++ FPM serial is 332× faster than Python FPM, 102× faster than the general matrix-exp baseline, 904× faster than QuTiP, and 2,523× faster than Qiskit Aer — at identical machine-precision accuracy.
What's in this bundle
fpm-cpp-port/
├── README.md ← This file
├── fpm_core.hpp ← C++ header-only core (380 LOC)
├── fpm_cpp_bindings.cpp ← pybind11 bindings (160 LOC)
├── build.sh ← Build script (run this first)
├── fpm_cpp.cpython-312-x86_64-linux-gnu.so ← Pre-compiled extension (Linux x86_64, Python 3.12)
├── equivalence_test.py ← 7-category bit-exact verification suite
├── benchmark_v2.py ← Head-to-head benchmark (9 methods × 7 qubit counts)
├── make_charts_v2.py ← Generates 10 PNG charts at 200 DPI
├── build_report_v2.py ← Builds the final PDF report
├── FPM-CPP-vs-Competitors_Analysis-Report_2026-06-18.pdf ← The 30-page report
├── results/
│ ├── benchmark_results_v2.json ← Full benchmark dataset (63 rows)
│ └── benchmark_results_v2.csv ← Same in CSV
└── charts/ ← 10 PNG charts at 200 DPI
├── 01_wall_time_vs_dim_v2.png
├── 02_speedup_vs_baselines_v2.png
├── 03_accuracy_by_method_v2.png
├── 04_memory_vs_dim_v2.png
├── 05_cpp_vs_py_breakdown_v2.png
├── 06_heatmap_v2.png
├── 07_fpm_features_cpp.png
├── 08_capability_radar_v2.png
├── 09_openmp_speedup_v2.png
└── 10_loc_comparison_v2.png
Quick start
Option A: Use the pre-compiled extension (Linux x86_64, Python 3.12)
cd fpm-cpp-port
# Verify the pre-compiled extension works
python3 equivalence_test.py
# Run the benchmark
pip install fpm-qsim qutip qiskit qiskit-aer scipy matplotlib pandas
python3 benchmark_v2.py
Option B: Build from source (any platform)
cd fpm-cpp-port
# Install build dependencies
pip install pybind11
# Build the extension
./build.sh
# Verify
python3 equivalence_test.py
Use it in your own code
import sys
sys.path.insert(0, "/path/to/fpm-cpp-port")
import fpm_cpp as fpm
import numpy as np
# Drop-in replacement for fpm_qsim
rho0 = np.array([[0.5, 0.5], [0.5, 0.5]], dtype=np.complex128) # |+><+|
# One dephasing step
rho1 = fpm.lindblad_step(rho0, gamma=0.1, dt=1.0, method="exact")
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# identical API to fpm_qsim.lindblad_step, just faster
# Full trajectory
traj = fpm.simulate(rho0, gamma=0.05, dt=1.0, n_steps=1000,
method="exact", use_omp=True)
# traj.shape == (1001, 2, 2)
# Falsifiability ceiling (raises FalsificationError for gamma > 32)
fpm.bounded_gamma(29.3) # OK (CERN muon)
# fpm.bounded_gamma(40.0) # raises FalsificationError
# Closed-universe conservation ledger
ledger = fpm.ConservationLedger(100.0)
daemon = ledger.add_daemon(80.0)
gamma = fpm.gamma_from_energy(daemon, gate_power=0.10, dt=1.0)
print(f"Endogenous gamma = {gamma}")
When to use OpenMP vs serial
The C++ port provides two variants, selected via the use_omp parameter:
| Qubit count | Use use_omp=True |
Use use_omp=False |
|---|---|---|
| 1–3 | ❌ (2 ms overhead dominates) | ✅ (fastest) |
| 4 | ⚠️ (about equal) | ⚠️ (about equal) |
| 5–7+ | ✅ (1.1–1.24× faster) | ❌ (slower) |
Default: use_omp=True (correct for production single-call workloads at 5+ qubits).
For many small simulations (parameter sweeps at 1–3 qubits): pass use_omp=False.
Bit-exact equivalence
The C++ port produces bit-identical output to Python FPM. Verified across:
- ✅ All 4 physical constants (GAMMA_MAX, FALSIFICATION_THRESHOLD, etc.)
- ✅
lindblad_stepat 1, 2, 3, 4, 5, 6 qubits — max diff = 0.000e+00 - ✅ 200-step trajectories at 1, 3, 5, 6 qubits — max diff = 0.000e+00
- ✅ Euler method (κ = 1 − γΔt) — max diff = 0.000e+00
- ✅
bounded_gammaaccepting γ=29.3 and raising for γ=40 — identical - ✅
gamma_from_energyon energy-rich and energy-poor daemons — bit-identical - ✅ Machine-precision regression across 6 γΔt regimes (incl. γΔt=10) — max err 5.1e-16 → 1.9e-34
Run python3 equivalence_test.py to re-verify on your machine.
Architecture
┌─────────────────────────────────────────────────────────────┐
│ Your Python code │
└───────────────────────────┬─────────────────────────────────┘
│ import fpm_cpp
▼
┌─────────────────────────────────────────────────────────────┐
│ fpm_cpp_bindings.cpp (160 LOC pybind11) │
│ • NumPy ↔ std::vector<Complex> converters │
│ • Exception bridge: C++ FalsificationError → Python │
│ • Index-based ledger access (no dangling pointers) │
└───────────────────────────┬─────────────────────────────────┘
│ calls into
▼
┌─────────────────────────────────────────────────────────────┐
│ fpm_core.hpp (380 LOC, header-only) │
│ • Physical constants (GAMMA_MAX = 31.87...) │
│ • kappa_from_gamma, kappa_exact, gamma_from_kappa │
│ • gamma_from_energy (endogenous noise) │
│ • bounded_gamma + FalsificationError │
│ • DaemonState, ConservationLedger │
│ • lindblad_step_serial (single-threaded hot path) │
│ • lindblad_step_omp (OpenMP-parallel hot path) │
│ • simulate_trajectory (in-place buffer, no per-step alloc)│
└─────────────────────────────────────────────────────────────┘
Build configuration
The recommended build flags (used by build.sh):
g++ -O3 -march=native -ffast-math -fopenmp \
-shared -std=c++17 -fPIC \
-I<python-include> -I<pybind11-include> \
fpm_cpp_bindings.cpp -o fpm_cpp.so -fopenmp
| Flag | Purpose |
|---|---|
-O3 |
Aggressive auto-vectorization |
-march=native |
Use host CPU's SIMD instructions (AVX2 on x86_64) |
-ffast-math |
Relax IEEE-754 for the inner loop (safe here — no summation, no ordering dependence) |
-fopenmp |
Enable OpenMP parallelization of the outer loop |
-std=c++17 |
Required for std::complex and structured bindings |
-fPIC |
Position-independent code (required for shared libraries) |
-shared |
Build as a shared library (.so) |
Reproducibility
- Random seed: 2026 (fixed across all benchmark scripts)
- Hardware: Single Linux x86_64 machine, 4 cores
- Python: 3.12.13 (CPython)
- C++ toolchain: g++ 14.2.0 (Debian)
- pybind11: 3.0.4
- Wall-time variance: ±10% across runs (single-machine, single-CPU)
- Tested package versions: fpm-qsim 0.1.8, qutip 5.3.0, qiskit 2.4.2, qiskit-aer 0.17.2, numpy 2.1.3, scipy 1.14.1
License
The C++ port is MIT-licensed (matching the upstream fpm-qsim license). The C++ port is a derivative work of fpm-qsim by Alx Spiker (https://github.com/alxspiker/fpm-qsim).
Citation
If you use the C++ port in published research, please cite:
@misc{fpm-qsim,
title = {fpm-qsim: Drop-in Lindblad dephasing simulator backed by the FPM affine map},
author = {Spiker, Alx},
year = {2026},
url = {https://github.com/alxspiker/fpm-qsim},
}
@misc{fpm-cpp-port,
title = {fpm-cpp: C++17 accelerated port of fpm-qsim core primitives},
author = {Z.ai},
year = {2026},
note = {Bit-exact verified drop-in replacement, 332× speedup at 1 qubit.},
}
Contact
For questions about the C++ port, the benchmark, or the report:
- C++ port: bundled in this archive
- Python FPM: https://github.com/alxspiker/fpm-qsim
- Report: see
FPM-CPP-vs-Competitors_Analysis-Report_2026-06-18.pdf
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fpm_qsim-0.1.9.tar.gz.
File metadata
- Download URL: fpm_qsim-0.1.9.tar.gz
- Upload date:
- Size: 1.6 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1a2f01a0f742a6a30af4b48173237e1c0a8d353b5063d462ccae01592551c2f8
|
|
| MD5 |
0ac77fb885ea9adeaf97acbfbc9ce851
|
|
| BLAKE2b-256 |
ebe4b712701f6d7eb43265203e80551e2813ed55ec171c36c49c58beb0f09fe4
|
File details
Details for the file fpm_qsim-0.1.9-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: fpm_qsim-0.1.9-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 129.6 kB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
281d6c80204b802ad3b61f52c00791f01563d4367a04bc0315ab6b7772fc141c
|
|
| MD5 |
e96250ac2a7ac60a19fd229a9559f0ca
|
|
| BLAKE2b-256 |
d34e3edb40813721642daedaea9a6103b42992abd1e8f7f21301234629c5de68
|