853 lines
36 KiB
Plaintext
853 lines
36 KiB
Plaintext
---
|
|
title: qiskit.algorithms migration guide
|
|
description: How to update your code to use the new interface for `qiskit.algorithms`.
|
|
---
|
|
|
|
# Algorithms migration guide
|
|
|
|
<Admonition type="caution">
|
|
**Deprecation Notice**
|
|
|
|
This guide precedes the introduction of the V2 primitives interface. Following the introduction of the V2 primitives, some providers have deprecated V1 primitive
|
|
implementations in favor of the V2 alternatives. If you are interested in following this guide, we recommend combining it with the
|
|
[Migrate to V2 primitives](./v2-primitives) guide to bring your code to the most updated state.
|
|
</Admonition>
|
|
|
|
In Qiskit 0.44 and later releases, the `qiskit.algorithms` module has been superseded by a new standalone library, `qiskit_algorithms`,
|
|
available on [GitHub](https://github.com/qiskit-community/qiskit-algorithms) and
|
|
[PyPi](https://pypi.org/project/qiskit-algorithms). The `qiskit.algorithms` module was migrated to a
|
|
separate package in order to clarify the purpose of Qiskit and make a distinction between the tools and libraries built on top of it.
|
|
|
|
If your code used `qiskit.algorithms`, follow these steps:
|
|
1. Check your code for any uses of the `qiskit.algorithms` module. If you are, follow this guide to
|
|
migrate to the primitives-based implementation.
|
|
2. After updating your code, run `pip install qiskit-algorithms` and update your imports from
|
|
`qiskit.algorithms` to `qiskit_algorithms`.
|
|
|
|
|
|
|
|
## Background
|
|
|
|
The [`qiskit.algorithms`](/api/qiskit/0.46/algorithms) module was originally built on top of the [`qiskit.opflow`](/api/qiskit/0.46/opflow) library and the
|
|
[`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance) utility. The development of the [`qiskit.primitives`](/api/qiskit/primitives)
|
|
introduced a higher-level execution paradigm, with the Estimator for computing expectation values for observables, and Sampler for executing circuits and returning probability distributions. These tools allowed the [`qiskit.algorithms`](/api/qiskit/0.46/algorithms) module to be refactored, after which,
|
|
[`qiskit.opflow`](/api/qiskit/0.46/opflow) and [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance) were deprecated.
|
|
|
|
<Admonition type="caution">
|
|
The transition away from [`qiskit.opflow`](/api/qiskit/0.46/opflow) affects the classes that algorithms use as part of the problem
|
|
setup. Most [`qiskit.opflow`](/api/qiskit/0.46/opflow) dependencies have a direct [`qiskit.quantum_info`](/api/qiskit/quantum_info)
|
|
replacement. One common example is the class [`qiskit.opflow.primitive_ops.PauliSumOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliSumOp), used to define Hamiltonians
|
|
(for example, to plug into VQE), which can be replaced by [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp).
|
|
For information to migrate other [`qiskit.opflow`](/api/qiskit/0.46/opflow) objects, refer to the [Opflow migration guide](./qiskit-opflow-module).
|
|
</Admonition>
|
|
|
|
For further background and detailed migration steps, see these guides:
|
|
|
|
- [Opflow migration guide](./qiskit-opflow-module)
|
|
- [QuantumInstance migration guide](./qiskit-quantum-instance)
|
|
|
|
## What has changed
|
|
|
|
The [`qiskit.algorithms`](/api/qiskit/0.46/algorithms) module has been fully refactored to use the [`qiskit.primitives`](/api/qiskit/primitives), for circuit execution, instead of the [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), which is now deprecated.
|
|
|
|
There have been three types of refactoring:
|
|
|
|
1. Algorithms that were refactored in a new location to support [`qiskit.primitives`](/api/qiskit/primitives). These algorithms have the same
|
|
class names as the [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance)-based ones but are in a new subpackage.
|
|
|
|
<Admonition type="caution">
|
|
Be careful with import paths. The legacy algorithms can still be imported from
|
|
[`qiskit.algorithms`](/api/qiskit/0.46/algorithms). Until the legacy imports are removed, this convenience import is not available
|
|
for the refactored algorithms. Thus, to import the refactored algorithms you must specify the full import path. For example, `from qiskit.algorithms.eigensolvers import VQD`.
|
|
</Admonition>
|
|
|
|
- [Minimum Eigensolvers](#minimum-eigensolvers)
|
|
- [Eigensolvers](#eigensolvers)
|
|
- [Time Evolvers](#time-evolvers)
|
|
|
|
2. Algorithms that were refactored in-place (same namespace) to support both [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance) and
|
|
[`qiskit.primitives`](/api/qiskit/primitives). In the future, [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance) will be removed.
|
|
|
|
- [Amplitude Amplifiers](#amplitude-amplifiers)
|
|
- [Amplitude Estimators](#amplitude-estimators)
|
|
- [Phase Estimators](#phase-estimators)
|
|
|
|
3. Algorithms that were deprecated and are now removed entirely from [`qiskit.algorithms`](/api/qiskit/0.46/algorithms). These are algorithms that do not serve
|
|
as building blocks for applications and are only valuable for education, as described in the following tutorials:
|
|
|
|
- [Linear Solvers (HHL)](https://github.com/Qiskit/textbook/blob/main/notebooks/ch-applications/hhl_tutorial.ipynb) ,
|
|
- [Factorizers (Shor)](https://github.com/Qiskit/textbook/blob/main/notebooks/ch-algorithms/shor.ipynb)
|
|
|
|
This migration guide focuses on the algorithms with migration alternatives within
|
|
[`qiskit.algorithms`](/api/qiskit/0.46/algorithms), that is, refactoring types 1 and 2.
|
|
|
|
## How to choose a primitive configuration for your algorithm
|
|
|
|
The classes in
|
|
[`qiskit.algorithms`](/api/qiskit/0.46/algorithms) are initialized with any implementation of [`qiskit.primitives.BaseSampler`](/api/qiskit/0.46/qiskit.primitives.BaseSampler) or [`qiskit.primitives.BaseEstimator`](/api/qiskit/0.46/qiskit.primitives.BaseEstimator).
|
|
|
|
Once you know which primitive you want to use, choose the primitive implementation that meets your needs. For example:
|
|
|
|
* For quick prototyping, use the reference implementations of primitives included in Qiskit: [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) and [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator).
|
|
|
|
* For finer algorithm tuning, use a local simulator such as the primitive implementation in Aer: [`qiskit_aer.primitives.Sampler`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Sampler.html) and [`qiskit_aer.primitives.Estimator`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Estimator.html).
|
|
|
|
* For running on quantum hardware choose from these options:
|
|
|
|
- Access services with native primitive implementations, such as the Qiskit Runtime service, by using [`qiskit_ibm_runtime.Sampler`](/api/qiskit-ibm-runtime/0.26/qiskit_ibm_runtime.Sampler) and [`qiskit_ibm_runtime.Estimator`.](/api/qiskit-ibm-runtime/0.26/qiskit_ibm_runtime.Estimator)
|
|
- Wrap any QPU (quantum processing unti) with `Backend` primitives ([`qiskit.primitives.BackendSampler`](/api/qiskit/qiskit.primitives.BackendSampler) and [`qiskit.primitives.BackendEstimator`](/api/qiskit/qiskit.primitives.BackendEstimator)). These wrappers implement a primitive interface on top of a backend that only supports `backend.run()`.
|
|
|
|
For detailed information and examples, particularly on the use of the `Backend` primitives, refer to
|
|
the [QuantumInstance migration guide](./qiskit-quantum-instance).
|
|
|
|
This guide describes these common configurations for algorithms that determine which primitive import to use:
|
|
|
|
* Running an algorithm with a statevector simulator when you want the ideal outcome without shot noise. For example, using the [`qiskit.opflow`](/api/qiskit/0.46/opflow) legacy
|
|
[`qiskit.opflow.expectations.MatrixExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.MatrixExpectation):
|
|
|
|
- Reference Primitives with default configuration. See [QAOA](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/05_qaoa.ipynb) for an example.
|
|
|
|
```python
|
|
from qiskit.primitives import Sampler, Estimator
|
|
```
|
|
|
|
- Aer Primitives with statevector simulator. See [QAOA](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/05_qaoa.ipynb) for an example.
|
|
|
|
```python
|
|
from qiskit_aer.primitives import Sampler, Estimator
|
|
|
|
sampler = Sampler(backend_options={"method": "statevector"})
|
|
estimator = Estimator(backend_options={"method": "statevector"})
|
|
```
|
|
|
|
* Running an algorithm using a simulator or device with shot noise. For example, using the [`qiskit.opflow`](/api/qiskit/0.46/opflow) legacy [`qiskit.opflow.expectations.PauliExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.PauliExpectation):
|
|
|
|
- Reference primitives with shots. See the [VQE](#vqe) examples.
|
|
|
|
```python
|
|
from qiskit.primitives import Sampler, Estimator
|
|
|
|
sampler = Sampler(options={"shots": 100})
|
|
estimator = Estimator(options={"shots": 100})
|
|
|
|
# or...
|
|
sampler = Sampler()
|
|
job = sampler.run(circuits, shots=100)
|
|
|
|
estimator = Estimator()
|
|
job = estimator.run(circuits, observables, shots=100)
|
|
```
|
|
|
|
- Aer primitives with default configuration. See the [VQE](#vqe) examples.
|
|
|
|
```python
|
|
from qiskit_aer.primitives import Sampler, Estimator
|
|
```
|
|
|
|
- IBM Qiskit Runtime primitives with default configuration. See [VQD](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/04_vqd.ipynb) for an example.
|
|
|
|
```python
|
|
from qiskit_ibm_runtime import Sampler, Estimator
|
|
```
|
|
|
|
* Running an algorithm on an Aer simulator using a custom instruction. For example, using the [`qiskit.opflow`](/api/qiskit/0.46/opflow) legacy
|
|
[`qiskit.opflow.expectations.AerPauliExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.AerPauliExpectation).
|
|
|
|
- Aer Primitives with default options. See [TrotterQRTE](#trotterqrte) for examples.
|
|
|
|
```python
|
|
from qiskit_aer.primitives import Sampler, Estimator
|
|
|
|
sampler = Sampler()
|
|
estimator = Estimator()
|
|
```
|
|
|
|
<span id="eigen"></span>
|
|
## Minimum Eigensolvers
|
|
|
|
The minimum eigensolver algorithms were refactored in a new location.
|
|
Instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), [`qiskit.algorithms.minimum_eigensolvers`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers) are now initialized
|
|
by using an instance of the [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) or [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive, depending
|
|
on the algorithm. The legacy classes can still be found in `qiskit.algorithms.minimum_eigen_solvers`.
|
|
|
|
<Admonition type="caution">
|
|
For the [`qiskit.algorithms.minimum_eigensolvers`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers) classes, depending on the import path,
|
|
you will access either the primitive-based or the quantum-instance-based implementation. You have to be careful, because the class name does not change.
|
|
|
|
- Old import (QuantumInstance-based): `from qiskit.algorithms import VQE, QAOA, NumPyMinimumEigensolver`
|
|
- New import (Primitives-based): `from qiskit.algorithms.minimum_eigensolvers import VQE, SamplingVQE, QAOA, NumPyMinimumEigensolver`
|
|
</Admonition>
|
|
|
|
### VQE
|
|
|
|
The legacy `qiskit.algorithms.minimum_eigen_solvers.VQE` class has now been split according to the use case:
|
|
|
|
- For general-purpose Hamiltonians, use the Estimator-based [`qiskit.algorithms.minimum_eigensolvers.VQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.VQE)
|
|
class.
|
|
- If you have a diagonal Hamiltonian and want the algorithm to return a sampling of the state, use
|
|
the new Sampler-based [`qiskit.algorithms.minimum_eigensolvers.SamplingVQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQE) algorithm. Previously, this was done by using the legacy `qiskit.algorithms.minimum_eigen_solvers.VQE` with
|
|
[`qiskit.opflow.expectations.CVaRExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.CVaRExpectation).
|
|
|
|
<Admonition type="note">
|
|
In addition to taking in an [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) instance instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance),
|
|
the new [`qiskit.algorithms.minimum_eigensolvers.VQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.VQE) signature has undergone the following changes:
|
|
|
|
* The `expectation` and `include_custom` parameters have been removed, as this functionality is now
|
|
defined at the Estimator level.
|
|
* The `gradient` parameter now takes in an instance of a primitive-based gradient class from
|
|
[`qiskit.algorithms.gradients`](/api/qiskit/0.46/qiskit.algorithms.gradients) instead of the legacy [`qiskit.opflow.gradients.Gradient`](/api/qiskit/0.46/qiskit.opflow.gradients.Gradient) class.
|
|
* The `max_evals_grouped` parameter has been removed, as it can be set directly on the optimizer class.
|
|
* The `estimator`, `ansatz` and `optimizer` are the only parameters that can be defined positionally
|
|
(and in this order). All others have become keyword-only arguments.
|
|
</Admonition>
|
|
|
|
<Admonition type="note">
|
|
The new [`qiskit.algorithms.minimum_eigensolvers.VQEResult`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.VQEResult) class does not include the state, as
|
|
this output was only useful in the case of diagonal operators. However, it is available as part of the new
|
|
[`qiskit.algorithms.minimum_eigensolvers.SamplingVQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQE) [`qiskit.algorithms.minimum_eigensolvers.SamplingVQEResult`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQEResult).
|
|
</Admonition>
|
|
|
|
#### VQE examples
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit.algorithms import VQE
|
|
from qiskit.algorithms.optimizers import SPSA
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.opflow import PauliSumOp
|
|
from qiskit.utils import QuantumInstance
|
|
from qiskit_aer import AerSimulator
|
|
|
|
ansatz = TwoLocal(2, 'ry', 'cz')
|
|
opt = SPSA(maxiter=50)
|
|
|
|
# shot-based simulation
|
|
backend = AerSimulator()
|
|
qi = QuantumInstance(backend=backend, shots=2048, seed_simulator=42)
|
|
vqe = VQE(ansatz, optimizer=opt, quantum_instance=qi)
|
|
|
|
hamiltonian = PauliSumOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = vqe.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue)
|
|
```
|
|
|
|
```python
|
|
(-0.9775390625+0j)
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms.minimum_eigensolvers import VQE # new import!!!
|
|
from qiskit.algorithms.optimizers import SPSA
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
from qiskit.primitives import Estimator
|
|
from qiskit_aer.primitives import Estimator as AerEstimator
|
|
|
|
ansatz = TwoLocal(2, 'ry', 'cz')
|
|
opt = SPSA(maxiter=50)
|
|
|
|
# shot-based simulation
|
|
estimator = Estimator(options={"shots": 2048})
|
|
vqe = VQE(estimator, ansatz, opt)
|
|
|
|
# another option
|
|
aer_estimator = AerEstimator(run_options={"shots": 2048, "seed": 42})
|
|
vqe = VQE(aer_estimator, ansatz, opt)
|
|
|
|
hamiltonian = SparsePauliOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = vqe.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue)
|
|
```
|
|
|
|
```python
|
|
-0.986328125
|
|
```
|
|
|
|
#### VQE applying CVaR (SamplingVQE) example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit.algorithms import VQE
|
|
from qiskit.algorithms.optimizers import SLSQP
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.opflow import PauliSumOp, CVaRExpectation
|
|
from qiskit.utils import QuantumInstance
|
|
from qiskit_aer import AerSimulator
|
|
|
|
ansatz = TwoLocal(2, 'ry', 'cz')
|
|
opt = SLSQP(maxiter=50)
|
|
|
|
# shot-based simulation
|
|
backend = AerSimulator()
|
|
qi = QuantumInstance(backend=backend, shots=2048)
|
|
expectation = CVaRExpectation(alpha=0.2)
|
|
vqe = VQE(ansatz, optimizer=opt, expectation=expectation, quantum_instance=qi)
|
|
|
|
# diagonal Hamiltonian
|
|
hamiltonian = PauliSumOp.from_list([("ZZ",1), ("IZ", -0.5), ("II", 0.12)])
|
|
result = vqe.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue.real)
|
|
```
|
|
|
|
```python
|
|
-1.38
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms.minimum_eigensolvers import SamplingVQE # new import!!!
|
|
from qiskit.algorithms.optimizers import SPSA
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
from qiskit.primitives import Sampler
|
|
from qiskit_aer.primitives import Sampler as AerSampler
|
|
|
|
ansatz = TwoLocal(2, 'ry', 'cz')
|
|
opt = SPSA(maxiter=50)
|
|
|
|
# shot-based simulation
|
|
sampler = Sampler(options={"shots": 2048})
|
|
vqe = SamplingVQE(sampler, ansatz, opt, aggregation=0.2)
|
|
|
|
# another option
|
|
aer_sampler = AerSampler(run_options={"shots": 2048, "seed": 42})
|
|
vqe = SamplingVQE(aer_sampler, ansatz, opt, aggregation=0.2)
|
|
|
|
# diagonal Hamiltonian
|
|
hamiltonian = SparsePauliOp.from_list([("ZZ",1), ("IZ", -0.5), ("II", 0.12)])
|
|
result = vqe.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue.real)
|
|
```
|
|
|
|
```python
|
|
-1.38
|
|
```
|
|
|
|
For complete code examples, see the following updated tutorials:
|
|
|
|
- [VQE introduction](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/01_algorithms_introduction.ipynb)
|
|
- [VQE, callback, gradients, initial point](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/02_vqe_advanced_options.ipynb)
|
|
- [VQE with Aer primitives](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/03_vqe_simulation_with_noise.ipynb)
|
|
|
|
### QAOA
|
|
|
|
The new QAOA only supports diagonal operators. This is because the legacy `qiskit.algorithms.minimum_eigen_solvers.QAOA` class extended
|
|
`qiskit.algorithms.minimum_eigen_solvers.VQE`, but now, [`qiskit.algorithms.minimum_eigensolvers.QAOA`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.QAOA)
|
|
extends [`qiskit.algorithms.minimum_eigensolvers.SamplingVQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQE).
|
|
|
|
<Admonition type="note">
|
|
In addition to taking in a [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) instance instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance),
|
|
the new [`qiskit.algorithms.minimum_eigensolvers.QAOA`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.QAOA) signature has undergone the following changes:
|
|
|
|
* The `expectation` and `include_custom` parameters have been removed and the `aggregation`
|
|
parameter has been added. This was previously defined through a custom `expectation` parameter.
|
|
* The `gradient` parameter now takes in an instance of a primitive-based gradient class from
|
|
[`qiskit.algorithms.gradients`](/api/qiskit/0.46/qiskit.algorithms.gradients) instead of the legacy [`qiskit.opflow.gradients.Gradient`](/api/qiskit/0.46/qiskit.opflow.gradients.Gradient) class.
|
|
* The `max_evals_grouped` parameter has been removed, as it can be set directly on the optimizer class.
|
|
* The `sampler` and `optimizer` parameters are the only parameters that can be defined positionally
|
|
(and in this order). All others have become keyword-only arguments.
|
|
</Admonition>
|
|
|
|
<Admonition type="note">
|
|
If you want to run QAOA on a non-diagonal operator, use the [`qiskit.circuit.library.QAOAAnsatz`](/api/qiskit/qiskit.circuit.library.QAOAAnsatz) with
|
|
[`qiskit.algorithms.minimum_eigensolvers.VQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.VQE), but there will be no state result.
|
|
If your application requires the final probability distribution, instantiate `SamplerV2`
|
|
and run it with the optimal circuit after [`qiskit.algorithms.minimum_eigensolvers.VQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.VQE).
|
|
</Admonition>
|
|
|
|
#### QAOA example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
|
|
from qiskit.algorithms import QAOA
|
|
from qiskit.algorithms.optimizers import COBYLA
|
|
from qiskit.opflow import PauliSumOp
|
|
from qiskit.utils import QuantumInstance
|
|
from qiskit_aer import AerSimulator
|
|
|
|
# exact statevector simulation
|
|
backend = AerSimulator()
|
|
qi = QuantumInstance(backend=backend, shots=None,
|
|
seed_simulator = 42, seed_transpiler = 42,
|
|
backend_options={"method": "statevector"})
|
|
|
|
optimizer = COBYLA()
|
|
qaoa = QAOA(optimizer=optimizer, reps=2, quantum_instance=qi)
|
|
|
|
# diagonal operator
|
|
qubit_op = PauliSumOp.from_list([("ZIII", 1),("IZII", 1), ("IIIZ", 1), ("IIZI", 1)])
|
|
result = qaoa.compute_minimum_eigenvalue(qubit_op)
|
|
|
|
print(result.eigenvalue.real)
|
|
```
|
|
|
|
```python
|
|
-4.0
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms.minimum_eigensolvers import QAOA
|
|
from qiskit.algorithms.optimizers import COBYLA
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
from qiskit.primitives import Sampler
|
|
from qiskit_aer.primitives import Sampler as AerSampler
|
|
|
|
# exact statevector simulation
|
|
sampler = Sampler()
|
|
|
|
# another option
|
|
sampler = AerSampler(backend_options={"method": "statevector"},
|
|
run_options={"shots": None, "seed": 42})
|
|
|
|
optimizer = COBYLA()
|
|
qaoa = QAOA(sampler, optimizer, reps=2)
|
|
|
|
# diagonal operator
|
|
qubit_op = SparsePauliOp.from_list([("ZIII", 1),("IZII", 1), ("IIIZ", 1), ("IIZI", 1)])
|
|
result = qaoa.compute_minimum_eigenvalue(qubit_op)
|
|
|
|
print(result.eigenvalue)
|
|
```
|
|
|
|
```python
|
|
-3.999999832366272
|
|
```
|
|
|
|
For complete code examples, see the updated [QAOA tutorial.](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/05_qaoa.ipynb)
|
|
|
|
### NumPyMinimumEigensolver
|
|
|
|
Because this is a classical solver, the workflow has not changed between the old and new implementation.
|
|
However, the import has changed from `qiskit.algorithms.minimum_eigen_solvers.NumPyMinimumEigensolver`
|
|
to [`qiskit.algorithms.minimum_eigensolvers.NumPyMinimumEigensolver`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.NumPyMinimumEigensolver) to conform to the new interfaces
|
|
and result classes.
|
|
|
|
#### NumPyMinimumEigensolver example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
|
|
from qiskit.algorithms import NumPyMinimumEigensolver
|
|
from qiskit.opflow import PauliSumOp
|
|
|
|
solver = NumPyMinimumEigensolver()
|
|
|
|
hamiltonian = PauliSumOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = solver.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue)
|
|
```
|
|
|
|
```python
|
|
-1.4142135623730958
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms.minimum_eigensolvers import NumPyMinimumEigensolver
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
|
|
solver = NumPyMinimumEigensolver()
|
|
|
|
hamiltonian = SparsePauliOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = solver.compute_minimum_eigenvalue(hamiltonian)
|
|
|
|
print(result.eigenvalue)
|
|
```
|
|
|
|
```python
|
|
-1.414213562373095
|
|
```
|
|
|
|
For complete code examples, see the updated [VQE, callback, gradients, initial point tutorial.](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/02_vqe_advanced_options.ipynb)
|
|
|
|
<span id="eigensolvers"></span>
|
|
## Eigensolvers
|
|
|
|
The eigensolver algorithms were refactored in a new location. Instead of using
|
|
[`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), [`qiskit.algorithms.eigensolvers`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers) are now initialized
|
|
using an instance of the [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) or [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive, or
|
|
a primitive-based subroutine, depending on the algorithm. The legacy classes can still be found
|
|
in `qiskit.algorithms.eigen_solvers`.
|
|
|
|
<Admonition type="caution">
|
|
For the [`qiskit.algorithms.eigensolvers`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers) classes, depending on the import path,
|
|
you will access either the primitive-based or the QuantumInstance-based
|
|
implementation. You have to be careful, because the class name is the same.
|
|
|
|
- Old import path (QuantumInstance): `from qiskit.algorithms import VQD, NumPyEigensolver`
|
|
- New import path (primitives): `from qiskit.algorithms.eigensolvers import VQD, NumPyEigensolver`
|
|
</Admonition>
|
|
|
|
### VQD
|
|
|
|
The new [`qiskit.algorithms.eigensolvers.VQD`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.VQD) class is initialized with an instance of the
|
|
[`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance).
|
|
It also takes an instance of a state fidelity class from mod:`qiskit.algorithms.state_fidelities`,
|
|
such as the [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler)-based [`qiskit.algorithms.state_fidelities.ComputeUncompute`](/api/qiskit/0.46/qiskit.algorithms.state_fidelities.ComputeUncompute).
|
|
|
|
<Admonition type="note">
|
|
In addition to taking in a [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) instance instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance),
|
|
the new [`qiskit.algorithms.eigensolvers.VQD`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.VQD) signature has undergone the following changes:
|
|
|
|
* The `expectation` and `include_custom` parameters have been removed, as this functionality is now
|
|
defined at the Estimator level.
|
|
* The custom `fidelity` parameter has been added and the custom `gradient` parameter has
|
|
been removed because current classes in [`qiskit.algorithms.gradients`](/api/qiskit/0.46/qiskit.algorithms.gradients) cannot use state fidelity
|
|
gradients.
|
|
* The `max_evals_grouped` parameter has been removed because it can be set directly on the `optimizer` class.
|
|
* The `estimator`, `fidelity`, `ansatz` and `optimizer` parameters are the only parameters that can be defined positionally
|
|
(and in this order). All others have become keyword-only arguments.
|
|
</Admonition>
|
|
|
|
<Admonition type="note">
|
|
Similar to VQE, the new [`qiskit.algorithms.eigensolvers.VQDResult`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.VQDResult) class does not include
|
|
the state. If your application requires the final probability distribution, instantiate
|
|
`SamplerV2` and run it with the optimal circuit for the desired excited state
|
|
after running [`qiskit.algorithms.eigensolvers.VQD`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.VQD).
|
|
</Admonition>
|
|
|
|
#### VQD Example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit import IBMQ
|
|
from qiskit.algorithms import VQD
|
|
from qiskit.algorithms.optimizers import SLSQP
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.opflow import PauliSumOp
|
|
from qiskit.utils import QuantumInstance
|
|
|
|
ansatz = TwoLocal(3, rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1)
|
|
optimizer = SLSQP(maxiter=10)
|
|
hamiltonian = PauliSumOp.from_list([("XXZ", 1), ("XYI", 1)])
|
|
|
|
# example executing in cloud simulator
|
|
provider = IBMQ.load_account()
|
|
backend = provider.get_backend("ibmq_qasm_simulator")
|
|
qi = QuantumInstance(backend=backend)
|
|
|
|
vqd = VQD(ansatz, k=3, optimizer=optimizer, quantum_instance=qi)
|
|
result = vqd.compute_eigenvalues(operator=hamiltonian)
|
|
|
|
print(result.eigenvalues)
|
|
```
|
|
|
|
```python
|
|
[ 0.01765114+0.0e+00j -0.58507654+0.0e+00j -0.15003642-2.8e-17j]
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit_ibm_runtime import Sampler, Estimator, QiskitRuntimeService, Session
|
|
from qiskit.algorithms.eigensolvers import VQD
|
|
from qiskit.algorithms.optimizers import SLSQP
|
|
from qiskit.algorithms.state_fidelities import ComputeUncompute
|
|
from qiskit.circuit.library import TwoLocal
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
|
|
ansatz = TwoLocal(3, rotation_blocks=["ry", "rz"], entanglement_blocks="cz", reps=1)
|
|
optimizer = SLSQP(maxiter=10)
|
|
hamiltonian = SparsePauliOp.from_list([("XXZ", 1), ("XYI", 1)])
|
|
|
|
# example executing on a QPU
|
|
service = QiskitRuntimeService(channel="ibm_quantum")
|
|
backend = service.backend("ibm_sherbrooke")
|
|
|
|
with Session(backend=backend) as session:
|
|
estimator = Estimator()
|
|
sampler = Sampler()
|
|
fidelity = ComputeUncompute(sampler)
|
|
vqd = VQD(estimator, fidelity, ansatz, optimizer, k=3)
|
|
result = vqd.compute_eigenvalues(operator=hamiltonian)
|
|
|
|
print(result.eigenvalues)
|
|
```
|
|
|
|
```python
|
|
[ 0.01765114+0.0e+00j -0.58507654+0.0e+00j -0.15003642-2.8e-17j]
|
|
```
|
|
|
|
For complete code examples, see the updated [VQD tutorial.](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/04_vqd.ipynb)
|
|
|
|
### NumPyEigensolver
|
|
|
|
Similarly to its minimum eigensolver counterpart, because this is a classical solver, the workflow has not changed
|
|
between the old and new implementation.
|
|
However, the import has changed from `qiskit.algorithms.eigen_solvers.NumPyEigensolver`
|
|
to [`qiskit.algorithms.eigensolvers.NumPyEigensolver`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.NumPyEigensolver) to conform to the new interfaces and result classes.
|
|
|
|
#### NumPyEigensolver Example
|
|
|
|
**[Legacy]:**
|
|
|
|
```python
|
|
|
|
from qiskit.algorithms import NumPyEigensolver
|
|
from qiskit.opflow import PauliSumOp
|
|
|
|
solver = NumPyEigensolver(k=2)
|
|
|
|
hamiltonian = PauliSumOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = solver.compute_eigenvalues(hamiltonian)
|
|
|
|
print(result.eigenvalues)
|
|
```
|
|
|
|
```python
|
|
[-1.41421356 -1.41421356]
|
|
```
|
|
|
|
**[Updated]:**
|
|
|
|
```python
|
|
from qiskit.algorithms.eigensolvers import NumPyEigensolver
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
|
|
solver = NumPyEigensolver(k=2)
|
|
|
|
hamiltonian = SparsePauliOp.from_list([("XX", 1), ("XY", 1)])
|
|
result = solver.compute_eigenvalues(hamiltonian)
|
|
|
|
print(result.eigenvalues)
|
|
```
|
|
|
|
```python
|
|
[-1.41421356 -1.41421356]
|
|
```
|
|
|
|
<span id="time"></span>
|
|
## Time Evolvers
|
|
|
|
The time evolvers were refactored in a new location.
|
|
Instead of using a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), `qiskit.algorithms.time_evolvers` are now initialized
|
|
using a [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive instance. The legacy classes can still be found
|
|
in `qiskit.algorithms.evolvers`.
|
|
|
|
In addition to the migration, the module has been substantially expanded to include Variational Quantum Time Evolution
|
|
(`qiskit.algorithms.time_evolvers.VarQTE`) solvers.
|
|
|
|
### TrotterQRTE
|
|
|
|
<Admonition type="caution">
|
|
For the `TrotterQRTE` class, depending on the import path,
|
|
you will access either the primitive-based or the QuantumInstance-based
|
|
implementation. You have to be careful because the class name did not change.
|
|
|
|
- Old import path (QuantumInstance): `from qiskit.algorithms import TrotterQRTE`
|
|
- New import path (Primitives): `from qiskit.algorithms.time_evolvers import TrotterQRTE`
|
|
</Admonition>
|
|
|
|
<Admonition type="note">
|
|
In addition to taking in a [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) instance instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance),
|
|
the new [`qiskit.algorithms.eigensolvers.VQD`](/api/qiskit/0.46/qiskit.algorithms.eigensolvers.VQD) signature has undergone the following changes:
|
|
|
|
* The `expectation` parameter has been removed, as this functionality is now
|
|
defined at the Estimator level.
|
|
* The `num_timesteps` parameter has been added so you can define how many steps to divide the full evolution time in to.
|
|
</Admonition>
|
|
|
|
#### TrotterQRTE Example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit.algorithms import EvolutionProblem, TrotterQRTE
|
|
from qiskit.circuit import QuantumCircuit
|
|
from qiskit.opflow import PauliSumOp, AerPauliExpectation
|
|
from qiskit.utils import QuantumInstance
|
|
from qiskit_aer import AerSimulator
|
|
|
|
operator = PauliSumOp.from_list([("X", 1),("Z", 1)])
|
|
initial_state = QuantumCircuit(1) # zero
|
|
time = 1
|
|
evolution_problem = EvolutionProblem(operator, 1, initial_state)
|
|
|
|
# Aer simulator using custom instruction
|
|
backend = AerSimulator()
|
|
quantum_instance = QuantumInstance(backend=backend)
|
|
expectation = AerPauliExpectation()
|
|
|
|
# LieTrotter with 1 rep
|
|
trotter_qrte = TrotterQRTE(expectation=expectation, quantum_instance=quantum_instance)
|
|
evolved_state = trotter_qrte.evolve(evolution_problem).evolved_state
|
|
|
|
print(evolved_state)
|
|
```
|
|
|
|
```text
|
|
CircuitStateFn(
|
|
┌─────────────────────┐
|
|
q: ┤ exp(-it (X + Z))(1) ├
|
|
└─────────────────────┘
|
|
)
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms.time_evolvers import TimeEvolutionProblem, TrotterQRTE # note new import!!!
|
|
from qiskit.circuit import QuantumCircuit
|
|
from qiskit.quantum_info import SparsePauliOp
|
|
from qiskit_aer.primitives import Estimator as AerEstimator
|
|
|
|
operator = SparsePauliOp.from_list([("X", 1),("Z", 1)])
|
|
initial_state = QuantumCircuit(1) # zero
|
|
time = 1
|
|
evolution_problem = TimeEvolutionProblem(operator, 1, initial_state)
|
|
|
|
# Aer simulator using custom instruction
|
|
estimator = AerEstimator()
|
|
|
|
# LieTrotter with 1 rep
|
|
trotter_qrte = TrotterQRTE(estimator=estimator)
|
|
evolved_state = trotter_qrte.evolve(evolution_problem).evolved_state
|
|
|
|
print(evolved_state.decompose())
|
|
```
|
|
|
|
```text
|
|
┌───────────┐┌───────────┐
|
|
q: ┤ exp(it X) ├┤ exp(it Z) ├
|
|
└───────────┘└───────────┘
|
|
```
|
|
|
|
<span id="amplitude"></span>
|
|
## Amplitude amplifiers
|
|
|
|
The amplitude amplifier algorithms were refactored in-place.
|
|
Instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), `qiskit.algorithms.amplitude_amplifiers` are now initialized
|
|
using an instance of any Sampler primitive. That is, [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler).
|
|
|
|
<Admonition type="note">
|
|
The full `qiskit.algorithms.amplitude_amplifiers` module has been refactored in place. Therefore, you don't need to
|
|
change import paths.
|
|
</Admonition>
|
|
|
|
### Grover example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
|
|
from qiskit.algorithms import Grover
|
|
from qiskit.utils import QuantumInstance
|
|
|
|
qi = QuantumInstance(backend=backend)
|
|
grover = Grover(quantum_instance=qi)
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms import Grover
|
|
from qiskit.primitives import Sampler
|
|
|
|
grover = Grover(sampler=Sampler())
|
|
```
|
|
|
|
For complete code examples, see the following updated tutorials:
|
|
|
|
- [Amplitude Amplification and Grover](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/06_grover.ipynb)
|
|
- [Grover Examples](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/07_grover_examples.ipynb)
|
|
|
|
<span id="amp-estimate"></span>
|
|
## Amplitude estimators
|
|
|
|
Similarly to the amplitude amplifiers, the amplitude estimators were refactored in-place.
|
|
Instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), `qiskit.algorithms.amplitude_estimators` are now initialized
|
|
using an instance of any Sampler primitive. That is, [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler).
|
|
|
|
<Admonition type="note">
|
|
The full `qiskit.algorithms.amplitude_estimators` module has been refactored in place. You do not need to
|
|
change import paths.
|
|
</Admonition>
|
|
|
|
### IAE example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit.algorithms import IterativeAmplitudeEstimation
|
|
from qiskit.utils import QuantumInstance
|
|
|
|
qi = QuantumInstance(backend=backend)
|
|
iae = IterativeAmplitudeEstimation(
|
|
epsilon_target=0.01, # target accuracy
|
|
alpha=0.05, # width of the confidence interval
|
|
quantum_instance=qi
|
|
)
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms import IterativeAmplitudeEstimation
|
|
from qiskit.primitives import Sampler
|
|
|
|
iae = IterativeAmplitudeEstimation(
|
|
epsilon_target=0.01, # target accuracy
|
|
alpha=0.05, # width of the confidence interval
|
|
sampler=Sampler()
|
|
)
|
|
```
|
|
|
|
For a complete code example, see the updated [Amplitude Estimation tutorial.](https://qiskit.org/ecosystem/finance/tutorials/00_amplitude_estimation.html)
|
|
|
|
<span id="phase"></span>
|
|
## Phase estimators
|
|
|
|
The phase estimators were refactored in-place.
|
|
Instead of a [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), `qiskit.algorithms.phase_estimators` are now initialized by
|
|
using an instance of any Sampler primitive. That is, [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler).
|
|
|
|
<Admonition type="note">
|
|
The full `qiskit.algorithms.phase_estimators` module has been refactored in place. Therefore, you do not need to change import paths.
|
|
</Admonition>
|
|
|
|
### IPE example
|
|
|
|
**[Legacy] Using QuantumInstance:**
|
|
|
|
```python
|
|
from qiskit.algorithms import IterativePhaseEstimation
|
|
from qiskit.utils import QuantumInstance
|
|
|
|
qi = QuantumInstance(backend=backend)
|
|
ipe = IterativePhaseEstimation(
|
|
num_iterations=num_iter,
|
|
quantum_instance=qi
|
|
)
|
|
```
|
|
|
|
**[Updated] Using primitives:**
|
|
|
|
```python
|
|
from qiskit.algorithms import IterativePhaseEstimation
|
|
from qiskit.primitives import Sampler
|
|
|
|
ipe = IterativePhaseEstimation(
|
|
num_iterations=num_iter,
|
|
sampler=Sampler()
|
|
)
|
|
```
|
|
|
|
For a complete code examples, see the updated [Iterative phase estimation tutorial.](https://github.com/Qiskit/qiskit-tutorials/blob/master/tutorials/algorithms/09_IQPE.ipynb)
|