Skip to content

Commit aa7179c

Browse files
tnemozwoodsp-ibm
andauthored
Replaced deprecated Qiskit classes by their respective replacement functions (#237)
Co-authored-by: Steve Wood <40241007+woodsp-ibm@users.noreply.github.com>
1 parent d84bd40 commit aa7179c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+643
-276
lines changed

docs/tutorials/01_algorithms_introduction.ipynb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"\n",
2020
"Algorithms are configurable, and part of the configuration will often be in the form of smaller building blocks. For instance `VQE`, the Variational Quantum Eigensolver, it takes a trial wavefunction, in the form of a `QuantumCircuit` and a classical optimizer among other things.\n",
2121
"\n",
22-
"Let's take a look at an example to construct a VQE instance. Here, `TwoLocal` is the variational form (trial wavefunction), a parameterized circuit which can be varied, and `SLSQP` a classical optimizer. These are created as separate instances and passed to VQE when it is constructed. Trying, for example, a different classical optimizer, or variational form is simply a case of creating an instance of the one you want and passing it into VQE."
22+
"Let's take a look at an example to construct a VQE instance. Here, `n_local` is the variational form (trial wavefunction), a parameterized circuit which can be varied, and `SLSQP` a classical optimizer. These are created as separate instances and passed to VQE when it is constructed. Trying, for example, a different classical optimizer, or variational form is simply a case of creating an instance of the one you want and passing it into VQE."
2323
]
2424
},
2525
{

docs/tutorials/02_vqe_advanced_options.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@
8181
"cell_type": "markdown",
8282
"metadata": {},
8383
"source": [
84-
"You are now ready to compare a set of optimizers through the `VQE` callback. The minimum energy of the H2 Hamiltonian can be found quite easily, so the maximum number of iterations (`maxiter`) does not have to be very large. You can once again use `TwoLocal` as the selected trial wavefunction (i.e. ansatz)."
84+
"You are now ready to compare a set of optimizers through the `VQE` callback. The minimum energy of the H2 Hamiltonian can be found quite easily, so the maximum number of iterations (`maxiter`) does not have to be very large. You can once again use `n_local` as the selected trial wavefunction (i.e. ansatz)."
8585
]
8686
},
8787
{
@@ -528,7 +528,7 @@
528528
"name": "python",
529529
"nbconvert_exporter": "python",
530530
"pygments_lexer": "ipython3",
531-
"version": "3.13.3"
531+
"version": "3.13.5"
532532
}
533533
},
534534
"nbformat": 4,

docs/tutorials/05_qaoa.ipynb

Lines changed: 4 additions & 4 deletions
Large diffs are not rendered by default.

docs/tutorials/06_grover.ipynb

Lines changed: 16 additions & 16 deletions
Large diffs are not rendered by default.

docs/tutorials/07_grover_examples.ipynb

Lines changed: 13 additions & 11 deletions
Large diffs are not rendered by default.

docs/tutorials/11_VarQTE.ipynb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@
9898
"source": [
9999
"## Imaginary Time Evolution\n",
100100
"\n",
101-
"Imaginary time evolution can be used, for example, to find the ground state or calculate the finite temperature expectation value of the system. Here, we will use the `VarQITE` class from `time_evolvers.variational` to compute a ground state energy. Firstly, we need to choose an ansatz. We can use `EfficientSU2` to easily construct an ansatz, setting the number of repetitions using `reps`."
101+
"Imaginary time evolution can be used, for example, to find the ground state or calculate the finite temperature expectation value of the system. Here, we will use the `VarQITE` class from `time_evolvers.variational` to compute a ground state energy. Firstly, we need to choose an ansatz. We can use `efficient_su2` to easily construct an ansatz, setting the number of repetitions using `reps`."
102102
]
103103
},
104104
{
@@ -948,7 +948,7 @@
948948
"name": "python",
949949
"nbconvert_exporter": "python",
950950
"pygments_lexer": "ipython3",
951-
"version": "3.13.3"
951+
"version": "3.13.5"
952952
}
953953
},
954954
"nbformat": 4,

