##### Quantum Computing and Quil for Python Programmers - Part 1

# Quil For Python Programmers

## Part 1: Intro to Quantum and Quil

### What is Quil?

Quil stands for **Qu**antum **I**nstruction **L**anguage and is an instruction set for quantum computers. Think of it as like Assembly, but for quantum computers! Now, you may be wondering why I'm going to make this tutorial for *Python* programmers and not Assembly programmers. Well, quantum computing is largely in the fields involving computation, not really so much just having low-level control of a device, so most Python programmers would find greater use of Quil and overall quantum technology than most x86/64 programmers would.

Now, Quil isn't the only of its type. There are also other quantum languages, the most notable of which are QASM and Qiskit (made by IBM). However, Quil is the only one on Repl.it currently. You can make a Quil repl here.

### Quantum Physics Basics

So, quantum computing highly leverages quantum mechanics. Though, we just need to really talk about superposition. Superposition is the idea that a quantum particle can exist in multiple states at one, with different probabilities of each state. The superposition, however, is lost when you measure it and then it becomes an actual value. Quantum computing uses these probabilities rather than the values in pretty much all cases other than conditional statements, although even this may change in the not so distant future!

### Quil Basics - Defining a Gate

*This part of the tutorial largely points to https://repl.it/talk/share/Quantum-RNG/60110 which also happens to be the first Quil Repl.it post ever if you would like to check it out!*

So, in quantum computing, quantum gates are defined by matrices. I'm not personally too familiar with linear algebra, so I'll have to explain this in a later tutorial. However, the Hadamard gate, a gate that produces a 50-50 random decision, has a matrix of `[[sqrt(2)/2, sqrt(2)/2], [sqrt(2)/2, -sqrt(2)/2]]`

. Now, many gates are predefined in Quil, but you can also define your own! Let's look at how to define the Hadamard gate.

```
DEFGATE HADAMARD:
sqrt(2)/2, sqrt(2)/2
sqrt(2)/2, -sqrt(2)/2
```

*Note: You have to double-indent or it won't work.*

So, as you can see here, we have the `DEFINE`

keyword which says we are defining a gate. Then, we have the name of the gate, `HADAMARD`

, and a `:`

to show we are starting the matrix definition. Then, we include the matrix for the Hadamard gate. Now, you can call this by using `HADAMARD <qubit>`

, for example, `HADAMARD 1`

which will apply the Hadamard gate to qubit 1. However, the Hadamard gate is also built in, so you could just use `H 1`

instead as `H`

is the built-in version.

### Quil Basics - Random Number Generator

Now, we will talk about how to create a random number generator in Quil!

First off, you can redefine the Hadamard gate if you would like or you can just use `H`

instead.

Then, you need to apply the Hadamard gate to all 4 qubits (we are doing a random number 0-15) like this:

```
H 0
H 1
H 2
H 3
```

Now, this puts all 4 qubits in a superposition between 0 and 1. Now, we need to measure the superposition. For this, we use the `MEASURE`

function.

```
MEASURE 0 [0]
MEASURE 1 [1]
MEASURE 2 [2]
MEASURE 3 [3]
```

This takes the qubits out of superposition so a number can be displayed. However, note the `[0]`

for example. That means that you are putting the value into classical bit 0. Of course, Quil will return the qubits, not the classical bits, but this is good to know, especially for conditionals as we will get to later on.

Now, this will print a number 0000 to 1111 or 0 to 15. It is in binary and there is no "print" function or anything in Quil as it is just for computation currently. However, real quantum processors can aid computers in high-powered computations, although we don't have an actual quantum computer yet.

### Quil Logic and Control

Now, you can't create a good program without logic and control. If you just have random numbers, you just have a random number generator and can't do anything with it. Also, this is where the Python comes in!

First off, we need to talk about a few new functions:

`X`

`SWAP`

`CNOT`

`CCNOT`

`X`

The quantum X gate simply flips a qubit. So, if it is 1, you get 0 or if it is 0, you get 1. This can be represented with the following Python code. I'll also include the translation for the Hadamard gate and some basic set-up stuff...

```
from random import randint as r # We need to use the random module.
qubits = [0, 0, 0] # Define 3 qubits for our program
bits = [0, 0, 0, 0, 0] # Define 5 bits for our program
# Hadamard gate
def H(n):
qubits[n] = r(0, 1) # Random 0 to 1
def X(n):
qubits[n] = 1 - qubits[n]
```

`SWAP`

The `SWAP`

command simply swaps two qubits! This can be represented in Python as

```
def SWAP(a, b):
temp = qubits[a]
qubits[a] = qubits[b]
qubits[b] = temp
```

`CNOT`

The `CNOT`

function is a conditional form of the `X`

gate. It is also in some instruction sets referred to as `CX`

. If the first qubit is 1, it will invert the second qubit. For example, `CNOT 0 1`

will flip qubit 1 if qubit 0 is 1. We do not need a Python equivalent since we will not use that in our program.

