Skip to content

Quantum Operations ​

All quantum operations require the Quantum effect to be declared on the function. Qubits are linear types and must be either measured or discarded.

Effect Declaration ​

All quantum operations must be used within a function that declares the Quantum effect:

kettle
fn my_quantum_function() -> Int with Quantum
  q = qubit()
  -- quantum operations here
  measure(q)
end fn

The quantum function must be executed with a handler:

kettle
fn main() -> Unit using quantum_simulator, file_io
  result = my_quantum_function()
  print(result)
end fn

Qubit Creation ​

qubit ​

Signature: qubit() -> Qubit

Creates a single qubit initialized in the |0> state.

qubits ​

Signature: qubits(n: Int) -> List[Qubit]

Creates n qubits, all initialized in the |0> state.

bell ​

Signature: bell() -> Tuple[Qubit, Qubit]

Creates a Bell pair - two maximally entangled qubits. When measured, they always produce the same result (both 0 or both 1).

Single-Qubit Gates ​

hadamard ​

Signature: hadamard(q: Qubit) -> Qubit

The Hadamard gate creates equal superposition:

  • |0> becomes (|0> + |1>)/sqrt(2)
  • |1> becomes (|0> - |1>)/sqrt(2)

This is the most fundamental gate for creating quantum superposition.

pauli_x ​

Signature: pauli_x(q: Qubit) -> Qubit

The Pauli-X gate (NOT gate). Flips the qubit state:

  • |0> becomes |1>
  • |1> becomes |0>

pauli_y ​

Signature: pauli_y(q: Qubit) -> Qubit

The Pauli-Y gate. Applies both bit flip and phase flip:

  • |0> becomes i|1>
  • |1> becomes -i|0>

pauli_z ​

Signature: pauli_z(q: Qubit) -> Qubit

The Pauli-Z gate (phase flip). Leaves |0> unchanged but flips the phase of |1>:

  • |0> stays |0>
  • |1> becomes -|1>

t_gate ​

Signature: t_gate(q: Qubit) -> Qubit

The T gate applies a pi/4 phase rotation. Important for universal quantum computation.

s_gate ​

Signature: s_gate(q: Qubit) -> Qubit

The S gate applies a pi/2 phase rotation. Equivalent to two T gates.

rx ​

Signature: rx(theta: Float, q: Qubit) -> Qubit

Rotation around the X-axis by angle theta (in radians).

ry ​

Signature: ry(theta: Float, q: Qubit) -> Qubit

Rotation around the Y-axis by angle theta (in radians).

rz ​

Signature: rz(theta: Float, q: Qubit) -> Qubit

Rotation around the Z-axis by angle theta (in radians).

Multi-Qubit Gates ​

cnot ​

Signature: cnot(control: Qubit, target: Qubit) -> Tuple[Qubit, Qubit]

The Controlled-NOT gate. Flips the target qubit if the control qubit is |1>. This is the primary entangling gate.

ControlTargetResult
000, 0
010, 1
101, 1
111, 0

cz ​

Signature: cz(q1: Qubit, q2: Qubit) -> Tuple[Qubit, Qubit]

The Controlled-Z gate. Applies a phase flip when both qubits are |1>. Symmetric - works the same regardless of which qubit is considered control or target.

swap ​

Signature: swap(q1: Qubit, q2: Qubit) -> Tuple[Qubit, Qubit]

Exchanges the states of two qubits.

ccnot ​

Signature: ccnot(c1: Qubit, c2: Qubit, target: Qubit) -> Tuple[Qubit, Qubit, Qubit]

The Toffoli gate (Controlled-Controlled-NOT). Flips the target qubit only when both control qubits are |1>. This gate is universal for classical computation.

Measurement ​

measure ​

Signature: measure(q: Qubit) -> Int

Measures a qubit in the computational basis, collapsing its superposition. Returns 0 or 1. This consumes the qubit - it cannot be used again after measurement.

measure_all ​

Signature: measure_all(qs: List[Qubit]) -> List[Int]

Measures all qubits in a list, returning a list of 0s and 1s. Consumes all the qubits.

discard ​

Signature: discard(value: Any) -> Unit

Discards a linear value (like a qubit) without measuring it. Use this when you need to dispose of a qubit but don't care about its measurement result.

expect_z ​

Signature: expect_z(q: Qubit) -> Tuple[Expectation, Qubit]

Computes the Pauli-Z expectation value ⟨ψ|Z|ψ⟩ for a qubit. Returns an Expectation record containing:

  • value: The expectation value in [-1, 1]
  • std_error: The standard error of the estimate

Behavior by mode:

Modevaluestd_error
quantum_simulator(shots = N)Statistical estimatesqrt(variance / N)
quantum_simulator(exact = True)Exact from statevector0.0

Non-destructive: The qubit is returned and can be used for further operations.

This is essential for variational quantum algorithms (VQE, QAOA) that need to compute energy expectations without destroying the quantum state.

Classically Controlled Gates ​

cgate ​

Signature: cgate(classical: Int, gate: fn(Qubit) -> Qubit, q: Qubit) -> Qubit

Applies a gate conditionally based on a classical bit value. If classical is 1, the gate is applied; otherwise, the qubit passes through unchanged.

cond_gate ​

Signature: cond_gate(condition: Bool, gate: fn(Qubit) -> Qubit) -> fn(Qubit) -> Qubit

Creates a conditional gate function. Returns a gate that either applies the given gate (if condition is true) or acts as identity (if condition is false).

Gate Summary Table ​

GateQubitsSyntaxDescription
hadamard1q <- hadamardCreates superposition
pauli_x1q <- pauli_xBit flip (NOT)
pauli_y1q <- pauli_yBit and phase flip
pauli_z1q <- pauli_zPhase flip
t_gate1q <- t_gatepi/4 phase
s_gate1q <- s_gatepi/2 phase
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
cz2a, b <- czControlled-Z
swap2a, b <- swapSwap states
ccnot3c1, c2, t <- ccnotToffoli (CCNOT)

Linear Types and Qubits ​

Qubits are linear types in Kettle, meaning:

  1. No cloning: You cannot copy a qubit (enforced by quantum mechanics)
  2. Must consume: Every qubit must be either measured or discarded
  3. Single use: After measurement or discard, the qubit cannot be used again

This is enforced at compile time:

kettle
-- This won't compile!
fn bad() -> Unit with Quantum
  q = qubit()
  measure(q)
  measure(q)  -- Error: q already consumed
end fn

See Also ​