Quantum Computing#

  • Author:

  • Date:

  • Time Spent on this Assignment:

!pip install qiskit[visualization];
!pip install qutip
!pip install qiskit_aer;
Hide code cell output
Collecting qiskit[visualization]
  Downloading qiskit-1.3.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (12 kB)
Collecting rustworkx>=0.15.0 (from qiskit[visualization])
  Downloading rustworkx-0.15.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (9.9 kB)
Requirement already satisfied: numpy<3,>=1.17 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (2.0.2)
Requirement already satisfied: scipy>=1.5 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (1.13.1)
Collecting sympy>=1.3 (from qiskit[visualization])
  Downloading sympy-1.13.3-py3-none-any.whl.metadata (12 kB)
Collecting dill>=0.3 (from qiskit[visualization])
  Downloading dill-0.3.9-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: python-dateutil>=2.8.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (2.9.0.post0)
Collecting stevedore>=3.0.0 (from qiskit[visualization])
  Downloading stevedore-5.4.0-py3-none-any.whl.metadata (2.3 kB)
Requirement already satisfied: typing-extensions in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (4.12.2)
Collecting symengine<0.14,>=0.11 (from qiskit[visualization])
  Downloading symengine-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.2 kB)
Requirement already satisfied: matplotlib>=3.3 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (3.9.4)
Collecting pydot (from qiskit[visualization])
  Downloading pydot-3.0.4-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: Pillow>=4.2.1 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit[visualization]) (11.1.0)
Collecting pylatexenc>=1.4 (from qiskit[visualization])
  Downloading pylatexenc-2.10.tar.gz (162 kB)
  Preparing metadata (setup.py) ... ?25l-
 done
?25hCollecting seaborn>=0.9.0 (from qiskit[visualization])
  Downloading seaborn-0.13.2-py3-none-any.whl.metadata (5.4 kB)
Requirement already satisfied: contourpy>=1.0.1 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (1.3.0)
Requirement already satisfied: cycler>=0.10 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (4.55.4)
Requirement already satisfied: kiwisolver>=1.3.1 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (1.4.7)
Requirement already satisfied: packaging>=20.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (24.2)
Requirement already satisfied: pyparsing>=2.3.1 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (3.2.1)
Requirement already satisfied: importlib-resources>=3.2.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from matplotlib>=3.3->qiskit[visualization]) (6.5.2)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from python-dateutil>=2.8.0->qiskit[visualization]) (1.17.0)
Requirement already satisfied: pandas>=1.2 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from seaborn>=0.9.0->qiskit[visualization]) (2.2.3)
Collecting pbr>=2.0.0 (from stevedore>=3.0.0->qiskit[visualization])
  Downloading pbr-6.1.0-py2.py3-none-any.whl.metadata (3.4 kB)
Collecting mpmath<1.4,>=1.1.0 (from sympy>=1.3->qiskit[visualization])
  Downloading mpmath-1.3.0-py3-none-any.whl.metadata (8.6 kB)
