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

QFI with the primitives #8688

Merged
merged 52 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
39e7e70
wip qfi
a-matsuo Sep 6, 2022
21ec238
wip qfi
a-matsuo Sep 8, 2022
e25d56c
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 13, 2022
87da32d
updated
a-matsuo Sep 14, 2022
6f4baf6
added tests
a-matsuo Sep 14, 2022
d618406
updated
a-matsuo Sep 15, 2022
8c4b4a0
updated
a-matsuo Sep 15, 2022
7676027
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 15, 2022
3823788
updated
a-matsuo Sep 15, 2022
5a1e6fb
lin comb qfi
a-matsuo Sep 15, 2022
07fea57
fix
a-matsuo Sep 16, 2022
8db3e3a
Merge branch 'main' into qfi-primitive
a-matsuo Sep 16, 2022
e0f9347
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 20, 2022
af09456
finilizing
a-matsuo Sep 21, 2022
2580571
Merge branch 'qfi-primitive' of github.com:a-matsuo/qiskit-terra into…
a-matsuo Sep 21, 2022
4eb4b43
fix lint
a-matsuo Sep 21, 2022
f8b08b3
started working on block diag qfi
a-matsuo Sep 22, 2022
a2bd837
updated utils
a-matsuo Sep 27, 2022
0c24ac7
fix
a-matsuo Sep 27, 2022
e0a22c8
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 27, 2022
e9f5a70
fix options
a-matsuo Sep 27, 2022
038c494
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 28, 2022
f23bb0a
fix
a-matsuo Sep 28, 2022
39aaad2
lint
a-matsuo Sep 28, 2022
aa7fd84
Merge branch 'main' into qfi-primitive
a-matsuo Sep 28, 2022
dc601ae
fix
a-matsuo Sep 28, 2022
3a1fa23
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 28, 2022
6b5f717
Merge branch 'qfi-primitive' of github.com:a-matsuo/qiskit-terra into…
a-matsuo Sep 28, 2022
e72d266
fix list
a-matsuo Sep 28, 2022
ac6f910
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Sep 30, 2022
59dba58
remove estimator from base qfi
a-matsuo Sep 30, 2022
4906f15
fix
a-matsuo Sep 30, 2022
c4707cf
Merge branch 'main' into qfi-primitive
a-matsuo Sep 30, 2022
0a49bc3
make a directory for gradient tests
a-matsuo Sep 30, 2022
ce6d933
added option to baseqfi + fied shots behavior
a-matsuo Oct 3, 2022
bfa8117
fixed qfi's derivative type complex
a-matsuo Oct 3, 2022
945146d
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Oct 3, 2022
3f1520c
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Oct 4, 2022
cd2c4d1
fix
a-matsuo Oct 4, 2022
37ac562
fix
a-matsuo Oct 4, 2022
2b98806
make parameter_values back to float
a-matsuo Oct 4, 2022
76d8afc
Merge branch 'main' into qfi-primitive
a-matsuo Oct 4, 2022
f635c80
Merge branch 'main' into qfi-primitive
a-matsuo Oct 26, 2022
fb56a60
Merge branch 'main' into qfi-primitive
a-matsuo Oct 27, 2022
03e94e1
updated
a-matsuo Oct 27, 2022
03642ef
fix lint
a-matsuo Oct 27, 2022
f0e05df
updated
a-matsuo Oct 28, 2022
d5db261
updated
a-matsuo Oct 28, 2022
7c8e127
Merge remote-tracking branch 'upstream/main' into qfi-primitive
a-matsuo Oct 28, 2022
a5bcda4
Merge branch 'main' into qfi-primitive
a-matsuo Oct 31, 2022
377d6c5
Merge branch 'main' into qfi-primitive
a-matsuo Nov 1, 2022
c0f749d
Merge branch 'main' into qfi-primitive
mergify[bot] Nov 1, 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
29 changes: 20 additions & 9 deletions qiskit/algorithms/gradients/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,15 @@

.. currentmodule:: qiskit.algorithms.gradients

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

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

