# Kaleido is used to convert Plotly to static png
!pip install -Uqq kaleido
# skq is used to build quantum circuits
!pip install -Uqq skq
This notebook is part of the q4p (Quantum Computing for Programmers) series. The original notebook can be found on Github.
3. Multi-qubit gates and algorithms
In previous notebooks we got an extensive overview of how to work with a single qubit. In this notebook we will generalize to multiple qubits and finally look at meaningful algorithms that quantum computing offers. The previous notebooks gave you a solid toolbox from which to construct these algorithms. From here we will focus more on applying gates to construct quantum circuits.
In this lesson you will learn:
- Build and convert quantum circuits with skq
- Bell and GHZ States
- Converting quantum circuits to quantum frameworks like Qiskit and OpenQASM
- Toffoli (\(CCX\)) Gate
- Simulating classical \(AND\) and \(OR\) gates with quantum circuits
- \(SWAP\) Gate
- BONUS: Fredkin (\(CSWAP\)) Gate
import numpy as np
from skq.gates.qubit import X, H, I, CX, CCX, SWAP, CSwap, Measure
from skq.circuits import Concat, Circuit, BellStates, GHZStates
import plotly.graph_objects as go
# Fix Plotly rendering in Jupyter forks.
# If you are running this notebook locally you can comment this out.
# This allows you to play with interactive Plotly plots.
import plotly.io as pio
= 'png' pio.renderers.default
Bell State
One of the first breakthroughs for quantum computing was the implementation of a completely entangled state called the Bell state. In this state 2 qubits are 100% correlated to each other. This enables use cases that are not possible classically, like quantum communication and quantum teleportation.
The traditional Bell State is called the Phi Plus state (\(| \Phi^+ \rangle\)) and is defined as follows:
\[ | \Phi^+ \rangle = \frac{1}{\sqrt{2}} (|00\rangle + |11\rangle) \]
To prepare entanglement we first initialize two qubits (\(|00 \rangle = [1, 0, 0, 0]\)) and put the 1st qubit in superposition with a Hadamard (\(H\)) gate. The 1st qubit is not changed in this first step so the \(I\) gate is applied.
Initial state: \[ |\psi_0 \rangle = |00 \rangle \]
After applying the Hadamard (\(H\)) gate: \[ |\psi_1 \rangle = \frac{1}{\sqrt{2}} (|00 \rangle + |10 \rangle) \]
Note that the 1st qubit is either 0 or 1 with equal probability, but the 2nd qubit is always 0. This leaves the possible states \(|00 \rangle\) and \(|10 \rangle\) with equal probability in this intermediate state.
To accomplish this operation in skq
letβs take a look at the Concat
object. We use Concat
to concatenate gates for multiple qubits. To obtain the concatenated operation the Kronecker product \(\otimes\) is used.
= Concat([H(), I()]) step1
# Transformation on a 2 qubit system that puts the first qubit in superposition
np.kron(H(), I())
H([[ 0.70710678+0.j, 0. +0.j, 0.70710678+0.j, 0. +0.j],
[ 0. +0.j, 0.70710678+0.j, 0. +0.j, 0.70710678+0.j],
[ 0.70710678+0.j, 0. +0.j, -0.70710678+0.j, -0. +0.j],
[ 0. +0.j, 0.70710678+0.j, -0. +0.j, -0.70710678+0.j]])
The result of a concatenation is not just stacking \(2\) matrices, but a new matrix that is applied to a \(2\)-qubit state. The concatenation of \(2\) single qubit gates results in a \(4 \times 4\) matrix. This grows exponentially with the number of qubits. For example, concatenating \(3\) single qubit gates results in a \(2^3 \times 2^3 = 8 \times 8\) matrix. In this notebook we will encounter fundamental 3-qubit gates that cannot be decomposed into single qubit gates, like the Toffoli (\(CCX\)) gate. It is important to treat multi-qubits systems as a single unit, because they are potentially entangled. This is an important difference compared to classical computing, where individual bits do not depend on each other.
= step1([1, 0, 0, 0])
output1 # Superposition between |00> and |10>
output1
H([0.70710678+0.j, 0. +0.j, 0.70710678+0.j, 0. +0.j])
We have learned that every qubit gate can also be applied in reverse, so also with Concat
.
# Transforms superposition of |00> and |10> back to |00>
round(8) step1.decodes(output1).
H([ 1.+0.j, 0.+0.j, -0.+0.j, 0.+0.j])
For the Bell state the two qubits are then entangled using the CNOT (\(CX\)) gate. This results in a fully entangled state of 2 qubits. The individual qubits cannot be visualized nicely on a Bloch sphere anymore, because the state of the qubits depend on each other. It is like flipping 2 coins at the same time, but the outcome will be either 2 heads or 2 tails.
The intermediate state we had before the \(CX\) gate is: \[ |\psi_1 \rangle = \frac{1}{\sqrt{2}} (|00 \rangle + |10 \rangle) \]
After the \(CX\) gate we obtain the final Bell state: \[ |\psi_2\rangle = CX \frac{1}{\sqrt{2}} (|00 \rangle + |10 \rangle) = \frac{1}{\sqrt{2}} (|00 \rangle + CX|10 \rangle) = \frac{1}{\sqrt{2}} (|00 \rangle + |11 \rangle) = | \Phi^+ \rangle \]
The operation flips the second qubit only if the first qubit is 1.
= CX()
step2 # Bell state Phi Plus: Superposition between |00> and |11>
1, 0, 0, 0])) step2(step1([
array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j])
These qubits can be separated over large distances and can enable secure communication, among other things.
Now letβs construct the complete circuit and verify that we implemented the Bell state correctly. Circuit
allows us to run quantum operations in sequence. It also has functionality to convert to popular quantum frameworks like Qiskit and OpenQASM. At the end of the Circuit
we add a Measure
step to obtain a probability distribution of possible outcomes.
= Circuit([step1, step2, Measure()])
bell_circuit = bell_circuit([1, 0, 0, 0])
bell_probs # 50% probability of 00 and 50% probability of 11
bell_probs
array([0.5, 0. , 0. , 0.5])
Recall that measurement is achieved by sampling from the probability distribution. You will see that the only possible outcomes are \(00\) and \(11\) and they are roughly evenly distributed. Be aware that on real quantum computers are noisy so there is a small chance of still measuring \(01\) or \(10\).
# Sample the Bell state 1000 times
= [np.random.choice([0, 1, 2, 3], p=bell_probs) for _ in range(1000)]
samples
= go.Figure()
fig
fig.add_trace(go.Histogram(=samples,
x=dict(
xbins=-0.5,
start=3.5,
end=1
size
),
))
fig.update_layout(="Measurement outcomes for Bell state (|00β© + |11β©)/β2",
title=dict(
xaxis="array",
tickmode=[0, 1, 2, 3],
tickvals=["00", "01", "10", "11"]
ticktext
),=dict(
yaxis="Count",
titlerange=[0, 600]
),=0.7
bargap
) fig.show()
In skq
we can directly intialize the Bell states as a building block in our circuits.
= BellStates().circuit(1)
phi_plus
= phi_plus([1,0,0,0])
bell_state1 # Superposition between |00> and |11>
bell_state1
array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j])
A convenient feature of skq
Circuit
is conversion to Qiskit
. A Qiskit
QuantumCircuit
can be run on a real IBM quantum computer and offers nice visualization methods.
="qiskit").draw(output="mpl") phi_plus.convert(framework
In total there are \(4\) Bell states, but the outcomes of the βPlusβ and βMinusβ states are the same, even though they are different circuits. For simplicity the conversion process from skq
to Qiskit
will remove any Identity (\(I\)) gates. Circuit.draw
uses Qiskitβs circuit visualization under the hood.
= BellStates()
bell for i, name in enumerate(["Phi Plus (|Ξ¦+β©). Entangles |00β© and |11β©.",
"Phi Minus (|Ξ¦-β©). Entangles |00β© and |11β© with opposite phase.",
"Psi Plus (|Ξ¨+β©). Entangles |01β© and |10β©.",
"Psi Minus (|Ξ¨-β©). Entangles |01β© and |10β© with opposite phase."],
=1):
start= bell.circuit(i)
circuit print(f"Bell state {i}: {name}")
print(circuit.draw())
Bell state 1: Phi Plus (|Ξ¦+β©). Entangles |00β© and |11β©.
βββββ
q_0: β€ H ββββ ββ
ββββββββ΄ββ
q_1: ββββββ€ X β
βββββ
Bell state 2: Phi Minus (|Ξ¦-β©). Entangles |00β© and |11β© with opposite phase.
βββββ βββββ
q_0: β€ H ββββ βββ€ Z β
ββββββββ΄βββββββ
q_1: ββββββ€ X ββββββ
βββββ
Bell state 3: Psi Plus (|Ξ¨+β©). Entangles |01β© and |10β©.
βββββ
q_0: β€ H ββββ ββ
βββββ€βββ΄ββ
q_1: β€ X ββ€ X β
ββββββββββ
Bell state 4: Psi Minus (|Ξ¨-β©). Entangles |01β© and |10β© with opposite phase.
ββββββββββ
q_0: β€ H ββ€ Z ββββ ββ
βββββ€βββββ€βββ΄ββ
q_1: β€ X ββ€ Z ββ€ X β
βββββββββββββββ
Often it will be clearer to use the Matplotlib circuit visualization that Qiskit offers. Define output="mpl"
to use this.
="mpl") phi_plus.draw(output
= BellStates().circuit(3)
psi_plus ="mpl") psi_plus.draw(output
Another popular standard for defining quantum circuits is OpenQASM. You can think of OpenQASM as assembly language for quantum computers. We will devote a separate notebook to go more in-depth into OpenQASM. For now be aware that many providers of quantum computers support OpenQASM. We can convert skq
circuits to an OpenQASM program (string).
print(psi_plus.convert(framework="qasm"))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
h q[0];
x q[1];
cx q[0], q[1];
Adding a Measure
step will include measurement to the end of the circuit for all qubits.
= Circuit([*psi_plus, Measure()])
psi_plus_with_measure ="mpl") psi_plus_with_measure.draw(output
print(psi_plus_with_measure.convert(framework="qasm"))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
x q[1];
cx q[0], q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];
GHZ State
A GHZ (Greenberger-Horne-Zeilinger) State generalizes the notion of a Bell state to \(n\) qubits. This creates a fully entangled state between all qubits.
Letβs for example take a 3-qubit GHZ state. It is defined as:
\[ GHZ_3 = \frac{1}{\sqrt{2}}(|000\rangle + |111\rangle) \]
= GHZStates().circuit(n_qubits=3)
ghz_3 # 50% probability of |000> and 50% probability of |111>
1,0,0,0,0,0,0,0]) ghz_3([
H([0.70710678+0.j, 0. +0.j, 0. +0.j, 0. +0.j,
0. +0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j])
="mpl") ghz_3.draw(output
If you look closely you will see a pattern of \(CX\) gates all the way down. The first qubit determines the state of all the other qubits. We can do this on an arbitrary number of qubits. For example, see the 10-qubit GHZ state below.
= 10
n_ghz_qubits
= GHZStates().circuit(n_qubits=n_ghz_qubits)
ghz ="mpl") ghz.draw(output
I invite you to play with this circuit and change the number of qubits with n_ghz_qubits
. Remember that the matrices grow exponentially with the number of qubits, so even a GHZ state with 15 qubits may take quite a while to compute on your machine. This is why we want to leverage real quantum computers to scale computations with entanglement.
The OpenQASM program for the GHZ state gives another perspective and makes it clear how the first qubit entangles with all the other qubits.
print(ghz.convert(framework="qasm"))
OPENQASM 2.0;
include "qelib1.inc";
qreg q[10];
h q[0];
cx q[0], q[1];
cx q[1], q[2];
cx q[2], q[3];
cx q[3], q[4];
cx q[4], q[5];
cx q[5], q[6];
cx q[6], q[7];
cx q[7], q[8];
cx q[8], q[9];
This concludes our discussion of the Bell states and GHZ states. The rest of this lesson will cover some fundamental multi-qubit gates and how it enables us to simulate classical \(AND\) and \(OR\) gates.
CCX (Toffoli) Gate
A \(CCX\) (Toffoli) gate is like a \(CNOT\) gate, but for \(3\) qubits. If the first \(2\) (control) qubits are \(1\), the third (target) qubit is flipped. A \(3\)-qubit gate requires a \(2^3 \times 2^3 = 8 \times 8\) matrix to represent classically.
\[CCX = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ \end{bmatrix} \]
CCX()
CCX([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j]])
="mpl") CCX().draw(output
A \(CCX\) will transform a \(|110\rangle\) state into a \(|111\rangle\) state.
\[ CCX|110\rangle = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ \end{bmatrix} \begin{bmatrix}0\\0\\0\\0\\0\\0\\1\\0\end{bmatrix} = \begin{bmatrix}0\\0\\0\\0\\0\\0\\0\\1\end{bmatrix} = |111\rangle \]
@ [0,0,0,0,0,0,1,0] CCX()
CCX([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j])
\(|111\rangle\) will be transformed into a \(|110\rangle\) state. \[ CCX|111\rangle = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ \end{bmatrix}\begin{bmatrix}0\\0\\0\\0\\0\\0\\0\\1\end{bmatrix} = \begin{bmatrix}0\\0\\0\\0\\0\\0\\1\\0\end{bmatrix} = |110\rangle \]
@ [0,0,0,0,0,0,0,1] CCX()
CCX([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j])
Simulating AND and OR gates
Note that the Toffoli gate behaves similarly to an \(AND\) gate in classical computing. In fact, classical \(AND\) and \(OR\) gates can be simulated using only \(CCX\) and \(X\) gates.
\(AND\) gate
Performing an \(AND\) in a quantum circuit takes 3 qubits. After the \(CCX\) gate the third qubit will represent the \(AND\) of the first two qubits. The first two qubits remain unchanged after the \(CCX\) gate.
|a>: βββ ββ |a>
β
|b>: βββ ββ |b>
βββ΄ββ
|0>: β€ X β |a β§ b>
βββββ
\(\land\) = AND
A Toffoli gate can be represented in quantum circuits like this:
= CCX()
and_gate ="mpl") and_gate.draw(output
\(OR\) gate
A \(OR\) gate can also be simulated using 3 qubits. The trick is to first flip the first two qubits with an \(X\), before applying the \(CCX\) gate. Then to retrieve the \(OR\) in the third qubit we apply another \(X\) gate on the third qubit. Note that this changes the state of the first 2 qubits, which represent the \(NOT\) of \(a\) and \(b\) after the operation. To get back the original state of \(|a>\) and \(|b>\) we would need to apply \(X\) to the first 2 qubits again after the \(OR\) gate.
βββββ
|a>: β€ X ββββ βββββββ |Β¬a>
βββββ€ β
|b>: β€ X ββββ βββββββ |Β¬b>
ββββββββ΄βββββββ
|0>: ββββββ€ X ββ€ X β |a β¨ b>
ββββββββββ
\(\neg\) = NOT
\(\lor\) = OR
= Circuit([Concat([X(), X(), I()]),
or_gate
CCX(),
Concat([I(), I(), X()])])="mpl") or_gate.draw(output
::: {#cell-58 .cell 0=β1β 1=β0β 2=β0β 3=β>β 4=β β 5=β-β 6=β>β 7=β β 8=βOβ 9=βRβ 10=β β 11=β-β 12=β>β 13=β β 14=β|β 15=β0β 16=β0β 17=β1β 18=β>β execution_count=28}
0,1,0,0,0,0,0,0]) or_gate([
I([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j])
:::
I leave it as an exercise to you to make a quantum circuit that implements an \(OR\) gate, but where the first 2 qubits keep their original state. It should transform \(100\rangle\) -> \(|101\rangle\).
If you like a challenge, think about generalizing this \(OR\) gates to \(n\) qubits.
And what would an \(XOR\) gate look like? HINT: \(XOR\) is simpler than you think. It involves only \(CCX\) gates.
= Circuit([
xor_gate
Concat([CX(), I()]),
Concat([I(), CX()]),
])="mpl") xor_gate.draw(output
SWAP
Quantum computers have a limited amount of qubit registers. Qubits that are far apart from each other can also become unstable. In larger quantum circuits it is necessary to move qubits around into different registers. We can achieve this by swapping qubits. The \(SWAP\) gate swaps \(2\) qubits.
\[SWAP = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \]
SWAP()
SWAP([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])
\[SWAP|01\rangle = \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix}0\\1\\0\\0\end{bmatrix} = \begin{bmatrix}0\\0\\1\\0\end{bmatrix} = |10\rangle \]
::: {#cell-66 .cell 0=β0β 1=β1β 2=β>β 3=β β 4=β-β 5=β>β 6=β β 7=βSβ 8=βWβ 9=βAβ 10=βPβ 11=β β 12=β-β 13=β>β 14=β β 15=β|β 16=β1β 17=β0β 18=β>β execution_count=31}
0,1,0,0] @ SWAP() [
SWAP([0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j])
:::
A \(SWAP\) gate is represented in quantum circuits like this:
="mpl") SWAP().draw(output
\(SWAP\) gates are most often used in transpilation. Transpilation is an automated process which optimizes a quantum circuit for a specific quantum computer. The process is very similar to how compilers work for classical computers. Modern quantum transpilers will utilize Machine Learning (ML) models for more efficient optimization of circuits. Further in the course we will dive deeper into transpilation. For now you donβt have to worry about it as quantum computing providers have developed efficient transpilers you can use.
BONUS: CSWAP (Fredkin) Gate
Practically any gate we have discussed so far can be extended to a controlled version. There can also be an arbitrary numbers of control and target qubits. A controlled gate you may encounter in the wild is the Controlled-SWAP gate (\(CSWAP\)), also known as the Fredkin gate. This gate has 1 control qubit (determines if the gate is applied or not) and 2 target qubits (qubits that are swapped).
\[CSWAP = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ \end{bmatrix} \]
CSwap()
CSwap([[1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j]])
In the example below we see that the second and third (target) qubits are swapped, because the first (control) qubit is \(1\).
\[CSWAP|110\rangle = \begin{bmatrix} 1 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 1 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 1 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 0 & 0 & 1 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 1 \\ \end{bmatrix} \begin{bmatrix}0\\0\\0\\0\\0\\1\\0\\0\end{bmatrix} = \begin{bmatrix}0\\0\\0\\0\\0\\0\\1\\0\end{bmatrix} = |101\rangle \]
::: {#cell-76 .cell 0=β1β 1=β1β 2=β0β 3=β>β 4=β β 5=β-β 6=β>β 7=β β 8=βCβ 9=βSβ 10=βWβ 11=βAβ 12=βPβ 13=β β 14=β-β 15=β>β 16=β β 17=β|β 18=β1β 19=β0β 20=β1β 21=β>β execution_count=34}
@ [0,0,0,0,0,1,0,0] CSwap()
CSwap([0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 1.+0.j, 0.+0.j])
:::
This is what a \(CSWAP\) gate looks like in quantum circuits:
="mpl") CSwap().draw(output
With these tools in your toolbox you are ready to build almost any quantum circuit. Subsequent lessons will therefore mostly focus on implementing practical quantum algorithms. We will also discuss the challenges we face with scaling these algorithms on real quantum computers.
Continue with the next lesson: - On Github - On Kaggle
This notebook is part of the q4p (Quantum Computing for Programmers) series. The original notebook can be found on Github.