10000 ENH: Add the 'heaviside' ufunc. · numpy/numpy@bf83345 · GitHub
[go: up one dir, main page]

Skip to content

Commit bf83345

Browse files
ENH: Add the 'heaviside' ufunc.
1 parent bdbd774 commit bf83345

File tree

6 files changed

+101
-0
lines changed

6 files changed

+101
-0
lines changed

doc/release/1.13.0-notes.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,16 @@ This means that, e.g., it is now possible to do the following:
121121
[array([[ 1. , 1. , -0.5], [ 1. , 1. , -0.5]]),
122122
array([[ 2. , 2. , 2. ], [ 2. , 1.7, 0.5]])]
123123

124+
``np.heaviside`` computes the Heaviside function
125+
------------------------------------------------
126+
The new function ``np.heaviside(x, h0)`` (a ufunc) computes the Heaviside
127+
function::
128+
129+
{ 0 if x < 0,
130+
heaviside(x, h0) = { h0 if x == 0,
131+
{ 1 if x > 0.
132+
133+
124134
Improvements
125135
============
126136

numpy/core/code_generators/generate_umath.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,12 @@ def english_upper(s):
550550
TD(ints, simd=[('avx2', ints)]),
551551
TD(O, f='PyNumber_Rshift'),
552552
),
553+
'heaviside':
554+
Ufunc(2, 1, None,
555+
docstrings.get('numpy.core.umath.heaviside'),
556+
None,
557+
TD(flts, f='heaviside', astype={'e':'f'}),
558+
),
553559
'degrees':
554560
Ufunc(1, 1, None,
555561
docstrings.get('numpy.core.umath.degrees'),

numpy/core/code_generators/ufunc_docstrings.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,50 @@ def add_newdoc(place, name, doc):
915915
916916
""")
917917

918+
add_newdoc('numpy.core.umath', 'heaviside',
919+
"""
920+
Compute the Heaviside step function.
921+
922+
The Heaviside step function is defined as::
923+
924+
0 if x < 0
925+
heaviside(x, h0) = h0 if x == 0
926+
1 if x > 0
927+
928+
where `h0` is often taken to be 0.5, but 0 and 1 are also sometimes used.
929+
930+
Parameters
931+
----------
932+
x : array_like
933+
Input values.
934+
h0 : array_like
935+
The value of the function at x = 0.
936+
out : ndarray, optional
937+
Array into which the output is placed. Its type is preserved and it
938+
must be of the right shape to hold the output. See doc.ufuncs.
939+
940+
Returns
941+
-------
942+
out : ndarray
943+
The output array, element-wise Heaviside step function of `x`.
944+
945+
Notes
946+
-----
947+
.. versionadded:: 1.13.0
948+
949+
References
950+
----------
951+
.. Wikipedia, "Heaviside step function",
952+
https://en.wikipedia.org/wiki/Heaviside_step_function
953+
954+
Examples
955+
--------
956+
>>> np.heaviside([-1.5, 0, 2.0], 0.5)
957+
array([ 0. , 0.5, 1. ])
958+
>>> np.heaviside([-1.5, 0, 2.0], 1)
959+
array([ 0., 1., 1.])
960+
""")
961+
918962
add_newdoc('numpy.core.umath', 'divide',
919963
"""
920964
Divide arguments element-wise.

numpy/core/include/numpy/npy_math.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,19 +316,22 @@ NPY_INPLACE double npy_rad2deg(double x);
316316
NPY_INPLACE double npy_logaddexp(double x, double y);
317317
NPY_INPLACE double npy_logaddexp2(double x, double y);
318318
NPY_INPLACE double npy_divmod(double x, double y, double *modulus);
319+
NPY_INPLACE double npy_heaviside(double x, double h0);
319320

320321
NPY_INPLACE float npy_deg2radf(float x);
321322
NPY_INPLACE float npy_rad2degf(float x);
322323
NPY_INPLACE float npy_logaddexpf(float x, float y);
323324
NPY_INPLACE float npy_logaddexp2f(float x, float y);
324325
NPY_INPLACE float npy_divmodf(float x, float y, float *modulus);
326+
NPY_INPLACE float npy_heavisidef(float x, float h0);
325327

326328
NPY_INPLACE npy_longdouble npy_deg2radl(npy_longdouble x);
327329
NPY_INPLACE npy_longdouble npy_rad2degl(npy_longdouble x);
328330
NPY_INPLACE npy_longdouble npy_logaddexpl(npy_longdouble x, npy_longdouble y);
329331
NPY_INPLACE npy_longdouble npy_logaddexp2l(npy_longdouble x, npy_longdouble y);
330332
NPY_INPLACE npy_longdouble npy_divmodl(npy_longdouble x, npy_longdouble y,
331333
npy_longdouble *modulus);
334+
NPY_INPLACE npy_longdouble npy_heavisidel(npy_longdouble x, npy_longdouble h0);
332335

333336
#define npy_degrees npy_rad2deg
334337
#define npy_degreesf npy_rad2degf

numpy/core/src/npymath/npy_math_internal.h.src

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,22 @@ NPY_INPLACE @type@ npy_cbrt@c@(@type@ x)
541541
* #C = F, ,L#
542542
*/
543543

544+
@type@ npy_heaviside@c@(@type@ x, @type@ h0)
545+
{
546+
if (npy_isnan(x)) {
547+
return (@type@) NPY_NAN;
548+
}
549+
else if (x == 0) {
550+
return h0;
551+
}
552+
else if (x < 0) {
553+
return (@type@) 0.0;
554+
}
555+
else {
556+
return (@type@) 1.0;
557+
}
558+
}
559+
544560
#define LOGE2 NPY_LOGE2@c@
545561
#define LOG2E NPY_LOG2E@c@
546562
#define RAD2DEG (180.0@c@/NPY_PI@c@)

numpy/core/tests/test_umath.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
11971197
assert_almost_equal(ncu.radians(-90.0), -0.5*np.pi)
11981198

11991199

1200+
class TestHeavside(TestCase):
1201+
def test_heaviside(self):
1202+
x = np.array([[-30.0, -0.1, 0.0, 0.2], [7.5, np.nan, np.inf, -np.inf]])
1203+
expectedhalf = np.array([[0.0, 0.0, 0.5, 1.0], [1.0, np.nan, 1.0, 0.0]])
1204+
expected1 = expectedhalf.copy()
1205+
expected1[0, 2] = 1
1206+
1207+
h = ncu.heaviside(x, 0.5)
1208+
assert_equal(h, expectedhalf)
1209+
1210+
h = ncu.heaviside(x, 1.0)
1211+
assert_equal(h, expected1)
1212+
1213+
x = x.astype(np.float32)
1214+
1215+
h = ncu.heaviside(x, np.float32(0.5))
1216+
assert_equal(h, expectedhalf.astype(np.float32))
1217+
1218+
h = ncu.heaviside(x, np.float32(1.0))
1219+
assert_equal(h, expected1.astype(np.float32))
1220+
1221+
12001222
class TestSign(TestCase):
12011223
def test_sign(self):
12021224
a = np.array([np.inf, -np.inf, np.nan, 0.0, 3.0, -3.0])

0 commit comments

Comments
 (0)
0