# Getting started with Intel Quantum Simulator: Examples¶

Tutorial on the basic use of Intel QS through its Python interface: Two examples are provided.

**NOTE:** Currently, the Python implementation only allows for single-core execution and does not take advantages of the MPI protocol. However the user can familiarize with the same functionalities available in the distributed implementation (only C++ at the moment) and the transition should be relatively straighforward since all methods maintain name and effect.

## Import Intel QS library¶

Let’s start by importing the Python library with the class and methods defined in the C++ implementation.

```
[2]:
```

```
# Import the Python library with the C++ class and methods of Intel Quantum Simulator.
# If the library is not contained in the same folder of this notebook, its path has to be added.
import sys
sys.path.insert(0, '../lib_python')
import intelqs as simulator
# Import NumPy library with Intel specialization.
import numpy as np
from numpy import random_intel
# Import graphical library for plots.
import matplotlib.pyplot as plt
```

## Example 1¶

Create the state of a quantum register, having \(N>3\) qubits.

The state is initialized as a computational basis state (using the keyword “base”) corresponding to the index 0.

The index corresponds to a \(N\)-bit integer in decimal representation. With \(N\) qubits there are \(2^N\) indices, from 0 to \(2^{N-1}\).

```
[3]:
```

```
# Allocate memory for the quantum register's state and initialize it to |000...0>.
num_qubits = 4;
if num_qubits<3:
num_qubits = 4;
psi1 = simulator.QubitRegister(num_qubits, "base", 0, 0);
```

Let us apply a X Pauli gate on qubit 0, effectively flipping it from |0> to |1>, followed by the Hadamard gate on all other qubits.

```
[4]:
```

```
# Let us apply a X Pauli gate on qubit 0, effectively flipping it from |0> to |1>.
psi1.ApplyPauliX(0);
# Let us apply an Hadamard gate on all other qubits.
for q in range(1,num_qubits):
psi1.ApplyHadamard(q);
```

In addition to one-qubit gates, universal quantum computation can be achieved via 2-qubit entangling gates. For example, we now apply a CNOT between qubit 2 (here the control qubit) and qubit 1 (target qubit).

```
[5]:
```

```
# Two qubit gates are applied in a similar way. For example, a C-NOT between qubit 2 (control qubit) and qubit 1 (target qubit):
control = 2;
target = 1;
psi1.ApplyCPauliX( control , target );
```

To extract information from the quantum register, one can obtain the probability of measuring a certain qubit in the computational basis and obtaining the outcome “1” (meaning that the state is in |1>). In this example we measure qubit 1. Once the probability is known, one can draw a random number to simulate the stochastic outcome of the measurement and collapse the wavefunction accordingly.

```
[7]:
```

```
# Compute the probability of qubit 1 being in state |1>.
measured_qubit = 1;
prob = psi1.GetProbability( measured_qubit );
print("Probability that qubit {}, if measured, is in state |1> = {}\n".format(measured_qubit, prob));
# Draw random number in [0,1)
r = np.random.rand()
if r < prob:
# Collapse the wavefunction according to qubit 1 being in |1>.
print("Simulated outcome is 1. Collapse the function accordingly.")
psi1.CollapseQubit(measured_qubit,True);
else:
# Collapse the wavefunction according to qubit 1 being in |0>
print("Simulated outcome is 0. Collapse the function accordingly.")
psi1.CollapseQubit(measured_qubit,False);
# In both cases one needs to re-normalize the wavefunction:
psi1.Normalize();
```

```
Probability that qubit 1, if measured, is in state |1> = 0.0
Simulated outcome is 0. Collapse the function accordingly.
```

## Example 2¶

Create the state of a quantum register, having \(N>3\) qubits.

The state is initialized as a random state (using the keyword “rand”):

This requires a random number generator (RNG), that we initialize just before the second register. Notice that ‘777’ plays the role of the seed to initialize the RNG.

```
[8]:
```