Requirement already satisfied: zipp>=3.1.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from importlib-resources>=3.2.0->matplotlib>=3.3->qiskit[visualization]) (3.21.0)
Requirement already satisfied: pytz>=2020.1 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from pandas>=1.2->seaborn>=0.9.0->qiskit[visualization]) (2024.2)
Requirement already satisfied: tzdata>=2022.7 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from pandas>=1.2->seaborn>=0.9.0->qiskit[visualization]) (2024.2)
Downloading dill-0.3.9-py3-none-any.whl (119 kB)
Downloading rustworkx-0.15.1-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.0 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/2.0 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.0/2.0 MB 90.5 MB/s eta 0:00:00
?25hDownloading seaborn-0.13.2-py3-none-any.whl (294 kB)
Downloading stevedore-5.4.0-py3-none-any.whl (49 kB)
Downloading symengine-0.13.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (49.7 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/49.7 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━ 39.8/49.7 MB 202.9 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.7/49.7 MB 139.2 MB/s eta 0:00:00
?25hDownloading sympy-1.13.3-py3-none-any.whl (6.2 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/6.2 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.2/6.2 MB 176.3 MB/s eta 0:00:00
?25hDownloading pydot-3.0.4-py3-none-any.whl (35 kB)
Downloading qiskit-1.3.2-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.8 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/6.8 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.8/6.8 MB 166.2 MB/s eta 0:00:00
?25hDownloading mpmath-1.3.0-py3-none-any.whl (536 kB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/536.2 kB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 536.2/536.2 kB 61.6 MB/s eta 0:00:00
?25hDownloading pbr-6.1.0-py2.py3-none-any.whl (108 kB)
Building wheels for collected packages: pylatexenc
  Building wheel for pylatexenc (setup.py) ... ?25l-
 done
?25h  Created wheel for pylatexenc: filename=pylatexenc-2.10-py3-none-any.whl size=136834 sha256=5777de9bc7149001a89e7183e03cb0f6960b6418f4ec7417a6f049fac5bcc1c0
  Stored in directory: /home/runner/.cache/pip/wheels/a3/68/66/2f15abd0673d83c02f354115feedeb89c3daed2ac319b11090
Successfully built pylatexenc
Installing collected packages: pylatexenc, mpmath, sympy, symengine, rustworkx, pydot, pbr, dill, stevedore, seaborn, qiskit
Successfully installed dill-0.3.9 mpmath-1.3.0 pbr-6.1.0 pydot-3.0.4 pylatexenc-2.10 qiskit-1.3.2 rustworkx-0.15.1 seaborn-0.13.2 stevedore-5.4.0 symengine-0.13.0 sympy-1.13.3
Collecting qutip
  Downloading qutip-5.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (9.2 kB)
Requirement already satisfied: numpy>=1.22 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qutip) (2.0.2)
Requirement already satisfied: scipy>=1.9 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qutip) (1.13.1)
Requirement already satisfied: packaging in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qutip) (24.2)
Downloading qutip-5.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (24.5 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/24.5 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸ 24.4/24.5 MB 160.3 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 24.5/24.5 MB 122.2 MB/s eta 0:00:00
?25h
Installing collected packages: qutip
Successfully installed qutip-5.0.4
Collecting qiskit_aer
  Downloading qiskit_aer-0.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (8.2 kB)
Requirement already satisfied: qiskit>=1.1.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit_aer) (1.3.2)
Requirement already satisfied: numpy>=1.16.3 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit_aer) (2.0.2)
Requirement already satisfied: scipy>=1.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit_aer) (1.13.1)
Requirement already satisfied: psutil>=5 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit_aer) (6.1.1)
Requirement already satisfied: rustworkx>=0.15.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (0.15.1)
Requirement already satisfied: sympy>=1.3 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (1.13.3)
Requirement already satisfied: dill>=0.3 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (0.3.9)
Requirement already satisfied: python-dateutil>=2.8.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (2.9.0.post0)
Requirement already satisfied: stevedore>=3.0.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (5.4.0)
Requirement already satisfied: typing-extensions in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (4.12.2)
Requirement already satisfied: symengine<0.14,>=0.11 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from qiskit>=1.1.0->qiskit_aer) (0.13.0)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from python-dateutil>=2.8.0->qiskit>=1.1.0->qiskit_aer) (1.17.0)
Requirement already satisfied: pbr>=2.0.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from stevedore>=3.0.0->qiskit>=1.1.0->qiskit_aer) (6.1.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /opt/hostedtoolcache/Python/3.9.21/x64/lib/python3.9/site-packages (from sympy>=1.3->qiskit>=1.1.0->qiskit_aer) (1.3.0)
Downloading qiskit_aer-0.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.4 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/12.4 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.4/12.4 MB 123.7 MB/s eta 0:00:00
?25h
Installing collected packages: qiskit_aer
Successfully installed qiskit_aer-0.16.0
import numpy as np
import pylab as plt
import qiskit
import qutip
from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
def RunMe(circuit,a=None):
  numQubits=circuit.num_qubits
  if a!=None:
    numQubits=max(numQubits,a.num_qubits)
    initCircuit=QuantumCircuit(a.num_qubits,a.num_qubits)
    initCircuit.initialize(a)
    circuit=AddCircuits([initCircuit,circuit])
  circuit.save_statevector(label='myStateVector')
  compiled_circuit = transpile(circuit, simulator)
  resultA = simulator.run(compiled_circuit).result()
  forward=list(range(0,numQubits))
  reverse=forward[::-1]
  circuit.measure(forward,reverse)
  compiled_circuit = transpile(circuit, simulator)
  resultB = simulator.run(compiled_circuit).result()
  return resultA.data()['myStateVector'],resultB.data()['counts']


def MakeState(v):
  numWires=int(round(np.log2(len(np.array(v)))))
  qc1=QuantumCircuit(numWires,numWires)
  qc1.initialize(v)
  a,_=RunMe(qc1)
  return a

def PrintDirac(out_state_a):
  out_state=np.asarray(out_state_a)
  l=len(out_state)
  num_qubits=int(round(np.log(len(out_state))/np.log(2)))
  for i in range(0,l):
    if not np.isclose(out_state[i],0):
      print(str(out_state[i])+'|'+bin(i)[2:].zfill(num_qubits)[::-1]+'>',end=' + ')
  print()

def PlotBloch(v,bb):
  vv=np.asarray(v)
  a=vv[0]*np.conj(vv[0])
  b=vv[1]*np.conj(vv[0])
  x = np.real(2.0 * b.real)
  y = np.real(2.0 * b.imag)
  z = np.real(2.0 * a - 1.0)
  bb.add_vectors([x,y,z])
  return

def PlotState(v,plotAll=True,myTitle=""):
  if plotAll:
    N=len(np.asarray(v))
  else:
    N=len(np.asarray(v))//2
  vv=np.zeros(N,dtype=complex)
  vv[:]=np.asarray(v)[0:N]
  vv=vv*np.exp(-1.j*np.angle(vv[0]))
  plt.axhline(0)
  for idx,i in enumerate(vv):
    plt.plot([int(idx),int(idx)],[0,np.real(i)],color='red')
    plt.plot([int(idx)],[np.real(i)],'o',color='red')
  for idx,i in enumerate(vv):
    plt.plot([idx+0.1,idx+0.1],[0,np.imag(i)],color='blue')
    plt.plot([idx+0.1],[np.imag(i)],'o',color='blue')
  avg=np.average(vv)
  plt.axhline(np.real(avg),linestyle='--')
  plt.ylim(-1,1)
  plt.title(myTitle)
  plt.show()



def AddCircuits(theCircuits):
  numQubits=np.array([c.num_qubits for c in theCircuits])
  numQubits=np.max(numQubits)
  circuit=QuantumCircuit(numQubits,numQubits)
  for i in range(0,len(theCircuits)):
    circuit=circuit.compose(theCircuits[i],qubits=list(range(0,theCircuits[i].num_qubits)))
  return circuit


def Mark(r,N):
  circuit=QuantumCircuit(N,N)
  circuit.barrier()


  myString=np.binary_repr(r,width=N)[::-1]
  for i in range(0,len(myString)):
    if myString[i]=='0':
      circuit.x(i)
  circuit.barrier()

  circuit.h(N-1)
  circuit.mcx(list(range(0,N-1)), N-1,mode='noancilla')
  circuit.h(N-1)
  circuit.barrier()

  for i in range(0,len(myString)):
    if myString[i]=='0':
      circuit.x(i)
  circuit.barrier()
  return circuit

def InitializeCircuitRandom(N):
  r=np.random.random(2**N)
  r=r/np.linalg.norm(r)
  circuit=QuantumCircuit(N,N)
  circuit.initialize(list(r))
  return circuit


def InitializeCircuit(my_string,N):
  circuit = QuantumCircuit(N,N)
  circuit.initialize(my_string[::-1])
  return circuit

simulator = AerSimulator()

Exercise 1: A Single Qubit (33 points)#

a. A one qubit state#

A quantum state consists of a certain fraction of \(|0\rangle\) and a certain fraction of \(|1\rangle\) - i.e. \(\sqrt{0.3} |0\rangle - \sqrt{0.7} |1\rangle\).

We can plot this state in a variety of ways.

state=np.array([np.sqrt(0.3),-np.sqrt(0.7)])
state=MakeState(state)
PrintDirac(state)
PlotState(state)
b=qutip.Bloch()
PlotBloch(state,b)
b.render()
b.show()

Go ahead and try it out

Answer (start)
### ANSWER HERE
Answer (end)

Let’s go ahead and plot these three states

  • \(|0\rangle \equiv [1,0]\)

  • \(|1\rangle \equiv [0,1]\)

  • \(1/\sqrt{2} |0\rangle + 1/\sqrt{2} |1\rangle \equiv [1/\sqrt{2},1/\sqrt{2}]\)

Pay special attention to where those three states are on the Bloch Sphere

Answer (start)
### ANSWER HERE
Answer (end)

b. One qubit gates#

Quantum circuits are made out of quantum gates. Let us start by considering 1-qubit gates. The 1-qubit gate rotates states around the Bloch sphere. Three special gates are rx, ry, and rz which respectively rotate around the X, Y, and Z axis. These gates take an angle and a wire - i.e. rx(1/3*np.pi,0) will rotate \(1/3 \pi\) around the X axis.

To set up your circuit you can do

circuit=QuantumCircuit(1,1)
#Build your circuit here
state,measure = RunMe(circuit) #<--- This runs the circuit
# now you can plot the circuit

Go ahead and figure out how to use rx gate to move from a \(|0\rangle\) to a \(|1\rangle\) state.

Answer (start)
### ANSWER HERE
Answer (start)

Now we want to go ahead and use ry to go from \(|0\rangle \rightarrow 1/\sqrt{2}|0\rangle + 1/\sqrt{2}|1\rangle\). Write such a circuit. Then check to see what your circuit does to the state \(|1\rangle\) (you can get this using your other circuit from above).

Answer (start)
### ANSWER HERE
Answer (end)

So far we’ve seen we can get half \(|0\rangle\) and half \(|1\rangle\). We can also adjust states to get more of \(|1\rangle\) then \(|0\rangle\) (or visa versa). Generically we can get a state \(\cos(\theta) |0\rangle + \sin(\theta) e^{i\phi} |1\rangle\).

If we had such a state, after measurement we get “0” with probability \(\cos^2\theta\) and “1” with probability \(\sin^2\theta\).
Notice that \(\cos^2\theta + \sin^2\theta =1\) so we either get “0” or “1”.

To produce this state with \(\phi=0\), we can use the gate qc.ry(2*theta,wire) which takes \(|0\rangle \rightarrow \cos \theta |0\rangle + \sin \theta |1\rangle\)

Produce the state \(\cos(0.5)|0\rangle + \sin(0.5)|1\rangle\) and check to make sure it gives you the right amplitudes.

Answer (start)
### ANSWER HERE
Answer (end)

Now, make a circuit that rotates rx and rz both by \(0.3 \pi\).

Answer (start)
### ANSWER HERE
Answer (end)

Notice that by smartly choosing the angles around rx and rz and then rx again you can produce an arbitrary rotation on the sphere and therefore take \(|0\rangle\) and \(|1\rangle\) to any two orthogonal states.

c. Seeing the rotation#

We would like to plot the rotation around the bloch sphere. We can do this as follows:

b=qutip.Bloch()
for angle in np.arange(0,2*np.pi*0.8,0.1):
  quantumWires=1
  qc = QuantumCircuit(quantumWires,quantumWires)
  # rotate around the x-axis by angle theta
  vec,output=RunMe(qc)
  PlotBloch(vec,b)
b.render()
b.show()
Answer (start)
### ANSWER HERE
Answer (end)

d. Measuring the state#

So far we’ve been cheating by looking at the quantum state. In the real world, you can’t do that. Instead you have to measure at the end of your circuit. The RunMe circuit returns two parameters. The second one is measurement outcomes - i.e.

vector,measure=RunMe(circuit)

can then plot the measurement outcomes by doing

plot_histgoram(measure)

Go ahead and measure the outcomes of a state rotated around the X axis by \(0.3\pi\). See that it gives you the expected raction of 0 and 1. Remember that the probability should be equal to the amplitude squared.

Answer (start)
### ANSWER HERE
Answer (end)

Exercise 2: Two qubits (34 points)#

In this exercise we will see how to build quantum states of two qubits.

a. Control-not gates#

The controlled-not gate: The key gate for two qubits is the control-not gate (circuit.cx(0,1)). The key gate “nots” the second wire (wire 1) if the first wire is “1” (wire 0). Let’s check it out. Apply the “control-not” to a state \(|00\rangle\) and to a state \(|10\rangle\) and print out the state (not the measurement outcome)

Answer (start)
### ANSWER HERE
Answer (end)

b. Build an EPR Pair#

The most interesting two qubit state is an EPR pair, \(\frac{1}{\sqrt{2}}\left(|00\rangle + |11\rangle\right)\). You can build it with a Hadamard and a CNOT. Go ahead and try different things and figure out how to build yourself an EPR pair. You can start out with

quantumWires=2
classicalWires=2
qc=QuantumCircuit(quantumWires,classicalWires)

to start out a quantum circuit with two wires. You can’t plot this on the bloch sphere but you can still plot it with PlotState. =

Answer (start)
### ANSWER HERE
Answer (end)

c. Measuring EPR Pairs#

Now that you’ve made an EPR pair, let’s go ahead and measure your EPR circuit above plotting the histogram of your measurements.

Answer (start)
### ANSWER HERE
Answer (end)

There is something very powerful here. If you get a “0” on the top wire, then you always get a “0” on the bottom wire. If you get a “1” on the top wire, then you get a “1” on bottom wire. This is even the case if these wires are taken miles apart before you measure.

Exercise 3: Grover’s Algorithm#

In this exercise, we are going to implement Grover’s algorithm. Grover’s algorithm takes a unitary which marks an element \(i\) and uses that as a subroutine with more circuit elements so that, after measurementt, you sample the marked element \(i\).

To do this we are going to need to put together a lot of different circuit elements. Let’s start with the unitary which does the marking which we will give you. In this case it’s going to mark element 3 by taking it and changing its sign. Go ahead and run this to see explicitly what it does.

## Check Mark
circuit=InitializeCircuitRandom(5)
a,b=RunMe(circuit)
PlotState(a,True,myTitle="Initial Random State")
circuit=Mark(3,5)
a,b=RunMe(circuit,a)
PlotState(a,True,myTitle="Hopefully marked state")
Answer (start)
### ANSWER HERE
Answer (end)

a. Control-Control-Control Z#

Define a function controlZ(N) which generates the control-control-control-control Z on \(n\) qubits. The first \(n-1\) qubits are targets which have to be 1 for the last Z qubit to happen.

This is an example for controlZ(5).

You can get a control-control-control-control-x from qiskit by doing the following:

circuit.mcx(list(range(0,N-1)), N-1,mode='noancilla')

where \(N-1\) is the numer of target wires.

Test out your circuit by using the following code:

initCircuit=InitializeCircuit('11110',5)
#initCircuit=InitializeCircuit('11010',5)
initCircuit.h(4)
circuit=AddCircuits([initCircuit,ControlZ(5)])
print(circuit)
a,b=RunMe(circuit)
PrintDirac(a)

You should get something close to

(0.7071067811865475+8.659560562354932e-17j)|11110> + (-0.7071067811865476-8.659560562354934e-17j)|11111>

and then if you comment out the second initialization with 11010 you will get

(0.7071067811865476+0j)|11010> + (0.7071067811865475+0j)|11011>
Answer (start)
### ANSWER HERE
Answer (end)

b. All Hadamards#

Define a function AllHadamard(n) which builds \(n\) wires of Hadamards

Check it by the following test:

circuit=AllHadamard(5)
a,b=RunMe(circuit)
PlotState(a,True)

and seeing that it produces a state which is uniform. This is what we will use for the start of Grover’s algorithm.

Answer (start)
### ANSWER HERE
Answer (end)

c. FlipAllButZero#

Define FlipAllButZero(n). which should flip all but the zero configurations on \(n\) bits. It will us \(n+1\) wires (you need an ancilla). The example below is the output for FlipAllbutZero(4)

You might want to add some circuits together. To add these circuits you can do

AddCircuits([circuit1,circuit2,circuit3])

You can test it your result by doing

circuit=InitializeCircuitRandom(4)
a,b =RunMe(circuit)
PlotState(a,True,myTitle="Initial State")
circuit=FlipAllButZero(4)
a,b =RunMe(circuit,a)
PlotState(a,False,myTitle="Flipped Circuit")

You should find that everything but the zero flipped. It is ok if you are finding the zero flipped and nothing else. Quantum states aren’t defined up to a global phase and so the flipping of everything is equivalent to doing nothing.

Answer (start)
### ANSWER HERE
Answer (end)

d. Invert#

Define the Invert(N) function. This will also be on \(N+1\) wires. Here you need to add together the AllHadamard and FlipAllButZero and AllHadamard again.

You can test it in the following way:

circuit=InitializeCircuitRandom(4)
a,b=RunMe(circuit)
PlotState(a,True)
circuit=Invert(4)
a,b=RunMe(circuit,a)
PlotState(a,False)

This will generate a random state and then invert it around the mean (shown in a blue dotted line). Your mean before and after should be the same and everything else should flip around that dotted line. (Also everything totally flipping is still allowed)

Answer (start)
### ANSWER HERE
Answer (end)

e. Running Grover’s Algorithm#

Put everything together to run Grover’s algorithm.

Answer (start)
### ANSWER HERE
Answer (end)

Acknowledgement:

  • Bryan Clark (original)

Copyright: 2025