Skip to content

Commit ec0bd69

Browse files
committed
implement dpnp.logaddexp
1 parent 4813810 commit ec0bd69

File tree

8 files changed

+139
-7
lines changed

8 files changed

+139
-7
lines changed

dpnp/dpnp_algo/dpnp_elementwise_common.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
"dpnp_less",
7272
"dpnp_less_equal",
7373
"dpnp_log",
74+
"dpnp_logaddexp",
7475
"dpnp_logical_and",
7576
"dpnp_logical_not",
7677
"dpnp_logical_or",
@@ -1599,6 +1600,58 @@ def dpnp_log(x, out=None, order="K"):
15991600
return dpnp_array._create_from_usm_ndarray(res_usm)
16001601

16011602

1603+
_logaddexp_docstring_ = """
1604+
logaddexp(x1, x2, out=None, order="K")
1605+
1606+
Calculates the natural logarithm of the sum of exponentiations for each element
1607+
`x1_i` of the input array `x1` with the respective element `x2_i` of the input
1608+
array `x2`.
1609+
1610+
This function calculates `log(exp(x1) + exp(x2))` more accurately for small
1611+
values of `x`.
1612+
1613+
Args:
1614+
x1 (dpnp.ndarray):
1615+
First input array, expected to have a real-valued floating-point
1616+
data type.
1617+
x2 (dpnp.ndarray):
1618+
Second input array, also expected to have a real-valued
1619+
floating-point data type.
1620+
out ({None, dpnp.ndarray}, optional):
1621+
Output array to populate.
1622+
Array have the correct shape and the expected data type.
1623+
order ("C","F","A","K", None, optional):
1624+
Memory layout of the newly output array, if parameter `out` is `None`.
1625+
Default: "K".
1626+
Returns:
1627+
dpnp.ndarray:
1628+
An array containing the result of element-wise result. The data type
1629+
of the returned array is determined by the Type Promotion Rules.
1630+
"""
1631+
1632+
1633+
logaddexp_func = BinaryElementwiseFunc(
1634+
"logaddexp",
1635+
ti._logaddexp_result_type,
1636+
ti._logaddexp,
1637+
_logaddexp_docstring_,
1638+
)
1639+
1640+
1641+
def dpnp_logaddexp(x1, x2, out=None, order="K"):
1642+
"""Invokes logaddexp() from dpctl.tensor implementation for logaddexp() function."""
1643+
1644+
# dpctl.tensor only works with usm_ndarray or scalar
1645+
x1_usm_or_scalar = dpnp.get_usm_ndarray_or_scalar(x1)
1646+
x2_usm_or_scalar = dpnp.get_usm_ndarray_or_scalar(x2)
1647+
out_usm = None if out is None else dpnp.get_usm_ndarray(out)
1648+
1649+
res_usm = logaddexp_func(
1650+
x1_usm_or_scalar, x2_usm_or_scalar, out=out_usm, order=order
1651+
)
1652+
return dpnp_array._create_from_usm_ndarray(res_usm)
1653+
1654+
16021655
_logical_and_docstring_ = """
16031656
logical_and(x1, x2, out=None, order='K')
16041657

dpnp/dpnp_iface_trigonometric.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@
5858
dpnp_cos,
5959
dpnp_cosh,
6060
dpnp_log,
61+
dpnp_logaddexp,
6162
dpnp_sin,
6263
dpnp_sinh,
6364
dpnp_sqrt,
@@ -87,6 +88,7 @@
8788
"log10",
8889
"log1p",
8990
"log2",
91+
"logaddexp",
9092
"rad2deg",
9193
"radians",
9294
"reciprocal",
@@ -1089,6 +1091,69 @@ def log2(x1):
10891091
return call_origin(numpy.log2, x1)
10901092

10911093

1094+
def logaddexp(
1095+
x1,
1096+
x2,
1097+
/,
1098+
out=None,
1099+
*,
1100+
where=True,
1101+
order="K",
1102+
dtype=None,
1103+
subok=True,
1104+
**kwargs,
1105+
):
1106+
"""
1107+
Calculates ``log(exp(x1) + exp(x2))``, element-wise.
1108+
1109+
For full documentation refer to :obj:`numpy.logaddexp`.
1110+
1111+
Returns
1112+
-------
1113+
out : dpnp.ndarray
1114+
Logarithm of ``exp(x1) + exp(x2)``, element-wise.
1115+
1116+
Limitations
1117+
-----------
1118+
Parameters `x1` and `x2` are supported as either scalar, :class:`dpnp.ndarray`
1119+
or :class:`dpctl.tensor.usm_ndarray`, but both `x1` and `x2` can not be scalars at the same time.
1120+
Parameters `where`, `dtype` and `subok` are supported with their default values.
1121+
Keyword arguments `kwargs` are currently unsupported.
1122+
Otherwise the function will be executed sequentially on CPU.
1123+
Input array data types are limited by supported DPNP :ref:`Data types`.
1124+
1125+
See Also
1126+
--------
1127+
:obj:`dpnp.log` : Natural logarithm, element-wise.
1128+
:obj:`dpnp.exp` : Exponential, element-wise.
1129+
1130+
Examples
1131+
--------
1132+
>>> import dpnp as np
1133+
>>> prob1 = np.log(np.array(1e-50))
1134+
>>> prob2 = np.log(np.array(2.5e-50))
1135+
>>> prob12 = np.logaddexp(prob1, prob2)
1136+
>>> prob12
1137+
-113.87649168120691
1138+
>>> np.exp(prob12)
1139+
3.5000000000000057e-50
1140+
1141+
"""
1142+
1143+
return check_nd_call_func(
1144+
numpy.logaddexp,
1145+
dpnp_logaddexp,
1146+
x1,
1147+
x2,
1148+
out=out,
1149+
where=where,
1150+
order=order,
1151+
dtype=dtype,
1152+
subok=subok,
1153+
**kwargs,
1154+
)
1155+
1156+
10921157
def reciprocal(x1, **kwargs):
10931158
"""
10941159
Return the reciprocal of the argument, element-wise.

