Quantum Teleportation: A Step-by-Step Guide

Designing quantum circuits may seem a challenging task, but the longer one does it, the easier it gets with another approach. However, there is one thing that remains a problem regardless of how experienced you are with quantum computing – moving a state from one qubit to another. 

In classical computing, you can simply read the result of your computations mid-air, copy it to another set of bits, and carry on like nothing happened. It is, physically, impossible to do in quantum computing, though. A theorem, known as the No-Cloning Theorem, explains why.

The No-Cloning Theorem is a fundamental principle in quantum mechanics, which states that it is impossible to create an identical copy of an arbitrary unknown quantum state. In simpler terms, you cannot duplicate an unmeasured qubit like you would with classical bits. I will save you the precise math that underpins it. What is important to remember, though, is that it is related to the destructive nature of the READ operation in QPUs. One cannot copy without reading what is to be copied in the first place. And reading a QPU result inevitably destroys any quantum state that was there, leaving only the classical result in the process.

Fortunately, a protocol exists that allows us to “move” an arbitrary quantum state from one qubit to another without destroying it. It is called quantum teleportation.

What the Teleportation Actually Means

No, unfortunately we will not feel like Spock from Star Trek. Nor will our qubits. Quantum teleportation is actually quite a misleading term. It does not instantly move matter from one place to another. It does not even do it with any information we may wish to transfer. It is much more grounded.

Quantum teleportation is a protocol that allows a sender (let her be Alice) to transmit a qubit to a receiver (let him be Bob) using a shared entangled quantum state and two bits of classical communication.

The protocol assumes Alice and Bob share an e-bit in the state |𝜙+⟩. The e-bit (entangled bit) in quantum computing refers to a quantum state that is shared between two parties and exhibits correlations that cannot be explained by classical physics. The state of an e-bit is represented in one of the Bell states. This shared state is essential for various quantum information processing tasks, including, unsurprisingly, quantum teleportation.

The e-bit could have been prepared in the past or through a third party or complex distributed process. Either way, how they both obtain the Bell state is of no concern to the protocol.

In addition to her part of the e-bit, Alice possesses a qubit Q that she wishes to transmit to Bob. Its state is unknown to both parties, and it may be entangled with other systems they cannot access. It is also important that the quantum teleportation protocol is only worth considering if physically sending the qubit Q to Bob is considered infeasible, for example because the quantum system would decohere before it reaches its destination. Alice can send classical information to Bob, though.

Remember that it is not possible to transmit quantum information using classical communication alone due to the no-cloning theorem. However, with the shared e-bit in place, Alice and Bob can accomplish their task through the quantum teleportation protocol.

As you can see, quantum teleportation, despite a fancy name, is just a protocol allowing for sending quantum information using entanglement and classical communication over arbitrary distances. Let us take a look at it.

The Protocol

The protocol involves a couple of steps which I will walk you through in order to get a good grasp of the topic. And nothing helps learning like a good visualisation of the subject.

The protocol consists of the following steps.

  1. Alice performs a controlled-NOT operation on the pair (A, Q), with Q being the control and A being the target, and then performs a Hadamard operation on Q.
  2. Alice then measures both A and Q, with respect to a standard basis measurement in both cases, and transmits the classical outcomes to Bob. Let us refer to the outcome of the measurement of A as a and the outcome of the measurement of Q as b.
  3. Bob receives a and b from Alice, and depending on the values of these bits he performs these operations:
    1. If a=1, then Bob performs a bit flip (or X gate) on his qubit B.
    2. If b=1, then Bob performs a phase flip (or Z gate) on his qubit B.
    3. That is, conditioned on ab being 00, 01, 10, or 11, Bob performs one of the operations I, Z, X, or ZX on the qubit B.

As a result, the state of qubit B is identical to the state of qubit Q the first step was applied. 

It is important to note that once Alice measures her qubits, the outcome of Bob’s measurement is instantly affected. In other words, the probability of getting one of the eight possible outcomes is set. However, it is not enough for Bob to get the desired state. He still needs to conditionally apply one or more operations in order to complete the state’s transfer. Perhaps the instantaneousness of the measurement probability setting inspired the name, but nothing in reality is teleported in this protocol, or happens at the same moment.

Under the Hood

I hope that you already have a good understanding of what quantum teleportation actually is. However, a step-by-step guide is not really step-by-step if it does not contain a detailed walkthrough of what is happening under the hood.

Setup

The first step is to create a Bell state from Alice’s and Bob’s qubits. Let us choose the |𝜙+⟩ state, which is 12(|00⟩ + |11⟩) when expanded. Then, I recommend that we actually initialise the Q qubit to some arbitrary values, since it makes the algebra easier to follow, and does not obscure any important details. We can pick |1⟩ for example.

With such choices we have now a three-qubit quantum system that can be represented by the following equation.

{"id":"43-0","code":"\\begin{align*}\n{|\\phi^{+}⟩\\otimes|1⟩}&={\\left(\\frac{1}{{\\sqrt[]{2}}}|00⟩+\\frac{1}{{\\sqrt[]{2}}}|11⟩\\right)\\otimes|1⟩}\\\\\n{\\,}&={\\frac{1}{{\\sqrt[]{2}}}|001⟩+\\frac{1}{{\\sqrt[]{2}}}|111⟩}\\\\\n{\\,}&={\\frac{|001⟩+|111⟩}{{\\sqrt[]{2}}}}\t\n\\end{align*}","backgroundColorModified":false,"aid":null,"backgroundColor":"#ffffff","font":{"family":"Arial","color":"#000000","size":11},"type":"align*","ts":1742283950753,"cs":"KZlAQMY4s/Fddql+4pAqiA==","size":{"width":298,"height":136}}

The three-qubit kets may look intimidating at first, but it’s quite easy to reason about them. They’re ordered left to right, and are essentially a concatenated |𝜙+⟩ Bell state and the state qubit (|1⟩). So we have Alice’s qubit, Bob’s qubit, and the state qubit represented in two, equally probable kets.

If you are not a big fan of linear algebra, you can alternatively use the circle notation (I described it in detail here). It is how the same quantum system can be represented using this alternative notation.

Alice’s Steps

Next, it is time for Alice to make her move. She applies a CNOT (CX) gate for her qubit (A), using the state qubit (Q) as the control qubit. 

It may be a bit counterintuitive, but if you apply more than one quantum gate to qubit(s), you have to multiply their respective matrices first, before calculating the tensor product of the entire system. This is how the result of Alice’s actions looks linearly. 

{"type":"align*","font":{"family":"Arial","color":"#000000","size":11},"code":"\\begin{align*}\n{CNOT\\left(q_{a}\\right)H\\left(q_{s}\\right)\\otimes\\frac{|001⟩+|111⟩}{{\\sqrt[]{2}}}}&={\\frac{|010⟩+|100⟩-|011⟩-|101⟩}{2}}\t\n\\end{align*}","backgroundColorModified":false,"backgroundColor":"#ffffff","id":"43-1-0-0","aid":null,"ts":1742466188709,"cs":"l2WLSiYoxr1Hs+j34vlkZg==","size":{"width":496,"height":42}}

The CNOT gate is primarily used to entangle the state qubit with Alice’s qubit. However, in our example it will also flip the value of Alice’s qubit since the state qubit’s value is |1⟩. The Hadamard gate will not only set the state qubit into superposition, but it’ll also affect its phase (which is reflected with minuses in the equation).

In the circle notation, our quantum system now looks like this.

The register may seem complicated now, and indeed it is if we treat all the qubits together. However, we can also think of them separately. Alice’s qubit is still in superposition due to the Bell state applied in the preparation step. The CNOT gate flipped the bits, but she can still read (if measures) 0 and 1 with equal probability. We have four possible readable states, and each two contain either 0 or 1 as the first qubit.

The same situation is with Bob’s qubit – he can still read 0 or 1 with equal probability when measured. The only difference is with the state qubit. Since we applied a Hadamard gate to it, we put it effectively in superposition of 0 and 1. Also, I have already mentioned that its phase was flipped.

Alice then measures her two qubits (the state qubit and Alice’s qubit), collapsing their joint state and producing classical bits that are stored in her classical register. This measurement step transfers the quantum information from the state qubit to Alice’s classical bits. They are sent then to Bob, so he can proceed with his part of the protocol.

Please remember that our quantum system is entangled, so Alice’s measurement affects Bob’s one. Depending on what she reads, possibilities for Bob’s readout are immediately set. However, as I already discussed, this evenement alone is not necessary to transfer the state qubit’s state to Bob’s qubit.

Bob’s Steps

Bob’s actions depend on outcomes of Alice’s computation, or more precisely, what bits were sent via the classical channel. The protocol branches now into four possible paths, implemented with two, conditionally applied gates. Which of these two gates is applied depends on two bits sent to Bob by Alice.

1. Bob receives 00.

This is the easiest path to implement. The only thing Bob has to do, is to apply an identity operation (I) to his qubit (or do nothing, since the identity operation does not change the state of a qubit). 

However, how come that Bob’s qubit already is in the desired state. Let us look at the state of the register from the previous step. Before Alice’s measurement we had four possible readable outcomes: |010⟩, |100⟩, |011⟩ and |101⟩. Just as a reminder, the state qubit is the right-hand most, and Alice’s qubit is the left-hand most. 

