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
Uniformly controlled rotations
Prepare an arbitrary state with one layer of uniformly controlled (multiplexed) Ry and Rz rotations per qubit, the angles computed analytically from the amplitude list. This is the exact, assumption-free method most software stacks emit by default.
Open the full recordFills the slot: Prepare an input state
Applies to any state, with no structural assumption — which is exactly why it cannot beat the exponential bound. Ancilla-free in its basic form.
A description of — an explicit list of amplitudes, an analytic density, a list of nonzero entries, or a low-bond-dimension tensor network — plus a target .
Vector to load → State you can preparezero one qubit per rotation layer
The amplitude vector is folded down to one qubit at a time and the same recursion is run on the target and inverted, so that . A cascade of uniformly controlled -rotations equalises the phases first, , with ; a cascade of -rotations then folds each sibling pair onto its parent's norm, , zeroing one qubit per level. assumption: the paper takes the state "normalized to unity", and each angle is fixed by the ratio of one subtree's norm to its parent's. Each cascade is a product of gates , one per control-bit string. assumption: "the operational principle of the gate sequence requires that ", met here because the axis is or .
assumption
An -qubit circuit, possibly using ancillas, with a stated gate count, depth, ancilla count, and — where the circuit is not deterministic — a success probability.
None found yet.
given n qubits and the amplitude list of the arbitrary state to prepare
for each of the n qubits:
apply one layer of uniformly controlled (multiplexed) Ry rotations
apply one layer of uniformly controlled (multiplexed) Rz rotations
# every angle in those layers is computed analytically from the amplitude
# list; Mottonen, Vartiainen, Bergholm and Salomaa give the analytic
# expression, which is not transcribed here
# the state is prepared exactly -- this is the assumption-free method most
# software stacks emit by default
# their count, ancilla-free in this basic form: 2^(n+2) - 4n - 4 CNOT gates
# and 2^(n+2) - 5 one-qubit rotations
# Yuan and Zhang settle the ancilla-assisted case: depth Theta(n + 2^n/(n+m))
# and size Theta(2^n), for any number m of ancillary qubits
# applies to any state, with no structural assumption -- which is exactly
# why it cannot beat the exponential boundMöttönen, Vartiainen, Bergholm and Salomaa give CNOT gates and one-qubit rotations, with an analytic expression for the angles. Yuan and Zhang settle the ancilla-assisted case, pinning the depth complexity to and the size complexity to for any number of ancillary qubits. Li and Luo independently give size for an -qubit -sparse state with unlimited ancillas; the substitution that turns this into is arithmetic we performed, not a statement in their paper.
None found yet.
None found yet.
PennyLane `qml.MottonenStatePreparation` template
- Transformation of quantum states using uniformly controlled rotations
Mikko Mottonen, Juha J. Vartiainen, Ville Bergholm, Martti M. Salomaa · 2004
About
Xanadu's PennyLane ships this method as a named built-in template, and names the paper in the class docstring: it "Prepares an arbitrary state on the given wires using a decomposition into gates developed by Möttönen et al. (2004)", and "The state is prepared via a sequence of uniformly controlled rotations." The docstring gives the order of the two cascades for the inverse direction: "In the work of Möttönen et al., inverse state preparation is executed by first equalizing the phases of the state vector via uniformly controlled Z rotations, and then rotating the now real state vector into the direction of the state via uniformly controlled Y rotations." That is the order the paper itself gives in its Sec. III, where the algorithm for taking to is stated as two steps: first a cascade of uniformly controlled -rotations , "rendering the vector real up to the global phase", then a similar cascade of uniformly controlled -rotations onto . The file also records where it came from — "This code is adapted from code written by Carsten Blank for PennyLane-Qiskit" — and carries one standing caveat: "Due to non-trivial classical processing of the state vector, this template is not always fully differentiable."
Methods
The two angle helpers write out, in their own docstrings, the same two expressions this record's theory carries. `_get_alpha_z` gives and `_get_alpha_y` gives . `compute_decomposition` splits the input into `a = qp.math.abs(state_vector)` and `omega = qp.math.angle(state_vector)`, reverses the wire order ("change ordering of wires, since original code was written for IBM machines"), and runs the cascade first — `for k in range(len(wires_reverse), 0, -1)`, target `wires_reverse[k - 1]`, controls `wires_reverse[k:]` — which is the dagger of the docstring's order. The cascade, and with it the single `global_phase = -1 * qp.math.sum(omega, axis=-1) / qp.math.shape(state_vector)[-1]` that closes it, runs unless the phases are all zero and the input is neither abstract nor differentiable: the guard is `qp.math.is_abstract(omega) or qp.math.requires_grad(omega) or not qp.math.allclose(omega, 0)`, so under jit or under autodiff the cascade is emitted even for an all-real state. Each uniformly controlled rotation is compiled by Gray code rather than by nested controls: `_apply_uniform_rotation_dagger` sets `theta = compute_theta(alpha, num_qubits=gray_code_rank)`, then `code = gray_code(gray_code_rank)` and `control_indices = np.log2(code ^ np.roll(code, -1)).astype(int)`, and emits one rotation and one `qp.CNOT` per index — except at the end of each cascade, where the control list is empty, `gray_code_rank == 0` takes an early return, and at most one rotation and no CNOT is emitted. `compute_theta`'s docstring names the identity that makes this cheap: "This function uses the fact that the transformation given by Eq. (3) in Möttönen et al. (2004) is equal to a Walsh-Hadamard transform followed by some permutations, which can be expressed as a ladder of CNOT gates applied to the angles, when interpreting them as a quantum state." A rotation whose angle falls below `_ATOL = np.finfo(qp.math.get_dtype_name(theta)).eps` is dropped, but never when the angles are abstract or differentiable: `skip_none` starts as `qp.math.is_abstract(theta) or qp.math.requires_grad(theta)` and is then set true again when every angle already exceeds `_ATOL`. Read at tag `v0.45.1`. The `master` branch read the same day has diverged on one point: `_get_alpha_y` there gains a leaf-level branch, , so that a real-valued state carries its signs in the angles and skips the cascade and the global phase entirely. Neither that branch nor the `is_real` test exists in `v0.45.1`.
Data
No dataset — the template takes a state vector, and the module runs nothing else. The docstring's worked example is three wires on `qp.device('default.qubit', wires=3)`, PennyLane's state-vector simulator, with `state = np.array([1, 2j, 3, 4j, 5, 6j, 7, 8j])` divided by its own norm.
Code
`pennylane/templates/state_preparations/mottonen.py` in https://github.com/PennyLaneAI/pennylane, Python, Apache License 2.0. The class is `MottonenStatePreparation`, reached as `qml.MottonenStatePreparation`; the module-level helpers are `gray_code`, `compute_theta`, `_get_alpha_y`, `_get_alpha_z`, `_apply_uniform_rotation_dagger` and `_uniform_rotation_dagger_ops`. Read at tag `v0.45.1`, released 2026-06-26.
Results
No runtime, fidelity or hardware figure appears in the module. What it does execute is its own docstring: `>>> print(np.allclose(state, circuit(state)))` returns `True` on three wires, a device-level drawing of that same circuit is printed beside it, and `compute_decomposition`'s docstring runs a second two-wire example whose printed op list opens `[RY(tensor(1.5708, dtype=torch.float64), wires=['a']),`. The gate counts the file carries are declared, not measured: `_mottonen_resources(num_wires)` sets `n = 2**num_wires - 1` and returns `{qp.GlobalPhase: 1, qp.RY: n, qp.RZ: n, qp.CNOT: 2 * (n - 1)}`, attached with `qp.register_resources(_mottonen_resources, MottonenStatePreparation.compute_decomposition, exact=False)`. PennyLane documents that flag, in `pennylane/decomposition/decomposition_rule.py`, as "whether the resources are computed exactly (``True``, default) or estimated heuristically (``False``)" — it marks the count as a heuristic and states no direction for the error. Where the gap shows is the docstring's own drawn circuit: counted off that drawing here, the three-wire case draws seven `RY` and twelve `CNOT`, matching the declared and , but a single `RZ(1.57)` against a declared seven.
- Transformation of quantum states using uniformly controlled rotations
Qiskit `UCRYGate` / `UCRZGate` and the `UCGate` multiplexer
- Quantum circuits with uniformly controlled one-qubit gates
Ville Bergholm, Juha J. Vartiainen, Mikko Mottonen, Martti M. Salomaa · 2004
- Quantum Multiplexer Simplification for State Preparation
José A. de Carvalho, Carlos A. Batista, Tiago M. L. de Veras, Israel F. Araujo, Adenilton J. da Silva · 2024
About
Qiskit ships the uniformly controlled rotation as a first-class library gate rather than only as a state-preparation subroutine, so it can be read as the construction itself. But the claim that this is what a software stack emits by default needs a date attached to it, because Qiskit's own state preparation stopped emitting it: the 1.2 release note records "Replacing the internal synthesis algorithm of :class:`~.library.StatePreparation` and :class:`~.library.Initialize` of Shende et al. by the algorithm given in :class:`~.library.Isometry` of Iten et al." At tag 2.5.2, `StatePreparation._define` branches three ways — from a label, from an integer, and otherwise into `_define_synthesis_isom`, the state-vector path, which builds `Isometry(self.params, 0, 0)`; that isometry disentangles one qubit at a time with `UCGate`, the multiplexed-single-qubit-unitary generalisation, and never constructs a `UCRYGate` or a `UCRZGate`. The two rotation gates remain in the library and remain used in-tree — `ExactReciprocalGate._define` appends `UCRYGate(angles)` directly, and `DiagonalGate._define` appends `UCRZGate(angles_rz)`.
Methods
`UCPauliRotGate` takes a "List of rotation angles " and an axis that "Must be either of ``"X"``, ``"Y"`` or ``"Z"``"; `UCRYGate` and `UCRZGate` are subclasses whose entire body is the one line that fixes the axis, `super().__init__(angle_list, "Y")`. `_dec_ucrot` first rewrites the angles in place with the recursion `_dec_uc_rotations`, whose base step is `_update_angles`, returning `(angle1 + angle2) / 2.0, (angle1 - angle2) / 2.0` — the pair's average and its half-difference — and documented as "Calculate the new rotation angles according to Shende's decomposition"; the module header credits the structure to "Emanuel Malvetti's semester thesis at ETH in 2018, which was supervised by Raban Iten and Prof. Renato Renner." It then places the CNOTs by a trailing-zero rule rather than by an explicit Gray code — the comment reads "Determine the index of the qubit we want to control the C-NOT gate. Note that it corresponds to the number of trailing zeros in the binary representation of i+1" — with the final iteration special-cased to `q_contr_index = len(q_controls) - 1`. A rotation is emitted only when `np.abs(angle) > _EPS` with `_EPS = 1e-10`, while `circuit.cx(...)` is appended on every one of the loop's `len(angles)` iterations, so the CNOT count does not thin out with the angles. For the X axis each CNOT is wrapped in `ry(np.pi / 2)` and `ry(-np.pi / 2)`, which the file explains as changing "the basis of the NOT operation, such that the decomposition of for uniformly controlled X rotations works correctly by symmetry with the decomposition of uniformly controlled Z or Y rotations". `UCGate` in `uc.py` is the general block-diagonal case, "The decomposition is based on Ref. [1]" — Bergholm et al. — with `_dec_ucg_help` pointing at "https://arxiv.org/pdf/quant-ph/0410066.pdf" and delegating the numerics to Rust through `from qiskit._accelerate import uc_gate`; it reuses the same trailing-zero CNOT rule. Since 2.0 it also carries `mux_simp`, default `True`, whose release note says it "enables the search for simplifications of Carvalho et al., implemented in :meth:`~.library.UCGate._simplify`. This optimization, enabled by default, identifies and removes unnecessary controls from the multiplexer, reducing the number of CX gates and circuit depth, especially in separable state preparation with :class:`~.library.Initialize`." Carvalho et al. confirm the same handover from their side: "The simplification proposed in this work is applied by default in the UCGate of qiskit version 2.0.0rc1."
Data
No dataset — `UCPauliRotGate` takes an angle list, `UCGate` a list of unitaries. Neither module executes a circuit; both only construct one.
Code
https://github.com/Qiskit/qiskit, Python, Apache License 2.0. `qiskit/circuit/library/generalized_gates/uc_pauli_rot.py` holds `UCPauliRotGate` with `_dec_ucrot`, `_dec_uc_rotations` and `_update_angles`; `ucry.py` and `ucrz.py` hold the axis-fixed subclasses `UCRYGate` and `UCRZGate`; `uc.py` holds `UCGate` with `_dec_ucg`, `_dec_ucg_help` and `_simplify`. The state-preparation path that no longer uses them is `qiskit/circuit/library/data_preparation/state_preparation.py` (`StatePreparation._define_synthesis_isom`) into `generalized_gates/isometry.py` (`Isometry`). The in-tree consumers are `qiskit/circuit/library/arithmetic/exact_reciprocal.py` for `UCRYGate` and `generalized_gates/diagonal.py` (`DiagonalGate._define`) for `UCRZGate`. Read at tag `2.5.2`, released 2026-08-13; `uc_pauli_rot.py`, `ucry.py` and `ucrz.py` are each headed "(C) Copyright IBM 2020".
Results
The modules themselves report no measurement. The only quantitative statement on this path is the 1.2 release note's claim for the algorithm that displaced the multiplexer route: "The new algorithm reduces the number of CX gates and the circuit depth by a factor of 2." The 2.0 note claims `mux_simp` reduces CX count and depth but attaches no figure to it, and Carvalho et al.'s own figures are plotted rather than tabulated.
- Quantum circuits with uniformly controlled one-qubit gates
qclib `TopDownInitialize` and the `multiplexor` it calls
- Transformation of quantum states using uniformly controlled rotations
Mikko Mottonen, Juha J. Vartiainen, Ville Bergholm, Martti M. Salomaa · 2004
- Configurable sublinear circuits for quantum state preparation
Israel F. Araujo, Daniel K. Park, Teresa B. Ludermir, Wilson R. Oliveira, Francesco Petruccione, Adenilton J. da Silva · 2021
About
qclib is a Qiskit-based library whose stated focus is this problem — "Qclib is a quantum computing library implemented using qiskit. The focus of qclib is on preparing quantum states, but it is not limited to that." `TopDownInitialize` is its direct realisation of this method, and it says so without prose: the module docstring of `topdown.py` is nothing but the two URLs it implements, `https://arxiv.org/abs/quant-ph/0407010` and `https://arxiv.org/abs/2108.10182`, and the class docstring repeats both under the heading "Top-down state preparation". It is one of the sixteen initialisers exported from `qclib/state_preparation/__init__.py`, so the library carries the multiplexor route as one option among many.
Methods
On its default `lib='qclib'` path — the alternative, `opt_params={'lib': 'qiskit'}`, returns a circuit built by `circuit.initialize(self.params)` and touches none of the machinery below — `_define_initialize` builds an amplitude tree and then an angle tree before it emits any gate: `state_tree = state_decomposition(self.num_qubits, data)`, `angle_tree = create_angles_tree(state_tree)`, then `add_register(circuit, angle_tree, 0)` and `top_down(angle_tree, circuit, 0)`. `state_decomposition` stores each leaf as `abs(k.amplitude)` and `cmath.phase(k.amplitude)` and folds parents upward as `mag = math.sqrt(nodes[k].mag ** 2 + nodes[k + 1].mag ** 2)` and `arg = (nodes[k].arg + nodes[k + 1].arg) / 2`. `create_angles_tree` then reads each node's pair of angles off the child-to-parent ratio and the phase difference: `mag = state_tree.right.mag / state_tree.mag`, `arg = state_tree.right.arg - state_tree.arg`, `angle_y = 2 * math.asin(mag)` and `angle_z = 2 * arg` — with `angle_y` set to or outright, rather than through `asin`, when `mag` falls below or above ("Avoid out-of-domain value due to numerical error"). `top_down` emits at most one Ry layer and one Rz layer per tree level, each behind its own `if any(...)` guard so that an all-zero layer is skipped, controlled on the qubits of the levels already visited: `angles_y = [node.angle_y for node in target_nodes]`, `ucry = multiplexor(RYGate, angles_y, last_control=not any(angles_z))`, and the Rz layer appended as `ucrz.reverse_ops()`. That reversal is a deliberate saving the file states outright: "If both multiplexors are used (RY and RZ), we can save two CNOTs. That is why the RZ multiplexor is reversed." The global phase is corrected by default with `circuit.global_phase += sum(np.angle(self.params)) / len(self.params)`. The multiplexer itself is the module-level function `multiplexor` in `qclib/gates/ucr.py` — `tree_walk.py` imports and calls that function, never the `Ucr` gate class in the same file — and its docstring names a different source than the state-preparation module does, "Synthesis of Quantum Logic Circuits" with the URL `https://arxiv.org/abs/quant-ph/0406176`. It recurses by applying `angle_multiplexor = np.kron([[0.5, 0.5], [0.5, -0.5]], np.identity(2 ** (n_qubits - 2)))` to the angle list, calling itself on each half with `last_control=False`, reversing the second half's operations, and composing one `c_gate()` between the two — a parameter `c_gate: Union[Type[CXGate], Type[CZGate]] = CXGate`, left at its `CXGate` default on the `top_down` path — with the closing one emitted only `if last_control`. The comment gives the cancellation this relies on: "Figure 2 from Synthesis of Quantum Logic Circuits: The recursive decomposition of a multiplexed Rz gate. The boxed CNOT gates may be canceled." The `Ucr` gate class in the same file wraps `multiplexor` and offers `'multiplexor'` (its default), `'mcg'` and `'auto'` as build methods, plus a `simplify` path, off by default, which groups control strings whose angles agree to `np.isclose(..., atol=0.0, rtol=1e-07)`, minimises each group's control patterns into don't-care strings with SymPy's `simplify_logic(..., form='dnf', force=True, deep=False)`, and then searches for separability — "qubits not used after simplification" — before choosing between the multiplexer and multi-controlled gates.
Data
No fixed dataset. The README's comparison runs "the same random 15-qubit state", which the notebook it links builds unseeded as `np.random.rand(2 ** n_qubits) + np.random.rand(2 ** n_qubits) * 1j` divided by its norm. The README's own quick-start example is a 3-qubit vector seeded with `np.random.RandomState(42)`, but it calls `LowRankInitialize`, not `TopDownInitialize`.
Code
https://github.com/qclib/qclib, Python on top of Qiskit, Apache License 2.0. `qclib/state_preparation/topdown.py` holds `TopDownInitialize`; `qclib/gates/ucr.py` holds the `multiplexor` function and the `Ucr` gate; the tree helpers are `qclib/state_preparation/util/state_tree_preparation.py` (`state_decomposition`), `angle_tree_preparation.py` (`create_angles_tree`), `tree_register.py` (`add_register`) and `tree_walk.py` (`top_down`, and a `bottom_up` alternative that swaps the multiplexers for plain `ry`/`rz` plus a `cswap` cascade in `_apply_cswaps`). The repository publishes no tags; read at commit `cf06981` on `master`, dated 2026-04-07.
Results
The README carries a table for one random 15-qubit state, transpiled by its linked notebook to `basis_gates=['u', 'cx']` at `optimization_level=0`. Two rows price the Qiskit routes — `multiplexor | qiskit | 15 | 65504 | 131025` and `isometry | qiskit | 15 | 32752 | 65505`, columns qubits, cnots, depth — and qclib's own uniformly-controlled-gate initialiser matches the second at `ucg | qclib | 15 | 32752 | 65505`. Three limits on reading that table: it has no `top-down` row, so it does not price `TopDownInitialize` itself; its `multiplexor` row is produced by `circuit_mul.initialize(state)`, which is the Qiskit call whose internal algorithm Qiskit 1.2 replaced; and neither the README nor the notebook states which Qiskit version produced the numbers.
- Transformation of quantum states using uniformly controlled rotations
None found yet.
References
- Transformation of quantum states using uniformly controlled rotations
Mikko Mottonen, Juha J. Vartiainen, Ville Bergholm, Martti M. Salomaa · 2004
- Optimal (controlled) quantum state preparation and improved unitary synthesis by quantum circuits with any number of ancillary qubits
Pei Yuan, Shengyu Zhang · 2022
- Nearly Optimal Circuit Size for Sparse Quantum State Preparation
Lvzhou Li, Jingquan Luo · 2024
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.
3 recorded ways of doing Prepare an input state. Nothing smaller is recorded inside it, so there is no object in the middle to draw.
Everything on this figure that opens is open.
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
- Prepare an input state
Ways through: 3
Routes that skip it
No recorded route avoids this step.
Narrower kinds
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