Measurement (shot sampling & pure-state fidelity)¶
A real quantum device never hands back a statevector -- it hands back a stream of
individual measurement outcomes, one per shot, that you have to run many times and
count up to approximate the underlying distribution. sample_counts does that
simulated-device step (a DenseSVSimulator equivalent of Qiskit's get_counts()).
statevector_fidelity answers a different question: how close are two known pure
states to each other -- useful for grading a result against an ideal target, something
no real device measurement alone can tell you.
Step 1. Finite-shot counts from a real statevector¶
import numpy as np
import dense_evolution as de
qasm = 'OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; cx q[0],q[1];'
circuit = de.QASMParser().parse(qasm)
sim = de.DenseSVSimulator(2)
sim.run_circuit_jit(circuit.to_tuples())
sv = sim.get_statevector()
de.sample_counts(sv, n_shots=1000, rng=np.random.default_rng(0))
sv is the same Bell state built on the Simulator page --
sample_counts(statevector, n_shots, rng) draws n_shots independent outcomes from
its exact Born-rule probabilities and returns a dict of bitstring counts, the same
shape get_probabilities() would predict exactly (50/50 here) but with the real
sampling noise a finite number of shots actually has -- 473/527, not 500/500.
Passing rng makes the draw reproducible; omit it for a fresh random draw each call.
Step 2. How close are two pure states?¶
qasm2 = 'OPENQASM 2.0; include "qelib1.inc"; qreg q[2]; h q[0]; h q[1];'
sim2 = de.DenseSVSimulator(2)
sim2.run_circuit_jit(de.QASMParser().parse(qasm2).to_tuples())
sv2 = sim2.get_statevector()
de.statevector_fidelity(sv, sv2)
statevector_fidelity(a, b) is |<a|b>|^2, computed directly on two statevectors --
no density matrix built first, unlike uhlmann_fidelity (this
function's mixed-state counterpart). A state compared to itself gives 1 (up to
floating-point rounding); the Bell state against |++> (independent H on each qubit,
no entanglement) gives exactly 0.5 -- the two states share half their overlap, not
zero and not identical.
Details¶
When to use which fidelity: statevector_fidelity needs both states to be pure
(exact statevectors, as any noiseless simulation produces) -- for a genuinely mixed
state (a real device's noisy output, or anything already reduced via
partial_trace), use uhlmann_fidelity instead, which
takes density matrices.
measurement ¶
Measurement-related conveniences: turning a statevector into finite-shot
counts the way real hardware and every other SDK report results (Qiskit's
get_counts(), PennyLane's qml.counts()), and comparing two pure states
directly without building a density matrix first.
Sampling a statevector into shot counts is another pattern found
hand-duplicated across this package's own experiment scripts -- always
the same rng.choice(dim, p=probs) + np.bincount (or np.unique)
couple of lines, rewritten fresh each time.
sample_counts ¶
Simulate n_shots projective measurements of every qubit in the computational basis, returning a Qiskit-style counts dict.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statevector
|
(array - like, shape(2 ** n_qubits))
|
|
required |
n_shots
|
int
|
Number of measurement shots to sample, must be >= 1. |
required |
rng
|
Generator
|
A fresh |
None
|
Returns:
| Type | Description |
|---|---|
dict[str, int]
|
Bitstring keys read left-to-right as qubit 0 upward (matching DenseSVSimulator's own qubit-0-is-MSB layout and pauli_expectation's string convention), each mapped to how many of the n_shots samples landed on it. Only bitstrings with at least one hit appear (unobserved outcomes are simply absent, as in Qiskit's get_counts()). |
Examples:
>>> import dense_evolution as de
>>> sim = de.DenseSVSimulator(2)
>>> sim.run_circuit([('h', 0), ('cx', 0, 1)])
>>> de.sample_counts(sim.get_statevector(), 1000)
{'00': 494, '11': 506}
Source code in dense_evolution/utils/measurement.py
statevector_fidelity ¶
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
statevector_a
|
(array - like, shape(2 ** n_qubits))
|
Must have the same shape. |
required |
statevector_b
|
(array - like, shape(2 ** n_qubits))
|
Must have the same shape. |
required |
Returns:
| Type | Description |
|---|---|
float
|
In [0, 1] up to floating-point error. 1.0 for identical states (up to global phase), 0.0 for orthogonal states. |