question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Expectation values of observables in Opflow framework are sometimes incorrect when circuit is deep.

See original GitHub issue

Environment

  • Qiskit Terra version: 0.19.2
  • Python version: 3.9.7
  • Operating system: CentOS 7

What is happening?

For moderately-sized systems where a deep ansatz circuit is used, the expectation value returned by sampling the circuit using CircuitSampler will return a verifiably incorrect answer. I first noticed this issue when running VQE simulations for moderately-sized systems such as H20 (14 qubits), NH3 (16 qubits), and N2 (20 qubits). When using a callback function to print out the function evaluations at each iteration, sometimes the objective function would evaluate to exactly 0.0 or -0.0 when it did not make sense to. The larger the system, the higher the probability that this would happen. I have been able to reproduce this phenomenon outside the context of VQE by simply taking the expectation value of the Hamiltonian with respect to some circuits. This happens, for instance, when the UCCSD ansatz is used, but not when a very shallow ansatz is used.

How can we reproduce the issue?

The following piece of code results in the bug:

from qiskit_nature.drivers import PySCFDriver
from qiskit.algorithms import VQE
from qiskit_nature.problems.second_quantization import ElectronicStructureProblem
from qiskit_nature.converters.second_quantization import QubitConverter
from qiskit_nature.mappers.second_quantization import JordanWignerMapper
from qiskit_nature.circuit.library import UCCSD, HartreeFock
from qiskit.utils.algorithm_globals import algorithm_globals
from qiskit.utils import QuantumInstance
from qiskit.opflow import CircuitStateFn, AerPauliExpectation, StateFn, CircuitSampler
from qiskit.providers.aer import AerSimulator
from qiskit.compiler import transpile
from time import perf_counter, process_time

import numpy as np

interatomic_distance = 1.0977
basis = 'sto6g'
ansatz_reps = 1

algorithm_globals.massive=True
algorithm_globals.random_seed = 1

    
backend = AerSimulator(method='statevector')
quantum_instance = QuantumInstance(backend=backend, seed_transpiler=1)

from qiskit_nature.drivers import PySCFDriver, UnitsType, Molecule
molecule = Molecule(geometry=[['N', [0., 0., 0.]],
                            ['N', [0., 0., interatomic_distance]]],
                    charge=0, multiplicity=1)
driver = PySCFDriver(molecule = molecule, unit=UnitsType.ANGSTROM, basis=basis)
q_molecule = driver.run()

qubit_converter = QubitConverter(JordanWignerMapper())
es_problem = ElectronicStructureProblem(driver=driver)
second_q_op = es_problem.second_q_ops()
qubit_op = qubit_converter.convert(second_q_op[0])

num_qubits = 2*q_molecule.num_molecular_orbitals

HF_state = HartreeFock(num_spin_orbitals=num_qubits,
                                                       num_particles=(q_molecule.num_alpha,q_molecule.num_beta),
                                                       qubit_converter=qubit_converter)

ansatz = UCCSD(qubit_converter=qubit_converter, num_particles=(q_molecule.num_alpha,q_molecule.num_beta), num_spin_orbitals=num_qubits, reps=ansatz_reps, initial_state=HF_state)
#ansatz = HF_state
print(f'Num qubits: {num_qubits}')
print(f'num_parameters: {ansatz.num_parameters}')

expectation = AerPauliExpectation()
observable_meas = expectation.convert(StateFn(qubit_op, is_measurement=True))
ansatz_circuit_op = CircuitStateFn(ansatz)
expect_op = observable_meas.compose(ansatz_circuit_op).reduce()
param_bindings = dict(zip(ansatz.parameters, np.zeros(ansatz.num_parameters).transpose().tolist()))

sampled_expect_op = CircuitSampler(backend=backend).convert(expect_op, params=param_bindings)
means = np.real(sampled_expect_op.eval())
print(means)

This returns:

-0.0

If we un-comment the line ansatz = HF_state, so that the ansatz used is no longer the UCCSD ansatz, but just the HartreeFock circuit (much shallower), then it returns:

-132.16365914584333

What should happen?

In the first instance, we used the UCCSD ansatz with all parameters set to zero, but initialized with the HartreeFock circuit. Thus, the UCCSD part of the circuit should be equivalent to the identity. In the second instance, we are just using the HartreeFock circuit. These two circuits should be equivalent, but they return completely different expectation values.

Any suggestions?

I have tried this on my local machine (MacOS arm64) using the same Qiskit-terra version and have so far not been able to reproduce the bug. This leads me to believe that this issue could be specific to the Linux wheels published, although this is difficult to know for sure because the python environments on the two machines I tested this on likely do not have identical dependencies.

The nature of this bug also seems to be probabilistic in some way. It does not happen every time, but it seems that the deeper the circuit, the higher the probability that it occurs. If the above code needs to be adjusted in any way to ensure reproducibility, please let me know. (I think this is what algorithm_globals.random_seed is supposed to do, but I’m not sure.)

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
mtreinishcommented, Feb 25, 2022

Just fyi the wheels for python 3.6-3.9 qiskit-aer-gpu are live on pypi now (as of yesterday): https://pypi.org/project/qiskit-aer-gpu/0.10.3/ the 3.10 wheels will take a little more time to get ironed out

0reactions
JoelHBiermancommented, Feb 24, 2022

Great thanks! I’ll close this issue for now then because it seems to go away when using the latest version of Aer. If it turns out I just haven’t tried hard enough to reproduce it and it shows up again, I’ll re-open it in the repository that seems most likely to be the issue.

Right now it seems that the fix most likely responsible for fixing this was mentioned in the 0.10.3 release notes as :

“Multi-threaded transpilations to generate diagonal gates will now work correctly if the number of gates of a circuit exceeds fusion_parallelization_threshold. Previously, different threads would occasionally fuse the same element into multiple blocks, causing incorrect results.”

Read more comments on GitHub >

github_iconTop Results From Across the Web

qiskit.opflow.expectations
Expectations are converters which enable the computation of the expectation value of an Observable with respect to some state function. They traverse an ......
Read more >
6.4: Expectation Values, Observables, and Uncertainty
An electron is trapped in a one-dimensional infinite potential well of length L. Find the expectation values of the electron's position and ...
Read more >
qiskit-terra Changelog - PyUp.io
Sampled expectation value for distributions (8748) ... Fix MPL and LaTeX circuit drawer when `idle_wires=False` and there are barriers (8321)
Read more >
(PDF) Approximate Optimization Algorithms with Quantum ...
Here we propose new methods for producing approximate solutions for the maximum cut problem and its weighted version, which are based on ...
Read more >
Water System Design Manual
solutions to the problem and the capacity of the water system to properly ... Automatic air-vacuum relief values installed in the distribution system:...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found