Skip to content

Commit 3ad87f0

Browse files
schweitzpgi1tnguyenbettinaheimsacpis
authored
[monolithic change] Rework the way CUDA-Q embeds in Python (#3693)
[Python] Total rewrite of the python/CUDA-Q interface. The current implementation of the Python handling of CUDA-Q has baked in various attempts to deal with the language coupling between Python and CUDA-Q kernels. These solutions have been accumulating and making it more and more difficult to work on the Python implementation. These changes are a total rewrite to bring the Python implementation more closely aligned with the C++ implementation. Changes: - The kernel builder and kernel decorator are fundamentally different and will no longer share a duck-typed interface. It doesn't work well. The builder assembles a CUDA-Q kernel dynamically. As such all symbolic references are known immediately. The decorator converts a static AST of code into a CUDA-Q kernel. Symbolic references are either local or not. Non-local symbols are unknown at the point the decorator is processed. All non-local symbols in a decorator are recorded with the decorator itself and lambda lifted as actual arguments. - MLIR requires that symbols be uniqued. The previous implementation ignored this requirement. - Lazy state maintenance in Python and the C++ runtime layers is buggy and not needed. It is removed. This includes dangling MLIR bindings from the AST bridge's python MLIR bindings. - Kernels are no longer built with assumptions, then rebuilt when those guesses prove wrong. Kernels are no longer built and rebuilt for different steps in the process. A kernel decorator builds a target agnostic, context independent kernel, and saves that MLIR ModuleOp under a unique name. - Launch scenarios have been reworked and consolidated to use the ModuleOp directly instead of shuffling between string representations (possibly under maps that were not thread-safe) and ModuleOp instances. - Every step of the process creating a brand new MLIRContext and loading all the dialects into that context, etc. is removed. This is done once and the Python interpreter uses the same context to build all modules. Other changes include: Fix GIL issue in get_state_async. Restructure lambda lifting so it handles recursive ops. Clone the ModuleOps as they go into the make_copyable_function closure to prevent them from being erased along the way. Remove VQE tests. Use VQE from CUDA-QX! Simplifying cudaq::state support. Handle kernel decorator from import module Simplify the symbol table. Python is not a scoped language other than LEGB. Convert kernel builder to generate code compatible with C++ for state initialization of veqs. Refactor the AST bridge to generate state objects from the runtime. Fixes for various tests. and many other changes! Signed-off-by: Eric Schweitz <eschweitz@nvidia.com> Co-authored-by: Thien Nguyen <thiennguyen@nvidia.com> Co-authored-by: Bettina Heim <heimb@outlook.com> Co-authored-by: Sachin Pisal <spisal@nvidia.com>
1 parent d6b8bc7 commit 3ad87f0

File tree

318 files changed

+12650
-15371
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

318 files changed

+12650
-15371
lines changed

.github/workflows/config/spelling_allowlist.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -190,8 +190,6 @@ couplers
190190
cuQuantum
191191
cuTensor
192192
cudaq
193-
dataclass
194-
dataclasses
195193
dataflow
196194
ddots
197195
deallocate
@@ -202,6 +200,8 @@ deallocations
202200
decrement
203201
decrementing
204202
dendrogram
203+
dependence
204+
dependences
205205
deserialize
206206
destructor
207207
detuning

cmake/Modules/CUDAQConfig.cmake

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,13 @@ if (CUDAQ_CUSVSIM_PATH)
5555
set(__base_nvtarget_name "cusvsim")
5656
endif()
5757

58+
# Default Target
59+
add_library(cudaq::cudaq-default-target SHARED IMPORTED)
60+
set_target_properties(cudaq::cudaq-default-target PROPERTIES
61+
IMPORTED_LOCATION "${CUDAQ_LIBRARY_DIR}/libnvqir-${__base_nvtarget_name}-fp64${CMAKE_SHARED_LIBRARY_SUFFIX}"
62+
IMPORTED_SONAME "libnvqir-${__base_nvtarget_name}-fp64${CMAKE_SHARED_LIBRARY_SUFFIX}"
63+
IMPORTED_LINK_INTERFACE_LIBRARIES "cudaq::cudaq-platform-default;cudaq::cudaq-em-default")
64+
5865
# NVIDIA Target
5966
add_library(cudaq::cudaq-nvidia-target SHARED IMPORTED)
6067
set_target_properties(cudaq::cudaq-nvidia-target PROPERTIES
@@ -147,4 +154,4 @@ if(NVIDIA_SMI)
147154
endif()
148155

149156
set(CUDAQ_TARGET ${__tmp_cudaq_target} CACHE STRING "The CUDA Quantum target to compile for and execute on. Defaults to `${__tmp_cudaq_target}`")
150-
cudaq_set_target(${CUDAQ_TARGET})
157+
cudaq_set_target(${CUDAQ_TARGET})

docs/notebook_validation.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,9 @@ def print_results(success, failed, skipped=[]):
143143
## `quantum_transformer`:
144144
## See: https://github.com/NVIDIA/cuda-quantum/issues/2689
145145
notebooks_skipped = [
146-
'quantum_transformer.ipynb', 'logical_aim_sqale.ipynb'
146+
'quantum_transformer.ipynb', 'logical_aim_sqale.ipynb',
147+
'hybrid_quantum_neural_networks.ipynb',
148+
'unitary_compilation_diffusion_models.ipynb', 'qsci.ipynb'
147149
]
148150

149151
for notebook_filename in notebook_filenames:

docs/sphinx/applications/python/adapt_qaoa.ipynb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@
252252
},
253253
{
254254
"cell_type": "code",
255-
"execution_count": 21,
255+
"execution_count": null,
256256
"metadata": {},
257257
"outputs": [],
258258
"source": [
@@ -264,7 +264,7 @@
264264
" qubits = cudaq.qvector(qubits_num)\n",
265265
" h(qubits)\n",
266266
"\n",
267-
"state = cudaq.get_state(initial_state, qubits_num)\n",
267+
"state = cudaq.StateMemoryView(cudaq.get_state(initial_state, qubits_num))\n",
268268
"\n",
269269
"#print(state)\n",
270270
"###############################################\n",
@@ -309,7 +309,7 @@
309309
},
310310
{
311311
"cell_type": "code",
312-
"execution_count": 22,
312+
"execution_count": null,
313313
"metadata": {},
314314
"outputs": [
315315
{
@@ -483,7 +483,7 @@
483483
" else:\n",
484484
"\n",
485485
" # Compute the state of this current step for the gradient\n",
486-
" state = cudaq.get_state(kernel_qaoa, qubits_num, ham_word, ham_coef,mixer_pool, gamma, beta, num_layer)\n",
486+
" state = cudaq.StateMemoryView(cudaq.get_state(kernel_qaoa, qubits_num, ham_word, ham_coef,mixer_pool, gamma, beta, num_layer))\n",
487487
" #print('State at step ', istep)\n",
488488
" #print(state)\n",
489489
" istep+=1\n",
@@ -537,7 +537,7 @@
537537
],
538538
"metadata": {
539539
"kernelspec": {
540-
"display_name": "Python 3 (ipykernel)",
540+
"display_name": "Python 3",
541541
"language": "python",
542542
"name": "python3"
543543
},
@@ -551,7 +551,7 @@
551551
"name": "python",
552552
"nbconvert_exporter": "python",
553553
"pygments_lexer": "ipython3",
554-
"version": "3.10.12"
554+
"version": "3.12.3"
555555
}
556556
},
557557
"nbformat": 4,

docs/sphinx/applications/python/adapt_vqe.ipynb

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@
262262
},
263263
{
264264
"cell_type": "code",
265-
"execution_count": 14,
265+
"execution_count": null,
266266
"metadata": {},
267267
"outputs": [
268268
{
@@ -285,7 +285,7 @@
285285
" for i in range(nelectrons):\n",
286286
" x(qubits[i])\n",
287287
"\n",
288-
"state = cudaq.get_state(initial_state, n_qubits, nelectrons)\n",
288+
"state = cudaq.StateMemoryView(cudaq.get_state(initial_state, n_qubits, nelectrons))\n",
289289
"print(state)"
290290
]
291291
},
@@ -345,7 +345,7 @@
345345
},
346346
{
347347
"cell_type": "code",
348-
"execution_count": 16,
348+
"execution_count": null,
349349
"metadata": {},
350350
"outputs": [
351351
{
@@ -557,8 +557,8 @@
557557
" E_prev=result_vqe.fun\n",
558558
" \n",
559559
" # Prepare a trial state with the current ansatz.\n",
560-
" state=cudaq.get_state(kernel, theta, n_qubits, nelectrons, pool_single, \n",
561-
" coef_single, pool_double, coef_double)\n",
560+
" state=cudaq.StateMemoryView(cudaq.get_state(kernel, theta, n_qubits, nelectrons, pool_single, \n",
561+
" coef_single, pool_double, coef_double))\n",
562562
" \n",
563563
"# When using mpi\n",
564564
"#cudaq.mpi.finalize()"
@@ -574,9 +574,13 @@
574574
],
575575
"metadata": {
576576
"kernelspec": {
577-
"display_name": "Python 3 (ipykernel)",
577+
"display_name": "Python 3",
578578
"language": "python",
579579
"name": "python3"
580+
},
581+
"language_info": {
582+
"name": "python",
583+
"version": "3.12.3"
580584
}
581585
},
582586
"nbformat": 4,

docs/sphinx/applications/python/afqmc_src/vqe_cudaq_qnp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,9 @@ def get_state_vector(self, param_list):
148148
"""
149149
kernel, thetas = self.layers()
150150
state = convert_state_big_endian(
151-
np.array(cudaq.get_state(kernel, param_list), dtype=complex))
151+
np.array(
152+
cudaq.StateMemoryView(cudaq.get_state(kernel, param_list),
153+
dtype=complex)))
152154
return state
153155

154156
def execute(self, hamiltonian):

docs/sphinx/applications/python/entanglement_acc_hamiltonian_simulation.ipynb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@
382382
},
383383
{
384384
"cell_type": "code",
385-
"execution_count": 10,
385+
"execution_count": null,
386386
"id": "7421e3e9-00fb-412a-9b01-4c9b60103e55",
387387
"metadata": {
388388
"id": "7421e3e9-00fb-412a-9b01-4c9b60103e55"
@@ -415,7 +415,7 @@
415415
" \n",
416416
" for step in range(1, r + 1):\n",
417417
" psi_ideal = ideal_next_state(U, psi_ideal)\n",
418-
" t_state = cudaq.get_state(trotter_step_pf1, t_state, dt, c_a, c_b, words_a, words_b)\n",
418+
" t_state = cudaq.StateMemoryView(cudaq.get_state(trotter_step_pf1, t_state, dt, c_a, c_b, words_a, words_b))\n",
419419
" \n",
420420
" psi_t = cp.asarray(t_state, dtype=cp.complex128) \n",
421421
"\n",
@@ -444,7 +444,7 @@
444444
},
445445
{
446446
"cell_type": "code",
447-
"execution_count": 11,
447+
"execution_count": null,
448448
"id": "00b574ce-9cd2-413c-a285-552d04305183",
449449
"metadata": {},
450450
"outputs": [
@@ -464,7 +464,7 @@
464464
"r = 100 # number of PF1 Trotter steps\n",
465465
"\n",
466466
"# initial state \n",
467-
"initial_state = cudaq.get_state(get_initial_state, n)\n",
467+
"initial_state = cudaq.StateMemoryView(cudaq.get_state(get_initial_state, n))\n",
468468
"\n",
469469
"# field strength and coupling strength \n",
470470
"h_x_val, h_y_val, J_val = 0.8090, 0.9045, 1\n",

docs/sphinx/applications/python/hadamard_test.ipynb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@
9292
},
9393
{
9494
"cell_type": "code",
95-
"execution_count": 2,
95+
"execution_count": null,
9696
"metadata": {},
9797
"outputs": [
9898
{
@@ -107,10 +107,10 @@
107107
}
108108
],
109109
"source": [
110-
"psi_state = cudaq.get_state(psi, qubit_num)\n",
110+
"psi_state = cudaq.StateMemoryView(cudaq.get_state(psi, qubit_num))\n",
111111
"print('Psi state: ', psi_state)\n",
112112
"\n",
113-
"phi_state = cudaq.get_state(phi, qubit_num)\n",
113+
"phi_state = cudaq.StateMemoryView(cudaq.get_state(phi, qubit_num))\n",
114114
"print('Phi state: ', phi_state)"
115115
]
116116
},

docs/sphinx/applications/python/hamiltonian_simulation.ipynb

Lines changed: 28 additions & 18 deletions
Large diffs are not rendered by default.

docs/sphinx/applications/python/mps_encoding.ipynb

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -403,7 +403,7 @@
403403
},
404404
{
405405
"cell_type": "code",
406-
"execution_count": 13,
406+
"execution_count": null,
407407
"id": "d753b977",
408408
"metadata": {},
409409
"outputs": [
@@ -424,13 +424,13 @@
424424
"\n",
425425
"# Sanity check\n",
426426
"print(np.dot(\n",
427-
" np.array(cudaq.get_state(qc)).conj().T, statevector\n",
427+
" np.array(cudaq.StateMemoryView(cudaq.get_state(qc))).conj().T, statevector\n",
428428
"))"
429429
]
430430
},
431431
{
432432
"cell_type": "code",
433-
"execution_count": 14,
433+
"execution_count": null,
434434
"id": "3a4e4472",
435435
"metadata": {},
436436
"outputs": [
@@ -451,7 +451,7 @@
451451
"\n",
452452
"# Sanity check\n",
453453
"print(np.dot(\n",
454-
" np.array(cudaq.get_state(qc)).conj().T, statevector\n",
454+
" np.array(cudaq.StateMemoryView(cudaq.get_state(qc))).conj().T, statevector\n",
455455
"))"
456456
]
457457
}

0 commit comments

Comments
 (0)