From 83f384aa120501655862185bb94b2b6abaeecf85 Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Fri, 5 Jun 2026 22:04:45 +0200 Subject: [PATCH 1/5] Add kernel math function support Signed-off-by: LubuSeb <187313664+LubuSeb@users.noreply.github.com> --- cudaq/lib/Frontend/nvqpp/ConvertExpr.cpp | 15 +++++ cudaq/test/AST-Quake/math_functions.cpp | 56 +++++++++++++++++ python/cudaq/kernel/ast_bridge.py | 45 ++++++++++++- python/tests/kernel/test_kernel_float.py | 80 ++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 cudaq/test/AST-Quake/math_functions.cpp diff --git a/cudaq/lib/Frontend/nvqpp/ConvertExpr.cpp b/cudaq/lib/Frontend/nvqpp/ConvertExpr.cpp index f548a749c85..58509e88c4f 100644 --- a/cudaq/lib/Frontend/nvqpp/ConvertExpr.cpp +++ b/cudaq/lib/Frontend/nvqpp/ConvertExpr.cpp @@ -1399,6 +1399,21 @@ bool QuakeBridgeVisitor::visitMathLibFunc(clang::CallExpr *x, (funcName == "tan" || funcName == "tanf")) return floatOperator(math::TanOp{}, "tan"); + // Handle std::asin + if ((isInNamespace(func, "std") || isNotInANamespace(func)) && + (funcName == "asin" || funcName == "asinf")) + return floatOperator(math::AsinOp{}, "asin"); + + // Handle std::acos + if ((isInNamespace(func, "std") || isNotInANamespace(func)) && + (funcName == "acos" || funcName == "acosf")) + return floatOperator(math::AcosOp{}, "acos"); + + // Handle std::atan + if ((isInNamespace(func, "std") || isNotInANamespace(func)) && + (funcName == "atan" || funcName == "atanf")) + return floatOperator(math::AtanOp{}, "atan"); + // Handle std::exp if ((isInNamespace(func, "std") || isNotInANamespace(func)) && (funcName == "exp" || funcName == "expf")) diff --git a/cudaq/test/AST-Quake/math_functions.cpp b/cudaq/test/AST-Quake/math_functions.cpp new file mode 100644 index 00000000000..55666c7e2ac --- /dev/null +++ b/cudaq/test/AST-Quake/math_functions.cpp @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2022 - 2026 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. * + ******************************************************************************/ + +// RUN: cudaq-quake %s | FileCheck %s + +#include +#include + +struct math_functions { + void operator()(double theta) __qpu__ { + cudaq::qubit q; + double angle = std::sin(theta) + std::cos(theta) + std::tan(theta) + + std::asin(theta) + std::acos(theta) + std::atan(theta) + + std::sqrt(theta) + std::exp(theta) + std::log(theta); + rx(angle, q); + } +}; + +struct math_functions_float { + void operator()(float theta) __qpu__ { + cudaq::qubit q; + float angle = sinf(theta) + cosf(theta) + tanf(theta) + asinf(theta) + + acosf(theta) + atanf(theta) + sqrtf(theta) + expf(theta) + + logf(theta); + rx(angle, q); + } +}; + +// CHECK-LABEL: func.func @__nvqpp__mlirgen__math_functions +// CHECK-DAG: math.sin +// CHECK-DAG: math.cos +// CHECK-DAG: math.tan +// CHECK-DAG: math.asin +// CHECK-DAG: math.acos +// CHECK-DAG: math.atan +// CHECK-DAG: math.sqrt +// CHECK-DAG: math.exp +// CHECK-DAG: math.log +// CHECK: quake.rx + +// CHECK-LABEL: func.func @__nvqpp__mlirgen__math_functions_float +// CHECK-DAG: math.sin +// CHECK-DAG: math.cos +// CHECK-DAG: math.tan +// CHECK-DAG: math.asin +// CHECK-DAG: math.acos +// CHECK-DAG: math.atan +// CHECK-DAG: math.sqrt +// CHECK-DAG: math.exp +// CHECK-DAG: math.log +// CHECK: quake.rx diff --git a/python/cudaq/kernel/ast_bridge.py b/python/cudaq/kernel/ast_bridge.py index 5cdbf342701..0afaa774c5f 100644 --- a/python/cudaq/kernel/ast_bridge.py +++ b/python/cudaq/kernel/ast_bridge.py @@ -815,7 +815,10 @@ def isArithmeticType(self, type): type) or F32Type.isinstance(type) or ComplexType.isinstance(type) def __isSupportedNumpyFunction(self, id): - return id in ['sin', 'cos', 'sqrt', 'ceil', 'exp'] + return id in [ + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sqrt', 'ceil', + 'exp', 'log' + ] def __isSupportedVectorFunction(self, id): return id in ['front', 'back', 'append'] @@ -3504,6 +3507,38 @@ def bodyBuilder(iterVar): return self.pushValue(math.SqrtOp(value).result) return + if node.func.attr == 'tan': + if ComplexType.isinstance(value.type): + self.emitFatalError( + f"numpy call ({node.func.attr}) is not " + f"supported for complex numbers", node) + return + self.pushValue(math.TanOp(value).result) + return + if node.func.attr == 'asin': + if ComplexType.isinstance(value.type): + self.emitFatalError( + f"numpy call ({node.func.attr}) is not " + f"supported for complex numbers", node) + return + self.pushValue(math.AsinOp(value).result) + return + if node.func.attr == 'acos': + if ComplexType.isinstance(value.type): + self.emitFatalError( + f"numpy call ({node.func.attr}) is not " + f"supported for complex numbers", node) + return + self.pushValue(math.AcosOp(value).result) + return + if node.func.attr == 'atan': + if ComplexType.isinstance(value.type): + self.emitFatalError( + f"numpy call ({node.func.attr}) is not " + f"supported for complex numbers", node) + return + self.pushValue(math.AtanOp(value).result) + return if node.func.attr == 'exp': if ComplexType.isinstance(value.type): # Note: using `complex.ExpOp` results in a "can't @@ -3527,6 +3562,14 @@ def bodyBuilder(iterVar): return self.pushValue(math.ExpOp(value).result) return + if node.func.attr == 'log': + if ComplexType.isinstance(value.type): + self.emitFatalError( + f"numpy call ({node.func.attr}) is not " + f"supported for complex numbers", node) + return + self.pushValue(math.LogOp(value).result) + return if node.func.attr == 'ceil': if ComplexType.isinstance(value.type): self.emitFatalError( diff --git a/python/tests/kernel/test_kernel_float.py b/python/tests/kernel/test_kernel_float.py index db0c2a166a0..fee01a0abef 100644 --- a/python/tests/kernel/test_kernel_float.py +++ b/python/tests/kernel/test_kernel_float.py @@ -135,6 +135,38 @@ def float_np_use() -> np.float64: t = np.cos(np.float64(np.pi / 2 + 1)) assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (tan) + @cudaq.kernel + def float_np_use() -> np.float64: + return np.tan(np.float64(0.25)) + + t = np.tan(np.float64(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (asin) + @cudaq.kernel + def float_np_use() -> np.float64: + return np.asin(np.float64(0.25)) + + t = np.asin(np.float64(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (acos) + @cudaq.kernel + def float_np_use() -> np.float64: + return np.acos(np.float64(0.25)) + + t = np.acos(np.float64(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (atan) + @cudaq.kernel + def float_np_use() -> np.float64: + return np.atan(np.float64(0.25)) + + t = np.atan(np.float64(0.25)) + assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (sqrt) @cudaq.kernel def float_np_use() -> np.float64: @@ -159,6 +191,14 @@ def float_np_use() -> np.float64: t = np.exp(np.float64(np.pi / 2 + 1)) assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (log) + @cudaq.kernel + def float_np_use() -> np.float64: + return np.log(np.float64(np.pi / 2 + 1)) + + t = np.log(np.float64(np.pi / 2 + 1)) + assert is_close(t, float_np_use()) + # np.float32 @@ -224,6 +264,38 @@ def float_np_use() -> np.float32: t = np.cos(np.float32(np.pi / 2 + 1)) assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (tan) + @cudaq.kernel + def float_np_use() -> np.float32: + return np.tan(np.float32(0.25)) + + t = np.tan(np.float32(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (asin) + @cudaq.kernel + def float_np_use() -> np.float32: + return np.asin(np.float32(0.25)) + + t = np.asin(np.float32(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (acos) + @cudaq.kernel + def float_np_use() -> np.float32: + return np.acos(np.float32(0.25)) + + t = np.acos(np.float32(0.25)) + assert is_close(t, float_np_use()) + + # Use a float inside np in a kernel (atan) + @cudaq.kernel + def float_np_use() -> np.float32: + return np.atan(np.float32(0.25)) + + t = np.atan(np.float32(0.25)) + assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (sqrt) @cudaq.kernel def float_np_use() -> np.float32: @@ -248,6 +320,14 @@ def float_np_use() -> np.float32: t = np.exp(np.float32(np.pi / 2 + 1)) assert is_close(t, float_np_use()) + # Use a float inside np in a kernel (log) + @cudaq.kernel + def float_np_use() -> np.float32: + return np.log(np.float32(np.pi / 2 + 1)) + + t = np.log(np.float32(np.pi / 2 + 1)) + assert is_close(t, float_np_use()) + def test_float_list_parameter_promotion(): From 5f79e6a86b732757afbc9dd8f4c9fd21e1f3a18c Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Thu, 11 Jun 2026 11:23:02 +0200 Subject: [PATCH 2/5] Fix NumPy inverse trig spellings Signed-off-by: LubuSeb <187313664+LubuSeb@users.noreply.github.com> --- python/cudaq/kernel/ast_bridge.py | 10 +++---- python/tests/kernel/test_kernel_float.py | 36 ++++++++++++------------ 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/python/cudaq/kernel/ast_bridge.py b/python/cudaq/kernel/ast_bridge.py index 0afaa774c5f..99cc010c249 100644 --- a/python/cudaq/kernel/ast_bridge.py +++ b/python/cudaq/kernel/ast_bridge.py @@ -816,8 +816,8 @@ def isArithmeticType(self, type): def __isSupportedNumpyFunction(self, id): return id in [ - 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sqrt', 'ceil', - 'exp', 'log' + 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'arcsin', 'arccos', + 'arctan', 'sqrt', 'ceil', 'exp', 'log' ] def __isSupportedVectorFunction(self, id): @@ -3515,7 +3515,7 @@ def bodyBuilder(iterVar): return self.pushValue(math.TanOp(value).result) return - if node.func.attr == 'asin': + if node.func.attr in ['asin', 'arcsin']: if ComplexType.isinstance(value.type): self.emitFatalError( f"numpy call ({node.func.attr}) is not " @@ -3523,7 +3523,7 @@ def bodyBuilder(iterVar): return self.pushValue(math.AsinOp(value).result) return - if node.func.attr == 'acos': + if node.func.attr in ['acos', 'arccos']: if ComplexType.isinstance(value.type): self.emitFatalError( f"numpy call ({node.func.attr}) is not " @@ -3531,7 +3531,7 @@ def bodyBuilder(iterVar): return self.pushValue(math.AcosOp(value).result) return - if node.func.attr == 'atan': + if node.func.attr in ['atan', 'arctan']: if ComplexType.isinstance(value.type): self.emitFatalError( f"numpy call ({node.func.attr}) is not " diff --git a/python/tests/kernel/test_kernel_float.py b/python/tests/kernel/test_kernel_float.py index fee01a0abef..f383f80d69a 100644 --- a/python/tests/kernel/test_kernel_float.py +++ b/python/tests/kernel/test_kernel_float.py @@ -143,28 +143,28 @@ def float_np_use() -> np.float64: t = np.tan(np.float64(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (asin) + # Use a float inside np in a kernel (arcsin) @cudaq.kernel def float_np_use() -> np.float64: - return np.asin(np.float64(0.25)) + return np.arcsin(np.float64(0.25)) - t = np.asin(np.float64(0.25)) + t = np.arcsin(np.float64(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (acos) + # Use a float inside np in a kernel (arccos) @cudaq.kernel def float_np_use() -> np.float64: - return np.acos(np.float64(0.25)) + return np.arccos(np.float64(0.25)) - t = np.acos(np.float64(0.25)) + t = np.arccos(np.float64(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (atan) + # Use a float inside np in a kernel (arctan) @cudaq.kernel def float_np_use() -> np.float64: - return np.atan(np.float64(0.25)) + return np.arctan(np.float64(0.25)) - t = np.atan(np.float64(0.25)) + t = np.arctan(np.float64(0.25)) assert is_close(t, float_np_use()) # Use a float inside np in a kernel (sqrt) @@ -272,28 +272,28 @@ def float_np_use() -> np.float32: t = np.tan(np.float32(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (asin) + # Use a float inside np in a kernel (arcsin) @cudaq.kernel def float_np_use() -> np.float32: - return np.asin(np.float32(0.25)) + return np.arcsin(np.float32(0.25)) - t = np.asin(np.float32(0.25)) + t = np.arcsin(np.float32(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (acos) + # Use a float inside np in a kernel (arccos) @cudaq.kernel def float_np_use() -> np.float32: - return np.acos(np.float32(0.25)) + return np.arccos(np.float32(0.25)) - t = np.acos(np.float32(0.25)) + t = np.arccos(np.float32(0.25)) assert is_close(t, float_np_use()) - # Use a float inside np in a kernel (atan) + # Use a float inside np in a kernel (arctan) @cudaq.kernel def float_np_use() -> np.float32: - return np.atan(np.float32(0.25)) + return np.arctan(np.float32(0.25)) - t = np.atan(np.float32(0.25)) + t = np.arctan(np.float32(0.25)) assert is_close(t, float_np_use()) # Use a float inside np in a kernel (sqrt) From a4daeb020270c7c4ed92f8777d1005b9388ac82a Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Fri, 12 Jun 2026 10:54:05 -0700 Subject: [PATCH 3/5] Apply suggestion from @schweitzpgi Signed-off-by: Eric Schweitz --- cudaq/test/AST-Quake/math_functions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cudaq/test/AST-Quake/math_functions.cpp b/cudaq/test/AST-Quake/math_functions.cpp index 55666c7e2ac..2f5e343d9e7 100644 --- a/cudaq/test/AST-Quake/math_functions.cpp +++ b/cudaq/test/AST-Quake/math_functions.cpp @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2022 - 2026 NVIDIA Corporation & Affiliates. * + * Copyright (c) 2026 NVIDIA Corporation & Affiliates. * * All rights reserved. * * * * This source code and the accompanying materials are made available under * From f8cc1de3c89409744ff75888a168d1f9999ad949 Mon Sep 17 00:00:00 2001 From: LubuSeb <187313664+LubuSeb@users.noreply.github.com> Date: Sun, 14 Jun 2026 02:58:09 +0200 Subject: [PATCH 4/5] Stabilize UCCSD sample assertion Signed-off-by: LubuSeb <187313664+LubuSeb@users.noreply.github.com> --- python/tests/kernel/test_kernel_uccsd.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/python/tests/kernel/test_kernel_uccsd.py b/python/tests/kernel/test_kernel_uccsd.py index 244bc707e55..6ba6de61b86 100644 --- a/python/tests/kernel/test_kernel_uccsd.py +++ b/python/tests/kernel/test_kernel_uccsd.py @@ -545,10 +545,10 @@ def kernel(): counts = cudaq.sample(kernel, shots_count=1000) - assert len(counts) == 6 or len(counts) == 5 - assert '00000011' in counts - assert '00000110' in counts - assert '00010010' in counts - assert '01000010' in counts - assert '10000001' in counts - assert '11000000' in counts + expected_states = { + '00000011', '00000110', '00010010', '01000010', '10000001', + '11000000' + } + observed_states = set(counts) + assert len(observed_states) == 6 or len(observed_states) == 5 + assert observed_states <= expected_states From aa7d30b0b61f86f055d0d4e90304c5841fd0f6a5 Mon Sep 17 00:00:00 2001 From: Eric Schweitz Date: Tue, 23 Jun 2026 09:05:58 -0700 Subject: [PATCH 5/5] yapf changes Signed-off-by: Eric Schweitz --- python/tests/kernel/test_kernel_uccsd.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python/tests/kernel/test_kernel_uccsd.py b/python/tests/kernel/test_kernel_uccsd.py index 6ba6de61b86..4eada3c8ced 100644 --- a/python/tests/kernel/test_kernel_uccsd.py +++ b/python/tests/kernel/test_kernel_uccsd.py @@ -546,8 +546,7 @@ def kernel(): counts = cudaq.sample(kernel, shots_count=1000) expected_states = { - '00000011', '00000110', '00010010', '01000010', '10000001', - '11000000' + '00000011', '00000110', '00010010', '01000010', '10000001', '11000000' } observed_states = set(counts) assert len(observed_states) == 6 or len(observed_states) == 5