Skip to content

Gates ​

Gates are functions that transform qubit states. They're reversible and operate on probability amplitudes.

Applying Gates with <- ​

Quantum gates use the same rebind operator (<-) you learned in Language Basics. This creates a unified model—whether you're transforming numbers or qubits, the syntax is the same:

ContextCodeMeaning
Classicalx <- doubleRebind x to double(x)
Quantumq <- hadamardRebind q to hadamard(q)

The syntax q <- hadamard is sugar for q <- hadamard(q). The gate function takes a qubit, transforms it, and the result is rebound to the same variable.

kettle
q <- hadamard      -- apply Hadamard gate to q
q <- pauli_x       -- apply Pauli-X gate to q

Gates can be chained in sequence:

Single-Qubit Gates ​

Hadamard Gate ​

The most important gate - creates equal superposition:

kettle
q <- hadamard    -- |0> -> (|0> + |1>)/sqrt(2)

Pauli Gates ​

The three Pauli gates rotate around different axes:

GateEffect
pauli_xBit flip: swaps
pauli_yBit and phase flip
pauli_zPhase flip:

Rotation Gates ​

Parameterized rotations around each axis:

GateDescription
rx(theta)Rotate around X-axis by theta radians
ry(theta)Rotate around Y-axis by theta radians
rz(theta)Rotate around Z-axis by theta radians

Multi-Qubit Gates ​

CNOT (Controlled-NOT) ​

The workhorse of quantum computing - flips the target qubit when the control is |1>:

kettle
control, target <- cnot   -- flip target if control is |1>

CZ (Controlled-Z) ​

Applies a phase flip when both qubits are |1>:

SWAP ​

Exchanges the states of two qubits:

Toffoli (CCNOT) ​

A three-qubit gate - flips the target only when both controls are |1>:

Gate Summary ​

GateQubitsSyntaxDescription
hadamard1q <- hadamardCreates superposition
pauli_x1q <- pauli_xBit flip (NOT)
pauli_y1q <- pauli_yBit and phase flip
pauli_z1q <- pauli_zPhase flip
rx(theta)1q <- rx(1.57)X-axis rotation
ry(theta)1q <- ry(1.57)Y-axis rotation
rz(theta)1q <- rz(1.57)Z-axis rotation
cnot2c, t <- cnotControlled-NOT
cz2c, t <- czControlled-Z
cy2c, t <- cyControlled-Y
ch2c, t <- chControlled-Hadamard
crx(theta)2(c, t) = crx(1.57, c, t)Controlled X-rotation
cry(theta)2(c, t) = cry(1.57, c, t)Controlled Y-rotation
crz(theta)2(c, t) = crz(1.57, c, t)Controlled Z-rotation
swap2q1, q2 <- swapSwap qubit states
ccnot3c1, c2, t <- ccnotToffoli
ccz3(c1, c2, t) = ccz(c1, c2, t)Controlled-controlled-Z

Gate Inverses ​

All quantum gates (except measurement) are reversible. Many are self-inverse; others have explicit adjoint versions:

GateInverseNotes
hadamardhadamardSelf-inverse
pauli_x, pauli_y, pauli_zSame gateSelf-inverse
cnot, cz, cy, chSame gateSelf-inverse
swapswapSelf-inverse
ccnot, cczSame gateSelf-inverse
s_gates_gate_dagS† (inverse phase)
t_gatet_gate_dagT† (inverse π/8 phase)
rx(θ), ry(θ), rz(θ)rx(-θ), ry(-θ), rz(-θ)Negate angle
crx(θ), cry(θ), crz(θ)crx(-θ), cry(-θ), crz(-θ)Negate angle

Manual uncomputation:

kettle
fn apply_and_undo(q: Qubit) -> Qubit with Quantum
  q <- hadamard     -- Apply H
  q <- hadamard     -- Undo H (self-inverse)

  q <- t_gate       -- Apply T
  q <- t_gate_dag   -- Undo T

  q <- rx(1.57)     -- Rotate by θ
  q <- rx(-1.57)    -- Rotate by -θ (undo)
  q
end fn

For automatic uncomputation, see Compute Blocks.