From 1c37edbee67190d7b89a75c9a0d03fc171080a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Sat, 10 Feb 2024 18:59:06 +0100 Subject: [PATCH 01/13] add link to random module documentation in readme (#659) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa3831a4..e7feeca6 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ the `imag`, and `real` properties are automatically included. ## `numpy` and `scipy` functions -In addition, `ulab` includes [universal functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-universal.html), [many `numpy` functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-functions.html), and functions from the [`numpy.fft`](https://micropython-ulab.readthedocs.io/en/latest/numpy-fft.html), [`numpy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/numpy-linalg.html), [`scipy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/scipy-linalg.html), [`scipy.optimize`](https://micropython-ulab.readthedocs.io/en/latest/scipy-optimize.html), [`scipy.signal`](https://micropython-ulab.readthedocs.io/en/latest/scipy-signal.html), and [`scipy.special`](https://micropython-ulab.readthedocs.io/en/latest/scipy-special.html) modules. A complete list of available routines can be found under [micropython-ulab](https://micropython-ulab.readthedocs.io/en/latest). +In addition, `ulab` includes [universal functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-universal.html), [many `numpy` functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-functions.html), and functions from the [`numpy.fft`](https://micropython-ulab.readthedocs.io/en/latest/numpy-fft.html), [`numpy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/numpy-linalg.html), [`numpy.random`](https://micropython-ulab.readthedocs.io/en/latest/numpy-random.html), [`scipy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/scipy-linalg.html), [`scipy.optimize`](https://micropython-ulab.readthedocs.io/en/latest/scipy-optimize.html), [`scipy.signal`](https://micropython-ulab.readthedocs.io/en/latest/scipy-signal.html), and [`scipy.special`](https://micropython-ulab.readthedocs.io/en/latest/scipy-special.html) modules. A complete list of available routines can be found under [micropython-ulab](https://micropython-ulab.readthedocs.io/en/latest). ## `ulab` utilities From acfec3e9af5d351df88a7d71786f11a12f7545d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Sat, 10 Feb 2024 20:46:34 +0100 Subject: [PATCH 02/13] fix reshape (#660) --- code/ndarray.c | 18 +++++------------- code/ulab.c | 2 +- tests/2d/numpy/reshape.py | 17 +++++++++++++++++ tests/2d/numpy/reshape.py.exp | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 14 deletions(-) create mode 100644 tests/2d/numpy/reshape.py create mode 100644 tests/2d/numpy/reshape.py.exp diff --git a/code/ndarray.c b/code/ndarray.c index ffd3d621..84ce8495 100644 --- a/code/ndarray.c +++ b/code/ndarray.c @@ -558,13 +558,9 @@ ndarray_obj_t *ndarray_new_dense_ndarray(uint8_t ndim, size_t *shape, uint8_t dt ndarray_obj_t *ndarray_new_ndarray_from_tuple(mp_obj_tuple_t *_shape, uint8_t dtype) { // creates a dense array from a tuple // the function should work in the general n-dimensional case - size_t *shape = m_new(size_t, ULAB_MAX_DIMS); - for(size_t i = 0; i < ULAB_MAX_DIMS; i++) { - if(i >= _shape->len) { - shape[ULAB_MAX_DIMS - 1 - i] = 0; - } else { - shape[ULAB_MAX_DIMS - 1 - i] = mp_obj_get_int(_shape->items[i]); - } + size_t *shape = m_new0(size_t, ULAB_MAX_DIMS); + for(size_t i = 0; i < _shape->len; i++) { + shape[ULAB_MAX_DIMS - 1 - i] = mp_obj_get_int(_shape->items[_shape->len - 1 - i]); } return ndarray_new_dense_ndarray(_shape->len, shape, dtype); } @@ -2021,7 +2017,7 @@ mp_obj_t ndarray_reshape_core(mp_obj_t oin, mp_obj_t _shape, bool inplace) { mp_obj_t *items = m_new(mp_obj_t, 1); items[0] = _shape; shape = mp_obj_new_tuple(1, items); - } else { + } else { // at this point it's certain that _shape is a tuple shape = MP_OBJ_TO_PTR(_shape); } @@ -2072,11 +2068,7 @@ mp_obj_t ndarray_reshape_core(mp_obj_t oin, mp_obj_t _shape, bool inplace) { if(inplace) { mp_raise_ValueError(MP_ERROR_TEXT("cannot assign new shape")); } - if(mp_obj_is_type(_shape, &mp_type_tuple)) { - ndarray = ndarray_new_ndarray_from_tuple(shape, source->dtype); - } else { - ndarray = ndarray_new_linear_array(source->len, source->dtype); - } + ndarray = ndarray_new_dense_ndarray(shape->len, new_shape, source->dtype); ndarray_copy_array(source, ndarray, 0); } return MP_OBJ_FROM_PTR(ndarray); diff --git a/code/ulab.c b/code/ulab.c index f55768bc..df73f7bb 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.5.0 +#define ULAB_VERSION 6.5.1 #define xstr(s) str(s) #define str(s) #s diff --git a/tests/2d/numpy/reshape.py b/tests/2d/numpy/reshape.py new file mode 100644 index 00000000..7f4add6a --- /dev/null +++ b/tests/2d/numpy/reshape.py @@ -0,0 +1,17 @@ +try: + from ulab import numpy as np +except ImportError: + import numpy as np + +dtypes = (np.uint8, np.int8, np.uint16, np.int16, np.float) + +for dtype in dtypes: + print() + print('=' * 50) + a = np.array(range(12), dtype=dtype).reshape((3, 4)) + print(a) + b = a[0,:] + print(b.reshape((1,4))) + b = a[:,0] + print(b.reshape((1,3))) + diff --git a/tests/2d/numpy/reshape.py.exp b/tests/2d/numpy/reshape.py.exp new file mode 100644 index 00000000..806a26c3 --- /dev/null +++ b/tests/2d/numpy/reshape.py.exp @@ -0,0 +1,35 @@ + +================================================== +array([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]], dtype=uint8) +array([[0, 1, 2, 3]], dtype=uint8) +array([[0, 4, 8]], dtype=uint8) + +================================================== +array([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]], dtype=int8) +array([[0, 1, 2, 3]], dtype=int8) +array([[0, 4, 8]], dtype=int8) + +================================================== +array([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]], dtype=uint16) +array([[0, 1, 2, 3]], dtype=uint16) +array([[0, 4, 8]], dtype=uint16) + +================================================== +array([[0, 1, 2, 3], + [4, 5, 6, 7], + [8, 9, 10, 11]], dtype=int16) +array([[0, 1, 2, 3]], dtype=int16) +array([[0, 4, 8]], dtype=int16) + +================================================== +array([[0.0, 1.0, 2.0, 3.0], + [4.0, 5.0, 6.0, 7.0], + [8.0, 9.0, 10.0, 11.0]], dtype=float64) +array([[0.0, 1.0, 2.0, 3.0]], dtype=float64) +array([[0.0, 4.0, 8.0]], dtype=float64) From c49110572dc47c2eeb413f610cc25ab8328e0e79 Mon Sep 17 00:00:00 2001 From: KB Sriram Date: Wed, 28 Feb 2024 11:27:29 -0800 Subject: [PATCH 03/13] Update type annotations in compare.c and vector.c (#663) - Add type annotations for functions in compare.c - Update annotations in vector.c to match behavior Fixes https://github.com/v923z/micropython-ulab/issues/662 --- code/numpy/compare.c | 123 ++++++++++++++++++++++++++++++++++++++++- code/numpy/numerical.c | 2 + code/numpy/vector.c | 62 ++++++++++----------- 3 files changed, 153 insertions(+), 34 deletions(-) diff --git a/code/numpy/compare.c b/code/numpy/compare.c index fabc33a9..b2762e41 100644 --- a/code/numpy/compare.c +++ b/code/numpy/compare.c @@ -140,7 +140,23 @@ static mp_obj_t compare_equal_helper(mp_obj_t x1, mp_obj_t x2, uint8_t comptype) #endif #if ULAB_NUMPY_HAS_CLIP - +//| def clip( +//| a: _ScalarOrArrayLike, +//| a_min: _ScalarOrArrayLike, +//| a_max: _ScalarOrArrayLike, +//| ) -> _ScalarOrNdArray: +//| """ +//| Clips (limits) the values in an array. +//| +//| :param a: Scalar or array containing elements to clip. +//| :param a_min: Minimum value, it will be broadcast against ``a``. +//| :param a_max: Maximum value, it will be broadcast against ``a``. +//| :return: +//| A scalar or array with the elements of ``a``, but where +//| values < ``a_min`` are replaced with ``a_min``, and those +//| > ``a_max`` with ``a_max``. +//| """ +//| ... mp_obj_t compare_clip(mp_obj_t x1, mp_obj_t x2, mp_obj_t x3) { // Note: this function could be made faster by implementing a single-loop comparison in // RUN_COMPARE_LOOP. However, that would add around 2 kB of compile size, while we @@ -166,7 +182,18 @@ MP_DEFINE_CONST_FUN_OBJ_3(compare_clip_obj, compare_clip); #endif #if ULAB_NUMPY_HAS_EQUAL - +//| def equal(x: _ScalarOrArrayLike, y: _ScalarOrArrayLike) -> _ScalarOrNdArray: +//| """ +//| Returns ``x == y`` element-wise. +//| +//| :param x, y: +//| Input scalar or array. If ``x.shape != y.shape`` they must +//| be broadcastable to a common shape (which becomes the +//| shape of the output.) +//| :return: +//| A boolean scalar or array with the element-wise result of ``x == y``. +//| """ +//| ... mp_obj_t compare_equal(mp_obj_t x1, mp_obj_t x2) { return compare_equal_helper(x1, x2, COMPARE_EQUAL); } @@ -175,7 +202,21 @@ MP_DEFINE_CONST_FUN_OBJ_2(compare_equal_obj, compare_equal); #endif #if ULAB_NUMPY_HAS_NOTEQUAL - +//| def not_equal( +//| x: _ScalarOrArrayLike, +//| y: _ScalarOrArrayLike, +//| ) -> Union[_bool, ulab.numpy.ndarray]: +//| """ +//| Returns ``x != y`` element-wise. +//| +//| :param x, y: +//| Input scalar or array. If ``x.shape != y.shape`` they must +//| be broadcastable to a common shape (which becomes the +//| shape of the output.) +//| :return: +//| A boolean scalar or array with the element-wise result of ``x != y``. +//| """ +//| ... mp_obj_t compare_not_equal(mp_obj_t x1, mp_obj_t x2) { return compare_equal_helper(x1, x2, COMPARE_NOT_EQUAL); } @@ -270,6 +311,16 @@ static mp_obj_t compare_isinf_isfinite(mp_obj_t _x, uint8_t mask) { #endif #if ULAB_NUMPY_HAS_ISFINITE +//| def isfinite(x: _ScalarOrNdArray) -> Union[_bool, ulab.numpy.ndarray]: +//| """ +//| Tests element-wise for finiteness (i.e., it should not be infinity or a NaN). +//| +//| :param x: Input scalar or ndarray. +//| :return: +//| A boolean scalar or array with True where ``x`` is finite, and +//| False otherwise. +//| """ +//| ... mp_obj_t compare_isfinite(mp_obj_t _x) { return compare_isinf_isfinite(_x, 0); } @@ -278,6 +329,16 @@ MP_DEFINE_CONST_FUN_OBJ_1(compare_isfinite_obj, compare_isfinite); #endif #if ULAB_NUMPY_HAS_ISINF +//| def isinf(x: _ScalarOrNdArray) -> Union[_bool, ulab.numpy.ndarray]: +//| """ +//| Tests element-wise for positive or negative infinity. +//| +//| :param x: Input scalar or ndarray. +//| :return: +//| A boolean scalar or array with True where ``x`` is positive or +//| negative infinity, and False otherwise. +//| """ +//| ... mp_obj_t compare_isinf(mp_obj_t _x) { return compare_isinf_isfinite(_x, 1); } @@ -286,6 +347,18 @@ MP_DEFINE_CONST_FUN_OBJ_1(compare_isinf_obj, compare_isinf); #endif #if ULAB_NUMPY_HAS_MAXIMUM +//| def maximum(x1: _ScalarOrArrayLike, x2: _ScalarOrArrayLike) -> _ScalarOrNdArray: +//| """ +//| Returns the element-wise maximum. +//| +//| :param x1, x2: +//| Input scalar or array. If ``x.shape != y.shape`` they must +//| be broadcastable to a common shape (which becomes the +//| shape of the output.) +//| :return: +//| A scalar or array with the element-wise maximum of ``x1`` and ``x2``. +//| """ +//| ... 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); @@ -301,6 +374,18 @@ MP_DEFINE_CONST_FUN_OBJ_2(compare_maximum_obj, compare_maximum); #if ULAB_NUMPY_HAS_MINIMUM +//| def minimum(x1: _ScalarOrArrayLike, x2: _ScalarOrArrayLike) -> _ScalarOrNdArray: +//| """ +//| Returns the element-wise minimum. +//| +//| :param x1, x2: +//| Input scalar or array. If ``x.shape != y.shape`` they must +//| be broadcastable to a common shape (which becomes the +//| shape of the output.) +//| :return: +//| A scalar or array with the element-wise minimum of ``x1`` and ``x2``. +//| """ +//| ... mp_obj_t compare_minimum(mp_obj_t x1, mp_obj_t x2) { // extra round, so that we can return minimum(3, 4) properly mp_obj_t result = compare_function(x1, x2, COMPARE_MINIMUM); @@ -316,6 +401,17 @@ MP_DEFINE_CONST_FUN_OBJ_2(compare_minimum_obj, compare_minimum); #if ULAB_NUMPY_HAS_NONZERO +//| def nonzero(x: _ScalarOrArrayLike) -> ulab.numpy.ndarray: +//| """ +//| Returns the indices of elements that are non-zero. +//| +//| :param x: +//| Input scalar or array. If ``x`` is a scalar, it is treated +//| as a single-element 1-d array. +//| :return: +//| An array of indices that are non-zero. +//| """ +//| ... mp_obj_t compare_nonzero(mp_obj_t x) { ndarray_obj_t *ndarray_x = ndarray_from_mp_obj(x, 0); // since ndarray_new_linear_array calls m_new0, the content of zero is a single zero @@ -446,6 +542,27 @@ MP_DEFINE_CONST_FUN_OBJ_1(compare_nonzero_obj, compare_nonzero); #if ULAB_NUMPY_HAS_WHERE +//| def where( +//| condition: _ScalarOrArrayLike, +//| x: _ScalarOrArrayLike, +//| y: _ScalarOrArrayLike, +//| ) -> ulab.numpy.ndarray: +//| """ +//| Returns elements from ``x`` or ``y`` depending on ``condition``. +//| +//| :param condition: +//| Input scalar or array. If an element (or scalar) is truthy, +//| the corresponding element from ``x`` is chosen, otherwise +//| ``y`` is used. ``condition``, ``x`` and ``y`` must also be +//| broadcastable to the same shape (which becomes the output +//| shape.) +//| :param x, y: +//| Input scalar or array. +//| :return: +//| An array with elements from ``x`` when ``condition`` is +//| truthy, and ``y`` elsewhere. +//| """ +//| ... mp_obj_t compare_where(mp_obj_t _condition, mp_obj_t _x, mp_obj_t _y) { // this implementation will work with ndarrays, and scalars only ndarray_obj_t *c = ndarray_from_mp_obj(_condition, 0); diff --git a/code/numpy/numerical.c b/code/numpy/numerical.c index b642d5a2..e3b42525 100644 --- a/code/numpy/numerical.c +++ b/code/numpy/numerical.c @@ -45,6 +45,8 @@ enum NUMERICAL_FUNCTION_TYPE { //| from typing import Dict //| //| _ArrayLike = Union[ndarray, List[_float], Tuple[_float], range] +//| _ScalarOrArrayLike = Union[int, _float, _ArrayLike] +//| _ScalarOrNdArray = Union[int, _float, ndarray] //| //| _DType = int //| """`ulab.numpy.int8`, `ulab.numpy.uint8`, `ulab.numpy.int16`, `ulab.numpy.uint16`, `ulab.numpy.float` or `ulab.numpy.bool`""" diff --git a/code/numpy/vector.c b/code/numpy/vector.c index 0df3a338..95e2e207 100644 --- a/code/numpy/vector.c +++ b/code/numpy/vector.c @@ -235,7 +235,7 @@ static mp_obj_t vector_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t) #if ULAB_NUMPY_HAS_ACOS -//| def acos(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def acos(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse cosine function""" //| ... //| @@ -249,7 +249,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_acos_obj, vector_acos); #endif /* ULAB_NUMPY_HAS_ACOS */ #if ULAB_NUMPY_HAS_ACOSH -//| def acosh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def acosh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse hyperbolic cosine function""" //| ... //| @@ -263,7 +263,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_acosh_obj, vector_acosh); #endif /* ULAB_NUMPY_HAS_ACOSH */ #if ULAB_NUMPY_HAS_ASIN -//| def asin(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def asin(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse sine function""" //| ... //| @@ -277,7 +277,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_asin_obj, vector_asin); #endif /* ULAB_NUMPY_HAS_ASIN */ #if ULAB_NUMPY_HAS_ASINH -//| def asinh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def asinh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse hyperbolic sine function""" //| ... //| @@ -291,7 +291,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_asinh_obj, vector_asinh); #endif /* ULAB_NUMPY_HAS_ASINH */ #if ULAB_NUMPY_HAS_AROUND -//| def around(a: _ArrayLike, *, decimals: int = 0) -> ulab.numpy.ndarray: +//| def around(a: ulab.numpy.ndarray, *, decimals: int = 0) -> ulab.numpy.ndarray: //| """Returns a new float array in which each element is rounded to //| ``decimals`` places.""" //| ... @@ -371,7 +371,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(vector_around_obj, 1, vector_around); #endif /* ULAB_NUMPY_HAS_AROUND */ #if ULAB_NUMPY_HAS_ATAN -//| def atan(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def atan(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse tangent function; the return values are in the //| range [-pi/2,pi/2].""" //| ... @@ -387,7 +387,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_atan_obj, vector_atan); #if ULAB_NUMPY_HAS_ATANH -//| def atanh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def atanh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse hyperbolic tangent function""" //| ... //| @@ -401,7 +401,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_atanh_obj, vector_atanh); #endif /* ULAB_NUMPY_HAS_ATANH */ #if ULAB_NUMPY_HAS_ARCTAN2 -//| def arctan2(ya: _ArrayLike, xa: _ArrayLike) -> ulab.numpy.ndarray: +//| def arctan2(ya: _ScalarOrArrayLike, xa: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the inverse tangent function of y/x; the return values are in //| the range [-pi, pi].""" //| ... @@ -494,7 +494,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(vector_arctan2_obj, vector_arctan2); #endif /* ULAB_VECTORISE_HAS_ARCTAN2 */ #if ULAB_NUMPY_HAS_CEIL -//| def ceil(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def ceil(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Rounds numbers up to the next whole number""" //| ... //| @@ -508,7 +508,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_ceil_obj, vector_ceil); #endif /* ULAB_NUMPY_HAS_CEIL */ #if ULAB_NUMPY_HAS_COS -//| def cos(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def cos(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the cosine function""" //| ... //| @@ -522,7 +522,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_cos_obj, vector_cos); #endif /* ULAB_NUMPY_HAS_COS */ #if ULAB_NUMPY_HAS_COSH -//| def cosh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def cosh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the hyperbolic cosine function""" //| ... //| @@ -536,7 +536,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_cosh_obj, vector_cosh); #endif /* ULAB_NUMPY_HAS_COSH */ #if ULAB_NUMPY_HAS_DEGREES -//| def degrees(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def degrees(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Converts angles from radians to degrees""" //| ... //| @@ -559,7 +559,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_degrees_obj, vector_degrees); #endif /* ULAB_NUMPY_HAS_DEGREES */ #if ULAB_SCIPY_SPECIAL_HAS_ERF -//| def erf(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def erf(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the error function, which has applications in statistics""" //| ... //| @@ -573,7 +573,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_erf_obj, vector_erf); #endif /* ULAB_SCIPY_SPECIAL_HAS_ERF */ #if ULAB_SCIPY_SPECIAL_HAS_ERFC -//| def erfc(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def erfc(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the complementary error function, which has applications in statistics""" //| ... //| @@ -587,7 +587,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_erfc_obj, vector_erfc); #endif /* ULAB_SCIPY_SPECIAL_HAS_ERFC */ #if ULAB_NUMPY_HAS_EXP -//| def exp(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def exp(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the exponent function.""" //| ... //| @@ -690,7 +690,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_exp_obj, vector_exp); #endif /* ULAB_NUMPY_HAS_EXP */ #if ULAB_NUMPY_HAS_EXPM1 -//| def expm1(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def expm1(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes $e^x-1$. In certain applications, using this function preserves numeric accuracy better than the `exp` function.""" //| ... //| @@ -704,7 +704,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_expm1_obj, vector_expm1); #endif /* ULAB_NUMPY_HAS_EXPM1 */ #if ULAB_NUMPY_HAS_FLOOR -//| def floor(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def floor(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Rounds numbers up to the next whole number""" //| ... //| @@ -718,7 +718,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_floor_obj, vector_floor); #endif /* ULAB_NUMPY_HAS_FLOOR */ #if ULAB_SCIPY_SPECIAL_HAS_GAMMA -//| def gamma(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def gamma(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the gamma function""" //| ... //| @@ -732,7 +732,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_gamma_obj, vector_gamma); #endif /* ULAB_SCIPY_SPECIAL_HAS_GAMMA */ #if ULAB_SCIPY_SPECIAL_HAS_GAMMALN -//| def lgamma(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def lgamma(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the natural log of the gamma function""" //| ... //| @@ -746,7 +746,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_lgamma_obj, vector_lgamma); #endif /* ULAB_SCIPY_SEPCIAL_HAS_GAMMALN */ #if ULAB_NUMPY_HAS_LOG -//| def log(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def log(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the natural log""" //| ... //| @@ -760,7 +760,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_log_obj, vector_log); #endif /* ULAB_NUMPY_HAS_LOG */ #if ULAB_NUMPY_HAS_LOG10 -//| def log10(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def log10(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the log base 10""" //| ... //| @@ -774,7 +774,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_log10_obj, vector_log10); #endif /* ULAB_NUMPY_HAS_LOG10 */ #if ULAB_NUMPY_HAS_LOG2 -//| def log2(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def log2(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the log base 2""" //| ... //| @@ -788,7 +788,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_log2_obj, vector_log2); #endif /* ULAB_NUMPY_HAS_LOG2 */ #if ULAB_NUMPY_HAS_RADIANS -//| def radians(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def radians(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Converts angles from degrees to radians""" //| ... //| @@ -811,7 +811,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_radians_obj, vector_radians); #endif /* ULAB_NUMPY_HAS_RADIANS */ #if ULAB_NUMPY_HAS_SIN -//| def sin(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def sin(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the sine function""" //| ... //| @@ -825,7 +825,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_sin_obj, vector_sin); #endif /* ULAB_NUMPY_HAS_SIN */ #if ULAB_NUMPY_HAS_SINC -//| def sinc(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def sinc(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the normalized sinc function""" //| ... //| @@ -852,7 +852,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_sinc_obj, vector_sinc); #endif /* ULAB_NUMPY_HAS_SINC */ #if ULAB_NUMPY_HAS_SINH -//| def sinh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def sinh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the hyperbolic sine""" //| ... //| @@ -867,7 +867,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_sinh_obj, vector_sinh); #if ULAB_NUMPY_HAS_SQRT -//| def sqrt(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def sqrt(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the square root""" //| ... //| @@ -1030,7 +1030,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_sqrt_obj, vector_sqrt); #endif /* ULAB_NUMPY_HAS_SQRT */ #if ULAB_NUMPY_HAS_TAN -//| def tan(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def tan(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the tangent""" //| ... //| @@ -1044,7 +1044,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(vector_tan_obj, vector_tan); #endif /* ULAB_NUMPY_HAS_TAN */ #if ULAB_NUMPY_HAS_TANH -//| def tanh(a: _ArrayLike) -> ulab.numpy.ndarray: +//| def tanh(a: _ScalarOrArrayLike) -> _ScalarOrNdArray: //| """Computes the hyperbolic tangent""" //| ... @@ -1158,12 +1158,12 @@ const mp_obj_type_t vector_function_type = { //| f: Union[Callable[[int], _float], Callable[[_float], _float]], //| *, //| otypes: Optional[_DType] = None -//| ) -> Callable[[_ArrayLike], ulab.numpy.ndarray]: +//| ) -> Callable[[_ScalarOrArrayLike], ulab.numpy.ndarray]: //| """ //| :param callable f: The function to wrap //| :param otypes: List of array types that may be returned by the function. None is interpreted to mean the return value is float. //| -//| Wrap a Python function ``f`` so that it can be applied to arrays. +//| Wrap a Python function ``f`` so that it can be applied to arrays or scalars. A scalar passed to the wrapped function is treated as a single-element 1-D array. //| The callable must return only values of the types specified by ``otypes``, or the result is undefined.""" //| ... //| From 63dfbd178ba3b5cfbff5d656f586d7f3f3e46409 Mon Sep 17 00:00:00 2001 From: Philip Howard Date: Thu, 29 Feb 2024 20:34:50 +0000 Subject: [PATCH 04/13] Remove the STATIC macro. (#664) Reflect the changes proposed in micropython/micropython#13763. --- code/ndarray.c | 4 ++-- code/numpy/approx.c | 4 ++-- code/numpy/fft/fft.c | 4 ++-- code/numpy/linalg/linalg.c | 4 ++-- code/scipy/optimize/optimize.c | 4 ++-- code/ulab.c | 12 ++++++------ docs/manual/source/ulab-programming.rst | 2 +- docs/ulab-programming.ipynb | 2 +- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/code/ndarray.c b/code/ndarray.c index 84ce8495..5e662851 100644 --- a/code/ndarray.c +++ b/code/ndarray.c @@ -917,7 +917,7 @@ ndarray_obj_t *ndarray_from_iterable(mp_obj_t obj, uint8_t dtype) { return ndarray; } -STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_INT(NDARRAY_FLOAT) } }, @@ -940,7 +940,7 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m return _dtype; } -STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) { +static mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) { uint8_t dtype = ndarray_init_helper(n_args, args, kw_args); if(mp_obj_is_type(args[0], &ulab_ndarray_type)) { diff --git a/code/numpy/approx.c b/code/numpy/approx.c index 23f9da1b..a268bb1d 100644 --- a/code/numpy/approx.c +++ b/code/numpy/approx.c @@ -47,7 +47,7 @@ ULAB_DEFINE_FLOAT_CONST(approx_trapz_dx, MICROPY_FLOAT_CONST(1.0), 0x3f800000UL, //| ... //| -STATIC mp_obj_t approx_interp(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t approx_interp(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, @@ -151,7 +151,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(approx_interp_obj, 2, approx_interp); //| ... //| -STATIC mp_obj_t approx_trapz(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t approx_trapz(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, { MP_QSTR_x, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, diff --git a/code/numpy/fft/fft.c b/code/numpy/fft/fft.c index 42621f52..e0893c2f 100644 --- a/code/numpy/fft/fft.c +++ b/code/numpy/fft/fft.c @@ -88,13 +88,13 @@ static mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft); #endif -STATIC const mp_rom_map_elem_t ulab_fft_globals_table[] = { +static const mp_rom_map_elem_t ulab_fft_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fft) }, { MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&fft_fft_obj) }, { MP_ROM_QSTR(MP_QSTR_ifft), MP_ROM_PTR(&fft_ifft_obj) }, }; -STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table); +static MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table); const mp_obj_module_t ulab_fft_module = { .base = { &mp_type_module }, diff --git a/code/numpy/linalg/linalg.c b/code/numpy/linalg/linalg.c index 6fc79aa0..70b1d20b 100644 --- a/code/numpy/linalg/linalg.c +++ b/code/numpy/linalg/linalg.c @@ -506,7 +506,7 @@ static mp_obj_t linalg_qr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ MP_DEFINE_CONST_FUN_OBJ_KW(linalg_qr_obj, 1, linalg_qr); #endif -STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = { +static const mp_rom_map_elem_t ulab_linalg_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_linalg) }, #if ULAB_MAX_DIMS > 1 #if ULAB_LINALG_HAS_CHOLESKY @@ -530,7 +530,7 @@ STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = { #endif }; -STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table); +static MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table); const mp_obj_module_t ulab_linalg_module = { .base = { &mp_type_module }, diff --git a/code/scipy/optimize/optimize.c b/code/scipy/optimize/optimize.c index 9bd80878..bd2e2c29 100644 --- a/code/scipy/optimize/optimize.c +++ b/code/scipy/optimize/optimize.c @@ -55,7 +55,7 @@ static mp_float_t optimize_python_call(const mp_obj_type_t *type, mp_obj_t fun, //| ... //| -STATIC mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // Simple bisection routine static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, @@ -125,7 +125,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(optimize_bisect_obj, 3, optimize_bisect); //| ... //| -STATIC mp_obj_t optimize_fmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { +static mp_obj_t optimize_fmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { // downhill simplex method in 1D static const mp_arg_t allowed_args[] = { { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } }, diff --git a/code/ulab.c b/code/ulab.c index df73f7bb..b18d9fa3 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -43,13 +43,13 @@ #define ULAB_VERSION_STRING xstr(ULAB_VERSION) xstr(-) xstr(ULAB_MAX_DIMS) xstr(D) #endif -STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, ULAB_VERSION_STRING); +static MP_DEFINE_STR_OBJ(ulab_version_obj, ULAB_VERSION_STRING); #ifdef ULAB_HASH -STATIC MP_DEFINE_STR_OBJ(ulab_sha_obj, xstr(ULAB_HASH)); +static MP_DEFINE_STR_OBJ(ulab_sha_obj, xstr(ULAB_HASH)); #endif -STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = { +static const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = { #if ULAB_MAX_DIMS > 1 #if NDARRAY_HAS_RESHAPE { MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ndarray_reshape_obj) }, @@ -78,7 +78,7 @@ STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = { #endif }; -STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table); +static MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table); #if defined(MP_DEFINE_CONST_OBJ_TYPE) // MicroPython after-b41aaaa (Sept 19 2022). @@ -192,7 +192,7 @@ const mp_obj_type_t ndarray_flatiter_type = { #endif #endif -STATIC const mp_rom_map_elem_t ulab_globals_table[] = { +static const mp_rom_map_elem_t ulab_globals_table[] = { { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ulab) }, { MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) }, #ifdef ULAB_HASH @@ -217,7 +217,7 @@ STATIC const mp_rom_map_elem_t ulab_globals_table[] = { #endif }; -STATIC MP_DEFINE_CONST_DICT ( +static MP_DEFINE_CONST_DICT ( mp_module_ulab_globals, ulab_globals_table ); diff --git a/docs/manual/source/ulab-programming.rst b/docs/manual/source/ulab-programming.rst index f8c81c9c..3abb3ac4 100644 --- a/docs/manual/source/ulab-programming.rst +++ b/docs/manual/source/ulab-programming.rst @@ -896,7 +896,7 @@ the ``user`` module: .. code:: c - STATIC const mp_rom_map_elem_t ulab_user_globals_table[] = { + static const mp_rom_map_elem_t ulab_user_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_user) }, { MP_OBJ_NEW_QSTR(MP_QSTR_square), (mp_obj_t)&user_square_obj }, }; diff --git a/docs/ulab-programming.ipynb b/docs/ulab-programming.ipynb index 6eabf6d5..9685991e 100644 --- a/docs/ulab-programming.ipynb +++ b/docs/ulab-programming.ipynb @@ -718,7 +718,7 @@ "Finally, we have to bind this function object in the globals table of the `user` module: \n", "\n", "```c\n", - "STATIC const mp_rom_map_elem_t ulab_user_globals_table[] = {\n", + "static const mp_rom_map_elem_t ulab_user_globals_table[] = {\n", " { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_user) },\n", " { MP_OBJ_NEW_QSTR(MP_QSTR_square), (mp_obj_t)&user_square_obj },\n", "};\n", From 65c941a8059afe1cfd6f4c2b15d0ade798dc24f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Wed, 6 Mar 2024 18:59:32 +0100 Subject: [PATCH 05/13] fix loadtxt for the case, when built-in complexes are not supported (#666) --- code/numpy/io/io.c | 4 ++++ code/ulab.c | 2 +- docs/ulab-change-log.md | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/code/numpy/io/io.c b/code/numpy/io/io.c index f2479f19..95e62adc 100644 --- a/code/numpy/io/io.c +++ b/code/numpy/io/io.c @@ -239,7 +239,11 @@ MP_DEFINE_CONST_FUN_OBJ_1(io_load_obj, io_load); #if ULAB_NUMPY_HAS_LOADTXT static void io_assign_value(const char *clipboard, uint8_t len, ndarray_obj_t *ndarray, size_t *idx, uint8_t dtype) { + #if MICROPY_PY_BUILTINS_COMPLEX mp_obj_t value = mp_parse_num_decimal(clipboard, len, false, false, NULL); + #else + mp_obj_t value = mp_parse_num_float(clipboard, len, false, NULL); + #endif if(dtype != NDARRAY_FLOAT) { mp_float_t _value = mp_obj_get_float(value); value = mp_obj_new_int((int32_t)MICROPY_FLOAT_C_FUN(round)(_value)); diff --git a/code/ulab.c b/code/ulab.c index b18d9fa3..ef2b06fe 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.5.1 +#define ULAB_VERSION 6.5.2 #define xstr(s) str(s) #define str(s) #s diff --git a/docs/ulab-change-log.md b/docs/ulab-change-log.md index 7113d8b3..9f885936 100644 --- a/docs/ulab-change-log.md +++ b/docs/ulab-change-log.md @@ -1,3 +1,9 @@ +Wed, 6 Mar 2024 + +version 6.5.2 + + allow loadtxt to parse numbers, even if built-in complexes are not supported + Tue, 9 Jan 2024 version 6.5.0 From 6fb60ef9cffc85a951d11fef85cd5df70c277b0f Mon Sep 17 00:00:00 2001 From: Philip Howard Date: Thu, 6 Jun 2024 20:54:24 +0100 Subject: [PATCH 06/13] CI: Update some deprecated dependency versions (#669) * CI: Bump various build workflow versions. * CI: Continue other jobs on failure. Give a more complete overview of failures, rather than forcing the developer to play whack-a-mole. * CI: Do not modify unix mpconfigport.h. Since `MICROPY_PY_UHASHLIB` does not occur in unix/mpconfigport.h this would have simply duplicated the config file and supplied it as `MP_CONFIGFILE` triggering a bug in how this define is handled. --- .github/workflows/build.yml | 20 +++++++++++--------- build-cp.sh | 3 +-- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8900bc71..c0477efb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,6 +16,7 @@ on: jobs: micropython: + continue-on-error: true strategy: matrix: os: @@ -28,10 +29,10 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - name: Set up Python 3.10 - uses: actions/setup-python@v1 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Install requirements run: | @@ -44,10 +45,10 @@ jobs: gcc --version python3 --version - name: Checkout ulab - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Checkout micropython repo - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: micropython/micropython path: micropython @@ -56,6 +57,7 @@ jobs: run: ./build.sh ${{ matrix.dims }} circuitpython: + continue-on-error: true strategy: matrix: os: @@ -68,10 +70,10 @@ jobs: env: GITHUB_CONTEXT: ${{ toJson(github) }} run: echo "$GITHUB_CONTEXT" - - name: Set up Python 3.10 - uses: actions/setup-python@v1 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: "3.10" + python-version: "3.12" - name: Versions run: | @@ -79,7 +81,7 @@ jobs: python3 --version - name: Checkout ulab - uses: actions/checkout@v1 + uses: actions/checkout@v4 - name: Install requirements run: | diff --git a/build-cp.sh b/build-cp.sh index ee6a95ef..9081a618 100755 --- a/build-cp.sh +++ b/build-cp.sh @@ -41,8 +41,7 @@ HERE="$(dirname -- "$(readlinkf_posix -- "${0}")" )" rm -rf circuitpython/extmod/ulab; ln -s "$HERE" circuitpython/extmod/ulab dims=${1-2} make -C circuitpython/mpy-cross -j$NPROC -sed -e '/MICROPY_PY_UHASHLIB/s/1/0/' < circuitpython/ports/unix/mpconfigport.h > circuitpython/ports/unix/mpconfigport_ulab.h -make -k -C circuitpython/ports/unix -j$NPROC DEBUG=1 MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 MICROPY_SSL_AXTLS=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMP_CONFIGFILE=\"\" -Wno-tautological-constant-out-of-range-compare -Wno-unknown-pragmas -DULAB_MAX_DIMS=$dims" BUILD=build-$dims PROG=micropython-$dims +make -k -C circuitpython/ports/unix -j$NPROC DEBUG=1 MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 MICROPY_SSL_AXTLS=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-Wno-tautological-constant-out-of-range-compare -Wno-unknown-pragmas -DULAB_MAX_DIMS=$dims" BUILD=build-$dims PROG=micropython-$dims # bash test-common.sh "${dims}" "circuitpython/ports/unix/micropython-$dims" From 519c48149f39ba9fa327f0cbb38b7d766a7d8ba9 Mon Sep 17 00:00:00 2001 From: Andy Piper Date: Sun, 21 Jul 2024 12:20:18 +0100 Subject: [PATCH 07/13] Removed Pycom reference (#675) UInfortunately Pycom is no longer a thing, removed from the platforms list. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index e7feeca6..df406254 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,6 @@ of the user manual. 1. `MaixPy` https://github.com/sipeed/MaixPy 1. `OpenMV` https://github.com/openmv/openmv 1. `pimoroni-pico` https://github.com/pimoroni/pimoroni-pico -3. `pycom` https://pycom.io/ ## Compiling From e40a667e3c22251fba36a4b7a38d9f75635210f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Tue, 23 Jul 2024 17:20:56 +0200 Subject: [PATCH 08/13] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df406254..5c91d671 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ulab -[![Documentation Status](https://readthedocs.org/projects/micropython-ulab-robert/badge/?version=latest)](https://micropython-ulab-robert.readthedocs.io/en/latest/?badge=latest) +[![Documentation Status](https://readthedocs.org/projects/micropython-ulab/badge/?version=latest)](https://micropython-ulab.readthedocs.io/en/latest/index.html) `ulab` is a `numpy`-like array manipulation library for [micropython](http://micropython.org/) and [CircuitPython](https://circuitpython.org/). The module is written in C, defines compact containers (`ndarray`s) for numerical data of one to four From 41c4363f11c8d639ff4676b3680a1e3f23a93327 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Tue, 23 Jul 2024 18:59:29 +0200 Subject: [PATCH 09/13] address issue raised in https://github.com/v923z/micropython-ulab/issues/676 (#677) * ndarrays can be created from buffer --- code/ndarray.c | 31 ++++++++++++++++++------------- code/ndarray.h | 2 +- code/numpy/create.c | 13 ++----------- code/numpy/numerical.c | 2 +- code/ulab.c | 2 +- 5 files changed, 23 insertions(+), 27 deletions(-) diff --git a/code/ndarray.c b/code/ndarray.c index 5e662851..26ced6fc 100644 --- a/code/ndarray.c +++ b/code/ndarray.c @@ -6,7 +6,7 @@ * * The MIT License (MIT) * - * Copyright (c) 2019-2022 Zoltán Vörös + * Copyright (c) 2019-2024 Zoltán Vörös * 2020 Jeff Epler for Adafruit Industries * 2020 Taku Fukada */ @@ -509,8 +509,9 @@ static size_t multiply_size(size_t a, size_t b) { return result; } -ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype) { +ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype, uint8_t *buffer) { // Creates the base ndarray with shape, and initialises the values to straight 0s + // optionally, values can be supplied via the last argument ndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t); ndarray->base.type = &ulab_ndarray_type; ndarray->dtype = dtype == NDARRAY_BOOL ? NDARRAY_UINT8 : dtype; @@ -536,9 +537,13 @@ ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides // if the length is 0, still allocate a single item, so that contractions can be handled size_t len = multiply_size(ndarray->itemsize, MAX(1, ndarray->len)); - uint8_t *array = m_new0(byte, len); - // this should set all elements to 0, irrespective of the of the dtype (all bits are zero) - // we could, perhaps, leave this step out, and initialise the array only, when needed + uint8_t *array; + array = buffer; + if(array == NULL) { + // this should set all elements to 0, irrespective of the of the dtype (all bits are zero) + // we could, perhaps, leave this step out, and initialise the array only, when needed + array = m_new0(byte, len); + } ndarray->array = array; ndarray->origin = array; return ndarray; @@ -547,12 +552,12 @@ ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides ndarray_obj_t *ndarray_new_dense_ndarray(uint8_t ndim, size_t *shape, uint8_t dtype) { // creates a dense array, i.e., one, where the strides are derived directly from the shapes // the function should work in the general n-dimensional case - int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); - strides[ULAB_MAX_DIMS-1] = (int32_t)ulab_binary_get_size(dtype); - for(size_t i=ULAB_MAX_DIMS; i > 1; i--) { - strides[i-2] = strides[i-1] * MAX(1, shape[i-1]); - } - return ndarray_new_ndarray(ndim, shape, strides, dtype); + // int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + // strides[ULAB_MAX_DIMS - 1] = (int32_t)ulab_binary_get_size(dtype); + // for(size_t i = ULAB_MAX_DIMS; i > 1; i--) { + // strides[i-2] = strides[i-1] * MAX(1, shape[i-1]); + // } + return ndarray_new_ndarray(ndim, shape, NULL, dtype, NULL); } ndarray_obj_t *ndarray_new_ndarray_from_tuple(mp_obj_tuple_t *_shape, uint8_t dtype) { @@ -650,7 +655,7 @@ ndarray_obj_t *ndarray_copy_view(ndarray_obj_t *source) { if(source->boolean) { dtype = NDARRAY_BOOL; } - ndarray_obj_t *ndarray = ndarray_new_ndarray(source->ndim, source->shape, strides, dtype); + ndarray_obj_t *ndarray = ndarray_new_ndarray(source->ndim, source->shape, strides, dtype, NULL); ndarray_copy_array(source, ndarray, 0); return ndarray; } @@ -1884,7 +1889,7 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { #if ULAB_SUPPORTS_COMPLEX if(self->dtype == NDARRAY_COMPLEX) { int32_t *strides = strides_from_shape(self->shape, NDARRAY_FLOAT); - ndarray_obj_t *target = ndarray_new_ndarray(self->ndim, self->shape, strides, NDARRAY_FLOAT); + ndarray_obj_t *target = ndarray_new_ndarray(self->ndim, self->shape, strides, NDARRAY_FLOAT, NULL); ndarray = MP_OBJ_TO_PTR(carray_abs(self, target)); } else { #endif diff --git a/code/ndarray.h b/code/ndarray.h index 2ce84bed..3e82b385 100644 --- a/code/ndarray.h +++ b/code/ndarray.h @@ -188,7 +188,7 @@ int32_t *ndarray_contract_strides(ndarray_obj_t *, uint8_t ); ndarray_obj_t *ndarray_from_iterable(mp_obj_t , uint8_t ); ndarray_obj_t *ndarray_new_dense_ndarray(uint8_t , size_t *, uint8_t ); ndarray_obj_t *ndarray_new_ndarray_from_tuple(mp_obj_tuple_t *, uint8_t ); -ndarray_obj_t *ndarray_new_ndarray(uint8_t , size_t *, int32_t *, uint8_t ); +ndarray_obj_t *ndarray_new_ndarray(uint8_t , size_t *, int32_t *, uint8_t , uint8_t *); ndarray_obj_t *ndarray_new_linear_array(size_t , uint8_t ); ndarray_obj_t *ndarray_new_view(ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t ); bool ndarray_is_dense(ndarray_obj_t *); diff --git a/code/numpy/create.c b/code/numpy/create.c index f427e374..e915f127 100644 --- a/code/numpy/create.c +++ b/code/numpy/create.c @@ -838,19 +838,10 @@ mp_obj_t create_frombuffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw len = count; } } - ndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t); - ndarray->base.type = &ulab_ndarray_type; - ndarray->dtype = dtype == NDARRAY_BOOL ? NDARRAY_UINT8 : dtype; - ndarray->boolean = dtype == NDARRAY_BOOL ? NDARRAY_BOOLEAN : NDARRAY_NUMERIC; - ndarray->ndim = 1; - ndarray->len = len; - ndarray->itemsize = sz; - ndarray->shape[ULAB_MAX_DIMS - 1] = len; - ndarray->strides[ULAB_MAX_DIMS - 1] = sz; + size_t *shape = ndarray_shape_vector(0, 0, 0, len); uint8_t *buffer = bufinfo.buf; - ndarray->array = buffer + offset; - return MP_OBJ_FROM_PTR(ndarray); + return ndarray_new_ndarray(1, shape, NULL, dtype, buffer + offset); } return mp_const_none; } diff --git a/code/numpy/numerical.c b/code/numpy/numerical.c index e3b42525..68cf44dd 100644 --- a/code/numpy/numerical.c +++ b/code/numpy/numerical.c @@ -746,7 +746,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw numerical_reduce_axes(ndarray, ax, shape, strides); // We could return an NDARRAY_UINT8 array, if all lengths are shorter than 256 - ndarray_obj_t *indices = ndarray_new_ndarray(ndarray->ndim, ndarray->shape, NULL, NDARRAY_UINT16); + ndarray_obj_t *indices = ndarray_new_ndarray(ndarray->ndim, ndarray->shape, NULL, NDARRAY_UINT16, NULL); int32_t *istrides = m_new0(int32_t, ULAB_MAX_DIMS); numerical_reduce_axes(indices, ax, shape, istrides); diff --git a/code/ulab.c b/code/ulab.c index ef2b06fe..24776986 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.5.2 +#define ULAB_VERSION 6.5.3 #define xstr(s) str(s) #define str(s) #s From 99cb54a4260e214b683654480aa4f5d104f1184c Mon Sep 17 00:00:00 2001 From: page200 <69221289+page200@users.noreply.github.com> Date: Tue, 6 Aug 2024 11:07:32 +0200 Subject: [PATCH 10/13] Correct `a[a < 5]` in ulab-ndarray.ipynb (#678) --- docs/ulab-ndarray.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/ulab-ndarray.ipynb b/docs/ulab-ndarray.ipynb index 0e2bb1b0..8d67ed9b 100644 --- a/docs/ulab-ndarray.ipynb +++ b/docs/ulab-ndarray.ipynb @@ -3270,7 +3270,7 @@ "output_type": "stream", "text": [ "a:\t array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], dtype=float)\n", - "a < 5:\t array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)\n", + "a[a < 5]:\t array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)\n", "\n", "\n" ] @@ -3283,7 +3283,7 @@ "\n", "a = np.array(range(9), dtype=np.float)\n", "print(\"a:\\t\", a)\n", - "print(\"a < 5:\\t\", a[a < 5])" + "print(\"a[a < 5]:\\t\", a[a < 5])" ] }, { From a77022dcd0de69392ffa1a1491ede44ed17020d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Mart=C3=ADnez?= <58857054+elpekenin@users.noreply.github.com> Date: Sun, 25 Aug 2024 16:09:47 +0200 Subject: [PATCH 11/13] add missing typing (#680) --- code/numpy/carray/carray.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/code/numpy/carray/carray.c b/code/numpy/carray/carray.c index 159c191d..bf0d7166 100644 --- a/code/numpy/carray/carray.c +++ b/code/numpy/carray/carray.c @@ -25,9 +25,11 @@ #if ULAB_SUPPORTS_COMPLEX +//| import builtins +//| //| import ulab.numpy -//| def real(val): +//| def real(val: ulab.numpy.ndarray) -> ulab.numpy.ndarray: //| """ //| Return the real part of the complex argument, which can be //| either an ndarray, or a scalar.""" @@ -54,7 +56,7 @@ mp_obj_t carray_real(mp_obj_t _source) { MP_DEFINE_CONST_FUN_OBJ_1(carray_real_obj, carray_real); -//| def imag(val): +//| def imag(val: ulab.numpy.ndarray) -> ulab.numpy.ndarray: //| """ //| Return the imaginary part of the complex argument, which can be //| either an ndarray, or a scalar.""" @@ -82,7 +84,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(carray_imag_obj, carray_imag); #if ULAB_NUMPY_HAS_CONJUGATE -//| def conjugate(val): +//| def conjugate( +//| val: builtins.complex | ulab.numpy.ndarray +//| ) -> builtins.complex | ulab.numpy.ndarray: //| """ //| Return the conjugate of the complex argument, which can be //| either an ndarray, or a scalar.""" From 1d3ddd8f5228e2c7335dac71f4846e6abb0ec9f9 Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Mon, 9 Sep 2024 00:55:05 -0400 Subject: [PATCH 12/13] numpy/random.c: fix use of MICROPY_PY_RANDOM_SEED_INIT_FUNC (#684) --- code/numpy/random/random.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/code/numpy/random/random.c b/code/numpy/random/random.c index 73a34f82..165f11b5 100644 --- a/code/numpy/random/random.c +++ b/code/numpy/random/random.c @@ -41,7 +41,7 @@ MP_DEFINE_CONST_OBJ_TYPE( MP_QSTR_generator, MP_TYPE_FLAG_NONE, print, random_generator_print, - make_new, random_generator_make_new, + make_new, random_generator_make_new, locals_dict, &random_generator_locals_dict ); #else @@ -76,11 +76,12 @@ mp_obj_t random_generator_make_new(const mp_obj_type_t *type, size_t n_args, siz if(args[0] == mp_const_none) { #ifndef MICROPY_PY_RANDOM_SEED_INIT_FUNC mp_raise_ValueError(MP_ERROR_TEXT("no default seed")); - #endif + #else random_generator_obj_t *generator = m_new_obj(random_generator_obj_t); generator->base.type = &random_generator_type; generator->state = MICROPY_PY_RANDOM_SEED_INIT_FUNC; return MP_OBJ_FROM_PTR(generator); + #endif } else if(mp_obj_is_int(args[0])) { random_generator_obj_t *generator = m_new_obj(random_generator_obj_t); generator->base.type = &random_generator_type; @@ -89,7 +90,7 @@ mp_obj_t random_generator_make_new(const mp_obj_type_t *type, size_t n_args, siz } else if(mp_obj_is_type(args[0], &mp_type_tuple)){ mp_obj_tuple_t *seeds = MP_OBJ_TO_PTR(args[0]); mp_obj_t *items = m_new(mp_obj_t, seeds->len); - + for(uint8_t i = 0; i < seeds->len; i++) { random_generator_obj_t *generator = m_new_obj(random_generator_obj_t); generator->base.type = &random_generator_type; @@ -175,7 +176,7 @@ static mp_obj_t random_normal(size_t n_args, const mp_obj_t *pos_args, mp_map_t mp_float_t *array = (mp_float_t *)ndarray->array; - // numpy's random supports only dense output arrays, so we can simply + // numpy's random supports only dense output arrays, so we can simply // loop through the elements in a linear fashion for(size_t i = 0; i < ndarray->len; i = i + 2) { #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT @@ -248,7 +249,7 @@ static mp_obj_t random_random(size_t n_args, const mp_obj_t *pos_args, mp_map_t if(!mp_obj_is_type(out, &ulab_ndarray_type)) { mp_raise_TypeError(MP_ERROR_TEXT("out has wrong type")); } - + ndarray = MP_OBJ_TO_PTR(out); if(ndarray->dtype != NDARRAY_FLOAT) { @@ -283,10 +284,10 @@ static mp_obj_t random_random(size_t n_args, const mp_obj_t *pos_args, mp_map_t mp_float_t *array = (mp_float_t *)ndarray->array; - // numpy's random supports only dense output arrays, so we can simply + // numpy's random supports only dense output arrays, so we can simply // loop through the elements in a linear fashion for(size_t i = 0; i < ndarray->len; i++) { - + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT uint32_t x = pcg32_next(&self->state); *array = (float)(int32_t)(x >> 8) * 0x1.0p-24f; @@ -375,4 +376,3 @@ const mp_obj_module_t ulab_numpy_random_module = { .base = { &mp_type_module }, .globals = (mp_obj_dict_t*)&mp_module_ulab_numpy_random_globals, }; - From 45f23ebc82426b3a4569377a04bb2747c447c2e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Sat, 14 Sep 2024 11:38:04 +0200 Subject: [PATCH 13/13] Roll fix (#687) * fix roll, when shift is 0 --- code/numpy/numerical.c | 8 +++++++- code/ulab.c | 2 +- docs/ulab-change-log.md | 6 ++++++ 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/code/numpy/numerical.c b/code/numpy/numerical.c index 68cf44dd..0961e3c0 100644 --- a/code/numpy/numerical.c +++ b/code/numpy/numerical.c @@ -1186,13 +1186,19 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar mp_raise_TypeError(MP_ERROR_TEXT("roll argument must be an ndarray")); } ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); - uint8_t *array = ndarray->array; ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim, ndarray->shape, ndarray->dtype); int32_t shift = mp_obj_get_int(args[1].u_obj); + + if(shift == 0) { + ndarray_copy_array(ndarray, results, 0); + return MP_OBJ_FROM_PTR(results); + } + int32_t _shift = shift < 0 ? -shift : shift; size_t counter; + uint8_t *array = ndarray->array; uint8_t *rarray = (uint8_t *)results->array; if(args[2].u_obj == mp_const_none) { // roll the flattened array diff --git a/code/ulab.c b/code/ulab.c index 24776986..948d621f 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.5.3 +#define ULAB_VERSION 6.5.4 #define xstr(s) str(s) #define str(s) #s diff --git a/docs/ulab-change-log.md b/docs/ulab-change-log.md index 9f885936..90b86307 100644 --- a/docs/ulab-change-log.md +++ b/docs/ulab-change-log.md @@ -1,3 +1,9 @@ +Sat, 14 Sep 2024 + +version 6.5.4 + + fix roll, when shift is 0 + Wed, 6 Mar 2024 version 6.5.2