Guide de migration des algorithmes#

En bref :#

Le module qiskit.algorithms a Γ©tΓ© entiΓ¨rement restructurΓ© pour utiliser le primitives, pour l’exΓ©cution du circuit, au lieu de QuantumInstance, qui est dΓ©sormais obsolΓ¨te.

Il y a eu 3 types de refactoring :

  1. Algorithmes refactorisΓ©s dans un nouvel emplacement pour supporter primitives. Ces algorithmes ont les mΓͺmes noms de classes que les classes QuantumInstancecorrespondantes mais sont dans un nouveau sous-paquet.

    Attention

    Attention aux chemins d’importation!! Les algorithmes hΓ©ritΓ©s sont toujours importables directement depuis qiskit.algorithms. Tant que les importations hΓ©ritΓ©es ne sont pas supprimΓ©es, cette importation de commoditΓ© n’est pas disponible pour les algorithmes refactorisΓ©s. Ainsi, pour importer les algorithmes refactorisΓ©s, vous devez toujours spΓ©cifier le chemin complet d’importation (par exemple, from qiskit.algorithms.eigensolvers import VQD)

  2. Algorithmes refactorisΓ©s en place (mΓͺme espace de nom) pour prendre en charge les valeurs QuantumInstance et primitives. A l’avenir, l’utilisation de QuantumInstance sera supprimΓ©e.

  3. Algorithmes dépréciés et maintenant entièrement supprimés de qiskit.algorithms. Ce sont des algorithmes qui ne servent pas actuellement de blocs de construction pour les applications. Leur valeur principale est éducative et, en tant que telle, sera conservée comme tutoriels dans le manuel de qiskit. Vous pouvez consulter les tutoriels dans les liens suivants :

Le reste de ce guide de migration se concentrera sur les algorithmes avec des alternatives de migration au sein de :mod:` qiskit.algorithmes `, c’est-Γ -dire les algorithmes de restructuration des types 1 et 2.

Historique#

*Retour Γ  la * ` TL; DR ` _

Le module :mod:` qiskit.algorithmes’a Γ©tΓ© construit Γ  l’origine sur la bibliothΓ¨que :mod:` qiskit.opflow’et l’utilitaire :class:` ~qiskit.utils.QuantumInstance. Le dΓ©veloppement des :mod:` ~qiskit.primitives a introduit un paradigme d’exΓ©cution de niveau supΓ©rieur, avec ` ` Estimateur ` ` pour le calcul des valeurs d’attente pour les observables, et ` ` Sampler ` ` pour l’exΓ©cution des circuits et les distributions de probabilitΓ© de retour. Ces outils ont permis de refacer le module :mod:` qiskit.algorithmes ` et d’en rendre compte Γ  la fois :mod:` qiskit.opflow ` et :class:` ~qiskit.utils.QuantumInstance `.

Attention

La transition de :mod:` qiskit.opflow` affecte les classes que les algorithmes prennent dans le cadre de la configuration du problΓ¨me. En rΓ¨gle gΓ©nΓ©rale, la plupart des dΓ©pendances :mod:` qiskit.opflow` ont un remplacement direct :mod:` qiskit.quantum_info`. Un exemple commun est la classe :mod:` qiskit.opflow.PauliSumOp , utilisΓ©e pour dΓ©finir les hamiltoniens (par exemple, pour connecter VQE), qui peuvent Γͺtre remplacΓ©s par :mod: qiskit.quantum_info.SparsePauliOp`. Pour plus d’informations sur la migration d’autres objets :mod:` ~qiskit.opflow`, vous pouvez vous rΓ©fΓ©rer au guide de migration Opflow <https://qisk.it/opflow_migration>` _.

Pour plus d’informations sur l’arriΓ¨re-plan et les Γ©tapes de migration dΓ©taillΓ©es, voir:

Comment choisir une configuration primitive pour votre algorithme#

*Retour Γ  la * ` TL; DR ` _

Les classes de qiskit.algorithmes sont initialisΓ©es avec toute implΓ©mentation de qiskit.primitive.BaseSampler ou :class: qiskit.primitive.BaseEstimator.

