How to design quantum circuits with Qiskit — Part 1

Matheus Cammarosano Hidalgo
6 min readJul 31, 2023

--

A basic tutorial on designing very simple quantum circuits in Qiskit

Introduction

In a previous post I described the beginning of my learning path in Quantum Machine Learning (QML) and how I decided to use Qiskit. I think this package is the best way to start because it is simple to use and to design basic quantum circuits, visualizing and simultaing them.

Nowadays I’m using Pennylanne for QML problems, mostly because Qiskit deprecated its ML tools, but I still think Qiskit is the best package to start learning and understanding basic quantum computing basic properties, because it is easier than Pennylane to design, simulate and visualize results.

In this post you will learn to design simple quantum circuits showing basic quantum computing properties.

What do you need to start?

I recommend you to install Anaconda with Python and after that install Qiskit (you can type !pip install qiskit in your notebook, simple as that), since we will be using basic functions, the version is not so important, but here I’m using 0.43.1. I’m also using Jupyter Notebook, since I can test segments of code separately. Matplotlib and Numpy are also a good packages to install, since we are using them as well.

If you prefer other engine than Anaconda, feel free to use it, the most important thing is having Python and Qiskit.

All of our circuits will follow this structure:

  1. Setting the quantity of qubits
  2. Quantum circuit performing transformations in our qubit
  3. Measurements

And our codes will have the following steps:

  1. Circuit design
  2. View our circuit
  3. Simulate our circuit
  4. View results

Circuit 1a: Setting a qubit and measuring it

In our first circuit, we are setting a quantum circuit with one qubit and directly measuring it with a classic bit.

Since quantum circuits are probabilistic, we are using an embedded simulator and running 1000 shots to determine the results.

The code that performs these tasks is:

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

backend = Aer.get_backend('qasm_simulator')

qc = QuantumCircuit(1, 1)

qc.measure(0, 0)

qc.draw('mpl')

job = backend.run(qc, shots=1000)

result = job.result()

counts = result.get_counts(qc)
plot_histogram(counts)

This circuit is actually really simple and very not useful for practical purposes. Firstly we import the dependencies and after that we choose our simulator. In here I chose qasm simulator. But for this circuit it could be any other simulator.

Then we create our circuit with this command: qc = QuantumCircuit(1, 1). Here we create a circuit with one qubit (first argument) and one classic bit. And with: qc.measure(0, 0) we are measuring our first qubit into our first classic bit.

And after that we draw our circuit, which results into:

Figure 1 — Quantum circuit 1a

Where q is our qubit and c is our classic bit. This draw represents our qubit being measured into the classic bit. Lastly we set our simulator to 1000 shots, in this case the amount of shots is irrelevant because our result will be deterministic. However, in other cases this quantity must satisfy a compromise between statistic significance and compution time. Too few shots might compromise statistical quality in results and too many might take a long time to simulate.

And we finally plot the results:

Figure 2— Results of circuit 1a simulation

In this circuit, all shots results were 0, because we didn’t manipulate our qubit, so, as default, qubit is set to 0. But how can we modify our qubit?

Circuit 1b — Setting a qubit to 1 and measuring it

This circuit will be basically the same as the previous one, but now we are changing our qubit from 0 to 1:

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

backend = Aer.get_backend('qasm_simulator')

qc = QuantumCircuit(1, 1)

qc.x(0)

qc.measure(0, 0)

qc.draw('mpl')

job = backend.run(qc, shots=1000)

result = job.result()

counts = result.get_counts(qc)
plot_histogram(counts)

This is almost the same code as the last one, but now we inserted an X-gate before measuring. The X-gate is analogous to the NOT gate in classical computing. I don’t like to say that it is the equivalent because the paradigm is different, but the idea is similar, the X-gate inverts the quantum states in a 1 qubit quantum system.

Our quantum circuit here is:

Figure 3 — Quantum circuit 1b

And our result is:

Figure 4— Results of circuit 1b simulation

As we expected, our result here is also deterministic and 1.

Circuit 2a- Quantum superposition with 1 qubit

In this example, we are setting a qubit into a superposition state using this code:

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

import numpy as np

backend = Aer.get_backend('qasm_simulator')

qc = QuantumCircuit(1, 1)

qc.ry(np.pi/3, 0)

qc.measure(0, 0)

qc.draw('mpl')

job = backend.run(qc, shots=1000)

result = job.result()

counts = result.get_counts(qc)
plot_histogram(counts)

Now the difference is that we inserted a RY-Gate, which rotates our qubit around the Y-axis of the Bloch Sphere:

Figure 5 — Bloch Sphere

So, in our circuit, we are rotating pi/3 radians (60°)from |0>, which is our default state, leading our system into a superposition state, somewhere between the north (|0>) and south (|1>) pole of the sphere.

Our circuit has the following design:

Figure 6— Quantum circuit 2a

And this results after 1000 shots:

Figure 7— Results of circuit 2a simulation with 1000 shots

Now we have 758 simulations resulting in 0 and 242 resulting in 1. So, we rotated our qubit in 60° around the Y-axis and now our probability of having the state 0 is sin²(60°)=3/4 and having 1 is cos²(60°) =1/4, which is very close to our simulation results.

But what happens if we reduce the quantity of shots to 10?

Figure 8— Results of circuit 2a simulation with 10 shots

Our amount of samples won’t be representative and our results might not be so close from the real probabilities. So, when we are running quantum circuits we need to know that if we reduce the number of shots we can lose accuracy and if we increase this quantity computation time will also increase.

But now I raise the question: what is the effect of an X-Gate over a system in superposition?

Circuit 2b- Quantum superposition with 1 qubit and X-Gate

Now we have the same code as circuit 2a, but adding an X-Gate before measurement:

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

import numpy as np

backend = Aer.get_backend('qasm_simulator')

qc = QuantumCircuit(1, 1)

qc.ry(np.pi/3, 0)
qc.x(0)

qc.measure(0, 0)

qc.draw('mpl')

job = backend.run(qc, shots=1000)

result = job.result()

counts = result.get_counts(qc)
plot_histogram(counts)

We have the following drawing of the circuit:

Figure 9 — Quantum circuit 2b

With these results for 1000 simulations:

Figure 10— Results of circuit 2b simulation with 1000 shots

Note that compared to circuit 2a, the X-Gate inverted the probabilities! Thereby, in quantum superposition the X-Gate really inverts quantum states.

Conclusions

Here we learned the very basic of designing quantum circuits with Qiskit focusing in 1 qubit systems. Note that even introducing some basic concepts of quantum computing, here I am focusing in practice, not theory . So, many concepts were not introduced, such as the Bloch Sphere is a complex vector space, so when we rotate our qubit around Y-axis, our quantum states is a complex number whose norm is the probability of being 0 or 1. Therefore, I encourage you to study quantum computing and QML theoretical topics.

In the next posts I will design circuits with more than one qubit and I will be gradually raising circuit complexity.

--

--

Responses (3)