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$
5
  • $\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$ 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$ 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$ Commented Mar 7, 2021 at 8:23

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.