# Mastering Complex Numbers for Quantum Computing with Python & NumPy

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:

```python
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$$

```python
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$$

```python
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$$

```python
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:

```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)`

```python
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:

```python
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$$

2. Square the result:

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

```python
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}$

```python
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!