If both yielded 0, then it means that our register is in the |010⟩ state (indicated by the full circle), and Bob’s qubit already has the value of |1⟩. Indeed, nothing has to be done.

2. Bob receives 10

It means that Alice’s qubit yielded 1, and the state qubit yielded 0. This indicates that the register is in the |100⟩ state. In this situation Bob applies a CNOT gate to his qubit. In linear algebra it transforms the whole system like in the following equation.

{"backgroundColor":"#ffffff","id":"43-1-0-1-0-0","aid":null,"code":"\\begin{align*}\n{CNOT\\left(q_{b}\\right)\\otimes\\frac{|010⟩+|100⟩-|011⟩-|101⟩}{2}=\\frac{|010⟩+|110⟩-|011⟩-|101⟩}{2}}&\\relempty{}\t\n\\end{align*}","type":"align*","font":{"color":"#000000","family":"Arial","size":7.5},"backgroundColorModified":false,"ts":1742466342913,"cs":"j/bM435wmIf4Tb3G22t27A==","size":{"width":384,"height":24}}

This is how the register looks after Alice’s measurement and the CNOT gate application.

Again, Bob’s qubit is now in the original state qubit’s state (|1⟩).

3. Bob receives 01

If Bob receives 0 from Alice’s qubit and 1 from the state qubit, then he applies only a CZ gate. Why so? If you look at the register, then you can see that Bob’s qubit seems to be already in the right state (it is the -|011⟩ part of the state equation). However, you may have noticed that there is a minus sign in front of this part of the state. This means that the phase was flipped during the teleportation, and must be reverted. It is done with the CZ gate like in the following equation.

{"font":{"family":"Arial","color":"#000000","size":7.5},"code":"\\begin{align*}\n{CZ\\left(q_{b}\\right)\\otimes\\frac{|010⟩+|100⟩-|011⟩-|101⟩}{2}=\\frac{|010⟩+|110⟩+|011⟩-|101⟩}{2}}&\\relempty{}\t\n\\end{align*}","type":"align*","aid":null,"id":"43-1-0-1-1","backgroundColorModified":false,"backgroundColor":"#ffffff","ts":1742466523427,"cs":"TftTLyHhMHeea0BMFrEKBw==","size":{"width":365,"height":24}}

And here is the final result for the registry written in the circle notation.

The phase is now rotated back, and Bob again reads 1 from his qubit.

4. Bob receives 11

In the final possible branch, Bob receives 1s from both qubits read out by Alice. In this case, he must flip both the value of his qubit, and the phase. It transforms the register in the following way.

{"backgroundColorModified":false,"backgroundColor":"#ffffff","font":{"color":"#000000","size":7.5,"family":"Arial"},"type":"align*","aid":null,"code":"\\begin{align*}\n{CNOT\\left(q_{b}\\right)CZ\\left(q_{b}\\right)\\otimes\\frac{|010⟩+|100⟩-|011⟩-|101⟩}{2}=\\frac{|010⟩+|110⟩-|011⟩+|111⟩}{2}}&\\relempty{}\t\n\\end{align*}","id":"43-1-0-1-0-1","ts":1742466712200,"cs":"2MnCgIyTYX7rLbWtJQcUIQ==","size":{"width":422,"height":24}}

And the final state looks like this.

Again, Bob’s qubit ends up in the same state as the state qubit originally was.

Conclusion

Quantum teleportation is a process that allows for the transfer of quantum information from one location to another without physically moving the quantum state itself. This process involves three parties: Alice, who holds the quantum state to be teleported; Bob, who will receive the state; and a classical communication channel between them.

The process begins with Alice and Bob sharing an entangled pair of qubits. Alice then performs a Bell state measurement on her qubit (the one she wants to teleport) and her half of the entangled pair. This measurement results in two classical bits being sent to Bob through the classical communication channel.

Bob, upon receiving these two bits, knows exactly which operation to perform on his half of the entangled pair to recover the original quantum state. This operation can be a bit flip, a phase flip, or both.

The four possible outcomes of Alice’s measurement and Bob’s subsequent operations are:

  1. If Alice sends 00, Bob does nothing (identity operation, I) because his qubit is already in the desired state.
  2. If Alice sends 10, Bob applies a CNOT gate to his qubit. This operation flips the value of his qubit, making it identical to the original state.
  3. If Alice sends 01, Bob applies a CZ gate to his qubit. This operation corrects the phase flip that occurred during teleportation.
  4. If Alice sends 11, Bob applies both a CNOT and a Z gate to his qubit. This operation flips both the value and the phase of his qubit, making it identical to the original state.

In all cases, after receiving the classical information from Alice and performing the appropriate operations, Bob’s qubit ends up in the same state as the original quantum state that Alice wanted to send. In other words, the quantum teleportation protocol allows sending arbitrary quantum states over arbitrary distances in a way that works around the No-Cloning Theorem. 

Understanding Quantum Register’s State with the Circle Notation

Every computation (regardless of it being quantum or classical) is useless unless we can store and access its results somehow. There are many different ways of storing computational results, but the one closest to the computation itself is a register. A quantum register is a concept in quantum computing that serves a similar purpose to a classical computer’s register, which stores and manipulates binary data (bits). However, instead of storing bits (which can be either 0 or 1), a quantum register holds quantum bits, or qubits. Those (qu)bits are called a register state.

The state is first injected into a register in a process called initialisation. It is nothing else but writing starting values for every qubit (since we are going to talk about quantum registers in this post, I will focus only on qubits from now on) that is present in the register. That is called an initial state. Then every operation on those qubits (implemented with one or more quantum gates) changes the state of the register.

Quantum registers and quantum gates are essentially matrices with complex numbers in them. Many people find them quite difficult to understand and use. The complexity can be somewhat masked by using real numbers instead (it works for a surprising number of cases), but it is still there. However, there is a way to picture the state of a quantum register with something conceptually much simpler. It is the circle notation introduced by Eric Johnston and co-authors in the book titled “Programming Quantum Computers” (O’Reilly, 2019). It is what I will cover in this article. I will accompany it with mathematical and code examples, so you can get a better grasp on the elegantly informative value it provides.

Superposition

Superposition is one of the most famous concepts that went from the quantum computing jargon to the everyday language. You can read more about it in my article about the standard bases if you are interested. In short, it is a quantum state that encodes bits (yes, bits) 0 and 1 with equal probabilistic distribution. We can create it by using a Hadamard gate. In this post I use Qiskit to demonstrate operations on a quantum register. All the code is written using this framework.

from qiskit import QuantumCircuit

circuit = QuantumCircuit(1, 1)
circuit.initialize([1, 0], 0)
circuit.h(0)

In the code above, I created a quantum circuit with one qubit, and one bit (forming respectively a quantum and a classical register). I initialised then the qubit to |0⟩ (zero-ket) which is encoded in Qiskit as [1, 0]. Finally, I applied a Hadamard gate to the first qubit in the register. Qubits are indexed in Qiskit starting from 0 as in most programming frameworks.

Mathematically, this circuit looks like this:

{"aid":null,"code":"$$H\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}$$","backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","size":11,"family":"Arial"},"backgroundColorModified":false,"id":"1","ts":1739954355679,"cs":"chp9KSTXPW5kEW3AsVr2tA==","size":{"width":40,"height":40}}

I we expand the Hadamard gate to a matrix, we will get this result

{"type":"$$","code":"$$\\begin{bmatrix}\n{\\frac{1}{{\\sqrt[]{2}}}}&{\\frac{1}{{\\sqrt[]{2}}}}\\\\\n{\\frac{1}{{\\sqrt[]{2}}}}&{-\\frac{1}{{\\sqrt[]{2}}}}\\\\\n\\end{bmatrix}\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}$$","backgroundColor":"#ffffff","font":{"color":"#000000","family":"Arial","size":11},"backgroundColorModified":false,"id":"2-0","aid":null,"ts":1739954474319,"cs":"jxu4BASLggoUWhK1ORQX4Q==","size":{"width":120,"height":56}}

This is the initial state for that particular circuit. If you have never done anything with matrices and linear algebra, then even such a simple example may feel intimidating (it surely was to me in the beginning). However, we can use the circle notation to help us understand what’s happening under the hood.

In the circle notation, every possible quantum register state has a circle assigned to it. Since we are computing with a superposition of one qubit, we can have the register only in two possible states: |0⟩ and |1⟩.

Right now, the circles are empty (and not very helpful). But we will fill them with state soon enough.

The circle notation allows us to work with magnitude (how likely a given result is to be yield) and relative phase (you can think of it as a distance between quantum states – at least for now). We will cover the relative phase soon enough, but Let’s focus on the magnitude first. 

Before we apply the Hadamard gate, the state of our register looks like the following.

We will read |0⟩ with probability equal to 1 and |1⟩ with probability equal to 0. Let’s apply the Hadamard gate, and see how it changes our register.

{"backgroundColorModified":false,"code":"$$\\begin{bmatrix}\n{\\frac{1}{{\\sqrt[]{2}}}}&{\\frac{1}{{\\sqrt[]{2}}}}\\\\\n{\\frac{1}{{\\sqrt[]{2}}}}&{-\\frac{1}{{\\sqrt[]{2}}}}\\\\\n\\end{bmatrix}\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}=\\frac{|0⟩ + |1⟩}{{\\sqrt[]{2}}}$$","id":"2-1","aid":null,"type":"$$","font":{"color":"#000000","family":"Arial","size":11},"backgroundColor":"#ffffff","ts":1739962299511,"cs":"fvcxqunYOS3tt1AKRbLAsg==","size":{"width":214,"height":56}}

The 2 is the denominator for both possible ket outcomes, is called the probability amplitude. In order to get the probability, you have to calculate the square root of it. In our case, it’s 1/2 for both values. What does it look like in the circle notation then?

After applying the gate, we have two light purple circles filling out both states. It means that they have equal magnitudes, resulting in equal probability of being read out. And indeed, if we add the following line to our program:

circuit.measure(0, 0)

we will randomly get 0 or 1.

Phase

I have already mentioned that you can utilise a concept called a relative phase in quantum computing. The relative phase refers to the difference in phase between two quantum states. In a superposition of states, these phases can be either identical or different. The relative phase plays a crucial role in quantum interference phenomena and is fundamental for many quantum algorithms. It essentially determines how the combined state evolves over time, affecting the outcome of measurements performed on the system.

In general, it is a fairly complicated concept which I will not cover in full detail in this article. However, I will demonstrate how it is represented in the circle notation.

from qiskit import QuantumCircuit

circuit = QuantumCircuit(1, 1)
circuit.initialize([1, 0], 0)
circuit.p(math.pi/2, 0) # Rotation by 90 degrees.
circuit.measure(0, 0)

This circuit is almost identical to the one where we used a superposition. However, this time we rotate the relative phase by 90°.

Again, we initialise our qubit to |0⟩, and apply the P(𝜃) gate to it, with 𝜃 = 𝝿/2. This is how this operation looks mathematically.

{"aid":null,"backgroundColorModified":false,"type":"$$","backgroundColor":"#ffffff","id":"3-0","font":{"color":"#000000","size":11,"family":"Arial"},"code":"$$P\\left(\\theta\\right)|0⟩=\\begin{bmatrix}\n{1}&{0}\\\\\n{0}&{e^{i\\theta}}\\\\\n\\end{bmatrix}\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}$$","ts":1740043911745,"cs":"9jZ3krd+B0iJIWCSQnvKZQ==","size":{"width":168,"height":40}}

And in the circle notation.

As you can see, we have a new element in the notation – a horizontal line starting from the middle of the circle and pointing at 12 o’clock. It represents the relative phase which the quantum register is in. Let’s see what happens to the register then the gate is applied. First, a bit of linear algebra, if we may.

{"id":"3-1","font":{"family":"Arial","color":"#000000","size":11},"aid":null,"type":"$$","backgroundColor":"#ffffff","code":"$$\\begin{bmatrix}\n{1}&{0}\\\\\n{0}&{e^{i\\theta}}\\\\\n\\end{bmatrix}\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}=\\begin{bmatrix}\n{1}\\\\\n{e^{i\\theta}}\\\\\n\\end{bmatrix}$$","backgroundColorModified":false,"ts":1740046845197,"cs":"ufLsqqLAU68z9zVxklN1lQ==","size":{"width":144,"height":40}}

Now it is time for the circle notation.

The relative phase was rotated by 90° differentiating the two possible states of the register. It is reflected in the circle assigned to |1⟩.

You may wonder what the {"type":"$$","aid":null,"id":"3-1","backgroundColor":"#ffffff","backgroundColorModified":false,"font":{"color":"#000000","family":"Arial","size":11},"code":"$$\\begin{bmatrix}\n{1}\\\\\n{e^{i\\theta}}\\\\\n\\end{bmatrix}$$","ts":1740047685013,"cs":"lzJmo3Wp1ZiQsE28vFPqCQ==","size":{"width":28,"height":40}} means. The ei𝜃 is the phase rotated by the angled described with 𝜃. However, this value is not readable. Hence, this matrix is read as |0⟩. There are techniques that allow to change whatever was computed using phase into a readable result (magnitude, in other words), but they are beyond the scope of this post.

Conclusion

In conclusion, quantum registers and their states play a crucial role in quantum computing, serving as the counterpart to classical computer registers. Instead of storing bits, these quantum registers store qubits, which can exist in superposition, encompassing both 0 and 1 with equal probability. The circle notation introduced by Eric Johnston and the colleagues simplified understanding of these states by representing magnitude and relative phase. This notation allows us to visualize the evolution of a register’s state after applying quantum gates like Hadamard or rotation gates. As demonstrated through Qiskit code examples, this circle notation helps in comprehending quantum computing concepts, making it an essential tool for researchers and enthusiasts alike.

Circuit Notation in Qiskit

One of the most basic concepts in modern days quantum computing is a quantum circuit. It is essentially the second thing most quantum computing students learn after getting familiar with a qubit is the quantum circuit. Though the initial circuits (resembling “Hello World!” examples from other computer science fields) seem to be fairly simple, the subject is actually quite complex. In this blog post I cover the essentials of circuit notation: what it is, what are the principles and conventions used when plotting them. I also focus on the most popular quantum computing framework by far – Qiskit – for reasons that I will explain later.

In essentials, circuits are models of computation in which information is carried by wires through a network of gates, which represent operations on the information that is being carried. Quantum circuits are a specific model of computation based on this more general concept. If this definition seems to be too abstract for you, you can think of circuits as graphs where nodes are gates and edges are wires. 

The concept itself comes from the field of electric engineering. Basically, classical circuits are no different from electric ones, since they follow exactly the same principals. The only difference is that computing circuits (regardless being classical or quantum) are rarely cyclic, and they usually represent a finite sequence of operations that does not permit a loop. Quantum circuits operate on completely different physical laws, but the concept itself is as described above.

Circuits can be boolean or arithmetic. Boolean circuits are used to compute logical values (true and false) for predicates, whereas arithmetic circuits are used to do maths. Fun fact, it can be also done with the boolean circuits, but is highly inefficient. 

Circuit Diagrams

In the quantum circuit model, wires represent qubits. Wires are plotted as horizontal lines stretching from left to right, usually denoted with some sort of a qubit’s identifier (q for example). 

Gates represent operations on these qubits. They are usually drawn as squares of different colouring with letters distinguishing their type. There are exceptions depending on what gate is used in a given circuit. The operations they represent can be a computation or a measurement. 

Below is a diagram of a sample circuit.

In the diagram, you can see one qubit (q) represented with a wire (the horizontal line), and one gate (the dark blue square with X) representing a computation. In this case it is a boolean negation implemented with a NOT (X) gate. You can read more about this gate here if you are unfamiliar with it.

Quantum computations must be eventually measured in order to make some use of them. After all, if we applied only computation steps, we would never know what we actually computed.

A measurement is represented in a diagram with a gray square with a control on it. It always must be accompanied by a double horizontal line representing a classical register. The classical register in quantum computing is used to store results of the computations in a form that is understandable by classical computers that oversee QPUs (Quantum Processing Units). Let’s take a look at an example.

Here, the measurement operation is represented with the grey square with a control, and the bit is represented with a double horizontal line (annotated c). Transfer of a state between a quantum and a classical register is drawn with a double line arrow.

Circuit Depth and Width

As you may intuitively think, circuits may vary in size. In fact, there are two parameters that describe it: width and depth.

Quantum circuit width refers to the number of qubits actively involved in a quantum circuit. In other words, it determines the size of the quantum state being manipulated. For example, a circuit acting on two qubits has a width of two like in the following diagram.

Here we have two qubits (q0 and q1) that are being used simultaneously in a computation (represented with a CNOT gate).

It is important to remember that even if some qubits are idle during certain operations, their presence contributes to the overall circuit width.

The other circuit’s parameter – quantum circuit depth – refers to the number of quantum gates used at a particular step or layer of a quantum circuit. To put it more formally, it relates to the computational parallelism or the number of simultaneous operations being performed in the circuit.

Let’s see it in an example. In the following diagram, there are two gates acting on two different qubits (q0 and q1) simultaneously, so the depth of the circuit at that layer is two.

Width and depth are independent values, though depth can never exceed the overall width of the circuit. Moreover, it is important to remember that while depth is measured for a given part of the circuit, the width is a global value of all the qubits constituting the given circuit.

Qubits Ordering

I have already hinted this in the introduction. Every quantum programming framework has its own convention of drawing quantum diagrams and ordering qubits in them. I use almost exclusively Qiskit, since it is by far the most popular programming framework for QPUs, as well as having really great learning resources. Therefore, I will explain in this post its respective convention.

In Qiskit, the topmost qubit in a circuit diagram has index 0, and corresponds to the rightmost position in a tuple of qubits. The second-from-top qubit has index 1, and corresponds to the position second-from-right in a tuple, and so on, down to the bottommost qubit, which has the highest index, and corresponds to the leftmost position in a tuple.

In particular, Qiskit’s default names for the qubits in an n-qubit circuit are represented by the n-tuple (qn−1, …, q0), with q0 being the qubit on the top and qn−1 on the bottom in quantum circuit diagrams.

This convention leads to confusing situations, since it is also reflected in memory arrays that store results of computations. You can read more about it in my post about endianness in Qiskit.

Plotting a Circuit

There is one final thing that must be covered before concluding. How can you get such nice quantum diagrams? In truth, plotting a circuit is fairly easy with Jupyter notebooks and Qiskit.

First, you have to define a circuit using Qiskit’s circuit API. Then, you can call the draw method to plot the circuit. It accepts an optional argument that defines what library is used to do the plotting. One of the most popular ones is the Matplotlib, which can be chosen by passing the ”mpl” string as an argument.

Here’s an example of a simple circuit and code that plots it with the Matplotlib library.

from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister

register_qubits = 1
register_bits = 1

quantum_register = QuantumRegister(register_qubits, "q")
classical_register = ClassicalRegister(register_bits, "c")

circuit = QuantumCircuit(quantum_register, classical_register)
circuit.h(quantum_register[0])
circuit.x(quantum_register[0])
circuit.measure(quantum_register, classical_register)

circuit.draw("mpl")

And the resulting diagram. Viola!

Conclusion

Circuits are models of computation in which information is carried by wires through a network of gates, which represent operations on the information carried by the wires. In quantum circuits, qubits are equivalent to wires, and operations on them to quantum gates.

The amount of qubits that are being used in a given circuit is called circuit’s width. The number of gates that are being applied parallel to one or more qubits in a given step is called circuit’s depth

Qubit ordering depends on the computational framework you use. In Qiskit, the topmost qubit in a circuit diagram has index 0, and corresponds to the rightmost position in a tuple of qubits. The bottommost qubit, which has the highest index, and corresponds to the leftmost position in a tuple.

A picture is worth a thousand words, and the same holds true with quantum circuits. The easiest way to plot a circuit is to define it programmatically, and then use the Matplotlib library to get the drawing.

I hope that this post puts an understandable picture on the somewhat complicated concept of quantum circuits, and they will become easier to reason with.

Behind the Mystery of “Wrong” Qubit Ordering in Qiskit

Almost everyone starts learning quantum computing using single quantum systems (i.e. with just one qubit). However, soon enough we switch to multiple quantum systems (with two or more qubits) in our pursuit of knowledge about gates and algorithms. One of the first things we learn then are two-qubit gates, like the collection of controlled gates (ex. CNOT) or the SWAP gate.

This is usually the moment when you may get confused with Qiskit’s behaviour. You take a two-qubit gate like the SWAP gate, you apply it to |01⟩ for example, and in the results you see that nothing was swapped. In reality the gate worked as expected, and the confusion is rooted in the way Qiskit stores its state in memory. 

Why is this happening? Let us start with implementing a program that can demonstrate this oddity. 

Swapping Qubits’ States

There are many ways of changing the state of a two-qubit quantum system. I have already mentioned controlled gates which I believe are the most popular gates in quantum circuits nowadays. However, in this post I would like to use a simple example with a SWAP gate. This gate works in a very intuitive way, and is easy to understand even without robust quantum computing or computing in general knowledge. 

The SWAP gate works in a pretty straightforward way: it swaps the values of two qubits. How does it exactly work? Every quantum gate can be represented with a unitary matrix. What a unitary matrix is is beyond the scope of this post. If you are nonetheless interested, I can tell for starters that it is a complex square matrix that, when multiplied by its conjugate transpose, results in the identity matrix. You can read more about unitary matrices here

Without going into further details, here’s the matrix for the SWAP gate. 

{"id":"39","type":"$$","code":"$$SWAP\\,=\\begin{bmatrix}\n{1}&{0}&{0}&{0}\\\\\n{0}&{0}&{1}&{0}\\\\\n{0}&{1}&{0}&{0}\\\\\n{0}&{0}&{0}&{1}\\\\\n\\end{bmatrix}$$","backgroundColorModified":false,"backgroundColor":"#ffffff","font":{"family":"Arial","size":11,"color":"#000000"},"aid":null,"ts":1732694362039,"cs":"aRHqpC4Q3iTzJMzrMq9i9g==","size":{"width":182,"height":88}}

In order to apply it to a two qubits quantum system we have to multiply it by the matrix representing that system.

In short, two-qubit quantum systems are represented by a single column matrix that corresponds to every possible combination of those systems. You can see them all below.

{"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","aid":null,"code":"$$|00\\rangle =\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n{0}\\\\\n{0}\\\\\n\\end{bmatrix}\\,\\,\\,\\,|01\\rangle =\\begin{bmatrix}\n{0}\\\\\n{1}\\\\\n{0}\\\\\n{0}\\\\\n\\end{bmatrix}\\,\\,\\,\\,|10\\rangle =\\begin{bmatrix}\n{0}\\\\\n{0}\\\\\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}\\,\\,\\,\\,|11\\rangle =\\begin{bmatrix}\n{0}\\\\\n{0}\\\\\n{0}\\\\\n{1}\\\\\n\\end{bmatrix}$$","id":"19","font":{"family":"Arial","color":"#000000","size":11},"ts":1732694341122,"cs":"glpliW/Ui8bRxvQjX7/Uig==","size":{"width":360,"height":88}}

(If you don’t know what these numbers are, please read my earlier blog post.)

When you apply this matrix to a ket, it simply swaps the second the the third coefficients. So in general:

{"backgroundColor":"#ffffff","backgroundColorModified":false,"id":"40","aid":null,"type":"$$","font":{"family":"Arial","size":11,"color":"#000000"},"code":"$$SWAP\\begin{bmatrix}\n{v_{1}}\\\\\n{v_{2}}\\\\\n{v_{3}}\\\\\n{v_{4}}\\\\\n\\end{bmatrix}=\\begin{bmatrix}\n{v_{1}}\\\\\n{v_{3}}\\\\\n{v_{2}}\\\\\n{v_{4}}\\\\\n\\end{bmatrix}$$","ts":1731396509048,"cs":"oQuinKOVInSv2hgis/c2KA==","size":{"width":152,"height":88}}

(If you do not know what kets are, you can read about them here.)

The SWAP Gate in Action 

In order to use the SWAP gate in our example, we must write a circuit that uses it. We start off with importing all necessary dependencies.

from itertools import product
from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister, transpile
from qiskit_aer import Aer

Then, we define a set of variables that we’ll use later in the program.

register_qubits = 2
register_bits = 2
zero_ket = [1, 0]
one_ket = [0, 1]
# Generate all possible combinations of zero_ket and one_ket
ket_combinations = list(product([zero_ket, one_ket], repeat=2))
first_qubit = 0
second_qubit = 1
shots = 100

Their purpose will come clear when they’re used later in the code.

As I mentioned before, we can have four different combinations of two basic computational states: |0⟩ and |1⟩. Just as a reminder, they’re |00⟩, |01⟩, |10⟩ and |11⟩. In order to fully demonstrate what the SWAP gate does, we have to take a look at all of those combinations. We created them on line 9 of this program:

ket_combinations = list(product([zero_ket, one_ket], repeat=2))

This line essentially combines |0⟩ and |1⟩ into a collection of |00⟩, |01⟩, |10⟩ and |11⟩. We can then iterate over these combinations.

for ket_combination in ket_combinations:

The actual circuit is created and run within the loop. I will not go into details here, but please read what quantum circuits are and quantum simulators are if you would like to know more.

    quantum_register = QuantumRegister(register_qubits, "q")
    classical_register = ClassicalRegister(register_bits, "c")
    circuit = QuantumCircuit(quantum_register, classical_register)
    circuit.initialize(ket_combination[0], first_qubit)
    circuit.initialize(ket_combination[1], second_qubit)
    circuit.swap(quantum_register[first_qubit], quantum_register[second_qubit])
    circuit.measure(quantum_register, classical_register)

    simulator = Aer.get_backend("qasm_simulator")
    transpiled_circuit = transpile(circuit, simulator)
    result = simulator.run(transpiled_circuit, shots=shots).result()
    print(f"For the first qubit {ket_combination[0]} and the second qubit {ket_combination[1]} the SWAP result is: {result.get_counts(circuit)}")

First off, we create a quantum and a classical register on lines 14 and 15. You can think of those registers as processor’s stack memory, the one that’s closest to it. The quantum register is used for storing qubits’ states, whereas the classical register is used for storing the values that are read out during measurement.

Then we implement the actual circuit (lines 16-20).

circuit = QuantumCircuit(quantum_register, classical_register)
circuit.initialize(ket_combination[0], first_qubit)
circuit.initialize(ket_combination[1], second_qubit)
circuit.swap(quantum_register[first_qubit], quantum_register[second_qubit])
circuit.measure(quantum_register, classical_register)

We define the circuit object by calling the QuantumCircuit(quantum_register, classical_register) constructor.

We then initialise our two qubits with whatever kets we have in a given loop iteration.

circuit.initialize(ket_combination[0], first_qubit)
circuit.initialize(ket_combination[1], second_qubit)

Finally, we apply the SWAP gate…

circuit.swap(quantum_register[first_qubit], quantum_register[second_qubit])

…and measure.

circuit.measure(quantum_register, classical_register)

If you plotted this circuit with the following line of code – circuit.draw(output=’mpl’) – you’d get this diagram.

