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 20 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
10 changes: 5 additions & 5 deletions qiskit/algorithms/gradients/base_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# that they have been altered from the originals.

"""
Abstract Base class of Gradient for Estimator.
Abstract base class of gradient for ``Estimator``.
"""

from __future__ import annotations
Expand All @@ -30,7 +30,7 @@


class BaseEstimatorGradient(ABC):
"""Base class for an EstimatorGradient to compute the gradients of the expectation value."""
"""Base class for an ``EstimatorGradient`` to compute the gradients of the expectation value."""

def __init__(
self,
Expand All @@ -45,7 +45,7 @@ def __init__(
setting. Higher priority setting overrides lower priority setting.

Raises:
ValueError: If the estimator is not an instance of BaseEstimator.
ValueError: If the estimator is not an instance of ``BaseEstimator``.
"""
if not isinstance(estimator, BaseEstimator):
raise ValueError(
Expand All @@ -68,8 +68,8 @@ def run(
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
parameters: The 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.
run_options: Backend runtime options used for circuit execution. The order of priority is:
Expand Down
12 changes: 6 additions & 6 deletions qiskit/algorithms/gradients/base_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
# that they have been altered from the originals.

"""
Abstract Base class of Gradient for Sampler.
Abstract base class of gradient for ``Sampler``.
"""

from __future__ import annotations
Expand All @@ -27,7 +27,7 @@


class BaseSamplerGradient(ABC):
"""Base class for a SamplerGradient to compute the gradients of the sampling probability."""
"""Base class for a ``SamplerGradient`` to compute the gradients of the sampling probability."""

def __init__(self, sampler: BaseSampler, **run_options):
"""
Expand All @@ -38,7 +38,7 @@ def __init__(self, sampler: BaseSampler, **run_options):
setting. Higher priority setting overrides lower priority setting.

Raises:
ValueError: If the sampler is not an instance of BaseEstimator.
ValueError: If the sampler is not an instance of ``BaseSampler``.
"""
if not isinstance(sampler, BaseSampler):
raise ValueError(
Expand All @@ -59,8 +59,8 @@ def run(
Args:
circuits: The list of quantum circuits to compute the gradients.
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
parameters: The 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.
run_options: Backend runtime options used for circuit execution. The order of priority is:
Expand Down Expand Up @@ -105,7 +105,7 @@ def _validate_arguments(
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
):
) -> None:
"""Validate the arguments of the ``run`` method.

Args:
Expand Down
13 changes: 5 additions & 8 deletions qiskit/algorithms/gradients/estimator_gradient_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,12 @@

@dataclass(frozen=True)
class EstimatorGradientResult:
"""Result of EstimatorGradient.

Args:
gradients: The gradients of the expectation values.
metadata: Additional information about the job.
run_options: run_options for the estimator. Currently, estimator's default run_options is not
included.
"""
"""Result of EstimatorGradient."""

gradients: list[np.ndarray]
"""The gradients of the expectation values."""
metadata: list[dict[str, Any]]
"""Additional information about the job."""
run_options: dict[str, Any]
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""run_options for the estimator. Currently, estimator's default run_options is not
included."""
11 changes: 8 additions & 3 deletions qiskit/algorithms/gradients/finite_diff_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@
import numpy as np

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
from qiskit.providers import JobStatus
from qiskit.quantum_info.operators.base_operator import BaseOperator

from .base_estimator_gradient import BaseEstimatorGradient
Expand All @@ -42,10 +44,10 @@ def __init__(self, estimator: BaseEstimator, epsilon: float, **run_options):
setting. Higher priority setting overrides lower priority setting.

Raises:
ValueError: If ``epsilon`` is not float.
ValueError: If ``epsilon`` is not positive.
"""
if not isinstance(epsilon, float):
raise ValueError(f"epsilon must be a float, but got {type(epsilon)} instead.")
if epsilon <= 0:
raise ValueError(f"epsilon ({epsilon}) should be positive.")
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
self._epsilon = epsilon
self._base_parameter_values_dict = {}
super().__init__(estimator, **run_options)
Expand Down Expand Up @@ -81,6 +83,9 @@ def _run(
jobs.append(job)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved

results = [job.result() for job in jobs]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In cases where we are using an underlying primitive should we not be looking that the status from the job to check if its DONE and if not take what action is appropriate.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

gradients = []
for result in results:
Expand Down
10 changes: 7 additions & 3 deletions qiskit/algorithms/gradients/finite_diff_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@
import numpy as np

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.primitives import BaseSampler
from qiskit.providers import JobStatus

from .base_sampler_gradient import BaseSamplerGradient
from .sampler_gradient_result import SamplerGradientResult
Expand All @@ -43,10 +45,10 @@ def __init__(
setting. Higher priority setting overrides lower priority setting.

Raises:
ValueError: If ``epsilon`` is not float.
ValueError: If ``epsilon`` is not positive.
"""
if not isinstance(epsilon, float):
raise ValueError(f"epsilon must be a float, but got {type(epsilon)} instead.")
if epsilon <= 0:
raise ValueError(f"epsilon ({epsilon}) should be positive.")
self._epsilon = epsilon
super().__init__(sampler, **run_options)

Expand Down Expand Up @@ -74,6 +76,8 @@ def _run(
jobs.append(job)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
results = [job.result() for job in jobs]
gradients = []
for i, result in enumerate(results):
Expand Down
12 changes: 10 additions & 2 deletions qiskit/algorithms/gradients/lin_comb_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@
import numpy as np

from qiskit.circuit import Parameter, ParameterExpression, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
from qiskit.primitives.utils import init_observable
from qiskit.providers import JobStatus
from qiskit.quantum_info import Pauli
from qiskit.quantum_info.operators.base_operator import BaseOperator

from .base_estimator_gradient import BaseEstimatorGradient
from .estimator_gradient_result import EstimatorGradientResult
from .utils import make_lin_comb_gradient_circuit
from .utils import _make_lin_comb_gradient_circuit


Pauli_Z = Pauli("Z")

Expand Down Expand Up @@ -65,6 +69,8 @@ def _run(
for circuit, observable, parameter_values_, parameters_ in zip(
circuits, observables, parameter_values, parameters
):
# Make the observable as observable as :class:`~qiskit.quantum_info.SparsePauliOp`.
observables = init_observable(observable)
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
# a set of parameters to be differentiated
if parameters_ is None:
param_set = set(circuit.parameters)
Expand All @@ -76,7 +82,7 @@ def _run(
observable_ = observable.expand(Pauli_Z)
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
gradient_circuits_ = self._gradient_circuits.get(id(circuit))
if gradient_circuits_ is None:
gradient_circuits_ = make_lin_comb_gradient_circuit(circuit)
gradient_circuits_ = _make_lin_comb_gradient_circuit(circuit)
self._gradient_circuits[id(circuit)] = gradient_circuits_

# only compute the gradients for parameters in the parameter set
Expand Down Expand Up @@ -112,6 +118,8 @@ def _run(
coeffs_all.append(coeffs)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
results = [job.result() for job in jobs]
gradients = []
for i, result in enumerate(results):
Expand Down
8 changes: 6 additions & 2 deletions qiskit/algorithms/gradients/lin_comb_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import numpy as np

from qiskit.circuit import Parameter, ParameterExpression, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.primitives import BaseSampler
from qiskit.providers import JobStatus

from .base_sampler_gradient import BaseSamplerGradient
from .sampler_gradient_result import SamplerGradientResult
from .utils import make_lin_comb_gradient_circuit
from .utils import _make_lin_comb_gradient_circuit


class LinCombSamplerGradient(BaseSamplerGradient):
Expand Down Expand Up @@ -68,7 +70,7 @@ def _run(
# TODO: support measurement in different basis (Y and Z+iY)
gradient_circuits_ = self._gradient_circuits.get(id(circuit))
if gradient_circuits_ is None:
gradient_circuits_ = make_lin_comb_gradient_circuit(circuit, add_measurement=True)
gradient_circuits_ = _make_lin_comb_gradient_circuit(circuit, add_measurement=True)
self._gradient_circuits[id(circuit)] = gradient_circuits_

# only compute the gradients for parameters in the parameter set
Expand Down Expand Up @@ -101,6 +103,8 @@ def _run(
coeffs_all.append(coeffs)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
results = [job.result() for job in jobs]
gradients = []
for i, result in enumerate(results):
Expand Down
10 changes: 7 additions & 3 deletions qiskit/algorithms/gradients/param_shift_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,16 @@
import numpy as np

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
from qiskit.providers import JobStatus
from qiskit.quantum_info.operators.base_operator import BaseOperator

from .base_estimator_gradient import BaseEstimatorGradient
from .estimator_gradient_result import EstimatorGradientResult

from .utils import param_shift_preprocessing, make_param_shift_parameter_values
from .utils import _param_shift_preprocessing, _make_param_shift_parameter_values


class ParamShiftEstimatorGradient(BaseEstimatorGradient):
Expand Down Expand Up @@ -67,7 +69,7 @@ def _run(
if self._gradient_circuits.get(id(circuit)):
gradient_circuit, base_parameter_values_all = self._gradient_circuits[id(circuit)]
else:
gradient_circuit, base_parameter_values_all = param_shift_preprocessing(circuit)
gradient_circuit, base_parameter_values_all = _param_shift_preprocessing(circuit)
self._gradient_circuits[id(circuit)] = (
gradient_circuit,
base_parameter_values_all,
Expand All @@ -78,7 +80,7 @@ def _run(
gradient_parameter_values_minus,
result_indices,
coeffs,
) = make_param_shift_parameter_values(
) = _make_param_shift_parameter_values(
gradient_circuit_data=gradient_circuit,
base_parameter_values=base_parameter_values_all,
parameter_values=parameter_values_,
Expand All @@ -96,6 +98,8 @@ def _run(
coeffs_all.append(coeffs)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
results = [job.result() for job in jobs]
gradients = []
for i, result in enumerate(results):
Expand Down
10 changes: 7 additions & 3 deletions qiskit/algorithms/gradients/param_shift_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@
import numpy as np

from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.exceptions import QiskitError
from qiskit.primitives import BaseSampler
from qiskit.providers import JobStatus

from .base_sampler_gradient import BaseSamplerGradient
from .sampler_gradient_result import SamplerGradientResult
from .utils import param_shift_preprocessing, make_param_shift_parameter_values
from .utils import _param_shift_preprocessing, _make_param_shift_parameter_values


class ParamShiftSamplerGradient(BaseSamplerGradient):
Expand Down Expand Up @@ -61,7 +63,7 @@ def _run(
if self._gradient_circuits.get(id(circuit)):
gradient_circuit, base_parameter_values_all = self._gradient_circuits[id(circuit)]
else:
gradient_circuit, base_parameter_values_all = param_shift_preprocessing(circuit)
gradient_circuit, base_parameter_values_all = _param_shift_preprocessing(circuit)
self._gradient_circuits[id(circuit)] = (
gradient_circuit,
base_parameter_values_all,
Expand All @@ -72,7 +74,7 @@ def _run(
gradient_parameter_values_minus,
result_indices,
coeffs,
) = make_param_shift_parameter_values(
) = _make_param_shift_parameter_values(
gradient_circuit_data=gradient_circuit,
base_parameter_values=base_parameter_values_all,
parameter_values=parameter_values_,
Expand All @@ -90,6 +92,8 @@ def _run(
coeffs_all.append(coeffs)

# combine the results
if any(job.status() is not JobStatus.DONE for job in jobs):
raise QiskitError("The gradient job was not completed successfully. ")
results = [job.result() for job in jobs]
gradients = []
for i, result in enumerate(results):
Expand Down
16 changes: 5 additions & 11 deletions qiskit/algorithms/gradients/sampler_gradient_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,14 @@
from typing import Any
from dataclasses import dataclass

from qiskit.result import QuasiDistribution


@dataclass(frozen=True)
class SamplerGradientResult:
"""Result of SamplerGradient.

Args:
gradients: The gradients of the quasi distributions.
metadata: Additional information about the job.
run_options: run_options for the sampler. Currently, sampler's default run_options is not
included.
"""
"""Result of SamplerGradient."""

gradients: list[list[QuasiDistribution]]
gradients: list[list[dict[int, float]]]
"""The gradients of the sample probabilities."""
metadata: list[dict[str, Any]]
"""Additional information about the job."""
run_options: dict[str, Any]
"""run_options for the sampler. Currently, sampler's default run_options is not included"""
Loading