qiboteam / qibo

A framework for quantum computing
https://qibo.science
Apache License 2.0
280 stars 56 forks source link

Execute circuit in a loop #555

Closed juliabarbera closed 1 year ago

juliabarbera commented 2 years ago

I was wondering if there is any way, in Qibo language, to execute a quantum circuit many times (inside a loop) in order to see how the probability to find the result increases with number of times the oracle is applied.

I am aware that when we execute the circuit we are collapsing the wave function so once I have executed it I can't do it again, but I was hoping if there was any way to do so.

stavros11 commented 2 years ago

I am aware that when we execute the circuit we are collapsing the wave function so once I have executed it I can't do it again, but I was hoping if there was any way to do so.

This is not true, unless you explicitly specify collapse=True in a measurement gate (the default is collapse=False). So for example in the following trivial circuit:

from qibo import models, gates

c = Circuit(1)
c.add(gates.H(0))
c.add(gates.M(0))

result = c(nshots=1)

The measurement outcome will be either 0 or 1, so if you do result.frequencies() you will get {"0": 1} or {"1": 1} but if you do result.state() (or print(result)) you will get the |0> + |1> which is the final state before collapsing.

I was wondering if there is any way, in Qibo language, to execute a quantum circuit many times (inside a loop) in order to see how the probability to find the result increases with number of times the oracle is applied.

Would something like the following work for you?

oracle = # (models.Circuit) the circuit that implements your oracle.
nreps = # (int) maximum number of times the oracle is applied.

# execute the oracle `nreps` times
state = oracle()
probs = []
for i in range(nreps - 1):
    state = oracle(state)
    probs.append( # calculate the probability you need using the state )

state.probabilities() may be useful for the probability calculation. This will give you the probability after applying the oracle from 2 to nreps times.

igres26 commented 2 years ago

The proposed solution by @stavros11 would solve the issue but I would like to suggest some alternatives.

First way: Run the full circuit every iteration (as you would on a quantum machine)

probs = []
init_c = # initial circuit (H gates for example)
step_c = # Circuit that needs to be repeated

for i in range(1, nreps+1):
    c = Circuit()
    c += init_c
    for j in range(i)
        c += step_c
    state = c()
    probs.append( # probabilities)

Second way: Run one step at a time reusing the output state (only possible through simulation)

probs = []
init_c = # initial circuit (H gates for example)
step_c = # Circuit that needs to be repeated

state = init_c()
for i in range(nreps):
    state = step_c(state)
    probs.append( # probabilities)

Third way: Use callbacks within a circuit

https://qibo.readthedocs.io/en/stable/api-reference/qibo.html?highlight=callbacks#callbacks

Callbacks are special gates that one can apply during a circuit to compute certain properties of the quantum state along the execution of a circuit.

Right now, using the callbacks available, I suggest using the callbacks.Overlap and compute the overlap after each step with the target state.

target state = # the state that you are trying to see the evolution of
overlap = callbacks.Overlap(target_state)

init_c = # initial circuit (H gates for example)
step_c = # Circuit that needs to be repeated
c = Circuit()
c += init_c
for i in range(nreps):
    c += step_c
    c.add(gates.CallbackGate(overlap))

c()

print(overlap)

We will try to implement a callback that keeps track of the full quantum state along the circuit for situations like this.