Skip to content

The Swap Test Algorithm

View on GitHub Experiment in the IDE

The swap test is a quantum function that checks the overlap between two quantum states: the inputs of the function are two quantum registers of the same size, \(|\psi_1\rangle, \,|\psi_2\rangle\), and it returns as an output a single "test" qubit whose state encodes the overlap between the two inputs: \(|q\rangle_{\rm test} = \alpha|0\rangle + \sqrt{1-\alpha^2}|1\rangle\), with

\[\alpha^2 = \frac{1}{2}\left(1+|\langle \psi_1 |\psi_2 \rangle |^2\right).\]

Thus, the probability of measuring the test qubit at state \(|0\rangle\) is \(1\) if the states are identical (up to a global phase) and 0.5 if the states are orthogonal to each other.

The quantum model starts with an H gate on the test qubit, followed by swapping between the two states controlled on the test qubit (a controlled-SWAP gate for each of the qubits in the two states), and a final H gate on the test qubit:

Closed (left panel) and opened (right panel) visualization of the swap test algorithm

Prepare two random states:

import numpy as np

np.random.seed(12)

NUM_QUBITS = 3
amps1 = 1 - 2 * np.random.rand(
    2**NUM_QUBITS
)  # vector of 2^3 numbers in the range [-1,1]
amps2 = 1 - 2 * np.random.rand(2**NUM_QUBITS)
amps1 = amps1 / np.linalg.norm(amps1)  # normalize the vector
amps2 = amps2 / np.linalg.norm(amps2)

Create a model and synthesize:

from classiq import (
    Output,
    QArray,
    QBit,
    create_model,
    execute,
    prepare_amplitudes,
    qfunc,
    set_execution_preferences,
    swap_test,
    synthesize,
)
from classiq.execution import ExecutionPreferences


@qfunc
def main(test: Output[QBit]):

    state1 = QArray("state1")
    state2 = QArray("state2")
    prepare_amplitudes(amps1.tolist(), 0.0, state1)
    prepare_amplitudes(amps2.tolist(), 0.0, state2)
    swap_test(state1, state2, test)


qmod = create_model(main)
qmod = set_execution_preferences(
    qmod, execution_preferences=ExecutionPreferences(num_shots=100_000)
)
qprog = synthesize(qmod)

swap test - qmod implementations

The swap test is defined as a library function in the qmod language (definition can be found on our public github ). Users can easily add their own functions

from classiq import show

show(qprog)
Opening: https://platform.classiq.io/circuit/56682c53-15bf-4d1f-81e2-1121ce978b16?version=0.41.0.dev39%2B79c8fd0855
from classiq import write_qmod

write_qmod(qmod, "swap_test", decimal_precision=15)

Verify the results:

res = execute(qprog).result()

Comparing the measured overlap with the exact overlap

Using the expected probability of measuring the state \(|0\rangle\) as defined above:

\[\alpha^2 = \frac{1}{2}\left(1+|\langle \psi_1 |\psi_2 \rangle |^2\right).\]

we extract the overlap \(|\langle \psi_1 |\psi_2 \rangle |^2=\sqrt{2 P\left(q_{\text{test}}=|0\rangle\right)-1}\)
The exact overlap is computed with the dot product of the two state-vectors. Note that for the sake of this demonstration we execute this circuit \(100,000\) times to improve the precision of the probability estimate. This is usually not required in actual programs.

overlap_from_swap_test = np.sqrt(
    2 * res[0].value.counts["0"] / sum(res[0].value.counts.values()) - 1
)
exact_overlap = np.abs(amps1 @ amps2)
print("States overlap from Swap-Test result:", overlap_from_swap_test)
print("States overlap from classical calculation:", exact_overlap)
States overlap from Swap-Test result: 0.4673970474874655
States overlap from classical calculation: 0.46972037234759095
RTOL = 0.05
assert np.isclose(
    overlap_from_swap_test, exact_overlap, RTOL
), f"""
The quantum result is too far than classical one, by a relative tolerance of {RTOL}. Please verify your parameters"""