Computing Expectation Values¶
CUDA-Q provides generic library functions enabling one to compute expectation values of quantum spin operators with respect to a parameterized CUDA-Q kernel. Let’s take a look at an example of this:
# The example here shows a simple use case for the `cudaq::observe``
# function in computing expected values of provided spin operators.
import cudaq
from cudaq import spin
@cudaq.kernel
def kernel(theta: float):
qvector = cudaq.qvector(2)
x(qvector[0])
ry(theta, qvector[1])
x.ctrl(qvector[1], qvector[0])
spin_operator = 5.907 - 2.1433 * spin.x(0) * spin.x(1) - 2.1433 * spin.y(
0) * spin.y(1) + .21829 * spin.z(0) - 6.125 * spin.z(1)
# Pre-computed angle that minimizes the energy expectation of the `spin_operator`.
angle = 0.59
energy = cudaq.observe(kernel, spin_operator, angle).expectation()
print(f"Energy is {energy}")
Here we define a parameterized CUDA-Q kernel that takes an angle, theta
, as a single
input. This angle becomes the argument of a single ry
rotation.
We define a Hamiltonian operator via the CUDA-Q cudaq.SpinOperator
type.
CUDA-Q provides a generic function cudaq.observe
. This function takes as input three
arguments. The first two argument are a parameterized kernel and the cudaq.SpinOperator
whose
expectation value we wish to compute. The final arguments are the runtime parameters at which we
evaluate the parameterized kernel.
// Compile and run with:
// ```
// nvq++ expectation_values.cpp -o d2.x && ./d2.x
// ```
#include <cudaq.h>
#include <cudaq/algorithm.h>
// The example here shows a simple use case for the `cudaq::observe`
// function in computing expected values of provided spin_ops.
struct ansatz {
auto operator()(double theta) __qpu__ {
cudaq::qvector q(2);
x(q[0]);
ry(theta, q[1]);
x<cudaq::ctrl>(q[1], q[0]);
}
};
int main() {
// Build up your spin op algebraically
using namespace cudaq::spin;
cudaq::spin_op h = 5.907 - 2.1433 * x(0) * x(1) - 2.1433 * y(0) * y(1) +
.21829 * z(0) - 6.125 * z(1);
// Observe takes the kernel, the spin_op, and the concrete
// parameters for the kernel
double energy = cudaq::observe(ansatz{}, h, .59);
printf("Energy is %lf\n", energy);
return 0;
}
Here we define a parameterized CUDA-Q kernel, a callable type named ansatz
that takes as
input a single angle theta
. This angle becomes the argument of a single ry
rotation.
In host code, we define a Hamiltonian operator via the CUDA-Q spin_op
type.
CUDA-Q provides a generic function cudaq::observe
. This function takes as input three terms.
The first two terms are a parameterized kernel and the spin_op
whose expectation value we wish to compute.
The last term contains the runtime parameters at which we evaluate the parameterized kernel.
The return type of this function is an cudaq::observe_result
which contains all the data
from the execution, but is trivially convertible to a double, resulting in the expectation value we are interested in.
To compile and execute this code, we run the following:
nvq++ expectation_values.cpp -o exp_vals.x
./exp_vals.x