Introductory tutorial
This tutorial will illustrate the basics of how to use qustop
.
This is a user guide for qustop
and is not meant to serve as an
introduction to quantum information. For introductory material on quantum
information, please consult “Quantum Information and Quantum Computation” by
Nielsen and Chuang or the freely available lecture notes “Introduction to
Quantum Computing” by
John Watrous.
More advanced tutorials can be found on the main documentation directory.
This tutorial assumes you have qustop
installed on your machine. If you
do not, please consult the getting started instructions.
States, ensembles, and measurements
Quantum states, and collections of those quantum states that form ensembles, are
the core building blocks of qustop
.
Quantum states
A quantum state is a density operator
where \(\mathbb{C}^d\) is a complex Euclidean space of dimension \(d\) and where \(\text{D}(\cdot)\) represents the set of density matrices, that is, the set of matrices that are positive semidefinite with trace equal to \(1\). We will typically represent complex Euclidean spaces using the scripted capital letters \(\mathcal{A}, \mathcal{B}, \mathcal{X}, \mathcal{Y}\), etc.
Consider the density matrix corresponding to one of the four Bell states
where
such that \(\mathcal{A} = \mathbb{C}^2\) and \(\mathcal{B} =
\mathbb{C}^2\). We can use qustop
to encode this state as follows.
import numpy as np
from qustop import State
# Define the |0> and |1> ket vectors.
q_0 = np.array([[1, 0]]).T
q_1 = np.array([[0, 1]]).T
# Define the respective dimensions of each complex Euclidean space.
dims = [2, 2]
# Define the Bell state vector.
psi_0 = 1/np.sqrt(2) * np.kron(q_0, q_0) + 1/np.sqrt(2) * np.kron(q_1, q_1)
# Define a `State` object corresponding to the Bell vector.
rho_0 = State(psi_0, dims)
Printing the rho_0
variable gives some further information about the
state.
>>> print(rho_0)
State:
dimensions = [2, 2],
spaces = ℂ^2 ⊗ ℂ^2,
labels = A_1 ⊗ B_2,
pure = True,
shape = (4, 4),
For instance, we see the shape
attribute gives information about the
size of the density matrix of the state. There is also information about the
subsystems along with which party the subsystems belong to (either Alice or
Bob), whether the state is pure, etc.
We can use the value
property of any State
object to obtain the
numpy
matrix representation of the quantum state
>>> print(rho_0.value)
[[0.5 0. 0. 0.5]
[0. 0. 0. 0. ]
[0. 0. 0. 0. ]
[0.5 0. 0. 0.5]]
We can also do things like take tensor products of State
objects.
>>> sigma_0 = rho_0.kron(rho_0)
>>> print(sigma_0)
State:
dimensions = [2, 2, 2, 2],
spaces = ℂ^2 ⊗ ℂ^2 ⊗ ℂ^2 ⊗ ℂ^2,
labels = A_1 ⊗ B_2 ⊗ A_3 ⊗ B_4,
pure = True,
shape = (16, 16),
It is sometimes convenient to swap the subsystems of a given state. For
instance, this example shows how we can swap the second and third subsystems of
the sigma_0
state.
>>> sigma_0.swap([2, 3])
>>> print(sigma_0)
State:
dimensions = [2, 2, 2, 2],
spaces = ℂ^2 ⊗ ℂ^2 ⊗ ℂ^2 ⊗ ℂ^2,
labels = A_1 ⊗ A_3 ⊗ B_2 ⊗ B_4,
pure = True,
shape = (16, 16),
Notice how the A_3
and B_2
subsystems are swapped.
Ensembles
An ensemble is a collection of \(N\) quantum states defined over some complex Euclidean space \(\mathcal{X}\) as
where \((p_1, \ldots, p_N)\) is a vector of probability values and where \(\rho_1, \ldots, \rho_N \in \text{D}(\mathcal{X})\) are quantum states.
Recall the four two-qubit Bell states
The corresponding density operators may be defined as
We can define the following ensemble consisting of the Bell states where the probability of selecting any one state from the ensemble is equal to \(1/4\):
In qustop
, we would define this ensemble like so
from toqito.states import bell
from qustop import State, Ensemble
# Construct the corresponding density matrices of the Bell states.
dims = [2, 2]
states = [
State(bell(0) * bell(0).conj().T, dims),
State(bell(1) * bell(1).conj().T, dims),
State(bell(2) * bell(2).conj().T, dims),
State(bell(3) * bell(3).conj().T, dims)
]
ensemble = Ensemble(states=states, probs=[1/4, 1/4, 1/4, 1/4])
Printing out any Ensemble
object gives us some information about the
contents:
>>> print(ensemble)
Ensemble:
num_states = 4,
states = ρ_0 ⊗ ρ_1 ⊗ ρ_2 ⊗ ρ_3,
is_mutually_orthogonal = True,
is_linearly_independent = True,
We can see certain pieces of information including how many states are contained in the ensemble, whether the states in the ensemble are all mutually orthogonal, linearly independent, etc.
We can access any of the states from the Ensemble
object using standard
array indexing notation. For instance, here is how we can access the first state
in the ensemble.
>>> print(ensemble[0])
State:
dimensions = [2, 2],
spaces = ℂ^2 ⊗ ℂ^2,
labels = A_1 ⊗ B_2,
pure = True,
shape = (4, 4),
We may also wish to apply some of the functions that we saw before for
State
objects onto the entire ensemble. For instance, here is an example
of how we can swap the first and second subsystems of each state in the
ensemble.
>>> ensemble.swap([1, 2])
>>> print(ensemble[0])
State:
dimensions = [2, 2],
spaces = ℂ^2 ⊗ ℂ^2,
labels = B_2 ⊗ A_1,
pure = True,
shape = (4, 4),
Measurements
A measurement is defined as a function
for some finite and nonempty set \(\Sigma\) and some complex Euclidean space \(\mathcal{X}\) satisfying the constraint that
There are many different classes of measurements.
Quantum state distinguishability
Given an ensemble of quantum states, we can consider the setting of quantum state distinguishability. This setting can be considered as an interaction between two parties–typically denoted as Alice and Bob.
A more in-depth description and tutorial on this setting in qustop
can
be found in:
More in-depth descriptions pertaining to quantum state distinguishability under positive, PPT, and separable measurements can be found in: