Skip to content

Commit 5c5804c

Browse files
authored
add parameter out to four mathematical functions (#785)
* add parameter out to exp, log and cos funcs
1 parent 6cdca2c commit 5c5804c

File tree

5 files changed

+198
-23
lines changed

5 files changed

+198
-23
lines changed

dpnp/dpnp_algo/dpnp_algo.pxd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ cpdef dparray dpnp_maximum(object x1_obj, object x2_obj, object dtype=*, dparray
294294
cpdef dparray dpnp_minimum(object x1_obj, object x2_obj, object dtype=*, dparray out=*, object where=*)
295295
cpdef dparray dpnp_multiply(object x1_obj, object x2_obj, object dtype=*, dparray out=*, object where=*)
296296
cpdef dparray dpnp_negative(dpnp_descriptor array1)
297-
cpdef dparray dpnp_power(object x1_obj, object x2_obj, object dtype=*, dparray out=*, object where=*)
297+
cpdef dparray dpnp_power(dpnp_descriptor x1_obj, dpnp_descriptor x2_obj, object dtype=*, dparray out=*, object where=*)
298298
cpdef dparray dpnp_remainder(object x1_obj, object x2_obj, object dtype=*, dparray out=*, object where=*)
299299
cpdef dparray dpnp_subtract(object x1_obj, object x2_obj, object dtype=*, dparray out=*, object where=*)
300300

dpnp/dpnp_algo/dpnp_algo.pyx

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,26 +277,38 @@ cdef dparray call_fptr_1in_1out(DPNPFuncName fptr_name, utils.dpnp_descriptor x1
277277
result = out
278278

279279
cdef fptr_1in_1out_t func = <fptr_1in_1out_t > kernel_data.ptr
280-
""" Call FPTR function """
280+
281281
func(x1.get_data(), result.get_data(), x1.size)
282282

283283
return result
284284

285285

286286
cdef dparray call_fptr_2in_1out(DPNPFuncName fptr_name, utils.dpnp_descriptor x1_obj, utils.dpnp_descriptor x2_obj,
287-
object dtype=None, dparray out=None, object where=True):
287+
object dtype=None, dparray out=None, object where=True, func_name=None):
288288
# Convert string type names (dparray.dtype) to C enum DPNPFuncType
289289
cdef DPNPFuncType x1_c_type = dpnp_dtype_to_DPNPFuncType(x1_obj.dtype)
290290
cdef DPNPFuncType x2_c_type = dpnp_dtype_to_DPNPFuncType(x2_obj.dtype)
291291

292292
# get the FPTR data structure
293293
cdef DPNPFuncData kernel_data = get_dpnp_function_ptr(fptr_name, x1_c_type, x2_c_type)
294294

295+
result_type = dpnp_DPNPFuncType_to_dtype(< size_t > kernel_data.return_type)
296+
295297
# Create result array
296298
cdef dparray_shape_type x1_shape = x1_obj.shape
297299
cdef dparray_shape_type x2_shape = x2_obj.shape
298300
cdef dparray_shape_type result_shape = utils.get_common_shape(x1_shape, x2_shape)
299-
cdef dparray result = utils.create_output_array(result_shape, kernel_data.return_type, out)
301+
cdef dparray result
302+
303+
if out is None:
304+
""" Create result array with type given by FPTR data """
305+
result = utils.create_output_array(result_shape, kernel_data.return_type, None)
306+
else:
307+
if out.dtype != result_type:
308+
utils.checker_throw_value_error(func_name, 'out.dtype', out.dtype, result_type)
309+
if out.shape != result_shape:
310+
utils.checker_throw_value_error(func_name, 'out.shape', out.shape, result_shape)
311+
result = out
300312

301313
""" Call FPTR function """
302314
cdef fptr_2in_1out_t func = <fptr_2in_1out_t > kernel_data.ptr

dpnp/dpnp_algo/dpnp_algo_mathematical.pyx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ cpdef dpnp_around(utils.dpnp_descriptor x1, int decimals):
126126
return result
127127

128128

129-
cpdef dparray dpnp_ceil(utils.dpnp_descriptor x1):
130-
return call_fptr_1in_1out(DPNP_FN_CEIL, x1, x1.shape)
129+
cpdef dparray dpnp_ceil(utils.dpnp_descriptor x1, dparray out):
130+
return call_fptr_1in_1out(DPNP_FN_CEIL, x1, x1.shape, out=out, func_name='ceil')
131131

132132

133133
cpdef dparray dpnp_conjugate(utils.dpnp_descriptor x1):
@@ -209,8 +209,8 @@ cpdef dparray dpnp_fabs(utils.dpnp_descriptor x1):
209209
return call_fptr_1in_1out(DPNP_FN_FABS, x1, x1.shape)
210210

211211

212-
cpdef dparray dpnp_floor(utils.dpnp_descriptor x1):
213-
return call_fptr_1in_1out(DPNP_FN_FLOOR, x1, x1.shape)
212+
cpdef dparray dpnp_floor(utils.dpnp_descriptor x1, dparray out):
213+
return call_fptr_1in_1out(DPNP_FN_FLOOR, x1, x1.shape, out=out, func_name='floor')
214214

215215

216216
cpdef dparray dpnp_floor_divide(object x1_obj, object x2_obj, object dtype=None, dparray out=None, object where=True):
@@ -339,8 +339,8 @@ cpdef dparray dpnp_negative(dpnp_descriptor x1):
339339
return call_fptr_1in_1out(DPNP_FN_NEGATIVE, x1, x1.shape)
340340

341341

342-
cpdef dparray dpnp_power(object x1_obj, object x2_obj, object dtype=None, dparray out=None, object where=True):
343-
return call_fptr_2in_1out(DPNP_FN_POWER, x1_obj, x2_obj, dtype=dtype, out=out, where=where)
342+
cpdef dparray dpnp_power(utils.dpnp_descriptor x1_obj, utils.dpnp_descriptor x2_obj, object dtype=None, dparray out=None, object where=True):
343+
return call_fptr_2in_1out(DPNP_FN_POWER, x1_obj, x2_obj, dtype=dtype, out=out, where=where, func_name="power")
344344

345345

346346
cpdef dparray dpnp_prod(utils.dpnp_descriptor input, object axis=None, object dtype=None, dparray out=None, cpp_bool keepdims=False, object initial=None, object where=True):
@@ -426,5 +426,5 @@ cpdef dpnp_trapz(utils.dpnp_descriptor y1, dparray x1, double dx):
426426
return result[0]
427427

428428

429-
cpdef dparray dpnp_trunc(utils.dpnp_descriptor x1):
430-
return call_fptr_1in_1out(DPNP_FN_TRUNC, x1, x1.shape)
429+
cpdef dparray dpnp_trunc(utils.dpnp_descriptor x1, dparray out):
430+
return call_fptr_1in_1out(DPNP_FN_TRUNC, x1, x1.shape, out=out, func_name='trunc')

dpnp/dpnp_iface_mathematical.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def around(x1, decimals=0, out=None):
250250
return call_origin(numpy.around, x1, decimals=decimals, out=out)
251251

252252

253-
def ceil(x1, **kwargs):
253+
def ceil(x1, out=None, **kwargs):
254254
"""
255255
Compute the ceiling of the input, element-wise.
256256
@@ -280,9 +280,9 @@ def ceil(x1, **kwargs):
280280

281281
x1_desc = dpnp.get_dpnp_descriptor(x1)
282282
if x1_desc and not kwargs:
283-
return dpnp_ceil(x1_desc)
283+
return dpnp_ceil(x1_desc, out)
284284

285-
return call_origin(numpy.ceil, x1, **kwargs)
285+
return call_origin(numpy.ceil, x1, out=out, **kwargs)
286286

287287

288288
def conjugate(x1, **kwargs):
@@ -638,7 +638,7 @@ def fabs(x1, **kwargs):
638638
return call_origin(numpy.fabs, x1, **kwargs)
639639

640640

641-
def floor(x1, **kwargs):
641+
def floor(x1, out=None, **kwargs):
642642
"""
643643
Round a number to the nearest integer toward minus infinity.
644644
@@ -673,9 +673,9 @@ def floor(x1, **kwargs):
673673

674674
x1_desc = dpnp.get_dpnp_descriptor(x1)
675675
if x1_desc and not kwargs:
676-
return dpnp_floor(x1_desc)
676+
return dpnp_floor(x1_desc, out)
677677

678-
return call_origin(numpy.floor, x1, **kwargs)
678+
return call_origin(numpy.floor, x1, out=out, **kwargs)
679679

680680

681681
def floor_divide(x1, x2, dtype=None, out=None, where=True, **kwargs):
@@ -1322,8 +1322,6 @@ def power(x1, x2, dtype=None, out=None, where=True, **kwargs):
13221322
pass
13231323
elif dtype is not None:
13241324
pass
1325-
elif out is not None:
1326-
pass
13271325
elif not where:
13281326
pass
13291327
else:
@@ -1614,7 +1612,7 @@ def true_divide(*args, **kwargs):
16141612
return dpnp.divide(*args, **kwargs)
16151613

16161614

1617-
def trunc(x1, **kwargs):
1615+
def trunc(x1, out=None, **kwargs):
16181616
"""
16191617
Compute the truncated value of the input, element-wise.
16201618
@@ -1644,6 +1642,6 @@ def trunc(x1, **kwargs):
16441642

16451643
x1_desc = dpnp.get_dpnp_descriptor(x1)
16461644
if x1_desc and not kwargs:
1647-
return dpnp_trunc(x1_desc)
1645+
return dpnp_trunc(x1_desc, out)
16481646

1649-
return call_origin(numpy.trunc, x1, **kwargs)
1647+
return call_origin(numpy.trunc, x1, out=out, **kwargs)

tests/test_mathematical.py

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,3 +409,168 @@ def test_gradient_y1_dx(self, array, dx):
409409
result = inp.gradient(iy1, dx)
410410
expected = numpy.gradient(y1, dx)
411411
numpy.testing.assert_array_equal(expected, result)
412+
413+
414+
class TestCeil:
415+
416+
def test_ceil(self):
417+
array_data = numpy.arange(10)
418+
out = numpy.empty(10, dtype=numpy.float64)
419+
420+
# DPNP
421+
dp_array = inp.array(array_data, dtype=inp.float64)
422+
dp_out = inp.array(out, dtype=inp.float64)
423+
result = inp.ceil(dp_array, out=dp_out)
424+
425+
# original
426+
np_array = numpy.array(array_data, dtype=numpy.float64)
427+
expected = numpy.ceil(np_array, out=out)
428+
429+
numpy.testing.assert_array_equal(expected, result)
430+
431+
@pytest.mark.parametrize("dtype",
432+
[numpy.float32, numpy.int64, numpy.int32],
433+
ids=['numpy.float32', 'numpy.int64', 'numpy.int32'])
434+
def test_invalid_dtype(self, dtype):
435+
436+
dp_array = inp.arange(10, dtype=inp.float64)
437+
dp_out = inp.empty(10, dtype=dtype)
438+
439+
with pytest.raises(ValueError):
440+
inp.ceil(dp_array, out=dp_out)
441+
442+
@pytest.mark.parametrize("shape",
443+
[(0,), (15, ), (2, 2)],
444+
ids=['(0,)', '(15, )', '(2,2)'])
445+
def test_invalid_shape(self, shape):
446+
447+
dp_array = inp.arange(10, dtype=inp.float64)
448+
dp_out = inp.empty(shape, dtype=inp.float64)
449+
450+
with pytest.raises(ValueError):
451+
inp.ceil(dp_array, out=dp_out)
452+
453+
454+
class TestFloor:
455+
456+
def test_floor(self):
457+
array_data = numpy.arange(10)
458+
out = numpy.empty(10, dtype=numpy.float64)
459+
460+
# DPNP
461+
dp_array = inp.array(array_data, dtype=inp.float64)
462+
dp_out = inp.array(out, dtype=inp.float64)
463+
result = inp.floor(dp_array, out=dp_out)
464+
465+
# original
466+
np_array = numpy.array(array_data, dtype=numpy.float64)
467+
expected = numpy.floor(np_array, out=out)
468+
469+
numpy.testing.assert_array_equal(expected, result)
470+
471+
@pytest.mark.parametrize("dtype",
472+
[numpy.float32, numpy.int64, numpy.int32],
473+
ids=['numpy.float32', 'numpy.int64', 'numpy.int32'])
474+
def test_invalid_dtype(self, dtype):
475+
476+
dp_array = inp.arange(10, dtype=inp.float64)
477+
dp_out = inp.empty(10, dtype=dtype)
478+
479+
with pytest.raises(ValueError):
480+
inp.floor(dp_array, out=dp_out)
481+
482+
@pytest.mark.parametrize("shape",
483+
[(0,), (15, ), (2, 2)],
484+
ids=['(0,)', '(15, )', '(2,2)'])
485+
def test_invalid_shape(self, shape):
486+
487+
dp_array = inp.arange(10, dtype=inp.float64)
488+
dp_out = inp.empty(shape, dtype=inp.float64)
489+
490+
with pytest.raises(ValueError):
491+
inp.floor(dp_array, out=dp_out)
492+
493+
494+
class TestTrunc:
495+
496+
def test_trunc(self):
497+
array_data = numpy.arange(10)
498+
out = numpy.empty(10, dtype=numpy.float64)
499+
500+
# DPNP
501+
dp_array = inp.array(array_data, dtype=inp.float64)
502+
dp_out = inp.array(out, dtype=inp.float64)
503+
result = inp.trunc(dp_array, out=dp_out)
504+
505+
# original
506+
np_array = numpy.array(array_data, dtype=numpy.float64)
507+
expected = numpy.trunc(np_array, out=out)
508+
509+
numpy.testing.assert_array_equal(expected, result)
510+
511+
@pytest.mark.parametrize("dtype",
512+
[numpy.float32, numpy.int64, numpy.int32],
513+
ids=['numpy.float32', 'numpy.int64', 'numpy.int32'])
514+
def test_invalid_dtype(self, dtype):
515+
516+
dp_array = inp.arange(10, dtype=inp.float64)
517+
dp_out = inp.empty(10, dtype=dtype)
518+
519+
with pytest.raises(ValueError):
520+
inp.trunc(dp_array, out=dp_out)
521+
522+
@pytest.mark.parametrize("shape",
523+
[(0,), (15, ), (2, 2)],
524+
ids=['(0,)', '(15, )', '(2,2)'])
525+
def test_invalid_shape(self, shape):
526+
527+
dp_array = inp.arange(10, dtype=inp.float64)
528+
dp_out = inp.empty(shape, dtype=inp.float64)
529+
530+
with pytest.raises(ValueError):
531+
inp.trunc(dp_array, out=dp_out)
532+
533+
534+
class TestPower:
535+
536+
def test_power(self):
537+
array1_data = numpy.arange(10)
538+
array2_data = numpy.arange(5, 15)
539+
out = numpy.empty(10, dtype=numpy.float64)
540+
541+
# DPNP
542+
dp_array1 = inp.array(array1_data, dtype=inp.float64)
543+
dp_array2 = inp.array(array2_data, dtype=inp.float64)
544+
dp_out = inp.array(out, dtype=inp.float64)
545+
result = inp.power(dp_array1, dp_array2, out=dp_out)
546+
547+
# original
548+
np_array1 = numpy.array(array1_data, dtype=numpy.float64)
549+
np_array2 = numpy.array(array2_data, dtype=numpy.float64)
550+
expected = numpy.power(np_array1, np_array2, out=out)
551+
552+
numpy.testing.assert_array_equal(expected, result)
553+
554+
@pytest.mark.parametrize("dtype",
555+
[numpy.float32, numpy.int64, numpy.int32],
556+
ids=['numpy.float32', 'numpy.int64', 'numpy.int32'])
557+
def test_invalid_dtype(self, dtype):
558+
559+
dp_array1 = inp.arange(10, dtype=inp.float64)
560+
dp_array2 = inp.arange(5, 15, dtype=inp.float64)
561+
dp_out = inp.empty(10, dtype=dtype)
562+
563+
with pytest.raises(ValueError):
564+
inp.power(dp_array1, dp_array2, out=dp_out)
565+
566+
@pytest.mark.parametrize("shape",
567+
[(0,), (15, ), (2, 2)],
568+
ids=['(0,)', '(15, )', '(2,2)'])
569+
def test_invalid_shape(self, shape):
570+
571+
dp_array1 = inp.arange(10, dtype=inp.float64)
572+
dp_array2 = inp.arange(5, 15, dtype=inp.float64)
573+
dp_out = inp.empty(shape, dtype=inp.float64)
574+
575+
with pytest.raises(ValueError):
576+
inp.power(dp_array1, dp_array2, out=dp_out)

0 commit comments

Comments
 (0)