Skip to content

Commit ee35bf4

Browse files
authored
add allclose function (#770)
* add allclose function
1 parent 06ca5e9 commit ee35bf4

File tree

7 files changed

+155
-0
lines changed

7 files changed

+155
-0
lines changed

dpnp/backend/include/dpnp_iface.hpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,20 @@ void dpnp_memory_memcpy_c(void* dst, const void* src, size_t size_in_bytes);
116116
template <typename _DataType, typename _ResultType>
117117
INP_DLLEXPORT void dpnp_all_c(const void* array, void* result, const size_t size);
118118

119+
/**
120+
* @ingroup BACKEND_API
121+
* @brief Test whether all array elements along a given axis evaluate to True.
122+
*
123+
* @param [in] array1_in First input array.
124+
* @param [in] array2_in Second input array.
125+
* @param [out] result1 Output array.
126+
* @param [in] size Number of input elements in `array`.
127+
* @param [in] rtol_val The relative tolerance parameter.
128+
* @param [in] atol_val The absolute tolerance parameter.
129+
*/
130+
template <typename _DataType1, typename _DataType2, typename _ResultType>
131+
INP_DLLEXPORT void dpnp_allclose_c(const void* array1_in, const void* array2_in, void* result1, const size_t size, double rtol, double atol);
132+
119133
/**
120134
* @ingroup BACKEND_API
121135
* @brief Test whether any array element along a given axis evaluates to True.

dpnp/backend/include/dpnp_iface_fptr.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ enum class DPNPFuncName : size_t
6161
DPNP_FN_ABSOLUTE, /**< Used in numpy.absolute() implementation */
6262
DPNP_FN_ADD, /**< Used in numpy.add() implementation */
6363
DPNP_FN_ALL, /**< Used in numpy.all() implementation */
64+
DPNP_FN_ALLCLOSE, /**< Used in numpy.allclose() implementation */
6465
DPNP_FN_ANY, /**< Used in numpy.any() implementation */
6566
DPNP_FN_ARANGE, /**< Used in numpy.arange() implementation */
6667
DPNP_FN_ARCCOS, /**< Used in numpy.arccos() implementation */

dpnp/backend/kernels/dpnp_krnl_logic.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,52 @@ void dpnp_all_c(const void* array1_in, void* result1, const size_t size)
7171
event.wait();
7272
}
7373

74+
template <typename _DataType1, typename _DataType2, typename _ResultType>
75+
class dpnp_allclose_c_kernel;
76+
77+
template <typename _DataType1, typename _DataType2, typename _ResultType>
78+
void dpnp_allclose_c(const void* array1_in, const void* array2_in, void* result1, const size_t size, double rtol_val, double atol_val)
79+
{
80+
if (!array1_in || !result1)
81+
{
82+
return;
83+
}
84+
85+
const _DataType1* array1 = reinterpret_cast<const _DataType1*>(array1_in);
86+
const _DataType2* array2 = reinterpret_cast<const _DataType2*>(array2_in);
87+
_ResultType* result = reinterpret_cast<_ResultType*>(result1);
88+
89+
result[0] = true;
90+
91+
if (!size)
92+
{
93+
return;
94+
}
95+
96+
cl::sycl::event event;
97+
98+
cl::sycl::range<1> gws(size);
99+
auto kernel_parallel_for_func = [=](cl::sycl::id<1> global_id) {
100+
size_t i = global_id[0];
101+
102+
if (std::abs(array1[i] - array2[i]) > (atol_val + rtol_val * std::abs(array2[i]))){
103+
104+
result[0]= false;
105+
106+
}
107+
108+
};
109+
110+
auto kernel_func = [&](cl::sycl::handler& cgh) {
111+
cgh.parallel_for<class dpnp_allclose_c_kernel<_DataType1, _DataType2, _ResultType>>(gws, kernel_parallel_for_func);
112+
};
113+
114+
event = DPNP_QUEUE.submit(kernel_func);
115+
116+
event.wait();
117+
118+
}
119+
74120
template <typename _DataType, typename _ResultType>
75121
class dpnp_any_c_kernel;
76122

