Giter VIP home page Giter VIP logo

qiskit-algorithms's Introduction

Qiskit Algorithms

LicenseBuild StatusCoverage Status

Installation

We encourage installing Qiskit Algorithms via the pip tool (a python package manager).

pip install qiskit-algorithms

pip will handle all dependencies automatically and you will always install the latest (and well-tested) version.

If you want to work on the very latest work-in-progress versions, either to try features ahead of their official release or if you want to contribute to Algorithms, then you can install from source. To do this follow the instructions in the documentation.


Optional Installs

Some optimization algorithms require specific libraries to be run:

  • Scikit-quant, may be installed using the command pip install scikit-quant.

  • SnobFit, may be installed using the command pip install SQSnobFit.

  • NLOpt, may be installed using the command pip install nlopt.


Contribution Guidelines

If you'd like to contribute to Qiskit Algorithms, please take a look at our contribution guidelines. This project adheres to Qiskit's code of conduct. By participating, you are expected to uphold this code.

We use GitHub issues for tracking requests and bugs. Please join the Qiskit Slack community and for discussion and simple questions. For questions that are more suited for a forum, we use the Qiskit tag in Stack Overflow.

Authors and Citation

Qiskit Algorithms was inspired, authored and brought about by the collective work of a team of researchers. Algorithms continues to grow with the help and work of many people, who contribute to the project at different levels. If you use Qiskit, please cite as per the provided BibTeX file.

License

This project uses the Apache License 2.0.

qiskit-algorithms's People

Contributors

1ucian0 avatar a-matsuo avatar anedumla avatar charmerdark avatar cryoris avatar declanmillar avatar divshacker avatar durd3nt avatar elept avatar eric-arellano avatar fs1132429 avatar garrison avatar huangjunye avatar ikkoham avatar jakelishman avatar jlapeyre avatar jwoehr avatar levbishop avatar manoelmarques avatar molar-volume avatar mrossinek avatar mtreinish avatar ng-glen avatar padraignix avatar sooluthomas avatar t-imamichi avatar tamiya-onodera avatar vanimiaou avatar vicenteperezsoloviev avatar woodsp-ibm avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

qiskit-algorithms's Issues

Remove deprecated algorithm use of opflow/QI

This should end up being just the new primitive based algos. The ones that were copied such as VQE, the former ones have been removed, but algos like Grover and AE, which support both, the deprecated opflow/QI path here should go.

Change `AlgorithmsTestCase` base class

What should we add?

Do we still want AlgorithmsTestCase to inherit from QiskitTestCase? (raised by @woodsp-ibm)

QiskitTestCase seems to have a lot of terra-specific setup that is not relevant to algorithm tests. Now that qiskit-algorithms is an independent repository, it might make more sense to follow the test setups of other community repos such as qiskit-optimization, and just add a minimal independent base test class that we can update as required.

Migrate release notes?

How to proceed about the algorithm-related qiskit-terra releasenotes?

TODO/to be discussed

[from qiskit] Two small improvements for EstimationProblem

What should we add?

Hello,
I would like to suggest two small improvements:

  • The EstimationProblem, when not explicitely given a Grover oracle, automatically produces one. Unfortunately, this standard oracle uses the multi-controlled NOT with 'noancillas' mode (lines 168 and 172), which is highly inefficient in terms of circuit depth (it scales as 2**n, where n is the number of qubits, while other implementations scale as n, at the expense of a higher width - refer to mcx). This behavior is very bad as it may strongly affect the performances in applications. I suggest we expose the mcx_mode in the EstimationProblem function, as currently done in GroverOperator. We shall also discuss which value should be the default for mcx_mode: 'noancillas' for backward compatibility?
  • The EstimationProblem has a parameter is_good_state, but the standard QAE is not able to handle it, for obvious reasons. This fact is very confusing. I think we should have a variable to keep trace whether is_good_state is not the default one, and AmplitudeEstimation should throw an exception if given an EstimationProblem with a user-defined is_good_state

I can contribute with the code, if you agree.

Address numpy<1.25 constraint

What should we add?

The numpy version is currently pinned to 1.24 because test_imfil in the test_optimizers_scikitquant.py module breaks with 1.25 (somewhere internal to the imfil optimizer when saving its history). There are 2 possible ways we could avoid this pinning

  1. We could add a numpy version check to test_imfil, similar to what is done with the SnobFit tests in that same test module, which are skipped based on a numpy version check.
  2. The scikit-quant pkg has not been updated in a couple of years, at some point we might want to think whether to keep it at all. If someone really wants to use it, they could still do it via some partial on their minimize.

State Fidelity should not cache circuits based on Python id()

https://docs.python.org/3/library/functions.html#id

Return the “identity” of an object. This is an integer which is guaranteed to be unique and constant for this object during its lifetime. Two objects with non-overlapping lifetimes may have the same id() value.

Id's get reused - this was an issue with the early reference primitives that used id for the key to store/manage circuits see

which is why the reference primitives use a more complex key, which could simply be used for the state fidelity cache instead of id.

# TODO: improve caching, what if the circuit is modified without changing the id?
circuit = self._circuit_cache.get((id(circuit_1), id(circuit_2)))

As to changing the circuit, since the key is more done around contents, and you cache a circuit based on how things were I think this change to key will address that TODO

[from qiskit] SPSA: occasionally evaluate at unperturbed parameters

What should we add?

SPSA is an efficient optimizer that approximates the gradient each iteration using only two evaluations of the cost-function f(theta). These evaluations occur at f(theta+delta) and f(theta-delta), where delta is a perturbation along a chosen axis in parameter space.

Notably, the cost function at the unperturbed parameters, f(theta), is not evaluated until the very end of the optimization process. This makes sense, as evaluating it each iteration would make the optimization take roughly 50% longer. However, it blinds the user to how the actual value of the cost function is evolving over time.

I think it would be helpful to have an option to additionally evaluate f(theta) periodically throughout the optimization. E.g. the user could specify a period of 10 iterations, which would only increase the runtime ~5%. I think this could provide useful diagnostic information, both for post-mortem analyses (e.g. tuning hyperparameters) or for real-time decision making (e.g. deciding whether to terminate an unpromising optimization run early to save time). It should also help produce plots that are easier to interpret.

