4
$\begingroup$

I want to turn a state

$$ |\Psi_1⟩ = \frac{1}{\sqrt{8}}(|000⟩+|001⟩+|010⟩+|011⟩+|100⟩+|101⟩+|110⟩+|111⟩) $$

into

$$ |\Psi_2⟩ = \frac{1}{\sqrt{8}}(|000⟩+|001⟩+|010⟩+|011⟩+|100⟩-|101⟩-|110⟩+|111⟩) $$

using a phase oracle before applying Grover's amplification.

One example from Qiskit's official page for Grover's Algorithm does this by manually building a circuit with Controlled-Z gates, but another Qiskit document simply uses a class Statevector.from_label to mark the target state $|11⟩$ without constructing a circuit, which I assume can only assign single state.

Having the desired states in a form of Python list, i.e. [101, 110], can I directly convert this into a phase oracle that does the intended job in Qiskit?

$\endgroup$
7
$\begingroup$

There are different ways to achieve that, my favorite is probably this one: The oracle you describe above is just a classical function ("True if my bitstring is 101 or 110") converted to a quantum phase flip. So essentially you only have to build a circuit that implements that classical logic plus some gates to do the phase flip.

Option A: Via classical logic

Step 1: Create the classical logic circuit in Qiskit:

from qiskit.circuit import classical_function, Int1

# define a classical function that can be turned into a circuit
@classical_function
def oracle(x1: Int1, x2: Int1, x3: Int1) -> Int1:
    return (x1 and not x2 and x3) or (x1 and x2 and not x3)

bitcircuit = oracle.synth()  # turn it into a circuit

Now you have something looking like this:

q_0: ──■────■──
       │    │
q_1: ──■────┼──
       │    │
q_2: ──┼────■──
     ┌─┴─┐┌─┴─┐
q_3: ┤ X ├┤ X ├
     └───┘└───┘

It flips the output bit (the one at the bottom) if the qubits are in state $|101\rangle$ or $|110\rangle$.

Step 2: To change this into a phaseflip oracle you can sandwich the bottom qubit in between X and H gates:

from qiskit.circuit import QuantumCircuit

phaseoracle = QuantumCircuit(4)
phaseoracle.x(3)
phaseoracle.h(3)
phaseoracle.compose(bitoracle, inplace=True)
phaseoracle.h(3)
phaseoracle.x(3)

to get this circuit, which implements your oracle:

q_0: ────────────■────■────────────
                 │    │
q_1: ────────────■────┼────────────
                 │    │
q_2: ────────────┼────■────────────
     ┌───┐┌───┐┌─┴─┐┌─┴─┐┌───┐┌───┐
q_3: ┤ X ├┤ H ├┤ X ├┤ X ├┤ H ├┤ X ├
     └───┘└───┘└───┘└───┘└───┘└───┘

So all together:

from qiskit.circuit import classical_function, Int1, QuantumCircuit

# define a classical function that can be turned into a circuit
@classical_function
def oracle(x1: Int1, x2: Int1, x3: Int1) -> Int1:
    return (x1 and not x2 and x3) or (x1 and x2 and not x3)

bitcircuit = oracle.synth()  # turn it into a circuit


phaseoracle = QuantumCircuit(4)
phaseoracle.x(3)
phaseoracle.h(3)
phaseoracle.compose(bitoracle, inplace=True)
phaseoracle.h(3)
phaseoracle.x(3)

Option B: Via looking hard

You could see that the oracle is implemented by two controlled Z gates:

from qiskit.circuit import QuantumCircuit

phaseoracle = QuantumCircuit(3)
phaseoracle.cz(0, 2)
phaseoracle.cz(0, 1)
$\endgroup$
6
  • $\begingroup$ Thank you. So I presume it is possible to use Option A to implement an oracle for Grover's max/min search as well? Something like "true if this bitstring's decimal value is above the given threshold". $\endgroup$ Feb 10 at 1:58
  • 1
    $\begingroup$ Not yet! Right now it just supports operations on binary values (not and or ^ (xor)). But support for integer valued operations (like >) can be added in future. $\endgroup$
    – Cryoris
    Feb 10 at 10:06
  • $\begingroup$ Is there any benefit in using method B over method A ? $\endgroup$ Feb 10 at 10:46
  • $\begingroup$ Yes, it uses one less qubit :) $\endgroup$
    – Cryoris
    Feb 10 at 17:45
  • $\begingroup$ @Cryoris I See. Thank you! $\endgroup$ Feb 15 at 2:05
2
$\begingroup$

Another option would be using CLASS Grover from qiskit.aqua.algorithms.

As you can see in this documentation, the parameter oracle of Grover can take one of the following forms, a QuantumCircuit, an Oracle, or a Statevector. Now as you've already found out by yourself, Statevector.from_label('..') accepts a single label.

For multiple states, you can simply prepare a list representing your chosen states and pass it to Statevector() in this way:


from qiskit import *
from qiskit.quantum_info import Statevector
from qiskit.aqua.algorithms import Grover


good_state = ['110','101']
oracle = Statevector([0,0,0,0,0,1,1,0])
grover = Grover(oracle=oracle, good_state=good_state)
my_gate=grover.grover_operator.to_gate() 
$\endgroup$
1
  • $\begingroup$ You might ask why $list=[0,0,0,0,0,1,1,0]$? Let's say you have 3 bits here, and you want $′101′$(=5) and $′110′$(=6). If you generate all possible bit-strings with 3 bits you'll have $′000′,′001′....′111′$ and you can easily see your target bit-strings are the 6th and 7th. Hence the 6th (5+1) and 7th (6+1) elements in the $list$ are 1. $\endgroup$
    – user9318
    Mar 7 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.