tests/skipped_tests.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,6 @@ tests/test_umath.py::test_umaths[('ldexp', 'fi')]
113113
tests/test_umath.py::test_umaths[('ldexp', 'fl')]
114114
tests/test_umath.py::test_umaths[('ldexp', 'di')]
115115
tests/test_umath.py::test_umaths[('ldexp', 'dl')]
116-
tests/test_umath.py::test_umaths[('logaddexp', 'ff')]
117-
tests/test_umath.py::test_umaths[('logaddexp', 'dd')]
118116
tests/test_umath.py::test_umaths[('logaddexp2', 'ff')]
119117
tests/test_umath.py::test_umaths[('logaddexp2', 'dd')]
120118
tests/test_umath.py::test_umaths[('nextafter', 'ff')]
@@ -513,7 +511,6 @@ tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticModf::test_m
513511

514512
tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticRaisesWithNumpyInput_param_3_{name='angle', nargs=1}::test_raises_with_numpy_input
515513

516-
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp
517514
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2
518515
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2_infinities
519516
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_copysign_float

tests/skipped_tests_gpu.tbl

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,6 @@ tests/test_umath.py::test_umaths[('ldexp', 'fi')]
5353
tests/test_umath.py::test_umaths[('ldexp', 'fl')]
5454
tests/test_umath.py::test_umaths[('ldexp', 'di')]
5555
tests/test_umath.py::test_umaths[('ldexp', 'dl')]
56-
tests/test_umath.py::test_umaths[('logaddexp', 'ff')]
57-
tests/test_umath.py::test_umaths[('logaddexp', 'dd')]
5856
tests/test_umath.py::test_umaths[('logaddexp2', 'ff')]
5957
tests/test_umath.py::test_umaths[('logaddexp2', 'dd')]
6058
tests/test_umath.py::test_umaths[('nextafter', 'ff')]
@@ -642,7 +640,6 @@ tests/third_party/cupy/manipulation_tests/test_tiling.py::TestTile_param_5_{reps
642640

643641
tests/third_party/cupy/math_tests/test_arithmetic.py::TestArithmeticRaisesWithNumpyInput_param_3_{name='angle', nargs=1}::test_raises_with_numpy_input
644642

645-
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp
646643
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2
647644
tests/third_party/cupy/math_tests/test_explog.py::TestExplog::test_logaddexp2_infinities
648645
tests/third_party/cupy/math_tests/test_floating.py::TestFloating::test_copysign_float

tests/test_strides.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def test_strides_reciprocal(dtype, shape):
138138
"arctan2",
139139
"divide",
140140
"hypot",
141+
"logaddexp",
141142
"maximum",
142143
"minimum",
143144
"multiply",

tests/test_sycl_queue.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,11 @@ def test_proj(device):
353353
[-3.0, -2.0, -1.0, 1.0, 2.0, 3.0],
354354
[2.0, 2.0, 2.0, 2.0, 2.0, 2.0],
355355
),
356+
pytest.param(
357+
"logaddexp",
358+
[[-1, 2, 5, 9]],
359+
[[4, -3, 2, -8]],
360+
),
356361
pytest.param(
357362
"matmul", [[1.0, 0.0], [0.0, 1.0]], [[4.0, 1.0], [1.0, 2.0]]
358363
),

tests/test_usm_type.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,11 @@ def test_1in_1out(func, data, usm_type):
337337
[[0.0, 1.0, 2.0], [3.0, 4.0, 5.0]],
338338
[[4.0, 4.0], [4.0, 4.0], [4.0, 4.0]],
339339
),
340+
pytest.param(
341+
"logaddexp",
342+
[[-1, 2, 5, 9]],
343+
[[4, -3, 2, -8]],
344+
),
340345
],
341346
)
342347
@pytest.mark.parametrize("usm_type_x", list_of_usm_types, ids=list_of_usm_types)

tests/third_party/cupy/math_tests/test_explog.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import numpy
44
import pytest
55

6+
from tests.helper import has_support_aspect64
67
from tests.third_party.cupy import testing
78

89

@@ -17,7 +18,7 @@ def check_unary(self, name, xp, dtype, no_complex=False):
1718
return getattr(xp, name)(a)
1819

1920
@testing.for_all_dtypes()
20-
@testing.numpy_cupy_allclose(atol=1e-5)
21+
@testing.numpy_cupy_allclose(atol=1e-5, type_check=has_support_aspect64())
2122
def check_binary(self, name, xp, dtype, no_complex=False):
2223
if no_complex:
2324
if numpy.dtype(dtype).kind == "c":
@@ -62,3 +63,11 @@ def test_logaddexp2(self):
6263
def test_logaddexp2_infinities(self, xp, dtype, val):
6364
a = xp.full((2, 3), val, dtype=dtype)
6465
return xp.logaddexp2(a, a)
66+
67+
68+
@pytest.mark.parametrize("val", [numpy.inf, -numpy.inf])
69+
@testing.for_float_dtypes()
70+
@testing.numpy_cupy_allclose()
71+
def test_logaddexp_infinities(xp, dtype, val):
72+
a = xp.full((2, 3), val, dtype=dtype)
73+
return xp.logaddexp(a, a)

0 commit comments

Comments
 (0)