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$

2 Answers 2

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$ Commented Feb 10, 2021 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
    Commented Feb 10, 2021 at 10:06
  • $\begingroup$ Is there any benefit in using method B over method A ? $\endgroup$ Commented Feb 10, 2021 at 10:46
  • $\begingroup$ Yes, it uses one less qubit :) $\endgroup$
    – Cryoris
    Commented Feb 10, 2021 at 17:45
  • $\begingroup$ @Cryoris I See. Thank you! $\endgroup$ Commented Feb 15, 2021 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$
    – 26118in
    Commented Mar 7, 2021 at 8:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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