Run basic quantum information use cases in Qrunch
Goal
Run basic custom quantum information use cases in Qrunch, such as sampling bit-strings from a quantum circuit or estimating the expectation value of a Pauli string.
Note Many classes and methods used in this guide are not part of the public API and WILL change in the future.
Prerequisites
Working installation of Qrunch.
A sampler for sampling from quantum circuits. See Create a Sampler for details.
An estimator for estimating expectation values of quantum circuits. See Create an Estimator for details.
Steps
Create a quantum circuit
A quantum circuit in Qrunch is built with the Circuit class. The following example creates a two-qubit
circuit, applies a Hadamard gate to the first qubit and a CNOT gate between the first and second qubits,
preparing a Bell state.
from qrunch.quantum.circuits import Circuit
from qrunch.quantum.gates import CXGate, HGate
circuit = Circuit(num_qubits=2)
circuit.append(HGate(0))
circuit.append(CXGate(0, 1))
Many other gates are available in qrunch.quantum.gates, including single-qubit gates such as
XGate, YGate, ZGate, SGate, HGate and the rotations RXGate, RYGate, RZGate,
as well as two-qubit gates such as CXGate, CZGate and SWAPGate. Use circuit.append to add a
single gate, or circuit.extend to add several at once.
from qrunch.quantum.gates import RXGate, RZGate, XGate
circuit = Circuit(num_qubits=2)
circuit.extend([XGate(0), RXGate(0.5, 1), RZGate(0.25, 0)])
# or in one go
circuit = Circuit(num_qubits=2, gates=[XGate(0), RXGate(0.5, 1), RZGate(0.25, 0)])
Sample from the circuit
To draw measurement outcomes, wrap the circuit in a MeasurementCircuit with the desired number of
shots and pass it to a sampler. The default sampler is created with qc.sampler_creator().
import qrunch as qc
from qrunch.quantum.measurement.measurement_circuit import MeasurementCircuit
options = qc.options.MemoryRestrictedSimulatorOptions(max_number_of_amplitudes=None, use_real_numbers=False)
sampler = qc.sampler_creator().memory_restricted().with_options(options=options).create()
measurement = sampler.run(MeasurementCircuit(circuit, shots=1000))
print(measurement.to_binary_dict()) # e.g. {"00": 0.49, "11": 0.51}
The returned QuantumMeasurement exposes probabilities through to_binary_dict() and raw counts through
as_counts(). For a Bell state the result concentrates on "00" and "11" with roughly equal weight.
All defaults in qrunch are chemistry specific and might not work with a general quantum circuit. The sampler from the
example above is a memory-restricted simulator with no memory restrictions and complex amplitudes that can be used for
general quantum circuits. Any backend sampler should also work.
Estimate a Pauli string expectation value
To estimate \(\langle\psi|P|\psi\rangle\) for a Pauli operator \(P\), build the observable from the
single-qubit Pauli operators X, Y and Z and pass it to an estimator. Operators are indexed by qubit
and combined with multiplication and addition.
import qrunch as qc
from qrunch.quantum.operators.pauli import X, Y, Z
estimator = qc.estimator_creator().create()
# The two-qubit observable Z0 * Z1.
observable = Z(0) * Z(1)
expectation_value = estimator.run(observable, circuit, shots=1000)
print(expectation_value) # estimated expectation value with error.
print(expectation_value.value) # estimated expectation value
print(expectation_value.error) # statistical error from shot noise
Passing shots=None performs an exact, noiseless state-vector estimation, while a positive integer emulates
finite shot noise. Multiple observables can be estimated at once by passing a sequence, which returns one
ExpectationValue per observable.
observables = [Z(0), Z(0) * Z(1), X(0) + X(1)]
expectation_values = estimator.run(observables, circuit, shots=None)
Not public API
The circuits, gates, and operators used in this guide are not part of the public API and WILL change in the future.
A warning will be issued when importing them as a reminder. This warning can be turned off by setting the
environment variable QRUNCH_NO_GUARD to true before importing Qrunch.
import os
os.environ["QRUNCH_NO_GUARD"] = "true"
This also turns off runtime type checking for all Qrunch public api.
Verify the result
For the Bell-state circuit, sampling should yield only
"00"and"11"with probabilities near 0.5 each.Z(0) * Z(1)should evaluate to1.0on the Bell state. Withshots=Nonethe value is exact.
Troubleshooting
ImportError: Check your environment path and reinstall
qrunch.Different qubit ordering: Bit-strings from
to_binary_dict()are big-endian.Large error bars: Increase
shotsor useshots=Nonefor an exact result.