Quantum Computing 1#

  • Author:

  • Date:

  • Time Spent on this Assignment:

!pip install qiskit[visualization];
!pip install qiskit_aer;
!pip install qutip
!pip install qiskit-ibmq-provider
Collecting qiskit[visualization]
  Downloading qiskit-1.2.4-cp38-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.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (1.24.4)
Requirement already satisfied: scipy>=1.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (1.10.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.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (2.9.0.post0)
Collecting stevedore>=3.0.0 (from qiskit[visualization])
  Downloading stevedore-5.3.0-py3-none-any.whl.metadata (2.3 kB)
Requirement already satisfied: typing-extensions in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (4.12.2)
Collecting symengine<0.14,>=0.11 (from qiskit[visualization])
  Downloading symengine-0.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.2 kB)
Requirement already satisfied: matplotlib>=3.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (3.7.5)
Collecting pydot (from qiskit[visualization])
  Downloading pydot-3.0.2-py3-none-any.whl.metadata (10 kB)
Requirement already satisfied: Pillow>=4.2.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit[visualization]) (10.4.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.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (1.1.1)
Requirement already satisfied: cycler>=0.10 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (0.12.1)
Requirement already satisfied: fonttools>=4.22.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (4.54.1)
Requirement already satisfied: kiwisolver>=1.0.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (1.4.7)
Requirement already satisfied: packaging>=20.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (24.2)
Requirement already satisfied: pyparsing>=2.3.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (3.1.4)
Requirement already satisfied: importlib-resources>=3.2.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from matplotlib>=3.3->qiskit[visualization]) (6.4.5)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from python-dateutil>=2.8.0->qiskit[visualization]) (1.16.0)
Requirement already satisfied: pandas>=1.2 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from seaborn>=0.9.0->qiskit[visualization]) (2.0.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.8.18/x64/lib/python3.8/site-packages (from importlib-resources>=3.2.0->matplotlib>=3.3->qiskit[visualization]) (3.20.2)
Requirement already satisfied: pytz>=2020.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from pandas>=1.2->seaborn>=0.9.0->qiskit[visualization]) (2024.2)
Requirement already satisfied: tzdata>=2022.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/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 94.2 MB/s eta 0:00:00
?25hDownloading seaborn-0.13.2-py3-none-any.whl (294 kB)
Downloading stevedore-5.3.0-py3-none-any.whl (49 kB)
Downloading symengine-0.13.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (49.7 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/49.7 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━╺━━━━━━━━━━━━━ 32.5/49.7 MB 243.1 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸ 49.5/49.7 MB 135.8 MB/s eta 0:00:01
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.7/49.7 MB 105.0 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.2-py3-none-any.whl (35 kB)
Downloading qiskit-1.2.4-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/4.8 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.8/4.8 MB 154.4 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 68.2 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=136824 sha256=f8692eaeae0c505998905f0955c5c95f403a862c7766e88737b8e0558c941d75
  Stored in directory: /home/runner/.cache/pip/wheels/72/99/be/81d9bcdf5dd5ee5acd8119a9dd5bc07204c9ce205fd341b021
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.2 pylatexenc-2.10 qiskit-1.2.4 rustworkx-0.15.1 seaborn-0.13.2 stevedore-5.3.0 symengine-0.13.0 sympy-1.13.3
Collecting qiskit_aer
  Downloading qiskit_aer-0.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (8.0 kB)
Requirement already satisfied: qiskit>=1.1.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit_aer) (1.2.4)
Requirement already satisfied: numpy>=1.16.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit_aer) (1.24.4)
Requirement already satisfied: scipy>=1.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit_aer) (1.10.1)
Requirement already satisfied: psutil>=5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit_aer) (6.1.0)
Requirement already satisfied: rustworkx>=0.15.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit>=1.1.0->qiskit_aer) (0.15.1)
Requirement already satisfied: sympy>=1.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit>=1.1.0->qiskit_aer) (1.13.3)
Requirement already satisfied: dill>=0.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/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.8.18/x64/lib/python3.8/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.8.18/x64/lib/python3.8/site-packages (from qiskit>=1.1.0->qiskit_aer) (5.3.0)
Requirement already satisfied: typing-extensions in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/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.8.18/x64/lib/python3.8/site-packages (from qiskit>=1.1.0->qiskit_aer) (0.13.0)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from python-dateutil>=2.8.0->qiskit>=1.1.0->qiskit_aer) (1.16.0)
Requirement already satisfied: pbr>=2.0.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/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.8.18/x64/lib/python3.8/site-packages (from sympy>=1.3->qiskit>=1.1.0->qiskit_aer) (1.3.0)
Downloading qiskit_aer-0.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (12.3 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/12.3 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 12.3/12.3 MB 121.5 MB/s eta 0:00:00
?25h
Installing collected packages: qiskit_aer
Successfully installed qiskit_aer-0.15.1
Collecting qutip
  Downloading qutip-5.0.1.tar.gz (6.4 MB)
?25l     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/6.4 MB ? eta -:--:--
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.4/6.4 MB 122.2 MB/s eta 0:00:00
?25h
  Installing build dependencies ... ?25l-
 \
 |
 /
 -
 \
 |
 /
 -
 \
 done
^C
?25h  Getting requirements to build wheel ... ?25l?25hcanceled
ERROR: Operation cancelled by user

Collecting qiskit-ibmq-provider
  Downloading qiskit_ibmq_provider-0.20.2-py3-none-any.whl.metadata (14 kB)
Collecting qiskit-terra>=0.18.0 (from qiskit-ibmq-provider)
  Downloading qiskit_terra-0.46.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (13 kB)
Requirement already satisfied: requests>=2.19 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-ibmq-provider) (2.32.3)
Collecting requests-ntlm<=1.1.0 (from qiskit-ibmq-provider)
  Downloading requests_ntlm-1.1.0-py2.py3-none-any.whl.metadata (938 bytes)
