qiskit-documentation/docs/migration-guides/qiskit-opflow-module.mdx

1370 lines
56 KiB
Plaintext

---
title: qiskit.opflow migration guide
description: How to update your code to stop using the deprecated `qiskit.opflow` module.
---
{/* cspell:ignore XYZY */}
# Opflow 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>
The new [`qiskit.primitives`](/api/qiskit/primitives), in combination with the [`qiskit.quantum_info`](/api/qiskit/quantum_info) module, have superseded
functionality of [`qiskit.opflow`](/api/qiskit/0.46/opflow), which is being deprecated.
This migration guide contains instructions and code examples to migrate Qiskit code that uses
the [`qiskit.opflow`](/api/qiskit/0.46/opflow) module to the [`qiskit.primitives`](/api/qiskit/primitives) and [`qiskit.quantum_info`](/api/qiskit/quantum_info) modules.
<Admonition type="note">
The [`qiskit.opflow`](/api/qiskit/0.46/opflow) module was tightly coupled to the [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance) class, which
is also being deprecated. For information about migrating the [`qiskit.utils.QuantumInstance`](/api/qiskit/0.46/qiskit.utils.QuantumInstance), see
the [Quantum instance migration guide.](./qiskit-quantum-instance)
</Admonition>
<span id="attention_primitives"></span>
<Admonition type="note">
Most references to the [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) or [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) in this guide
can be replaced with instances of any primitive implementation. For example, Aer primitives ([`qiskit_aer.primitives.Sampler`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Sampler.html)/[`qiskit_aer.primitives.Estimator`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Estimator.html)) or the Qiskit Runtime primitives ([`qiskit_ibm_runtime.Sampler`](/api/qiskit-ibm-runtime/0.26/qiskit_ibm_runtime.Sampler)/[`qiskit_ibm_runtime.Estimator`](/api/qiskit-ibm-runtime/0.26/qiskit_ibm_runtime.Estimator)).
Specific QPUs (quantum processing units) can be wrapped with ([`qiskit.primitives.BackendSampler`](/api/qiskit/qiskit.primitives.BackendSampler), [`qiskit.primitives.BackendEstimator`](/api/qiskit/qiskit.primitives.BackendEstimator)) to also present primitive-compatible interfaces.
Certain classes, such as the
[`qiskit.opflow.expectations.AerPauliExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.AerPauliExpectation), can only be replaced by a specific primitive instance
(in this case, [`qiskit_aer.primitives.Estimator`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Estimator.html)), or require a specific option configuration.
If this is the case, it will be explicitly indicated in the corresponding section.
</Admonition>
## Background
The [`qiskit.opflow`](/api/qiskit/0.46/opflow) module was originally introduced as a layer between circuits and algorithms, a series of building blocks
for quantum algorithm research and development.
The release of the [`qiskit.primitives`](/api/qiskit/primitives) introduced a new paradigm for interacting with quantum computers. Instead of
preparing a circuit to execute with a `backend.run()` type of method, algorithms can leverage the [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) and
[`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitives, send parametrized circuits and observables, and directly receive quasi-probability distributions or
expectation values (respectively). This workflow simplifies the pre-processing and post-processing steps
that previously relied on this module; allowing us to move away from [`qiskit.opflow`](/api/qiskit/0.46/opflow)
and find new paths for developing algorithms based on the [`qiskit.primitives`](/api/qiskit/primitives) interface and
the [`qiskit.quantum_info`](/api/qiskit/quantum_info) module.
This guide describes the opflow submodules and provides either a direct alternative
(for example, using [`qiskit.quantum_info`](/api/qiskit/quantum_info)), or an explanation of how to replace their functionality in algorithms.
The functional equivalency can be roughly summarized as follows:
| Opflow Module | Alternative |
| --- | --- |
| Operators ([`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase), [`Operator Globals`](#operator-globals), [`qiskit.opflow.primitive_ops`](/api/qiskit/0.46/qiskit.opflow.primitive_ops), [`qiskit.opflow.list_ops`](/api/qiskit/0.46/qiskit.opflow.list_ops)) | `qiskit.quantum_info` [`Operators`](/api/qiskit/quantum_info#operators) |
| [`qiskit.opflow.state_fns`](/api/qiskit/0.46/qiskit.opflow.state_fns) | `qiskit.quantum_info` [`States`](/api/qiskit/quantum_info#states) |
| [`qiskit.opflow.converters`](/api/qiskit/0.46/qiskit.opflow.converters) | [`qiskit.primitives`](/api/qiskit/primitives) |
| [`qiskit.opflow.evolutions`](/api/qiskit/0.46/qiskit.opflow.evolutions) | `qiskit.synthesis` [`Evolution`](/api/qiskit/synthesis#evolution-synthesis) |
| [`qiskit.opflow.expectations`](/api/qiskit/0.46/qiskit.opflow.expectations) | [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) |
| [`qiskit.opflow.gradients`](/api/qiskit/0.46/qiskit.opflow.gradients) | [`qiskit.algorithms.gradients`](/api/qiskit/0.46/qiskit.algorithms.gradients) |
## Operator base class
The [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) abstract class can be replaced with `qiskit.quantum_info.BaseOperator`,
keeping in mind that `qiskit.quantum_info.BaseOperator` is more generic than its opflow counterpart.
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) | `qiskit.quantum_info.BaseOperator` |
<Admonition type="note">
Despite the similar class names, [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) and
`qiskit.quantum_info.BaseOperator` are not completely equivalent, and the transition
should be handled with care. Namely:
* [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) implements a broader algebra mixin. Some operator overloads that were
commonly used in [`qiskit.opflow`](/api/qiskit/0.46/opflow) (for example `~` for `.adjoint()`) are not defined for
`qiskit.quantum_info.BaseOperator`. You might want to check the specific
[`qiskit.quantum_info`](/api/qiskit/quantum_info) subclass instead.
* [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) also implements methods such as `.to_matrix()` or `.to_spmatrix()`,
which are only found in some of the `qiskit.quantum_info.BaseOperator` subclasses.
See the [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) and [`qiskit.quantum_info.BaseOperator`](/api/qiskit/quantum_info#quantum-information) API references
for more information.
</Admonition>
## Operator globals
Opflow provided shortcuts to define common single qubit states, operators, and non-parametrized gates in the
[`operator_globals`](/api/qiskit/0.46/opflow#operator-globals) module.
These were mainly used for didactic purposes or quick prototyping and can easily be replaced by their corresponding
[`qiskit.quantum_info`](/api/qiskit/quantum_info) class: [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli), [`qiskit.quantum_info.Clifford`](/api/qiskit/qiskit.quantum_info.Clifford) or
[`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector).
### Single-qubit Paulis
The single-qubit Paulis were commonly used for algorithm testing, as they could be combined to create more complex operators
(for example, `0.39 * (I ^ Z) + 0.5 * (X ^ X)`).
These operations implicitly created operators of type [`qiskit.opflow.primitive_ops.PauliSumOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliSumOp), and can be replaced by
directly creating a corresponding [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp), as shown in the following examples.
| Opflow | Alternative |
| --- | --- |
| `qiskit.opflow.X`, `qiskit.opflow.Y`, `qiskit.opflow.Z`, `qiskit.opflow.I` | [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) <Admonition type="note">For direct compatibility with classes in [`qiskit.algorithms`](/api/qiskit/0.46/algorithms), wrap in [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp).</Admonition> |
#### Example 1: Define the XX operator
Opflow:
```python
from qiskit.opflow import X
operator = X ^ X
print(repr(operator))
```
```python
PauliOp(Pauli('XX'), coeff=1.0)
```
Alternative:
```python
from qiskit.quantum_info import Pauli, SparsePauliOp
operator = Pauli('XX')
# equivalent to:
X = Pauli('X')
operator = X ^ X
print("As Pauli Op: ", repr(operator))
# another alternative is:
operator = SparsePauliOp('XX')
print("As Sparse Pauli Op: ", repr(operator))
```
```text
As Pauli Op: Pauli('XX')
As Sparse Pauli Op: SparsePauliOp(['XX'],
coeffs=[1.+0.j])
```
#### Example 2: Define a more complex operator
Opflow:
```python
from qiskit.opflow import I, X, Z, PauliSumOp
operator = 0.39 * (I ^ Z ^ I) + 0.5 * (I ^ X ^ X)
# equivalent to:
operator = PauliSumOp.from_list([("IZI", 0.39), ("IXX", 0.5)])
print(repr(operator))
```
```python
PauliSumOp(SparsePauliOp(['IZI', 'IXX'],
coeffs=[0.39+0.j, 0.5 +0.j]), coeff=1.0)
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
operator = SparsePauliOp(["IZI", "IXX"], coeffs = [0.39, 0.5])
# equivalent to:
operator = SparsePauliOp.from_list([("IZI", 0.39), ("IXX", 0.5)])
# equivalent to:
operator = SparsePauliOp.from_sparse_list([("Z", [1], 0.39), ("XX", [0,1], 0.5)], num_qubits = 3)
print(repr(operator))
```
```python
SparsePauliOp(['IZI', 'IXX'],
coeffs=[0.39+0.j, 0.5 +0.j])
```
### Common non-parametrized gates (Clifford)
| Opflow | Alternative |
| --- | --- |
| `qiskit.opflow.CX`, `qiskit.opflow.S`, `qiskit.opflow.H`, `qiskit.opflow.T`, `qiskit.opflow.CZ`, `qiskit.opflow.Swap` | Append corresponding gate to [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit). If necessary, a [`qiskit.quantum_info.Operator`](/api/qiskit/qiskit.quantum_info.Operator) can be directly constructed from quantum circuits. Another alternative is to wrap the circuit in [`qiskit.quantum_info.Clifford`](/api/qiskit/qiskit.quantum_info.Clifford) and call `Clifford.to_operator()` <Admonition type="note">Constructing [`qiskit.quantum_info`](/api/qiskit/quantum_info) operators from circuits is not efficient, as it is a dense operation and scales exponentially with the size of the circuit.</Admonition> |
#### Example 1: Define the HH operator
Opflow:
```python
from qiskit.opflow import H
operator = H ^ H
print(operator)
```
```text
┌───┐
q_0: ┤ H ├
├───┤
q_1: ┤ H ├
└───┘
```
Alternative:
```python
from qiskit import QuantumCircuit
from qiskit.quantum_info import Clifford, Operator
qc = QuantumCircuit(2)
qc.h(0)
qc.h(1)
print(qc)
```
```text
┌───┐
q_0: ┤ H ├
├───┤
q_1: ┤ H ├
└───┘
```
To turn this circuit into an operator, you can do the following:
```python
operator = Clifford(qc).to_operator()
# or, directly
operator = Operator(qc)
print(operator)
```
```python
Operator([[ 0.5+0.j, 0.5+0.j, 0.5+0.j, 0.5+0.j],
[ 0.5+0.j, -0.5+0.j, 0.5+0.j, -0.5+0.j],
[ 0.5+0.j, 0.5+0.j, -0.5+0.j, -0.5+0.j],
[ 0.5+0.j, -0.5+0.j, -0.5+0.j, 0.5+0.j]],
input_dims=(2, 2), output_dims=(2, 2))
```
### 1-qubit states
| Opflow | Alternative |
| --- | --- |
| `qiskit.opflow.Zero`, `qiskit.opflow.One`, `qiskit.opflow.Plus`, `qiskit.opflow.Minus` | [`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector) or [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit), depending on the use case. <Admonition type="note">To efficiently simulate stabilizer states, [`qiskit.quantum_info`](/api/qiskit/quantum_info) includes a [`qiskit.quantum_info.StabilizerState`](/api/qiskit/qiskit.quantum_info.StabilizerState) class. See the [`qiskit.quantum_info.StabilizerState`](/api/qiskit/qiskit.quantum_info.StabilizerState) API reference for more information.</Admonition> |
#### Example 1: Stabilizer states
Opflow:
```python
from qiskit.opflow import Zero, One, Plus, Minus
# Zero, One, Plus, Minus are all stabilizer states
state1 = Zero ^ One
state2 = Plus ^ Minus
print("State 1: ", state1)
print("State 2: ", state2)
```
```text
State 1: DictStateFn({'01': 1})
State 2: CircuitStateFn(
┌───┐┌───┐
q_0: ┤ X ├┤ H ├
├───┤└───┘
q_1: ┤ H ├─────
└───┘
)
```
Alternative:
```python
from qiskit import QuantumCircuit
from qiskit.quantum_info import StabilizerState, Statevector
qc_zero = QuantumCircuit(1)
qc_one = qc_zero.copy()
qc_one.x(0)
state1 = Statevector(qc_zero) ^ Statevector(qc_one)
print("State 1: ", state1)
qc_plus = qc_zero.copy()
qc_plus.h(0)
qc_minus = qc_one.copy()
qc_minus.h(0)
state2 = StabilizerState(qc_plus) ^ StabilizerState(qc_minus)
print("State 2: ", state2)
```
```text
State 1: Statevector([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
dims=(2, 2))
State 2: StabilizerState(StabilizerTable: ['-IX', '+XI'])
```
## Primitive and List Ops
Most of the workflows that previously relied on components from [`qiskit.opflow.primitive_ops`](/api/qiskit/0.46/qiskit.opflow.primitive_ops) and
[`qiskit.opflow.list_ops`](/api/qiskit/0.46/qiskit.opflow.list_ops) can now leverage elements from [`qiskit.quantum_info`](/api/qiskit/quantum_info)
operators instead.
Some of these classes do not require a one-to-one replacement because they were created to interface with other
opflow components.
### Primitive Ops
[`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) is the [`qiskit.opflow.primitive_ops`](/api/qiskit/0.46/qiskit.opflow.primitive_ops) module's base class.
It also acts as a factory to instantiate a corresponding sub-class, depending on the computational primitive used
to initialize it.
<Admonition type="tip">
Interpreting [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) as a factory class:
| Class passed to [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) | Subclass returned |
| --- | --- |
| [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) | [`qiskit.opflow.primitive_ops.PauliOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliOp) |
| [`qiskit.circuit.Instruction`](/api/qiskit/qiskit.circuit.Instruction), [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit) | [`qiskit.opflow.primitive_ops.CircuitOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.CircuitOp) |
| `list`, `np.ndarray`, `scipy.sparse.spmatrix`, [`qiskit.quantum_info.Operator`](/api/qiskit/qiskit.quantum_info.Operator) | [`qiskit.opflow.primitive_ops.MatrixOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.MatrixOp) |
</Admonition>
When migrating opflow code, it is important to look for alternatives to replace the specific subclasses that
are used within the original code:
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) | As mentioned previously, this class is used to generate an instance of one of the classes below, so there is no direct replacement. |
| [`qiskit.opflow.primitive_ops.CircuitOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.CircuitOp) | [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit) |
| [`qiskit.opflow.primitive_ops.MatrixOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.MatrixOp) | [`qiskit.quantum_info.Operator`](/api/qiskit/qiskit.quantum_info.Operator) |
| [`qiskit.opflow.primitive_ops.PauliOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliOp) | [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli). For direct compatibility with classes in [`qiskit.algorithms`](/api/qiskit/0.46/algorithms), wrap in [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp). |
| [`qiskit.opflow.primitive_ops.PauliSumOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliSumOp) | [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp). See example [below](#example-pauli-sum-op). |
| [`qiskit.opflow.primitive_ops.TaperedPauliSumOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.TaperedPauliSumOp) | This class was used to combine a [`qiskit.opflow.primitive_ops.PauliSumOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PauliSumOp) with its identified symmetries in one object. This functionality is not currently used in any workflow, and has been deprecated without replacement. See [`qiskit.quantum_info.analysis.Z2Symmetries`](/api/qiskit/qiskit.quantum_info.Z2Symmetries) example for updated workflow. |
| [`qiskit.opflow.primitive_ops.Z2Symmetries`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.Z2Symmetries) | [`qiskit.quantum_info.analysis.Z2Symmetries`](/api/qiskit/qiskit.quantum_info.Z2Symmetries). See example [below](#example-z2-sym). |
<span id="example-pauli-sum-op"></span>
#### Example 1: `PauliSumOp`
Opflow:
```python
from qiskit.opflow import PauliSumOp
from qiskit.quantum_info import SparsePauliOp, Pauli
qubit_op = PauliSumOp(SparsePauliOp(Pauli("XYZY"), coeffs=[2]), coeff=-3j)
print(repr(qubit_op))
```
```python
PauliSumOp(SparsePauliOp(['XYZY'],
coeffs=[2.+0.j]), coeff=(-0-3j))
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp, Pauli
qubit_op = SparsePauliOp(Pauli("XYZY"), coeffs=[-6j])
print(repr(qubit_op))
```
```python
SparsePauliOp(['XYZY'],
coeffs=[0.-6.j])
```
<span id="example-z2-sym"></span>
#### Example 2: `Z2Symmetries` and `TaperedPauliSumOp`
Opflow:
```python
from qiskit.opflow import PauliSumOp, Z2Symmetries, TaperedPauliSumOp
qubit_op = PauliSumOp.from_list(
[
("II", -1.0537076071291125),
("IZ", 0.393983679438514),
("ZI", -0.39398367943851387),
("ZZ", -0.01123658523318205),
("XX", 0.1812888082114961),
]
)
z2_symmetries = Z2Symmetries.find_Z2_symmetries(qubit_op)
print(z2_symmetries)
tapered_op = z2_symmetries.taper(qubit_op)
print("Tapered Op from Z2 symmetries: ", tapered_op)
# can be represented as:
tapered_op = TaperedPauliSumOp(qubit_op.primitive, z2_symmetries)
print("Tapered PauliSumOp: ", tapered_op)
```
```text
Z2 symmetries:
Symmetries:
ZZ
Single-Qubit Pauli X:
IX
Cliffords:
0.7071067811865475 * ZZ
+ 0.7071067811865475 * IX
Qubit index:
[0]
Tapering values:
- Possible values: [1], [-1]
Tapered Op from Z2 symmetries: ListOp([
-1.0649441923622942 * I
+ 0.18128880821149604 * X,
-1.0424710218959303 * I
- 0.7879673588770277 * Z
- 0.18128880821149604 * X
])
Tapered PauliSumOp: -1.0537076071291125 * II
+ 0.393983679438514 * IZ
- 0.39398367943851387 * ZI
- 0.01123658523318205 * ZZ
+ 0.1812888082114961 * XX
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info.analysis import Z2Symmetries
qubit_op = SparsePauliOp.from_list(
[
("II", -1.0537076071291125),
("IZ", 0.393983679438514),
("ZI", -0.39398367943851387),
("ZZ", -0.01123658523318205),
("XX", 0.1812888082114961),
]
)
z2_symmetries = Z2Symmetries.find_z2_symmetries(qubit_op)
print(z2_symmetries)
tapered_op = z2_symmetries.taper(qubit_op)
print("Tapered Op from Z2 symmetries: ", tapered_op)
```
```text
Z2 symmetries:
Symmetries:
ZZ
Single-Qubit Pauli X:
IX
Cliffords:
SparsePauliOp(['ZZ', 'IX'],
coeffs=[0.70710678+0.j, 0.70710678+0.j])
Qubit index:
[0]
Tapering values:
- Possible values: [1], [-1]
Tapered Op from Z2 symmetries: [SparsePauliOp(['I', 'X'],
coeffs=[-1.06494419+0.j, 0.18128881+0.j]), SparsePauliOp(['I', 'Z', 'X'],
coeffs=[-1.04247102+0.j, -0.78796736+0.j, -0.18128881+0.j])]
```
### ListOps
The [`qiskit.opflow.list_ops`](/api/qiskit/0.46/qiskit.opflow.list_ops) module contained classes for manipulating lists of [`qiskit.opflow.primitive_ops`](/api/qiskit/0.46/qiskit.opflow.primitive_ops)
or [`qiskit.opflow.state_fns`](/api/qiskit/0.46/qiskit.opflow.state_fns). The [`qiskit.quantum_info`](/api/qiskit/quantum_info) alternatives for this functionality are
[`qiskit.quantum_info.PauliList`](/api/qiskit/qiskit.quantum_info.PauliList) and [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp) (for sums of [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli)s).
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.list_ops.ListOp`](/api/qiskit/0.46/qiskit.opflow.list_ops.ListOp) | No direct replacement. This is the base class for operator lists. In general, these could be replaced with a Python `list`. For [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) operators, there are a few alternatives, depending on the use case. One alternative is [`qiskit.quantum_info.PauliList`](/api/qiskit/qiskit.quantum_info.PauliList). |
| [`qiskit.opflow.list_ops.ComposedOp`](/api/qiskit/0.46/qiskit.opflow.list_ops.ComposedOp) | No direct replacement. Current workflows do not require composing states and operators within one object (no lazy evaluation). |
| [`qiskit.opflow.list_ops.SummedOp`](/api/qiskit/0.46/qiskit.opflow.list_ops.SummedOp) | No direct replacement. For [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) operators, use [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp). |
| [`qiskit.opflow.list_ops.TensoredOp`](/api/qiskit/0.46/qiskit.opflow.list_ops.TensoredOp) | No direct replacement. For [`qiskit.quantum_info.Pauli`](/api/qiskit/qiskit.quantum_info.Pauli) operators, use [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp). |
## State functions
The [`qiskit.opflow.state_fns`](/api/qiskit/0.46/qiskit.opflow.state_fns) module can generally be replaced by subclasses of the [`qiskit.quantum_info`](/api/qiskit/quantum_info)
`qiskit.quantum_info.states.quantum_state.QuantumState`.
Similar to [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp), [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn)
acts as a factory to create the corresponding subclass depending on the computational primitive used to initialize it.
<Admonition type="tip">
Interpreting [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn) as a factory class:
| Class passed to [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn) | Subclass returned |
| --- | --- |
| `str`, `dict`, [`qiskit.result.Result`](/api/qiskit/qiskit.result.Result) | [`qiskit.opflow.state_fns.DictStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.DictStateFn) |
| `list`, `np.ndarray`, [`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector) | [`qiskit.opflow.state_fns.VectorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.VectorStateFn) |
| [`qiskit.circuit.QuantumCircuit`](/api/qiskit/qiskit.circuit.QuantumCircuit), [`qiskit.circuit.Instruction`](/api/qiskit/qiskit.circuit.Instruction) | [`qiskit.opflow.state_fns.CircuitStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.CircuitStateFn) |
| [`qiskit.opflow.OperatorBase`](/api/qiskit/0.46/qiskit.opflow.OperatorBase) | [`qiskit.opflow.state_fns.OperatorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.OperatorStateFn) |
</Admonition>
Examine references to [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn) in opflow code to identify the subclass that is being used, then find an alternative.
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn) | In most cases, [`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector). However, remember that [`qiskit.opflow.state_fns.StateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.StateFn) is a factory class. |
| [`qiskit.opflow.state_fns.CircuitStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.CircuitStateFn) | [`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector) |
| [`qiskit.opflow.state_fns.DictStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.DictStateFn) | This class was used to store efficient representations of sparse measurement results. The [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) now returns the measurements as an instance of [`qiskit.result.QuasiDistribution`](/api/qiskit/qiskit.result.QuasiDistribution). See the example in [`Converters`](#converters). |
| [`qiskit.opflow.state_fns.VectorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.VectorStateFn) | This class can be replaced with [`qiskit.quantum_info.Statevector`](/api/qiskit/qiskit.quantum_info.Statevector) or [`qiskit.quantum_info.StabilizerState`](/api/qiskit/qiskit.quantum_info.StabilizerState), for Clifford-based vectors.|
| [`qiskit.opflow.state_fns.SparseVectorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.SparseVectorStateFn) | No direct replacement. This class was used for sparse statevector representations. |
| [`qiskit.opflow.state_fns.OperatorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.OperatorStateFn) | No direct replacement. This class was used to represent measurements against operators. |
| [`qiskit.opflow.state_fns.CVaRMeasurement`](/api/qiskit/0.46/qiskit.opflow.state_fns.CVaRMeasurement) | Used in [`qiskit.opflow.expectations.CVaRExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.CVaRExpectation). This function is now covered by [`qiskit.algorithms.minimum_eigensolvers.SamplingVQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQE). See the example in [`Expectations`](#expectations). |
### Example 1: Apply an operator to a state
Opflow:
```python
from qiskit.opflow import StateFn, X, Y
from qiskit import QuantumCircuit
qc = QuantumCircuit(2)
qc.x(0)
qc.z(1)
op = X ^ Y
state = StateFn(qc)
comp = ~op @ state
eval = comp.eval()
print(state)
print(comp)
print(repr(eval))
```
```text
CircuitStateFn(
┌───┐
q_0: ┤ X ├
├───┤
q_1: ┤ Z ├
└───┘
)
CircuitStateFn(
┌───┐┌────────────┐
q_0: ┤ X ├┤0 ├
├───┤│ Pauli(XY) │
q_1: ┤ Z ├┤1 ├
└───┘└────────────┘
)
VectorStateFn(Statevector([ 0.0e+00+0.j, 0.0e+00+0.j, -6.1e-17-1.j, 0.0e+00+0.j],
dims=(2, 2)), coeff=1.0, is_measurement=False)
```
Alternative:
```python
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp, Statevector
qc = QuantumCircuit(2)
qc.x(0)
qc.z(1)
op = SparsePauliOp("XY")
state = Statevector(qc)
eval = state.evolve(op)
print(state)
print(eval)
```
```python
Statevector([0.+0.j, 1.+0.j, 0.+0.j, 0.+0.j],
dims=(2, 2))
Statevector([0.+0.j, 0.+0.j, 0.-1.j, 0.+0.j],
dims=(2, 2))
```
See more examples in [Expectations](#expectations) and [Converters](#converters).
## Converters
The role of the [`qiskit.opflow.converters`](/api/qiskit/0.46/qiskit.opflow.converters) submodule was to convert the operators into other opflow operator classes:
([`qiskit.opflow.converters.TwoQubitReduction`](/api/qiskit/0.46/qiskit.opflow.converters.TwoQubitReduction), [`qiskit.opflow.converters.PauliBasisChange`](/api/qiskit/0.46/qiskit.opflow.converters.PauliBasisChange), and so on).
The [`qiskit.opflow.converters.CircuitSampler`](/api/qiskit/0.46/qiskit.opflow.converters.CircuitSampler) traversed an operator and outputted
approximations of its state functions using a quantum computer.
This functionality has been replaced by the [`qiskit.primitives`](/api/qiskit/primitives).
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.converters.CircuitSampler`](/api/qiskit/0.46/qiskit.opflow.converters.CircuitSampler) | [`qiskit.primitives.Sampler`](/api/qiskit/qiskit.primitives.Sampler) or [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) if used with [`qiskit.opflow.expectations`](/api/qiskit/0.46/qiskit.opflow.expectations). See examples [below]( #example-convert-state). |
| [`qiskit.opflow.converters.AbelianGrouper`](/api/qiskit/0.46/qiskit.opflow.converters.AbelianGrouper) | This class allowed a sum a of Pauli operators to be grouped. Similar functionality can be achieved through the [`qiskit.quantum_info.SparsePauliOp.group_commuting`](/api/qiskit/qiskit.quantum_info.SparsePauliOp#group_commuting) method of [`qiskit.quantum_info.SparsePauliOp`](/api/qiskit/qiskit.quantum_info.SparsePauliOp). However, this is not a one-to-one replacement, as you can see in the example [below](#example-commuting). |
| [`qiskit.opflow.converters.DictToCircuitSum`](/api/qiskit/0.46/qiskit.opflow.converters.DictToCircuitSum) | No direct replacement. This class was used to convert from [`qiskit.opflow.state_fns.DictStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.DictStateFn) or [`qiskit.opflow.state_fns.VectorStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.VectorStateFn) to an equivalent [`qiskit.opflow.state_fns.CircuitStateFn`](/api/qiskit/0.46/qiskit.opflow.state_fns.CircuitStateFn). |
| [`qiskit.opflow.converters.PauliBasisChange`](/api/qiskit/0.46/qiskit.opflow.converters.PauliBasisChange) | No direct replacement. This class was used for changing Paulis into other bases. |
| [`qiskit.opflow.converters.TwoQubitReduction`](/api/qiskit/0.46/qiskit.opflow.converters.TwoQubitReduction) | No direct replacement. This class implements a chemistry-specific reduction for the `ParityMapper` class in [Qiskit Nature](https://qiskit.org/ecosystem/nature/). The general symmetry logic this mapper depends on has been refactored to other classes in [`qiskit.quantum_info`](/api/qiskit/quantum_info), so this specific [`qiskit.opflow`](/api/qiskit/0.46/opflow) implementation is no longer necessary. |
<span id="example-convert-state"></span>
### Example 1: `CircuitSampler` for sampling parametrized circuits
Opflow:
```python
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.opflow import ListOp, StateFn, CircuitSampler
from qiskit_aer import AerSimulator
x, y = Parameter("x"), Parameter("y")
circuit1 = QuantumCircuit(1)
circuit1.p(0.2, 0)
circuit2 = QuantumCircuit(1)
circuit2.p(x, 0)
circuit3 = QuantumCircuit(1)
circuit3.p(y, 0)
bindings = {x: -0.4, y: 0.4}
listop = ListOp([StateFn(circuit) for circuit in [circuit1, circuit2, circuit3]])
sampler = CircuitSampler(AerSimulator())
sampled = sampler.convert(listop, params=bindings).eval()
for s in sampled:
print(s)
```
```text
SparseVectorStateFn( (0, 0) 1.0)
SparseVectorStateFn( (0, 0) 1.0)
SparseVectorStateFn( (0, 0) 1.0)
```
Alternative:
```python
from qiskit.circuit import QuantumCircuit, Parameter
from qiskit.primitives import Sampler
x, y = Parameter("x"), Parameter("y")
circuit1 = QuantumCircuit(1)
circuit1.p(0.2, 0)
circuit1.measure_all() # Sampler primitive requires measurement readout
circuit2 = QuantumCircuit(1)
circuit2.p(x, 0)
circuit2.measure_all()
circuit3 = QuantumCircuit(1)
circuit3.p(y, 0)
circuit3.measure_all()
circuits = [circuit1, circuit2, circuit3]
param_values = [[], [-0.4], [0.4]]
sampler = Sampler()
sampled = sampler.run(circuits, param_values).result().quasi_dists
print(sampled)
```
```python
[{0: 1.0}, {0: 1.0}, {0: 1.0}]
```
### Example 2: `CircuitSampler` for computing expectation values
Opflow:
```python
from qiskit import QuantumCircuit
from qiskit.opflow import X, Z, StateFn, CircuitStateFn, CircuitSampler
from qiskit_aer import AerSimulator
qc = QuantumCircuit(1)
qc.h(0)
state = CircuitStateFn(qc)
hamiltonian = X + Z
expr = StateFn(hamiltonian, is_measurement=True).compose(state)
backend = AerSimulator(method="statevector")
sampler = CircuitSampler(backend)
expectation = sampler.convert(expr)
expectation_value = expectation.eval().real
print(expectation_value)
```
```python
1.0000000000000002
```
Alternative:
```python
from qiskit import QuantumCircuit
from qiskit.primitives import Estimator
from qiskit.quantum_info import SparsePauliOp
state = QuantumCircuit(1)
state.h(0)
hamiltonian = SparsePauliOp.from_list([('X', 1), ('Z',1)])
estimator = Estimator()
expectation_value = estimator.run(state, hamiltonian).result().values.real
print(expectation_value)
```
```python
[1.]
```
<span id="example-commuting"></span>
### Example 3: `AbelianGrouper` for grouping operators
Opflow:
```python
from qiskit.opflow import PauliSumOp, AbelianGrouper
op = PauliSumOp.from_list([("XX", 2), ("YY", 1), ("IZ",2j), ("ZZ",1j)])
grouped_sum = AbelianGrouper.group_subops(op)
print(repr(grouped_sum))
```
```python
SummedOp([PauliSumOp(SparsePauliOp(['XX'],
coeffs=[2.+0.j]), coeff=1.0), PauliSumOp(SparsePauliOp(['YY'],
coeffs=[1.+0.j]), coeff=1.0), PauliSumOp(SparsePauliOp(['IZ', 'ZZ'],
coeffs=[0.+2.j, 0.+1.j]), coeff=1.0)], coeff=1.0, abelian=False)
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
op = SparsePauliOp.from_list([("XX", 2), ("YY", 1), ("IZ",2j), ("ZZ",1j)])
grouped = op.group_commuting()
grouped_sum = op.group_commuting(qubit_wise=True)
print(repr(grouped))
print(repr(grouped_sum))
```
```text
[SparsePauliOp(['IZ', 'ZZ'],
coeffs=[0.+2.j, 0.+1.j]), SparsePauliOp(['XX', 'YY'],
coeffs=[2.+0.j, 1.+0.j])]
[SparsePauliOp(['XX'],
coeffs=[2.+0.j]), SparsePauliOp(['YY'],
coeffs=[1.+0.j]), SparsePauliOp(['IZ', 'ZZ'],
coeffs=[0.+2.j, 0.+1.j])]
```
## Evolutions
The [`qiskit.opflow.evolutions`](/api/qiskit/0.46/qiskit.opflow.evolutions) submodule was created to provide building blocks for Hamiltonian simulation algorithms,
including methods for Trotterization. The original opflow workflow for Hamiltonian simulation did not allow for
delayed synthesis of the gates or efficient transpilation of the circuits, so this functionality was migrated to the
`qiskit.synthesis` [Evolution Synthesis](/api/qiskit/synthesis#evolution-synthesis) module.
<Admonition type="note">
The [`qiskit.opflow.evolutions.PauliTrotterEvolution`](/api/qiskit/0.46/qiskit.opflow.evolutions.PauliTrotterEvolution) class computes evolutions for exponentiated
sums of Paulis by converting to the Z basis, rotating with an RZ, changing back, and Trotterizing.
When calling `.convert()`, the class follows a recursive strategy that involves creating
[`qiskit.opflow.evolutions.EvolvedOp`](/api/qiskit/0.46/qiskit.opflow.evolutions.EvolvedOp) placeholders for the operators,
constructing [`qiskit.circuit.library.PauliEvolutionGate`s](/api/qiskit/qiskit.circuit.library.PauliEvolutionGate) out of the operator primitives, and supplying one of
the desired synthesis methods to perform the Trotterization. The methods can be specified by using a
`string`, which is then inputted into a [`qiskit.opflow.evolutions.TrotterizationFactory`](/api/qiskit/0.46/qiskit.opflow.evolutions.TrotterizationFactory),
or by supplying a method instance of [`qiskit.opflow.evolutions.Trotter`](/api/qiskit/0.46/qiskit.opflow.evolutions.Trotter),
[`qiskit.opflow.evolutions.Suzuki`](/api/qiskit/0.46/qiskit.opflow.evolutions.Suzuki) or [`qiskit.opflow.evolutions.QDrift`](/api/qiskit/0.46/qiskit.opflow.evolutions.QDrift).
The Trotterization methods that extend [`qiskit.opflow.evolutions.TrotterizationBase`](/api/qiskit/0.46/qiskit.opflow.evolutions.TrotterizationBase) were migrated to
[`qiskit.synthesis`](/api/qiskit/synthesis)
and now extend the [`qiskit.synthesis.ProductFormula`](/api/qiskit/qiskit.synthesis.ProductFormula) base class. They no longer contain a `.convert()` method for
standalone use, but are designed to be plugged into the [`qiskit.circuit.library.PauliEvolutionGate`](/api/qiskit/qiskit.circuit.library.PauliEvolutionGate) and called by using `.synthesize()`.
In this context, the job of the [`qiskit.opflow.evolutions.PauliTrotterEvolution`](/api/qiskit/0.46/qiskit.opflow.evolutions.PauliTrotterEvolution) class can now be handled directly by the algorithms, for example, [`qiskit.algorithms.time_evolvers.trotterization.TrotterQRTE`](/api/qiskit/0.46/qiskit.algorithms.time_evolvers.trotterization.TrotterQRTE).
Similarly, the [`qiskit.opflow.evolutions.MatrixEvolution`](/api/qiskit/0.46/qiskit.opflow.evolutions.MatrixEvolution) class performs evolution by classical matrix exponentiation,
constructing a circuit with [`qiskit.extensions.UnitaryGate`s](/api/qiskit/0.44/qiskit.extensions.UnitaryGate) or [`qiskit.extensions.HamiltonianGate`s](/api/qiskit/0.44/qiskit.extensions.HamiltonianGate) that contain the exponentiation of the operator.
This class is no longer necessary, as the [`qiskit.extensions.HamiltonianGate`s](/api/qiskit/0.44/qiskit.extensions.HamiltonianGate) can be directly handled by the algorithms.
</Admonition>
### Trotterizations
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.evolutions.TrotterizationFactory`](/api/qiskit/0.46/qiskit.opflow.evolutions.TrotterizationFactory) | No direct replacement. This class was used to create instances of one of the classes listed below. |
| [`qiskit.opflow.evolutions.Trotter`](/api/qiskit/0.46/qiskit.opflow.evolutions.Trotter) | [`qiskit.synthesis.SuzukiTrotter`](/api/qiskit/qiskit.synthesis.SuzukiTrotter) or [`qiskit.synthesis.LieTrotter`](/api/qiskit/qiskit.synthesis.LieTrotter) |
| [`qiskit.opflow.evolutions.Suzuki`](/api/qiskit/0.46/qiskit.opflow.evolutions.Suzuki) | [`qiskit.synthesis.SuzukiTrotter`](/api/qiskit/qiskit.synthesis.SuzukiTrotter) |
| [`qiskit.opflow.evolutions.QDrift`](/api/qiskit/0.46/qiskit.opflow.evolutions.QDrift) | [`qiskit.synthesis.QDrift`](/api/qiskit/qiskit.synthesis.QDrift) |
### Other evolution classes
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.evolutions.EvolutionFactory`](/api/qiskit/0.46/qiskit.opflow.evolutions.EvolutionFactory) | No direct replacement. This class was used to create instances of one of the classes listed below. |
| [`qiskit.opflow.evolutions.EvolvedOp`](/api/qiskit/0.46/qiskit.opflow.evolutions.EvolvedOp) | No direct replacement. The workflow no longer requires a specific operator for evolutions. |
| [`qiskit.opflow.evolutions.MatrixEvolution`](/api/qiskit/0.46/qiskit.opflow.evolutions.MatrixEvolution) | [`qiskit.extensions.HamiltonianGate`](/api/qiskit/0.44/qiskit.extensions.HamiltonianGate) |
| [`qiskit.opflow.evolutions.PauliTrotterEvolution`](/api/qiskit/0.46/qiskit.opflow.evolutions.PauliTrotterEvolution) | [`qiskit.circuit.library.PauliEvolutionGate`](/api/qiskit/qiskit.circuit.library.PauliEvolutionGate) |
#### Example 1: Trotter evolution
Opflow:
```python
from qiskit.opflow import Trotter, PauliTrotterEvolution, PauliSumOp
hamiltonian = PauliSumOp.from_list([('X', 1), ('Z',1)])
evolution = PauliTrotterEvolution(trotter_mode=Trotter(), reps=2)
evol_result = evolution.convert(hamiltonian.exp_i())
evolved_state = evol_result.to_circuit()
print(evolved_state)
```
```text
┌─────────────────────┐
q: ┤ exp(-it (X + Z))(1) ├
└─────────────────────┘
```
Alternative:
```python
from qiskit import QuantumCircuit
from qiskit.quantum_info import SparsePauliOp
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.synthesis import SuzukiTrotter
hamiltonian = SparsePauliOp.from_list([('X', 1), ('Z',1)])
evol_gate = PauliEvolutionGate(hamiltonian, time=1, synthesis=SuzukiTrotter(reps=2))
evolved_state = QuantumCircuit(1)
evolved_state.append(evol_gate, [0])
print(evolved_state)
```
```text
┌─────────────────────┐
q: ┤ exp(-it (X + Z))(1) ├
└─────────────────────┘
```
#### Example 2: Evolution with time-dependent Hamiltonian
Opflow:
```python
from qiskit.opflow import Trotter, PauliTrotterEvolution, PauliSumOp
from qiskit.circuit import Parameter
time = Parameter('t')
hamiltonian = PauliSumOp.from_list([('X', 1), ('Y',1)])
evolution = PauliTrotterEvolution(trotter_mode=Trotter(), reps=1)
evol_result = evolution.convert((time * hamiltonian).exp_i())
evolved_state = evol_result.to_circuit()
print(evolved_state)
```
```text
┌─────────────────────────┐
q: ┤ exp(-it (X + Y))(1.0*t) ├
└─────────────────────────┘
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
from qiskit.synthesis import LieTrotter
from qiskit.circuit.library import PauliEvolutionGate
from qiskit import QuantumCircuit
from qiskit.circuit import Parameter
time = Parameter('t')
hamiltonian = SparsePauliOp.from_list([('X', 1), ('Y',1)])
evol_gate = PauliEvolutionGate(hamiltonian, time=time, synthesis=LieTrotter())
evolved_state = QuantumCircuit(1)
evolved_state.append(evol_gate, [0])
print(evolved_state)
```
```text
┌─────────────────────┐
q: ┤ exp(-it (X + Y))(t) ├
└─────────────────────┘
```
#### Example 3: Matrix evolution
Opflow:
```python
from qiskit.opflow import MatrixEvolution, MatrixOp
hamiltonian = MatrixOp([[0, 1], [1, 0]])
evolution = MatrixEvolution()
evol_result = evolution.convert(hamiltonian.exp_i())
evolved_state = evol_result.to_circuit()
print(evolved_state.decompose().decompose())
```
```X
┌────────────────┐
q: ┤ U3(2,-π/2,π/2) ├
└────────────────┘
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
from qiskit.extensions import HamiltonianGate
from qiskit import QuantumCircuit
evol_gate = HamiltonianGate([[0, 1], [1, 0]], 1)
evolved_state = QuantumCircuit(1)
evolved_state.append(evol_gate, [0])
print(evolved_state.decompose().decompose())
```
```text
┌────────────────┐
q: ┤ U3(2,-π/2,π/2) ├
└────────────────┘
```
## Expectations
Expectations are converters that enable an observable's expectation value to be computed with respect to some state function.
This function can now be found in the [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive. Remember that there
are different Estimator implementations, as noted [previously.](#attention_primitives)
### Algorithm-Agnostic Expectations
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.expectations.ExpectationFactory`](/api/qiskit/0.46/qiskit.opflow.expectations.ExpectationFactory) | No direct replacement. This class was used to create instances of one of the classes listed below. |
| [`qiskit.opflow.expectations.AerPauliExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.AerPauliExpectation) | Use [`qiskit_aer.primitives.Estimator`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Estimator.html). See example below. |
| [`qiskit.opflow.expectations.MatrixExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.MatrixExpectation) | Use [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator) primitive. If no shots are set, it performs an exact Statevector calculation. See example below. |
| [`qiskit.opflow.expectations.PauliExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.PauliExpectation) | Use any Estimator primitive. For [`qiskit.primitives.Estimator`](/api/qiskit/qiskit.primitives.Estimator), set `shots!=None` for a shotbased simulation. For [`qiskit_aer.primitives.Estimator`](https://qiskit.org/ecosystem/aer/stubs/qiskit_aer.primitives.Estimator.html), this is the default. |
#### Example 1: Aer Pauli expectation
Opflow:
```python
from qiskit.opflow import X, Minus, StateFn, AerPauliExpectation, CircuitSampler
from qiskit.utils import QuantumInstance
from qiskit_aer import AerSimulator
backend = AerSimulator()
q_instance = QuantumInstance(backend)
sampler = CircuitSampler(q_instance, attach_results=True)
expectation = AerPauliExpectation()
state = Minus
operator = 1j * X
converted_meas = expectation.convert(StateFn(operator, is_measurement=True) @ state)
expectation_value = sampler.convert(converted_meas).eval()
print(expectation_value)
```
```python
-1j
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
from qiskit import QuantumCircuit
from qiskit_aer.primitives import Estimator
estimator = Estimator()
op = SparsePauliOp.from_list([("X", 1j)])
states_op = QuantumCircuit(1)
states_op.x(0)
states_op.h(0)
expectation_value = estimator.run(states_op, op).result().values
print(expectation_value)
```
```python
[0.-1.j]
```
#### Example 2: Matrix expectation
Opflow:
```python
from qiskit.opflow import X, H, I, MatrixExpectation, ListOp, StateFn
from qiskit.utils import QuantumInstance
from qiskit_aer import AerSimulator
backend = AerSimulator(method='statevector')
q_instance = QuantumInstance(backend)
sampler = CircuitSampler(q_instance, attach_results=True)
expect = MatrixExpectation()
mixed_ops = ListOp([X.to_matrix_op(), H])
converted_meas = expect.convert(~StateFn(mixed_ops))
plus_mean = converted_meas @ Plus
values_plus = sampler.convert(plus_mean).eval()
print(values_plus)
```
```python
[(1+0j), (0.7071067811865476+0j)]
```
Alternative:
```python
from qiskit.primitives import Estimator
from qiskit.quantum_info import SparsePauliOp
from qiskit.quantum_info import Clifford
X = SparsePauliOp("X")
qc = QuantumCircuit(1)
qc.h(0)
H = Clifford(qc).to_operator()
plus = QuantumCircuit(1)
plus.h(0)
estimator = Estimator()
values_plus = estimator.run([plus, plus], [X, H]).result().values
print(values_plus)
```
```text
[1. 0.70710678]
```
### CVaRExpectation
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.expectations.CVaRExpectation`](/api/qiskit/0.46/qiskit.opflow.expectations.CVaRExpectation) | Functionality migrated into new VQE algorithm: [`qiskit.algorithms.minimum_eigensolvers.SamplingVQE`](/api/qiskit/0.46/qiskit.algorithms.minimum_eigensolvers.SamplingVQE) |
#### Example 1: VQE with CVaR
Opflow:
```python
from qiskit.opflow import CVaRExpectation, PauliSumOp
from qiskit.algorithms import VQE
from qiskit.algorithms.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal
from qiskit_aer import AerSimulator
backend = AerSimulator(method="statevector")
ansatz = TwoLocal(2, 'ry', 'cz')
op = PauliSumOp.from_list([('ZZ',1), ('IZ',1), ('II',1)])
alpha = 0.2
cvar_expectation = CVaRExpectation(alpha=alpha)
opt = SLSQP(maxiter=1000)
vqe = VQE(ansatz, expectation=cvar_expectation, optimizer=opt, quantum_instance=backend)
result = vqe.compute_minimum_eigenvalue(op)
print(result.eigenvalue)
```
```python
(-1+0j)
```
Alternative:
```python
from qiskit.quantum_info import SparsePauliOp
from qiskit.algorithms.minimum_eigensolvers import SamplingVQE
from qiskit.algorithms.optimizers import SLSQP
from qiskit.circuit.library import TwoLocal
from qiskit.primitives import Sampler
ansatz = TwoLocal(2, 'ry', 'cz')
op = SparsePauliOp.from_list([('ZZ',1), ('IZ',1), ('II',1)])
opt = SLSQP(maxiter=1000)
alpha = 0.2
vqe = SamplingVQE(Sampler(), ansatz, opt, aggregation=alpha)
result = vqe.compute_minimum_eigenvalue(op)
print(result.eigenvalue)
```
```python
-1.0
```
## Gradients
The opflow [`qiskit.opflow.gradients`](/api/qiskit/0.46/qiskit.opflow.gradients) framework has been replaced by the [`qiskit.algorithms.gradients`](/api/qiskit/0.46/qiskit.algorithms.gradients)
module. The new gradients are **primitive-based subroutines** commonly used by algorithms and applications, which
can also be run standalone. For this reason, they now reside under [`qiskit.algorithms`](/api/qiskit/0.46/algorithms).
The former gradient framework contained base classes, converters, and derivatives. The "derivatives"
followed a factory design pattern, where different methods could be provided by using string identifiers
to each of these classes. The new gradient framework contains two main families of subroutines:
**Gradients** and **QGT/QFI**. The **Gradients** can either be Sampler or Estimator based, while the current
**QGT/QFI** implementations are Estimator based.
This leads to a change in the workflow:
**Previous workflow**
```python
from qiskit.opflow import Gradient
grad = Gradient(method="param_shift")
# task based on expectation value computations + gradients
```
**New workflow**
We now explicitly import the desired class, depending on the target primitive (Sampler or Estimator) and target method:
```python
from qiskit.algorithms.gradients import ParamShiftEstimatorGradient
from qiskit.primitives import Estimator
grad = ParamShiftEstimatorGradient(Estimator())
# task based on expectation value computations + gradients
```
This works similarly for the QFI class:
**Previous workflow**
```python
from qiskit.opflow import QFI
qfi = QFI(method="lin_comb_full")
# task based on expectation value computations + QFI
```
**New workflow**
There is a generic QFI implementation that can be initialized with different QGT (Quantum Gradient Tensor)
implementations:
```python
from qiskit.algorithms.gradients import LinCombQGT, QFI
from qiskit.primitives import Estimator
qgt = LinCombQGT(Estimator())
qfi = QFI(qgt)
# task based on expectation value computations + QFI
```
<Admonition type="note">
Here is a quick guide for migrating the most common gradient settings. All new gradient
imports follow the format:
```python
from qiskit.algorithms.gradients import MethodPrimitiveGradient, QFI
```
Gradients:
| Opflow | Alternative |
| --- | --- |
| `Gradient(method="lin_comb")` | `LinCombEstimatorGradient(estimator=estimator)` or `LinCombSamplerGradient(sampler=sampler)` |
| `Gradient(method="param_shift")` | `ParamShiftEstimatorGradient(estimator=estimator)` or `ParamShiftSamplerGradient(sampler=sampler)` |
| `Gradient(method="fin_diff")` | `FiniteDiffEstimatorGradient(estimator=estimator)` or `ParamShiftSamplerGradient(sampler=sampler)` |
QFI/QGT:
| Opflow | Alternative |
| --- | --- |
| `QFI(method="lin_comb_full")` | `qgt=LinCombQGT(Estimator())` |
</Admonition>
Other auxiliary classes in the legacy gradient framework have been deprecated. Here is the complete migration
list:
| Opflow | Alternative |
| --- | --- |
| [`qiskit.opflow.gradients.DerivativeBase`](/api/qiskit/0.46/qiskit.opflow.gradients.DerivativeBase) | No replacement. This was the base class for the gradient, hessian, and QFI base classes. |
| [`qiskit.opflow.gradients.GradientBase`](/api/qiskit/0.46/qiskit.opflow.gradients.GradientBase) and [`qiskit.opflow.gradients.Gradient`](/api/qiskit/0.46/qiskit.opflow.gradients.Gradient) | [`qiskit.algorithms.gradients.BaseSamplerGradient`](/api/qiskit/0.46/qiskit.algorithms.gradients.BaseSamplerGradient) or [`qiskit.algorithms.gradients.BaseEstimatorGradient`](/api/qiskit/0.46/qiskit.algorithms.gradients.BaseEstimatorGradient), and specific subclasses per method, as explained above. |
| [`qiskit.opflow.gradients.HessianBase`](/api/qiskit/0.46/qiskit.opflow.gradients.HessianBase) and [`qiskit.opflow.gradients.Hessian`](/api/qiskit/0.46/qiskit.opflow.gradients.Hessian) | No replacement. The new gradient framework does not work with hessians as independent objects. |
| [`qiskit.opflow.gradients.QFIBase`](/api/qiskit/0.46/qiskit.opflow.gradients.QFIBase) and [`qiskit.opflow.gradients.QFI`](/api/qiskit/0.46/qiskit.opflow.gradients.QFI) | The new [`qiskit.algorithms.gradients.QFI`](/api/qiskit/0.46/qiskit.algorithms.gradients.QFI) class extends QGT, so the corresponding base class is [`qiskit.algorithms.gradients.BaseQGT`](/api/qiskit/0.46/qiskit.algorithms.gradients.BaseQGT) |
| [`qiskit.opflow.gradients.CircuitGradient`](/api/qiskit/0.46/qiskit.opflow.gradients.CircuitGradient) | No replacement. This class was used to convert between circuit and gradient [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) and this functionality is no longer necessary. |
| [`qiskit.opflow.gradients.CircuitQFI`](/api/qiskit/0.46/qiskit.opflow.gradients.CircuitQFI) | No replacement. This class was used to convert between circuit and QFI [`qiskit.opflow.primitive_ops.PrimitiveOp`](/api/qiskit/0.46/qiskit.opflow.primitive_ops.PrimitiveOp) and this functionality is no longer necessary. |
| [`qiskit.opflow.gradients.NaturalGradient`](/api/qiskit/0.46/qiskit.opflow.gradients.NaturalGradient) | No replacement. The same functionality can be achieved with the QFI module. |
### Example 1: Finite differences batched gradient
Opflow:
```python
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.opflow import Gradient, X, Z, StateFn, CircuitStateFn
import numpy as np
ham = 0.5 * X - 1 * Z
a = Parameter("a")
b = Parameter("b")
c = Parameter("c")
params = [a,b,c]
qc = QuantumCircuit(1)
qc.h(0)
qc.u(a, b, c, 0)
qc.h(0)
op = ~StateFn(ham) @ CircuitStateFn(primitive=qc, coeff=1.0)
# the gradient class acted similarly opflow converters,
# with a .convert() step and an .eval() step
state_grad = Gradient(grad_method="param_shift").convert(operator=op, params=params)
# the old workflow did not allow for batched evaluation of parameter values
values_dict = [{a: np.pi / 4, b: 0, c: 0}, {a: np.pi / 4, b: np.pi / 4, c: np.pi / 4}]
gradients = []
for i, value_dict in enumerate(values_dict):
gradients.append(state_grad.assign_parameters(value_dict).eval())
print(gradients)
```
```python
[[(0.35355339059327356+0j), (-1.182555756156289e-16+0j), (-1.6675e-16+0j)], [(0.10355339059327384+0j), (0.8535533905932734+0j), (1.103553390593273+0j)]]
```
Alternative:
```python
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.primitives import Estimator
from qiskit.algorithms.gradients import ParamShiftEstimatorGradient
from qiskit.quantum_info import SparsePauliOp
import numpy as np
ham = SparsePauliOp.from_list([("X", 0.5), ("Z", -1)])
a = Parameter("a")
b = Parameter("b")
c = Parameter("c")
qc = QuantumCircuit(1)
qc.h(0)
qc.u(a, b, c, 0)
qc.h(0)
estimator = Estimator()
gradient = ParamShiftEstimatorGradient(estimator)
# The new workflow follows an interface close to that of the primitives.
param_list = [[np.pi / 4, 0, 0], [np.pi / 4, np.pi / 4, np.pi / 4]]
# For batched evaluations, the number of circuits must match the
# number of parameter value sets.
gradients = gradient.run([qc] * 2, [ham] * 2, param_list).result().gradients
print(gradients)
```
```python
[array([ 3.53553391e-01, 0.00000000e+00, -1.80411242e-16]), array([0.10355339, 0.85355339, 1.10355339])]
```
### Example 2: QFI
Opflow:
```python
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.opflow import QFI, CircuitStateFn
import numpy as np
# Create the circuit.
a, b = Parameter("a"), Parameter("b")
qc = QuantumCircuit(1)
qc.h(0)
qc.rz(a, 0)
qc.rx(b, 0)
# Convert the circuit to a QFI object.
op = CircuitStateFn(qc)
qfi = QFI(qfi_method="lin_comb_full").convert(operator=op)
# Bind parameters and evaluate.
values_dict = {a: np.pi / 4, b: 0.1}
qfi = qfi.bind_parameters(values_dict).eval()
print(qfi)
```
```python
[[ 1.00000000e+00+0.j -3.63575685e-16+0.j]
[-3.63575685e-16+0.j 5.00000000e-01+0.j]]
```
Alternative:
```python
from qiskit.circuit import Parameter, QuantumCircuit
from qiskit.primitives import Estimator
from qiskit.algorithms.gradients import LinCombQGT, QFI
import numpy as np
# Create the circuit.
a, b = Parameter("a"), Parameter("b")
qc = QuantumCircuit(1)
qc.h(0)
qc.rz(a, 0)
qc.rx(b, 0)
# Initialize QFI.
estimator = Estimator()
qgt = LinCombQGT(estimator)
qfi = QFI(qgt)
# Evaluate
values_list = [[np.pi / 4, 0.1]]
qfi = qfi.run(qc, values_list).result().qfis
print(qfi)
```
```python
[array([[ 1.00000000e+00, -1.50274614e-16],
[-1.50274614e-16, 5.00000000e-01]])]
```