Path: blob/main/quick-start-to-quantum/solutions/03_quick_start_to_quantum_solution.ipynb
1128 views
Quick start to Quantum Computing with CUDA-Q
Lab 3 - Add a Bit of Variation: Write your first variational program
The third and fourth labs in this series culminate with building your first variational hybrid program. In the first notebook (lab 3), we cover sections 1 and 2. The second notebook covers the remaining sections.
Section 1: Comparing Classical Random Walks and Discrete Time Quantum Walk (DTQW)
Section 2: Programming a variational DTQW with CUDA-Q
Section 3: Defining Hamiltonians and Computing Expectation Values
Section 4: Identify Parameters to Generate a Targeted Mean Value
We begin with the same framework for developing a quantum program as used in Lab 1 and Lab 2, only in this lab we use parameterized gates. Then, in Lab 4, we adapt this framework into a hybrid quantum-classical workflow to identify parameters that optimize a cost function. The adapted framework is outlined below:
Initialize parameters
Encode information into the quantum state by initializing qubit(s)
Manipulate the quantum state of the qubit(s) with quantum gate(s) using the parameters
Extract information from the quantum state by measuring the state of the qubit(s) and computing the expectation value of the cost function
Run a classical optimizer to either determine a new state of parameters and repeat from step 2, or converge to an optimal solution.
These steps, of what is known as a variational quantum algorithm, are outlined in the diagram below.

What you'll do:
Define and visualize discrete time quantum walks for generating probability distributions
Add variational gates for the coin operators to create your first variational program
Construct a Hamiltonian that can be used to compute the average of the probability distribution generated by a quantum walk
Use a classical optimizer to identify optimal parameters in the variational quantum walk that will generate a distribution with a targeted average value
Terminology you'll use:
Computational basis states (basis states for short)
Probability amplitude
Statevector
Control and target for multi-qubit controlled-operations
Hamiltonian
Pauli-Z operator
CUDA-Q syntax you'll use:
quantum kernel function decoration:
@cudaq.kernelqubit initialization:
cudaq.qvectorandcudaq.qubitquantum gates:
x,h,t, _.ctrl,cudaq.register_operation,u3spin operators:
spin.z,spin.iextract information from a kernel:
sample,get_state, _.amplitudevisualization tools:
add_to_bloch_sphere,show,draw
🎥 You can watch a recording of the presentation of a version of this notebook from a GTC DC tutorial in October 2025.
Let's begin by installing the necessary packages.
Section 1 Comparing Classical Random Walks and Discrete Time Quantum Walk (DTQW)
Quantum walks are a generalization of classical random walks. Unlike classical random walks, where probabilities dictate movement, quantum walks rely on amplitudes. Interference between paths leads to a faster spread over the position space, making quantum walks useful for tasks like quantum search algorithms (Li and Sun and Wong) and for generating probability distributions as we'll explore here.
We begin this section with the definitions of classical random walks and discrete time quantum walks (DTQW). In Section 1.2, we use CUDA-Q to encode an example of a DTQW into a CUDA-Q kernel.
Section 1.1 Classical Random Walks
Let's consider a discrete walk taking place on a line. In this scenario, we envision a walker progressing along the x-axis in discrete increments, with the movement governed by predefined rules based on coin flips. A classical random walk can be viewed as a decision tree as in the diagram below. In this scenario, a walker begins in the center of the line. After a coin flip, the walker moves to the left or right depending on the outcome of the coin flip (e.g., flipping a heads will send the walker one step to the left and flipping a tails will send the walk one step to the right). After num_time_steps coin flips, we record the position of the walker. We repeat this experiment multiple times and generate a histogram of the ending position of the walker in each experiment.

Let's see this in action with the random walk widget below. The green dot represents the walker whose movements are dictated by flips of a coin whose fairness is controlled by the probability slider. The ending position from each run of the experiment is recorded in the histogram. Experiment by changing the number of total steps and the probabilities. What patterns do you notice?
Note: If the widget does not appear below, you can access it directly using this link.
Section 1.2 Discrete Time Quantum Walks
A discrete-time quantum walk (DTQW) is the quantum analogue of a classical random walk. In this scenario, both the position of the walker and the coin are represented as quantum states, and , respectively. Throughout this walk, the state of the walker changes according to a quantum shift operators () which depend on the state of the coin . In particular, the operation checks if in the state (i.e., heads) and if so, induces a shift left operation on the quantum walker. Similarly, is defined for tails and shifting right. At each time step, the state of the coin changes (i.e., is "flipped") via a quantum operation (), which we'll call the coin-flip operator. Unlike the classical random walk, we will not know the position of the walker until the end of the process, when the quantum state of the walker is measured, and we'll never know the state of the coin!
In the diagram below we illustrate a 2-step quantum walk where the coin-flip operator is the Hadamard gate. Notice how the final distribution of the walker's possible positions differs from the classical case. In particular, the state of the walker after 2 time steps is in superposition. Moreover, upon measurement of the final state, the walker never ends up in the location , as might occur with two tails in the classical case depicted above.

The Line that the Walker Traverses
For our example, let's consider a line that contains positions, labeled . We can use qubits and the computational basis states, (), to represent positions on the line. In other words, the computational basis state represents the location on the line.
The Walker's Position State
The walker's position after time steps is given by a linear combination of the computational basis states for some satisfying . For instance, if the walker began the experiment at position , then the state of the walker at time would be . More interestingly, the walker might begin the experiment in a superposition of two or more positions. For example, the initial state of the walker could be the positions and . In this case the walker's initial state is as depicted in the image below.

You can explore more steps in a quantum walk with the visualization tool below.
Section 2 Programming a variational DTQW with CUDA-Q
Let's start coding up the variational DTQW in CUDA-Q. This is depicted in the diagram below.

We'll explain each portion of this diagram as we work through this section. First, let's start with the purple optional quantum walker initialization in the upper left hand corner of the diagram.
Exercise 1:
Edit the code block below to create a kernel that generates the initial state using an x gate and CNOT gates x.ctrl(control_qubit, target_qubit).
Let's verify that our solution is correct by using the cudaq.get_state and _.amplitudes commands.
Walking the Line
The next step (no pun intended) is to code incrementer and decrementer operations, drawn as light green and yellow blocks and denoted by and in the diagram. These will change the state of the walker with shifts to the left and right on the number line. We'll use these operations to build up the shift operators and which depend on the state of the coin, depicted in the diagram with the control operators.
First let's define so that when applied to a basis state , the result is for . The kernel for INC is defined below.
Exercise 2:
Using the fact that DEC is the inverse of INC, create the DEC kernel by completing the code block below.
The State of the Coin
Not only is the position of the walker at any given time step a linear combination of the computational basis states, but also the coin is a linear combinations of heads:
and tails:
and depends on : for with In case it helps to think of this qubit as "heads up" and "heads down" and distinguish it from the position state, we introduced the alternative (and optional) notation and for the zero-state (heads up) and the one-state (heads down), respectively.
Let's look at a couple of examples. We might begin the experiment with a coin in the zero (heads) state: . Another option would be to start the experiment with the coin in a state of superposition of both heads and tails: .
Changing the State of the Coin
The flipping of the coin is carried out by a quantum operation, . If the coinflip operation is the bitflip operation, , and the initial state of the coin is , then, flipping the coin would just change the state from to — much like the classical random walk.
A common and more interesting quantum coinflip operation is the Hadamard operator, , as illustrated in the diagrams of the DTQW that appeared earlier in this notebook. Applying this operator iteratively to the coin in the initial state , will result in alternating coin states and . The initializing the state of the coin is depicted in the diagram as a purple block on the lower left corner.
We're not limited to constant coin operators, and could consider a coin operator that depends on parameters such as the Grover operator used for searching a graph for marked vertices (Li and Sun and Wong). Moreover, the coin operator might depend on parameters that change from one step to the next and can be learnable (Chang et al., 2023 Chang et al., 2025), as we'll see in the next example.
So far we have considered single-qubit operations that rotate the Bloch sphere by a fixed amount. For instance the x-gate corresponds to a rotation of the Bloch sphere about the -axis by 180 degrees, and the t-gate rotates a statevector 45 degrees about the -axis. What about all the other rotation angles and all the other axis of rotation? The u3-gate is a universal rotation gate that allows us to define arbitrary rotation gates. The unitary matrix for this gate is:
where , , and are variables which we will assign values to before executing the kernel. We've drawn this as a dark green block in the diagram.
Experiment with different gates and different values of , , and in the code block below to see the effect of a coin flip defined by the u3-gate on a coin which is initiated in the heads up, zero-state.
Changing the State of the Walker Based on Coin Flips:
Exercise 3:
Now we're ready to put all of these kernels together to program one step of the DTQW. Let's set the initial state of the walker to be . The steps and , which depend on the state of the coin, can be modeled with controlled-gates and the INC and DEC operations, respectively. We've defined the step below, which uses a controlled-gate to apply INC to the walker state, if the coin is in the one-state . How would you adapt the code to call up the operator, when the coin qubit is in the state?
The code block below helps us to visualize the results of the sampling:
Go ahead and experiment with the single DTQW code above by changing the parameter values and initial position to get a sense of how the and operators work.
Exercise 4:
Your next task is to edit the code below to perform num_time_steps iterations of the quantum walk, sample the outcomes, and plot a histogram of the final position state. Keep in mind that you cannot embed DTQW_one_step within a loop, as the DTQW algorithm prescribes taking a single measurement only after completing all steps, rather than after each individual step.
Change the initial walker's position and parameter values for the coin flip operator to see the variety of distributions that can be generated with a quantum random walk.
Our next goal will be to use the quantum random walk to load a probability distribution into a quantum state. This will require us to be able to match a given probability distribution with parameter values that will generate that distribution. To do this, we'll use a classical optimizer. That's the challenge of the next notebook.