In [1]:

```
from math import sqrt
from qutip import about, basis, tensor
from qutip_qip.circuit import QubitCircuit
from qutip_qip.operations import Measurement
```

This notebook introduces the basic quantum teleportation circuit (https://en.wikipedia.org/wiki/Quantum_teleportation), complete with measurements and classical control. This notebook also serves as an example on how to add measurement gates and classical controls to a circuit.

We will describe the circuit that enables quantum teleportation. We will use two classical wires and three qubit wires. The first qubit wire represents the quantum state $| q0 ⟩ = | \psi ⟩$ that needs to be transferred from Alice to Bob (so the first qubit is in the possession of Alice).

In [2]:

```
teleportation = QubitCircuit(
3, num_cbits=2, input_states=[r"\psi", "0", "0", "c0", "c1"]
)
```

In [3]:

```
teleportation.add_gate("SNOT", targets=[1])
teleportation.add_gate("CNOT", targets=[2], controls=[1])
```

In [4]:

```
teleportation.add_gate("CNOT", targets=[1], controls=[0])
teleportation.add_gate("SNOT", targets=[0])
teleportation.add_measurement("M0", targets=[0], classical_store=1)
teleportation.add_measurement("M1", targets=[1], classical_store=0)
```

Now, we apply the $X$ gate on Bob's qubit based on the classical control $c0$ and $Z$ gate based on classical control $c1$. These operations correspond to the following operations based on the state of Alice's measurement.

$|00⟩ \rightarrow $ no operation

$|01⟩ \rightarrow Z$

$|10⟩ \rightarrow X$

$|11⟩ \rightarrow ZX$

The final circuit mathematically must result in the third qubit taking the state $|\psi⟩$.

In [5]:

```
teleportation.add_gate("X", targets=[2], classical_controls=[0])
teleportation.add_gate("Z", targets=[2], classical_controls=[1])
```

In [6]:

```
teleportation.gates
```

Out[6]:

[Gate(SNOT, targets=[1], controls=None, classical controls=None, control_value=None, classical_control_value=None), Gate(CNOT, targets=[2], controls=[1], classical controls=None, control_value=1, classical_control_value=None), Gate(CNOT, targets=[1], controls=[0], classical controls=None, control_value=1, classical_control_value=None), Gate(SNOT, targets=[0], controls=None, classical controls=None, control_value=None, classical_control_value=None), Measurement(M0, target=[0], classical_store=1), Measurement(M1, target=[1], classical_store=0), Gate(X, targets=[2], controls=None, classical controls=[0], control_value=None, classical_control_value=1), Gate(Z, targets=[2], controls=None, classical controls=[1], control_value=None, classical_control_value=1)]

The circuit can also be visualized:

In [7]:

```
teleportation
```

/home/runner/work/qutip-tutorials/qutip-tutorials/qutip-qip/src/qutip_qip/circuit/circuit_latex.py:95: UserWarning: Could not locate system 'pdfcrop': image output may have additional margins. warnings.warn(

Out[7]:

In [8]:

```
a = 1 / sqrt(2) * basis(2, 0) + 1 / sqrt(2) * basis(2, 1)
state = tensor(a, basis(2, 0), basis(2, 0))
```

In [9]:

```
initial_measurement = Measurement("start", targets=[0])
initial_measurement.measurement_comp_basis(state)
```

Out[9]:

([Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[1.] [0.] [0.] [0.] [0.] [0.] [0.] [0.]], Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [1.] [0.] [0.] [0.]]], [0.4999999999999999, 0.4999999999999999])

`QubitCircuit.run()`

function which provided the initial state-vector (or density matrix) initiates one run on the circuit (including sampling any intermediate measurements) and providing the final results (any classical bits can also be explicitly set using the argument `cbits`

). The results are returned as a `Result`

object. The result states can be accessed through the `get_states()`

function where the argument `index=0`

specifies the first(only) result should be returned

In [10]:

```
state_final = teleportation.run(state)
print(state_final)
```

In [11]:

```
final_measurement = Measurement("start", targets=[2])
final_measurement.measurement_comp_basis(state_final)
```

Out[11]:

([Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [1.] [0.] [0.] [0.]], Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [0.] [1.] [0.] [0.]]], [0.4999999999999999, 0.4999999999999999])

In [12]:

```
state = tensor(basis(2, 1), basis(2, 0), basis(2, 0))
initial_measurement = Measurement("start", targets=[0])
initial_measurement.measurement_comp_basis(state)
```

Out[12]:

([None, Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [1.] [0.] [0.] [0.]]], [0.0, 1.0])

In [13]:

```
state_final = teleportation.run(state)
print(state_final)
```

In [14]:

```
final_measurement = Measurement("start", targets=[2])
final_measurement.measurement_comp_basis(state_final)
```

Out[14]:

([None, Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [1.] [0.] [0.] [0.] [0.]]], [0.0, 1.0])

**QubitCircuit.run_statistics()** feature which provides the opportunity to gather all the possible output states of the circuit along with their output probabilities. Again, the results are returned as a `Result`

object. The result states and respective probabilites can be accessed through the `get_results()`

function.

In [15]:

```
results = teleportation.run_statistics(state)
results.probabilities
```

Out[15]:

[0.24999999999999994, 0.24999999999999994, 0.24999999999999994, 0.24999999999999994]

In [16]:

```
results.final_states
```

Out[16]:

[Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [1.] [0.] [0.] [0.] [0.] [0.] [0.]], Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [1.] [0.] [0.] [0.] [0.]], Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [0.] [1.] [0.] [0.]], Quantum object: dims = [[2, 2, 2], [1, 1, 1]], shape = (8, 1), type = ket Qobj data = [[0.] [0.] [0.] [0.] [0.] [0.] [0.] [1.]]]

In [17]:

```
about()
```