(I’ll cover circuit diagrams in one of the future blog posts.)

It represent the following quantum operation: SWAP|00⟩.

Run the program, and you’ll get the following results.

For the first qubit [1, 0] and the second qubit [1, 0] the SWAP result is: {'00': 100}
For the first qubit [1, 0] and the second qubit [0, 1] the SWAP result is: {'01': 100}
For the first qubit [0, 1] and the second qubit [1, 0] the SWAP result is: {'10': 100}
For the first qubit [0, 1] and the second qubit [0, 1] the SWAP result is: {'11': 100}

The number 100 is the number of times a given circuit was run (it’s important in a non-one probability readout like in this example).

[1, 0] is a row matrix that can be also written as |0⟩, and [0, 1] is a row matrix that can be written as |1⟩. So reading the results as they are yields this:

  • |00⟩ → {’00’: 100}
  • |01⟩ → {’01’: 100}
  • |10⟩ → {’10’: 100}
  • |11⟩ → {’11’: 100}

It looks like this program doesn’t work at all! But it does. The confusion lies in the way Qiskit stores values internally. It uses little endian.

Little Endian

What is little endian, or endianness in general? Endianness is the order in which bytes within a word of digital data are transmitted over a data communication medium or addressed (by rising addresses) in computer memory, counting only byte significance compared to earliness. The name is taken from the novel Gulliver’s Travels. You can read more about it here.

It sure sounds complicated, but in simpler words, endianness determines from which end of memory space the bytes are ordered. There are two types of endianness: the big endian and the little endian.

  • A big-endian system stores the most significant byte of a word at the smallest memory address and the least significant byte at the largest.
  • A little-endian system, in contrast, stores the least-significant byte at the smallest address.

Big endian is thus closer to the way the digits of numbers are written left-to-right in English, comparing digits to bytes. Little endian, on the other hand, reverses the natural ordering of the bits.

Here is a visual representation of these two systems.

Source: https://en.wikipedia.org/wiki/Endianness#/media/File:32bit-Endianess.svg 

In the above example you can clearly see that while the big-endian preserves the natural ordering of a given processor word (or any binary value in general), the little-endian essentially reverses it. And this is the case with Qiskit. It uses internally little-endian to store quantum processing results, and hence prints them accordingly. For two-qubit systems it maps to the following list.

QubitsQiskit
|00⟩00
|01⟩10
|10⟩01
|11⟩11

Getting the Big-endian Result

It is possible in Qiskit to change the ordering of the qubits from little-endian to big-endian. However, it is quite limited. For example, it can be easily done for circuit drawings with the reverse_bits() function. Unfortunately, it looks like switching to big-endian for the Result object that we use to query for whatever we computed is not supported.

Conclusion

Interpreting results obtained from quantum circuits in Qiskit can be challenging. This is due to the fact that Qiskit uses little-endian to store computation results. It stores the least significant bit (the right-hand most) in the first memory index, and the rest of the bits follow. The result is hence a reverse of natural ordering that we expect in ket representations of quantum systems and can be confusing for new and experienced users.

The Standard Computational Bases

In the previous article, I covered the Bloch sphere, one of the most helpful visual tools for understanding qubits. The Bloch sphere allows us to represent a qubit’s state as a point in three-dimensional space. While this point represents the qubit’s state, it’s often even more useful to consider its position in relation to one of the three primary axes on the sphere – x, y, and z. These axes are not arbitrary; each one is linked to a unique set of orthonormal basis vectors, commonly referred to as computational bases.

In quantum computing, a computational basis provides a standardised framework to measure or affect a qubit’s state. If you’re unfamiliar with the term “orthonormal basis vectors,” consider reviewing this helpful Wikipedia page on orthonormality. These bases are “computational” because they lay the groundwork for every computation we perform in quantum computing.

While any set of orthonormal basis vectors could theoretically serve as computational bases in quantum computing, there are three primary ones that are used most frequently: the computational basis, the Hadamard basis, and the circular basis. Each of these serves a distinct purpose in interpreting and manipulating qubit states.

The Computational Basis

The computational basis, aligned with the z-axis of the Bloch sphere, is the foundation of quantum measurement. It’s the most common basis for reading the results of quantum computations because it directly corresponds to binary classical states, making it easier to translate quantum states into familiar classical outputs. The computational basis consists of two column vectors {"aid":null,"id":"1-0","backgroundColorModified":false,"type":"$$","code":"$$\\begin{bmatrix}\n{1}\\\\\n{0}\\\\\n\\end{bmatrix}$$","backgroundColor":"#ffffff","font":{"size":11,"color":"#000000","family":"Arial"},"ts":1730705283029,"cs":"htX4ZvSp/vZU5LxOdr4lKg==","size":{"width":17,"height":40}} and {"id":"1","font":{"color":"#000000","family":"Arial","size":11},"backgroundColorModified":false,"backgroundColor":"#ffffff","aid":null,"type":"$$","code":"$$\\begin{bmatrix}\n{0}\\\\\n{1}\\\\\n\\end{bmatrix}$$","ts":1730705302677,"cs":"KT/yysX+vZcUfh8RBD5pbQ==","size":{"width":17,"height":40}}, often written in Dirac notation as |0⟩ and |1⟩. These two states represent the “north” and “south” poles of the Bloch sphere, and they correspond to the conventional binary states, 0 and 1. When a qubit is measured in this basis, it “collapses” to one of these two poles, giving us a straightforward binary result.

The Hadamard Basis

Next, the Hadamard basis is associated with the x-axis of the Bloch sphere, which represents a state along the sphere’s equator rather than at its poles. This basis is one of the most powerful tools in quantum computing because it allows us to use any real number as a qubit’s state, not just the discrete values of 0 or 1. For a deeper dive into why this is significant, check out my article on quantum vs classical computing. The Hadamard basis enables superdense coding, a technique that leverages quantum superposition to represent classical bits in more complex ways. 

The Hadamard basis consists of two vectors {"backgroundColor":"#ffffff","id":"4-0","code":"$$\\begin{bmatrix}\n{\\frac{{\\sqrt[]{3}}}{2}}\\\\\n{\\frac{1}{2}}\\\\\n\\end{bmatrix}$$","aid":null,"type":"$$","font":{"family":"Arial","color":"#000000","size":11},"backgroundColorModified":false,"ts":1730791999404,"cs":"hTWAQA6GbNSUcVtenr2D2A==","size":{"width":34,"height":52}} and {"code":"$$\\begin{bmatrix}\n{\\frac{1}{2}}\\\\\n{-\\frac{{\\sqrt[]{3}}}{2}}\\\\\n\\end{bmatrix}$$","backgroundColor":"#ffffff","type":"$$","font":{"size":11,"color":"#000000","family":"Arial"},"aid":null,"backgroundColorModified":false,"id":"4-1","ts":1730792031290,"cs":"/1LehwHPaq45D7XFsEbg1g==","size":{"width":48,"height":52}}, denoted in Dirac notation as |+⟩ and |-⟩. These states lie along the equator of the Bloch sphere, representing the ability of qubits to exist in a superposition of 0 and 1 simultaneously. This property underlies many of quantum computing’s most promising applications, such as quantum parallelism, where the system explores multiple possibilities at once, and quantum encryption, where superpositions contribute to secure data encoding.

The Circular Basis

Finally, the circular basis aligns with the y-dimension of the Bloch sphere and introduces an essential concept called phase. In quantum mechanics, a qubit’s phase describes the relative angle or orientation of its wave function in its quantum state. This phase does not impact the probability of measuring the qubit in a particular state; rather, it influences how qubits interact with each other, particularly in superpositions and entangled states. 

This phase-based interference is foundational for many quantum algorithms and gate operations, such as the Hadamard gate and controlled-phase gates, which rely on phase manipulation to perform complex calculations. The circular basis uses two vectors {"backgroundColorModified":false,"backgroundColor":"#ffffff","font":{"color":"#000000","family":"Arial","size":11},"type":"$$","id":"5","code":"$$\\begin{bmatrix}\n{\\frac{1}{{\\sqrt[]{2}}}}\\\\\n{\\frac{1}{{\\sqrt[]{2}}}}\\\\\n\\end{bmatrix}$$","aid":null,"ts":1730792529020,"cs":"7EktR3+oTgrPSWxbYh2kZg==","size":{"width":36,"height":56}} and {"code":"$$\\begin{bmatrix}\n{\\frac{1}{{\\sqrt[]{2}}}}\\\\\n{-\\frac{1}{{\\sqrt[]{2}}}}\\\\\n\\end{bmatrix}$$","type":"$$","backgroundColor":"#ffffff","font":{"color":"#000000","family":"Arial","size":11},"id":"5","backgroundColorModified":false,"aid":null,"ts":1730792547294,"cs":"uBfxjoFz/ylEchizDQptRw==","size":{"width":48,"height":56}}, usually written as |i⟩ and |-i⟩ in Dirac notation, to describe these states. This notation represents the relative phase of the qubit, allowing for fine-tuned control over quantum states and facilitating advanced computational processes like error correction and phase estimation.

Conclusion

Understanding the computational bases—computational, Hadamard, and circular—is essential for anyone delving into quantum computing. These bases provide different frameworks for interpreting and manipulating qubit states, whether through straightforward binary measurement, superposition, or phase manipulation.

Each basis has a unique role: the computational basis is the go-to for classical readouts, the Hadamard basis introduces superpositions that allow for more complex computations, and the circular basis enables control over phase, crucial for advanced algorithms and gate operations.

By mastering these foundations, we gain a toolkit to understand and perform quantum operations more effectively, unlocking the full potential of qubits for quantum computing tasks. Whether you’re analysing measurement outcomes or engineering interference patterns, these computational bases form the core of your journey through quantum mechanics and computation.

Understanding the Bloch Sphere: A Visualisation of Qubits in Quantum Computing

In my previous blog post I briefly described the fundamental advantages of quantum computing, such as superposition and entanglement. The key player behind these powerful features is the qubit, which serves as the fundamental unit of quantum information. Unlike classical bits that represent only 0s and 1s, qubits can exist in multiple states at once due to the principles of superposition and entanglement. This allows quantum computers to solve certain problems much faster than classical computers.

But how do we actually represent a qubit? One of the most useful ways to visualise qubits is through the Bloch sphere, which is what I will explain in this post. The Bloch sphere gives us a geometrical representation of a qubit’s state, helping us better understand its behaviour and how it can be manipulated during quantum computations.

Qubit States on the Bloch Sphere

The Bloch sphere is a geometrical representation of a qubit’s state space. Named after physicist Felix Bloch, who contributed to nuclear magnetic resonance (NMR) theory, and was awarded a Nobel prize for this work, it is essentially a unit sphere in a three-dimensional space. Each point on this sphere represents a possible state of a qubit, with the surface of the sphere encoding all possible superpositions of the quantum states {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} and {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}.

In the traditional representation of a qubit, its state can be written as:

{"font":{"color":"#000000","family":"Arial","size":11},"aid":null,"id":"1","type":"$$","code":"$$a\\lbrack0\\rangle \\,+\\,b\\lbrack1\\rangle $$","backgroundColor":"#ffffff","backgroundColorModified":false,"ts":1728628958459,"cs":"pzD7Y3hCvVkJmrkKQ+sJwg==","size":{"width":80,"height":16}}

where {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} and {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}} are the basic states (think of them as the quantum version of 0 and 1), and a and b are complex numbers that describe the probabilities of the qubit being in state {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} or {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}.

The coefficients a and b can be written using complex numbers, which introduce both magnitude and phase. But rather than get bogged down in complex numbers, we can think of the Bloch sphere as a way of mapping these values into three dimensions that correspond to specific aspects of the qubit’s state.

The Three Dimensions of the Bloch Sphere

The Bloch sphere has three key axes that correspond to different aspects of a qubit’s state:

Z-axis (Computational Basis)

This dimension is the simplest to understand and relates to the “classical” states of a qubit: {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} and {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}

  • If the qubit is at the north pole of the Bloch sphere, it represents {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}}.
  • If the qubit is at the south pole, it represents {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}.

This is why the z-axis is often referred to as the computational basis, since these states are the fundamental building blocks of classical computing.

X-axis (Superposition on the Equator)

This dimension captures superposition, where the qubit exists in a state between {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} and {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}. A qubit in superposition might lie on the equator of the Bloch sphere, representing a mix of both classical states.

For example, the states {"code":"$$\\lbrack+\\rangle $$","id":"2-1","backgroundColorModified":false,"aid":null,"font":{"color":"#000000","family":"Arial","size":10},"backgroundColor":"#ffffff","type":"$$","ts":1728633544861,"cs":"G8l4wtC/5G/z3f7Vve0pUw==","size":{"width":18,"height":14}} and {"type":"$$","font":{"size":10,"color":"#000000","family":"Arial"},"backgroundColorModified":false,"id":"2","code":"$$\\lbrack-\\rangle $$","backgroundColor":"#ffffff","aid":null,"ts":1728633575159,"cs":"ZivHJVPxJ6Z6UfnmbbDmcg==","size":{"width":18,"height":14}} lie on the equator. These states are key to many quantum algorithms because they describe qubits that are equally likely to be measured as {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} or {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}.

The x-axis helps us understand how qubits are manipulated during quantum computations, particularly when using gates like the Hadamard gate, which create superposition.

Y-axis (Phase)

The y-axis deals with the phase of a qubit. Phase is a bit tricky—it’s not something we can directly measure, but it plays a critical role in quantum computations. Phase helps differentiate states that might have the same probabilities of being {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} or {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}, but which behave differently when subjected to certain quantum gates.

For example, the qubit can have a positive or negative phase ({"type":"$$","code":"$$\\lbrack i\\rangle $$","backgroundColor":"#ffffff","backgroundColorModified":false,"id":"10","aid":null,"font":{"family":"Arial","color":"#000000","size":12},"ts":1728633607114,"cs":"TKiTByTL2a/pmLuqdBhKyg==","size":{"width":13,"height":17}} or {"backgroundColorModified":false,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"aid":null,"backgroundColor":"#ffffff","code":"$$\\lbrack -i\\rangle $$","id":"8","ts":1728633631336,"cs":"r9QBSnt+6me+TR5iRpxvCA==","size":{"width":28,"height":17}}), which describes how the qubit oscillates over time. This oscillation (or rotation on the sphere) affects how qubits interfere with each other during quantum operations.

Putting It All Together

At any given moment, a qubit’s state can be represented by a point on the surface of the Bloch sphere. This point is determined by two angles:

  • θ (theta): This angle tells us how far the state is from the north or south pole (i.e., the computational basis). A qubit at the poles is in a classical state, while a qubit on the equator is in a superposition.
  • φ (phi): This angle defines where on the equator the qubit lies, describing the phase of the superposition.

We can mathematically represent any qubit state ({"font":{"color":"#000000","size":12,"family":"Arial"},"backgroundColor":"#ffffff","code":"$$\\lbrack\\psi\\rangle $$","id":"12","backgroundColorModified":false,"type":"$$","aid":null,"ts":1728633682411,"cs":"O46rls3dSzxr1042dHPIEw==","size":{"width":20,"height":17}}) using these two angles:

{"type":"$$","backgroundColorModified":false,"backgroundColor":"#ffffff","id":"13","aid":null,"font":{"size":11,"family":"Arial","color":"#000000"},"code":"$$\\lbrack\\psi\\rangle \\,=\\,\\cos\\left(\\frac{\\theta}{2}\\right)\\lbrack0\\rangle +\\,\\sin\\left(\\frac{\\theta}{2}\\right)e^{\\varphi^{i}}\\lbrack1\\rangle $$","ts":1728630633800,"cs":"LVHfevq05WQXYay9pf45Pg==","size":{"width":264,"height":40}}

In this equation, θ and φ map the qubit’s state to a specific point on the Bloch sphere, where we use trigonometry to describe its position. And since we have come to the point where we are talking about trigonometry, we can finally plot the Bloch sphere.


This model gives us an intuitive way to visualise qubits and the operations we perform on them. For example:

  • Quantum gates can be thought of as rotations of the qubit on the Bloch sphere. When we apply a quantum gate, we essentially rotate the point that represents the qubit’s state.
  • Superposition is clearly seen when a qubit lies on the equator, halfway between {"id":"2-1","code":"$$\\lbrack0\\rangle $$","aid":null,"backgroundColorModified":false,"backgroundColor":"#ffffff","type":"$$","font":{"color":"#000000","family":"Arial","size":12},"ts":1728633312005,"cs":"54cxfABlUHryeVsbIcegtg==","size":{"width":16,"height":17}} and {"code":"$$\\lbrack1\\rangle $$","backgroundColorModified":false,"id":"3","aid":null,"type":"$$","font":{"size":12,"color":"#000000","family":"Arial"},"backgroundColor":"#ffffff","ts":1728633332948,"cs":"dfJUZHYoh6Y8oqfTT3WFjQ==","size":{"width":16,"height":17}}.
  • Phase changes are rotations around the z-axis, altering the angle φ but keeping the qubit’s probabilities the same.

Most importantly, the Bloch sphere shows us how quantum operations work in three dimensions, even though we might only measure the final state in one dimension (the z-axis). It helps explain why quantum algorithms can achieve speedups by harnessing the full power of quantum mechanics.

Conclusion

The Bloch sphere is an incredibly useful tool for visualising the state of a qubit and understanding how quantum operations work. By representing qubit states as points on a sphere, we can grasp key quantum properties like superposition and phase, which are crucial for quantum computations. As we continue exploring quantum computing, the Bloch sphere will serve as a fundamental concept for understanding how qubits behave and how quantum gates manipulate them.

In the next post, I’ll dive deeper into the computational basis and how it’s used in quantum algorithms. If you’re curious about the notation used to represent qubit states, check out this article on bra-ket notation until then!

Quantum vs Classical Computing: How Different Are They?

Computation is a core aspect of modern technology, driving innovations across science, engineering, entertainment, and communication. But what exactly is a computation, and how does it differ in classical and quantum contexts?

What is Computation?