BaseSamplerGradient
BaseEstimatorGradient

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

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

BaseEstimatorGradient
DerivativeType
FiniteDiffEstimatorGradient
LinCombEstimatorGradient
ParamShiftEstimatorGradient
Expand All @@ -43,44 +37,61 @@
.. autosummary::
:toctree: ../stubs/

BaseSamplerGradient
FiniteDiffSamplerGradient
LinCombSamplerGradient
ParamShiftSamplerGradient
SPSASamplerGradient

QFI
===
.. autosummary::
:toctree: ../stubs/

BaseQFI
LinCombQFI

Results
=======

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

EstimatorGradientResult
QFIResult
SamplerGradientResult
"""

from .base_estimator_gradient import BaseEstimatorGradient
from .base_qfi import BaseQFI
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_estimator_gradient import DerivativeType, LinCombEstimatorGradient
from .lin_comb_qfi import LinCombQFI
from .lin_comb_sampler_gradient import LinCombSamplerGradient
from .param_shift_estimator_gradient import ParamShiftEstimatorGradient
from .param_shift_sampler_gradient import ParamShiftSamplerGradient
from .qfi_result import QFIResult
from .sampler_gradient_result import SamplerGradientResult
from .spsa_estimator_gradient import SPSAEstimatorGradient
from .spsa_sampler_gradient import SPSASamplerGradient

__all__ = [
"BaseEstimatorGradient",
"BaseQFI",
"BaseSamplerGradient",
"DerivativeType",
"EstimatorGradientResult",
"FiniteDiffEstimatorGradient",
"FiniteDiffSamplerGradient",
"LinCombEstimatorGradient",
"LinCombQFI",
"LinCombSamplerGradient",
"ParamShiftEstimatorGradient",
"ParamShiftSamplerGradient",
"QFIResult",
"SamplerGradientResult",
"SPSAEstimatorGradient",
"SPSASamplerGradient",
Expand Down
6 changes: 3 additions & 3 deletions qiskit/algorithms/gradients/base_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameter_values: Sequence[Sequence[complex]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
**options,
) -> AlgorithmJob:
Expand Down Expand Up @@ -103,7 +103,7 @@ def _run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameter_values: Sequence[Sequence[complex]],
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
parameters: Sequence[Sequence[Parameter] | None],
**options,
) -> EstimatorGradientResult:
Expand All @@ -114,7 +114,7 @@ def _validate_arguments(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameter_values: Sequence[Sequence[complex]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
) -> None:
"""Validate the arguments of the ``run`` method.
Expand Down
182 changes: 182 additions & 0 deletions qiskit/algorithms/gradients/base_qfi.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
# 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 the Quantum Fisher Information (QFI).
"""

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.algorithms import AlgorithmJob
from qiskit.providers import Options

from .qfi_result import QFIResult


class BaseQFI(ABC):
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
r"""Base class to computes the Quantum Fisher Information (QFI) given a pure,
parameterized quantum state. QFI is defined as:

.. math::

\mathrm{QFI}_{kl}= 4 \mathrm{Re}[\langle \partial_k \psi | \partial_l \psi \rangle
- \langle\partial_k \psi | \psi \rangle \langle\psi | \partial_l \psi \rangle].
"""

def __init__(
self,
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
options: Options | None = None,
):
"""
Args:
options: Backend runtime options used for circuit execution. The order of priority is:
options in ``run`` method > QFI's default options > primitive's default
setting. Higher priority setting overrides lower priority setting.
"""
self._default_options = Options()
if options is not None:
self._default_options.update_options(**options)

def run(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[complex]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
**options,
) -> AlgorithmJob:
"""Run the job of the QFIs on the given circuits.

Args:
circuits: The list of quantum circuits to compute the QFIs.
parameter_values: The list of parameter values to be bound to the circuit.
parameters: The sequence of parameters to calculate only the QFIs of
the specified parameters. Each sequence of parameters corresponds to a circuit in
``circuits``. Defaults to None, which means that the QFIs of all parameters in
each circuit are calculated.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > QFI's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting

Returns:
The job object of the QFIs of the expectation values. The i-th result corresponds to
``circuits[i]`` evaluated with parameters bound as ``parameter_values[i]``. The j-th
element of the i-th result corresponds to the QFI 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] * len(circuits)
# Validate the arguments.
self._validate_arguments(circuits, parameter_values, parameters)
# The priority of run option is as follows:
# options in ``run`` method > QFI's default options > primitive's default setting.
opts = copy(self._default_options)
opts.update_options(**options)
job = AlgorithmJob(self._run, circuits, parameter_values, parameters, **opts.__dict__)
job.submit()
return job

@abstractmethod
def _run(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[complex]],
parameters: Sequence[Sequence[Parameter] | None],
**options,
) -> QFIResult:
"""Compute the QFIs on the given circuits."""
raise NotImplementedError()

def _validate_arguments(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[complex]],
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 QFIs.
parameter_values: The list of parameter values to be bound to the circuit.
parameters: The Sequence of Sequence of Parameters to calculate only the QFIs of
the specified parameters. Each Sequence of Parameters corresponds to a circuit in
``circuits``. Defaults to None, which means that the QFIs 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 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."
)

@property
def options(self) -> Options:
a-matsuo marked this conversation as resolved.
Show resolved Hide resolved
"""Return the union of estimator options setting and QFI default options,
where, if the same field is set in both, the QFI's default options override
the primitive's default setting.

Returns:
The QFI default + estimator options.
"""
return self._get_local_options(self._default_options.__dict__)

def update_default_options(self, **options):
"""Update the QFI's default options setting.

Args:
**options: The fields to update the default options.
"""
self._default_options.update_options(**options)

@abstractmethod
def _get_local_options(self, options: Options) -> Options:
"""Return the union of the primitive's default setting,
the QFI default options, and the options in the ``run`` method.
The order of priority is: options in ``run`` method > QFI's default options > primitive's
default setting.

Args:
options: The fields to update the options

Returns:
The QFI default + estimator + run options.
"""
pass
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.opflow import PauliSumOp
from qiskit.primitives import BaseEstimator
from qiskit.providers import Options
from qiskit.quantum_info.operators.base_operator import BaseOperator

from .base_estimator_gradient import BaseEstimatorGradient
Expand All @@ -33,7 +34,7 @@ class FiniteDiffEstimatorGradient(BaseEstimatorGradient):
Compute the gradients of the expectation values by finite difference method.
"""

def __init__(self, estimator: BaseEstimator, epsilon: float, **options):
def __init__(self, estimator: BaseEstimator, epsilon: float, options: Options | None = None):
"""
Args:
estimator: The estimator used to compute the gradients.
Expand All @@ -50,13 +51,13 @@ def __init__(self, estimator: BaseEstimator, epsilon: float, **options):
raise ValueError(f"epsilon ({epsilon}) should be positive.")
self._epsilon = epsilon
self._base_parameter_values_dict = {}
super().__init__(estimator, **options)
super().__init__(estimator, options)

def _run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameter_values: Sequence[Sequence[complex]],
parameters: Sequence[Sequence[Parameter] | None],
**options,
) -> EstimatorGradientResult:
Expand Down
5 changes: 3 additions & 2 deletions qiskit/algorithms/gradients/finite_diff_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from qiskit.algorithms import AlgorithmError
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.primitives import BaseSampler
from qiskit.providers import Options

from .base_sampler_gradient import BaseSamplerGradient
from .sampler_gradient_result import SamplerGradientResult
Expand All @@ -33,7 +34,7 @@ def __init__(
self,
sampler: BaseSampler,
epsilon: float,
**options,
options: Options | None = None,
):
"""
Args:
Expand All @@ -50,7 +51,7 @@ def __init__(
if epsilon <= 0:
raise ValueError(f"epsilon ({epsilon}) should be positive.")
self._epsilon = epsilon
super().__init__(sampler, **options)
super().__init__(sampler, options)

def _run(
self,
Expand Down
Loading