```
num_qubits = 4;
if num_qubits<3:
num_qubits = 4;
psi2 = simulator.QubitRegister(num_qubits, "rand", 777, 0);
```

Let us apply one- and two-qubit gates as in the previous exmaple.

```
[9]:
```

```
# Let us apply a X Pauli gate on qubit 0, effectively flipping it from |0> to |1>.
psi2.ApplyPauliX(0);
# Let us apply an Hadamard gate on all other qubits.
for q in range(1,num_qubits):
psi2.ApplyHadamard(q);
```

One can define an arbitrary single-qubit gate and apply it to the chosen qubit.

In addition one can apply a custom one-qubit gate conditionally on the state of a control qubit.

```
[10]:
```

```
# Define an arbitrary single qubit gate and apply it to the chosen qubit.
# The quantum gate G is given by a 2x2 unitary matrix, here using a bi-dimensional NumPy array.
G = np.zeros((2,2),dtype=np.complex_);
G[0,0] = 0.592056606032915 + 0.459533060553574j;
G[0,1] = -0.314948020757856 - 0.582328159830658j;
G[1,0] = 0.658235557641767 + 0.070882241549507j;
G[1,1] = 0.649564427121402 + 0.373855203932477j;
qubit = 0;
psi2.Apply1QubitGate(qubit,G);
# It is also possible to apply the arbitrary gate specified by G controlled on the state of another qubit.
# G is applied conditioned on the control qubit being in |1>.
control = 1;
target = 2;
psi2.ApplyControlled1QubitGate( control, target, G);
# Notice that this output is directed to the terminal and not re-directed to the iPython notebook.
psi2.Print("After all gates.")
```

```
<<the output has been redirected to the terminal>>
```

To extract information from the quantum register, one can obtain the expectation value of Pauli strings.

For example, consider the Pauli string given by:

Such observable is defined by: - the position of the non-trivial Pauli matrices, in this case {0,2,3} - the corresponding Pauli matrices (X=1, Y=2, Z=3).

To facilitate the verification of the expectation value, we reinitialize the quantum state to |+-01>.

We also consider the Pauli staing

.

```
[12]:
```

```
# Prepare the state |+-01>
index = 2+8;
psi2.Initialize("base",index);
# Notice that GetProbability() does not change the state.
for qubit in range(0,num_qubits):
prob = psi2.GetProbability( qubit );
print("Probability that qubit {}, if measured, is in state |1> = {}\n".format(qubit, prob));
psi2.ApplyHadamard(0);
psi2.ApplyHadamard(1);
# The Pauli string given by: X_0 . id_1 . Z_2 . Y_3
# Such observable is defined by the position of the non-trivial Pauli matrices:
qubits_to_be_measured = [0,2,3]
# And by the corresponding Pauli matrices (X=1, Y=2, Z=3)
observables = [1,3,2]
# The expectation value <psi2|X_0.id_1.Z_2.Y_3|psi2> is obtained via:
average = psi2.ExpectationValue(qubits_to_be_measured, observables, 1.);
print("Expectation value <+-01|X_0.id_1.Z_2.Y_3|+-01> = {}\n".format(average));
# The expectation value <psi2|X_0.id_1.Z_2.Y_3|psi2> is obtained via:
qubits_to_be_measured = [0,2,3]
observables = [1,3,3]
average = psi2.ExpectationValue(qubits_to_be_measured, observables, 1.);
print("Expectation value <+-01|X_0.id_1.Z_2.Z_3|+-01> = {}\n".format(average));
# Trivial expectation:
average = psi2.ExpectationValue([0],[1], 1.);
print("Expectation value <+-01|X_0|+-01> = {}\n".format(average));
# The expectation value <psi2|X_0.id_1.id_2.Z_3|psi2> is obtained via:
average = psi2.ExpectationValue([0,3],[1,3], 1.);
print("Expectation value <+-01|X_0.Z_3|+-01> = {}\n".format(average));
```

