Sign outOpen workspaceSign in

MethodLayer 2

Quantum singular value transformation

Interleave the block-encoding UU, its inverse, and projector-controlled phase shifts eiφ(2ΠI)e^{iφ(2Π-I)} so that the designated block becomes PP applied to the singular values of AA. The phase sequence is the compiled form of the polynomial, and a single ancilla qubit carries the phase shifts.

Takes

A block-encoding of AA together with its subnormalisation α\alpha; a target function ff on [1,1][-1,1]; an error budget ε\varepsilon.

Returns

A circuit implementing a block-encoding of f(A)f(A) to error ε\varepsilon, together with the query count in UU and UU^\dagger.

Same contract as the slot it fills.

This one, drawn

Quantum singular value transformationQuantum singular value transformation · 2 parts inside, openQuantum singular value transformation · 2 parts inside, openQuantum singular value transformation · 2 parts inside, open — click the line to close itBlock-encode a matrix ×n · 4 ways throughBlock-encode a matrix ×n · 4 ways through — click the line to open it hereQuantum singular value transformationChebyshev series by linear combination of unitaries · 2 parts inside, openChebyshev series by linear combination of unitaries · 2 parts inside, openChebyshev series by linear combination of unitaries · 2 parts inside, open — click the line to close itBlock-encode a matrix · 4 ways throughBlock-encode a matrix · 4 ways through — click the line to open it hereChebyshev series by linear combination of unitariesQuantum singular value transformation · 2 parts inside, open — click the name to close itQSVTBlock-encode a matrix ×n · 4 ways through — click the name to read about itBlock-encode a matrix ×nQuantum singular value transformation — click the name to read about itinterleave the encoding with phase shiftsChebyshev series by linear combination of unitaries · 2 parts inside, open — click the name to close itChebyshev series by LCUBlock-encode a matrix · 4 ways through — click the name to read about itBlock-encode a matrixChebyshev series by linear combination of unitaries — click the name to read about itcombine the Chebyshev terms, post-selectBlock-encoding — you start hereBlock-encoding of f(A) — you finish hereBlock-encoding — what one part hands to the nextBlock-encoding — what one part hands to the next

Drag to pan. Pinch, or hold ctrl and scroll, to zoom. Arrow keys pan, plus and minus zoom, zero resets the view.

From Block-encoding to Block-encoding of f(A)

A circle is an object you are holding. This method is drawn heavier, opened into its own steps; the other lines between the same two ends are the alternatives recorded for the same slot. Circles are named on hover, and each one is a link.

2 lines here have ways through that this figure does not open. The map opens them in place. See it on the map

What it fills

  • Matrix function

    Given a block-encoding of AA and a target function ff bounded on [1,1][-1,1], produce a circuit whose designated block is an ε\varepsilon-approximation of ff applied to the singular values (or eigenvalues) of AA.

When it applies

The polynomial must have definite parity, matching the degree mod 2, and satisfy P(x)1|P(x)| ≤ 1 for every xx in [1,1][-1,1]. 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 PP is handled directly; a real PP — which is what approximations of 1/x1/x, 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.

Requires

These do not move the route along. The method needs each of them alongside its own work, and the cost of getting them is part of what the method costs.

  • Polynomial approximation

    Given a target function, a domain and an error ε\varepsilon, return a polynomial of definite parity, bounded on [1,1][-1,1], that is ε\varepsilon-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 sup[1,1]P\sup_{[-1,1]}|P_\Re| — and what returns is a degree-nn polynomial PP_\Re the circuit never performs arithmetic on: only the phases compiled from it appear. The degree nn 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-dd Chebyshev polynomial with d1d-1 uses of the block-encoding UU, since Td(x)T_d(x) takes the value 11 at x=1x = 1 with derivative d2d^2. A shorter circuit can only be bought as a coarser approximation here. approximation: the sequence realizes PP_\Re and not the function PP_\Re 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 ε\varepsilon in classical finite-precision arithmetic.

    QSVT asks this layer for ΦRn\Phi \in \mathbb{R}^n, one angle per turn for a degree-nn polynomial, and the ask depends on nothing quantum: Corollary 10 takes only the target polynomial PP_\Re and an accuracy δ0\delta \ge 0 as input — no property of AA, UU or α\alpha 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 Φ\Phi exists, proved non-constructively from Theorems 3–5. The constructive statement is Corollary 10: given PP_\Re and δ\delta one can find a PP and a corresponding Φ\Phi “using a classical computer in time O(poly(d,log(1/δ)))O(\mathrm{poly}(d, \log(1/\delta)))” — polynomial in the degree dd, logarithmic in the precision. approximation: the guarantee is [P]Pδ|\Re[P] - P_\Re| \le \delta for all x[1,1]x \in [-1,1], so Φ\Phi reproduces the requested polynomial only to δ\delta and not exactly. Recovering Φ\Phi from the intermediate phases, the paper adds, “only yields a small overhead”.

    approximation

Example

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
# dequantized

Cost, as the source states it

Gilyén, Su, Low and Wiebe (Lemma 19): a degree-nn transform costs nn uses of UU and UU\dagger, nn uses of CΠC_Π NOT, nn uses of CΠ~C_Π̃ NOT and nn single-qubit gates, with a single ancilla qubit. The degree nn is handed down by the polynomial-approximation layer, so that layer is what sets this circuit's query count.

Implementations

  • PennyLane qml.QSVT template and qml.qsvt function

    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.

    `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 UQSVT=Π~ϕ1U[k=1(d1)/2Πϕ2kUΠ~ϕ2k+1U]Πϕd+1U_{QSVT} = \tilde{\Pi}_{\phi_1}U\left[\prod^{(d-1)/2}_{k=1}\Pi_{\phi_{2k}}U^\dagger \tilde{\Pi}_{\phi_{2k+1}}U\right]\Pi_{\phi_{d+1}} when the number of phase shifts is even (dd odd), and UQSVT=[k=1d/2Πϕ2k1UΠ~ϕ2kU]Πϕd+1U_{QSVT} = \left[\prod^{d/2}_{k=1}\Pi_{\phi_{2k-1}}U^\dagger\tilde{\Pi}_{\phi_{2k}}U\right]\Pi_{\phi_{d+1}} when it is odd (dd even); a degree-dd polynomial is therefore carried by d+1d+1 phase shifts, and the documented call for P(x)=xx32+x53P(x) = x - \frac{x^3}{2} + \frac{x^5}{3} 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 Πϕ1,U,Πϕ2,U,Πϕ3\Pi_{\phi_1}, U, \Pi_{\phi_2}, U^\dagger, \Pi_{\phi_3}. Nothing in that method tells Π\Pi from Π~\tilde{\Pi}: position in the list is the only thing deciding whether a phase shift is followed by UU or by UU^\dagger, and `compute_decomposition`'s own docstring restates the first formula with its leading factor written Πϕ1\Pi_{\phi_1} where the class docstring writes Π~ϕ1\tilde{\Pi}_{\phi_1}. 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 Π(ϕ)=exp(iϕ(2ΠIN))\Pi(\phi) = \exp(i\phi(2\Pi-\mathbb{I}_N)) with Π\Pi "the diagonal projector with dim ones and N-dim zeros" — this record's own eiφ(2ΠI)e^{iφ(2Π-I)} — 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 CΠNOTC_\Pi\mathrm{NOT} 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 c=rc = r 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 (1,1)(-1,1) is not stopped here.

    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 H=0.1X30.7X3Z40.2Z3Y4H = 0.1X_3 - 0.7X_3Z_4 - 0.2Z_3Y_4, a different operator on different wires from the one the code beneath builds. And under the angle helpers, the scalar x=0.2x = 0.2 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 P(x)=x+0.5x3+0.5x5P(x) = -x + 0.5x^3 + 0.5x^5, 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 P(x)=xx32+x53P(x) = x - \frac{x^3}{2} + \frac{x^5}{3}. 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.

    `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.

    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 x=0.2x = 0.2 as `RX(2 * np.arccos(x))`, apply P(x)=xx32+x53P(x) = x - \frac{x^3}{2} + \frac{x^5}{3} 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 2×10132 \times 10^{-13}. 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 4×44 \times 4 real block for P(x)=x+0.5x3+0.5x5P(x) = -x + 0.5x^3 + 0.5x^5 applied to 0.3Z1+0.7X1Z20.3 Z_1 + 0.7 X_1 Z_2 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 xx 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.

Where the claim is contested

Where the matrix is close to low rank and the input model is 2ℓ²-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.

What it needs

  1. Block-encode a matrix 4 methodsruns n uses of U and n of U†, for a degree-n transform

    Wrap an operator AA inside a larger unitary UU so that A/αA/α sits in UU's top-left block, giving every routine above it one uniform way to touch the matrix. The subnormalization αα and the ancilla count are outputs of this layer, not free parameters.

    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.

Other ways to fill the same slot

Different approaches

  • Chebyshev series by linear combination of unitaries

    Write the target function as a Chebyshev series, then implement that series as a linear combination of walk-operator powers using a PREPARE/SELECT pair on an ancilla register, and post-select. No phase factors are computed — the polynomial enters through the coefficients of the combination instead.

In the Atlas

Sources