Understanding Quantum Interference

Amplitudes carry signs, so they can reinforce or cancel. How the cancellation works on one qubit, in Grover's search and in three community projects.

About the author

Nicolaas Spijker
Nicolaas Spijker
Community manager, Qollab

Nico runs the builder community at Qollab. These concept articles come out of that work: forking and running the projects people publish, and talking with their authors.

Quantum interference lets a circuit move probability onto some outcomes and away from others. Superposition alone does not: a qubit in an equal superposition measured a thousand times gives roughly five hundred 0s and five hundred 1s, the same split as a thousand coin flips.

What is quantum interference?

Quantum interference happens when a circuit can reach the same outcome by more than one route. Every route carries an amplitude, a number with a size and a direction, and the simplest useful case is an amplitude that is either positive or negative. The routes leading to one outcome are added together, and the probability comes from the size of that sum. Routes that point the same way reinforce each other, and a positive and a negative route of the same size cancel to zero.

Grover's search uses cancellation between routes to raise a one-in-eight guess to a 94.5% hit rate in two iterations.

Where interference came from

Interference was observed in light long before anyone built a qubit, and since then in electrons and in molecules.

1803Thomas Young splits a narrow beam of sunlight with a thin card and observes bright and dark interference fringes.
1909G. I. Taylor gets the same fringes from light as faint as a candle a mile away, after a three-month exposure.
1927Davisson and Germer diffract electrons off a nickel crystal, showing that matter interferes too.
1961Claus Jönsson sends electrons through a double slit.
1989Tonomura's team uses an electron biprism and films single electrons landing one dot at a time until the fringes appear.
1999Markus Arndt and colleagues in Anton Zeilinger's group get interference from molecules of sixty carbon atoms.

At Young's bright fringes the light from the two sides of the card arrives in step, and the two contributions add. Each dark band is a place that light can reach by either route but where little or none arrives, and blocking one of the two routes makes it brighter: the second route subtracts from the first.

Each experiment in the timeline gives the light or the particles more than one route to the screen.

Taylor's fringes came out as sharp as with a bright lamp, so the pattern does not come from photons interacting with each other. In Tonomura's film the pattern builds up from single electrons over about twenty minutes.

Adding amplitudes before squaring

A quantum state carries an amplitude for each outcome. Squaring an amplitude's size gives the probability of that outcome, so a negative amplitude and a positive one of the same size are equally likely to be measured. When two routes lead to the same outcome their amplitudes are added first, and the squaring happens to the sum. Feynman's Lectures on Physics introduce the rule with the two-slit experiment.

Classical probabilities for separate routes can only add: two routes to the same outcome, each with a one-in-four chance, give a one-in-two chance of getting there. Two positive numbers do not add to zero, so Young's dark bands cannot come from adding probabilities.

Take two routes with amplitudes of +0.5 and −0.5. Add the two amplitudes and the sum is 0, and 0 squared is 0, so the outcome never happens. Square each amplitude first and each route gives 0.25, and 0.25 plus 0.25 is 0.5, so the outcome happens half the time.

Cancelling in one place does not remove probability from the pattern as a whole, which always totals one. The probability missing from a dark band turns up at the bright bands, so a bright band is brighter than either route produces alone.

The smallest cancellation you can make

A circuit version of Young's experiment takes three gates. A Hadamard opens two routes, an rz sets how far out of step they are, and a second Hadamard brings them back together, where they add or cancel.

one_phase.py Python · Playground version
# 'backend' is pre-created for you in the Qollab Playground.
from math import pi
from qiskit import QuantumCircuit
​
def zeros(theta):
    qc = QuantumCircuit(1, 1)
1    qc.h(0)
2    qc.rz(theta, 0)
3    qc.h(0)
    qc.measure(0, 0)
    counts = backend.run(qc, shots=1000).result().get_counts()
4    return counts.get('0', 0)
​
for name, theta in [("0", 0), ("pi/4", pi / 4), ("pi/2", pi / 2), ("3pi/4", 3 * pi / 4), ("pi", pi)]:
5    print(f"rz({name:>5}) -> {zeros(theta)} zeros out of 1000")
  1. 1After one Hadamard the qubit has two routes open, the 0 route and the 1 route, and measuring here gives roughly 500 of each.
  2. 2Turn a phase on the 1 route. The rz moves no probability: measure right after this line and the tally is still about 500 each, whatever the angle.
  3. 3The second Hadamard sends both routes to both answers, so each answer is reached twice, and the two contributions add or cancel according to the angle.
  4. 4How many of the thousand shots read 0.
  5. 5Five jobs at five angles: the count of 0s falls from 1000 to 0, and only the phase changes.