Collecting numpy<1.24 (from qiskit-ibmq-provider)
  Downloading numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.3 kB)
Requirement already satisfied: urllib3>=1.21.1 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-ibmq-provider) (2.2.3)
Requirement already satisfied: python-dateutil>=2.8.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-ibmq-provider) (2.9.0.post0)
Collecting websocket-client>=1.5.1 (from qiskit-ibmq-provider)
  Downloading websocket_client-1.8.0-py3-none-any.whl.metadata (8.0 kB)
Collecting websockets>=10.0 (from qiskit-ibmq-provider)
  Downloading websockets-13.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.8 kB)
Requirement already satisfied: six>=1.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from python-dateutil>=2.8.0->qiskit-ibmq-provider) (1.16.0)
Requirement already satisfied: rustworkx>=0.13.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (0.15.1)
Collecting ply>=3.10 (from qiskit-terra>=0.18.0->qiskit-ibmq-provider)
  Downloading ply-3.11-py2.py3-none-any.whl.metadata (844 bytes)
Requirement already satisfied: psutil>=5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (6.1.0)
Requirement already satisfied: scipy>=1.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (1.10.1)
Requirement already satisfied: sympy>=1.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (1.13.3)
Requirement already satisfied: dill>=0.3 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (0.3.9)
Requirement already satisfied: stevedore>=3.0.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (5.3.0)
Requirement already satisfied: symengine>=0.11 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (0.13.0)
Requirement already satisfied: typing-extensions in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from qiskit-terra>=0.18.0->qiskit-ibmq-provider) (4.12.2)
Requirement already satisfied: charset-normalizer<4,>=2 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from requests>=2.19->qiskit-ibmq-provider) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from requests>=2.19->qiskit-ibmq-provider) (3.10)
Requirement already satisfied: certifi>=2017.4.17 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from requests>=2.19->qiskit-ibmq-provider) (2024.8.30)
Collecting ntlm-auth>=1.0.2 (from requests-ntlm<=1.1.0->qiskit-ibmq-provider)
  Downloading ntlm_auth-1.5.0-py2.py3-none-any.whl.metadata (10 kB)
Collecting cryptography>=1.3 (from requests-ntlm<=1.1.0->qiskit-ibmq-provider)
  Downloading cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl.metadata (5.4 kB)
Collecting cffi>=1.12 (from cryptography>=1.3->requests-ntlm<=1.1.0->qiskit-ibmq-provider)
  Downloading cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (1.5 kB)
Requirement already satisfied: pbr>=2.0.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from stevedore>=3.0.0->qiskit-terra>=0.18.0->qiskit-ibmq-provider) (6.1.0)
Requirement already satisfied: mpmath<1.4,>=1.1.0 in /opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages (from sympy>=1.3->qiskit-terra>=0.18.0->qiskit-ibmq-provider) (1.3.0)
Collecting pycparser (from cffi>=1.12->cryptography>=1.3->requests-ntlm<=1.1.0->qiskit-ibmq-provider)
  Downloading pycparser-2.22-py3-none-any.whl.metadata (943 bytes)
Downloading qiskit_ibmq_provider-0.20.2-py3-none-any.whl (241 kB)
Downloading numpy-1.23.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (17.1 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/17.1 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 17.1/17.1 MB 172.8 MB/s eta 0:00:00
?25h
Downloading qiskit_terra-0.46.3-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.4 MB)
?25l   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 0.0/5.4 MB ? eta -:--:--
   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 5.4/5.4 MB 127.0 MB/s eta 0:00:00
?25h
import numpy as np
from qiskit import QuantumCircuit, QuantumRegister, transpile
from qiskit.providers.aer import QasmSimulator
from qiskit.visualization import plot_histogram
from qiskit.circuit.library.standard_gates import ZGate, XGate
from qiskit import IBMQ
from qiskit.circuit.quantumregister import AncillaRegister
import pylab as plt
from qiskit.quantum_info import Statevector, partial_trace
from qiskit_aer import AerSimulator
from qiskit import QuantumCircuit, QuantumRegister, transpile
import qutip
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, Aer, execute
/usr/local/lib/python3.10/dist-packages/qutip/__init__.py:65: UserWarning: The new version of Cython, (>= 3.0.0) is not supported.
  warnings.warn(
simulator = AerSimulator()

Today we will do most our simulations on a classical simulator that runs on the OWL server. But, we will run one thing on an actual quantum computer. To do that, you need to sign up for the quantum computer. Go ahead and sign up for a quantum computing account here: https://quantum-computing.ibm.com/login

You will need to put your API key into the commented out section below so it will know to run your code on the quantum computer.

IBMQ.save_account("..")
IBMQ.load_account()
provider = IBMQ.get_provider(hub='ibm-q')
def RunMe(qc,num_shots=1024):
    backend = BasicAer.get_backend('qasm_simulator')
    job = execute(qc, backend,shots=num_shots)
    result = job.result()
    return result

def RunMeState(qc):
    backend = BasicAer.get_backend('statevector_simulator')
    job = execute(qc, backend,shots=1024)
    result = job.result()
    return result

def RunMeQC(qc):
    provider = IBMQ.get_provider(hub='ibm-q')
    from qiskit.providers.ibmq import least_busy
    small_devices = provider.backends(filters=lambda x: x.configuration().n_qubits == 5
                                       and not x.configuration().simulator)
    backend = least_busy(small_devices)
    jobReal = execute(qc, backend)
    return jobReal


def RunCircuit(circuit):
  circuit.save_statevector()
  compiled_circuit = transpile(circuit, simulator)
  result = simulator.run(compiled_circuit).result()
  out_state = result.get_statevector()
  return out_state


def StateToBinary(b):
    wires=int(round(np.log2(len(b))))
    for i in range(0,2**wires):
        myFormat="0"+str(wires)+"b"
        if np.abs(b[i])!=0:
            print(b[i],'|',format(i, myFormat)[::-1],'>')


def RunMe(circuit):
  circuit.save_statevector(label='myStateVector')
  compiled_circuit = transpile(circuit, simulator)
  resultA = simulator.run(compiled_circuit).result()
  numQubits=circuit.num_qubits
  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 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 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(avg,linestyle='--')
  plt.ylim(-1,1)
  plt.title(myTitle)
  plt.show()


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

def PlotBloch(v,bb):
  vv=np.asarray(v)
  #print(vv)
  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)
  #print(x,y,z)
  bb.add_vectors([x,y,z])
  return  #plot_bloch_vector([x,y,z])


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 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 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 RunMeQC(qc,num_shots=1024):
    numQubits=qc.num_qubits
    forward=list(range(0,numQubits))
    reverse=forward[::-1]
    qc.measure(forward,reverse)
    backend = provider.get_backend('ibm_lagos')
    job = execute(qc, backend,shots=num_shots)
    #result = job.result()
    return job

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

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()
(0.5477225575051661+0j)|0> + (-0.8366600265340756+0j)|1> + 
_images/5d5b1c6430cc52dc9bcc21e0d90d4816b676342d61f4ac8eca8518589a861a05.png _images/f326aa548cf19e1d2a69dcb32cf2ba3c2af5667a3078e6cf187746232c2f62b7.png

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

## Plot the three states here

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(0.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 HERE

Now we want to go ahead and use rx 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).

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.rx(-2*theta,wire) which takes \(|0\rangle \rightarrow \cos \theta |0\rangle + \sin \theta |1\rangle\)

  • Produce some plots with \(\theta=0.5\) and check to make sure it gives you the right amplitudes.

## ANSWER HERE

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

## ANSWER HERE

Notice that by smartly choosing the angles around rx and rz and then rx again you should be able to take \(|0\rangle\) to any state and \(|1\rangle\) to any state which is orthogonal to \(|0\rangle\).

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 HERE
_images/09029cbc7485df00c9b7351599fc45c5d50239257d5db9baa507047aeafd08d7.png

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.

## ANSWER HERE

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 (qc.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 (i.e. RunMeState). Don’t put in a measurement.

To apply a control-not gate you want to do circuit.cx(wire)

### Circuit here applying control-not to |00>.  Print the state when you're done.
(1+0j) | 00 >
### Circuit here applying control-not to |10>.  Print the state when you're done.
(1+0j) | 11 >

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. Go ahead and do this.

### Make an EPR Pair. It can be done with Hadamards and CNOTs.  Run it and look at the state when you're done.

c. Measuring EPR Pairs#

Let’s go ahead and measure your EPR circuit above plotting the histogram of your measurements.

### Do the same thing with the EPR Pair but now look at the measurements.

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.

d. Running on an actual Quantum Computer#

Now we are going to build an EPR pair on an actual quantum computer. To do this you need to build your quantum circuit again (with measurement) for building an EPR pair and then call job=RunMeQC(qc).

## Remake your circuit and run it on a real live quantum computer.

Once you have run that, your job is sent off to a quantum computer. It may take a bit of time to run. To check whether it has run yet, we need to do

print(job.status())
print(job.queue_position())

You should run these lines until your job status is JobStatus.DONE

print(job.status())
print(job.queue_position())
JobStatus.QUEUED
None

Now that your job has gotten off the quantum computer we can now query it. To get the counts do job.result().get_counts. Go ahead and plot a histogram of them.

You should notice that you don’t get perfect correlation anymore. Current quantum computers are not particularly good.

#go ahead and make a histogram of the results.

e. Entanglement (Extra Credit: 5 points)#

The EPR pair is called entangled.
Not entangled means
Pr(wires measures “00”) = Pr(wire 0 measures “0”) \(\times\) Pr(wire 1 measures “0”) Note that when you check things you aren’t going to get this exactly even if things are independent because things are stochastic. If you’re careful you can compute error bars but otherwise use reasonable judgement

We want to check if things are entangled. To accomplish this, let’s write a function to measure the probability that wire \(i\) is 0 - i.e. def wire_i_probability(myCounts,wire_i) (you can assume wire_i will either be 0 or 1).

Now write a function def wires_probability(myCounts) which returns the probability that the two wires are “00”.

Given these two functions we want to see which circuits produce entangled states. In particular check

  • The EPR Pair

  • A circuit you generate which has no two wire gates in it (i.e. no CNOT) and demonstrate what you find.

You should run this with the simulator and not on the quantum computer.

# Measure the probability of getting "0" on the wire `wire`
def Probability(myCounts,wire):
    zeroProb=0.0
    if wire==0:

    elif wire==1:
    return zeroProb/1024.
  File "<ipython-input-8-9fe96e3ec3ad>", line 6
    elif wire==1:
    ^
IndentationError: expected an indented block after 'if' statement on line 4
## Now check the entanglement of the EPR pair and a state you make only using 1-qubit gates.

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:

## 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")
## Check Mark
circuit=InitializeCircuitRandom(5)
a,b=RunMe(circuit)
PlotState(a,True,myTitle="Initial Random State")
circuit=Mark(1,5)
a,b=RunMe(circuit,a)
PlotState(a,True,myTitle="Hopefully marked state")
_images/0490fe40713058c376a3f17e8c0b9c72a815ea6563238cc7e0ea7474ecd2aec8.png _images/91727f768e111243546cf05969e103880425050cdf2629e5ef537766b2716fd8.png

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=RunCircuit(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>

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=RunCircuit(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.

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=RunCircuit(circuit)
PlotState(a,True)
circuit=FlipAllButZero(4)
a,b=RunCircuit(circuit,a)
PlotState(a,False)

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.

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=RunCircuit(circuit)
PlotState(a,True)
circuit=Invert(4)
a,b=RunCircuit(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)

e. Running Grover’s Algorithm#

Put everything together to run Grover’s algorithm.

Exercise 4 Quantum Key Distribution (EC - 20 points)#

a. One time pads#

If Alice and Bob have two identical secret books of bits which agree, they could send secret messages to each other. Here’s a way to make a bunch of secret bits by sharing a quantum state. After the quantum state is produced, they can separate their wires to be far apart.

def MakeSinglet(qc):
    aliceWire=0
    bobWire=1
    qc.h(aliceWire)
    qc.cx(aliceWire,bobWire)

def MakeSharedState(qc):
    MakeSinglet(qc)
    qc.barrier()
    return qc

qc=QuantumCircuit(2,2)
qc=MakeSharedState(qc)
qc.draw(output='mpl')
_images/deb64e0078a1a438b47ba8979fcfb6a0bfc64b75179cd727a394c9a707d2bcb9.png

Let AliceWire=0 and BobWire=1 .

  • Add some measurement to the circuit above

  • execute this circuit 100 times (use RunMe(qc,1) so you only run one copy of it)

  • store a list of Alice and Bob’s bits and report what fraction of the time they agree.

For this latter task I find the following helpful:     theKey=list(result.get_counts().keys())[0]. theKey will be the bitstring of measured state in reversed order (i.e. theKey[0] is q0, theKey[1] is q1, etc)

aliceBits=[]
bobBits=[]

qc.measure([0,1],[0,1])
## After measurement how often do Alice and Bob's bits agree.

print("They agree this fraction of the time: " ,amountAgree)
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-11-f96726f9186e> in <module>
      2 bobBits=[]
      3 
----> 4 qc.measure([0,1],[0,1])
      5 ## After measurement how often do Alice and Bob's bits agree.
      6 

NameError: name 'qc' is not defined

b. Eve’s arrival#

Unfortunately this approach has a problem. Suppose that you’re sending an EPR pair to Alice and the eavesdropper Eve gets a hold of it. Is their a way to have Eve sneakily get the message without Alice and Bob noticing? Add some circuit for Eve. Assume that she can do anything she wants to the state (and her wire) after the shared state is made but before it’s shipped off to Alice and Bob.

Then, measure what fraction of the time Alice and Bob agree and what fraction of the time Eve has successfully figured out the bit.

image.png

AliceBits=[]
EveBits=[]
BobBits=[]
eveWire=2
qc=QuantumCircuit(3,3)
qc=MakeSharedState(qc)
###What can Eve do here so that she knows the secret bit and can't be detected by Alice and Bob
qc.cx(0,2)
qc.measure([2],[2])
qc.barrier()
### Eve is done now.

qc.measure([0,1],[0,1])  #this is your measure from earlier.

###How often do Alice and Bob's bits agree.
### How often do Alice and Eve's bits agree.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-12-35d1d42d0720> in <module>
      3 BobBits=[]
      4 eveWire=2
----> 5 qc=QuantumCircuit(3,3)
      6 qc=MakeSharedState(qc)
      7 ###What can Eve do here so that she knows the secret bit and can't be detected by Alice and Bob

NameError: name 'QuantumCircuit' is not defined

If you’ve done it correctly you should find that Alice and Bob always agree but also Alice and Eve also always agree. So our protocol was a good way to share some secrete bits but doesn’t work if Even can get a hold of the state before Alice and Bob gert it. We need an improved protocol.

c. An improved protocol#

Let’s remove Eve for the moment and work on an improved protocol. Suppose Alice and Bob agree that for each of the 100 trials, Alice and Bob are going to flip a shared coin and decide to randomly put a Hadamard on both their wires if you get heads (np.random.random()>0.5) and leave it alone otherwise (Yes - I know flipping a shared coin is cheating. We will fix it later). Emulate this new protocol and see how often Alice and Bob’s bits agree? Store also an array which specifies when you decided to add the Hadamard.

### Build here the improved protocol and see how often Alice and Bob's bits agree.

d. Eve in the improved protocol#

Now add Eve back using your approach from (b). How often do Alice and Bob agree? How often do Alice and Eve agree? Suppose Alice and Bob were willing to talk some - can they catch Eve’s eavsdropping and still have some useful random bits left if Eve wasn’t listening.

# Use the same Eve technique as you did in (b) and see how often they agree.  If Alice and Bob's bits don't
# always agree is their a way for Alice and Bob to then detect Eve's eavesdropping while still having
# some one-time pad bits left.
Alice and Bob Agree:  0.74
Alice and Eve Agree:  0.71

e. Not flipping shared coins#

In practice, Alice and Bob can’t randomly choose to both use the Hadamard gate at the same time. Let’s assume instead they independently add a random Hadamard gate. Modify your code to do this and record when Bob and Alice chose Hadamard. Now write some code to allow Alice and Bob to identify when there is eavesdropping. To do this, Alice and Bob need to not only talk about what answers they got but also whether not they both added their Hadamard gate.

HadamardA=[]
HadamardB=[]

## Now remove the cheating from the approach.
## This time, Alice and Bob are going to have to talk about both the decisions they made (Hadamard or not)
## as well as what result they get

mask=np.array(HadamardA)==(HadamardB)

## How often do they agree if we only consider the cases when they made the same choice.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-15-0a1f5e87666f> in <module>
      6 ## as well as what result they get
      7 
----> 8 mask=np.array(HadamardA)==(HadamardB)
      9 
     10 ## How often do they agree if we only consider the cases when they made the same choice.

NameError: name 'np' is not defined

Exercise 5: Building up tools (EC - 10 points)#

Now we are going to build up some tools and intuition so we can learn to build more complicated circuits.

a. Initializing a binary number#

Often it is useful to get some binary state (like \(|0110\rangle\)) into your quantum computer. Write a function def Init(qc,myBinaryNumber) which generates the state \(|\textrm{myBinaryNumber}\rangle\). Run

Init(qc,'011')
qc.draw(output='mpl')
def Init(qc,myString='000'):
    #write me

qc=QuantumCircuit(3,3)
Init(qc,'011')
qc.draw(output='mpl')
  File "<ipython-input-16-64a1f88e0e9c>", line 4
    qc=QuantumCircuit(3,3)
     ^
IndentationError: expected an indented block

b. A sum over all states#

A useful state to be able to make is $\(\frac{1}{\sqrt{N}}\sum_{i=1}^N |i\rangle\)$

Write a function def AllSum(qc,w) which adds this circuit to qc for \(N=2^w\). Run it with \(w=5\) and draw out your circuit.

qr = QuantumRegister(5)
cr = ClassicalRegister(5)
qc=QuantumCircuit(qr,cr)
AllSum(qc,5)
qc.measure(qr,cr)

qc.draw(output='mpl')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-17-7c39755fd900> in <module>
----> 1 qr = QuantumRegister(5)
      2 cr = ClassicalRegister(5)
      3 qc=QuantumCircuit(qr,cr)
      4 AllSum(qc,5)
      5 qc.measure(qr,cr)

NameError: name 'QuantumRegister' is not defined

Now run the state on your simulator and measure how often you get various states.

# Run me looking at the measurements and see what happens

c. Angle of a random gate#

In this section, we are going to start out with a \(R_z(\theta)\) gate but we don’t know what \(\theta\) is. Your goal is to use other gates to figure out \(\theta\). Write some code which returns your guess of \(\theta\). To add your random gate to your circuit, you may call RandomGate(qc).

def RandomGateHelp():
    theta=np.random.random()*2*np.pi
    def RandomGate(qc):
        qc.rz(theta,0)
    return RandomGate

RandomGate=RandomGateHelp()
def ReturnTheta():
    qr=QuantumRegister(1)
    cr=ClassicalRegister(1)
    qc=QuantumCircuit(qr,cr)
    #change this function somehow
    RandomGate(qc)
    qc.measure(0,0)
    result=RunMe(qc)
    myCounts=result.get_counts()
    print(myCounts)
    return 0.0
print("Theta is ",ReturnTheta())
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-19-1a8f8b58a905> in <module>
     10     print(myCounts)
     11     return 0.0
---> 12 print("Theta is ",ReturnTheta())

<ipython-input-19-1a8f8b58a905> in ReturnTheta()
      1 def ReturnTheta():
----> 2     qr=QuantumRegister(1)
      3     cr=ClassicalRegister(1)
      4     qc=QuantumCircuit(qr,cr)
      5     #change this function somehow

NameError: name 'QuantumRegister' is not defined

d. Inverting a CNOT#

Suppose you have a quantum computer which can generate a CNOT where the control wire is smaller then the NOT wire - i.e. qc.cx(i,j) where \(i<j\). Now, you need the gate qc.cx(j,i) . Figure out how to use 1-qubit gates and qc.cx(i,j) to build the gate qc.cx(j,i) and demonstrate that it works. Hint: You can do this with one CNOT some number of Hadamards.

# Write code here

e. Deferred Measurements#

Suppose you have a calculation where you do a measurement in the middle of your simulation.

qr=QuantumRegister(1)
cr=ClassicalRegister(1)
qc=QuantumCircuit(qr,cr)
qc.h(0)
qc.rx(np.pi/2.,0)
qc.rz(np.pi/3.,0)
qc.rx(np.pi/5.,0)
qc.measure(0,0)
qc.h(0)
qc.rz(np.pi/5.,0)
qc.ry(np.pi/2.,0)
qc.measure(0,0)
qc.draw(output='mpl')
_images/b10f15513f5170901f49f0d22125e71f601e9701c9ed547015aba597443d8fa4.png

We can measure the probabilities of the output:

plot_histogram(RunMe(qc).get_counts())
_images/7d95c9a386cfac208b6314cc54a733e8ae066ae5e499c984b3bc0fe9fcb2ef9c.png

We want to rewrite the circuit on two wires so that you can do all the measurements at the end. Figure out how to pull this off and show that you get the same probability distribution over the first wire. You should be able to do this essentially independently of the gates that I include on the top wire. Hint: You want to essentially copy what would have been the result of the measurement to the bottom wire. Then you can measure the bottom wire whenever since there are no gates there.

qr=QuantumRegister(2)
cr=ClassicalRegister(2)
qc=QuantumCircuit(qr,cr)
# do stuff before the measurement which is the last thing you do
qc.measure([0,1],[0,1])

qc.draw(output='mpl')
#only plot the probability of wire 1. You want to get the same result.
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-22-58c437e115d3> in <module>
----> 1 qr=QuantumRegister(2)
      2 cr=ClassicalRegister(2)
      3 qc=QuantumCircuit(qr,cr)
      4 # do stuff before the measurement which is the last thing you do
      5 qc.measure([0,1],[0,1])

NameError: name 'QuantumRegister' is not defined

Acknowledgement:

  • Bryan Clark and Ryan Level (original)

Copyright: 2021