Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
4318f2c
Buffer postselection survivors in a preallocated array
rafaelha Oct 13, 2026
728a083
Sample noise with a parallel numba kernel
rafaelha Oct 13, 2026
bfdcd47
Write direct detectors and the discard test in one numba pass
rafaelha Oct 13, 2026
feb18e4
Fix the issues the reviews of the numba kernels found
rafaelha Oct 13, 2026
d06de41
Run trajectory sharing in a numba executor on the CPU
rafaelha Oct 13, 2026
8de99dd
Fix the issues the review of the numba shared executor found
rafaelha Oct 13, 2026
57e670d
Strengthen the shared executor's tests as their review suggested
rafaelha Oct 13, 2026
a062208
Speed up the noise model setup of large circuits
rafaelha Oct 13, 2026
acedb3c
Polish the noise setup code as its review suggested
rafaelha Oct 13, 2026
bd743c7
Sample whole batches on worker threads with trajectory sharing
rafaelha Oct 15, 2026
87eb174
Put the sharing path's outputs together on the host
rafaelha Oct 16, 2026
412d3d0
Thread the one-lane JAX path and trim the sharing executor's overhead
rafaelha Oct 16, 2026
a6769b0
Fix the lint error and the thread-order race in two postselection tests
rafaelha Oct 19, 2026
87926d9
Split default batches so that every thread has one
rafaelha Oct 19, 2026
832a621
Run each shared batch in one numba function
rafaelha Oct 19, 2026
960cff0
Sample strategy="active_statevector" without JAX
rafaelha Oct 19, 2026
eba929e
Keep calls too small for a batch per thread in one batch
rafaelha Oct 19, 2026
c27c129
Fix the issues the review of the JAX-free statevector path found
rafaelha Oct 19, 2026
e6caade
Parallelize only the explicit prange loops of numba kernels
rafaelha Oct 19, 2026
a4af91a
Sort the imports of the shared executor and its sampler tests
rafaelha Oct 19, 2026
7e13528
Address the stack review of the statevector sampler
rafaelha Oct 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The samplers now default to `strategy="active_statevector"`; pass
`strategy="cat5"` for the previous stabilizer-rank default.
`CompiledStateProbs` keeps `"cat5"`. (#203)
- `strategy="active_statevector"` no longer uses JAX: it samples on the CPU
with numba kernels, also when JAX has a GPU, and trajectory sharing is on
by default (`trajectory_sharing=None` means True for this strategy and
False for the others). Amplitudes are complex128. Postselected
detectors of a component prune its shots with sharing off as well, and also
when no direct detector is postselected. (#199)
- Without a `batch_size`, a statevector call is split into one batch per
numba thread whenever each batch gets at least 4096 shots, and smaller
calls run as one batch on the parallel kernels. An explicit `batch_size`
keeps samples independent of the thread count. (#199)
- Noise sampling runs in numba kernels, so the samples for a given seed
differ from earlier versions; `numba>=0.61` is now a dependency. (#199)
- Tsim now uses zxparam instead of pyzx-param. Circuits are built directly as quantum/classical ZX diagrams (no more composing with the adjoint), and reduction and stabilizer-rank decomposition run in zxparam.
- `Circuit.get_graph()` and `Circuit.get_sampling_graph()` return `zxparam.Graph`.
- In `Circuit.get_graph()` (and the `"zx"` diagram), every detector and observable has a classical output boundary, with ports after the qubit outputs, so the graph's tensor is the circuit's channel together with the detector and observable bits.
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ dependencies = [
"ipywidgets>=8.0.0",
"jax>=0.4.38",
"lxml>=5.0.0",
"numba>=0.61",
"numpy>=1.25.0",
"psutil>=5.9.0",
"stim>=1.0.0",
Expand Down
18 changes: 12 additions & 6 deletions src/tsim/circuit.py
Original file line number Diff line number Diff line change
Expand Up @@ -865,17 +865,20 @@ def compile_sampler(
*,
strategy: SamplingStrategy = "active_statevector",
seed: int | None = None,
trajectory_sharing: bool = False,
trajectory_sharing: bool | None = None,
) -> CompiledMeasurementSampler:
"""Compile circuit into a measurement sampler.

Args:
strategy: "active_statevector" (the default) to simulate each
non-direct component on a dense state vector over its active
qubits, or a stabilizer rank decomposition strategy ("cat5",
"bss", "cutting").
"bss", "cutting"). "active_statevector" samples on the CPU, up
to ``numba.get_num_threads()`` batches at once, each with its
own memory.
trajectory_sharing: With ``strategy="active_statevector"``, simulate shots
with equal histories on one lane (experimental).
with equal histories on one lane. Defaults to True for
``"active_statevector"`` and False otherwise.
seed: Random seed for the sampler. IMPORTANT: Currently, the sampler will
only produce deterministic samples for fixed batch size. If
deterministic samples are needed, the batch size should be set
Expand All @@ -896,7 +899,7 @@ def compile_detector_sampler(
*,
strategy: SamplingStrategy = "active_statevector",
seed: int | None = None,
trajectory_sharing: bool = False,
trajectory_sharing: bool | None = None,
) -> CompiledDetectorSampler:
"""Compile circuit into a detector sampler.

Expand All @@ -909,9 +912,12 @@ def compile_detector_sampler(
strategy: "active_statevector" (the default) to simulate each
non-direct component on a dense state vector over its active
qubits, or a stabilizer rank decomposition strategy ("cat5",
"bss", "cutting").
"bss", "cutting"). "active_statevector" samples on the CPU, up
to ``numba.get_num_threads()`` batches at once, each with its
own memory.
trajectory_sharing: With ``strategy="active_statevector"``, simulate shots
with equal histories on one lane (experimental).
with equal histories on one lane. Defaults to True for
``"active_statevector"`` and False otherwise.
seed: Random seed for the sampler. IMPORTANT: Currently, the sampler will
only produce deterministic samples for fixed batch size. If
deterministic samples are needed, the batch size should be set
Expand Down
8 changes: 4 additions & 4 deletions src/tsim/compile/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,10 @@ def compile_program(

return CompiledProgram(
components=tuple(compiled_components),
direct_f_indices=jnp.array([e[1] for e in direct_entries], dtype=jnp.int32),
direct_flips=jnp.array([e[2] for e in direct_entries], dtype=jnp.bool_),
output_order=jnp.asarray(output_order),
output_reindex=None if is_identity else jnp.asarray(reindex),
direct_f_indices=np.array([e[1] for e in direct_entries], dtype=np.int32),
direct_flips=np.array([e[2] for e in direct_entries], dtype=np.bool_),
output_order=output_order,
output_reindex=None if is_identity else reindex,
num_outputs=prepared.num_outputs,
num_detectors=prepared.num_detectors,
)
Expand Down
8 changes: 4 additions & 4 deletions src/tsim/core/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,9 @@ class CompiledProgram:
"""

components: tuple[CompiledComponent | StatevectorComponent, ...]
direct_f_indices: Array
direct_flips: Array
output_order: Array
output_reindex: Array | None
direct_f_indices: np.ndarray
direct_flips: np.ndarray
output_order: np.ndarray
output_reindex: np.ndarray | None
num_outputs: int
num_detectors: int
Loading
Loading