Skip to content

cudaq.observe with a list of multi-term operators drops term coefficients, and fails when arguments are broadcast #5679

Open

Description

@v0ropaev

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.py on 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

  1. muditagrawal2007 commented on Oct 27, 2026

    @muditagrawal2007

    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_list and test_combine_sweep are
    unaffected, 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
    observe call.

    Two things beyond the report turned up while writing the tests, and are
    covered as well:

    • The broadcast path was not the only one that failed on an identity only
      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 .
    • The broadcast path and the non broadcast path did not agree on the counts
      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.
  2. v0ropaev commented on Nov 3, 2026

    @v0ropaev
    Author

    Still an issue on main as far as I can tell. #5738 has the fix and is waiting for review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    stale-notifiedStale notification has already fired for this issue

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions