# Quantum Operations and Gates

```elixir
Mix.install([
  {:qx, "~> 0.11", hex: :qx_sim},
  {:kino, "~> 0.12"},
  {:vega_lite, "~> 0.1.11"},
  {:kino_vega_lite, "~> 0.1.11"}
])
```

## Learning objectives

By the end of this tutorial you will be able to:

* Explain why every quantum gate is a unitary matrix, and verify unitarity numerically
* Apply the Pauli gates ($X$, $Y$, $Z$) and the Hadamard gate, and predict their effect on any state you met in the previous tutorial
* Use the phase gates ($S$, $T$) and rotation gates ($R_x$, $R_y$, $R_z$) to move a state anywhere on the Bloch sphere
* Demonstrate that quantum gates are reversible by undoing them
* Watch a circuit evolve gate by gate with `Qx.steps/2`, then end it with a measurement and read shot statistics from `Qx.run/2`

## Introduction

This is the second tutorial in the series, following **Quantum State and The Qubit**. There we established what a qubit *is*: a normalised vector $\ket{\psi} = \alpha\ket{0} + \beta\ket{1}$, visualised as a point on the Bloch sphere. This tutorial is about what qubits *do* — or rather, what we do to them.

A quantum computation is a sequence of operations applied to qubits. The operations are called **quantum gates**, by analogy with the logic gates of classical computing. The analogy is real but imperfect, and the differences are where quantum computing gets interesting: quantum gates are rotations, they are always reversible, and some of them manipulate information (phase) that no classical bit can hold.

Every example is a small circuit: queue gates with `Qx.create_circuit` pipelines, then step through the result with `Qx.steps/2` to inspect the state after every gate. At the end we add the missing piece, measurement with shots via `Qx.run/2`, which the rest of the series relies on.

**Prerequisites:** the previous tutorial in this series. Everything here builds on state vectors, amplitudes, bases, phase, and the Bloch sphere as covered there.

## Gates are unitary matrices

In the previous tutorial we represented a qubit state as a column vector. Quantum mechanics says that the evolution of an isolated quantum system is *linear*: the new state is a matrix multiplied by the old state. For a single qubit, that matrix is $2 \times 2$ with complex entries:

$$
\ket{\psi'} = U\ket{\psi}
$$

Not just any matrix qualifies. The output must still be a valid quantum state, so $U$ must preserve the normalisation $|\alpha|^2 + |\beta|^2 = 1$ for *every* input. Matrices that preserve vector length are called **unitary**, and they satisfy:

$$
U^\dagger U = I
$$

where $U^\dagger$ (the *adjoint* or *conjugate transpose*) is obtained by transposing $U$ and conjugating each entry, and $I$ is the identity matrix.

Unitarity has two consequences worth holding onto for the rest of the series:

1. **Gates are rotations.** A length-preserving transformation of the Bloch sphere is a rotation of it. Every single-qubit gate rotates the state vector around some axis, by some angle.
2. **Gates are reversible.** $U^\dagger$ undoes $U$ exactly. No information is ever destroyed by a gate — a sharp contrast with classical gates like AND, which take 2 bits in and give 1 bit out.

Let's check the first claim empirically. A pipeline of gates applied to any state should always leave a valid, normalised qubit:

```elixir
# Run this several times: random start, arbitrary gates, still normalised
[a, b] = for _ <- 1..2, do: :rand.uniform() * 2 * :math.pi()

Qx.create_circuit(1)
|> Qx.ry(0, a)
|> Qx.phase(0, b)
|> Qx.h(0)
|> Qx.t(0)
|> Qx.rx(0, 0.7)
|> Qx.z(0)
|> Qx.get_probabilities()
|> Nx.sum()
```

The first two rotations use random angles, so the pipeline starts from a different state every run. However the qubit starts and whatever we throw at it, the probabilities always sum to 1: the norm survives. Now let's meet the gates individually.

## The Pauli-X gate: bit flip

The $X$ gate is the closest thing quantum computing has to the classical NOT. Its matrix swaps the two amplitudes:

$$
X = \begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}, \qquad X\begin{pmatrix} \alpha \\ \beta \end{pmatrix} = \begin{pmatrix} \beta \\ \alpha \end{pmatrix}
$$

On basis states it acts exactly like NOT: $X\ket{0} = \ket{1}$ and $X\ket{1} = \ket{0}$.

