Skip to content

[python] Allow kernel arguments with cudaq.draw's format overload - #5180

Open
udsy19 wants to merge 1 commit into
NVIDIA:mainfrom
udsy19:fix/draw-format-args-assert
Open

[python] Allow kernel arguments with cudaq.draw's format overload#5180
udsy19 wants to merge 1 commit into
NVIDIA:mainfrom
udsy19:fix/draw-format-args-assert

Conversation

@udsy19

@udsy19 udsy19 commented Aug 18, 2026

Copy link
Copy Markdown

The format-string overload of cudaq.draw cannot be used with a kernel that takes
arguments:

@cudaq.kernel
def kernel(theta: float):
    q = cudaq.qvector(2)
    ry(theta, q[0])
    x.ctrl(q[0], q[1])


cudaq.draw(kernel, 0.59)           # works
cudaq.draw("ascii", kernel, 0.59)  # AssertionError

In python/cudaq/runtime/draw.py the format branch asserted len(args) == 1, but in that
overload args is (kernel, *kernel_args), so the assertion holds only for a kernel with
no arguments. The following line, vargs = args[1:], exists to forward those arguments and
could never carry a non-empty value. The non-format branch forwards *args correctly, so
the two overloads disagreed with each other, and the signature documented in the function's
own docstring, in the py_draw.cpp docstring, and in the published API reference was not
usable.

cudaq.getSVGstring and cudaq.displaySVG hit the same path — display_trace.py calls
cudaq.draw("latex", kernel, *args) — so the SVG renderer was broken for every
parameterized kernel.

This is a regression from #3693, which replaced the C++ draw overload set with this
Python shim. The previous pyDraw(std::string format, py::object &kernel, py::args args)
forwarded args in both its ascii and latex branches.

What this changes

-        assert (len(args) == 1) and "must have a kernel"
+        assert len(args) >= 1, "must have a kernel"

Two things on that one line:

  • == becomes >=, so the assertion only checks what it is named for — that a kernel
    was supplied after the format string — and vargs = args[1:] becomes meaningful.
    Argument-count validation is not weakened: _detail_draw already compares the kernel's
    formal arity against the arguments given and raises
    RuntimeError: Invalid number of arguments passed to run. N given and M expected.
    for both too few and too many, in both overloads.
  • assert COND and "msg" becomes assert COND, "msg". In the first form the string is
    folded into the condition — it is truthy, so it never changed the outcome — and the
    AssertionError was raised with no message. Calling cudaq.draw("ascii") with no
    kernel now reports AssertionError: must have a kernel instead of a bare
    AssertionError.

A useful control while confirming the diagnosis: the failing script runs correctly under
python -O, which strips assert statements and changes nothing else. The rest of the
path already handled the arguments; the assertion was the only thing rejecting them.

Testing

python/tests/visualization/test_draw.py gains test_draw_format_with_arguments, placed
next to test_draw, which owns the existing zero-argument cudaq.draw("latex", kernel)
case. It checks that the format overload agrees with the non-format overload, that the
parameter value actually reaches the drawing in both ascii and latex, and that the
no-kernel guard still fires with its message. It fails on main at draw.py:42 and
passes with this change.

No existing test covered this combination: the only format-string call sites in the repo
are test_draw.py:104 and docs/sphinx/examples/python/visualization.ipynb:352, both
with a zero-argument kernel, while every call site that passes kernel arguments uses the
non-format overload. That is why this survived.

Fixes #5179

… arguments

The format-string overload of `cudaq.draw` asserts `len(args) == 1`, but in
that overload `args` is `(kernel, *kernel_args)`, so passing any argument to
the kernel raises `AssertionError`. The very next line, `vargs = args[1:]`,
exists to forward those arguments and is unreachable-by-construction under
`== 1`. The non-format overload forwards `*args` correctly, so the two
overloads disagree, and the documented signature
`cudaq.draw("<format>", kernel, opt_args...)` cannot be used.

This also affects `cudaq.getSVGstring` and `cudaq.displaySVG`, which call
`cudaq.draw("latex", kernel, *args)` in `cudaq/display/display_trace.py`.

Relax the comparison to `>= 1`. Wrong argument counts are still rejected
downstream by `_detail_draw`, which raises `RuntimeError` when the kernel's
formal arity does not match.

Additionally, `assert COND and "msg"` folds the message into the condition,
so the `AssertionError` was raised with no message at all. Use `assert
COND, "msg"` so the "must have a kernel" text is actually reported.

Add a regression test covering the format overload with kernel arguments;
no existing test exercised that combination.

Signed-off-by: Udaya Tejas <udayatejas2004@gmail.com>
@copy-pr-bot

copy-pr-bot Bot commented Aug 18, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions github-actions Bot added the python-lang Anything related to the Python CUDA Quantum language implementation label Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python-lang Anything related to the Python CUDA Quantum language implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

cudaq.draw with a format string and kernel arguments raises AssertionError

1 participant