Skip to content

Added V2 and ISA support #197

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

Draft
wants to merge 97 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
634dc69
Added TODO
tnemoz Aug 7, 2024
ecee0c6
Started to adapt to V2 primitives
tnemoz Aug 7, 2024
529c5da
Modified phase estimators to work with V2 primitives and ISA circuits
tnemoz Aug 9, 2024
e390037
Merge branch 'main' into main
woodsp-ibm Aug 9, 2024
da40425
Changed PassManager to more generic transpiler
tnemoz Aug 12, 2024
d83408c
Changed custom types to support Python 3.8
tnemoz Aug 12, 2024
0e6e6f0
Added transpiler to .pylintdict
tnemoz Aug 12, 2024
0e8ac74
Adapted Grover to V2 primitives
tnemoz Aug 12, 2024
3d79bb5
Changed custom types using __future__ annotations
tnemoz Aug 16, 2024
eae6cff
Adapated VQD to V2 primitives
tnemoz Aug 16, 2024
df69ea7
Adapted tests for Grover
tnemoz Aug 16, 2024
111188b
Fixed styling
tnemoz Aug 16, 2024
4b46931
Merge branch 'main' into main
tnemoz Aug 24, 2024
c03c3a1
Merge branch 'min_eigen' into dev
Aug 25, 2024
93af774
removed useless comments in vqe and changed SamplingVQE to match v2 p…
Aug 26, 2024
63332e9
changed AdaptVQE
Aug 26, 2024
1b58074
changed diagonal_estimators from v1 to v2 primitives
Aug 26, 2024
b48c66d
updated TODO
Aug 30, 2024
1cd76ff
changed qaoa to match v2 and isa
Aug 30, 2024
4f734d9
modified all associated tests for min_eigen classes
Aug 30, 2024
d7b671f
changed todo
Aug 30, 2024
d2bc2db
ComputeUncompute done
tnemoz Sep 2, 2024
cae37b2
QNSPSA done
tnemoz Sep 2, 2024
84128a8
Restored SPSA test to previous values
tnemoz Sep 10, 2024
b3c32a3
Refactored test for transpilers, make linter happy, test_vqd not passing
tnemoz Sep 10, 2024
dc075d0
Updated TODO
tnemoz Sep 10, 2024
0790c53
PVQD done
tnemoz Sep 10, 2024
7ff3ab6
Slight modifications of VQD, still isn't working
tnemoz Sep 18, 2024
bf6a931
Adapted PVQD to EstimatorV2
tnemoz Aug 16, 2024
dea4bd0
Adapted Trotter QRTE to EstimatorV2
tnemoz Aug 16, 2024
8d9a54c
Trotter QRTE
tnemoz Sep 18, 2024
8c87b8d
Time evolvers
tnemoz Dec 5, 2024
e3150cf
Merge branch 'main' into main
tnemoz Dec 5, 2024
3fcc265
Fixed linting and VQD test
tnemoz Dec 5, 2024
a1171dc
Updated TODO
tnemoz Dec 5, 2024
82f7ced
Merge branch 'main' into main
woodsp-ibm May 29, 2025
d45c9ad
started mlae.py, not finished
Aug 30, 2024
cefd334
finished mlae file
Oct 9, 2024
4b95ced
updated todo andneed to continue fae and addtranspilation to mlae and…
Oct 9, 2024
9eab51a
modified gradient base
Mar 14, 2025
3af5a57
started changes into gradients
Mar 29, 2025
fb4dcc6
finished finite-diff gradient
Mar 29, 2025
950b24e
Updated gradients test
tnemoz Mar 29, 2025
6fbd45e
updated reverse gradients
Mar 29, 2025
af1c097
updated lin_comb files, missing transpilation added to the TODO list …
Mar 29, 2025
c5a46b3
updated spsa estimator gradient
Mar 29, 2025
b4fcadb
finished spsa sampler
Mar 30, 2025
8fa65ce
finished lin comb
Mar 30, 2025
004e28c
started changes for tests
Mar 30, 2025
48e63f9
Amplitude estimators, tests failing but no errors
tnemoz Mar 29, 2025
b63a36e
Almost done, weird bug on transpiler test on mlae
tnemoz Mar 30, 2025
4299816
Amplitude estimatorsd done
tnemoz Apr 26, 2025
2c21f99
Updated TODO
tnemoz Apr 29, 2025
73fbb5d
Estimator gradients working
tnemoz Apr 29, 2025
2e78525
QGT working
tnemoz Apr 30, 2025
ee0597e
QFI working
tnemoz May 1, 2025
0610b7c
Sampler gradients working
tnemoz May 5, 2025
c9f823d
Started working on _DiagonalEstimator
tnemoz May 6, 2025
188c5ae
Continued working on _DiagonalEstimator
tnemoz May 6, 2025
dd53643
Continued working on _DiagonalEstimator #2, _call method todo
tnemoz May 12, 2025
d0e7203
Continued working on _DiagonalEstimator #3, test sampling_vqe todo
tnemoz May 13, 2025
cf84ba6
_DiagonalEstimator supposedly done, test with QNSPSA fails for now
tnemoz May 26, 2025
25f1c55
_DiagonalEstimator done
tnemoz May 27, 2025
941043b
SamplingVQE done
tnemoz May 27, 2025
207f365
Working QAOA
tnemoz May 27, 2025
822e204
Removed TODO and added more shots for the QAOA test
tnemoz May 27, 2025
757a277
Changed initial point in QAOA test to be able to seed
tnemoz May 27, 2025
6f39d76
Updated VQE tutorials
tnemoz May 29, 2025
fb47a1b
VQE working
tnemoz May 29, 2025
8c402ad
Most tutorials updated. QAOA to be checked, tweedldum to be removed f…
tnemoz Jun 2, 2025
bf2d326
Replaced test for transpiler
tnemoz Jun 2, 2025
aff31d8
Added pVQD to docs
tnemoz Jun 2, 2025
4ff895f
All tests passing
tnemoz Jun 2, 2025
75cc776
Removed aliases
tnemoz Jun 2, 2025
64b8352
Fixed time evolvers
tnemoz Jun 6, 2025
303bcb4
Added future imports annotations for Python 3.9
tnemoz Jun 6, 2025
47c22fb
Added copyrights
tnemoz Jun 6, 2025
d89db0b
Linting done, spelling to fix
tnemoz Jun 6, 2025
6d8a705
Spell checked
tnemoz Jun 6, 2025
e6db4f2
Rollback RealAmplitudes and EfficientSU2
tnemoz Jun 6, 2025
9ab842c
Additional copyrights and linting
tnemoz Jun 6, 2025
fb9c417
Removed strict=True in zip
tnemoz Jun 6, 2025
fc17c5d
Lowered precision of VQD test
tnemoz Jun 6, 2025
ba0c35d
Correct wrong import and line too long
tnemoz Jun 6, 2025
e33745b
Added tweedledum to dictionnary and added missing copyright
tnemoz Jun 6, 2025
515bc54
Corrected spelling in optional
tnemoz Jun 9, 2025
bceaf06
Seeded StatevectorSampler in gradients test
tnemoz Jun 9, 2025
924d2f3
black formatting
tnemoz Jun 9, 2025
f4dd0e6
Added _circuit_key
tnemoz Jun 9, 2025
3ec9df7
lback formatting circuit_key
tnemoz Jun 9, 2025
8d83580
Accessed _op_start_times private attribute
tnemoz Jun 9, 2025
077052d
Removed last instance of Estimator and changed ClassicalRegister impo…
tnemoz Jun 9, 2025
6afadc4
Changed Copyright for test_optimizers_scikitquant
tnemoz Jun 10, 2025
54e7bf0
Changed requirements
tnemoz Jun 10, 2025
6a1e92c
Added simplify in adaptVQE
tnemoz Jun 10, 2025
2eac1eb
Changed copyright of adaptvqe
tnemoz Jun 10, 2025
d6e1911
Merge branch 'main' into main
tnemoz Jun 16, 2025
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
6 changes: 6 additions & 0 deletions .pylintdict
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ hopkins
hoyer
https
hyperparameters
iae
idx
im
imag
Expand All @@ -155,6 +156,7 @@ interatomic
ints
iprint
iqft
isa
ising
iteratively
iz
Expand Down Expand Up @@ -333,6 +335,7 @@ spsa
sqrt
statefn
statevector
statevectorestimator
statevectors
stddev
stdout
Expand Down Expand Up @@ -367,8 +370,11 @@ trainability
transpilation
transpile
transpiled
transpiler
transpiler's
trotterization
trotterized
tweedledum
uncompute
unitaries
univariate
Expand Down
90 changes: 45 additions & 45 deletions docs/tutorials/01_algorithms_introduction.ipynb

