qml.quantum_monte_carlo¶
- quantum_monte_carlo(tape, wires, target_wire, estimation_wires)[source]¶
Applies the transform quantum Monte Carlo estimation algorithm.
The input tape` should be the quantum circuit corresponding to the F unitary in the paper above. This unitary encodes the probability distribution and random variable onto
wires
so that measurement of thetarget_wire
provides the expectation value to be estimated. The quantum Monte Carlo algorithm then estimates the expectation value using quantum phase estimation (check outQuantumPhaseEstimation
for more details), using theestimation_wires
.Note
A complementary approach for quantum Monte Carlo is available with the
QuantumMonteCarlo
template.The
quantum_monte_carlo
transform is intended for use when you already have the circuit for performing F set up, and is compatible with resource estimation and potential hardware implementation. TheQuantumMonteCarlo
template is only compatible with simulators, but may perform faster and is suited to quick prototyping.- Parameters
tape (QNode or QuantumTape or Callable) – the quantum circuit that applies quantum operations according to the F unitary used as part of quantum Monte Carlo estimation
wires (Union[Wires or Sequence[int]]) – the wires acted upon by the
fn
circuittarget_wire (Union[Wires, int]) – The wire in which the expectation value is encoded. Must be contained within
wires
.estimation_wires (Union[Wires, Sequence[int], or int]) – the wires used for phase estimation
- Returns
The transformed circuit as described in
qml.transform
. Executing this circuit will perform the quantum Monte Carlo estimation.- Return type
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]
- Raises
ValueError – if
wires
andestimation_wires
share a common wire
Usage Details
Consider an input quantum circuit
fn
that performs the unitaryF=RA.Here, the unitary A prepares a probability distribution p(i) of dimension M=2m over m≥1 qubits:
A|0⟩⊗m=∑i∈Xp(i)|i⟩,where X={0,1,…,M−1} and |i⟩ is the basis state corresponding to i. The R unitary imprints the result of a function f:X→[0,1] onto an ancilla qubit:
R|i⟩|0⟩=|i⟩(√1−f(i)|0⟩+√f(i)|1⟩).Following this paper, the probability of measuring the state |1⟩ in the final qubit is
μ=∑i∈Xp(i)f(i).However, it is possible to measure μ more efficiently using quantum Monte Carlo estimation. This function transforms an input quantum circuit
fn
that performs the unitary F to a larger circuit for measuring μ using the quantum Monte Carlo algorithm.The algorithm proceeds as follows:
The probability distribution p(i) is encoded using a unitary A applied to the first m qubits specified by
wires
.The function f(i) is encoded onto the
target_wire
using a unitary R.The unitary Q is defined with eigenvalues e±2πiθ such that the phase θ encodes the expectation value through the equation μ=(1+cos(πθ))/2. The circuit in steps 1 and 2 prepares an equal superposition over the two states corresponding to the eigenvalues e±2πiθ.
The circuit returned by this function is applied so that ±θ can be estimated by finding the probabilities of the n estimation wires. This in turn allows for the estimation of μ.
Visit Rebentrost et al. (2018) for further details. In this algorithm, the number of applications N of the Q unitary scales as 2n. However, due to the use of quantum phase estimation, the error ϵ scales as O(2−n). Hence,
N=O(1ϵ).This scaling can be compared to standard Monte Carlo estimation, where N samples are generated from the probability distribution and the average over f is taken. In that case,
N=O(1ϵ2).Hence, the quantum Monte Carlo algorithm has a quadratically improved time complexity with N.
Example
Consider a standard normal distribution p(x) and a function f(x)=sin2(x). The expectation value of f(x) is ∫∞−∞f(x)p(x)dx≈0.432332. This number can be approximated by discretizing the problem and using the quantum Monte Carlo algorithm.
First, the problem is discretized:
from scipy.stats import norm m = 5 M = 2 ** m xmax = np.pi # bound to region [-pi, pi] xs = np.linspace(-xmax, xmax, M) probs = np.array([norm().pdf(x) for x in xs]) probs /= np.sum(probs) func = lambda i: np.sin(xs[i]) ** 2 r_rotations = np.array([2 * np.arcsin(np.sqrt(func(i))) for i in range(M)])
The
quantum_monte_carlo
transform can then be used:from pennylane.templates.state_preparations.mottonen import ( _apply_uniform_rotation_dagger as r_unitary, ) n = 6 N = 2 ** n a_wires = range(m) wires = range(m + 1) target_wire = m estimation_wires = range(m + 1, n + m + 1) dev = qml.device("default.qubit", wires=(n + m + 1)) def fn(): qml.templates.MottonenStatePreparation(np.sqrt(probs), wires=a_wires) r_unitary(qml.RY, r_rotations, control_wires=a_wires[::-1], target_wire=target_wire) @qml.qnode(dev) def qmc(): qml.quantum_monte_carlo(fn, wires, target_wire, estimation_wires)() return qml.probs(estimation_wires) phase_estimated = np.argmax(qmc()[:int(N / 2)]) / N
The estimated value can be retrieved using the formula μ=(1−cos(πθ))/2
>>> (1 - np.cos(np.pi * phase_estimated)) / 2 0.42663476277231915
It is also possible to explore the resources required to perform the quantum Monte Carlo algorithm
>>> qml.specs(qmc, level="device")() {'resources': Resources( num_wires=12, num_gates=31882, gate_types=defaultdict(<class 'int'>, {'RY': 7747, 'CNOT': 7874, 'Hadamard': 258, 'CZ': 126, 'Adjoint(CNOT)': 7812, 'Adjoint(RY)': 7686, 'PauliX': 252, 'MultiControlledX': 126, 'Adjoint(QFT)': 1}), gate_sizes=defaultdict(<class 'int'>, {1: 15943, 2: 15812, 7: 126, 6: 1}), depth=30610, shots=Shots(total_shots=None, shot_vector=()), ), 'num_observables': 1, 'num_diagonalizing_gates': 0, 'num_trainable_params': 15433, 'num_device_wires': 12, 'device_name': 'default.qubit', 'gradient_options': {}, 'interface': 'auto', 'diff_method': 'best', 'gradient_fn': 'backprop'}