Gradient estimators
One of the most important element of performing optimization algorithms is computing the gradient of a physical observable's gradient with respect to a set of circuit parameters:
In this tutorial, we introduce the gradient estimators provided by QURI Parts. They are:
- Numerical gradient estimator: A gradient estimator that estimates the gradient based on finite difference method.
- Parameter shift gradient estimator: A gradient estimator that estimates the gradient based on the parameter shift method.
Prerequisite
QURI Parts modules used in this tutorial: quri-parts-circuit
, quri-parts-core
, and quri-parts-qulacs
. You can install them as follows:
!pip install "quri-parts[qulacs]"
Requirement already satisfied: quri-parts[qulacs] in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (0.20.3)
Requirement already satisfied: quri-parts-algo in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts[qulacs]) (0.20.3)
Requirement already satisfied: quri-parts-chem in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts[qulacs]) (0.20.3)
Requirement already satisfied: quri-parts-circuit in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts[qulacs]) (0.20.3)
Requirement already satisfied: quri-parts-core in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts[qulacs]) (0.20.3)
Requirement already satisfied: quri-parts-qulacs in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts[qulacs]) (0.20.3)
Requirement already satisfied: scipy<2.0.0,>=1.9.1 in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-algo->quri-parts[qulacs]) (1.11.4)
Requirement already satisfied: typing-extensions<5.0.0,>=4.1.1 in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-algo->quri-parts[qulacs]) (4.12.2)
Requirement already satisfied: numpy>=1.22.0 in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-circuit->quri-parts[qulacs]) (1.26.4)
Requirement already satisfied: quri-parts-rust in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-circuit->quri-parts[qulacs]) (0.20.2)
Requirement already satisfied: networkx in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-core->quri-parts[qulacs]) (3.4.2)
Requirement already satisfied: Qulacs<0.7.0,>=0.3.0 in /home/drokles/.cache/pypoetry/virtualenvs/quri-sdk-notebooks-l1kMe6Lz-py3.11/lib/python3.11/site-packages (from quri-parts-qulacs->quri-parts[qulacs]) (0.6.10)
``````output
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m A new release of pip is available: [0m[31;49m24.0[0m[39;49m -> [0m[32;49m24.3.1[0m
[1m[[0m[34;49mnotice[0m[1;39;49m][0m[39;49m To update, run: [0m[32;49mpip install --upgrade pip[0m
Interface
A gradient estimator is represented by the GradientEstimator
interface. It represents a function that estimates gradient values of an expectation value of a given Operator
for a given parametric state with given parameter values (the third argument). It's function signature is
from typing import Callable, Sequence, Union
from typing_extensions import TypeAlias, TypeVar
from quri_parts.core.estimator import Estimatable, Estimates
from quri_parts.core.state import ParametricCircuitQuantumState, ParametricQuantumStateVector
# Generic type of parametric states
_ParametricStateT = TypeVar(
"_ParametricStateT",
bound=Union[ParametricCircuitQuantumState, ParametricQuantumStateVector],
)
# Function signature of a `GradientEstimator` defined in QURI Parts.
GradientEstimator: TypeAlias = Callable[
[Estimatable, _ParametricStateT, Sequence[float]],
Estimates[complex],
]
You may create a GradientEstimator
from a generating function. They are often named as create_..._gradient_estimator
. To create a GradientEstimator
, you need to pass in a ConcurrentParametricQuantumEstimator
to the generating function. Here, we use the one provided by quri_parts.qulacs
from quri_parts.qulacs.estimator import create_qulacs_vector_concurrent_parametric_estimator
concurrent_parametric_estimator = create_qulacs_vector_concurrent_parametric_estimator()
Preparation
Let's prepare the operator and the parametric state we use through out this tutorial.
from quri_parts.core.operator import Operator, pauli_label
operator = Operator({
pauli_label("X0 Y1"): 0.5,
pauli_label("Z0 X1"): 0.2,
})
The linear mapping of the parametric circuit is slightly different from previous sections. Here, the circuit parameter and gate parameters are related via:
for aesthetical reason when we discuss the details of the parameter shift rule later.
import numpy as np
from quri_parts.circuit import LinearMappedUnboundParametricQuantumCircuit, CONST
from quri_parts.core.state import quantum_state
n_qubits = 2
linear_param_circuit = LinearMappedUnboundParametricQuantumCircuit(n_qubits)
theta, phi = linear_param_circuit.add_parameters("theta", "phi")
linear_param_circuit.add_H_gate(0)
linear_param_circuit.add_CNOT_gate(0, 1)
linear_param_circuit.add_ParametricRX_gate(0, {theta: np.pi/2, phi: np.pi/3, CONST: np.pi/2})
linear_param_circuit.add_ParametricRY_gate(0, {theta: -np.pi/2, phi: np.pi/3})
linear_param_circuit.add_ParametricRZ_gate(1, {theta: np.pi/3, phi: -np.pi/2, CONST: -np.pi/2})
param_state = quantum_state(n_qubits, circuit=linear_param_circuit)
Numerical gradient estimator
The numerical gradient estimator computes the gradient according to the finite difference method, i.e.