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 8 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
74 changes: 74 additions & 0 deletions qiskit/algorithms/gradients/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# 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.

"""
=====================================
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
Gradients (:mod:`qiskit.algorithms.gradients`)
=====================================

.. currentmodule:: qiskit.algorithms.gradients

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

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

BaseSamplerGradient
BaseEstimatorGradient

Gradients
=========

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

FiniteDiffEstimatorGradient
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
FiniteDiffSamplerGradient
LinCombEstimatorGradient
LinCombSamplerGradient
ParamShiftEstimatorGradient
ParamShiftSamplerGradient

Results
=======

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

EstimatorResult
SamplerResult
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""

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

__all__ = [
"BaseEstimatorGradient",
"BaseSamplerGradient",
"EstimatorGradientResult",
"FiniteDiffEstimatorGradient",
"FiniteDiffSamplerGradient",
"LinCombEstimatorGradient",
"LinCombSamplerGradient",
"ParamShiftEstimatorGradient",
"ParamShiftSamplerGradient",
"SamplerGradientResult",
]
122 changes: 122 additions & 0 deletions qiskit/algorithms/gradients/base_estimator_gradient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# 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 qiskit.circuit import Parameter, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
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.
"""
self._estimator: BaseEstimator = estimator
self._circuits: Sequence[QuantumCircuit] = []
self._circuit_ids: dict[int, int] = {}
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
self._default_run_options = run_options

def evaluate(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
partial: Sequence[Sequence[Parameter]] | None = None,
**run_options,
) -> EstimatorGradientResult:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""Run the job of the gradients of expectation values.

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.
partial: The list of Parameters to calculate only the gradients of the specified parameters.
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
Defaults to None, which means that the gradients of all parameters will be calculated.
run_options: Backend runtime options used for circuit execution.

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]``.

Raises:
QiskitError: Invalid arguments are given.
"""
# Validation
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
if len(circuits) != len(parameter_values):
raise QiskitError(
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
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 QiskitError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of observables ({len(partial)})."
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
)

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

for i, (circuit, parameter_value) in enumerate(zip(circuits, parameter_values)):
if len(parameter_value) != circuit.num_parameters:
raise QiskitError(
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 QiskitError(
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})."
)

# The priority of run option is as follows:
# run_options in `run` method > gradient's default run_options > primitive's default setting.
run_options = run_options or self._default_run_options
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
return self._evaluate(circuits, observables, parameter_values, partial, **run_options)

@abstractmethod
def _evaluate(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
partial: Sequence[Sequence[Parameter]] | None = None,
**run_options,
) -> EstimatorGradientResult:
raise NotImplementedError()
99 changes: 99 additions & 0 deletions qiskit/algorithms/gradients/base_sampler_gradient.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# 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 Sampler.
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 qiskit.circuit import QuantumCircuit, Parameter
from qiskit.exceptions import QiskitError
from qiskit.primitives import BaseSampler
from .sampler_gradient_result import SamplerGradientResult


class BaseSamplerGradient(ABC):
"""Base class for a SamplerGradient to compute the gradients of the sampling probability."""
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved

def __init__(self, sampler: BaseSampler, **run_options):
"""
Args:
sampler: The sampler used to compute the gradients.
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""
self._sampler: BaseSampler = sampler
self._circuits: list[QuantumCircuit] = []
self._circuit_ids: dict[int, int] = {}
self._default_run_options = run_options

def evaluate(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[float]],
partial: Sequence[Sequence[Parameter]] | None = None,
**run_options,
) -> SamplerGradientResult:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""Run the job of the gradients of the sampling probability.

Args:
circuits: The list of quantum circuits to compute the gradients.
parameter_values: The list of parameter values to be bound to the circuit.
partial: The list of Parameters to calculate only the gradients of the specified parameters.
Defaults to None, which means that the gradients of all parameters will be calculated.
run_options: Backend runtime options used for circuit execution.

Returns:
The job object of the gradients of the sampling probability. The i-th result corresponds to
``circuits[i]`` evaluated with parameters bound as ``parameter_values[i]``. The j-th
quasi-probability distribution in the i-th result corresponds to the gradients of the
sampling probability for the j-th parameter in ``circuits[i]``.

Raises:
QiskitError: Invalid arguments are given.
"""
# Validation
if len(circuits) != len(parameter_values):
raise QiskitError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of parameter value sets ({len(parameter_values)})."
)
if partial is not None:
if len(circuits) != len(partial):
raise QiskitError(
f"The number of circuits ({len(circuits)}) does not match "
f"the number of partial parameter sets ({len(partial)})."
)

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

# The priority of run option is as follows:
# run_options in `run` method > gradient's default run_options > primitive's default run_options.
run_options = run_options or self._default_run_options
return self._evaluate(circuits, parameter_values, partial, **run_options)

@abstractmethod
def _evaluate(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[float]],
partial: Sequence[Sequence[Parameter]] | None = None,
**run_options,
) -> SamplerGradientResult:
raise NotImplementedError()
39 changes: 39 additions & 0 deletions qiskit/algorithms/gradients/estimator_gradient_result.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 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.
"""
Estimator result class
"""

from __future__ import annotations

from dataclasses import dataclass
from typing import Any

import numpy as np

from qiskit.providers import JobStatus


@dataclass(frozen=True)
class EstimatorGradientResult:
"""Result of EstimatorGradient.
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved

Args:
results (list[EstimatorResult]): List of EstimatorResults. 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 value
in the i-th result corresponds to the gradients of the j-th parameter in ``circuits[i]``.
status: List of JobStatus for each EstimatorResult.
"""

values: list[np.ndarray]
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
status: list[JobStatus]
metadata: list[dict[str, Any]]
Loading