# Superdense coding

Alice has 2 classical bits she wants to send to Bob. Without quantum computing, Alice would have to send Bob 2 bits, one per piece information. But in fact, it is possible to send both bits using just 1 qubit!

Like many protocols in quantum computing, the key is making use of the entangled state
\begin{equation}
 |\Psi\rangle = \frac{1}{\sqrt{2}} \left( |00\rangle + |11 \rangle \right)
\end{equation}

We will see that if Alice and Bob each have a qubit of this entangled state, Alice can manipulate her qubit such that Bob is able to obtain both bits.


```python
import numpy as np

from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit
from qiskit import execute, BasicAer

import qiskit.tools.visualization as qvis

import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning) 
```

Let's give Alice two bits at random.


```python
alice_bits = [int(x) for x in np.round(np.random.rand(2))]
print(f"Alice wants to send Bob the bits {alice_bits[0]} and {alice_bits[1]}.")
```

    Alice wants to send Bob the bits 0 and 1.


First, let's set up the shared entangled state.


```python
# One qubit each for Alice and Bob
alice = QuantumRegister(1, 'a')
bob = QuantumRegister(1, 'b')

# Bob needs to measure his qubits, so this is a classical register to store results
bob_outputs = ClassicalRegister(2, 'm')

# Initialize a quantum circuit
superdense_circuit = QuantumCircuit(alice, bob, bob_outputs)

# Create the entangled state
superdense_circuit.h(alice[0])
superdense_circuit.cx(alice[0], bob[0]);

superdense_circuit.draw()
```




<pre style="word-wrap: normal;white-space: pre;line-height: 15px;">        ┌───┐     
a_0: |0>┤ H ├──■──
        └───┘┌─┴─┐
b_0: |0>─────┤ X ├
             └───┘
 m_0: 0 ══════════

 m_1: 0 ══════════
                  </pre>



Now, based on Alice's bits, she's going to perform one of the following operations to her qubit:
\begin{eqnarray}
 00 &\rightarrow& I \\
 01 &\rightarrow& X \\
 10 &\rightarrow& Z \\
 11 &\rightarrow& ZX \\
\end{eqnarray}


```python
if alice_bits[0] == 0 and alice_bits[1] == 1:
    superdense_circuit.x(alice[0])
    print("Alice applies the X gate.")
elif alice_bits[0] == 1 and alice_bits[1] == 0:
    superdense_circuit.z(alice[0])
    print("Alice applies the Z gate.")
elif alice_bits[0] == 1 and alice_bits[1] == 1:
    superdense_circuit.x(alice[0])
    superdense_circuit.z(alice[0])
    print("Alice applies the X gate followed by the Z gate.")
else:
    print("Alice does nothing else to her qubits.")
    
superdense_circuit.draw()
```

    Alice applies the X gate.





<pre style="word-wrap: normal;white-space: pre;line-height: 15px;">        ┌───┐     ┌───┐
a_0: |0>┤ H ├──■──┤ X ├
        └───┘┌─┴─┐└───┘
b_0: |0>─────┤ X ├─────
             └───┘     
 m_0: 0 ═══════════════

 m_1: 0 ═══════════════
                       </pre>



You might notice that this looks suspiciously similar to the circuits we made in notebook 01-03, where we constructed all four Bell states - this is exactly what Alice has done! She has performed a basis change; based on her first two bits, the two qubits are now in the state

\begin{eqnarray}
 00 &\rightarrow& \frac{1}{\sqrt{2}} \left( |00\rangle + |11 \rangle \right) \\
 01 &\rightarrow& \frac{1}{\sqrt{2}} \left( |10\rangle + |01 \rangle \right) \\
 10 &\rightarrow& \frac{1}{\sqrt{2}} \left( |00\rangle - |11 \rangle \right) \\
 11 &\rightarrow& \frac{1}{\sqrt{2}} \left( |01\rangle - |10 \rangle \right) 
\end{eqnarray}

Alice proceeds to send her qubit to Bob. With both qubits in hand, Bob has to make a measurement in the Bell basis. Depending on which of the four states he gets, he will know exactly which bits Alice sent.

Note: Qiskit doesn't have an implementation for measuring directly in the Bell basis, so we will need to do a basis change to get us back to the computational basis. This is just a CNOT from qubit 1 to 2 and then a Hadamard on qubit 1.


```python
# Basis change from Bell basis to computational basis
superdense_circuit.cx(alice[0], bob[0]) # Technically Bob now has both qubits
superdense_circuit.h(alice[0]);

superdense_circuit.draw()
```




<pre style="word-wrap: normal;white-space: pre;line-height: 15px;">        ┌───┐     ┌───┐     ┌───┐
a_0: |0>┤ H ├──■──┤ X ├──■──┤ H ├
        └───┘┌─┴─┐└───┘┌─┴─┐└───┘
b_0: |0>─────┤ X ├─────┤ X ├─────
             └───┘     └───┘     
 m_0: 0 ═════════════════════════

 m_1: 0 ═════════════════════════
                                 </pre>



Now let's measure Bob's qubits. 


```python
superdense_circuit.measure(alice[0], bob_outputs[0])
superdense_circuit.measure(bob[0], bob_outputs[1]);

superdense_circuit.draw()
```




<pre style="word-wrap: normal;white-space: pre;line-height: 15px;">        ┌───┐     ┌───┐     ┌───┐┌─┐
a_0: |0>┤ H ├──■──┤ X ├──■──┤ H ├┤M├
        └───┘┌─┴─┐└───┘┌─┴─┐└┬─┬┘└╥┘
b_0: |0>─────┤ X ├─────┤ X ├─┤M├──╫─
             └───┘     └───┘ └╥┘  ║ 
 m_0: 0 ══════════════════════╬═══╩═
                              ║     
 m_1: 0 ══════════════════════╩═════
                                    </pre>



We'll run the circuit only a single time - we should get the answer right away...

Note: registers in Qiskit circuits are ordered in 'reverse'. So when we measure, we are actually getting something like $... b_2 b_1 b_0$. To make sure the bits are ordered correctly with respect to the problem, then, we have to reverse the output of the result.


```python
# Execute the quantum circuit
backend = BasicAer.get_backend('qasm_simulator')
result = execute(superdense_circuit, backend, shots = 1).result()
counts = result.get_counts()

# Counts is a dictionary and the keys are bit strings; take the first one and split
bob_bits = list(list(counts.keys())[0])
bob_bits.reverse()
```


```python
print(f"Alice sent Bob bits {alice_bits[0]} and {alice_bits[1]}.")
print(f"Bob received bits {bob_bits[0]} and {bob_bits[1]} from Alice")
```

    Alice sent Bob bits 0 and 1.
    Bob received bits 0 and 1 from Alice


cabac6a18e3e17e0eed6a4a59b74fec35564b65d
ipynb
Jupyter Notebook
01-gate-model-theory/notebooks/Superdense-Coding.ipynb
abhishekabhishek/Intro-QC-TRIUMF
9c780446988b327e32f62113d03b55d689876079
MIT
01-gate-model-theory/notebooks/Superdense-Coding.ipynb
abhishekabhishek/Intro-QC-TRIUMF
9c780446988b327e32f62113d03b55d689876079
MIT
01-gate-model-theory/notebooks/Superdense-Coding.ipynb
abhishekabhishek/Intro-QC-TRIUMF
9c780446988b327e32f62113d03b55d689876079
MIT
Qwen/Qwen-72B
1. YES
2. YES