Une fois que le type de primitive est connu, vous pouvez choisir entre les implΓ©mentations primitives qui s’adaptent mieux Γ  votre cas. Par exemple :

  1. Pour le prototypage rapide, vous pouvez utiliser les implΓ©mentations de rΓ©fΓ©rence des primitives incluses dans Qiskit: qiskit.primitives.Sampler et qiskit.primitives.Estimator.

  2. Pour l’optimisation d’un algorithme plus fin, un simulateur local tel que l’implΓ©mentation primitive dans Aer: qiskit_aer.primitives.Sampler et qiskit_aer.primitives.Estimator.

  3. Pour l’exΓ©cution sur un ordinateur quantique, vous pouvez :

    • des services d’accΓ¨s avec des implΓ©mentations primitives natives, telles que IBM Qiskit Runtime service via qiskit_ibm_runtime.Sampler et qiskit_ibm_runtime.Estimator

    • Enveloppez n’importe quel backend avec Primitives Backend (BackendSampler et ackendEstimator). Ces encapsuleurs implΓ©mentent une interface primitive sur un backend qui ne supporte que Backend.run().

Pour des informations et des exemples plus dΓ©taillΓ©s, en particulier sur l’utilisation des ** Primitives Backend**, reportez-vous au guide de migration Quantum Instance.

In this guide, we will cover 3 different common configurations for algorithms that determine which primitive import you should be selecting:

  1. Running an algorithm with a statevector simulator (i.e., using qiskit.opflow's legacy MatrixExpectation), when you want the ideal outcome without shot noise:

    • Reference Primitives with default configuration (see QAOA example):

    from qiskit.primitives import Sampler, Estimator
    
    • Aer Primitives with statevector simulator (see QAOA example):

    from qiskit_aer.primitives import Sampler, Estimator
    
    sampler = Sampler(backend_options={"method": "statevector"})
    estimator = Estimator(backend_options={"method": "statevector"})
    
  2. Running an algorithm using a simulator/device with shot noise (i.e., using qiskit.opflow's legacy PauliExpectation):

    • Reference Primitives with shots (see VQE examples):

    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 VQE examples):

    from qiskit_aer.primitives import Sampler, Estimator
    
    • IBM’s Qiskit Runtime Primitives with default configuration (see VQD example):

    from qiskit_ibm_runtime import Sampler, Estimator
    

3. Running an algorithm on an Aer simulator using a custom instruction (i.e., using qiskit.opflow's legacy AerPauliExpectation):

  • Aer Primitives with shots=None, approximation=True (see TrotterQRTE example):

from qiskit_aer.primitives import Sampler, Estimator

sampler = Sampler(run_options={"approximation": True, "shots": None})
estimator = Estimator(run_options={"approximation": True, "shots": None})

Minimum Eigensolvers#

*Retour Γ  la * ` TL; DR ` _

The minimum eigensolver algorithms belong to the first type of refactoring listed above (Algorithms refactored in a new location to support primitives). Instead of a QuantumInstance, qiskit.algorithms.minimum_eigensolvers are now initialized using an instance of the Sampler or Estimator primitive, depending on the algorithm. The legacy classes can still be found in qiskit.algorithms.minimum_eigen_solvers.

Attention

For the 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 extra-careful, because the class name does not change.

  • Old import (Quantum Instance based): from qiskit.algorithms import VQE, QAOA, NumPyMinimumEigensolver

  • New import (Primitives based): from qiskit.algorithms.minimum_eigensolvers import VQE, SamplingVQE, QAOA, NumPyMinimumEigensolver

VQE#

The legacy qiskit.algorithms.minimum_eigen_solvers.VQE class has now been split according to the use-case:

Note

In addition to taking in an Estimator instance instead of a QuantumInstance, the new VQE signature has undergone the following changes:

  1. The expectation and include_custom parameters have been removed, as this functionality is now defined at the Estimator level.

  2. The gradient parameter now takes in an instance of a primitive-based gradient class from qiskit.algorithms.gradients instead of the legacy qiskit.opflow.gradients.Gradient class.

  3. The max_evals_grouped parameter has been removed, as it can be set directly on the optimizer class.

  4. 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.

Note

The new VQEResult class does not include the state anymore, as this output was only useful in the case of diagonal operators. However, if it is available as part of the new SamplingVQE’s SamplingVQEResult.

VQE Example

[Legacy] Using Quantum Instance:

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)
(-0.9775390625+0j)

[Updated] Using Primitives:

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)
-0.986328125
VQE applying CVaR (SamplingVQE) Example

[Legacy] Using Quantum Instance:

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)
-1.38

[Updated] Using Primitives:

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)
-1.38

For complete code examples, see the following updated tutorials:

QAOA#