```elixir
# X flips |0⟩ to |1⟩
Qx.create_circuit(1)
|> Qx.x(0)
|> Qx.steps()
|> Enum.to_list()
```

Each step line shows the gate that just ran and the state right after it, and that single step reads $1.000\ket{1}$. On the Bloch sphere, $X$ is a half-turn ($\pi$ radians) around the X-axis — which is why $\ket{0}$ at the north pole lands on $\ket{1}$ at the south pole.

**Predict first:** what does $X$ do to the superposition $\ket{+} = \frac{1}{\sqrt{2}}(\ket{0} + \ket{1})$? Apply the amplitude-swap rule, then run the cell. (The $H$ gate on the first line builds $\ket{+}$ from $\ket{0}$; it gets a proper introduction three sections down.)

```elixir
Qx.create_circuit(1)
|> Qx.h(0)
|> Qx.x(0)
|> Qx.steps()
|> Enum.to_list()
```

The two steps show the same state. Swapping two equal amplitudes gives the same state back. Geometrically, $\ket{+}$ sits *on* the X-axis, and rotating around an axis leaves the points on that axis fixed. States that a gate leaves unchanged are called **eigenstates** of that gate, and they matter a great deal in later tutorials.

## The Pauli-Z gate: phase flip

The $Z$ gate looks almost trivial:

$$
Z = \begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}, \qquad Z\begin{pmatrix} \alpha \\ \beta \end{pmatrix} = \begin{pmatrix} \alpha \\ -\beta \end{pmatrix}
$$

It leaves $\ket{0}$ untouched and merely flips the sign of the $\ket{1}$ amplitude. From the previous tutorial you know exactly what that sign is: the **relative phase**. $Z$ is a half-turn around the Z-axis.

```elixir
# Z turns |+⟩ into |−⟩
qc = Qx.create_circuit(1) |> Qx.h(0) |> Qx.z(0)

qc |> Qx.steps() |> Enum.to_list()
```

The final amplitudes read $0.707$ and $-0.707$: this is $\ket{-}$. And as we established last time, a Z-basis measurement can't see the difference, but an X-basis one can. `Qx.get_probabilities/1` reads the Z-basis distribution straight off the circuit, and adding one more $H$ rotates the X-basis onto the Z-basis so the same trick reads the X-basis:

```elixir
qc |> Qx.get_probabilities() |> IO.inspect(label: "Z-basis (blind to the flip)")

qc |> Qx.h(0) |> Qx.get_probabilities() |> IO.inspect(label: "X-basis (sees it: this is |−⟩)")
```

```elixir
Qx.draw_bloch(Qx.get_state(qc))
```

The Bloch vector has swung from the positive X-axis to the negative X-axis: a half-turn about Z, exactly as advertised. $X$ flips bits; $Z$ flips phase. The two flips are equally physical, and quantum algorithms use both.

## The Pauli-Y gate

The third Pauli gate does both flips at once, with complex entries:

$$
Y = \begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}, \qquad Y\begin{pmatrix} \alpha \\ \beta \end{pmatrix} = \begin{pmatrix} -i\beta \\ i\alpha \end{pmatrix}
$$

**Predict first:** apply the action rule to $\ket{0} = \begin{pmatrix} 1 \\ 0 \end{pmatrix}$. The amplitudes swap like $X$, but each also picks up a factor of $\pm i$ — which entry gets which sign? Work it out, then run:

```elixir
Qx.create_circuit(1)
|> Qx.y(0)
|> Qx.steps()
|> Enum.at(-1)
|> Qx.Step.show()
```

The result is $i\ket{1}$: the bit flipped *and* picked up a phase of $i$. Since the factor $i$ here multiplies the entire state, it is a **global phase** with no observable effect — the measurement probabilities are identical to those of $X\ket{0}$. On the Bloch sphere, $Y$ is a half-turn around the Y-axis. Together $X$, $Y$, $Z$ give a half-turn around each of the sphere's three axes.

```elixir
Qx.draw_bloch(Qx.create_circuit(1) |> Qx.y(0) |> Qx.get_state())
```

## The Hadamard gate

The Hadamard gate is the workhorse of quantum computing — it is how nearly every algorithm creates superposition from definite states:

$$
H = \frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}
$$

Its action on the basis states:

$$
H\ket{0} = \frac{\ket{0} + \ket{1}}{\sqrt{2}} = \ket{+} \qquad H\ket{1} = \frac{\ket{0} - \ket{1}}{\sqrt{2}} = \ket{-}
$$

$H$ converts the Z-basis into the X-basis and back. Geometrically it is a half-turn around the diagonal axis that lies midway between X and Z.

```elixir
qc = Qx.create_circuit(1) |> Qx.h(0)

qc |> Qx.steps() |> Enum.to_list()
```

```elixir
Qx.draw_bloch(Qx.get_state(qc))
```

**Predict first:** what does applying $H$ twice do? Trace $\ket{0} \to \ket{+} \to \,?$ through the equations above, then run:

```elixir
Qx.create_circuit(1)
|> Qx.h(0)
|> Qx.h(0)
|> Qx.steps()
|> Enum.to_list()
```

Back to $\ket{0}$: the Hadamard is its own inverse, $H^2 = I$. We can verify this at the matrix level. $H$ is real and symmetric, so $H^\dagger = H$, and the unitarity condition $H^\dagger H = I$ becomes simply $H \cdot H = I$:

```elixir
h = Nx.divide(Nx.tensor([[1.0, 1.0], [1.0, -1.0]]), :math.sqrt(2))
Nx.dot(h, h)
```

The identity matrix, up to floating-point dust. This is what "unitary" looks like as arithmetic.

One more useful fact — $H$ maps $\ket{1}$ to $\ket{-}$, which we can confirm with the basis-change trick from the $Z$ section: one more $H$ rotates the X-basis question into the Z-basis, where we can read probabilities directly:

```elixir
Qx.create_circuit(1)
|> Qx.x(0)
|> Qx.h(0)   # build |−⟩ from |1⟩
|> Qx.h(0)   # rotate the X-basis onto the Z-basis
|> Qx.get_probabilities()
```

Probability 1 at index 1: definitely $\ket{-}$.

## Phase gates: S and T

$Z$ flips the phase by a half-turn ($\pi$). The $S$ and $T$ gates apply finer phase rotations:

$$
S = \begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix} \qquad T = \begin{pmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{pmatrix}
$$

$S$ rotates the phase by $\pi/2$ (a quarter-turn around the Z-axis) and $T$ by $\pi/4$ (an eighth-turn). A quarter-turn applied to $\ket{+}$ should carry it from the X-axis to the Y-axis — that is, onto $\ket{i}$. The basis-change trick verifies it: `Qx.get_probabilities/1` reads the Z-basis, one extra $H$ reads the X-basis, and $S^\dagger$ then $H$ reads the Y-basis ($S^\dagger$ is the inverse quarter-turn; we meet it properly just below):

```elixir
sq = Qx.create_circuit(1) |> Qx.h(0) |> Qx.s(0)

sq |> Qx.get_probabilities() |> IO.inspect(label: "Z-basis")
sq |> Qx.h(0) |> Qx.get_probabilities() |> IO.inspect(label: "X-basis")
sq |> Qx.sdg(0) |> Qx.h(0) |> Qx.get_probabilities() |> IO.inspect(label: "Y-basis")
```

A 50/50 coin to the Z and X bases, but certainty in the Y-basis: this is $\ket{i}$.

```elixir
Qx.draw_bloch(Qx.get_state(sq))
```

**Predict first:** if $T$ is an eighth-turn and $S$ is a quarter-turn, what should two $T$ gates equal? Run the cell and compare the state vectors:

```elixir
two_ts = Qx.create_circuit(1) |> Qx.h(0) |> Qx.t(0) |> Qx.t(0) |> Qx.get_state()
one_s = Qx.create_circuit(1) |> Qx.h(0) |> Qx.s(0) |> Qx.get_state()

{two_ts, one_s}
```

Identical up to floating-point dust in the last digit: $T^2 = S$, and by the same logic $S^2 = Z$. Phase gates compose by adding their angles.

Unlike the Paulis and $H$, the $S$ gate is *not* its own inverse (a quarter-turn forward twice is a half-turn, not a return). Its inverse is the $S^\dagger$ gate, available as `Qx.sdg/2`. Step through the round trip:

```elixir
Qx.create_circuit(1)
|> Qx.h(0)
|> Qx.s(0)
|> Qx.sdg(0)
|> Qx.steps()
|> Enum.to_list()
```

That round trip is not a coincidence of this particular gate — it is the unitarity law $U^\dagger U = I$ from the start of this tutorial, caught in the act. The dagger is not just notation: $S^\dagger$ is literally the conjugate transpose of $S$, a matrix you can build yourself. We verified $H \cdot H = I$ at the matrix level earlier; do the same for $S$, constructing the dagger in its two visible steps:

```elixir
i = Complex.new(0, 1)
s = Nx.tensor([[1, 0], [0, i]], type: :c64)
s_dag = s |> Nx.transpose() |> Nx.conjugate()

IO.inspect(s_dag, label: "S† = transpose, then conjugate")
Nx.dot(s_dag, s)
```

Two things to read off. First, $S^\dagger \neq S$: transposing did nothing (the matrix is diagonal), but conjugating turned the $i$ into $-i$. $H$ got away with $H^\dagger = H$ because it is real and symmetric; $S$ is not, and the arithmetic shows exactly where its self-inverseness fails. Second, $S^\dagger S$ is the identity matrix on the nose — the unitarity condition, no longer quoted but computed.

This is the general picture. The self-inverse gates ($X$, $Y$, $Z$, $H$) are precisely the ones whose conjugate transpose is themselves, $U^\dagger = U$. For every other gate the inverse is a genuinely *different* matrix, so the computer needs it as a separate gate — that is why `Qx.sdg/2` and `Qx.tdg/2` exist. But unitarity guarantees the inverse is always there: every gate can be undone, and $U^\dagger$ is how you spell the undo.

The same goes for $T$, and we have already proved it. We saw above that $T^2 = S$, so two $T$ gates land on $S$, not on the identity. $T$ isn't its own inverse. Its turn is just finer, so the full cycle is longer:

$$
T^2 = S, \qquad T^4 = Z, \qquad T^8 = I
$$

Eight eighth-turns add up to a full $2\pi$ trip around the Z-axis, back to where you started. Run all eight on $\ket{+}$ and compare:

```elixir
t_eighth =
  Qx.create_circuit(1)
  |> Qx.h(0)
  |> Qx.t(0) |> Qx.t(0) |> Qx.t(0) |> Qx.t(0)
  |> Qx.t(0) |> Qx.t(0) |> Qx.t(0) |> Qx.t(0)
  |> Qx.get_state()

just_plus = Qx.create_circuit(1) |> Qx.h(0) |> Qx.get_state()

{t_eighth, just_plus}
```

Identical, again up to floating-point dust: eight $T$s return $\ket{+}$.

To undo a single $T$ you want its $T^\dagger$ gate, available as `Qx.tdg/2` — the counterpart of `Qx.sdg/2`:

```elixir
Qx.create_circuit(1)
|> Qx.h(0)
|> Qx.t(0)
|> Qx.tdg(0)
|> Qx.steps()
|> Enum.to_list()
```

The $T$ and the $T^\dagger$ cancel: the last step shows $\ket{+}$ restored. Worth knowing: $T^\dagger$ is nothing more than a $-\pi/4$ phase, so `Qx.phase(qc, 0, -:math.pi() / 4)` does the same job — `Qx.phase/3` with $-\phi$ inverts *any* phase gate, including angles that have no named dagger.

## Rotation gates

The fixed gates above are special cases of a continuous family. The rotation gates turn the Bloch vector by *any* angle $\theta$ around each axis:

$$
R_y(\theta) = \begin{pmatrix} \cos\frac{\theta}{2} & -\sin\frac{\theta}{2} \\ \sin\frac{\theta}{2} & \cos\frac{\theta}{2} \end{pmatrix}
$$

with analogous $R_x(\theta)$ and $R_z(\theta)$ (their matrices involve $i$; the pattern of half-angles is the same). Note the $\theta/2$ inside the matrix — the same Hilbert-space-vs-sphere factor of 2 we derived in the previous tutorial.

One disambiguation before you meet $R_z$ in the wild: `Qx.phase/3`, which you have been using since the previous tutorial, *also* turns the Bloch vector about the Z-axis. On a single qubit $R_z(\theta)$ and $\text{phase}(\theta)$ differ only by a global phase of $e^{-i\theta/2}$, so they are physically interchangeable — another appearance of the global-phase quirk, and worth remembering when hardware-oriented material writes everything in terms of $R_z$.

**Predict first:** $R_y(\pi/2)$ turns $\ket{0}$ a quarter of the way around the Y-axis. Starting at the north pole, where does a quarter-turn land? Check the matrix: $\cos(\pi/4) = \sin(\pi/4) = \frac{1}{\sqrt{2}}$.

```elixir
Qx.create_circuit(1)
|> Qx.ry(0, :math.pi() / 2)
|> Qx.steps()
|> Enum.to_list()
```

It lands on $\ket{+}$, on the equator. A rotation gate with the right angle reaches any point on the sphere, which is why hardware only needs a small set of these to do everything.

A half-turn should reproduce a Pauli gate. Almost:

```elixir
Qx.create_circuit(1)
|> Qx.rx(0, :math.pi())
|> Qx.steps()
|> Enum.at(-1)
|> Qx.Step.show()
```

The amplitude reads $-i$ rather than $1$, yet the measurement probabilities match $X\ket{0}$ exactly. That stray $-i$ multiplies the whole state — another unobservable global phase. $R_x(\pi)$ and $X$ are physically the same operation.

### Drive the rotation yourself

Run the slider cell, then re-run the render cell each time you change the angle:

```elixir
theta_input = Kino.Input.range("θ — rotation angle (0 to 2π)", min: 0.0, max: 6.28318, step: 0.01, default: 0.0)
```

```elixir
theta = Kino.Input.read(theta_input)

Qx.create_circuit(1)
|> Qx.ry(0, theta)
|> Qx.tap_state(fn state ->
  IO.inspect(Nx.to_flat_list(state), label: "After ry(#{Float.round(theta, 2)}) on |0⟩")
end)
|> Qx.get_state()
|> Qx.draw_bloch()
```

Experiments worth running:

* $\theta = \pi/2$ should land on $\ket{+}$ and $\theta = \pi$ on $\ket{1}$, sweeping down the X–Z plane.
* Push $\theta$ all the way to $2\pi$, a full turn, and look closely at the amplitude of $\ket{0}$. It comes back as $-1$, not $+1$. A qubit needs a $4\pi$ rotation to truly return to its original description — a deep quantum fact (physicists call such objects *spinors*). The minus sign is a global phase, so no measurement can detect it here, but it becomes physical when only *part* of a system is rotated. File it away for the entanglement tutorial.

## Reversibility

Unitarity promised that every gate can be undone, and the $S^\dagger$ arithmetic in the phase-gate section showed the mechanism: conjugate-transpose the matrix and you are holding the inverse. So this list is a corollary, not a catalogue — the inverses we have met:

* $X$, $Y$, $Z$, $H$ — each is its own inverse
* $S$ — undone by `Qx.sdg/2`; $T$ — undone by `Qx.tdg/2`; arbitrary phases by `Qx.phase/3` with the negated angle
* $R_x$, $R_y$, $R_z$ — undone by rotating the same axis with $-\theta$

Watch reversal work on a state we don't even know. Two rotations with random angles put the qubit somewhere unpredictable on the sphere, then $H$ twice takes it away and brings it back:

```elixir
# Run this a few times — H followed by H restores any random start
theta = :rand.uniform() * :math.pi()
phi = :rand.uniform() * 2 * :math.pi()

Qx.create_circuit(1)
|> Qx.ry(0, theta)
|> Qx.phase(0, phi)
|> Qx.h(0)
|> Qx.h(0)
|> Qx.steps()
|> Enum.to_list()
```

The last step matches the state on the `phase` line every time: the second $H$ undid the first. Compare this with a classical AND gate: given the output `0`, you cannot say whether the inputs were `00`, `01`, or `10` — information is gone. A quantum computation never loses information between gates. The only irreversible step in quantum computing is measurement, which is the subject of the next tutorial.

## Running a circuit with shots

So far we have peeked at the state after every gate with `Qx.steps/2`: invaluable for learning, impossible on real hardware, where the state cannot be inspected mid-computation. A real quantum program ends with **measurements**, runs many times, and hands back statistics. That last piece is `Qx.run/2`:

```elixir
# 1 qubit, 1 classical bit to hold the measured result
qc =
  Qx.create_circuit(1, 1)
  |> Qx.h(0)
  |> Qx.measure(0, 0)

result = Qx.run(qc, shots: 1024)
IO.inspect(result.counts, label: "counts")
Qx.draw_counts(result, title: "H then measure — 1024 shots")
```

Reading the pipeline: `create_circuit(1, 1)` declares one qubit (which starts in $\ket{0}$) and one classical bit, `h(0)` queues a Hadamard on qubit 0, and `measure(0, 0)` records qubit 0's outcome into classical bit 0. Nothing executes until `Qx.run/2`, which simulates the circuit 1024 times — each repetition is called a **shot** — and tallies the outcomes.

The chart shows roughly 512 counts each for `0` and `1`. That's our familiar $\ket{+}$ state, seen the way an experimenter sees it: through repeated measurement statistics rather than direct state inspection.

Above the chart, the inspected `result.counts` shows the same data as a plain map — something like `%{"0" => 518, "1" => 506}` — where each key is the classical-bit string in measurement order. The chart is for your eyes; this map is what your programs read, and it is the shape every later tutorial (and any real Qx program) consumes.

**Try it:** add `Qx.x(0)` before the Hadamard in the circuit above and predict the counts before re-running. (Recall $H\ket{1} = \ket{-}$, and what $\ket{-}$ gives under Z-basis measurement.)

Why the counts are *roughly* 512 rather than exactly, what measurement does to the state, and how to measure in other bases at circuit level — all of that is the next tutorial's territory.

## Gate cheat sheet

| Gate            | Qx                        | Matrix                                                            | Bloch action                       | Inverse             |
| --------------- | ------------------------- | ----------------------------------------------------------------- | ---------------------------------- | ------------------- |
| $X$             | `Qx.x/2`                  | $\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}$                    | half-turn about X                  | itself              |
| $Y$             | `Qx.y/2`                  | $\begin{pmatrix} 0 & -i \\ i & 0 \end{pmatrix}$                   | half-turn about Y                  | itself              |
| $Z$             | `Qx.z/2`                  | $\begin{pmatrix} 1 & 0 \\ 0 & -1 \end{pmatrix}$                   | half-turn about Z                  | itself              |
| $H$             | `Qx.h/2`                  | $\frac{1}{\sqrt{2}}\begin{pmatrix} 1 & 1 \\ 1 & -1 \end{pmatrix}$ | half-turn about X+Z diagonal       | itself              |
| $S$             | `Qx.s/2`                  | $\begin{pmatrix} 1 & 0 \\ 0 & i \end{pmatrix}$                    | quarter-turn about Z               | `Qx.sdg/2`          |
| $T$             | `Qx.t/2`                  | $\begin{pmatrix} 1 & 0 \\ 0 & e^{i\pi/4} \end{pmatrix}$           | eighth-turn about Z                | `Qx.tdg/2`          |
| $R_x, R_y, R_z$ | `Qx.rx/3`, `ry/3`, `rz/3` | half-angle rotation matrices                                      | any angle $\theta$ about that axis | same axis, $-\theta$ |

Each takes the circuit and a qubit index (rotations add the angle), so gates chain naturally in a pipeline.

## Summary

* **Gates are unitary matrices:** $U^\dagger U = I$. Unitarity preserves normalisation, makes every gate a rotation of the Bloch sphere, and guarantees reversibility.
* **The Pauli gates** give half-turns about the three axes: $X$ flips bits, $Z$ flips phase, $Y$ does both.
* **The Hadamard gate** converts between the Z-basis and the X-basis, creating superposition from definite states. It is its own inverse.
* **Phase gates** $S$ and $T$ apply quarter- and eighth-turns about Z; their effects are invisible to Z-basis measurements but show up in the X and Y bases.
* **Rotation gates** reach any point on the Bloch sphere, and expose the global-phase quirk that a $2\pi$ turn returns a qubit with a minus sign.
* **Circuits build, then run.** Queue gates with `Qx.create_circuit/2` pipelines, watch the state evolve with `Qx.steps/2` while you learn, and read shot statistics from `Qx.run/2` when the circuit ends in a measurement.

### What's next

In the next tutorial, **Quantum Measurement**, we look closely at the one operation that is *not* unitary: why measurement is irreversible, what collapse does to a superposition, where the randomness in shot counts comes from, and how to measure in any basis at circuit level.
