Skip to main content

Mastering Complex Numbers for Quantum Computing with Python & NumPy

Updated 7 min readMarkdown

If you want to understand Quantum Computing, you cannot escape Complex Numbers.

In classical computers, a bit is strictly 0 or 1. But a quantum qubit exists in a superposition state:

$$\vert{}\psi\rangle = \alpha \vert{}0\rangle + \beta \vert{}1\rangle$$

Here, \(\alpha\) and \(\beta\) are not ordinary real numbers — they are complex numbers (called probability amplitudes). The relative phase between quantum states is an angle in the complex plane, and quantum gates are unitary matrices of complex numbers.

In this guide, we'll walk through everything you need to know about complex numbers for quantum computing, backed by practical, executable Python and NumPy examples.


1. The Basics: Writing Complex Numbers in Python

In standard mathematics, the imaginary unit is written as \(i = \sqrt{-1}\). However, in engineering, physics, and Python, we use $j$.

⚠️ Common Beginner Gotcha:

You must always put a numeric coefficient in front of j. Just typing j raises a NameError: name 'j' is not defined.

  • ❌ z = 3 - j
  • ✅ z = 3 - 1j

Also, remember standard NumPy convention:

import numpy as np  # NOT: from numpy import np

2. Basic Arithmetic Operations

Let's take two complex numbers:

$$z_1 = 2 + 3j, \quad z_2 = 5 + 8j$$

import numpy as np

z1 = 2 + 3j
z2 = 5 + 8j

# 1. Addition
sum_result = np.add(z1, z2)        # (7+11j)

# 2. Subtraction
diff_result = np.subtract(z1, z2)  # (-3-5j)

# 3. Multiplication
# (2*5 - 3*8) + (2*8 + 3*5)j = 10 - 24 + 31j = -14 + 31j
prod_result = np.multiply(z1, z2)  # (-14+31j)

# 4. Division
quot_result = np.divide(z1, z2)    # (0.3846-0.0112j)

Tip: In Python and NumPy, standard operators (+, -, *, /) work out of the box on scalars and NumPy arrays!


3. The Complex Conjugate & The Inverse

What is a Complex Conjugate (\(z^*\))?

It simply flips the sign of the imaginary part:

$$\text{If } z = a + bj \implies z^* = a - bj$$

z = 3 + 4j
z_conj = np.conj(z)  # (3-4j)

Why is the conjugate crucial in Quantum?

When you multiply any complex number by its conjugate, the imaginary parts cancel out, leaving a purely real number (magnitude squared):

$$z \times z^* = (a + bj)(a - bj) = a^2 + b^2 = \vert{}z\vert{}^2$$

print(z * z_conj)  # (25+0j)

In quantum mechanics, the probability of measuring a qubit state \(\vert{}\psi\rangle\) is given by Born's Rule:

$$P = \vert{}\alpha\vert{}^2 = \alpha \cdot \alpha^*$$

Multiplicative Inverse (\(\frac{1}{z}\))

Using the conjugate, finding the reciprocal is straightforward:

$$z^{-1} = \frac{1}{z} = \frac{z^*}{\vert{}z\vert{}^2} = \frac{a - bj}{a^2 + b^2}$$

For \(z = 3 - 4j\):

$$\frac{1}{3 - 4j} = \frac{3 + 4j}{3^2 + (-4)^2} = \frac{3 + 4j}{25} = 0.12 + 0.16j$$

In Python:

z = 3 - 4j

# Direct division
inv = 1 / z
print(inv)  # (0.12+0.16j)

# Or via formula:
inv_formula = np.conj(z) / (np.abs(z) ** 2)
print(inv_formula)  # (0.12+0.16j)

4. Polar Form and Euler's Formula

Cartesian form \((a + bj)\) describes a point on a 2D coordinate grid $(x, y)$. Polar form describes that same point as a distance ($r$) and a **counter-clockwise rotation angle (\(\theta\))**.

Euler's Formula

$$e^{j\theta} = \cos(\theta) + j\sin(\theta)$$

Using Euler's formula, any complex number can be written in Exponential Polar Form:

$$\mathbf{z = r \cdot e^{j\theta}}$$

Where:

  • \(r = \sqrt{a^2 + b^2}\) (Magnitude / absolute value) \(\rightarrow\) np.abs(z)
  • \(\theta = \arctan(b / a)\) (Phase / angle in radians) \(\rightarrow\) np.angle(z)
import numpy as np

z = -2 + 2j

# 1. Magnitude (radius)
r = np.abs(z)                      # 2.8284... (2√2)

# 2. Phase Angle
theta_rad = np.angle(z)            # 2.3561... rad (3π/4)
theta_deg = np.degrees(theta_rad)  # 135.0°

# 3. Reconstruct back using Euler's Formula:
z_reconstructed = r * np.exp(1j * theta_rad)
print(np.round(z_reconstructed))   # (-2+2j)

Important Theorem: Modulus of a Product

The magnitude of a product equals the product of their individual magnitudes:

$$\vert{}z_1 \cdot z_2\vert{} = \vert{}z_1\vert{} \cdot \vert{}z_2\vert{}$$

In NumPy:

z1 = 3 + 4j
z2 = 1 - 1j

print(np.isclose(np.abs(z1 * z2), np.abs(z1) * np.abs(z2)))  # True

5. Compound Arithmetic Chains

When evaluating compound expressions, standard operator precedence (PEMDAS) applies to complex numbers just like real numbers.

Take this classic simplification:

$$\left( \frac{1 + j}{1 - j} \right)^2$$

  1. Simplify the fraction inside:

$$\frac{1 + j}{1 - j} = \frac{(1 + j)(1 + j)}{(1 - j)(1 + j)} = \frac{2j}{2} = j$$

  1. Square the result:

$$(j)^2 = -1$$

result = ((1 + 1j) / (1 - 1j)) ** 2
print(result)  # (-1+0j)

(Always remember outer parentheses so Python squares the whole quotient rather than just the denominator!)


6. Roots of Unity: The Quantum Pizza 🍕

What complex numbers satisfy \(z^n = 1\)? These are called the $n$-th Roots of Unity.

In real numbers, only $1$ and \(-1\) can square to $1$. But in complex numbers, there are always exactly $n$ distinct solutions.

To find them, divide the \(360^\circ\) (\(2\pi\) radians) unit circle into $n$ equal slices:

$$\mathbf{\omega_k = e^{j \frac{2\pi k}{n}}, \quad \text{for } k = 0, 1, \dots, n-1}$$

For \(n = 4\) ($4$-th roots of unity, spaced every \(90^\circ\)):

  • \(k = 0 \implies e^{j \cdot 0} = \mathbf{1}\)
  • \(k = 1 \implies e^{j \cdot \pi/2} = \mathbf{j}\)
  • \(k = 2 \implies e^{j \cdot \pi} = \mathbf{-1}\)
  • \(k = 3 \implies e^{j \cdot 3\pi/2} = \mathbf{-j}\)
import numpy as np

n = 4
for k in range(n):
    theta = 2 * np.pi * k / n
    root = np.exp(1j * theta)
    print(f"k={k}: angle={np.degrees(theta):5.1f}° -> root={np.round(root, 4)}")

Why it matters in Quantum Computing: Roots of unity are the foundation of the Quantum Fourier Transform (QFT) and Shor's Algorithm for period finding and RSA cryptography factorization!


7. NumPy vs cmath: What Should You Use for Quantum?

Python has a built-in cmath module, but NumPy is the universal standard in quantum computing:

  1. Statevectors are Vectors: A qubit \(|\psi\rangle\) is a 1D array of complex amplitudes (np.array([1, 0], dtype=complex)).
  2. Gates are Matrices: Operations like Hadamard ($H$), Pauli-$X$, and Pauli-$Z$ are 2D complex matrices.
  3. Gate Application is Matrix Multiplication: Applying a gate to a state is matrix-vector multiplication (@ or np.matmul).
  4. Adjoint / Conjugate Transpose: Taking \(U^\dagger\) is U.conj().T.

cmath only handles individual scalar numbers and cannot work with multidimensional vectors or matrices. All major quantum frameworks — Qiskit, Cirq, PennyLane, QuTiP — are built directly on top of NumPy arrays.


Summary & Quick Cheat Sheet

Concept Math NumPy Code
Complex number \(a + bj\) z = a + bj
Conjugate \(z^* = a - bj\) np.conj(z)
Magnitude \(r = \sqrt{a^2 + b^2}\) np.abs(z)
Phase Angle \(\theta = \arctan(b/a)\) np.angle(z)
Polar \(\rightarrow\) Cartesian \(r e^{j\theta}\) r * np.exp(1j * theta)
Inverse $\frac{1}{z} = \frac{z^*}{ z
$n$-th Root of Unity \(e^{j \frac{2\pi k}{n}}\) np.exp(1j * 2 * np.pi * k / n)

Mastering these operations gives you the solid mathematical intuition needed to handle qubit statevectors, Bloch sphere rotations, and quantum circuits!

Happy Quantum Coding!

About the author

  • Backend Engineer | Python | FastAPI | PostgreSQL | AI I’m a Backend Engineer passionate about building scalable applications, AI-powered systems, APIs, and developer-focused products. I work primarily with Python, FastAPI, PostgreSQL, Firebase, Supabase, and modern cloud technologies. I’m also exploring AI agents, Generative AI, quantum computing, and emerging technologies. On Hashnode, I share practical lessons, technical deep dives, project experiences, and concepts I learn along the way, with a focus on making complex technology easier to understand. Build. Learn. Share.

No comments yet. Be the first to comment.