Quantum programming introduction with Qiskit

Guilherme Dobins
12 min readMar 10, 2022

--

If you just discovered the field of quantum computing, it is possible you saw a lot of material about the concept of the subject, or mostly about theory of what is possible to be done using the technology (and what is being done). However, considering you likely don’t have a quantum computer, you might feel it is still a distant technology, or something you cannot use yet. My goal here is to show you how one can start writing codes for quantum computing, as well as using a real quantum computer to run it.

First of all, even though the concepts I will present here are introductory, it would be really good if you had a basic idea of quantum computing, such as how a quantum state is represented, what are the most common quantum gates and how measurement works. If you don’t, you can check out my previous story, where I introduce said concepts. There are many other resources online as well, so you can search for specific material in case you need help with any of the topics presented here.

Installing Qiskit

Before talking about the codes, we need a platform in which we can write and run them. For this tutorial, I’ll be using qiskit, a Python library for quantum programming, and one of the most popular tools for quantum programming, in general. This library can be installed either locally or in an online environment, such as Google Colab. If your goal is simply to see quantum computing in action and you want to do it as quickly as possible, then I’d recommend using Colab, but installing Qiskit locally is pretty straightforward as well.

Installing Qiskit locally: In order to install Qiskit in your computer, you must have Python 3 already installed. Besides that, Qiskit is often used in notebooks, so you also need to install Jupyter. You can get both of them from Anaconda, so it is recommended to install it on your computer, but downloading Python and Jupyter by following the instructions on their websites is fine as well. After that, we can proceed to installing Qiskit itself. To do it, open your terminal and type the command according to your OS:

  • MAC/Windows: $ pip install qiskit;
  • Linux: $ pip install -U pip && pip install qiskit.

And then you just need to open a new Jupyter notebook and start using qiskit.

Installing Qiskit on Google colab: Considering Colab already has Python installed and it works as a notebook, the only thing you need to do is install Qiskit. In Colab, create a new python notebook, and then paste the command “$ pip install qiskit” in a cell, run that cell and wait for the installation to complete. After that, you are ready to start using Qiskit. If you are not familiar with Colab or Python notebooks, check out this introduction made by the people on TensorFlow.

With Qiskit installed, you can launch a notebook and start using the power of quantum computers. But one thing important mentioning is that, as you probably know, quantum computers are pretty rare, so to use them, you have to wait in a queue. In order to avoid it, it is a common practice to run your programs in a simulator, as they are a good approximation of the quantum computers you can use right now, considering the number of simulated qubits is pretty close to the number of real qubits on the available computers. Because of that, I will show you how to run your codes on a simulator first, and after that, how to run it on a real quantum computer. This way it will be possible to show their differences as well.

Running your first code

Now that we have somewhere to write and run our algorithm, we need the code itself. If you have some programming background, especially with high-level programming languages, such as Python, then you are used to variables, instructions and functions. Considering Qiskit is a Python library, it also uses these features to create the codes.

Now, it is important to explain what the “code” really means in a quantum program. In order to program any quantum algorithm, we have to make use of a circuit, which is built using qubits, quantum logic gates, responsible for making changes to the state of the qubits, and also classical bits, often used to read the measurements. So, when you think about programming a quantum code, what you will likely be doing is using the variables, instructions and functions available in the language you are using in order to assemble a circuit.

With that said, it is finally time to implement something. Let’s start with a simple circuit, so you can get comfortable with Qiskit. The first step is to set up our environment, by importing the necessary tools for our code.

from qiskit import QuantumCircuit, Aer
from qiskit.visualization import plot_histogram

These commands above simply import some useful functions we will be using next.

  • The QuantumCircuit function is responsible for letting us create an empty circuit, in which we will add qubits, bits, gates and/or measurements.
  • Aer helps us use simulators, and it is necessary when you don’t intend to run your code on a real computer.
  • The plot_histogram function is pretty important to see your results. This is because quantum mechanics are probabilistic, so, if you run your code only once, then there is a chance you won’t get the expected result (since a small probability of the unexpected outcome occurring still exists). To solve this problem, the code is executed many times, and you get the distribution of the results, which are correlated to the probabilities of the possible outcomes. The plot_histogram shows you this distribution.

Now, we can start to build our circuit.

qc = QuantumCircuit(1, 1)
qc.x(0)
qc.measure(0,0) # measures the 0 qubits into the 0 bits
qc.draw()
Output: Circuit 1
┌───┐┌─┐
q: ┤ X ├┤M├
└───┘└╥┘
c: 1/══════╩═
0