rz angleshots reading 0
01000
π/4~854
π/2~500
3π/4~146
π0

To run the listing, paste it into a Playground project and choose the Built-in simulator, the first entry under Locally Run Simulators in the Run on Qollab dialog. The listing sends five jobs, one per angle, and on an IonQ backend the Playground allows one job per run of your code. The IBM entries in the same group add a device's noise, so on those the top and bottom rows come out near 1000 and 0.

The expected number of 0s is 1000 × cos²(θ/2). The top and bottom rows use the same three gates and the same measurement, and one gives 0 with certainty while the other gives 1.

random.randint(0, 1) gives you the middle row. A classical random draw can be biased, but two classical probabilities cannot cancel, because a probability has no sign.

The second Hadamard is the circuit's screen: the qubit reaches 0 along both routes, the two amplitudes are added there, and θ sets whether they reinforce or cancel. At θ = π the two amplitudes cancel exactly, and all thousand shots land on 1.

The gates in these circuits

Five gates cover most of the excerpts on this page.

h

Hadamard

Takes a qubit sitting at 0 and leaves it with no fixed value: measure it and you get 0 or 1 with equal probability.

The Hadamard is its own inverse. Many circuits here start and end with a layer of Hadamards: the first opens the routes, the second recombines them, and the gates in between decide how they add.

rz

Rotates the phase. The angle comes before the qubit, and it shifts the 1 half of the state out of step with the 0 half by that much; at π that is a flipped sign, and smaller angles go part of the way.

An rz on its own changes no probability: the counts are the same whether the angle is 0 or π, and the difference shows only after another gate recombines the two halves.

cz

Controlled-Z

Flips the sign of one outcome, the one where both qubits read 1, and leaves the other three alone. Like rz it moves no probability by itself.

For more than two qubits the same job is written as h, a multi-controlled x, then h again on the last qubit. Both Grover circuits below write the flip that way, and Qiskit calls the three-qubit version of that x a ccx.

x

Swaps 0 and 1 on a single qubit, like a classical NOT.

In these circuits, x gates select which outcome gets a sign flip: wrap a cz in x gates and the flip applies to the outcome you choose.

measure

Reads a qubit into an ordinary bit and forces it to a definite 0 or 1. Measurement cannot be undone, and the sign of an amplitude never appears in its counts.

So every circuit here has to turn its signs into probabilities before this line.

Grover's search: a mark that changes none of the odds

Qollab ships a runnable Grover's search. Three qubits give eight possible answers, one of which is the target, and a Hadamard on each qubit starts all eight at 12.5%.

The first half of the algorithm is the oracle, which marks the target.

grovers_search.py Python · Playground versionOpen in Playground ↗
target = "101"
# ...
​
# ── Oracle: phase-flip the target state ──────────────────────────────
def build_oracle(target):
    n = len(target)
    oracle = QuantumCircuit(n, name="Oracle")
    for i, bit in enumerate(reversed(target)):
        if bit == "0":
1            oracle.x(i)
    if n == 2:
        oracle.cz(0, 1)
    elif n == 3:
        oracle.h(2)
2        oracle.ccx(0, 1, 2)
        oracle.h(2)
    else:
        oracle.h(n - 1)
        oracle.mcx(list(range(n - 1)), n - 1)
        oracle.h(n - 1)
    for i, bit in enumerate(reversed(target)):
        if bit == "0":
3            oracle.x(i)
    return oracle
  1. 1These x gates select which outcome the flip below applies to. 101 has a 0 in the middle, so the middle qubit gets flipped and the answer being marked temporarily becomes 111.
  2. 2These three lines are the mark: h, ccx, h together flip the sign of the one outcome where all three qubits read 1, so one of eight amplitudes becomes negative and the other seven are untouched.
  3. 3Undo those x flips, so the sign now sits on 101, the target.
▶ Run on QollabBackend

The function as a whole moves no probability: run it on the eight-way superposition and all eight outcomes still sit at 12.5%.

The mark is a sign, which a measurement cannot report, like the phase the rz wrote in the one-qubit listing.