Large diffs are not rendered by default.

84 changes: 41 additions & 43 deletions docs/tutorials/02_vqe_advanced_options.ipynb

Large diffs are not rendered by default.

61 changes: 30 additions & 31 deletions docs/tutorials/03_vqe_simulation_with_noise.ipynb

Large diffs are not rendered by default.

31 changes: 17 additions & 14 deletions docs/tutorials/04_vqd.ipynb

Large diffs are not rendered by default.

649 changes: 320 additions & 329 deletions docs/tutorials/10_pvqd.ipynb

Large diffs are not rendered by default.

44 changes: 22 additions & 22 deletions docs/tutorials/11_VarQTE.ipynb

Large diffs are not rendered by default.

32 changes: 16 additions & 16 deletions docs/tutorials/12_gradients_framework.ipynb

Large diffs are not rendered by default.

92 changes: 38 additions & 54 deletions docs/tutorials/13_trotterQRTE.ipynb

Large diffs are not rendered by default.

22 changes: 1 addition & 21 deletions qiskit_algorithms/algorithm_job.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,26 +20,6 @@ class AlgorithmJob(PrimitiveJob):
"""
This class is introduced for typing purposes and provides no
additional function beyond that inherited from its parents.

Update: :meth:`AlgorithmJob.submit()` method added. See its
documentation for more info.
"""

def submit(self) -> None:
"""
Submit the job for execution.

For V1 primitives, Qiskit ``PrimitiveJob`` subclassed JobV1 and defined ``submit()``.
``PrimitiveJob`` was updated for V2 primitives, no longer subclasses ``JobV1``, and
now has a private ``_submit()`` method, with ``submit()`` being deprecated as of
Qiskit version 0.46. This maintains the ``submit()`` for ``AlgorithmJob`` here as
it's called in many places for such a job. An alternative could be to make
0.46 the required minimum version and alter all algorithm's call sites to use
``_submit()`` and make this an empty class again as it once was. For now this
way maintains compatibility with the current min version of 0.44.
"""
# TODO: Considering changing this in the future - see above docstring.
try:
super()._submit()
except AttributeError:
super().submit()
pass
62 changes: 38 additions & 24 deletions qiskit_algorithms/amplitude_amplifiers/grover.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2018, 2023.
# (C) Copyright IBM 2018, 2025.
#
# 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
Expand All @@ -18,16 +18,14 @@
from typing import Any

import numpy as np

from qiskit import ClassicalRegister, QuantumCircuit
from qiskit.primitives import BaseSampler
from qiskit.quantum_info import Statevector
from qiskit.primitives import BaseSamplerV2

from qiskit_algorithms.exceptions import AlgorithmError
from qiskit_algorithms.utils import algorithm_globals

from .amplification_problem import AmplificationProblem
from .amplitude_amplifier import AmplitudeAmplifier, AmplitudeAmplifierResult
from ..custom_types import Transpiler


class Grover(AmplitudeAmplifier):
Expand Down Expand Up @@ -116,7 +114,10 @@ def __init__(
iterations: list[int] | Iterator[int] | int | None = None,
growth_rate: float | None = None,
sample_from_iterations: bool = False,
sampler: BaseSampler | None = None,
sampler: BaseSamplerV2 | None = None,
*,
transpiler: Transpiler | None = None,
transpiler_options: dict[str, Any] | None = None,
) -> None:
r"""
Args:
Expand All @@ -136,6 +137,11 @@ def __init__(
powers of the Grover operator, a random integer sample between 0 and smaller value
than the iteration is used as a power, see [1], Section 4.
sampler: A Sampler to use for sampling the results of the circuits.
transpiler: An optional object with a `run` method allowing to transpile the circuits
that are produced within this algorithm. If set to `None`, these won't be
transpiled.
transpiler_options: A dictionary of options to be passed to the transpiler's `run`
method as keyword arguments.

Raises:
ValueError: If ``growth_rate`` is a float but not larger than 1.
Expand Down Expand Up @@ -165,9 +171,11 @@ def __init__(
self._sampler = sampler
self._sample_from_iterations = sample_from_iterations
self._iterations_arg = iterations
self._transpiler = transpiler
self._transpiler_options = transpiler_options if transpiler_options is not None else {}

@property
def sampler(self) -> BaseSampler | None:
def sampler(self) -> BaseSamplerV2 | None:
"""Get the sampler.

Returns:
Expand All @@ -176,7 +184,7 @@ def sampler(self) -> BaseSampler | None:
return self._sampler

@sampler.setter
def sampler(self, sampler: BaseSampler) -> None:
def sampler(self, sampler: BaseSamplerV2) -> None:
"""Set the sampler.

Args:
Expand Down Expand Up @@ -234,23 +242,29 @@ def amplify(self, amplification_problem: AmplificationProblem) -> "GroverResult"
# sample from [0, power) if specified
if self._sample_from_iterations:
power = algorithm_globals.random.integers(power)

# Run a grover experiment for a given power of the Grover operator.
if self._sampler is not None:
qc = self.construct_circuit(amplification_problem, power, measurement=True)
job = self._sampler.run([qc])

try:
results = job.result()
except Exception as exc:
raise AlgorithmError("Sampler job failed.") from exc

num_bits = len(amplification_problem.objective_qubits)
circuit_results: dict[str, Any] | Statevector | np.ndarray = {
np.binary_repr(k, num_bits): v for k, v in results.quasi_dists[0].items()
}
top_measurement, max_probability = max(
circuit_results.items(), key=lambda x: x[1] # type: ignore[union-attr]
)
qc = self.construct_circuit(amplification_problem, power, measurement=True)

if self._transpiler is not None:
qc = self._transpiler.run(qc, **self._transpiler_options)

job = self._sampler.run([qc])

try:
results = job.result()
except Exception as exc:
raise AlgorithmError("Sampler job failed.") from exc

circuit_results = getattr(results[0].data, qc.cregs[0].name)
circuit_results = {
label: value / circuit_results.num_shots
for label, value in circuit_results.get_counts().items()
}

top_measurement, max_probability = max(
circuit_results.items(), key=lambda x: x[1] # type: ignore[union-attr]
)

all_circuit_results.append(circuit_results)

Expand Down
66 changes: 37 additions & 29 deletions qiskit_algorithms/amplitude_estimators/ae.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# This code is part of a Qiskit project.
#
# (C) Copyright IBM 2018, 2023.
# (C) Copyright IBM 2018, 2025.
#
# 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
Expand All @@ -13,17 +13,21 @@
"""The Quantum Phase Estimation-based Amplitude Estimation algorithm."""

from __future__ import annotations
from collections import OrderedDict

import warnings
from collections import OrderedDict
from typing import Any

import numpy as np
from scipy.stats import chi2, norm
from qiskit import QuantumCircuit, ClassicalRegister
from qiskit.primitives import BaseSamplerV2, StatevectorSampler
from scipy.optimize import bisect
from scipy.stats import chi2, norm

from qiskit import QuantumCircuit, ClassicalRegister
from qiskit.primitives import BaseSampler, Sampler
from .amplitude_estimator import AmplitudeEstimator, AmplitudeEstimatorResult
from .ae_utils import pdf_a, derivative_log_pdf_a, bisect_max
from .amplitude_estimator import AmplitudeEstimator, AmplitudeEstimatorResult
from .estimation_problem import EstimationProblem
from ..custom_types import Transpiler
from ..exceptions import AlgorithmError


Expand Down Expand Up @@ -66,7 +70,10 @@ def __init__(
num_eval_qubits: int,
phase_estimation_circuit: QuantumCircuit | None = None,
iqft: QuantumCircuit | None = None,
sampler: BaseSampler | None = None,
sampler: BaseSamplerV2 | None = None,
*,
transpiler: Transpiler | None = None,
transpiler_options: dict[str, Any] | None = None,
) -> None:
r"""
Args:
Expand All @@ -77,6 +84,10 @@ def __init__(
iqft: The inverse quantum Fourier transform component, defaults to using a standard
implementation from `qiskit.circuit.library.QFT` when None.
sampler: A sampler primitive to evaluate the circuits.
transpiler: An optional object with a `run` method allowing to transpile the circuits
that are produced within this algorithm. If set to `None`, these won't be transpiled.
transpiler_options: A dictionary of options to be passed to the transpiler's `run`
method as keyword arguments.

Raises:
ValueError: If the number of evaluation qubits is smaller than 1.
Expand All @@ -94,8 +105,11 @@ def __init__(
self._pec = phase_estimation_circuit
self._sampler = sampler

self._transpiler = transpiler
self._transpiler_options = transpiler_options

@property
def sampler(self) -> BaseSampler | None:
def sampler(self) -> BaseSamplerV2 | None:
"""Get the sampler primitive.

Returns:
Expand All @@ -104,7 +118,7 @@ def sampler(self) -> BaseSampler | None:
return self._sampler

@sampler.setter
def sampler(self, sampler: BaseSampler) -> None:
def sampler(self, sampler: BaseSamplerV2) -> None:
"""Set sampler primitive.

Args:
Expand Down Expand Up @@ -149,6 +163,9 @@ def construct_circuit(
circuit.add_register(cr)
circuit.measure(list(range(self._m)), list(range(self._m)))

if self._transpiler is not None:
circuit = self._transpiler.run(circuit, **self._transpiler_options)

return circuit

def evaluate_measurements(
Expand Down Expand Up @@ -288,8 +305,10 @@ def estimate(self, estimation_problem: EstimationProblem) -> "AmplitudeEstimatio
"The state_preparation property of the estimation problem must be set."
)
if self._sampler is None:
warnings.warn("No sampler provided, defaulting to Sampler from qiskit.primitives")
self._sampler = Sampler()
warnings.warn(
"No sampler provided, defaulting to StatevectorSampler from qiskit.primitives"
)
self._sampler = StatevectorSampler()

if estimation_problem.objective_qubits is None:
raise ValueError("The objective_qubits property of the estimation problem must be set.")
Expand All @@ -307,23 +326,17 @@ def estimate(self, estimation_problem: EstimationProblem) -> "AmplitudeEstimatio
result.post_processing = estimation_problem.post_processing # type: ignore[assignment]

circuit = self.construct_circuit(estimation_problem, measurement=True)

try:
job = self._sampler.run([circuit])
ret = job.result()
job = self._sampler.run([(circuit,)])
ret = job.result()[0]
except Exception as exc:
raise AlgorithmError("The job was not completed successfully. ") from exc

shots = ret.metadata[0].get("shots")
exact = True
circuit_results = getattr(ret.data, next(iter(ret.data.keys())))
shots = ret.metadata["shots"]

if shots is None:
result.circuit_results = ret.quasi_dists[0].binary_probabilities()
shots = 1
else:
result.circuit_results = {
k: round(v * shots) for k, v in ret.quasi_dists[0].binary_probabilities().items()
}
exact = False
result.circuit_results = circuit_results.get_counts()

# store shots
result.shots = shots
Expand Down Expand Up @@ -356,7 +369,7 @@ def estimate(self, estimation_problem: EstimationProblem) -> "AmplitudeEstimatio
mle # type: ignore[assignment,arg-type]
)

result.confidence_interval = self.compute_confidence_interval(result, exact=exact)
result.confidence_interval = self.compute_confidence_interval(result)
result.confidence_interval_processed = tuple(
estimation_problem.post_processing(value) # type: ignore[assignment,arg-type]
for value in result.confidence_interval
Expand All @@ -369,7 +382,6 @@ def compute_confidence_interval(
result: "AmplitudeEstimationResult",
alpha: float = 0.05,
kind: str = "likelihood_ratio",
exact: bool = False,
) -> tuple[float, float]:
"""Compute the (1 - alpha) confidence interval.

Expand All @@ -378,17 +390,13 @@ def compute_confidence_interval(
alpha: Confidence level: compute the (1 - alpha) confidence interval.
kind: The method to compute the confidence interval, can be 'fisher', 'observed_fisher'
or 'likelihood_ratio' (default)
exact: Whether the result comes from a statevector simulation or not

Returns:
The (1 - alpha) confidence interval of the specified kind.

Raises:
NotImplementedError: If the confidence interval method `kind` is not implemented.
"""
# if statevector simulator the estimate is exact
if exact:
return (result.mle, result.mle)

if kind in ["likelihood_ratio", "lr"]:
return _likelihood_ratio_confint(result, alpha)
Expand Down
Loading
Loading