@@ -121,6 +167,23 @@ void func_map_init_logic(func_map_t& fmap)
121167
fmap[DPNPFuncName::DPNP_FN_ALL][eft_FLT][eft_FLT] = {eft_FLT, (void*)dpnp_all_c<float, bool>};
122168
fmap[DPNPFuncName::DPNP_FN_ALL][eft_DBL][eft_DBL] = {eft_DBL, (void*)dpnp_all_c<double, bool>};
123169

170+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_INT][eft_INT] = {eft_BLN, (void*)dpnp_allclose_c<int, int, bool>};
171+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_LNG][eft_INT] = {eft_BLN, (void*)dpnp_allclose_c<long, int, bool>};
172+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_FLT][eft_INT] = {eft_BLN, (void*)dpnp_allclose_c<float, int, bool>};
173+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_DBL][eft_INT] = {eft_BLN, (void*)dpnp_allclose_c<double, int, bool>};
174+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_INT][eft_LNG] = {eft_BLN, (void*)dpnp_allclose_c<int, long, bool>};
175+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_LNG][eft_LNG] = {eft_BLN, (void*)dpnp_allclose_c<long, long, bool>};
176+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_FLT][eft_LNG] = {eft_BLN, (void*)dpnp_allclose_c<float, long, bool>};
177+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_DBL][eft_LNG] = {eft_BLN, (void*)dpnp_allclose_c<double, long, bool>};
178+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_INT][eft_FLT] = {eft_BLN, (void*)dpnp_allclose_c<int, float, bool>};
179+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_LNG][eft_FLT] = {eft_BLN, (void*)dpnp_allclose_c<long, float, bool>};
180+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_FLT][eft_FLT] = {eft_BLN, (void*)dpnp_allclose_c<float, float, bool>};
181+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_DBL][eft_FLT] = {eft_BLN, (void*)dpnp_allclose_c<double, float, bool>};
182+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_INT][eft_DBL] = {eft_BLN, (void*)dpnp_allclose_c<int, double, bool>};
183+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_LNG][eft_DBL] = {eft_BLN, (void*)dpnp_allclose_c<long, double, bool>};
184+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_FLT][eft_DBL] = {eft_BLN, (void*)dpnp_allclose_c<float, double, bool>};
185+
fmap[DPNPFuncName::DPNP_FN_ALLCLOSE][eft_DBL][eft_DBL] = {eft_BLN, (void*)dpnp_allclose_c<double, double, bool>};
186+
124187
fmap[DPNPFuncName::DPNP_FN_ANY][eft_BLN][eft_BLN] = {eft_BLN, (void*)dpnp_any_c<bool, bool>};
125188
fmap[DPNPFuncName::DPNP_FN_ANY][eft_INT][eft_INT] = {eft_INT, (void*)dpnp_any_c<int, bool>};
126189
fmap[DPNPFuncName::DPNP_FN_ANY][eft_LNG][eft_LNG] = {eft_LNG, (void*)dpnp_any_c<long, bool>};

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ cdef extern from "dpnp_iface_fptr.hpp" namespace "DPNPFuncName": # need this na
3636
DPNP_FN_ABSOLUTE
3737
DPNP_FN_ADD
3838
DPNP_FN_ALL
39+
DPNP_FN_ALLCLOSE
3940
DPNP_FN_ANY
4041
DPNP_FN_ARANGE
4142
DPNP_FN_ARCCOS

dpnp/dpnp_algo/dpnp_algo_logic.pyx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ and the rest of the library
3636

