qsim
qsim copied to clipboard
Implement SimulatesIntermediateState Cirq interface
This interface allows access to intermediate states as the circuit is simulated moment-by-moment. See https://github.com/quantumlib/Cirq/blob/720ea341b0082dc0cbbfb0142c161f01d8edca3e/cirq/sim/simulator.py#L258.
How difficult would this be?
As I understand it, a core part of qsim behavior is fusing gates along the time-axis into independent chunks. Simulating step by step in a single execution would require modifying that core behavior, which is likely a significant amount of effort. The alternative is to run each timestep as a separate circuit in sequence, which I suspect would impact the overall performance of the simulator.
@sergeisakov, could you offer your thoughts on this?
In principle, this can be implemented. One doesn't need to modify qsim as it can run gates step by step without fusion. As @95-martin-orion pointed out, this will impact the overall performance of the simulator. The effort would be to implement the interface between Cirq and qsim.
Has there been any development on this? I suspect it will enable big savings for things like XEB where we have one big circuit that we want to know the wavefunction at various steps
on an XEB workload:
- Cirq w/intermediate is 5x faster than Cirq (simulate each truncated circuit separately)
- Speedup increases to 7x using
multiprocessing
on my laptop for each - QSim simulating each truncated circuit separately is 3x faster than cirq
- But QSim simulating each truncated circuit separately is 1.75x slower than Cirq w/intermediate
- ~~But when using
multiprocessing
for both the trend flips and qsim with each circuit separate is 4.5x faster than Cirq w/intermediate~~ sorry, had my numbers transposed - The difference expands to 4x when using multiprocessing for both
Since we only need the results after each "cycle" (and indeed, only for certain cycle settings) it could be worthwhile to
- improve the cirq interface to have some notion of "step by this many moments". At a minimum, this could prevent shuttling around some wavefunctions that I'm just going to discard anyways
- tell qsim what the minimum step I'm going to request is, so it can fuse except respecting those boundaries
I guess there's been no development on this. The core qsim library supports boundaries and can return the wavefunction at various steps. One sample C++ application (qsim_amplitudes.cc) saves intermediate results. The qsimcirq interface doesn't support that.
I think it would be possible to construct this with a combination of CircuitOperation
s and existing qsim-core methods. A rough outline for what this would look like:
- When creating the circuit, the user condenses each "step" into a set of parallel
CircuitOperation
s. SinceCircuitOperation
s exist within a single moment of the outer circuit, this allows us to keep the "step moment-by-moment" behavior of the interface while providing more flexibility over where those steps arrive. - This circuit gets passed to a new qsimcirq implementation of
simulate_moment_steps
. This method would need to: a. Decompose the circuit into single gates; b. Identify where the moment boundaries in the Cirq circuit occur in the qsim circuit; c. Pass the timesteps for these boundaries to qsim'sRun
method as thetimes_to_measure_at
; d. Define a "measurement" function that simply copies the entire state vector. (This "measurement" is not in the "destructive measure" sense, but rather refers to analyzing the state vector without modifying it.) - Users can then call a new
_base_iterator
method which iterates through the results generated in (2).
There are a few key flaws with this format, most notably that qsim would need to store all intermediate states since we have no way of doing "streaming output" from a qsim run. Separately, I don't think we support returning results from MeasurementGate
s when using the version of Run
linked above - though I haven't tried it myself.
Unfortunately, I don't have a lot of bandwidth to look at this right now. @mpharrigan, if you're interested in taking a stab at it I'd be happy to point you to the relevant parts of the code.
Two updates on this:
Update 1
#499 adds QSimSimulator.simulate_moment_expectation_values
, which outputs expectation values for selected observables after each moment or a user-specified set of moments. For experiments which only need EVs, this is significantly faster than simulating each truncated circuit.
Update 2
SimulatesIntermediateStates
remains at odds with qsim due to the reasons outlined above (namely gate fusion and state copying), but the existing simulator methods now properly support input states. This means you can define a simulation like:
circuits, ... = [cycle_1, cycle_2, ...]
input_state = 0
for cycle in circuits:
result = qsimulator.simulate(cycle, input_state=state)
# ...inspect new_state without modifying it...
input_state = result._final_simulator_state
which achieves the desired result and allows Python-side management of the resulting state copies.