# Efficient simulation of circuit with variable depth using Cirq

I have a program that needs to evaluate several Cirq circuits by using both simulators the Simulator() and DensityMatrixSimulator(). I want to evaluate a circuit that its composed by repeating blocks n=1,2,3,..., so the pseudocode for evaluation looks like this:

for n in some range:

n=1 -> Evaluate block and employ simulate_expectation_values() method of the simulators

n=2 -> Evaluate block+block and employ simulate_expectation_values() method of the simulators

n=3 -> Evaluate block+block+block and employ simulate_expectation_values() method of the simulators

etc...

This is highly inefficient as every time I evaluate for a fixed n, the circuit is repeated from the beginning until it reaches n-blocks depth, and I get the expectation values. In real hardware, of course the circuit depth is determined by the time when measurements take place. But at the simulation level, is there a way to perform the above operations in a more efficient way? This means to perform the simulation over all "n"s values at once, and get the expectation values corresponding to each of the n circuit depths without the need to explicitly evaluate the outer loop, and thus, avoiding starting from the beginning on each iteration.

cirq.Simulator supports this behavior via simulate_moment_steps and directly calling expectation_value_from_state_vector on each observable:

qubit = cirq.GridQubit(0, 0)
# Rotate the state about Y by an increment of pi/10 per moment
angle = np.pi/10
steps = 10
circuit = cirq.Circuit([cirq.ry(angle)(qubit) for i in range(10)])

# We will compute <Z> after each Ry(pi/10) gate:
observable = cirq.Z(qubit)

simulator = cirq.Simulator()
results = []
for step_result in simulator.simulate_moment_steps(circuit):
expect = observable.expectation_from_state_vector(step_result.state_vector(), {qubit: 0})
results.append(np.round(expect.real, 3)) # this is just to make the printout pretty

print(results)
>> [0.951, 0.809, 0.588, 0.309, -0.0, -0.309, -0.588, -0.809, -0.951, -1.0]


You can adapt this to iterate through a list of observables at each step, as well as use a density matrix simulator instead of just Simulator.

• Thanks a lot! I was actually using the generator as result of the simulate moment steps and compress it to measure only at those moments I am interested into. Mar 1 at 21:44
• Is there a way to calculate dynamical correlations in Cirq? By using the approach above, getting something like $\langle \sigma^z(i)(t_1)\sigma^z(j)(t_2)\rangle$, at two different moments $t_1,t_2$. Mar 2 at 15:23
• I'm not sure - might be worth asking another question on that. One possibility: Time evolve Z_i by constructing the circuit U(t)* Z_i U(t) and then call cirq.unitary to get the full unitary matrix for each t (which just happens to be unitary because Z_i is unitary). Then d o the same for Z_j and compute expectation values by hand in numpy... Mar 2 at 18:06