Qubit ordering¶
An MPS is a one-dimensional chain. Entanglement between neighbouring sites is cheap; entanglement between distant sites is expensive, because every bond in between has to carry it. A gate on qubits 0 and 40 forces a wide bond across everything separating them, and the cost is paid by every gate that follows.
Qubit numbering is a labelling, not physics. Relabelling so that interacting qubits sit near each other can lower the bond dimension a circuit needs, for the same answer. This is the one control that can make a run cheaper without making it less accurate.
Turning it on¶
Reordering is off by default. The layout you wrote is the layout that runs.
True runs the whole portfolio of searches and keeps whichever result scores
best. Naming one ("greedy", "sa" / "simulated_annealing", "multilevel")
pins the search instead, which is mostly useful for comparing them: the result
is scored the same way either way.
The same arguments work on TwSimulator:
How a layout is chosen¶
The searches minimise the total weighted distance between interacting qubits. That is a good thing to descend, and a poor thing to decide by: it has no bond dimension in it, so it cannot tell a layout that fits under your cap from one that does not, and on a ring it will happily fold the chain and double every cut.
So the search result is not the answer, it is a candidate. What decides is a
different cost. For each bond k of the chain, with u_k two-qubit gate
applications crossing it and h_k bits of entanglement those gates can create:
Over every bond: how many truncations happen there, times how many bits each one
has to throw away. C = 0 means no bond ever exceeds bonddim, so the layout
truncates nothing. Your own layout is always one of the candidates, and a
search result has to beat it by reorderqubits_margin (default 2.0) before it
is used. A layout that truncates nothing is used whatever the margin.
Two consequences worth knowing:
bonddimchanges the answer. The same circuit can want different layouts at 64 and at 1024, because what matters is which bonds do not fit.- Gates are weighted by what they entangle, not by how many there are. A
CP(π)is worth one bit, aCP(1e-9)none. A circuit carrying a cloud of negligible controlled phases used to drag the layout towards gates that do nothing.
What it decided, and why¶
Both outcomes are reported, so you never have to guess whether the pass helped:
sim = tw.TwSimulator(bonddim=256, reorderqubits=True)
sim.compile(circuit)
print(sim.last_layout_report)
The report carries the cost, the widest bond in bits, and the number of bonds
over budget, each for the chosen layout and for the one you wrote, plus which
search won. It is also logged at INFO on the tensorweaver.reorder logger:
You get your own labelling back¶
The permutation is internal. Samples, amplitudes, and z-variables are all translated back to the qubit numbering you wrote, so nothing downstream has to know a reordering happened. A circuit run with and without reordering answers in the same frame.
When it helps¶
Reordering pays when the interaction graph has locality that the numbering hides:
- long-range pairings, such as a circuit coupling qubit
iwith qubitn-1-i - a layout inherited from hardware whose numbering does not match its connectivity
- a circuit generated from a graph problem, where the graph is local but the labelling is arbitrary
It cannot help when the interaction graph is genuinely all-to-all, because there is no layout in which every pair is close. It does nothing for a circuit that is already nearest-neighbour, because the identity permutation is already the best one. In both cases the searches run, score no better than your layout, and the circuit passes through unchanged.
The search is a compile step, so it costs preparation time: milliseconds on a hundred qubits, under a second on a thousand. Above a size threshold the portfolio runs fewer searches rather than slower ones, so it never costs more than a large multiple of a single search.
Deciding whether it is worth it¶
Measure it. The peak bond dimension is the number that moves:
import tensorweaver as tw
for reorder in (False, True):
sim = tw.TwSimulator(bonddim=256, reorderqubits=reorder, seed=1)
state, fidelity = sim.evolve(sim.zerostate(n), sim.compile(circuit))
print(f"reorderqubits={reorder!s:>5} "
f"chi {state.mps.max_used_bond_dim:>4} "
f"fidelity {float(fidelity):.6f}")
Run it once at a bonddim large enough that neither configuration saturates, so
you are comparing the width each layout genuinely needs rather than the ceiling.
If the reordered run needs a much smaller bond dimension, it will be faster and
more accurate at every bonddim below that; if the two are close, the layout
was already reasonable and reordering is not where the cost is.
Example 07 in the bundled examples builds the canonical bad case and prints the peak bond dimension with and without reordering.
Bond observables pin the layout¶
Bond observables are the one thing not permuted. BondDim(), SchmidtRank()
and VonNeumannEntropy() take a bond index, naming the bipartition
{0..k-1} | {k..n-1}, not a qubit. A layout that moved a qubit across such a cut
would change what the observable measures, so those cuts are kept intact and the
index is left alone: the observable still reports the bipartition you asked for.
A circuit that profiles every bond is therefore fully pinned, and no reordering is available to it.
Reading the entropy profile¶
Where the entanglement sits is what tells you whether a different layout could help at all. The von Neumann entropy across each bond is the direct measurement: a profile with one tall peak in the middle usually means a few long-range couplings are responsible and a layout change may pay, while a broad, flat profile means the entanglement is spread across the whole chain and no relabelling will concentrate it.