This is a really simple circuit. In fact, it can be understood without any quantum phenomena being presented.

  • The first line is where the circuit is created, and assigned to the variable “qc”. This circuit was created with the parameters (1,1), meaning I want the circuit to have 1 qubit (first argument), and also 1 classical bit (second argument). When circuits are created this way, all of the qubits are started on the |0> state.
  • After that, whenever you want to add a gate to the circuit, you can write something like “qc.gate(#qubit)”, with “gate” being the name of the quantum gate you want to apply, and “#qubit” being the number of the qubit in which the gate must be applied. In the example, the code qc.x(0) means I applied the X (NOT) gate to the qubit 0. It is important to note that the number of the qubit follows the standards of array positions, so the qubit 0 is the 1st qubit.
  • Then, a measurement operator is added to the circuit, and it maps the measurement of the qubit 0 (first argument) to the bit 0 (second argument). When you have multiple qubits and bits, it is common to write the measurements in a single line. To do that, instead of using numbers as arguments, you use lists of numbers, one list representing the qubits and the other one representing the classical bits. This following line shows an example of adding the measurement operator of 4 qubits into 4 classical bits.
qc.measure([0,1,2,3], [0,1,2,3]) 
  • Finally, the function .draw() was used to show us the circuit, as you can see in the output. If you look closely, the output is named Circuit 1, but that is just something I wrote to make the explanation clearer, and it is not something you will see when executing the code.

Considering there is nothing more to add to the circuit, we can predict what the results will be. As I said before, when you initialize a circuit, the qubits are in state |0>, and we applied a NOT to this qubit, which, in this case, takes the qubit to the |1> state. Then, we will measure this qubit, and a qubit being in the state |1> means it has 100% probability of being measured as 1.

To run this code, we need to set up the simulator, and then run the circuit in it. You can use the following commands to do that.

sim = Aer.get_backend('qasm_simulator')
result = sim.run(qc).result()
answer = result.get_counts()
plot_histogram(answer)

In this example, the variable “sim” represents the simulator, and with this variable, you just have to use the .run(circuit) command to execute your circuit, and after that, use the .result() function to get the outcomes. To finish our code, you can use the .get_counts() function to get the distribution of the outcomes, so you can plot it as a histogram.

Results of Circuit 1

And as you can see, we got 1 as the result, as expected.

Before I show you how to run codes on a real quantum computer, it would be nice to take a look at a slightly more advanced circuit, one that uses actual quantum phenomena to determine the results.

The structure of the code will be similar to the previous one, so the setup and execution of the code are basically the same, with the difference being in the actual circuit. The goal of this new circuit is to analyze the outcomes based on the circuit and the quantum gates on it, and not to present any more code, since it is pretty much the same as the previous one.

qc = QuantumCircuit(2, 2)
qc.h(0)
qc.cx(0,1)
qc.barrier()#Used to split parts of the circuit
qc.measure([0,1],[0,1]) # measures the 0,1 qubits into the 0,1 bits
qc.draw()
Output: Circuit 2
┌───┐ ░ ┌─┐
q_0: ┤ H ├──■───░─┤M├───
└───┘┌─┴─┐ ░ └╥┘┌─┐
q_1: ─────┤ X ├─░──╫─┤M├
└───┘ ░ ║ └╥┘
c: 2/══════════════╩══╩═
0 1

What makes this circuit more complex than the previous one is the fact that, instead of having a NOT gate, there is a Hadamard and a CNOT (controlled not) gate, which means that, at some point, the system will be in a superposition, and the qubits will be entangled. You will see the effect it has on the results after we run our code.

As we did before, we can now preview the results by looking at the circuit. The system starts in the state |00>. After the Hadamard gate, the first qubit goes to the state |+>, taking the system to the state |+0>. What this means is this system is in a superposition of states |00> and |10>.
After that, we have the CNOT gate. Just to refresh your mind, this gate uses the control qubit (in this case, the first qubit) to determine if it will act on the target qubit (the second one). More specifically, if the control qubit is in state |0>, then nothing happens to the target, but if the control is in state |1>, then a NOT is applied to the target.
If we look at our system, you can notice that the control qubit is in a superposition of two states, so the CNOT will act on the target based on the superposition. What this means is that, in the case where the control qubit is in state |0>, nothing will happen to the target and the resulting state will still be |00>, but for the case where the control qubit is in the |1> state, the target will be flipped, and state will change from |10> to |11>. It is important to notice that both of these things will happen at the same time, so the actual state after the CNOT will be a superposition of |00> and |11>.

Despite the system being in both states at the same time, we know for sure that it must collapse to one of these states when we measure the system, and, in that case, we should get the answer “00” 50% of the time, and “11” the other 50%. To check if this is right, let’s run the code using the same process as we did in the first circuit.

sim = Aer.get_backend('qasm_simulator')
result = sim.run(qc).result()
answer = result.get_counts()
plot_histogram(answer)

Back to the solution, on the last line, the counts are plotted, and you can see they are close to the expected values.

Results of circuit 2 on the simulator

Hopefully, you are now more familiar with the concepts of quantum computing, and mostly with the programming of a quantum code. Despite the examples presented being pretty basic, most algorithms will be based on these simple instructions, with the difference being the algorithms will use the quantum mechanics you just saw in a more sophisticated way, so that the circuits created are able to solve problems.

However, all of the stuff I showed you was executed using a simulator, and this does not sound as exciting as running your code on a real quantum computer. Because of that, I want to finish this story by showing you how to run a code on a real quantum computer, more specifically, the ones available from IBM. It should also be useful to demonstrate some of the differences between ideal models and the reality of this technology.

Running the code on a real quantum computer:

Assuming no one wants to have the need to program two different codes, one for a real computer and one for the simulator, the first important feature is that most of the code, especially the building of the circuit, are done in the same way, no matter where you intend to execute said circuit. With that said, the only real difference we need to make in our code is that, instead of setting up the simulator, we must set up our environment to allow us to connect to the available computers by IBM.

Setting up the environment: Before you have access to their computers, it is necessary to create an IBM account. After that, go to “account settings” and copy your API token, since it is necessary to complete the configuration. Now, you can start to write your code.

from qiskit import IBMQ, executeIBMQ.save_account("*api_token*")
IBMQ.load_account()
provider = IBMQ.get_provider("ibm-q")

Checking for available computers: Now that you have access to the computers, you must choose the one you want to use. For that, it is relevant to look at the queue in each computer, so you can choose the least busy one, and also look at the available qubits in each computer, so you don’t choose one that is too small for your purposes.

A nice way to look at the available computers is by using this code, provided by sentdex, who has a nice series of videos introducing quantum computing on his youtube channel.

for backend in provider.backends():
try:
qubit_count = len(backend.properties().qubits)
except:
qubit_count = "simulated"
print(f"{backend.name()} has {backend.status().pending_jobs} queued and {qubit_count} qubits")

This will show you a list of all the quantum computers you can access, as well as their queue and number of qubits. Looking at this list, choose the one that better fits your needs.

Running your code: To use the chosen computer to run your code, you can use the lines above, which are an adaptation of the code used for the simulator. As you can see, the structure is still really similar, and you just need to select a different backend. Notice that I am using the “execute” command here, and it can also be used for a simulator. I just wanted to show that there are different ways to perform some actions in Qiskit, and you can pick the one you prefer.

backend = provider.get_backend("*chosen_computer*")
job = execute(qc, backend=backend, shots=500)
result = job.result()
answer = result.get_counts()
plot_histogram(answer)

If you replace the simulator configuration from the last circuit with the codes above, then you can run the circuit and see their results. Just be aware that this can take several minutes, and that is the biggest reason why we often use simulators. After the results are done, this is the distribution of the answers.

Results of Circuit 2 on a real quantum computer

It is clear that there are some differences between this result and the simulated one. The biggest disparity is that, in this result, there are four possible outcomes, and in the previous one there were only two, matching our predictions. You might feel tempted to think the prediction was wrong and the real computer is more reliable, but that was not the case. What happened here is that the real world is not ideal. In order for a quantum computer to work properly, many conditions must be met, and this is really hard to do in real life. Because of that, some “noise” affects the execution of the code, resulting in wrong results. It is nice to point out that solving these types of problems is an important field of study for quantum computing, and it is essential in order to demonstrate quantum supremacy in the near future.

Despite the results not being the ideal ones, it is still a really nice way to experiment with real quantum computers, so you can get a better idea about the current state of their evolution. Also, I believe it is pretty awesome that we can have access to one of the rarest technologies in the world from home, and I hope this tutorial makes you feel more comfortable experimenting with it and more excited to learn!

--

--