Repository navigation
Description
Required prerequisites
- Consult the security policy. If reporting a security vulnerability, do not report the bug using this form. Use the process described in the policy to report the issue.
- Make sure you've read the documentation. Your issue may be addressed there.
- Search the issue tracker to verify that this hasn't already been reported. +1 or comment there if it has.
- If possible, make a PR with a failing test to give us a starting point to work on!
Describe the bug
When cudaq.observe gets a list of operators and one element has more than one term, the result for that element ignores the term coefficients. Identity terms still add their coefficient, so the number is neither the raw Pauli expectation nor the operator expectation. With broadcast kernel arguments the same list raises instead.
Steps to reproduce the bug
import numpy as np, cudaq
from cudaq import spin
@cudaq.kernel
def k(t: float):
q = cudaq.qvector(2)
x(q[0])
rx(t, q[1])
Z0 = spin.z(0); Z1 = spin.z(1)
ops = [2*Z0 + 3*Z1, 0.5*Z0*Z1 + 1.0, spin.x(0) + 4*Z1]
print([cudaq.observe(k, o, 0.7).expectation() for o in ops])
print([r.expectation() for r in cudaq.observe(k, ops, 0.7)])
cudaq.observe(k, ops, [0.0, 0.7])Output, rounded to six places, with only the last line of the traceback
[0.294527, 0.617579, 3.059369]
[-0.235158, 0.235158, 0.764842]
ValueError: expecting a spin op with a single term
-0.235158 is <Z0> + <Z1> = -1 + cos(0.7), while 2*Z0 + 3*Z1 has expectation -2 + 3*cos(0.7) = 0.294527.
Expected behavior
The second line should match the first, and the broadcast call should return one such row per argument value.
The list path came in with #3835 for #3745. It sums observe_result.expectation(term) over the terms of each element, and that method returns the raw Pauli string expectation without the coefficient. The test added there only puts a coefficient on the identity term, so it passes either way. The broadcast path in the same function still calls p.expectation(o) on the whole operator, which is the error from #3745.
Is this a regression? If it is, put the last known working version (or commit) here.
Not a regression
Environment
- CUDA-Q version: 0.16.0.post1 (cuda-quantum-cu13 wheel, qpp-cpu target).
python/cudaq/runtime/observe.pyon main is identical to the one in this wheel. - Python version: 3.12.15
- Operating system: Debian 13 (python:3.12-slim container), aarch64
Suggestions
Single-term elements return the raw Pauli expectation. With the kernel above, [2*Z0, -3*Z1] at t = 0.7 gives [-1.0, 0.764842]. That matches the C++ term list overload and test_observe_list, so I would leave it alone and only change the multi-term case. I have a small patch with a test and can open a PR if that sounds right.
Activity
Add figure for PR NVIDIA#5679
muditagrawal2007 commentedon Oct 27, 2026
Thanks for the detailed analysis, this made the fix straightforward to follow.
A PR is open: #5738
It follows the approach you suggested: single term elements keep reporting the
raw Pauli expectation, so
test_observe_listandtest_combine_sweepareunaffected, and only the multi term case changes to the coefficient weighted
sum of its terms, which makes the list form agree with a per operator
observecall.Two things beyond the report turned up while writing the tests, and are
covered as well:
operator: it looked the counts of the identity term up, but the identity is
never measured and has no register, so it raised
RuntimeError: no results stored for.data either, the former scoped the counts to the operator, the latter
returned the counts of the whole list. Both now return the counts of the
single measurement of the whole list.
v0ropaev commentedon Nov 3, 2026
Still an issue on main as far as I can tell. #5738 has the fix and is waiting for review.