3737
__all__ += [
3838
"dpnp_all",
39+
"dpnp_allclose",
3940
"dpnp_any",
4041
"dpnp_equal",
4142
"dpnp_greater",
@@ -55,6 +56,7 @@ __all__ += [
5556

5657

5758
ctypedef void(*custom_logic_1in_1out_func_ptr_t)(void * , void * , const size_t)
59+
ctypedef void(*custom_allclose_1in_1out_func_ptr_t)(void * , void * , void *, const size_t, double, double)
5860

5961

6062
cpdef dparray dpnp_all(dpnp_descriptor array1):
@@ -71,6 +73,21 @@ cpdef dparray dpnp_all(dpnp_descriptor array1):
7173
return result
7274

7375

76+
cpdef dparray dpnp_allclose(dpnp_descriptor array1, dpnp_descriptor array2, double rtol_val, double atol_val):
77+
cdef dparray result = dparray((1,), dtype=numpy.bool)
78+
79+
cdef DPNPFuncType param1_type = dpnp_dtype_to_DPNPFuncType(array1.dtype)
80+
cdef DPNPFuncType param2_type = dpnp_dtype_to_DPNPFuncType(array2.dtype)
81+
82+
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(DPNP_FN_ALLCLOSE, param1_type, param2_type)
83+
84+
cdef custom_allclose_1in_1out_func_ptr_t func = <custom_allclose_1in_1out_func_ptr_t > kernel_data.ptr
85+
86+
func(array1.get_data(), array2.get_data(), result.get_data(), array1.size, rtol_val, atol_val)
87+
88+
return result
89+
90+
7491
cpdef dparray dpnp_any(dpnp_descriptor array1):
7592
cdef dparray result = dparray((1,), dtype=numpy.bool)
7693

dpnp/dpnp_iface_logic.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050

5151
__all__ = [
5252
"all",
53+
"allclose",
5354
"any",
5455
"equal",
5556
"greater",
@@ -122,6 +123,42 @@ def all(x1, axis=None, out=None, keepdims=False):
122123
return call_origin(numpy.all, x1, axis, out, keepdims)
123124

124125

126+
def allclose(x1, x2, rtol=1.e-5, atol=1.e-8, **kwargs):
127+
"""
128+
Returns True if two arrays are element-wise equal within a tolerance.
129+
130+
For full documentation refer to :obj:`numpy.allclose`.
131+
132+
Limitations
133+
-----------
134+
Parameters ``x1`` and ``x2`` are supported as either :obj:`dpnp.ndarray` or scalar.
135+
Keyword arguments ``kwargs`` are currently unsupported.
136+
Otherwise the functions will be executed sequentially on CPU.
137+
Input array data types are limited by supported DPNP :ref:`Data types`.
138+
139+
Examples
140+
--------
141+
>>> import dpnp as np
142+
>>> np.allclose([1e10,1e-7], [1.00001e10,1e-8])
143+
>>> False
144+
145+
"""
146+
147+
rtol_is_scalar = dpnp.isscalar(rtol)
148+
atol_is_scalar = dpnp.isscalar(atol)
149+
x1_desc = dpnp.get_dpnp_descriptor(x1)
150+
x2_desc = dpnp.get_dpnp_descriptor(x2)
151+
152+
if x1_desc and x2_desc and not kwargs:
153+
if not rtol_is_scalar or not atol_is_scalar:
154+
pass
155+
else:
156+
result = dpnp_allclose(x1_desc, x2_desc, rtol, atol)
157+
return result[0]
158+
159+
return call_origin(numpy.allclose, x1, x2, rtol=rtol, atol=atol, **kwargs)
160+
161+
125162
def any(x1, axis=None, out=None, keepdims=False):
126163
"""
127164
Test whether any array element along a given axis evaluates to True.

tests/test_logic.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,28 @@ def test_all(type, shape):
3737
dpnp_res = ia.all()
3838
numpy.testing.assert_allclose(dpnp_res, np_res)
3939

40+
@pytest.mark.parametrize("type",
41+
[numpy.float64, numpy.float32, numpy.int64, numpy.int32],
42+
ids=['float64', 'float32', 'int64', 'int32'])
43+
def test_allclose(type):
44+
45+
a = numpy.random.rand(10)
46+
b = a + numpy.random.rand(10) * 1e-8
47+
48+
dpnp_a = dpnp.array(a, dtype=type)
49+
dpnp_b = dpnp.array(b, dtype=type)
50+
51+
np_res = numpy.allclose(a, b)
52+
dpnp_res = dpnp.allclose(dpnp_a, dpnp_b)
53+
numpy.testing.assert_allclose(dpnp_res, np_res)
54+
55+
a[0] = numpy.inf
56+
57+
dpnp_a = dpnp.array(a)
58+
59+
np_res = numpy.allclose(a, b)
60+
dpnp_res = dpnp.allclose(dpnp_a, dpnp_b)
61+
numpy.testing.assert_allclose(dpnp_res, np_res)
4062

4163
@pytest.mark.parametrize("type",
4264
[numpy.float64, numpy.float32, numpy.int64, numpy.int32, numpy.bool, numpy.bool_],

0 commit comments

Comments
 (0)