```
Probability that qubit 0, if measured, is in state |1> = 0.0
Probability that qubit 1, if measured, is in state |1> = 1.0
Probability that qubit 2, if measured, is in state |1> = 0.0
Probability that qubit 3, if measured, is in state |1> = 1.0
Expectation value <+-01|X_0.id_1.Z_2.Y_3|+-01> = 0.0
Expectation value <+-01|X_0.id_1.Z_2.Z_3|+-01> = -0.9999999999999989
Expectation value <+-01|X_0|+-01> = 1.0
Expectation value <+-01|X_0.Z_3|+-01> = -1.0000000000000004
```

```
[13]:
```

```
# Prepare the state |+-01>
index = 2+8;
psi2.Initialize("base",index);
# Notice that GetProbability() does not change the state.
for qubit in range(0,num_qubits):
prob = psi2.GetProbability( qubit );
print("Probability that qubit {}, if measured, is in state |1> = {}\n".format(qubit, prob));
psi2.ApplyHadamard(0);
psi2.ApplyHadamard(1);
# The Pauli string given by: X_0 . id_1 . Z_2 . Y_3
# Such observable is defined by the position of the non-trivial Pauli matrices:
qubits_to_be_measured = [0,2,3]
# And by the corresponding Pauli matrices (X=1, Y=2, Z=3)
observables = [1,3,2]
# The expectation value <psi2|X_0.id_1.Z_2.Y_3|psi2> is obtained via:
average = psi2.ExpectationValue(qubits_to_be_measured, observables, 1.);
print("Expectation value <+-01|X_0.id_1.Z_2.Y_3|+-01> = {}\n".format(average));
# The expectation value <psi2|X_0.id_1.Z_2.Y_3|psi2> is obtained via:
qubits_to_be_measured = [0,2,3]
observables = [1,3,3]
average = psi2.ExpectationValue(qubits_to_be_measured, observables, 1.);
print("Expectation value <+-01|X_0.id_1.Z_2.Z_3|+-01> = {}\n".format(average));
```

```
Probability that qubit 0, if measured, is in state |1> = 0.0
Probability that qubit 1, if measured, is in state |1> = 1.0
Probability that qubit 2, if measured, is in state |1> = 0.0
Probability that qubit 3, if measured, is in state |1> = 1.0
Expectation value <+-01|X_0.id_1.Z_2.Y_3|+-01> = 0.0
Expectation value <+-01|X_0.id_1.Z_2.Z_3|+-01> = -0.9999999999999989
```

```
[14]:
```

```
# Extra expectation values.
# Prepare the state |+-01>
index = 2+8;
psi2.Initialize("base",index);
psi2.ApplyHadamard(0);
psi2.ApplyHadamard(1);
# The expectation value of X_0:
average = psi2.ExpectationValue([0],[1], 1.);
print("Expectation value <+-01|X_0|+-01> = {}\n".format(average));
# The expectation value of X_0.Z_3:
average = psi2.ExpectationValue([0,3],[1,3], 1.);
print("Expectation value <+-01|X_0.Z_3|+-01> = {}\n".format(average));
# The expectation value of X_0.Z_2:
average = psi2.ExpectationValue([0,2],[1,3], 1.);
print("Expectation value <+-01|X_0.Z_2|+-01> = {}\n".format(average));
# The expectation value of X_1.Z_2:
average = psi2.ExpectationValue([1,2],[1,3], 1.);
print("Expectation value <+-01|X_1.Z_2|+-01> = {}\n".format(average));
```

```
Expectation value <+-01|X_0|+-01> = 1.0
Expectation value <+-01|X_0.Z_3|+-01> = -1.0000000000000002
Expectation value <+-01|X_0.Z_2|+-01> = 0.999999999999998
Expectation value <+-01|X_1.Z_2|+-01> = -1.0000000000000002
```

### END |

```
[ ]:
```

```
```