Implementing Grover's oracle with multiple solutions in Qiskit

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?

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)
• 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". – Alternative7 Feb 10 at 1:58
• 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. – Cryoris Feb 10 at 10:06
• Is there any benefit in using method B over method A ? – BrockenDuck Feb 10 at 10:46
• Yes, it uses one less qubit :) – Cryoris Feb 10 at 17:45
• @Cryoris I See. Thank you! – Alternative7 Feb 15 at 2:05

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()
• 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. – user9318 Mar 7 at 8:23