Also, this could in some cases allow users to manually terminate (interrupt) a lengthy optimization run and still get a usable result, e.g. if the user notices that the optimizer has already converged but still has many iterations left to run, they could interrupt the execution and still salvage a good estimate of f(theta_optimal) from the saved data.

[from qiskit] Inconsistency of `TimeEvolutionResult.observables`

Environment

  • Qiskit Terra version: 0.24
  • Python version: 3.10
  • Operating system: mac OS

What is happening?

As noticed in Qiskit/qiskit#8271 (comment), 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

Figure what to do about `algorithm_globals`

The algorithms, since Aqua days, all used/relied on a central RNG in algorithm_globals which can be seeded for reproducibility. This file is in Qiskit in qiskit.utils and the code here still refers to that. While the file there is not deprecated it was really for the algorithms, hence its name, so I could see it being removed from Qiskit. Most likely we need that function moved/copied here but this will be a change for end users on what should be seeded so we need to figure how to move forwards with this.

Raising QiskitError

While part of Qiskit, qiskit.algorithms raised, in a few places, QiskitError directly. Now there is an AlgorithmError (similar to the apps having their own exceptions) which is also used - maybe this should be raised now in those places too now that algorithms are no longer part of Qiskit. I will note AlgorithmError, and the apps' exceptions, derive from QiskitError, but it will list as the former type in a stacketrace which maybe is more desirable than directly raising QiskitError which may cause confusion now that algorithms is no longer part of Qiskit.

[from qiskit] Use dataclass for AlgorithmResult

What should we add?

Now that the Python 3.6 support is dropped we can use dataclasses in Qiskit. Since our AlgorithmResult was essentially a dictionary replacement we implemented ourselves, should we switch to simply using dataclass as an algorithm result?

That would have advantages like

  • much less overhead in writing algorithm results since no getters/setters are required (the docs can go into the class docstring)
  • access to dataclass features such as easy conversion to dicts or easily creating immutable results

Grover assumes type GroverOperator

In Grover here

max_power = np.ceil(
2 ** (len(amplification_problem.grover_operator.reflection_qubits) / 2)
)
it simply accesses reflection_qubits on what was passed to the AmplificationProblem as a grover_operator
grover_operator: QuantumCircuit | None = None,
but this is of type QuantumCircuit which does not have that field - only the GroverOperator subclass does. This should be more dynamically taken care of such that if a QuantumCircuit is passed, without that field, that it is handled accordingly.

Improve typing

What should we add?

While working on #73, @ElePT and I have identified the following inconsistencies and/or problems around the type hints which should be investigated further. Rather than holding up that PR unnecessarily, we decided to gather these here.
That way, they can be investigated one-by-one.

Note: some of these may very likely require code changes to resolve inconsistencies in the interfaces.

  • Typing around np.ndarray vs Sequence[float]. It is a known issue that to mypy the numpy arrays do not satisfy the Sequence type. This leads to many type ignore statements right now which can hopefully be improved upon.
    • For example, typing around parameter values being passed on to the primitives: sometimes its Sequence[float], sometimes its Sequence[Sequence[float]], and oftentimes internally it ends up as np.ndarray causing many type ignore comments
  • The typing of the initial_point attributes is very inconsistent across its various occurrences.
  • The Minimizer interface does not appear to be supported properly by VQD and PVQD (for example) since they do not provide the required jac argument
  • The ListOrDict type is causing quite some oddities. This has multiple cases:
    • for the metadata (e.g. variance) types and implementations are inconsistent with the variance sometimes wrapped in dictionaries and sometimes provided as a single number
    • for aux_operators and/or observables we had to add many type ignores which would need to be re-evaluated (possibly linked to the previous point)
  • All classes that use the EsimationProblem have very poor typing around the following points:
    • the post_processing function
    • the confidence intervals
    • the circuit_results
  • Add py.typed file back again - removed by #121

IAE: `inverse()` not implemented for reset

Environment

  • Qiskit Algorithms version: 0.2.0
  • Python version:3.10.12
  • Operating system:Linux

What is happening?

While Implementing an IAE routine, when I reset some qubits to |0> using circuit.reset, the following error is shown:

CircuitError: 'inverse() not implemented for reset.'

How can we reproduce the issue?

Make a simple circuit just for testing:

from qiskit import QuantumRegister, ClassicalRegister
from qiskit import QuantumCircuit, execute
from qiskit.circuit.library import IntegerComparator
from qiskit import Aer


backend = Aer.get_backend('aer_simulator')

q = QuantumRegister(9,'q')


circuit = QuantumCircuit(q)

a = 3

comparator = IntegerComparator(num_state_qubits=3, value=a, geq=True)



circuit = circuit.compose(comparator,qubits=[0,1,2,3,7,8])


circuit.reset([3, 4, 5])



The Quantum circuit looks like this:

output

Then simply run the IAE


epsilon = 0.01   # the error
alpha = 0.5      # the alpha value
num_shots = 5000

problem = EstimationProblem(state_preparation=circuit,objective_qubits=[8])     # the quantum circuit

# construct amplitude estimation
iae = IterativeAmplitudeEstimation(
    epsilon_target=epsilon,
    alpha=alpha,
    sampler=Sampler(run_options={"shots": num_shots})
)

and

result = iae.estimate(problem)
print(result)

What should happen?

It should print out IAE result.

Any suggestions?

It has something to do with the reset function, and IAE compatibility with it.

[from qiskit] Unify callback signatures in `qiskit_algorithms.optimizers`

What should we add?

As previously already discussed eg. in Qiskit/qiskit#8628 (comment), it would be great it all Qiskit Optimizers have the same signature for the callback function.

The callback function allows to pass back information on the state of the optimization to the user during the optimization. This is useful to track additional information like the optimization history or to check whether the optimization is converging. However, currently each optimizer has it's own signature on the callback, which makes it difficult to write modular code. It would be great it they had consistent signature, such as:

callback(current_parameters, optimizer_state)

The current parameters are known to each optimizer (also the SciPy optimizers) and additional information could be stored in an optimization state, such as introduced in https://github.com/Qiskit/qiskit-terra/blob/5177db6e09917809895fe37878422ba8fcb6321a/qiskit/algorithms/optimizers/gradient_descent.py#L28

Remove py.typed until #74 is addressed

