Measurement ​
Measurement is how we extract classical information from quantum states. When you measure a qubit, its superposition collapses to either 0 or 1.
The measure() Function ​
measure(q: Qubit) returns a typed Measurement value — a handle that references a classical-bit slot in the circuit. To read out the bit value, coerce it with read_measurement:
A Measurement has two consumers:
| To... | Use |
|---|---|
| Read the bit value into host code (Int) | read_measurement(m) — this is the "bump" that resolves the bit |
| Apply a classically-conditioned gate | cgate(m, gate, qubit) — emits if (c[bit] == 1) gate q[X]; into the circuit |
Prefer cgate for adaptive corrections (teleportation, Pauli updates) — the conditional is encoded in the QASM itself, so the simulator/hardware applies the gate using its own observed bit. read_measurement reads the bit into host code, which is what you want when the value flows out as the program's result.
Whole-register measurement is different
measure(QInt) and measure(QubitArray[N]) return Int directly — there's no per-bit-index handle to thread through cgate for an N-qubit register. Only single-qubit measure(q: Qubit) returns a Measurement.
Measurement Collapses State ​
Before measurement, a qubit in superposition has probabilities for both outcomes. Measurement forces it into a definite state:
|0> -> always measures 0
|1> -> always measures 1
(|0> + |1>)/sqrt(2) -> measures 0 or 1 with 50% probability eachAfter measurement, the qubit is consumed - it cannot be used again.
Running Multiple Shots ​
Quantum algorithms are probabilistic. To see the distribution of outcomes, run multiple shots:
The shots Parameter ​
The quantum_simulator(shots = N) handler runs your quantum function N times:
fn main() -> Unit using quantum_simulator(shots = 100), file_io
results = my_quantum_fn() -- returns List[T] with 100 elements
end fnWithout shots, you get a single execution:
The counts() Function ​
Use counts() to get a frequency distribution:
Mid-Circuit Measurement ​
You can measure qubits in the middle of a circuit and use the results to control later operations:
cgate(m: Measurement, gate: Gate, q: Qubit) -> Qubit emits a classically-conditioned gate into the circuit (if (c[bit_index] == 1) gate q[X];). The simulator or hardware decides whether to apply the gate at execution time, using its own observed bit. Pass Measurement directly — do not wrap it in read_measurement first, that would resolve the bit into host code and break the conditional's self-consistency under re-execution.
IBM portability
read_measurement reads a bit into host code, which IBM hardware cannot service mid-shot. The typechecker rejects programs that call read_measurement under using ibm_quantum(...) and points you at cgate instead. Adaptive control logic must be encoded in the QASM circuit, not in the host language, for IBM-targeted programs.
Teleportation Example ​
Quantum teleportation uses mid-circuit measurement and classical feedback. Note that m1 and m2 stay as Measurement values — the corrections are encoded as conditional QASM:
This demonstrates:
- Creating an entangled Bell pair
- Bell measurement (mid-circuit, returns
Measurementhandles) - Classical corrections via
cgate(encoded in the circuit, not host-side) - Final readout via
read_measurementat the function boundary
Expectation Values ​
Sometimes you need to know the expected measurement outcome without actually collapsing the qubit. The expect_z function computes the Pauli-Z expectation value ⟨ψ|Z|ψ⟩:
Temporarily disabled
expect_z is currently disabled in the build that ships with this beta — it returns an error pointing at the unified-execution-path refactor. It will be reintroduced via the session trace in a follow-up. Programs that need observable estimation today should stick to sampled measure reads with shots = N and aggregate classically.
How It Works ​
The expect_z function returns an Expectation record with two fields:
exp.value: The expectation value (weighted average of measurement outcomes)exp.std_error: The standard error of the estimate
The expectation value tells you:
- +1 for |0⟩ (would always measure 0)
- -1 for |1⟩ (would always measure 1)
- 0 for equal superposition (50/50 chance)
- cos(θ) after
ry(θ)rotation
Simulation Modes ​
By default, expect_z uses statistical sampling. For debugging with exact values, use quantum_simulator(exact = True). See Backends for details.
Non-Destructive ​
Unlike measure, expect_z does not collapse the qubit:
(exp, q) = expect_z(q) -- Returns (Expectation, Qubit) tuple
-- Access the value and error
print(exp.value)
print(exp.std_error)
-- q can still be used!
q <- hadamard
measure(q)This is useful for variational algorithms (VQE, QAOA) where you compute energies many times during optimization.
Use Cases ​
- VQE: Compute molecular ground state energies
- QAOA: Evaluate cost function for optimization problems
- Quantum machine learning: Gradient computation for training