Turning the mark into probability

The second half of Grover's search is the diffuser, the same h, phase, h arrangement on three qubits.

grovers_search.py Python · Playground versionOpen in Playground ↗
# ── Diffuser: amplify the marked state ───────────────────────────────
def build_diffuser(n):
    diffuser = QuantumCircuit(n, name="Diffuser")
1    diffuser.h(range(n))
    diffuser.x(range(n))
    if n == 2:
        diffuser.cz(0, 1)
    elif n == 3:
        diffuser.h(2)
2        diffuser.ccx(0, 1, 2)
        diffuser.h(2)
    else:
        diffuser.h(n - 1)
        diffuser.mcx(list(range(n - 1)), n - 1)
        diffuser.h(n - 1)
    diffuser.x(range(n))
3    diffuser.h(range(n))
    return diffuser
  1. 1Recombine the routes, the same move as the second Hadamard in the one-qubit listing, on all three qubits at once.
  2. 2The same sign flip as the oracle, which the x layer applies to the all-zeros outcome this time. The diffuser is the same for every target; only the oracle depends on it.
  3. 3After the closing Hadamard layer, every amplitude is the same distance from the average as before, on the other side of it, so the one the oracle pushed below the average ends up furthest above it.
▶ Run on QollabBackend

The standard name for those seven lines is inversion about the mean. In the first iteration, seven amplitudes are positive and one is negative, so the average sits below the positive ones. Reflecting each amplitude through that average takes the negative one from −0.35 to about +0.88 and halves each of the other seven, from 0.35 to about 0.18. The project's diffuser also flips every sign at once, so a statevector of its circuit shows −0.88 and −0.18; a sign shared by every amplitude changes no count.

Run the oracle and the diffuser as a pair and the chance of measuring 101 moves like this.

Grover iterationschance of reading 101
012.5%
178.1%
294.5%
333.0%

Two iterations, and so two calls to the oracle, take a one-in-eight guess to a 94.5% hit rate. A classical scan that checks the eight items one by one until it finds the target takes 4.5 checks on average.

Too many iterations undo the answer

After three iterations the target is back down to 33.0%. The project computes how many iterations to run from the size of the search space.

grovers_search.py Python · Playground versionOpen in Playground ↗
target = "101"
shots = 1000
num_qubits = len(target)
1num_iterations = int(math.pi / 4 * math.sqrt(2 ** num_qubits))
  1. 1For three qubits this works out at 2.221, and int takes it down to 2. The formula is π/4 times the square root of the search space, and that square-root growth is Grover's quadratic speedup.
▶ Run on QollabBackend

Each iteration turns the state by a fixed angle toward the marked answer and keeps turning past it: after the peak, the same interference spreads the probability out again.

Try this when you fork it. Replace num_iterations with 3 and run. The target falls from 94.5% to about a third, and a fourth iteration takes it to roughly 1%, worse than the 12.5% you started with.

Grover's Searchu/qollab · Python + QiskitImplements Grover's search algorithm on IonQ's trapped-ion simulator to find a marked item in an unsorted database. A 3-qubit example searches 8 items and finds the target with roughly 95% probability.

Quantum Advantage Lab: a quantum walk

Quantum Advantage Lab's third race compares a quantum walk with a classical random walk, both in the same repository. Interference in the quantum walk shapes the whole distribution of where the walker ends up.

The Lab streams a race step by step, with the quantum solver beside its classical counterpart. Press play.

A classical random walker starts at node 0 and picks a neighbour at each step. By default the race runs a thousand walkers.

backend/classical/random_walk.py Python · from the Quantum Advantage Lab repository
        # For each walker, pick next position based on transition probabilities
        new_positions = np.empty(n_trials, dtype=int)
        for trial_idx in range(n_trials):
            current = positions[trial_idx]
            new_positions[trial_idx] = rng.choice(
                n_nodes, p=transition[current]
1            )
        positions = new_positions
​
        # Build empirical distribution
        counts = np.bincount(positions, minlength=n_nodes)
2        distribution = (counts / n_trials).tolist()
  1. 1Each walker makes a fresh random draw on every step, so the race's defaults of a thousand walkers and ten steps come to ten thousand draws.
  2. 2Tally where the thousand walkers ended up. Around the ring the tally is a bell curve centred on the start; the Lab's chart puts the start at its left edge, so the two halves of the bell sit at the chart's two ends.

The quantum walk draws no random number at any step. The walk turns a coin qubit and shifts the walker according to the coin, both as ordinary gates, and nothing is sampled until the finished circuit is measured.

backend/quantum/quantum_walks.py Python · from the Quantum Advantage Lab repository
    # Initial state: walker at position 0, coin in superposition
    if graph_type == "cycle":
1        qc.h(coin_qubits[0])
    # ...
    for step in range(n_steps):
        # Coin
        if graph_type == "cycle":
2            _hadamard_coin(qc, coin_qubits[0])
        # ...
        # Shift
        if graph_type == "cycle":
3            _cycle_shift(qc, coin_qubits[0], position_qubits)
  1. 1The Hadamard leaves the coin with no fixed value, and nothing in the walk measures it.
  2. 2Each step turns the coin again with another Hadamard, and the walk keeps every route open.
  3. 3Move the walker according to the coin, both ways at once. The position register is a superposition over every node the walker could have reached, held open until the final measurement.

Ten steps in, the classical walker has taken one of 1,024 routes and the tally counts how often each endpoint came up. The quantum walk samples none of them: the amplitudes of routes that reach the same node are added, and routes that arrive out of step cancel before anything is counted.

The quantum walk's distribution is not a bell curve: cancellation leaves it lopsided and ridged. On a ring big enough that routes going round in opposite directions have not yet met, the distribution also widens in proportion to the number of steps, where the classical walk widens with the square root.

Quantum Advantage LabQuantum Advantage LabHossein Sadeghi Esfahani · u/hsadeghi · Python + QiskitReal-time interactive platform that races four foundational quantum algorithms against their classical counterparts, visualizing each solver's progress step by step.

Quantum Regime Radar: running a circuit backwards to compare two states

Quantum Regime Radar scores a market window, such as NVDA's 2022 returns, against five volatility regimes taken from past market episodes, each one encoded as a twelve-qubit state. Scoring means comparing two states, and neither state can be read.

The project builds one state, then runs the other's circuit in reverse and counts how many shots return to all-zeros.

regime_radar_cell.py Python · excerptOpen in Playground ↗
def _inversion(qc_live: QuantumCircuit, qc_ref: QuantumCircuit) -> QuantumCircuit:
    n = qc_live.num_qubits
    qc = QuantumCircuit(n, n)
1    qc.compose(qc_live, inplace=True)
2    qc.compose(qc_ref.inverse(), inplace=True)
    qc.measure(range(n), range(n))
    return qc
  1. 1Prepare the market window's twelve-qubit state.
  2. 2Then append the inverse of the reference regime's circuit: the same gates in reverse order, each one reversed, which undoes the preparation of the reference state exactly.
▶ Run on QollabBackend

Four thousand and ninety-six outcomes are possible on twelve qubits, and every one of them is reached by many routes through the two circuits. If the window's state and the reference are the same, the inverse cancels the preparation and every route recombines on all-zeros. If the two states differ, the cancellation is partial and shots land on other bitstrings.

So the fraction of shots reading all zeros estimates the squared overlap between the two states, measured without either state being inspected.

regime_radar_cell.py Python · excerptOpen in Playground ↗
    live = _build(DEMO_PARAMS[ci][REF_FAM[target]])
    ref = _build(REF_PARAMS[target])
    circuit = transpile(_inversion(live, ref), backend=backend, optimization_level=0)
1    result = backend.run(circuit, shots=shots).result()
    counts = result.get_counts()
    if isinstance(counts, list):                # defensive; single circuit expected
        counts = counts[0]
2    K_meas = _zero_frac(counts)
3    sigma = (K_meas * (1.0 - K_meas) / max(shots, 1)) ** 0.5
  1. 1On IonQ backends the Playground allows one job per run, so this cell spends it on one comparison.
  2. 2The kernel is the fraction of all-zero shots.
  3. 3Its error bar: the standard error of a fraction estimated from shots samples.
▶ Run on QollabBackend

The inversion test has the shape of the one-qubit listing, prepare then undo, with a second circuit doing the undoing.

Quantum Regime RadarAlireza Khodaei · u/alireza · Python + QiskitScores live equity returns against five volatility regimes taken from real market history, using quantum kernels on IonQ.

Musiq: a phase on every qubit at once

