About this map
Sections
What this is
Quantum algorithms are not written from scratch. They are assembled from a small number of reusable steps, and almost every published method is a different route through the same handful of them.
This is a map of those routes. Circles are the things an algorithm can be holding. Lines are the steps that carry you from one to the next. A method is a path across.
Nothing here is generated. Every line was read out of a paper and checked against it.
How to read it
- Something you can hold — a state, a matrix, a circuit, an answer.
- The same, in the middle of a step you have opened.
- A step. Someone has published a way through it.
- A step whose way through has not been pinned to one method.
- A step nothing published fills yet.
- A step you have opened. What is drawn inside it is how it was done.
- There is a record in the repository for this one.
How to move around
- Two fingers move the map. Pinch to zoom, or hold ctrl and scroll.
- Click a step to open it in place — everything else stays where it is.
- Click a name to read the full record without leaving the map.
- Arrow keys move, plus and minus zoom, zero puts it back.
What a line is claiming
A solid line means a paper puts those two steps together and we have the citation. A long-dashed line means the route is recorded but no single method has been named for that step. A short-dashed line means nothing published fills it — the step is real, the way through is not written yet.
A count after a step's name — ×T/h, ×O(κ) — means the route walks that step that many times rather than once. It is the source's own symbol, and the card says what it stands for and what one turn costs. A step with no count is a step no source we read said is repeated, which is not the same as one taken once.
A line drawn nested under another, on the soft shaded band behind it, is a narrower version of the line above it: the same construction, re-analysed or re-tuned, filling the same step. It is why two lines can draw the identical interior and still be two entries. Lines outside the band are alternatives to their neighbours, not versions of them.
The map does not hide the gaps. An empty step is drawn as an empty step.
What is not here yet
The map covers the algorithm literature. The repository covers circuits and primitives. They overlap less than you would expect, and where a method has no record we say so on its page rather than leaving the space blank.
Where something named here does have a record, its name links straight to it.
Method
Follow the steepest descent in the state's own geometry
Take the step that moves the state fastest, not the one that moves the parameters fastest. The two differ because equal changes in parameters do not make equal changes in the state, and the metric measuring that difference has to be estimated before every step.
Open the full recordFills the slot: Minimise the objective over the parameters
Stokes et al. state exactly what the step is taken with respect to: the optimization dynamics "is interpreted as moving in the steepest descent direction with respect to the Quantum Information Geometry, corresponding to the real part of the Quantum Geometric Tensor (QGT), also known as the Fubini-Study metric tensor". That tensor is the extra thing this method buys its better steps with, and the paper's own contribution is making it affordable rather than exact — "an efficient algorithm is presented for computing a block-diagonal approximation to the Fubini-Study metric tensor for parametrized quantum circuits". Block-diagonal is an approximation, and the abstract states no bound on what it costs in step quality, so none is quoted here.
A parameterised circuit family; an objective function of its parameters, evaluated only through estimates bought with a finite shot budget; a starting point; and a stopping rule — a tolerance, an iteration cap, or an exhausted budget.
Parameterised circuit family → State you can prepareinvert the block-diagonal metric each step
The step solves the linear system , where is built from the Quantum Geometric Tensor . For a layered circuit whose layer generators satisfy , assumption: within a layer for , forcing , so each block reduces to expectation values on the subcircuit state : . approximation: cross-layer blocks of are discarded, so only are estimated and inverted rather than the full metric.
approximationassumption
A preparation routine for the state at the parameters the search stopped at, and the total number of objective evaluations it consumed. The routine is returned whether or not the search found a minimum; that it stopped is not evidence that it converged.
None found yet.
given parametrized circuit U_L(theta) = V_L(theta_L) W_L ... V_1(theta_1) W_1
with theta = theta_1 (+) ... (+) theta_L in R^d split into L layers (Eq. 14)
layer l carrying m parameters with generators K_i, partial_i V_l = -i K_i V_l
fixed reference |0> and Hermitian observable H
objective L(theta) = (1/2) <psi_theta|H|psi_theta>, psi_theta = U_theta|0> (Eq. 9)
requires within every layer l, for distinct parameters i != j: partial_i K_j = 0
# the paper takes this as "the defining property of a layer" itself,
# not a general fact about circuits -- it is what forces the layer's
# generators to commute, [K_i, K_j] = 0 (Sec. 2.5)
# global optimization of L(theta) is impractical since it is nonconvex;
# this method only searches for a local optimum (Sec. 2.2)
# --- gradient, by parameter shift -------------------------------------------
grad_L(theta_t) <- parameter-shift evaluation of each of the d components (Sec. 3)
# 2d quantum evaluations total -- two shifted circuits per parameter
# --- block-diagonal Fubini-Study metric, one block per layer ----------------
for l = 1 .. L:
psi_l = U_[1:l](theta) |0> (Eq. 17)
rotate psi_l into the shared eigenbasis of {K_i : 1 <= i <= m} u
{K_i K_j : 1 <= i,j <= m} over that layer's own m parameters, and
measure all qubits in the Pauli-Z basis, once (Sec. 2.6, step 3a)
# one measurement suffices because every operator in that set
# commutes within the layer, by the requires clause above
# the paper's quoted saving -- naive count n(n+1)/2 collapsing to a
# single measurement -- is stated only for the family it narrows to
# "for simplicity of exposition": tensor products of single-qubit
# Pauli rotations, one per qubit, so that m = n there (Eqs. 29-32, Sec. 2.6)
# for a general layer the naive count is m(m+1)/2, not n(n+1)/2
classically recover <psi_l|K_i K_j|psi_l>, <psi_l|K_i|psi_l>, <psi_l|K_j|psi_l>
from that one measurement's statistics (Sec. 2.6, step 3a)
G(l)_ij = <psi_l|K_i K_j|psi_l> - <psi_l|K_i|psi_l> <psi_l|K_j|psi_l> (Eq. 27)
g(l)_ij = Re[G(l)_ij] = G(l)_ij
# K_i K_j is Hermitian here because [K_i,K_j] = 0, so nothing
# imaginary is being discarded to get the real part (Eq. 28)
assemble g(theta_t) as block-diagonal in g(1) .. g(L)
# cross-layer blocks are NOT estimated -- they are the paper's named
# approximation to the full metric, and no bound on the resulting
# step error is given (Eq. 18, abstract)
# --- step: solve the linear system, don't invert -----------------------------
solve g(theta_t) (theta_{t+1} - theta_t) = -eta * grad_L(theta_t) for theta_{t+1} (Eq. 12)
# equivalent in principle to theta_{t+1} = theta_t - eta * g+(theta_t) grad_L(theta_t)
# using the pseudo-inverse g+ of the metric (Eq. 13),
# but the paper avoids materializing g+ and solves (12) directly instead,
# "both more efficient and more numerically stable" (Sec. 2.2)
# the paper says nothing about g being singular at Eq. (13); its only
# "possible degeneracies" remark is about the classical Fisher
# Information Matrix, a different tensor (Sec. 2.1)
repeat until the stopping rule fires
return theta_t, and the evaluation count 2d + L spent per step (Sec. 3)
# a cheaper diagonal-only variant exists: replace each block g(l) above with
# just the per-parameter variances <K_i^2> - <K_i>^2 on its diagonal;
# the paper's own n = 11 run used this variant in place of the
# block-diagonal one purely to avoid the classical cost of computing the
# shared eigenbasis, not because the block-diagonal form had failed
# (Sec. 2.6 step 3b, Sec. 3)Stokes, Izaac, Killoran and Carleo: in their PennyLane implementation each optimization step requires quantum evaluations — parameter-shift evaluations for the gradient over parameters, plus one per parametrized layer for the block-diagonal Fubini-Study metric. Those are expectation values, each from shots ( in Figs. 1 to 3). The one-per-layer figure follows from the layer definition , which forces ; the naive count it replaces is specific to Eq. (29)'s single-qubit Pauli rotations. Classical work — the per-layer shared eigenbasis, the Eq. (12) linear solve — sits outside the count and dominated their runs: at they dropped the block-diagonal variant for the diagonal one, same evaluations, saving only classical time. Nothing bounds the step count; global optimization is called impractical, and convergence "in a small number of iterations" is measured — at (Fig. 1), at to (Figs. 2 to 3), block-diagonal only at — not proved.
None found yet.
None found yet.
`QNGOptimizer`, the quantum natural gradient optimizer in PennyLane
- Quantum Natural Gradient
James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo · 2019
About
This is the implementation the paper itself points at. Sec. 3 closes its description of the algorithm with "Finally, a Quantum Natural Gradient optimizer was implemented in PennyLane (see [35] for full source code)", and reference [35] is "Xanadu Quantum Technologies. PennyLane source code. https://github.com/XanaduAI/pennylane, 2019" — an address the GitHub API today resolves to `PennyLaneAI/pennylane`. Two of the four authors give the same affiliation, "Xanadu, 777 Bay Street, Toronto, Canada", and the module header reads "Copyright 2018-2021 Xanadu Quantum Technologies Inc." The class docstring carries the paper's own construction, with a slip at the first formula: its prose says the learning rate is "dependent on the pseudo-inverse of the Fubini-Study metric tensor", and the display beneath it then writes an ordinary inverse, , where the paper's Eq. (13) writes the pseudo-inverse and Sec. 2.2 declines to form it at all — "In practice, however, we avoid materializing the pseudo-inverse by directly solving the linear system (12) which is both more efficient and more numerically stable". Read the display as the pseudo-inverse its own surrounding prose names, which is also what the code computes. What follows it is the paper's: the per-layer block is with "the quantum state prior to the application of parametrized layer ", and the count is the paper's own: "Combining the quantum natural gradient optimizer with the analytic parameter-shift rule to optimize a variational circuit with parameters and layers, a total of quantum evaluations are required per optimization step." The citation given is the published version, "Quantum 4, 269", 2020, not the preprint. What the class accepts is narrow: "The QNG optimizer supports using a single :class:`~.QNode` as the objective function", and `step_and_cost` raises otherwise unless the caller supplies the metric — "The objective function must be encoded as a single QNode for the natural gradient to be automatically computed. Otherwise, metric_tensor_fn must be explicitly provided to the optimizer."
Methods
The constructor is `__init__(self, stepsize=0.01, approx="block-diag", lam=0)` and `step_and_cost` runs three stages. First the metric, behind the guard `if recompute_tensor or self.metric_tensor is None:` — so `recompute_tensor=False` reuses the previous step's tensor but cannot skip the first one, where `self.metric_tensor` is still `None`. What it builds is `metric_tensor(qnode, approx=self.approx)` from `pennylane/gradients/metric_tensor.py`, whose own signature defaults to `approx=None`. The block-diagonal restriction is therefore the optimizer's choice and not the transform's — and the transform's docstring says what the unrestricted branch costs beyond the paper's construction: "The block-diagonal part of the metric tensor always is computed using the covariance-based approach. If no approximation is selected, the off block-diagonal is computed using Hadamard tests", which "requires a device that has an additional wire as compared to the wires on which the original circuit was defined". The tensor then passes through `_reshape_and_regularize(tensor, lam)`, which flattens it to a square `(size, size)` matrix and adds `tensor += lam * math.eye(size, like=tensor)`; `lam` is a regularization the paper does not have, and it is off by default. Second the gradient, `self.compute_grad(qnode, args, kwargs, grad_fn=grad_fn)`, inherited from `GradientDescentOptimizer`. Third the step — and here the implementation departs from the paper it cites. `apply_grad` computes `update = pnp.linalg.pinv(mt[trained_index]) @ grad_flat`, materializing the pseudo-inverse the paper's Sec. 2.2 says it avoids, where Sec. 3 describes its own PennyLane optimizer as one that "updates the parameter values by classically solving the linear system (12)". The sibling class `QNGOptimizerQJIT`, in `pennylane/optimize/qng_qjit.py`, carries the same three defaults and takes the same route, `update_flat = math.linalg.pinv(mt) @ grad_flat`. One further approximation sits on top of the paper's block-diagonal one and is named in the docstring: "If the objective function takes multiple trainable arguments, ``QNGOptimizer`` applies the metric tensor for each argument individually. This means that "correlations" between parameters from different arguments are not taken into account."
Data
No dataset and no hardware. The docstring's worked example is a two-parameter circuit whose gates both act on wire 0 — `qp.RX(params[0], wires=0)` then `qp.RY(params[1], wires=0)` — read out through an observable that spans two, `qp.expval(qp.X(0) + qp.X(1))`, on a device declaring three, `qp.device("default.qubit", wires=(0, 1, "aux"))`, from `init_params = np.array([0.011, 0.012])` at `eta = 0.01`. `tests/optimize/test_qng.py` stays at that scale: every device is `default.qubit`, five declared `wires=1`, one `wires=4`, three with no wire count given, and no device in the file sets `shots`, so every number the tests compare against is analytic rather than sampled.
Code
`pennylane/optimize/qng.py` in https://github.com/PennyLaneAI/pennylane — Python, Apache License 2.0, header "Copyright 2018-2021 Xanadu Quantum Technologies Inc.", module docstring "Quantum natural gradient optimizer". The file is 368 lines and holds `class QNGOptimizer(GradientDescentOptimizer)` together with four module-level helpers, `_reshape_and_regularize`, `_flatten_np`, `_unflatten_np_dispatch` and its thin wrapper `_unflatten_np`. Read at tag `v0.45.1`, the release published 2026-06-26; that tag's copy of the file is byte-identical to `master` as of 2026-08-26. The documented entry point is `qp.QNGOptimizer`, used as `opt.step(circuit, init_params)` or `opt.step_and_cost(...)`, and the metric it calls into is `qp.metric_tensor` from `pennylane/gradients/metric_tensor.py` (882 lines at the same tag). The `jax.jit`-compatible variant the docstring points to, `QNGOptimizerQJIT`, is a separate 253-line file, `pennylane/optimize/qng_qjit.py`, and is not a subclass of this one.
Results
The module reports no figures of its own; what is pinned is in `tests/optimize/test_qng.py`, 459 lines. `test_initialization_default` fixes the three defaults — `assert opt.stepsize == 0.01`, `assert opt.approx == "block-diag"`, `assert opt.lam == 0` — plus `assert opt.metric_tensor is None` before any step. `test_qubit_rotation` runs a two-gate one-qubit circuit, `qp.RX(params[0], wires=0)` then `qp.RY(params[1], wires=0)`, against `qp.expval(qp.PauliZ(0))` at `eta = 0.2` from `init_params = np.array([0.011, 0.012])` for `num_steps = 15`, and checks all three parts each step: the metric against the closed form `np.diag([0.25, (np.cos(theta[0]) ** 2) / 4])`, the update against `eta * sp.linalg.pinvh(exp) @ gradient(theta)` with the gradient supplied analytically, and at the end `assert np.allclose(circuit(theta), -1)`. Two further tests isolate the attributes the paper does not have, and neither runs that circuit: both prepend a fixed, non-trainable `qp.RY(eta, wires=0)` to the two trainable rotations, which is what gives the metric an off-diagonal to argue about at all — on the two-gate circuit above the file's own assertion is that the metric is exactly diagonal. `test_no_approx` sets `eta = 0.7` and `params = np.array([0.11, 0.412])`, checks the unrestricted tensor against a hand-derived `exp_mt` with `assert np.allclose(opt.metric_tensor, exp_mt)`, then asserts the default run keeps only its diagonal, `assert np.allclose(opt_with_approx.metric_tensor, np.diag(np.diag(exp_mt)))`, and that the two produce different parameters, `assert not np.allclose(new_params_no_approx, new_params_block_approx)`. Both trainable rotations sit in separate layers on the same wire here, so block-diagonal and diagonal coincide for this circuit; that is a property of the circuit, not an identity. `test_lam` takes the same three-gate circuit to `eta = np.pi` and `params = np.array([np.pi / 2, 0.412])`, where the test's own expression for `exp_mt` evaluates to and the second direction has no metric left, and shows the regularization is what rescues the step, in its own words: "# With regularization, y can be updated. Without regularization it can not." — `assert np.isclose(new_params_without_lam[1], y)` against `assert not np.isclose(new_params_with_lam[1], y, atol=1e-11, rtol=0.0)`, at `lam = 1e-9` and `stepsize=1.0`. Nothing in the file measures step counts, wall time or a comparison against another optimizer.
- Quantum Natural Gradient
The QN-SPSA optimizer in qiskit-algorithms
- Simultaneous Perturbation Stochastic Approximation of the Quantum Fisher Information
Julien Gacon, Christa Zoufal, Giuseppe Carleo, Stefan Woerner · 2021
About
`QNSPSA` exists to buy the natural-gradient step at a price that does not grow with the number of parameters, and its class docstring states the trade in one sentence: "Compared to natural gradients, which require expectation value evaluations for a circuit with parameters, QN-SPSA only requires and can therefore significantly speed up the natural gradient calculation by sacrificing some accuracy." It says how the geometry is reached — "This optimizer is based on SPSA but attempts to improve the convergence by sampling the **natural gradient** instead of the vanilla, first-order gradient. It achieves this by approximating Hessian of the ``fidelity`` of the ansatz circuit" — and it says the accuracy is recoverable rather than fixed: "The stochastic approximation of the natural gradient can be systematically improved by increasing the number of ``resamplings``. This leads to a Monte Carlo-style convergence to the exact, analytic value." The it measures itself against is the cost of the full tensor, which is the figure the cited paper's own abstract quotes — "Computing the full QFIM for a model with parameters, however, is computationally expensive and generally requires function evaluations" — and not the per-step count recorded for Stokes et al.'s block-diagonal construction. It ships in `qiskit-algorithms`, a community package whose README carries the warning "**Qiskit Algorithms is no longer officially supported by IBM**."
Methods
`class QNSPSA(SPSA)` reaches the metric through the fidelity rather than through layer structure, so none of the paper-side conditions on this method — layers, , commuting generators — appear anywhere in the file. `get_fidelity(circuit, sampler, ...)` is a static method that wraps `ComputeUncompute` and returns a handle to , and the optimizer takes that callable as its first constructor argument. Each sample, in `_point_sample(self, loss, x, eps, delta1, delta2)`, evaluates the loss at two points, `x + eps * delta1` and `x - eps * delta1`, and the fidelity at four pairs — `(x, x + eps * delta1)`, `(x, x - eps * delta1)`, `(x, x + eps * (delta1 + delta2))`, `(x, x + eps * (-delta1 + delta2))` — then charges all six at once, `self._nfev += 6`. The gradient is the ordinary two-point SPSA estimate, `(loss_values[0] - loss_values[1]) / (2 * eps) * delta1`; the preconditioner is a second difference of the fidelity, `diff / (2 * eps**2)` after `fidelity_values[2] - fidelity_values[0]` less `fidelity_values[3] - fidelity_values[1]`, turned into a symmetrized rank-one matrix, `hessian_estimate = -0.5 * diff * (rank_one + rank_one.T) / 2` with `rank_one = np.outer(delta1, delta2)`, whose sign the code explains in place — "# -0.5 factor comes from the fact that we need -0.5 * fidelity". The constructor then hands the parent class a fixed configuration rather than a choice: `second_order=True` always, and `trust_region=False` with the reason written beside it, "# trust region *must* be false for natural gradients to work". The two `settings` keys those correspond to are removed from the serialized dictionary, `settings.pop("trust_region")` and `settings.pop("second_order")`. One default is inverted relative to the parent: `blocking: bool = True` here, where `SPSA` leaves it `False`, so a QN-SPSA run rejects non-improving steps unless told not to, at the cost of a further loss evaluation per iteration. Everything else — the power-series gains, `resamplings`, `perturbation_dims`, the `regularization` that forces the smoothed Hessian symmetric positive definite, `hessian_delay`, `lse_solver` — is inherited unchanged from `SPSA`.
Data
Toy circuits in simulation; no dataset and no hardware anywhere in the module or its tests. The docstring example minimizes `Pauli("ZZ")` on `pauli_two_design(2, reps=1, seed=2)` through a `StatevectorEstimator`, from `np.random.random(ansatz.num_parameters)`, with `QNSPSA(fidelity, maxiter=300)` and the fidelity built from a bare `StatevectorSampler()`. The tests run the same family one qubit larger, `pauli_two_design(3, reps=1, seed=1)` against `SparsePauliOp("ZZI")`, with the fidelity sampled rather than exact — `QNSPSA.get_fidelity(circuit, sampler=StatevectorSampler(seed=12, default_shots=10_000))` in `test_qnspsa_max_evals_grouped` — and one test with the circuits removed altogether: a fidelity stub returning ones over the identity objective, `def objective(x): return x`. Those circuits are the ones `test/optimizers/test_spsa.py` already uses for plain `SPSA`; this class has no test module of its own.
Code
`qiskit_algorithms/optimizers/qnspsa.py` in https://github.com/qiskit-community/qiskit-algorithms — Python, Apache License 2.0, header "(C) Copyright IBM 2021, 2026", module docstring "The QN-SPSA optimizer." It is 283 lines on `main` and imports its parent from the sibling file, `from .spsa import SPSA, CALLBACK, TERMINATIONCHECKER, _batch_evaluate`, and its fidelity machinery from `qiskit_algorithms.state_fidelities` as `ComputeUncompute`. Used as `from qiskit_algorithms.optimizers import QNSPSA`, then `QNSPSA.get_fidelity(ansatz, sampler)` and `QNSPSA(fidelity, maxiter=300).minimize(loss, x0=initial_point)`. The module is in the released package — `qiskit-algorithms` 0.4.0 on PyPI, uploaded 2025-08-29, Apache-2.0, Python >= 3.9 — and the file at tag `0.4.0` differs from `main` in three places only: the copyright year, whether `Callable` is imported from `collections.abc` or `typing`, and two blank lines.
Results
The module reports no accuracy figures of its own and has no test file of its own either: every assertion about it sits in `test/optimizers/test_spsa.py`, 267 lines, beside the `SPSA` tests. Four of that file's ten test methods reach this class. The largest numbers are in the shared one: `test_pauli_two_design`'s `"qnspsa"` arm runs `pauli_two_design(3, reps=1, seed=1)` against `SparsePauliOp("ZZI")` for `maxiter = 100` under `{"maxiter": 100, "blocking": True, "allowed_increase": 0}` with `regularization = 0.001`, `learning_rate = 0.05` and `perturbation = 0.05`, and asserts an accuracy floor and a price together — `self.assertLess(result.fun, -0.95)` and `expected_nfev = settings["maxiter"] * 7 + 1`, which is 701 evaluations. The three QN-SPSA-only tests all sit at `maxiter = 1`. `test_qnspsa_max_evals_grouped` pins a value, `self.assertAlmostEqual(result.fun[0], 0.473, places=3)`, and that same law's smallest case, `expected_nfev = 8 # 7 * maxiter + 1`, under `set_max_evals_grouped(50)`. `test_point_sample` reaches `expected_nfev = 8` again with the circuits stripped out entirely — the fidelity stub, the identity objective, a scalar `initial_point = 1.0` and a perturbation generator yielding 1 — so the count is a property of the code path rather than of the circuit. `test_qnspsa_fidelity_primitives` checks only that the fidelity handle is self-consistent, `fidelity(initial_point, initial_point)` against `self.assertAlmostEqual(result[0], 1)` on `pauli_two_design(2, reps=1, seed=2)`. Of the seven evaluations an iteration costs, the six this file is responsible for are the ones `_point_sample` charges at `self._nfev += 6`; the rest of the accounting is `spsa.py`'s. No test in the file compares QN-SPSA against an optimizer from outside the SPSA family, and none runs on hardware.
- Simultaneous Perturbation Stochastic Approximation of the Quantum Fisher Information
The "Accelerating VQEs with quantum natural gradient" PennyLane demonstration
- Quantum Natural Gradient
James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo · 2019
About
A runnable tutorial that puts `QNGOptimizer` and `GradientDescentOptimizer` on the same problem from the same starting point and reports what each spends. Its own statement of purpose is "This tutorial showcases how one can apply quantum natural gradients (QNG) to accelerate the optimization step of the Variational Quantum Eigensolver (VQE) algorithm", and it does so twice — "We will implement two small examples: estimating the ground state energy of a single-qubit VQE problem, which we can visualize using the Bloch sphere, and the hydrogen molecule." The comparison is deliberately controlled: "To perform a fair comparison, we fix the initial parameters for the two optimizers." It carries its own caveat about what the step counts do not say — "While using QNG may help accelerate the VQE algorithm in terms of optimization steps, each QNG step is more costly than its vanilla gradient descent counterpart due to a greater number of calls to the quantum computer that are needed to compute the Fubini-Study metric tensor" — and about how far the evidence reaches: "While further benchmark studies are needed to better understand the advantages of quantum natural gradient, preliminary studies such as this tutorial show the potentials of the method."
Methods
The single-qubit arm minimizes , built in three lines as `coeffs = [1, 1]`, `obs = [qp.PauliX(0), qp.PauliZ(0)]` and `H = qp.Hamiltonian(coeffs, obs)`, over `qp.RX(params[0], wires=wires)` then `qp.RY(params[1], wires=wires)` on a one-wire `default.qubit`, from `init_params = np.array([3.97507603, 3.00854038], requires_grad=True)`, with `max_iterations = 500`, `conv_tol = 1e-06` and `step_size = 0.01` shared by both arms; the optimizers are `qp.GradientDescentOptimizer(stepsize=step_size)` and `qp.QNGOptimizer(stepsize=step_size, approx="block-diag")`, and the loop stops on `conv = np.abs(energy - prev_energy)` falling to `conv_tol`. The hydrogen arm keeps the same skeleton and changes four things: the ansatz is `qp.BasisState(hf_state, wires=[0, 1, 2, 3])` followed by `RZ`, `RY`, `RZ` on each of the four wires and then `CNOT` on `[2, 3]`, `[2, 0]` and `[3, 1]`, giving twelve parameters drawn as `np.random.uniform(low=0, high=2 * np.pi, size=12, requires_grad=True)` under `np.random.seed(0)`; the step size is 0.5; the QNG optimizer is constructed with the regularization on, `qp.QNGOptimizer(step_size, lam=0.001, approx="block-diag")`; and the Hamiltonian is rebuilt with `requires_grad=False` coefficients before the QNG run, which the text explains as "We also need to make the Hamiltonian coefficients non-differentiable by setting ``requires_grad=False``." A third experiment is described but not coded: ten random initializations at a fixed two hundred iterations, presented as a figure with the note "We show the result of this test below (after pre-computing)", so the file contains neither its loop nor its numbers.
Data
at bond length 0.7, loaded rather than built — `dataset = qp.data.load('qchem', molname="H2", bondlength=0.7)[0]` — from which the demo takes both the Hamiltonian and the reference energy, `exact_value = dataset.fci_energy`, which the file records inline as `# -1.1361895496530567`. The register is initialized to the Hartree-Fock state, `hf_state = np.array([1, 1, 0, 0], requires_grad=False)`, described as encoding "the Hartree-Fock state of the hydrogen molecule described in the minimal basis", on a four-wire `default.qubit`. The single-qubit arm has no dataset at all: its Hamiltonian is two Pauli terms with unit coefficients, and its contour plot reads a pre-computed grid from `vqe_qng/param_landscape.npy` rather than evaluating one.
Code
`demonstrations_v2/tutorial_vqe_qng/demo.py`, 472 lines, in the PennyLane demonstrations repository — Python, Apache License 2.0. The repository is https://github.com/PennyLaneAI/demos; the raw path under the older name `PennyLaneAI/qml` still resolves by redirect, and the GitHub API reports the current `full_name` as `PennyLaneAI/demos`, created 2019-10-09. The demo's own `metadata.json` gives the title "Accelerating VQEs with quantum natural gradient", the author usernames `mli`, `lbozanic` and `ssim`, `"dateOfPublication": "2020-11-06T00:00:00+00:00"` and `"dateOfLastModification": "2026-05-28T00:00:00+00:00"`, and lists three references — the Stokes paper, Yamamoto's arXiv:1909.05074 and the Peruzzo photonic-processor paper. The rendered page at https://pennylane.ai/qml/demos/tutorial_vqe_qng names Maggie Li, Lana Bozanic and Sukin Sim, and carries the same two dates in its structured data (`"datePublished":"2020-11-06T00:00:00+00:00"`, `"dateModified":"2026-05-28T00:00:00+00:00"`) while its visible byline renders each one day earlier: "Published: November 05, 2020. Last updated: May 27, 2026." The only dependencies the file imports are `matplotlib.pyplot`, `pennylane` and `pennylane.numpy`; no PennyLane version is pinned in the demo directory or stated on the page.
Results
The source file hard-codes no output — every figure below is printed by the run and read off the rendered page. The single-qubit problem's Hamiltonian is with unit coefficients, whose eigenvalues are , so its exact ground energy is ; the demo never prints that number, and it is stated here as arithmetic on the Hamiltonian the file builds. Against it, gradient descent ends at "Final value of the energy = -1.41365468 Ha" with "Number of iterations = 499", the last index of its five-hundred-step budget, and its last printed diagnostic is "Iteration = 480, Energy = -1.41325360 Ha, Convergence parameter = 0.00002772 Ha" — still about twenty-eight times `conv_tol = 1e-06`. Quantum natural gradient ends at "Final value of the energy = -1.41420585 Ha" with "Number of iterations = 117". On both arms meet the tolerance and the gap is in the count and in the accuracy: gradient descent takes 130 iterations to "Final value of the ground-state energy = -1.13616408 Ha", which the run itself scores as "Accuracy with respect to the FCI energy: 0.00002547 Ha (0.01598211 kcal/mol)", against quantum natural gradient's 17 iterations to -1.13618947 Ha and "Accuracy with respect to the FCI energy: 0.00000008 Ha (0.00004853 kcal/mol)". The demo's own reading of the pair is "We see that by employing quantum natural gradients, it takes fewer steps to reach a ground state estimate and the optimized energy achieved by the optimizer is lower than that obtained using vanilla gradient descent." No count of quantum evaluations, and no wall time, is reported for either arm.
- Quantum Natural Gradient
Quantum natural-gradient VQE · Qiskit
From the repository — run, not written up from a paper · unsupported
About
The Fubini–Study metric preconditions parameter updates according to circuit-state geometry.
Methods
None found yet.
Data
None found yet.
Code
Qiskit
Results
Literature-backed method record; algorithmic scope and evidence boundary reviewed, with no benchmark run claimed.
- Quantum natural-gradient VQE
The Fubini–Study metric preconditions parameter updates according to circuit-state geometry.
References
- Quantum Natural Gradient
James Stokes, Josh Izaac, Nathan Killoran, Giuseppe Carleo · 2019
Where the routes meet
11 problems nothing else needs — the places a reader arrives. Open a line to see what is recorded inside it, or click its name to go there.
15 lines have something recorded inside that you have not opened.
Of the routes that have been taken apart, 15 are built entirely from named slots, 15 hand off part of the work and finish the rest themselves, and 20 are one undivided act. None of the three is a defect; they are different things to reuse.
Every line on this figure, in words
The lines on this figure
Solve a nonlinear ODE dy/dt = F(y)
- Embed a nonlinear system into a linear one — opens into 6 · a way across — click it to open it here
- Solve a linear ODE du/dt = A(t)u + b(t) — opens into 9 · a way across — click it to open it here
- Choose a time discretization or propagator approximation → Quantum linear solve — open
- Choose a time discretization or propagator approximation — opens into 6 · a way across — click it to open it here
- Quantum linear solve — opens into 5 · a way across — click it to open it here
- Simulate Hamiltonian evolution → Estimate an observable — open
- Simulate Hamiltonian evolution — opens into 3 · a way across — click it to open it here
- Estimate an observable — opens into 4 · a way across — click it to open it here
Estimate an excited-state energy
- Variational quantum deflation — open · opened: what was inside is drawn in its place
- Choose a parameterised trial state — opens into 13 · a way across — click it to open it here
- Minimise the objective over the parameters — opens into 6 · a way across — click it to open it here
- Estimate an observable — opens into 4 · a way across — click it to open it here
- Subspace-search variational eigensolver — opens into 3 · a way across — click it to open it here
- Quantum subspace expansion
- Quantum equation of motion
- Folded-spectrum variational eigensolver — opens into 3 · a way across — click it to open it here
- Penalty-constrained variational eigensolver — opens into 3 · a way across — click it to open it here
- Multistate contracted variational eigensolver — opens into 3 · a way across — click it to open it here
Every step you can open
1 of these have an object recorded in the middle; the rest open into the methods that fill them.
- Solve a nonlinear ODE dy/dt = F(y)
- Replace a spatial domain with a finite grid
- Discretize a PDE into one linear system
- Embed a nonlinear system into a linear one
- Solve a linear ODE du/dt = A(t)u + b(t)
- Recast a non-Hermitian generator as Hamiltonian evolution
- Choose a time discretization or propagator approximation
- Quantum linear solve
- Matrix function
- QSP phase factors
- Polynomial approximation
- Block-encode a matrix
- Prepare an input state
- Amplify a success branch
- Simulate Hamiltonian evolution
- Estimate an observable
- Compile a circuit to a specific device
- Satisfy the hardware connectivity constraint
- Approximate a continuous rotation in a discrete gate set
- Recover a noiseless expectation value by post-processing
- Build logical qubits at a target logical error rate
- Estimate a Hamiltonian's ground-state energy
- Choose a parameterised trial state
- Minimise the objective over the parameters
- Estimate an excited-state energy
- Measure what the machine can actually do
- Recover the period of a periodic function
- Estimate the eigenphase of a unitary
- Find the item a check accepts
- Walk a graph to the vertex you want
- Search a cost Hamiltonian for the assignment it minimises
What is on this map, counted
What is here, counted
147 nodes — 31 slots and 116 methods.
76 of the 147 link to a record in the Atlas, between them naming 89 records. The rest name papers and nothing else: this graph describes work the catalogue has not got yet, and the nodes with no record are the list of what a corpus pass has to go and read.
0 slots have no method recorded, and 32 methods have not been taken apart. Both are shown as what they are rather than left blank.
Every claim here rests on a source. This graph cites 140 papers; they and the 172 the Atlas cites alone are registered in one place, with what each reports and everywhere it is cited from. Papers