Hello,
I am trying to run a VQA on IBM’s quantum computers through the Qiskit plugin, but I’m not sure how to do so. I have an algorithm that, on every iteration step, runs a bunch of different (related) circuits and accumulates the values for a single calculation of the cost function. I saw that Pennylane supports a few primitives like circuit_runner that would let you run the entire optimization with a single job to the quantum computer, but I’m not sure how to prevent my code from spawning over 30 jobs per iteration.
Here is my code run on a toy problem:
import pennylane as qml
from pennylane import numpy as np
import matplotlib.pyplot as plt
# Number of system qubits; this determines the size of the matrix A and vector b
n_qubits = 3
print(type(n_qubits))
# Number of quantum measurements performed to get a probability distribution of results
n_shots = 10**6
# Total number of qubits; here we add an ancillary qubit
tot_qubits = n_qubits + 1
# Index of ancillary qubit (Python lists are 0-indexed)
ancilla_idx = n_qubits
# Number of optimization steps
steps = 30
# Learning rate of optimization algorithm
eta = 0.8
# Initial spread of random quantum weights
q_delta = 0.001
# Seed for RNG
rng_seed = 0
# Coefficients of the linear combination A = c_0 A_0 + c_1 A_1 ...
c = np.array([1.0, 0.2, 0.2])
print(type(c))
print(len(c))
def U_b():
"""Unitary matrix rotating the ground state to the problem vector |b> = U_b |0>."""
# This loop applies the Hadamard operator on each wire
for idx in range(n_qubits):
qml.Hadamard(wires=idx)
# This function gives the components of A
def CA(idx):
"""Controlled versions of the unitary components A_l of the problem matrix A."""
if idx == 0:
# Identity operation
None
elif idx == 1:
# CNOT gate is the same as controlled Pauli-X gate
qml.CNOT(wires=[ancilla_idx, 0])
qml.CZ(wires=[ancilla_idx, 1])
elif idx == 2:
qml.CNOT(wires=[ancilla_idx, 0])
def variational_block(weights):
"""Variational circuit mapping the ground state |0> to the ansatz state |x>."""
# We first prepare an equal superposition of all the states of the computational basis.
for idx in range(n_qubits):
qml.Hadamard(wires=idx)
# A very minimal variational circuit.
for idx, element in enumerate(weights):
qml.RY(element, wires=idx)
# TODO: this is what we vary to access different devices (like IBM, Rigetti etc.)
# Loads a particular quantum device
# 'default.qubit' is a simple state simulator
# 'wires' is a aparamter specifying the number of wires (subsytems) to initialise the device with
dev_mu = qml.device("default.qubit", wires=tot_qubits)
# Quantum node contains a quantum function (in this case, local_hadamard_test) and the computational
# device it's executed on (in this case, dev_mu)
@qml.qnode(dev_mu, interface="autograd")
# For this function, l, lp, j are the indices for the mu coefficients
def local_hadamard_test(weights, l=None, lp=None, j=None, part=None):
# First Hadamard gate applied to the ancillary qubit.
qml.Hadamard(wires=ancilla_idx)
# For estimating the imaginary part of the coefficient "mu", we must add a "-i"
# phase gate.
if part == "Im" or part == "im":
qml.PhaseShift(-np.pi / 2, wires=ancilla_idx)
# Variational circuit generating a guess for the solution vector |x>
variational_block(weights)
# Controlled application of the unitary component A_l of the problem matrix A.
CA(l)
# Adjoint of the unitary U_b associated to the problem vector |b>.
# In this specific example Adjoint(U_b) = U_b.
U_b()
# Controlled Z operator at position j. If j = -1, apply the identity.
if j != -1:
qml.CZ(wires=[ancilla_idx, j])
# Unitary U_b associated to the problem vector |b>.
U_b()
# Controlled application of Adjoint(A_lp).
# In this specific example Adjoint(A_lp) = A_lp.
CA(lp)
# Second Hadamard gate applied to the ancillary qubit.
qml.Hadamard(wires=ancilla_idx)
# Expectation value of Z for the ancillary qubit.
return qml.expval(qml.PauliZ(wires=ancilla_idx))
# Computes the mu coefficients
def mu(weights, l=None, lp=None, j=None):
"""Generates the coefficients to compute the "local" cost function C_L."""
mu_real = local_hadamard_test(weights, l=l, lp=lp, j=j, part="Re")
mu_imag = local_hadamard_test(weights, l=l, lp=lp, j=j, part="Im")
return mu_real + 1.0j * mu_imag
def psi_norm(weights):
"""Returns the normalization constant <psi|psi>, where |psi> = A |x>."""
norm = 0.0
for l in range(0, len(c)):
for lp in range(0, len(c)):
norm = norm + c[l] * np.conj(c[lp]) * mu(weights, l, lp, -1)
return abs(norm)
def cost_loc(weights):
"""Local version of the cost function. Tends to zero when A|x> is proportional to |b>."""
mu_sum = 0.0
for l in range(0, len(c)):
for lp in range(0, len(c)):
for j in range(0, n_qubits):
mu_sum = mu_sum + c[l] * np.conj(c[lp]) * mu(weights, l, lp, j)
mu_sum = abs(mu_sum)
# Cost function C_L
return 0.5 - 0.5 * mu_sum / (n_qubits * psi_norm(weights))
np.random.seed(rng_seed)
w = q_delta * np.random.randn(n_qubits, requires_grad=True)
opt = qml.GradientDescentOptimizer(eta)
cost_history = []
for it in range(steps):
w, cost = opt.step_and_cost(cost_loc, w)
print("Step {:3d} Cost_L = {:9.7f}".format(it, cost))
cost_history.append(cost)
If you want help with diagnosing an error, please put the full error message below:
qml.about()
:
Name: PennyLane
Version: 0.30.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author:
Author-email:
License: Apache License 2.0
Location: /Users/bigsad/Downloads/Algorithm-Research/Student-Hub/Indy-Ng/.venv/lib/python3.11/site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml
Required-by: PennyLane-Lightning
Platform info: macOS-12.6-x86_64-i386-64bit
Python version: 3.11.6
Numpy version: 1.23.5
Scipy version: 1.10.1
Installed devices:
- default.gaussian (PennyLane-0.30.0)
- default.mixed (PennyLane-0.30.0)
- default.qubit (PennyLane-0.30.0)
- default.qubit.autograd (PennyLane-0.30.0)
- default.qubit.jax (PennyLane-0.30.0)
- default.qubit.tf (PennyLane-0.30.0)
- default.qubit.torch (PennyLane-0.30.0)
- default.qutrit (PennyLane-0.30.0)
- null.qubit (PennyLane-0.30.0)
- lightning.qubit (PennyLane-Lightning-0.30.0)