added isinf/isfinite functions

This commit is contained in:
Zoltán Vörös 2021-01-29 22:38:40 +01:00
parent 9611a0a638
commit c622fe61d8
10 changed files with 438 additions and 37 deletions

View file

@ -174,8 +174,108 @@ mp_obj_t compare_not_equal(mp_obj_t x1, mp_obj_t x2) {
MP_DEFINE_CONST_FUN_OBJ_2(compare_not_equal_obj, compare_not_equal);
#endif
#if ULAB_NUMPY_HAS_MAXIMUM
#if ULAB_NUMPY_HAS_ISFINITE | ULAB_NUMPY_HAS_ISINF
static mp_obj_t compare_isinf_isfinite(mp_obj_t _x, uint8_t mask) {
// mask should signify, whether the function is called from isinf (mask = 1),
// or from isfinite (mask = 0)
if(MP_OBJ_IS_INT(_x)) {
if(mask) {
return mp_const_false;
} else {
return mp_const_true;
}
} else if(mp_obj_is_float(_x)) {
mp_float_t x = mp_obj_get_float(_x);
if(isnan(x)) {
return mp_const_false;
}
if(mask) { // called from isinf
return isinf(x) ? mp_const_true : mp_const_false;
} else { // called from isfinite
return isinf(x) ? mp_const_false : mp_const_true;
}
} else if(MP_OBJ_IS_TYPE(_x, &ulab_ndarray_type)) {
ndarray_obj_t *x = MP_OBJ_TO_PTR(_x);
ndarray_obj_t *results = ndarray_new_dense_ndarray(x->ndim, x->shape, NDARRAY_BOOL);
// At this point, results is all False
uint8_t *rarray = (uint8_t *)results->array;
if(x->dtype != NDARRAY_FLOAT) {
// int types can never be infinite...
if(!mask) {
// ...so flip all values in the array, if the function was called from isfinite
memset(rarray, 1, results->len);
}
return results;
}
uint8_t *xarray = (uint8_t *)x->array;
#if ULAB_MAX_DIMS > 3
size_t i = 0;
do {
#endif
#if ULAB_MAX_DIMS > 2
size_t j = 0;
do {
#endif
#if ULAB_MAX_DIMS > 1
size_t k = 0;
do {
#endif
size_t l = 0;
do {
mp_float_t value = *(mp_float_t *)xarray;
if(isnan(value)) {
*rarray++ = 0;
} else {
*rarray++ = isinf(value) ? mask : 1 - mask;
}
xarray += x->strides[ULAB_MAX_DIMS - 1];
l++;
} while(l < x->shape[ULAB_MAX_DIMS - 1]);
#if ULAB_MAX_DIMS > 1
xarray -= x->strides[ULAB_MAX_DIMS - 1] * x->shape[ULAB_MAX_DIMS-1];
xarray += x->strides[ULAB_MAX_DIMS - 2];
k++;
} while(k < x->shape[ULAB_MAX_DIMS - 2]);
#endif
#if ULAB_MAX_DIMS > 2
xarray -= x->strides[ULAB_MAX_DIMS - 2] * x->shape[ULAB_MAX_DIMS-2];
xarray += x->strides[ULAB_MAX_DIMS - 3];
j++;
} while(j < x->shape[ULAB_MAX_DIMS - 3]);
#endif
#if ULAB_MAX_DIMS > 3
xarray -= x->strides[ULAB_MAX_DIMS - 3] * x->shape[ULAB_MAX_DIMS-3];
xarray += x->strides[ULAB_MAX_DIMS - 4];
i++;
} while(i < x->shape[ULAB_MAX_DIMS - 4]);
#endif
return results;
} else {
mp_raise_TypeError(translate("wrong input type"));
}
return mp_const_none;
}
#endif
#if ULAB_NUMPY_HAS_ISFINITE
mp_obj_t compare_isfinite(mp_obj_t _x) {
return compare_isinf_isfinite(_x, 0);
}
MP_DEFINE_CONST_FUN_OBJ_1(compare_isfinite_obj, compare_isfinite);
#endif
#if ULAB_NUMPY_HAS_ISINF
mp_obj_t compare_isinf(mp_obj_t _x) {
return compare_isinf_isfinite(_x, 1);
}
MP_DEFINE_CONST_FUN_OBJ_1(compare_isinf_obj, compare_isinf);
#endif
#if ULAB_NUMPY_HAS_MAXIMUM
mp_obj_t compare_maximum(mp_obj_t x1, mp_obj_t x2) {
// extra round, so that we can return maximum(3, 4) properly
mp_obj_t result = compare_function(x1, x2, COMPARE_MAXIMUM);

View file

@ -23,11 +23,13 @@ enum COMPARE_FUNCTION_TYPE {
COMPARE_CLIP,
};
MP_DECLARE_CONST_FUN_OBJ_3(compare_clip_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_equal_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_not_equal_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_isfinite_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_isinf_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_minimum_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_maximum_obj);
MP_DECLARE_CONST_FUN_OBJ_3(compare_clip_obj);
MP_DECLARE_CONST_FUN_OBJ_2(compare_not_equal_obj);
#if ULAB_MAX_DIMS == 1
#define COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\

View file

@ -132,6 +132,12 @@ static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
#if ULAB_NUMPY_HAS_NOTEQUAL
{ MP_OBJ_NEW_QSTR(MP_QSTR_not_equal), (mp_obj_t)&compare_not_equal_obj },
#endif
#if ULAB_NUMPY_HAS_ISFINITE
{ MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&compare_isfinite_obj },
#endif
#if ULAB_NUMPY_HAS_ISINF
{ MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&compare_isinf_obj },
#endif
#if ULAB_NUMPY_HAS_MAXIMUM
{ MP_OBJ_NEW_QSTR(MP_QSTR_maximum), (mp_obj_t)&compare_maximum_obj },
#endif

View file

@ -33,7 +33,7 @@
#include "user/user.h"
#define ULAB_VERSION 2.1.5
#define ULAB_VERSION 2.2.0
#define xstr(s) str(s)
#define str(s) #s
#define ULAB_VERSION_STRING xstr(ULAB_VERSION) xstr(-) xstr(ULAB_MAX_DIMS) xstr(D)

View file

@ -25,7 +25,7 @@
// A considerable amount of flash space can be saved by removing (setting
// the corresponding constants to 0) the unnecessary functions and features.
// Values defined here can be overridden by your own config file as
// Values defined here can be overridden by your own config file as
// make -DULAB_CONFIG_FILE="my_ulab_config.h"
#if defined(ULAB_CONFIG_FILE)
#include ULAB_CONFIG_FILE
@ -307,8 +307,12 @@
#define ULAB_NUMPY_HAS_EQUAL (1)
#endif
#ifndef ULAB_NUMPY_HAS_NOTEQUAL
#define ULAB_NUMPY_HAS_NOTEQUAL (1)
#ifndef ULAB_NUMPY_HAS_ISFINITE
#define ULAB_NUMPY_HAS_ISFINITE (1)
#endif
#ifndef ULAB_NUMPY_HAS_ISINF
#define ULAB_NUMPY_HAS_ISINF (1)
#endif
#ifndef ULAB_NUMPY_HAS_MAXIMUM
@ -319,6 +323,10 @@
#define ULAB_NUMPY_HAS_MINIMUM (1)
#endif
#ifndef ULAB_NUMPY_HAS_NOTEQUAL
#define ULAB_NUMPY_HAS_NOTEQUAL (1)
#endif
// the linalg module; functions of the linalg module still have
// to be defined separately
#ifndef ULAB_NUMPY_HAS_LINALG_MODULE

View file

@ -27,7 +27,7 @@ copyright = '2019-2021, Zoltán Vörös and contributors'
author = 'Zoltán Vörös'
# The full version, including alpha/beta/rc tags
release = '2.1.2'
release = '2.2.0'
# -- General configuration ---------------------------------------------------

View file

@ -14,20 +14,22 @@ from ``numpy``.
7. `numpy.equal <#equal>`__
8. `numpy.flip <#flip>`__
9. `numpy.interp <#interp>`__
10. `numpy.max <#max>`__
11. `numpy.maximum <#maximum>`__
12. `numpy.mean <#mean>`__
13. `numpy.median <#median>`__
14. `numpy.min <#min>`__
15. `numpy.minimum <#minimum>`__
16. `numpy.not_equal <#equal>`__
17. `numpy.polyfit <#polyfit>`__
18. `numpy.polyval <#polyval>`__
19. `numpy.roll <#roll>`__
20. `numpy.sort <#sort>`__
21. `numpy.std <#std>`__
22. `numpy.sum <#sum>`__
23. `numpy.trapz <#trapz>`__
10. `numpy.isfinite <#isfinite>`__
11. `numpy.isinf <#isinf>`__
12. `numpy.max <#max>`__
13. `numpy.maximum <#maximum>`__
14. `numpy.mean <#mean>`__
15. `numpy.median <#median>`__
16. `numpy.min <#min>`__
17. `numpy.minimum <#minimum>`__
18. `numpy.not_equal <#equal>`__
19. `numpy.polyfit <#polyfit>`__
20. `numpy.polyval <#polyval>`__
21. `numpy.roll <#roll>`__
22. `numpy.sort <#sort>`__
23. `numpy.std <#std>`__
24. `numpy.sum <#sum>`__
25. `numpy.trapz <#trapz>`__
argmax
------
@ -426,6 +428,130 @@ respectively. If these arguments are not supplied, ``left``, and
isfinite
--------
``numpy``:
https://numpy.org/doc/stable/reference/generated/numpy.isfinite.html
Returns a Boolean array of the same shape as the input, or a
``True/False``, if the input is a scalar. In the return value, all
elements are ``True`` at positions, where the input value was finite.
Integer types are automatically finite, therefore, if the input is of
integer type, the output will be the ``True`` tensor.
.. code::
# code to be run in micropython
from ulab import numpy as np
print('isfinite(0): ', np.isfinite(0))
a = np.array([1, 2, np.nan])
print('\n' + '='*20)
print('a:\n', a)
print('\nisfinite(a):\n', np.isfinite(a))
b = np.array([1, 2, np.inf])
print('\n' + '='*20)
print('b:\n', b)
print('\nisfinite(b):\n', np.isfinite(b))
c = np.array([1, 2, 3], dtype=np.uint16)
print('\n' + '='*20)
print('c:\n', c)
print('\nisfinite(c):\n', np.isfinite(c))
.. parsed-literal::
isfinite(0): True
====================
a:
array([1.0, 2.0, nan], dtype=float64)
isfinite(a):
array([True, True, False], dtype=bool)
====================
b:
array([1.0, 2.0, inf], dtype=float64)
isfinite(b):
array([True, True, False], dtype=bool)
====================
c:
array([1, 2, 3], dtype=uint16)
isfinite(c):
array([True, True, True], dtype=bool)
isinf
-----
``numpy``:
https://numpy.org/doc/stable/reference/generated/numpy.isinf.html
Similar to `isfinite <#isfinite>`__, but the output is ``True`` at
positions, where the input is infinite. Integer types return the
``False`` tensor.
.. code::
# code to be run in micropython
from ulab import numpy as np
print('isinf(0): ', np.isinf(0))
a = np.array([1, 2, np.nan])
print('\n' + '='*20)
print('a:\n', a)
print('\nisinf(a):\n', np.isinf(a))
b = np.array([1, 2, np.inf])
print('\n' + '='*20)
print('b:\n', b)
print('\nisinf(b):\n', np.isinf(b))
c = np.array([1, 2, 3], dtype=np.uint16)
print('\n' + '='*20)
print('c:\n', c)
print('\nisinf(c):\n', np.isinf(c))
.. parsed-literal::
isinf(0): False
====================
a:
array([1.0, 2.0, nan], dtype=float64)
isinf(a):
array([False, False, False], dtype=bool)
====================
b:
array([1.0, 2.0, inf], dtype=float64)
isinf(b):
array([False, False, True], dtype=bool)
====================
c:
array([1, 2, 3], dtype=uint16)
isinf(c):
array([False, False, False], dtype=bool)
mean
----

View file

@ -2,11 +2,11 @@
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-13T15:57:33.452434Z",
"start_time": "2021-01-13T15:57:33.236531Z"
"end_time": "2021-01-29T21:13:12.041212Z",
"start_time": "2021-01-29T21:13:10.138344Z"
}
},
"outputs": [
@ -34,8 +34,8 @@
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-13T15:57:34.464768Z",
"start_time": "2021-01-13T15:57:34.457873Z"
"end_time": "2021-01-29T21:24:02.702618Z",
"start_time": "2021-01-29T21:24:02.696753Z"
}
},
"outputs": [],
@ -52,8 +52,8 @@
"execution_count": 4,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-13T15:57:35.036920Z",
"start_time": "2021-01-13T15:57:34.993058Z"
"end_time": "2021-01-29T21:24:05.849861Z",
"start_time": "2021-01-29T21:24:05.796272Z"
}
},
"outputs": [],
@ -241,6 +241,8 @@
"1. [numpy.equal](#equal)\n",
"1. [numpy.flip](#flip)\n",
"1. [numpy.interp](#interp)\n",
"1. [numpy.isfinite](#isfinite)\n",
"1. [numpy.isinf](#isinf)\n",
"1. [numpy.max](#max)\n",
"1. [numpy.maximum](#maximum)\n",
"1. [numpy.mean](#mean)\n",
@ -737,6 +739,156 @@
"print(np.interp(x, xp, fp, right=10.0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## isfinite\n",
"\n",
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.isfinite.html\n",
"\n",
"Returns a Boolean array of the same shape as the input, or a `True/False`, if the input is a scalar. In the return value, all elements are `True` at positions, where the input value was finite. Integer types are automatically finite, therefore, if the input is of integer type, the output will be the `True` tensor."
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-29T21:34:42.026689Z",
"start_time": "2021-01-29T21:34:42.010935Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"isfinite(0): True\n",
"\n",
"====================\n",
"a:\n",
" array([1.0, 2.0, nan], dtype=float64)\n",
"\n",
"isfinite(a):\n",
" array([True, True, False], dtype=bool)\n",
"\n",
"====================\n",
"b:\n",
" array([1.0, 2.0, inf], dtype=float64)\n",
"\n",
"isfinite(b):\n",
" array([True, True, False], dtype=bool)\n",
"\n",
"====================\n",
"c:\n",
" array([1, 2, 3], dtype=uint16)\n",
"\n",
"isfinite(c):\n",
" array([True, True, True], dtype=bool)\n",
"\n",
"\n"
]
}
],
"source": [
"%%micropython -unix 1\n",
"\n",
"from ulab import numpy as np\n",
"\n",
"print('isfinite(0): ', np.isfinite(0))\n",
"\n",
"a = np.array([1, 2, np.nan])\n",
"print('\\n' + '='*20)\n",
"print('a:\\n', a)\n",
"print('\\nisfinite(a):\\n', np.isfinite(a))\n",
"\n",
"b = np.array([1, 2, np.inf])\n",
"print('\\n' + '='*20)\n",
"print('b:\\n', b)\n",
"print('\\nisfinite(b):\\n', np.isfinite(b))\n",
"\n",
"c = np.array([1, 2, 3], dtype=np.uint16)\n",
"print('\\n' + '='*20)\n",
"print('c:\\n', c)\n",
"print('\\nisfinite(c):\\n', np.isfinite(c))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## isinf\n",
"\n",
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.isinf.html\n",
"\n",
"Similar to [isfinite](#isfinite), but the output is `True` at positions, where the input is infinite. Integer types return the `False` tensor."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-29T21:35:21.938514Z",
"start_time": "2021-01-29T21:35:21.923741Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"isinf(0): False\n",
"\n",
"====================\n",
"a:\n",
" array([1.0, 2.0, nan], dtype=float64)\n",
"\n",
"isinf(a):\n",
" array([False, False, False], dtype=bool)\n",
"\n",
"====================\n",
"b:\n",
" array([1.0, 2.0, inf], dtype=float64)\n",
"\n",
"isinf(b):\n",
" array([False, False, True], dtype=bool)\n",
"\n",
"====================\n",
"c:\n",
" array([1, 2, 3], dtype=uint16)\n",
"\n",
"isinf(c):\n",
" array([False, False, False], dtype=bool)\n",
"\n",
"\n"
]
}
],
"source": [
"%%micropython -unix 1\n",
"\n",
"from ulab import numpy as np\n",
"\n",
"print('isinf(0): ', np.isinf(0))\n",
"\n",
"a = np.array([1, 2, np.nan])\n",
"print('\\n' + '='*20)\n",
"print('a:\\n', a)\n",
"print('\\nisinf(a):\\n', np.isinf(a))\n",
"\n",
"b = np.array([1, 2, np.inf])\n",
"print('\\n' + '='*20)\n",
"print('b:\\n', b)\n",
"print('\\nisinf(b):\\n', np.isinf(b))\n",
"\n",
"c = np.array([1, 2, 3], dtype=np.uint16)\n",
"print('\\n' + '='*20)\n",
"print('c:\\n', c)\n",
"print('\\nisinf(c):\\n', np.isinf(c))"
]
},
{
"cell_type": "markdown",
"metadata": {},

View file

@ -1,5 +1,11 @@
Fri, 29 Jan 2021
version 2.2.0
added isinf/infinite functions
Fri, 29 Jan 2021
version 2.1.5
fixed error, when calculating standard deviation of iterables

View file

@ -17,8 +17,8 @@
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-15T13:53:42.464150Z",
"start_time": "2021-01-15T13:53:42.449894Z"
"end_time": "2021-01-29T21:35:55.409749Z",
"start_time": "2021-01-29T21:35:55.403775Z"
}
},
"outputs": [
@ -61,7 +61,7 @@
"author = 'Zoltán Vörös'\n",
"\n",
"# The full version, including alpha/beta/rc tags\n",
"release = '2.1.2'\n",
"release = '2.2.0'\n",
"\n",
"\n",
"# -- General configuration ---------------------------------------------------\n",
@ -212,11 +212,11 @@
},
{
"cell_type": "code",
"execution_count": 31,
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2021-01-15T14:09:47.022621Z",
"start_time": "2021-01-15T14:09:46.985214Z"
"end_time": "2021-01-29T21:36:05.745584Z",
"start_time": "2021-01-29T21:36:02.083320Z"
}
},
"outputs": [],
@ -253,10 +253,11 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 3,
"metadata": {
"ExecuteTime": {
"start_time": "2021-01-15T14:38:15.993Z"
"end_time": "2021-01-29T21:36:17.800965Z",
"start_time": "2021-01-29T21:36:08.328563Z"
}
},
"outputs": [],