Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Python] Unable to properly find interop kernels. #2348

Open
3 of 4 tasks
boschmitt opened this issue Nov 1, 2024 · 0 comments
Open
3 of 4 tasks

[Python] Unable to properly find interop kernels. #2348

boschmitt opened this issue Nov 1, 2024 · 0 comments

Comments

@boschmitt
Copy link
Collaborator

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

With python device kernel interoperability, users can write quantum kernels in C++ and bind them to python. In such cases, the common pattern is to have a C++ python module that gets imported into a python module.

For example, if we have a python package named foo to which we add C++ extensions using pybind11. The common pattern is to end up with a with a module named _cppfoo (or whaterver). Then, we import all of its symbols to foo:

foo/__init__.py:
  from ._cppfoo import *

Now, if _cppfoo contains a device kernel named bar, then users are able to access it using foo.bar(...). This, however, is not the real path of bar, the real path is foo._cppfoo.bar(..).

Currently, device kernels get registered with their real path name, and thus, when the python AST bridge parse another kernel that uses foo.bar(...), it needs to figure it out if that is its real path or not. This process is not working correctly when there is this extra level of indirection.

Steps to reproduce the bug

Applying the following patch to the repo will create a test case that fails:

diff --git a/python/tests/interop/qlib.py b/python/tests/interop/qlib.py
new file mode 100644
index 000000000..cea8b1861
--- /dev/null
+++ b/python/tests/interop/qlib.py
@@ -0,0 +1,10 @@
+# ============================================================================ #
+# Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates.                   #
+# All rights reserved.                                                         #
+#                                                                              #
+# This source code and the accompanying materials are made available under     #
+# the terms of the Apache License 2.0 which accompanies this distribution.     #
+# ============================================================================ #
+
+from cudaq_test_cpp_algo import *
+
diff --git a/python/tests/interop/test_interop.py b/python/tests/interop/test_interop.py
index 78d46e576..0d52d8e4e 100644
--- a/python/tests/interop/test_interop.py
+++ b/python/tests/interop/test_interop.py
@@ -222,6 +222,27 @@ def test_cpp_kernel_from_python_2():

     callUCCSD()

+def test_cpp_kernel_from_python_3():
+
+    import qlib
+
+    # Sanity checks
+    print(qlib.qstd.qft)
+    print(qlib.qstd.another)
+
+    @cudaq.kernel
+    def callQftAndAnother():
+        q = cudaq.qvector(4)
+        qlib.qstd.qft(q)
+        h(q)
+        qlib.qstd.another(q, 2)
+
+    callQftAndAnother()
+
+    counts = cudaq.sample(callQftAndAnother)
+    counts.dump()
+    assert len(counts) == 1 and '0010' in counts
+
 def test_capture():
     @cudaq.kernel
     def takesCapture(s : int):
@@ -232,4 +253,4 @@ def test_capture():
     @cudaq.kernel(verbose=True)
     def entry():
         takesCapture(spin)
-    entry.compile()
\ No newline at end of file
+    entry.compile()

It creates a level of indirection by creating a new module, qlib, importing the symbols from cudaq_test_cpp_algo, and then trying to call the kernels from qlib, e.g., qlib.qstd.qft.

Expected behavior

CUDA-Q should correctly find the kernel.

Is this a regression? If it is, put the last known working version (or commit) here.

Not a regression

Environment

Suggestions

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant