Skip to content

uwarring82/iontrap-dynamics

Repository files navigation

iontrap-dynamics

Open-system quantum dynamics of trapped-ion spin-motion systems.

New here? See docs/overview.md for an accessible introduction to what we do, how we work, and what we don't claim — written with three reading levels for students, collaborators, and curious visitors.

iontrap-dynamics is a domain-specific Python library for modelling trapped-ion spin-motion physics with explicit, typed configuration objects for species, drives, modes, and measurement conventions. The project is built around a hard separation between physics, apparatus, and observation layers. QuTiP is the reference backend; a JAX / Dynamiqs backend is available on the same public solver surface via backend="jax".

Status

v0.6.0 released 2026-06-04 — adds the reduced light–matter models surface (Jaynes–Cummings / anti-Jaynes–Cummings / quantum-Rabi builders plus a model_deviation comparison harness) and completes the two-mode / motional surface, on top of the v0.5.0 estimation / quantum-Darwinism and two-mode / motional service surfaces and the device-neutral JAX spectrum backend. Phase 0 foundations, Phase 1 (dynamics core + measurement layer + systematics layer + registered entanglement observables), Phase 2 (performance track + JAX / Dynamiqs backend end-to-end), the Clos 2016 integration (full-Lamb–Dicke carrier dynamics, exact-diagonalization spectrum tools, N = 1 / 2 / 3 reproduction inside declared tolerances), and the v0.5.0 / v0.6.0 service surfaces are all shipped on main. CONVENTIONS.md carries §1–25: §19–24 (Fisher information / quantum Darwinism, two-mode squeezing / SU(1,1), motional CPTP channels) sealed at the v0.3 Convention Freeze (CONVENTION_VERSION 0.2 → 0.3), and §25 (reduced light–matter models) sealed by WP-03 (CONVENTION_VERSION 0.3 → 0.4). Additive only: existing v0.2.0 callers see no behaviour change — every new backend= kwarg defaults to "qutip", every channels= argument defaults to none, every JAX entry is behind an opt-in backend="jax".

The v0.6.0 cut bundles two things. The two-mode / motional service surface is complete: interferometric fringe observables (MCD), Lamb–Dicke regime helpers — Debye–Waller factor, a deep/intermediate/beyond classifier, and the all-orders sideband-Rabi forms (MCE), a probe-QFI benchmark that consumes the estimation primitive (MCF), and a motional ModeFrequencyDrift systematic (MCG). And the reduced light–matter models surface (WP-03) is new: the reduced_models JC / AJC / QRM builders, a model_deviation comparison helper, an analytic oracle suite (the four hierarchy cases), Tutorial 18 with a deterministic comparison benchmark, and the vendored model-hierarchy companion note (docs/models-hierarchy.md), anchored by CONVENTIONS §25 — all additive.

End-to-end stacks work dynamics-through-statistics, on either backend:

  • DriveConfigcarrier_hamiltoniansolve(...) → expected π-pulse flip (Phase 1 core; QuTiP default, or backend="jax" for the Dynamiqs path — cross-backend agreement under 1e-3 across all builder families).
  • TrajectoryResultSpinReadout.runMeasurementResult → Wilson CI band on finite-shot estimator (Phase 1 measurement).
  • Base DriveConfigperturb_carrier_rabi → ensemble of solves → inhomogeneous-dephasing signature (Phase 1 systematics).
  • detuned_carrier_hamiltonian(..., backend="jax")solve(..., backend="jax")TrajectoryResult(backend_name="jax-dynamiqs") with StorageMode.LAZY per-index loader (Phase 2 JAX backend end-to-end).

Phase 0 + Phase 1 + Phase 2 artefacts delivered:

  • Public conventions frozen in CONVENTIONS.md v0.3 (§1–24 complete; §19–24 added at the v0.3 Convention Freeze, post-v0.4.0).
  • Three-layer regression harness populated: migration (5 / 5 scenarios with legacy qc.py-generated references, bit-identical across three runs; 3 / 5 active comparisons, 2 / 5 skipped with probe-informed blockers), analytic (6 closed-form formulas), invariant (9 checks).
  • Cache-integrity contract + tests.
  • CI with ruff, ruff-format, mypy strict, pytest, pa11y WCAG 2 Level A (hard gate, AA advisory per v0.3.2 amendment).

Today the importable code surface covers:

Foundation (Phase 0)

  • iontrap_dynamics.exceptions — canonical exception hierarchy (IonTrapError, ConventionError, BackendError, IntegrityError, ConvergenceError)
  • iontrap_dynamics.results — frozen TrajectoryResult schema with storage-mode consistency enforcement
  • iontrap_dynamics.cache — hash-verified .npz + JSON persistence
  • iontrap_dynamics.conventionsCONVENTION_VERSION marker
  • iontrap_dynamics.invariants — density-matrix / state-vector validators
  • iontrap_dynamics.analytic — closed-form reference formulas (carrier Rabi, sideband rates, Lamb–Dicke parameter, coherent-state occupation), plus the Lamb–Dicke regime helpers (debye_waller_factor, lamb_dicke_regimeLambDickeRegime, all-orders {red,blue}_sideband_rabi_frequency_full_ld)

Configuration layer (Phase 1)

  • iontrap_dynamics.operators — single-ion Pauli set in the atomic-physics convention (sigma_z_ion, sigma_plus_ion, ...; see CONVENTIONS.md §3)
  • iontrap_dynamics.speciesIonSpecies, Transition, TransitionType and factories for ²⁵Mg⁺, ⁴⁰Ca⁺, ⁴³Ca⁺
  • iontrap_dynamics.drivesDriveConfig (wavevector, Rabi, detuning, ...)
  • iontrap_dynamics.modesModeConfig with CONVENTIONS.md §11 normalisation enforced at construction
  • iontrap_dynamics.systemIonSystem composition with cross-validation
  • iontrap_dynamics.hilbertHilbertSpace implementing the §2 tensor ordering, operator embedding helpers, motional primitives (a, a†, n̂)
  • iontrap_dynamics.statesground_state ket, compose_density, coherent_mode / squeezed_vacuum_mode / squeezed_coherent_mode factories (CONVENTIONS.md §6, §7), the two-mode two_mode_squeezed_vacuum factory (§23), and the ghz_state / cat_mode entangled-probe factories
  • iontrap_dynamics.observables — named Observable records and expectations_over_time(...); spin x/y/z, multi-ion parity (σ_z product), mode number, plus the interferometric fringe analysis fringe_visibility / fit_fringeFringeFit
  • iontrap_dynamics.entanglement — nonlinear trajectory evaluators for concurrence, entanglement_of_formation, and log_negativity (with partition="spins" | "modes" for bipartite splits). Consume TrajectoryResult.states under storage_mode=EAGER
  • iontrap_dynamics.systematics — dynamics-side noise models (§18 — frozen at v0.2). Jitter primitives RabiJitter (multiplicative on Ω), DetuningJitter (additive on δ), PhaseJitter (additive on φ) with perturb_* ensemble helpers. Parallel drift primitives RabiDrift, DetuningDrift, PhaseDrift (deterministic single-value offsets) with apply_*_drift composition helpers — plus the motional ModeFrequencyDrift (ω_m → ω_m·(1+δ) on a ModeConfig) and the correlated CommonModePhase channel. SPAM primitives SpinPreparationError, ThermalPreparationError produce per-subsystem density matrices via imperfect_spin_ground / imperfect_motional_ground that compose into a full initial state via states.compose_density.
  • iontrap_dynamics.information — the estimation surface (§19–20): SLD quantum Fisher information, classical Fisher information, Cramér–Rao bound and a linear-Gaussian oracle (quantum_fisher_information_trajectory, classical_fisher_information, cramer_rao_bound), plus quantum-Darwinism redundancy and Schumacher–Nielsen recoverability.

Dynamics (Phase 1, full builder family)

The public Hamiltonian surface is symmetric across four families:

exact (time-indep. Qobj) detuned (list format)
carrier carrier_hamiltonian detuned_carrier_hamiltonian
red sideband red_sideband_hamiltonian detuned_red_sideband_hamiltonian
blue sideband blue_sideband_hamiltonian detuned_blue_sideband_hamiltonian
MS gate ms_gate_hamiltonian detuned_ms_gate_hamiltonian

Plus modulated_carrier_hamiltonian (time-dependent envelope primitive), two_ion_{red,blue}_sideband_hamiltonian (single-tone shared-mode), the two-mode two_mode_squeezing_hamiltonian / beamsplitter_hamiltonian (SU(1,1) / SU(2), §23), and a full_lamb_dicke: bool flag on the sideband builders (Wineland–Itano all-orders operator via matrix exponentiation). Solver entry point: iontrap_dynamics.sequences.solve(...) — accepts both Qobj and QuTiP list-format Hamiltonians, enforces the §13 Fock-saturation ladder on every call, and accepts typed motional CPTP channels via solve(channels=…) (iontrap_dynamics.channels: AmplitudeDamping, Heating, Dephasing, with optional time windows; §24).

Measurement (Phase 1, v0.2 — frozen)

  • iontrap_dynamics.results.MeasurementResultResult sibling carrying the ideal / sampled dual-view mandated by WORKPLAN §5; enforces shots ≥ 1 and storage_mode = OMITTED at construction.
  • iontrap_dynamics.measurement.BernoulliChannel — per-shot Bernoulli sampler; returns (shots, n_inputs) bits with leading shot axis (CONVENTIONS.md §17.1).
  • iontrap_dynamics.measurement.BinomialChannel — aggregated sampler; returns (n_inputs,) int64 counts (CONVENTIONS.md §17.7, shape classes). Distributionally equivalent to summing Bernoulli bits, not bit-identical under matched seed.
  • iontrap_dynamics.measurement.PoissonChannel — per-shot photon- counting channel; consumes non-negative rates (not probabilities) and returns (shots, n_inputs) int64 counts via rng.poisson(λ).
  • iontrap_dynamics.measurement.DetectorConfig — detector-response parameters (efficiency η, dark-count rate γ_d, threshold ) with apply(rate), discriminate(counts), and classification_fidelity(lambda_bright, lambda_dark) methods. Composes explicitly with PoissonChannel via Poisson thinning plus additive background (exact; §17.8).
  • iontrap_dynamics.measurement.sample_outcome(channel, inputs=..., shots, seed, upstream) — orchestrator that seeds the RNG, dispatches uniformly on channel type, stores inputs under ideal_outcome[channel.ideal_label] ("probability" or "rate"), and inherits upstream-trajectory metadata when supplied.
  • iontrap_dynamics.measurement.SpinReadout — first protocol-layer composer. .run(trajectory, shots, seed) executes the projective- shot readout model (§17.9) and returns a MeasurementResult with per-shot counts / bits / bright-fraction plus the ideal p_↑ and TP · p_↑ + (1 − TN) · (1 − p_↑) envelope.
  • iontrap_dynamics.measurement.ParityScan — two-ion joint readout protocol (§17.10). Reconstructs P(s_0, s_1) from ⟨σ_z^i⟩, ⟨σ_z^j⟩, and ⟨σ_z^i σ_z^j⟩, draws joint categorical samples so entangled-state correlations survive, and returns parity estimate
    • envelope shrunk by (TP + TN − 1)². Requires the new iontrap_dynamics.observables.parity factory.
  • iontrap_dynamics.measurement.SidebandInference — motional-state thermometry protocol (§17.11). Takes paired RSB / BSB trajectories and reports fidelity-corrected n̄ = r / (1 − r) via the short-time Leibfried–Wineland ratio; independent RNG streams per sideband; NaN propagates on singular ratios.
  • iontrap_dynamics.measurement.wilson_interval, clopper_pearson_interval, and binomial_summary / the BinomialSummary dataclass (§17.12) — vectorised confidence intervals on binomial shot counts. Wilson is the recommended default; Clopper–Pearson is exact and conservative.

The measurement track is complete: CONVENTIONS.md §17.1–17.12 close the read-through, with §17 frozen at the v0.2.0 Convention Freeze gate.

