Skip to content

Conversation

@sagnikpal2004
Copy link
Collaborator

@sagnikpal2004 sagnikpal2004 commented Jul 11, 2025

This PR introduces a new method backtrajectory, implementing an efficient stabilizer simulation algorithm inspired by Craig Gidney’s Stim paper (Quantum, 2021). Instead of evolving stabilizer states forward through the circuit, this method incrementally folds inverse operations into an identity tableau, resolving measurements in reverse to efficiently extract outcomes.

Currently, the simulator can perform the following operations:

  • <:AbstractCliffordOperator (anything supported by apply_right!)
  • <:AbstractMeasurement -> PauliMeasurement, sMX, sMY, sMZ
  • <:AbstractReset -> sRX, sRY, sRZ
  • (measure and reset) -> sMRX, sMRY, sMRZ

Not supported yet

  • Reset, BellMeasurement, NoisyCircuits

Checklist:

  • The code is properly formatted and commented.
  • Substantial new functionality is documented within the docs.
  • All new functionality is tested.
  • All of the automated tests on github pass.

Changelog:

  • added BacktrackRegister

Notes:

  • Added three new symbolic operations under <:AbstractReset -> sRX, sRY, sRZ
  • Possibility of using the Register interface for returning results
  • Need advice on naming of functions in backtrajectory.jl
  • Need advice for measurement convention
  • Possiblity of having a unified simulations interface for various simulators
  • Hashing issues - should they hash in the type also?

Dependency:

References:
Gidney, C. (2021). Stim: A fast stabilizer circuit simulator. Quantum, 5, 497. https://doi.org/10.22331/q-2021-07-06-497

@sagnikpal2004 sagnikpal2004 mentioned this pull request Jul 23, 2025
4 tasks
@codecov
Copy link

codecov bot commented Jul 27, 2025

Codecov Report

❌ Patch coverage is 49.18478% with 187 lines in your changes missing coverage. Please review.
✅ Project coverage is 73.81%. Comparing base (d86ff67) to head (f7fda1b).
⚠️ Report is 3 commits behind head on master.

Files with missing lines Patch % Lines
src/backtrajectory.jl 0.00% 148 Missing ⚠️
src/apply_right.jl 84.97% 32 Missing ⚠️
src/classical_register.jl 0.00% 3 Missing ⚠️
src/symbolic_cliffords.jl 0.00% 3 Missing ⚠️
src/affectedqubits.jl 0.00% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (d86ff67) and HEAD (f7fda1b). Click for more details.

HEAD has 2 uploads less than BASE
Flag BASE (d86ff67) HEAD (f7fda1b)
10 8
Additional details and impacted files
@@             Coverage Diff             @@
##           master     #551       +/-   ##
===========================================
- Coverage   84.46%   73.81%   -10.66%     
===========================================
  Files          95      103        +8     
  Lines        5956     6610      +654     
===========================================
- Hits         5031     4879      -152     
- Misses        925     1731      +806     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

resolved by transforming their observables to the initial state; deterministic measurements are directly computed from tableau signs,
while random measurements are simplified and simulated with randomized gate insertions.
Reference:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for references we have @cite and a bibtex file




function do_op!(T, op::sMX)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

to not explode the name space, let's either use a name like _backtraj_do_meas or put this in a module from which we just make backtrajectory available

Comment on lines 13 to 14
T = one(CliffordOperator, n)
result = Register(one(Stabilizer, n), falses(m))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these guys together seem to represent something, so a structure that has them together might be useful, e.g. BacktrajectoryRegister

Comment on lines 17 to 28
if op isa AbstractCliffordOperator
apply_right!(T, op)
elseif op isa AbstractMeasurement
res = do_op!(T, op)
op.bit!=0 && (bitview(result)[op.bit] = res)
elseif typeof(op) [sMRX, sMRY, sMRZ]
res = do_op!(T, op)
op.bit!=0 && (bitview(result)[op.bit] = res)
elseif op isa AbstractReset
do_op!(T, op)
else
error("Unsupported operation: $(typeof(op))")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if you are using isa you are probably doing something unidiomatic. This whole if/else tree should probably be multimethods

(and we will need to discuss issues with "union splitting" and "sum types" later on)

return pivot
end

@inline is_deterministic_x(T, q::Int) = all(getxbytes(T, q) .== 0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the T would lead folks to think this is a Type

SparseGate,
sMX, sMY, sMZ, PauliMeasurement, Reset, sMRX, sMRY, sMRZ,
sMX, sMY, sMZ, PauliMeasurement,
Reset, sMRX, sMRY, sMRZ, sRX, sRY, sRZ,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's not export the new resets until their API is fully implemented

Copy link
Member

@Krastanov Krastanov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some minor suggestions for changes

let's discuss again when the tests are done

using LinearAlgebra: inv, mul!, rank, Adjoint, dot, tr
import DataStructures
using DataStructures: DefaultDict, Accumulator
using DataStructures: DefaultDict, Accumulator, counter
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

double check that the recent 0.19 does not break this


nqubits(r::StimRegister) = nqubits(r.inv_circuit)
bitview(r::StimRegister) = r.bits
quantumstate(r::StimRegister) = apply_inv!(one(Stabilizer, nqubits(r)), r.inv_circuit)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe add a docstring that using this is not a view and it requires calling inv(::CliffordOperator) which is relatively slow?

you should add a header to make it more obvious that it is for this method. DocStringExtensions provides an automated way to do that

Comment on lines +230 to +231
@inline getxrow(s::Tableau, r::Int) = s.xzs[1:2:end, r]
@inline getzrow(s::Tableau, r::Int) = s.xzs[2:2:end, r] No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there elsewhere in the codebase that functions like this are defined, maybe in the linalg file or somewhere near where Tableau is defined -- just double check that there is no better place to put them

@@ -0,0 +1,4 @@
@testitem "test backtrajectory" begin

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's discuss again after we have the tests

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants