Author: Soham Bopardikar
Advisor: Hanrui Wang

Superdense Coding#

Superdense coding is a quantum communication protocol that allows the transmission of two classical bits of information using only one qubit[1]. It takes advantage of quantum entanglement and the ability to manipulate qubits in superposition. Charles H. Bennett and Stephen Wiesner proposed this technique in 1970(though it was not published until 1992 [2]) and it was experimentally realised in 1996 by Klaus Mattle, Harald Weinfurter, Paul G. Kwiat, and Anton Zeilinger utilising entangled photon pairs.

image.png

In this tutorial, we will learn how to implement superdense coding using the torchquantum library. We will cover the following steps:-

Step 1 - Preparing the entangled state/ 2 qubit bell pair.#

First, a bell pair of two qubits is created. Where q0 represents the sender’s qubit and q1 represents the receiver’s qubit. A hadamard gate is used to place q0 in a superposition of states. Then, with q0 as the control and q1 as the target, a CNOT operation is conducted.

image.png

Step 2 - Encoding the message#

Rules:

  1. For sending 00 - Perform no operation.

  2. For sending 01 - Perform a Pauli-Z operation where q1s state is flipped.

  3. For sending 10 - Apply a Pauli-X gate.

  4. For sending 11 - Apply a Pauli-Z gate followed by a Pauli-X gate.

Step 3 - Decoding the message#

Bob gets Alice’s qubit (leftmost qubit) and decodes the message sent. He does not need to know the state to decode it; instead, he simply applies the restoration operation. Bob employs a CNOT gate, with the leftmost qubit serving as control and the rightmost serving as target. Then he uses a Hadamard gate and eventually measures both qubits to extract the sent message.

image.png

Step 4 - Measurement#

In superdense coding, measurement plays a crucial role in extracting the classical bits that Alice encoded. After Bob has applied the decoding gates, he performs a measurement on both qubits to extract the information.

Installation#

[ ]:
!git clone https://github.com/mit-han-lab/torchquantum.git
Cloning into 'torchquantum'...
remote: Enumerating objects: 12494, done.
remote: Counting objects: 100% (765/765), done.
remote: Compressing objects: 100% (345/345), done.
remote: Total 12494 (delta 423), reused 674 (delta 392), pack-reused 11729
Receiving objects: 100% (12494/12494), 74.92 MiB | 31.26 MiB/s, done.
Resolving deltas: 100% (6780/6780), done.
[ ]:
%cd torchquantum
/content/torchquantum
[ ]:
!pip install --editable .
Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/
Obtaining file:///content/torchquantum
  Preparing metadata (setup.py) ... done
Requirement already satisfied: numpy>=1.19.2 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (1.22.4)
Requirement already satisfied: torchvision>=0.9.0.dev20210130 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (0.15.2+cu118)
Requirement already satisfied: tqdm>=4.56.0 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (4.65.0)
Requirement already satisfied: setuptools>=52.0.0 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (67.7.2)
Requirement already satisfied: torch>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (2.0.1+cu118)
Collecting torchpack>=0.3.0 (from torchquantum==0.1.7)
  Downloading torchpack-0.3.1-py3-none-any.whl (34 kB)
Collecting qiskit==0.38.0 (from torchquantum==0.1.7)
  Downloading qiskit-0.38.0.tar.gz (13 kB)
  Preparing metadata (setup.py) ... done
Requirement already satisfied: matplotlib>=3.3.2 in /usr/local/lib/python3.10/dist-packages (from torchquantum==0.1.7) (3.7.1)
Collecting pathos>=0.2.7 (from torchquantum==0.1.7)
  Downloading pathos-0.3.0-py3-none-any.whl (79 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79.8/79.8 kB 7.5 MB/s eta 0:00:00
Collecting pylatexenc>=2.10 (from torchquantum==0.1.7)
  Downloading pylatexenc-2.10.tar.gz (162 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 162.6/162.6 kB 15.6 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Collecting dill==0.3.4 (from torchquantum==0.1.7)
  Downloading dill-0.3.4-py2.py3-none-any.whl (86 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 86.9/86.9 kB 3.5 MB/s eta 0:00:00
Collecting qiskit-terra==0.21.2 (from qiskit==0.38.0->torchquantum==0.1.7)
  Downloading qiskit_terra-0.21.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.7 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.7/6.7 MB 58.1 MB/s eta 0:00:00
Collecting qiskit-aer==0.11.0 (from qiskit==0.38.0->torchquantum==0.1.7)
  Downloading qiskit_aer-0.11.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (19.2 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 19.2/19.2 MB 58.5 MB/s eta 0:00:00
Collecting qiskit-ibmq-provider==0.19.2 (from qiskit==0.38.0->torchquantum==0.1.7)
  Downloading qiskit_ibmq_provider-0.19.2-py3-none-any.whl (240 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 240.4/240.4 kB 22.8 MB/s eta 0:00:00
Requirement already satisfied: scipy>=1.0 in /usr/local/lib/python3.10/dist-packages (from qiskit-aer==0.11.0->qiskit==0.38.0->torchquantum==0.1.7) (1.10.1)
Requirement already satisfied: requests>=2.19 in /usr/local/lib/python3.10/dist-packages (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (2.27.1)
Collecting requests-ntlm>=1.1.0 (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading requests_ntlm-1.2.0-py3-none-any.whl (6.0 kB)
Requirement already satisfied: urllib3>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (1.26.15)
Requirement already satisfied: python-dateutil>=2.8.0 in /usr/local/lib/python3.10/dist-packages (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (2.8.2)
Requirement already satisfied: websocket-client>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (1.5.1)
Collecting websockets>=10.0 (from qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (129 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 129.9/129.9 kB 13.7 MB/s eta 0:00:00
Collecting retworkx>=0.11.0 (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading retworkx-0.12.1-py3-none-any.whl (10 kB)
Collecting ply>=3.10 (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading ply-3.11-py2.py3-none-any.whl (49 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.6/49.6 kB 5.2 MB/s eta 0:00:00
Requirement already satisfied: psutil>=5 in /usr/local/lib/python3.10/dist-packages (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7) (5.9.5)
Requirement already satisfied: sympy>=1.3 in /usr/local/lib/python3.10/dist-packages (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7) (1.11.1)
Collecting stevedore>=3.0.0 (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading stevedore-5.1.0-py3-none-any.whl (49 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.6/49.6 kB 5.1 MB/s eta 0:00:00
Collecting tweedledum<2.0,>=1.1 (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading tweedledum-1.1.1-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (929 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 929.7/929.7 kB 59.3 MB/s eta 0:00:00
Collecting symengine>=0.9 (from qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading symengine-0.10.0-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl (37.4 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 37.4/37.4 MB 18.7 MB/s eta 0:00:00
Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (1.0.7)
Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (0.11.0)
Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (4.39.3)
Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (1.4.4)
Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (23.1)
Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (8.4.0)
Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib>=3.3.2->torchquantum==0.1.7) (3.0.9)
Collecting ppft>=1.7.6.6 (from pathos>=0.2.7->torchquantum==0.1.7)
  Downloading ppft-1.7.6.6-py3-none-any.whl (52 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 52.8/52.8 kB 6.1 MB/s eta 0:00:00
INFO: pip is looking at multiple versions of pathos to determine which version is compatible with other requirements. This could take a while.
Collecting pathos>=0.2.7 (from torchquantum==0.1.7)
  Downloading pathos-0.2.9-py3-none-any.whl (76 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 76.9/76.9 kB 7.8 MB/s eta 0:00:00
  Downloading pathos-0.2.8-py2.py3-none-any.whl (81 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81.7/81.7 kB 9.1 MB/s eta 0:00:00
Collecting multiprocess>=0.70.12 (from pathos>=0.2.7->torchquantum==0.1.7)
  Downloading multiprocess-0.70.14-py310-none-any.whl (134 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 134.3/134.3 kB 13.7 MB/s eta 0:00:00
Collecting pox>=0.3.0 (from pathos>=0.2.7->torchquantum==0.1.7)
  Downloading pox-0.3.2-py3-none-any.whl (29 kB)
Requirement already satisfied: filelock in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->torchquantum==0.1.7) (3.12.0)
Requirement already satisfied: typing-extensions in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->torchquantum==0.1.7) (4.5.0)
Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->torchquantum==0.1.7) (3.1)
Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->torchquantum==0.1.7) (3.1.2)
Requirement already satisfied: triton==2.0.0 in /usr/local/lib/python3.10/dist-packages (from torch>=1.8.0->torchquantum==0.1.7) (2.0.0)
Requirement already satisfied: cmake in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.8.0->torchquantum==0.1.7) (3.25.2)
Requirement already satisfied: lit in /usr/local/lib/python3.10/dist-packages (from triton==2.0.0->torch>=1.8.0->torchquantum==0.1.7) (16.0.5)
Requirement already satisfied: h5py in /usr/local/lib/python3.10/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.7) (3.8.0)
Collecting loguru (from torchpack>=0.3.0->torchquantum==0.1.7)
  Downloading loguru-0.7.0-py3-none-any.whl (59 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 60.0/60.0 kB 5.3 MB/s eta 0:00:00
Collecting multimethod (from torchpack>=0.3.0->torchquantum==0.1.7)
  Downloading multimethod-1.9.1-py3-none-any.whl (10 kB)
Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.7) (6.0)
Requirement already satisfied: tensorboard in /usr/local/lib/python3.10/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.7) (2.12.2)
Collecting tensorpack (from torchpack>=0.3.0->torchquantum==0.1.7)
  Downloading tensorpack-0.11-py2.py3-none-any.whl (296 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 296.3/296.3 kB 26.0 MB/s eta 0:00:00
Requirement already satisfied: toml in /usr/local/lib/python3.10/dist-packages (from torchpack>=0.3.0->torchquantum==0.1.7) (0.10.2)
INFO: pip is looking at multiple versions of multiprocess to determine which version is compatible with other requirements. This could take a while.
Collecting multiprocess>=0.70.12 (from pathos>=0.2.7->torchquantum==0.1.7)
  Downloading multiprocess-0.70.13-py310-none-any.whl (133 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 133.1/133.1 kB 13.6 MB/s eta 0:00:00
  Downloading multiprocess-0.70.12.2-py39-none-any.whl (128 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 128.7/128.7 kB 14.4 MB/s eta 0:00:00
Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.8.0->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (1.16.0)
Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (2022.12.7)
Requirement already satisfied: charset-normalizer~=2.0.0 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (2.0.12)
Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.19->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (3.4)
Requirement already satisfied: mpmath>=0.19 in /usr/local/lib/python3.10/dist-packages (from sympy>=1.3->qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7) (1.3.0)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->torch>=1.8.0->torchquantum==0.1.7) (2.1.2)
Requirement already satisfied: absl-py>=0.4 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (1.4.0)
Requirement already satisfied: grpcio>=1.48.2 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (1.54.0)
Requirement already satisfied: google-auth<3,>=1.6.3 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (2.17.3)
Requirement already satisfied: google-auth-oauthlib<1.1,>=0.5 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (1.0.0)
Requirement already satisfied: markdown>=2.6.8 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (3.4.3)
Requirement already satisfied: protobuf>=3.19.6 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (3.20.3)
Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (0.7.0)
Requirement already satisfied: tensorboard-plugin-wit>=1.6.0 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (1.8.1)
Requirement already satisfied: werkzeug>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (2.3.0)
Requirement already satisfied: wheel>=0.26 in /usr/local/lib/python3.10/dist-packages (from tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (0.40.0)
Requirement already satisfied: termcolor>=1.1 in /usr/local/lib/python3.10/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.7) (2.3.0)
Requirement already satisfied: tabulate>=0.7.7 in /usr/local/lib/python3.10/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.7) (0.8.10)
Requirement already satisfied: msgpack>=0.5.2 in /usr/local/lib/python3.10/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.7) (1.0.5)
Collecting msgpack-numpy>=0.4.4.2 (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.7)
  Downloading msgpack_numpy-0.4.8-py2.py3-none-any.whl (6.9 kB)
Requirement already satisfied: pyzmq>=16 in /usr/local/lib/python3.10/dist-packages (from tensorpack->torchpack>=0.3.0->torchquantum==0.1.7) (23.2.1)
Requirement already satisfied: cachetools<6.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (5.3.0)
Requirement already satisfied: pyasn1-modules>=0.2.1 in /usr/local/lib/python3.10/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (0.3.0)
Requirement already satisfied: rsa<5,>=3.1.4 in /usr/local/lib/python3.10/dist-packages (from google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (4.9)
Requirement already satisfied: requests-oauthlib>=0.7.0 in /usr/local/lib/python3.10/dist-packages (from google-auth-oauthlib<1.1,>=0.5->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (1.3.1)
Requirement already satisfied: cryptography>=1.3 in /usr/local/lib/python3.10/dist-packages (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (40.0.2)
Collecting pyspnego>=0.1.6 (from requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading pyspnego-0.9.0-py3-none-any.whl (132 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 132.7/132.7 kB 11.8 MB/s eta 0:00:00
Collecting rustworkx==0.12.1 (from retworkx>=0.11.0->qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading rustworkx-0.12.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.9 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.9/1.9 MB 54.2 MB/s eta 0:00:00
Collecting pbr!=2.1.0,>=2.0.0 (from stevedore>=3.0.0->qiskit-terra==0.21.2->qiskit==0.38.0->torchquantum==0.1.7)
  Downloading pbr-5.11.1-py2.py3-none-any.whl (112 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 112.7/112.7 kB 11.5 MB/s eta 0:00:00
Requirement already satisfied: cffi>=1.12 in /usr/local/lib/python3.10/dist-packages (from cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (1.15.1)
Requirement already satisfied: pyasn1<0.6.0,>=0.4.6 in /usr/local/lib/python3.10/dist-packages (from pyasn1-modules>=0.2.1->google-auth<3,>=1.6.3->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (0.5.0)
Requirement already satisfied: oauthlib>=3.0.0 in /usr/local/lib/python3.10/dist-packages (from requests-oauthlib>=0.7.0->google-auth-oauthlib<1.1,>=0.5->tensorboard->torchpack>=0.3.0->torchquantum==0.1.7) (3.2.2)
Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.12->cryptography>=1.3->requests-ntlm>=1.1.0->qiskit-ibmq-provider==0.19.2->qiskit==0.38.0->torchquantum==0.1.7) (2.21)
Building wheels for collected packages: qiskit, pylatexenc
  Building wheel for qiskit (setup.py) ... done
  Created wheel for qiskit: filename=qiskit-0.38.0-py3-none-any.whl size=12128 sha256=4f7f0a0ad10fc979b9d35c9ab5851f0edc5c4661e807161ab1b13170575857c8
  Stored in directory: /root/.cache/pip/wheels/9c/b0/59/d6281e20610c76a5f88c9b931c6b338410f70b4ba6561453bc
  Building wheel for pylatexenc (setup.py) ... done
  Created wheel for pylatexenc: filename=pylatexenc-2.10-py3-none-any.whl size=136820 sha256=27ea7bd84314063cf13f0bc9b2890f6314fa9969d41ba1bd4ac5be1c7ccae66c
  Stored in directory: /root/.cache/pip/wheels/d3/31/8b/e09b0386afd80cfc556c00408c9aeea5c35c4d484a9c762fd5
Successfully built qiskit pylatexenc
Installing collected packages: pylatexenc, ply, websockets, tweedledum, symengine, rustworkx, ppft, pox, pbr, multimethod, msgpack-numpy, loguru, dill, tensorpack, stevedore, retworkx, multiprocess, qiskit-terra, pyspnego, pathos, requests-ntlm, qiskit-aer, qiskit-ibmq-provider, qiskit, torchpack, torchquantum
  Running setup.py develop for torchquantum
Successfully installed dill-0.3.4 loguru-0.7.0 msgpack-numpy-0.4.8 multimethod-1.9.1 multiprocess-0.70.12.2 pathos-0.2.8 pbr-5.11.1 ply-3.11 pox-0.3.2 ppft-1.7.6.6 pylatexenc-2.10 pyspnego-0.9.0 qiskit-0.38.0 qiskit-aer-0.11.0 qiskit-ibmq-provider-0.19.2 qiskit-terra-0.21.2 requests-ntlm-1.2.0 retworkx-0.12.1 rustworkx-0.12.1 stevedore-5.1.0 symengine-0.10.0 tensorpack-0.11 torchpack-0.3.1 torchquantum-0.1.7 tweedledum-1.1.1 websockets-11.0.3
[ ]:
%env PYTHONPATH=.
env: PYTHONPATH=.

Importing modules#

[ ]:
import math

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.nn.utils.rnn import pad_sequence
import torchquantum as tq
import torchquantum.functional as tqf
import argparse
import tqdm
import time

##Step 1: Preparing the 2-qubit bell pair

To prepare an entangled state, we use the Hadamard gate (h) and the CNOT gate (cx). The Hadamard gate (h) is applied to the first qubit (qubit 0) to put it into a superposition of |0⟩ and |1⟩. This creates an entangled state between the two qubits. The controlled-X gate (cx) is applied with the first qubit as the control and the second qubit as the target. It entangles the qubits further and prepares them for superdense coding. Let’s wrap this all up in a function.

[ ]:
def bell_pair():
  qdev = tq.QuantumDevice(n_wires=2, bsz=1, device="cpu")
  qdev.h(wires=0)
  qdev.cnot(wires=[0, 1])
  return qdev

Step 2: Encoding the message#

Here, we develop a function to encrypt any message with classical bits 00, 01, 10 and 11 that Alice wishes to transmit over the channel.

[ ]:
def encode_message(qdev, qubit, msg):
    if len(msg) != 2 or not set(msg).issubset({"0","1"}):
        raise ValueError(f"message '{msg}' is invalid")
    if msg[1] == "1":
        qdev.x(wires=qubit)
    if msg[0] == "1":
        qdev.z(wires=qubit)
    return qdev

Step 3 - Decoding the message#

Once Alice has encoded her message, she sends her qubit to Bob. Bob can then decode the message by applying the corresponding gates to his qubit. Bob applies a controlled-X gate (cx) with the first qubit as the control and the second qubit as the target. This operation “transfers” the encoded message from Alice’s qubit to Bob’s qubit. Then, Bob applies a Hadamard gate (h) to the first qubit. This allows Bob to extract the original classical bits.

[ ]:
def decode_message(qdev):
    qdev.cx(wires=[0, 1])
    qdev.h(wires=0)
    return qdev

Putting all these functions together

[ ]:
qdev = bell_pair() # Creating the entangled pair between Alice and Bob

message = '10'
qdev = encode_message(qdev, 1, message) # Encoding the message at Alice's end

qdev = decode_message(qdev) # Decoding the original message at Bob's end

Step 4 - Measurement#

Finally, Bob can measure the qubits to extract the encoded message. The tq.measure function in torchquantum is used to measure the qubits. This collapses the qubits into classical states, and the measurement results give us the original message bits ‘10’ sent by Alice with a probability of 100%.

[ ]:
print(tq.measure(qdev, n_shots=1024)) # Finally, Bob measures his qubits to read Alice's message
[OrderedDict([('00', 0), ('01', 0), ('10', 1024), ('11', 0)])]

The tq.measure function in torchquantum is used to measure the qubits. This collapses the qubits into classical states, and the measurement results give us the original message bits ‘10’ sent by Alice with a probability of 100%.

References:#

[1] Bennett, C.H., Brassard, G., Crépeau, C., Jozsa, R., Peres, A. and Wootters, W.K., 1993. Teleporting an unknown quantum state via dual classical and Einstein-Podolsky-Rosen channels. Physical review letters, 70(13), p.1895.

[2] Bennett, C.H. and Wiesner, S.J., 1992. Communication via one-and two-particle operators on Einstein-Podolsky-Rosen states. Physical review letters, 69(20), p.2881.

[3] Superdense Coding - Qiskit

[4] Superdense coding - Wikipedia