Phase 2 — performance and JAX backend (v0.3)

  • sequences.solve(...) gains a backend: str = "qutip" keyword- only parameter; backend="jax" dispatches to the Dynamiqs integrator via iontrap_dynamics.backends.jax. Solver / backend compatibility is validated (explicit solver="sesolve" or "mesolve" with backend="jax" raises ConventionError; only solver="auto" is accepted on the JAX path).
  • iontrap_dynamics.backends.jax.solve_via_jax(...) — opt-in JAX-backend entry. Dispatches to dynamiqs.sesolve for ket inputs, dynamiqs.mesolve for density matrices. Honours all three StorageMode values (OMITTED / EAGER / LAZY — the LAZY loader closes over the Dynamiqs-returned JAX array, materialises one Qobj per index on demand, bounds-checks against JAX's silent-clamp behaviour). Forces JAX x64 at solve entry for complex128 arithmetic (CONVENTIONS.md §1 unit commitment).
  • Results on the JAX backend are tagged with ResultMetadata.backend_name="jax-dynamiqs" and backend_version=f"dynamiqs-{ver}+jax-{ver}". The backend_name string is a schema-commitment tag: a future integrator swap requires a new string (not a suffix), so users' cache manifests stay consistent. convention_version is read from hilbert.system.convention_version, honouring archival pins exactly like the QuTiP path.
  • Every time-dependent Hamiltonian builder gains a backend= kwarg on the same pattern (carrier, RSB, BSB, MS gate, modulated carrier). The four structured detuning builders share backends.jax._coefficients.timeqarray_cos_sin for dq.modulated(cos, H_static) + dq.modulated(sin, H_quadrature) assembly; modulated_carrier_hamiltonian takes a user-supplied envelope_jax keyword (JAX-traceable mirror of envelope) for arbitrary pulse shapes. Missing envelope_jax on backend="jax" raises ConventionError — no silent translation.
  • Cross-backend numeric equivalence validated at library-default integrator tolerances across all five time-dependent builders: worst-case 1.35e-5 absolute expectation delta, well under the 1e-3 design-target tolerance. Honest performance null result at dim ≥ 100 / 5000 steps (QuTiP 5 is ~2.8× faster than Dynamiqs + JAX on CPU at current library scales; see docs/benchmarks.md). The JAX backend's value is positioning, cross-backend consistency checking, and forward-looking capability (autograd scaffolding ready via envelope_jax coefficients; GPU / TPU dispatch if the user installs a CUDA / Metal JAX build).

Demo tools (tools/run_*.py with canonical manifest.json + arrays.npz + demo_report.json artefacts under benchmarks/data/): run_benchmark_sideband, run_demo_carrier, run_demo_gaussian_pulse, run_demo_ms_gate, run_demo_bernoulli_readout, run_demo_binomial_readout, run_demo_poisson_readout, run_demo_detected_readout, run_demo_spin_readout, run_demo_parity_scan, run_demo_sideband_inference, run_demo_wilson_ci, run_demo_bell_entanglement, run_demo_rabi_jitter, run_demo_detuning_jitter, run_demo_rabi_drift_scan, run_demo_spam_prep.

Phase 2 benchmark tools (tools/run_benchmark_*.py with report.json + plot.png artefacts under benchmarks/data/): run_benchmark_sesolve_speedup (Dispatch X — sesolve / mesolve parity on QuTiP 5), run_benchmark_ensemble_parallel (Dispatch Y — serial / loky / threading crossover), run_benchmark_sparse_vs_dense (Dispatch OO — CSR / dense operator-dtype baseline; closes the Phase 2 sparse-matrix-tuning open item), run_benchmark_jax_timedep (Dispatch YY / β.4.5 — cross-backend QuTiP-vs-JAX at dim ≥ 100 / 5000 steps across all five time-dependent builders; needs the [jax] extras).

Test suite at v0.6.0 (base CI, no extras):

  • 1319 passed, 3 skipped. Two skipped tests are migration-tier builder-comparison slots (scenarios 3 and 4) with probe-informed blockers (see CHANGELOG.md); one skipped module is the Dynamiqs-gated integration test file (tests/unit/test_backends_jax_dynamiqs.py, gated on pytest.importorskip("dynamiqs")).
  • With the [jax] extras the suite additionally runs the Dynamiqs-gated integration tests (cross-backend numeric equivalence, result metadata, storage modes, Fock-saturation check, time-dependent builders, user-envelope dual-callable contract, and solve_ensemble on JAX); run under the extra to confirm the current total.

Docs site scaffold:

  • mkdocs.yml configures the public-facing documentation build
  • docs/index.md — welcome page
  • docs/getting-started.md — install + first run
  • docs/framework.md — high-level design rules
  • docs/conventions.md — rendered live from root CONVENTIONS.md (single source of truth via pymdownx.snippets)
  • docs/phase-1-architecture.md — concrete public-API reference (module map, per-module surface, extension points, non-goals; now also hosts the result-family vs backend-variety decision record from D5 / Dispatch NN)
  • docs/phase-2-jax-backend-design.md — deliberation note for the Phase 2 JAX / Dynamiqs backend (design axes A-D, chosen Option β, ten open questions + their recorded answers)
  • docs/phase-2-jax-time-dep-design.md — β.4 staging note for the time-dependent Hamiltonian track (Option X parallel JAX-native builders; 5-sub-dispatch plan; scope inventory)
  • docs/benchmarks.md — honest performance baselines for every Phase 2 dispatch including the β.4.5 cross-backend benchmark at dim ≥ 100 / 5000 steps
  • docs/boundary-decision-tree.md — contributor scope rules (closes D8)
  • docs/tutorials/ — task-oriented walkthroughs. Twelve tutorials shipped (Tutorials 1–12 cover the full public-surface pipeline end-to-end, from carrier Rabi + Wilson CIs through two-ion Bell-state entanglement); see docs/tutorials/index.md
  • docs/stylesheets/tokens.css — vendored from threehouse-plus-ec/cd-rules

The authoritative project documents are:

  • WORKPLAN_v0.3.md for scope, architecture, milestones, and governance
  • CONVENTIONS.md for physical, numerical, and notational rules
  • LICENCE for the repository split-licence declaration

Scope

Planned capabilities include:

  • Unitary and dissipative dynamics for coupled spin-motion systems
  • Standard ion-trap Hamiltonians: carrier, sideband, Mølmer-Sørensen, parametric modulation, and stroboscopic drives
  • Standard state preparations and observables for spins and motional modes
  • Backend-agnostic architecture: QuTiP reference backend + JAX / Dynamiqs backend (opt-in via backend="jax" — see docs/benchmarks.md for when each is the right choice)

Explicitly out of scope:

  • Trap geometry simulation
  • Molecular dynamics of ion crystals
  • Pulse-sequence compilers and hardware-control stacks
  • Electromagnetic field modelling

Development

Python 3.11+ is required.

Editable install:

python -m pip install -e ".[dev]"

Optional groups:

  • .[docs] for documentation tooling
  • .[plot] for plotting helpers used by examples and tutorials
  • .[jax] for the JAX / Dynamiqs backend (Phase 2 β.1–β.4 on main: opt in via backend="jax" on solve and on the time-dependent Hamiltonian builders)

Example:

python -m pip install -e ".[dev,docs]"

Repository Layout

  • src/iontrap_dynamics/ — Python package (core + measurement/ subpackage)
  • tests/unit/, conventions/, regression/{analytic,invariants,migration}/, benchmarks/
  • tools/ — maintenance scripts (asset fetch / checksum, SPDX check, pa11y config, migration-reference generator) and demo runners
  • benchmarks/data/ — canonical manifest + arrays + report artefacts per demo / benchmark
  • docs/ — mkdocs-material source for the documentation site
  • assets/ — design assets consumed from threehouse-plus-ec/cd-rules
  • legacy/ — pinned legacy qc.py used by migration-tier regression
  • WORKPLAN_v0.3.md — project workplan (v0.3.7 amendments applied: §4.0 repo-hosting, §5.0 release-mapping, §5.1 v0.2 release, §5.2 post-v0.2 on-main, §5.3 β.4 as v0.3.x follow-up, §5.4 estimation/Darwinism and §5.5 two-mode/motional open-system surfaces)
  • CONVENTIONS.md — binding conventions document (v0.3 frozen: §17 measurement and §18 systematics closed at the v0.2.0 release; §19–24 estimation/Darwinism + two-mode/motional closed at the v0.3 Convention Freeze, post-v0.4.0)
  • CHANGELOG.md — Keep-a-Changelog log of dispatches on main

Licence

The distributable Python package is MIT-licensed. The repository as a whole uses a split-licence architecture declared in LICENCE; design documents and tutorial material do not all share the same terms.

Endorsement Marker

Local candidate framework under active stewardship. No external endorsement is implied.

About

No description, website, or topics provided.

Resources

License

Unknown, Unknown licenses found

Licenses found

Unknown
LICENCE
Unknown
LICENCE-MIT

Stars

1 star

Watchers

0 watching

Forks

Packages

 
 
 

Contributors