Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Gradients with the primitives #8528

Merged
merged 55 commits into from
Sep 5, 2022
Merged
Show file tree
Hide file tree
Changes from 28 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
72d7c25
added the gradients with the primitives
a-matsuo Aug 12, 2022
f97b218
Merge branch 'main' into gradients-primitives
Cryoris Aug 12, 2022
ad81449
add run_options and supported gate
a-matsuo Aug 16, 2022
c1423bb
Merge branch 'gradients-primitives' of github.com:a-matsuo/qiskit-ter…
a-matsuo Aug 16, 2022
7ee8f28
added unittests
a-matsuo Aug 22, 2022
9454075
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Aug 22, 2022
b7ad4aa
lint
a-matsuo Aug 22, 2022
f918a2a
Merge branch 'main' into gradients-primitives
a-matsuo Aug 23, 2022
9ebe3ef
fix based on the comments
a-matsuo Aug 24, 2022
aeb76ff
fix
a-matsuo Aug 24, 2022
f19222d
add spsa gradient
a-matsuo Aug 24, 2022
8c63899
simplify + async
a-matsuo Aug 26, 2022
3154838
added gradient variance
a-matsuo Aug 26, 2022
03a6d80
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Aug 26, 2022
44cc926
lint
a-matsuo Aug 26, 2022
89353ea
added the run_options field
a-matsuo Aug 26, 2022
9abbd2a
fix lint
a-matsuo Aug 26, 2022
3cd1dbe
fix based on comments
a-matsuo Aug 30, 2022
9f04e76
wip fix2
a-matsuo Aug 30, 2022
a7d183f
fix
a-matsuo Aug 31, 2022
cf5caa1
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Aug 31, 2022
0a3f700
lint
a-matsuo Aug 31, 2022
d815073
Merge branch 'main' into gradients-primitives
a-matsuo Aug 31, 2022
d7f80db
fix epsilon and doc
a-matsuo Aug 31, 2022
79fb87c
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Aug 31, 2022
0433f9a
lint
a-matsuo Aug 31, 2022
f12070e
fix
a-matsuo Aug 31, 2022
b316f3d
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Aug 31, 2022
c961b5d
Update qiskit/algorithms/gradients/base_sampler_gradient.py
a-matsuo Sep 1, 2022
08b8a72
Update qiskit/algorithms/gradients/base_sampler_gradient.py
a-matsuo Sep 1, 2022
fa51f86
Update qiskit/algorithms/gradients/base_estimator_gradient.py
a-matsuo Sep 1, 2022
f400e72
Update qiskit/algorithms/gradients/base_sampler_gradient.py
a-matsuo Sep 1, 2022
dfc3bb0
Update qiskit/algorithms/gradients/base_estimator_gradient.py
a-matsuo Sep 1, 2022
9f748a0
Update qiskit/algorithms/gradients/base_estimator_gradient.py
a-matsuo Sep 1, 2022
84f0ee5
change epsilon error
a-matsuo Sep 1, 2022
618c90b
Update qiskit/algorithms/gradients/estimator_gradient_result.py
a-matsuo Sep 1, 2022
e8b6f4f
Update qiskit/algorithms/gradients/sampler_gradient_result.py
a-matsuo Sep 1, 2022
f73b009
add gradient test
t-imamichi Sep 1, 2022
a30e7b3
added batch size in spsa gradients
a-matsuo Sep 1, 2022
b9a6586
fix
a-matsuo Sep 1, 2022
19cf340
Merge branch 'gradients-primitives' of github.com:a-matsuo/qiskit-ter…
a-matsuo Sep 1, 2022
be76427
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Sep 1, 2022
c849f39
Merge branch 'main' into gradients-primitives
a-matsuo Sep 2, 2022
d26fa9b
Merge branch 'gradients-primitives' into grad-test
a-matsuo Sep 2, 2022
22cf235
Merge pull request #12 from t-imamichi/grad-test
a-matsuo Sep 2, 2022
b8b98fa
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Sep 2, 2022
9242360
lint
a-matsuo Sep 2, 2022
5b40c6f
Merge branch 'main' into gradients-primitives
a-matsuo Sep 2, 2022
f8a45b0
Update qiskit/algorithms/gradients/lin_comb_estimator_gradient.py
a-matsuo Sep 2, 2022
c17b53d
add operator tests
a-matsuo Sep 2, 2022
044089b
Merge branch 'gradients-primitives' of github.com:a-matsuo/qiskit-ter…
a-matsuo Sep 2, 2022
5957422
consistent name
a-matsuo Sep 2, 2022
dd960a0
rewrite spsa
a-matsuo Sep 2, 2022
9855aae
Merge remote-tracking branch 'upstream/main' into gradients-primitives
a-matsuo Sep 5, 2022
c16672f
use algorithm job
a-matsuo Sep 5, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions qiskit/algorithms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@
ShorResult


Gradients
----------

Algorithms to calculate the gradient of a quantum circuit.

.. autosummary::
:toctree: ../stubs/

gradients


Linear Solvers
--------------

Expand Down
87 changes: 87 additions & 0 deletions qiskit/algorithms/gradients/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2022.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
==============================================
Gradients (:mod:`qiskit.algorithms.gradients`)
==============================================

.. currentmodule:: qiskit.algorithms.gradients

Base Classes
============

.. autosummary::
:toctree: ../stubs/

BaseSamplerGradient
BaseEstimatorGradient

Estimator Gradients
===================

.. autosummary::
:toctree: ../stubs/

FiniteDiffEstimatorGradient
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
LinCombEstimatorGradient
ParamShiftEstimatorGradient
SPSAEstimatorGradient

Sampler Gradients
=================

.. autosummary::
:toctree: ../stubs/

FiniteDiffSamplerGradient
LinCombSamplerGradient
ParamShiftSamplerGradient
SPSASamplerGradient

Results
=======

.. autosummary::
:toctree: ../stubs/

EstimatorGradientResult
SamplerGradientResult
"""

from .base_estimator_gradient import BaseEstimatorGradient
from .base_sampler_gradient import BaseSamplerGradient
from .estimator_gradient_result import EstimatorGradientResult
from .finite_diff_estimator_gradient import FiniteDiffEstimatorGradient
from .finite_diff_sampler_gradient import FiniteDiffSamplerGradient
from .lin_comb_estimator_gradient import LinCombEstimatorGradient
from .lin_comb_sampler_gradient import LinCombSamplerGradient
from .param_shift_estimator_gradient import ParamShiftEstimatorGradient
from .param_shift_sampler_gradient import ParamShiftSamplerGradient
from .sampler_gradient_result import SamplerGradientResult
from .spsa_estimator_gradient import SPSAEstimatorGradient
from .spsa_sampler_gradient import SPSASamplerGradient

__all__ = [
"BaseEstimatorGradient",
"BaseSamplerGradient",
"EstimatorGradientResult",
"FiniteDiffEstimatorGradient",
"FiniteDiffSamplerGradient",
"LinCombEstimatorGradient",
"LinCombSamplerGradient",
"ParamShiftEstimatorGradient",
"ParamShiftSamplerGradient",
"SamplerGradientResult",
"SPSAEstimatorGradient",
"SPSASamplerGradient",
]
172 changes: 172 additions & 0 deletions qiskit/algorithms/gradients/base_estimator_gradient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2022.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.

"""
Abstract Base class of Gradient for Estimator.
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""

from __future__ import annotations

from abc import ABC, abstractmethod
from collections.abc import Sequence
from copy import copy

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
from qiskit.primitives.primitive_job import PrimitiveJob
from qiskit.quantum_info.operators.base_operator import BaseOperator

from .estimator_gradient_result import EstimatorGradientResult


class BaseEstimatorGradient(ABC):
"""Base class for an EstimatorGradient to compute the gradients of the expectation value."""
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved

def __init__(
self,
estimator: BaseEstimator,
**run_options,
):
"""
Args:
estimator: The estimator used to compute the gradients.
run_options: Backend runtime options used for circuit execution. The order of priority is:
run_options in ``run`` method > gradient's default run_options > primitive's default
setting. Higher priority setting overrides lower priority setting.

Raises:
ValueError: If the estimator is not an instance of BaseEstimator.
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""
if not isinstance(estimator, BaseEstimator):
raise ValueError(
f"The estimator should be an instance of BaseEstimator, but got {type(estimator)}"
)
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
self._estimator: BaseEstimator = estimator
self._default_run_options = run_options

def run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
**run_options,
) -> PrimitiveJob:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""Run the job of the estimator gradient on the given circuits.

Args:
circuits: The list of quantum circuits to compute the gradients.
observables: The list of observables.
parameter_values: The list of parameter values to be bound to the circuit.
parameters: The Sequence of Sequence of Parameters to calculate only the gradients of
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
the specified parameters. Each Sequence of Parameters corresponds to a circuit in
``circuits``. Defaults to None, which means that the gradients of all parameters in
each circuit are calculated.
run_options: Backend runtime options used for circuit execution. The order of priority is:
run_options in ``run`` method > gradient's default run_options > primitive's default
setting. Higher priority setting overrides lower priority setting.

Returns:
The job object of the gradients of the expectation values. The i-th result corresponds to
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
``circuits[i]`` evaluated with parameters bound as ``parameter_values[i]``. The j-th
element of the i-th result corresponds to the gradient of the i-th circuit with respect
to the j-th parameter.

Raises:
ValueError: Invalid arguments are given.
"""
# if ``parameters`` is none, all parameters in each circuit are differentiated.
if parameters is None:
parameters = [None for _ in range(len(circuits))]
# Validate the arguments.
self._validate_arguments(circuits, observables, parameter_values, parameters)
# The priority of run option is as follows:
# run_options in ``run`` method > gradient's default run_options > primitive's default setting.
run_opts = copy(self._default_run_options)
run_opts.update(run_options)

job = PrimitiveJob(
self._run, circuits, observables, parameter_values, parameters, **run_opts
)
job.submit()
return job

@abstractmethod
def _run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
) -> EstimatorGradientResult:
"""Compute the estimator gradients on the given circuits."""
raise NotImplementedError()

def _validate_arguments(
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
) -> None:
"""Validate the arguments of the ``run`` method.

Args:
circuits: The list of quantum circuits to compute the gradients.
observables: The list of observables.
parameter_values: The list of parameter values to be bound to the circuit.
parameters: The Sequence of Sequence of Parameters to calculate only the gradients of
the specified parameters. Each Sequence of Parameters corresponds to a circuit in
``circuits``. Defaults to None, which means that the gradients of all parameters in
each circuit are calculated.

Raises:
ValueError: Invalid arguments are given.
"""
# Validation
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
if len(circuits) != len(parameter_values):
raise ValueError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of parameter value sets ({len(parameter_values)})."
)

if len(circuits) != len(observables):
raise ValueError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of observables ({len(observables)})."
)

if parameters is not None:
if len(circuits) != len(parameters):
raise ValueError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of the specified parameter sets ({len(parameters)})."
)

for i, (circuit, parameter_value) in enumerate(zip(circuits, parameter_values)):
if not circuit.num_parameters:
raise ValueError(f"The {i}-th circuit is not parameterised.")
if len(parameter_value) != circuit.num_parameters:
raise ValueError(
f"The number of values ({len(parameter_value)}) does not match "
f"the number of parameters ({circuit.num_parameters}) for the {i}-th circuit."
)

for i, (circuit, observable) in enumerate(zip(circuits, observables)):
if circuit.num_qubits != observable.num_qubits:
raise ValueError(
f"The number of qubits of the {i}-th circuit ({circuit.num_qubits}) does "
f"not match the number of qubits of the {i}-th observable "
f"({observable.num_qubits})."
)
Loading