Skip to main content

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_step at 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_gamma accepting γ=29.3 and raising for γ=40 — identical
  • gamma_from_energy on 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:

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fpm_qsim-0.1.9.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fpm_qsim-0.1.9-cp314-cp314-win_amd64.whl (129.6 kB view details)

Uploaded CPython 3.14Windows x86-64

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

Hashes for fpm_qsim-0.1.9.tar.gz
Algorithm Hash digest
SHA256 1a2f01a0f742a6a30af4b48173237e1c0a8d353b5063d462ccae01592551c2f8
MD5 0ac77fb885ea9adeaf97acbfbc9ce851
BLAKE2b-256 ebe4b712701f6d7eb43265203e80551e2813ed55ec171c36c49c58beb0f09fe4

See more details on using hashes here.

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

Hashes for fpm_qsim-0.1.9-cp314-cp314-win_amd64.whl
Algorithm Hash digest
SHA256 281d6c80204b802ad3b61f52c00791f01563d4367a04bc0315ab6b7772fc141c
MD5 e96250ac2a7ac60a19fd229a9559f0ca
BLAKE2b-256 d34e3edb40813721642daedaea9a6103b42992abd1e8f7f21301234629c5de68

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page