`CCNOT`

The `CCNOT`

function is a conditional that only inverts a qubit if *two* conditions are true. It is a lot like a classical `AND`

gate. We can represent this as

```
def CCNOT(a, b, c):
if qubits[a] == 1 and qubits[b] == 1:
X(c)
```

Now, we also need to define `MEASURE`

and add a way to read a bit as a boolean, so we add this:

```
def MEASURE(a, b):
bits[b] = qubits[a]
def bit(n):
return bits[n] == 1
```

#### Changing the Probabilities

Using these new gates and functions, we will create another random number generator, but make it instead a 25% chance of a 1 and 75% chance of a 0.

First, we know that `P(A and B) = 25%`

if `P(A) = 50%`

and `P(B) = 50%`

. We know that the Hadamard gate satisfies this, so we will make it return 1 if two Hadamard gates are true. First, we need to create these Hadamard gates.

```
H 0
H 1
```

Now, if both of these are 1, we want qubit 2 to be 1.

`CCNOT 0 1 2`

And we want to move qubit 2 to 0 so that we get 1, not 4, for the 25% chance.

`SWAP 0 2`

Now, we just need to get qubits 1 and 2 to 0 and measure.

In many versions of Quil, there is a `RESET`

function where you can reset a qubit to 0. However, Repl.it doesn't have that, so we have to make it ourselves!

```
MEASURE 1 [3]
JUMP-WHEN @one [3]
X 1
LABEL @one
X 1
```

First, this measures qubit 1 and puts it into bit 3. Then, if 3 is true, it will jump to the label `@one`

and only undergo 1 `X`

gate. However, if it is not 1, it will do two `X`

gates and these will cancel each other out. This guarantees that qubit 1 will be 0 afterwards.

We can also do the same with qubit 2!

```
MEASURE 2 [4]
JUMP-WHEN @two [4]
X 2
LABEL @two
X 2
```

And lastly, we have to measure qubit 0.

`MEASURE 0 [0]`

This will produce either `(1+0j)|000>`

or `(1+0j)|001>`

. This means, that there is a 100% probability of 0 or 1 respectively.

### The Final Programs

Quil Version:

```
H 0
H 1
CCNOT 0 1 2
SWAP 0 2
MEASURE 1 [3]
JUMP-WHEN @one [3]
X 1
LABEL @one
X 1
MEASURE 2 [4]
JUMP-WHEN @two [4]
X 2
LABEL @two
X 2
MEASURE 0 [0]
```

Repl: https://repl.it/@AmazingMech2418/1-in-4-Quantum

Python Version:

```
from random import randint as r
qubits = [0, 0, 0]
bits = [0, 0, 0, 0, 0]
def H(n):
qubits[n] = r(0, 1)
def SWAP(a, b):
temp = qubits[a]
qubits[a] = qubits[b]
qubits[b] = temp
def X(n):
qubits[n] = 1 - qubits[n]
def CCNOT(a, b, c):
if qubits[a] == 1 and qubits[b] == 1:
X(c)
def MEASURE(a, b):
bits[b] = qubits[a]
def bit(n):
return bits[n] == 1
H(0)
H(1)
CCNOT(0, 1, 2)
SWAP(0, 2)
MEASURE(1, 3)
if not bit(3):
X(1)
X(1)
MEASURE(2, 4)
if not bit(4):
X(2)
X(2)
MEASURE(0, 0)
qubits.reverse()
print("".join(str(x) for x in qubits))
```

Repl: https://repl.it/@AmazingMech2418/Quil-To-Python-1-in-4

## Closing Notes

Thank you for reading this tutorial! If you have any questions, please leave a comment. Also, @amasad, would it be possible to update Quil on Repl.it and/or add QASM? Repl.it Quil is very stripped down and doesn't have many features, as we can even see with the lack of the `RESET`

function.

What do the (1+0j)|000> stuff mean?

@SwaagatB Those are the probabilities and values. When it is in the form of a|b>, a^2 is the probability that b will be the result. In this case, a=(1+0j) and b=000. j represents iota or the square root of -1 (often displayed as i instead of j) and (1+0j)^2 is just 1, so there is a 100% chance for that runtime for the result to be 000. Of course, this specific program uses measuring though, so it could be other values, but arrives at a raw value rather than a series of values and probabilities.

@AmazingMech2418 Thanks!

@SwaagatB You're welcome!

Huh, I think even LOLCODE makes more sense xD. (Not bullying your teaching, just the Lang) Maybe quantum stuff isn’t for me lmao.

@RayhanADev Yeah. LOL! Quantum computing isn't really the easiest ever...

Uh so how is it being run?

@realTronsi What do you mean? It's running a Quil simulator. It isn't using a real quantum computer. LOL!

@AmazingMech2418 yes of course, but perfect quantum computers are extremely difficult to simulate, how deep does it go

@realTronsi I'm not exactly sure. It uses PyQuil which is created by Rigetti Computing.

pog