The legacy qiskit.algorithms.minimum_eigen_solvers.QAOA class used to extend qiskit.algorithms.minimum_eigen_solvers.VQE, but now, qiskit.algorithms.minimum_eigensolvers.QAOA extends qiskit.algorithms.minimum_eigensolvers.SamplingVQE. For this reason, the new QAOA only supports diagonal operators.

Note

In addition to taking in an Sampler instance instead of a QuantumInstance, the new QAOA signature has undergone the following changes:

  1. The expectation and include_custom parameters have been removed. In return, the aggregation parameter has been added (it used to be defined through a custom expectation).

  2. The gradient parameter now takes in an instance of a primitive-based gradient class from qiskit.algorithms.gradients instead of the legacy qiskit.opflow.gradients.Gradient class.

  3. The max_evals_grouped parameter has been removed, as it can be set directly on the optimizer class.

  4. The sampler and optimizer are the only parameters that can be defined positionally (and in this order), all others have become keyword-only arguments.

Note

If you want to run QAOA on a non-diagonal operator, you can use the QAOAAnsatz with qiskit.algorithms.minimum_eigensolvers.VQE, but bear in mind there will be no state result. If your application requires the final probability distribution, you can instantiate a Sampler and run it with the optimal circuit after VQE.

Exemple QAOA

[Legacy] Using Quantum Instance:

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)
-4.0

[Updated] Using Primitives:

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)
-3.999999832366272

For complete code examples, see the following updated tutorials:

NumPyMinimumEigensolver#

Because this is a classical solver, the workflow has not changed between the old and new implementation. The import has however changed from qiskit.algorithms.minimum_eigen_solvers.NumPyMinimumEigensolver to qiskit.algorithms.minimum_eigensolvers.NumPyMinimumEigensolver to conform to the new interfaces and result classes.

NumPyMinimumEigensolver Example

[Legacy] Using Quantum Instance:

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)
-1.4142135623730958

[Updated] Using Primitives:

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)
-1.414213562373095

For complete code examples, see the following updated tutorials:

Eigensolvers#

*Retour Γ  la * ` TL; DR ` _

The eigensolver algorithms also belong to the first type of refactoring (Algorithms refactored in a new location to support primitives). Instead of a QuantumInstance, qiskit.algorithms.eigensolvers are now initialized using an instance of the Sampler or Estimator primitive, or a primitive-based subroutine, depending on the algorithm. The legacy classes can still be found in qiskit.algorithms.eigen_solvers.

Attention

For the qiskit.algorithms.eigensolvers classes, depending on the import path, you will access either the primitive-based or the quantum-instance-based implementation. You have to be extra-careful, because the class name does not change.

  • Old import path (Quantum Instance): from qiskit.algorithms import VQD, NumPyEigensolver

  • New import path (Primitives): from qiskit.algorithms.eigensolvers import VQD, NumPyEigensolver

VQD#

The new qiskit.algorithms.eigensolvers.VQD class is initialized with an instance of the Estimator primitive instead of a QuantumInstance. In addition to this, it takes an instance of a state fidelity class from mod:qiskit.algorithms.state_fidelities, such as the Sampler-based ComputeUncompute.

Note

In addition to taking in an Estimator instance instead of a QuantumInstance, the new VQD signature has undergone the following changes:

  1. The expectation and include_custom parameters have been removed, as this functionality is now defined at the Estimator level.

  2. The custom fidelity parameter has been added, and the custom gradient parameter has been removed, as current classes in qiskit.algorithms.gradients cannot deal with state fidelity gradients.

  3. The max_evals_grouped parameter has been removed, as it can be set directly on the optimizer class.

  4. The estimator, fidelity, ansatz and optimizer are the only parameters that can be defined positionally (and in this order), all others have become keyword-only arguments.

Note

Similarly to VQE, the new VQDResult class does not include the state anymore. If your application requires the final probability distribution, you can instantiate a Sampler and run it with the optimal circuit for the desired excited state after running VQD.

Exemple VQD

[Legacy] Using Quantum Instance:

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)
[ 0.01765114+0.0e+00j -0.58507654+0.0e+00j -0.15003642-2.8e-17j]

[Updated] Using Primitives:

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 in cloud simulator
service = QiskitRuntimeService(channel="ibm_quantum")
backend = service.backend("ibmq_qasm_simulator")

with Session(service=service, 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)
[ 0.01765114+0.0e+00j -0.58507654+0.0e+00j -0.15003642-2.8e-17j]

For complete code examples, see the following updated tutorial:

NumPyEigensolver#

Similarly to its minimum eigensolver counterpart, because this is a classical solver, the workflow has not changed between the old and new implementation. The import has however changed from qiskit.algorithms.eigen_solvers.NumPyEigensolver to qiskit.algorithms.eigensolvers.MinimumEigensolver to conform to the new interfaces and result classes.

NumPyEigensolver Example

[Legacy]:

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)
[-1.41421356 -1.41421356]

[Updated]:

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)
[-1.41421356 -1.41421356]

Time Evolvers#

*Retour Γ  la * ` TL; DR ` _

The time evolvers are the last group of algorithms to undergo the first type of refactoring (Algorithms refactored in a new location to support primitives). Instead of a QuantumInstance, qiskit.algorithms.time_evolvers are now initialized using an instance of the Estimator primitive. The legacy classes can still be found in qiskit.algorithms.evolvers.

On top of the migration, the module has been substantially expanded to include Variational Quantum Time Evolution (VarQTE) solvers.

TrotterQRTE#

Attention

For the qiskit.algorithms.time_evolvers.TrotterQRTE class, depending on the import path, you will access either the primitive-based or the quantum-instance-based implementation. You have to be extra-careful, because the class name does not change.

  • Old import path (Quantum Instance): from qiskit.algorithms import TrotterQRTE

  • New import path (Primitives): from qiskit.algorithms.time_evolvers import TrotterQRTE

Note

In addition to taking in an Estimator instance instead of a QuantumInstance, the new VQD signature has undergone the following changes:

  1. The expectation parameter has been removed, as this functionality is now defined at the Estimator level.

  2. The num_timesteps parameters has been added, to allow to define the number of steps the full evolution time is divided into.

TrotterQRTE Example

[Legacy] Using Quantum Instance:

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)
CircuitStateFn(
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
q: ─ exp(-it (X + Z))(1) β”œ
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
)

[Updated] Using Primitives:

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(run_options={"approximation": True, "shots": None})

# LieTrotter with 1 rep
trotter_qrte = TrotterQRTE(estimator=estimator)
evolved_state = trotter_qrte.evolve(evolution_problem).evolved_state

print(evolved_state.decompose())
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
q: ─ exp(it X) β”œβ”€ exp(it Z) β”œ
   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Amplitude Amplifiers#

*Retour Γ  la * ` TL; DR ` _

The amplitude amplifier algorithms belong to the second type of refactoring (Algorithms refactored in-place). Instead of a QuantumInstance, qiskit.algorithms.amplitude_amplifiers are now initialized using an instance of any « Sampler » primitive e.g. Sampler.

Note

The full qiskit.algorithms.amplitude_amplifiers module has been refactored in place. No need to change import paths.

Grover Example

[Legacy] Using Quantum Instance:

from qiskit.algorithms import Grover
from qiskit.utils import QuantumInstance

qi = QuantumInstance(backend=backend)
grover = Grover(quantum_instance=qi)

[Updated] Using Primitives:

from qiskit.algorithms import Grover
from qiskit.primitives import Sampler

grover = Grover(sampler=Sampler())

For complete code examples, see the following updated tutorials:

Amplitude Estimators#

*Retour Γ  la * ` TL; DR ` _

Similarly to the amplitude amplifiers, the amplitude estimators also belong to the second type of refactoring (Algorithms refactored in-place). Instead of a QuantumInstance, qiskit.algorithms.amplitude_estimators are now initialized using an instance of any « Sampler » primitive e.g. Sampler.

Note

The full qiskit.algorithms.amplitude_estimators module has been refactored in place. No need to change import paths.

IAE Example

[Legacy] Using Quantum Instance:

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:

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 complete code examples, see the following updated tutorials:

Phase Estimators#

*Retour Γ  la * ` TL; DR ` _

Finally, the phase estimators are the last group of algorithms to undergo the first type of refactoring (Algorithms refactored in-place). Instead of a QuantumInstance, qiskit.algorithms.phase_estimators are now initialized using an instance of any « Sampler » primitive e.g. Sampler.

Note

The full qiskit.algorithms.phase_estimators module has been refactored in place. No need to change import paths.

IPE Example

[Legacy] Using Quantum Instance:

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:

from qiskit.algorithms import IterativePhaseEstimation
from qiskit.primitives import Sampler

ipe = IterativePhaseEstimation(
    num_iterations=num_iter,
    sampler=Sampler()
)

For complete code examples, see the following updated tutorials: