From 2c9031a0ec6a97e693e85be52fcf90722e71b72f Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Thu, 7 May 2026 19:30:32 -0500 Subject: [PATCH 01/22] allow for unary reductions with arbitrary dims --- lib/cunumeric_jl_wrapper/src/ndarray.cpp | 17 +++++++++++++ src/ndarray/detail/ndarray.jl | 8 ++++++ src/ndarray/unary.jl | 9 ++++++- test/tests/unary_tests.jl | 31 ++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/lib/cunumeric_jl_wrapper/src/ndarray.cpp b/lib/cunumeric_jl_wrapper/src/ndarray.cpp index 47cdf3b02..8b24f6e55 100644 --- a/lib/cunumeric_jl_wrapper/src/ndarray.cpp +++ b/lib/cunumeric_jl_wrapper/src/ndarray.cpp @@ -237,6 +237,23 @@ void nda_unary_reduction(CN_NDArray* out, CuPyNumericUnaryRedCode op_code, out->obj.unary_reduction(op_code, input->obj); } +CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray* input, const int32_t* axes, int32_t num_axes, bool keepdims) { + std::vector axis_vec(axes, axes + num_axes); + NDArray result = input->obj.perform_unary_reduction( + static_cast(op_code), + input->obj, + axis_vec, + std::nullopt, // dtype + std::nullopt, // res_dtype + std::nullopt, // out + keepdims, + {}, // args + std::nullopt, // initial + std::nullopt // where + ); + return new CN_NDArray{NDArray(std::move(result))}; +} + NDArray get_slice(NDArray arr, std::vector slices) { switch (slices.size()) { case 1: { diff --git a/src/ndarray/detail/ndarray.jl b/src/ndarray/detail/ndarray.jl index b11c41015..57160b835 100644 --- a/src/ndarray/detail/ndarray.jl +++ b/src/ndarray/detail/ndarray.jl @@ -219,6 +219,14 @@ function nda_unary_reduction(out::NDArray, op_code::UnaryRedCode, input::NDArray return out end +function nda_unary_reduction_axes(op_code::UnaryRedCode, input::NDArray{T,N}, axes::Vector{Int32}, keepdims::Bool) where {T,N} + axes_c = collect(Int32, axes) + ptr = ccall((:nda_unary_reduction_axes, libnda), + NDArray_t, (UnaryRedCode, NDArray_t, Ptr{Int32}, Int32, Cint), + op_code, input.ptr, axes_c, Int32(length(axes_c)), keepdims) + return NDArray(ptr) +end + function nda_array_equal(rhs1::NDArray{T,N}, rhs2::NDArray{T,N}) where {T,N} ptr = ccall((:nda_array_equal, libnda), NDArray_t, (NDArray_t, NDArray_t), diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index 6cc7b7491..0c0fbc765 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -248,9 +248,16 @@ for (base_func, op_code) in unary_reduction_map function $(Symbol(base_func))(input::NDArray{T}) where {T} T_OUT = Base.promote_op($base_func, Vector{T}) is_wider_type(T_OUT, T) && assertpromotion($base_func, T, T_OUT) - out = cuNumeric.zeros(T_OUT) #0D result (not right if reducing along dims) + out = cuNumeric.zeros(T_OUT) return nda_unary_reduction(out, $(op_code), unchecked_promote_arr(input, T_OUT)) end + + function $(Symbol(base_func))(input::NDArray{T,N}; dims) where {T,N} + T_OUT = Base.promote_op($base_func, Vector{T}) + is_wider_type(T_OUT, T) && assertpromotion($base_func, T, T_OUT) + axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) + return nda_unary_reduction_axes($(op_code), unchecked_promote_arr(input, T_OUT), axes, false) + end end end diff --git a/test/tests/unary_tests.jl b/test/tests/unary_tests.jl index 88f284ff6..1ad7b34f8 100644 --- a/test/tests/unary_tests.jl +++ b/test/tests/unary_tests.jl @@ -88,3 +88,34 @@ function test_unary_function_set(func_dict, T, N) test_unary_operation(func, julia_arr_2D, cunumeric_arr_2D, T) end end + +function test_unary_reduction_dims(func, julia_arr::AbstractArray{T,N}, cunumeric_arr::NDArray{T,N}) where {T,N} + for d in 1:N + julia_res = func(julia_arr, dims=d) + cunumeric_res = func(cunumeric_arr, dims=d) + allowscalar() do + @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + end + end + + if N >= 2 + julia_res = func(julia_arr, dims=(1,2)) + cunumeric_res = func(cunumeric_arr, dims=(1,2)) + allowscalar() do + @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + end + end +end + +@testset "unary reductions with dims" begin + for T in (Float32, Float64, Int32, Int64) + julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) + cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( + [julia_arr_1D], [julia_arr_2D], T, N + ) + @testset "$func $T" for (func, _) in unary_reduction_map + test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) + test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) + end + end +end From 12fff072e61ee4ac3252024058620568959e7f18 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 12:45:53 -0500 Subject: [PATCH 02/22] fix test bug --- test/tests/unary_tests.jl | 1 + 1 file changed, 1 insertion(+) diff --git a/test/tests/unary_tests.jl b/test/tests/unary_tests.jl index 1ad7b34f8..f2cd8f68e 100644 --- a/test/tests/unary_tests.jl +++ b/test/tests/unary_tests.jl @@ -108,6 +108,7 @@ function test_unary_reduction_dims(func, julia_arr::AbstractArray{T,N}, cunumeri end @testset "unary reductions with dims" begin + N = 100 for T in (Float32, Float64, Int32, Int64) julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( From 33d8f60255e44c5f04a8663d69d4a514db109544 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 12:53:04 -0500 Subject: [PATCH 03/22] more testing fixes --- test/tests/unary_tests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/tests/unary_tests.jl b/test/tests/unary_tests.jl index f2cd8f68e..3c562ee1f 100644 --- a/test/tests/unary_tests.jl +++ b/test/tests/unary_tests.jl @@ -114,7 +114,7 @@ end cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( [julia_arr_1D], [julia_arr_2D], T, N ) - @testset "$func $T" for (func, _) in unary_reduction_map + @testset "$func $T" for (func, _) in cuNumeric.unary_reduction_map test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) end From 0a61ee5543f62b390efb19c26362280534b83644 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 13:46:10 -0500 Subject: [PATCH 04/22] fix c++ --- lib/cunumeric_jl_wrapper/src/ndarray.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/cunumeric_jl_wrapper/src/ndarray.cpp b/lib/cunumeric_jl_wrapper/src/ndarray.cpp index 8b24f6e55..ed157b077 100644 --- a/lib/cunumeric_jl_wrapper/src/ndarray.cpp +++ b/lib/cunumeric_jl_wrapper/src/ndarray.cpp @@ -239,7 +239,7 @@ void nda_unary_reduction(CN_NDArray* out, CuPyNumericUnaryRedCode op_code, CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray* input, const int32_t* axes, int32_t num_axes, bool keepdims) { std::vector axis_vec(axes, axes + num_axes); - NDArray result = input->obj.perform_unary_reduction( + NDArray result = input->obj._perform_unary_reduction( static_cast(op_code), input->obj, axis_vec, From 8381f19ca68c6f6d7429521cfd9cce978c6edef4 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 14:03:44 -0500 Subject: [PATCH 05/22] keepdims --- src/ndarray/unary.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index 0c0fbc765..2bf2036d8 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -256,7 +256,7 @@ for (base_func, op_code) in unary_reduction_map T_OUT = Base.promote_op($base_func, Vector{T}) is_wider_type(T_OUT, T) && assertpromotion($base_func, T, T_OUT) axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) - return nda_unary_reduction_axes($(op_code), unchecked_promote_arr(input, T_OUT), axes, false) + return nda_unary_reduction_axes($(op_code), unchecked_promote_arr(input, T_OUT), axes, true) end end end From d7f7635c372357e6e745f0a56944602c75f20cae Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 14:09:38 -0500 Subject: [PATCH 06/22] allow promotion on unit test --- test/tests/unary_tests.jl | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/test/tests/unary_tests.jl b/test/tests/unary_tests.jl index 3c562ee1f..84392cbfe 100644 --- a/test/tests/unary_tests.jl +++ b/test/tests/unary_tests.jl @@ -90,19 +90,21 @@ function test_unary_function_set(func_dict, T, N) end function test_unary_reduction_dims(func, julia_arr::AbstractArray{T,N}, cunumeric_arr::NDArray{T,N}) where {T,N} - for d in 1:N - julia_res = func(julia_arr, dims=d) - cunumeric_res = func(cunumeric_arr, dims=d) - allowscalar() do - @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + allowpromotion(true) do + for d in 1:N + julia_res = func(julia_arr, dims=d) + cunumeric_res = func(cunumeric_arr, dims=d) + allowscalar() do + @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + end end - end - if N >= 2 - julia_res = func(julia_arr, dims=(1,2)) - cunumeric_res = func(cunumeric_arr, dims=(1,2)) - allowscalar() do - @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + if N >= 2 + julia_res = func(julia_arr, dims=(1,2)) + cunumeric_res = func(cunumeric_arr, dims=(1,2)) + allowscalar() do + @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) + end end end end From 9808d8c2d1e33fb3ef209244663e6da63ec83a9f Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 17:58:56 -0500 Subject: [PATCH 07/22] support multi-axis reductions --- lib/cunumeric_jl_wrapper/src/ndarray.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/cunumeric_jl_wrapper/src/ndarray.cpp b/lib/cunumeric_jl_wrapper/src/ndarray.cpp index ed157b077..c0520270b 100644 --- a/lib/cunumeric_jl_wrapper/src/ndarray.cpp +++ b/lib/cunumeric_jl_wrapper/src/ndarray.cpp @@ -239,7 +239,15 @@ void nda_unary_reduction(CN_NDArray* out, CuPyNumericUnaryRedCode op_code, CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray* input, const int32_t* axes, int32_t num_axes, bool keepdims) { std::vector axis_vec(axes, axes + num_axes); - NDArray result = input->obj._perform_unary_reduction( + + auto input_shape = input->obj.shape(); + std::vector out_shape = input_shape; + for (int i = 0; i < num_axes; i++) { + out_shape[axes[i]] = 1; + } + + NDArray out = zeros(out_shape, input->obj.type()); + out._perform_unary_reduction( static_cast(op_code), input->obj, axis_vec, @@ -251,7 +259,7 @@ CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray std::nullopt, // initial std::nullopt // where ); - return new CN_NDArray{NDArray(std::move(result))}; + return new CN_NDArray{NDArray(std::move(out))}; } NDArray get_slice(NDArray arr, std::vector slices) { From 21891b9b6e786cb3c81bd6b46e53712b771c5164 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Tue, 12 May 2026 18:07:29 -0500 Subject: [PATCH 08/22] ok that didnt work --- lib/cunumeric_jl_wrapper/src/ndarray.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/lib/cunumeric_jl_wrapper/src/ndarray.cpp b/lib/cunumeric_jl_wrapper/src/ndarray.cpp index c0520270b..ed157b077 100644 --- a/lib/cunumeric_jl_wrapper/src/ndarray.cpp +++ b/lib/cunumeric_jl_wrapper/src/ndarray.cpp @@ -239,15 +239,7 @@ void nda_unary_reduction(CN_NDArray* out, CuPyNumericUnaryRedCode op_code, CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray* input, const int32_t* axes, int32_t num_axes, bool keepdims) { std::vector axis_vec(axes, axes + num_axes); - - auto input_shape = input->obj.shape(); - std::vector out_shape = input_shape; - for (int i = 0; i < num_axes; i++) { - out_shape[axes[i]] = 1; - } - - NDArray out = zeros(out_shape, input->obj.type()); - out._perform_unary_reduction( + NDArray result = input->obj._perform_unary_reduction( static_cast(op_code), input->obj, axis_vec, @@ -259,7 +251,7 @@ CN_NDArray* nda_unary_reduction_axes(CuPyNumericUnaryRedCode op_code, CN_NDArray std::nullopt, // initial std::nullopt // where ); - return new CN_NDArray{NDArray(std::move(out))}; + return new CN_NDArray{NDArray(std::move(result))}; } NDArray get_slice(NDArray arr, std::vector slices) { From 51d7a44b10742fa6090587c0060d57dece530dea Mon Sep 17 00:00:00 2001 From: krasow Date: Wed, 13 May 2026 11:03:56 -0500 Subject: [PATCH 09/22] refactor impl to add dims keyword --- src/ndarray/unary.jl | 47 ++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index 2bf2036d8..b7244f522 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -242,33 +242,46 @@ global const unary_reduction_map = Dict{Function,UnaryRedCode}( #! IT WOULD BE NICE IF THESE JUST RETURNED SCALARS WHEN APPROPRIATE # #*TODO HOW TO GET THESE ACTING ON CERTAIN DIMS + +function _unary_reduction_impl(base_func, op_code, input::NDArray{T}, ::Colon) where {T} + T_OUT = Base.promote_op(base_func, Vector{T}) + is_wider_type(T_OUT, T) && assertpromotion(base_func, T, T_OUT) + out = cuNumeric.zeros(T_OUT) + return nda_unary_reduction(out, op_code, unchecked_promote_arr(input, T_OUT)) +end + +function _unary_reduction_impl(base_func, op_code, input::NDArray{T,N}, dims) where {T,N} + T_OUT = Base.promote_op(base_func, Vector{T}) + is_wider_type(T_OUT, T) && assertpromotion(base_func, T, T_OUT) + axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) + return nda_unary_reduction_axes(op_code, unchecked_promote_arr(input, T_OUT), axes, true) +end + # Generate code for all unary reductions. for (base_func, op_code) in unary_reduction_map @eval begin - function $(Symbol(base_func))(input::NDArray{T}) where {T} - T_OUT = Base.promote_op($base_func, Vector{T}) - is_wider_type(T_OUT, T) && assertpromotion($base_func, T, T_OUT) - out = cuNumeric.zeros(T_OUT) - return nda_unary_reduction(out, $(op_code), unchecked_promote_arr(input, T_OUT)) - end - - function $(Symbol(base_func))(input::NDArray{T,N}; dims) where {T,N} - T_OUT = Base.promote_op($base_func, Vector{T}) - is_wider_type(T_OUT, T) && assertpromotion($base_func, T, T_OUT) - axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) - return nda_unary_reduction_axes($(op_code), unchecked_promote_arr(input, T_OUT), axes, true) + function $(Symbol(base_func))(input::NDArray{T,N}; dims=Colon()) where {T,N} + return _unary_reduction_impl($base_func, $(op_code), input, dims) end end end -function Base.all(input::NDArray{Bool}) +function _bool_reduction_impl(op_code, input::NDArray{Bool}, ::Colon) out = cuNumeric.zeros(Bool) - return nda_unary_reduction(out, cuNumeric.ALL, input) + return nda_unary_reduction(out, op_code, input) end -function Base.any(input::NDArray{Bool}) - out = cuNumeric.zeros(Bool) - return nda_unary_reduction(out, cuNumeric.ANY, input) +function _bool_reduction_impl(op_code, input::NDArray{Bool}, dims) + axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) + return nda_unary_reduction_axes(op_code, input, axes, true) +end + +function Base.all(input::NDArray{Bool}; dims=Colon()) + return _bool_reduction_impl(cuNumeric.ALL, input, dims) +end + +function Base.any(input::NDArray{Bool}; dims=Colon()) + return _bool_reduction_impl(cuNumeric.ANY, input, dims) end #! ONLY ADD ONCE REDUCTIONS RETURN A SCALAR From 82b04753a9b33c3dd5f7cd4653c97c0feaa57952 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Wed, 13 May 2026 13:34:22 -0500 Subject: [PATCH 10/22] add docs --- src/ndarray/unary.jl | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index b7244f522..922826734 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -209,9 +209,11 @@ The following unary reduction operations are supported and can be applied direct • `prod` • `sum` - These operations follow standard Julia semantics. +Reduction over specific dimensions is supported via the `dims` keyword argument, +following the same semantics as Julia's base reduction functions. + Examples -------- @@ -220,6 +222,14 @@ A = cuNumeric.ones(5) maximum(A) sum(A) + +# Reduce over a specific dimension +B = cuNumeric.ones(3, 4) +sum(B, dims=1) # 1×4 result +sum(B, dims=2) # 3×1 result + +# Reduce over multiple dimensions +sum(B, dims=(1,2)) # 1×1 result ``` """ global const unary_reduction_map = Dict{Function,UnaryRedCode}( From 416450df9cfe7d8fa5616bc35ac5620d7c13b937 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Wed, 13 May 2026 16:22:19 -0500 Subject: [PATCH 11/22] add runtime check --- src/ndarray/unary.jl | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index 922826734..15db3a959 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -264,6 +264,9 @@ function _unary_reduction_impl(base_func, op_code, input::NDArray{T,N}, dims) wh T_OUT = Base.promote_op(base_func, Vector{T}) is_wider_type(T_OUT, T) && assertpromotion(base_func, T, T_OUT) axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) + if length(axes) > 1 + error("$(base_func): reducing over multiple dimensions is not yet supported. Got dims=$dims") + end return nda_unary_reduction_axes(op_code, unchecked_promote_arr(input, T_OUT), axes, true) end From b727d215ae46040a3dc37c37297ba825f9931f86 Mon Sep 17 00:00:00 2001 From: Nader Rahhal <107228500+Nader-Rahhal@users.noreply.github.com> Date: Wed, 13 May 2026 16:56:57 -0500 Subject: [PATCH 12/22] add dispatch --- src/ndarray/unary.jl | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/ndarray/unary.jl b/src/ndarray/unary.jl index 15db3a959..96e69f981 100644 --- a/src/ndarray/unary.jl +++ b/src/ndarray/unary.jl @@ -260,13 +260,21 @@ function _unary_reduction_impl(base_func, op_code, input::NDArray{T}, ::Colon) w return nda_unary_reduction(out, op_code, unchecked_promote_arr(input, T_OUT)) end -function _unary_reduction_impl(base_func, op_code, input::NDArray{T,N}, dims) where {T,N} +function _unary_reduction_impl(base_func, op_code, input::NDArray{T,N}, dims::Integer) where {T,N} T_OUT = Base.promote_op(base_func, Vector{T}) is_wider_type(T_OUT, T) && assertpromotion(base_func, T, T_OUT) - axes = collect(Int32, (d - 1 for d in (dims isa Integer ? (dims,) : dims))) - if length(axes) > 1 + axes = Int32[dims - 1] + return nda_unary_reduction_axes(op_code, unchecked_promote_arr(input, T_OUT), axes, true) +end + +function _unary_reduction_impl(base_func, op_code, input::NDArray{T,N}, dims::Tuple) where {T,N} + if length(dims) > 1 error("$(base_func): reducing over multiple dimensions is not yet supported. Got dims=$dims") end + # single element tuple + T_OUT = Base.promote_op(base_func, Vector{T}) + is_wider_type(T_OUT, T) && assertpromotion(base_func, T, T_OUT) + axes = Int32[dims[1] - 1] return nda_unary_reduction_axes(op_code, unchecked_promote_arr(input, T_OUT), axes, true) end From 53c0bdbede824e1b27b008b15d0cdbf6f635be3c Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 08:29:39 -0500 Subject: [PATCH 13/22] expected failures on multi-axis unary reductions --- test/runtests.jl | 18 +++++++++++++++++- test/tests/unary_tests.jl | 32 +++++++++----------------------- 2 files changed, 26 insertions(+), 24 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index d2396b3f8..31852281b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,4 +1,4 @@ -#= Copyright 2026 Northwestern University, +#= Copyright 2026 Northwestern University, * Carnegie Mellon University University * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -167,6 +167,22 @@ end end end +@testset "Unary Reductions with Dims" begin + N = 100 + for T in (Float32, Float64, Int32, Int64) + @testset "T = $T" begin + julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) + cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( + [julia_arr_1D], [julia_arr_2D], T, N + ) + for (func, _) in cuNumeric.unary_reduction_map + test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) + test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) + end + end + end +end + @testset verbose = true "Binary Ops" begin N = 100 diff --git a/test/tests/unary_tests.jl b/test/tests/unary_tests.jl index 84392cbfe..8c1e4f527 100644 --- a/test/tests/unary_tests.jl +++ b/test/tests/unary_tests.jl @@ -1,4 +1,4 @@ -#= Copyright 2026 Northwestern University, +#= Copyright 2026 Northwestern University, * Carnegie Mellon University University * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -89,36 +89,22 @@ function test_unary_function_set(func_dict, T, N) end end -function test_unary_reduction_dims(func, julia_arr::AbstractArray{T,N}, cunumeric_arr::NDArray{T,N}) where {T,N} +function test_unary_reduction_dims( + func, julia_arr::AbstractArray{T,N}, cunumeric_arr::NDArray{T,N} +) where {T,N} allowpromotion(true) do for d in 1:N - julia_res = func(julia_arr, dims=d) - cunumeric_res = func(cunumeric_arr, dims=d) + julia_res = func(julia_arr; dims=d) + cunumeric_res = func(cunumeric_arr; dims=d) allowscalar() do @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) end end + # we are testing a multi axis reduction. This will throw a runtime error. + # https://github.com/nv-legate/cupynumeric/blob/main/src/cupynumeric/ndarray.cc#L1132 if N >= 2 - julia_res = func(julia_arr, dims=(1,2)) - cunumeric_res = func(cunumeric_arr, dims=(1,2)) - allowscalar() do - @test cuNumeric.compare(julia_res, cunumeric_res, atol(T), rtol(T)) - end - end - end -end - -@testset "unary reductions with dims" begin - N = 100 - for T in (Float32, Float64, Int32, Int64) - julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) - cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( - [julia_arr_1D], [julia_arr_2D], T, N - ) - @testset "$func $T" for (func, _) in cuNumeric.unary_reduction_map - test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) - test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) + @test_throws Exception func(cunumeric_arr, dims=(1, 2)) end end end From 6ca427521be8d20af0e393050dc550d645f746b5 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 08:51:09 -0500 Subject: [PATCH 14/22] add verbose=true --- .githash | 2 +- test/runtests.jl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.githash b/.githash index cee7a1140..0b20e71f0 100644 --- a/.githash +++ b/.githash @@ -1 +1 @@ -ff81537a0c8e23806869eef5c28c235b0dc3fbbe +53c0bdbede824e1b27b008b15d0cdbf6f635be3c diff --git a/test/runtests.jl b/test/runtests.jl index 31852281b..01a9dfee4 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -167,7 +167,7 @@ end end end -@testset "Unary Reductions with Dims" begin +@testset verbose=true "Unary Reductions with Dims" begin N = 100 for T in (Float32, Float64, Int32, Int64) @testset "T = $T" begin From 840b61f97570142e010f8d85e96409ec1230cc18 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 09:11:00 -0500 Subject: [PATCH 15/22] model after Unary Reductions --- test/runtests.jl | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 01a9dfee4..657c6e879 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -169,16 +169,25 @@ end @testset verbose=true "Unary Reductions with Dims" begin N = 100 - for T in (Float32, Float64, Int32, Int64) - @testset "T = $T" begin - julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) - cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( - [julia_arr_1D], [julia_arr_2D], T, N + + @testset for T in Base.uniontypes(cuNumeric.SUPPORTED_ARRAY_TYPES) + julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) + cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( + [julia_arr_1D], [julia_arr_2D], T, N + ) + + @testset "$(func)" for (func, _) in cuNumeric.unary_reduction_map + # Skip reductions not supported by the cuNumeric backend for complex types + if T <: Complex && ( + func == Base.maximum || + func == Base.minimum || + func == Base.prod ) - for (func, _) in cuNumeric.unary_reduction_map - test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) - test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) + continue end + + test_unary_reduction_dims(func, julia_arr_1D, cunumeric_arr_1D) + test_unary_reduction_dims(func, julia_arr_2D, cunumeric_arr_2D) end end end From fd8603035a07b18e4b4c072501e9824e2b97ad7c Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 09:32:06 -0500 Subject: [PATCH 16/22] not sure why developer ci turned on jll mode in the last run --- .github/workflows/developer.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index 10c5094bd..1244c9847 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -89,14 +89,14 @@ jobs: - name: Setup cuNumeric.jl with build from src wrappers run: | - julia --color=yes -e ' + julia --color=yes --project -e ' using Pkg; Pkg.develop(PackageSpec(path = "lib/CNPreferences")) using CNPreferences; CNPreferences.use_developer_mode(); Pkg.develop(PackageSpec(path = ".")) ' - julia --color=yes -e 'using Pkg; Pkg.build("cuNumeric")' + julia --color=yes --project -e 'using Pkg; Pkg.build()' - name: Perform Test run: | - GPUTESTS=0 julia --color=yes -e 'using Pkg; Pkg.test("cuNumeric")' + GPUTESTS=0 julia --color=yes --project -e 'using Pkg; Pkg.test()' From f30a619171b96a0b72e354b616ac5f58911dfa01 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 09:52:32 -0500 Subject: [PATCH 17/22] fix uuid --- .github/workflows/developer.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index 1244c9847..ea5d7acad 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -93,10 +93,14 @@ jobs: using Pkg; Pkg.develop(PackageSpec(path = "lib/CNPreferences")) using CNPreferences; CNPreferences.use_developer_mode(); + ' + julia --color=yes -e ' + using Pkg; + Pkg.develop(PackageSpec(path = "lib/CNPreferences")) Pkg.develop(PackageSpec(path = ".")) + Pkg.build("cuNumeric") ' - julia --color=yes --project -e 'using Pkg; Pkg.build()' - name: Perform Test run: | - GPUTESTS=0 julia --color=yes --project -e 'using Pkg; Pkg.test()' + GPUTESTS=0 julia --color=yes -e 'using Pkg; Pkg.test("cuNumeric")' From 787d502a50ef74bc346e89bae63ad276a94892c9 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 10:08:48 -0500 Subject: [PATCH 18/22] try this --- .github/workflows/developer.yml | 9 +++++---- test/Project.toml | 1 + 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/developer.yml b/.github/workflows/developer.yml index ea5d7acad..f2bef3a89 100644 --- a/.github/workflows/developer.yml +++ b/.github/workflows/developer.yml @@ -89,17 +89,18 @@ jobs: - name: Setup cuNumeric.jl with build from src wrappers run: | - julia --color=yes --project -e ' + julia --color=yes -e ' using Pkg; Pkg.develop(PackageSpec(path = "lib/CNPreferences")) using CNPreferences; CNPreferences.use_developer_mode(); + Pkg.develop(PackageSpec(path = ".")) ' - julia --color=yes -e ' + julia --color=yes --project=test -e ' using Pkg; Pkg.develop(PackageSpec(path = "lib/CNPreferences")) - Pkg.develop(PackageSpec(path = ".")) - Pkg.build("cuNumeric") + using CNPreferences; CNPreferences.use_developer_mode(); ' + julia --color=yes -e 'using Pkg; Pkg.build("cuNumeric")' - name: Perform Test run: | diff --git a/test/Project.toml b/test/Project.toml index 7dd0521e1..8e41dd68b 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -1,4 +1,5 @@ [deps] +CNPreferences = "3e078157-ea10-49d5-bf32-908f777cd46f" CUDA = "052768ef-5323-5732-b1bb-66c8b64840ba" CUDA_Driver_jll = "4ee394cb-3365-5eb0-8335-949819d2adfc" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" From 38a48c841ac20c0ea3a01fe4336176d6981eb43b Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 10:22:17 -0500 Subject: [PATCH 19/22] fix array init --- test/runtests.jl | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 657c6e879..c33e794dc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -171,10 +171,11 @@ end N = 100 @testset for T in Base.uniontypes(cuNumeric.SUPPORTED_ARRAY_TYPES) - julia_arr_1D, julia_arr_2D = make_julia_arrays(T, N, :unit_interval) - cunumeric_arr_1D, cunumeric_arr_2D = make_cunumeric_arrays( - [julia_arr_1D], [julia_arr_2D], T, N - ) + julia_arr_1D = my_rand(T, N) + julia_arr_2D = my_rand(T, (isqrt(N), isqrt(N))) + + cunumeric_arr_1D = @allowscalar NDArray(julia_arr_1D) + cunumeric_arr_2D = @allowscalar NDArray(julia_arr_2D) @testset "$(func)" for (func, _) in cuNumeric.unary_reduction_map # Skip reductions not supported by the cuNumeric backend for complex types From e4cc4b6a778aa828e5647803f594222053797f54 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 10:41:46 -0500 Subject: [PATCH 20/22] try this? --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index c33e794dc..7cf26acfb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -172,7 +172,7 @@ end @testset for T in Base.uniontypes(cuNumeric.SUPPORTED_ARRAY_TYPES) julia_arr_1D = my_rand(T, N) - julia_arr_2D = my_rand(T, (isqrt(N), isqrt(N))) + julia_arr_2D = my_rand(T, isqrt(N), isqrt(N)) cunumeric_arr_1D = @allowscalar NDArray(julia_arr_1D) cunumeric_arr_2D = @allowscalar NDArray(julia_arr_2D) From 3713a2acb6579891706b08f970e99f9ae5e6472f Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 11:08:12 -0500 Subject: [PATCH 21/22] skip CPU and GPU tests on PRs that aren't into main --- .buildkite/pipeline.yml | 2 +- .github/workflows/ci.yml | 2 ++ .github/workflows/container.yml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml index f7bcfd4f8..e9abf561e 100644 --- a/.buildkite/pipeline.yml +++ b/.buildkite/pipeline.yml @@ -28,7 +28,7 @@ steps: agents: queue: "juliagpu" cuda: "*" - if: build.message !~ /\[skip tests\]/ + if: build.message !~ /\[skip tests\]/ && (build.branch == "main" || build.pull_request.base_branch == "main") timeout_in_minutes: 44 env: LD_LIBRARY_PATH: "" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0daab8c40..cb77a387c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,6 +26,8 @@ on: branches: - main pull_request: + branches: + - main paths: - 'src/**' - 'scripts/**' diff --git a/.github/workflows/container.yml b/.github/workflows/container.yml index 00d5d995e..07a68c927 100644 --- a/.github/workflows/container.yml +++ b/.github/workflows/container.yml @@ -18,6 +18,7 @@ on: - main jobs: push_to_registry: + if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} name: Container for ${{ matrix.platform }} - Julia ${{ matrix.julia }} - CUDA ${{ matrix.cuda }} permissions: contents: read From 1a2d299743a74c10be82be97f5e1526f13595144 Mon Sep 17 00:00:00 2001 From: krasow Date: Thu, 14 May 2026 11:35:49 -0500 Subject: [PATCH 22/22] filtering ci.yml --- .githash | 2 +- .github/workflows/ci.yml | 22 ++++++++++++++++------ 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/.githash b/.githash index 6cdfeea5d..f2d1e6df2 100644 --- a/.githash +++ b/.githash @@ -1 +1 @@ -dec047f1bd1c8287513c6c437f946982e516ccd4 +3713a2acb6579891706b08f970e99f9ae5e6472f diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cb77a387c..e979e8968 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,26 +19,36 @@ on: - 'deps/build.jl' - 'Project.toml' - 'lib/CNPreferences/src/**' - - '.github/workflows/ci.yml' - - 'Dockerfile' # container.yml depends on this tags: - 'v*' branches: - main pull_request: - branches: - - main paths: - 'src/**' - 'scripts/**' - 'deps/build.jl' - 'Project.toml' - 'lib/CNPreferences/src/**' - - '.github/workflows/ci.yml' - - 'Dockerfile' # container.yml depends on this jobs: + check_changes: + name: Check for wrapper changes + runs-on: ubuntu-latest + outputs: + wrapper_changed: ${{ steps.filter.outputs.wrapper }} + steps: + - uses: actions/checkout@v4 + - uses: dorny/paths-filter@v3 + id: filter + with: + filters: | + wrapper: + - 'lib/cunumeric_jl_wrapper/**' + test: name: Julia ${{ matrix.julia }} - ${{ matrix.os }} + needs: check_changes + if: ${{ needs.check_changes.outputs.wrapper_changed != 'true' }} runs-on: ${{ matrix.os }} strategy: fail-fast: false