qiskit-community / qiskit-algorithms

A library of quantum algorithms for Qiskit.
https://qiskit-community.github.io/qiskit-algorithms/
Apache License 2.0
116 stars 59 forks source link

[from qiskit] Inconsistency of `TimeEvolutionResult.observables` #59

Open ElePT opened 1 year ago

ElePT commented 1 year ago

Environment

What is happening?

As noticed in https://github.com/Qiskit/qiskit-terra/pull/8271#discussion_r1155284375, the value of TimeEvolutionResult.observables differs for the different available implementations.

How can we reproduce the issue?

Here's a snippet for comparison

import numpy as np
from qiskit.circuit import QuantumCircuit
from qiskit.circuit.library import RealAmplitudes
from qiskit.algorithms.state_fidelities import ComputeUncompute
from qiskit.algorithms.optimizers import L_BFGS_B
from qiskit.primitives import Sampler, Estimator
from qiskit.quantum_info import Pauli
from qiskit.algorithms.time_evolvers import (
    TimeEvolutionProblem,
    PVQD,
    VarQRTE,
    SciPyRealEvolver,
    TrotterQRTE,
)

hamiltonian = Pauli("Y")
observables = [Pauli("X"), Pauli("Z")]

ansatz = RealAmplitudes(1, reps=0)
initial_parameters = np.zeros(ansatz.num_parameters)

problem = TimeEvolutionProblem(hamiltonian, time=1, aux_operators=observables)

num_timesteps = 10

fidelity = ComputeUncompute(Sampler())
pvqd = PVQD(
    fidelity,
    ansatz,
    initial_parameters,
    estimator=Estimator(),
    num_timesteps=num_timesteps,
    optimizer=L_BFGS_B(),
)
print("PVQD:")
print(pvqd.evolve(problem).observables)

varqrte = VarQRTE(ansatz, initial_parameters, estimator=Estimator())
print("VarQRTE:")
print(varqrte.evolve(problem).observables)

initial_state = QuantumCircuit(1)
problem.initial_state = ansatz.bind_parameters(initial_parameters)
scipy = SciPyRealEvolver(num_timesteps)
print("SciPy:")
print(scipy.evolve(problem).observables)

trotter = TrotterQRTE(estimator=Estimator())
print("Trotter:")
print(trotter.evolve(problem).observables)

which prints

PVQD:
[array([0., 1.]), array([0.19866933, 0.98006658]), array([0.38941834, 0.92106099]), array([0.56464247, 0.82533562]), array([0.71735609, 0.69670671]), array([0.84147098, 0.54030231]), array([0.93203908, 0.36235776]), array([0.98544973, 0.16996715]), array([ 0.9995736 , -0.02919952]), array([ 0.97384763, -0.22720209]), array([ 0.90929743, -0.41614683])]
VarQRTE:
[[(0.0, {}), (1.0, {})]]
SciPy:
[(array([0.        +0.j, 0.19866933+0.j, 0.38941834+0.j, 0.56464247+0.j,
       0.71735609+0.j, 0.84147098+0.j, 0.93203909+0.j, 0.98544973+0.j,
       0.9995736 +0.j, 0.97384763+0.j, 0.90929743+0.j]), array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])), (array([ 1.        +0.j,  0.98006658+0.j,  0.92106099+0.j,  0.82533561+0.j,
        0.69670671+0.j,  0.54030231+0.j,  0.36235775+0.j,  0.16996714+0.j,
       -0.02919952+0.j, -0.22720209+0.j, -0.41614684+0.j]), array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.]))]
Trotter:
[[(0.0, {}), (1.0, {})], [(0.9092974268256818, {}), (-0.4161468365471423, {})]]

What should happen?

The result types should be consistent. I think from a user perspective, the most convenient would be to capture the expectation values of a single observable over all timesteps in an array, which would allow computing averages or plotting very easily. For example, the format of the SciPyEvolvers seems like a good idea:

observables = [
  (values_observable1, stddevs_observable1),
  (values_observable2, stddevs_observable2),
  ...
]

Any suggestions?

No response

ElePT commented 1 year ago

Opened by @Cryoris Original issue & discussion: https://github.com/Qiskit/qiskit/issues/9905

declanmillar commented 1 year ago

@ElePT, I'm likely going to use the time evolvers for several research projects. So, I'm happy to look at related issues like this one if it's not already covered :).