At its most fundamental level, computation refers to using technology to perform tasks, solve problems, and manipulate information. Whether it’s simulating physical systems, developing intelligent algorithms, or managing vast data sets, computation is the bedrock of all digital advancements. Classical computing, which powers most of today’s digital systems, has long been the standard. However, quantum computing, a revolutionary paradigm, promises to redefine what’s possible in the field.

Classical vs. Quantum Computation

Classical Computing

Classical computing is rooted in binary logic. The smallest unit of information is a bit, which can exist in one of two possible states: 0 or 1. Every computation a classical computer performs is deterministic, meaning the result is always predictable based on the input. Operations are executed using logic gates, and bits can be copied, stored, and manipulated across various systems and memory registers without loss of information.

To illustrate, consider a light switch. A light switch can only be ON or OFF just like a bit can only be 1 or 0. Classical computers, no matter how complex, are simply massive collections of these switches, manipulating them to perform calculations. While highly effective for many applications, classical computers are limited by their binary nature.

Quantum Computing

Quantum computing, on the other hand, is a game changer because it relies on principles from quantum mechanics, which describe the behaviour of particles at extremely small scales. Instead of bits, quantum computers use qubits as the fundamental unit of information. Unlike classical bits, qubits can exist in an infinite number of states.

The state of a qubit can be visualised using a Bloch sphere. Imagine a globe, with 0 at the South Pole and 1 at the North Pole. While a classical bit is like a light switch, only toggling between ON (1) or OFF (0), a qubit can be any point on the surface of this globe. It can blend 0 and 1 in a continuum of possibilities, opening up a much larger space for computation.

Moreover, quantum operations exploit unique quantum phenomena, such as entanglement and superdense coding, which enable powerful new methods of processing information that classical systems cannot easily replicate.

What Makes Quantum Computation Different?

Quantum computing fundamentally differs from classical computing in several key ways:

  1. Superposition and Infinite States: A single qubit can encode an infinite number of possible states, as opposed to the strict binary options of classical bits. This means quantum computers can process much more information simultaneously.
  2. Measurement and Probability: While qubits can exist in an infinite number of states, any attempt to measure them translates their quantum state into a classical state (either 0 or 1). This process is probabilistic. The quantum state does not yield a fixed answer but rather gives a probability distribution over possible outcomes, which makes quantum computing inherently different from the deterministic operations of classical systems.
  3. No Cloning: A vital distinction between classical and quantum systems is that qubits cannot be copied. In classical computing, data can be duplicated as needed, but in quantum systems, copying qubits requires measurement, which essentially destroys their quantum states. This limitation introduces significant challenges in designing quantum memory and other hardware.
  4. Quantum Speedup: While quantum computers still rely on classical control processors, they can solve certain types of problems far more efficiently. The sheer complexity of operations performed on multiple qubits in superposition provides a level of computational parallelism that classical systems can’t achieve. As a result, quantum computers can solve some problems exponentially faster than classical computers.

Classical vs Quantum: Two Types of Computation

In formal terms, classical computing is a subset of quantum computing. Quantum systems are, by their nature, a more general form of computation. A quantum computer can theoretically perform any task a classical computer can, but the reverse isn’t true.

While classical systems excel at deterministic, straightforward calculations and are still the most practical solution for everyday computing needs, quantum computers promise breakthroughs in fields like cryptography, materials science, and complex simulations. However, the full potential of quantum computing is still in its early stages, with numerous technical challenges remaining.

Conclusion

The advent of quantum computing represents a paradigm shift in how we think about computation. While classical computing remains essential for most of today’s technology, quantum computing opens the door to unprecedented computational power. By leveraging the principles of quantum mechanics, future quantum computers will tackle problems once deemed unsolvable, pushing the boundaries of science, technology, and innovation.

The light switch analogy offers a simple glimpse into the complexity of these two systems: while classical bits are limited to being ON or OFF, qubits, like points on the surface of a sphere, reveal an infinite range of possibilities. This difference is the key to quantum computing’s extraordinary potential. The future of computation lies in the quantum realm, where the probabilistic nature of the universe is harnessed for revolutionary breakthroughs.

Why is Quantum Computing So Hard to Understand?

Preface

As a software engineer, I recently embarked on a journey to learn quantum computing. The experience has been both fascinating and frustrating, as I found it incredibly difficult to come across simple explanations for this complex field. In light of this, I decided to start a “Simple Quantum Computing” series. Through this series, I aim to demystify quantum computing for myself and for you, dear reader, as we explore what could very well be the most revolutionary computing technology of the 21st century.

Introduction

Quantum computing represents the bleeding edge of technology. As software engineers, it is one of the most advanced areas we can dive into. Its potential impact on the world is enormous, particularly when it comes to cryptography. Quantum computers have already shown that they can break modern cryptographic algorithms with relative ease.

Despite its prospect, quantum computing has not yet gained widespread popularity. Unlike artificial intelligence, which saw a surge in interest with the advent of models like ChatGPT, quantum computing remains a niche area. This is partly due to the limited job market demanding quantum skills, but it is also due to the steep learning curve associated with the technology.

So, why exactly is quantum computing so hard to understand?

Analog Computational Values

As software engineers, we are used to binary computational values—0s and 1s. These discrete values form the foundation of classical computing, with processor words built from them, and every computation within a CPU is based on these simple, binary states.

Quantum Processing Units (QPUs), however, operate on a completely different principle. They use analog, or continuous, values instead of discrete ones. There is no clear-cut 0 or 1 in quantum computing; instead, everything is represented by complex numbers that can take on any value between the quantum states |0⟩ and |1⟩. These states are known as kets, a concept I will delve into further in a later post.

This shift from binary to analog values presents a significant challenge. As developers, we are not trained to work with these continuous values. For example, there is no straightforward equivalent of a boolean in quantum computing—no simple 0 or 1 to latch onto.

Moreover, modern QPUs must be controlled by classical CPUs. This means that the analog values computed by a QPU have to be translated into discrete values for the CPU to process. This translation introduces a loss of information and a level of unpredictability, as the process is not deterministic. The notion of working with probabilities—something that quantum computing heavily relies on—is foreign to most of us in the field of computer science, where even pseudo-random numbers are not truly random.

Overall, the different computational bases and the need to convert between them add a significant layer of complexity that we are simply not accustomed to dealing with.

Complex Mathematics

Another major hurdle in understanding quantum computing is the complex mathematics involved. To grasp the concepts of quantum computing, one must be comfortable with advanced mathematical theories and methods that go beyond basic arithmetic or algebra.

Some of the key mathematical areas used in quantum computing include:

  • Complex Numbers: One of the fundamental concepts is the extension of the real number system to include imaginary numbers. A complex number is expressed as a + bi, where a and b are real numbers, and i is the imaginary unit, satisfying i2 = −1.
  • Complex Analysis: This is the study of functions that operate on complex numbers. It includes topics such as analytic functions, complex integration, and conformal mappings.
  • Abstract Algebra: This area involves the study of algebraic structures like groups, rings, and fields. These structures are used to generalise algebraic concepts and solve equations in more abstract settings.

While it is possible to create simpler mathematical models by abstracting parts of this complex mathematics, understanding the original concepts is still crucial, and may be difficult (definitely for me!).

Programming a Processing Unit

Beyond the challenge of analog values and complex mathematics, there is the task of actually programming quantum processing units. Programming modern QPUs is reminiscent of programming early CPUs in the 1950s. If you compare quantum programming frameworks like Qiskit to early high-level programming languages like Autocode, you will notice striking similarities.

Both require you to think in terms of bits (or qubits), registers, memory, and gates. It is a very low-level form of programming that most modern software engineers are unaccustomed to. We lack the high-level frameworks and abstractions that we are familiar with in classical computing, making it even harder to get started in quantum computing.

Conclusion

Quantum computing represents a paradigm shift in how we approach computation, challenging many of the fundamental principles that have guided software engineering for decades. The complexity of analog computational values, the necessity to grasp advanced mathematics, and the low-level nature of quantum programming make it a field that is difficult to understand and master. 

However, these very challenges are what make quantum computing so promising and exciting. Just as classical computing evolved from low-level machine code to high-level languages and user-friendly frameworks, quantum computing will likely undergo a similar evolution. We are simply not there yet.

In this post series – simple quantum computing – I plan to write about different aspects of quantum computing that I found difficult to learn, and do my best to explain them in much simpler terms. I hope it will help both me and you understand what I believe to be the most promising computational technology of the XXI century. 

How to Implement the Pipes and Filters Architecture with Java and Azure

In my previous blog post, I provided an in-depth explanation of the Pipes and Filters architecture, which you can check out here. To recap, the Pipes and Filters architecture breaks down a system into small, self-contained processing components known as filters. Each filter is responsible for performing a specific task or transformation on the data it receives, promoting modularity and reusability. These filters are connected via pipes, which facilitate the flow of data from one filter to the next. This architecture is particularly effective in scenarios involving data integration, processing workflows, transformation pipelines, and stream processing.

In this blog post, I will walk you through a sample implementation of the Pipes and Filters architecture using Java and Azure. Our example project will centre around a chatbot designed to assist in creative thinking activities such as brainstorming.

Sample Project Overview

The goal of this project is to create a tool that integrates with a company’s creative thinking solutions. Specifically, it’s a chatbot that aids teams during brainstorming sessions and other creative activities. The process begins when a user interacts with the application by typing a question, such as “How will the ongoing AI revolution affect the financial industry?” This question is then sent to the application for processing.

How the System Works

  1. Input Validation: The first filter is responsible for validating the user’s question. The question might be in a language that the AI model doesn’t understand, or it might be too long or contain sensitive information. Therefore, the first task is to verify whether the question can be processed further.
  2. Prompt Engineering: If the question is valid, the application uses predefined templates to enrich it. These templates provide context to the AI-powered tool, making the model’s output more valuable. For example, a template might be: “You are a CEO. Given a strategic prompt, you will create X futuristic, hypothetical scenarios that happen Y years from now. The strategic prompt is: Z”. This step is crucial as it leverages prompt engineering to guide the AI model in generating more meaningful responses.
  3. AI Model Interaction: The final step involves sending the enriched prompts to the AI model, which processes them and generates answers. These answers are then displayed back to the user.

Implementation Details

The system consists of three filters:

  1. Input Validation Filter: Validates the user’s input according to the application’s data requirements.
  2. Prompt Engineering Filter: Analyses and enriches the validated input to create a prompt.
  3. AI Model Facade Filter: Sends the engineered prompt to the AI model and handles the response.

The First Filter: Input Validation

The first filter is implemented as an Azure Function, and its primary role is to validate the incoming question.

@FunctionName("QuestionValidationFunction")
public HttpResponseMessage validate(
       @HttpTrigger(name = "question",
               methods = {HttpMethod.POST},
               authLevel = AuthorizationLevel.FUNCTION)
       HttpRequestMessage<String> question,
       @QueueOutput(name = "questionQueue",
               queueName = "question-queue",
               connection = "AzureWebJobsStorage")
       OutputBinding<String> questionQueue,
       ExecutionContext executionContext) {
    // Implementation of validation.
}

The validate method, annotated with @FunctionName("QuestionValidationFunction"), is triggered by an HTTP request. It takes two parameters: the HTTP request containing the question and an output binding to a storage queue named "question-queue". The method validates the question and, if valid, sends it down the pipeline.

The Second Filter: Prompt Engineering

The second filter enriches the validated question with a template to maximise the AI model’s response quality.

@FunctionName("PromptEngineeringFunction")
public void sendPrompt(
       @QueueTrigger(
               name = "question",
               queueName = "question-queue",
               connection = "AzureWebJobsStorage")
       String question,
       @QueueOutput(
               name = "promptQueue",
               queueName = "prompt-queue",
               connection = "AzureWebJobsStorage")
       OutputBinding<String> promptQueue,
       ExecutionContext executionContext) {
   // Prompt engineering logic.
}

This function is triggered by messages in the "question-queue". When a new message arrives, the function is invoked, and the question is enriched before being sent to the next queue, "prompt-queue".

The Third Filter: AI Model Facade

The third filter handles communication with the AI model. This filter is implemented using the Spring Cloud Function framework, which decouples infrastructure configuration from the business logic. I’ll describe it in detail in the next blog post, but I’ll give you a short description here so you understand the code.

The functions are implemented as Java function interfaces and autowired into respective request handlers. The handlers contain logic that configures integration with the serverless platform provider. In our case it’ll be the Azure SDK (which examples we’ve seen before). With this setup, you can change the cloud provider by simply rewriting the handlers (and changing build definition) without any need to rewrite the functions itself. 

Let’s now look at the function’s code. 

@Bean
public Function<String, String> answer(ModelClient modelClient) {
   	// Function’s logic
}

The answer function is a simple Java function interface that handles the logic for interacting with the AI model. It is autowired into a handler that manages the integration with Azure.

@Component
public class AnswerHandler {

   private final Function<String, String> answer;

   public AnswerHandler(Function<String, String> answer) {
       this.answer = answer;
   }

   @FunctionName("answer")
   public void answer(
           @QueueTrigger(
                   name = "promptQueue",
                   queueName = "prompt-queue",
                   connection = "AzureWebJobsStorage")
           String prompt,
           @QueueOutput(
                   name = "answerQueue",
                   queueName = "answer-queue",
                   connection = "AzureWebJobsStorage")
           OutputBinding<String> answerQueue
   ) {
       // Handler’s logic
   }
}

This handler is similar to the previous filters, but it delegates the business logic to the answer function. The answerQueue is used to send the final answer for further consumption. 

Deployment

With all three filters implemented, you can now deploy the application to Azure, to play with the code. The deployment process can be accomplished using Maven, as described in this article

In summary, we implemented a complete Pipes and Filters architecture using both the Azure SDK and Spring Cloud Function. The system comprises three filters – each responsible for a distinct part of the application’s workflow: input validation, prompt engineering, and AI model communication. The unidirectional data flow is managed primarily by queues, ensuring a clean separation of concerns and easy scalability.

Summary

This blog post demonstrates how to implement the Pipes and Filters architecture using Java and Azure for a chatbot that assists in creative thinking activities. The architecture is broken down into three filters: input validation, prompt engineering, and AI model interaction. Each filter handles a specific task in the data processing pipeline, ensuring modularity and reusability. The post also covers the deployment process using Azure and Spring Cloud Function, highlighting the benefits of separating business logic from infrastructure configuration.

If you’re interested in how this architecture style can be used to implement serverless solutions, and how to work with Azure Functions in Java, check out my Udemy course that covers these topics in detail.  

The working code example can be found on my GitHub

Serverless with the Pipes and Filters Architecture

In a previous blog post I argued that serverless computing is not an architecture style. However, I made a point there that – as with every technology – some architecture styles go along with it better than the others. What most probably comes to your mind are microservices and event-driven architecture. In this blog post though, I would like to cover a less known architecture style that seems to perfectly match serverless computing – the pipes and filters architecture, which emphasises modularity and reusability in processing components. This architecture is built on the concept of “pipes” that connect filters, enabling the transformation or processing of data as it flows through the system. 

Understanding Pipes and Filters Architecture

The Pipes and Filters architecture is characterised by decomposing a system into small, self-contained processing components called filters. Each filter performs a specific task or transformation on the data it receives, promoting a highly modular and reusable design. Filters are connected using pipes, which serve as conduits for data flow, ensuring a one-way flow of information through the system. This architecture is particularly useful in scenarios such as data integration, data processing workflows, data transformation pipelines, and stream processing systems.

Key features of the Pipes and Filters architecture include:

  • Modularity and Reusability: Each filter is designed to be independent, reusable, and replaceable. This modularity allows for flexible composition of processing components.
  • Sequential Data Flow: Data passes from one filter to the next through pipes, enabling sequential processing.
  • Loose Coupling: Filters interact through well-defined data interfaces provided by the pipes, promoting loose coupling and reusability.
  • Scalability and Parallelism: Filters can be replicated or distributed to handle increased processing loads, allowing for parallel processing.
  • Flexibility and Adaptability: Filters can be added, removed, or rearranged within the pipeline to accommodate changing processing needs.

Serverless Pipes and Filters

Serverless computing naturally complements the Pipes and Filters architecture through several key features. One significant aspect is the modularity and reusability inherent in both paradigms. In serverless computing, individual functions are designed to perform specific tasks and can be independently deployed, updated, or replaced without impacting the rest of the system. This mirrors the independent and reusable nature of filters in the Pipes and Filters architecture, where each filter is a standalone processing unit. Additionally, serverless platforms inherently support sequential data flow through event-driven triggers, similar to how data flows through pipes from one filter to another. This ensures that each function or filter performs its task in sequence, enhancing the clarity and manageability of the data processing pipeline. Moreover, serverless functions communicate through well-defined event interfaces, which aligns with the loose coupling seen in the Pipes and Filters architecture. This separation allows for easier maintenance and testing, as changes in one function or filter do not directly affect others. The scalability and parallelism provided by serverless architectures are also a perfect match for the scalable and distributable nature of filters, allowing the system to handle varying loads efficiently. Finally, the flexibility and adaptability of serverless functions, which can be quickly modified or scaled, resonate with the ability to add, remove, or rearrange filters within the pipeline, making it easy to adapt to changing requirements or workloads.

Functions Chaining

There is one special feature of serverless computing that goes particularly well with the pipes and filters architecture – functions chaining. It is the practice of linking multiple serverless functions together, where the output of one function serves as the input for the next. This allows for the creation of complex workflows by decomposing tasks into smaller, manageable, and reusable functions that execute sequentially. It mirrors exactly how a pipes-and-filters application should be designed, and that is the main reason why serverless computing is my go-to technology whenever I use the pipes and filter architecture in my design.

Summary

In this blog post, we explored the synergy between serverless computing and the pipes and filters architecture, a lesser-known but highly effective design that emphasises modularity and reusability in processing components. The pipes and filters architecture decomposes systems into self-contained filters connected by pipes, ensuring a sequential data flow. Serverless computing complements this by offering modular, independently deployable functions that support sequential processing and loose coupling through well-defined event interfaces. This combination enhances scalability, parallelism, and flexibility, making it ideal for dynamic workloads. A key feature of serverless computing, function chaining, perfectly aligns with the pipes and filters model, enabling the creation of complex, manageable workflows.

In the next blog post I will show you in example how serverless computing can be used in such a design.