py.typed was removed in the stable branch since otherwise mypy testing in upstream application repos fails since as typing needs to be addressed - see #74

I would suggest to remove py.typed from main until such time as #74 is addressed to avoid it being included in any future release that might be made before #74 is done.

Add the L-curve solver from `opflow.NaturalGradient`

What should we add?

The L-curve solver implemented in qiskit.opflow.NaturalGradient is a powerful solver for ill-conditioned linear systems. It determines the required regularization by trading off noise in the solution and introduced bias and is an important subroutine in variational time evolution, natural gradient descent or 2nd order gradient descent.

It would be great to have a submodule solvers or linear_systems next to qiskit_algorithms.optimizers where we can add this function.

[from qiskit] Add a `filter_limit` option on `NumPy(Minimum)Eigensolver`

What should we add?

What should we add?

The Problem

When prototyping or debugging non-quantum parts of the stack I often find myself getting back to the NumPy(Minimum)Eigensolver classes. However, in less trivial chemistry applications, the naive lowest eigenvalue is oftentimes not a physical one, so I need to rely on adding a filter_criterion to find a physically meaningful eigenvalue.

Unfortunately, the code currently hard-codes k when a filter_criterion is supplied:
https://github.com/Qiskit/qiskit-terra/blob/332bd9fe0bea82c0fdf7329cea3da115d86e3fc2/qiskit/algorithms/eigensolvers/numpy_eigensolver.py#L257-L259

This means that ALL eigenvalues will be computed, which can take a VERY long time.
The reason for doing this is well motivated though, because one cannot know a priori what value to pick for k.

My proposed solution

I would like to propose that we support setting k and filter_criterion simultaneously.
Since as an end-user I have written the filter_criterion myself, I do have more knowledge about the problem that I am trying to solve. Thus, I may also be able to make an educated guess for k.
And even if that fails, I may be willing to try setting k to 100, then 200, then 300 and so on , rather than having to wait for say 2**10=1024 eigenvalues to be computed regardless of whether my value of interest might have been in the first 10% or so.

I think the prototyping and debugging speed that could be gained here is quite significant.

So in summary:

  • the defaults should remain as they are right now
  • but it should be possible for an end-user to manually set k while also setting a filter_criterion

I would work on this myself, but in the recent months where I thought of doing this I have not found the time to come up with a clean code solution. Thus, I am opening this issue to see if someone else might find this interesting and has the time to do this.
I will gladly review a PR once time has come. Otherwise I might get back to this once I have a bit more time on my hands in the (potentially far) future.

Bring back short imports

With the introduction of primitive-based algorithms we had 2 separate import paths for classes with the same name, so we enforced using the "long" import path to make the import process intentional, instead of allowing importing directly from qiskit.algorithms. For example:

from qiskit.algorithms import VQE used to do: from qiskit.algorithms.minimum_eigen_solvers import VQE, and it was replaced with from qiskit.algorithms.minimum_eigensolvers import VQE for the new VQE class (while from qiskit.algorithms import VQE would import the old class).

Now that the old paths have been deprecated and removed, we can bring back the short import path to point to the new classes, should we want to do it for convenience.

[from qiskit] SamplingMinimumEigensolverResult and subclasses thereof when printing

What should we add?

Printing a SamplingVQE result shows a limited number of fields -it should show the full result as we do for other algorithms.

AlgorithmResult, which SamplingMinimumEigensolverResult inherits, defines a str which prints all the fields in a manner similar to a dict print with field name and value.

SamplingMinimumEigensolverResult however overrides this https://github.com/Qiskit/qiskit-terra/blob/9d336182f41533888a728609ce9e7102bb143180/qiskit/algorithms/minimum_eigensolvers/sampling_mes.py#L128-L138 and prints a limited amount of information. A user then using SamplingVQE or QAOA and printing the result, unlike other algorithm results that print based off AlgorithmResult, sees just this limited data - no info about optimizer, optimal point etc.

I could see this being removed from SamplingMinimumEigensolverResult - but maybe this was done for a nicer format of the fields it does print. The other thought is to have AlgorithmResult prepended to this; or even rework the code to be more like AlgorithResult except these chosen fields to do an improved format. Bottom line is that I think the SamplingVQE result, or other result subclasses should print all their info.

[from qiskit] Optimizer bounds improvement

What should we add?

I would like to discuss improving the way bounds are handled and settle/implement such an improvment:

For variational algorithms, like VQE, that use an optimizer, while the initial_point (x0) for the minimize can be passed through the algorithm, if an optimizer supports/requires bounds the way a user might influence this for the algorithm is not obvious. For instance using BOBYQA with VQE works with RealAmplitudes, but fails with UCC since the later ends up with an unbounded setting which fails on the current code. SNOBIT needs bounds and raises an error to that effect, but how to get it to work is asked. NLOpt global optimizers need a bounds and internally this defaults in the case of any limit being unbounded to something that is not (-3pi or 3pi for lower, upper respectively).

In VQE etc initial point used to be informed by the ansatz (preferred_init_point) such that if an explicit value was not passed by the user then it would look to the ansatz, and if that did not exist then just picked a random point. This implicit informing by ansatz was rather hidden and it was preferred to remove this mechanism. Now the initial point must be set by a user and if its left at the default it will be random. I start since things are similar and action was taken for initial point.

An anstaz can presently inform about parameter_bounds. RealAmplitudes does (-pi, pi), Its NLocal parent defaults to None and UCC extends this (via EvolvedOpAnstz) but does not override this. parameter_bounds has a setter, if you know about it and how this is used by VQE etc., so the value can be set/overridden. For a plain parameterized circuit this property does not exist, but of course, given things are Python. it can set (added) at runtime to inform the bounds for VQE. This allows one to set the bounds such that VQE will run with UCC with BOBYQA etc.

So this is to discuss a possible improvement to variational algos like VQE in regards of bounds:

We could simply just document better how things are currently , a tutorial/howto that covers things.

Another option (which can come with doc improvements related to bounds) would be adding an optional bounds parameter that defaults to None (unbounded)

We could, like was done with initial_point remove the information from the ansatz and require a user to explicitly pass a bounds if the optimizer requires it (optimizers have flags to query such) - but using minimizer protocol this is unknown to the algo. When using an optimizer the variational algo can simply raise an error if no bounds is given and the optimizer needs it. For minimizer it would be reliant on whatever the underlying behavior of the code is in regards of bounds if it fails to get it.