Musiq turns a circuit into sound. One of Musiq's generators maps the phase of each statevector amplitude onto the phase of an oscillator.

Musiq, a browser-based quantum sonification platform
Musiq's circuit editor, with a five-qubit template loaded and the IonQ simulator selected.

Musiq's waveform generator, which turns measured counts into sound, includes an IQP builder with the same shape as the Grover diffuser.

musiq/modules/quantum_waveform_generator.py Python · from the Musiq repository
        n = self.n_qubits
        # n diagonal Rz params + (n-1)+(n-2) CZ layer = n + 2*n-3 for two CZ "bands"
        num_rz = n
        params = ParameterVector("λ", num_rz)
        qc = QuantumCircuit(n)
1        qc.h(range(n))
        for qubit in range(n):
2            qc.rz(params[qubit], qubit)
        # Fixed CZ pattern (nearest-neighbor style, no random choice)
        for i in range(n):
            for j in range(i + 1, min(i + 3, n)):
3                qc.cz(i, j)
4        qc.h(range(n))
        qc.measure_all()
  1. 1Open every route at once. At the waveform generator's default of eight qubits that is 256 outcomes, all equally likely at this line.
  2. 2One phase per qubit, with the parameters named λ; none of these angles changes a probability.
  3. 3The cz gates add phases between pairs of qubits, on top of the per-qubit ones, and every outcome is still equally likely going into the next line.
  4. 4The closing Hadamard layer recombines every route: the phases written above decide where routes reinforce and where they cancel, and the equal probabilities become a distribution shaped by those angles.

IQP stands for instantaneous quantum polynomial time. Everything between the two Hadamard layers is diagonal, so every gate there only writes phases.

Musiq's waveform generator draws the λ angles at random each time it builds this circuit, so each build gives a different distribution and a different spectrum.

MusiqMusiqTomoya Hatanaka & Emmanuella Adams · u/doraking · Python + QiskitMusiq is a browser-based quantum sonification platform that transforms quantum-circuit outputs into generative audio.

Interference on noisy hardware

Interference needs the relative phase between two routes to survive from the gate that writes it to the gate that converts it, and on hardware, noise degrades phases as the circuit runs.

Deeper circuits give noise more time to degrade the phases. One iteration is an oracle and a diffuser, each with a multi-controlled sign flip that hardware does not have as a single operation. Transpiled for hardware, each flip becomes a run of two-qubit gates, and the three-qubit search is tens of operations deep by its second iteration.

The Grover's search project checks its own result at the end.

grovers_search.py Python · Playground versionOpen in Playground ↗
target_count = counts.get(target, 0)
success_rate = target_count / shots
print(f"\nTarget |{target}⟩ found: {target_count}/{shots} ({100*success_rate:.1f}%)")
1print(f"Classical random guess would give: {100/2**num_qubits:.1f}%")
# ...
​
2if success_rate > 0.8:
    print("✓ Grover's search successful!")
else:
    print("⚠ Lower than expected — noise may be affecting results")
  1. 1This prints 12.5%, what a uniform random guess scores; the circuit has to beat that for its interference to show in the counts.
  2. 2The threshold is picked by hand, well below the 94.5% the maths predicts, to allow for gate and readout error and the scatter of a thousand shots.
▶ Run on QollabBackend

None of these circuits is faster than a laptop. Eight items is a trivial search, and a classical computer checks all of them before an IonQ job has left the queue. Grover's advantage is quadratic and it needs a search space far larger than anything a current device can hold with its phases intact.

A hardware run shows what noise does to the result. An ideal simulator matches the predicted 94.5% up to shot noise, so the gap between that figure and the success rate on hardware is the combined effect of gate and readout errors.

Quantum Advantage Lab caches its hardware runs in its repository and replays them, so a race can show a hardware result without queuing the same job again.

Start with Grover

Every circuit on this page relies on signs or phases that a measurement cannot see, until a later gate recombines the routes. In Grover's search the oracle writes the sign, and the diffuser turns it into counts.

Fork Grover's search first: it runs in the Playground with no setup, and the oracle and the diffuser are under forty lines together.

Run it, then move the target.

Fork Grover's search, run it as shipped, and run it again with target set to another of the eight bitstrings. Then open any project above and find the line where its phases turn back into counts.

Stay in the loop.

Get the latest tutorials, demos, and project showcases straight to your inbox. No noise, just the good stuff.