Skip to main content

View on GitHub

Open this notebook in GitHub to run it yourself

What This Notebook Does

Quantum walks are often used as building blocks for graph exploration / graph-based quantum algorithms. This notebook simulates a discrete-time quantum walk on a complex network (graph).
  • The graph is a set of nodes connected by edges (we generate it with NetworkX).
  • The walker position is stored in a quantum register x.
  • A second register y acts like a coin / direction / neighbor-choice register.
  • Each step of the walk applies:
  1. Coin operator (mix amplitudes in a way that depends on the current node’s neighbors)
  2. Shift operator (moves the walker according to the coin register)
At the end we measure the position register and plot a probability distribution over nodes.
Note: This is a discrete-time walk (coin + shift), not a continuous-time walk.

Imports and Dependencies

Step 1

  • Create a “Complex Network” (the Graph)
Here we generate a small graph G. The notebook currently uses a Watts-Strogatz model, which is a classic “small-world” network model:
  • it has high clustering (like regular lattices),
  • and short path lengths (like random graphs).
You can switch to other models by uncommenting the alternatives:
  • Erdős-Rényi (random graph)
  • Barabási-Albert (scale-free graph)
Then we draw the graph so we can visually connect the output distribution to the network structure.
output

Step 2

  • Decide How Many Qubits Are Needed for the Position Register
If the graph has N nodes, we need enough qubits to encode node indices in binary.
  • N = len(G.nodes())
  • num_qubits = ceil(log2(N))
That means the quantum register x can represent 2**num_qubits = N.
Output:

Step 3

  • Build “Neighbor-Aware” Probability Vectors
A quantum walk on a graph needs a way to represent “where can I go next from node ii?”. We create helper functions:
  • get_edges_of_node(G, i): returns the neighbors of node i.
  • inner_degree(G, num_qubits, i): builds a length 2**num_qubits vector where:
    • entries corresponding to neighbors of i are 1,
    • all others are 0,
    • then we normalize by the node degree k to get a uniform distribution over neighbors.
This vector is used to prepare the y register so it represents “allowed moves” from the current node.

Step 4

  • Define the Quantum Walk (State Prep, Coin, Shift, and Repeated Steps)
This cell defines the core quantum logic using Classiq @qfunc.

Registers

  • x: position register (which node the walker is on)
  • y: coin / neighbor register (encodes the neighbor-choice space)

4.1 Initial State: prepare_initial_state(x, y)

Goal: start with a clean, interpretable state.
  1. Prepare x in a uniform superposition over valid nodes:
  • If N is exactly 2**num_qubits, a Hadamard transform gives uniform superposition automatically.
  • Otherwise, we prepare a custom probability vector that gives equal weight to nodes 0..N-1 and zero to invalid states.
  1. Prepare y conditioned on the current node in x: For each node i, if x == i, we prepare y using the neighbor distribution vector from inner_degree(...).
So after this, the state is conceptually:
  • “uniform over nodes” in x,
  • and for each node, y contains amplitudes only on its neighbors.

4.2 Coin Operator: my_coin(x, y)

A discrete-time quantum walk needs a “coin flip” to mix amplitudes. Here, the coin depends on the current node:
  • If x == i, apply a Grover diffuser on register y corresponding to neighbors of node i.
This mixes the neighbor amplitudes in a structured way.

4.3 Shift Operator: my_shift(x, y)

This updates the position based on the coin information.

4.4 Repeating Steps: discrete_quantum_walk(time, coin, shift, x, y)

We apply the pair (coin, shift) repeatedly time times using power(time, ...). That is exactly the discrete-time walk loop: (coin→shift)×t(\text{coin} \to \text{shift}) \times t

Step 5

  • Choose Number of Steps, Build main, and Synthesize the Circuit

Number of Steps

t controls how far the quantum walk evolves. More steps usually means:
  • wider spreading over the graph,
  • more interference patterns,
  • sometimes more “structure” in the final distribution (depending on the graph).

The main Quantum Program

main(x: Output[QNum[num_qubits]]):
  1. Allocates x (position) and y (coin).
  2. Prepares the initial state.
  3. Applies the discrete-time quantum walk for t steps.
  4. Drops y (we only care about measuring the position distribution in x).
Finally:
  • synthesize(main) compiles the high-level program into an executable quantum program.
  • show(qprog) displays the synthesized result.
Output:

Step 6

  • Execute and Collect Results
Here we run the synthesized program and fetch the results. The key output we care about is the measured distribution of the position register x:
  • each possible node index x has a probability,
  • these probabilities should sum to ~1 (up to sampling / execution effects).
Output:
Output:

Step 7

  • Visualize the Probability Distribution Over Nodes
We plot a bar chart:
  • x-axis: node index (the measured value of the position register x)
  • y-axis: probability of measuring that node
Tip for interpretation:
  • Compare “high-probability nodes” to the graph drawing.
  • Try changing the graph model or t and see how the distribution changes.
Output:
output

(Optional) Hardware-Aware Synthesis and Hardware Execution

In this notebook, we executed the circuit on the ibm_torino processor. The Classiq platform allows specifying a particular processor through ExecutionPreferences. Before executing on quantum hardware, you can perform synthesis that incorporates hardware-specific constraints by configuring the preference settings. The following command runs hardware-aware synthesis to optimize your circuit for a target device. For more details, refer to the Hardware-Aware Synthesis.
Once the synthesis is complete, you can configure the execution settings to run your circuit on a real quantum device or a specific simulator. The ExecutionPreferences class allows you to define parameters such as the number of shots and backend-specific credentials. The following code demonstrates how to set up an execution session for an IBM Quantum backend:

Result

N=4N=4

Once the graph structure is defined, you can perform a quantum spatial search to find a specific node. In this example, the search is conducted on a Watts-Strogatz small-world graph, which is generated using the NetworkX library to create a complex network topology. Below data is quantum spatial search on G = nx.connected_watts_strogatz_graph(n=4, k=2, p=0.2, tries=100, seed=312) .

N=8N=8

Below data is quantum spatial search on G = nx.connected_watts_strogatz_graph(n=8, k=4, p=0.2, tries=100, seed=312) .

Vizualization

output