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
Quantum singular value transformation
Interleave the block-encoding , its inverse, and projector-controlled phase shifts so that the designated block becomes applied to the singular values of . The phase sequence is the compiled form of the polynomial, and a single ancilla qubit carries the phase shifts.
Open the full recordFills the slot: Matrix functionExpand it here — a map of just this
The polynomial must have definite parity, matching the degree mod 2, and satisfy for every in . Parity is not a convention: Gilyén, Su, Low and Wiebe argue it is necessary, following from the sign ambiguity in pairing singular vectors. A complex is handled directly; a real — which is what approximations of , sign and cos give you — needs the extra-ancilla construction of their Corollary 18. The route from single-qubit quantum signal processing through the eigenvalue transform to QSVT is laid out rung by rung by Martyn, Rossi, Tan and Chuang.
A block-encoding of together with its subnormalisation ; a target function on ; an error budget .
Block-encoding → Block-encodingBlock-encode a matrix runs n uses of U and n of U†, for a degree-n transform
QSVT never opens this box: what it takes is the block itself, the operator , whose singular values are those of and not of . Those are what the alternating phased sequence transforms, which makes the slot's subnormalization a mathematical constraint and not bookkeeping: Corollary 18 admits only a polynomial bounded on , and it is whose singular values are guaranteed to sit there, so a caller wanting must ask the layer above for a polynomial in the rescaled variable. approximation: the block agrees with only to the encoding error of Definition 43, so what the sequence transforms is the encoded operator and not itself. The slot must also expose the inverse , which the sequence alternates with , and the ancilla flag the projector-controlled phase shifts are conditioned on — for Definition 43's standard form, .
approximation
The loop stays coherent: nothing is measured between turns. The preparation may still be reapplied every turn — what the loop never pays is a readout and a restart from classical data. The price is depth, and a success probability that multiplies down the chain. The repetition is the circuit: U, U†, U, U† interleaved with the phase shifts, and the degree of the polynomial is the number of turns. It is the cleanest case on this map of a count that is set by a *different* layer — the polynomial-approximation step above hands down n, so a coarser approximation is literally a shorter loop here. Nothing is measured; the whole sequence is one coherent circuit, which is why the price shows up as depth and as query count rather than as shots.
Block-encoding → Block-encoding of f(A)interleave the encoding with phase shifts
The block-encoding is consumed by an alternating phase modulation sequence. For , interleaves , and the projector-controlled phase shifts and , and Theorem 17 of Gilyen, Su, Low and Wiebe gives for odd and for even — the designated block now holds applied to the singular values. Each phase shift is itself , so one ancilla qubit carries the whole sequence, at uses of and , of each controlled-NOT and single-qubit gates (Lemma 19). assumption: The polynomial must have parity and satisfy on (Corollary 18). The authors argue the parity is necessary rather than conventional: the sign ambiguity in pairing singular vectors would otherwise demand and of the same polynomial. Which projector reads the answer follows from that parity — the odd sequence starts in the right singular-vector space and ends in the left, so it is read with and ; the even sequence starts and ends in the right space and is read with alone.
assumption
A circuit implementing a block-encoding of to error , together with the query count in and .
- Polynomial approximation
Given a target function, a domain and an error , return a polynomial of definite parity, bounded on , that is -close to the target on that domain, with an explicit degree.
This ingredient is asked for one object and one number, and QSVT evaluates neither. The constraint sent down is Corollary 18's hypothesis — the parity condition and the bound on — and what returns is a degree- polynomial the circuit never performs arithmetic on: only the phases compiled from it appear. The degree is the whole of what is spent, and Gilyén, Su, Low and Wiebe close that trade from below as well as above: one cannot implement a degree- Chebyshev polynomial with uses of the block-encoding , since takes the value at with derivative . A shorter circuit can only be bought as a coarser approximation here. approximation: the sequence realizes and not the function approximates, so the error accepted at this layer is the error of the transformed block — QSVT is never told the target.
approximation
- QSP phase factors
Given an admissible polynomial, compute the phase sequence that makes the quantum-signal-processing product reproduce it to accuracy in classical finite-precision arithmetic.
QSVT asks this layer for , one angle per turn for a degree- polynomial, and the ask depends on nothing quantum: Corollary 10 takes only the target polynomial and an accuracy as input — no property of , or enters — so one phase sequence serves every matrix that polynomial is applied to, computed once, classically, before the circuit exists. Corollary 18 asserts only that such a exists, proved non-constructively from Theorems 3–5. The constructive statement is Corollary 10: given and one can find a and a corresponding “using a classical computer in time ” — polynomial in the degree , logarithmic in the precision. approximation: the guarantee is for all , so reproduces the requested polynomial only to and not exactly. Recovering from the intermediate phases, the paper adds, “only yields a small overhead”.
approximation
given the block-encoding U of A from the block-encode-matrix step, and a
polynomial P whose degree n is handed down by the
polynomial-approximation layer
require P has definite parity, matching the degree mod 2
require |P(x)| <= 1 for every x in [-1,1]
# parity is not a convention: Gilyen, Su, Low and Wiebe argue it is
# necessary, following from the sign ambiguity in pairing singular vectors
take the phase sequence from the qsp-phase-factors step
# the phase sequence is the compiled form of the polynomial
if P is complex:
it is handled directly
else:
# a real P -- which is what approximations of 1/x, sign and cos give you
use the extra-ancilla |+> construction of Gilyen, Su, Low and Wiebe,
Corollary 18
interleave U, its inverse, and the projector-controlled phase shifts
e^{i phi (2 Pi - I)}
# a single ancilla qubit carries the phase shifts
the designated block becomes P applied to the singular values of A
# Gilyen, Su, Low and Wiebe, Lemma 19: a degree-n transform costs n uses of
# U and U dagger, n uses of C_Pi NOT, n uses of C_Pi-tilde NOT and n
# single-qubit gates, with a single ancilla qubit. The degree n is handed
# down by the polynomial-approximation layer, so that layer is what sets
# this circuit's query count.
# where the matrix is close to low rank and the input model is l2-norm
# sampling access, Chia, Gilyen, Li, Lin, Tang and Wang give classical
# singular value transformation running in time independent of the input
# dimension; sparse-access QSVT and general Hamiltonian simulation are not
# dequantizedGilyén, Su, Low and Wiebe (Lemma 19): a degree- transform costs uses of and , uses of NOT, uses of NOT and single-qubit gates, with a single ancilla qubit. The degree is handed down by the polynomial-approximation layer, so that layer is what sets this circuit's query count.
None found yet.
Where the matrix is close to low rank and the input model is -norm sampling access — the classical counterpart of the QRAM data-structure assumption these algorithms are costed against — Chia, Gilyén, Li, Lin, Tang and Wang give classical algorithms for singular value transformation that run in time independent of the input dimension, and state that their results give compelling evidence that in the corresponding QRAM data structure input model quantum SVT does not yield exponential quantum speedups. Sparse-access QSVT and general Hamiltonian simulation are not dequantized; overstating this in either direction is the usual failure.
PennyLane qml.QSVT template and qml.qsvt function
About
Xanadu's PennyLane ships this circuit as a built-in, and it ships two of them. The v0.30.0 release (on PyPI 2023-05-01) added the feature under the heading "Quantum singular value transformation" with the sentence "PennyLane now supports the quantum singular value transformation (QSVT), which describes how a quantum circuit can be constructed to apply a polynomial transformation to the singular values of an input matrix", linking arXiv:1806.01838 for it. The same note says why there are two entry points rather than one: "The qml.qsvt function creates a circuit that is targeted at simulators due to the use of matrix-based operations. For advanced users, you can use the operation-based qml.QSVT template to perform the transformation with a custom choice of unitary and projector operations, which may be hardware compatible if a decomposition is provided." The template is the half that matches this record — handed a block-encoding and a list of phase shifts, it interleaves them and computes nothing — and the function is the layer above it, which builds both of those from a matrix and a polynomial.
Methods
`QSVT(UA, projectors)` takes `UA`, "the block encoding circuit, specified as an Operator, like BlockEncode", and `projectors`, "a list of projector-controlled phase shifts that implement the desired polynomial". Its docstring writes the circuit as when the number of phase shifts is even ( odd), and when it is odd ( even); a degree- polynomial is therefore carried by phase shifts, and the documented call for returns six angles. `compute_decomposition` appends `projectors[0]`, then for each odd `i` appends `change_op_basis(UA, projectors[i])` followed by `projectors[i + 1]`, and closes with `UA` and `projectors[-1]` when the list length is even. `ChangeOpBasis` is documented to decompose as "each of compute_op, target_op, compute_op† applied in succession", so for three projectors the emitted sequence is . Nothing in that method tells from : position in the list is the only thing deciding whether a phase shift is followed by or by , and `compute_decomposition`'s own docstring restates the first formula with its leading factor written where the class docstring writes . The template does not require any particular operation in that list: `projectors` is typed `Sequence[Operator]`, and the class's own Example fills it with plain rotations — `phase_shifts = [qp.RZ(-2 * theta, wires=0) for theta in (1.23, -0.5, 4)]`, annotated "-2*theta to match convention". It is the `qsvt` function, and the worked examples in the `QSVT` usage details, that put `qml.PCPhase(phi, dim, wires)` there instead, whose docstring gives it as with "the diagonal projector with dim ones and N-dim zeros" — this record's own — and even there it is not assembled the way Lemma 19 assembles it. In all four routes `qsvt` builds, the `PCPhase` operations sit on the same wires as the block-encoding, `encoding_wires` for a matrix and `encoding_wires + A.wires` for a Hamiltonian, so no ancilla qubit is added for them; and `PCPhase` "operations are decomposed into (multi-)controlled PhaseShift operations which share the same control values on common control wires, and Pauli-X operations, possibly complemented by a global phase", not into a pair around a single-qubit rotation. `qsvt(A, poly, encoding_wires, block_encoding=None, angle_solver="root-finding")` is what fills those two arguments in. The angles come from `poly_to_angles(poly, "QSVT", angle_solver=...)`, and in the QSVT branch every one of its three solvers returns `transform_angles(..., "QSP", "QSVT")` — the sequence is always reached by converting a QSP one, never computed directly. The block encoder is chosen from four names: "prepselprep" (`PrepSelPrep`, the default when `A` has a Pauli representation), "qubitization" (`Qubitization`), "embedding" (`BlockEncode`, the default for a matrix, and "Template not hardware compatible"), and "fable" (`FABLE`, "Template hardware compatible"). Only the "embedding" route lets a projector's size depend on which angle it carries, which is the one place in the code where the theorem's two projectors could be told apart: it sets `c, r = math.shape(A)` and then `dim = c if idx % 2 else r`, alternating on the index of the angle. That alternation is inert for every input the function documents as valid, though. `c` and `r` are the row and column counts of `math.atleast_2d(A)`, and the docstring's note on the matrix routes reads "Note that for QSVT to work, the input matrix must be Hermitian.", so and every `PCPhase` is handed the same `dim` after all — the sizes differ only for a non-square `BlockEncode` input, which that requirement excludes. The other three routes hand every `PCPhase` a single `dim` outright: `len(A)` under "fable", `2 ** len(A.wires)` under the two Pauli routes. The two conditions this record states as hypotheses of Corollary 18 are both checked in `poly_to_angles`, and one of them at only three points. Parity is checked in full: unless one of the two coefficient strides sums to zero in absolute value it raises "The polynomial has no definite parity. All odd or even entries in the array must take a value of zero." The bound is not: the loop is `for x in [-1, 0, 1]`, with the source's own comment beside it reading "Check that |P(x)| ≤ 1. Only points -1, 0, 1 will be checked.", so a polynomial exceeding 1 somewhere strictly inside is not stopped here.
Data
No benchmark and no dataset ship with the module; what it is exercised on is its own docstrings, and that inventory is short enough to give whole. Under `qsvt`: the two-term Hamiltonian `qp.dot([0.3, 0.7], [qp.Z(1), qp.X(1) @ qp.Z(2)])` and a three-term one, `qp.dot([0.3, 0.4, 0.3], [qp.Z(2), qp.X(2) @ qp.Z(3), qp.X(2)])`, both through `PrepSelPrep`; and `np.array([[-0.1, 0, 0, 0.1], [0, 0.2, 0, 0], [0, 0, -0.2, -0.2], [0.1, 0, -0.2, -0.1]])` through `FABLE`. Under `QSVT`: the Example's `qp.Hadamard(wires=0)`, annotated "note H is a block encoding of 1/sqrt(2)"; `np.array([[0.2, 0.1], [0.1, -0.1]])` through `BlockEncode`; and a second, different three-term Hamiltonian, `H = 0.1 * qp.X(2) - 0.7 * qp.X(2) @ qp.Z(3) - 0.2 * qp.Z(2)`, through `PrepSelPrep` — which the prose directly above it names as , a different operator on different wires from the one the code beneath builds. And under the angle helpers, the scalar block-encoded as `RX(2 * np.arccos(x))` on a single wire, set up twice over — once under `transform_angles` and again under `poly_to_angles`. Seven circuits, then, and six of them name a polynomial. Three carry , all written `poly = np.array([0, -1, 0, 0.5, 0, 0.5])`: the two-term Hamiltonian, the `BlockEncode` matrix and the class's three-term Hamiltonian. The scalar example carries . The remaining two are quartics — `np.array([-1, 0, 0.2, 0, 0.5])` on the three-term Hamiltonian under `qsvt`, and `np.array([-0.1, 0, 0.2, 0, 0.5])` on the `FABLE` matrix. The seventh, the `QSVT` Example, names no polynomial at all: it passes three phase angles directly. The widest of these examples uses five wires.
Code
`pennylane/templates/subroutines/qsvt.py` in https://github.com/PennyLaneAI/pennylane — Python, Apache License 2.0, the header on master reading "Copyright 2025 Xanadu Quantum Technologies Inc." One module carries both entry points and the angle machinery: the `qsvt` function, the `QSVT` class, `poly_to_angles` and `transform_angles`. Both were added by pull request 3909, "Add qml.QSVT template and qml.qsvt function" by DSGuala, merged on 2023-04-10 into the feature branch `add_qsvt_functionality` rather than into `master`; that branch landed on 2023-04-19 as pull request 3756, "Add QSVT Functionality", and the v0.30.0 changelog credits the feature to seven pull requests in all — 3756, 3757, 3758, 3905, 3909, 3926 and 4023. The name `qml.qsvt` no longer means what it meant then. v0.40.0 (2025-01-14) rewrote it to take polynomial coefficients where it had taken angles, recording that "The old `qml.qsvt` functionality is moved to `qml.qsvt_legacy` and is now deprecated. It will be removed in v0.41.", and the v0.41.0 release notes (2025-04-15) record "The `qsvt_legacy` method, along with its private helper `_qsp_to_qsvt`, has been removed." The `QSVT` template's own signature did not move across that break. A third angle solver, `"iterative-optax"`, arrived in v0.45.0 and requires `jax` and `optax`. The file read here is master as of 2026-08-26; 0.45.1 is the release then on PyPI. The test file quoted in `results`, `tests/templates/subroutines/test_qsvt.py`, was fetched from the same master and is 1225 lines.
Results
Every `qp.device` call in the module names `default.qubit`, PennyLane's state-vector simulator; no example in either entry point's docstring names a hardware device. Inside the module file itself, the closest thing to a correctness check is the usage-details example that appears twice under the angle helpers — once under `transform_angles`, reaching the angles through `poly_to_angles(poly, "QSP")` and then `transform_angles(qsp_angles, "QSP", "QSVT")`, and once under `poly_to_angles`, reaching them in a single call. Both block-encode the scalar as `RX(2 * np.arccos(x))`, apply through `QSVT` with `PCPhase(angle, dim=1, wires=0)` projectors, and print the top-left entry of the circuit matrix beside the polynomial evaluated classically: `output qsvt: 0.19610666666647059` against `P(x) = 0.19610666666666668`, a gap of about . The `QSVT` class's own example is a one-wire toy — `qp.Hadamard(wires=0)`, commented "note H is a block encoding of 1/sqrt(2)", with `phase_shifts = [qp.RZ(-2 * theta, wires=0) for theta in (1.23, -0.5, 4)]`, commented "-2*theta to match convention" — returning `np.float64(0.5403...)`; expanded it draws `0: ──RZ(-2.46)──H──RZ(1.00)──H──RZ(-8.00)─┤`, which is exactly the five-operator sequence `compute_decomposition` builds from three projectors. For the function, the v0.40.0 note and the current docstring print the same leading real block for applied to under `prepselprep`: rows `[-0.1625, 0., -0.3793, 0.]`, `[0., -0.1625, 0., 0.3793]`, `[-0.3793, 0., 0.1625, 0.]`, `[0., 0.3793, 0., 0.1625]`. None of those printed outputs is executed from the docstring: the printed matrices in `qsvt`'s docstring and the printed states in `QSVT`'s usage details are marked `# doctest: +SKIP`, and the two scalar comparisons are written as a `code-block` rather than as a doctest; only the class example's `np.float64(0.5403...)` and the drawn decompositions carry no such marker. The correctness claim itself is re-derived outside the module, and at a larger scale than any docstring reaches, in the 1225-line `tests/templates/subroutines/test_qsvt.py`. `test_correctness_QSVT_angles`, docstring "Tests that angles generate desired poly", rebuilds the same one-wire construction the docstring uses, with the rotation reversed — `block_encoding = qp.RX(-2 * np.arccos(x), wires=0)` where the docstring writes `2 * np.arccos(x)`, then `projectors = [qp.PCPhase(angle, dim=1, wires=0) for angle in angles]` and `qp.QSVT(block_encoding, projectors)` — and asserts `qp.math.isclose(output.real, expected.real)` for `output = qp.matrix(circuit_qsvt, wire_order=[0])()[0, 0]` against `expected = sum(coef * (x**i) for i, coef in enumerate(poly))`, at an drawn from `np.random.default_rng(123).uniform(low=-1.0, high=1.0)` rather than at the fixed 0.2, and parametrized over polynomials of degree 4, 3, 6 and 100 and over both the `"root-finding"` and `"iterative"` solvers. `test_matrix_input` and `test_ham_input` do the same for the function across all four block encoders, asserting `np.allclose(qp.matrix(circuit)()[: len(A_matrix), : len(A_matrix)].real, expected)` against `expected = sum(coef * matrix_power(A_matrix, i) for i, coef in enumerate(poly))` over five matrix parametrizations through "fable" and "embedding" and four Hamiltonian ones through "prepselprep" and "qubitization". All three of those tests run on `default.qubit` as well, so the simulator is the whole of the evidence either way.
Quantum singular value transformation · Qiskit
From the repository — run, not written up from a paper · native
About
A framework for applying bounded polynomial transformations to singular values of a block-encoded matrix.
Methods
None found yet.
Data
None found yet.
Code
Qiskit
Results
Alternating block-encoding / inverse structure checked against the QSVT construction · polynomial degree and ancilla invariants recorded
- Quantum singular value transformation
A framework for applying bounded polynomial transformations to singular values of a block-encoded matrix.
References
- Quantum singular value transformation and beyond: exponential improvements for quantum matrix arithmetics
András Gilyén, Yuan Su, Guang Hao Low, Nathan Wiebe · 2018
- A Grand Unification of Quantum Algorithms
John M. Martyn, Zane M. Rossi, Andrew K. Tan, Isaac L. Chuang · 2021
- Sampling-based sublinear low-rank matrix arithmetic framework for dequantizing quantum machine learning
Nai-Hui Chia, András Gilyén, Tongyang Li, Han-Hsuan Lin, Ewin Tang, Chunhao Wang · 2019
Where the routes meet
Every circle is drawn once. This step has no smaller object recorded inside it, so the strands between its two circles are the recorded ways of taking it — one strand per method.
2 recorded ways of doing Matrix function. Nothing smaller is recorded inside it, so there is no object in the middle to draw.
2 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
- Every line on this figure is one a recorded source takes.
Open the cardRead the full write-up
Where you are
Path
- Solve a nonlinear ODE dy/dt = F(y)
- Quantum linear solve
- Matrix function
Ways through: 2
Routes that skip it
No recorded route avoids this step.
Narrower kinds
Nothing recorded is a narrower kind of this.
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