Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
48 changes: 26 additions & 22 deletions qiskit/algorithms/gradients/base_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,28 @@ class BaseEstimatorGradient(ABC):
def __init__(
self,
estimator: BaseEstimator,
run_options: dict | None = None,
options: Options | None = None,
):
"""
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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting
"""
self._estimator: BaseEstimator = estimator
self._default_run_options = Options()
if run_options is not None:
self._default_run_options.update_options(**run_options)
self._default_options = Options()
if options is not None:
self._default_options.update_options(**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,
**options,
) -> AlgorithmJob:
"""Run the job of the estimator gradient on the given circuits.

Expand All @@ -68,9 +69,10 @@ def run(
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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default 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
Expand All @@ -87,11 +89,11 @@ def run(
# 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_options(**run_options)
# options in ``run`` method > gradient's default options > primitive's default setting.
opts = copy(self._default_options)
opts.update_options(**options)
job = AlgorithmJob(
self._run, circuits, observables, parameter_values, parameters, **run_opts.__dict__
self._run, circuits, observables, parameter_values, parameters, **opts.__dict__
)
job.submit()
return job
Expand All @@ -103,7 +105,7 @@ def _run(
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
**options,
) -> EstimatorGradientResult:
"""Compute the estimator gradients on the given circuits."""
raise NotImplementedError()
Expand Down Expand Up @@ -166,15 +168,17 @@ def _validate_arguments(
f"({observable.num_qubits})."
)

def _get_local_run_options(self, run_options: dict) -> Options:
"""Update the run options in the results.
def _get_local_options(self, options: Options) -> Options:
"""Update the runtime options in the results to reflect the final setting,
where the options can come from the primitive's default setting, the gradient's
default options, or the options in the ``run`` method.

Args:
run_options: The run options to update.
options: The run options to update.

Returns:
The updated run options.
"""
run_opts = copy(self._estimator.options)
run_opts.update_options(**run_options)
return run_opts
opts = copy(self._estimator.options)
opts.update_options(**options)
return opts
49 changes: 26 additions & 23 deletions qiskit/algorithms/gradients/base_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,26 @@
class BaseSamplerGradient(ABC):
"""Base class for a ``SamplerGradient`` to compute the gradients of the sampling probability."""

def __init__(self, sampler: BaseSampler, run_options: dict | None = None):
def __init__(self, sampler: BaseSampler, options: Options | None = None):
"""
Args:
sampler: The sampler 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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting
"""
self._sampler: BaseSampler = sampler
self._default_run_options = Options()
if run_options is not None:
self._default_run_options.update_options(**run_options)
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[float]],
parameters: Sequence[Sequence[Parameter] | None] | None = None,
**run_options,
**options,
) -> AlgorithmJob:
"""Run the job of the sampler gradient on the given circuits.

Expand All @@ -59,10 +60,10 @@ def run(
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.

options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting
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]``.
Expand All @@ -78,10 +79,10 @@ def run(
# Validate the arguments.
self._validate_arguments(circuits, parameter_values, parameters)
# The priority of run option is as follows:
# run_options in `run` method > gradient's default run_options > primitive's default run_options.
run_opts = copy(self._default_run_options)
run_opts.update_options(**run_options)
job = AlgorithmJob(self._run, circuits, parameter_values, parameters, **run_opts.__dict__)
# options in `run` method > gradient's default options > primitive's default options.
opts = copy(self._default_options)
opts.update_options(**options)
job = AlgorithmJob(self._run, circuits, parameter_values, parameters, **opts.__dict__)
job.submit()
return job

Expand All @@ -91,7 +92,7 @@ def _run(
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
**options,
) -> SamplerGradientResult:
"""Compute the sampler gradients on the given circuits."""
raise NotImplementedError()
Expand Down Expand Up @@ -138,15 +139,17 @@ def _validate_arguments(
f"the number of parameters ({circuit.num_parameters}) for the {i}-th circuit."
)

def _get_local_run_options(self, run_options: dict) -> dict:
"""Update the run options in the results.
def _get_local_options(self, options: Options) -> Options:
"""Update the runtime options in the results to reflect the final setting,
where the options can come from the primitive's default setting, the gradient's
default options, or the options in the ``run`` method.

Args:
run_options: The run options to update.
options: The run options to update.

Returns:
The updated run options.
"""
run_opts = copy(self._sampler.options)
run_opts.update_options(**run_options)
return run_opts
opts = copy(self._sampler.options)
opts.update_options(**options)
return opts
4 changes: 2 additions & 2 deletions qiskit/algorithms/gradients/estimator_gradient_result.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,5 @@ class EstimatorGradientResult:
"""The gradients of the expectation values."""
metadata: list[dict[str, Any]]
"""Additional information about the job."""
run_options: Options
"""run_options for the job."""
options: Options
"""Primitive runtime options for the execution of the job."""
19 changes: 10 additions & 9 deletions qiskit/algorithms/gradients/finite_diff_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ class FiniteDiffEstimatorGradient(BaseEstimatorGradient):
Compute the gradients of the expectation values by finite difference method.
"""

def __init__(self, estimator: BaseEstimator, epsilon: float, **run_options):
def __init__(self, estimator: BaseEstimator, epsilon: float, **options):
"""
Args:
estimator: The estimator used to compute the gradients.
epsilon: The offset size for the finite difference 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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting

Raises:
ValueError: If ``epsilon`` is not positive.
Expand All @@ -49,15 +50,15 @@ def __init__(self, estimator: BaseEstimator, epsilon: float, **run_options):
raise ValueError(f"epsilon ({epsilon}) should be positive.")
self._epsilon = epsilon
self._base_parameter_values_dict = {}
super().__init__(estimator, **run_options)
super().__init__(estimator, **options)

def _run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
**options,
) -> EstimatorGradientResult:
"""Compute the estimator gradients on the given circuits."""
jobs, metadata_ = [], []
Expand All @@ -76,7 +77,7 @@ def _run(
minus = parameter_values_ - self._epsilon * offset
n = 2 * len(indices)
job = self._estimator.run(
[circuit] * n, [observable] * n, plus.tolist() + minus.tolist(), **run_options
[circuit] * n, [observable] * n, plus.tolist() + minus.tolist(), **options
)
jobs.append(job)

Expand All @@ -91,5 +92,5 @@ def _run(
n = len(result.values) // 2 # is always a multiple of 2
gradient_ = (result.values[:n] - result.values[n:]) / (2 * self._epsilon)
gradients.append(gradient_)
run_opt = self._get_local_run_options(run_options)
return EstimatorGradientResult(gradients=gradients, metadata=metadata_, run_options=run_opt)
opt = self._get_local_options(options)
return EstimatorGradientResult(gradients=gradients, metadata=metadata_, options=opt)
19 changes: 10 additions & 9 deletions qiskit/algorithms/gradients/finite_diff_sampler_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,31 @@ def __init__(
self,
sampler: BaseSampler,
epsilon: float,
**run_options,
**options,
):
"""
Args:
sampler: The sampler used to compute the gradients.
epsilon: The offset size for the finite difference 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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting

Raises:
ValueError: If ``epsilon`` is not positive.
"""
if epsilon <= 0:
raise ValueError(f"epsilon ({epsilon}) should be positive.")
self._epsilon = epsilon
super().__init__(sampler, **run_options)
super().__init__(sampler, **options)

def _run(
self,
circuits: Sequence[QuantumCircuit],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
**options,
) -> SamplerGradientResult:
"""Compute the sampler gradients on the given circuits."""
jobs, metadata_ = [], []
Expand All @@ -71,7 +72,7 @@ def _run(
plus = parameter_values_ + self._epsilon * offset
minus = parameter_values_ - self._epsilon * offset
n = 2 * len(indices)
job = self._sampler.run([circuit] * n, plus.tolist() + minus.tolist(), **run_options)
job = self._sampler.run([circuit] * n, plus.tolist() + minus.tolist(), **options)
jobs.append(job)

# combine the results
Expand All @@ -92,5 +93,5 @@ def _run(
gradient_.append(dict(enumerate(grad_dist)))
gradients.append(gradient_)

run_opt = self._get_local_run_options(run_options)
return SamplerGradientResult(gradients=gradients, metadata=metadata_, run_options=run_opt)
opt = self._get_local_options(options)
return SamplerGradientResult(gradients=gradients, metadata=metadata_, options=opt)
21 changes: 11 additions & 10 deletions qiskit/algorithms/gradients/lin_comb_estimator_gradient.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,31 +44,32 @@ class LinCombEstimatorGradient(BaseEstimatorGradient):
`arXiv:1811.11184 <https://arxiv.org/pdf/1811.11184.pdf>`_
"""

def __init__(self, estimator: BaseEstimator, **run_options):
def __init__(self, estimator: BaseEstimator, **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.
options: Primitive backend runtime options used for circuit execution.
The order of priority is: options in ``run`` method > gradient's
default options > primitive's default setting.
Higher priority setting overrides lower priority setting
"""
self._gradient_circuits = {}
super().__init__(estimator, **run_options)
super().__init__(estimator, **options)

def _run(
self,
circuits: Sequence[QuantumCircuit],
observables: Sequence[BaseOperator | PauliSumOp],
parameter_values: Sequence[Sequence[float]],
parameters: Sequence[Sequence[Parameter] | None],
**run_options,
**options,
) -> EstimatorGradientResult:
"""Compute the estimator gradients on the given circuits."""
jobs, result_indices_all, coeffs_all, metadata_ = [], [], [], []
for circuit, observable, parameter_values_, parameters_ in zip(
circuits, observables, parameter_values, parameters
):
# Make the observable as observable as :class:`~qiskit.quantum_info.SparsePauliOp`.
# Make the observable as :class:`~qiskit.quantum_info.SparsePauliOp`.
observable = init_observable(observable)
# a set of parameters to be differentiated
if parameters_ is None:
Expand Down Expand Up @@ -110,7 +111,7 @@ def _run(

n = len(gradient_circuits)
job = self._estimator.run(
gradient_circuits, [observable_] * n, [parameter_values_] * n, **run_options
gradient_circuits, [observable_] * n, [parameter_values_] * n, **options
)
jobs.append(job)
result_indices_all.append(result_indices)
Expand All @@ -129,5 +130,5 @@ def _run(
gradient_[idx] += coeff * grad_
gradients.append(gradient_)

run_opt = self._get_local_run_options(run_options)
return EstimatorGradientResult(gradients=gradients, metadata=metadata_, run_options=run_opt)
opt = self._get_local_options(options)
return EstimatorGradientResult(gradients=gradients, metadata=metadata_, options=opt)
Loading