We could leave parameter_bounds on ansatz and make it clear in some improved docs that this is also used and how. A variational algo could let any user defined bounds override any informed by the ansatz. The goal being to have the way bounds is set be more exposed to the user rather than how things are currently and make it easier for them.

@Cryoris @mrossinek @adekusar-drl I would welcome opinions, other ideas....

CI is failing creating html from notebooks

Nightly CI has been failing for the past 3 days (the contents of the repo have not changed at all in that time).

/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:161: ERROR: Unexpected indentation.
/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:169: ERROR: Unexpected indentation.
/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:172: ERROR: Content block expected for the "raw" directive; none found.
/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:191: ERROR: Unexpected indentation.
/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:199: ERROR: Unexpected indentation.
/home/runner/work/qiskit-algorithms/qiskit-algorithms/docs/tutorials/02_vqe_advanced_options.ipynb:202: ERROR: Content block expected for the "raw" directive; none found.

One change that I do notice is that nbconvert is now 7.14.0, and has been failing since that version, where the last time it passed was when 7.13.1 was the latest. It appears to be similar to this issue raised on nbconvert jupyter/nbconvert#2092

ComputeUncompute State Fidelity threading issue

Description

Recently this job failed, as below, in similar manner to that raised by

Looking into this further its not the test case as such rather the ComputeUncompute implementation and the job thread logic it uses, more detail below.

test.state_fidelities.test_compute_uncompute.TestComputeUncompute.test_symmetry
-------------------------------------------------------------------------------

Captured traceback:
~~~~~~~~~~~~~~~~~~~
    Traceback (most recent call last):

      File "/home/runner/work/qiskit-algorithms/qiskit-algorithms/qiskit_algorithms/state_fidelities/compute_uncompute.py", line 161, in _run
    result = job.result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/qiskit/primitives/primitive_job.py", line 55, in result
    return self._future.result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/_base.py", line 437, in result
    return self.__get_result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result
    raise self._exception

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/qiskit/primitives/sampler.py", line 88, in _call
    if len(value) != len(self._parameters[i]):

    IndexError: list index out of range

    
The above exception was the direct cause of the following exception:


    Traceback (most recent call last):

      File "/home/runner/work/qiskit-algorithms/qiskit-algorithms/test/state_fidelities/test_compute_uncompute.py", line 106, in test_symmetry
    results_2 = job_2.result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/site-packages/qiskit/primitives/primitive_job.py", line 55, in result
    return self._future.result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/_base.py", line 437, in result
    return self.__get_result()

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/_base.py", line 389, in __get_result
    raise self._exception

      File "/opt/hostedtoolcache/Python/3.8.18/x64/lib/python3.8/concurrent/futures/thread.py", line 57, in run
    result = self.fn(*self.args, **self.kwargs)

      File "/home/runner/work/qiskit-algorithms/qiskit-algorithms/qiskit_algorithms/state_fidelities/compute_uncompute.py", line 163, in _run
    raise AlgorithmError("Sampler job failed!") from exc

    qiskit_algorithms.exceptions.AlgorithmError: 'Sampler job failed!'

Reproducing the error

Running this script, which replicates the logic the failing test, fairly quickly fails the same way as show above.

import numpy as np

from qiskit.circuit import QuantumCircuit, ParameterVector
from qiskit.primitives import Sampler

from qiskit_algorithms.state_fidelities import ComputeUncompute


def main():
    i = 1
    while True:
        do_fidelity()
        print(f"{i}\r", end="")
        i+=1


def do_fidelity(serial=False):

    parameters = ParameterVector("x", 2)

    circuit = QuantumCircuit(2)
    circuit.rx(parameters[0], 0)
    circuit.rx(parameters[1], 1)

    sampler = Sampler()
    params_l = np.array([[0, 0], [np.pi / 2, 0], [0, np.pi / 2], [np.pi, np.pi]])
    params_r = np.array([[0, 0], [0, 0], [np.pi / 2, 0], [0, 0]])

    fidelity = ComputeUncompute(sampler)
    n = len(params_l)
    job_1 = fidelity.run(
        [circuit] * n, [circuit] * n, params_l, params_r
    )
    job_2 = fidelity.run(
        [circuit] * n, [circuit] * n, params_r, params_l
    )
    results_1 = job_1.result()
    results_2 = job_2.result()

    if not np.allclose(results_1.fidelities, results_2.fidelities, atol=1e-16):
        print("Failed")
        sys.exit()


if __name__ == "__main__":
    main()

Analysis

From investigation it appears that failure is that the sampler.run() is part of the logic called by the function that is passed job thread producing the result. That sampler code updates a number of instance variables and is not safe for such usage. I verified things by acquiring and releasing a threading lock in the fidelity primitive around the run call and the above has run over a weekend with no failure. That will not do as a general solution though.

Suggestion

My suggestion would be, if we want the same async behavior on the result/job, to change what is done in the thread to just be the call to the get the sampler job result, from running the sampler (which should happen in the main thread instead) and format up the result. It will be far less in the thread but that should be safe.

[from qiskit] Chernoff confidence intervals in IAE when summing samples up

What should we add?

In the IAE algorithm, on line 478, shouldn't the probability prob be replaced by round_one_counts/round_shots?

In the case where the data from different iterations with the same Grover power are joined together, only the Clopper Pearson confidence intervals seem to consider the joint information, whereas the Chernoff method considers the total shots but the probability of the latest iteration alone.

GSLS optimizer crashing with QAOA default parameter bounds

Environment

  • Qiskit Algorithms version: 0.2.1
  • Python version: 3.11.1
  • Operating system: Windows 10

What is happening?

When using the GSLS optimizer in combination with the QAOA minimum_eigensolver, the optimization crashes. This seems to stem from the GSLS optimizer not being capable of dealing with parameter bounds of the form [(None, None)].

How can we reproduce the issue?

The bug can be reproduced by trying to compute the minimum eigenvalue of a trivial hamiltonian:

from qiskit import Aer
from qiskit.primitives import BackendSampler
from qiskit.quantum_info import SparsePauliOp
from qiskit_algorithms.optimizers import GSLS
from qiskit_algorithms.minimum_eigensolvers import QAOA

backend = Aer.get_backend("aer_simulator")
sampler = BackendSampler(backend)

optimizer = GSLS()
qaoa = QAOA(optimizer=optimizer, sampler=sampler)

hamiltonian = SparsePauliOp(["ZI"])
result = qaoa.compute_minimum_eigenvalue(hamiltonian)
print(result)

This results in the following Traceback:

Traceback (most recent call last):
  File "C:\...\minimal_example.py", line 19, in <module>
    result = qaoa.compute_minimum_eigenvalue(hamiltonian)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\...\venv\Lib\site-packages\qiskit_algorithms\minimum_eigensolvers\sampling_vqe.py", line 218, in compute_minimum_eigenvalue
    optimizer_result = self.optimizer.minimize(
                       ^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\...\venv\Lib\site-packages\qiskit_algorithms\optimizers\gsls.py", line 125, in minimize
    x, fun, nfev, _ = self.ls_optimize(x0.size, fun, x0, var_lb, var_ub)
                      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\...\venv\Lib\site-packages\qiskit_algorithms\optimizers\gsls.py", line 185, in ls_optimize
    directions, sample_set_x = self.sample_set(n, x, var_lb, var_ub, sample_set_size)
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "C:\...\venv\Lib\site-packages\qiskit_algorithms\optimizers\gsls.py", line 298, in sample_set
    if (points >= var_lb).all() and (points <= var_ub).all():
        ^^^^^^^^^^^^^^^^
TypeError: '>=' not supported between instances of 'float' and 'NoneType'

What should happen?

I would expect the optimization process to finish without crashing and to print the final result.

Any suggestions?

No response

Bump Win CI Python max version too 3.12 when Aer releases 3.12 supported wheels

#108 added support for Python 3.12. This works fine for the algorithms but CI here uses Aer, its listed in requirements.dev, to run the VQE tutorial that shows it with a noise model on Aer. While the published source builds here for CI in Ubuntu and Mac so CI is producing the installs for Aer for 3.12 for those platforms, for Windows it fails to build the wheel. It was decided, see #108, in the interim to limit Win CI here to 3.11 (normally for Mac and Win we do these at min and max Python versions supported - Ubuntu on every version). This issue is a reminder to bump back up the Win CI to 3.12 at when Aer officially supports it and releases pre-built wheels.

Migrate tutorials from qiskit-tutorials

What should we add?

Given Qiskit/qiskit-tutorials#1473, we should migrate algorithm-related tutorials from qiskit-tutorials to qiskit-algorithms.

To do:

  • History-preserving move from qiskit-tutorials/algorithms to qiskit_algorithms/tutorials
  • Update imports in code snippets from qiskit.algorithms to qiskit_algorithms
  • Update API-reference links and other documentation links in the tutorial body
  • Update any references to tutorials in code API docstrings - grover.py has a note that links to the textbook and the tutorial (I noticed this first and searched for others but that was the only place I saw that needed fixing)
  • Update wording around Qiskit. For instance the title of the 1st tutorial is An Introduction to Algorithms in Qiskit and perhaps we need something more like An Introduction to Algorithms for Qiskit instead given the move etc. Text in the main body should be checked over too and reworded appropriately e.g. from same tutorial Qiskit provides a number of Algorithms...
  • Update random_seed setting using algorithm_globals (an import change) - see #33

AdaptVQE deprecated function

AdaptVQE had some deprecated code when brought over from qiskit.algorithms which was not removed and perhaps should have been. The message refers to Qiskit version which will be confusing now. We had expected users to migrate code before moving from qiskit.algorithms to qiskit_algorithms. .

    @deprecate_arg(
        "threshold",
        since="0.24.0",
        pending=True,
        new_alias="gradient_threshold",
    )

I note this is pending deprecated rather than deprecated so perhaps users are not as aware of it. The alternative to removing it is to leave it but switch version and perhaps go over to deprecated and remove it later.

Figure out what to do about use of qiskit.utils validation.py

That file was used by algorithms to validate parameters and have consistent error messages. Though in Qiskit its only used by algorithms (came from Aqua originally) and so I imagine it likely to be removed from Qiskit.

Related to #21

See also Qiskit/qiskit#10516 where its noted and I suggest that simply making a copy here and switching the algorithms to use that here is likely all that is needed on this side since validation is all internal logic here.

IAE works differently for sampler from Aer and Sampler from qiskit ibm runtime.

Environment

  • Qiskit Algorithms version: 0.2.0
  • Python version: 3.10.12
  • Operating system: Linux

What is happening?

Describe the bug : I am working on an Iterative Amplitude Estimation routine that works on sampler. I have a quantum circuit, that I run first using the sampler from aer, I import it from there, simply set
sampler = _Sampler(run_options={"shots": num_shots})

and run the algorithm, It gives me a result of 0.64165 which is very near to what I shoud be getting (i verified it using classical caluclations , it should be around 0.64)

Then I use
from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Estimator, Options

where my qiskit_ibm_runtime version is 0.11.3

Then I run the exact same quantum circuit qc, using backend = "ibmq_qasm_simulator"

options = Options()
options.execution.shots = 2000
options.resilience_level = 0

and then invoke the session and make use of sampler = Sampler(options=options)

The result I'm getting from this is never the same, and is no where close to my answer that I was getting using aer Sampler.

Even though the backend I'm using is IBM_Qasm_simulator , which is error free and ideal simulator, so there should not be any error in the result, but I'm not able to replicate the result that I was getting using the aer sampler. Why is it so? Since both these make use of shot-type backend, the only difference is that one is running on my local device and the other on IBM cloud. But the answers are so different.

Suggested solutions :

Additional Information : I also had a lengthy conversation on Qiskit's slack as well on this said topic
Slack Chat: https://qiskit.slack.com/archives/C7SJ0PJ5A/p1693194989748429?thread_ts=1693194989.748429&cid=C7SJ0PJ5A

  • qiskit-ibm-runtime version: 0.11.3
  • Python version: 3.10.12
  • Operating system: Linux

How can we reproduce the issue?

Steps to reproduce :
Here's the code for the quantum circuit

n = 3
obj = 8
mu = 4
c = 0.1
sigma = 1
a = 0
b = 7
reps = 2
p_s = 0.5
p_b = 0.2
demand = NormalDistribution(num_qubits=n,mu=mu,sigma=sigma,  bounds=[a,b])
supply = RealAmplitudes(n, reps=reps)
supply = supply.assign_parameters(parameters)
qc = QuantumCircuit(9)
qc.compose(demand,qubits=[3,4,5], inplace=True)
qc.compose(supply, qubits = [0,1,2], inplace=True)
z = 6
z1 = 7
for i in range(n):
    qc.x(i)

for i in range(1,n):
    qc.cnot(z,i)

for i in range(1,n):
    qc.cnot(z,i+n)

qc.ccx(0,n,n+n)

qc.x(0)

for i in range(1,n-1):
  qc.cnot(n+n,i)
  qc.cnot(n+n,i+n)
  qc.ccx(i+n,i,n+n)
  qc.ccx(i+n,i,n)

qc.cnot(n+n,n-1)
qc.cnot(n+n,n+n-1)
qc.ccx(n+n-1,n-1,n+n)

for i in range(1,n-1):
    qc.cnot(n,n-i)
    qc.cnot(n,2*n-i)
    qc.ccx(2*n-i-1,n-i-1,n)

for i in range(1,n-1):
    qc.ccx(0,n,n-i)
    qc.ccx(0,n,2*n-i)

qc.x(0)

qc.ccx(0,n,1)

qc.ccx(0,n,n+1)

for i in range(n):
  qc.x(i)

qc.x(2*n)

for i in range(n):
    qc.x(i+n)

for i in range(1,n):
    qc.cnot(z1,i)

for i in range(1,n):
    qc.cnot(z1,i+n)

qc.ccx(0,n,z1)

qc.x(n)

for i in range(1,n-1):
  qc.cnot(z1,i+n)
  qc.cnot(z1,i)
  qc.ccx(i,i+n,z1)
  qc.ccx(i,i+n,0)

qc.cnot(z1,z1-2)
qc.cnot(z1,n-1)
qc.ccx(z1-2,n-1,z1)

for i in range(1,n-1):
    qc.cnot(0,z1-(i+1))
    qc.cnot(0,n-i)
    qc.ccx(z1-i-2,n-i-1,0)

for i in range(1,n-1):
    qc.ccx(0,n,z1-(i+1))
    qc.ccx(0,n,n-i)

qc.x(n)
qc.ccx(0,n,n+1)
qc.ccx(0,n,1)

for i in range(n):
    qc.x(n+i)
qc.x(z1)

for i in range(n):
    c2ry = RYGate(2*c*p_s * 2**(i)).control(2)
    qc.append(c2ry,[i+n,obj-2,obj])

for i in range(n):
    c2ry = RYGate(2*c*p_s * 2**(i)).control(2)
    qc.append(c2ry,[i,obj-1,obj])

for i in range(n):
    c2ry = RYGate(-2*c*p_s * 2**(i)).control(3)
    qc.append(c2ry,[i,obj-1,obj-2,obj])

for i in range(n):
  qc.cry(-2*c*p_b*(2**i),i,obj)

qc.ry(np.pi/2,obj)
qc.draw('mpl')

Once the quantum circuit qc is made, first we import sampler from :

from qiskit_aer.primitives import Sampler

Then call the IAE function:

epsilon = 0.01   # the error
alpha = 0.5      # the alpha value


problem = EstimationProblem(state_preparation=qc,objective_qubits=[obj])     # the quantum circuit

# construct amplitude estimation
iae = IterativeAmplitudeEstimation(
    epsilon_target=epsilon,
    alpha=alpha,
    sampler=Sampler(run_options={"shots": num_shots})
)

and then:

result = iae.estimate(problem)
print(result)
print((result.estimation-0.5)/c)

The result for the final print command is 0.641

But then, when i make use of :

from qiskit_ibm_runtime import QiskitRuntimeService, Sampler, Estimator, Session, Options
# Save an IBM Quantum account.
QiskitRuntimeService.save_account(channel="ibm_quantum", token="MY API TOKEN",overwrite=True)

and then set the backend:

backend = "ibmq_qasm_simulator"

and then the options

options = Options()
options.execution.shots = num_shots
options.resilience_level = 0

and finally calling the IAE:

# runt he circuit on sampler

epsilon = 0.01   # the error
alpha = 0.5



with Session(service=service, backend=backend):
    sampler = Sampler(options = options)
    iae = IterativeAmplitudeEstimation(epsilon_target=epsilon,alpha=alpha, sampler=sampler)
    problem = EstimationProblem(state_preparation=qc,objective_qubits=[obj])
    result = iae.estimate(problem)
    print(result)
    print((result.estimation-0.5)/c)

always give me a different result from what is Intended.

What should happen?

Expected behavior : I expect to see the same behaviour as I was seeing from the aer sampler in qiskit ibm runtime sampler.

Any suggestions?

I already discussed this issue on Slack : https://qiskit.slack.com/archives/C7SJ0PJ5A/p1693194989748429?thread_ts=1693194989.748429&cid=C7SJ0PJ5A

and also opened an Issue in qiskit-ibm-runtime and they suggested to open an issue here,

Qiskit/qiskit-ibm-runtime#1043

[from qiskit] QAOA callback attribute docstring incorrectly includes best measurement

What should we add?

The QOAO callback attribute docstring says this

        callback (Callable[[int, np.ndarray, float, dict[str, Any]], None] | None): A callback
            that can access the intermediate data at each optimization step. These data are: the
            evaluation count, the optimizer parameters for the ansatz, the evaluated value, the
            the metadata dictionary, and the best measurement.

Whereas the callback parameter in the constructor does not have and the best measurement nor does the SamplingVQE callback, in either situation, that this class extends where the callback is done by the parent. I believe and the best measurement should just be simply removed unless there was somehow an intent to have had this - but the callback signature does not accommodate such presently.

Overall release note

Add a release note, with a prelude section that gives an overview of the move of this code out of Qiskit, similar text to what was done there I imagine.

[from qiskit] AQGD optimizer groups objective funtion calls by default

What should we add?

Optimizers are normally expected to use the objective function to evaluate a single point being returned a single value. This is as per scipy optimizers, upon which several are based.

However it was recognized that optimizers computing gradient, say by finite diff, want to evaluate a set of points independently, to compute the gradient, and as such this was parallelizable which could help performance. To inform an optimizer that it was able to do this, ie ask the objective function for the values of a lits of points, where the objective function provided supported that, a max_grouped_evals flag could be set on the optimizer to a number bigger than the default of 1. In this case an optimizer could ask for a list of points and get a list of values back, though. Given the current optimizer spec this should only be done if max_grouped_evals allows it. However it seems a change, not too long ago, altered AQGD to do this by default which violates the current accepted spec we have for optimizers.

So either we change the spec, and require all objective functions to support a list in/out, which I do not think I am in favor of, or we correct AGQD to honor max_grouped_evals. The failure to conform was noted when Qiskit/qiskit#6299 was looked where there is a test with Aer which ends up using the Aer qobj re-parameterization in Circuit Sampler, since it passes in multiple values, and fails in the test when it was attempted to be converted to the newer backend interface.

[from qiskit] Add transition amplitude calculations on NumpyEigensolver

What should we add?

Currently, the NumpyEigensolver implements a _eval_aux_operators which evaluates the auxiliary operators on the excited states.
Without much effort and using an equality in the form of Eq. 13 in https://doi.org/10.1103%2Fphysrevresearch.3.023244, we can extend it to evaluate transition amplitudes for the same auxiliary operators between two eigenstates of the Hamiltonian.
This would allow, among other, the evaluation of non-adiabatic couplings between the excited states (see in the same article).

The idea would be to have a static method for two fixed eigenstates:

@staticmethod
def _eval_transition_amplitudes(
    aux_operators: ListOrDict[OperatorBase], wavefn, wavefm, threshold: float = 1e-12
) -> ListOrDict[Tuple[complex, complex]]:

which would be called by a higher level method for a Dict of pairs (i, j)

def compute_transition_amplitudes(
    self,
    aux_operators: Optional[ListOrDict[OperatorBase]],
    transition_amplitude_pairs: Optional[Dict[Tuple[int, int]]]
) -> Optional[ListOrDict[Tuple[complex, complex]]]:

Consider deprecation and removal of scikit-quant based optimizers

The algorithms.optimizers module contains optimizers based on the scikit-quant package - snobfit, imfil and bobyqa. This source code repo for that package seems pretty much unmaintained with last activity 2 years ago and the snobfit issue /scikit-quant/scikit-quant#24, for which unit tests here are skipped, has been open and without any activity since it was created at the end of last year. The Infil optimizer is now emitting numpy deprecation warnings and will break when that function is changed in numpy.

Unlike when these optimizer "wrappers" were added, to conform to the base Optimizer class, there is now also Minimizer protocol so the scikit-quant optimizers could still be used via that e.g. using a partial over their current interface. And as such, given these are breaking down and failing, no longer seem to be supported, and require using older numpy versions to have them work deprecating and removing them from here seems like best course of action but does no longer preclude someone if they really want to use them doing so via the Minimizer protocol that now exists.

SPSA doc string out of date

Environment

  • Qiskit Algorithms version: 0.2.1
  • Python version:
  • Operating system:

What is happening?

The small code examples in the doc string of qiskit_algorithms/optimizers/spsa.py still show the old signature of optimizers in qiskit instead of the new scipy-style optimizers. This includes a method optimize that is now called minimize, returning point, value, niter instead of OptimizationResult objects, etc.

How can we reproduce the issue?

--

What should happen?

The code examples shout show the new way of using optimizers in qiskit.

Any suggestions?

No response

[from qiskit] Max Likelihood Amplitude Estimator applies post processing twice to the confidence interval

Information

  • Qiskit Terra version: 0.17.1
  • Python version: 3.8.3
  • Operating system: macOS 11.2.3

What is the current behavior?

The confidence_interval of the Max Likelihood Amplitude Estimator is already rescaled. The confidence_interval_processed is rescaled twice. This does not happen for example with the Iterative Amplitude Estimator

Steps to reproduce the problem

Run a Max Likelihood Amplitude Estimator with a post processing function

What is the expected behavior?

Have the confidence_interval not rescaled, and the confidence_interval_processed only rescaled once

Suggested solutions

I haven't seen where the bug is

test/gradients/test_estimator_gradient.py needs updating

/home/runner/work/qiskit-algorithms/qiskit-algorithms/test/gradients/test_estimator_gradient.py:388: DeprecationWarning: The method qiskit.circuit.quantumcircuit.QuantumCircuit.toffoli() is deprecated as of qiskit 0.45.0. It will be removed no earlier than 3 months after the release date. Use QuantumCircuit.ccx as direct replacement.

Test cases and QiskitTestCase

It appears that some unit test cases directly extended QiskitTestCase rather than the QiskitAlgorithmsTestCase (which used to extend that class but since moving from Qiskit no longer does so). The test cases that remain using QiskitTestCase as their parent should be changed to QiskitAlgorithmsTestCase

Update urls in documentation from ecosystem to new github pages location

There are a number of files with links to the docs in qiskit.org/ecosystem that need updating to the new location as follow-up after #115

  • setup.py (see #125)
  • readme.md (see #125)

and also

  • a number of tutorial notebooks #142 updated links except for Aer so now only 01 and 03 tutorials need updating for the couple of Aer links in each once the Aer docs are deployed in a new location. Aer urls updated by #147

and I listed this separately since the notebooks have links to Aer and Nature for which maybe its better to wait until they are all migrated off ecosystem and update them just the once. The redirects will suffice for now.

Update copyright text

Tracking TODOs for 0.1.0.

Update header from:
This code is part of Qiskit to
This code is part of a Qiskit project.

[from qiskit] Extend `qiskit_algorithms.eval_observables` to allow returning a callable

What should we add?

If we want to evaluate a set of expectation values for the same observables and circuits, but with different circuit parameters, we can cache the whole transpilation and basis transformation processes. Qiskit's opflow easily allows this and to leverage this it would be nice if we extended the eval_observables to allow returning a callable that takes as input circuit parameters and returns the (efficiently) evaluated expectation values.

Something like this is already used in #8304 and can be extracted and merged with the existing eval_observables in a follow-up.

Add support for `mps` and `mps.gz` files

What should we add?

Most collections of optimization models use the old-fashioned MPS format for model storage, e.g., MIPLIB. Furthermore, due to their verbosity (compare, e.g., square47.mps.gz wit squaren47.mps from MIPLIB - 80 MB vs. 1.4GB) people tend to use the gzipped files directly.

If qiskit optimization serves as gateway to classical and quantum optimization, I think it makes perfect sense to include this widely-adopted file format. docplex supports mps natively.

CI unit testing has failures under 3.12.1

The nightly CI runs have been failing for the last few nights under Python 3.12 - mainly Ubuntu but it did do it with Mac too (Windows has no 3.12 runs yet - see #108)

E.g. https://github.com/qiskit-community/qiskit-algorithms/actions/runs/7256311824/job/19768394836

  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/stestr/subunit_runner/program.py", line 247, in runTests
    self.result = testRunner.run(self.test)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/stestr/subunit_runner/run.py", line 51, in run
    test(result)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/suite.py", line 122, in run
    test(result)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/case.py", line 692, in __call__
    return self.run(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/case.py", line 662, in run
    result.stopTest(self)
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/subunit/test_results.py", line 127, in stopTest
    return self.super.stopTest(test)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/subunit/test_results.py", line 56, in stopTest
    return self.decorated.stopTest(test)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/site-packages/testtools/testresult/real.py", line 1539, in stopTest
    self._tags = self._tags.parent
                 ^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'parent'

And there are numerous warnings about a lack of addDuration in test result e.g.

/opt/hostedtoolcache/Python/3.12.1/x64/lib/python3.12/unittest/case.py:580: RuntimeWarning: TestResult has no addDuration method
  warnings.warn("TestResult has no addDuration method",

A similar issue is noted here too

[from qiskit] Error in MaximumLikelihoodAmplitudeEstimation when using Sampler

What should we add?

Environment

  • Qiskit Terra version: 0.22.2
  • Python version: 3.9.13
  • Operating system: macOS

What is happening?

Wrong answer when using MaximumLikelihoodAmplitudeEstimationwith with Sampler

How can we reproduce the issue?

from qiskit.utils import QuantumInstance
from qiskit.algorithms import EstimationProblem, MaximumLikelihoodAmplitudeEstimation
from qiskit import Aer, QuantumCircuit
from qiskit.primitives import Sampler
import numpy as np

number_qubits = 3
state_prep =  QuantumCircuit(number_qubits)
for i in range(number_qubits):
    state_prep.h(i)

qi = QuantumInstance(Aer.get_backend("aer_simulator"), shots=4000)
sampler = Sampler()

problem = EstimationProblem(
    state_preparation=state_prep,
    objective_qubits=[number_qubits-1],
)

ae_instance = MaximumLikelihoodAmplitudeEstimation(evaluation_schedule=[0,1,2], quantum_instance=qi)
ae_sampler = MaximumLikelihoodAmplitudeEstimation(evaluation_schedule=[0,1,2], sampler=sampler)

result_instance  = ae_instance.estimate(problem)
result_sampler = ae_sampler.estimate(problem)

print("--------- Correct result ---------")
print("Good counts with aer simulator: ",result_instance.good_counts)
print("Circuit results with aer simulator: " ,result_instance.circuit_results)

conf_int = np.array(result_instance.confidence_interval)
print("Estimated value with aer simulator:    \t%.4f" % (result_instance.estimation_processed))
print("Confidence interval with aer simulator :\t[%.4f, %.4f]" % tuple(conf_int))

print("\n")

print("--------- Incorrect result ---------")
print("Good counts with Sampler:",result_sampler.good_counts)
print("Circuit results with Sampler:",result_sampler.circuit_results)

conf_int = np.array(result_sampler.confidence_interval)
print("Estimated value with Sampler:    \t%.4f" % (result_sampler.estimation_processed))
print("Confidence interval with Sampler:\t[%.4f, %.4f]" % tuple(conf_int))
--------- Correct result ---------
Good counts with aer simulator:  [1976, 2000, 2061]
Circuit results with aer simulator:  
[{'0': 2024, '1': 1976}, 
{'0': 2000, '1': 2000},
 {'0': 1939, '1': 2061}]
Estimated value with aer simulator:  0.5020
Confidence interval with aer simulator : [0.4994, 0.5046]

--------- Incorrect result ---------
Good counts with Sampler: [0, 0, 0]
Circuit results with Sampler: 
[{'000': 0.4999999999999998, '001': 0.4999999999999998}, 
{'000': 0.49999999999999895, '001': 0.49999999999999895},
 {'000': 0.49999999999999817, '001': 0.49999999999999817}]
Estimated value with Sampler:  0.0000
Confidence interval with Sampler:[-0.0000, 0.0000]

What should happen?

Using Sampler should get similar results as with aer simulator

Any suggestions?

I have identified the problem in MaximumLikelihoodAmplitudeEstimation and have created a diagram explaining it:

Screenshot 2022-12-19 at 00 18 42

To fix the issue, I suggest changing some parts in the function estimate in MaximumLikelihoodAmplitudeEstimation. From this:

                if shots is None:
                    for i, quasi_dist in enumerate(ret.quasi_dists):
                        circuit_result = {
                            np.binary_repr(k, circuits[i].num_qubits): v
                            for k, v in quasi_dist.items()
                        }
                        result.circuit_results.append(circuit_result)
                    shots = 1
                else:
                    # get counts and construct MLE input
                    for circuit in circuits:
                        counts = {
                            np.binary_repr(k, circuit.num_qubits): round(v * shots)
                            for k, v in ret.quasi_dists[0].items()
                        }
                        result.circuit_results.append(counts)

To this:

                if shots is None:
                    for i, quasi_dist in enumerate(ret.quasi_dists):
                        circuit_result = {
                            str(k): v
                            for k, v in quasi_dist.items()
                        }
                        result.circuit_results.append(circuit_result)
                    shots = 1
                else:
                    # get counts and construct MLE input
                    for index,circuit in enumerate(circuits):
                        counts = {
                            str(k): round(v * shots)
                            for k, v in ret.quasi_dists[index].items()
                        }
                        result.circuit_results.append(counts)

If everyone agrees with the solution, I would love to try and push the changes (it will be my first time contributing to Qiskit)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.