qiskit_algorithms/amplitude_amplifiers/amplification_problem.py

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This code is part of a Qiskit project.
22
#
3-
# (C) Copyright IBM 2021, 2024.
3+
# (C) Copyright IBM 2021, 2025.
44
#
55
# This code is licensed under the Apache License, Version 2.0. You may
66
# obtain a copy of this license in the LICENSE.txt file in the root directory
@@ -16,7 +16,7 @@
1616
from collections.abc import Callable
1717
from typing import Any, List, cast
1818

19-
from qiskit.circuit import QuantumCircuit
19+
from qiskit.circuit import QuantumCircuit, Gate
2020
from qiskit.circuit.library import GroverOperator
2121
from qiskit.quantum_info import Statevector
2222

@@ -32,7 +32,7 @@ class AmplificationProblem:
3232
# pylint: disable=too-many-positional-arguments
3333
def __init__(
3434
self,
35-
oracle: QuantumCircuit | Statevector,
35+
oracle: QuantumCircuit | Gate | Statevector,
3636
state_preparation: QuantumCircuit | None = None,
3737
grover_operator: QuantumCircuit | None = None,
3838
post_processing: Callable[[str], Any] | None = None,
@@ -41,7 +41,9 @@ def __init__(
4141
) -> None:
4242
r"""
4343
Args:
44-
oracle: The oracle reflecting about the bad states.
44+
oracle: The oracle reflecting about the bad states. If a
45+
:class:`~qiskit.circuit.library.Gate` is passed, it will be converted to a
46+
:class:`~qiskit.circuit.QuantumCircuit`.
4547
state_preparation: A circuit preparing the input state, referred to as
4648
:math:`\mathcal{A}`. If None, a layer of Hadamard gates is used.
4749
grover_operator: The Grover operator :math:`\mathcal{Q}` used as unitary in the
@@ -52,19 +54,26 @@ def __init__(
5254
If None, all qubits will be measured. The ``is_good_state`` function will be
5355
applied on the measurement outcome of these qubits.
5456
is_good_state: A function to check whether a string represents a good state. By default
55-
if the ``oracle`` argument has an ``evaluate_bitstring`` method (currently only
56-
provided by the :class:`~qiskit.circuit.library.PhaseOracle` class) this will be
57-
used, otherwise this kwarg is required and **must** be specified.
57+
if the ``oracle`` argument has a ``boolean_expression`` attribute (currently only
58+
provided by the :class:`~qiskit.circuit.library.PhaseOracle` and
59+
:class:`~qiskit.circuit.library.PhaseOracleGate` classes) this will be
60+
used for the check, otherwise this kwarg is required and **must** be specified.
5861
"""
59-
self._oracle = oracle
62+
if isinstance(oracle, Gate):
63+
self._oracle = QuantumCircuit(oracle.num_qubits).compose(oracle)
64+
else:
65+
self._oracle = oracle
66+
6067
self._state_preparation = state_preparation
6168
self._grover_operator = grover_operator
6269
self._post_processing = post_processing
6370
self._objective_qubits = objective_qubits
6471
if is_good_state is not None:
6572
self._is_good_state = is_good_state
66-
elif hasattr(oracle, "evaluate_bitstring"):
67-
self._is_good_state = oracle.evaluate_bitstring
73+
elif hasattr(oracle, "boolean_expression"):
74+
self._is_good_state = lambda bitstring: oracle.boolean_expression.simulate(
75+
bitstring[::-1]
76+
)
6877
else:
6978
self._is_good_state = None
7079

qiskit_algorithms/eigensolvers/vqd.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
from __future__ import annotations
1919

2020
import logging
21+
import warnings
2122
from collections.abc import Callable, Sequence, Iterable
2223
from time import time
2324
from typing import Any, cast
@@ -213,6 +214,18 @@ def _check_operator_ansatz(self, operator: BaseOperator):
213214
# try to set the number of qubits on the ansatz, if possible
214215
try:
215216
self.ansatz.num_qubits = operator.num_qubits
217+
warnings.warn(
218+
"Previously, it was possible to pass to VQD a BlueprintCircuit as an "
219+
"ansatz without its number of qubits being set, the algorithm taking care "
220+
"of setting it. Since BlueprintCircuits are now deprecated, and those "
221+
"being the only ones that can have their number of qubits set after their "
222+
"initialization, this behavior is now also deprecated, and won't be "
223+
"supported once the oldest supported Qiskit version is 3.0. As such, users "
224+
"that made use of this feature would now need to ensure that the ansatz "
225+
"they pass to these algorithms have their number of qubits set and matching "
226+
"with that of the operator they wish to run the algorithm on.",
227+
category=DeprecationWarning,
228+
)
216229
except AttributeError as exc:
217230
raise AlgorithmError(
218231
"The number of qubits of the ansatz does not match the "

qiskit_algorithms/minimum_eigensolvers/adapt_vqe.py

Lines changed: 120 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,14 @@
1515

1616
import logging
1717
import re
18+
import warnings
19+
from collections.abc import Sequence
1820
from enum import Enum
1921
from typing import Iterable
2022

2123
import numpy as np
22-
from qiskit.circuit.library import EvolvedOperatorAnsatz
24+
from qiskit import QuantumCircuit
25+
from qiskit.circuit.library import EvolvedOperatorAnsatz, evolved_operator_ansatz
2326
from qiskit.quantum_info import SparsePauliOp
2427
from qiskit.quantum_info.operators.base_operator import BaseOperator
2528
from qiskit.version import get_version_info as get_qiskit_version_info
@@ -62,6 +65,7 @@ class AdaptVQE(VariationalAlgorithm, MinimumEigensolver):
6265
from qiskit_algorithms.optimizers import SLSQP
6366
from qiskit.primitives import StatevectorEstimator
6467
from qiskit.circuit.library import EvolvedOperatorAnsatz
68+
from qiskit import QuantumCircuit
6569
6670
# get your Hamiltonian
6771
hamiltonian = ...
@@ -73,6 +77,11 @@ class AdaptVQE(VariationalAlgorithm, MinimumEigensolver):
7377
7478
adapt_vqe = AdaptVQE(vqe)
7579
80+
# or you can do it without EvolvedOperatorAnsatz
81+
vqe = VQE(StatevectorEstimator(), QuantumCircuit(1), SLSQP())
82+
83+
adapt_vqe = AdaptVQE(vqe, operators=...)
84+
7685
eigenvalue, _ = adapt_vqe.compute_minimum_eigenvalue(hamiltonian)
7786
7887
The following attributes can be set via the initializer but can also be read and updated once
@@ -81,7 +90,8 @@ class AdaptVQE(VariationalAlgorithm, MinimumEigensolver):
8190
Attributes:
8291
solver: a :class:`~.VQE` instance used internally to compute the minimum eigenvalues.
8392
It is a requirement that the :attr:`~.VQE.ansatz` of this solver is of type
84-
:class:`~qiskit.circuit.library.EvolvedOperatorAnsatz`.
93+
:class:`~qiskit.circuit.library.EvolvedOperatorAnsatz` if the `operators` arguments is
94+
not set.
8595
gradient_threshold: once all gradients have an absolute value smaller than this threshold,
8696
the algorithm has converged and terminates.
8797
eigenvalue_threshold: once the eigenvalue has changed by less than this threshold from one
@@ -100,12 +110,25 @@ def __init__(
100110
gradient_threshold: float = 1e-5,
101111
eigenvalue_threshold: float = 1e-5,
102112
max_iterations: int | None = None,
113+
operators: BaseOperator | Sequence[BaseOperator] | None = None,
114+
reps: int = 1,
115+
evolution=None,
116+
insert_barriers: bool = False,
117+
name: str = "EvolvedOps",
118+
parameter_prefix: str | Sequence[str] = "t",
119+
remove_identities: bool = True,
120+
initial_state: QuantumCircuit | None = None,
121+
flatten: bool | None = None,
103122
) -> None:
104123
"""
105124
Args:
106125
solver: a :class:`~.VQE` instance used internally to compute the minimum eigenvalues.
107-
It is a requirement that the :attr:`~.VQE.ansatz` of this solver is of type
108-
:class:`~qiskit.circuit.library.EvolvedOperatorAnsatz`.
126+
It is a requirement that either the :attr:`~.VQE.ansatz` of this solver is of type
127+
:class:`~qiskit.circuit.library.EvolvedOperatorAnsatz` or that the `operators`
128+
argument is specified. The former is deprecated from the 0.4 version of
129+
qiskit-algorithms and this option won't be possible anymore once the oldest
130+
supported Qiskit version is 3.0. In the latter case, this class will build its own
131+
ansatz using the evolved_operator_ansatz function.
109132
gradient_threshold: once all gradients have an absolute value smaller than this
110133
threshold, the algorithm has converged and terminates. Defaults to ``1e-5``.
111134
eigenvalue_threshold: once the eigenvalue has changed by less than this threshold from
@@ -115,18 +138,75 @@ def __init__(
115138
are not considered.
116139
max_iterations: the maximum number of iterations for the adaptive loop. If ``None``, the
117140
algorithm is not bound in its number of iterations.
141+
operators: used to build the ansatz using the
142+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function. If set, the
143+
ansatz of the underlying :class:`.VQE` solver won't be used.
144+
reps: used to build the ansatz using the
145+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
146+
evolution: used to build the ansatz using the
147+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
148+
insert_barriers: used to build the ansatz using the
149+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
150+
name: used to build the ansatz using the
151+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
152+
parameter_prefix: used to build the ansatz using the
153+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
154+
remove_identities: used to build the ansatz using the
155+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
156+
initial_state: a :class:`~qiskit.circuit.QuantumCircuit` object to prepend to the
157+
ansatz.
158+
flatten: used to build the ansatz using the
159+
:func:`~qiskit.circuit.library.evolved_operator_ansatz` function.
118160
"""
119161
validate_min("gradient_threshold", gradient_threshold, 1e-15)
120162
validate_min("eigenvalue_threshold", eigenvalue_threshold, 1e-15)
121163

122164
self.solver = solver
165+
166+
if (
167+
not isinstance(self.solver._original_ansatz, EvolvedOperatorAnsatz)
168+
and operators is None
169+
):
170+
raise TypeError(
171+
"The AdaptVQE ansatz must be of the EvolvedOperatorAnsatz type or the operators "
172+
"argument must be set."
173+
)
174+
if operators is not None:
175+
if not isinstance(operators, list):
176+
operators = list(operators)
177+
178+
self._excitation_pool: list[BaseOperator] = operators
179+
self._initial_state = (
180+
initial_state
181+
if initial_state is not None
182+
else QuantumCircuit(operators[0].num_qubits)
183+
)
184+
else:
185+
warnings.warn(
186+
"The :class:`~qiskit.circuit.library.EvolvedOperatorAnsatz` is deprecated "
187+
"as of Qiskit 2.1 and will be removed in Qiskit 3.0. Use the keywords arguments of"
188+
"the AdaptVQE's constructor to specify the ansatz instead. Passing the ansatz via the "
189+
"underlying :class:`.VQE` solver is deprecated as of qiskit-algorithms 0.4 and "
190+
"won't be supported anymore one the oldest supported Qiskit version is 3.0.",
191+
category=DeprecationWarning,
192+
)
193+
self._excitation_pool = self.solver._original_ansatz.operators
194+
123195
self.gradient_threshold = gradient_threshold
124196
self.eigenvalue_threshold = eigenvalue_threshold
125197
self.max_iterations = max_iterations
126198
self._tmp_ansatz: EvolvedOperatorAnsatz | None = None
127-
self._excitation_pool: list[BaseOperator] = []
128199
self._excitation_list: list[BaseOperator] = []
129200

201+
self._operators = operators
202+
self._reps = reps
203+
self._evolution = evolution
204+
self._insert_barriers = insert_barriers
205+
self._name = name
206+
self._parameter_prefix = parameter_prefix
207+
self._remove_identities = remove_identities
208+
self._flatten = flatten
209+
130210
@property
131211
def initial_point(self) -> np.ndarray | None:
132212
"""Returns the initial point of the internal :class:`~.VQE` solver."""
@@ -198,6 +278,21 @@ def _check_cyclicity(indices: list[int]) -> bool:
198278
# nature of the algorithm.
199279
return match is not None or (len(indices) > 1 and indices[-2] == indices[-1])
200280

281+
def _build_ansatz(self) -> QuantumCircuit:
282+
"""Builds the ansatz out of the provided parameters."""
283+
return self._initial_state.compose(
284+
evolved_operator_ansatz(
285+
operators=self._operators,
286+
reps=self._reps,
287+
evolution=self._evolution,
288+
insert_barriers=self._insert_barriers,
289+
name=self._name,
290+
parameter_prefix=self._parameter_prefix,
291+
remove_identities=self._remove_identities,
292+
flatten=self._flatten,
293+
)
294+
)
295+
201296
def compute_minimum_eigenvalue(
202297
self,
203298
operator: BaseOperator,
@@ -219,14 +314,12 @@ def compute_minimum_eigenvalue(
219314
includes runtime information about the AdaptVQE algorithm like the number of iterations,
220315
termination criterion, and the final maximum gradient.
221316
"""
222-
if not isinstance(self.solver._original_ansatz, EvolvedOperatorAnsatz):
223-
raise TypeError("The AdaptVQE ansatz must be of the EvolvedOperatorAnsatz type.")
224-
225317
# Overwrite the solver's ansatz with the initial state
226-
self._tmp_ansatz = self.solver._original_ansatz
227-
self._excitation_pool = self._tmp_ansatz.operators
228-
# This will transpile the initial state if the solver has a transpiler that is set
229-
self.solver.ansatz = self._tmp_ansatz.initial_state
318+
if self._operators is not None:
319+
self.solver.ansatz = self._initial_state
320+
elif isinstance(self.solver._original_ansatz, EvolvedOperatorAnsatz):
321+
self._tmp_ansatz = self.solver._original_ansatz
322+
self.solver.ansatz = self._tmp_ansatz.initial_state
230323

231324
prev_op_indices: list[int] = []
232325
raw_vqe_result: VQEResult | None = None
@@ -284,8 +377,13 @@ def compute_minimum_eigenvalue(
284377
self._excitation_list.append(self._excitation_pool[max_grad_index])
285378
theta.append(0.0)
286379
# setting up the ansatz for the VQE iteration
287-
self._tmp_ansatz.operators = self._excitation_list
288-
self.solver.ansatz = self._tmp_ansatz
380+
if self._operators is not None:
381+
self._operators = self._excitation_list
382+
self.solver.ansatz = self._build_ansatz()
383+
else:
384+
self._tmp_ansatz.operators = self._excitation_list
385+
self.solver.ansatz = self._tmp_ansatz
386+
289387
self.solver.initial_point = np.asarray(theta)
290388
# evaluating the eigenvalue with the internal VQE
291389
prev_raw_vqe_result = raw_vqe_result
@@ -306,8 +404,13 @@ def compute_minimum_eigenvalue(
306404
)
307405
self._excitation_list.pop()
308406
theta.pop()
309-
self._tmp_ansatz.operators = self._excitation_list
310-
self.solver.ansatz = self._tmp_ansatz
407+
if self._operators is not None:
408+
self._operators = self._excitation_list
409+
self.solver.ansatz = self._build_ansatz()
410+
else:
411+
self._tmp_ansatz.operators = self._excitation_list
412+
self.solver.ansatz = self._tmp_ansatz
413+
311414
self.solver.initial_point = np.asarray(theta)
312415
raw_vqe_result = prev_raw_vqe_result
313416
break
@@ -354,7 +457,7 @@ def compute_minimum_eigenvalue(
354457
result.aux_operators_evaluated = aux_values # type: ignore[assignment]
355458

356459
logger.info("The final eigenvalue is: %s", str(result.eigenvalue))
357-
self.solver.ansatz.operators = self._excitation_pool
460+
358461
return result
359462

360463

0 commit comments

Comments
 (0)