From b0befbdbc5c66e5f0eeb880d0e9afe6ff13e6d87 Mon Sep 17 00:00:00 2001 From: ArtichOwO Date: Wed, 23 Jun 2021 22:40:41 +0200 Subject: [PATCH 1/7] [MPY/MOD] Added uLab --- python/Makefile | 26 + python/port/genhdr/qstrdefs.in.h | 117 + python/port/mod/ulab/ndarray.c | 2180 +++++++++++++++++ python/port/mod/ulab/ndarray.h | 736 ++++++ python/port/mod/ulab/ndarray_operators.c | 807 ++++++ python/port/mod/ulab/ndarray_operators.h | 277 +++ python/port/mod/ulab/ndarray_properties.c | 100 + python/port/mod/ulab/ndarray_properties.h | 92 + python/port/mod/ulab/numpy/approx/approx.c | 221 ++ python/port/mod/ulab/numpy/approx/approx.h | 29 + python/port/mod/ulab/numpy/compare/compare.c | 417 ++++ python/port/mod/ulab/numpy/compare/compare.h | 150 ++ python/port/mod/ulab/numpy/fft/fft.c | 82 + python/port/mod/ulab/numpy/fft/fft.h | 24 + python/port/mod/ulab/numpy/fft/fft_tools.c | 165 ++ python/port/mod/ulab/numpy/fft/fft_tools.h | 23 + python/port/mod/ulab/numpy/filter/filter.c | 84 + python/port/mod/ulab/numpy/filter/filter.h | 20 + python/port/mod/ulab/numpy/linalg/linalg.c | 397 +++ python/port/mod/ulab/numpy/linalg/linalg.h | 26 + .../port/mod/ulab/numpy/linalg/linalg_tools.c | 171 ++ .../port/mod/ulab/numpy/linalg/linalg_tools.h | 28 + .../port/mod/ulab/numpy/numerical/numerical.c | 1338 ++++++++++ .../port/mod/ulab/numpy/numerical/numerical.h | 652 +++++ python/port/mod/ulab/numpy/numpy.c | 336 +++ python/port/mod/ulab/numpy/numpy.h | 21 + python/port/mod/ulab/numpy/poly/poly.c | 232 ++ python/port/mod/ulab/numpy/poly/poly.h | 21 + python/port/mod/ulab/numpy/stats/stats.c | 52 + python/port/mod/ulab/numpy/stats/stats.h | 20 + .../port/mod/ulab/numpy/transform/transform.c | 89 + .../port/mod/ulab/numpy/transform/transform.h | 28 + python/port/mod/ulab/numpy/vector/vector.c | 635 +++++ python/port/mod/ulab/numpy/vector/vector.h | 156 ++ python/port/mod/ulab/scipy/linalg/linalg.c | 279 +++ python/port/mod/ulab/scipy/linalg/linalg.h | 21 + .../port/mod/ulab/scipy/optimize/optimize.c | 414 ++++ .../port/mod/ulab/scipy/optimize/optimize.h | 41 + python/port/mod/ulab/scipy/scipy.c | 51 + python/port/mod/ulab/scipy/scipy.h | 21 + python/port/mod/ulab/scipy/signal/signal.c | 153 ++ python/port/mod/ulab/scipy/signal/signal.h | 24 + python/port/mod/ulab/scipy/special/special.c | 42 + python/port/mod/ulab/scipy/special/special.h | 21 + python/port/mod/ulab/ulab.c | 162 ++ python/port/mod/ulab/ulab.h | 658 +++++ python/port/mod/ulab/ulab_create.c | 706 ++++++ python/port/mod/ulab/ulab_create.h | 78 + python/port/mod/ulab/ulab_tools.c | 233 ++ python/port/mod/ulab/ulab_tools.h | 37 + python/port/mod/ulab/user/user.c | 95 + python/port/mod/ulab/user/user.h | 20 + python/port/mod/ulab/utils/utils.c | 215 ++ python/port/mod/ulab/utils/utils.h | 19 + python/port/mpconfigport.h | 2 + python/port/port.cpp | 1 + 56 files changed, 13045 insertions(+) create mode 100644 python/port/mod/ulab/ndarray.c create mode 100644 python/port/mod/ulab/ndarray.h create mode 100644 python/port/mod/ulab/ndarray_operators.c create mode 100644 python/port/mod/ulab/ndarray_operators.h create mode 100644 python/port/mod/ulab/ndarray_properties.c create mode 100644 python/port/mod/ulab/ndarray_properties.h create mode 100644 python/port/mod/ulab/numpy/approx/approx.c create mode 100644 python/port/mod/ulab/numpy/approx/approx.h create mode 100644 python/port/mod/ulab/numpy/compare/compare.c create mode 100644 python/port/mod/ulab/numpy/compare/compare.h create mode 100644 python/port/mod/ulab/numpy/fft/fft.c create mode 100644 python/port/mod/ulab/numpy/fft/fft.h create mode 100644 python/port/mod/ulab/numpy/fft/fft_tools.c create mode 100644 python/port/mod/ulab/numpy/fft/fft_tools.h create mode 100644 python/port/mod/ulab/numpy/filter/filter.c create mode 100644 python/port/mod/ulab/numpy/filter/filter.h create mode 100644 python/port/mod/ulab/numpy/linalg/linalg.c create mode 100644 python/port/mod/ulab/numpy/linalg/linalg.h create mode 100644 python/port/mod/ulab/numpy/linalg/linalg_tools.c create mode 100644 python/port/mod/ulab/numpy/linalg/linalg_tools.h create mode 100644 python/port/mod/ulab/numpy/numerical/numerical.c create mode 100644 python/port/mod/ulab/numpy/numerical/numerical.h create mode 100644 python/port/mod/ulab/numpy/numpy.c create mode 100644 python/port/mod/ulab/numpy/numpy.h create mode 100644 python/port/mod/ulab/numpy/poly/poly.c create mode 100644 python/port/mod/ulab/numpy/poly/poly.h create mode 100644 python/port/mod/ulab/numpy/stats/stats.c create mode 100644 python/port/mod/ulab/numpy/stats/stats.h create mode 100644 python/port/mod/ulab/numpy/transform/transform.c create mode 100644 python/port/mod/ulab/numpy/transform/transform.h create mode 100644 python/port/mod/ulab/numpy/vector/vector.c create mode 100644 python/port/mod/ulab/numpy/vector/vector.h create mode 100644 python/port/mod/ulab/scipy/linalg/linalg.c create mode 100644 python/port/mod/ulab/scipy/linalg/linalg.h create mode 100644 python/port/mod/ulab/scipy/optimize/optimize.c create mode 100644 python/port/mod/ulab/scipy/optimize/optimize.h create mode 100644 python/port/mod/ulab/scipy/scipy.c create mode 100644 python/port/mod/ulab/scipy/scipy.h create mode 100644 python/port/mod/ulab/scipy/signal/signal.c create mode 100644 python/port/mod/ulab/scipy/signal/signal.h create mode 100644 python/port/mod/ulab/scipy/special/special.c create mode 100644 python/port/mod/ulab/scipy/special/special.h create mode 100644 python/port/mod/ulab/ulab.c create mode 100644 python/port/mod/ulab/ulab.h create mode 100644 python/port/mod/ulab/ulab_create.c create mode 100644 python/port/mod/ulab/ulab_create.h create mode 100644 python/port/mod/ulab/ulab_tools.c create mode 100644 python/port/mod/ulab/ulab_tools.h create mode 100644 python/port/mod/ulab/user/user.c create mode 100644 python/port/mod/ulab/user/user.h create mode 100644 python/port/mod/ulab/utils/utils.c create mode 100644 python/port/mod/ulab/utils/utils.h diff --git a/python/Makefile b/python/Makefile index 6957ed586..15a770c73 100644 --- a/python/Makefile +++ b/python/Makefile @@ -154,6 +154,32 @@ port_src += $(addprefix python/port/,\ mod/turtle/modturtle.cpp \ mod/turtle/modturtle_table.c \ mod/turtle/turtle.cpp \ + mod/ulab/scipy/linalg/linalg.c \ + mod/ulab/scipy/optimize/optimize.c \ + mod/ulab/scipy/signal/signal.c \ + mod/ulab/scipy/special/special.c \ + mod/ulab/ndarray_operators.c \ + mod/ulab/ulab_tools.c \ + mod/ulab/ndarray.c \ + mod/ulab/ndarray_properties.c \ + mod/ulab/numpy/approx/approx.c \ + mod/ulab/numpy/compare/compare.c \ + mod/ulab/ulab_create.c \ + mod/ulab/numpy/fft/fft.c \ + mod/ulab/numpy/fft/fft_tools.c \ + mod/ulab/numpy/filter/filter.c \ + mod/ulab/numpy/linalg/linalg.c \ + mod/ulab/numpy/linalg/linalg_tools.c \ + mod/ulab/numpy/numerical/numerical.c \ + mod/ulab/numpy/poly/poly.c \ + mod/ulab/numpy/stats/stats.c \ + mod/ulab/numpy/transform/transform.c \ + mod/ulab/numpy/vector/vector.c \ + mod/ulab/numpy/numpy.c \ + mod/ulab/scipy/scipy.c \ + mod/ulab/user/user.c \ + mod/ulab/utils/utils.c \ + mod/ulab/ulab.c \ mphalport.c \ ) diff --git a/python/port/genhdr/qstrdefs.in.h b/python/port/genhdr/qstrdefs.in.h index c580bcb8e..f6d637bff 100644 --- a/python/port/genhdr/qstrdefs.in.h +++ b/python/port/genhdr/qstrdefs.in.h @@ -545,3 +545,120 @@ Q(machine) Q(rename) Q(listdir) +// ulab QSTRs +Q(threshold) +Q(edgeitems) +Q(inplace) +Q(dtype) +Q(order) +Q(C) +Q(shape) +Q(strides) +Q(itemsize) +Q(size) +Q(T) +Q(x) +Q(dx) +Q(fft) +Q(ifft) +Q(a) +Q(v) +Q(linalg) +Q(cholesky) +Q(det) +Q(eig) +Q(inv) +Q(norm) +Q(n) +Q(ddof) +Q(numpy) +Q(ndarray) +Q(array) +Q(frombuffer) +Q(inf) +Q(nan) +Q(uint8) +Q(int8) +Q(uint16) +Q(int16) +Q(set_printoptions) +Q(get_printoptions) +Q(ndinfo) +Q(arange) +Q(concatenate) +Q(diag) +Q(empty) +Q(eye) +Q(interp) +Q(trapz) +Q(full) +Q(linspace) +Q(logspace) +Q(ones) +Q(zeros) +Q(clip) +Q(equal) +Q(not_equal) +Q(maximum) +Q(minimum) +Q(where) +Q(convolve) +Q(argmax) +Q(argmin) +Q(argsort) +Q(cross) +Q(diff) +Q(dot) +Q(decimals) +Q(otypes) +Q(solve_triangular) +Q(cho_solve) +Q(trace) +Q(flip) +Q(mean) +Q(median) +Q(roll) +Q(std) +Q(polyfit) +Q(polyval) +Q(arctan2) +Q(around) +Q(vectorize) +Q(xtol) +Q(maxiter) +Q(xatol) +Q(fatol) +Q(tol) +Q(rtol) +Q(scipy) +Q(optimize) +Q(signal) +Q(bisect) +Q(special) +Q(fmin) +Q(newton) +Q(sos) +Q(zi) +Q(spectrogram) +Q(sosfilt) +Q(gammaln) +Q(reshape) +Q(transpose) +Q(byteswap) +Q(flatten) +Q(k) +Q(tobytes) +Q(M) +Q(ulab) +Q(num) +Q(endpoint) +Q(__version__) +Q(utils) +Q(retstep) +Q(base) +Q(offset) +Q(out) +Q(from_int16_buffer) +Q(from_uint16_buffer) +Q(from_int32_buffer) +Q(from_uint32_buffer) diff --git a/python/port/mod/ulab/ndarray.c b/python/port/mod/ulab/ndarray.c new file mode 100644 index 000000000..e37802efe --- /dev/null +++ b/python/port/mod/ulab/ndarray.c @@ -0,0 +1,2180 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ulab_tools.h" +#include "ndarray.h" +#include "ndarray_operators.h" + +mp_uint_t ndarray_print_threshold = NDARRAY_PRINT_THRESHOLD; +mp_uint_t ndarray_print_edgeitems = NDARRAY_PRINT_EDGEITEMS; + +//| """Manipulate numeric data similar to numpy +//| +//| `ulab` is a numpy-like module for micropython, meant to simplify and +//| speed up common mathematical operations on arrays. The primary goal was to +//| implement a small subset of numpy that might be useful in the context of a +//| microcontroller. This means low-level data processing of linear (array) and +//| two-dimensional (matrix) data. +//| +//| `ulab` is adapted from micropython-ulab, and the original project's +//| documentation can be found at +//| https://micropython-ulab.readthedocs.io/en/latest/ +//| +//| `ulab` is modeled after numpy, and aims to be a compatible subset where +//| possible. Numpy's documentation can be found at +//| https://docs.scipy.org/doc/numpy/index.html""" +//| +//| from typing import Dict +//| +//| _DType = int +//| """`ulab.int8`, `ulab.uint8`, `ulab.int16`, `ulab.uint16`, `ulab.float` or `ulab.bool`""" +//| +//| _float = float +//| """Type alias of the bulitin float""" +//| +//| _bool = bool +//| """Type alias of the bulitin bool""" +//| +//| _Index = Union[int, slice, ulab.ndarray, Tuple[Union[int, slice], ...]] +//| + +//| class ndarray: +//| """1- and 2- dimensional ndarray""" +//| +//| def __init__( +//| self, +//| values: Union[ndarray, Iterable[Union[_float, _bool, Iterable[Any]]]], +//| *, +//| dtype: _DType = ulab.float +//| ) -> None: +//| """:param sequence values: Sequence giving the initial content of the ndarray. +//| :param ~ulab._DType dtype: The type of ndarray values, `ulab.int8`, `ulab.uint8`, `ulab.int16`, `ulab.uint16`, `ulab.float` or `ulab.bool` +//| +//| The ``values`` sequence can either be another ~ulab.ndarray, sequence of numbers +//| (in which case a 1-dimensional ndarray is created), or a sequence where each +//| subsequence has the same length (in which case a 2-dimensional ndarray is +//| created). +//| +//| Passing a `ulab.ndarray` and a different dtype can be used to convert an ndarray +//| from one dtype to another. +//| +//| In many cases, it is more convenient to create an ndarray from a function +//| like `zeros` or `linspace`. +//| +//| `ulab.ndarray` implements the buffer protocol, so it can be used in many +//| places an `array.array` can be used.""" +//| ... +//| +//| shape: Tuple[int, ...] +//| """The size of the array, a tuple of length 1 or 2""" +//| +//| size: int +//| """The number of elements in the array""" +//| +//| itemsize: int +//| """The size of a single item in the array""" +//| +//| strides: Tuple[int, ...] +//| """Tuple of bytes to step in each dimension, a tuple of length 1 or 2""" +//| +//| def copy(self) -> ulab.ndarray: +//| """Return a copy of the array""" +//| ... +//| +//| def dtype(self) -> _DType: +//| """Returns the dtype of the array""" +//| ... +//| +//| def flatten(self, *, order: str = "C") -> ulab.ndarray: +//| """:param order: Whether to flatten by rows ('C') or columns ('F') +//| +//| Returns a new `ulab.ndarray` object which is always 1 dimensional. +//| If order is 'C' (the default", then the data is ordered in rows; +//| If it is 'F', then the data is ordered in columns. "C" and "F" refer +//| to the typical storage organization of the C and Fortran languages.""" +//| ... +//| +//| def reshape(self, shape: Tuple[int, ...]) -> ulab.ndarray: +//| """Returns an ndarray containing the same data with a new shape.""" +//| ... +//| +//| def sort(self, *, axis: Optional[int] = 1) -> None: +//| """:param axis: Whether to sort elements within rows (0), columns (1), or elements (None)""" +//| ... +//| +//| def tobytes(self) -> bytearray: +//| """Return the raw data bytes in the ndarray""" +//| ... +//| +//| def transpose(self) -> ulab.ndarray: +//| """Swap the rows and columns of a 2-dimensional ndarray""" +//| ... +//| +//| def __add__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| """Adds corresponding elements of the two ndarrays, or adds a number to all +//| elements of the ndarray. If both arguments are ndarrays, their sizes must match.""" +//| ... +//| def __radd__(self, other: _float) -> ulab.ndarray: ... +//| +//| def __sub__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| """Subtracts corresponding elements of the two ndarrays, or subtracts a number from all +//| elements of the ndarray. If both arguments are ndarrays, their sizes must match.""" +//| ... +//| def __rsub__(self, other: _float) -> ulab.ndarray: ... +//| +//| def __mul__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| """Multiplies corresponding elements of the two ndarrays, or multiplies +//| all elements of the ndarray by a number. If both arguments are ndarrays, +//| their sizes must match.""" +//| ... +//| def __rmul__(self, other: _float) -> ulab.ndarray: ... +//| +//| def __div__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| """Multiplies corresponding elements of the two ndarrays, or divides +//| all elements of the ndarray by a number. If both arguments are ndarrays, +//| their sizes must match.""" +//| ... +//| def __rdiv__(self, other: _float) -> ulab.ndarray: ... +//| +//| def __pow__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| """Computes the power (x**y) of corresponding elements of the the two ndarrays, +//| or one number and one ndarray. If both arguments are ndarrays, their sizes +//| must match.""" +//| ... +//| def __rpow__(self, other: _float) -> ulab.ndarray: ... +//| +//| def __inv__(self) -> ulab.ndarray: +//| ... +//| def __neg__(self) -> ulab.ndarray: +//| ... +//| def __pos__(self) -> ulab.ndarray: +//| ... +//| def __abs__(self) -> ulab.ndarray: +//| ... +//| def __len__(self) -> int: +//| ... +//| def __lt__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| ... +//| def __le__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| ... +//| def __gt__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| ... +//| def __ge__(self, other: Union[ndarray, _float]) -> ulab.ndarray: +//| ... +//| +//| def __iter__(self) -> Union[Iterator[ndarray], Iterator[_float]]: +//| ... +//| +//| def __getitem__(self, index: _Index) -> Union[ndarray, _float]: +//| """Retrieve an element of the ndarray.""" +//| ... +//| +//| def __setitem__(self, index: _Index, value: Union[ndarray, _float]) -> None: +//| """Set an element of the ndarray.""" +//| ... +//| +//| _ArrayLike = Union[ndarray, List[_float], Tuple[_float], range] +//| """`ulab.ndarray`, ``List[float]``, ``Tuple[float]`` or `range`""" +//| +//| int8: _DType +//| """Type code for signed integers in the range -128 .. 127 inclusive, like the 'b' typecode of `array.array`""" +//| +//| int16: _DType +//| """Type code for signed integers in the range -32768 .. 32767 inclusive, like the 'h' typecode of `array.array`""" +//| +//| float: _DType +//| """Type code for floating point values, like the 'f' typecode of `array.array`""" +//| +//| uint8: _DType +//| """Type code for unsigned integers in the range 0 .. 255 inclusive, like the 'H' typecode of `array.array`""" +//| +//| uint16: _DType +//| """Type code for unsigned integers in the range 0 .. 65535 inclusive, like the 'h' typecode of `array.array`""" +//| +//| bool: _DType +//| """Type code for boolean values""" +//| +//| def get_printoptions() -> Dict[str, int]: +//| """Get printing options""" +//| ... +//| +//| def set_printoptions(threshold: Optional[int] = None, edgeitems: Optional[int] = None) -> None: +//| """Set printing options""" +//| ... +//| +//| def ndinfo(array: ulab.ndarray) -> None: +//| ... +//| +//| def array( +//| values: Union[ndarray, Iterable[Union[_float, _bool, Iterable[Any]]]], +//| *, +//| dtype: _DType = ulab.float +//| ) -> ulab.ndarray: +//| """alternate constructor function for `ulab.ndarray`. Mirrors numpy.array""" +//| ... + + +#ifdef CIRCUITPY +void ndarray_set_value(char typecode, void *p, size_t index, mp_obj_t val_in) { + switch (typecode) { + case NDARRAY_INT8: + ((signed char *)p)[index] = mp_obj_get_int(val_in); + break; + case NDARRAY_UINT8: + ((unsigned char *)p)[index] = mp_obj_get_int(val_in); + break; + case NDARRAY_INT16: + ((short *)p)[index] = mp_obj_get_int(val_in); + break; + case NDARRAY_UINT16: + ((unsigned short *)p)[index] = mp_obj_get_int(val_in); + break; + case NDARRAY_FLOAT: + ((mp_float_t *)p)[index] = mp_obj_get_float(val_in); + break; + } +} +#endif + +#if defined(MICROPY_VERSION_MAJOR) && MICROPY_VERSION_MAJOR == 1 && MICROPY_VERSION_MINOR == 12 + +void mp_obj_slice_indices(mp_obj_t self_in, mp_int_t length, mp_bound_slice_t *result) { + mp_obj_slice_t *self = MP_OBJ_TO_PTR(self_in); + mp_int_t start, stop, step; + + if (self->step == mp_const_none) { + step = 1; + } else { + step = mp_obj_get_int(self->step); + if (step == 0) { + mp_raise_ValueError(translate("slice step can't be zero")); + } + } + + if (step > 0) { + // Positive step + if (self->start == mp_const_none) { + start = 0; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length, MAX(start, 0)); + } + + if (self->stop == mp_const_none) { + stop = length; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length, MAX(stop, 0)); + } + } else { + // Negative step + if (self->start == mp_const_none) { + start = length - 1; + } else { + start = mp_obj_get_int(self->start); + if (start < 0) { + start += length; + } + start = MIN(length - 1, MAX(start, -1)); + } + + if (self->stop == mp_const_none) { + stop = -1; + } else { + stop = mp_obj_get_int(self->stop); + if (stop < 0) { + stop += length; + } + stop = MIN(length - 1, MAX(stop, -1)); + } + } + + result->start = start; + result->stop = stop; + result->step = step; +} +#endif /* MICROPY_VERSION v1.11 */ + +void ndarray_fill_array_iterable(mp_float_t *array, mp_obj_t iterable) { + mp_obj_iter_buf_t x_buf; + mp_obj_t x_item, x_iterable = mp_getiter(iterable, &x_buf); + while ((x_item = mp_iternext(x_iterable)) != MP_OBJ_STOP_ITERATION) { + *array++ = (mp_float_t)mp_obj_get_float(x_item); + } +} + +#if ULAB_HAS_FUNCTION_ITERATOR +size_t *ndarray_new_coords(uint8_t ndim) { + size_t *coords = m_new(size_t, ndim); + memset(coords, 0, ndim*sizeof(size_t)); + return coords; +} + +void ndarray_rewind_array(uint8_t ndim, uint8_t *array, size_t *shape, int32_t *strides, size_t *coords) { + // resets the data pointer of a single array, whenever an axis is full + // since we always iterate over the very last axis, we have to keep track of + // the last ndim-2 axes only + array -= shape[ULAB_MAX_DIMS - 1] * strides[ULAB_MAX_DIMS - 1]; + array += strides[ULAB_MAX_DIMS - 2]; + for(uint8_t i=1; i < ndim-1; i++) { + coords[ULAB_MAX_DIMS - 1 - i] += 1; + if(coords[ULAB_MAX_DIMS - 1 - i] == shape[ULAB_MAX_DIMS - 1 - i]) { // we are at a dimension boundary + array -= shape[ULAB_MAX_DIMS - 1 - i] * strides[ULAB_MAX_DIMS - 1 - i]; + array += strides[ULAB_MAX_DIMS - 2 - i]; + coords[ULAB_MAX_DIMS - 1 - i] = 0; + coords[ULAB_MAX_DIMS - 2 - i] += 1; + } else { // coordinates can change only, if the last coordinate changes + return; + } + } +} +#endif + +static int32_t *strides_from_shape(size_t *shape, uint8_t dtype) { + // returns a strides array that corresponds to a dense array with the prescribed shape + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + strides[ULAB_MAX_DIMS-1] = (int32_t)mp_binary_get_size('@', dtype, NULL); + for(uint8_t i=ULAB_MAX_DIMS; i > 1; i--) { + strides[i-2] = strides[i-1] * shape[i-1]; + } + return strides; +} + +size_t *ndarray_shape_vector(size_t a, size_t b, size_t c, size_t d) { + // returns a ULAB_MAX_DIMS-aware array of shapes + // WARNING: this assumes that the maximum possible dimension is 4! + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + shape[ULAB_MAX_DIMS - 1] = d; + #if ULAB_MAX_DIMS > 1 + shape[ULAB_MAX_DIMS - 2] = c; + #endif + #if ULAB_MAX_DIMS > 2 + shape[ULAB_MAX_DIMS - 3] = b; + #endif + #if ULAB_MAX_DIMS > 3 + shape[ULAB_MAX_DIMS - 4] = a; + #endif + return shape; +} + +bool ndarray_object_is_array_like(mp_obj_t o_in) { + if(mp_obj_is_type(o_in, &ulab_ndarray_type) || + mp_obj_is_type(o_in, &mp_type_tuple) || + mp_obj_is_type(o_in, &mp_type_list) || + mp_obj_is_type(o_in, &mp_type_range)) { + return true; + } + return false; +} + +void fill_array_iterable(mp_float_t *array, mp_obj_t iterable) { + mp_obj_iter_buf_t x_buf; + mp_obj_t x_item, x_iterable = mp_getiter(iterable, &x_buf); + size_t i=0; + while ((x_item = mp_iternext(x_iterable)) != MP_OBJ_STOP_ITERATION) { + array[i] = (mp_float_t)mp_obj_get_float(x_item); + i++; + } +} + +#if NDARRAY_HAS_DTYPE +#if ULAB_HAS_DTYPE_OBJECT +void ndarray_dtype_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + dtype_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_print_str(print, "dtype('"); + if(self->dtype == NDARRAY_BOOLEAN) { + mp_print_str(print, "bool')"); + } else if(self->dtype == NDARRAY_UINT8) { + mp_print_str(print, "uint8')"); + } else if(self->dtype == NDARRAY_INT8) { + mp_print_str(print, "int8')"); + } else if(self->dtype == NDARRAY_UINT16) { + mp_print_str(print, "uint16')"); + } else if(self->dtype == NDARRAY_INT16) { + mp_print_str(print, "int16')"); + } else { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + mp_print_str(print, "float32')"); + #else + mp_print_str(print, "float64')"); + #endif + } +} + +mp_obj_t ndarray_dtype_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void) type; + mp_arg_check_num(n_args, n_kw, 0, 1, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_OBJ, { .u_obj = mp_const_none } }, + }; + mp_arg_val_t _args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, _args); + + dtype_obj_t *dtype = m_new_obj(dtype_obj_t); + dtype->base.type = &ulab_dtype_type; + + if(mp_obj_is_type(args[0], &ulab_ndarray_type)) { + // return the dtype of the array + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0]); + dtype->dtype = ndarray->dtype; + } else { + uint8_t _dtype; + if(mp_obj_is_int(_args[0].u_obj)) { + _dtype = mp_obj_get_int(_args[0].u_obj); + if((_dtype != NDARRAY_BOOL) && (_dtype != NDARRAY_UINT8) + && (_dtype != NDARRAY_INT8) && (_dtype != NDARRAY_UINT16) + && (_dtype != NDARRAY_INT16) && (_dtype != NDARRAY_FLOAT)) { + mp_raise_TypeError(translate("data type not understood")); + } + } else { + GET_STR_DATA_LEN(_args[0].u_obj, _dtype_, len); + if(memcmp(_dtype_, "uint8", 5) == 0) { + _dtype = NDARRAY_UINT8; + } else if(memcmp(_dtype_, "int8", 4) == 0) { + _dtype = NDARRAY_INT8; + } else if(memcmp(_dtype_, "uint16", 6) == 0) { + _dtype = NDARRAY_UINT16; + } else if(memcmp(_dtype_, "int16", 5) == 0) { + _dtype = NDARRAY_INT16; + } else if(memcmp(_dtype_, "float", 5) == 0) { + _dtype = NDARRAY_FLOAT; + } else { + mp_raise_TypeError(translate("data type not understood")); + } + } + dtype->dtype = _dtype; + } + return dtype; +} + +mp_obj_t ndarray_dtype(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + dtype_obj_t *dtype = m_new_obj(dtype_obj_t); + dtype->base.type = &ulab_dtype_type; + dtype->dtype = self->dtype; + return dtype; +} + +#else +// this is the cheap implementation of tbe dtype +mp_obj_t ndarray_dtype(mp_obj_t self_in) { + uint8_t dtype; + if(mp_obj_is_type(self_in, &ulab_ndarray_type)) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + dtype = self->dtype; + } else { // we assume here that the input is a single character + GET_STR_DATA_LEN(self_in, _dtype, len); + if((len != 1) || ((*_dtype != NDARRAY_BOOL) && (*_dtype != NDARRAY_UINT8) + && (*_dtype != NDARRAY_INT8) && (*_dtype != NDARRAY_UINT16) + && (*_dtype != NDARRAY_INT16) && (*_dtype != NDARRAY_FLOAT))) { + mp_raise_TypeError(translate("data type not understood")); + } + dtype = *_dtype; + } + return mp_obj_new_int(dtype); +} +#endif /* ULAB_HAS_DTYPE_OBJECT */ +#endif /* NDARRAY_HAS_DTYPE */ + +#if ULAB_HAS_PRINTOPTIONS +mp_obj_t ndarray_set_printoptions(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_threshold, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + { MP_QSTR_edgeitems, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if(args[0].u_rom_obj != mp_const_none) { + ndarray_print_threshold = mp_obj_get_int(args[0].u_rom_obj); + } + if(args[1].u_rom_obj != mp_const_none) { + ndarray_print_edgeitems = mp_obj_get_int(args[1].u_rom_obj); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_set_printoptions_obj, 0, ndarray_set_printoptions); + +mp_obj_t ndarray_get_printoptions(void) { + mp_obj_t dict = mp_obj_new_dict(2); + mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(MP_QSTR_threshold), mp_obj_new_int(ndarray_print_threshold)); + mp_obj_dict_store(MP_OBJ_FROM_PTR(dict), MP_OBJ_NEW_QSTR(MP_QSTR_edgeitems), mp_obj_new_int(ndarray_print_edgeitems)); + return dict; +} + +MP_DEFINE_CONST_FUN_OBJ_0(ndarray_get_printoptions_obj, ndarray_get_printoptions); +#endif + +mp_obj_t ndarray_get_item(ndarray_obj_t *ndarray, void *array) { + // returns a proper micropython object from an array + if(!ndarray->boolean) { + return mp_binary_get_val_array(ndarray->dtype, array, 0); + } else { + if(*(uint8_t *)array) { + return mp_const_true; + } else { + return mp_const_false; + } + } +} + +static void ndarray_print_row(const mp_print_t *print, ndarray_obj_t * ndarray, uint8_t *array, size_t stride, size_t n) { + if(n == 0) { + return; + } + mp_print_str(print, "["); + if((n <= ndarray_print_threshold) || (n <= 2*ndarray_print_edgeitems)) { // if the array is short, print everything + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + array += stride; + for(size_t i=1; i < n; i++, array += stride) { + mp_print_str(print, ", "); + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + } + } else { + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + array += stride; + for(size_t i=1; i < ndarray_print_edgeitems; i++, array += stride) { + mp_print_str(print, ", "); + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + } + mp_printf(print, ", ..., "); + array += stride * (n - 2 * ndarray_print_edgeitems); + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + array += stride; + for(size_t i=1; i < ndarray_print_edgeitems; i++, array += stride) { + mp_print_str(print, ", "); + mp_obj_print_helper(print, ndarray_get_item(ndarray, array), PRINT_REPR); + } + } + mp_print_str(print, "]"); +} + +static void ndarray_print_bracket(const mp_print_t *print, const size_t condition, const size_t shape, const char *string) { + if(condition < shape) { + mp_print_str(print, string); + } +} + +void ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { + (void)kind; + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + uint8_t *array = (uint8_t *)self->array; + mp_print_str(print, "array("); + if(self->len == 0) { + mp_print_str(print, "[]"); + if(self->ndim > 1) { + mp_print_str(print, ", shape=("); + for(uint8_t ndim = self->ndim; ndim > 1; ndim--) { + mp_printf(MP_PYTHON_PRINTER, "%d,", self->shape[ULAB_MAX_DIMS - ndim]); + } + mp_printf(MP_PYTHON_PRINTER, "%d)", self->shape[ULAB_MAX_DIMS - 1]); + } + } else { + #if ULAB_MAX_DIMS > 3 + size_t i=0; + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-4], "["); + do { + #endif + #if ULAB_MAX_DIMS > 2 + size_t j = 0; + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-3], "["); + do { + #endif + #if ULAB_MAX_DIMS > 1 + size_t k = 0; + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-2], "["); + do { + #endif + ndarray_print_row(print, self, array, self->strides[ULAB_MAX_DIMS-1], self->shape[ULAB_MAX_DIMS-1]); + #if ULAB_MAX_DIMS > 1 + array += self->strides[ULAB_MAX_DIMS-2]; + k++; + ndarray_print_bracket(print, k, self->shape[ULAB_MAX_DIMS-2], ",\n "); + } while(k < self->shape[ULAB_MAX_DIMS-2]); + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-2], "]"); + #endif + #if ULAB_MAX_DIMS > 2 + j++; + ndarray_print_bracket(print, j, self->shape[ULAB_MAX_DIMS-3], ",\n\n "); + array -= self->strides[ULAB_MAX_DIMS-2] * self->shape[ULAB_MAX_DIMS-2]; + array += self->strides[ULAB_MAX_DIMS-3]; + } while(j < self->shape[ULAB_MAX_DIMS-3]); + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-3], "]"); + #endif + #if ULAB_MAX_DIMS > 3 + array -= self->strides[ULAB_MAX_DIMS-3] * self->shape[ULAB_MAX_DIMS-3]; + array += self->strides[ULAB_MAX_DIMS-4]; + i++; + ndarray_print_bracket(print, i, self->shape[ULAB_MAX_DIMS-4], ",\n\n "); + } while(i < self->shape[ULAB_MAX_DIMS-4]); + ndarray_print_bracket(print, 0, self->shape[ULAB_MAX_DIMS-4], "]"); + #endif + } + if(self->boolean) { + mp_print_str(print, ", dtype=bool)"); + } else if(self->dtype == NDARRAY_UINT8) { + mp_print_str(print, ", dtype=uint8)"); + } else if(self->dtype == NDARRAY_INT8) { + mp_print_str(print, ", dtype=int8)"); + } else if(self->dtype == NDARRAY_UINT16) { + mp_print_str(print, ", dtype=uint16)"); + } else if(self->dtype == NDARRAY_INT16) { + mp_print_str(print, ", dtype=int16)"); + } else { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + mp_print_str(print, ", dtype=float32)"); + #else + mp_print_str(print, ", dtype=float64)"); + #endif + } +} + +void ndarray_assign_elements(ndarray_obj_t *ndarray, mp_obj_t iterable, uint8_t dtype, size_t *idx) { + // assigns a single row in the tensor + mp_obj_t item; + if(ndarray->boolean) { + uint8_t *array = (uint8_t *)ndarray->array; + array += *idx; + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + // TODO: this might be wrong here: we have to check for the trueness of item + if(mp_obj_is_true(item)) { + *array = 1; + } + array++; + (*idx)++; + } + } else { + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + ndarray_set_value(dtype, ndarray->array, (*idx)++, item); + } + } +} + +bool ndarray_is_dense(ndarray_obj_t *ndarray) { + // returns true, if the array is dense, false otherwise + // the array should be dense, if the very first stride can be calculated from shape + int32_t stride = ndarray->itemsize; + for(uint8_t i = ULAB_MAX_DIMS - 1; i > ULAB_MAX_DIMS-ndarray->ndim; i--) { + stride *= ndarray->shape[i]; + } + return stride == ndarray->strides[ULAB_MAX_DIMS-ndarray->ndim] ? true : false; +} + + +ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype) { + // Creates the base ndarray with shape, and initialises the values to straight 0s + 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 = ndim; + ndarray->len = ndim == 0 ? 0 : 1; + ndarray->itemsize = mp_binary_get_size('@', ndarray->dtype, NULL); + int32_t *_strides; + if(strides == NULL) { + _strides = strides_from_shape(shape, ndarray->dtype); + } else { + _strides = strides; + } + for(uint8_t i=ULAB_MAX_DIMS; i > ULAB_MAX_DIMS-ndim; i--) { + ndarray->shape[i-1] = shape[i-1]; + ndarray->strides[i-1] = _strides[i-1]; + ndarray->len *= shape[i-1]; + } + + // if the length is 0, still allocate a single item, so that contractions can be handled + size_t len = ndarray->itemsize * MAX(1, ndarray->len); + uint8_t *array = m_new(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 + memset(array, 0, len); + ndarray->array = array; + ndarray->origin = array; + return ndarray; +} + +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] = dtype == NDARRAY_BOOL ? 1 : mp_binary_get_size('@', dtype, NULL); + 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); +} + +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 < ULAB_MAX_DIMS - _shape->len) { + shape[i] = 0; + } else { + shape[i] = mp_obj_get_int(_shape->items[i]); + } + } + return ndarray_new_dense_ndarray(_shape->len, shape, dtype); +} + +void ndarray_copy_array(ndarray_obj_t *source, ndarray_obj_t *target) { + // TODO: if the array is dense, the content could be copied in a single pass + // copies the content of source->array into a new dense void pointer + // it is assumed that the dtypes in source and target are the same + // Since the target is a new array, it is supposed to be dense + uint8_t *sarray = (uint8_t *)source->array; + uint8_t *tarray = (uint8_t *)target->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 { + memcpy(tarray, sarray, source->itemsize); + tarray += target->itemsize; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif +} + +ndarray_obj_t *ndarray_new_view(ndarray_obj_t *source, uint8_t ndim, size_t *shape, int32_t *strides, int32_t offset) { + // creates a new view from the input arguments + ndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t); + ndarray->base.type = &ulab_ndarray_type; + ndarray->boolean = source->boolean; + ndarray->dtype = source->dtype; + ndarray->ndim = ndim; + ndarray->itemsize = source->itemsize; + ndarray->len = ndim == 0 ? 0 : 1; + for(uint8_t i=ULAB_MAX_DIMS; i > ULAB_MAX_DIMS-ndim; i--) { + ndarray->shape[i-1] = shape[i-1]; + ndarray->strides[i-1] = strides[i-1]; + ndarray->len *= shape[i-1]; + } + uint8_t *pointer = (uint8_t *)source->array; + pointer += offset; + ndarray->array = pointer; + ndarray->origin = source->origin; + return ndarray; +} + +ndarray_obj_t *ndarray_copy_view(ndarray_obj_t *source) { + // creates a one-to-one deep copy of the input ndarray or its view + // the function should work in the general n-dimensional case + // In order to make it dtype-agnostic, we copy the memory content + // instead of reading out the values + + int32_t *strides = strides_from_shape(source->shape, source->dtype); + + uint8_t dtype = source->dtype; + if(source->boolean) { + dtype = NDARRAY_BOOLEAN; + } + ndarray_obj_t *ndarray = ndarray_new_ndarray(source->ndim, source->shape, strides, dtype); + ndarray_copy_array(source, ndarray); + return ndarray; +} + +#if NDARRAY_HAS_BYTESWAP +mp_obj_t ndarray_byteswap(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // changes the endiannes of an array + // if the dtype of the input uint8/int8/bool, simply return a copy or view + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_inplace, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ndarray_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj); + ndarray_obj_t *ndarray = NULL; + if(args[1].u_obj == mp_const_false) { + ndarray = ndarray_copy_view(self); + } else { + ndarray = ndarray_new_view(self, self->ndim, self->shape, self->strides, 0); + } + if((self->dtype == NDARRAY_BOOL) || (self->dtype == NDARRAY_UINT8) || (self->dtype == NDARRAY_INT8)) { + return MP_OBJ_FROM_PTR(ndarray); + } else { + uint8_t *array = (uint8_t *)ndarray->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 { + if(self->dtype == NDARRAY_FLOAT) { + #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT + SWAP(uint8_t, array[0], array[3]); + SWAP(uint8_t, array[1], array[2]); + #else + SWAP(uint8_t, array[0], array[7]); + SWAP(uint8_t, array[1], array[6]); + SWAP(uint8_t, array[2], array[5]); + SWAP(uint8_t, array[3], array[4]); + #endif + } else { + SWAP(uint8_t, array[0], array[1]); + } + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < ndarray->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1]; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < ndarray->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= ndarray->strides[ULAB_MAX_DIMS - 2] * ndarray->shape[ULAB_MAX_DIMS-2]; + array += ndarray->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < ndarray->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= ndarray->strides[ULAB_MAX_DIMS - 3] * ndarray->shape[ULAB_MAX_DIMS-3]; + array += ndarray->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < ndarray->shape[ULAB_MAX_DIMS - 4]); + #endif + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_byteswap_obj, 1, ndarray_byteswap); +#endif + +#if NDARRAY_HAS_COPY +mp_obj_t ndarray_copy(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_FROM_PTR(ndarray_copy_view(self)); +} + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_copy_obj, ndarray_copy); +#endif + +ndarray_obj_t *ndarray_new_linear_array(size_t len, uint8_t dtype) { + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + if(len == 0) { + return ndarray_new_dense_ndarray(0, shape, dtype); + } + shape[ULAB_MAX_DIMS-1] = len; + return ndarray_new_dense_ndarray(1, shape, dtype); +} + +ndarray_obj_t *ndarray_from_iterable(mp_obj_t obj, uint8_t dtype) { + // returns an ndarray from an iterable micropython object + // if the input is an ndarray, returns the input... + if(mp_obj_is_type(obj, &ulab_ndarray_type)) { + return MP_OBJ_TO_PTR(obj); + } + // ... otherwise, takes the values from the iterable, and creates the corresponding ndarray + + // First, we have to figure out, whether the elements of the iterable are iterables themself + uint8_t ndim = 0; + size_t shape[ULAB_MAX_DIMS]; + mp_obj_iter_buf_t iter_buf[ULAB_MAX_DIMS]; + mp_obj_t iterable[ULAB_MAX_DIMS]; + // inspect only the very first element in each dimension; this is fast, + // but not completely safe, e.g., length compatibility is not checked + mp_obj_t item = obj; + + while(1) { + if(mp_obj_len_maybe(item) == MP_OBJ_NULL) { + break; + } + if(ndim == ULAB_MAX_DIMS) { + mp_raise_ValueError(translate("too many dimensions")); + } + shape[ndim] = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(item)); + if(shape[ndim] == 0) { + ndim++; + break; + } + iterable[ndim] = mp_getiter(item, &iter_buf[ndim]); + item = mp_iternext(iterable[ndim]); + ndim++; + } + for(uint8_t i = 0; i < ndim; i++) { + // align all values to the right + shape[ULAB_MAX_DIMS - i - 1] = shape[ndim - 1 - i]; + } + + ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(ndim, shape, dtype); + item = obj; + for(uint8_t i = 0; i < ndim - 1; i++) { + // if ndim > 1, descend into the hierarchy + iterable[ULAB_MAX_DIMS - ndim + i] = mp_getiter(item, &iter_buf[ULAB_MAX_DIMS - ndim + i]); + item = mp_iternext(iterable[ULAB_MAX_DIMS - ndim + i]); + } + + size_t idx = 0; + // TODO: this could surely be done in a more elegant way... + #if ULAB_MAX_DIMS > 3 + do { + #endif + #if ULAB_MAX_DIMS > 2 + do { + #endif + #if ULAB_MAX_DIMS > 1 + do { + #endif + iterable[ULAB_MAX_DIMS - 1] = mp_getiter(item, &iter_buf[ULAB_MAX_DIMS - 1]); + ndarray_assign_elements(ndarray, iterable[ULAB_MAX_DIMS - 1], ndarray->dtype, &idx); + #if ULAB_MAX_DIMS > 1 + item = ndim > 1 ? mp_iternext(iterable[ULAB_MAX_DIMS - 2]) : MP_OBJ_STOP_ITERATION; + } while(item != MP_OBJ_STOP_ITERATION); + #endif + #if ULAB_MAX_DIMS > 2 + item = ndim > 2 ? mp_iternext(iterable[ULAB_MAX_DIMS - 3]) : MP_OBJ_STOP_ITERATION; + if(item != MP_OBJ_STOP_ITERATION) { + iterable[ULAB_MAX_DIMS - 2] = mp_getiter(item, &iter_buf[ULAB_MAX_DIMS - 2]); + item = mp_iternext(iterable[ULAB_MAX_DIMS - 2]); + } else { + iterable[ULAB_MAX_DIMS - 2] = MP_OBJ_STOP_ITERATION; + } + } while(iterable[ULAB_MAX_DIMS - 2] != MP_OBJ_STOP_ITERATION); + #endif + #if ULAB_MAX_DIMS > 3 + item = ndim > 3 ? mp_iternext(iterable[ULAB_MAX_DIMS - 4]) : MP_OBJ_STOP_ITERATION; + if(item != MP_OBJ_STOP_ITERATION) { + iterable[ULAB_MAX_DIMS - 3] = mp_getiter(item, &iter_buf[ULAB_MAX_DIMS - 3]); + item = mp_iternext(iterable[ULAB_MAX_DIMS - 3]); + } else { + iterable[ULAB_MAX_DIMS - 3] = MP_OBJ_STOP_ITERATION; + } + } while(iterable[ULAB_MAX_DIMS - 3] != MP_OBJ_STOP_ITERATION); + #endif + + return ndarray; +} + +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_const_none } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_ROM_INT(NDARRAY_FLOAT) } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t _dtype; + #if ULAB_HAS_DTYPE_OBJECT + if(mp_obj_is_type(args[1].u_obj, &ulab_dtype_type)) { + dtype_obj_t *dtype = MP_OBJ_TO_PTR(args[1].u_obj); + _dtype = dtype->dtype; + } else { // this must be an integer defined as a class constant (ulba.uint8 etc.) + _dtype = mp_obj_get_int(args[1].u_obj); + } + #else + _dtype = mp_obj_get_int(args[1].u_obj); + #endif + 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) { + uint8_t dtype = ndarray_init_helper(n_args, args, kw_args); + + if(mp_obj_is_type(args[0], &ulab_ndarray_type)) { + ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0]); + if(dtype == source->dtype) { + return ndarray_copy_view(source); + } + ndarray_obj_t *target = ndarray_new_dense_ndarray(source->ndim, source->shape, dtype); + uint8_t *sarray = (uint8_t *)source->array; + uint8_t *tarray = (uint8_t *)target->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_obj_t item; + if((source->dtype == NDARRAY_FLOAT) && (dtype != NDARRAY_FLOAT)) { + // floats must be treated separately, because they can't directly be converted to integer types + mp_float_t f = ndarray_get_float_value(sarray, source->dtype); + item = mp_obj_new_int((int32_t)MICROPY_FLOAT_C_FUN(floor)(f)); + } else { + item = mp_binary_get_val_array(source->dtype, sarray, 0); + } + ndarray_set_value(dtype, tarray, 0, item); + tarray += target->itemsize; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif + return MP_OBJ_FROM_PTR(target); + } else { + // assume that the input is an iterable + return MP_OBJ_FROM_PTR(ndarray_from_iterable(args[0], dtype)); + } +} + +mp_obj_t ndarray_array_constructor(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // array constructor for ndarray, equivalent to numpy.array(...) + return ndarray_make_new_core(&ulab_ndarray_type, n_args, kw_args->used, pos_args, kw_args); +} +MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_array_constructor_obj, 1, ndarray_array_constructor); + +#ifdef CIRCUITPY +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) { + (void) type; + mp_arg_check_num(n_args, kw_args, 1, 2, true); + size_t n_kw = 0; + if (kw_args != 0) { + n_kw = kw_args->used; + } + mp_map_init_fixed_table(kw_args, n_kw, args + n_args); + return ndarray_make_new_core(type, n_args, n_kw, args, kw_args); +} +#else +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void) type; + mp_arg_check_num(n_args, n_kw, 1, 2, true); + mp_map_t kw_args; + mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); + return ndarray_make_new_core(type, n_args, n_kw, args, &kw_args); +} +#endif + +// broadcasting is used at a number of places, always include +bool ndarray_can_broadcast(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t *ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + // Returns true or false, depending on, whether the two arrays can be broadcast together + // with numpy's broadcasting rules. These are as follows: + // + // 1. the two shapes are either equal + // 2. one of the shapes is 1 + memset(lstrides, 0, sizeof(size_t)*ULAB_MAX_DIMS); + memset(rstrides, 0, sizeof(size_t)*ULAB_MAX_DIMS); + lstrides[ULAB_MAX_DIMS - 1] = lhs->strides[ULAB_MAX_DIMS - 1]; + rstrides[ULAB_MAX_DIMS - 1] = rhs->strides[ULAB_MAX_DIMS - 1]; + for(uint8_t i=ULAB_MAX_DIMS; i > 0; i--) { + if((lhs->shape[i-1] == rhs->shape[i-1]) || (lhs->shape[i-1] == 0) || (lhs->shape[i-1] == 1) || + (rhs->shape[i-1] == 0) || (rhs->shape[i-1] == 1)) { + shape[i-1] = MAX(lhs->shape[i-1], rhs->shape[i-1]); + if(shape[i-1] > 0) (*ndim)++; + if(lhs->shape[i-1] < 2) { + lstrides[i-1] = 0; + } else { + lstrides[i-1] = lhs->strides[i-1]; + } + if(rhs->shape[i-1] < 2) { + rstrides[i-1] = 0; + } else { + rstrides[i-1] = rhs->strides[i-1]; + } + } else { + return false; + } + } + return true; +} + +#if NDARRAY_HAS_INPLACE_OPS +bool ndarray_can_broadcast_inplace(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) { + // returns true or false, depending on, whether the two arrays can be broadcast together inplace + // this means that the right hand side always must be "smaller" than the left hand side, i.e. + // the broadcasting rules are as follows: + // + // 1. the two shapes are either equal + // 2. the shapes on the right hand side is 1 + memset(rstrides, 0, sizeof(size_t)*ULAB_MAX_DIMS); + rstrides[ULAB_MAX_DIMS - 1] = rhs->strides[ULAB_MAX_DIMS - 1]; + for(uint8_t i=ULAB_MAX_DIMS; i > 0; i--) { + if((lhs->shape[i-1] == rhs->shape[i-1]) || (rhs->shape[i-1] == 0) || (rhs->shape[i-1] == 1)) { + if(rhs->shape[i-1] < 2) { + rstrides[i-1] = 0; + } else { + rstrides[i-1] = rhs->strides[i-1]; + } + } else { + return false; + } + } + return true; +} +#endif + +#if NDARRAY_IS_SLICEABLE +static size_t slice_length(mp_bound_slice_t slice) { + ssize_t len, correction = 1; + if(slice.step > 0) correction = -1; + len = (ssize_t)(slice.stop - slice.start + (slice.step + correction)) / slice.step; + if(len < 0) return 0; + return (size_t)len; +} + +static mp_bound_slice_t generate_slice(mp_int_t n, mp_obj_t index) { + mp_bound_slice_t slice; + if(mp_obj_is_type(index, &mp_type_slice)) { + mp_obj_slice_indices(index, n, &slice); + } else if(mp_obj_is_int(index)) { + mp_int_t _index = mp_obj_get_int(index); + if(_index < 0) { + _index += n; + } + if((_index >= n) || (_index < 0)) { + mp_raise_msg(&mp_type_IndexError, translate("index is out of bounds")); + } + slice.start = _index; + slice.stop = _index + 1; + slice.step = 1; + } else { + mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists")); + } + return slice; +} + +static ndarray_obj_t *ndarray_view_from_slices(ndarray_obj_t *ndarray, mp_obj_tuple_t *tuple) { + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(size_t)*ULAB_MAX_DIMS); + + uint8_t ndim = ndarray->ndim; + + for(uint8_t i=0; i < ndim; i++) { + // copy from the end + shape[ULAB_MAX_DIMS - 1 - i] = ndarray->shape[ULAB_MAX_DIMS - 1 - i]; + strides[ULAB_MAX_DIMS - 1 - i] = ndarray->strides[ULAB_MAX_DIMS - 1 - i]; + } + int32_t offset = 0; + for(uint8_t i=0; i < tuple->len; i++) { + if(mp_obj_is_int(tuple->items[i])) { + // if item is an int, the dimension will first be reduced ... + ndim--; + int32_t k = mp_obj_get_int(tuple->items[i]); + if(k < 0) { + k += ndarray->shape[ULAB_MAX_DIMS - ndarray->ndim + i]; + } + if((k >= (int32_t)ndarray->shape[ULAB_MAX_DIMS - ndarray->ndim + i]) || (k < 0)) { + mp_raise_msg(&mp_type_IndexError, translate("index is out of bounds")); + } + offset += ndarray->strides[ULAB_MAX_DIMS - ndarray->ndim + i] * k; + // ... and then we have to shift the shapes to the right + for(uint8_t j=0; j < i; j++) { + shape[ULAB_MAX_DIMS - ndarray->ndim + i - j] = shape[ULAB_MAX_DIMS - ndarray->ndim + i - j - 1]; + strides[ULAB_MAX_DIMS - ndarray->ndim + i - j] = strides[ULAB_MAX_DIMS - ndarray->ndim + i - j - 1]; + } + } else { + mp_bound_slice_t slice = generate_slice(shape[ULAB_MAX_DIMS - ndarray->ndim + i], tuple->items[i]); + shape[ULAB_MAX_DIMS - ndarray->ndim + i] = slice_length(slice); + offset += ndarray->strides[ULAB_MAX_DIMS - ndarray->ndim + i] * (int32_t)slice.start; + strides[ULAB_MAX_DIMS - ndarray->ndim + i] = (int32_t)slice.step * ndarray->strides[ULAB_MAX_DIMS - ndarray->ndim + i]; + } + } + return ndarray_new_view(ndarray, ndim, shape, strides, offset); +} + +void ndarray_assign_view(ndarray_obj_t *view, ndarray_obj_t *values) { + if(values->len == 0) { + return; + } + uint8_t ndim = 0; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + int32_t *lstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS); + if(!ndarray_can_broadcast(view, values, &ndim, shape, lstrides, rstrides)) { + mp_raise_ValueError(translate("operands could not be broadcast together")); + m_del(size_t, shape, ULAB_MAX_DIMS); + m_del(int32_t, lstrides, ULAB_MAX_DIMS); + m_del(int32_t, rstrides, ULAB_MAX_DIMS); + } + + uint8_t *rarray = (uint8_t *)values->array; + // since in ASSIGNMENT_LOOP the array has a type, we have to divide the strides by the itemsize + for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) { + lstrides[i] /= view->itemsize; + } + + if(view->dtype == NDARRAY_UINT8) { + if(values->dtype == NDARRAY_UINT8) { + ASSIGNMENT_LOOP(view, uint8_t, uint8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT8) { + ASSIGNMENT_LOOP(view, uint8_t, int8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_UINT16) { + ASSIGNMENT_LOOP(view, uint8_t, uint16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT16) { + ASSIGNMENT_LOOP(view, uint8_t, int16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_FLOAT) { + ASSIGNMENT_LOOP(view, uint8_t, mp_float_t, lstrides, rarray, rstrides); + } + } else if(view->dtype == NDARRAY_INT8) { + if(values->dtype == NDARRAY_UINT8) { + ASSIGNMENT_LOOP(view, int8_t, uint8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT8) { + ASSIGNMENT_LOOP(view, int8_t, int8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_UINT16) { + ASSIGNMENT_LOOP(view, int8_t, uint16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT16) { + ASSIGNMENT_LOOP(view, int8_t, int16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_FLOAT) { + ASSIGNMENT_LOOP(view, int8_t, mp_float_t, lstrides, rarray, rstrides); + } + } else if(view->dtype == NDARRAY_UINT16) { + if(values->dtype == NDARRAY_UINT8) { + ASSIGNMENT_LOOP(view, uint16_t, uint8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT8) { + ASSIGNMENT_LOOP(view, uint16_t, int8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_UINT16) { + ASSIGNMENT_LOOP(view, uint16_t, uint16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT16) { + ASSIGNMENT_LOOP(view, uint16_t, int16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_FLOAT) { + ASSIGNMENT_LOOP(view, uint16_t, mp_float_t, lstrides, rarray, rstrides); + } + } else if(view->dtype == NDARRAY_INT16) { + if(values->dtype == NDARRAY_UINT8) { + ASSIGNMENT_LOOP(view, int16_t, uint8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT8) { + ASSIGNMENT_LOOP(view, int16_t, int8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_UINT16) { + ASSIGNMENT_LOOP(view, int16_t, uint16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT16) { + ASSIGNMENT_LOOP(view, int16_t, int16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_FLOAT) { + ASSIGNMENT_LOOP(view, int16_t, mp_float_t, lstrides, rarray, rstrides); + } + } else { // the dtype must be an mp_float_t now + if(values->dtype == NDARRAY_UINT8) { + ASSIGNMENT_LOOP(view, mp_float_t, uint8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT8) { + ASSIGNMENT_LOOP(view, mp_float_t, int8_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_UINT16) { + ASSIGNMENT_LOOP(view, mp_float_t, uint16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_INT16) { + ASSIGNMENT_LOOP(view, mp_float_t, int16_t, lstrides, rarray, rstrides); + } else if(values->dtype == NDARRAY_FLOAT) { + ASSIGNMENT_LOOP(view, mp_float_t, mp_float_t, lstrides, rarray, rstrides); + } + } +} + +static mp_obj_t ndarray_from_boolean_index(ndarray_obj_t *ndarray, ndarray_obj_t *index) { + // returns a 1D array, indexed by a Boolean array + if(ndarray->len != index->len) { + mp_raise_ValueError(translate("array and index length must be equal")); + } + uint8_t *iarray = (uint8_t *)index->array; + // first we have to find out how many trues there are + size_t count = 0; + for(size_t i=0; i < index->len; i++) { + count += *iarray; + iarray += index->strides[ULAB_MAX_DIMS - 1]; + } + ndarray_obj_t *results = ndarray_new_linear_array(count, ndarray->dtype); + uint8_t *rarray = (uint8_t *)results->array; + uint8_t *array = (uint8_t *)ndarray->array; + // re-wind the index array + iarray = index->array; + for(size_t i=0; i < index->len; i++) { + if(*iarray) { + memcpy(rarray, array, results->itemsize); + rarray += results->itemsize; + count++; + } + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + iarray += index->strides[ULAB_MAX_DIMS - 1]; + } + return MP_OBJ_FROM_PTR(results); +} + +static mp_obj_t ndarray_assign_from_boolean_index(ndarray_obj_t *ndarray, ndarray_obj_t *index, ndarray_obj_t *values) { + // assigns values to a Boolean-indexed array + // first we have to find out how many trues there are + uint8_t *iarray = (uint8_t *)index->array; + size_t count = 0; + for(size_t i=0; i < index->len; i++) { + count += *iarray; + iarray += index->strides[ULAB_MAX_DIMS - 1]; + } + // re-wind the index array + iarray = index->array; + uint8_t *varray = (uint8_t *)values->array; + size_t vstride; + size_t istride = index->strides[ULAB_MAX_DIMS - 1]; + + if(count == values->len) { + // there are as many values as true indices + vstride = values->strides[ULAB_MAX_DIMS - 1]; + } else { + // there is a single value + vstride = 0; + } + if(ndarray->dtype == NDARRAY_UINT8) { + if(values->dtype == NDARRAY_UINT8) { + BOOLEAN_ASSIGNMENT_LOOP(uint8_t, uint8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT8) { + BOOLEAN_ASSIGNMENT_LOOP(uint8_t, int8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_UINT16) { + BOOLEAN_ASSIGNMENT_LOOP(uint8_t, uint16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT16) { + BOOLEAN_ASSIGNMENT_LOOP(uint8_t, int16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_FLOAT) { + BOOLEAN_ASSIGNMENT_LOOP(uint8_t, mp_float_t, ndarray, iarray, istride, varray, vstride); + } + } else if(ndarray->dtype == NDARRAY_INT8) { + if(values->dtype == NDARRAY_UINT8) { + BOOLEAN_ASSIGNMENT_LOOP(int8_t, uint8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT8) { + BOOLEAN_ASSIGNMENT_LOOP(int8_t, int8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_UINT16) { + BOOLEAN_ASSIGNMENT_LOOP(int8_t, uint16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT16) { + BOOLEAN_ASSIGNMENT_LOOP(int8_t, int16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_FLOAT) { + BOOLEAN_ASSIGNMENT_LOOP(int8_t, mp_float_t, ndarray, iarray, istride, varray, vstride); + } + } else if(ndarray->dtype == NDARRAY_UINT16) { + if(values->dtype == NDARRAY_UINT8) { + BOOLEAN_ASSIGNMENT_LOOP(uint16_t, uint8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT8) { + BOOLEAN_ASSIGNMENT_LOOP(uint16_t, int8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_UINT16) { + BOOLEAN_ASSIGNMENT_LOOP(uint16_t, uint16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT16) { + BOOLEAN_ASSIGNMENT_LOOP(uint16_t, int16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_FLOAT) { + BOOLEAN_ASSIGNMENT_LOOP(uint16_t, mp_float_t, ndarray, iarray, istride, varray, vstride); + } + } else if(ndarray->dtype == NDARRAY_INT16) { + if(values->dtype == NDARRAY_UINT8) { + BOOLEAN_ASSIGNMENT_LOOP(int16_t, uint8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT8) { + BOOLEAN_ASSIGNMENT_LOOP(int16_t, int8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_UINT16) { + BOOLEAN_ASSIGNMENT_LOOP(int16_t, uint16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT16) { + BOOLEAN_ASSIGNMENT_LOOP(int16_t, int16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_FLOAT) { + BOOLEAN_ASSIGNMENT_LOOP(int16_t, mp_float_t, ndarray, iarray, istride, varray, vstride); + } + } else { + if(values->dtype == NDARRAY_UINT8) { + BOOLEAN_ASSIGNMENT_LOOP(mp_float_t, uint8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT8) { + BOOLEAN_ASSIGNMENT_LOOP(mp_float_t, int8_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_UINT16) { + BOOLEAN_ASSIGNMENT_LOOP(mp_float_t, uint16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_INT16) { + BOOLEAN_ASSIGNMENT_LOOP(mp_float_t, int16_t, ndarray, iarray, istride, varray, vstride); + } else if(values->dtype == NDARRAY_FLOAT) { + BOOLEAN_ASSIGNMENT_LOOP(mp_float_t, mp_float_t, ndarray, iarray, istride, varray, vstride); + } + } + return MP_OBJ_FROM_PTR(ndarray); +} + +static mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t *values) { + if(mp_obj_is_type(index, &ulab_ndarray_type)) { + ndarray_obj_t *nindex = MP_OBJ_TO_PTR(index); + if((nindex->ndim > 1) || (nindex->boolean == false)) { + mp_raise_NotImplementedError(translate("operation is implemented for 1D Boolean arrays only")); + } + if(values == NULL) { // return value(s) + return ndarray_from_boolean_index(ndarray, nindex); + } else { // assign value(s) + ndarray_assign_from_boolean_index(ndarray, index, values); + } + } + if(mp_obj_is_type(index, &mp_type_tuple) || mp_obj_is_int(index) || mp_obj_is_type(index, &mp_type_slice)) { + mp_obj_tuple_t *tuple; + if(mp_obj_is_type(index, &mp_type_tuple)) { + tuple = MP_OBJ_TO_PTR(index); + if(tuple->len > ndarray->ndim) { + mp_raise_msg(&mp_type_IndexError, translate("too many indices")); + } + } else { + mp_obj_t *items = m_new(mp_obj_t, 1); + items[0] = index; + tuple = mp_obj_new_tuple(1, items); + } + ndarray_obj_t *view = ndarray_view_from_slices(ndarray, tuple); + if(values == NULL) { // return value(s) + // if the view has been reduced to nothing, return a single value + if(view->ndim == 0) { + return mp_binary_get_val_array(view->dtype, view->array, 0); + } else { + return MP_OBJ_FROM_PTR(view); + } + } else { // assign value(s) + ndarray_assign_view(view, values); + } + } + return mp_const_none; +} + +mp_obj_t ndarray_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + + if (value == MP_OBJ_SENTINEL) { // return value(s) + return ndarray_get_slice(self, index, NULL); + } else { // assignment to slices; the value must be an ndarray, or a scalar + ndarray_obj_t *values = ndarray_from_mp_obj(value, 0); + return ndarray_get_slice(self, index, values); + } + return mp_const_none; +} +#endif /* NDARRAY_IS_SLICEABLE */ + +#if NDARRAY_IS_ITERABLE + +// itarray iterator +mp_obj_t ndarray_getiter(mp_obj_t o_in, mp_obj_iter_buf_t *iter_buf) { + return ndarray_new_ndarray_iterator(o_in, iter_buf); +} + +typedef struct _mp_obj_ndarray_it_t { + mp_obj_base_t base; + mp_fun_1_t iternext; + mp_obj_t ndarray; + size_t cur; +} mp_obj_ndarray_it_t; + +mp_obj_t ndarray_iternext(mp_obj_t self_in) { + mp_obj_ndarray_it_t *self = MP_OBJ_TO_PTR(self_in); + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(self->ndarray); + uint8_t *array = (uint8_t *)ndarray->array; + + size_t iter_end = ndarray->shape[ULAB_MAX_DIMS-ndarray->ndim]; + if(self->cur < iter_end) { + // separating this case out saves 50 bytes for 1D arrays + #if ULAB_MAX_DIMS == 1 + array += self->cur * ndarray->strides[0]; + self->cur++; + return ndarray_get_item(ndarray, array); + #else + if(ndarray->ndim == 1) { // we have a linear array + array += self->cur * ndarray->strides[ULAB_MAX_DIMS - 1]; + self->cur++; + return ndarray_get_item(ndarray, array); + } else { // we have a tensor, return the reduced view + size_t offset = self->cur * ndarray->strides[ULAB_MAX_DIMS - ndarray->ndim]; + self->cur++; + return MP_OBJ_FROM_PTR(ndarray_new_view(ndarray, ndarray->ndim-1, ndarray->shape, ndarray->strides, offset)); + } + #endif + } else { + return MP_OBJ_STOP_ITERATION; + } +} + +mp_obj_t ndarray_new_ndarray_iterator(mp_obj_t ndarray, mp_obj_iter_buf_t *iter_buf) { + assert(sizeof(mp_obj_ndarray_it_t) <= sizeof(mp_obj_iter_buf_t)); + mp_obj_ndarray_it_t *o = (mp_obj_ndarray_it_t*)iter_buf; + o->base.type = &mp_type_polymorph_iter; + o->iternext = ndarray_iternext; + o->ndarray = ndarray; + o->cur = 0; + return MP_OBJ_FROM_PTR(o); +} +#endif /* NDARRAY_IS_ITERABLE */ + +#if NDARRAY_HAS_FLATTEN +mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_order, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_QSTR(MP_QSTR_C)} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + ndarray_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]); + GET_STR_DATA_LEN(args[0].u_obj, order, len); + if((len != 1) || ((memcmp(order, "C", 1) != 0) && (memcmp(order, "F", 1) != 0))) { + mp_raise_ValueError(translate("flattening order must be either 'C', or 'F'")); + } + + uint8_t *sarray = (uint8_t *)self->array; + ndarray_obj_t *ndarray = ndarray_new_linear_array(self->len, self->dtype); + uint8_t *array = (uint8_t *)ndarray->array; + + if(memcmp(order, "C", 1) == 0) { // C-type ordering + #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 { + memcpy(array, sarray, self->itemsize); + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + sarray += self->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < self->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= self->strides[ULAB_MAX_DIMS - 1] * self->shape[ULAB_MAX_DIMS-1]; + sarray += self->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < self->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= self->strides[ULAB_MAX_DIMS - 2] * self->shape[ULAB_MAX_DIMS-2]; + sarray += self->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < self->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= self->strides[ULAB_MAX_DIMS - 3] * self->shape[ULAB_MAX_DIMS-3]; + sarray += self->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < self->shape[ULAB_MAX_DIMS - 4]); + #endif + } else { // 'F', Fortran-type ordering + #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 { + memcpy(array, sarray, self->itemsize); + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + sarray += self->strides[0]; + l++; + } while(l < self->shape[0]); + #if ULAB_MAX_DIMS > 1 + sarray -= self->strides[0] * self->shape[0]; + sarray += self->strides[1]; + k++; + } while(k < self->shape[1]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= self->strides[1] * self->shape[1]; + sarray += self->strides[2]; + j++; + } while(j < self->shape[2]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= self->strides[2] * self->shape[2]; + sarray += self->strides[3]; + i++; + } while(i < self->shape[3]); + #endif + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten); +#endif + +#if NDARRAY_HAS_ITEMSIZE +mp_obj_t ndarray_itemsize(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + return MP_OBJ_NEW_SMALL_INT(self->itemsize); +} +#endif + +#if NDARRAY_HAS_SHAPE +mp_obj_t ndarray_shape(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t *items = m_new(mp_obj_t, self->ndim); + for(uint8_t i=0; i < self->ndim; i++) { + items[self->ndim - i - 1] = mp_obj_new_int(self->shape[ULAB_MAX_DIMS - i - 1]); + } + mp_obj_t tuple = mp_obj_new_tuple(self->ndim, items); + m_del(mp_obj_t, items, self->ndim); + return tuple; +} +#endif + +#if NDARRAY_HAS_SIZE +mp_obj_t ndarray_size(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + return mp_obj_new_int(self->len); +} +#endif + +#if NDARRAY_HAS_STRIDES +mp_obj_t ndarray_strides(mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t *items = m_new(mp_obj_t, self->ndim); + for(int8_t i=0; i < self->ndim; i++) { + items[i] = mp_obj_new_int(self->strides[ULAB_MAX_DIMS - self->ndim + i]); + } + mp_obj_t tuple = mp_obj_new_tuple(self->ndim, items); + m_del(mp_obj_t, items, self->ndim); + return tuple; +} +#endif + +#if NDARRAY_HAS_TOBYTES +mp_obj_t ndarray_tobytes(mp_obj_t self_in) { + // As opposed to numpy, this function returns a bytearray object with the data pointer (i.e., not a copy) + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + // Piping into a bytearray makes sense for dense arrays only, + // so bail out, if that is not the case + if(!ndarray_is_dense(self)) { + mp_raise_ValueError(translate("tobytes can be invoked for dense arrays only")); + } + return mp_obj_new_bytearray_by_ref(self->itemsize * self->len, self->array); +} + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_tobytes_obj, ndarray_tobytes); +#endif + +// Binary operations +ndarray_obj_t *ndarray_from_mp_obj(mp_obj_t obj, uint8_t other_type) { + // creates an ndarray from a micropython int or float + // if the input is an ndarray, it is returned + // if other_type is 0, return the smallest type that can accommodate the object + ndarray_obj_t *ndarray; + + if(mp_obj_is_int(obj)) { + int32_t ivalue = mp_obj_get_int(obj); + if((ivalue < -32767) || (ivalue > 32767)) { + // the integer value clearly does not fit the ulab integer types, so move on to float + ndarray = ndarray_new_linear_array(1, NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)ndarray->array; + array[0] = (mp_float_t)ivalue; + } else { + uint8_t dtype; + if(ivalue < 0) { + if(ivalue > -128) { + dtype = NDARRAY_INT8; + } else { + dtype = NDARRAY_INT16; + } + } else { // ivalue >= 0 + if((other_type == NDARRAY_INT8) || (other_type == NDARRAY_INT16)) { + if(ivalue < 128) { + dtype = NDARRAY_INT8; + } else { + dtype = NDARRAY_INT16; + } + } else { // other_type = 0 is also included here + if(ivalue < 256) { + dtype = NDARRAY_UINT8; + } else { + dtype = NDARRAY_UINT16; + } + } + } + ndarray = ndarray_new_linear_array(1, dtype); + ndarray_set_value(dtype, ndarray->array, 0, obj); + } + } else if(mp_obj_is_float(obj)) { + ndarray = ndarray_new_linear_array(1, NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)ndarray->array; + array[0] = mp_obj_get_float(obj); + } else if(mp_obj_is_type(obj, &ulab_ndarray_type)){ + return obj; + } else { + // assume that the input is an iterable (raises an exception, if it is not the case) + ndarray = ndarray_from_iterable(obj, NDARRAY_FLOAT); + } + return ndarray; +} + +#if NDARRAY_HAS_BINARY_OPS || NDARRAY_HAS_INPLACE_OPS +mp_obj_t ndarray_binary_op(mp_binary_op_t _op, mp_obj_t lobj, mp_obj_t robj) { + // TODO: implement in-place operators + // if the ndarray stands on the right hand side of the expression, simply swap the operands + ndarray_obj_t *lhs, *rhs; + mp_binary_op_t op = _op; + if((op == MP_BINARY_OP_REVERSE_ADD) || (op == MP_BINARY_OP_REVERSE_MULTIPLY) || + (op == MP_BINARY_OP_REVERSE_POWER) || (op == MP_BINARY_OP_REVERSE_SUBTRACT) || + (op == MP_BINARY_OP_REVERSE_TRUE_DIVIDE)) { + lhs = ndarray_from_mp_obj(robj, 0); + rhs = ndarray_from_mp_obj(lobj, lhs->dtype); + } else { + lhs = ndarray_from_mp_obj(lobj, 0); + rhs = ndarray_from_mp_obj(robj, lhs->dtype); + } + if(op == MP_BINARY_OP_REVERSE_ADD) { + op = MP_BINARY_OP_ADD; + } else if(op == MP_BINARY_OP_REVERSE_MULTIPLY) { + op = MP_BINARY_OP_MULTIPLY; + } else if(op == MP_BINARY_OP_REVERSE_POWER) { + op = MP_BINARY_OP_POWER; + } else if(op == MP_BINARY_OP_REVERSE_SUBTRACT) { + op = MP_BINARY_OP_SUBTRACT; + } else if(op == MP_BINARY_OP_REVERSE_TRUE_DIVIDE) { + op = MP_BINARY_OP_TRUE_DIVIDE; + } + + uint8_t ndim = 0; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + int32_t *lstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS); + uint8_t broadcastable; + if((op == MP_BINARY_OP_INPLACE_ADD) || (op == MP_BINARY_OP_INPLACE_MULTIPLY) || (op == MP_BINARY_OP_INPLACE_POWER) || + (op == MP_BINARY_OP_INPLACE_SUBTRACT) || (op == MP_BINARY_OP_INPLACE_TRUE_DIVIDE)) { + broadcastable = ndarray_can_broadcast_inplace(lhs, rhs, rstrides); + } else { + broadcastable = ndarray_can_broadcast(lhs, rhs, &ndim, shape, lstrides, rstrides); + } + if(!broadcastable) { + mp_raise_ValueError(translate("operands could not be broadcast together")); + m_del(size_t, shape, ULAB_MAX_DIMS); + m_del(int32_t, lstrides, ULAB_MAX_DIMS); + m_del(int32_t, rstrides, ULAB_MAX_DIMS); + } + // the empty arrays have to be treated separately + uint8_t dtype = NDARRAY_INT16; + ndarray_obj_t *nd; + if((lhs->ndim == 0) || (rhs->ndim == 0)) { + switch(op) { + case MP_BINARY_OP_INPLACE_ADD: + case MP_BINARY_OP_INPLACE_MULTIPLY: + case MP_BINARY_OP_INPLACE_SUBTRACT: + case MP_BINARY_OP_ADD: + case MP_BINARY_OP_MULTIPLY: + case MP_BINARY_OP_SUBTRACT: + // here we don't have to list those cases that result in an int16, + // because dtype is initialised with that NDARRAY_INT16 + if(lhs->dtype == rhs->dtype) { + dtype = rhs->dtype; + } else if((lhs->dtype == NDARRAY_FLOAT) || (rhs->dtype == NDARRAY_FLOAT)) { + dtype = NDARRAY_FLOAT; + } else if(((lhs->dtype == NDARRAY_UINT8) && (rhs->dtype == NDARRAY_UINT16)) || + ((lhs->dtype == NDARRAY_INT8) && (rhs->dtype == NDARRAY_UINT16)) || + ((rhs->dtype == NDARRAY_UINT8) && (lhs->dtype == NDARRAY_UINT16)) || + ((rhs->dtype == NDARRAY_INT8) && (lhs->dtype == NDARRAY_UINT16))) { + dtype = NDARRAY_UINT16; + } + return MP_OBJ_FROM_PTR(ndarray_new_linear_array(0, dtype)); + break; + + case MP_BINARY_OP_INPLACE_POWER: + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + case MP_BINARY_OP_POWER: + case MP_BINARY_OP_TRUE_DIVIDE: + return MP_OBJ_FROM_PTR(ndarray_new_linear_array(0, NDARRAY_FLOAT)); + break; + + case MP_BINARY_OP_LESS: + case MP_BINARY_OP_LESS_EQUAL: + case MP_BINARY_OP_MORE: + case MP_BINARY_OP_MORE_EQUAL: + case MP_BINARY_OP_EQUAL: + case MP_BINARY_OP_NOT_EQUAL: + nd = ndarray_new_linear_array(0, NDARRAY_UINT8); + nd->boolean = true; + return MP_OBJ_FROM_PTR(nd); + + default: + return mp_const_none; + break; + } + } + + switch(op) { + // first the in-place operators + #if NDARRAY_HAS_INPLACE_ADD + case MP_BINARY_OP_INPLACE_ADD: + return ndarray_inplace_ams(lhs, rhs, rstrides, op); + break; + #endif + #if NDARRAY_HAS_INPLACE_MULTIPLY + case MP_BINARY_OP_INPLACE_MULTIPLY: + return ndarray_inplace_ams(lhs, rhs, rstrides, op); + break; + #endif + #if NDARRAY_HAS_INPLACE_POWER + case MP_BINARY_OP_INPLACE_POWER: + return ndarray_inplace_power(lhs, rhs, rstrides); + break; + #endif + #if NDARRAY_HAS_INPLACE_SUBTRACT + case MP_BINARY_OP_INPLACE_SUBTRACT: + return ndarray_inplace_ams(lhs, rhs, rstrides, op); + break; + #endif + #if NDARRAY_HAS_INPLACE_TRUE_DIVIDE + case MP_BINARY_OP_INPLACE_TRUE_DIVIDE: + return ndarray_inplace_divide(lhs, rhs, rstrides); + break; + #endif + // end if in-place operators + + #if NDARRAY_HAS_BINARY_OP_LESS + case MP_BINARY_OP_LESS: + // here we simply swap the operands + return ndarray_binary_more(rhs, lhs, ndim, shape, rstrides, lstrides, MP_BINARY_OP_MORE); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_LESS_EQUAL + case MP_BINARY_OP_LESS_EQUAL: + // here we simply swap the operands + return ndarray_binary_more(rhs, lhs, ndim, shape, rstrides, lstrides, MP_BINARY_OP_MORE_EQUAL); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_EQUAL + case MP_BINARY_OP_EQUAL: + return ndarray_binary_equality(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_EQUAL); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_NOT_EQUAL + case MP_BINARY_OP_NOT_EQUAL: + return ndarray_binary_equality(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_NOT_EQUAL); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_ADD + case MP_BINARY_OP_ADD: + return ndarray_binary_add(lhs, rhs, ndim, shape, lstrides, rstrides); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_MULTIPLY + case MP_BINARY_OP_MULTIPLY: + return ndarray_binary_multiply(lhs, rhs, ndim, shape, lstrides, rstrides); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_MORE + case MP_BINARY_OP_MORE: + return ndarray_binary_more(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_MORE); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_MORE_EQUAL + case MP_BINARY_OP_MORE_EQUAL: + return ndarray_binary_more(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_MORE_EQUAL); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_SUBTRACT + case MP_BINARY_OP_SUBTRACT: + return ndarray_binary_subtract(lhs, rhs, ndim, shape, lstrides, rstrides); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE + case MP_BINARY_OP_TRUE_DIVIDE: + return ndarray_binary_true_divide(lhs, rhs, ndim, shape, lstrides, rstrides); + break; + #endif + #if NDARRAY_HAS_BINARY_OP_POWER + case MP_BINARY_OP_POWER: + return ndarray_binary_power(lhs, rhs, ndim, shape, lstrides, rstrides); + break; + #endif + default: + return MP_OBJ_NULL; // op not supported + break; + } + return MP_OBJ_NULL; +} +#endif /* NDARRAY_HAS_BINARY_OPS || NDARRAY_HAS_INPLACE_OPS */ + +#if NDARRAY_HAS_UNARY_OPS +mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + ndarray_obj_t *ndarray = NULL; + + switch (op) { + #if NDARRAY_HAS_UNARY_OP_ABS + case MP_UNARY_OP_ABS: + ndarray = ndarray_copy_view(self); + // if Boolean, NDARRAY_UINT8, or NDARRAY_UINT16, there is nothing to do + if(self->dtype == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) { + if(*array < 0) *array = -(*array); + } + } else if(self->dtype == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) { + if(*array < 0) *array = -(*array); + } + } else { + mp_float_t *array = (mp_float_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) { + if(*array < 0) *array = -(*array); + } + } + return MP_OBJ_FROM_PTR(ndarray); + break; + #endif + #if NDARRAY_HAS_UNARY_OP_INVERT + case MP_UNARY_OP_INVERT: + if(self->dtype == NDARRAY_FLOAT) { + mp_raise_ValueError(translate("operation is not supported for given type")); + } + // we can invert the content byte by byte, no need to distinguish between different dtypes + ndarray = ndarray_copy_view(self); // from this point, this is a dense copy + uint8_t *array = (uint8_t *)ndarray->array; + if(ndarray->boolean) { + for(size_t i=0; i < ndarray->len; i++, array++) *array = *array ^ 0x01; + } else { + uint8_t itemsize = mp_binary_get_size('@', self->dtype, NULL); + for(size_t i=0; i < ndarray->len*itemsize; i++, array++) *array ^= 0xFF; + } + return MP_OBJ_FROM_PTR(ndarray); + break; + #endif + #if NDARRAY_HAS_UNARY_OP_LEN + case MP_UNARY_OP_LEN: + return mp_obj_new_int(self->shape[ULAB_MAX_DIMS - self->ndim]); + break; + #endif + #if NDARRAY_HAS_UNARY_OP_NEGATIVE + case MP_UNARY_OP_NEGATIVE: + ndarray = ndarray_copy_view(self); // from this point, this is a dense copy + if(self->dtype == NDARRAY_UINT8) { + uint8_t *array = (uint8_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) *array = -(*array); + } else if(self->dtype == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) *array = -(*array); + } else if(self->dtype == NDARRAY_UINT16) { + uint16_t *array = (uint16_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) *array = -(*array); + } else if(self->dtype == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) *array = -(*array); + } else { + mp_float_t *array = (mp_float_t *)ndarray->array; + for(size_t i=0; i < self->len; i++, array++) *array = -(*array); + } + return MP_OBJ_FROM_PTR(ndarray); + break; + #endif + #if NDARRAY_HAS_UNARY_OP_POSITIVE + case MP_UNARY_OP_POSITIVE: + return MP_OBJ_FROM_PTR(ndarray_copy_view(self)); + #endif + + default: + return MP_OBJ_NULL; // operator not supported + break; + } +} +#endif /* NDARRAY_HAS_UNARY_OPS */ + +#if NDARRAY_HAS_TRANSPOSE +mp_obj_t ndarray_transpose(mp_obj_t self_in) { + #if ULAB_MAX_DIMS == 1 + return self_in; + #endif + // TODO: check, what happens to the offset here, if we have a view + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + if(self->ndim == 1) { + return self_in; + } + size_t *shape = m_new(size_t, self->ndim); + int32_t *strides = m_new(int32_t, self->ndim); + for(uint8_t i=0; i < self->ndim; i++) { + shape[ULAB_MAX_DIMS - 1 - i] = self->shape[ULAB_MAX_DIMS - self->ndim + i]; + strides[ULAB_MAX_DIMS - 1 - i] = self->strides[ULAB_MAX_DIMS - self->ndim + i]; + } + // TODO: I am not sure ndarray_new_view is OK here... + // should be deep copy... + ndarray_obj_t *ndarray = ndarray_new_view(self, self->ndim, shape, strides, 0); + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_transpose_obj, ndarray_transpose); +#endif /* NDARRAY_HAS_TRANSPOSE */ + +#if ULAB_MAX_DIMS > 1 +#if NDARRAY_HAS_RESHAPE +mp_obj_t ndarray_reshape_core(mp_obj_t oin, mp_obj_t _shape, bool inplace) { + ndarray_obj_t *source = MP_OBJ_TO_PTR(oin); + if(!mp_obj_is_type(_shape, &mp_type_tuple)) { + mp_raise_TypeError(translate("shape must be a tuple")); + } + + mp_obj_tuple_t *shape = MP_OBJ_TO_PTR(_shape); + if(shape->len > ULAB_MAX_DIMS) { + mp_raise_ValueError(translate("maximum number of dimensions is 4")); + } + size_t *new_shape = m_new(size_t, ULAB_MAX_DIMS); + memset(new_shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + size_t new_length = 1; + for(uint8_t i=0; i < shape->len; i++) { + new_shape[ULAB_MAX_DIMS - i - 1] = mp_obj_get_int(shape->items[shape->len - i - 1]); + new_length *= new_shape[ULAB_MAX_DIMS - i - 1]; + } + if(source->len != new_length) { + mp_raise_ValueError(translate("input and output shapes are not compatible")); + } + ndarray_obj_t *ndarray; + if(ndarray_is_dense(source)) { + int32_t *new_strides = strides_from_shape(new_shape, source->dtype); + if(inplace) { + for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) { + source->shape[i] = new_shape[i]; + source->strides[i] = new_strides[i]; + } + return MP_OBJ_FROM_PTR(oin); + } else { + ndarray = ndarray_new_view(source, shape->len, new_shape, new_strides, 0); + } + } else { + if(inplace) { + mp_raise_ValueError(translate("cannot assign new shape")); + } + ndarray = ndarray_new_ndarray_from_tuple(shape, source->dtype); + ndarray_copy_array(source, ndarray); + } + return MP_OBJ_FROM_PTR(ndarray); +} + +mp_obj_t ndarray_reshape(mp_obj_t oin, mp_obj_t _shape) { + return ndarray_reshape_core(oin, _shape, 0); +} + +MP_DEFINE_CONST_FUN_OBJ_2(ndarray_reshape_obj, ndarray_reshape); +#endif /* NDARRAY_HAS_RESHAPE */ +#endif /* ULAB_MAX_DIMS > 1 */ + +#if ULAB_NUMPY_HAS_NDINFO +mp_obj_t ndarray_info(mp_obj_t obj_in) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(obj_in); + if(!mp_obj_is_type(ndarray, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("function is defined for ndarrays only")); + } + mp_printf(MP_PYTHON_PRINTER, "class: ndarray\n"); + mp_printf(MP_PYTHON_PRINTER, "shape: ("); + if(ndarray->ndim == 1) { + mp_printf(MP_PYTHON_PRINTER, "%d,", ndarray->shape[ULAB_MAX_DIMS-1]); + } else { + for(uint8_t i=0; i < ndarray->ndim-1; i++) mp_printf(MP_PYTHON_PRINTER, "%d, ", ndarray->shape[i]); + mp_printf(MP_PYTHON_PRINTER, "%d", ndarray->shape[ULAB_MAX_DIMS-1]); + } + mp_printf(MP_PYTHON_PRINTER, ")\n"); + mp_printf(MP_PYTHON_PRINTER, "strides: ("); + if(ndarray->ndim == 1) { + mp_printf(MP_PYTHON_PRINTER, "%d,", ndarray->strides[ULAB_MAX_DIMS-1]); + } else { + for(uint8_t i=0; i < ndarray->ndim-1; i++) mp_printf(MP_PYTHON_PRINTER, "%d, ", ndarray->strides[i]); + mp_printf(MP_PYTHON_PRINTER, "%d", ndarray->strides[ULAB_MAX_DIMS-1]); + } + mp_printf(MP_PYTHON_PRINTER, ")\n"); + mp_printf(MP_PYTHON_PRINTER, "itemsize: %d\n", ndarray->itemsize); + mp_printf(MP_PYTHON_PRINTER, "data pointer: 0x%p\n", ndarray->array); + mp_printf(MP_PYTHON_PRINTER, "type: "); + if(ndarray->boolean) { + mp_printf(MP_PYTHON_PRINTER, "bool\n"); + } else if(ndarray->dtype == NDARRAY_UINT8) { + mp_printf(MP_PYTHON_PRINTER, "uint8\n"); + } else if(ndarray->dtype == NDARRAY_INT8) { + mp_printf(MP_PYTHON_PRINTER, "int8\n"); + } else if(ndarray->dtype == NDARRAY_UINT16) { + mp_printf(MP_PYTHON_PRINTER, "uint16\n"); + } else if(ndarray->dtype == NDARRAY_INT16) { + mp_printf(MP_PYTHON_PRINTER, "int16\n"); + } else if(ndarray->dtype == NDARRAY_FLOAT) { + mp_printf(MP_PYTHON_PRINTER, "float\n"); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_info_obj, ndarray_info); +#endif + +// (the get_buffer protocol returns 0 for success, 1 for failure) +mp_int_t ndarray_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { + ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); + if(!ndarray_is_dense(self)) { + return 1; + } + bufinfo->len = self->itemsize * self->len; + bufinfo->buf = self->array; + bufinfo->typecode = self->dtype; + return 0; +} diff --git a/python/port/mod/ulab/ndarray.h b/python/port/mod/ulab/ndarray.h new file mode 100644 index 000000000..aa7f499af --- /dev/null +++ b/python/port/mod/ulab/ndarray.h @@ -0,0 +1,736 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries +*/ + +#ifndef _NDARRAY_ +#define _NDARRAY_ + +#include "py/objarray.h" +#include "py/binary.h" +#include "py/objstr.h" +#include "py/objlist.h" + +#include "ulab.h" + +#ifndef MP_PI +#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) +#endif +#ifndef MP_E +#define MP_E MICROPY_FLOAT_CONST(2.71828182845904523536) +#endif + +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define FLOAT_TYPECODE 'f' +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define FLOAT_TYPECODE 'd' +#endif + +// this typedef is lifted from objfloat.c, because mp_obj_float_t is not exposed +typedef struct _mp_obj_float_t { + mp_obj_base_t base; + mp_float_t value; +} mp_obj_float_t; + +#if defined(MICROPY_VERSION_MAJOR) && MICROPY_VERSION_MAJOR == 1 && MICROPY_VERSION_MINOR == 12 +typedef struct _mp_obj_slice_t { + mp_obj_base_t base; + mp_obj_t start; + mp_obj_t stop; + mp_obj_t step; +} mp_obj_slice_t; +#define MP_ERROR_TEXT(x) x +#endif + +#if !CIRCUITPY +#define translate(x) MP_ERROR_TEXT(x) +#define ndarray_set_value(a, b, c, d) mp_binary_set_val_array(a, b, c, d) +#else +void ndarray_set_value(char , void *, size_t , mp_obj_t ); +#endif + +#define NDARRAY_NUMERIC 0 +#define NDARRAY_BOOLEAN 1 + +#define NDARRAY_NDARRAY_TYPE 1 +#define NDARRAY_ITERABLE_TYPE 2 + +extern const mp_obj_type_t ulab_ndarray_type; + +enum NDARRAY_TYPE { + NDARRAY_BOOL = '?', // this must never be assigned to the dtype! + NDARRAY_UINT8 = 'B', + NDARRAY_INT8 = 'b', + NDARRAY_UINT16 = 'H', + NDARRAY_INT16 = 'h', + NDARRAY_FLOAT = FLOAT_TYPECODE, +}; + +typedef struct _ndarray_obj_t { + mp_obj_base_t base; + uint8_t dtype; + uint8_t itemsize; + uint8_t boolean; + uint8_t ndim; + size_t len; + size_t shape[ULAB_MAX_DIMS]; + int32_t strides[ULAB_MAX_DIMS]; + void *array; + void *origin; +} ndarray_obj_t; + +#if ULAB_HAS_DTYPE_OBJECT +extern const mp_obj_type_t ulab_dtype_type; + +typedef struct _dtype_obj_t { + mp_obj_base_t base; + uint8_t dtype; +} dtype_obj_t; + +void ndarray_dtype_print(const mp_print_t *, mp_obj_t , mp_print_kind_t ); + +#ifdef CIRCUITPY +mp_obj_t ndarray_dtype_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args); +#else +mp_obj_t ndarray_dtype_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *); +#endif /* CIRCUITPY */ +#endif /* ULAB_HAS_DTYPE_OBJECT */ + +mp_obj_t ndarray_new_ndarray_iterator(mp_obj_t , mp_obj_iter_buf_t *); + +mp_float_t ndarray_get_float_value(void *, uint8_t ); +mp_float_t ndarray_get_float_index(void *, uint8_t , size_t ); +bool ndarray_object_is_array_like(mp_obj_t ); +void fill_array_iterable(mp_float_t *, mp_obj_t ); +size_t *ndarray_shape_vector(size_t , size_t , size_t , size_t ); + +void ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t ); + +#if ULAB_HAS_PRINTOPTIONS +mp_obj_t ndarray_set_printoptions(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_set_printoptions_obj); + +mp_obj_t ndarray_get_printoptions(void); +MP_DECLARE_CONST_FUN_OBJ_0(ndarray_get_printoptions_obj); +#endif + +void ndarray_assign_elements(ndarray_obj_t *, mp_obj_t , uint8_t , size_t *); +size_t *ndarray_contract_shape(ndarray_obj_t *, uint8_t ); +int32_t *ndarray_contract_strides(ndarray_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_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 *); +ndarray_obj_t *ndarray_copy_view(ndarray_obj_t *); +void ndarray_copy_array(ndarray_obj_t *, ndarray_obj_t *); + +MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_array_constructor_obj); +#ifdef CIRCUITPY +mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args); +#else +mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *); +#endif +mp_obj_t ndarray_subscr(mp_obj_t , mp_obj_t , mp_obj_t ); +mp_obj_t ndarray_getiter(mp_obj_t , mp_obj_iter_buf_t *); +bool ndarray_can_broadcast(ndarray_obj_t *, ndarray_obj_t *, uint8_t *, size_t *, int32_t *, int32_t *); +bool ndarray_can_broadcast_inplace(ndarray_obj_t *, ndarray_obj_t *, int32_t *); +mp_obj_t ndarray_binary_op(mp_binary_op_t , mp_obj_t , mp_obj_t ); +mp_obj_t ndarray_unary_op(mp_unary_op_t , mp_obj_t ); + +size_t *ndarray_new_coords(uint8_t ); +void ndarray_rewind_array(uint8_t , uint8_t *, size_t *, int32_t *, size_t *); + +// various ndarray methods +#if NDARRAY_HAS_BYTESWAP +mp_obj_t ndarray_byteswap(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_byteswap_obj); +#endif + +#if NDARRAY_HAS_COPY +mp_obj_t ndarray_copy(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_copy_obj); +#endif + +#if NDARRAY_HAS_FLATTEN +mp_obj_t ndarray_flatten(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_flatten_obj); +#endif + +mp_obj_t ndarray_dtype(mp_obj_t ); +mp_obj_t ndarray_itemsize(mp_obj_t ); +mp_obj_t ndarray_size(mp_obj_t ); +mp_obj_t ndarray_shape(mp_obj_t ); +mp_obj_t ndarray_strides(mp_obj_t ); + +#if NDARRAY_HAS_RESHAPE +mp_obj_t ndarray_reshape_core(mp_obj_t , mp_obj_t , bool ); +mp_obj_t ndarray_reshape(mp_obj_t , mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_2(ndarray_reshape_obj); +#endif + +#if NDARRAY_HAS_TOBYTES +mp_obj_t ndarray_tobytes(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_tobytes_obj); +#endif + +#if NDARRAY_HAS_TRANSPOSE +mp_obj_t ndarray_transpose(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_transpose_obj); +#endif + +#if ULAB_NUMPY_HAS_NDINFO +mp_obj_t ndarray_info(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_info_obj); +#endif + +mp_int_t ndarray_get_buffer(mp_obj_t , mp_buffer_info_t *, mp_uint_t ); +//void ndarray_attributes(mp_obj_t , qstr , mp_obj_t *); + +ndarray_obj_t *ndarray_from_mp_obj(mp_obj_t , uint8_t ); + + +#define BOOLEAN_ASSIGNMENT_LOOP(type_left, type_right, ndarray, iarray, istride, varray, vstride)\ + type_left *array = (type_left *)(ndarray)->array;\ + for(size_t i=0; i < (ndarray)->len; i++) {\ + if(*(iarray)) {\ + *array = (type_left)(*((type_right *)(varray)));\ + }\ + array += (ndarray)->strides[ULAB_MAX_DIMS - 1] / (ndarray)->itemsize;\ + (iarray) += (istride);\ + (varray) += (vstride);\ + } while(0) + +#if ULAB_HAS_FUNCTION_ITERATOR +#define BINARY_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + type_out *array = (type_out *)(results)->array;\ + size_t *lcoords = ndarray_new_coords((results)->ndim);\ + size_t *rcoords = ndarray_new_coords((results)->ndim);\ + for(size_t i=0; i < (results)->len/(results)->shape[ULAB_MAX_DIMS -1]; i++) {\ + size_t l = 0;\ + do {\ + *array++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + ndarray_rewind_array((results)->ndim, (larray), (results)->shape, (lstrides), lcoords);\ + ndarray_rewind_array((results)->ndim, (rarray), (results)->shape, (rstrides), rcoords);\ + } while(0) + +#define INPLACE_LOOP(results, type_left, type_right, larray, rarray, rstrides, OPERATOR)\ + size_t *lcoords = ndarray_new_coords((results)->ndim);\ + size_t *rcoords = ndarray_new_coords((results)->ndim);\ + for(size_t i=0; i < (results)->len/(results)->shape[ULAB_MAX_DIMS -1]; i++) {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + ndarray_rewind_array((results)->ndim, (larray), (results)->shape, (results)->strides, lcoords);\ + ndarray_rewind_array((results)->ndim, (rarray), (results)->shape, (rstrides), rcoords);\ + } while(0) + +#define EQUALITY_LOOP(results, array, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t *lcoords = ndarray_new_coords((results)->ndim);\ + size_t *rcoords = ndarray_new_coords((results)->ndim);\ + for(size_t i=0; i < (results)->len/(results)->shape[ULAB_MAX_DIMS -1]; i++) {\ + size_t l = 0;\ + do {\ + *(array)++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? 1 : 0;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + ndarray_rewind_array((results)->ndim, (larray), (results)->shape, (lstrides), lcoords);\ + ndarray_rewind_array((results)->ndim, (rarray), (results)->shape, (rstrides), rcoords);\ + } while(0) + +#define POWER_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides)\ + type_out *array = (type_out *)(results)->array;\ + size_t *lcoords = ndarray_new_coords((results)->ndim);\ + size_t *rcoords = ndarray_new_coords((results)->ndim);\ + for(size_t i=0; i < (results)->len/(results)->shape[ULAB_MAX_DIMS -1]; i++) {\ + size_t l = 0;\ + do {\ + *array++ = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + ndarray_rewind_array((results)->ndim, (larray), (results)->shape, (lstrides), lcoords);\ + ndarray_rewind_array((results)->ndim, (rarray), (results)->shape, (rstrides), rcoords);\ + } while(0) + +#else + +#if ULAB_MAX_DIMS == 1 +#define BINARY_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + type_out *array = (type_out *)results->array;\ + size_t l = 0;\ + do {\ + *array++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + +#define INPLACE_LOOP(results, type_left, type_right, larray, rarray, rstrides, OPERATOR)\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + +#define EQUALITY_LOOP(results, array, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t l = 0;\ + do {\ + *(array)++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? 1 : 0;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + +#define POWER_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides)\ + type_out *array = (type_out *)results->array;\ + size_t l = 0;\ + do {\ + *array++ = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + +#endif /* ULAB_MAX_DIMS == 1 */ + +#if ULAB_MAX_DIMS == 2 +#define BINARY_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + type_out *array = (type_out *)(results)->array;\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + +#define INPLACE_LOOP(results, type_left, type_right, larray, rarray, rstrides, OPERATOR)\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + +#define EQUALITY_LOOP(results, array, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? 1 : 0;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + +#define POWER_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides)\ + type_out *array = (type_out *)(results)->array;\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + +#endif /* ULAB_MAX_DIMS == 2 */ + +#if ULAB_MAX_DIMS == 3 +#define BINARY_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + type_out *array = (type_out *)results->array;\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + +#define INPLACE_LOOP(results, type_left, type_right, larray, rarray, rstrides, OPERATOR)\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + +#define EQUALITY_LOOP(results, array, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? 1 : 0;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + +#define POWER_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides)\ + type_out *array = (type_out *)results->array;\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + +#endif /* ULAB_MAX_DIMS == 3 */ + +#if ULAB_MAX_DIMS == 4 +#define BINARY_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + type_out *array = (type_out *)results->array;\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ + +#define INPLACE_LOOP(results, type_left, type_right, larray, rarray, rstrides, OPERATOR)\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) OPERATOR *((type_right *)(rarray));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ + +#define EQUALITY_LOOP(results, array, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? 1 : 0;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ + +#define POWER_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides)\ + type_out *array = (type_out *)results->array;\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *array++ = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ + +#endif /* ULAB_MAX_DIMS == 4 */ +#endif /* ULAB_HAS_FUNCTION_ITERATOR */ + + +#if ULAB_MAX_DIMS == 1 +#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\ + type_left *larray = (type_left *)(results)->array;\ + size_t l = 0;\ + do {\ + *larray = (type_left)(*((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + +#endif /* ULAB_MAX_DIMS == 1 */ + +#if ULAB_MAX_DIMS == 2 +#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\ + type_left *larray = (type_left *)(results)->array;\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *larray = (type_left)(*((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + +#endif /* ULAB_MAX_DIMS == 2 */ + +#if ULAB_MAX_DIMS == 3 +#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\ + type_left *larray = (type_left *)(results)->array;\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *larray = (type_left)(*((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + +#endif /* ULAB_MAX_DIMS == 3 */ + +#if ULAB_MAX_DIMS == 4 +#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\ + type_left *larray = (type_left *)(results)->array;\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *larray = (type_left)(*((type_right *)(rarray)));\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ + +#endif /* ULAB_MAX_DIMS == 4 */ + +#endif diff --git a/python/port/mod/ulab/ndarray_operators.c b/python/port/mod/ulab/ndarray_operators.c new file mode 100644 index 000000000..ac2386053 --- /dev/null +++ b/python/port/mod/ulab/ndarray_operators.c @@ -0,0 +1,807 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + + +#include + +#include +#include +#include "ndarray.h" +#include "ndarray_operators.h" +#include "ulab.h" +#include "ulab_tools.h" + +/* + This file contains the actual implementations of the various + ndarray operators. + + These are the upcasting rules of the binary operators + + - if one of the operarands is a float, the result is always float + - operation on identical types preserves type + + uint8 + int8 => int16 + uint8 + int16 => int16 + uint8 + uint16 => uint16 + int8 + int16 => int16 + int8 + uint16 => uint16 + uint16 + int16 => float +*/ + +#if NDARRAY_HAS_BINARY_OP_EQUAL | NDARRAY_HAS_BINARY_OP_NOT_EQUAL +mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides, mp_binary_op_t op) { + + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8); + results->boolean = 1; + uint8_t *array = (uint8_t *)results->array; + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + #if NDARRAY_HAS_BINARY_OP_EQUAL + if(op == MP_BINARY_OP_EQUAL) { + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint8_t, int8_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint8_t, int16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, ==); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int8_t, int8_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int8_t, uint16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int8_t, int16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, ==); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint16_t, int16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, ==); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int16_t, int16_t, larray, lstrides, rarray, rstrides, ==); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, ==); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, ==); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } + } + #endif /* NDARRAY_HAS_BINARY_OP_EQUAL */ + + #if NDARRAY_HAS_BINARY_OP_NOT_EQUAL + if(op == MP_BINARY_OP_NOT_EQUAL) { + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint8_t, int8_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint8_t, int16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, !=); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int8_t, int8_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int8_t, uint16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int8_t, int16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, !=); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint16_t, int16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, !=); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int16_t, int16_t, larray, lstrides, rarray, rstrides, !=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, !=); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, !=); + } else { + return ndarray_binary_op(op, rhs, lhs); + } + } + } + #endif /* NDARRAY_HAS_BINARY_OP_NOT_EQUAL */ + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_EQUAL | NDARRAY_HAS_BINARY_OP_NOT_EQUAL */ + +#if NDARRAY_HAS_BINARY_OP_ADD +mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + + ndarray_obj_t *results = NULL; + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, +); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8); + BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, +); + } else { + return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, +); + } else { + return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, +); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, +); + } else { + return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, +); + } else { + return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs); + } + } + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_ADD */ + +#if NDARRAY_HAS_BINARY_OP_MULTIPLY +mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + + ndarray_obj_t *results = NULL; + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, *); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8); + BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, *); + } else { + return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, *); + } else { + return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, *); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, *); + } else { + return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, *); + } else { + return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs); + } + } + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_MULTIPLY */ + +#if NDARRAY_HAS_BINARY_OP_MORE | NDARRAY_HAS_BINARY_OP_MORE_EQUAL | NDARRAY_HAS_BINARY_OP_LESS | NDARRAY_HAS_BINARY_OP_LESS_EQUAL +mp_obj_t ndarray_binary_more(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides, mp_binary_op_t op) { + + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8); + results->boolean = 1; + uint8_t *array = (uint8_t *)results->array; + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + #if NDARRAY_HAS_BINARY_OP_MORE | NDARRAY_HAS_BINARY_OP_LESS + if(op == MP_BINARY_OP_MORE) { + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint8_t, int8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint8_t, int16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, >); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, int8_t, uint8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int8_t, int8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int8_t, uint16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int8_t, int16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, >); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint16_t, int8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint16_t, int16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, >); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, int16_t, uint8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int16_t, int8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int16_t, uint16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int16_t, int16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, >); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, mp_float_t, int8_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, mp_float_t, int16_t, larray, lstrides, rarray, rstrides, >); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, >); + } + } + } + #endif /* NDARRAY_HAS_BINARY_OP_MORE | NDARRAY_HAS_BINARY_OP_LESS*/ + #if NDARRAY_HAS_BINARY_OP_MORE_EQUAL | NDARRAY_HAS_BINARY_OP_LESS_EQUAL + if(op == MP_BINARY_OP_MORE_EQUAL) { + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint8_t, int8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint8_t, int16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, >=); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, int8_t, uint8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int8_t, int8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int8_t, uint16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int8_t, int16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, >=); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, uint16_t, int8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, uint16_t, int16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, >=); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, int16_t, uint8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, int16_t, int8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, int16_t, uint16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, int16_t, int16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, >=); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + EQUALITY_LOOP(results, array, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT8) { + EQUALITY_LOOP(results, array, mp_float_t, int8_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_UINT16) { + EQUALITY_LOOP(results, array, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_INT16) { + EQUALITY_LOOP(results, array, mp_float_t, int16_t, larray, lstrides, rarray, rstrides, >=); + } else if(rhs->dtype == NDARRAY_FLOAT) { + EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, >=); + } + } + } + #endif /* NDARRAY_HAS_BINARY_OP_MORE_EQUAL | NDARRAY_HAS_BINARY_OP_LESS_EQUAL */ + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_MORE | NDARRAY_HAS_BINARY_OP_MORE_EQUAL | NDARRAY_HAS_BINARY_OP_LESS | NDARRAY_HAS_BINARY_OP_LESS_EQUAL */ + +#if NDARRAY_HAS_BINARY_OP_SUBTRACT +mp_obj_t ndarray_binary_subtract(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + + ndarray_obj_t *results = NULL; + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8); + BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, -); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8); + BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, -); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16); + BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, -); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16); + BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, -); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT8) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_UINT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_INT16) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides, -); + } else if(rhs->dtype == NDARRAY_FLOAT) { + results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, -); + } + } + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_SUBTRACT */ + +#if NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE +mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + #if NDARRAY_BINARY_USES_FUN_POINTER + mp_float_t (*get_lhs)(void *) = ndarray_get_float_function(lhs->dtype); + mp_float_t (*get_rhs)(void *) = ndarray_get_float_function(rhs->dtype); + + uint8_t *array = (uint8_t *)results->array; + void (*set_result)(void *, mp_float_t ) = ndarray_set_float_function(NDARRAY_FLOAT); + + // Note that lvalue and rvalue are local variables in the macro itself + FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, lvalue/rvalue); + + #else + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + BINARY_LOOP(results, mp_float_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT8) { + BINARY_LOOP(results, mp_float_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_UINT16) { + BINARY_LOOP(results, mp_float_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT16) { + BINARY_LOOP(results, mp_float_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_FLOAT) { + BINARY_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, /); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + BINARY_LOOP(results, mp_float_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT8) { + BINARY_LOOP(results, mp_float_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_UINT16) { + BINARY_LOOP(results, mp_float_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT16) { + BINARY_LOOP(results, mp_float_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_FLOAT) { + BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, /); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + BINARY_LOOP(results, mp_float_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT8) { + BINARY_LOOP(results, mp_float_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_UINT16) { + BINARY_LOOP(results, mp_float_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT16) { + BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_FLOAT) { + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, /); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + BINARY_LOOP(results, mp_float_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT8) { + BINARY_LOOP(results, mp_float_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_UINT16) { + BINARY_LOOP(results, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT16) { + BINARY_LOOP(results, mp_float_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_FLOAT) { + BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, /); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + BINARY_LOOP(results, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT8) { + BINARY_LOOP(results, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_UINT16) { + BINARY_LOOP(results, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_INT16) { + BINARY_LOOP(results, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides, /); + } else if(rhs->dtype == NDARRAY_FLOAT) { + BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, /); + } + } + #endif /* NDARRAY_BINARY_USES_FUN_POINTER */ + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE */ + +#if NDARRAY_HAS_BINARY_OP_POWER +mp_obj_t ndarray_binary_power(ndarray_obj_t *lhs, ndarray_obj_t *rhs, + uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) { + + // Note that numpy upcasts the results to int64, if the inputs are of integer type, + // while we always return a float array. + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + #if NDARRAY_BINARY_USES_FUN_POINTER + mp_float_t (*get_lhs)(void *) = ndarray_get_float_function(lhs->dtype); + mp_float_t (*get_rhs)(void *) = ndarray_get_float_function(rhs->dtype); + + uint8_t *array = (uint8_t *)results->array; + void (*set_result)(void *, mp_float_t ) = ndarray_set_float_function(NDARRAY_FLOAT); + + // Note that lvalue and rvalue are local variables in the macro itself + FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, MICROPY_FLOAT_C_FUN(pow)(lvalue, rvalue)); + + #else + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + POWER_LOOP(results, mp_float_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + POWER_LOOP(results, mp_float_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + POWER_LOOP(results, mp_float_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + POWER_LOOP(results, mp_float_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_FLOAT) { + POWER_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + POWER_LOOP(results, mp_float_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + POWER_LOOP(results, mp_float_t, int8_t, int8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + POWER_LOOP(results, mp_float_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + POWER_LOOP(results, mp_float_t, int8_t, int16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_FLOAT) { + POWER_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + POWER_LOOP(results, mp_float_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + POWER_LOOP(results, mp_float_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + POWER_LOOP(results, mp_float_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + POWER_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_FLOAT) { + POWER_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + POWER_LOOP(results, mp_float_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + POWER_LOOP(results, mp_float_t, int16_t, int8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + POWER_LOOP(results, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + POWER_LOOP(results, mp_float_t, int16_t, int16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_FLOAT) { + POWER_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + POWER_LOOP(results, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + POWER_LOOP(results, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + POWER_LOOP(results, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + POWER_LOOP(results, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_FLOAT) { + POWER_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides); + } + } + #endif /* NDARRAY_BINARY_USES_FUN_POINTER */ + + return MP_OBJ_FROM_PTR(results); +} +#endif /* NDARRAY_HAS_BINARY_OP_POWER */ + +#if NDARRAY_HAS_INPLACE_ADD || NDARRAY_HAS_INPLACE_MULTIPLY || NDARRAY_HAS_INPLACE_SUBTRACT +mp_obj_t ndarray_inplace_ams(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides, uint8_t optype) { + + if((lhs->dtype != NDARRAY_FLOAT) && (rhs->dtype == NDARRAY_FLOAT)) { + mp_raise_TypeError(translate("cannot cast output with casting rule")); + } + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + #if NDARRAY_HAS_INPLACE_ADD + if(optype == MP_BINARY_OP_INPLACE_ADD) { + UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, +=); + } + #endif + #if NDARRAY_HAS_INPLACE_ADD + if(optype == MP_BINARY_OP_INPLACE_MULTIPLY) { + UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, *=); + } + #endif + #if NDARRAY_HAS_INPLACE_SUBTRACT + if(optype == MP_BINARY_OP_INPLACE_SUBTRACT) { + UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, -=); + } + #endif + + return MP_OBJ_FROM_PTR(lhs); +} +#endif /* NDARRAY_HAS_INPLACE_ADD || NDARRAY_HAS_INPLACE_MULTIPLY || NDARRAY_HAS_INPLACE_SUBTRACT */ + +#if NDARRAY_HAS_INPLACE_TRUE_DIVIDE +mp_obj_t ndarray_inplace_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) { + + if((lhs->dtype != NDARRAY_FLOAT)) { + mp_raise_TypeError(translate("results cannot be cast to specified type")); + } + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(rhs->dtype == NDARRAY_UINT8) { + INPLACE_LOOP(lhs, mp_float_t, uint8_t, larray, rarray, rstrides, /=); + } else if(rhs->dtype == NDARRAY_INT8) { + INPLACE_LOOP(lhs, mp_float_t, int8_t, larray, rarray, rstrides, /=); + } else if(rhs->dtype == NDARRAY_UINT16) { + INPLACE_LOOP(lhs, mp_float_t, uint16_t, larray, rarray, rstrides, /=); + } else if(rhs->dtype == NDARRAY_INT16) { + INPLACE_LOOP(lhs, mp_float_t, int16_t, larray, rarray, rstrides, /=); + } else if(lhs->dtype == NDARRAY_FLOAT) { + INPLACE_LOOP(lhs, mp_float_t, mp_float_t, larray, rarray, rstrides, /=); + } + return MP_OBJ_FROM_PTR(lhs); +} +#endif /* NDARRAY_HAS_INPLACE_DIVIDE */ + +#if NDARRAY_HAS_INPLACE_POWER +mp_obj_t ndarray_inplace_power(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) { + + if((lhs->dtype != NDARRAY_FLOAT)) { + mp_raise_TypeError(translate("results cannot be cast to specified type")); + } + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(rhs->dtype == NDARRAY_UINT8) { + INPLACE_POWER(lhs, mp_float_t, uint8_t, larray, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT8) { + INPLACE_POWER(lhs, mp_float_t, int8_t, larray, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_UINT16) { + INPLACE_POWER(lhs, mp_float_t, uint16_t, larray, rarray, rstrides); + } else if(rhs->dtype == NDARRAY_INT16) { + INPLACE_POWER(lhs, mp_float_t, int16_t, larray, rarray, rstrides); + } else if(lhs->dtype == NDARRAY_FLOAT) { + INPLACE_POWER(lhs, mp_float_t, mp_float_t, larray, rarray, rstrides); + } + return MP_OBJ_FROM_PTR(lhs); +} +#endif /* NDARRAY_HAS_INPLACE_POWER */ diff --git a/python/port/mod/ulab/ndarray_operators.h b/python/port/mod/ulab/ndarray_operators.h new file mode 100644 index 000000000..7849e0309 --- /dev/null +++ b/python/port/mod/ulab/ndarray_operators.h @@ -0,0 +1,277 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#include "ndarray.h" + +mp_obj_t ndarray_binary_equality(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t ); +mp_obj_t ndarray_binary_add(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *); +mp_obj_t ndarray_binary_multiply(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *); +mp_obj_t ndarray_binary_more(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t ); +mp_obj_t ndarray_binary_power(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *); +mp_obj_t ndarray_binary_subtract(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *); +mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *); + +mp_obj_t ndarray_inplace_ams(ndarray_obj_t *, ndarray_obj_t *, int32_t *, uint8_t ); +mp_obj_t ndarray_inplace_power(ndarray_obj_t *, ndarray_obj_t *, int32_t *); +mp_obj_t ndarray_inplace_divide(ndarray_obj_t *, ndarray_obj_t *, int32_t *); + +#define UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, OPERATOR)\ +({\ + if((lhs)->dtype == NDARRAY_UINT8) {\ + if((rhs)->dtype == NDARRAY_UINT8) {\ + INPLACE_LOOP((lhs), uint8_t, uint8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT8) {\ + INPLACE_LOOP((lhs), uint8_t, int8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_UINT16) {\ + INPLACE_LOOP((lhs), uint8_t, uint16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else {\ + INPLACE_LOOP((lhs), uint8_t, int16_t, (larray), (rarray), (rstrides), OPERATOR);\ + }\ + } else if(lhs->dtype == NDARRAY_INT8) {\ + if(rhs->dtype == NDARRAY_UINT8) {\ + INPLACE_LOOP((lhs), int8_t, uint8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT8) {\ + INPLACE_LOOP((lhs), int8_t, int8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_UINT16) {\ + INPLACE_LOOP((lhs), int8_t, uint16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else {\ + INPLACE_LOOP((lhs), int8_t, int16_t, (larray), (rarray), (rstrides), OPERATOR);\ + }\ + } else if(lhs->dtype == NDARRAY_UINT16) {\ + if(rhs->dtype == NDARRAY_UINT8) {\ + INPLACE_LOOP((lhs), uint16_t, uint8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT8) {\ + INPLACE_LOOP((lhs), uint16_t, int8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_UINT16) {\ + INPLACE_LOOP((lhs), uint16_t, uint16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else {\ + INPLACE_LOOP((lhs), uint16_t, int16_t, (larray), (rarray), (rstrides), OPERATOR);\ + }\ + } else if(lhs->dtype == NDARRAY_INT16) {\ + if(rhs->dtype == NDARRAY_UINT8) {\ + INPLACE_LOOP((lhs), int16_t, uint8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT8) {\ + INPLACE_LOOP((lhs), int16_t, int8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_UINT16) {\ + INPLACE_LOOP((lhs), int16_t, uint16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else {\ + INPLACE_LOOP((lhs), int16_t, int16_t, (larray), (rarray), (rstrides), OPERATOR);\ + }\ + } else if(lhs->dtype == NDARRAY_FLOAT) {\ + if(rhs->dtype == NDARRAY_UINT8) {\ + INPLACE_LOOP((lhs), mp_float_t, uint8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT8) {\ + INPLACE_LOOP((lhs), mp_float_t, int8_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_UINT16) {\ + INPLACE_LOOP((lhs), mp_float_t, uint16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else if(rhs->dtype == NDARRAY_INT16) {\ + INPLACE_LOOP((lhs), mp_float_t, int16_t, (larray), (rarray), (rstrides), OPERATOR);\ + } else {\ + INPLACE_LOOP((lhs), mp_float_t, mp_float_t, (larray), (rarray), (rstrides), OPERATOR);\ + }\ + }\ +}) + +#if ULAB_MAX_DIMS == 1 +#define INPLACE_POWER(results, type_left, type_right, larray, rarray, rstrides)\ +({ size_t l = 0;\ + do {\ + *((type_left *)(larray)) = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ +}) + +#define FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, OPERATION)\ +({ size_t l = 0;\ + do {\ + mp_float_t lvalue = (get_lhs)((larray));\ + mp_float_t rvalue = (get_rhs)((rarray));\ + (set_result)((array), OPERATION);\ + (array) += (results)->itemsize;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ +}) +#endif /* ULAB_MAX_DIMS == 1 */ + +#if ULAB_MAX_DIMS == 2 +#define INPLACE_POWER(results, type_left, type_right, larray, rarray, rstrides)\ +({ size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ +}) + +#define FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, OPERATION)\ +({ size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + mp_float_t lvalue = (get_lhs)((larray));\ + mp_float_t rvalue = (get_rhs)((rarray));\ + (set_result)((array), OPERATION);\ + (array) += (results)->itemsize;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ +}) +#endif /* ULAB_MAX_DIMS == 2 */ + +#if ULAB_MAX_DIMS == 3 +#define INPLACE_POWER(results, type_left, type_right, larray, rarray, rstrides)\ +({ size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ +}) + + +#define FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, OPERATION)\ +({ size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + mp_float_t lvalue = (get_lhs)((larray));\ + mp_float_t rvalue = (get_rhs)((rarray));\ + (set_result)((array), OPERATION);\ + (array) += (results)->itemsize;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ +}) +#endif /* ULAB_MAX_DIMS == 3 */ + +#if ULAB_MAX_DIMS == 4 +#define INPLACE_POWER(results, type_left, type_right, larray, rarray, rstrides)\ +({ size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_left *)(larray)) = MICROPY_FLOAT_C_FUN(pow)(*((type_left *)(larray)), *((type_right *)(rarray)));\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ +}) + +#define FUNC_POINTER_LOOP(results, array, get_lhs, get_rhs, larray, lstrides, rarray, rstrides, OPERATION)\ +({ size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + mp_float_t lvalue = (get_lhs)((larray));\ + mp_float_t rvalue = (get_rhs)((rarray));\ + (set_result)((array), OPERATION);\ + (array) += (results)->itemsize;\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (results)->strides[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (larray) += (results)->strides[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\ +}) +#endif /* ULAB_MAX_DIMS == 4 */ diff --git a/python/port/mod/ulab/ndarray_properties.c b/python/port/mod/ulab/ndarray_properties.c new file mode 100644 index 000000000..0fcf83bca --- /dev/null +++ b/python/port/mod/ulab/ndarray_properties.c @@ -0,0 +1,100 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Zoltán Vörös + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "ulab.h" +#include "ndarray.h" + +#ifndef CIRCUITPY + +// a somewhat hackish implementation of property getters/setters; +// this functions is hooked into the attr member of ndarray + +STATIC void call_local_method(mp_obj_t obj, qstr attr, mp_obj_t *dest) { + const mp_obj_type_t *type = mp_obj_get_type(obj); + while (type->locals_dict != NULL) { + assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now + mp_map_t *locals_map = &type->locals_dict->map; + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem != NULL) { + mp_convert_member_lookup(obj, type, elem->value, dest); + break; + } + if (type->parent == NULL) { + break; + } + type = type->parent; + } +} + + +void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + switch(attr) { + #if NDARRAY_HAS_DTYPE + case MP_QSTR_dtype: + dest[0] = ndarray_dtype(self_in); + break; + #endif + #if NDARRAY_HAS_ITEMSIZE + case MP_QSTR_itemsize: + dest[0] = ndarray_itemsize(self_in); + break; + #endif + #if NDARRAY_HAS_SHAPE + case MP_QSTR_shape: + dest[0] = ndarray_shape(self_in); + break; + #endif + #if NDARRAY_HAS_SIZE + case MP_QSTR_size: + dest[0] = ndarray_size(self_in); + break; + #endif + #if NDARRAY_HAS_STRIDES + case MP_QSTR_strides: + dest[0] = ndarray_strides(self_in); + break; + #endif + #if NDARRAY_HAS_TRANSPOSE + case MP_QSTR_T: + dest[0] = ndarray_transpose(self_in); + break; + #endif + default: + call_local_method(self_in, attr, dest); + break; + } + } else { + if(dest[1]) { + switch(attr) { + #if NDARRAY_HAS_RESHAPE + case MP_QSTR_shape: + ndarray_reshape_core(self_in, dest[1], 1); + break; + #endif + default: + return; + break; + } + dest[0] = MP_OBJ_NULL; + } + } +} + +#endif /* CIRCUITPY */ \ No newline at end of file diff --git a/python/port/mod/ulab/ndarray_properties.h b/python/port/mod/ulab/ndarray_properties.h new file mode 100644 index 000000000..9d3b4ee9b --- /dev/null +++ b/python/port/mod/ulab/ndarray_properties.h @@ -0,0 +1,92 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Zoltán Vörös +*/ + +#ifndef _NDARRAY_PROPERTIES_ +#define _NDARRAY_PROPERTIES_ + +#include +#include +#include +#include + +#include "ulab.h" +#include "ndarray.h" + +#if CIRCUITPY +typedef struct _mp_obj_property_t { + mp_obj_base_t base; + mp_obj_t proxy[3]; // getter, setter, deleter +} mp_obj_property_t; + +#if NDARRAY_HAS_DTYPE +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_dtype_obj, ndarray_dtype); +STATIC const mp_obj_property_t ndarray_dtype_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_dtype_obj, + mp_const_none, + mp_const_none }, +}; +#endif /* NDARRAY_HAS_DTYPE */ + +#if NDARRAY_HAS_ITEMSIZE +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_itemsize_obj, ndarray_itemsize); +STATIC const mp_obj_property_t ndarray_itemsize_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_itemsize_obj, + mp_const_none, + mp_const_none }, +}; +#endif /* NDARRAY_HAS_ITEMSIZE */ + +#if NDARRAY_HAS_SHAPE +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_shape_obj, ndarray_shape); +STATIC const mp_obj_property_t ndarray_shape_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_shape_obj, + mp_const_none, + mp_const_none }, +}; +#endif /* NDARRAY_HAS_SHAPE */ + +#if NDARRAY_HAS_SIZE +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_size_obj, ndarray_size); +STATIC const mp_obj_property_t ndarray_size_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_size_obj, + mp_const_none, + mp_const_none }, +}; +#endif /* NDARRAY_HAS_SIZE */ + +#if NDARRAY_HAS_STRIDES +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_strides_obj, ndarray_strides); +STATIC const mp_obj_property_t ndarray_strides_obj = { + .base.type = &mp_type_property, + .proxy = {(mp_obj_t)&ndarray_get_strides_obj, + mp_const_none, + mp_const_none }, +}; +#endif /* NDARRAY_HAS_STRIDES */ + +#else + +void ndarray_properties_attr(mp_obj_t , qstr , mp_obj_t *); + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_dtype_obj, ndarray_dtype); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size); +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_strides_obj, ndarray_strides); + +#endif /* CIRCUITPY */ + +#endif diff --git a/python/port/mod/ulab/numpy/approx/approx.c b/python/port/mod/ulab/numpy/approx/approx.c new file mode 100644 index 000000000..706a969a7 --- /dev/null +++ b/python/port/mod/ulab/numpy/approx/approx.c @@ -0,0 +1,221 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * 2020 Diego Elio Pettenò + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "approx.h" + +//| """Numerical approximation methods""" +//| + +const mp_obj_float_t approx_trapz_dx = {{&mp_type_float}, MICROPY_FLOAT_CONST(1.0)}; + +#if ULAB_NUMPY_HAS_INTERP +//| def interp( +//| x: ulab.ndarray, +//| xp: ulab.ndarray, +//| fp: ulab.ndarray, +//| *, +//| left: Optional[float] = None, +//| right: Optional[float] = None +//| ) -> ulab.ndarray: +//| """ +//| :param ulab.ndarray x: The x-coordinates at which to evaluate the interpolated values. +//| :param ulab.ndarray xp: The x-coordinates of the data points, must be increasing +//| :param ulab.ndarray fp: The y-coordinates of the data points, same length as xp +//| :param left: Value to return for ``x < xp[0]``, default is ``fp[0]``. +//| :param right: Value to return for ``x > xp[-1]``, default is ``fp[-1]``. +//| +//| Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (xp, fp), evaluated at x.""" +//| ... +//| + +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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_left, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + { MP_QSTR_right, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ndarray_obj_t *x = ndarray_from_mp_obj(args[0].u_obj, 0); + ndarray_obj_t *xp = ndarray_from_mp_obj(args[1].u_obj, 0); // xp must hold an increasing sequence of independent values + ndarray_obj_t *fp = ndarray_from_mp_obj(args[2].u_obj, 0); + if((xp->ndim != 1) || (fp->ndim != 1) || (xp->len < 2) || (fp->len < 2) || (xp->len != fp->len)) { + mp_raise_ValueError(translate("interp is defined for 1D iterables of equal length")); + } + + ndarray_obj_t *y = ndarray_new_linear_array(x->len, NDARRAY_FLOAT); + mp_float_t left_value, right_value; + uint8_t *xparray = (uint8_t *)xp->array; + + mp_float_t xp_left = ndarray_get_float_value(xparray, xp->dtype); + xparray += (xp->len-1) * xp->strides[ULAB_MAX_DIMS - 1]; + mp_float_t xp_right = ndarray_get_float_value(xparray, xp->dtype); + + uint8_t *fparray = (uint8_t *)fp->array; + + if(args[3].u_obj == mp_const_none) { + left_value = ndarray_get_float_value(fparray, fp->dtype); + } else { + left_value = mp_obj_get_float(args[3].u_obj); + } + if(args[4].u_obj == mp_const_none) { + fparray += (fp->len-1) * fp->strides[ULAB_MAX_DIMS - 1]; + right_value = ndarray_get_float_value(fparray, fp->dtype); + } else { + right_value = mp_obj_get_float(args[4].u_obj); + } + + xparray = xp->array; + fparray = fp->array; + + uint8_t *xarray = (uint8_t *)x->array; + mp_float_t *yarray = (mp_float_t *)y->array; + uint8_t *temp; + + for(size_t i=0; i < x->len; i++, yarray++) { + mp_float_t x_value = ndarray_get_float_value(xarray, x->dtype); + xarray += x->strides[ULAB_MAX_DIMS - 1]; + if(x_value < xp_left) { + *yarray = left_value; + } else if(x_value > xp_right) { + *yarray = right_value; + } else { // do the binary search here + mp_float_t xp_left_, xp_right_; + mp_float_t fp_left, fp_right; + size_t left_index = 0, right_index = xp->len - 1, middle_index; + while(right_index - left_index > 1) { + middle_index = left_index + (right_index - left_index) / 2; + temp = xparray + middle_index * xp->strides[ULAB_MAX_DIMS - 1]; + mp_float_t xp_middle = ndarray_get_float_value(temp, xp->dtype); + if(x_value <= xp_middle) { + right_index = middle_index; + } else { + left_index = middle_index; + } + } + temp = xparray + left_index * xp->strides[ULAB_MAX_DIMS - 1]; + xp_left_ = ndarray_get_float_value(temp, xp->dtype); + + temp = xparray + right_index * xp->strides[ULAB_MAX_DIMS - 1]; + xp_right_ = ndarray_get_float_value(temp, xp->dtype); + + temp = fparray + left_index * fp->strides[ULAB_MAX_DIMS - 1]; + fp_left = ndarray_get_float_value(temp, fp->dtype); + + temp = fparray + right_index * fp->strides[ULAB_MAX_DIMS - 1]; + fp_right = ndarray_get_float_value(temp, fp->dtype); + + *yarray = fp_left + (x_value - xp_left_) * (fp_right - fp_left) / (xp_right_ - xp_left_); + } + } + return MP_OBJ_FROM_PTR(y); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(approx_interp_obj, 2, approx_interp); +#endif + +#if ULAB_NUMPY_HAS_TRAPZ +//| def trapz(y: ulab.ndarray, x: Optional[ulab.ndarray] = None, dx: float = 1.0) -> float: +//| """ +//| :param 1D ulab.ndarray y: the values of the dependent variable +//| :param 1D ulab.ndarray x: optional, the coordinates of the independent variable. Defaults to uniformly spaced values. +//| :param float dx: the spacing between sample points, if x=None +//| +//| Returns the integral of y(x) using the trapezoidal rule. +//| """ +//| ... +//| + +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_const_none } }, + { MP_QSTR_x, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_dx, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&approx_trapz_dx)} }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ndarray_obj_t *y = ndarray_from_mp_obj(args[0].u_obj, 0); + ndarray_obj_t *x; + mp_float_t mean = MICROPY_FLOAT_CONST(0.0); + if(y->len < 2) { + return mp_obj_new_float(mean); + } + if((y->ndim != 1)) { + mp_raise_ValueError(translate("trapz is defined for 1D iterables")); + } + + mp_float_t (*funcy)(void *) = ndarray_get_float_function(y->dtype); + uint8_t *yarray = (uint8_t *)y->array; + + size_t count = 1; + mp_float_t y1, y2, m; + + if(args[1].u_obj != mp_const_none) { + x = ndarray_from_mp_obj(args[1].u_obj, 0); // x must hold an increasing sequence of independent values + if((x->ndim != 1) || (y->len != x->len)) { + mp_raise_ValueError(translate("trapz is defined for 1D arrays of equal length")); + } + + mp_float_t (*funcx)(void *) = ndarray_get_float_function(x->dtype); + uint8_t *xarray = (uint8_t *)x->array; + mp_float_t x1, x2; + + y1 = funcy(yarray); + yarray += y->strides[ULAB_MAX_DIMS - 1]; + x1 = funcx(xarray); + xarray += x->strides[ULAB_MAX_DIMS - 1]; + + for(size_t i=1; i < y->len; i++) { + y2 = funcy(yarray); + yarray += y->strides[ULAB_MAX_DIMS - 1]; + x2 = funcx(xarray); + xarray += x->strides[ULAB_MAX_DIMS - 1]; + mp_float_t value = (x2 - x1) * (y2 + y1); + m = mean + (value - mean) / (mp_float_t)count; + mean = m; + x1 = x2; + y1 = y2; + count++; + } + } else { + mp_float_t dx = mp_obj_get_float(args[2].u_obj); + y1 = funcy(yarray); + yarray += y->strides[ULAB_MAX_DIMS - 1]; + + for(size_t i=1; i < y->len; i++) { + y2 = ndarray_get_float_index(y->array, y->dtype, i); + mp_float_t value = (y2 + y1); + m = mean + (value - mean) / (mp_float_t)count; + mean = m; + y1 = y2; + count++; + } + mean *= dx; + } + return mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)*mean*(y->len-1)); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(approx_trapz_obj, 1, approx_trapz); +#endif diff --git a/python/port/mod/ulab/numpy/approx/approx.h b/python/port/mod/ulab/numpy/approx/approx.h new file mode 100644 index 000000000..7708bb789 --- /dev/null +++ b/python/port/mod/ulab/numpy/approx/approx.h @@ -0,0 +1,29 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#ifndef _APPROX_ +#define _APPROX_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +#define APPROX_EPS MICROPY_FLOAT_CONST(1.0e-4) +#define APPROX_NONZDELTA MICROPY_FLOAT_CONST(0.05) +#define APPROX_ZDELTA MICROPY_FLOAT_CONST(0.00025) +#define APPROX_ALPHA MICROPY_FLOAT_CONST(1.0) +#define APPROX_BETA MICROPY_FLOAT_CONST(2.0) +#define APPROX_GAMMA MICROPY_FLOAT_CONST(0.5) +#define APPROX_DELTA MICROPY_FLOAT_CONST(0.5) + +MP_DECLARE_CONST_FUN_OBJ_KW(approx_interp_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(approx_trapz_obj); + +#endif /* _APPROX_ */ diff --git a/python/port/mod/ulab/numpy/compare/compare.c b/python/port/mod/ulab/numpy/compare/compare.c new file mode 100644 index 000000000..73dfaa135 --- /dev/null +++ b/python/port/mod/ulab/numpy/compare/compare.c @@ -0,0 +1,417 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ndarray_operators.h" +#include "../../ulab_tools.h" +#include "compare.h" + +static mp_obj_t compare_function(mp_obj_t x1, mp_obj_t x2, uint8_t op) { + ndarray_obj_t *lhs = ndarray_from_mp_obj(x1, 0); + ndarray_obj_t *rhs = ndarray_from_mp_obj(x2, 0); + uint8_t ndim = 0; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + int32_t *lstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS); + if(!ndarray_can_broadcast(lhs, rhs, &ndim, shape, lstrides, rstrides)) { + mp_raise_ValueError(translate("operands could not be broadcast together")); + m_del(size_t, shape, ULAB_MAX_DIMS); + m_del(int32_t, lstrides, ULAB_MAX_DIMS); + m_del(int32_t, rstrides, ULAB_MAX_DIMS); + } + + uint8_t *larray = (uint8_t *)lhs->array; + uint8_t *rarray = (uint8_t *)rhs->array; + + if(op == COMPARE_EQUAL) { + return ndarray_binary_equality(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_EQUAL); + } else if(op == COMPARE_NOT_EQUAL) { + return ndarray_binary_equality(lhs, rhs, ndim, shape, lstrides, rstrides, MP_BINARY_OP_NOT_EQUAL); + } + // These are the upcasting rules + // float always becomes float + // operation on identical types preserves type + // uint8 + int8 => int16 + // uint8 + int16 => int16 + // uint8 + uint16 => uint16 + // int8 + int16 => int16 + // int8 + uint16 => uint16 + // uint16 + int16 => float + // The parameters of RUN_COMPARE_LOOP are + // typecode of result, type_out, type_left, type_right, lhs operand, rhs operand, operator + if(lhs->dtype == NDARRAY_UINT8) { + if(rhs->dtype == NDARRAY_UINT8) { + RUN_COMPARE_LOOP(NDARRAY_UINT8, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT8) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_UINT16) { + RUN_COMPARE_LOOP(NDARRAY_UINT16, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT16) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_FLOAT) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } + } else if(lhs->dtype == NDARRAY_INT8) { + if(rhs->dtype == NDARRAY_UINT8) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT8) { + RUN_COMPARE_LOOP(NDARRAY_INT8, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_UINT16) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT16) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_FLOAT) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } + } else if(lhs->dtype == NDARRAY_UINT16) { + if(rhs->dtype == NDARRAY_UINT8) { + RUN_COMPARE_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT8) { + RUN_COMPARE_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_UINT16) { + RUN_COMPARE_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT16) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_FLOAT) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } + } else if(lhs->dtype == NDARRAY_INT16) { + if(rhs->dtype == NDARRAY_UINT8) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT8) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_UINT16) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT16) { + RUN_COMPARE_LOOP(NDARRAY_INT16, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_FLOAT) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } + } else if(lhs->dtype == NDARRAY_FLOAT) { + if(rhs->dtype == NDARRAY_UINT8) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT8) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_UINT16) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_INT16) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } else if(rhs->dtype == NDARRAY_FLOAT) { + RUN_COMPARE_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, ndim, shape, op); + } + } + return mp_const_none; // we should never reach this point +} + +static mp_obj_t compare_equal_helper(mp_obj_t x1, mp_obj_t x2, uint8_t comptype) { + // scalar comparisons should return a single object of mp_obj_t type + mp_obj_t result = compare_function(x1, x2, comptype); + if((mp_obj_is_int(x1) || mp_obj_is_float(x1)) && (mp_obj_is_int(x2) || mp_obj_is_float(x2))) { + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(result, &iter_buf); + mp_obj_t item = mp_iternext(iterable); + return item; + } + return result; +} + +#if ULAB_NUMPY_HAS_CLIP + +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 + // would not gain a factor of two in speed, since the two comparisons should still be + // evaluated. In contrast, calling the function twice adds only 140 bytes to the firmware + if(mp_obj_is_int(x1) || mp_obj_is_float(x1)) { + mp_float_t v1 = mp_obj_get_float(x1); + mp_float_t v2 = mp_obj_get_float(x2); + mp_float_t v3 = mp_obj_get_float(x3); + if(v1 < v2) { + return x2; + } else if(v1 > v3) { + return x3; + } else { + return x1; + } + } else { // assume ndarrays + return compare_function(x2, compare_function(x1, x3, COMPARE_MINIMUM), COMPARE_MAXIMUM); + } +} + +MP_DEFINE_CONST_FUN_OBJ_3(compare_clip_obj, compare_clip); +#endif + +#if ULAB_NUMPY_HAS_EQUAL + +mp_obj_t compare_equal(mp_obj_t x1, mp_obj_t x2) { + return compare_equal_helper(x1, x2, COMPARE_EQUAL); +} + +MP_DEFINE_CONST_FUN_OBJ_2(compare_equal_obj, compare_equal); +#endif + +#if ULAB_NUMPY_HAS_NOTEQUAL + +mp_obj_t compare_not_equal(mp_obj_t x1, mp_obj_t x2) { + return compare_equal_helper(x1, x2, COMPARE_NOT_EQUAL); +} + +MP_DEFINE_CONST_FUN_OBJ_2(compare_not_equal_obj, compare_not_equal); +#endif + +#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); + if((mp_obj_is_int(x1) || mp_obj_is_float(x1)) && (mp_obj_is_int(x2) || mp_obj_is_float(x2))) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(result); + return mp_binary_get_val_array(ndarray->dtype, ndarray->array, 0); + } + return result; +} + +MP_DEFINE_CONST_FUN_OBJ_2(compare_maximum_obj, compare_maximum); +#endif + +#if ULAB_NUMPY_HAS_MINIMUM + +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); + if((mp_obj_is_int(x1) || mp_obj_is_float(x1)) && (mp_obj_is_int(x2) || mp_obj_is_float(x2))) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(result); + return mp_binary_get_val_array(ndarray->dtype, ndarray->array, 0); + } + return result; +} + +MP_DEFINE_CONST_FUN_OBJ_2(compare_minimum_obj, compare_minimum); +#endif + +#if ULAB_NUMPY_HAS_WHERE + +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); + ndarray_obj_t *x = ndarray_from_mp_obj(_x, 0); + ndarray_obj_t *y = ndarray_from_mp_obj(_y, 0); + + int32_t *cstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *xstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *ystrides = m_new(int32_t, ULAB_MAX_DIMS); + + size_t *oshape = m_new(size_t, ULAB_MAX_DIMS); + + uint8_t ndim; + + // establish the broadcasting conditions first + // if any two of the arrays can be broadcast together, then + // the three arrays can also be broadcast together + if(!ndarray_can_broadcast(c, x, &ndim, oshape, cstrides, ystrides) || + !ndarray_can_broadcast(c, y, &ndim, oshape, cstrides, ystrides) || + !ndarray_can_broadcast(x, y, &ndim, oshape, xstrides, ystrides)) { + mp_raise_ValueError(translate("operands could not be broadcast together")); + } + + ndim = MAX(MAX(c->ndim, x->ndim), y->ndim); + + for(uint8_t i = 1; i <= ndim; i++) { + cstrides[ULAB_MAX_DIMS - i] = c->shape[ULAB_MAX_DIMS - i] < 2 ? 0 : c->strides[ULAB_MAX_DIMS - i]; + xstrides[ULAB_MAX_DIMS - i] = x->shape[ULAB_MAX_DIMS - i] < 2 ? 0 : x->strides[ULAB_MAX_DIMS - i]; + ystrides[ULAB_MAX_DIMS - i] = y->shape[ULAB_MAX_DIMS - i] < 2 ? 0 : y->strides[ULAB_MAX_DIMS - i]; + oshape[ULAB_MAX_DIMS - i] = MAX(MAX(c->shape[ULAB_MAX_DIMS - i], x->shape[ULAB_MAX_DIMS - i]), y->shape[ULAB_MAX_DIMS - i]); + } + + uint8_t out_dtype = ndarray_upcast_dtype(x->dtype, y->dtype); + ndarray_obj_t *out = ndarray_new_dense_ndarray(ndim, oshape, out_dtype); + + mp_float_t (*cfunc)(void *) = ndarray_get_float_function(c->dtype); + mp_float_t (*xfunc)(void *) = ndarray_get_float_function(x->dtype); + mp_float_t (*yfunc)(void *) = ndarray_get_float_function(y->dtype); + mp_float_t (*ofunc)(void *, mp_float_t ) = ndarray_set_float_function(out->dtype); + + uint8_t *oarray = (uint8_t *)out->array; + uint8_t *carray = (uint8_t *)c->array; + uint8_t *xarray = (uint8_t *)x->array; + uint8_t *yarray = (uint8_t *)y->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 cvalue = cfunc(carray); + if(cvalue != MICROPY_FLOAT_CONST(0.0)) { + value = xfunc(xarray); + } else { + value = yfunc(yarray); + } + ofunc(oarray, value); + oarray += out->itemsize; + carray += cstrides[ULAB_MAX_DIMS - 1]; + xarray += xstrides[ULAB_MAX_DIMS - 1]; + yarray += ystrides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < out->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + carray -= cstrides[ULAB_MAX_DIMS - 1] * c->shape[ULAB_MAX_DIMS-1]; + carray += cstrides[ULAB_MAX_DIMS - 2]; + xarray -= xstrides[ULAB_MAX_DIMS - 1] * x->shape[ULAB_MAX_DIMS-1]; + xarray += xstrides[ULAB_MAX_DIMS - 2]; + yarray -= ystrides[ULAB_MAX_DIMS - 1] * y->shape[ULAB_MAX_DIMS-1]; + yarray += ystrides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < out->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + carray -= cstrides[ULAB_MAX_DIMS - 2] * c->shape[ULAB_MAX_DIMS-2]; + carray += cstrides[ULAB_MAX_DIMS - 3]; + xarray -= xstrides[ULAB_MAX_DIMS - 2] * x->shape[ULAB_MAX_DIMS-2]; + xarray += xstrides[ULAB_MAX_DIMS - 3]; + yarray -= ystrides[ULAB_MAX_DIMS - 2] * y->shape[ULAB_MAX_DIMS-2]; + yarray += ystrides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < out->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + carray -= cstrides[ULAB_MAX_DIMS - 3] * c->shape[ULAB_MAX_DIMS-3]; + carray += cstrides[ULAB_MAX_DIMS - 4]; + xarray -= xstrides[ULAB_MAX_DIMS - 3] * x->shape[ULAB_MAX_DIMS-3]; + xarray += xstrides[ULAB_MAX_DIMS - 4]; + yarray -= ystrides[ULAB_MAX_DIMS - 3] * y->shape[ULAB_MAX_DIMS-3]; + yarray += ystrides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < out->shape[ULAB_MAX_DIMS - 4]); + #endif + return MP_OBJ_FROM_PTR(out); +} + +MP_DEFINE_CONST_FUN_OBJ_3(compare_where_obj, compare_where); +#endif diff --git a/python/port/mod/ulab/numpy/compare/compare.h b/python/port/mod/ulab/numpy/compare/compare.h new file mode 100644 index 000000000..12a559e0a --- /dev/null +++ b/python/port/mod/ulab/numpy/compare/compare.h @@ -0,0 +1,150 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#ifndef _COMPARE_ +#define _COMPARE_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +enum COMPARE_FUNCTION_TYPE { + COMPARE_EQUAL, + COMPARE_NOT_EQUAL, + COMPARE_MINIMUM, + COMPARE_MAXIMUM, + 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_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_2(compare_not_equal_obj); +MP_DECLARE_CONST_FUN_OBJ_3(compare_where_obj); + +#if ULAB_MAX_DIMS == 1 +#define COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t l = 0;\ + do {\ + *((type_out *)(array)) = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? (type_out)(*((type_left *)(larray))) : (type_out)(*((type_right *)(rarray)));\ + (array) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < results->shape[ULAB_MAX_DIMS - 1]);\ + return MP_OBJ_FROM_PTR(results);\ + +#endif // ULAB_MAX_DIMS == 1 + +#if ULAB_MAX_DIMS == 2 +#define COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_out *)(array)) = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? (type_out)(*((type_left *)(larray))) : (type_out)(*((type_right *)(rarray)));\ + (array) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < results->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ + return MP_OBJ_FROM_PTR(results);\ + +#endif // ULAB_MAX_DIMS == 2 + +#if ULAB_MAX_DIMS == 3 +#define COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_out *)(array)) = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? (type_out)(*((type_left *)(larray))) : (type_out)(*((type_right *)(rarray)));\ + (array) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < results->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < results->shape[ULAB_MAX_DIMS - 3]);\ + return MP_OBJ_FROM_PTR(results);\ + +#endif // ULAB_MAX_DIMS == 3 + +#if ULAB_MAX_DIMS == 4 +#define COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\ + size_t i = 0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *((type_out *)(array)) = *((type_left *)(larray)) OPERATOR *((type_right *)(rarray)) ? (type_out)(*((type_left *)(larray))) : (type_out)(*((type_right *)(rarray)));\ + (array) += (results)->strides[ULAB_MAX_DIMS - 1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < results->shape[ULAB_MAX_DIMS - 1]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 2];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < results->shape[ULAB_MAX_DIMS - 2]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < results->shape[ULAB_MAX_DIMS - 3]);\ + (larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];\ + (larray) += (lstrides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];\ + (rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < results->shape[ULAB_MAX_DIMS - 4]);\ + return MP_OBJ_FROM_PTR(results);\ + +#endif // ULAB_MAX_DIMS == 4 + +#define RUN_COMPARE_LOOP(dtype, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, ndim, shape, op) do {\ + ndarray_obj_t *results = ndarray_new_dense_ndarray((ndim), (shape), (dtype));\ + uint8_t *array = (uint8_t *)results->array;\ + if((op) == COMPARE_MINIMUM) {\ + COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, <);\ + }\ + if((op) == COMPARE_MAXIMUM) {\ + COMPARE_LOOP(results, array, type_out, type_left, type_right, larray, lstrides, rarray, rstrides, >);\ + }\ +} while(0) + +#endif diff --git a/python/port/mod/ulab/numpy/fft/fft.c b/python/port/mod/ulab/numpy/fft/fft.c new file mode 100644 index 000000000..ff2373fe0 --- /dev/null +++ b/python/port/mod/ulab/numpy/fft/fft.c @@ -0,0 +1,82 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "fft.h" + +//| """Frequency-domain functions""" +//| + + +//| def fft(r: ulab.ndarray, c: Optional[ulab.ndarray] = None) -> Tuple[ulab.ndarray, ulab.ndarray]: +//| """ +//| :param ulab.ndarray r: A 1-dimension array of values whose size is a power of 2 +//| :param ulab.ndarray c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value +//| :return tuple (r, c): The real and complex parts of the FFT +//| +//| Perform a Fast Fourier Transform from the time domain into the frequency domain +//| +//| See also ~ulab.extras.spectrum, which computes the magnitude of the fft, +//| rather than separately returning its real and imaginary parts.""" +//| ... +//| +static mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) { + if(n_args == 2) { + return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_FFT); + } else { + return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_FFT); + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft); + +//| def ifft(r: ulab.ndarray, c: Optional[ulab.ndarray] = None) -> Tuple[ulab.ndarray, ulab.ndarray]: +//| """ +//| :param ulab.ndarray r: A 1-dimension array of values whose size is a power of 2 +//| :param ulab.ndarray c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value +//| :return tuple (r, c): The real and complex parts of the inverse FFT +//| +//| Perform an Inverse Fast Fourier Transform from the frequeny domain into the time domain""" +//| ... +//| + +static mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { + if(n_args == 2) { + return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_IFFT); + } else { + return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_IFFT); + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft); + +STATIC const mp_rom_map_elem_t ulab_fft_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_fft) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_fft), (mp_obj_t)&fft_fft_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ifft), (mp_obj_t)&fft_ifft_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table); + +mp_obj_module_t ulab_fft_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_fft_globals, +}; diff --git a/python/port/mod/ulab/numpy/fft/fft.h b/python/port/mod/ulab/numpy/fft/fft.h new file mode 100644 index 000000000..66acafe11 --- /dev/null +++ b/python/port/mod/ulab/numpy/fft/fft.h @@ -0,0 +1,24 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _FFT_ +#define _FFT_ + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "../../ndarray.h" +#include "fft_tools.h" + +extern mp_obj_module_t ulab_fft_module; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj); +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj); +#endif diff --git a/python/port/mod/ulab/numpy/fft/fft_tools.c b/python/port/mod/ulab/numpy/fft/fft_tools.c new file mode 100644 index 000000000..ab737a850 --- /dev/null +++ b/python/port/mod/ulab/numpy/fft/fft_tools.c @@ -0,0 +1,165 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#include +#include + +#include "../../ndarray.h" +#include "../../ulab_tools.h" +#include "fft_tools.h" + +#ifndef MP_PI +#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) +#endif +#ifndef MP_E +#define MP_E MICROPY_FLOAT_CONST(2.71828182845904523536) +#endif + +/* + * The following function takes two arrays, namely, the real and imaginary + * parts of a complex array, and calculates the Fourier transform in place. + * + * The function is basically a modification of four1 from Numerical Recipes, + * has no dependencies beyond micropython itself (for the definition of mp_float_t), + * and can be used independent of ulab. + */ + +void fft_kernel(mp_float_t *real, mp_float_t *imag, size_t n, int isign) { + size_t j, m, mmax, istep; + mp_float_t tempr, tempi; + mp_float_t wtemp, wr, wpr, wpi, wi, theta; + + j = 0; + for(size_t i = 0; i < n; i++) { + if (j > i) { + SWAP(mp_float_t, real[i], real[j]); + SWAP(mp_float_t, imag[i], imag[j]); + } + m = n >> 1; + while (j >= m && m > 0) { + j -= m; + m >>= 1; + } + j += m; + } + + mmax = 1; + while (n > mmax) { + istep = mmax << 1; + theta = MICROPY_FLOAT_CONST(-2.0)*isign*MP_PI/istep; + wtemp = MICROPY_FLOAT_C_FUN(sin)(MICROPY_FLOAT_CONST(0.5) * theta); + wpr = MICROPY_FLOAT_CONST(-2.0) * wtemp * wtemp; + wpi = MICROPY_FLOAT_C_FUN(sin)(theta); + wr = MICROPY_FLOAT_CONST(1.0); + wi = MICROPY_FLOAT_CONST(0.0); + for(m = 0; m < mmax; m++) { + for(size_t i = m; i < n; i += istep) { + j = i + mmax; + tempr = wr * real[j] - wi * imag[j]; + tempi = wr * imag[j] + wi * real[j]; + real[j] = real[i] - tempr; + imag[j] = imag[i] - tempi; + real[i] += tempr; + imag[i] += tempi; + } + wtemp = wr; + wr = wr*wpr - wi*wpi + wr; + wi = wi*wpr + wtemp*wpi + wi; + } + mmax = istep; + } +} + +/* + * The following function is a helper interface to the python side. + * It has been factored out from fft.c, so that the same argument parsing + * routine can be called from scipy.signal.spectrogram. + */ + +mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { + if(!mp_obj_is_type(arg_re, &ulab_ndarray_type)) { + mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); + } + if(n_args == 2) { + if(!mp_obj_is_type(arg_im, &ulab_ndarray_type)) { + mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); + } + } + ndarray_obj_t *re = MP_OBJ_TO_PTR(arg_re); + #if ULAB_MAX_DIMS > 1 + if(re->ndim != 1) { + mp_raise_TypeError(translate("FFT is implemented for linear arrays only")); + } + #endif + size_t len = re->len; + // Check if input is of length of power of 2 + if((len & (len-1)) != 0) { + mp_raise_ValueError(translate("input array length must be power of 2")); + } + + ndarray_obj_t *out_re = ndarray_new_linear_array(len, NDARRAY_FLOAT); + mp_float_t *data_re = (mp_float_t *)out_re->array; + + uint8_t *array = (uint8_t *)re->array; + mp_float_t (*func)(void *) = ndarray_get_float_function(re->dtype); + + for(size_t i=0; i < len; i++) { + *data_re++ = func(array); + array += re->strides[ULAB_MAX_DIMS - 1]; + } + data_re -= len; + ndarray_obj_t *out_im = ndarray_new_linear_array(len, NDARRAY_FLOAT); + mp_float_t *data_im = (mp_float_t *)out_im->array; + + if(n_args == 2) { + ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im); + #if ULAB_MAX_DIMS > 1 + if(im->ndim != 1) { + mp_raise_TypeError(translate("FFT is implemented for linear arrays only")); + } + #endif + if (re->len != im->len) { + mp_raise_ValueError(translate("real and imaginary parts must be of equal length")); + } + array = (uint8_t *)im->array; + func = ndarray_get_float_function(im->dtype); + for(size_t i=0; i < len; i++) { + *data_im++ = func(array); + array += im->strides[ULAB_MAX_DIMS - 1]; + } + data_im -= len; + } + + if((type == FFT_FFT) || (type == FFT_SPECTROGRAM)) { + fft_kernel(data_re, data_im, len, 1); + if(type == FFT_SPECTROGRAM) { + for(size_t i=0; i < len; i++) { + *data_re = MICROPY_FLOAT_C_FUN(sqrt)(*data_re * *data_re + *data_im * *data_im); + data_re++; + data_im++; + } + } + } else { // inverse transform + fft_kernel(data_re, data_im, len, -1); + // TODO: numpy accepts the norm keyword argument + for(size_t i=0; i < len; i++) { + *data_re++ /= len; + *data_im++ /= len; + } + } + if(type == FFT_SPECTROGRAM) { + return MP_OBJ_TO_PTR(out_re); + } else { + mp_obj_t tuple[2]; + tuple[0] = out_re; + tuple[1] = out_im; + return mp_obj_new_tuple(2, tuple); + } +} diff --git a/python/port/mod/ulab/numpy/fft/fft_tools.h b/python/port/mod/ulab/numpy/fft/fft_tools.h new file mode 100644 index 000000000..d3b856d07 --- /dev/null +++ b/python/port/mod/ulab/numpy/fft/fft_tools.h @@ -0,0 +1,23 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _FFT_TOOLS_ +#define _FFT_TOOLS_ + +enum FFT_TYPE { + FFT_FFT, + FFT_IFFT, + FFT_SPECTROGRAM, +}; + +void fft_kernel(mp_float_t *, mp_float_t *, size_t , int ); +mp_obj_t fft_fft_ifft_spectrogram(size_t , mp_obj_t , mp_obj_t , uint8_t ); + +#endif /* _FFT_TOOLS_ */ diff --git a/python/port/mod/ulab/numpy/filter/filter.c b/python/port/mod/ulab/numpy/filter/filter.c new file mode 100644 index 000000000..9be43946b --- /dev/null +++ b/python/port/mod/ulab/numpy/filter/filter.c @@ -0,0 +1,84 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../scipy/signal/signal.h" +#include "filter.h" + +#if ULAB_NUMPY_HAS_CONVOLVE + +mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_v, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type) || !mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("convolve arguments must be ndarrays")); + } + + ndarray_obj_t *a = MP_OBJ_TO_PTR(args[0].u_obj); + ndarray_obj_t *c = MP_OBJ_TO_PTR(args[1].u_obj); + // deal with linear arrays only + #if ULAB_MAX_DIMS > 1 + if((a->ndim != 1) || (c->ndim != 1)) { + mp_raise_TypeError(translate("convolve arguments must be linear arrays")); + } + #endif + size_t len_a = a->len; + size_t len_c = c->len; + if(len_a == 0 || len_c == 0) { + mp_raise_TypeError(translate("convolve arguments must not be empty")); + } + + int len = len_a + len_c - 1; // convolve mode "full" + ndarray_obj_t *out = ndarray_new_linear_array(len, NDARRAY_FLOAT); + mp_float_t *outptr = (mp_float_t *)out->array; + uint8_t *aarray = (uint8_t *)a->array; + uint8_t *carray = (uint8_t *)c->array; + + int32_t off = len_c - 1; + int32_t as = a->strides[ULAB_MAX_DIMS - 1] / a->itemsize; + int32_t cs = c->strides[ULAB_MAX_DIMS - 1] / c->itemsize; + + for(int32_t k=-off; k < len-off; k++) { + mp_float_t accum = (mp_float_t)0.0; + int32_t top_n = MIN(len_c, len_a - k); + int32_t bot_n = MAX(-k, 0); + for(int32_t n=bot_n; n < top_n; n++) { + int32_t idx_c = (len_c - n - 1) * cs; + int32_t idx_a = (n + k) * as; + mp_float_t ai = ndarray_get_float_index(aarray, a->dtype, idx_a); + mp_float_t ci = ndarray_get_float_index(carray, c->dtype, idx_c); + accum += ai * ci; + } + *outptr++ = accum; + } + + return out; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve); + +#endif diff --git a/python/port/mod/ulab/numpy/filter/filter.h b/python/port/mod/ulab/numpy/filter/filter.h new file mode 100644 index 000000000..9b1ad1875 --- /dev/null +++ b/python/port/mod/ulab/numpy/filter/filter.h @@ -0,0 +1,20 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020-2021 Zoltán Vörös +*/ + +#ifndef _FILTER_ +#define _FILTER_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +MP_DECLARE_CONST_FUN_OBJ_KW(filter_convolve_obj); +#endif diff --git a/python/port/mod/ulab/numpy/linalg/linalg.c b/python/port/mod/ulab/numpy/linalg/linalg.c new file mode 100644 index 000000000..209330f86 --- /dev/null +++ b/python/port/mod/ulab/numpy/linalg/linalg.c @@ -0,0 +1,397 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Roberto Colistete Jr. + * 2020 Taku Fukada + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "linalg.h" + +#if ULAB_NUMPY_HAS_LINALG_MODULE +//| +//| import ulab.numpy +//| +//| """Linear algebra functions""" +//| + +#if ULAB_MAX_DIMS > 1 +//| def cholesky(A: ulab.numpy.ndarray) -> ulab.numpy.ndarray: +//| """ +//| :param ~ulab.numpy.ndarray A: a positive definite, symmetric square matrix +//| :return ~ulab.numpy.ndarray L: a square root matrix in the lower triangular form +//| :raises ValueError: If the input does not fulfill the necessary conditions +//| +//| The returned matrix satisfies the equation m=LL*""" +//| ... +//| + +static mp_obj_t linalg_cholesky(mp_obj_t oin) { + ndarray_obj_t *ndarray = tools_object_is_square(oin); + ndarray_obj_t *L = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, ndarray->shape[ULAB_MAX_DIMS - 1], ndarray->shape[ULAB_MAX_DIMS - 1]), NDARRAY_FLOAT); + mp_float_t *Larray = (mp_float_t *)L->array; + + size_t N = ndarray->shape[ULAB_MAX_DIMS - 1]; + uint8_t *array = (uint8_t *)ndarray->array; + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + + for(size_t m=0; m < N; m++) { // rows + for(size_t n=0; n < N; n++) { // columns + *Larray++ = func(array); + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + } + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * N; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + } + Larray -= N*N; + // make sure the matrix is symmetric + for(size_t m=0; m < N; m++) { // rows + for(size_t n=m+1; n < N; n++) { // columns + // compare entry (m, n) to (n, m) + if(LINALG_EPSILON < MICROPY_FLOAT_C_FUN(fabs)(Larray[m * N + n] - Larray[n * N + m])) { + mp_raise_ValueError(translate("input matrix is asymmetric")); + } + } + } + + // this is actually not needed, but Cholesky in numpy returns the lower triangular matrix + for(size_t i=0; i < N; i++) { // rows + for(size_t j=i+1; j < N; j++) { // columns + Larray[i*N + j] = MICROPY_FLOAT_CONST(0.0); + } + } + mp_float_t sum = 0.0; + for(size_t i=0; i < N; i++) { // rows + for(size_t j=0; j <= i; j++) { // columns + sum = Larray[i * N + j]; + for(size_t k=0; k < j; k++) { + sum -= Larray[i * N + k] * Larray[j * N + k]; + } + if(i == j) { + if(sum <= MICROPY_FLOAT_CONST(0.0)) { + mp_raise_ValueError(translate("matrix is not positive definite")); + } else { + Larray[i * N + i] = MICROPY_FLOAT_C_FUN(sqrt)(sum); + } + } else { + Larray[i * N + j] = sum / Larray[j * N + j]; + } + } + } + return MP_OBJ_FROM_PTR(L); +} + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky); + +//| def det(m: ulab.numpy.ndarray) -> float: +//| """ +//| :param: m, a square matrix +//| :return float: The determinant of the matrix +//| +//| Computes the eigenvalues and eigenvectors of a square matrix""" +//| ... +//| + +static mp_obj_t linalg_det(mp_obj_t oin) { + ndarray_obj_t *ndarray = tools_object_is_square(oin); + uint8_t *array = (uint8_t *)ndarray->array; + size_t N = ndarray->shape[ULAB_MAX_DIMS - 1]; + mp_float_t *tmp = m_new(mp_float_t, N * N); + for(size_t m=0; m < N; m++) { // rows + for(size_t n=0; n < N; n++) { // columns + *tmp++ = ndarray_get_float_value(array, ndarray->dtype); + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + } + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * N; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + } + + // re-wind the pointer + tmp -= N*N; + + mp_float_t c; + mp_float_t det_sign = 1.0; + + for(size_t m=0; m < N-1; m++){ + if(MICROPY_FLOAT_C_FUN(fabs)(tmp[m * (N+1)]) < LINALG_EPSILON) { + size_t m1 = m + 1; + for(; m1 < N; m1++) { + if(!(MICROPY_FLOAT_C_FUN(fabs)(tmp[m1*N+m]) < LINALG_EPSILON)) { + //look for a line to swap + for(size_t m2=0; m2 < N; m2++) { + mp_float_t swapVal = tmp[m*N+m2]; + tmp[m*N+m2] = tmp[m1*N+m2]; + tmp[m1*N+m2] = swapVal; + } + det_sign = -det_sign; + break; + } + } + if (m1 >= N) { + m_del(mp_float_t, tmp, N * N); + return mp_obj_new_float(0.0); + } + } + for(size_t n=0; n < N; n++) { + if(m != n) { + c = tmp[N * n + m] / tmp[m * (N+1)]; + for(size_t k=0; k < N; k++){ + tmp[N * n + k] -= c * tmp[N * m + k]; + } + } + } + } + mp_float_t det = det_sign; + + for(size_t m=0; m < N; m++){ + det *= tmp[m * (N+1)]; + } + m_del(mp_float_t, tmp, N * N); + return mp_obj_new_float(det); +} + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det); + +#endif + +#if ULAB_MAX_DIMS > 1 +//| def eig(m: ulab.numpy.ndarray) -> Tuple[ulab.numpy.ndarray, ulab.numpy.ndarray]: +//| """ +//| :param m: a square matrix +//| :return tuple (eigenvectors, eigenvalues): +//| +//| Computes the eigenvalues and eigenvectors of a square matrix""" +//| ... +//| + +static mp_obj_t linalg_eig(mp_obj_t oin) { + ndarray_obj_t *in = tools_object_is_square(oin); + uint8_t *iarray = (uint8_t *)in->array; + size_t S = in->shape[ULAB_MAX_DIMS - 1]; + mp_float_t *array = m_new(mp_float_t, S*S); + for(size_t i=0; i < S; i++) { // rows + for(size_t j=0; j < S; j++) { // columns + *array++ = ndarray_get_float_value(iarray, in->dtype); + iarray += in->strides[ULAB_MAX_DIMS - 1]; + } + iarray -= in->strides[ULAB_MAX_DIMS - 1] * S; + iarray += in->strides[ULAB_MAX_DIMS - 2]; + } + array -= S * S; + // make sure the matrix is symmetric + for(size_t m=0; m < S; m++) { + for(size_t n=m+1; n < S; n++) { + // compare entry (m, n) to (n, m) + // TODO: this must probably be scaled! + if(LINALG_EPSILON < MICROPY_FLOAT_C_FUN(fabs)(array[m * S + n] - array[n * S + m])) { + mp_raise_ValueError(translate("input matrix is asymmetric")); + } + } + } + + // if we got this far, then the matrix will be symmetric + + ndarray_obj_t *eigenvectors = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, S, S), NDARRAY_FLOAT); + mp_float_t *eigvectors = (mp_float_t *)eigenvectors->array; + + size_t iterations = linalg_jacobi_rotations(array, eigvectors, S); + + if(iterations == 0) { + // the computation did not converge; numpy raises LinAlgError + m_del(mp_float_t, array, in->len); + mp_raise_ValueError(translate("iterations did not converge")); + } + ndarray_obj_t *eigenvalues = ndarray_new_linear_array(S, NDARRAY_FLOAT); + mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array; + for(size_t i=0; i < S; i++) { + eigvalues[i] = array[i * (S + 1)]; + } + m_del(mp_float_t, array, in->len); + + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + tuple->items[0] = MP_OBJ_FROM_PTR(eigenvalues); + tuple->items[1] = MP_OBJ_FROM_PTR(eigenvectors); + return tuple; +} + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig); + +//| def inv(m: ulab.numpy.ndarray) -> ulab.numpy.ndarray: +//| """ +//| :param ~ulab.numpy.ndarray m: a square matrix +//| :return: The inverse of the matrix, if it exists +//| :raises ValueError: if the matrix is not invertible +//| +//| Computes the inverse of a square matrix""" +//| ... +//| +static mp_obj_t linalg_inv(mp_obj_t o_in) { + ndarray_obj_t *ndarray = tools_object_is_square(o_in); + uint8_t *array = (uint8_t *)ndarray->array; + size_t N = ndarray->shape[ULAB_MAX_DIMS - 1]; + ndarray_obj_t *inverted = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, N, N), NDARRAY_FLOAT); + mp_float_t *iarray = (mp_float_t *)inverted->array; + + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + + for(size_t i=0; i < N; i++) { // rows + for(size_t j=0; j < N; j++) { // columns + *iarray++ = func(array); + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + } + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * N; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + } + // re-wind the pointer + iarray -= N*N; + + if(!linalg_invert_matrix(iarray, N)) { + mp_raise_ValueError(translate("input matrix is singular")); + } + return MP_OBJ_FROM_PTR(inverted); +} + +MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv); +#endif + +//| def norm(x: ulab.numpy.ndarray) -> float: +//| """ +//| :param ~ulab.numpy.ndarray x: a vector or a matrix +//| +//| Computes the 2-norm of a vector or a matrix, i.e., ``sqrt(sum(x*x))``, however, without the RAM overhead.""" +//| ... +//| + +static mp_obj_t linalg_norm(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_const_none} } , + { MP_QSTR_axis, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t x = args[0].u_obj; + mp_obj_t axis = args[1].u_obj; + + mp_float_t dot = 0.0, value; + size_t count = 1; + + if(mp_obj_is_type(x, &mp_type_tuple) || mp_obj_is_type(x, &mp_type_list) || mp_obj_is_type(x, &mp_type_range)) { + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(x, &iter_buf); + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + value = mp_obj_get_float(item); + // we could simply take the sum of value ** 2, + // but this method is numerically stable + dot = dot + (value * value - dot) / count++; + } + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(dot * (count - 1))); + } else if(mp_obj_is_type(x, &ulab_ndarray_type)) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(x); + uint8_t *array = (uint8_t *)ndarray->array; + // always get a float, so that we don't have to resolve the dtype later + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + shape_strides _shape_strides = tools_reduce_axes(ndarray, axis); + ndarray_obj_t *results = ndarray_new_dense_ndarray(_shape_strides.ndim, _shape_strides.shape, NDARRAY_FLOAT); + mp_float_t *rarray = (mp_float_t *)results->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; + if(axis != mp_const_none) { + count = 1; + dot = 0.0; + } + do { + value = func(array); + dot = dot + (value * value - dot) / count++; + array += _shape_strides.strides[0]; + l++; + } while(l < _shape_strides.shape[0]); + *rarray = MICROPY_FLOAT_C_FUN(sqrt)(dot * (count - 1)); + #if ULAB_MAX_DIMS > 1 + rarray += _shape_strides.increment; + array -= _shape_strides.strides[0] * _shape_strides.shape[0]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 1]; + k++; + } while(k < _shape_strides.shape[ULAB_MAX_DIMS - 1]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 1] * _shape_strides.shape[ULAB_MAX_DIMS - 1]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 2]; + j++; + } while(j < _shape_strides.shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 2] * _shape_strides.shape[ULAB_MAX_DIMS - 2]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 3]; + i++; + } while(i < _shape_strides.shape[ULAB_MAX_DIMS - 3]); + #endif + if(results->ndim == 0) { + return mp_obj_new_float(*rarray); + } + return results; + } + return mp_const_none; // we should never reach this point +} + +MP_DEFINE_CONST_FUN_OBJ_KW(linalg_norm_obj, 1, linalg_norm); +// MP_DEFINE_CONST_FUN_OBJ_1(linalg_norm_obj, linalg_norm); + +STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) }, + #if ULAB_MAX_DIMS > 1 + #if ULAB_LINALG_HAS_CHOLESKY + { MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj }, + #endif + #if ULAB_LINALG_HAS_DET + { MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj }, + #endif + #if ULAB_LINALG_HAS_EIG + { MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj }, + #endif + #if ULAB_LINALG_HAS_INV + { MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj }, + #endif + #endif + #if ULAB_LINALG_HAS_NORM + { MP_ROM_QSTR(MP_QSTR_norm), (mp_obj_t)&linalg_norm_obj }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table); + +mp_obj_module_t ulab_linalg_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_linalg_globals, +}; + +#endif diff --git a/python/port/mod/ulab/numpy/linalg/linalg.h b/python/port/mod/ulab/numpy/linalg/linalg.h new file mode 100644 index 000000000..fc1867fb8 --- /dev/null +++ b/python/port/mod/ulab/numpy/linalg/linalg.h @@ -0,0 +1,26 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _LINALG_ +#define _LINALG_ + +#include "../../ulab.h" +#include "../../ndarray.h" +#include "linalg_tools.h" + +extern mp_obj_module_t ulab_linalg_module; + +MP_DECLARE_CONST_FUN_OBJ_1(linalg_cholesky_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_eig_obj); +MP_DECLARE_CONST_FUN_OBJ_1(linalg_inv_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(linalg_norm_obj); +#endif diff --git a/python/port/mod/ulab/numpy/linalg/linalg_tools.c b/python/port/mod/ulab/numpy/linalg/linalg_tools.c new file mode 100644 index 000000000..cf48f1140 --- /dev/null +++ b/python/port/mod/ulab/numpy/linalg/linalg_tools.c @@ -0,0 +1,171 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2010 Zoltán Vörös +*/ + +#include +#include +#include + +#include "linalg_tools.h" + +/* + * The following function inverts a matrix, whose entries are given in the input array + * The function has no dependencies beyond micropython itself (for the definition of mp_float_t), + * and can be used independent of ulab. + */ + +bool linalg_invert_matrix(mp_float_t *data, size_t N) { + // returns true, of the inversion was successful, + // false, if the matrix is singular + + // initially, this is the unit matrix: the contents of this matrix is what + // will be returned after all the transformations + mp_float_t *unit = m_new(mp_float_t, N*N); + mp_float_t elem = 1.0; + // initialise the unit matrix + memset(unit, 0, sizeof(mp_float_t)*N*N); + for(size_t m=0; m < N; m++) { + memcpy(&unit[m * (N+1)], &elem, sizeof(mp_float_t)); + } + for(size_t m=0; m < N; m++){ + // this could be faster with ((c < epsilon) && (c > -epsilon)) + if(MICROPY_FLOAT_C_FUN(fabs)(data[m * (N+1)]) < LINALG_EPSILON) { + //look for a line to swap + size_t m1 = m + 1; + for(; m1 < N; m1++) { + if(!(MICROPY_FLOAT_C_FUN(fabs)(data[m1*N + m]) < LINALG_EPSILON)) { + for(size_t m2=0; m2 < N; m2++) { + mp_float_t swapVal = data[m*N+m2]; + data[m*N+m2] = data[m1*N+m2]; + data[m1*N+m2] = swapVal; + swapVal = unit[m*N+m2]; + unit[m*N+m2] = unit[m1*N+m2]; + unit[m1*N+m2] = swapVal; + } + break; + } + } + if (m1 >= N) { + m_del(mp_float_t, unit, N*N); + return false; + } + } + for(size_t n=0; n < N; n++) { + if(m != n){ + elem = data[N * n + m] / data[m * (N+1)]; + for(size_t k=0; k < N; k++) { + data[N * n + k] -= elem * data[N * m + k]; + unit[N * n + k] -= elem * unit[N * m + k]; + } + } + } + } + for(size_t m=0; m < N; m++) { + elem = data[m * (N+1)]; + for(size_t n=0; n < N; n++) { + data[N * m + n] /= elem; + unit[N * m + n] /= elem; + } + } + memcpy(data, unit, sizeof(mp_float_t)*N*N); + m_del(mp_float_t, unit, N * N); + return true; +} + +/* + * The following function calculates the eigenvalues and eigenvectors of a symmetric + * real matrix, whose entries are given in the input array. + * The function has no dependencies beyond micropython itself (for the definition of mp_float_t), + * and can be used independent of ulab. + */ + +size_t linalg_jacobi_rotations(mp_float_t *array, mp_float_t *eigvectors, size_t S) { + // eigvectors should be a 0-array; start out with the unit matrix + for(size_t m=0; m < S; m++) { + eigvectors[m * (S+1)] = 1.0; + } + mp_float_t largest, w, t, c, s, tau, aMk, aNk, vm, vn; + size_t M, N; + size_t iterations = JACOBI_MAX * S * S; + do { + iterations--; + // find the pivot here + M = 0; + N = 0; + largest = 0.0; + for(size_t m=0; m < S-1; m++) { // -1: no need to inspect last row + for(size_t n=m+1; n < S; n++) { + w = MICROPY_FLOAT_C_FUN(fabs)(array[m * S + n]); + if((largest < w) && (LINALG_EPSILON < w)) { + M = m; + N = n; + largest = w; + } + } + } + if(M + N == 0) { // all entries are smaller than epsilon, there is not much we can do... + break; + } + // at this point, we have the pivot, and it is the entry (M, N) + // now we have to find the rotation angle + w = (array[N * S + N] - array[M * S + M]) / (MICROPY_FLOAT_CONST(2.0)*array[M * S + N]); + // The following if/else chooses the smaller absolute value for the tangent + // of the rotation angle. Going with the smaller should be numerically stabler. + if(w > 0) { + t = MICROPY_FLOAT_C_FUN(sqrt)(w*w + MICROPY_FLOAT_CONST(1.0)) - w; + } else { + t = MICROPY_FLOAT_CONST(-1.0)*(MICROPY_FLOAT_C_FUN(sqrt)(w*w + MICROPY_FLOAT_CONST(1.0)) + w); + } + s = t / MICROPY_FLOAT_C_FUN(sqrt)(t*t + MICROPY_FLOAT_CONST(1.0)); // the sine of the rotation angle + c = MICROPY_FLOAT_CONST(1.0) / MICROPY_FLOAT_C_FUN(sqrt)(t*t + MICROPY_FLOAT_CONST(1.0)); // the cosine of the rotation angle + tau = (MICROPY_FLOAT_CONST(1.0)-c)/s; // this is equal to the tangent of the half of the rotation angle + + // at this point, we have the rotation angles, so we can transform the matrix + // first the two diagonal elements + // a(M, M) = a(M, M) - t*a(M, N) + array[M * S + M] = array[M * S + M] - t * array[M * S + N]; + // a(N, N) = a(N, N) + t*a(M, N) + array[N * S + N] = array[N * S + N] + t * array[M * S + N]; + // after the rotation, the a(M, N), and a(N, M) entries should become zero + array[M * S + N] = array[N * S + M] = MICROPY_FLOAT_CONST(0.0); + // then all other elements in the column + for(size_t k=0; k < S; k++) { + if((k == M) || (k == N)) { + continue; + } + aMk = array[M * S + k]; + aNk = array[N * S + k]; + // a(M, k) = a(M, k) - s*(a(N, k) + tau*a(M, k)) + array[M * S + k] -= s * (aNk + tau * aMk); + // a(N, k) = a(N, k) + s*(a(M, k) - tau*a(N, k)) + array[N * S + k] += s * (aMk - tau * aNk); + // a(k, M) = a(M, k) + array[k * S + M] = array[M * S + k]; + // a(k, N) = a(N, k) + array[k * S + N] = array[N * S + k]; + } + // now we have to update the eigenvectors + // the rotation matrix, R, multiplies from the right + // R is the unit matrix, except for the + // R(M,M) = R(N, N) = c + // R(N, M) = s + // (M, N) = -s + // entries. This means that only the Mth, and Nth columns will change + for(size_t m=0; m < S; m++) { + vm = eigvectors[m * S + M]; + vn = eigvectors[m * S + N]; + // the new value of eigvectors(m, M) + eigvectors[m * S + M] = c * vm - s * vn; + // the new value of eigvectors(m, N) + eigvectors[m * S + N] = s * vm + c * vn; + } + } while(iterations > 0); + + return iterations; +} diff --git a/python/port/mod/ulab/numpy/linalg/linalg_tools.h b/python/port/mod/ulab/numpy/linalg/linalg_tools.h new file mode 100644 index 000000000..942da001c --- /dev/null +++ b/python/port/mod/ulab/numpy/linalg/linalg_tools.h @@ -0,0 +1,28 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _TOOLS_TOOLS_ +#define _TOOLS_TOOLS_ + +#ifndef LINALG_EPSILON +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define LINALG_EPSILON MICROPY_FLOAT_CONST(1.2e-7) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define LINALG_EPSILON MICROPY_FLOAT_CONST(2.3e-16) +#endif +#endif /* LINALG_EPSILON */ + +#define JACOBI_MAX 20 + +bool linalg_invert_matrix(mp_float_t *, size_t ); +size_t linalg_jacobi_rotations(mp_float_t *, mp_float_t *, size_t ); + +#endif /* _TOOLS_TOOLS_ */ + diff --git a/python/port/mod/ulab/numpy/numerical/numerical.c b/python/port/mod/ulab/numpy/numerical/numerical.c new file mode 100644 index 000000000..af9ff1c02 --- /dev/null +++ b/python/port/mod/ulab/numpy/numerical/numerical.c @@ -0,0 +1,1338 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "numerical.h" + +enum NUMERICAL_FUNCTION_TYPE { + NUMERICAL_ALL, + NUMERICAL_ANY, + NUMERICAL_ARGMAX, + NUMERICAL_ARGMIN, + NUMERICAL_MAX, + NUMERICAL_MEAN, + NUMERICAL_MIN, + NUMERICAL_STD, + NUMERICAL_SUM, +}; + +//| """Numerical and Statistical functions +//| +//| Most of these functions take an "axis" argument, which indicates whether to +//| operate over the flattened array (None), or a particular axis (integer).""" +//| +//| from ulab import _ArrayLike +//| + +static void numerical_reduce_axes(ndarray_obj_t *ndarray, int8_t axis, size_t *shape, int32_t *strides) { + // removes the values corresponding to a single axis from the shape and strides array + uint8_t index = ULAB_MAX_DIMS - ndarray->ndim + axis; + if((ndarray->ndim == 1) && (axis == 0)) { + index = 0; + shape[ULAB_MAX_DIMS - 1] = 1; + return; + } + for(uint8_t i = ULAB_MAX_DIMS - 1; i > 0; i--) { + if(i > index) { + shape[i] = ndarray->shape[i]; + strides[i] = ndarray->strides[i]; + } else { + shape[i] = ndarray->shape[i-1]; + strides[i] = ndarray->strides[i-1]; + } + } +} + +#if ULAB_NUMPY_HAS_ALL | ULAB_NUMPY_HAS_ANY +static mp_obj_t numerical_all_any(mp_obj_t oin, mp_obj_t axis, uint8_t optype) { + bool anytype = optype == NUMERICAL_ALL ? 1 : 0; + if(mp_obj_is_type(oin, &ulab_ndarray_type)) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); + uint8_t *array = (uint8_t *)ndarray->array; + if(ndarray->len == 0) { // return immediately with empty arrays + if(optype == NUMERICAL_ALL) { + return mp_const_true; + } else { + return mp_const_false; + } + } + // always get a float, so that we don't have to resolve the dtype later + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + ndarray_obj_t *results = NULL; + uint8_t *rarray = NULL; + shape_strides _shape_strides = tools_reduce_axes(ndarray, axis); + if(axis != mp_const_none) { + results = ndarray_new_dense_ndarray(_shape_strides.ndim, _shape_strides.shape, NDARRAY_BOOL); + rarray = results->array; + if(optype == NUMERICAL_ALL) { + memset(rarray, 1, results->len); + } + } + + #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; + if(axis == mp_const_none) { + do { + mp_float_t value = func(array); + if((value != MICROPY_FLOAT_CONST(0.0)) & !anytype) { + // optype = NUMERICAL_ANY + return mp_const_true; + } else if((value == MICROPY_FLOAT_CONST(0.0)) & anytype) { + // optype == NUMERICAL_ALL + return mp_const_false; + } + array += _shape_strides.strides[0]; + l++; + } while(l < _shape_strides.shape[0]); + } else { // a scalar axis keyword was supplied + do { + mp_float_t value = func(array); + if((value != MICROPY_FLOAT_CONST(0.0)) & !anytype) { + // optype == NUMERICAL_ANY + *rarray = 1; + // since we are breaking out of the loop, move the pointer forward + array += _shape_strides.strides[0] * (_shape_strides.shape[0] - l); + break; + } else if((value == MICROPY_FLOAT_CONST(0.0)) & anytype) { + // optype == NUMERICAL_ALL + *rarray = 0; + // since we are breaking out of the loop, move the pointer forward + array += _shape_strides.strides[0] * (_shape_strides.shape[0] - l); + break; + } + array += _shape_strides.strides[0]; + l++; + } while(l < _shape_strides.shape[0]); + } + #if ULAB_MAX_DIMS > 1 + rarray += _shape_strides.increment; + array -= _shape_strides.strides[0] * _shape_strides.shape[0]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 1]; + k++; + } while(k < _shape_strides.shape[ULAB_MAX_DIMS - 1]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 1] * _shape_strides.shape[ULAB_MAX_DIMS - 1]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 2]; + j++; + } while(j < _shape_strides.shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 2] * _shape_strides.shape[ULAB_MAX_DIMS - 2]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 3]; + i++; + } while(i < _shape_strides.shape[ULAB_MAX_DIMS - 3]) + #endif + return results; + } else if(mp_obj_is_int(oin) || mp_obj_is_float(oin)) { + return mp_obj_is_true(oin) ? mp_const_true : mp_const_false; + } else { + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(oin, &iter_buf); + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if(!mp_obj_is_true(item) & !anytype) { + return mp_const_false; + } else if(mp_obj_is_true(item) & anytype) { + return mp_const_true; + } + } + } + return anytype ? mp_const_true : mp_const_false; +} +#endif + +#if ULAB_NUMPY_HAS_SUM | ULAB_NUMPY_HAS_MEAN | ULAB_NUMPY_HAS_STD +static mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, size_t ddof) { + mp_float_t value = MICROPY_FLOAT_CONST(0.0); + mp_float_t M = MICROPY_FLOAT_CONST(0.0); + mp_float_t m = MICROPY_FLOAT_CONST(0.0); + mp_float_t S = MICROPY_FLOAT_CONST(0.0); + mp_float_t s = MICROPY_FLOAT_CONST(0.0); + size_t count = 0; + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(oin, &iter_buf); + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + value = mp_obj_get_float(item); + m = M + (value - M) / (count + 1); + s = S + (value - M) * (value - m); + M = m; + S = s; + count++; + } + if(optype == NUMERICAL_SUM) { + return mp_obj_new_float(m * count); + } else if(optype == NUMERICAL_MEAN) { + return count > 0 ? mp_obj_new_float(m) : mp_obj_new_float(MICROPY_FLOAT_CONST(0.0)); + } else { // this should be the case of the standard deviation + return count > ddof ? mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(s / (count - ddof))) : mp_obj_new_float(MICROPY_FLOAT_CONST(0.0)); + } +} + +static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype, size_t ddof) { + uint8_t *array = (uint8_t *)ndarray->array; + shape_strides _shape_strides = tools_reduce_axes(ndarray, axis); + + if(axis == mp_const_none) { + // work with the flattened array + if((optype == NUMERICAL_STD) && (ddof > ndarray->len)) { + // if there are too many degrees of freedom, there is no point in calculating anything + return mp_obj_new_float(MICROPY_FLOAT_CONST(0.0)); + } + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + mp_float_t M =MICROPY_FLOAT_CONST(0.0); + mp_float_t m = MICROPY_FLOAT_CONST(0.0); + mp_float_t S = MICROPY_FLOAT_CONST(0.0); + mp_float_t s = MICROPY_FLOAT_CONST(0.0); + size_t count = 0; + + #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 { + count++; + mp_float_t value = func(array); + m = M + (value - M) / (mp_float_t)count; + if(optype == NUMERICAL_STD) { + s = S + (value - M) * (value - m); + S = s; + } + M = m; + array += _shape_strides.strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < _shape_strides.shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 1] * _shape_strides.shape[ULAB_MAX_DIMS - 1]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < _shape_strides.shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 2] * _shape_strides.shape[ULAB_MAX_DIMS - 2]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < _shape_strides.shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= _shape_strides.strides[ULAB_MAX_DIMS - 3] * _shape_strides.shape[ULAB_MAX_DIMS - 3]; + array += _shape_strides.strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < _shape_strides.shape[ULAB_MAX_DIMS - 4]); + #endif + if(optype == NUMERICAL_SUM) { + // numpy returns an integer for integer input types + if(ndarray->dtype == NDARRAY_FLOAT) { + return mp_obj_new_float(M * ndarray->len); + } else { + return mp_obj_new_int((int32_t)(M * ndarray->len)); + } + } else if(optype == NUMERICAL_MEAN) { + return mp_obj_new_float(M); + } else { // this must be the case of the standard deviation + // we have already made certain that ddof < ndarray->len holds + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(S / (ndarray->len - ddof))); + } + } else { + ndarray_obj_t *results = NULL; + uint8_t *rarray = NULL; + mp_float_t *farray = NULL; + if(optype == NUMERICAL_SUM) { + results = ndarray_new_dense_ndarray(_shape_strides.ndim, _shape_strides.shape, ndarray->dtype); + rarray = (uint8_t *)results->array; + // TODO: numpy promotes the output to the highest integer type + if(ndarray->dtype == NDARRAY_UINT8) { + RUN_SUM(uint8_t, array, results, rarray, _shape_strides); + } else if(ndarray->dtype == NDARRAY_INT8) { + RUN_SUM(int8_t, array, results, rarray, _shape_strides); + } else if(ndarray->dtype == NDARRAY_UINT16) { + RUN_SUM(uint16_t, array, results, rarray, _shape_strides); + } else if(ndarray->dtype == NDARRAY_INT16) { + RUN_SUM(int16_t, array, results, rarray, _shape_strides); + } else { + // for floats, the sum might be inaccurate with the naive summation + // call mean, and multiply with the number of samples + farray = (mp_float_t *)results->array; + RUN_MEAN_STD(mp_float_t, array, farray, _shape_strides, MICROPY_FLOAT_CONST(0.0), 0); + mp_float_t norm = (mp_float_t)_shape_strides.shape[0]; + // re-wind the array here + farray = (mp_float_t *)results->array; + for(size_t i=0; i < results->len; i++) { + *farray++ *= norm; + } + } + } else { + bool isStd = optype == NUMERICAL_STD ? 1 : 0; + results = ndarray_new_dense_ndarray(_shape_strides.ndim, _shape_strides.shape, NDARRAY_FLOAT); + farray = (mp_float_t *)results->array; + // we can return the 0 array here, if the degrees of freedom is larger than the length of the axis + if((optype == NUMERICAL_STD) && (_shape_strides.shape[0] <= ddof)) { + return MP_OBJ_FROM_PTR(results); + } + mp_float_t div = optype == NUMERICAL_STD ? (mp_float_t)(_shape_strides.shape[0] - ddof) : MICROPY_FLOAT_CONST(0.0); + if(ndarray->dtype == NDARRAY_UINT8) { + RUN_MEAN_STD(uint8_t, array, farray, _shape_strides, div, isStd); + } else if(ndarray->dtype == NDARRAY_INT8) { + RUN_MEAN_STD(int8_t, array, farray, _shape_strides, div, isStd); + } else if(ndarray->dtype == NDARRAY_UINT16) { + RUN_MEAN_STD(uint16_t, array, farray, _shape_strides, div, isStd); + } else if(ndarray->dtype == NDARRAY_INT16) { + RUN_MEAN_STD(int16_t, array, farray, _shape_strides, div, isStd); + } else { + RUN_MEAN_STD(mp_float_t, array, farray, _shape_strides, div, isStd); + } + } + if(results->ndim == 0) { // return a scalar here + return mp_binary_get_val_array(results->dtype, results->array, 0); + } + return MP_OBJ_FROM_PTR(results); + } + return mp_const_none; +} +#endif + +#if ULAB_NUMPY_HAS_ARGMINMAX +static mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, uint8_t optype) { + if(MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(oin)) == 0) { + mp_raise_ValueError(translate("attempt to get argmin/argmax of an empty sequence")); + } + size_t idx = 0, best_idx = 0; + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(oin, &iter_buf); + mp_obj_t item; + uint8_t op = 0; // argmin, min + if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = 1; + item = mp_iternext(iterable); + mp_obj_t best_obj = item; + mp_float_t value, best_value = mp_obj_get_float(item); + value = best_value; + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + idx++; + value = mp_obj_get_float(item); + if((op == 0) && (value < best_value)) { + best_obj = item; + best_idx = idx; + best_value = value; + } else if((op == 1) && (value > best_value)) { + best_obj = item; + best_idx = idx; + best_value = value; + } + } + if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { + return MP_OBJ_NEW_SMALL_INT(best_idx); + } else { + return best_obj; + } +} + +static mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) { + // TODO: treat the flattened array + if(ndarray->len == 0) { + mp_raise_ValueError(translate("attempt to get (arg)min/(arg)max of empty sequence")); + } + + if(axis == mp_const_none) { + // work with the flattened array + mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype); + uint8_t *array = (uint8_t *)ndarray->array; + mp_float_t best_value = func(array); + mp_float_t value; + size_t index = 0, best_index = 0; + + #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 { + value = func(array); + if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) { + if(best_value < value) { + best_value = value; + best_index = index; + } + } else { + if(best_value > value) { + best_value = value; + best_index = index; + } + } + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + l++; + index++; + } while(l < ndarray->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1]; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < ndarray->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= ndarray->strides[ULAB_MAX_DIMS - 2] * ndarray->shape[ULAB_MAX_DIMS-2]; + array += ndarray->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < ndarray->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= ndarray->strides[ULAB_MAX_DIMS - 3] * ndarray->shape[ULAB_MAX_DIMS-3]; + array += ndarray->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < ndarray->shape[ULAB_MAX_DIMS - 4]); + #endif + + if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { + return mp_obj_new_int(best_index); + } else { + if(ndarray->dtype == NDARRAY_FLOAT) { + return mp_obj_new_float(best_value); + } else { + return MP_OBJ_NEW_SMALL_INT((int32_t)best_value); + } + } + } else { + int8_t ax = mp_obj_get_int(axis); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("axis is out of bounds")); + } + + uint8_t *array = (uint8_t *)ndarray->array; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(ndarray, ax, shape, strides); + uint8_t index = ULAB_MAX_DIMS - ndarray->ndim + ax; + + ndarray_obj_t *results = NULL; + + if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) { + results = ndarray_new_dense_ndarray(MAX(1, ndarray->ndim-1), shape, NDARRAY_INT16); + } else { + results = ndarray_new_dense_ndarray(MAX(1, ndarray->ndim-1), shape, ndarray->dtype); + } + + uint8_t *rarray = (uint8_t *)results->array; + + if(ndarray->dtype == NDARRAY_UINT8) { + RUN_ARGMIN(ndarray, uint8_t, array, results, rarray, shape, strides, index, optype); + } else if(ndarray->dtype == NDARRAY_INT8) { + RUN_ARGMIN(ndarray, int8_t, array, results, rarray, shape, strides, index, optype); + } else if(ndarray->dtype == NDARRAY_UINT16) { + RUN_ARGMIN(ndarray, uint16_t, array, results, rarray, shape, strides, index, optype); + } else if(ndarray->dtype == NDARRAY_INT16) { + RUN_ARGMIN(ndarray, int16_t, array, results, rarray, shape, strides, index, optype); + } else { + RUN_ARGMIN(ndarray, mp_float_t, array, results, rarray, shape, strides, index, optype); + } + if(results->len == 1) { + return mp_binary_get_val_array(results->dtype, results->array, 0); + } + return MP_OBJ_FROM_PTR(results); + } + return mp_const_none; +} +#endif + +static mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none} } , + { MP_QSTR_axis, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t oin = args[0].u_obj; + mp_obj_t axis = args[1].u_obj; + if((axis != mp_const_none) && (!mp_obj_is_int(axis))) { + mp_raise_TypeError(translate("axis must be None, or an integer")); + } + + if((optype == NUMERICAL_ALL) || (optype == NUMERICAL_ANY)) { + return numerical_all_any(oin, axis, optype); + } + if(mp_obj_is_type(oin, &mp_type_tuple) || mp_obj_is_type(oin, &mp_type_list) || + mp_obj_is_type(oin, &mp_type_range)) { + switch(optype) { + case NUMERICAL_MIN: + case NUMERICAL_ARGMIN: + case NUMERICAL_MAX: + case NUMERICAL_ARGMAX: + return numerical_argmin_argmax_iterable(oin, optype); + case NUMERICAL_SUM: + case NUMERICAL_MEAN: + return numerical_sum_mean_std_iterable(oin, optype, 0); + default: // we should never reach this point, but whatever + return mp_const_none; + } + } else if(mp_obj_is_type(oin, &ulab_ndarray_type)) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); + switch(optype) { + case NUMERICAL_MIN: + case NUMERICAL_MAX: + case NUMERICAL_ARGMIN: + case NUMERICAL_ARGMAX: + return numerical_argmin_argmax_ndarray(ndarray, axis, optype); + case NUMERICAL_SUM: + case NUMERICAL_MEAN: + return numerical_sum_mean_std_ndarray(ndarray, axis, optype, 0); + default: + mp_raise_NotImplementedError(translate("operation is not implemented on ndarrays")); + } + } else { + mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray")); + } + return mp_const_none; +} + +#if ULAB_NUMPY_HAS_SORT | NDARRAY_HAS_SORT +static mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) { + if(!mp_obj_is_type(oin, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("sort argument must be an ndarray")); + } + + ndarray_obj_t *ndarray; + if(inplace == 1) { + ndarray = MP_OBJ_TO_PTR(oin); + } else { + ndarray = ndarray_copy_view(MP_OBJ_TO_PTR(oin)); + } + + int8_t ax = 0; + if(axis == mp_const_none) { + // flatten the array + for(uint8_t i=0; i < ULAB_MAX_DIMS - 1; i++) { + ndarray->shape[i] = 0; + ndarray->strides[i] = 0; + } + ndarray->shape[ULAB_MAX_DIMS - 1] = ndarray->len; + ndarray->strides[ULAB_MAX_DIMS - 1] = ndarray->itemsize; + ndarray->ndim = 1; + } else { + ax = mp_obj_get_int(axis); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + } + + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(ndarray, ax, shape, strides); + ax = ULAB_MAX_DIMS - ndarray->ndim + ax; + // we work with the typed array, so re-scale the stride + int32_t increment = ndarray->strides[ax] / ndarray->itemsize; + + uint8_t *array = (uint8_t *)ndarray->array; + if((ndarray->dtype == NDARRAY_UINT8) || (ndarray->dtype == NDARRAY_INT8)) { + HEAPSORT(ndarray, uint8_t, array, shape, strides, ax, increment, ndarray->shape[ax]); + } else if((ndarray->dtype == NDARRAY_INT16) || (ndarray->dtype == NDARRAY_INT16)) { + HEAPSORT(ndarray, uint16_t, array, shape, strides, ax, increment, ndarray->shape[ax]); + } else { + HEAPSORT(ndarray, mp_float_t, array, shape, strides, ax, increment, ndarray->shape[ax]); + } + if(inplace == 1) { + return mp_const_none; + } else { + return MP_OBJ_FROM_PTR(ndarray); + } +} +#endif /* ULAB_NUMERICAL_HAS_SORT | NDARRAY_HAS_SORT */ + +#if ULAB_NUMPY_HAS_ALL +mp_obj_t numerical_all(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ALL); +} +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_all_obj, 1, numerical_all); +#endif + +#if ULAB_NUMPY_HAS_ANY +mp_obj_t numerical_any(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ANY); +} +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_any_obj, 1, numerical_any); +#endif + +#if ULAB_NUMPY_HAS_ARGMINMAX +//| def argmax(array: _ArrayLike, *, axis: Optional[int] = None) -> int: +//| """Return the index of the maximum element of the 1D array""" +//| ... +//| + +mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMAX); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax); + +//| def argmin(array: _ArrayLike, *, axis: Optional[int] = None) -> int: +//| """Return the index of the minimum element of the 1D array""" +//| ... +//| + +static mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMIN); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin); +#endif + +#if ULAB_NUMPY_HAS_ARGSORT +//| def argsort(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray: +//| """Returns an array which gives indices into the input array from least to greatest.""" +//| ... +//| + +mp_obj_t numerical_argsort(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("argsort argument must be an ndarray")); + } + + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); + if(args[1].u_obj == mp_const_none) { + // bail out, though dense arrays could still be sorted + mp_raise_NotImplementedError(translate("argsort is not implemented for flattened arrays")); + } + // Since we are returning an NDARRAY_UINT16 array, bail out, + // if the axis is longer than what we can hold + for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) { + if(ndarray->shape[i] > 65535) { + mp_raise_ValueError(translate("axis too long")); + } + } + int8_t ax = mp_obj_get_int(args[1].u_obj); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS); + 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); + int32_t *istrides = m_new(int32_t, ULAB_MAX_DIMS); + memset(istrides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(indices, ax, shape, istrides); + for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) { + istrides[i] /= sizeof(uint16_t); + } + + ax = ULAB_MAX_DIMS - ndarray->ndim + ax; + // we work with the typed array, so re-scale the stride + int32_t increment = ndarray->strides[ax] / ndarray->itemsize; + uint16_t iincrement = indices->strides[ax] / sizeof(uint16_t); + + uint8_t *array = (uint8_t *)ndarray->array; + uint16_t *iarray = (uint16_t *)indices->array; + + // fill in the index values + #if ULAB_MAX_DIMS > 3 + size_t j = 0; + do { + #endif + #if ULAB_MAX_DIMS > 2 + size_t k = 0; + do { + #endif + #if ULAB_MAX_DIMS > 1 + size_t l = 0; + do { + #endif + uint16_t m = 0; + do { + *iarray = m++; + iarray += iincrement; + } while(m < indices->shape[ax]); + #if ULAB_MAX_DIMS > 1 + iarray -= iincrement * indices->shape[ax]; + iarray += istrides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < shape[ULAB_MAX_DIMS - 1]); + iarray -= istrides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS - 1]; + iarray += istrides[ULAB_MAX_DIMS - 2]; + #endif + #if ULAB_MAX_DIMS > 2 + k++; + } while(k < shape[ULAB_MAX_DIMS - 2]); + iarray -= istrides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS - 2]; + iarray += istrides[ULAB_MAX_DIMS - 3]; + #endif + #if ULAB_MAX_DIMS > 3 + j++; + } while(j < shape[ULAB_MAX_DIMS - 3]); + #endif + // reset the array + iarray = indices->array; + + if((ndarray->dtype == NDARRAY_UINT8) || (ndarray->dtype == NDARRAY_INT8)) { + HEAP_ARGSORT(ndarray, uint8_t, array, shape, strides, ax, increment, ndarray->shape[ax], iarray, istrides, iincrement); + } else if((ndarray->dtype == NDARRAY_UINT16) || (ndarray->dtype == NDARRAY_INT16)) { + HEAP_ARGSORT(ndarray, uint16_t, array, shape, strides, ax, increment, ndarray->shape[ax], iarray, istrides, iincrement); + } else { + HEAP_ARGSORT(ndarray, mp_float_t, array, shape, strides, ax, increment, ndarray->shape[ax], iarray, istrides, iincrement); + } + return MP_OBJ_FROM_PTR(indices); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort); +#endif + +#if ULAB_NUMPY_HAS_CROSS +//| def cross(a: ulab.ndarray, b: ulab.ndarray) -> ulab.ndarray: +//| """Return the cross product of two vectors of length 3""" +//| ... +//| + +static mp_obj_t numerical_cross(mp_obj_t _a, mp_obj_t _b) { + if (!mp_obj_is_type(_a, &ulab_ndarray_type) || !mp_obj_is_type(_b, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("arguments must be ndarrays")); + } + ndarray_obj_t *a = MP_OBJ_TO_PTR(_a); + ndarray_obj_t *b = MP_OBJ_TO_PTR(_b); + if((a->ndim != 1) || (b->ndim != 1) || (a->len != b->len) || (a->len != 3)) { + mp_raise_ValueError(translate("cross is defined for 1D arrays of length 3")); + } + + mp_float_t *results = m_new(mp_float_t, 3); + results[0] = ndarray_get_float_index(a->array, a->dtype, 1) * ndarray_get_float_index(b->array, b->dtype, 2); + results[0] -= ndarray_get_float_index(a->array, a->dtype, 2) * ndarray_get_float_index(b->array, b->dtype, 1); + results[1] = -ndarray_get_float_index(a->array, a->dtype, 0) * ndarray_get_float_index(b->array, b->dtype, 2); + results[1] += ndarray_get_float_index(a->array, a->dtype, 2) * ndarray_get_float_index(b->array, b->dtype, 0); + results[2] = ndarray_get_float_index(a->array, a->dtype, 0) * ndarray_get_float_index(b->array, b->dtype, 1); + results[2] -= ndarray_get_float_index(a->array, a->dtype, 1) * ndarray_get_float_index(b->array, b->dtype, 0); + + /* The upcasting happens here with the rules + + - if one of the operarands is a float, the result is always float + - operation on identical types preserves type + + uint8 + int8 => int16 + uint8 + int16 => int16 + uint8 + uint16 => uint16 + int8 + int16 => int16 + int8 + uint16 => uint16 + uint16 + int16 => float + + */ + + uint8_t dtype = NDARRAY_FLOAT; + if(a->dtype == b->dtype) { + dtype = a->dtype; + } else if(((a->dtype == NDARRAY_UINT8) && (b->dtype == NDARRAY_INT8)) || ((a->dtype == NDARRAY_INT8) && (b->dtype == NDARRAY_UINT8))) { + dtype = NDARRAY_INT16; + } else if(((a->dtype == NDARRAY_UINT8) && (b->dtype == NDARRAY_INT16)) || ((a->dtype == NDARRAY_INT16) && (b->dtype == NDARRAY_UINT8))) { + dtype = NDARRAY_INT16; + } else if(((a->dtype == NDARRAY_UINT8) && (b->dtype == NDARRAY_UINT16)) || ((a->dtype == NDARRAY_UINT16) && (b->dtype == NDARRAY_UINT8))) { + dtype = NDARRAY_UINT16; + } else if(((a->dtype == NDARRAY_INT8) && (b->dtype == NDARRAY_INT16)) || ((a->dtype == NDARRAY_INT16) && (b->dtype == NDARRAY_INT8))) { + dtype = NDARRAY_INT16; + } else if(((a->dtype == NDARRAY_INT8) && (b->dtype == NDARRAY_UINT16)) || ((a->dtype == NDARRAY_UINT16) && (b->dtype == NDARRAY_INT8))) { + dtype = NDARRAY_UINT16; + } + + ndarray_obj_t *ndarray = ndarray_new_linear_array(3, dtype); + if(dtype == NDARRAY_UINT8) { + uint8_t *array = (uint8_t *)ndarray->array; + for(uint8_t i=0; i < 3; i++) array[i] = (uint8_t)results[i]; + } else if(dtype == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array; + for(uint8_t i=0; i < 3; i++) array[i] = (int8_t)results[i]; + } else if(dtype == NDARRAY_UINT16) { + uint16_t *array = (uint16_t *)ndarray->array; + for(uint8_t i=0; i < 3; i++) array[i] = (uint16_t)results[i]; + } else if(dtype == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array; + for(uint8_t i=0; i < 3; i++) array[i] = (int16_t)results[i]; + } else { + mp_float_t *array = (mp_float_t *)ndarray->array; + for(uint8_t i=0; i < 3; i++) array[i] = results[i]; + } + m_del(mp_float_t, results, 3); + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_2(numerical_cross_obj, numerical_cross); + +#endif /* ULAB_NUMERICAL_HAS_CROSS */ + +#if ULAB_NUMPY_HAS_DIFF +//| def diff(array: ulab.ndarray, *, n: int = 1, axis: int = -1) -> ulab.ndarray: +//| """Return the numerical derivative of successive elements of the array, as +//| an array. axis=None is not supported.""" +//| ... +//| + +mp_obj_t numerical_diff(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_const_none } }, + { MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("diff argument must be an ndarray")); + } + + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); + int8_t ax = args[2].u_int; + if(ax < 0) ax += ndarray->ndim; + + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + + if((args[1].u_int < 0) || (args[1].u_int > 9)) { + mp_raise_ValueError(translate("differentiation order out of range")); + } + uint8_t N = (uint8_t)args[1].u_int; + uint8_t index = ULAB_MAX_DIMS - ndarray->ndim + ax; + if(N > ndarray->shape[index]) { + mp_raise_ValueError(translate("differentiation order out of range")); + } + + int8_t *stencil = m_new(int8_t, N+1); + stencil[0] = 1; + for(uint8_t i=1; i < N+1; i++) { + stencil[i] = -stencil[i-1]*(N-i+1)/i; + } + + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) { + shape[i] = ndarray->shape[i]; + if(i == index) { + shape[i] -= N; + } + } + uint8_t *array = (uint8_t *)ndarray->array; + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim, shape, ndarray->dtype); + uint8_t *rarray = (uint8_t *)results->array; + + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(int32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(ndarray, ax, shape, strides); + + if(ndarray->dtype == NDARRAY_UINT8) { + RUN_DIFF(ndarray, uint8_t, array, results, rarray, shape, strides, index, stencil, N); + } else if(ndarray->dtype == NDARRAY_INT8) { + RUN_DIFF(ndarray, int8_t, array, results, rarray, shape, strides, index, stencil, N); + } else if(ndarray->dtype == NDARRAY_UINT16) { + RUN_DIFF(ndarray, uint16_t, array, results, rarray, shape, strides, index, stencil, N); + } else if(ndarray->dtype == NDARRAY_INT16) { + RUN_DIFF(ndarray, int16_t, array, results, rarray, shape, strides, index, stencil, N); + } else { + RUN_DIFF(ndarray, mp_float_t, array, results, rarray, shape, strides, index, stencil, N); + } + m_del(int8_t, stencil, N+1); + m_del(size_t, shape, ULAB_MAX_DIMS); + m_del(int32_t, strides, ULAB_MAX_DIMS); + return MP_OBJ_FROM_PTR(results); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff); +#endif + +#if ULAB_NUMPY_HAS_FLIP +//| def flip(array: ulab.ndarray, *, axis: Optional[int] = None) -> ulab.ndarray: +//| """Returns a new array that reverses the order of the elements along the +//| given axis, or along all axes if axis is None.""" +//| ... +//| + +mp_obj_t numerical_flip(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("flip argument must be an ndarray")); + } + + ndarray_obj_t *results = NULL; + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); + if(args[1].u_obj == mp_const_none) { // flip the flattened array + results = ndarray_new_linear_array(ndarray->len, ndarray->dtype); + ndarray_copy_array(ndarray, results); + uint8_t *rarray = (uint8_t *)results->array; + rarray += (results->len - 1) * results->itemsize; + results->array = rarray; + results->strides[ULAB_MAX_DIMS - 1] = -results->strides[ULAB_MAX_DIMS - 1]; + } else if(mp_obj_is_int(args[1].u_obj)){ + int8_t ax = mp_obj_get_int(args[1].u_obj); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + ax = ULAB_MAX_DIMS - ndarray->ndim + ax; + int32_t offset = (ndarray->shape[ax] - 1) * ndarray->strides[ax]; + results = ndarray_new_view(ndarray, ndarray->ndim, ndarray->shape, ndarray->strides, offset); + results->strides[ax] = -results->strides[ax]; + } else { + mp_raise_TypeError(translate("wrong axis index")); + } + return results; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip); +#endif + +#if ULAB_NUMPY_HAS_MINMAX +//| def max(array: _ArrayLike, *, axis: Optional[int] = None) -> float: +//| """Return the maximum element of the 1D array""" +//| ... +//| + +mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MAX); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max); +#endif + +#if ULAB_NUMPY_HAS_MEAN +//| def mean(array: _ArrayLike, *, axis: Optional[int] = None) -> float: +//| """Return the mean element of the 1D array, as a number if axis is None, otherwise as an array.""" +//| ... +//| + +mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MEAN); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean); +#endif + +#if ULAB_NUMPY_HAS_MEDIAN +//| def median(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray: +//| """Find the median value in an array along the given axis, or along all axes if axis is None.""" +//| ... +//| + +mp_obj_t numerical_median(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("median argument must be an ndarray")); + } + + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); + if(ndarray->len == 0) { + return mp_obj_new_float(MICROPY_FLOAT_C_FUN(nan)("")); + } + + ndarray = numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0); + + if((args[1].u_obj == mp_const_none) || (ndarray->ndim == 1)) { + // at this point, the array holding the sorted values should be flat + uint8_t *array = (uint8_t *)ndarray->array; + size_t len = ndarray->len; + array += (len >> 1) * ndarray->itemsize; + mp_float_t median = ndarray_get_float_value(array, ndarray->dtype); + if(!(len & 0x01)) { // len is an even number + array -= ndarray->itemsize; + median += ndarray_get_float_value(array, ndarray->dtype); + median *= MICROPY_FLOAT_CONST(0.5); + } + return mp_obj_new_float(median); + } else { + int8_t ax = mp_obj_get_int(args[1].u_obj); + if(ax < 0) ax += ndarray->ndim; + // here we can save the exception, because if the axis is out of range, + // then numerical_sort_helper has already taken care of the issue + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(ndarray, ax, shape, strides); + ax = ULAB_MAX_DIMS - ndarray->ndim + ax; + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim-1, shape, NDARRAY_FLOAT); + mp_float_t *rarray = (mp_float_t *)results->array; + + uint8_t *array = (uint8_t *)ndarray->array; + + size_t len = ndarray->shape[ax]; + + #if ULAB_MAX_DIMS > 3 + size_t i = 0; + do { + #endif + #if ULAB_MAX_DIMS > 2 + size_t j = 0; + do { + #endif + size_t k = 0; + do { + array += ndarray->strides[ax] * (len >> 1); + mp_float_t median = ndarray_get_float_value(array, ndarray->dtype); + if(!(len & 0x01)) { // len is an even number + array -= ndarray->strides[ax]; + median += ndarray_get_float_value(array, ndarray->dtype); + median *= MICROPY_FLOAT_CONST(0.5); + array += ndarray->strides[ax]; + } + array -= ndarray->strides[ax] * (len >> 1); + array += strides[ULAB_MAX_DIMS - 1]; + *rarray = median; + rarray++; + k++; + } while(k < shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 2 + array -= strides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS - 1]; + array += strides[ULAB_MAX_DIMS - 2]; + j++; + } while(j < shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= strides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS-2]; + array += strides[ULAB_MAX_DIMS - 3]; + i++; + } while(i < shape[ULAB_MAX_DIMS - 3]); + #endif + + return MP_OBJ_FROM_PTR(results); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_median_obj, 1, numerical_median); +#endif + +#if ULAB_NUMPY_HAS_MINMAX +//| def min(array: _ArrayLike, *, axis: Optional[int] = None) -> float: +//| """Return the minimum element of the 1D array""" +//| ... +//| + +mp_obj_t numerical_min(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MIN); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min); +#endif + +#if ULAB_NUMPY_HAS_ROLL +//| def roll(array: ulab.ndarray, distance: int, *, axis: Optional[int] = None) -> None: +//| """Shift the content of a vector by the positions given as the second +//| argument. If the ``axis`` keyword is supplied, the shift is applied to +//| the given axis. The array is modified in place.""" +//| ... +//| + +mp_obj_t numerical_roll(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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("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); + int32_t _shift = shift < 0 ? -shift : shift; + + size_t counter; + uint8_t *rarray = (uint8_t *)results->array; + + if(args[2].u_obj == mp_const_none) { // roll the flattened array + _shift = _shift % results->len; + if(shift > 0) { // shift to the right + rarray += _shift * results->itemsize; + counter = results->len - _shift; + } else { // shift to the left + rarray += (results->len - _shift) * results->itemsize; + counter = _shift; + } + #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 { + memcpy(rarray, array, ndarray->itemsize); + rarray += results->itemsize; + array += ndarray->strides[ULAB_MAX_DIMS - 1]; + l++; + if(--counter == 0) { + rarray = results->array; + } + } while(l < ndarray->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1]; + array += ndarray->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < ndarray->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + array -= ndarray->strides[ULAB_MAX_DIMS - 2] * ndarray->shape[ULAB_MAX_DIMS-2]; + array += ndarray->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < ndarray->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + array -= ndarray->strides[ULAB_MAX_DIMS - 3] * ndarray->shape[ULAB_MAX_DIMS-3]; + array += ndarray->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < ndarray->shape[ULAB_MAX_DIMS - 4]); + #endif + } else if(mp_obj_is_int(args[2].u_obj)){ + int8_t ax = mp_obj_get_int(args[2].u_obj); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS); + memset(strides, 0, sizeof(int32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(ndarray, ax, shape, strides); + + size_t *rshape = m_new(size_t, ULAB_MAX_DIMS); + memset(rshape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS); + memset(rstrides, 0, sizeof(int32_t)*ULAB_MAX_DIMS); + numerical_reduce_axes(results, ax, rshape, rstrides); + + ax = ULAB_MAX_DIMS - ndarray->ndim + ax; + uint8_t *_rarray; + _shift = _shift % results->shape[ax]; + + #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; + _rarray = rarray; + if(shift < 0) { + rarray += (results->shape[ax] - _shift) * results->strides[ax]; + counter = _shift; + } else { + rarray += _shift * results->strides[ax]; + counter = results->shape[ax] - _shift; + } + do { + memcpy(rarray, array, ndarray->itemsize); + array += ndarray->strides[ax]; + rarray += results->strides[ax]; + if(--counter == 0) { + rarray = _rarray; + } + l++; + } while(l < ndarray->shape[ax]); + #if ULAB_MAX_DIMS > 1 + rarray = _rarray; + rarray += rstrides[ULAB_MAX_DIMS - 1]; + array -= ndarray->strides[ax] * ndarray->shape[ax]; + array += strides[ULAB_MAX_DIMS - 1]; + k++; + } while(k < shape[ULAB_MAX_DIMS - 1]); + #endif + #if ULAB_MAX_DIMS > 2 + rarray -= rstrides[ULAB_MAX_DIMS - 1] * rshape[ULAB_MAX_DIMS-1]; + rarray += rstrides[ULAB_MAX_DIMS - 2]; + array -= strides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS-1]; + array += strides[ULAB_MAX_DIMS - 2]; + j++; + } while(j < shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 3 + rarray -= rstrides[ULAB_MAX_DIMS - 2] * rshape[ULAB_MAX_DIMS-2]; + rarray += rstrides[ULAB_MAX_DIMS - 3]; + array -= strides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS-2]; + array += strides[ULAB_MAX_DIMS - 3]; + i++; + } while(i < shape[ULAB_MAX_DIMS - 3]); + #endif + } else { + mp_raise_TypeError(translate("wrong axis index")); + } + return results; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll); +#endif + +#if ULAB_NUMPY_HAS_SORT +//| def sort(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray: +//| """Sort the array along the given axis, or along all axes if axis is None. +//| The array is modified in place.""" +//| ... +//| + +mp_obj_t numerical_sort(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort); +#endif + +#if NDARRAY_HAS_SORT +// method of an ndarray +static mp_obj_t numerical_sort_inplace(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 1); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace); +#endif /* NDARRAY_HAS_SORT */ + +#if ULAB_NUMPY_HAS_STD +//| def std(array: _ArrayLike, *, axis: Optional[int] = None, ddof: int = 0) -> float: +//| """Return the standard deviation of the array, as a number if axis is None, otherwise as an array.""" +//| ... +//| + +mp_obj_t numerical_std(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_const_none } } , + { MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t oin = args[0].u_obj; + mp_obj_t axis = args[1].u_obj; + size_t ddof = args[2].u_int; + if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) { + // this seems to pass with False, and True... + mp_raise_ValueError(translate("axis must be None, or an integer")); + } + if(mp_obj_is_type(oin, &mp_type_tuple) || mp_obj_is_type(oin, &mp_type_list) || mp_obj_is_type(oin, &mp_type_range)) { + return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof); + } else if(mp_obj_is_type(oin, &ulab_ndarray_type)) { + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); + return numerical_sum_mean_std_ndarray(ndarray, axis, NUMERICAL_STD, ddof); + } else { + mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray")); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std); +#endif + +#if ULAB_NUMPY_HAS_SUM +//| def sum(array: _ArrayLike, *, axis: Optional[int] = None) -> Union[float, int, ulab.ndarray]: +//| """Return the sum of the array, as a number if axis is None, otherwise as an array.""" +//| ... +//| + +mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return numerical_function(n_args, pos_args, kw_args, NUMERICAL_SUM); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum); +#endif diff --git a/python/port/mod/ulab/numpy/numerical/numerical.h b/python/port/mod/ulab/numpy/numerical/numerical.h new file mode 100644 index 000000000..ef7b95d74 --- /dev/null +++ b/python/port/mod/ulab/numpy/numerical/numerical.h @@ -0,0 +1,652 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _NUMERICAL_ +#define _NUMERICAL_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +// TODO: implement cumsum + +#define RUN_ARGMIN1(ndarray, type, array, results, rarray, index, op)\ +({\ + uint16_t best_index = 0;\ + type best_value = *((type *)(array));\ + if(((op) == NUMERICAL_MAX) || ((op) == NUMERICAL_ARGMAX)) {\ + for(uint16_t i=0; i < (ndarray)->shape[(index)]; i++) {\ + if(*((type *)(array)) > best_value) {\ + best_index = i;\ + best_value = *((type *)(array));\ + }\ + (array) += (ndarray)->strides[(index)];\ + }\ + } else {\ + for(uint16_t i=0; i < (ndarray)->shape[(index)]; i++) {\ + if(*((type *)(array)) < best_value) {\ + best_index = i;\ + best_value = *((type *)(array));\ + }\ + (array) += (ndarray)->strides[(index)];\ + }\ + }\ + if(((op) == NUMERICAL_ARGMAX) || ((op) == NUMERICAL_ARGMIN)) {\ + memcpy((rarray), &best_index, (results)->itemsize);\ + } else {\ + memcpy((rarray), &best_value, (results)->itemsize);\ + }\ + (rarray) += (results)->itemsize;\ +}) + +#define RUN_SUM1(type, array, results, rarray, ss)\ +({\ + type sum = 0;\ + for(size_t i=0; i < (ss).shape[0]; i++) {\ + sum += *((type *)(array));\ + (array) += (ss).strides[0];\ + }\ + memcpy((rarray), &sum, (results)->itemsize);\ + (rarray) += (results)->itemsize;\ +}) + +// The mean could be calculated by simply dividing the sum by +// the number of elements, but that method is numerically unstable +#define RUN_MEAN1(type, array, rarray, ss)\ +({\ + mp_float_t M = 0.0;\ + for(size_t i=0; i < (ss).shape[0]; i++) {\ + mp_float_t value = (mp_float_t)(*(type *)(array));\ + M = M + (value - M) / (mp_float_t)(i+1);\ + (array) += (ss).strides[0];\ + }\ + *(rarray)++ = M;\ +}) + +// Instead of the straightforward implementation of the definition, +// we take the numerically stable Welford algorithm here +// https://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/ +#define RUN_STD1(type, array, rarray, ss, div)\ +({\ + mp_float_t M = 0.0, m = 0.0, S = 0.0;\ + for(size_t i=0; i < (ss).shape[0]; i++) {\ + mp_float_t value = (mp_float_t)(*(type *)(array));\ + m = M + (value - M) / (mp_float_t)(i+1);\ + S = S + (value - M) * (value - m);\ + M = m;\ + (array) += (ss).strides[0];\ + }\ + *(rarray)++ = MICROPY_FLOAT_C_FUN(sqrt)(S / (div));\ +}) + +#define RUN_MEAN_STD1(type, array, rarray, ss, div, isStd)\ +({\ + mp_float_t M = 0.0, m = 0.0, S = 0.0;\ + for(size_t i=0; i < (ss).shape[0]; i++) {\ + mp_float_t value = (mp_float_t)(*(type *)(array));\ + m = M + (value - M) / (mp_float_t)(i+1);\ + if(isStd) {\ + S += (value - M) * (value - m);\ + }\ + M = m;\ + (array) += (ss).strides[0];\ + }\ + *(rarray)++ = isStd ? MICROPY_FLOAT_C_FUN(sqrt)(S / (div)) : M;\ +}) + +#define RUN_DIFF1(ndarray, type, array, results, rarray, index, stencil, N)\ +({\ + for(size_t i=0; i < (results)->shape[ULAB_MAX_DIMS - 1]; i++) {\ + type sum = 0;\ + uint8_t *source = (array);\ + for(uint8_t d=0; d < (N)+1; d++) {\ + sum -= (stencil)[d] * *((type *)source);\ + source += (ndarray)->strides[(index)];\ + }\ + (array) += (ndarray)->strides[ULAB_MAX_DIMS - 1];\ + *(type *)(rarray) = sum;\ + (rarray) += (results)->itemsize;\ + }\ +}) + +#define HEAPSORT1(type, array, increment, N)\ +({\ + type *_array = (type *)array;\ + type tmp;\ + size_t c, q = (N), p, r = (N) >> 1;\ + for (;;) {\ + if (r > 0) {\ + tmp = _array[(--r)*(increment)];\ + } else {\ + q--;\ + if(q == 0) {\ + break;\ + }\ + tmp = _array[q*(increment)];\ + _array[q*(increment)] = _array[0];\ + }\ + p = r;\ + c = r + r + 1;\ + while (c < q) {\ + if((c + 1 < q) && (_array[(c+1)*(increment)] > _array[c*(increment)])) {\ + c++;\ + }\ + if(_array[c*(increment)] > tmp) {\ + _array[p*(increment)] = _array[c*(increment)];\ + p = c;\ + c = p + p + 1;\ + } else {\ + break;\ + }\ + }\ + _array[p*(increment)] = tmp;\ + }\ +}) + +#define HEAP_ARGSORT1(type, array, increment, N, iarray, iincrement)\ +({\ + type *_array = (type *)array;\ + type tmp;\ + uint16_t itmp, c, q = (N), p, r = (N) >> 1;\ + for (;;) {\ + if (r > 0) {\ + r--;\ + itmp = (iarray)[r*(iincrement)];\ + tmp = _array[itmp*(increment)];\ + } else {\ + q--;\ + if(q == 0) {\ + break;\ + }\ + itmp = (iarray)[q*(iincrement)];\ + tmp = _array[itmp*(increment)];\ + (iarray)[q*(iincrement)] = (iarray)[0];\ + }\ + p = r;\ + c = r + r + 1;\ + while (c < q) {\ + if((c + 1 < q) && (_array[(iarray)[(c+1)*(iincrement)]*(increment)] > _array[(iarray)[c*(iincrement)]*(increment)])) {\ + c++;\ + }\ + if(_array[(iarray)[c*(iincrement)]*(increment)] > tmp) {\ + (iarray)[p*(iincrement)] = (iarray)[c*(iincrement)];\ + p = c;\ + c = p + p + 1;\ + } else {\ + break;\ + }\ + }\ + (iarray)[p*(iincrement)] = itmp;\ + }\ +}) + +#if ULAB_MAX_DIMS == 1 +#define RUN_SUM(type, array, results, rarray, ss) do {\ + RUN_SUM1(type, (array), (results), (rarray), (ss));\ +} while(0) + +#define RUN_MEAN(type, array, rarray, ss) do {\ + RUN_MEAN1(type, (array), (rarray), (ss));\ +} while(0) + +#define RUN_STD(type, array, rarray, ss, div) do {\ + RUN_STD1(type, (array), (results), (rarray), (ss), (div));\ +} while(0) + +#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\ + RUN_MEAN_STD1(type, (array), (results), (rarray), (ss), (div), (isStd));\ +} while(0) + +#define RUN_ARGMIN(ndarray, type, array, results, rarray, shape, strides, index, op) do {\ + RUN_ARGMIN1((ndarray), type, (array), (results), (rarray), (index), (op));\ +} while(0) + +#define RUN_DIFF(ndarray, type, array, results, rarray, shape, strides, index, stencil, N) do {\ + RUN_DIFF1((ndarray), type, (array), (results), (rarray), (index), (stencil), (N));\ +} while(0) + +#define HEAPSORT(ndarray, type, array, shape, strides, index, increment, N) do {\ + HEAPSORT1(type, (array), (increment), (N));\ +} while(0) + +#define HEAP_ARGSORT(ndarray, type, array, shape, strides, index, increment, N, iarray, istrides, iincrement) do {\ + HEAP_ARGSORT1(type, (array), (increment), (N), (iarray), (iincrement));\ +} while(0) + +#endif + +#if ULAB_MAX_DIMS == 2 +#define RUN_SUM(type, array, results, rarray, ss) do {\ + size_t l = 0;\ + do {\ + RUN_SUM1(type, (array), (results), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#define RUN_MEAN(type, array, rarray, ss) do {\ + size_t l = 0;\ + do {\ + RUN_MEAN1(type, (array), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#define RUN_STD(type, array, rarray, ss, div) do {\ + size_t l = 0;\ + do {\ + RUN_STD1(type, (array), (rarray), (ss), (div));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\ + size_t l = 0;\ + do {\ + RUN_MEAN_STD1(type, (array), (rarray), (ss), (div), (isStd));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ +} while(0) + + +#define RUN_ARGMIN(ndarray, type, array, results, rarray, shape, strides, index, op) do {\ + size_t l = 0;\ + do {\ + RUN_ARGMIN1((ndarray), type, (array), (results), (rarray), (index), (op));\ + (array) -= (ndarray)->strides[(index)] * (ndarray)->shape[(index)];\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#define RUN_DIFF(ndarray, type, array, results, rarray, shape, strides, index, stencil, N) do {\ + size_t l = 0;\ + do {\ + RUN_DIFF1((ndarray), type, (array), (results), (rarray), (index), (stencil), (N));\ + (array) -= (ndarray)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (array) += (ndarray)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + l++;\ + } while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define HEAPSORT(ndarray, type, array, shape, strides, index, increment, N) do {\ + size_t l = 0;\ + do {\ + HEAPSORT1(type, (array), (increment), (N));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#define HEAP_ARGSORT(ndarray, type, array, shape, strides, index, increment, N, iarray, istrides, iincrement) do {\ + size_t l = 0;\ + do {\ + HEAP_ARGSORT1(type, (array), (increment), (N), (iarray), (iincrement));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ +} while(0) + +#endif + +#if ULAB_MAX_DIMS == 3 +#define RUN_SUM(type, array, results, rarray, ss) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_SUM1(type, (array), (results), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define RUN_MEAN(type, array, rarray, ss) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_MEAN1(type, (array), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define RUN_STD(type, array, rarray, ss, div) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_STD1(type, (array), (rarray), (ss), (div));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_MEAN_STD1(type, (array), (rarray), (ss), (div), (isStd));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define RUN_ARGMIN(ndarray, type, array, results, rarray, shape, strides, index, op) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_ARGMIN1((ndarray), type, (array), (results), (rarray), (index), (op));\ + (array) -= (ndarray)->strides[(index)] * (ndarray)->shape[(index)];\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define RUN_DIFF(ndarray, type, array, results, rarray, shape, strides, index, stencil, N) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_DIFF1((ndarray), type, (array), (results), (rarray), (index), (stencil), (N));\ + (array) -= (ndarray)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (array) += (ndarray)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 2]);\ + (array) -= (ndarray)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS-2];\ + (array) += (ndarray)->strides[ULAB_MAX_DIMS - 3];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define HEAPSORT(ndarray, type, array, shape, strides, index, increment, N) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + HEAPSORT1(type, (array), (increment), (N));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#define HEAP_ARGSORT(ndarray, type, array, shape, strides, index, increment, N, iarray, istrides, iincrement) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + HEAP_ARGSORT1(type, (array), (increment), (N), (iarray), (iincrement));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (iarray) -= (istrides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 2];\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ +} while(0) + +#endif + +#if ULAB_MAX_DIMS == 4 +#define RUN_SUM(type, array, results, rarray, shape, strides, index) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_SUM1(type, (array), (results), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define RUN_MEAN(type, array, rarray, ss) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_MEAN1(type, (array), (rarray), (ss));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define RUN_STD(type, array, rarray, ss, div) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_STD1(type, (array), (rarray), (ss), (div));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_MEAN_STD1(type, (array), (rarray), (ss), (div), (isStd));\ + (array) -= (ss).strides[0] * (ss).shape[0];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\ + (array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\ + (array) += (ss).strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define RUN_ARGMIN(ndarray, type, array, results, rarray, shape, strides, index, op) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_ARGMIN1((ndarray), type, (array), (results), (rarray), (index), (op));\ + (array) -= (ndarray)->strides[(index)] * (ndarray)->shape[(index)];\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 2] * (shape)[ULAB_MAX_DIMS-2];\ + (array) += (strides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (shape)[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define RUN_DIFF(ndarray, type, array, results, rarray, shape, strides, index, stencil, N) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + RUN_DIFF1((ndarray), type, (array), (results), (rarray), (index), (stencil), (N));\ + (array) -= (ndarray)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (array) += (ndarray)->strides[ULAB_MAX_DIMS - 2];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 2];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 2]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 2] * (shape)[ULAB_MAX_DIMS-2];\ + (array) += (strides)[ULAB_MAX_DIMS - 3];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 3];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 3]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 3] * (shape)[ULAB_MAX_DIMS-3];\ + (array) += (strides)[ULAB_MAX_DIMS - 4];\ + (rarray) -= (results)->strides[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\ + (rarray) += (results)->strides[ULAB_MAX_DIMS - 4];\ + j++;\ + } while(j < (shape)[ULAB_MAX_DIMS - 4]);\ +} while(0) + +#define HEAPSORT(ndarray, type, array, shape, strides, index, increment, N) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + HEAPSORT1(type, (array), (increment), (N));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ + (array) -= (strides)[ULAB_MAX_DIMS - 2] * (shape)[ULAB_MAX_DIMS-2];\ + (array) += (strides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (shape)[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#define HEAP_ARGSORT(ndarray, type, array, shape, strides, index, increment, N, iarray, istrides, iincrement) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + HEAP_ARGSORT1(type, (array), (increment), (N), (iarray), (iincrement));\ + (array) += (strides)[ULAB_MAX_DIMS - 1];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (shape)[ULAB_MAX_DIMS - 1]);\ + (iarray) -= (istrides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 2];\ + (array) -= (strides)[ULAB_MAX_DIMS - 1] * (shape)[ULAB_MAX_DIMS-1];\ + (array) += (strides)[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (shape)[ULAB_MAX_DIMS - 2]);\ + (iarray) -= (istrides)[ULAB_MAX_DIMS - 2] * (shape)[ULAB_MAX_DIMS-2];\ + (iarray) += (istrides)[ULAB_MAX_DIMS - 3];\ + (array) -= (strides)[ULAB_MAX_DIMS - 2] * (shape)[ULAB_MAX_DIMS-2];\ + (array) += (strides)[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (shape)[ULAB_MAX_DIMS - 3]);\ +} while(0) + +#endif + +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_all_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_any_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmax_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmin_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argsort_obj); +MP_DECLARE_CONST_FUN_OBJ_2(numerical_cross_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_diff_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_flip_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_max_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_mean_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_median_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_min_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_roll_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_std_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sum_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj); + +#endif diff --git a/python/port/mod/ulab/numpy/numpy.c b/python/port/mod/ulab/numpy/numpy.c new file mode 100644 index 000000000..8d8f3ab6b --- /dev/null +++ b/python/port/mod/ulab/numpy/numpy.c @@ -0,0 +1,336 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include +#include + +#include "numpy.h" +#include "../ulab_create.h" +#include "approx/approx.h" +#include "compare/compare.h" +#include "fft/fft.h" +#include "filter/filter.h" +#include "linalg/linalg.h" +#include "numerical/numerical.h" +#include "stats/stats.h" +#include "transform/transform.h" +#include "poly/poly.h" +#include "vector/vector.h" + +//| """Compatibility layer for numpy""" +//| + +//| class ndarray: ... + +// math constants +#if ULAB_NUMPY_HAS_E +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#define ulab_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000)) +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define ulab_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))} +#else +mp_obj_float_t ulab_const_float_e_obj = {{&mp_type_float}, MP_E}; +#define ulab_const_float_e MP_ROM_PTR(&ulab_const_float_e_obj) +#endif +#endif + +#if ULAB_NUMPY_HAS_INF +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#define numpy_const_float_inf MP_ROM_PTR((mp_obj_t)(0x7f800002 + 0x80800000)) +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define numpy_const_float_inf {((mp_obj_t)((uint64_t)0x7ff0000000000000 + 0x8004000000000000))} +#else +mp_obj_float_t numpy_const_float_inf_obj = {{&mp_type_float}, (mp_float_t)INFINITY}; +#define numpy_const_float_inf MP_ROM_PTR(&numpy_const_float_inf_obj) +#endif +#endif + +#if ULAB_NUMPY_HAS_NAN +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#define numpy_const_float_nan MP_ROM_PTR((mp_obj_t)(0x7fc00002 + 0x80800000)) +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define numpy_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))} +#else +mp_obj_float_t numpy_const_float_nan_obj = {{&mp_type_float}, (mp_float_t)NAN}; +#define numpy_const_float_nan MP_ROM_PTR(&numpy_const_float_nan_obj) +#endif +#endif + +#if ULAB_NUMPY_HAS_PI +#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C +#define ulab_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000)) +#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D +#define ulab_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))} +#else +mp_obj_float_t ulab_const_float_pi_obj = {{&mp_type_float}, MP_PI}; +#define ulab_const_float_pi MP_ROM_PTR(&ulab_const_float_pi_obj) +#endif +#endif + +static const mp_rom_map_elem_t ulab_numpy_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_numpy) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_ndarray), (mp_obj_t)&ulab_ndarray_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_array), MP_ROM_PTR(&ndarray_array_constructor_obj) }, + #if ULAB_NUMPY_HAS_FROMBUFFER + { MP_ROM_QSTR(MP_QSTR_frombuffer), MP_ROM_PTR(&create_frombuffer_obj) }, + #endif + // math constants + #if ULAB_NUMPY_HAS_E + { MP_ROM_QSTR(MP_QSTR_e), ulab_const_float_e }, + #endif + #if ULAB_NUMPY_HAS_INF + { MP_ROM_QSTR(MP_QSTR_inf), numpy_const_float_inf }, + #endif + #if ULAB_NUMPY_HAS_NAN + { MP_ROM_QSTR(MP_QSTR_nan), numpy_const_float_nan }, + #endif + #if ULAB_NUMPY_HAS_PI + { MP_ROM_QSTR(MP_QSTR_pi), ulab_const_float_pi }, + #endif + // class constants, always included + { MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_INT(NDARRAY_BOOL) }, + { MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) }, + { MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) }, + { MP_ROM_QSTR(MP_QSTR_uint16), MP_ROM_INT(NDARRAY_UINT16) }, + { MP_ROM_QSTR(MP_QSTR_int16), MP_ROM_INT(NDARRAY_INT16) }, + { MP_ROM_QSTR(MP_QSTR_float), MP_ROM_INT(NDARRAY_FLOAT) }, + // modules of numpy + #if ULAB_NUMPY_HAS_FFT_MODULE + { MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&ulab_fft_module) }, + #endif + #if ULAB_NUMPY_HAS_LINALG_MODULE + { MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) }, + #endif + #if ULAB_HAS_PRINTOPTIONS + { MP_ROM_QSTR(MP_QSTR_set_printoptions), (mp_obj_t)&ndarray_set_printoptions_obj }, + { MP_ROM_QSTR(MP_QSTR_get_printoptions), (mp_obj_t)&ndarray_get_printoptions_obj }, + #endif + #if ULAB_NUMPY_HAS_NDINFO + { MP_ROM_QSTR(MP_QSTR_ndinfo), (mp_obj_t)&ndarray_info_obj }, + #endif + #if ULAB_NUMPY_HAS_ARANGE + { MP_ROM_QSTR(MP_QSTR_arange), (mp_obj_t)&create_arange_obj }, + #endif + #if ULAB_NUMPY_HAS_CONCATENATE + { MP_ROM_QSTR(MP_QSTR_concatenate), (mp_obj_t)&create_concatenate_obj }, + #endif + #if ULAB_NUMPY_HAS_DIAG + { MP_ROM_QSTR(MP_QSTR_diag), (mp_obj_t)&create_diag_obj }, + #endif + #if ULAB_NUMPY_HAS_EMPTY + { MP_ROM_QSTR(MP_QSTR_empty), (mp_obj_t)&create_zeros_obj }, + #endif + #if ULAB_MAX_DIMS > 1 + #if ULAB_NUMPY_HAS_EYE + { MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&create_eye_obj }, + #endif + #endif /* ULAB_MAX_DIMS */ + // functions of the approx sub-module + #if ULAB_NUMPY_HAS_INTERP + { MP_OBJ_NEW_QSTR(MP_QSTR_interp), (mp_obj_t)&approx_interp_obj }, + #endif + #if ULAB_NUMPY_HAS_TRAPZ + { MP_OBJ_NEW_QSTR(MP_QSTR_trapz), (mp_obj_t)&approx_trapz_obj }, + #endif + // functions of the create sub-module + #if ULAB_NUMPY_HAS_FULL + { MP_ROM_QSTR(MP_QSTR_full), (mp_obj_t)&create_full_obj }, + #endif + #if ULAB_NUMPY_HAS_LINSPACE + { MP_ROM_QSTR(MP_QSTR_linspace), (mp_obj_t)&create_linspace_obj }, + #endif + #if ULAB_NUMPY_HAS_LOGSPACE + { MP_ROM_QSTR(MP_QSTR_logspace), (mp_obj_t)&create_logspace_obj }, + #endif + #if ULAB_NUMPY_HAS_ONES + { MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&create_ones_obj }, + #endif + #if ULAB_NUMPY_HAS_ZEROS + { MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&create_zeros_obj }, + #endif + // functions of the compare sub-module + #if ULAB_NUMPY_HAS_CLIP + { MP_OBJ_NEW_QSTR(MP_QSTR_clip), (mp_obj_t)&compare_clip_obj }, + #endif + #if ULAB_NUMPY_HAS_EQUAL + { MP_OBJ_NEW_QSTR(MP_QSTR_equal), (mp_obj_t)&compare_equal_obj }, + #endif + #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 + #if ULAB_NUMPY_HAS_MINIMUM + { MP_OBJ_NEW_QSTR(MP_QSTR_minimum), (mp_obj_t)&compare_minimum_obj }, + #endif + #if ULAB_NUMPY_HAS_WHERE + { MP_OBJ_NEW_QSTR(MP_QSTR_where), (mp_obj_t)&compare_where_obj }, + #endif + // functions of the filter sub-module + #if ULAB_NUMPY_HAS_CONVOLVE + { MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj }, + #endif + // functions of the numerical sub-module + #if ULAB_NUMPY_HAS_ALL + { MP_OBJ_NEW_QSTR(MP_QSTR_all), (mp_obj_t)&numerical_all_obj }, + #endif + #if ULAB_NUMPY_HAS_ANY + { MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&numerical_any_obj }, + #endif + #if ULAB_NUMPY_HAS_ARGMINMAX + { MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj }, + #endif + #if ULAB_NUMPY_HAS_ARGSORT + { MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj }, + #endif + #if ULAB_NUMPY_HAS_CROSS + { MP_OBJ_NEW_QSTR(MP_QSTR_cross), (mp_obj_t)&numerical_cross_obj }, + #endif + #if ULAB_NUMPY_HAS_DIFF + { MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj }, + #endif + #if ULAB_NUMPY_HAS_DOT + { MP_OBJ_NEW_QSTR(MP_QSTR_dot), (mp_obj_t)&transform_dot_obj }, + #endif + #if ULAB_NUMPY_HAS_TRACE + { MP_ROM_QSTR(MP_QSTR_trace), (mp_obj_t)&stats_trace_obj }, + #endif + #if ULAB_NUMPY_HAS_FLIP + { MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj }, + #endif + #if ULAB_NUMPY_HAS_MINMAX + { MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj }, + #endif + #if ULAB_NUMPY_HAS_MEAN + { MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj }, + #endif + #if ULAB_NUMPY_HAS_MEDIAN + { MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&numerical_median_obj }, + #endif + #if ULAB_NUMPY_HAS_MINMAX + { MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj }, + #endif + #if ULAB_NUMPY_HAS_ROLL + { MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj }, + #endif + #if ULAB_NUMPY_HAS_SORT + { MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj }, + #endif + #if ULAB_NUMPY_HAS_STD + { MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj }, + #endif + #if ULAB_NUMPY_HAS_SUM + { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj }, + #endif + // functions of the poly sub-module + #if ULAB_NUMPY_HAS_POLYFIT + { MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj }, + #endif + #if ULAB_NUMPY_HAS_POLYVAL + { MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj }, + #endif + // functions of the vector sub-module + #if ULAB_NUMPY_HAS_ACOS + { MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj }, + #endif + #if ULAB_NUMPY_HAS_ACOSH + { MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj }, + #endif + #if ULAB_NUMPY_HAS_ARCTAN2 + { MP_OBJ_NEW_QSTR(MP_QSTR_arctan2), (mp_obj_t)&vectorise_arctan2_obj }, + #endif + #if ULAB_NUMPY_HAS_AROUND + { MP_OBJ_NEW_QSTR(MP_QSTR_around), (mp_obj_t)&vectorise_around_obj }, + #endif + #if ULAB_NUMPY_HAS_ASIN + { MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj }, + #endif + #if ULAB_NUMPY_HAS_ASINH + { MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj }, + #endif + #if ULAB_NUMPY_HAS_ATAN + { MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj }, + #endif + #if ULAB_NUMPY_HAS_ATANH + { MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj }, + #endif + #if ULAB_NUMPY_HAS_CEIL + { MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj }, + #endif + #if ULAB_NUMPY_HAS_COS + { MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj }, + #endif + #if ULAB_NUMPY_HAS_COSH + { MP_OBJ_NEW_QSTR(MP_QSTR_cosh), (mp_obj_t)&vectorise_cosh_obj }, + #endif + #if ULAB_NUMPY_HAS_DEGREES + { MP_OBJ_NEW_QSTR(MP_QSTR_degrees), (mp_obj_t)&vectorise_degrees_obj }, + #endif + #if ULAB_NUMPY_HAS_EXP + { MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj }, + #endif + #if ULAB_NUMPY_HAS_EXPM1 + { MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj }, + #endif + #if ULAB_NUMPY_HAS_FLOOR + { MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj }, + #endif + #if ULAB_NUMPY_HAS_LOG + { MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj }, + #endif + #if ULAB_NUMPY_HAS_LOG10 + { MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj }, + #endif + #if ULAB_NUMPY_HAS_LOG2 + { MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj }, + #endif + #if ULAB_NUMPY_HAS_RADIANS + { MP_OBJ_NEW_QSTR(MP_QSTR_radians), (mp_obj_t)&vectorise_radians_obj }, + #endif + #if ULAB_NUMPY_HAS_SIN + { MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj }, + #endif + #if ULAB_NUMPY_HAS_SINH + { MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj }, + #endif + #if ULAB_NUMPY_HAS_SQRT + { MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj }, + #endif + #if ULAB_NUMPY_HAS_TAN + { MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj }, + #endif + #if ULAB_NUMPY_HAS_TANH + { MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj }, + #endif + #if ULAB_NUMPY_HAS_VECTORIZE + { MP_OBJ_NEW_QSTR(MP_QSTR_vectorize), (mp_obj_t)&vectorise_vectorize_obj }, + #endif + +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_numpy_globals, ulab_numpy_globals_table); + +mp_obj_module_t ulab_numpy_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_numpy_globals, +}; diff --git a/python/port/mod/ulab/numpy/numpy.h b/python/port/mod/ulab/numpy/numpy.h new file mode 100644 index 000000000..cccebde18 --- /dev/null +++ b/python/port/mod/ulab/numpy/numpy.h @@ -0,0 +1,21 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * +*/ + +#ifndef _NUMPY_ +#define _NUMPY_ + +#include "../ulab.h" +#include "../ndarray.h" + +extern mp_obj_module_t ulab_numpy_module; + +#endif /* _NUMPY_ */ diff --git a/python/port/mod/ulab/numpy/poly/poly.c b/python/port/mod/ulab/numpy/poly/poly.c new file mode 100644 index 000000000..c9a07655f --- /dev/null +++ b/python/port/mod/ulab/numpy/poly/poly.c @@ -0,0 +1,232 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Taku Fukada +*/ + +#include +#include +#include + +#include "../../ulab.h" +#include "../linalg/linalg_tools.h" +#include "../../ulab_tools.h" +#include "poly.h" + +#if ULAB_NUMPY_HAS_POLYFIT + +mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { + if(!ndarray_object_is_array_like(args[0])) { + mp_raise_ValueError(translate("input data must be an iterable")); + } + size_t lenx = 0, leny = 0; + uint8_t deg = 0; + mp_float_t *x, *XT, *y, *prod; + + if(n_args == 2) { // only the y values are supplied + // TODO: this is actually not enough: the first argument can very well be a matrix, + // in which case we are between the rock and a hard place + leny = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); + deg = (uint8_t)mp_obj_get_int(args[1]); + if(leny < deg) { + mp_raise_ValueError(translate("more degrees of freedom than data points")); + } + lenx = leny; + x = m_new(mp_float_t, lenx); // assume uniformly spaced data points + for(size_t i=0; i < lenx; i++) { + x[i] = i; + } + y = m_new(mp_float_t, leny); + fill_array_iterable(y, args[0]); + } else /* n_args == 3 */ { + if(!ndarray_object_is_array_like(args[1])) { + mp_raise_ValueError(translate("input data must be an iterable")); + } + lenx = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); + leny = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[1])); + if(lenx != leny) { + mp_raise_ValueError(translate("input vectors must be of equal length")); + } + deg = (uint8_t)mp_obj_get_int(args[2]); + if(leny < deg) { + mp_raise_ValueError(translate("more degrees of freedom than data points")); + } + x = m_new(mp_float_t, lenx); + fill_array_iterable(x, args[0]); + y = m_new(mp_float_t, leny); + fill_array_iterable(y, args[1]); + } + + // one could probably express X as a function of XT, + // and thereby save RAM, because X is used only in the product + XT = m_new(mp_float_t, (deg+1)*leny); // XT is a matrix of shape (deg+1, len) (rows, columns) + for(size_t i=0; i < leny; i++) { // column index + XT[i+0*lenx] = 1.0; // top row + for(uint8_t j=1; j < deg+1; j++) { // row index + XT[i+j*leny] = XT[i+(j-1)*leny]*x[i]; + } + } + + prod = m_new(mp_float_t, (deg+1)*(deg+1)); // the product matrix is of shape (deg+1, deg+1) + mp_float_t sum; + for(uint8_t i=0; i < deg+1; i++) { // column index + for(uint8_t j=0; j < deg+1; j++) { // row index + sum = 0.0; + for(size_t k=0; k < lenx; k++) { + // (j, k) * (k, i) + // Note that the second matrix is simply the transpose of the first: + // X(k, i) = XT(i, k) = XT[k*lenx+i] + sum += XT[j*lenx+k]*XT[i*lenx+k]; // X[k*(deg+1)+i]; + } + prod[j*(deg+1)+i] = sum; + } + } + if(!linalg_invert_matrix(prod, deg+1)) { + // Although X was a Vandermonde matrix, whose inverse is guaranteed to exist, + // we bail out here, if prod couldn't be inverted: if the values in x are not all + // distinct, prod is singular + m_del(mp_float_t, XT, (deg+1)*lenx); + m_del(mp_float_t, x, lenx); + m_del(mp_float_t, y, lenx); + m_del(mp_float_t, prod, (deg+1)*(deg+1)); + mp_raise_ValueError(translate("could not invert Vandermonde matrix")); + } + // at this point, we have the inverse of X^T * X + // y is a column vector; x is free now, we can use it for storing intermediate values + for(uint8_t i=0; i < deg+1; i++) { // row index + sum = 0.0; + for(size_t j=0; j < lenx; j++) { // column index + sum += XT[i*lenx+j]*y[j]; + } + x[i] = sum; + } + // XT is no longer needed + m_del(mp_float_t, XT, (deg+1)*leny); + + ndarray_obj_t *beta = ndarray_new_linear_array(deg+1, NDARRAY_FLOAT); + mp_float_t *betav = (mp_float_t *)beta->array; + // x[0..(deg+1)] contains now the product X^T * y; we can get rid of y + m_del(float, y, leny); + + // now, we calculate beta, i.e., we apply prod = (X^T * X)^(-1) on x = X^T * y; x is a column vector now + for(uint8_t i=0; i < deg+1; i++) { + sum = 0.0; + for(uint8_t j=0; j < deg+1; j++) { + sum += prod[i*(deg+1)+j]*x[j]; + } + betav[i] = sum; + } + m_del(mp_float_t, x, lenx); + m_del(mp_float_t, prod, (deg+1)*(deg+1)); + for(uint8_t i=0; i < (deg+1)/2; i++) { + // We have to reverse the array, for the leading coefficient comes first. + SWAP(mp_float_t, betav[i], betav[deg-i]); + } + return MP_OBJ_FROM_PTR(beta); +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit); +#endif + +#if ULAB_NUMPY_HAS_POLYVAL + +mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) { + if(!ndarray_object_is_array_like(o_p) || !ndarray_object_is_array_like(o_x)) { + mp_raise_TypeError(translate("inputs are not iterable")); + } + // p had better be a one-dimensional standard iterable + uint8_t plen = mp_obj_get_int(mp_obj_len_maybe(o_p)); + mp_float_t *p = m_new(mp_float_t, plen); + mp_obj_iter_buf_t p_buf; + mp_obj_t p_item, p_iterable = mp_getiter(o_p, &p_buf); + uint8_t i = 0; + while((p_item = mp_iternext(p_iterable)) != MP_OBJ_STOP_ITERATION) { + p[i] = mp_obj_get_float(p_item); + i++; + } + + // polynomials are going to be of type float, except, when both + // the coefficients and the independent variable are integers + ndarray_obj_t *ndarray; + if(mp_obj_is_type(o_x, &ulab_ndarray_type)) { + ndarray_obj_t *source = MP_OBJ_TO_PTR(o_x); + uint8_t *sarray = (uint8_t *)source->array; + ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)ndarray->array; + + mp_float_t (*func)(void *) = ndarray_get_float_function(source->dtype); + + // TODO: these loops are really nothing, but the re-impplementation of + // ITERATE_VECTOR from vectorise.c. We could pass a function pointer here + #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 y = p[0]; + mp_float_t _x = func(sarray); + for(uint8_t m=0; m < plen-1; m++) { + y *= _x; + y += p[m+1]; + } + *array++ = y; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif + } else { + // o_x had better be a one-dimensional standard iterable + ndarray = ndarray_new_linear_array(mp_obj_get_int(mp_obj_len_maybe(o_x)), NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)ndarray->array; + mp_obj_iter_buf_t x_buf; + mp_obj_t x_item, x_iterable = mp_getiter(o_x, &x_buf); + while ((x_item = mp_iternext(x_iterable)) != MP_OBJ_STOP_ITERATION) { + mp_float_t _x = mp_obj_get_float(x_item); + mp_float_t y = p[0]; + for(uint8_t j=0; j < plen-1; j++) { + y *= _x; + y += p[j+1]; + } + *array++ = y; + } + } + m_del(mp_float_t, p, plen); + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval); +#endif diff --git a/python/port/mod/ulab/numpy/poly/poly.h b/python/port/mod/ulab/numpy/poly/poly.h new file mode 100644 index 000000000..cf66ab193 --- /dev/null +++ b/python/port/mod/ulab/numpy/poly/poly.h @@ -0,0 +1,21 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _POLY_ +#define _POLY_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj); +MP_DECLARE_CONST_FUN_OBJ_2(poly_polyval_obj); + +#endif diff --git a/python/port/mod/ulab/numpy/stats/stats.c b/python/port/mod/ulab/numpy/stats/stats.c new file mode 100644 index 000000000..9172b2340 --- /dev/null +++ b/python/port/mod/ulab/numpy/stats/stats.c @@ -0,0 +1,52 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Roberto Colistete Jr. + * 2020 Taku Fukada + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "stats.h" + +#if ULAB_MAX_DIMS > 1 +#if ULAB_NUMPY_HAS_TRACE + +//| def trace(m: ulab.numpy.ndarray) -> float: +//| """ +//| :param m: a square matrix +//| +//| Compute the trace of the matrix, the sum of its diagonal elements.""" +//| ... +//| + +static mp_obj_t stats_trace(mp_obj_t oin) { + ndarray_obj_t *ndarray = tools_object_is_square(oin); + mp_float_t trace = 0.0; + for(size_t i=0; i < ndarray->shape[ULAB_MAX_DIMS - 1]; i++) { + int32_t pos = i * (ndarray->strides[ULAB_MAX_DIMS - 1] + ndarray->strides[ULAB_MAX_DIMS - 2]); + trace += ndarray_get_float_index(ndarray->array, ndarray->dtype, pos/ndarray->itemsize); + } + if(ndarray->dtype == NDARRAY_FLOAT) { + return mp_obj_new_float(trace); + } + return mp_obj_new_int_from_float(trace); +} + +MP_DEFINE_CONST_FUN_OBJ_1(stats_trace_obj, stats_trace); +#endif +#endif diff --git a/python/port/mod/ulab/numpy/stats/stats.h b/python/port/mod/ulab/numpy/stats/stats.h new file mode 100644 index 000000000..e5fab5f9f --- /dev/null +++ b/python/port/mod/ulab/numpy/stats/stats.h @@ -0,0 +1,20 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _STATS_ +#define _STATS_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +MP_DECLARE_CONST_FUN_OBJ_1(stats_trace_obj); + +#endif diff --git a/python/port/mod/ulab/numpy/transform/transform.c b/python/port/mod/ulab/numpy/transform/transform.c new file mode 100644 index 000000000..71473f5c6 --- /dev/null +++ b/python/port/mod/ulab/numpy/transform/transform.c @@ -0,0 +1,89 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "transform.h" + + +#if ULAB_NUMPY_HAS_DOT +//| def dot(m1: ulab.numpy.ndarray, m2: ulab.numpy.ndarray) -> Union[ulab.numpy.ndarray, float]: +//| """ +//| :param ~ulab.numpy.ndarray m1: a matrix, or a vector +//| :param ~ulab.numpy.ndarray m2: a matrix, or a vector +//| +//| Computes the product of two matrices, or two vectors. In the letter case, the inner product is returned.""" +//| ... +//| + +mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) { + // TODO: should the results be upcast? + // This implements 2D operations only! + if(!mp_obj_is_type(_m1, &ulab_ndarray_type) || !mp_obj_is_type(_m2, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("arguments must be ndarrays")); + } + ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1); + ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2); + uint8_t *array1 = (uint8_t *)m1->array; + uint8_t *array2 = (uint8_t *)m2->array; + + mp_float_t (*func1)(void *) = ndarray_get_float_function(m1->dtype); + mp_float_t (*func2)(void *) = ndarray_get_float_function(m2->dtype); + + if(m1->shape[ULAB_MAX_DIMS - 1] != m2->shape[ULAB_MAX_DIMS - m2->ndim]) { + mp_raise_ValueError(translate("dimensions do not match")); + } + uint8_t ndim = MIN(m1->ndim, m2->ndim); + size_t shape1 = m1->ndim == 2 ? m1->shape[ULAB_MAX_DIMS - m1->ndim] : 1; + size_t shape2 = m2->ndim == 2 ? m2->shape[ULAB_MAX_DIMS - 1] : 1; + + size_t *shape = NULL; + if(ndim == 2) { // matrix times matrix -> matrix + shape = ndarray_shape_vector(0, 0, shape1, shape2); + } else { // matrix times vector -> vector, vector times vector -> vector (size 1) + shape = ndarray_shape_vector(0, 0, 0, shape1); + } + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + mp_float_t *rarray = (mp_float_t *)results->array; + + for(size_t i=0; i < shape1; i++) { // rows of m1 + for(size_t j=0; j < shape2; j++) { // columns of m2 + mp_float_t dot = 0.0; + for(size_t k=0; k < m1->shape[ULAB_MAX_DIMS - 1]; k++) { + // (i, k) * (k, j) + dot += func1(array1) * func2(array2); + array1 += m1->strides[ULAB_MAX_DIMS - 1]; + array2 += m2->strides[ULAB_MAX_DIMS - m2->ndim]; + } + *rarray++ = dot; + array1 -= m1->strides[ULAB_MAX_DIMS - 1] * m1->shape[ULAB_MAX_DIMS - 1]; + array2 -= m2->strides[ULAB_MAX_DIMS - m2->ndim] * m2->shape[ULAB_MAX_DIMS - m2->ndim]; + array2 += m2->strides[ULAB_MAX_DIMS - 1]; + } + array1 += m1->strides[ULAB_MAX_DIMS - m1->ndim]; + array2 = m2->array; + } + if((m1->ndim * m2->ndim) == 1) { // return a scalar, if product of two vectors + return mp_obj_new_float(*(--rarray)); + } else { + return MP_OBJ_FROM_PTR(results); + } +} + +MP_DEFINE_CONST_FUN_OBJ_2(transform_dot_obj, transform_dot); +#endif diff --git a/python/port/mod/ulab/numpy/transform/transform.h b/python/port/mod/ulab/numpy/transform/transform.h new file mode 100644 index 000000000..ba4194e3b --- /dev/null +++ b/python/port/mod/ulab/numpy/transform/transform.h @@ -0,0 +1,28 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * +*/ + +#ifndef _TRANSFORM_ +#define _TRANSFORM_ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "transform.h" + +MP_DECLARE_CONST_FUN_OBJ_2(transform_dot_obj); + +#endif diff --git a/python/port/mod/ulab/numpy/vector/vector.c b/python/port/mod/ulab/numpy/vector/vector.c new file mode 100644 index 000000000..bc8326c6d --- /dev/null +++ b/python/port/mod/ulab/numpy/vector/vector.c @@ -0,0 +1,635 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "vector.h" + +//| """Element-by-element functions +//| +//| These functions can operate on numbers, 1-D iterables, and arrays of 1 to 4 dimensions by +//| applying the function to every element in the array. This is typically +//| much more efficient than expressing the same operation as a Python loop.""" +//| +//| from ulab import _DType, _ArrayLike +//| + +static mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) { + // Return a single value, if o_in is not iterable + if(mp_obj_is_float(o_in) || mp_obj_is_int(o_in)) { + return mp_obj_new_float(f(mp_obj_get_float(o_in))); + } + ndarray_obj_t *ndarray = NULL; + if(mp_obj_is_type(o_in, &ulab_ndarray_type)) { + ndarray_obj_t *source = MP_OBJ_TO_PTR(o_in); + uint8_t *sarray = (uint8_t *)source->array; + ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_FLOAT); + mp_float_t *array = (mp_float_t *)ndarray->array; + + #if ULAB_VECTORISE_USES_FUN_POINTER + + mp_float_t (*func)(void *) = ndarray_get_float_function(source->dtype); + + #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 = func(sarray); + *array++ = f(value); + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif /* ULAB_MAX_DIMS > 1 */ + #if ULAB_MAX_DIMS > 2 + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif /* ULAB_MAX_DIMS > 2 */ + #if ULAB_MAX_DIMS > 3 + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif /* ULAB_MAX_DIMS > 3 */ + #else + if(source->dtype == NDARRAY_UINT8) { + ITERATE_VECTOR(uint8_t, array, source, sarray); + } else if(source->dtype == NDARRAY_INT8) { + ITERATE_VECTOR(int8_t, array, source, sarray); + } else if(source->dtype == NDARRAY_UINT16) { + ITERATE_VECTOR(uint16_t, array, source, sarray); + } else if(source->dtype == NDARRAY_INT16) { + ITERATE_VECTOR(int16_t, array, source, sarray); + } else { + ITERATE_VECTOR(mp_float_t, array, source, sarray); + } + #endif /* ULAB_VECTORISE_USES_FUN_POINTER */ + } else { + ndarray = ndarray_from_mp_obj(o_in, 0); + mp_float_t *array = (mp_float_t *)ndarray->array; + for(size_t i = 0; i < ndarray->len; i++) { + *array = f(*array); + array++; + } + } + return MP_OBJ_FROM_PTR(ndarray); +} + +#if ULAB_NUMPY_HAS_ACOS +//| def acos(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse cosine function""" +//| ... +//| + +MATH_FUN_1(acos, acos); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos); +#endif + +#if ULAB_NUMPY_HAS_ACOSH +//| def acosh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse hyperbolic cosine function""" +//| ... +//| + +MATH_FUN_1(acosh, acosh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh); +#endif + +#if ULAB_NUMPY_HAS_ASIN +//| def asin(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse sine function""" +//| ... +//| + +MATH_FUN_1(asin, asin); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin); +#endif + +#if ULAB_NUMPY_HAS_ASINH +//| def asinh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse hyperbolic sine function""" +//| ... +//| + +MATH_FUN_1(asinh, asinh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh); +#endif + +#if ULAB_NUMPY_HAS_AROUND +//| def around(a: _ArrayLike, *, decimals: int = 0) -> ulab.ndarray: +//| """Returns a new float array in which each element is rounded to +//| ``decimals`` places.""" +//| ... +//| + +mp_obj_t vectorise_around(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_const_none} }, + { MP_QSTR_decimals, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } } + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("first argument must be an ndarray")); + } + int8_t n = args[1].u_int; + mp_float_t mul = MICROPY_FLOAT_C_FUN(pow)(10.0, n); + ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0].u_obj); + ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_FLOAT); + mp_float_t *narray = (mp_float_t *)ndarray->array; + uint8_t *sarray = (uint8_t *)source->array; + + mp_float_t (*func)(void *) = ndarray_get_float_function(source->dtype); + + #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 f = func(sarray); + *narray++ = MICROPY_FLOAT_C_FUN(round)(f * mul) / mul; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(vectorise_around_obj, 1, vectorise_around); +#endif + +#if ULAB_NUMPY_HAS_ATAN +//| def atan(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse tangent function; the return values are in the +//| range [-pi/2,pi/2].""" +//| ... +//| + +MATH_FUN_1(atan, atan); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan); +#endif + +#if ULAB_NUMPY_HAS_ARCTAN2 +//| def arctan2(ya: _ArrayLike, xa: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse tangent function of y/x; the return values are in +//| the range [-pi, pi].""" +//| ... +//| + +mp_obj_t vectorise_arctan2(mp_obj_t y, mp_obj_t x) { + ndarray_obj_t *ndarray_x = ndarray_from_mp_obj(x, 0); + ndarray_obj_t *ndarray_y = ndarray_from_mp_obj(y, 0); + + uint8_t ndim = 0; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + int32_t *xstrides = m_new(int32_t, ULAB_MAX_DIMS); + int32_t *ystrides = m_new(int32_t, ULAB_MAX_DIMS); + if(!ndarray_can_broadcast(ndarray_x, ndarray_y, &ndim, shape, xstrides, ystrides)) { + mp_raise_ValueError(translate("operands could not be broadcast together")); + m_del(size_t, shape, ULAB_MAX_DIMS); + m_del(int32_t, xstrides, ULAB_MAX_DIMS); + m_del(int32_t, ystrides, ULAB_MAX_DIMS); + } + + uint8_t *xarray = (uint8_t *)ndarray_x->array; + uint8_t *yarray = (uint8_t *)ndarray_y->array; + + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT); + mp_float_t *rarray = (mp_float_t *)results->array; + + mp_float_t (*funcx)(void *) = ndarray_get_float_function(ndarray_x->dtype); + mp_float_t (*funcy)(void *) = ndarray_get_float_function(ndarray_y->dtype); + + #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 _x = funcx(xarray); + mp_float_t _y = funcy(yarray); + *rarray++ = MICROPY_FLOAT_C_FUN(atan2)(_y, _x); + xarray += xstrides[ULAB_MAX_DIMS - 1]; + yarray += ystrides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < results->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + xarray -= xstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1]; + xarray += xstrides[ULAB_MAX_DIMS - 2]; + yarray -= ystrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1]; + yarray += ystrides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < results->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + xarray -= xstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2]; + xarray += xstrides[ULAB_MAX_DIMS - 3]; + yarray -= ystrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2]; + yarray += ystrides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < results->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + xarray -= xstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3]; + xarray += xstrides[ULAB_MAX_DIMS - 4]; + yarray -= ystrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3]; + yarray += ystrides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < results->shape[ULAB_MAX_DIMS - 4]); + #endif + + return MP_OBJ_FROM_PTR(results); +} + +MP_DEFINE_CONST_FUN_OBJ_2(vectorise_arctan2_obj, vectorise_arctan2); +#endif /* ULAB_VECTORISE_HAS_ARCTAN2 */ + +#if ULAB_NUMPY_HAS_ATANH +//| def atanh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the inverse hyperbolic tangent function""" +//| ... +//| + +MATH_FUN_1(atanh, atanh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh); +#endif + +#if ULAB_NUMPY_HAS_CEIL +//| def ceil(a: _ArrayLike) -> ulab.ndarray: +//| """Rounds numbers up to the next whole number""" +//| ... +//| + +MATH_FUN_1(ceil, ceil); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil); +#endif + +#if ULAB_NUMPY_HAS_COS +//| def cos(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the cosine function""" +//| ... +//| + +MATH_FUN_1(cos, cos); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos); +#endif + +#if ULAB_NUMPY_HAS_COSH +//| def cosh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the hyperbolic cosine function""" +//| ... +//| + +MATH_FUN_1(cosh, cosh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cosh_obj, vectorise_cosh); +#endif + +#if ULAB_NUMPY_HAS_DEGREES +//| def degrees(a: _ArrayLike) -> ulab.ndarray: +//| """Converts angles from radians to degrees""" +//| ... +//| + +static mp_float_t vectorise_degrees_(mp_float_t value) { + return value * MICROPY_FLOAT_CONST(180.0) / MP_PI; +} + +static mp_obj_t vectorise_degrees(mp_obj_t x_obj) { + return vectorise_generic_vector(x_obj, vectorise_degrees_); +} + +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_degrees_obj, vectorise_degrees); +#endif + +#if ULAB_SCIPY_SPECIAL_HAS_ERF +//| def erf(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the error function, which has applications in statistics""" +//| ... +//| + +MATH_FUN_1(erf, erf); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf); +#endif + +#if ULAB_SCIPY_SPECIAL_HAS_ERFC +//| def erfc(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the complementary error function, which has applications in statistics""" +//| ... +//| + +MATH_FUN_1(erfc, erfc); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc); +#endif + +#if ULAB_NUMPY_HAS_EXP +//| def exp(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the exponent function.""" +//| ... +//| + +MATH_FUN_1(exp, exp); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp); +#endif + +#if ULAB_NUMPY_HAS_EXPM1 +//| def expm1(a: _ArrayLike) -> ulab.ndarray: +//| """Computes $e^x-1$. In certain applications, using this function preserves numeric accuracy better than the `exp` function.""" +//| ... +//| + +MATH_FUN_1(expm1, expm1); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1); +#endif + +#if ULAB_NUMPY_HAS_FLOOR +//| def floor(a: _ArrayLike) -> ulab.ndarray: +//| """Rounds numbers up to the next whole number""" +//| ... +//| + +MATH_FUN_1(floor, floor); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor); +#endif + +#if ULAB_SCIPY_SPECIAL_HAS_GAMMA +//| def gamma(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the gamma function""" +//| ... +//| + +MATH_FUN_1(gamma, tgamma); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma); +#endif + +#if ULAB_SCIPY_SPECIAL_HAS_GAMMALN +//| def lgamma(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the natural log of the gamma function""" +//| ... +//| + +MATH_FUN_1(lgamma, lgamma); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma); +#endif + +#if ULAB_NUMPY_HAS_LOG +//| def log(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the natural log""" +//| ... +//| + +MATH_FUN_1(log, log); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log); +#endif + +#if ULAB_NUMPY_HAS_LOG10 +//| def log10(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the log base 10""" +//| ... +//| + +MATH_FUN_1(log10, log10); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10); +#endif + +#if ULAB_NUMPY_HAS_LOG2 +//| def log2(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the log base 2""" +//| ... +//| + +MATH_FUN_1(log2, log2); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2); +#endif + +#if ULAB_NUMPY_HAS_RADIANS +//| def radians(a: _ArrayLike) -> ulab.ndarray: +//| """Converts angles from degrees to radians""" +//| ... +//| + +static mp_float_t vectorise_radians_(mp_float_t value) { + return value * MP_PI / MICROPY_FLOAT_CONST(180.0); +} + +static mp_obj_t vectorise_radians(mp_obj_t x_obj) { + return vectorise_generic_vector(x_obj, vectorise_radians_); +} + +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_radians_obj, vectorise_radians); +#endif + +#if ULAB_NUMPY_HAS_SIN +//| def sin(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the sine function""" +//| ... +//| + +MATH_FUN_1(sin, sin); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin); +#endif + +#if ULAB_NUMPY_HAS_SINH +//| def sinh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the hyperbolic sine""" +//| ... +//| + +MATH_FUN_1(sinh, sinh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh); +#endif + +#if ULAB_NUMPY_HAS_SQRT +//| def sqrt(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the square root""" +//| ... +//| + +MATH_FUN_1(sqrt, sqrt); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt); +#endif + +#if ULAB_NUMPY_HAS_TAN +//| def tan(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the tangent""" +//| ... +//| + +MATH_FUN_1(tan, tan); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan); +#endif + +#if ULAB_NUMPY_HAS_TANH +//| def tanh(a: _ArrayLike) -> ulab.ndarray: +//| """Computes the hyperbolic tangent""" +//| ... + +MATH_FUN_1(tanh, tanh); +MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh); +#endif + +#if ULAB_NUMPY_HAS_VECTORIZE +static mp_obj_t vectorise_vectorized_function_call(mp_obj_t self_in, size_t n_args, size_t n_kw, const mp_obj_t *args) { + (void) n_args; + (void) n_kw; + vectorized_function_obj_t *self = MP_OBJ_TO_PTR(self_in); + mp_obj_t avalue[1]; + mp_obj_t fvalue; + if(mp_obj_is_type(args[0], &ulab_ndarray_type)) { + ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0]); + ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, self->otypes); + for(size_t i=0; i < source->len; i++) { + avalue[0] = mp_binary_get_val_array(source->dtype, source->array, i); + fvalue = self->type->call(self->fun, 1, 0, avalue); + ndarray_set_value(self->otypes, ndarray->array, i, fvalue); + } + return MP_OBJ_FROM_PTR(ndarray); + } else if(mp_obj_is_type(args[0], &mp_type_tuple) || mp_obj_is_type(args[0], &mp_type_list) || + mp_obj_is_type(args[0], &mp_type_range)) { // i.e., the input is a generic iterable + size_t len = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); + ndarray_obj_t *ndarray = ndarray_new_linear_array(len, self->otypes); + mp_obj_iter_buf_t iter_buf; + mp_obj_t iterable = mp_getiter(args[0], &iter_buf); + size_t i=0; + while ((avalue[0] = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + fvalue = self->type->call(self->fun, 1, 0, avalue); + ndarray_set_value(self->otypes, ndarray->array, i, fvalue); + i++; + } + return MP_OBJ_FROM_PTR(ndarray); + } else if(mp_obj_is_int(args[0]) || mp_obj_is_float(args[0])) { + ndarray_obj_t *ndarray = ndarray_new_linear_array(1, self->otypes); + fvalue = self->type->call(self->fun, 1, 0, args); + ndarray_set_value(self->otypes, ndarray->array, 0, fvalue); + return MP_OBJ_FROM_PTR(ndarray); + } else { + mp_raise_ValueError(translate("wrong input type")); + } + return mp_const_none; +} + +const mp_obj_type_t vectorise_function_type = { + { &mp_type_type }, + .name = MP_QSTR_, + .call = vectorise_vectorized_function_call, +}; + +//| def vectorize( +//| f: Union[Callable[[int], float], Callable[[float], float]], +//| *, +//| otypes: Optional[_DType] = None +//| ) -> Callable[[_ArrayLike], ulab.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. +//| The callable must return only values of the types specified by ``otypes``, or the result is undefined.""" +//| ... +//| + +static mp_obj_t vectorise_vectorize(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_const_none} }, + { MP_QSTR_otypes, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} } + }; + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + const mp_obj_type_t *type = mp_obj_get_type(args[0].u_obj); + if(type->call == NULL) { + mp_raise_TypeError(translate("first argument must be a callable")); + } + mp_obj_t _otypes = args[1].u_obj; + uint8_t otypes = NDARRAY_FLOAT; + if(_otypes == mp_const_none) { + // TODO: is this what numpy does? + otypes = NDARRAY_FLOAT; + } else if(mp_obj_is_int(_otypes)) { + otypes = mp_obj_get_int(_otypes); + if(otypes != NDARRAY_FLOAT && otypes != NDARRAY_UINT8 && otypes != NDARRAY_INT8 && + otypes != NDARRAY_UINT16 && otypes != NDARRAY_INT16) { + mp_raise_ValueError(translate("wrong output type")); + } + } + else { + mp_raise_ValueError(translate("wrong output type")); + } + vectorized_function_obj_t *function = m_new_obj(vectorized_function_obj_t); + function->base.type = &vectorise_function_type; + function->otypes = otypes; + function->fun = args[0].u_obj; + function->type = type; + return MP_OBJ_FROM_PTR(function); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(vectorise_vectorize_obj, 1, vectorise_vectorize); +#endif diff --git a/python/port/mod/ulab/numpy/vector/vector.h b/python/port/mod/ulab/numpy/vector/vector.h new file mode 100644 index 000000000..6b00a221b --- /dev/null +++ b/python/port/mod/ulab/numpy/vector/vector.h @@ -0,0 +1,156 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef _VECTOR_ +#define _VECTOR_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acos_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acosh_obj); +MP_DECLARE_CONST_FUN_OBJ_2(vectorise_arctan2_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(vectorise_around_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asin_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asinh_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atan_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atanh_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_ceil_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_cos_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_cosh_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_degrees_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erf_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erfc_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_exp_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_expm1_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_floor_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_gamma_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_lgamma_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log10_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log2_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_radians_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sin_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sinh_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sqrt_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tan_obj); +MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tanh_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(vectorise_vectorize_obj); + +typedef struct _vectorized_function_obj_t { + mp_obj_base_t base; + uint8_t otypes; + mp_obj_t fun; + const mp_obj_type_t *type; +} vectorized_function_obj_t; + +#if ULAB_HAS_FUNCTION_ITERATOR +#define ITERATE_VECTOR(type, array, source, sarray)\ +({\ + size_t *scoords = ndarray_new_coords((source)->ndim);\ + for(size_t i=0; i < (source)->len/(source)->shape[ULAB_MAX_DIMS -1]; i++) {\ + for(size_t l=0; l < (source)->shape[ULAB_MAX_DIMS - 1]; l++) {\ + *(array)++ = f(*((type *)(sarray)));\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\ + }\ + ndarray_rewind_array((source)->ndim, sarray, (source)->shape, (source)->strides, scoords);\ + }\ +}) + +#else + +#if ULAB_MAX_DIMS == 4 +#define ITERATE_VECTOR(type, array, source, sarray) do {\ + size_t i=0;\ + do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = f(*((type *)(sarray)));\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (source)->shape[ULAB_MAX_DIMS-1]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (source)->shape[ULAB_MAX_DIMS-2]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS-2];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (source)->shape[ULAB_MAX_DIMS-3]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 3] * (source)->shape[ULAB_MAX_DIMS-3];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 4];\ + i++;\ + } while(i < (source)->shape[ULAB_MAX_DIMS-4]);\ +} while(0) +#endif /* ULAB_MAX_DIMS == 4 */ + +#if ULAB_MAX_DIMS == 3 +#define ITERATE_VECTOR(type, array, source, sarray) do {\ + size_t j = 0;\ + do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = f(*((type *)(sarray)));\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (source)->shape[ULAB_MAX_DIMS-1]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (source)->shape[ULAB_MAX_DIMS-2]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS-2];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\ + j++;\ + } while(j < (source)->shape[ULAB_MAX_DIMS-3]);\ +} while(0) +#endif /* ULAB_MAX_DIMS == 3 */ + +#if ULAB_MAX_DIMS == 2 +#define ITERATE_VECTOR(type, array, source, sarray) do {\ + size_t k = 0;\ + do {\ + size_t l = 0;\ + do {\ + *(array)++ = f(*((type *)(sarray)));\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (source)->shape[ULAB_MAX_DIMS-1]);\ + (sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\ + k++;\ + } while(k < (source)->shape[ULAB_MAX_DIMS-2]);\ +} while(0) +#endif /* ULAB_MAX_DIMS == 2 */ + +#if ULAB_MAX_DIMS == 1 +#define ITERATE_VECTOR(type, array, source, sarray) do {\ + size_t l = 0;\ + do {\ + *(array)++ = f(*((type *)(sarray)));\ + (sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\ + l++;\ + } while(l < (source)->shape[ULAB_MAX_DIMS-1]);\ +} while(0) +#endif /* ULAB_MAX_DIMS == 1 */ +#endif /* ULAB_HAS_FUNCTION_ITERATOR */ + +#define MATH_FUN_1(py_name, c_name) \ + static mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \ + return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \ +} + +#endif /* _VECTOR_ */ diff --git a/python/port/mod/ulab/scipy/linalg/linalg.c b/python/port/mod/ulab/scipy/linalg/linalg.c new file mode 100644 index 000000000..0f1b933af --- /dev/null +++ b/python/port/mod/ulab/scipy/linalg/linalg.c @@ -0,0 +1,279 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Vikas Udupa + * +*/ + +#include +#include +#include +#include +#include +#include + +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "linalg.h" + +#if ULAB_SCIPY_HAS_LINALG_MODULE +//| +//| import ulab.scipy +//| +//| """Linear algebra functions""" +//| + +#if ULAB_MAX_DIMS > 1 + +#define TOLERANCE 0.0000001 + +//| def solve_triangular(A: ulab.numpy.ndarray, b: ulab.numpy.ndarray, lower: bool) -> ulab.numpy.ndarray: +//| """ +//| :param ~ulab.numpy.ndarray A: a matrix +//| :param ~ulab.numpy.ndarray b: a vector +//| :param ~bool lower: if true, use only data contained in lower triangle of A, else use upper triangle of A +//| :return: solution to the system A x = b. Shape of return matches b +//| :raises TypeError: if A and b are not of type ndarray and are not dense +//| :raises ValueError: if A is a singular matrix +//| +//| Solve the equation A x = b for x, assuming A is a triangular matrix""" +//| ... +//| + +static mp_obj_t solve_triangular(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + + size_t i, j; + + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none} } , + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none} } , + { MP_QSTR_lower, MP_ARG_OBJ, { .u_rom_obj = mp_const_false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type) || !mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("first two arguments must be ndarrays")); + } + + ndarray_obj_t *A = MP_OBJ_TO_PTR(args[0].u_obj); + ndarray_obj_t *b = MP_OBJ_TO_PTR(args[1].u_obj); + + if(!ndarray_is_dense(A) || !ndarray_is_dense(b)) { + mp_raise_TypeError(translate("input must be a dense ndarray")); + } + + size_t A_rows = A->shape[ULAB_MAX_DIMS - 2]; + size_t A_cols = A->shape[ULAB_MAX_DIMS - 1]; + + uint8_t *A_arr = (uint8_t *)A->array; + uint8_t *b_arr = (uint8_t *)b->array; + + mp_float_t (*get_A_ele)(void *) = ndarray_get_float_function(A->dtype); + mp_float_t (*get_b_ele)(void *) = ndarray_get_float_function(b->dtype); + + uint8_t *temp_A = A_arr; + + // check if input matrix A is singular + for (i = 0; i < A_rows; i++) { + if (MICROPY_FLOAT_C_FUN(fabs)(get_A_ele(A_arr)) < TOLERANCE) + mp_raise_ValueError(translate("input matrix is singular")); + A_arr += A->strides[ULAB_MAX_DIMS - 2]; + A_arr += A->strides[ULAB_MAX_DIMS - 1]; + } + + A_arr = temp_A; + + ndarray_obj_t *x = ndarray_new_dense_ndarray(b->ndim, b->shape, NDARRAY_FLOAT); + mp_float_t *x_arr = (mp_float_t *)x->array; + + if (mp_obj_is_true(args[2].u_obj)) { + // Solve the lower triangular matrix by iterating each row of A. + // Start by finding the first unknown using the first row. + // On finding this unknown, find the second unknown using the second row. + // Continue the same till the last unknown is found using the last row. + + for (i = 0; i < A_rows; i++) { + mp_float_t sum = 0.0; + for (j = 0; j < i; j++) { + sum += (get_A_ele(A_arr) * (*x_arr++)); + A_arr += A->strides[ULAB_MAX_DIMS - 1]; + } + + sum = (get_b_ele(b_arr) - sum) / (get_A_ele(A_arr)); + *x_arr = sum; + + x_arr -= j; + A_arr -= A->strides[ULAB_MAX_DIMS - 1] * j; + A_arr += A->strides[ULAB_MAX_DIMS - 2]; + b_arr += b->strides[ULAB_MAX_DIMS - 1]; + } + } else { + // Solve the upper triangular matrix by iterating each row of A. + // Start by finding the last unknown using the last row. + // On finding this unknown, find the last-but-one unknown using the last-but-one row. + // Continue the same till the first unknown is found using the first row. + + A_arr += (A->strides[ULAB_MAX_DIMS - 2] * A_rows); + b_arr += (b->strides[ULAB_MAX_DIMS - 1] * A_cols); + x_arr += A_cols; + + for (i = A_rows - 1; i < A_rows; i--) { + mp_float_t sum = 0.0; + for (j = i + 1; j < A_cols; j++) { + sum += (get_A_ele(A_arr) * (*x_arr++)); + A_arr += A->strides[ULAB_MAX_DIMS - 1]; + } + + x_arr -= (j - i); + A_arr -= (A->strides[ULAB_MAX_DIMS - 1] * (j - i)); + b_arr -= b->strides[ULAB_MAX_DIMS - 1]; + + sum = (get_b_ele(b_arr) - sum) / get_A_ele(A_arr); + *x_arr = sum; + + A_arr -= A->strides[ULAB_MAX_DIMS - 2]; + } + } + + return MP_OBJ_FROM_PTR(x); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(linalg_solve_triangular_obj, 2, solve_triangular); + +//| def cho_solve(L: ulab.numpy.ndarray, b: ulab.numpy.ndarray) -> ulab.numpy.ndarray: +//| """ +//| :param ~ulab.numpy.ndarray L: the lower triangular, Cholesky factorization of A +//| :param ~ulab.numpy.ndarray b: right-hand-side vector b +//| :return: solution to the system A x = b. Shape of return matches b +//| :raises TypeError: if L and b are not of type ndarray and are not dense +//| +//| Solve the linear equations A x = b, given the Cholesky factorization of A as input""" +//| ... +//| + +static mp_obj_t cho_solve(mp_obj_t _L, mp_obj_t _b) { + + if(!mp_obj_is_type(_L, &ulab_ndarray_type) || !mp_obj_is_type(_b, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("first two arguments must be ndarrays")); + } + + ndarray_obj_t *L = MP_OBJ_TO_PTR(_L); + ndarray_obj_t *b = MP_OBJ_TO_PTR(_b); + + if(!ndarray_is_dense(L) || !ndarray_is_dense(b)) { + mp_raise_TypeError(translate("input must be a dense ndarray")); + } + + mp_float_t (*get_L_ele)(void *) = ndarray_get_float_function(L->dtype); + mp_float_t (*get_b_ele)(void *) = ndarray_get_float_function(b->dtype); + void (*set_L_ele)(void *, mp_float_t) = ndarray_set_float_function(L->dtype); + + size_t L_rows = L->shape[ULAB_MAX_DIMS - 2]; + size_t L_cols = L->shape[ULAB_MAX_DIMS - 1]; + + // Obtain transpose of the input matrix L in L_t + size_t L_t_shape[ULAB_MAX_DIMS]; + size_t L_t_rows = L_t_shape[ULAB_MAX_DIMS - 2] = L_cols; + size_t L_t_cols = L_t_shape[ULAB_MAX_DIMS - 1] = L_rows; + ndarray_obj_t *L_t = ndarray_new_dense_ndarray(L->ndim, L_t_shape, L->dtype); + + uint8_t *L_arr = (uint8_t *)L->array; + uint8_t *L_t_arr = (uint8_t *)L_t->array; + uint8_t *b_arr = (uint8_t *)b->array; + + size_t i, j; + + uint8_t *L_ptr = L_arr; + uint8_t *L_t_ptr = L_t_arr; + for (i = 0; i < L_rows; i++) { + for (j = 0; j < L_cols; j++) { + set_L_ele(L_t_ptr, get_L_ele(L_ptr)); + L_t_ptr += L_t->strides[ULAB_MAX_DIMS - 2]; + L_ptr += L->strides[ULAB_MAX_DIMS - 1]; + } + + L_t_ptr -= j * L_t->strides[ULAB_MAX_DIMS - 2]; + L_t_ptr += L_t->strides[ULAB_MAX_DIMS - 1]; + L_ptr -= j * L->strides[ULAB_MAX_DIMS - 1]; + L_ptr += L->strides[ULAB_MAX_DIMS - 2]; + } + + ndarray_obj_t *x = ndarray_new_dense_ndarray(b->ndim, b->shape, NDARRAY_FLOAT); + mp_float_t *x_arr = (mp_float_t *)x->array; + + ndarray_obj_t *y = ndarray_new_dense_ndarray(b->ndim, b->shape, NDARRAY_FLOAT); + mp_float_t *y_arr = (mp_float_t *)y->array; + + // solve L y = b to obtain y, where L_t x = y + for (i = 0; i < L_rows; i++) { + mp_float_t sum = 0.0; + for (j = 0; j < i; j++) { + sum += (get_L_ele(L_arr) * (*y_arr++)); + L_arr += L->strides[ULAB_MAX_DIMS - 1]; + } + + sum = (get_b_ele(b_arr) - sum) / (get_L_ele(L_arr)); + *y_arr = sum; + + y_arr -= j; + L_arr -= L->strides[ULAB_MAX_DIMS - 1] * j; + L_arr += L->strides[ULAB_MAX_DIMS - 2]; + b_arr += b->strides[ULAB_MAX_DIMS - 1]; + } + + // using y, solve L_t x = y to obtain x + L_t_arr += (L_t->strides[ULAB_MAX_DIMS - 2] * L_t_rows); + y_arr += L_t_cols; + x_arr += L_t_cols; + + for (i = L_t_rows - 1; i < L_t_rows; i--) { + mp_float_t sum = 0.0; + for (j = i + 1; j < L_t_cols; j++) { + sum += (get_L_ele(L_t_arr) * (*x_arr++)); + L_t_arr += L_t->strides[ULAB_MAX_DIMS - 1]; + } + + x_arr -= (j - i); + L_t_arr -= (L_t->strides[ULAB_MAX_DIMS - 1] * (j - i)); + y_arr--; + + sum = ((*y_arr) - sum) / get_L_ele(L_t_arr); + *x_arr = sum; + + L_t_arr -= L_t->strides[ULAB_MAX_DIMS - 2]; + } + + return MP_OBJ_FROM_PTR(x); +} + +MP_DEFINE_CONST_FUN_OBJ_2(linalg_cho_solve_obj, cho_solve); + +#endif + +static const mp_rom_map_elem_t ulab_scipy_linalg_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) }, + #if ULAB_MAX_DIMS > 1 + #if ULAB_SCIPY_LINALG_HAS_SOLVE_TRIANGULAR + { MP_ROM_QSTR(MP_QSTR_solve_triangular), (mp_obj_t)&linalg_solve_triangular_obj }, + #endif + #if ULAB_SCIPY_LINALG_HAS_CHO_SOLVE + { MP_ROM_QSTR(MP_QSTR_cho_solve), (mp_obj_t)&linalg_cho_solve_obj }, + #endif + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_linalg_globals, ulab_scipy_linalg_globals_table); + +mp_obj_module_t ulab_scipy_linalg_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_linalg_globals, +}; + +#endif diff --git a/python/port/mod/ulab/scipy/linalg/linalg.h b/python/port/mod/ulab/scipy/linalg/linalg.h new file mode 100644 index 000000000..7396affd6 --- /dev/null +++ b/python/port/mod/ulab/scipy/linalg/linalg.h @@ -0,0 +1,21 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2021 Vikas Udupa + * +*/ + +#ifndef _SCIPY_LINALG_ +#define _SCIPY_LINALG_ + +extern mp_obj_module_t ulab_scipy_linalg_module; + +MP_DECLARE_CONST_FUN_OBJ_KW(linalg_solve_triangular_obj); +MP_DECLARE_CONST_FUN_OBJ_2(linalg_cho_solve_obj); + +#endif /* _SCIPY_LINALG_ */ diff --git a/python/port/mod/ulab/scipy/optimize/optimize.c b/python/port/mod/ulab/scipy/optimize/optimize.c new file mode 100644 index 000000000..9218e6936 --- /dev/null +++ b/python/port/mod/ulab/scipy/optimize/optimize.c @@ -0,0 +1,414 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include + +#include "../../ndarray.h" +#include "../../ulab.h" +#include "../../ulab_tools.h" +#include "optimize.h" + +const mp_obj_float_t xtolerance = {{&mp_type_float}, MICROPY_FLOAT_CONST(2.4e-7)}; +const mp_obj_float_t rtolerance = {{&mp_type_float}, MICROPY_FLOAT_CONST(0.0)}; + +static mp_float_t optimize_python_call(const mp_obj_type_t *type, mp_obj_t fun, mp_float_t x, mp_obj_t *fargs, uint8_t nparams) { + // Helper function for calculating the value of f(x, a, b, c, ...), + // where f is defined in python. Takes a float, returns a float. + // The array of mp_obj_t type must be supplied, as must the number of parameters (a, b, c...) in nparams + fargs[0] = mp_obj_new_float(x); + return mp_obj_get_float(type->call(fun, nparams+1, 0, fargs)); +} + +#if ULAB_SCIPY_OPTIMIZE_HAS_BISECT +//| def bisect( +//| fun: Callable[[float], float], +//| a: float, +//| b: float, +//| *, +//| xtol: float = 2.4e-7, +//| maxiter: int = 100 +//| ) -> float: +//| """ +//| :param callable f: The function to bisect +//| :param float a: The left side of the interval +//| :param float b: The right side of the interval +//| :param float xtol: The tolerance value +//| :param float maxiter: The maximum number of iterations to perform +//| +//| Find a solution (zero) of the function ``f(x)`` on the interval +//| (``a``..``b``) using the bisection method. The result is accurate to within +//| ``xtol`` unless more than ``maxiter`` steps are required.""" +//| ... +//| + +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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_xtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} }, + { MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t fun = args[0].u_obj; + const mp_obj_type_t *type = mp_obj_get_type(fun); + if(type->call == NULL) { + mp_raise_TypeError(translate("first argument must be a function")); + } + mp_float_t xtol = mp_obj_get_float(args[3].u_obj); + mp_obj_t *fargs = m_new(mp_obj_t, 1); + mp_float_t left, right; + mp_float_t x_mid; + mp_float_t a = mp_obj_get_float(args[1].u_obj); + mp_float_t b = mp_obj_get_float(args[2].u_obj); + left = optimize_python_call(type, fun, a, fargs, 0); + right = optimize_python_call(type, fun, b, fargs, 0); + if(left * right > 0) { + mp_raise_ValueError(translate("function has the same sign at the ends of interval")); + } + mp_float_t rtb = left < MICROPY_FLOAT_CONST(0.0) ? a : b; + mp_float_t dx = left < MICROPY_FLOAT_CONST(0.0) ? b - a : a - b; + if(args[4].u_int < 0) { + mp_raise_ValueError(translate("maxiter should be > 0")); + } + for(uint16_t i=0; i < args[4].u_int; i++) { + dx *= MICROPY_FLOAT_CONST(0.5); + x_mid = rtb + dx; + if(optimize_python_call(type, fun, x_mid, fargs, 0) < MICROPY_FLOAT_CONST(0.0)) { + rtb = x_mid; + } + if(MICROPY_FLOAT_C_FUN(fabs)(dx) < xtol) break; + } + return mp_obj_new_float(rtb); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(optimize_bisect_obj, 3, optimize_bisect); +#endif + +#if ULAB_SCIPY_OPTIMIZE_HAS_FMIN +//| def fmin( +//| fun: Callable[[float], float], +//| x0: float, +//| *, +//| xatol: float = 2.4e-7, +//| fatol: float = 2.4e-7, +//| maxiter: int = 200 +//| ) -> float: +//| """ +//| :param callable f: The function to bisect +//| :param float x0: The initial x value +//| :param float xatol: The absolute tolerance value +//| :param float fatol: The relative tolerance value +//| +//| Find a minimum of the function ``f(x)`` using the downhill simplex method. +//| The located ``x`` is within ``fxtol`` of the actual minimum, and ``f(x)`` +//| is within ``fatol`` of the actual minimum unless more than ``maxiter`` +//| steps are requried.""" +//| ... +//| + +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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_xatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} }, + { MP_QSTR_fatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} }, + { MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 200} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t fun = args[0].u_obj; + const mp_obj_type_t *type = mp_obj_get_type(fun); + if(type->call == NULL) { + mp_raise_TypeError(translate("first argument must be a function")); + } + + // parameters controlling convergence conditions + mp_float_t xatol = mp_obj_get_float(args[2].u_obj); + mp_float_t fatol = mp_obj_get_float(args[3].u_obj); + if(args[4].u_int <= 0) { + mp_raise_ValueError(translate("maxiter must be > 0")); + } + uint16_t maxiter = (uint16_t)args[4].u_int; + + mp_float_t x0 = mp_obj_get_float(args[1].u_obj); + mp_float_t x1 = MICROPY_FLOAT_C_FUN(fabs)(x0) > OPTIMIZE_EPSILON ? (MICROPY_FLOAT_CONST(1.0) + OPTIMIZE_NONZDELTA) * x0 : OPTIMIZE_ZDELTA; + mp_obj_t *fargs = m_new(mp_obj_t, 1); + mp_float_t f0 = optimize_python_call(type, fun, x0, fargs, 0); + mp_float_t f1 = optimize_python_call(type, fun, x1, fargs, 0); + if(f1 < f0) { + SWAP(mp_float_t, x0, x1); + SWAP(mp_float_t, f0, f1); + } + for(uint16_t i=0; i < maxiter; i++) { + uint8_t shrink = 0; + f0 = optimize_python_call(type, fun, x0, fargs, 0); + f1 = optimize_python_call(type, fun, x1, fargs, 0); + + // reflection + mp_float_t xr = (MICROPY_FLOAT_CONST(1.0) + OPTIMIZE_ALPHA) * x0 - OPTIMIZE_ALPHA * x1; + mp_float_t fr = optimize_python_call(type, fun, xr, fargs, 0); + if(fr < f0) { // expansion + mp_float_t xe = (1 + OPTIMIZE_ALPHA * OPTIMIZE_BETA) * x0 - OPTIMIZE_ALPHA * OPTIMIZE_BETA * x1; + mp_float_t fe = optimize_python_call(type, fun, xe, fargs, 0); + if(fe < fr) { + x1 = xe; + f1 = fe; + } else { + x1 = xr; + f1 = fr; + } + } else { + if(fr < f1) { // contraction + mp_float_t xc = (1 + OPTIMIZE_GAMMA * OPTIMIZE_ALPHA) * x0 - OPTIMIZE_GAMMA * OPTIMIZE_ALPHA * x1; + mp_float_t fc = optimize_python_call(type, fun, xc, fargs, 0); + if(fc < fr) { + x1 = xc; + f1 = fc; + } else { + shrink = 1; + } + } else { // inside contraction + mp_float_t xc = (MICROPY_FLOAT_CONST(1.0) - OPTIMIZE_GAMMA) * x0 + OPTIMIZE_GAMMA * x1; + mp_float_t fc = optimize_python_call(type, fun, xc, fargs, 0); + if(fc < f1) { + x1 = xc; + f1 = fc; + } else { + shrink = 1; + } + } + if(shrink == 1) { + x1 = x0 + OPTIMIZE_DELTA * (x1 - x0); + f1 = optimize_python_call(type, fun, x1, fargs, 0); + } + if((MICROPY_FLOAT_C_FUN(fabs)(f1 - f0) < fatol) || + (MICROPY_FLOAT_C_FUN(fabs)(x1 - x0) < xatol)) { + break; + } + if(f1 < f0) { + SWAP(mp_float_t, x0, x1); + SWAP(mp_float_t, f0, f1); + } + } + } + return mp_obj_new_float(x0); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(optimize_fmin_obj, 2, optimize_fmin); +#endif + +#if ULAB_SCIPY_OPTIMIZE_HAS_CURVE_FIT +static void optimize_jacobi(const mp_obj_type_t *type, mp_obj_t fun, mp_float_t *x, mp_float_t *y, uint16_t len, mp_float_t *params, uint8_t nparams, mp_float_t *jacobi, mp_float_t *grad) { + /* Calculates the Jacobian and the gradient of the cost function + * + * The entries in the Jacobian are + * J(m, n) = de_m/da_n, + * + * where + * + * e_m = (f(x_m, a1, a2, ...) - y_m)/sigma_m is the error at x_m, + * + * and + * + * a1, a2, ..., a_n are the free parameters + */ + mp_obj_t *fargs0 = m_new(mp_obj_t, lenp+1); + mp_obj_t *fargs1 = m_new(mp_obj_t, lenp+1); + for(uint8_t p=0; p < nparams; p++) { + fargs0[p+1] = mp_obj_new_float(params[p]); + fargs1[p+1] = mp_obj_new_float(params[p]); + } + for(uint8_t p=0; p < nparams; p++) { + mp_float_t da = params[p] != MICROPY_FLOAT_CONST(0.0) ? (MICROPY_FLOAT_CONST(1.0) + APPROX_NONZDELTA) * params[p] : APPROX_ZDELTA; + fargs1[p+1] = mp_obj_new_float(params[p] + da); + grad[p] = MICROPY_FLOAT_CONST(0.0); + for(uint16_t i=0; i < len; i++) { + mp_float_t f0 = optimize_python_call(type, fun, x[i], fargs0, nparams); + mp_float_t f1 = optimize_python_call(type, fun, x[i], fargs1, nparams); + jacobi[i*nparamp+p] = (f1 - f0) / da; + grad[p] += (f0 - y[i]) * jacobi[i*nparamp+p]; + } + fargs1[p+1] = fargs0[p+1]; // set back to the original value + } +} + +static void optimize_delta(mp_float_t *jacobi, mp_float_t *grad, uint16_t len, uint8_t nparams, mp_float_t lambda) { + // +} + +mp_obj_t optimize_curve_fit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // Levenberg-Marquardt non-linear fit + // The implementation follows the introductory discussion in Mark Tanstrum's paper, https://arxiv.org/abs/1201.5885 + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_p0, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_xatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} }, + { MP_QSTR_fatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} }, + { MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t fun = args[0].u_obj; + const mp_obj_type_t *type = mp_obj_get_type(fun); + if(type->call == NULL) { + mp_raise_TypeError(translate("first argument must be a function")); + } + + mp_obj_t x_obj = args[1].u_obj; + mp_obj_t y_obj = args[2].u_obj; + mp_obj_t p0_obj = args[3].u_obj; + if(!ndarray_object_is_array_like(x_obj) || !ndarray_object_is_array_like(y_obj)) { + mp_raise_TypeError(translate("data must be iterable")); + } + if(!ndarray_object_is_nditerable(p0_obj)) { + mp_raise_TypeError(translate("initial values must be iterable")); + } + size_t len = (size_t)mp_obj_get_int(mp_obj_len_maybe(x_obj)); + uint8_t lenp = (uint8_t)mp_obj_get_int(mp_obj_len_maybe(p0_obj)); + if(len != (uint16_t)mp_obj_get_int(mp_obj_len_maybe(y_obj))) { + mp_raise_ValueError(translate("data must be of equal length")); + } + + mp_float_t *x = m_new(mp_float_t, len); + fill_array_iterable(x, x_obj); + mp_float_t *y = m_new(mp_float_t, len); + fill_array_iterable(y, y_obj); + mp_float_t *p0 = m_new(mp_float_t, lenp); + fill_array_iterable(p0, p0_obj); + mp_float_t *grad = m_new(mp_float_t, len); + mp_float_t *jacobi = m_new(mp_float_t, len*len); + mp_obj_t *fargs = m_new(mp_obj_t, lenp+1); + + m_del(mp_float_t, p0, lenp); + // parameters controlling convergence conditions + //mp_float_t xatol = mp_obj_get_float(args[2].u_obj); + //mp_float_t fatol = mp_obj_get_float(args[3].u_obj); + + // this has finite binary representation; we will multiply/divide by 4 + //mp_float_t lambda = 0.0078125; + + //linalg_invert_matrix(mp_float_t *data, size_t N) + + m_del(mp_float_t, x, len); + m_del(mp_float_t, y, len); + m_del(mp_float_t, grad, len); + m_del(mp_float_t, jacobi, len*len); + m_del(mp_obj_t, fargs, lenp+1); + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(optimize_curve_fit_obj, 2, optimize_curve_fit); +#endif + +#if ULAB_SCIPY_OPTIMIZE_HAS_NEWTON +//| def newton( +//| fun: Callable[[float], float], +//| x0: float, +//| *, +//| xtol: float = 2.4e-7, +//| rtol: float = 0.0, +//| maxiter: int = 50 +//| ) -> float: +//| """ +//| :param callable f: The function to bisect +//| :param float x0: The initial x value +//| :param float xtol: The absolute tolerance value +//| :param float rtol: The relative tolerance value +//| :param float maxiter: The maximum number of iterations to perform +//| +//| Find a solution (zero) of the function ``f(x)`` using Newton's Method. +//| The result is accurate to within ``xtol * rtol * |f(x)|`` unless more than +//| ``maxiter`` steps are requried.""" +//| ... +//| + +static mp_obj_t optimize_newton(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + // this is actually the secant method, as the first derivative of the function + // is not accepted as an argument. The function whose root we want to solve for + // must depend on a single variable without parameters, i.e., f(x) + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&xtolerance) } }, + { MP_QSTR_rtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&rtolerance) } }, + { MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 50 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + mp_obj_t fun = args[0].u_obj; + const mp_obj_type_t *type = mp_obj_get_type(fun); + if(type->call == NULL) { + mp_raise_TypeError(translate("first argument must be a function")); + } + mp_float_t x = mp_obj_get_float(args[1].u_obj); + mp_float_t tol = mp_obj_get_float(args[2].u_obj); + mp_float_t rtol = mp_obj_get_float(args[3].u_obj); + mp_float_t dx, df, fx; + dx = x > MICROPY_FLOAT_CONST(0.0) ? OPTIMIZE_EPS * x : -OPTIMIZE_EPS * x; + mp_obj_t *fargs = m_new(mp_obj_t, 1); + if(args[4].u_int <= 0) { + mp_raise_ValueError(translate("maxiter must be > 0")); + } + for(uint16_t i=0; i < args[4].u_int; i++) { + fx = optimize_python_call(type, fun, x, fargs, 0); + df = (optimize_python_call(type, fun, x + dx, fargs, 0) - fx) / dx; + dx = fx / df; + x -= dx; + if(MICROPY_FLOAT_C_FUN(fabs)(dx) < (tol + rtol * MICROPY_FLOAT_C_FUN(fabs)(x))) break; + } + return mp_obj_new_float(x); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(optimize_newton_obj, 2, optimize_newton); +#endif + +static const mp_rom_map_elem_t ulab_scipy_optimize_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_optimize) }, + #if ULAB_SCIPY_OPTIMIZE_HAS_BISECT + { MP_OBJ_NEW_QSTR(MP_QSTR_bisect), (mp_obj_t)&optimize_bisect_obj }, + #endif + #if ULAB_SCIPY_OPTIMIZE_HAS_CURVE_FIT + { MP_OBJ_NEW_QSTR(MP_QSTR_curve_fit), (mp_obj_t)&optimize_curve_fit_obj }, + #endif + #if ULAB_SCIPY_OPTIMIZE_HAS_FMIN + { MP_OBJ_NEW_QSTR(MP_QSTR_fmin), (mp_obj_t)&optimize_fmin_obj }, + #endif + #if ULAB_SCIPY_OPTIMIZE_HAS_NEWTON + { MP_OBJ_NEW_QSTR(MP_QSTR_newton), (mp_obj_t)&optimize_newton_obj }, + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_optimize_globals, ulab_scipy_optimize_globals_table); + +mp_obj_module_t ulab_scipy_optimize_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_optimize_globals, +}; diff --git a/python/port/mod/ulab/scipy/optimize/optimize.h b/python/port/mod/ulab/scipy/optimize/optimize.h new file mode 100644 index 000000000..5d956df49 --- /dev/null +++ b/python/port/mod/ulab/scipy/optimize/optimize.h @@ -0,0 +1,41 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * +*/ + +#ifndef _SCIPY_OPTIMIZE_ +#define _SCIPY_OPTIMIZE_ + +#include "../../ulab_tools.h" + +#ifndef OPTIMIZE_EPSILON +#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT +#define OPTIMIZE_EPSILON MICROPY_FLOAT_CONST(1.2e-7) +#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE +#define OPTIMIZE_EPSILON MICROPY_FLOAT_CONST(2.3e-16) +#endif +#endif + +#define OPTIMIZE_EPS MICROPY_FLOAT_CONST(1.0e-4) +#define OPTIMIZE_NONZDELTA MICROPY_FLOAT_CONST(0.05) +#define OPTIMIZE_ZDELTA MICROPY_FLOAT_CONST(0.00025) +#define OPTIMIZE_ALPHA MICROPY_FLOAT_CONST(1.0) +#define OPTIMIZE_BETA MICROPY_FLOAT_CONST(2.0) +#define OPTIMIZE_GAMMA MICROPY_FLOAT_CONST(0.5) +#define OPTIMIZE_DELTA MICROPY_FLOAT_CONST(0.5) + +extern mp_obj_module_t ulab_scipy_optimize_module; + +MP_DECLARE_CONST_FUN_OBJ_KW(optimize_bisect_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(optimize_curve_fit_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(optimize_fmin_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(optimize_newton_obj); + +#endif /* _SCIPY_OPTIMIZE_ */ diff --git a/python/port/mod/ulab/scipy/scipy.c b/python/port/mod/ulab/scipy/scipy.c new file mode 100644 index 000000000..3e3a8280f --- /dev/null +++ b/python/port/mod/ulab/scipy/scipy.c @@ -0,0 +1,51 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include + +#include "../ulab.h" +#include "optimize/optimize.h" +#include "signal/signal.h" +#include "special/special.h" +#include "linalg/linalg.h" + +#if ULAB_HAS_SCIPY + +//| """Compatibility layer for scipy""" +//| + +static const mp_rom_map_elem_t ulab_scipy_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_scipy) }, + #if ULAB_SCIPY_HAS_LINALG_MODULE + { MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_scipy_linalg_module) }, + #endif + #if ULAB_SCIPY_HAS_OPTIMIZE_MODULE + { MP_ROM_QSTR(MP_QSTR_optimize), MP_ROM_PTR(&ulab_scipy_optimize_module) }, + #endif + #if ULAB_SCIPY_HAS_SIGNAL_MODULE + { MP_ROM_QSTR(MP_QSTR_signal), MP_ROM_PTR(&ulab_scipy_signal_module) }, + #endif + #if ULAB_SCIPY_HAS_SPECIAL_MODULE + { MP_ROM_QSTR(MP_QSTR_special), MP_ROM_PTR(&ulab_scipy_special_module) }, + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_globals, ulab_scipy_globals_table); + +mp_obj_module_t ulab_scipy_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_globals, +}; +#endif diff --git a/python/port/mod/ulab/scipy/scipy.h b/python/port/mod/ulab/scipy/scipy.h new file mode 100644 index 000000000..ff287a5a1 --- /dev/null +++ b/python/port/mod/ulab/scipy/scipy.h @@ -0,0 +1,21 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * +*/ + +#ifndef _SCIPY_ +#define _SCIPY_ + +#include "../ulab.h" +#include "../ndarray.h" + +extern mp_obj_module_t ulab_scipy_module; + +#endif /* _SCIPY_ */ diff --git a/python/port/mod/ulab/scipy/signal/signal.c b/python/port/mod/ulab/scipy/signal/signal.c new file mode 100644 index 000000000..0dbafd2c1 --- /dev/null +++ b/python/port/mod/ulab/scipy/signal/signal.c @@ -0,0 +1,153 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include +#include + +#include "../../ulab.h" +#include "../../ndarray.h" +#include "../../numpy/fft/fft_tools.h" + +#if ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM +//| def spectrogram(r: ulab.ndarray) -> ulab.ndarray: +//| """ +//| :param ulab.ndarray r: A 1-dimension array of values whose size is a power of 2 +//| +//| Computes the spectrum of the input signal. This is the absolute value of the (complex-valued) fft of the signal. +//| This function is similar to scipy's ``scipy.signal.spectrogram``.""" +//| ... +//| + +mp_obj_t signal_spectrogram(size_t n_args, const mp_obj_t *args) { + if(n_args == 2) { + return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_SPECTROGRAM); + } else { + return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_SPECTROGRAM); + } +} + +MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_spectrogram_obj, 1, 2, signal_spectrogram); +#endif /* ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM */ + +#if ULAB_SCIPY_SIGNAL_HAS_SOSFILT +static void signal_sosfilt_array(mp_float_t *x, const mp_float_t *coeffs, mp_float_t *zf, const size_t len) { + for(size_t i=0; i < len; i++) { + mp_float_t xn = *x; + *x = coeffs[0] * xn + zf[0]; + zf[0] = zf[1] + coeffs[1] * xn - coeffs[4] * *x; + zf[1] = coeffs[2] * xn - coeffs[5] * *x; + x++; + } + x -= len; +} + +mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_sos, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + { MP_QSTR_zi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!ndarray_object_is_array_like(args[0].u_obj) || !ndarray_object_is_array_like(args[1].u_obj)) { + mp_raise_TypeError(translate("sosfilt requires iterable arguments")); + } + size_t lenx = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[1].u_obj)); + ndarray_obj_t *y = ndarray_new_linear_array(lenx, NDARRAY_FLOAT); + mp_float_t *yarray = (mp_float_t *)y->array; + mp_float_t coeffs[6]; + if(mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) { + ndarray_obj_t *inarray = MP_OBJ_TO_PTR(args[1].u_obj); + #if ULAB_MAX_DIMS > 1 + if(inarray->ndim > 1) { + mp_raise_ValueError(translate("input must be one-dimensional")); + } + #endif + uint8_t *iarray = (uint8_t *)inarray->array; + for(size_t i=0; i < lenx; i++) { + *yarray++ = ndarray_get_float_value(iarray, inarray->dtype); + iarray += inarray->strides[ULAB_MAX_DIMS - 1]; + } + yarray -= lenx; + } else { + fill_array_iterable(yarray, args[1].u_obj); + } + + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(args[0].u_obj, &iter_buf); + size_t lensos = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0].u_obj)); + + size_t *shape = ndarray_shape_vector(0, 0, lensos, 2); + ndarray_obj_t *zf = ndarray_new_dense_ndarray(2, shape, NDARRAY_FLOAT); + mp_float_t *zf_array = (mp_float_t *)zf->array; + + if(args[2].u_obj != mp_const_none) { + if(!mp_obj_is_type(args[2].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("zi must be an ndarray")); + } else { + ndarray_obj_t *zi = MP_OBJ_TO_PTR(args[2].u_obj); + if((zi->shape[ULAB_MAX_DIMS - 1] != lensos) || (zi->shape[ULAB_MAX_DIMS - 1] != 2)) { + mp_raise_ValueError(translate("zi must be of shape (n_section, 2)")); + } + if(zi->dtype != NDARRAY_FLOAT) { + mp_raise_ValueError(translate("zi must be of float type")); + } + // TODO: this won't work with sparse arrays + memcpy(zf_array, zi->array, 2*lensos*sizeof(mp_float_t)); + } + } + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + if(mp_obj_get_int(mp_obj_len_maybe(item)) != 6) { + mp_raise_ValueError(translate("sos array must be of shape (n_section, 6)")); + } else { + fill_array_iterable(coeffs, item); + if(coeffs[3] != MICROPY_FLOAT_CONST(1.0)) { + mp_raise_ValueError(translate("sos[:, 3] should be all ones")); + } + signal_sosfilt_array(yarray, coeffs, zf_array, lenx); + zf_array += 2; + } + } + if(args[2].u_obj == mp_const_none) { + return MP_OBJ_FROM_PTR(y); + } else { + mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL)); + tuple->items[0] = MP_OBJ_FROM_PTR(y); + tuple->items[1] = MP_OBJ_FROM_PTR(zf); + return tuple; + } +} + +MP_DEFINE_CONST_FUN_OBJ_KW(signal_sosfilt_obj, 2, signal_sosfilt); +#endif /* ULAB_SCIPY_SIGNAL_HAS_SOSFILT */ + +static const mp_rom_map_elem_t ulab_scipy_signal_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_signal) }, + #if ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM + { MP_OBJ_NEW_QSTR(MP_QSTR_spectrogram), (mp_obj_t)&signal_spectrogram_obj }, + #endif + #if ULAB_SCIPY_SIGNAL_HAS_SOSFILT + { MP_OBJ_NEW_QSTR(MP_QSTR_sosfilt), (mp_obj_t)&signal_sosfilt_obj }, + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_signal_globals, ulab_scipy_signal_globals_table); + +mp_obj_module_t ulab_scipy_signal_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_signal_globals, +}; diff --git a/python/port/mod/ulab/scipy/signal/signal.h b/python/port/mod/ulab/scipy/signal/signal.h new file mode 100644 index 000000000..d33220e62 --- /dev/null +++ b/python/port/mod/ulab/scipy/signal/signal.h @@ -0,0 +1,24 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * +*/ + +#ifndef _SCIPY_SIGNAL_ +#define _SCIPY_SIGNAL_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +extern mp_obj_module_t ulab_scipy_signal_module; + +MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(signal_spectrogram_obj); +MP_DECLARE_CONST_FUN_OBJ_KW(signal_sosfilt_obj); + +#endif /* _SCIPY_SIGNAL_ */ diff --git a/python/port/mod/ulab/scipy/special/special.c b/python/port/mod/ulab/scipy/special/special.c new file mode 100644 index 000000000..bd4cf87c4 --- /dev/null +++ b/python/port/mod/ulab/scipy/special/special.c @@ -0,0 +1,42 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2020 Scott Shawcroft for Adafruit Industries + * 2020-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include + +#include "../../ulab.h" +#include "../../numpy/vector/vector.h" + +static const mp_rom_map_elem_t ulab_scipy_special_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_special) }, + #if ULAB_SCIPY_SPECIAL_HAS_ERF + { MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj }, + #endif + #if ULAB_SCIPY_SPECIAL_HAS_ERFC + { MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj }, + #endif + #if ULAB_SCIPY_SPECIAL_HAS_GAMMA + { MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj }, + #endif + #if ULAB_SCIPY_SPECIAL_HAS_GAMMALN + { MP_OBJ_NEW_QSTR(MP_QSTR_gammaln), (mp_obj_t)&vectorise_lgamma_obj }, + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_special_globals, ulab_scipy_special_globals_table); + +mp_obj_module_t ulab_scipy_special_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_special_globals, +}; diff --git a/python/port/mod/ulab/scipy/special/special.h b/python/port/mod/ulab/scipy/special/special.h new file mode 100644 index 000000000..ca0bac58d --- /dev/null +++ b/python/port/mod/ulab/scipy/special/special.h @@ -0,0 +1,21 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + * +*/ + +#ifndef _SCIPY_SPECIAL_ +#define _SCIPY_SPECIAL_ + +#include "../../ulab.h" +#include "../../ndarray.h" + +extern mp_obj_module_t ulab_scipy_special_module; + +#endif /* _SCIPY_SPECIAL_ */ diff --git a/python/port/mod/ulab/ulab.c b/python/port/mod/ulab/ulab.c new file mode 100644 index 000000000..d7a563c85 --- /dev/null +++ b/python/port/mod/ulab/ulab.c @@ -0,0 +1,162 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös + * 2020 Jeff Epler for Adafruit Industries +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "ulab.h" +#include "ulab_create.h" +#include "ndarray.h" +#include "ndarray_properties.h" + +#include "numpy/numpy.h" +#include "scipy/scipy.h" +#include "numpy/fft/fft.h" +#include "numpy/linalg/linalg.h" +// TODO: we should get rid of this; array.sort depends on it +#include "numpy/numerical/numerical.h" + +#include "user/user.h" +#include "utils/utils.h" + +#define ULAB_VERSION 3.1.0 +#define xstr(s) str(s) +#define str(s) #s +#define ULAB_VERSION_STRING xstr(ULAB_VERSION) xstr(-) xstr(ULAB_MAX_DIMS) xstr(D) + +STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, ULAB_VERSION_STRING); + + +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) }, + #endif + #if NDARRAY_HAS_TRANSPOSE + { MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ndarray_transpose_obj) }, + #endif + #endif + #if NDARRAY_HAS_BYTESWAP + { MP_ROM_QSTR(MP_QSTR_byteswap), MP_ROM_PTR(&ndarray_byteswap_obj) }, + #endif + #if NDARRAY_HAS_COPY + { MP_ROM_QSTR(MP_QSTR_copy), MP_ROM_PTR(&ndarray_copy_obj) }, + #endif + #if NDARRAY_HAS_FLATTEN + { MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) }, + #endif + #if NDARRAY_HAS_TOBYTES + { MP_ROM_QSTR(MP_QSTR_tobytes), MP_ROM_PTR(&ndarray_tobytes_obj) }, + #endif + #if NDARRAY_HAS_SORT + { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) }, + #endif + #ifdef CIRCUITPY + #if NDARRAY_HAS_DTYPE + { MP_ROM_QSTR(MP_QSTR_dtype), MP_ROM_PTR(&ndarray_dtype_obj) }, + #endif + #if NDARRAY_HAS_ITEMSIZE + { MP_ROM_QSTR(MP_QSTR_itemsize), MP_ROM_PTR(&ndarray_itemsize_obj) }, + #endif + #if NDARRAY_HAS_SHAPE + { MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) }, + #endif + #if NDARRAY_HAS_SIZE + { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) }, + #endif + #if NDARRAY_HAS_STRIDES + { MP_ROM_QSTR(MP_QSTR_strides), MP_ROM_PTR(&ndarray_strides_obj) }, + #endif + #endif /* CIRCUITPY */ +}; + +STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table); + +const mp_obj_type_t ulab_ndarray_type = { + { &mp_type_type }, + #if defined(MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) && defined(MP_TYPE_FLAG_EQ_HAS_NEQ_TEST) + .flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST, + #endif + .name = MP_QSTR_ndarray, + .print = ndarray_print, + .make_new = ndarray_make_new, + #if NDARRAY_IS_SLICEABLE + .subscr = ndarray_subscr, + #endif + #if NDARRAY_IS_ITERABLE + .getiter = ndarray_getiter, + #endif + #if NDARRAY_HAS_UNARY_OPS + .unary_op = ndarray_unary_op, + #endif + #if NDARRAY_HAS_BINARY_OPS + .binary_op = ndarray_binary_op, + #endif + #ifndef CIRCUITPY + .attr = ndarray_properties_attr, + #endif + .buffer_p = { .get_buffer = ndarray_get_buffer, }, + .locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict, +}; + +#if ULAB_HAS_DTYPE_OBJECT +const mp_obj_type_t ulab_dtype_type = { + { &mp_type_type }, + .name = MP_QSTR_dtype, + .print = ndarray_dtype_print, + .make_new = ndarray_dtype_make_new, +}; +#endif + +STATIC const mp_map_elem_t ulab_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) }, + { MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) }, + #if ULAB_HAS_DTYPE_OBJECT + { MP_OBJ_NEW_QSTR(MP_QSTR_dtype), (mp_obj_t)&ulab_dtype_type }, + #else + #if NDARRAY_HAS_DTYPE + { MP_OBJ_NEW_QSTR(MP_QSTR_dtype), (mp_obj_t)&ndarray_dtype_obj }, + #endif /* NDARRAY_HAS_DTYPE */ + #endif /* ULAB_HAS_DTYPE_OBJECT */ + { MP_ROM_QSTR(MP_QSTR_numpy), MP_ROM_PTR(&ulab_numpy_module) }, + #if ULAB_HAS_SCIPY + { MP_ROM_QSTR(MP_QSTR_scipy), MP_ROM_PTR(&ulab_scipy_module) }, + #endif + #if ULAB_HAS_USER_MODULE + { MP_ROM_QSTR(MP_QSTR_user), MP_ROM_PTR(&ulab_user_module) }, + #endif + #if ULAB_HAS_UTILS_MODULE + { MP_ROM_QSTR(MP_QSTR_utils), MP_ROM_PTR(&ulab_utils_module) }, + #endif +}; + +STATIC MP_DEFINE_CONST_DICT ( + mp_module_ulab_globals, + ulab_globals_table +); + +#ifdef OPENMV +const struct _mp_obj_module_t ulab_user_cmodule = { +#else +const mp_obj_module_t ulab_user_cmodule = { +#endif + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_globals, +}; + +MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED); diff --git a/python/port/mod/ulab/ulab.h b/python/port/mod/ulab/ulab.h new file mode 100644 index 000000000..e38310020 --- /dev/null +++ b/python/port/mod/ulab/ulab.h @@ -0,0 +1,658 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019-2021 Zoltán Vörös +*/ + +#ifndef __ULAB__ +#define __ULAB__ + + + +// The pre-processor constants in this file determine how ulab behaves: +// +// - how many dimensions ulab can handle +// - which functions are included in the compiled firmware +// - whether the python syntax is numpy-like, or modular +// - whether arrays can be sliced and iterated over +// - which binary/unary operators are supported +// +// 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 +// make -DULAB_CONFIG_FILE="my_ulab_config.h" +#if defined(ULAB_CONFIG_FILE) +#include ULAB_CONFIG_FILE +#endif + + +// Determines, whether scipy is defined in ulab. The sub-modules and functions +// of scipy have to be defined separately +#ifndef ULAB_HAS_SCIPY +#define ULAB_HAS_SCIPY (0) +#endif + +// The maximum number of dimensions the firmware should be able to support +// Possible values lie between 1, and 4, inclusive +#define ULAB_MAX_DIMS 2 + +// By setting this constant to 1, iteration over array dimensions will be implemented +// as a function (ndarray_rewind_array), instead of writing out the loops in macros +// This reduces firmware size at the expense of speed +#define ULAB_HAS_FUNCTION_ITERATOR (0) + +// If NDARRAY_IS_ITERABLE is 1, the ndarray object defines its own iterator function +// This option saves approx. 250 bytes of flash space +#ifndef NDARRAY_IS_ITERABLE +#define NDARRAY_IS_ITERABLE (1) +#endif + +// Slicing can be switched off by setting this variable to 0 +#ifndef NDARRAY_IS_SLICEABLE +#define NDARRAY_IS_SLICEABLE (1) +#endif + +// The default threshold for pretty printing. These variables can be overwritten +// at run-time via the set_printoptions() function +#ifndef ULAB_HAS_PRINTOPTIONS +#define ULAB_HAS_PRINTOPTIONS (1) +#endif +#define NDARRAY_PRINT_THRESHOLD 10 +#define NDARRAY_PRINT_EDGEITEMS 3 + +// determines, whether the dtype is an object, or simply a character +// the object implementation is numpythonic, but requires more space +#ifndef ULAB_HAS_DTYPE_OBJECT +#define ULAB_HAS_DTYPE_OBJECT (0) +#endif + +// the ndarray binary operators +#ifndef NDARRAY_HAS_BINARY_OPS +#define NDARRAY_HAS_BINARY_OPS (1) +#endif + +// Firmware size can be reduced at the expense of speed by using function +// pointers in iterations. For each operator, he function pointer saves around +// 2 kB in the two-dimensional case, and around 4 kB in the four-dimensional case. + +#ifndef NDARRAY_BINARY_USES_FUN_POINTER +#define NDARRAY_BINARY_USES_FUN_POINTER (0) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_ADD +#define NDARRAY_HAS_BINARY_OP_ADD (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_EQUAL +#define NDARRAY_HAS_BINARY_OP_EQUAL (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_LESS +#define NDARRAY_HAS_BINARY_OP_LESS (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_LESS_EQUAL +#define NDARRAY_HAS_BINARY_OP_LESS_EQUAL (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_MORE +#define NDARRAY_HAS_BINARY_OP_MORE (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_MORE_EQUAL +#define NDARRAY_HAS_BINARY_OP_MORE_EQUAL (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_MULTIPLY +#define NDARRAY_HAS_BINARY_OP_MULTIPLY (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_NOT_EQUAL +#define NDARRAY_HAS_BINARY_OP_NOT_EQUAL (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_POWER +#define NDARRAY_HAS_BINARY_OP_POWER (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_SUBTRACT +#define NDARRAY_HAS_BINARY_OP_SUBTRACT (1) +#endif + +#ifndef NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE +#define NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_OPS +#define NDARRAY_HAS_INPLACE_OPS (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_ADD +#define NDARRAY_HAS_INPLACE_ADD (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_MULTIPLY +#define NDARRAY_HAS_INPLACE_MULTIPLY (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_POWER +#define NDARRAY_HAS_INPLACE_POWER (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_SUBTRACT +#define NDARRAY_HAS_INPLACE_SUBTRACT (1) +#endif + +#ifndef NDARRAY_HAS_INPLACE_TRUE_DIVIDE +#define NDARRAY_HAS_INPLACE_TRUE_DIVIDE (1) +#endif + +// the ndarray unary operators +#ifndef NDARRAY_HAS_UNARY_OPS +#define NDARRAY_HAS_UNARY_OPS (1) +#endif + +#ifndef NDARRAY_HAS_UNARY_OP_ABS +#define NDARRAY_HAS_UNARY_OP_ABS (1) +#endif + +#ifndef NDARRAY_HAS_UNARY_OP_INVERT +#define NDARRAY_HAS_UNARY_OP_INVERT (1) +#endif + +#ifndef NDARRAY_HAS_UNARY_OP_LEN +#define NDARRAY_HAS_UNARY_OP_LEN (1) +#endif + +#ifndef NDARRAY_HAS_UNARY_OP_NEGATIVE +#define NDARRAY_HAS_UNARY_OP_NEGATIVE (1) +#endif + +#ifndef NDARRAY_HAS_UNARY_OP_POSITIVE +#define NDARRAY_HAS_UNARY_OP_POSITIVE (1) +#endif + + +// determines, which ndarray methods are available +#ifndef NDARRAY_HAS_BYTESWAP +#define NDARRAY_HAS_BYTESWAP (1) +#endif + +#ifndef NDARRAY_HAS_COPY +#define NDARRAY_HAS_COPY (1) +#endif + +#ifndef NDARRAY_HAS_DTYPE +#define NDARRAY_HAS_DTYPE (1) +#endif + +#ifndef NDARRAY_HAS_FLATTEN +#define NDARRAY_HAS_FLATTEN (1) +#endif + +#ifndef NDARRAY_HAS_ITEMSIZE +#define NDARRAY_HAS_ITEMSIZE (1) +#endif + +#ifndef NDARRAY_HAS_RESHAPE +#define NDARRAY_HAS_RESHAPE (1) +#endif + +#ifndef NDARRAY_HAS_SHAPE +#define NDARRAY_HAS_SHAPE (1) +#endif + +#ifndef NDARRAY_HAS_SIZE +#define NDARRAY_HAS_SIZE (1) +#endif + +#ifndef NDARRAY_HAS_SORT +#define NDARRAY_HAS_SORT (1) +#endif + +#ifndef NDARRAY_HAS_STRIDES +#define NDARRAY_HAS_STRIDES (1) +#endif + +#ifndef NDARRAY_HAS_TOBYTES +#define NDARRAY_HAS_TOBYTES (0) +#endif + +#ifndef NDARRAY_HAS_TRANSPOSE +#define NDARRAY_HAS_TRANSPOSE (1) +#endif + +// Firmware size can be reduced at the expense of speed by using a function +// pointer in iterations. Setting ULAB_VECTORISE_USES_FUNCPOINTER to 1 saves +// around 800 bytes in the four-dimensional case, and around 200 in two dimensions. +#ifndef ULAB_VECTORISE_USES_FUN_POINTER +#define ULAB_VECTORISE_USES_FUN_POINTER (1) +#endif + +// determines, whether e is defined in ulab.numpy itself +#ifndef ULAB_NUMPY_HAS_E +#define ULAB_NUMPY_HAS_E (1) +#endif + +// ulab defines infinite as a class constant in ulab.numpy +#ifndef ULAB_NUMPY_HAS_INF +#define ULAB_NUMPY_HAS_INF (1) +#endif + +// ulab defines NaN as a class constant in ulab.numpy +#ifndef ULAB_NUMPY_HAS_NAN +#define ULAB_NUMPY_HAS_NAN (1) +#endif + +// determines, whether pi is defined in ulab.numpy itself +#ifndef ULAB_NUMPY_HAS_PI +#define ULAB_NUMPY_HAS_PI (1) +#endif + +// determines, whether the ndinfo function is available +#ifndef ULAB_NUMPY_HAS_NDINFO +#define ULAB_NUMPY_HAS_NDINFO (1) +#endif + +// frombuffer adds 600 bytes to the firmware +#ifndef ULAB_NUMPY_HAS_FROMBUFFER +#define ULAB_NUMPY_HAS_FROMBUFFER (1) +#endif + +// functions that create an array +#ifndef ULAB_NUMPY_HAS_ARANGE +#define ULAB_NUMPY_HAS_ARANGE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_CONCATENATE +#define ULAB_NUMPY_HAS_CONCATENATE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_DIAG +#define ULAB_NUMPY_HAS_DIAG (1) +#endif + +#ifndef ULAB_NUMPY_HAS_EMPTY +#define ULAB_NUMPY_HAS_EMPTY (1) +#endif + +#ifndef ULAB_NUMPY_HAS_EYE +#define ULAB_NUMPY_HAS_EYE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_FULL +#define ULAB_NUMPY_HAS_FULL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_LINSPACE +#define ULAB_NUMPY_HAS_LINSPACE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_LOGSPACE +#define ULAB_NUMPY_HAS_LOGSPACE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ONES +#define ULAB_NUMPY_HAS_ONES (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ZEROS +#define ULAB_NUMPY_HAS_ZEROS (1) +#endif + +// functions that compare arrays +#ifndef ULAB_NUMPY_HAS_CLIP +#define ULAB_NUMPY_HAS_CLIP (1) +#endif + +#ifndef ULAB_NUMPY_HAS_EQUAL +#define ULAB_NUMPY_HAS_EQUAL (1) +#endif + +#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 +#define ULAB_NUMPY_HAS_MAXIMUM (1) +#endif + +#ifndef ULAB_NUMPY_HAS_MINIMUM +#define ULAB_NUMPY_HAS_MINIMUM (1) +#endif + +#ifndef ULAB_NUMPY_HAS_NOTEQUAL +#define ULAB_NUMPY_HAS_NOTEQUAL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_WHERE +#define ULAB_NUMPY_HAS_WHERE (1) +#endif + +// the linalg module; functions of the linalg module still have +// to be defined separately +#ifndef ULAB_NUMPY_HAS_LINALG_MODULE +#define ULAB_NUMPY_HAS_LINALG_MODULE (1) +#endif + +#ifndef ULAB_LINALG_HAS_CHOLESKY +#define ULAB_LINALG_HAS_CHOLESKY (1) +#endif + +#ifndef ULAB_LINALG_HAS_DET +#define ULAB_LINALG_HAS_DET (1) +#endif + +#ifndef ULAB_LINALG_HAS_EIG +#define ULAB_LINALG_HAS_EIG (1) +#endif + +#ifndef ULAB_LINALG_HAS_INV +#define ULAB_LINALG_HAS_INV (1) +#endif + +#ifndef ULAB_LINALG_HAS_NORM +#define ULAB_LINALG_HAS_NORM (1) +#endif + +// the FFT module; functions of the fft module still have +// to be defined separately +#ifndef ULAB_NUMPY_HAS_FFT_MODULE +#define ULAB_NUMPY_HAS_FFT_MODULE (1) +#endif + +#ifndef ULAB_FFT_HAS_FFT +#define ULAB_FFT_HAS_FFT (1) +#endif + +#ifndef ULAB_FFT_HAS_IFFT +#define ULAB_FFT_HAS_IFFT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ALL +#define ULAB_NUMPY_HAS_ALL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ANY +#define ULAB_NUMPY_HAS_ANY (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ARGMINMAX +#define ULAB_NUMPY_HAS_ARGMINMAX (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ARGSORT +#define ULAB_NUMPY_HAS_ARGSORT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_CONVOLVE +#define ULAB_NUMPY_HAS_CONVOLVE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_CROSS +#define ULAB_NUMPY_HAS_CROSS (1) +#endif + +#ifndef ULAB_NUMPY_HAS_DIFF +#define ULAB_NUMPY_HAS_DIFF (1) +#endif + +#ifndef ULAB_NUMPY_HAS_DOT +#define ULAB_NUMPY_HAS_DOT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_FLIP +#define ULAB_NUMPY_HAS_FLIP (1) +#endif + +#ifndef ULAB_NUMPY_HAS_INTERP +#define ULAB_NUMPY_HAS_INTERP (1) +#endif + +#ifndef ULAB_NUMPY_HAS_MEAN +#define ULAB_NUMPY_HAS_MEAN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_MEDIAN +#define ULAB_NUMPY_HAS_MEDIAN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_MINMAX +#define ULAB_NUMPY_HAS_MINMAX (1) +#endif + +#ifndef ULAB_NUMPY_HAS_POLYFIT +#define ULAB_NUMPY_HAS_POLYFIT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_POLYVAL +#define ULAB_NUMPY_HAS_POLYVAL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ROLL +#define ULAB_NUMPY_HAS_ROLL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_SORT +#define ULAB_NUMPY_HAS_SORT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_STD +#define ULAB_NUMPY_HAS_STD (1) +#endif + +#ifndef ULAB_NUMPY_HAS_SUM +#define ULAB_NUMPY_HAS_SUM (1) +#endif + +#ifndef ULAB_NUMPY_HAS_TRACE +#define ULAB_NUMPY_HAS_TRACE (1) +#endif + +#ifndef ULAB_NUMPY_HAS_TRAPZ +#define ULAB_NUMPY_HAS_TRAPZ (1) +#endif + +// vectorised versions of the functions of the math python module, with +// the exception of the functions listed in scipy.special +#ifndef ULAB_NUMPY_HAS_ACOS +#define ULAB_NUMPY_HAS_ACOS (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ACOSH +#define ULAB_NUMPY_HAS_ACOSH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ARCTAN2 +#define ULAB_NUMPY_HAS_ARCTAN2 (1) +#endif + +#ifndef ULAB_NUMPY_HAS_AROUND +#define ULAB_NUMPY_HAS_AROUND (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ASIN +#define ULAB_NUMPY_HAS_ASIN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ASINH +#define ULAB_NUMPY_HAS_ASINH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ATAN +#define ULAB_NUMPY_HAS_ATAN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_ATANH +#define ULAB_NUMPY_HAS_ATANH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_CEIL +#define ULAB_NUMPY_HAS_CEIL (1) +#endif + +#ifndef ULAB_NUMPY_HAS_COS +#define ULAB_NUMPY_HAS_COS (1) +#endif + +#ifndef ULAB_NUMPY_HAS_COSH +#define ULAB_NUMPY_HAS_COSH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_DEGREES +#define ULAB_NUMPY_HAS_DEGREES (1) +#endif + +#ifndef ULAB_NUMPY_HAS_EXP +#define ULAB_NUMPY_HAS_EXP (1) +#endif + +#ifndef ULAB_NUMPY_HAS_EXPM1 +#define ULAB_NUMPY_HAS_EXPM1 (1) +#endif + +#ifndef ULAB_NUMPY_HAS_FLOOR +#define ULAB_NUMPY_HAS_FLOOR (1) +#endif + +#ifndef ULAB_NUMPY_HAS_LOG +#define ULAB_NUMPY_HAS_LOG (1) +#endif + +#ifndef ULAB_NUMPY_HAS_LOG10 +#define ULAB_NUMPY_HAS_LOG10 (1) +#endif + +#ifndef ULAB_NUMPY_HAS_LOG2 +#define ULAB_NUMPY_HAS_LOG2 (1) +#endif + +#ifndef ULAB_NUMPY_HAS_RADIANS +#define ULAB_NUMPY_HAS_RADIANS (1) +#endif + +#ifndef ULAB_NUMPY_HAS_SIN +#define ULAB_NUMPY_HAS_SIN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_SINH +#define ULAB_NUMPY_HAS_SINH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_SQRT +#define ULAB_NUMPY_HAS_SQRT (1) +#endif + +#ifndef ULAB_NUMPY_HAS_TAN +#define ULAB_NUMPY_HAS_TAN (1) +#endif + +#ifndef ULAB_NUMPY_HAS_TANH +#define ULAB_NUMPY_HAS_TANH (1) +#endif + +#ifndef ULAB_NUMPY_HAS_VECTORIZE +#define ULAB_NUMPY_HAS_VECTORIZE (1) +#endif + +#ifndef ULAB_SCIPY_HAS_LINALG_MODULE +#define ULAB_SCIPY_HAS_LINALG_MODULE (1) +#endif + +#ifndef ULAB_SCIPY_LINALG_HAS_CHO_SOLVE +#define ULAB_SCIPY_LINALG_HAS_CHO_SOLVE (1) +#endif + +#ifndef ULAB_SCIPY_LINALG_HAS_SOLVE_TRIANGULAR +#define ULAB_SCIPY_LINALG_HAS_SOLVE_TRIANGULAR (1) +#endif + +#ifndef ULAB_SCIPY_HAS_SIGNAL_MODULE +#define ULAB_SCIPY_HAS_SIGNAL_MODULE (1) +#endif + +#ifndef ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM +#define ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM (1) +#endif + +#ifndef ULAB_SCIPY_SIGNAL_HAS_SOSFILT +#define ULAB_SCIPY_SIGNAL_HAS_SOSFILT (1) +#endif + +#ifndef ULAB_SCIPY_HAS_OPTIMIZE_MODULE +#define ULAB_SCIPY_HAS_OPTIMIZE_MODULE (1) +#endif + +#ifndef ULAB_SCIPY_OPTIMIZE_HAS_BISECT +#define ULAB_SCIPY_OPTIMIZE_HAS_BISECT (1) +#endif + +#ifndef ULAB_SCIPY_OPTIMIZE_HAS_CURVE_FIT +#define ULAB_SCIPY_OPTIMIZE_HAS_CURVE_FIT (0) // not fully implemented +#endif + +#ifndef ULAB_SCIPY_OPTIMIZE_HAS_FMIN +#define ULAB_SCIPY_OPTIMIZE_HAS_FMIN (1) +#endif + +#ifndef ULAB_SCIPY_OPTIMIZE_HAS_NEWTON +#define ULAB_SCIPY_OPTIMIZE_HAS_NEWTON (1) +#endif + +#ifndef ULAB_SCIPY_HAS_SPECIAL_MODULE +#define ULAB_SCIPY_HAS_SPECIAL_MODULE (1) +#endif + +#ifndef ULAB_SCIPY_SPECIAL_HAS_ERF +#define ULAB_SCIPY_SPECIAL_HAS_ERF (1) +#endif + +#ifndef ULAB_SCIPY_SPECIAL_HAS_ERFC +#define ULAB_SCIPY_SPECIAL_HAS_ERFC (1) +#endif + +#ifndef ULAB_SCIPY_SPECIAL_HAS_GAMMA +#define ULAB_SCIPY_SPECIAL_HAS_GAMMA (1) +#endif + +#ifndef ULAB_SCIPY_SPECIAL_HAS_GAMMALN +#define ULAB_SCIPY_SPECIAL_HAS_GAMMALN (1) +#endif + +// user-defined module; source of the module and +// its sub-modules should be placed in code/user/ +#ifndef ULAB_HAS_USER_MODULE +#define ULAB_HAS_USER_MODULE (0) +#endif + +#ifndef ULAB_HAS_UTILS_MODULE +#define ULAB_HAS_UTILS_MODULE (1) +#endif + +#ifndef ULAB_UTILS_HAS_FROM_INT16_BUFFER +#define ULAB_UTILS_HAS_FROM_INT16_BUFFER (1) +#endif + +#ifndef ULAB_UTILS_HAS_FROM_UINT16_BUFFER +#define ULAB_UTILS_HAS_FROM_UINT16_BUFFER (1) +#endif + +#ifndef ULAB_UTILS_HAS_FROM_INT32_BUFFER +#define ULAB_UTILS_HAS_FROM_INT32_BUFFER (1) +#endif + +#ifndef ULAB_UTILS_HAS_FROM_UINT32_BUFFER +#define ULAB_UTILS_HAS_FROM_UINT32_BUFFER (1) +#endif + +#endif diff --git a/python/port/mod/ulab/ulab_create.c b/python/port/mod/ulab/ulab_create.c new file mode 100644 index 000000000..2cb8f2325 --- /dev/null +++ b/python/port/mod/ulab/ulab_create.c @@ -0,0 +1,706 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2019-2021 Zoltán Vörös + * 2020 Taku Fukada +*/ + +#include +#include +#include +#include +#include +#include + +#include "ulab.h" +#include "ulab_create.h" + +#if ULAB_NUMPY_HAS_ONES | ULAB_NUMPY_HAS_ZEROS | ULAB_NUMPY_HAS_FULL | ULAB_NUMPY_HAS_EMPTY +static mp_obj_t create_zeros_ones_full(mp_obj_t oshape, uint8_t dtype, mp_obj_t value) { + if(!mp_obj_is_int(oshape) && !mp_obj_is_type(oshape, &mp_type_tuple) && !mp_obj_is_type(oshape, &mp_type_list)) { + mp_raise_TypeError(translate("input argument must be an integer, a tuple, or a list")); + } + ndarray_obj_t *ndarray = NULL; + if(mp_obj_is_int(oshape)) { + size_t n = mp_obj_get_int(oshape); + ndarray = ndarray_new_linear_array(n, dtype); + } else if(mp_obj_is_type(oshape, &mp_type_tuple) || mp_obj_is_type(oshape, &mp_type_list)) { + uint8_t len = (uint8_t)mp_obj_get_int(mp_obj_len_maybe(oshape)); + if(len > ULAB_MAX_DIMS) { + mp_raise_TypeError(translate("too many dimensions")); + } + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, ULAB_MAX_DIMS * sizeof(size_t)); + size_t i = 0; + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(oshape, &iter_buf); + while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION){ + shape[ULAB_MAX_DIMS - len + i] = (size_t)mp_obj_get_int(item); + i++; + } + ndarray = ndarray_new_dense_ndarray(len, shape, dtype); + } + if(value != mp_const_none) { + if(dtype == NDARRAY_BOOL) { + dtype = NDARRAY_UINT8; + if(mp_obj_is_true(value)) { + value = mp_obj_new_int(1); + } else { + value = mp_obj_new_int(0); + } + } + for(size_t i=0; i < ndarray->len; i++) { + ndarray_set_value(dtype, ndarray->array, i, value); + } + } + // if zeros calls the function, we don't have to do anything + return MP_OBJ_FROM_PTR(ndarray); +} +#endif + +#if ULAB_NUMPY_HAS_ARANGE | ULAB_NUMPY_HAS_LINSPACE +static ndarray_obj_t *create_linspace_arange(mp_float_t start, mp_float_t step, size_t len, uint8_t dtype) { + mp_float_t value = start; + + ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype); + if(ndarray->boolean == NDARRAY_BOOLEAN) { + uint8_t *array = (uint8_t *)ndarray->array; + for(size_t i=0; i < len; i++, value += step) { + *array++ = value == MICROPY_FLOAT_CONST(0.0) ? 0 : 1; + } + } else if(dtype == NDARRAY_UINT8) { + ARANGE_LOOP(uint8_t, ndarray, len, step); + } else if(dtype == NDARRAY_INT8) { + ARANGE_LOOP(int8_t, ndarray, len, step); + } else if(dtype == NDARRAY_UINT16) { + ARANGE_LOOP(uint16_t, ndarray, len, step); + } else if(dtype == NDARRAY_INT16) { + ARANGE_LOOP(int16_t, ndarray, len, step); + } else { + ARANGE_LOOP(mp_float_t, ndarray, len, step); + } + return ndarray; +} +#endif + +#if ULAB_NUMPY_HAS_ARANGE +//| @overload +//| def arange(stop: _float, step: _float = 1, *, dtype: _DType = ulab.float) -> ulab.ndarray: ... +//| @overload +//| def arange(start: _float, stop: _float, step: _float = 1, *, dtype: _DType = ulab.float) -> ulab.ndarray: +//| """ +//| .. param: start +//| First value in the array, optional, defaults to 0 +//| .. param: stop +//| Final value in the array +//| .. param: step +//| Difference between consecutive elements, optional, defaults to 1.0 +//| .. param: dtype +//| Type of values in the array +//| +//| Return a new 1-D array with elements ranging from ``start`` to ``stop``, with step size ``step``.""" +//| ... +//| + +mp_obj_t create_arange(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_const_none } }, + { MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + uint8_t dtype = NDARRAY_FLOAT; + mp_float_t start, stop, step; + if(n_args == 1) { + start = 0.0; + stop = mp_obj_get_float(args[0].u_obj); + step = 1.0; + if(mp_obj_is_int(args[0].u_obj)) dtype = NDARRAY_INT16; + } else if(n_args == 2) { + start = mp_obj_get_float(args[0].u_obj); + stop = mp_obj_get_float(args[1].u_obj); + step = 1.0; + if(mp_obj_is_int(args[0].u_obj) && mp_obj_is_int(args[1].u_obj)) dtype = NDARRAY_INT16; + } else if(n_args == 3) { + start = mp_obj_get_float(args[0].u_obj); + stop = mp_obj_get_float(args[1].u_obj); + step = mp_obj_get_float(args[2].u_obj); + if(mp_obj_is_int(args[0].u_obj) && mp_obj_is_int(args[1].u_obj) && mp_obj_is_int(args[2].u_obj)) dtype = NDARRAY_INT16; + } else { + mp_raise_TypeError(translate("wrong number of arguments")); + } + if((MICROPY_FLOAT_C_FUN(fabs)(stop) > 32768) || (MICROPY_FLOAT_C_FUN(fabs)(start) > 32768) || (MICROPY_FLOAT_C_FUN(fabs)(step) > 32768)) { + dtype = NDARRAY_FLOAT; + } + if(args[3].u_obj != mp_const_none) { + dtype = (uint8_t)mp_obj_get_int(args[3].u_obj); + } + ndarray_obj_t *ndarray; + if((stop - start)/step < 0) { + ndarray = ndarray_new_linear_array(0, dtype); + } else { + size_t len = (size_t)(MICROPY_FLOAT_C_FUN(ceil)((stop - start)/step)); + ndarray = create_linspace_arange(start, step, len, dtype); + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_arange_obj, 1, create_arange); +#endif + +#if ULAB_NUMPY_HAS_CONCATENATE +//| def concatenate(arrays: Tuple[ulab.ndarray], *, axis: int = 0) -> ulab.ndarray: +//| """ +//| .. param: arrays +//| tuple of ndarrays +//| .. param: axis +//| axis along which the arrays will be joined +//| +//| Join a sequence of arrays along an existing axis.""" +//| ... +//| + +mp_obj_t create_concatenate(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_const_none } }, + { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) { + mp_raise_TypeError(translate("first argument must be a tuple of ndarrays")); + } + int8_t axis = (int8_t)args[1].u_int; + size_t *shape = m_new(size_t, ULAB_MAX_DIMS); + memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS); + mp_obj_tuple_t *ndarrays = MP_OBJ_TO_PTR(args[0].u_obj); + + // first check, whether the arrays are compatible + ndarray_obj_t *_ndarray = MP_OBJ_TO_PTR(ndarrays->items[0]); + uint8_t dtype = _ndarray->dtype; + uint8_t ndim = _ndarray->ndim; + if(axis < 0) { + axis += ndim; + } + if((axis < 0) || (axis >= ndim)) { + mp_raise_ValueError(translate("wrong axis specified")); + } + // shift axis + axis = ULAB_MAX_DIMS - ndim + axis; + for(uint8_t j=0; j < ULAB_MAX_DIMS; j++) { + shape[j] = _ndarray->shape[j]; + } + + for(uint8_t i=1; i < ndarrays->len; i++) { + _ndarray = MP_OBJ_TO_PTR(ndarrays->items[i]); + // check, whether the arrays are compatible + if((dtype != _ndarray->dtype) || (ndim != _ndarray->ndim)) { + mp_raise_ValueError(translate("input arrays are not compatible")); + } + for(uint8_t j=0; j < ULAB_MAX_DIMS; j++) { + if(j == axis) { + shape[j] += _ndarray->shape[j]; + } else { + if(shape[j] != _ndarray->shape[j]) { + mp_raise_ValueError(translate("input arrays are not compatible")); + } + } + } + } + + ndarray_obj_t *target = ndarray_new_dense_ndarray(ndim, shape, dtype); + uint8_t *tpos = (uint8_t *)target->array; + uint8_t *tarray; + + for(uint8_t p=0; p < ndarrays->len; p++) { + // reset the pointer along the axis + ndarray_obj_t *source = MP_OBJ_TO_PTR(ndarrays->items[p]); + uint8_t *sarray = (uint8_t *)source->array; + tarray = tpos; + + #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 { + memcpy(tarray, sarray, source->itemsize); + tarray += target->strides[ULAB_MAX_DIMS - 1]; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + l++; + } while(l < source->shape[ULAB_MAX_DIMS - 1]); + #if ULAB_MAX_DIMS > 1 + tarray -= target->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + tarray += target->strides[ULAB_MAX_DIMS - 2]; + sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1]; + sarray += source->strides[ULAB_MAX_DIMS - 2]; + k++; + } while(k < source->shape[ULAB_MAX_DIMS - 2]); + #endif + #if ULAB_MAX_DIMS > 2 + tarray -= target->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + tarray += target->strides[ULAB_MAX_DIMS - 3]; + sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2]; + sarray += source->strides[ULAB_MAX_DIMS - 3]; + j++; + } while(j < source->shape[ULAB_MAX_DIMS - 3]); + #endif + #if ULAB_MAX_DIMS > 3 + tarray -= target->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + tarray += target->strides[ULAB_MAX_DIMS - 4]; + sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3]; + sarray += source->strides[ULAB_MAX_DIMS - 4]; + i++; + } while(i < source->shape[ULAB_MAX_DIMS - 4]); + #endif + if(p < ndarrays->len - 1) { + tpos += target->strides[axis] * source->shape[axis]; + } + } + return MP_OBJ_FROM_PTR(target); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_concatenate_obj, 1, create_concatenate); +#endif + +#if ULAB_NUMPY_HAS_DIAG +//| def diag(a: ulab.ndarray, *, k: int = 0) -> ulab.ndarray: +//| """ +//| .. param: a +//| an ndarray +//| .. param: k +//| Offset of the diagonal from the main diagonal. Can be positive or negative. +//| +//| Return specified diagonals.""" +//| ... +//| +mp_obj_t create_diag(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_const_none } }, + { MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("input must be an ndarray")); + } + ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0].u_obj); + if(source->ndim == 1) { // return a rank-2 tensor with the prescribed diagonal + ndarray_obj_t *target = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, source->len, source->len), source->dtype); + uint8_t *sarray = (uint8_t *)source->array; + uint8_t *tarray = (uint8_t *)target->array; + for(size_t i=0; i < source->len; i++) { + memcpy(tarray, sarray, source->itemsize); + sarray += source->strides[ULAB_MAX_DIMS - 1]; + tarray += (source->len + 1) * target->itemsize; + } + return MP_OBJ_FROM_PTR(target); + } + if(source->ndim > 2) { + mp_raise_TypeError(translate("input must be a tensor of rank 2")); + } + int32_t k = args[1].u_int; + size_t len = 0; + uint8_t *sarray = (uint8_t *)source->array; + if(k < 0) { // move the pointer "vertically" + if(-k < (int32_t)source->shape[ULAB_MAX_DIMS - 2]) { + sarray -= k * source->strides[ULAB_MAX_DIMS - 2]; + len = MIN(source->shape[ULAB_MAX_DIMS - 2] + k, source->shape[ULAB_MAX_DIMS - 1]); + } + } else { // move the pointer "horizontally" + if(k < (int32_t)source->shape[ULAB_MAX_DIMS - 1]) { + sarray += k * source->strides[ULAB_MAX_DIMS - 1]; + len = MIN(source->shape[ULAB_MAX_DIMS - 1] - k, source->shape[ULAB_MAX_DIMS - 2]); + } + } + + if(len == 0) { + mp_raise_ValueError(translate("offset is too large")); + } + + ndarray_obj_t *target = ndarray_new_linear_array(len, source->dtype); + uint8_t *tarray = (uint8_t *)target->array; + + for(size_t i=0; i < len; i++) { + memcpy(tarray, sarray, source->itemsize); + sarray += source->strides[ULAB_MAX_DIMS - 2]; + sarray += source->strides[ULAB_MAX_DIMS - 1]; + tarray += source->itemsize; + } + return MP_OBJ_FROM_PTR(target); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_diag_obj, 1, create_diag); +#endif /* ULAB_NUMPY_HAS_DIAG */ + +#if ULAB_MAX_DIMS > 1 +#if ULAB_NUMPY_HAS_EYE +//| def eye(size: int, *, M: Optional[int] = None, k: int = 0, dtype: _DType = ulab.float) -> ulab.ndarray: +//| """Return a new square array of size, with the diagonal elements set to 1 +//| and the other elements set to 0.""" +//| ... +//| + +mp_obj_t create_eye(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_INT, { .u_int = 0 } }, + { MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + size_t n = args[0].u_int, m; + size_t k = args[2].u_int > 0 ? (size_t)args[2].u_int : (size_t)(-args[2].u_int); + uint8_t dtype = args[3].u_int; + if(args[1].u_rom_obj == mp_const_none) { + m = n; + } else { + m = mp_obj_get_int(args[1].u_rom_obj); + } + ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, n, m), dtype); + if(dtype == NDARRAY_BOOL) { + dtype = NDARRAY_UINT8; + } + mp_obj_t one = mp_obj_new_int(1); + size_t i = 0; + if((args[2].u_int >= 0)) { + while(k < m) { + ndarray_set_value(dtype, ndarray->array, i*m+k, one); + k++; + i++; + } + } else { + while(k < n) { + ndarray_set_value(dtype, ndarray->array, k*m+i, one); + k++; + i++; + } + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_eye_obj, 1, create_eye); +#endif /* ULAB_NUMPY_HAS_EYE */ +#endif /* ULAB_MAX_DIMS > 1 */ + +#if ULAB_NUMPY_HAS_FULL +//| def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[_float, _bool], *, dtype: _DType = ulab.float) -> ulab.ndarray: +//| """ +//| .. param: shape +//| Shape of the array, either an integer (for a 1-D array) or a tuple of integers (for tensors of higher rank) +//| .. param: fill_value +//| scalar, the value with which the array is filled +//| .. param: dtype +//| Type of values in the array +//| +//| Return a new array of the given shape with all elements set to 0.""" +//| ... +//| + +mp_obj_t create_full(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_obj = MP_OBJ_NULL } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_obj = MP_OBJ_NULL } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t dtype = args[2].u_int; + + return create_zeros_ones_full(args[0].u_obj, dtype, args[1].u_obj); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_full_obj, 0, create_full); +#endif + + +#if ULAB_NUMPY_HAS_LINSPACE +//| def linspace( +//| start: _float, +//| stop: _float, +//| *, +//| dtype: _DType = ulab.float, +//| num: int = 50, +//| endpoint: _bool = True, +//| retstep: _bool = False +//| ) -> ulab.ndarray: +//| """ +//| .. param: start +//| First value in the array +//| .. param: stop +//| Final value in the array +//| .. param int: num +//| Count of values in the array. +//| .. param: dtype +//| Type of values in the array +//| .. param bool: endpoint +//| Whether the ``stop`` value is included. Note that even when +//| endpoint=True, the exact ``stop`` value may not be included due to the +//| inaccuracy of floating point arithmetic. +// .. param bool: retstep, +//| If True, return (`samples`, `step`), where `step` is the spacing between samples. +//| +//| Return a new 1-D array with ``num`` elements ranging from ``start`` to ``stop`` linearly.""" +//| ... +//| + +mp_obj_t create_linspace(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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_num, MP_ARG_INT, { .u_int = 50 } }, + { MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_true } }, + { MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_false } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(args[2].u_int < 2) { + mp_raise_ValueError(translate("number of points must be at least 2")); + } + size_t len = (size_t)args[2].u_int; + mp_float_t start, step; + start = mp_obj_get_float(args[0].u_obj); + uint8_t typecode = args[5].u_int; + if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-start)/(len-1); + else step = (mp_obj_get_float(args[1].u_obj)-start)/len; + ndarray_obj_t *ndarray = create_linspace_arange(start, step, len, typecode); + if(args[4].u_obj == mp_const_false) { + return MP_OBJ_FROM_PTR(ndarray); + } else { + mp_obj_t tuple[2]; + tuple[0] = ndarray; + tuple[1] = mp_obj_new_float(step); + return mp_obj_new_tuple(2, tuple); + } +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_linspace_obj, 2, create_linspace); +#endif + +#if ULAB_NUMPY_HAS_LOGSPACE +//| def logspace( +//| start: _float, +//| stop: _float, +//| *, +//| dtype: _DType = ulab.float, +//| num: int = 50, +//| endpoint: _bool = True, +//| base: _float = 10.0 +//| ) -> ulab.ndarray: +//| """ +//| .. param: start +//| First value in the array +//| .. param: stop +//| Final value in the array +//| .. param int: num +//| Count of values in the array. Defaults to 50. +//| .. param: base +//| The base of the log space. The step size between the elements in +//| ``ln(samples) / ln(base)`` (or ``log_base(samples)``) is uniform. Defaults to 10.0. +//| .. param: dtype +//| Type of values in the array +//| .. param bool: endpoint +//| Whether the ``stop`` value is included. Note that even when +//| endpoint=True, the exact ``stop`` value may not be included due to the +//| inaccuracy of floating point arithmetic. Defaults to True. +//| +//| Return a new 1-D array with ``num`` evenly spaced elements on a log scale. +//| The sequence starts at ``base ** start``, and ends with ``base ** stop``.""" +//| ... +//| + +const mp_obj_float_t create_float_const_ten = {{&mp_type_float}, MICROPY_FLOAT_CONST(10.0)}; + +mp_obj_t create_logspace(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_const_none } }, + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_num, MP_ARG_INT, { .u_int = 50 } }, + { MP_QSTR_base, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&create_float_const_ten) } }, + { MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_true } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + if(args[2].u_int < 2) { + mp_raise_ValueError(translate("number of points must be at least 2")); + } + size_t len = (size_t)args[2].u_int; + mp_float_t start, step, quotient; + start = mp_obj_get_float(args[0].u_obj); + uint8_t dtype = args[5].u_int; + mp_float_t base = mp_obj_get_float(args[3].u_obj); + if(args[4].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj) - start)/(len - 1); + else step = (mp_obj_get_float(args[1].u_obj) - start) / len; + quotient = MICROPY_FLOAT_C_FUN(pow)(base, step); + ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype); + + mp_float_t value = MICROPY_FLOAT_C_FUN(pow)(base, start); + if(ndarray->dtype == NDARRAY_UINT8) { + uint8_t *array = (uint8_t *)ndarray->array; + if(ndarray->boolean) { + memset(array, 1, len); + } else { + for(size_t i=0; i < len; i++, value *= quotient) *array++ = (uint8_t)value; + } + } else if(ndarray->dtype == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array; + for(size_t i=0; i < len; i++, value *= quotient) *array++ = (int8_t)value; + } else if(ndarray->dtype == NDARRAY_UINT16) { + uint16_t *array = (uint16_t *)ndarray->array; + for(size_t i=0; i < len; i++, value *= quotient) *array++ = (uint16_t)value; + } else if(ndarray->dtype == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array; + for(size_t i=0; i < len; i++, value *= quotient) *array++ = (int16_t)value; + } else { + mp_float_t *array = (mp_float_t *)ndarray->array; + for(size_t i=0; i < len; i++, value *= quotient) *array++ = value; + } + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_logspace_obj, 2, create_logspace); +#endif + +#if ULAB_NUMPY_HAS_ONES +//| def ones(shape: Union[int, Tuple[int, ...]], *, dtype: _DType = ulab.float) -> ulab.ndarray: +//| """ +//| .. param: shape +//| Shape of the array, either an integer (for a 1-D array) or a tuple of 2 integers (for a 2-D array) +//| .. param: dtype +//| Type of values in the array +//| +//| Return a new array of the given shape with all elements set to 1.""" +//| ... +//| + +mp_obj_t create_ones(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_obj = MP_OBJ_NULL } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t dtype = args[1].u_int; + mp_obj_t one = mp_obj_new_int(1); + return create_zeros_ones_full(args[0].u_obj, dtype, one); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones); +#endif + +#if ULAB_NUMPY_HAS_ZEROS +//| def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: _DType = ulab.float) -> ulab.ndarray: +//| """ +//| .. param: shape +//| Shape of the array, either an integer (for a 1-D array) or a tuple of 2 integers (for a 2-D array) +//| .. param: dtype +//| Type of values in the array +//| +//| Return a new array of the given shape with all elements set to 0.""" +//| ... +//| + +mp_obj_t create_zeros(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_obj = MP_OBJ_NULL } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t dtype = args[1].u_int; + return create_zeros_ones_full(args[0].u_obj, dtype, mp_const_none); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_zeros_obj, 0, create_zeros); +#endif + +#if ULAB_NUMPY_HAS_FROMBUFFER +mp_obj_t create_frombuffer(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_const_none } }, + { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(NDARRAY_FLOAT) } }, + { MP_QSTR_count, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(-1) } }, + { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(0) } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + uint8_t dtype = mp_obj_get_int(args[1].u_obj); + size_t offset = mp_obj_get_int(args[3].u_obj); + + mp_buffer_info_t bufinfo; + if(mp_get_buffer(args[0].u_obj, &bufinfo, MP_BUFFER_READ)) { + size_t sz = 1; + if(dtype != NDARRAY_BOOL) { // mp_binary_get_size doesn't work with Booleans + sz = mp_binary_get_size('@', dtype, NULL); + } + if(bufinfo.len < offset) { + mp_raise_ValueError(translate("offset must be non-negative and no greater than buffer length")); + } + size_t len = (bufinfo.len - offset) / sz; + if((len * sz) != (bufinfo.len - offset)) { + mp_raise_ValueError(translate("buffer size must be a multiple of element size")); + } + if(mp_obj_get_int(args[2].u_obj) > 0) { + size_t count = mp_obj_get_int(args[2].u_obj); + if(len < count) { + mp_raise_ValueError(translate("buffer is smaller than requested size")); + } else { + 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; + + uint8_t *buffer = bufinfo.buf; + ndarray->array = buffer + offset; + return MP_OBJ_FROM_PTR(ndarray); + } + return mp_const_none; +} + +MP_DEFINE_CONST_FUN_OBJ_KW(create_frombuffer_obj, 1, create_frombuffer); +#endif diff --git a/python/port/mod/ulab/ulab_create.h b/python/port/mod/ulab/ulab_create.h new file mode 100644 index 000000000..9aefc0b2b --- /dev/null +++ b/python/port/mod/ulab/ulab_create.h @@ -0,0 +1,78 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020 Jeff Epler for Adafruit Industries + * 2019-2021 Zoltán Vörös +*/ + +#ifndef _CREATE_ +#define _CREATE_ + +#include "ulab.h" +#include "ndarray.h" + +#if ULAB_NUMPY_HAS_ARANGE +mp_obj_t create_arange(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_arange_obj); +#endif + +#if ULAB_NUMPY_HAS_CONCATENATE +mp_obj_t create_concatenate(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_concatenate_obj); +#endif + +#if ULAB_NUMPY_HAS_DIAG +mp_obj_t create_diag(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_diag_obj); +#endif + +#if ULAB_MAX_DIMS > 1 +#if ULAB_NUMPY_HAS_EYE +mp_obj_t create_eye(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_eye_obj); +#endif +#endif + +#if ULAB_NUMPY_HAS_FULL +mp_obj_t create_full(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_full_obj); +#endif + +#if ULAB_NUMPY_HAS_LINSPACE +mp_obj_t create_linspace(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_linspace_obj); +#endif + +#if ULAB_NUMPY_HAS_LOGSPACE +mp_obj_t create_logspace(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_logspace_obj); +#endif + +#if ULAB_NUMPY_HAS_ONES +mp_obj_t create_ones(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_ones_obj); +#endif + +#if ULAB_NUMPY_HAS_ZEROS +mp_obj_t create_zeros(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_zeros_obj); +#endif + +#if ULAB_NUMPY_HAS_FROMBUFFER +mp_obj_t create_frombuffer(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(create_frombuffer_obj); +#endif + +#define ARANGE_LOOP(type_, ndarray, len, step) \ +({\ + type_ *array = (type_ *)(ndarray)->array;\ + for (size_t i = 0; i < (len); i++, (value) += (step)) {\ + *array++ = (type_)value;\ + }\ +}) + +#endif diff --git a/python/port/mod/ulab/ulab_tools.c b/python/port/mod/ulab/ulab_tools.c new file mode 100644 index 000000000..dd93787ba --- /dev/null +++ b/python/port/mod/ulab/ulab_tools.c @@ -0,0 +1,233 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös + */ + + +#include +#include + +#include "ulab.h" +#include "ndarray.h" +#include "ulab_tools.h" + +// The following five functions return a float from a void type +// The value in question is supposed to be located at the head of the pointer + +mp_float_t ndarray_get_float_uint8(void *data) { + // Returns a float value from an uint8_t type + return (mp_float_t)(*(uint8_t *)data); +} + +mp_float_t ndarray_get_float_int8(void *data) { + // Returns a float value from an int8_t type + return (mp_float_t)(*(int8_t *)data); +} + +mp_float_t ndarray_get_float_uint16(void *data) { + // Returns a float value from an uint16_t type + return (mp_float_t)(*(uint16_t *)data); +} + +mp_float_t ndarray_get_float_int16(void *data) { + // Returns a float value from an int16_t type + return (mp_float_t)(*(int16_t *)data); +} + + +mp_float_t ndarray_get_float_float(void *data) { + // Returns a float value from an mp_float_t type + return *((mp_float_t *)data); +} + +// returns a single function pointer, depending on the dtype +void *ndarray_get_float_function(uint8_t dtype) { + if(dtype == NDARRAY_UINT8) { + return ndarray_get_float_uint8; + } else if(dtype == NDARRAY_INT8) { + return ndarray_get_float_int8; + } else if(dtype == NDARRAY_UINT16) { + return ndarray_get_float_uint16; + } else if(dtype == NDARRAY_INT16) { + return ndarray_get_float_int16; + } else { + return ndarray_get_float_float; + } +} + +mp_float_t ndarray_get_float_index(void *data, uint8_t dtype, size_t index) { + // returns a single float value from an array located at index + if(dtype == NDARRAY_UINT8) { + return (mp_float_t)((uint8_t *)data)[index]; + } else if(dtype == NDARRAY_INT8) { + return (mp_float_t)((int8_t *)data)[index]; + } else if(dtype == NDARRAY_UINT16) { + return (mp_float_t)((uint16_t *)data)[index]; + } else if(dtype == NDARRAY_INT16) { + return (mp_float_t)((int16_t *)data)[index]; + } else { + return (mp_float_t)((mp_float_t *)data)[index]; + } +} + +mp_float_t ndarray_get_float_value(void *data, uint8_t dtype) { + // Returns a float value from an arbitrary data type + // The value in question is supposed to be located at the head of the pointer + if(dtype == NDARRAY_UINT8) { + return (mp_float_t)(*(uint8_t *)data); + } else if(dtype == NDARRAY_INT8) { + return (mp_float_t)(*(int8_t *)data); + } else if(dtype == NDARRAY_UINT16) { + return (mp_float_t)(*(uint16_t *)data); + } else if(dtype == NDARRAY_INT16) { + return (mp_float_t)(*(int16_t *)data); + } else { + return *((mp_float_t *)data); + } +} + +#if NDARRAY_BINARY_USES_FUN_POINTER | ULAB_NUMPY_HAS_WHERE +uint8_t ndarray_upcast_dtype(uint8_t ldtype, uint8_t rdtype) { + // returns a single character that corresponds to the broadcasting rules + // - if one of the operarands is a float, the result is always float + // - operation on identical types preserves type + // + // uint8 + int8 => int16 + // uint8 + int16 => int16 + // uint8 + uint16 => uint16 + // int8 + int16 => int16 + // int8 + uint16 => uint16 + // uint16 + int16 => float + + if(ldtype == rdtype) { + // if the two dtypes are equal, the result is also of that type + return ldtype; + } else if(((ldtype == NDARRAY_UINT8) && (rdtype == NDARRAY_INT8)) || + ((ldtype == NDARRAY_INT8) && (rdtype == NDARRAY_UINT8)) || + ((ldtype == NDARRAY_UINT8) && (rdtype == NDARRAY_INT16)) || + ((ldtype == NDARRAY_INT16) && (rdtype == NDARRAY_UINT8)) || + ((ldtype == NDARRAY_INT8) && (rdtype == NDARRAY_INT16)) || + ((ldtype == NDARRAY_INT16) && (rdtype == NDARRAY_INT8))) { + return NDARRAY_INT16; + } else if(((ldtype == NDARRAY_UINT8) && (rdtype == NDARRAY_UINT16)) || + ((ldtype == NDARRAY_UINT16) && (rdtype == NDARRAY_UINT8)) || + ((ldtype == NDARRAY_INT8) && (rdtype == NDARRAY_UINT16)) || + ((ldtype == NDARRAY_UINT16) && (rdtype == NDARRAY_INT8))) { + return NDARRAY_UINT16; + } + return NDARRAY_FLOAT; +} + +// The following five functions are the inverse of the ndarray_get_... functions, +// and write a floating point datum into a void pointer + +void ndarray_set_float_uint8(void *data, mp_float_t datum) { + *((uint8_t *)data) = (uint8_t)datum; +} + +void ndarray_set_float_int8(void *data, mp_float_t datum) { + *((int8_t *)data) = (int8_t)datum; +} + +void ndarray_set_float_uint16(void *data, mp_float_t datum) { + *((uint16_t *)data) = (uint16_t)datum; +} + +void ndarray_set_float_int16(void *data, mp_float_t datum) { + *((int16_t *)data) = (int16_t)datum; +} + +void ndarray_set_float_float(void *data, mp_float_t datum) { + *((mp_float_t *)data) = datum; +} + +// returns a single function pointer, depending on the dtype +void *ndarray_set_float_function(uint8_t dtype) { + if(dtype == NDARRAY_UINT8) { + return ndarray_set_float_uint8; + } else if(dtype == NDARRAY_INT8) { + return ndarray_set_float_int8; + } else if(dtype == NDARRAY_UINT16) { + return ndarray_set_float_uint16; + } else if(dtype == NDARRAY_INT16) { + return ndarray_set_float_int16; + } else { + return ndarray_set_float_float; + } +} +#endif /* NDARRAY_BINARY_USES_FUN_POINTER */ + +shape_strides tools_reduce_axes(ndarray_obj_t *ndarray, mp_obj_t axis) { + // TODO: replace numerical_reduce_axes with this function, wherever applicable + // This function should be used, whenever a tensor is contracted; + // The shape and strides at `axis` are moved to the zeroth position, + // everything else is aligned to the right + if(!mp_obj_is_int(axis) & (axis != mp_const_none)) { + mp_raise_TypeError(translate("axis must be None, or an integer")); + } + shape_strides _shape_strides; + + size_t *shape = m_new(size_t, ULAB_MAX_DIMS + 1); + _shape_strides.shape = shape; + int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS + 1); + _shape_strides.strides = strides; + + _shape_strides.increment = 0; + // this is the contracted dimension (won't be overwritten for axis == None) + _shape_strides.ndim = 0; + + memcpy(_shape_strides.shape, ndarray->shape, sizeof(size_t) * ULAB_MAX_DIMS); + memcpy(_shape_strides.strides, ndarray->strides, sizeof(int32_t) * ULAB_MAX_DIMS); + + if(axis == mp_const_none) { + return _shape_strides; + } + + uint8_t index = ULAB_MAX_DIMS - 1; // value of index for axis == mp_const_none (won't be overwritten) + + if(axis != mp_const_none) { // i.e., axis is an integer + int8_t ax = mp_obj_get_int(axis); + if(ax < 0) ax += ndarray->ndim; + if((ax < 0) || (ax > ndarray->ndim - 1)) { + mp_raise_ValueError(translate("index out of range")); + } + index = ULAB_MAX_DIMS - ndarray->ndim + ax; + _shape_strides.ndim = ndarray->ndim - 1; + } + + // move the value stored at index to the leftmost position, and align everything else to the right + _shape_strides.shape[0] = ndarray->shape[index]; + _shape_strides.strides[0] = ndarray->strides[index]; + for(uint8_t i = 0; i < index; i++) { + // entries to the right of index must be shifted by one position to the left + _shape_strides.shape[i + 1] = ndarray->shape[i]; + _shape_strides.strides[i + 1] = ndarray->strides[i]; + } + + if(_shape_strides.ndim != 0) { + _shape_strides.increment = 1; + } + + return _shape_strides; +} + + +#if ULAB_MAX_DIMS > 1 +ndarray_obj_t *tools_object_is_square(mp_obj_t obj) { + // Returns an ndarray, if the object is a square ndarray, + // raises the appropriate exception otherwise + if(!mp_obj_is_type(obj, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("size is defined for ndarrays only")); + } + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(obj); + if((ndarray->shape[ULAB_MAX_DIMS - 1] != ndarray->shape[ULAB_MAX_DIMS - 2]) || (ndarray->ndim != 2)) { + mp_raise_ValueError(translate("input must be square matrix")); + } + return ndarray; +} +#endif diff --git a/python/port/mod/ulab/ulab_tools.h b/python/port/mod/ulab/ulab_tools.h new file mode 100644 index 000000000..378e4f0ca --- /dev/null +++ b/python/port/mod/ulab/ulab_tools.h @@ -0,0 +1,37 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#ifndef _TOOLS_ +#define _TOOLS_ + +#include "ndarray.h" + +#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; } + +typedef struct _shape_strides_t { + uint8_t increment; + uint8_t ndim; + size_t *shape; + int32_t *strides; +} shape_strides; + +mp_float_t ndarray_get_float_uint8(void *); +mp_float_t ndarray_get_float_int8(void *); +mp_float_t ndarray_get_float_uint16(void *); +mp_float_t ndarray_get_float_int16(void *); +mp_float_t ndarray_get_float_float(void *); +void *ndarray_get_float_function(uint8_t ); + +uint8_t ndarray_upcast_dtype(uint8_t , uint8_t ); +void *ndarray_set_float_function(uint8_t ); + +shape_strides tools_reduce_axes(ndarray_obj_t *, mp_obj_t ); +ndarray_obj_t *tools_object_is_square(mp_obj_t ); +#endif diff --git a/python/port/mod/ulab/user/user.c b/python/port/mod/ulab/user/user.c new file mode 100644 index 000000000..be7c6d0a0 --- /dev/null +++ b/python/port/mod/ulab/user/user.c @@ -0,0 +1,95 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#include +#include +#include +#include +#include +#include +#include "user.h" + +#if ULAB_HAS_USER_MODULE + +//| """This module should hold arbitrary user-defined functions.""" +//| + +static mp_obj_t user_square(mp_obj_t arg) { + // the function takes a single dense ndarray, and calculates the + // element-wise square of its entries + + // raise a TypeError exception, if the input is not an ndarray + if(!mp_obj_is_type(arg, &ulab_ndarray_type)) { + mp_raise_TypeError(translate("input must be an ndarray")); + } + ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(arg); + + // make sure that the input is a dense array + if(!ndarray_is_dense(ndarray)) { + mp_raise_TypeError(translate("input must be a dense ndarray")); + } + + // if the input is a dense array, create `results` with the same number of + // dimensions, shape, and dtype + ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim, ndarray->shape, ndarray->dtype); + + // since in a dense array the iteration over the elements is trivial, we + // can cast the data arrays ndarray->array and results->array to the actual type + if(ndarray->dtype == NDARRAY_UINT8) { + uint8_t *array = (uint8_t *)ndarray->array; + uint8_t *rarray = (uint8_t *)results->array; + for(size_t i=0; i < ndarray->len; i++, array++) { + *rarray++ = (*array) * (*array); + } + } else if(ndarray->dtype == NDARRAY_INT8) { + int8_t *array = (int8_t *)ndarray->array; + int8_t *rarray = (int8_t *)results->array; + for(size_t i=0; i < ndarray->len; i++, array++) { + *rarray++ = (*array) * (*array); + } + } else if(ndarray->dtype == NDARRAY_UINT16) { + uint16_t *array = (uint16_t *)ndarray->array; + uint16_t *rarray = (uint16_t *)results->array; + for(size_t i=0; i < ndarray->len; i++, array++) { + *rarray++ = (*array) * (*array); + } + } else if(ndarray->dtype == NDARRAY_INT16) { + int16_t *array = (int16_t *)ndarray->array; + int16_t *rarray = (int16_t *)results->array; + for(size_t i=0; i < ndarray->len; i++, array++) { + *rarray++ = (*array) * (*array); + } + } else { // if we end up here, the dtype is NDARRAY_FLOAT + mp_float_t *array = (mp_float_t *)ndarray->array; + mp_float_t *rarray = (mp_float_t *)results->array; + for(size_t i=0; i < ndarray->len; i++, array++) { + *rarray++ = (*array) * (*array); + } + } + // at the end, return a micrppython object + return MP_OBJ_FROM_PTR(results); +} + +MP_DEFINE_CONST_FUN_OBJ_1(user_square_obj, user_square); + +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 }, +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_user_globals, ulab_user_globals_table); + +mp_obj_module_t ulab_user_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_user_globals, +}; + +#endif diff --git a/python/port/mod/ulab/user/user.h b/python/port/mod/ulab/user/user.h new file mode 100644 index 000000000..4ec366af1 --- /dev/null +++ b/python/port/mod/ulab/user/user.h @@ -0,0 +1,20 @@ + +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#ifndef _USER_ +#define _USER_ + +#include "../ulab.h" +#include "../ndarray.h" + +extern mp_obj_module_t ulab_user_module; + +#endif diff --git a/python/port/mod/ulab/utils/utils.c b/python/port/mod/ulab/utils/utils.c new file mode 100644 index 000000000..6ff787b3b --- /dev/null +++ b/python/port/mod/ulab/utils/utils.c @@ -0,0 +1,215 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#include +#include +#include +#include +#include +#include +#include "utils.h" + +#if ULAB_HAS_UTILS_MODULE + +enum UTILS_BUFFER_TYPE { + UTILS_INT16_BUFFER, + UTILS_UINT16_BUFFER, + UTILS_INT32_BUFFER, + UTILS_UINT32_BUFFER, +}; + +#if ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER | ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER +static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t buffer_type) { + static const mp_arg_t allowed_args[] = { + { MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none } } , + { MP_QSTR_count, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(-1) } }, + { MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(0) } }, + { MP_QSTR_out, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } }, + { MP_QSTR_byteswap, MP_ARG_OBJ, { .u_rom_obj = mp_const_false } }, + }; + + mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; + mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); + + ndarray_obj_t *ndarray = NULL; + + if(args[3].u_obj != mp_const_none) { + ndarray = MP_OBJ_TO_PTR(args[3].u_obj); + if((ndarray->dtype != NDARRAY_FLOAT) || !ndarray_is_dense(ndarray)) { + mp_raise_TypeError(translate("out must be a float dense array")); + } + } + + size_t offset = mp_obj_get_int(args[2].u_obj); + + mp_buffer_info_t bufinfo; + if(mp_get_buffer(args[0].u_obj, &bufinfo, MP_BUFFER_READ)) { + if(bufinfo.len < offset) { + mp_raise_ValueError(translate("offset is too large")); + } + uint8_t sz = sizeof(int16_t); + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if((buffer_type == UTILS_INT32_BUFFER) || (buffer_type == UTILS_UINT32_BUFFER)) { + sz = sizeof(int32_t); + } + #endif + + size_t len = (bufinfo.len - offset) / sz; + if((len * sz) != (bufinfo.len - offset)) { + mp_raise_ValueError(translate("buffer size must be a multiple of element size")); + } + if(mp_obj_get_int(args[1].u_obj) > 0) { + size_t count = mp_obj_get_int(args[1].u_obj); + if(len < count) { + mp_raise_ValueError(translate("buffer is smaller than requested size")); + } else { + len = count; + } + } + if(args[3].u_obj == mp_const_none) { + ndarray = ndarray_new_linear_array(len, NDARRAY_FLOAT); + } else { + if(ndarray->len < len) { + mp_raise_ValueError(translate("out array is too small")); + } + } + uint8_t *buffer = bufinfo.buf; + + mp_float_t *array = (mp_float_t *)ndarray->array; + if(args[4].u_obj == mp_const_true) { + // swap the bytes before conversion + uint8_t *tmpbuff = m_new(uint8_t, sz); + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER + if((buffer_type == UTILS_INT16_BUFFER) || (buffer_type == UTILS_UINT16_BUFFER)) { + for(size_t i = 0; i < len; i++) { + tmpbuff += sz; + for(uint8_t j = 0; j < sz; j++) { + memcpy(--tmpbuff, buffer++, 1); + } + if(buffer_type == UTILS_INT16_BUFFER) { + *array++ = (mp_float_t)(*(int16_t *)tmpbuff); + } else { + *array++ = (mp_float_t)(*(uint16_t *)tmpbuff); + } + } + } + #endif + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if((buffer_type == UTILS_INT32_BUFFER) || (buffer_type == UTILS_UINT32_BUFFER)) { + for(size_t i = 0; i < len; i++) { + tmpbuff += sz; + for(uint8_t j = 0; j < sz; j++) { + memcpy(--tmpbuff, buffer++, 1); + } + if(buffer_type == UTILS_INT32_BUFFER) { + *array++ = (mp_float_t)(*(int32_t *)tmpbuff); + } else { + *array++ = (mp_float_t)(*(uint32_t *)tmpbuff); + } + } + } + #endif + } else { + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER + if(buffer_type == UTILS_INT16_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(int16_t *)buffer); + buffer += sz; + } + } + #endif + #if ULAB_UTILS_HAS_FROM_UINT16_BUFFER + if(buffer_type == UTILS_UINT16_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(uint16_t *)buffer); + buffer += sz; + } + } + #endif + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER + if(buffer_type == UTILS_INT32_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(int32_t *)buffer); + buffer += sz; + } + } + #endif + #if ULAB_UTILS_HAS_FROM_UINT32_BUFFER + if(buffer_type == UTILS_UINT32_BUFFER) { + for(size_t i = 0; i < len; i++) { + *array++ = (mp_float_t)(*(uint32_t *)buffer); + buffer += sz; + } + } + #endif + } + return MP_OBJ_FROM_PTR(ndarray); + } + return mp_const_none; +} + +#ifdef ULAB_UTILS_HAS_FROM_INT16_BUFFER +static mp_obj_t utils_from_int16_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_INT16_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_int16_buffer_obj, 1, utils_from_int16_buffer); +#endif + +#ifdef ULAB_UTILS_HAS_FROM_UINT16_BUFFER +static mp_obj_t utils_from_uint16_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_UINT16_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint16_buffer_obj, 1, utils_from_uint16_buffer); +#endif + +#ifdef ULAB_UTILS_HAS_FROM_INT32_BUFFER +static mp_obj_t utils_from_int32_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_INT32_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_int32_buffer_obj, 1, utils_from_int32_buffer); +#endif + +#ifdef ULAB_UTILS_HAS_FROM_UINT32_BUFFER +static mp_obj_t utils_from_uint32_buffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { + return utils_from_intbuffer_helper(n_args, pos_args, kw_args, UTILS_UINT32_BUFFER); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint32_buffer_obj, 1, utils_from_uint32_buffer); +#endif + +#endif + +static const mp_rom_map_elem_t ulab_utils_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utils) }, + #if ULAB_UTILS_HAS_FROM_INT16_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_int16_buffer), (mp_obj_t)&utils_from_int16_buffer_obj }, + #endif + #if ULAB_UTILS_HAS_FROM_UINT16_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_uint16_buffer), (mp_obj_t)&utils_from_uint16_buffer_obj }, + #endif + #if ULAB_UTILS_HAS_FROM_INT32_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_int32_buffer), (mp_obj_t)&utils_from_int32_buffer_obj }, + #endif + #if ULAB_UTILS_HAS_FROM_UINT32_BUFFER + { MP_OBJ_NEW_QSTR(MP_QSTR_from_uint32_buffer), (mp_obj_t)&utils_from_uint32_buffer_obj }, + #endif +}; + +static MP_DEFINE_CONST_DICT(mp_module_ulab_utils_globals, ulab_utils_globals_table); + +mp_obj_module_t ulab_utils_module = { + .base = { &mp_type_module }, + .globals = (mp_obj_dict_t*)&mp_module_ulab_utils_globals, +}; + +#endif diff --git a/python/port/mod/ulab/utils/utils.h b/python/port/mod/ulab/utils/utils.h new file mode 100644 index 000000000..3b258bf24 --- /dev/null +++ b/python/port/mod/ulab/utils/utils.h @@ -0,0 +1,19 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2020-2021 Zoltán Vörös +*/ + +#ifndef _UTILS_ +#define _UTILS_ + +#include "../ulab.h" +#include "../ndarray.h" + +extern mp_obj_module_t ulab_utils_module; + +#endif diff --git a/python/port/mpconfigport.h b/python/port/mpconfigport.h index fa3d71da6..07a6e3e99 100644 --- a/python/port/mpconfigport.h +++ b/python/port/mpconfigport.h @@ -136,6 +136,7 @@ extern const struct _mp_obj_module_t modpyplot_module; extern const struct _mp_obj_module_t modtime_module; extern const struct _mp_obj_module_t modos_module; extern const struct _mp_obj_module_t modturtle_module; +extern const struct _mp_obj_module_t ulab_user_cmodule; #define MICROPY_PORT_BUILTIN_MODULES \ { MP_ROM_QSTR(MP_QSTR_ion), MP_ROM_PTR(&modion_module) }, \ @@ -145,6 +146,7 @@ extern const struct _mp_obj_module_t modturtle_module; { MP_ROM_QSTR(MP_QSTR_time), MP_ROM_PTR(&modtime_module) }, \ { MP_ROM_QSTR(MP_QSTR_os), MP_ROM_PTR(&modos_module) }, \ { MP_ROM_QSTR(MP_QSTR_turtle), MP_ROM_PTR(&modturtle_module) }, \ + { MP_ROM_QSTR(MP_QSTR_ulab), MP_ROM_PTR(&ulab_user_cmodule) }, \ // Enable setjmp in debug mode. This is to avoid some optimizations done // specifically for x86_64 using inline assembly, which makes the debug binary diff --git a/python/port/port.cpp b/python/port/port.cpp index 1f83a01dd..e90b9de0b 100644 --- a/python/port/port.cpp +++ b/python/port/port.cpp @@ -61,6 +61,7 @@ extern "C" { #include "mphalport.h" #include "mod/turtle/modturtle.h" #include "mod/matplotlib/pyplot/modpyplot.h" +#include "mod/ulab/ulab.h" } #include From 837fcd9bcc491e491f8aa392cd5c09d47e1927b9 Mon Sep 17 00:00:00 2001 From: ArtichOwO Date: Wed, 23 Jun 2021 23:08:46 +0200 Subject: [PATCH 2/7] [MPY/MOD/ULAB] Added N100 compatibility N100: - doesn't have Scipy; - uses function pointers --- python/port/mod/ulab/ulab.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/python/port/mod/ulab/ulab.h b/python/port/mod/ulab/ulab.h index e38310020..647672d8b 100644 --- a/python/port/mod/ulab/ulab.h +++ b/python/port/mod/ulab/ulab.h @@ -35,7 +35,11 @@ // Determines, whether scipy is defined in ulab. The sub-modules and functions // of scipy have to be defined separately #ifndef ULAB_HAS_SCIPY +#if defined(DEVICE_N0100) #define ULAB_HAS_SCIPY (0) +#else +#define ULAB_HAS_SCIPY (1) +#endif #endif // The maximum number of dimensions the firmware should be able to support @@ -82,8 +86,12 @@ // 2 kB in the two-dimensional case, and around 4 kB in the four-dimensional case. #ifndef NDARRAY_BINARY_USES_FUN_POINTER +#if defined(DEVICE_N0100) +#define NDARRAY_BINARY_USES_FUN_POINTER (1) +#else #define NDARRAY_BINARY_USES_FUN_POINTER (0) #endif +#endif #ifndef NDARRAY_HAS_BINARY_OP_ADD #define NDARRAY_HAS_BINARY_OP_ADD (1) From 74635f8d88191aa21fd30ba4f743eb9c4aad9fc2 Mon Sep 17 00:00:00 2001 From: Laury Date: Fri, 3 Sep 2021 22:57:04 +0200 Subject: [PATCH 3/7] [code/ulab] Added ulab to toolbox --- apps/code/catalog.de.i18n | 98 ++++++++++++++ apps/code/catalog.en.i18n | 98 ++++++++++++++ apps/code/catalog.es.i18n | 98 ++++++++++++++ apps/code/catalog.fr.i18n | 98 ++++++++++++++ apps/code/catalog.hu.i18n | 98 ++++++++++++++ apps/code/catalog.it.i18n | 98 ++++++++++++++ apps/code/catalog.nl.i18n | 98 ++++++++++++++ apps/code/catalog.pt.i18n | 98 ++++++++++++++ apps/code/catalog.universal.i18n | 110 ++++++++++++++++ apps/code/python_toolbox.cpp | 122 ++++++++++++++++++ apps/code/toolbox.universal.i18n | 5 + .../include/escher/nested_menu_controller.h | 2 +- 12 files changed, 1022 insertions(+), 1 deletion(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 1e2e2e419..2c942a56e 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Kandinsky-Modul importieren" PythonImportRandom = "Random-Modul importieren" PythonImportMath = "Math-Modul importieren" PythonImportMatplotlibPyplot = "Matplotlib.pyplot-Modul importieren" +PythonImportNumpy = "Ulab.numpy-Modul importieren" PythonImportOs = "OS-Modul importieren" PythonOsUname = "Informationen über das System holen" PythonOsGetlogin = "Benutzernamen holen" @@ -104,6 +105,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Bruch- und Ganzzahl-Anteile von x" PythonMonotonic = "Wert einer monotonen Uhr" +PythonNumpyFunction = "numpy Modul-Präfix" +PythonNumpyFftFunction = "numpy.fft Modul-Präfix" +PythonNumpyLinalgFunction = "numpy.linalg Modul-Präfix" +PythonNumpyArray = "Konvertieren Sie ein Array in ndarray" +PythonNumpyArange = "Erstellen Sie eine Tabelle aus dem Bereich (i)" +PythonNumpyConcatenate = "Verketten Sie a und b" +PythonNumpyDiag = "Extrahiere oder konstruiere ein diagonales Array" +PythonNumpyZeros = "S-förmiges Array gefüllt mit 0" +PythonNumpyOnes = "S-förmiges Array gefüllt mit 1" +PythonNumpyEmpty = "Nicht initialisiertes Array der Form s" +PythonNumpyEye = "Tabelle mit Einsen auf der Diagonale und Nullen an anderer Stelle" +PythonNumpyFull = "S-förmiges Array gefüllt mit v" +PythonNumpyLinspace = "Zahlen, die über ein bestimmtes Intervall verteilt sind" +PythonNumpyLogspace = "Zahlen mit logarithmischem Abstand" +PythonNumpyCopy = "Kopie der Tabelle" +PythonNumpyDtype = "Tischtyp" +PythonNumpyFlat = "Flat-Array-Iterator" +PythonNumpyFlatten = "Abgeflachte Version der Tabelle" +PythonNumpyShape = "Holen Sie sich die Form des Arrays" +PythonNumpyReshape = "Array-Form durch s ersetzen" +PythonNumpySize = "Anzahl der Elemente im Array" +PythonNumpyTranspose = "Transponierte Version der Tabelle" +PythonNumpySortWithArguments = "Sortierte Version der Tabelle" +PythonNumpyNdinfo = "Informationen zu a . drucken" +PythonNumpyAll = "Testen Sie, ob alle Elemente von a trye sind" +PythonNumpyAny = "Teste, ob ein Element von a wahr ist" +PythonNumpyArgmax = "Index des Maximalwertes von a" +PythonNumpyArgmin = "Tiefgestellter Wert des Mindestwertes von a" +PythonNumpyArgsort = "Hinweise, die ein Array sortieren würden" +PythonNumpyClip = "Werte in einem Array ausschneiden" +PythonNumpyConvolve = "Diskrete lineare Faltung von a und b" +PythonNumpyDiff = "Abgeleitet von a" +PythonNumpyInterp = "Linear interpolierte Werte von a" +PythonNumpyDot = "Punktprodukt von a und b" +PythonNumpyCross = "Kreuzprodukt von a und b" +PythonNumpyEqual = "A == Element für Element" +PythonNumpyNot_equal = "A! = Element für Element" +PythonNumpyFlip = "Turnaround-Tabelle" +PythonNumpyIsfinite = "Testen Sie die Endlichkeit Element für Element" +PythonNumpyIsinf = "Teste die Unendlichkeit Element für Element" +PythonNumpyMean = "Durchschnitt d" +PythonNumpyMin = "Maximalwert von a" +PythonNumpyMax = "Mindestwert von a" +PythonNumpyMedian = "Medianwert von a" +PythonNumpyMinimum = "Minimale Array-Elemente pro Element" +PythonNumpyMaximum = "Maximum pro Element von Array-Elementen" +PythonNumpyPolyfit = "Polynomanpassung der kleinsten Quadrate" +PythonNumpyPolyval = "Bewerte ein Polynom bei bestimmten Werten" +PythonNumpyRoll = "Verschiebe den Inhalt von a um n" +PythonNumpySort = "Sortieren nach" +PythonNumpyStd = "Berechnen Sie die Standardabweichung von a" +PythonNumpySum = "Berechnen Sie die Summe von a" +PythonNumpyTrace = "Berechnen Sie die Summe der diagonalen Elemente von a" +PythonNumpyTrapz = "Integrieren Sie mit dem zusammengesetzten Trapezlineal" +PythonNumpyWhere = "Gibt Elemente aus x oder y gemäß c . zurück" +PythonNumpyVectorize = "Vektorisieren Sie die generische Python-Funktion f" +PythonNumpyAcos = "Wenden Sie acos Artikel für Artikel an" +PythonNumpyAcosh = "Wenden Sie acosh Artikel für Artikel an" +PythonNumpyArctan2 = "arctan2 Element für Element anwenden" +PythonNumpyAround = "Um das Element herum auftragen" +PythonNumpyAsin = "Element für Element anwenden" +PythonNumpyAsinh = "Wenden Sie asinh Element für Element an" +PythonNumpyAtan = "Wenden Sie ein Element für Element an" +PythonNumpyAtanh = "Wenden Sie atanh Element für Element an" +PythonNumpyCeil = "Bringen Sie die Decke nach Element an" +PythonNumpyCos = "Wenden Sie cos Element für Element an" +PythonNumpyCosh = "Wenden Sie cosh Element für Element an" +PythonNumpyDegrees = "Grade Element für Element anwenden" +PythonNumpyExp = "Exp pro Artikel anwenden" +PythonNumpyExpm1 = "Wenden Sie expm1 Element für Element an" +PythonNumpyFloor = "Boden nach Element auftragen" +PythonNumpyLog = "Tagebuch nach Artikel anwenden" +PythonNumpyLog10 = "Wenden Sie log10 Element für Element an" +PythonNumpyLog2 = "Wenden Sie log2 Element für Element an" +PythonNumpyRadians = "Wenden Sie Radiant pro Element an" +PythonNumpySin = "Wende Sünde nach Element an" +PythonNumpySinh = "Wenden Sie sinh Element für Element an" +PythonNumpySqrt = "Wenden Sie sqrt Element für Element an" +PythonNumpyTan = "Trage die Bräune nach Element auf" +PythonNumpyTanh = "Tanh pro Artikel auftragen" +PythonNumpyBool = "Bool Typ von numpy" +PythonNumpyFloat = "Float-Typ von numpy" +PythonNumpyUint8 = "Geben Sie uint8 von numpy . ein" +PythonNumpyInt8 = "Geben Sie int8 von numpy . ein" +PythonNumpyUint16 = "Geben Sie uint16 von numpy ein" +PythonNumpyInt16 = "Geben Sie int16 von numpy . ein" +PythonNumpyNan = "Nan-Darstellung von numpy" +PythonNumpyInf = "Inf-Darstellung von numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "Eindimensionale diskrete Fourier-Transformation" +PythonNumpyIfft = "Eindimensionale inverse diskrete Fourier-Transformation" +PythonNumpyDet = "Determinante von a" +PythonNumpyEig = "Eigenwerte und rechte Eigenvektoren von a" +PythonNumpyCholesky = "Cholesky-Zerlegung" +PythonNumpyInv = "Inverse Matrix a" +PythonNumpyNorm = "Matrix- oder Vektorstandard" PythonOct = "Ganzzahl in Oktal umwandeln" PythonPhase = "Phase von z" PythonPlot = "Plotten von y gegen x als Linien" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 169955b45..09de24ccb 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Import kandinsky module" PythonImportRandom = "Import random module" PythonImportMath = "Import math module" PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" +PythonImportNumpy = "Import ulab.numpy module" PythonImportTime = "Import time module" PythonImportTurtle = "Import turtle module" PythonIndex = "Index of the first x occurrence" @@ -98,6 +99,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" +PythonNumpyFunction = "numpy module prefix" +PythonNumpyFftFunction = "numpy.fft module prefix" +PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonNumpyArray = "Convert an array to ndarray" +PythonNumpyArange = "Make a table from the range (i)" +PythonNumpyConcatenate = "Concatenate a and b" +PythonNumpyDiag = "Extract or construct a diagonal array" +PythonNumpyZeros = "S shape array filled with 0" +PythonNumpyOnes = "S shape array filled with 1" +PythonNumpyEmpty = "Uninitialized array of form s" +PythonNumpyEye = "Table with 1s on the diagonal and 0s elsewhere" +PythonNumpyFull = "S shape array filled with v" +PythonNumpyLinspace = "Numbers spaced over a specified interval" +PythonNumpyLogspace = "Numbers spaced on a logarithmic scale" +PythonNumpyCopy = "Copy of table" +PythonNumpyDtype = "Table type" +PythonNumpyFlat = "Flat array iterator" +PythonNumpyFlatten = "Flattened version of the table" +PythonNumpyShape = "Get the shape of the array" +PythonNumpyReshape = "Replace array shape with s" +PythonNumpySize = "Number of elements in the array" +PythonNumpyTranspose = "Transposed version of the table" +PythonNumpySortWithArguments = "Sorted version of the table" +PythonNumpyNdinfo = "Print information about a" +PythonNumpyAll = "Test if all elements of a are trye" +PythonNumpyAny = "Test if an element of a is true" +PythonNumpyArgmax = "Index of the maximum value of a" +PythonNumpyArgmin = "Subscript of the minimum value of a" +PythonNumpyArgsort = "Clues that would sort an array" +PythonNumpyClip = "Cut values in an array" +PythonNumpyConvolve = "Discrete linear convolution of a and b" +PythonNumpyDiff = "Derived from a" +PythonNumpyInterp = "Linearly interpolated values of a" +PythonNumpyDot = "Dot product of a and b" +PythonNumpyCross = "Cross product of a and b" +PythonNumpyEqual = "A == a element by element" +PythonNumpyNot_equal = "A! = A element by element" +PythonNumpyFlip = "Turnaround table" +PythonNumpyIsfinite = "Test the finiteness element by element" +PythonNumpyIsinf = "Test the infinity element by element" +PythonNumpyMean = "Average d" +PythonNumpyMin = "Maximum value of a" +PythonNumpyMax = "Minimum value of a" +PythonNumpyMedian = "Median value of a" +PythonNumpyMinimum = "Minimum array elements per element" +PythonNumpyMaximum = "Maximum per element of array elements" +PythonNumpyPolyfit = "Least squares polynomial fit" +PythonNumpyPolyval = "Evaluate a polynomial at specific values" +PythonNumpyRoll = "Shift the content of a by n" +PythonNumpySort = "Sort to" +PythonNumpyStd = "Calculate the standard deviation of a" +PythonNumpySum = "Calculate the sum of a" +PythonNumpyTrace = "Calculate the sum of the diagonal elements of a" +PythonNumpyTrapz = "Integrate using the composite trapezoidal ruler" +PythonNumpyWhere = "Returns elements chosen from x or y according to c" +PythonNumpyVectorize = "Vectorize the generic python function f" +PythonNumpyAcos = "Apply acos item by item" +PythonNumpyAcosh = "Apply acosh item by item" +PythonNumpyArctan2 = "Apply arctan2 element by element" +PythonNumpyAround = "Apply around the element" +PythonNumpyAsin = "Apply asin element by element" +PythonNumpyAsinh = "Apply asinh element by element" +PythonNumpyAtan = "Apply one item by item" +PythonNumpyAtanh = "Apply atanh element by element" +PythonNumpyCeil = "Apply the ceiling by element" +PythonNumpyCos = "Apply cos element by element" +PythonNumpyCosh = "Apply cosh element by element" +PythonNumpyDegrees = "Apply degrees element by element" +PythonNumpyExp = "Apply exp per item" +PythonNumpyExpm1 = "Apply expm1 element by element" +PythonNumpyFloor = "Apply soil by element" +PythonNumpyLog = "Apply journal by item" +PythonNumpyLog10 = "Apply log10 element by element" +PythonNumpyLog2 = "Apply log2 element by element" +PythonNumpyRadians = "Apply radians per element" +PythonNumpySin = "Apply sin by element" +PythonNumpySinh = "Apply sinh element by element" +PythonNumpySqrt = "Apply sqrt element by element" +PythonNumpyTan = "Apply the tan by element" +PythonNumpyTanh = "Apply tanh per item" +PythonNumpyBool = "Bool type of numpy" +PythonNumpyFloat = "Float type of numpy" +PythonNumpyUint8 = "Type uint8 of numpy" +PythonNumpyInt8 = "Type int8 of numpy" +PythonNumpyUint16 = "Type uint16 from numpy" +PythonNumpyInt16 = "Type int16 of numpy" +PythonNumpyNan = "Nan representation of numpy" +PythonNumpyInf = "Inf representation of numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "One-dimensional discrete fourier transform" +PythonNumpyIfft = "One-dimensional inverse discrete fourier transform" +PythonNumpyDet = "Determinant of a" +PythonNumpyEig = "Eigenvalues and right eigenvectors of a" +PythonNumpyCholesky = "Cholesky decomposition" +PythonNumpyInv = "Inverse matrix a" +PythonNumpyNorm = "Matrix or vector standard" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index ef181756a..48bff282b 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Import kandinsky module" PythonImportRandom = "Import random module" PythonImportMath = "Import math module" PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" +PythonImportNumpy = "Import ulab.numpy module" PythonImportTime = "Import time module" PythonImportTurtle = "Import turtle module" PythonIndex = "Index of the first x occurrence" @@ -98,6 +99,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Fractional and integer parts of x" PythonMonotonic = "Value of a monotonic clock" +PythonNumpyFunction = "numpy module prefix" +PythonNumpyFftFunction = "numpy.fft module prefix" +PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonNumpyArray = "Convertir una matriz a ndarray" +PythonNumpyArange = "Haz una tabla de la gama (i)" +PythonNumpyConcatenate = "Concatenar ayb" +PythonNumpyDiag = "Extraer o construir una matriz diagonal" +PythonNumpyZeros = "Matriz en forma de S rellena con 0" +PythonNumpyOnes = "Matriz en forma de S llena con 1" +PythonNumpyEmpty = "Matriz no inicializada de formulario s" +PythonNumpyEye = "Tabla con 1 en la diagonal y 0 en el resto" +PythonNumpyFull = "Matriz en forma de S rellena con v" +PythonNumpyLinspace = "Números espaciados en un intervalo específico" +PythonNumpyLogspace = "Números espaciados en una escala logarítmica" +PythonNumpyCopy = "Copia de la tabla" +PythonNumpyDtype = "Tipo de mesa" +PythonNumpyFlat = "Iterador de matriz plana" +PythonNumpyFlatten = "Versión aplanada de la mesa." +PythonNumpyShape = "Obtén la forma de la matriz" +PythonNumpyReshape = "Reemplazar la forma de la matriz con s" +PythonNumpySize = "Número de elementos en la matriz" +PythonNumpyTranspose = "Versión transpuesta de la tabla" +PythonNumpySortWithArguments = "Versión ordenada de la tabla" +PythonNumpyNdinfo = "Imprimir información sobre un" +PythonNumpyAll = "Prueba si todos los elementos de a son probables" +PythonNumpyAny = "Prueba si un elemento de a es verdadero" +PythonNumpyArgmax = "Índice del valor máximo de un" +PythonNumpyArgmin = "Subíndice del valor mínimo de un" +PythonNumpyArgsort = "Pistas que ordenarían una matriz" +PythonNumpyClip = "Cortar valores en una matriz" +PythonNumpyConvolve = "Convolución lineal discreta de ayb" +PythonNumpyDiff = "Derivado de un" +PythonNumpyInterp = "Valores interpolados linealmente de a" +PythonNumpyDot = "Producto escalar de ayb" +PythonNumpyCross = "Producto cruzado de ayb" +PythonNumpyEqual = "A == un elemento por elemento" +PythonNumpyNot_equal = "A! = Un elemento por elemento" +PythonNumpyFlip = "Tabla de cambio" +PythonNumpyIsfinite = "Prueba la finitud elemento por elemento" +PythonNumpyIsinf = "Prueba el infinito elemento por elemento" +PythonNumpyMean = "Promedio d" +PythonNumpyMin = "Valor máximo de un" +PythonNumpyMax = "Valor mínimo de un" +PythonNumpyMedian = "Valor mediano de a" +PythonNumpyMinimum = "Elementos de matriz mínimos por elemento" +PythonNumpyMaximum = "Máximo por elemento de elementos de matriz" +PythonNumpyPolyfit = "Ajuste de polinomio de mínimos cuadrados" +PythonNumpyPolyval = "Evaluar un polinomio en valores específicos" +PythonNumpyRoll = "Cambiar el contenido de a por n" +PythonNumpySort = "Ordenar por" +PythonNumpyStd = "Calcule la desviación estándar de un" +PythonNumpySum = "Calcule la suma de a" +PythonNumpyTrace = "Calcule la suma de los elementos diagonales de un" +PythonNumpyTrapz = "Integrar usando la regla trapezoidal compuesta" +PythonNumpyWhere = "Devuelve elementos elegidos de xoy según c" +PythonNumpyVectorize = "Vectorizar la función genérica de python f" +PythonNumpyAcos = "Aplicar acos artículo por artículo" +PythonNumpyAcosh = "Aplicar un elemento por elemento" +PythonNumpyArctan2 = "Aplicar arctan2 elemento por elemento" +PythonNumpyAround = "Aplicar alrededor del elemento" +PythonNumpyAsin = "Aplicar asin elemento por elemento" +PythonNumpyAsinh = "Aplicar asinh elemento por elemento" +PythonNumpyAtan = "Aplicar un artículo por artículo" +PythonNumpyAtanh = "Aplicar atanh elemento por elemento" +PythonNumpyCeil = "Aplicar el techo por elemento" +PythonNumpyCos = "Aplicar cos elemento por elemento" +PythonNumpyCosh = "Aplicar cosh elemento por elemento" +PythonNumpyDegrees = "Aplicar grados elemento por elemento" +PythonNumpyExp = "Aplicar exp por artículo" +PythonNumpyExpm1 = "Aplicar expm1 elemento por elemento" +PythonNumpyFloor = "Aplicar suelo por elemento" +PythonNumpyLog = "Aplicar diario por artículo" +PythonNumpyLog10 = "Aplicar log10 elemento por elemento" +PythonNumpyLog2 = "Aplicar log2 elemento por elemento" +PythonNumpyRadians = "Aplicar radianes por elemento" +PythonNumpySin = "Aplicar el pecado por elemento" +PythonNumpySinh = "Aplicar sinh elemento por elemento" +PythonNumpySqrt = "Aplicar elemento sqrt por elemento" +PythonNumpyTan = "Aplicar el bronceado por elemento" +PythonNumpyTanh = "Aplicar tanh por artículo" +PythonNumpyBool = "Bool tipo de numpy" +PythonNumpyFloat = "Flotador tipo de numpy" +PythonNumpyUint8 = "Escriba uint8 de numpy" +PythonNumpyInt8 = "Escriba int8 de numpy" +PythonNumpyUint16 = "Escriba uint16 desde numpy" +PythonNumpyInt16 = "Escriba int16 de numpy" +PythonNumpyNan = "Nan representación de numpy" +PythonNumpyInf = "Inf representación de numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "Transformada de Fourier discreta unidimensional" +PythonNumpyIfft = "Transformada de Fourier discreta inversa unidimensional" +PythonNumpyDet = "Determinante de un" +PythonNumpyEig = "Autovalores y autovectores derechos de un" +PythonNumpyCholesky = "Descomposición de Cholesky" +PythonNumpyInv = "Matriz inversa a" +PythonNumpyNorm = "Matriz o estándar vectorial" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index efb491f41..5846f7c4a 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Importation du module kandinsky" PythonImportRandom = "Importation du module random" PythonImportMath = "Importation du module math" PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot" +PythonImportNumpy = "Importation de ulab.numpy" PythonImportTurtle = "Importation du module turtle" PythonImportTime = "Importation du module time" PythonIndex = "Indice première occurrence de x" @@ -98,6 +99,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Parties fractionnaire et entière" PythonMonotonic = "Renvoie la valeur de l'horloge" +PythonNumpyFunction = "Préfixe fonction du module numpy" +PythonNumpyFftFunction = "Préfixe fonction du module numpy.fft" +PythonNumpyLinalgFunction = "Préfixe fonction du module numpy.linalg" +PythonNumpyArray = "Convertir un tableau en ndarray" +PythonNumpyArange = "Faire un tableau à partir de la plage (i)" +PythonNumpyConcatenate = "Concaténer a et b" +PythonNumpyDiag = "Extraire ou construire un tableau diagonal" +PythonNumpyZeros = "Tableau de forme s rempli de 0" +PythonNumpyOnes = "Tableau de forme s rempli de 1" +PythonNumpyEmpty = "Tableau uninitialisé de forme s" +PythonNumpyEye = "Tableau avec des 1 sur la diagonale et des 0 ailleurs" +PythonNumpyFull = "Tableau de forme s rempli de v" +PythonNumpyLinspace = "Nombres espacés sur un intervalle spécifié" +PythonNumpyLogspace = "Nombres espacés sur une échelle logarithmique" +PythonNumpyCopy = "Copie du tableau" +PythonNumpyDtype = "Dtype du tableau" +PythonNumpyFlat = "Itérateur plat du tableau" +PythonNumpyFlatten = "Version aplatie du tableau" +PythonNumpyShape = "Obtenir la forme du tableau" +PythonNumpyReshape = "Remplacer la forme du tableau par s" +PythonNumpySize = "Nombre d'éléments dans le tableau" +PythonNumpyTranspose = "Version transposée du tableau" +PythonNumpySortWithArguments = "Version triée du tableau" +PythonNumpyNdinfo = "Imprimer des informations sur un" +PythonNumpyAll = "Tester si tous les éléments de a sont trye" +PythonNumpyAny = "Tester si un élément de a est vrai" +PythonNumpyArgmax = "Indice de la valeur maximale de a" +PythonNumpyArgmin = "Indice de la valeur minimale de a" +PythonNumpyArgsort = "Indices qui trieraient un tableau" +PythonNumpyClip = "Couper les valeurs dans un tableau" +PythonNumpyConvolve = "Convolution linéaire discrète de a et b" +PythonNumpyDiff = "Dérivée du a" +PythonNumpyInterp = "Valeurs interpolées linéairement de a" +PythonNumpyDot = "Produit scalaire de a et b" +PythonNumpyCross = "Produit vectoriel de a et b" +PythonNumpyEqual = "a == a élément par élément" +PythonNumpyNot_equal = "a != a élément par élément" +PythonNumpyFlip = "Tableau de retournement" +PythonNumpyIsfinite = "Testez la finitude élément par élément" +PythonNumpyIsinf = "Testez l'infinité élément par élément" +PythonNumpyMean = "Moyenne d" +PythonNumpyMin = "Valeur maximale de a" +PythonNumpyMax = "Valeur minimale de a" +PythonNumpyMedian = "Valeur médiane de a" +PythonNumpyMinimum = "Minimum d'éléments de tableau par élément" +PythonNumpyMaximum = "Maximum par élément d'éléments de tableau" +PythonNumpyPolyfit = "Ajustement polynomial des moindres carrés" +PythonNumpyPolyval = "Évaluer un polynôme à des valeurs spécifiques" +PythonNumpyRoll = "Décaler le contenu de a par n" +PythonNumpySort = "Trier a" +PythonNumpyStd = "Calculer l'écart type de a" +PythonNumpySum = "Calculer la somme de a" +PythonNumpyTrace = "Calculer la somme des éléments diagonaux de a" +PythonNumpyTrapz = "Intégrer à l'aide de la règle trapézoïdale composite" +PythonNumpyWhere = "Renvoie des éléments choisis parmi x ou y selon c" +PythonNumpyVectorize = "Vectoriser la fonction python générique f" +PythonNumpyAcos = "Appliquer acos élément par élément" +PythonNumpyAcosh = "Appliquer acosh élément par élément" +PythonNumpyArctan2 = "Appliquer arctan2 élément par élément" +PythonNumpyAround = "Appliquer autour de l'élément" +PythonNumpyAsin = "Appliquer asin élément par élément" +PythonNumpyAsinh = "Appliquer asinh élément par élément" +PythonNumpyAtan = "Appliquer un élément par élément" +PythonNumpyAtanh = "Appliquer atanh élément par élément" +PythonNumpyCeil = "Appliquer le plafond par élément" +PythonNumpyCos = "Appliquer cos élément par élément" +PythonNumpyCosh = "Appliquer cosh élément par élément" +PythonNumpyDegrees = "Appliquer des degrés élément par élément" +PythonNumpyExp = "Appliquer exp par élément" +PythonNumpyExpm1 = "Appliquer expm1 élément par élément" +PythonNumpyFloor = "Appliquer le sol par élément" +PythonNumpyLog = "Appliquer le journal par élément" +PythonNumpyLog10 = "Appliquer log10 élément par élément" +PythonNumpyLog2 = "Appliquer log2 élément par élément" +PythonNumpyRadians = "Appliquer des radians par élément" +PythonNumpySin = "Appliquer le péché par élément" +PythonNumpySinh = "Appliquer sinh élément par élément" +PythonNumpySqrt = "Appliquer sqrt élément par élément" +PythonNumpyTan = "Appliquer le bronzage par élément" +PythonNumpyTanh = "Appliquer tanh par élément" +PythonNumpyBool = "Type bool de numpy" +PythonNumpyFloat = "Type float de numpy" +PythonNumpyUint8 = "Tapez uint8 de numpy" +PythonNumpyInt8 = "Tapez int8 de numpy" +PythonNumpyUint16 = "Tapez uint16 de numpy" +PythonNumpyInt16 = "Tapez int16 de numpy" +PythonNumpyNan = "Nan représentation de numpy" +PythonNumpyInf = "Inf représentation de numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "Transformée de Fourier discrète à une dimension" +PythonNumpyIfft = "Transformée de Fourier discrète inverse unidimensionnelle" +PythonNumpyDet = "Déterminant de a" +PythonNumpyEig = "Valeurs propres et vecteurs propres droits de a" +PythonNumpyCholesky = "Décomposition de Cholesky" +PythonNumpyInv = "Matrice inverse a" +PythonNumpyNorm = "Norme matricielle ou vectorielle" PythonOct = "Conversion en octal" PythonPhase = "Argument de z" PythonPlot = "Trace y en fonction de x" diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n index 90a82696f..f5365e633 100644 --- a/apps/code/catalog.hu.i18n +++ b/apps/code/catalog.hu.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Kandinsky modul importálása" PythonImportRandom = "Véletlenszerü modul importálása" PythonImportMath = "math modul importálása" PythonImportMatplotlibPyplot = "matplotlib.pyplot modul importálása" +PythonImportNumpy = "ulab.numpy modul importálása" PythonImportTurtle = "turtle modul importálása" PythonImportTime = "time modul importálása" PythonIndex = "Az elsö x esemény indexe" @@ -98,6 +99,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "x-nek tört és egész részei" PythonMonotonic = "Az óra értékét adja vissza" +PythonNumpyFunction = "numpy elötag" +PythonNumpyFftFunction = "numpy.fft elötag" +PythonNumpyLinalgFunction = "numpy.linalg elötag" +PythonNumpyArray = "Egy tömb konvertálása ndarray -re" +PythonNumpyArange = "Készítsen táblázatot az (i) tartományból" +PythonNumpyConcatenate = "Összekapcsolás a és b" +PythonNumpyDiag = "Bontson ki vagy készítsen átlós tömböt" +PythonNumpyZeros = "S alakú tömb 0 -val kitöltve" +PythonNumpyOnes = "S alakú tömb 1-el" +PythonNumpyEmpty = "Az űrlap inicializálatlan tömbje" +PythonNumpyEye = "Asztal 1 -es átlóval és 0 -val máshol" +PythonNumpyFull = "S alakú tömb tele v" +PythonNumpyLinspace = "Számok meghatározott intervallumon belül" +PythonNumpyLogspace = "A számok logaritmikus skálán helyezkednek el" +PythonNumpyCopy = "A táblázat másolata" +PythonNumpyDtype = "Táblázat típusa" +PythonNumpyFlat = "Lapos tömb iterátor" +PythonNumpyFlatten = "Az asztal lapított változata" +PythonNumpyShape = "Szerezd meg a tömb alakját" +PythonNumpyReshape = "Cserélje le a tömb alakját az s -vel" +PythonNumpySize = "A tömb elemeinek száma" +PythonNumpyTranspose = "A táblázat átültetett változata" +PythonNumpySortWithArguments = "A táblázat rendezett változata" +PythonNumpyNdinfo = "Információk nyomtatása a" +PythonNumpyAll = "Ellenőrizze, hogy egy elem minden eleme trye" +PythonNumpyAny = "Ellenőrizze, hogy az a eleme igaz -e" +PythonNumpyArgmax = "A maximális érték indexe a" +PythonNumpyArgmin = "A minimális értékének a indexe" +PythonNumpyArgsort = "Nyomok, amelyek rendeznek egy tömböt" +PythonNumpyClip = "Vágja le az értékeket egy tömbben" +PythonNumpyConvolve = "A és b diszkrét lineáris konvolúciója" +PythonNumpyDiff = "Származik a" +PythonNumpyInterp = "A lineárisan interpolált értékei" +PythonNumpyDot = "Az a és b pontszerű szorzata" +PythonNumpyCross = "Az a és b keresztterméke" +PythonNumpyEqual = "A == elemenként" +PythonNumpyNot_equal = "A! = Elemenként" +PythonNumpyFlip = "Fordulóasztal" +PythonNumpyIsfinite = "Tesztelje a végességet elemenként" +PythonNumpyIsinf = "Tesztelje a végtelen elemet elemenként" +PythonNumpyMean = "Átlagos d" +PythonNumpyMin = "Maximális értéke a" +PythonNumpyMax = "Minimális értéke a" +PythonNumpyMedian = "Medián értéke a" +PythonNumpyMinimum = "Minimális tömb elemek elemenként" +PythonNumpyMaximum = "Maximum tömb elemenként" +PythonNumpyPolyfit = "Legkevesebb négyzet polinom illeszkedés" +PythonNumpyPolyval = "Polinom értékelése meghatározott értékeken" +PythonNumpyRoll = "Az a tartalmának eltolása n -vel" +PythonNumpySort = "Rendezés ide" +PythonNumpyStd = "Számítsa ki a szórását a" +PythonNumpySum = "Számítsa ki a összegét" +PythonNumpyTrace = "Számítsa ki az a átlós elemeinek összegét!" +PythonNumpyTrapz = "Integrálja az összetett trapéz vonalzó használatával" +PythonNumpyWhere = "A c szerint x vagy y közül választott elemeket adja vissza" +PythonNumpyVectorize = "Vektorizálja az általános python függvényt f" +PythonNumpyAcos = "Alkalmazza az acos -t elemenként" +PythonNumpyAcosh = "Alkalmazza az elemeket elemenként" +PythonNumpyArctan2 = "Alkalmazza az arctan2 elemet elemenként" +PythonNumpyAround = "Alkalmazza az elem körül" +PythonNumpyAsin = "Alkalmazza az asszonyt elemenként" +PythonNumpyAsinh = "Alkalmazza az elemet elemenként" +PythonNumpyAtan = "Alkalmazzon egy elemet elemenként" +PythonNumpyAtanh = "Alkalmazza az atanh elemenként" +PythonNumpyCeil = "Alkalmazza a mennyezetet elemenként" +PythonNumpyCos = "Alkalmazza a cos elemet elemenként" +PythonNumpyCosh = "Alkalmazza a cosh elemet elemenként" +PythonNumpyDegrees = "Alkalmazza a fokokat elemenként" +PythonNumpyExp = "Alkalmazza az exp -ot elemenként" +PythonNumpyExpm1 = "Alkalmazza az expm1 elemet elemenként" +PythonNumpyFloor = "A talajt elemenként vigye fel" +PythonNumpyLog = "Napló alkalmazása tétel szerint" +PythonNumpyLog10 = "Alkalmazza a log10 elemet elemenként" +PythonNumpyLog2 = "Alkalmazza a log2 elemet elemenként" +PythonNumpyRadians = "Alkalmazzon radiánt elemenként" +PythonNumpySin = "Alkalmazza a bűnt elemenként" +PythonNumpySinh = "Alkalmazza a sinh elemet elemenként" +PythonNumpySqrt = "Alkalmazza az sqrt elemet elemenként" +PythonNumpyTan = "Vigye fel a barnulást elemenként" +PythonNumpyTanh = "Alkalmazzon tannt elemenként" +PythonNumpyBool = "Bull típusú numpy" +PythonNumpyFloat = "Lebegő típusú számológép" +PythonNumpyUint8 = "Írja be az uint8 számot" +PythonNumpyInt8 = "Írja be a numpy int8 típusát" +PythonNumpyUint16 = "Írja be az uint16 parancsot a numpy -ból" +PythonNumpyInt16 = "Írja be a numpy int16 típusát" +PythonNumpyNan = "A numpy nanos ábrázolása" +PythonNumpyInf = "A numpy inf ábrázolása" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "Egydimenziós diszkrét Fourier-transzformáció" +PythonNumpyIfft = "Egydimenziós inverz diszkrét Fourier-transzformáció" +PythonNumpyDet = "Meghatározó a" +PythonNumpyEig = "Sajátértékek és jobb sajátvektorok a" +PythonNumpyCholesky = "Cholesky bomlás" +PythonNumpyInv = "Fordított mátrix a" +PythonNumpyNorm = "Mátrix vagy vektor standard" PythonOct = "Decimális szám konvertálása octális számra" PythonPhase = "z fázisa" PythonPlot = "y-t jelöli x függvényében" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index da188e0be..9402ad69a 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Importa modulo kandinsky" PythonImportRandom = "Importa modulo random" PythonImportMath = "Importa modulo math" PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot" +PythonImportNumpy = "Importa modulo ulab.numpy" PythonImportTurtle = "Importa del modulo turtle" PythonImportTime = "Importa del modulo time" PythonImportOs = "Importa modulo os" @@ -104,6 +105,103 @@ PythonMax = "Massimo" PythonMin = "Minimo" PythonModf = "Parti frazionarie e intere" PythonMonotonic = "Restituisce il valore dell'orologio" +PythonNumpyFunction = "Prefisso modulo numpy" +PythonNumpyFftFunction = "Prefisso modulo numpy.fft" +PythonNumpyLinalgFunction = "Prefisso modulo numpy.linalg" +PythonNumpyArray = "Converti un array in ndarray" +PythonNumpyArange = "Crea una tabella dall'intervallo (i)" +PythonNumpyConcatenate = "Concatena a e b" +PythonNumpyDiag = "Estrai o costruisci un array diagonale" +PythonNumpyZeros = "Matrice a forma di S riempita con 0" +PythonNumpyOnes = "Array a forma di S riempito con 1" +PythonNumpyEmpty = "Matrice non inizializzata della forma s" +PythonNumpyEye = "Tabella con 1 in diagonale e 0 altrove" +PythonNumpyFull = "Matrice a forma di S riempita con v" +PythonNumpyLinspace = "Numeri spaziati su un intervallo specificato" +PythonNumpyLogspace = "Numeri spaziati su una scala logaritmica" +PythonNumpyCopy = "Copia della tabella" +PythonNumpyDtype = "Tipo di tabella" +PythonNumpyFlat = "Iteratore flat array" +PythonNumpyFlatten = "Versione appiattita del tavolo" +PythonNumpyShape = "Ottieni la forma dell'array" +PythonNumpyReshape = "Sostituisci la forma dell'array con s" +PythonNumpySize = "Numero di elementi nell'array" +PythonNumpyTranspose = "Versione trasposta della tabella" +PythonNumpySortWithArguments = "Versione ordinata della tabella" +PythonNumpyNdinfo = "Stampa informazioni su a" +PythonNumpyAll = "Verifica se tutti gli elementi di a sono provati" +PythonNumpyAny = "Verifica se un elemento di a è vero" +PythonNumpyArgmax = "Indice del valore massimo di a" +PythonNumpyArgmin = "Pedice del valore minimo di a" +PythonNumpyArgsort = "Indizi che ordinerebbero un array" +PythonNumpyClip = "Taglia i valori in un array" +PythonNumpyConvolve = "Convoluzione lineare discreta di a e b" +PythonNumpyDiff = "Derivato da a" +PythonNumpyInterp = "Valori interpolati linearmente di a" +PythonNumpyDot = "Prodotto scalare di a e b" +PythonNumpyCross = "Prodotto incrociato di a e b" +PythonNumpyEqual = "A == un elemento per elemento" +PythonNumpyNot_equal = "A! = Un elemento per elemento" +PythonNumpyFlip = "Tavolo di turnaround" +PythonNumpyIsfinite = "Testa la finitezza elemento per elemento" +PythonNumpyIsinf = "Prova l'infinito elemento per elemento" +PythonNumpyMean = "d . medio" +PythonNumpyMin = "Valore massimo di a" +PythonNumpyMax = "Valore minimo di a" +PythonNumpyMedian = "Valore medio di a" +PythonNumpyMinimum = "Elementi minimi dell'array per elemento" +PythonNumpyMaximum = "Massimo per elemento di elementi dell'array" +PythonNumpyPolyfit = "Approssimazione polinomiale ai minimi quadrati" +PythonNumpyPolyval = "Valuta un polinomio a valori specifici" +PythonNumpyRoll = "Sposta il contenuto di a di n" +PythonNumpySort = "Ordina per" +PythonNumpyStd = "Calcola la deviazione standard di a" +PythonNumpySum = "Calcola la somma di a" +PythonNumpyTrace = "Calcola la somma degli elementi diagonali di a" +PythonNumpyTrapz = "Integrare utilizzando il righello trapezoidale composito" +PythonNumpyWhere = "Restituisce elementi scelti da x o y secondo c" +PythonNumpyVectorize = "Vettorizza la funzione Python generica f" +PythonNumpyAcos = "Applica acos articolo per articolo" +PythonNumpyAcosh = "Applica acosh articolo per articolo" +PythonNumpyArctan2 = "Applica arctan2 elemento per elemento" +PythonNumpyAround = "Applicare intorno all'elemento" +PythonNumpyAsin = "Applica asin elemento per elemento" +PythonNumpyAsinh = "Applica asinh elemento per elemento" +PythonNumpyAtan = "Applicare un articolo per articolo" +PythonNumpyAtanh = "Applicare atanh elemento per elemento" +PythonNumpyCeil = "Applicare il soffitto per elemento" +PythonNumpyCos = "Applica cos elemento per elemento" +PythonNumpyCosh = "Applicare cosh elemento per elemento" +PythonNumpyDegrees = "Applica gradi elemento per elemento" +PythonNumpyExp = "Applica esperienza per articolo" +PythonNumpyExpm1 = "Applica expm1 elemento per elemento" +PythonNumpyFloor = "Applicare terreno per elemento" +PythonNumpyLog = "Applica giornale per articolo" +PythonNumpyLog10 = "Applica log10 elemento per elemento" +PythonNumpyLog2 = "Applica log2 elemento per elemento" +PythonNumpyRadians = "Applica radianti per elemento" +PythonNumpySin = "Applica sin per elemento" +PythonNumpySinh = "Applica sinh elemento per elemento" +PythonNumpySqrt = "Applica sqrt elemento per elemento" +PythonNumpyTan = "Applicare l'abbronzatura per elemento" +PythonNumpyTanh = "Applicare tanh per articolo" +PythonNumpyBool = "Tipo bool di numpy" +PythonNumpyFloat = "Tipo galleggiante di numpy" +PythonNumpyUint8 = "Digita uint8 di numpy" +PythonNumpyInt8 = "Digita int8 di numpy" +PythonNumpyUint16 = "Digita uint16 da numpy" +PythonNumpyInt16 = "Digita int16 di numpy" +PythonNumpyNan = "Nan rappresentazione di numpy" +PythonNumpyInf = "Inf rappresentazione di numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589933" +PythonNumpyFft = "Trasformata di Fourier discreta unidimensionale" +PythonNumpyIfft = "Trasformata di Fourier discreta inversa unidimensionale" +PythonNumpyDet = "Determinante di a" +PythonNumpyEig = "Autovalori e autovettori giusti di a" +PythonNumpyCholesky = "Decomposizione Cholesky" +PythonNumpyInv = "matrice inversa a" +PythonNumpyNorm = "Matrice o standard vettoriale" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" PythonPlot = "Disegna y in f. di x come linee" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index fb6669df3..fa54b6bc1 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Importeer kandinsky module" PythonImportRandom = "Importeer random module" PythonImportMath = "Importeer math module" PythonImportMatplotlibPyplot = "Importeer matplotlib.pyplot module" +PythonImportNumpy = "Importeer ulab.numpy module" PythonImportTime = "Importeer time module" PythonImportOs = "Importeer os module" PythonOsUname = " Krijg systeeminfo" @@ -104,6 +105,103 @@ PythonMax = "Maximum" PythonMin = "Minimum" PythonModf = "Fractionele en gehele delen van x" PythonMonotonic = "Waarde van een monotone klok" +PythonNumpyFunction = "numpy module prefix" +PythonNumpyFftFunction = "numpy.fft module prefix" +PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonNumpyArray = "Converteer een array naar ndarray" +PythonNumpyArange = "Maak een tabel uit de reeks (i)" +PythonNumpyConcatenate = "Samenvoegen a en b" +PythonNumpyDiag = "Een diagonale array extraheren of construeren" +PythonNumpyZeros = "S-vormarray gevuld met 0" +PythonNumpyOnes = "S-vormige array gevuld met 1" +PythonNumpyEmpty = "Niet-geïnitialiseerde matrix van vorm s" +PythonNumpyEye = "Tabel met enen op de diagonaal en nullen elders" +PythonNumpyFull = "S-vormarray gevuld met v" +PythonNumpyLinspace = "Getallen verdeeld over een opgegeven interval" +PythonNumpyLogspace = "Getallen op een logaritmische schaal verdeeld" +PythonNumpyCopy = "Kopie van tabel" +PythonNumpyDtype = "Tafeltype:" +PythonNumpyFlat = "Flat array iterator" +PythonNumpyFlatten = "Afgeplatte versie van de tafel" +PythonNumpyShape = "De vorm van de array verkrijgen" +PythonNumpyReshape = "Vervang matrixvorm door s" +PythonNumpySize = "Aantal elementen in de array" +PythonNumpyTranspose = "Getransponeerde versie van de tabel" +PythonNumpySortWithArguments = "Gesorteerde versie van de tafel" +PythonNumpyNdinfo = "Informatie afdrukken over a" +PythonNumpyAll = "Test of alle elementen van a trye zijn" +PythonNumpyAny = "Test of een element van a waar is" +PythonNumpyArgmax = "Index van de maximale waarde van a" +PythonNumpyArgmin = "Subscript van de minimumwaarde van a" +PythonNumpyArgsort = "Aanwijzingen die een array zouden sorteren" +PythonNumpyClip = "Knip waarden in een array" +PythonNumpyConvolve = "Discrete lineaire convolutie van a en b" +PythonNumpyDiff = "Afgeleid van a" +PythonNumpyInterp = "Lineair geïnterpoleerde waarden van a" +PythonNumpyDot = "Puntproduct van a en b" +PythonNumpyCross = "Kruisproduct van a en b" +PythonNumpyEqual = "A == een element voor element" +PythonNumpyNot_equal = "A! = Een element voor element" +PythonNumpyFlip = "Omslagtabel" +PythonNumpyIsfinite = "Test de eindigheid element voor element" +PythonNumpyIsinf = "Test het oneindige element voor element" +PythonNumpyMean = "gemiddelde d" +PythonNumpyMin = "Maximale waarde van a" +PythonNumpyMax = "Minimale waarde van a" +PythonNumpyMedian = "Mediane waarde van a" +PythonNumpyMinimum = "Minimum array-elementen per element" +PythonNumpyMaximum = "Maximum per element van array-elementen" +PythonNumpyPolyfit = "Kleinste kwadraten polynoom fit" +PythonNumpyPolyval = "Een polynoom evalueren op specifieke waarden" +PythonNumpyRoll = "Verschuif de inhoud van a met n" +PythonNumpySort = "Sorteren op" +PythonNumpyStd = "Bereken de standaarddeviatie van a" +PythonNumpySum = "Bereken de som van a" +PythonNumpyTrace = "Bereken de som van de diagonale elementen van a" +PythonNumpyTrapz = "Integreer met behulp van de samengestelde trapeziumvormige liniaal" +PythonNumpyWhere = "Retourneert elementen gekozen uit x of y volgens c" +PythonNumpyVectorize = "Vectoriseer de generieke python-functie f" +PythonNumpyAcos = "Acos item per item toepassen" +PythonNumpyAcosh = "Acosh item voor item toepassen" +PythonNumpyArctan2 = "Arctan2 element voor element toepassen" +PythonNumpyAround = "Toepassen rond het element" +PythonNumpyAsin = "Asin element voor element toepassen" +PythonNumpyAsinh = "Asinh element voor element toepassen" +PythonNumpyAtan = "Eén item per item toepassen" +PythonNumpyAtanh = "Atanh element voor element toepassen" +PythonNumpyCeil = "Breng het plafond per element aan" +PythonNumpyCos = "Pas co element voor element toe" +PythonNumpyCosh = "Cosh element voor element toepassen" +PythonNumpyDegrees = "Graden element voor element toepassen" +PythonNumpyExp = "exp per item toepassen" +PythonNumpyExpm1 = "expm1 element voor element toepassen" +PythonNumpyFloor = "Grond per element aanbrengen" +PythonNumpyLog = "Journaal per item toepassen" +PythonNumpyLog10 = "Pas log10 element voor element toe" +PythonNumpyLog2 = "Log2 element voor element toepassen" +PythonNumpyRadians = "Pas radialen toe per element" +PythonNumpySin = "Zonde per element toepassen" +PythonNumpySinh = "Sinh element voor element toepassen" +PythonNumpySqrt = "Sqrt element voor element toepassen" +PythonNumpyTan = "Breng de kleur aan per element" +PythonNumpyTanh = "Tanh toepassen per item" +PythonNumpyBool = "Bool type numpy" +PythonNumpyFloat = "Float type numpy" +PythonNumpyUint8 = "Typ uint8 van numpy" +PythonNumpyInt8 = "Typ int8 van numpy" +PythonNumpyUint16 = "Typ uint16 van numpy" +PythonNumpyInt16 = "Typ int16 van numpy" +PythonNumpyNan = "Nan vertegenwoordiging van numpy" +PythonNumpyInf = "Inf representatie van numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3.141592653589793" +PythonNumpyFft = "Eendimensionale discrete fouriertransformatie" +PythonNumpyIfft = "Eendimensionale inverse discrete fouriertransformatie" +PythonNumpyDet = "Determinant van a" +PythonNumpyEig = "Eigenwaarden en rechter eigenvectoren van a" +PythonNumpyCholesky = "Cholesky-decompositie" +PythonNumpyInv = "Inverse matrix a" +PythonNumpyNorm = "Matrix- of vectorstandaard" PythonOct = "Integer omzetten naar octaal" PythonPhase = "Fase van z in radialen" PythonPlot = "Plot y versus x als lijnen" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 2cfc976cd..be87d2285 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -74,6 +74,7 @@ PythonImportKandinsky = "Importar módulo kandinsky" PythonImportRandom = "Importar módulo random" PythonImportMath = "Importar módulo math" PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot" +PythonImportNumpy = "Importar módulo ulab.numpy" PythonImportTime = "Importar módulo time" PythonImportTurtle = "Importar módulo turtle" PythonIndex = "Índice da primeira ocorrência de x" @@ -98,6 +99,103 @@ PythonMax = "Máximo" PythonMin = "Mínimo" PythonModf = "Partes inteira e frácionária de x" PythonMonotonic = "Devolve o valor do relógio" +PythonNumpyFunction = "Prefixo do módulo numpy" +PythonNumpyFftFunction = "Prefixo do módulo numpy.fft" +PythonNumpyLinalgFunction = "Prefixo do módulo numpy.linalg" +PythonNumpyArray = "Converter uma matriz em ndarray" +PythonNumpyArange = "Faça uma mesa do intervalo (i)" +PythonNumpyConcatenate = "Concatenar a e b" +PythonNumpyDiag = "Extraia ou construa uma matriz diagonal" +PythonNumpyZeros = "Matriz de forma S preenchida com 0" +PythonNumpyOnes = "Matriz em forma de S preenchida com 1" +PythonNumpyEmpty = "Matriz não inicializada de formulários" +PythonNumpyEye = "Tabela com 1s na diagonal e 0s em outros lugares" +PythonNumpyFull = "Matriz de forma S preenchida com v" +PythonNumpyLinspace = "Números espaçados em um intervalo especificado" +PythonNumpyLogspace = "Números espaçados em escala logarítmica" +PythonNumpyCopy = "Cópia da tabela" +PythonNumpyDtype = "Tipo de mesa" +PythonNumpyFlat = "Iterador de matriz plana" +PythonNumpyFlatten = "Versão achatada da mesa" +PythonNumpyShape = "Obtenha a forma da matriz" +PythonNumpyReshape = "Substitua a forma da matriz por s" +PythonNumpySize = "Número de elementos na matriz" +PythonNumpyTranspose = "Versão transposta da tabela" +PythonNumpySortWithArguments = "Versão ordenada da tabela" +PythonNumpyNdinfo = "Imprimir informações sobre um" +PythonNumpyAll = "Teste se todos os elementos de um são trye" +PythonNumpyAny = "Teste se um elemento de a é verdadeiro" +PythonNumpyArgmax = "Índice do valor máximo de um" +PythonNumpyArgmin = "Subscrito do valor mínimo de um" +PythonNumpyArgsort = "Pistas que classificariam um array" +PythonNumpyClip = "Corte os valores em uma matriz" +PythonNumpyConvolve = "Convolução linear discreta de a e b" +PythonNumpyDiff = "Derivado de um" +PythonNumpyInterp = "Valores linearmente interpolados de um" +PythonNumpyDot = "Produto escalar de a e b" +PythonNumpyCross = "Produto cruzado de a e b" +PythonNumpyEqual = "A == um elemento por elemento" +PythonNumpyNot_equal = "A! = Um elemento por elemento" +PythonNumpyFlip = "Mesa giratória" +PythonNumpyIsfinite = "Teste a finitude elemento por elemento" +PythonNumpyIsinf = "Teste o infinito elemento por elemento" +PythonNumpyMean = "D médio" +PythonNumpyMin = "Valor máximo de a" +PythonNumpyMax = "Valor mínimo de a" +PythonNumpyMedian = "Valor mediano de a" +PythonNumpyMinimum = "Elementos mínimos da matriz por elemento" +PythonNumpyMaximum = "Máximo por elemento de elementos da matriz" +PythonNumpyPolyfit = "Ajuste polinomial de mínimos quadrados" +PythonNumpyPolyval = "Avalie um polinômio em valores específicos" +PythonNumpyRoll = "Mudar o conteúdo de a por n" +PythonNumpySort = "Classificar para" +PythonNumpyStd = "Calcule o desvio padrão de um" +PythonNumpySum = "Calcule a soma de um" +PythonNumpyTrace = "Calcule a soma dos elementos diagonais de um" +PythonNumpyTrapz = "Integre usando a régua trapezoidal composta" +PythonNumpyWhere = "Retorna elementos escolhidos de x ou y de acordo com c" +PythonNumpyVectorize = "Vectorize a função python genérica f" +PythonNumpyAcos = "Aplicar acos item por item" +PythonNumpyAcosh = "Aplicar acosh item por item" +PythonNumpyArctan2 = "Aplicar arctan2 elemento por elemento" +PythonNumpyAround = "Aplicar ao redor do elemento" +PythonNumpyAsin = "Aplicar asin elemento a elemento" +PythonNumpyAsinh = "Aplicar asinh elemento por elemento" +PythonNumpyAtan = "Aplicar um item por item" +PythonNumpyAtanh = "Aplicar atanh elemento por elemento" +PythonNumpyCeil = "Aplicar o teto por elemento" +PythonNumpyCos = "Aplicar cos elemento por elemento" +PythonNumpyCosh = "Aplicar cosh elemento por elemento" +PythonNumpyDegrees = "Aplicar graus elemento a elemento" +PythonNumpyExp = "Aplicar exp por item" +PythonNumpyExpm1 = "Aplicar expm1 elemento a elemento" +PythonNumpyFloor = "Aplicar solo por elemento" +PythonNumpyLog = "Aplicar diário por item" +PythonNumpyLog10 = "Aplicar log10 elemento a elemento" +PythonNumpyLog2 = "Aplicar log2 elemento por elemento" +PythonNumpyRadians = "Aplicar radianos por elemento" +PythonNumpySin = "Aplicar pecado por elemento" +PythonNumpySinh = "Aplicar sinh elemento a elemento" +PythonNumpySqrt = "Aplicar sqrt elemento a elemento" +PythonNumpyTan = "Aplicar o bronzeado por elemento" +PythonNumpyTanh = "Aplicar tanh por item" +PythonNumpyBool = "Tipo Bool de entorpecido" +PythonNumpyFloat = "Tipo flutuante de entorpecimento" +PythonNumpyUint8 = "Digite uint8 de numpy" +PythonNumpyInt8 = "Digite int8 de numpy" +PythonNumpyUint16 = "Digite uint16 de numpy" +PythonNumpyInt16 = "Digite int16 de numpy" +PythonNumpyNan = "Representação Nan de numpy" +PythonNumpyInf = "Representação de inf de numpy" +PythonNumpyE = "2.718281828459045" +PythonNumpyPi = "3,141592653589793" +PythonNumpyFft = "Transformada discreta de Fourier unidimensional" +PythonNumpyIfft = "Transformada de Fourier discreta inversa unidimensional" +PythonNumpyDet = "Determinante de um" +PythonNumpyEig = "Valores próprios e vetores próprios direitos de um" +PythonNumpyCholesky = "Decomposição de Cholesky" +PythonNumpyInv = "Matriz inversa a" +PythonNumpyNorm = "Matriz ou padrão vetorial" PythonOct = "Converter número inteiro em octal" PythonPhase = "Argumento de z" PythonPlot = "Desenhar y em função de x" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index fd3d42945..106d57dbb 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -90,6 +90,7 @@ PythonCommandImportIon = "import ion" PythonCommandImportKandinsky = "import kandinsky" PythonCommandImportMath = "import math" PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot" +PythonCommandImportFromNumpy = "from ulab import numpy as np" PythonCommandImportRandom = "import random" PythonCommandImportOs = "import os" PythonCommandImportFromOs = "from os import *" @@ -170,6 +171,115 @@ PythonCommandMax = "max(list)" PythonCommandMin = "min(list)" PythonCommandModf = "modf(x)" PythonCommandMonotonic = "monotonic()" +PythonCommandNumpyArray = "np.array(a)" +PythonCommandNumpyArange = "np.arange(i)" +PythonCommandNumpyConcatenate = "np.concatenate(a,b)" +PythonCommandNumpyDiag = "np.diag(a)" +PythonCommandNumpyZeros = "np.zeros(s)" +PythonCommandNumpyOnes = "np.ones(s)" +PythonCommandNumpyEmpty = "np.empty(s)" +PythonCommandNumpyEye = "np.eye(n, m)" +PythonCommandNumpyFull = "np.full(s, v)" +PythonCommandNumpyLinspace = "np.linspace(s, e)" +PythonCommandNumpyLogspace = "np.logspace(s, e)" +PythonCommandNumpyCopy = "ndarray.copy()" +PythonCommandNumpyCopyWithoutArg = ".copy()" +PythonCommandNumpyDtype = "ndarray.dtype" +PythonCommandNumpyDtypeWithoutArg = ".dtype" +PythonCommandNumpyFlat = "ndarray.flat" +PythonCommandNumpyFlatWithoutArg = ".flat" +PythonCommandNumpyFlatten = "ndarray.flatten()" +PythonCommandNumpyFlattenWithoutArg = ".flatten()" +PythonCommandNumpyShape = "ndarray.shape" +PythonCommandNumpyShapeWithoutArg = ".shape" +PythonCommandNumpyReshape = "ndarray.reshape(s)" +PythonCommandNumpyReshapeWithoutArg = ".reshape(\x11)" +PythonCommandNumpySize = "ndarray.size" +PythonCommandNumpySizeWithoutArg = ".size" +PythonCommandNumpyTranspose = "ndarray.transpose()" +PythonCommandNumpyTransposeWithoutArg = ".transpose()" +PythonCommandNumpySort = "ndarray.sort()" +PythonCommandNumpySortWithoutArg = ".sort()" +PythonCommandNumpyNdinfo = "np.ndinfo(a)" +PythonCommandNumpyAll = "np.all(a)" +PythonCommandNumpyAny = "np.any(a)" +PythonCommandNumpyArgmax = "np.argmax(a)" +PythonCommandNumpyArgmin = "np.argmin(a)" +PythonCommandNumpyArgsort = "np.argsort(a)" +PythonCommandNumpyClip = "np.clip(a, min, max)" +PythonCommandNumpyConvolve = "np.convolve(a, b)" +PythonCommandNumpyDiff = "np.diff(a)" +PythonCommandNumpyInterp = "np.interp(a)" +PythonCommandNumpyDot = "np.dot(a, b)" +PythonCommandNumpyCross = "np.cross(a, b)" +PythonCommandNumpyEqual = "np.equal(a, b)" +PythonCommandNumpyNot_equal = "np.not_equal(a, b)" +PythonCommandNumpyFlip = "np.flip(a)" +PythonCommandNumpyIsfinite = "np.isfinite(a)" +PythonCommandNumpyIsinf = "np.isinf(a)" +PythonCommandNumpyMean = "np.mean(a)" +PythonCommandNumpyMin = "np.min(a)" +PythonCommandNumpyMax = "np.max(a)" +PythonCommandNumpyMedian = "np.median(a)" +PythonCommandNumpyMinimum = "np.minimum(a, b)" +PythonCommandNumpyMaximum = "np.maximum(a, b)" +PythonCommandNumpyPolyfit = "np.polyfit(a, b, y)" +PythonCommandNumpyPolyval = "np.polyval(p, x)" +PythonCommandNumpyRoll = "np.roll(a, n)" +PythonCommandNumpySortWithArguments = "np.sort(a)" +PythonCommandNumpyStd = "np.std(a)" +PythonCommandNumpySum = "np.sum(a)" +PythonCommandNumpyTrace = "np.trace(a)" +PythonCommandNumpyTrapz = "np.trapz(y)" +PythonCommandNumpyWhere = "np.where(c, x, y)" +PythonCommandNumpyVectorize = "np.vectorize(f)" +PythonCommandNumpyAcos = "np.acos(a)" +PythonCommandNumpyAcosh = "np.acosh(a)" +PythonCommandNumpyArctan2 = "np.arctan2(a)" +PythonCommandNumpyAround = "np.around(a)" +PythonCommandNumpyAsin = "np.asin(a)" +PythonCommandNumpyAsinh = "np.asinh(a)" +PythonCommandNumpyAtan = "np.atan(a)" +PythonCommandNumpyAtanh = "np.atanh(a)" +PythonCommandNumpyCeil = "np.ceil(a)" +PythonCommandNumpyCos = "np.cos(a)" +PythonCommandNumpyCosh = "np.cosh(a)" +PythonCommandNumpyDegrees = "np.degrees(a)" +PythonCommandNumpyExp = "np.exp(a)" +PythonCommandNumpyExpm1 = "np.expm1(a)" +PythonCommandNumpyFloor = "np.floor(a)" +PythonCommandNumpyLog = "np.log(a)" +PythonCommandNumpyLog10 = "np.log10(a)" +PythonCommandNumpyLog2 = "np.log2(a)" +PythonCommandNumpyRadians = "np.radians(a)" +PythonCommandNumpySin = "np.sin(a)" +PythonCommandNumpySinh = "np.sinh(a)" +PythonCommandNumpySqrt = "np.sqrt(a)" +PythonCommandNumpyTan = "np.tan(a)" +PythonCommandNumpyTanh = "np.tanh(a)" +PythonCommandNumpyBool = "np.bool" +PythonCommandNumpyFloat = "np.float" +PythonCommandNumpyUint8 = "np.uint8" +PythonCommandNumpyInt8 = "np.int8" +PythonCommandNumpyUint16 = "np.uint16" +PythonCommandNumpyInt16 = "np.int16" +PythonCommandNumpyNan = "np.nan" +PythonCommandNumpyInf = "np.inf" +PythonCommandNumpyE = "np.e" +PythonCommandNumpyPi = "np.pi" +PythonCommandNumpyFft = "np.fft.fft(a)" +PythonCommandNumpyIfft = "np.fft.ifft(a)" +PythonCommandNumpyDet = "np.linalg.det(a)" +PythonCommandNumpyEig = "np.linalg.eig(a)" +PythonCommandNumpyCholesky = "np.linalg.cholesky(a)" +PythonCommandNumpyInv = "np.linalg.inv(a)" +PythonCommandNumpyNorm = "np.linalg.norm(a)" +PythonCommandNumpyFunction = "np.function" +PythonCommandNumpyFunctionWithoutArg = "np.\x11" +PythonCommandNumpyFftFunction = "np.fft.function" +PythonCommandNumpyFftFunctionWithoutArg = "np.fft.\x11" +PythonCommandNumpyLinalgFunction = "np.linalg.function" +PythonCommandNumpyLinalgFunctionWithoutArg = "np.linalg.\x11" PythonCommandOct = "oct(x)" PythonCommandPhase = "phase(z)" PythonCommandPlot = "plot(x,y,color)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 3a17fe503..7d4c5384f 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -135,6 +135,127 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandColorGray, I18n::Message::PythonColorGray, false) }; + const ToolboxMessageTree NumpyNdarrayModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArray, I18n::Message::PythonNumpyArray), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArange, I18n::Message::PythonNumpyArange), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConcatenate, I18n::Message::PythonNumpyConcatenate), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiag, I18n::Message::PythonNumpyDiag), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyZeros, I18n::Message::PythonNumpyZeros), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyOnes, I18n::Message::PythonNumpyOnes), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEmpty, I18n::Message::PythonNumpyEmpty), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEye, I18n::Message::PythonNumpyEye), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFull, I18n::Message::PythonNumpyFull), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinspace, I18n::Message::PythonNumpyLinspace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLogspace, I18n::Message::PythonNumpyLogspace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCopy, I18n::Message::PythonNumpyCopy, false, I18n::Message::PythonCommandNumpyCopyWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDtype, I18n::Message::PythonNumpyDtype, false, I18n::Message::PythonCommandNumpyDtypeWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlat, I18n::Message::PythonNumpyFlat, false, I18n::Message::PythonCommandNumpyFlatWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlatten, I18n::Message::PythonNumpyFlatten, false, I18n::Message::PythonCommandNumpyFlattenWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyShape, I18n::Message::PythonNumpyShape, false, I18n::Message::PythonCommandNumpyShapeWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyReshape, I18n::Message::PythonNumpyReshape, false, I18n::Message::PythonCommandNumpyReshapeWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySize, I18n::Message::PythonNumpySize, false, I18n::Message::PythonCommandNumpySizeWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTranspose, I18n::Message::PythonNumpyTranspose, false, I18n::Message::PythonCommandNumpyTransposeWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySort, I18n::Message::PythonNumpySortWithArguments, false, I18n::Message::PythonCommandNumpySortWithoutArg), +}; + +const ToolboxMessageTree NumpyFunctionsModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNdinfo, I18n::Message::PythonNumpyNdinfo), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAll, I18n::Message::PythonNumpyAll), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAny, I18n::Message::PythonNumpyAny), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmax, I18n::Message::PythonNumpyArgmax), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmin, I18n::Message::PythonNumpyArgmin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgsort, I18n::Message::PythonNumpyArgsort), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyClip, I18n::Message::PythonNumpyClip), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConvolve, I18n::Message::PythonNumpyConvolve), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiff, I18n::Message::PythonNumpyDiff), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInterp, I18n::Message::PythonNumpyInterp), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDot, I18n::Message::PythonNumpyDot), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCross, I18n::Message::PythonNumpyCross), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEqual, I18n::Message::PythonNumpyEqual), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNot_equal, I18n::Message::PythonNumpyNot_equal), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlip, I18n::Message::PythonNumpyFlip), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsfinite, I18n::Message::PythonNumpyIsfinite), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsinf, I18n::Message::PythonNumpyIsinf), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMean, I18n::Message::PythonNumpyMean), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMin, I18n::Message::PythonNumpyMin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMax, I18n::Message::PythonNumpyMax), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMedian, I18n::Message::PythonNumpyMedian), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMinimum, I18n::Message::PythonNumpyMinimum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMaximum, I18n::Message::PythonNumpyMaximum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyfit, I18n::Message::PythonNumpyPolyfit), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyval, I18n::Message::PythonNumpyPolyval), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRoll, I18n::Message::PythonNumpyRoll), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySortWithArguments, I18n::Message::PythonNumpySort), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyStd, I18n::Message::PythonNumpyStd), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySum, I18n::Message::PythonNumpySum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrace, I18n::Message::PythonNumpyTrace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrapz, I18n::Message::PythonNumpyTrapz), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyWhere, I18n::Message::PythonNumpyWhere), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyVectorize, I18n::Message::PythonNumpyVectorize), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcos, I18n::Message::PythonNumpyAcos), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcosh, I18n::Message::PythonNumpyAcosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArctan2, I18n::Message::PythonNumpyArctan2), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAround, I18n::Message::PythonNumpyAround), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsin, I18n::Message::PythonNumpyAsin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsinh, I18n::Message::PythonNumpyAsinh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtan, I18n::Message::PythonNumpyAtan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtanh, I18n::Message::PythonNumpyAtanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCeil, I18n::Message::PythonNumpyCeil), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCos, I18n::Message::PythonNumpyCos), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCosh, I18n::Message::PythonNumpyCosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDegrees, I18n::Message::PythonNumpyDegrees), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExp, I18n::Message::PythonNumpyExp), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExpm1, I18n::Message::PythonNumpyExpm1), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloor, I18n::Message::PythonNumpyFloor), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog, I18n::Message::PythonNumpyLog), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog10, I18n::Message::PythonNumpyLog10), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog2, I18n::Message::PythonNumpyLog2), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRadians, I18n::Message::PythonNumpyRadians), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySin, I18n::Message::PythonNumpySin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySinh, I18n::Message::PythonNumpySinh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySqrt, I18n::Message::PythonNumpySqrt), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTan, I18n::Message::PythonNumpyTan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTanh, I18n::Message::PythonNumpyTanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyBool, I18n::Message::PythonNumpyBool), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloat, I18n::Message::PythonNumpyFloat), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint8, I18n::Message::PythonNumpyUint8), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt8, I18n::Message::PythonNumpyInt8), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint16, I18n::Message::PythonNumpyUint16), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt16, I18n::Message::PythonNumpyInt16), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNan, I18n::Message::PythonNumpyNan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInf, I18n::Message::PythonNumpyInf), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyE, I18n::Message::PythonNumpyE), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi, I18n::Message::PythonNumpyPi) +}; + +const ToolboxMessageTree NumpyFftModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFftFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyFftFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFft, I18n::Message::PythonNumpyFft), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIfft, I18n::Message::PythonNumpyIfft) +}; + +const ToolboxMessageTree NumpyLinalgModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinalgFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyLinalgFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDet, I18n::Message::PythonNumpyDet), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEig, I18n::Message::PythonNumpyEig), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCholesky, I18n::Message::PythonNumpyCholesky), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInv, I18n::Message::PythonNumpyInv), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNorm, I18n::Message::PythonNumpyNorm) +}; + +const ToolboxMessageTree NumpyModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromNumpy, I18n::Message::PythonImportTurtle, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyPythonCommandNumpyFunctionWithoutArgFunction), + ToolboxMessageTree::Node(I18n::Message::NumpyNdarray, NumpyNdarrayModuleChildren), + ToolboxMessageTree::Node(I18n::Message::Functions, NumpyFunctionsModuleChildren), + ToolboxMessageTree::Node(I18n::Message::NumpyFftModule, NumpyFftModuleChildren), + ToolboxMessageTree::Node(I18n::Message::NumpyLinalgModule, NumpyLinalgModuleChildren) +}; + +const ToolboxMessageTree UlabModuleChildren[] = { + ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren) +}; + const ToolboxMessageTree TurtleModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportTurtle, I18n::Message::PythonImportTurtle, false), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromTurtle, I18n::Message::PythonImportTurtle, false), @@ -231,6 +352,7 @@ const ToolboxMessageTree modulesChildren[] = { ToolboxMessageTree::Node(I18n::Message::MathModule, MathModuleChildren), ToolboxMessageTree::Node(I18n::Message::CmathModule, CMathModuleChildren), ToolboxMessageTree::Node(I18n::Message::MatplotlibPyplotModule, MatplotlibPyplotModuleChildren), + ToolboxMessageTree::Node(I18n::Message::UlabModule, UlabModuleChildren), ToolboxMessageTree::Node(I18n::Message::TurtleModule, TurtleModuleChildren), ToolboxMessageTree::Node(I18n::Message::RandomModule, RandomModuleChildren), ToolboxMessageTree::Node(I18n::Message::KandinskyModule, KandinskyModuleChildren), diff --git a/apps/code/toolbox.universal.i18n b/apps/code/toolbox.universal.i18n index 4dd5345de..df6a9171d 100644 --- a/apps/code/toolbox.universal.i18n +++ b/apps/code/toolbox.universal.i18n @@ -3,9 +3,14 @@ IonModule = "ion" KandinskyModule = "kandinsky" MathModule = "math" MatplotlibPyplotModule = "matplotlib.pyplot" +NumpyModule = "numpy" +NumpyFftModule = "fft" +NumpyLinalgModule = "linalg" +NumpyNdarray = "ndarray" OsModule = "os" TimeModule = "time" TurtleModule = "turtle" +UlabModule = "ulab" ForLoopMenu = "For" IfStatementMenu = "If" WhileLoopMenu = "While" diff --git a/escher/include/escher/nested_menu_controller.h b/escher/include/escher/nested_menu_controller.h index 44ac41eca..ca671a1b7 100644 --- a/escher/include/escher/nested_menu_controller.h +++ b/escher/include/escher/nested_menu_controller.h @@ -41,7 +41,7 @@ protected: int depth() const; void resetStack(); private: - constexpr static int k_maxModelTreeDepth = 3; + constexpr static int k_maxModelTreeDepth = 4; State m_statesStack[k_maxModelTreeDepth]; }; From a15c682e3ee6d83465dd73a8cd34a67da9cefd8d Mon Sep 17 00:00:00 2001 From: Laury Date: Sat, 4 Sep 2021 21:23:23 +0200 Subject: [PATCH 4/7] [code/ulab] Replaced translations by official documentation --- apps/code/catalog.de.i18n | 94 -------------- apps/code/catalog.en.i18n | 94 -------------- apps/code/catalog.es.i18n | 94 -------------- apps/code/catalog.fr.i18n | 94 -------------- apps/code/catalog.hu.i18n | 94 -------------- apps/code/catalog.it.i18n | 94 -------------- apps/code/catalog.nl.i18n | 94 -------------- apps/code/catalog.pt.i18n | 94 -------------- apps/code/python_toolbox.cpp | 204 ++++++++++++++++--------------- apps/code/toolbox.de.i18n | 1 + apps/code/toolbox.en.i18n | 1 + apps/code/toolbox.es.i18n | 1 + apps/code/toolbox.fr.i18n | 1 + apps/code/toolbox.hu.i18n | 1 + apps/code/toolbox.it.i18n | 1 + apps/code/toolbox.nl.i18n | 1 + apps/code/toolbox.pt.i18n | 1 + apps/code/toolbox.universal.i18n | 1 + 18 files changed, 113 insertions(+), 852 deletions(-) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index 2c942a56e..da6c16f99 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -108,100 +108,6 @@ PythonMonotonic = "Wert einer monotonen Uhr" PythonNumpyFunction = "numpy Modul-Präfix" PythonNumpyFftFunction = "numpy.fft Modul-Präfix" PythonNumpyLinalgFunction = "numpy.linalg Modul-Präfix" -PythonNumpyArray = "Konvertieren Sie ein Array in ndarray" -PythonNumpyArange = "Erstellen Sie eine Tabelle aus dem Bereich (i)" -PythonNumpyConcatenate = "Verketten Sie a und b" -PythonNumpyDiag = "Extrahiere oder konstruiere ein diagonales Array" -PythonNumpyZeros = "S-förmiges Array gefüllt mit 0" -PythonNumpyOnes = "S-förmiges Array gefüllt mit 1" -PythonNumpyEmpty = "Nicht initialisiertes Array der Form s" -PythonNumpyEye = "Tabelle mit Einsen auf der Diagonale und Nullen an anderer Stelle" -PythonNumpyFull = "S-förmiges Array gefüllt mit v" -PythonNumpyLinspace = "Zahlen, die über ein bestimmtes Intervall verteilt sind" -PythonNumpyLogspace = "Zahlen mit logarithmischem Abstand" -PythonNumpyCopy = "Kopie der Tabelle" -PythonNumpyDtype = "Tischtyp" -PythonNumpyFlat = "Flat-Array-Iterator" -PythonNumpyFlatten = "Abgeflachte Version der Tabelle" -PythonNumpyShape = "Holen Sie sich die Form des Arrays" -PythonNumpyReshape = "Array-Form durch s ersetzen" -PythonNumpySize = "Anzahl der Elemente im Array" -PythonNumpyTranspose = "Transponierte Version der Tabelle" -PythonNumpySortWithArguments = "Sortierte Version der Tabelle" -PythonNumpyNdinfo = "Informationen zu a . drucken" -PythonNumpyAll = "Testen Sie, ob alle Elemente von a trye sind" -PythonNumpyAny = "Teste, ob ein Element von a wahr ist" -PythonNumpyArgmax = "Index des Maximalwertes von a" -PythonNumpyArgmin = "Tiefgestellter Wert des Mindestwertes von a" -PythonNumpyArgsort = "Hinweise, die ein Array sortieren würden" -PythonNumpyClip = "Werte in einem Array ausschneiden" -PythonNumpyConvolve = "Diskrete lineare Faltung von a und b" -PythonNumpyDiff = "Abgeleitet von a" -PythonNumpyInterp = "Linear interpolierte Werte von a" -PythonNumpyDot = "Punktprodukt von a und b" -PythonNumpyCross = "Kreuzprodukt von a und b" -PythonNumpyEqual = "A == Element für Element" -PythonNumpyNot_equal = "A! = Element für Element" -PythonNumpyFlip = "Turnaround-Tabelle" -PythonNumpyIsfinite = "Testen Sie die Endlichkeit Element für Element" -PythonNumpyIsinf = "Teste die Unendlichkeit Element für Element" -PythonNumpyMean = "Durchschnitt d" -PythonNumpyMin = "Maximalwert von a" -PythonNumpyMax = "Mindestwert von a" -PythonNumpyMedian = "Medianwert von a" -PythonNumpyMinimum = "Minimale Array-Elemente pro Element" -PythonNumpyMaximum = "Maximum pro Element von Array-Elementen" -PythonNumpyPolyfit = "Polynomanpassung der kleinsten Quadrate" -PythonNumpyPolyval = "Bewerte ein Polynom bei bestimmten Werten" -PythonNumpyRoll = "Verschiebe den Inhalt von a um n" -PythonNumpySort = "Sortieren nach" -PythonNumpyStd = "Berechnen Sie die Standardabweichung von a" -PythonNumpySum = "Berechnen Sie die Summe von a" -PythonNumpyTrace = "Berechnen Sie die Summe der diagonalen Elemente von a" -PythonNumpyTrapz = "Integrieren Sie mit dem zusammengesetzten Trapezlineal" -PythonNumpyWhere = "Gibt Elemente aus x oder y gemäß c . zurück" -PythonNumpyVectorize = "Vektorisieren Sie die generische Python-Funktion f" -PythonNumpyAcos = "Wenden Sie acos Artikel für Artikel an" -PythonNumpyAcosh = "Wenden Sie acosh Artikel für Artikel an" -PythonNumpyArctan2 = "arctan2 Element für Element anwenden" -PythonNumpyAround = "Um das Element herum auftragen" -PythonNumpyAsin = "Element für Element anwenden" -PythonNumpyAsinh = "Wenden Sie asinh Element für Element an" -PythonNumpyAtan = "Wenden Sie ein Element für Element an" -PythonNumpyAtanh = "Wenden Sie atanh Element für Element an" -PythonNumpyCeil = "Bringen Sie die Decke nach Element an" -PythonNumpyCos = "Wenden Sie cos Element für Element an" -PythonNumpyCosh = "Wenden Sie cosh Element für Element an" -PythonNumpyDegrees = "Grade Element für Element anwenden" -PythonNumpyExp = "Exp pro Artikel anwenden" -PythonNumpyExpm1 = "Wenden Sie expm1 Element für Element an" -PythonNumpyFloor = "Boden nach Element auftragen" -PythonNumpyLog = "Tagebuch nach Artikel anwenden" -PythonNumpyLog10 = "Wenden Sie log10 Element für Element an" -PythonNumpyLog2 = "Wenden Sie log2 Element für Element an" -PythonNumpyRadians = "Wenden Sie Radiant pro Element an" -PythonNumpySin = "Wende Sünde nach Element an" -PythonNumpySinh = "Wenden Sie sinh Element für Element an" -PythonNumpySqrt = "Wenden Sie sqrt Element für Element an" -PythonNumpyTan = "Trage die Bräune nach Element auf" -PythonNumpyTanh = "Tanh pro Artikel auftragen" -PythonNumpyBool = "Bool Typ von numpy" -PythonNumpyFloat = "Float-Typ von numpy" -PythonNumpyUint8 = "Geben Sie uint8 von numpy . ein" -PythonNumpyInt8 = "Geben Sie int8 von numpy . ein" -PythonNumpyUint16 = "Geben Sie uint16 von numpy ein" -PythonNumpyInt16 = "Geben Sie int16 von numpy . ein" -PythonNumpyNan = "Nan-Darstellung von numpy" -PythonNumpyInf = "Inf-Darstellung von numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "Eindimensionale diskrete Fourier-Transformation" -PythonNumpyIfft = "Eindimensionale inverse diskrete Fourier-Transformation" -PythonNumpyDet = "Determinante von a" -PythonNumpyEig = "Eigenwerte und rechte Eigenvektoren von a" -PythonNumpyCholesky = "Cholesky-Zerlegung" -PythonNumpyInv = "Inverse Matrix a" -PythonNumpyNorm = "Matrix- oder Vektorstandard" PythonOct = "Ganzzahl in Oktal umwandeln" PythonPhase = "Phase von z" PythonPlot = "Plotten von y gegen x als Linien" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 09de24ccb..363dd820e 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -102,100 +102,6 @@ PythonMonotonic = "Value of a monotonic clock" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" -PythonNumpyArray = "Convert an array to ndarray" -PythonNumpyArange = "Make a table from the range (i)" -PythonNumpyConcatenate = "Concatenate a and b" -PythonNumpyDiag = "Extract or construct a diagonal array" -PythonNumpyZeros = "S shape array filled with 0" -PythonNumpyOnes = "S shape array filled with 1" -PythonNumpyEmpty = "Uninitialized array of form s" -PythonNumpyEye = "Table with 1s on the diagonal and 0s elsewhere" -PythonNumpyFull = "S shape array filled with v" -PythonNumpyLinspace = "Numbers spaced over a specified interval" -PythonNumpyLogspace = "Numbers spaced on a logarithmic scale" -PythonNumpyCopy = "Copy of table" -PythonNumpyDtype = "Table type" -PythonNumpyFlat = "Flat array iterator" -PythonNumpyFlatten = "Flattened version of the table" -PythonNumpyShape = "Get the shape of the array" -PythonNumpyReshape = "Replace array shape with s" -PythonNumpySize = "Number of elements in the array" -PythonNumpyTranspose = "Transposed version of the table" -PythonNumpySortWithArguments = "Sorted version of the table" -PythonNumpyNdinfo = "Print information about a" -PythonNumpyAll = "Test if all elements of a are trye" -PythonNumpyAny = "Test if an element of a is true" -PythonNumpyArgmax = "Index of the maximum value of a" -PythonNumpyArgmin = "Subscript of the minimum value of a" -PythonNumpyArgsort = "Clues that would sort an array" -PythonNumpyClip = "Cut values in an array" -PythonNumpyConvolve = "Discrete linear convolution of a and b" -PythonNumpyDiff = "Derived from a" -PythonNumpyInterp = "Linearly interpolated values of a" -PythonNumpyDot = "Dot product of a and b" -PythonNumpyCross = "Cross product of a and b" -PythonNumpyEqual = "A == a element by element" -PythonNumpyNot_equal = "A! = A element by element" -PythonNumpyFlip = "Turnaround table" -PythonNumpyIsfinite = "Test the finiteness element by element" -PythonNumpyIsinf = "Test the infinity element by element" -PythonNumpyMean = "Average d" -PythonNumpyMin = "Maximum value of a" -PythonNumpyMax = "Minimum value of a" -PythonNumpyMedian = "Median value of a" -PythonNumpyMinimum = "Minimum array elements per element" -PythonNumpyMaximum = "Maximum per element of array elements" -PythonNumpyPolyfit = "Least squares polynomial fit" -PythonNumpyPolyval = "Evaluate a polynomial at specific values" -PythonNumpyRoll = "Shift the content of a by n" -PythonNumpySort = "Sort to" -PythonNumpyStd = "Calculate the standard deviation of a" -PythonNumpySum = "Calculate the sum of a" -PythonNumpyTrace = "Calculate the sum of the diagonal elements of a" -PythonNumpyTrapz = "Integrate using the composite trapezoidal ruler" -PythonNumpyWhere = "Returns elements chosen from x or y according to c" -PythonNumpyVectorize = "Vectorize the generic python function f" -PythonNumpyAcos = "Apply acos item by item" -PythonNumpyAcosh = "Apply acosh item by item" -PythonNumpyArctan2 = "Apply arctan2 element by element" -PythonNumpyAround = "Apply around the element" -PythonNumpyAsin = "Apply asin element by element" -PythonNumpyAsinh = "Apply asinh element by element" -PythonNumpyAtan = "Apply one item by item" -PythonNumpyAtanh = "Apply atanh element by element" -PythonNumpyCeil = "Apply the ceiling by element" -PythonNumpyCos = "Apply cos element by element" -PythonNumpyCosh = "Apply cosh element by element" -PythonNumpyDegrees = "Apply degrees element by element" -PythonNumpyExp = "Apply exp per item" -PythonNumpyExpm1 = "Apply expm1 element by element" -PythonNumpyFloor = "Apply soil by element" -PythonNumpyLog = "Apply journal by item" -PythonNumpyLog10 = "Apply log10 element by element" -PythonNumpyLog2 = "Apply log2 element by element" -PythonNumpyRadians = "Apply radians per element" -PythonNumpySin = "Apply sin by element" -PythonNumpySinh = "Apply sinh element by element" -PythonNumpySqrt = "Apply sqrt element by element" -PythonNumpyTan = "Apply the tan by element" -PythonNumpyTanh = "Apply tanh per item" -PythonNumpyBool = "Bool type of numpy" -PythonNumpyFloat = "Float type of numpy" -PythonNumpyUint8 = "Type uint8 of numpy" -PythonNumpyInt8 = "Type int8 of numpy" -PythonNumpyUint16 = "Type uint16 from numpy" -PythonNumpyInt16 = "Type int16 of numpy" -PythonNumpyNan = "Nan representation of numpy" -PythonNumpyInf = "Inf representation of numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "One-dimensional discrete fourier transform" -PythonNumpyIfft = "One-dimensional inverse discrete fourier transform" -PythonNumpyDet = "Determinant of a" -PythonNumpyEig = "Eigenvalues and right eigenvectors of a" -PythonNumpyCholesky = "Cholesky decomposition" -PythonNumpyInv = "Inverse matrix a" -PythonNumpyNorm = "Matrix or vector standard" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index 48bff282b..d39456839 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -102,100 +102,6 @@ PythonMonotonic = "Value of a monotonic clock" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" -PythonNumpyArray = "Convertir una matriz a ndarray" -PythonNumpyArange = "Haz una tabla de la gama (i)" -PythonNumpyConcatenate = "Concatenar ayb" -PythonNumpyDiag = "Extraer o construir una matriz diagonal" -PythonNumpyZeros = "Matriz en forma de S rellena con 0" -PythonNumpyOnes = "Matriz en forma de S llena con 1" -PythonNumpyEmpty = "Matriz no inicializada de formulario s" -PythonNumpyEye = "Tabla con 1 en la diagonal y 0 en el resto" -PythonNumpyFull = "Matriz en forma de S rellena con v" -PythonNumpyLinspace = "Números espaciados en un intervalo específico" -PythonNumpyLogspace = "Números espaciados en una escala logarítmica" -PythonNumpyCopy = "Copia de la tabla" -PythonNumpyDtype = "Tipo de mesa" -PythonNumpyFlat = "Iterador de matriz plana" -PythonNumpyFlatten = "Versión aplanada de la mesa." -PythonNumpyShape = "Obtén la forma de la matriz" -PythonNumpyReshape = "Reemplazar la forma de la matriz con s" -PythonNumpySize = "Número de elementos en la matriz" -PythonNumpyTranspose = "Versión transpuesta de la tabla" -PythonNumpySortWithArguments = "Versión ordenada de la tabla" -PythonNumpyNdinfo = "Imprimir información sobre un" -PythonNumpyAll = "Prueba si todos los elementos de a son probables" -PythonNumpyAny = "Prueba si un elemento de a es verdadero" -PythonNumpyArgmax = "Índice del valor máximo de un" -PythonNumpyArgmin = "Subíndice del valor mínimo de un" -PythonNumpyArgsort = "Pistas que ordenarían una matriz" -PythonNumpyClip = "Cortar valores en una matriz" -PythonNumpyConvolve = "Convolución lineal discreta de ayb" -PythonNumpyDiff = "Derivado de un" -PythonNumpyInterp = "Valores interpolados linealmente de a" -PythonNumpyDot = "Producto escalar de ayb" -PythonNumpyCross = "Producto cruzado de ayb" -PythonNumpyEqual = "A == un elemento por elemento" -PythonNumpyNot_equal = "A! = Un elemento por elemento" -PythonNumpyFlip = "Tabla de cambio" -PythonNumpyIsfinite = "Prueba la finitud elemento por elemento" -PythonNumpyIsinf = "Prueba el infinito elemento por elemento" -PythonNumpyMean = "Promedio d" -PythonNumpyMin = "Valor máximo de un" -PythonNumpyMax = "Valor mínimo de un" -PythonNumpyMedian = "Valor mediano de a" -PythonNumpyMinimum = "Elementos de matriz mínimos por elemento" -PythonNumpyMaximum = "Máximo por elemento de elementos de matriz" -PythonNumpyPolyfit = "Ajuste de polinomio de mínimos cuadrados" -PythonNumpyPolyval = "Evaluar un polinomio en valores específicos" -PythonNumpyRoll = "Cambiar el contenido de a por n" -PythonNumpySort = "Ordenar por" -PythonNumpyStd = "Calcule la desviación estándar de un" -PythonNumpySum = "Calcule la suma de a" -PythonNumpyTrace = "Calcule la suma de los elementos diagonales de un" -PythonNumpyTrapz = "Integrar usando la regla trapezoidal compuesta" -PythonNumpyWhere = "Devuelve elementos elegidos de xoy según c" -PythonNumpyVectorize = "Vectorizar la función genérica de python f" -PythonNumpyAcos = "Aplicar acos artículo por artículo" -PythonNumpyAcosh = "Aplicar un elemento por elemento" -PythonNumpyArctan2 = "Aplicar arctan2 elemento por elemento" -PythonNumpyAround = "Aplicar alrededor del elemento" -PythonNumpyAsin = "Aplicar asin elemento por elemento" -PythonNumpyAsinh = "Aplicar asinh elemento por elemento" -PythonNumpyAtan = "Aplicar un artículo por artículo" -PythonNumpyAtanh = "Aplicar atanh elemento por elemento" -PythonNumpyCeil = "Aplicar el techo por elemento" -PythonNumpyCos = "Aplicar cos elemento por elemento" -PythonNumpyCosh = "Aplicar cosh elemento por elemento" -PythonNumpyDegrees = "Aplicar grados elemento por elemento" -PythonNumpyExp = "Aplicar exp por artículo" -PythonNumpyExpm1 = "Aplicar expm1 elemento por elemento" -PythonNumpyFloor = "Aplicar suelo por elemento" -PythonNumpyLog = "Aplicar diario por artículo" -PythonNumpyLog10 = "Aplicar log10 elemento por elemento" -PythonNumpyLog2 = "Aplicar log2 elemento por elemento" -PythonNumpyRadians = "Aplicar radianes por elemento" -PythonNumpySin = "Aplicar el pecado por elemento" -PythonNumpySinh = "Aplicar sinh elemento por elemento" -PythonNumpySqrt = "Aplicar elemento sqrt por elemento" -PythonNumpyTan = "Aplicar el bronceado por elemento" -PythonNumpyTanh = "Aplicar tanh por artículo" -PythonNumpyBool = "Bool tipo de numpy" -PythonNumpyFloat = "Flotador tipo de numpy" -PythonNumpyUint8 = "Escriba uint8 de numpy" -PythonNumpyInt8 = "Escriba int8 de numpy" -PythonNumpyUint16 = "Escriba uint16 desde numpy" -PythonNumpyInt16 = "Escriba int16 de numpy" -PythonNumpyNan = "Nan representación de numpy" -PythonNumpyInf = "Inf representación de numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "Transformada de Fourier discreta unidimensional" -PythonNumpyIfft = "Transformada de Fourier discreta inversa unidimensional" -PythonNumpyDet = "Determinante de un" -PythonNumpyEig = "Autovalores y autovectores derechos de un" -PythonNumpyCholesky = "Descomposición de Cholesky" -PythonNumpyInv = "Matriz inversa a" -PythonNumpyNorm = "Matriz o estándar vectorial" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index 5846f7c4a..d8d9daced 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -102,100 +102,6 @@ PythonMonotonic = "Renvoie la valeur de l'horloge" PythonNumpyFunction = "Préfixe fonction du module numpy" PythonNumpyFftFunction = "Préfixe fonction du module numpy.fft" PythonNumpyLinalgFunction = "Préfixe fonction du module numpy.linalg" -PythonNumpyArray = "Convertir un tableau en ndarray" -PythonNumpyArange = "Faire un tableau à partir de la plage (i)" -PythonNumpyConcatenate = "Concaténer a et b" -PythonNumpyDiag = "Extraire ou construire un tableau diagonal" -PythonNumpyZeros = "Tableau de forme s rempli de 0" -PythonNumpyOnes = "Tableau de forme s rempli de 1" -PythonNumpyEmpty = "Tableau uninitialisé de forme s" -PythonNumpyEye = "Tableau avec des 1 sur la diagonale et des 0 ailleurs" -PythonNumpyFull = "Tableau de forme s rempli de v" -PythonNumpyLinspace = "Nombres espacés sur un intervalle spécifié" -PythonNumpyLogspace = "Nombres espacés sur une échelle logarithmique" -PythonNumpyCopy = "Copie du tableau" -PythonNumpyDtype = "Dtype du tableau" -PythonNumpyFlat = "Itérateur plat du tableau" -PythonNumpyFlatten = "Version aplatie du tableau" -PythonNumpyShape = "Obtenir la forme du tableau" -PythonNumpyReshape = "Remplacer la forme du tableau par s" -PythonNumpySize = "Nombre d'éléments dans le tableau" -PythonNumpyTranspose = "Version transposée du tableau" -PythonNumpySortWithArguments = "Version triée du tableau" -PythonNumpyNdinfo = "Imprimer des informations sur un" -PythonNumpyAll = "Tester si tous les éléments de a sont trye" -PythonNumpyAny = "Tester si un élément de a est vrai" -PythonNumpyArgmax = "Indice de la valeur maximale de a" -PythonNumpyArgmin = "Indice de la valeur minimale de a" -PythonNumpyArgsort = "Indices qui trieraient un tableau" -PythonNumpyClip = "Couper les valeurs dans un tableau" -PythonNumpyConvolve = "Convolution linéaire discrète de a et b" -PythonNumpyDiff = "Dérivée du a" -PythonNumpyInterp = "Valeurs interpolées linéairement de a" -PythonNumpyDot = "Produit scalaire de a et b" -PythonNumpyCross = "Produit vectoriel de a et b" -PythonNumpyEqual = "a == a élément par élément" -PythonNumpyNot_equal = "a != a élément par élément" -PythonNumpyFlip = "Tableau de retournement" -PythonNumpyIsfinite = "Testez la finitude élément par élément" -PythonNumpyIsinf = "Testez l'infinité élément par élément" -PythonNumpyMean = "Moyenne d" -PythonNumpyMin = "Valeur maximale de a" -PythonNumpyMax = "Valeur minimale de a" -PythonNumpyMedian = "Valeur médiane de a" -PythonNumpyMinimum = "Minimum d'éléments de tableau par élément" -PythonNumpyMaximum = "Maximum par élément d'éléments de tableau" -PythonNumpyPolyfit = "Ajustement polynomial des moindres carrés" -PythonNumpyPolyval = "Évaluer un polynôme à des valeurs spécifiques" -PythonNumpyRoll = "Décaler le contenu de a par n" -PythonNumpySort = "Trier a" -PythonNumpyStd = "Calculer l'écart type de a" -PythonNumpySum = "Calculer la somme de a" -PythonNumpyTrace = "Calculer la somme des éléments diagonaux de a" -PythonNumpyTrapz = "Intégrer à l'aide de la règle trapézoïdale composite" -PythonNumpyWhere = "Renvoie des éléments choisis parmi x ou y selon c" -PythonNumpyVectorize = "Vectoriser la fonction python générique f" -PythonNumpyAcos = "Appliquer acos élément par élément" -PythonNumpyAcosh = "Appliquer acosh élément par élément" -PythonNumpyArctan2 = "Appliquer arctan2 élément par élément" -PythonNumpyAround = "Appliquer autour de l'élément" -PythonNumpyAsin = "Appliquer asin élément par élément" -PythonNumpyAsinh = "Appliquer asinh élément par élément" -PythonNumpyAtan = "Appliquer un élément par élément" -PythonNumpyAtanh = "Appliquer atanh élément par élément" -PythonNumpyCeil = "Appliquer le plafond par élément" -PythonNumpyCos = "Appliquer cos élément par élément" -PythonNumpyCosh = "Appliquer cosh élément par élément" -PythonNumpyDegrees = "Appliquer des degrés élément par élément" -PythonNumpyExp = "Appliquer exp par élément" -PythonNumpyExpm1 = "Appliquer expm1 élément par élément" -PythonNumpyFloor = "Appliquer le sol par élément" -PythonNumpyLog = "Appliquer le journal par élément" -PythonNumpyLog10 = "Appliquer log10 élément par élément" -PythonNumpyLog2 = "Appliquer log2 élément par élément" -PythonNumpyRadians = "Appliquer des radians par élément" -PythonNumpySin = "Appliquer le péché par élément" -PythonNumpySinh = "Appliquer sinh élément par élément" -PythonNumpySqrt = "Appliquer sqrt élément par élément" -PythonNumpyTan = "Appliquer le bronzage par élément" -PythonNumpyTanh = "Appliquer tanh par élément" -PythonNumpyBool = "Type bool de numpy" -PythonNumpyFloat = "Type float de numpy" -PythonNumpyUint8 = "Tapez uint8 de numpy" -PythonNumpyInt8 = "Tapez int8 de numpy" -PythonNumpyUint16 = "Tapez uint16 de numpy" -PythonNumpyInt16 = "Tapez int16 de numpy" -PythonNumpyNan = "Nan représentation de numpy" -PythonNumpyInf = "Inf représentation de numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "Transformée de Fourier discrète à une dimension" -PythonNumpyIfft = "Transformée de Fourier discrète inverse unidimensionnelle" -PythonNumpyDet = "Déterminant de a" -PythonNumpyEig = "Valeurs propres et vecteurs propres droits de a" -PythonNumpyCholesky = "Décomposition de Cholesky" -PythonNumpyInv = "Matrice inverse a" -PythonNumpyNorm = "Norme matricielle ou vectorielle" PythonOct = "Conversion en octal" PythonPhase = "Argument de z" PythonPlot = "Trace y en fonction de x" diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n index f5365e633..b2011816b 100644 --- a/apps/code/catalog.hu.i18n +++ b/apps/code/catalog.hu.i18n @@ -102,100 +102,6 @@ PythonMonotonic = "Az óra értékét adja vissza" PythonNumpyFunction = "numpy elötag" PythonNumpyFftFunction = "numpy.fft elötag" PythonNumpyLinalgFunction = "numpy.linalg elötag" -PythonNumpyArray = "Egy tömb konvertálása ndarray -re" -PythonNumpyArange = "Készítsen táblázatot az (i) tartományból" -PythonNumpyConcatenate = "Összekapcsolás a és b" -PythonNumpyDiag = "Bontson ki vagy készítsen átlós tömböt" -PythonNumpyZeros = "S alakú tömb 0 -val kitöltve" -PythonNumpyOnes = "S alakú tömb 1-el" -PythonNumpyEmpty = "Az űrlap inicializálatlan tömbje" -PythonNumpyEye = "Asztal 1 -es átlóval és 0 -val máshol" -PythonNumpyFull = "S alakú tömb tele v" -PythonNumpyLinspace = "Számok meghatározott intervallumon belül" -PythonNumpyLogspace = "A számok logaritmikus skálán helyezkednek el" -PythonNumpyCopy = "A táblázat másolata" -PythonNumpyDtype = "Táblázat típusa" -PythonNumpyFlat = "Lapos tömb iterátor" -PythonNumpyFlatten = "Az asztal lapított változata" -PythonNumpyShape = "Szerezd meg a tömb alakját" -PythonNumpyReshape = "Cserélje le a tömb alakját az s -vel" -PythonNumpySize = "A tömb elemeinek száma" -PythonNumpyTranspose = "A táblázat átültetett változata" -PythonNumpySortWithArguments = "A táblázat rendezett változata" -PythonNumpyNdinfo = "Információk nyomtatása a" -PythonNumpyAll = "Ellenőrizze, hogy egy elem minden eleme trye" -PythonNumpyAny = "Ellenőrizze, hogy az a eleme igaz -e" -PythonNumpyArgmax = "A maximális érték indexe a" -PythonNumpyArgmin = "A minimális értékének a indexe" -PythonNumpyArgsort = "Nyomok, amelyek rendeznek egy tömböt" -PythonNumpyClip = "Vágja le az értékeket egy tömbben" -PythonNumpyConvolve = "A és b diszkrét lineáris konvolúciója" -PythonNumpyDiff = "Származik a" -PythonNumpyInterp = "A lineárisan interpolált értékei" -PythonNumpyDot = "Az a és b pontszerű szorzata" -PythonNumpyCross = "Az a és b keresztterméke" -PythonNumpyEqual = "A == elemenként" -PythonNumpyNot_equal = "A! = Elemenként" -PythonNumpyFlip = "Fordulóasztal" -PythonNumpyIsfinite = "Tesztelje a végességet elemenként" -PythonNumpyIsinf = "Tesztelje a végtelen elemet elemenként" -PythonNumpyMean = "Átlagos d" -PythonNumpyMin = "Maximális értéke a" -PythonNumpyMax = "Minimális értéke a" -PythonNumpyMedian = "Medián értéke a" -PythonNumpyMinimum = "Minimális tömb elemek elemenként" -PythonNumpyMaximum = "Maximum tömb elemenként" -PythonNumpyPolyfit = "Legkevesebb négyzet polinom illeszkedés" -PythonNumpyPolyval = "Polinom értékelése meghatározott értékeken" -PythonNumpyRoll = "Az a tartalmának eltolása n -vel" -PythonNumpySort = "Rendezés ide" -PythonNumpyStd = "Számítsa ki a szórását a" -PythonNumpySum = "Számítsa ki a összegét" -PythonNumpyTrace = "Számítsa ki az a átlós elemeinek összegét!" -PythonNumpyTrapz = "Integrálja az összetett trapéz vonalzó használatával" -PythonNumpyWhere = "A c szerint x vagy y közül választott elemeket adja vissza" -PythonNumpyVectorize = "Vektorizálja az általános python függvényt f" -PythonNumpyAcos = "Alkalmazza az acos -t elemenként" -PythonNumpyAcosh = "Alkalmazza az elemeket elemenként" -PythonNumpyArctan2 = "Alkalmazza az arctan2 elemet elemenként" -PythonNumpyAround = "Alkalmazza az elem körül" -PythonNumpyAsin = "Alkalmazza az asszonyt elemenként" -PythonNumpyAsinh = "Alkalmazza az elemet elemenként" -PythonNumpyAtan = "Alkalmazzon egy elemet elemenként" -PythonNumpyAtanh = "Alkalmazza az atanh elemenként" -PythonNumpyCeil = "Alkalmazza a mennyezetet elemenként" -PythonNumpyCos = "Alkalmazza a cos elemet elemenként" -PythonNumpyCosh = "Alkalmazza a cosh elemet elemenként" -PythonNumpyDegrees = "Alkalmazza a fokokat elemenként" -PythonNumpyExp = "Alkalmazza az exp -ot elemenként" -PythonNumpyExpm1 = "Alkalmazza az expm1 elemet elemenként" -PythonNumpyFloor = "A talajt elemenként vigye fel" -PythonNumpyLog = "Napló alkalmazása tétel szerint" -PythonNumpyLog10 = "Alkalmazza a log10 elemet elemenként" -PythonNumpyLog2 = "Alkalmazza a log2 elemet elemenként" -PythonNumpyRadians = "Alkalmazzon radiánt elemenként" -PythonNumpySin = "Alkalmazza a bűnt elemenként" -PythonNumpySinh = "Alkalmazza a sinh elemet elemenként" -PythonNumpySqrt = "Alkalmazza az sqrt elemet elemenként" -PythonNumpyTan = "Vigye fel a barnulást elemenként" -PythonNumpyTanh = "Alkalmazzon tannt elemenként" -PythonNumpyBool = "Bull típusú numpy" -PythonNumpyFloat = "Lebegő típusú számológép" -PythonNumpyUint8 = "Írja be az uint8 számot" -PythonNumpyInt8 = "Írja be a numpy int8 típusát" -PythonNumpyUint16 = "Írja be az uint16 parancsot a numpy -ból" -PythonNumpyInt16 = "Írja be a numpy int16 típusát" -PythonNumpyNan = "A numpy nanos ábrázolása" -PythonNumpyInf = "A numpy inf ábrázolása" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "Egydimenziós diszkrét Fourier-transzformáció" -PythonNumpyIfft = "Egydimenziós inverz diszkrét Fourier-transzformáció" -PythonNumpyDet = "Meghatározó a" -PythonNumpyEig = "Sajátértékek és jobb sajátvektorok a" -PythonNumpyCholesky = "Cholesky bomlás" -PythonNumpyInv = "Fordított mátrix a" -PythonNumpyNorm = "Mátrix vagy vektor standard" PythonOct = "Decimális szám konvertálása octális számra" PythonPhase = "z fázisa" PythonPlot = "y-t jelöli x függvényében" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 9402ad69a..8627e679c 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -108,100 +108,6 @@ PythonMonotonic = "Restituisce il valore dell'orologio" PythonNumpyFunction = "Prefisso modulo numpy" PythonNumpyFftFunction = "Prefisso modulo numpy.fft" PythonNumpyLinalgFunction = "Prefisso modulo numpy.linalg" -PythonNumpyArray = "Converti un array in ndarray" -PythonNumpyArange = "Crea una tabella dall'intervallo (i)" -PythonNumpyConcatenate = "Concatena a e b" -PythonNumpyDiag = "Estrai o costruisci un array diagonale" -PythonNumpyZeros = "Matrice a forma di S riempita con 0" -PythonNumpyOnes = "Array a forma di S riempito con 1" -PythonNumpyEmpty = "Matrice non inizializzata della forma s" -PythonNumpyEye = "Tabella con 1 in diagonale e 0 altrove" -PythonNumpyFull = "Matrice a forma di S riempita con v" -PythonNumpyLinspace = "Numeri spaziati su un intervallo specificato" -PythonNumpyLogspace = "Numeri spaziati su una scala logaritmica" -PythonNumpyCopy = "Copia della tabella" -PythonNumpyDtype = "Tipo di tabella" -PythonNumpyFlat = "Iteratore flat array" -PythonNumpyFlatten = "Versione appiattita del tavolo" -PythonNumpyShape = "Ottieni la forma dell'array" -PythonNumpyReshape = "Sostituisci la forma dell'array con s" -PythonNumpySize = "Numero di elementi nell'array" -PythonNumpyTranspose = "Versione trasposta della tabella" -PythonNumpySortWithArguments = "Versione ordinata della tabella" -PythonNumpyNdinfo = "Stampa informazioni su a" -PythonNumpyAll = "Verifica se tutti gli elementi di a sono provati" -PythonNumpyAny = "Verifica se un elemento di a è vero" -PythonNumpyArgmax = "Indice del valore massimo di a" -PythonNumpyArgmin = "Pedice del valore minimo di a" -PythonNumpyArgsort = "Indizi che ordinerebbero un array" -PythonNumpyClip = "Taglia i valori in un array" -PythonNumpyConvolve = "Convoluzione lineare discreta di a e b" -PythonNumpyDiff = "Derivato da a" -PythonNumpyInterp = "Valori interpolati linearmente di a" -PythonNumpyDot = "Prodotto scalare di a e b" -PythonNumpyCross = "Prodotto incrociato di a e b" -PythonNumpyEqual = "A == un elemento per elemento" -PythonNumpyNot_equal = "A! = Un elemento per elemento" -PythonNumpyFlip = "Tavolo di turnaround" -PythonNumpyIsfinite = "Testa la finitezza elemento per elemento" -PythonNumpyIsinf = "Prova l'infinito elemento per elemento" -PythonNumpyMean = "d . medio" -PythonNumpyMin = "Valore massimo di a" -PythonNumpyMax = "Valore minimo di a" -PythonNumpyMedian = "Valore medio di a" -PythonNumpyMinimum = "Elementi minimi dell'array per elemento" -PythonNumpyMaximum = "Massimo per elemento di elementi dell'array" -PythonNumpyPolyfit = "Approssimazione polinomiale ai minimi quadrati" -PythonNumpyPolyval = "Valuta un polinomio a valori specifici" -PythonNumpyRoll = "Sposta il contenuto di a di n" -PythonNumpySort = "Ordina per" -PythonNumpyStd = "Calcola la deviazione standard di a" -PythonNumpySum = "Calcola la somma di a" -PythonNumpyTrace = "Calcola la somma degli elementi diagonali di a" -PythonNumpyTrapz = "Integrare utilizzando il righello trapezoidale composito" -PythonNumpyWhere = "Restituisce elementi scelti da x o y secondo c" -PythonNumpyVectorize = "Vettorizza la funzione Python generica f" -PythonNumpyAcos = "Applica acos articolo per articolo" -PythonNumpyAcosh = "Applica acosh articolo per articolo" -PythonNumpyArctan2 = "Applica arctan2 elemento per elemento" -PythonNumpyAround = "Applicare intorno all'elemento" -PythonNumpyAsin = "Applica asin elemento per elemento" -PythonNumpyAsinh = "Applica asinh elemento per elemento" -PythonNumpyAtan = "Applicare un articolo per articolo" -PythonNumpyAtanh = "Applicare atanh elemento per elemento" -PythonNumpyCeil = "Applicare il soffitto per elemento" -PythonNumpyCos = "Applica cos elemento per elemento" -PythonNumpyCosh = "Applicare cosh elemento per elemento" -PythonNumpyDegrees = "Applica gradi elemento per elemento" -PythonNumpyExp = "Applica esperienza per articolo" -PythonNumpyExpm1 = "Applica expm1 elemento per elemento" -PythonNumpyFloor = "Applicare terreno per elemento" -PythonNumpyLog = "Applica giornale per articolo" -PythonNumpyLog10 = "Applica log10 elemento per elemento" -PythonNumpyLog2 = "Applica log2 elemento per elemento" -PythonNumpyRadians = "Applica radianti per elemento" -PythonNumpySin = "Applica sin per elemento" -PythonNumpySinh = "Applica sinh elemento per elemento" -PythonNumpySqrt = "Applica sqrt elemento per elemento" -PythonNumpyTan = "Applicare l'abbronzatura per elemento" -PythonNumpyTanh = "Applicare tanh per articolo" -PythonNumpyBool = "Tipo bool di numpy" -PythonNumpyFloat = "Tipo galleggiante di numpy" -PythonNumpyUint8 = "Digita uint8 di numpy" -PythonNumpyInt8 = "Digita int8 di numpy" -PythonNumpyUint16 = "Digita uint16 da numpy" -PythonNumpyInt16 = "Digita int16 di numpy" -PythonNumpyNan = "Nan rappresentazione di numpy" -PythonNumpyInf = "Inf rappresentazione di numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589933" -PythonNumpyFft = "Trasformata di Fourier discreta unidimensionale" -PythonNumpyIfft = "Trasformata di Fourier discreta inversa unidimensionale" -PythonNumpyDet = "Determinante di a" -PythonNumpyEig = "Autovalori e autovettori giusti di a" -PythonNumpyCholesky = "Decomposizione Cholesky" -PythonNumpyInv = "matrice inversa a" -PythonNumpyNorm = "Matrice o standard vettoriale" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" PythonPlot = "Disegna y in f. di x come linee" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index fa54b6bc1..f46b4606f 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -108,100 +108,6 @@ PythonMonotonic = "Waarde van een monotone klok" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" -PythonNumpyArray = "Converteer een array naar ndarray" -PythonNumpyArange = "Maak een tabel uit de reeks (i)" -PythonNumpyConcatenate = "Samenvoegen a en b" -PythonNumpyDiag = "Een diagonale array extraheren of construeren" -PythonNumpyZeros = "S-vormarray gevuld met 0" -PythonNumpyOnes = "S-vormige array gevuld met 1" -PythonNumpyEmpty = "Niet-geïnitialiseerde matrix van vorm s" -PythonNumpyEye = "Tabel met enen op de diagonaal en nullen elders" -PythonNumpyFull = "S-vormarray gevuld met v" -PythonNumpyLinspace = "Getallen verdeeld over een opgegeven interval" -PythonNumpyLogspace = "Getallen op een logaritmische schaal verdeeld" -PythonNumpyCopy = "Kopie van tabel" -PythonNumpyDtype = "Tafeltype:" -PythonNumpyFlat = "Flat array iterator" -PythonNumpyFlatten = "Afgeplatte versie van de tafel" -PythonNumpyShape = "De vorm van de array verkrijgen" -PythonNumpyReshape = "Vervang matrixvorm door s" -PythonNumpySize = "Aantal elementen in de array" -PythonNumpyTranspose = "Getransponeerde versie van de tabel" -PythonNumpySortWithArguments = "Gesorteerde versie van de tafel" -PythonNumpyNdinfo = "Informatie afdrukken over a" -PythonNumpyAll = "Test of alle elementen van a trye zijn" -PythonNumpyAny = "Test of een element van a waar is" -PythonNumpyArgmax = "Index van de maximale waarde van a" -PythonNumpyArgmin = "Subscript van de minimumwaarde van a" -PythonNumpyArgsort = "Aanwijzingen die een array zouden sorteren" -PythonNumpyClip = "Knip waarden in een array" -PythonNumpyConvolve = "Discrete lineaire convolutie van a en b" -PythonNumpyDiff = "Afgeleid van a" -PythonNumpyInterp = "Lineair geïnterpoleerde waarden van a" -PythonNumpyDot = "Puntproduct van a en b" -PythonNumpyCross = "Kruisproduct van a en b" -PythonNumpyEqual = "A == een element voor element" -PythonNumpyNot_equal = "A! = Een element voor element" -PythonNumpyFlip = "Omslagtabel" -PythonNumpyIsfinite = "Test de eindigheid element voor element" -PythonNumpyIsinf = "Test het oneindige element voor element" -PythonNumpyMean = "gemiddelde d" -PythonNumpyMin = "Maximale waarde van a" -PythonNumpyMax = "Minimale waarde van a" -PythonNumpyMedian = "Mediane waarde van a" -PythonNumpyMinimum = "Minimum array-elementen per element" -PythonNumpyMaximum = "Maximum per element van array-elementen" -PythonNumpyPolyfit = "Kleinste kwadraten polynoom fit" -PythonNumpyPolyval = "Een polynoom evalueren op specifieke waarden" -PythonNumpyRoll = "Verschuif de inhoud van a met n" -PythonNumpySort = "Sorteren op" -PythonNumpyStd = "Bereken de standaarddeviatie van a" -PythonNumpySum = "Bereken de som van a" -PythonNumpyTrace = "Bereken de som van de diagonale elementen van a" -PythonNumpyTrapz = "Integreer met behulp van de samengestelde trapeziumvormige liniaal" -PythonNumpyWhere = "Retourneert elementen gekozen uit x of y volgens c" -PythonNumpyVectorize = "Vectoriseer de generieke python-functie f" -PythonNumpyAcos = "Acos item per item toepassen" -PythonNumpyAcosh = "Acosh item voor item toepassen" -PythonNumpyArctan2 = "Arctan2 element voor element toepassen" -PythonNumpyAround = "Toepassen rond het element" -PythonNumpyAsin = "Asin element voor element toepassen" -PythonNumpyAsinh = "Asinh element voor element toepassen" -PythonNumpyAtan = "Eén item per item toepassen" -PythonNumpyAtanh = "Atanh element voor element toepassen" -PythonNumpyCeil = "Breng het plafond per element aan" -PythonNumpyCos = "Pas co element voor element toe" -PythonNumpyCosh = "Cosh element voor element toepassen" -PythonNumpyDegrees = "Graden element voor element toepassen" -PythonNumpyExp = "exp per item toepassen" -PythonNumpyExpm1 = "expm1 element voor element toepassen" -PythonNumpyFloor = "Grond per element aanbrengen" -PythonNumpyLog = "Journaal per item toepassen" -PythonNumpyLog10 = "Pas log10 element voor element toe" -PythonNumpyLog2 = "Log2 element voor element toepassen" -PythonNumpyRadians = "Pas radialen toe per element" -PythonNumpySin = "Zonde per element toepassen" -PythonNumpySinh = "Sinh element voor element toepassen" -PythonNumpySqrt = "Sqrt element voor element toepassen" -PythonNumpyTan = "Breng de kleur aan per element" -PythonNumpyTanh = "Tanh toepassen per item" -PythonNumpyBool = "Bool type numpy" -PythonNumpyFloat = "Float type numpy" -PythonNumpyUint8 = "Typ uint8 van numpy" -PythonNumpyInt8 = "Typ int8 van numpy" -PythonNumpyUint16 = "Typ uint16 van numpy" -PythonNumpyInt16 = "Typ int16 van numpy" -PythonNumpyNan = "Nan vertegenwoordiging van numpy" -PythonNumpyInf = "Inf representatie van numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3.141592653589793" -PythonNumpyFft = "Eendimensionale discrete fouriertransformatie" -PythonNumpyIfft = "Eendimensionale inverse discrete fouriertransformatie" -PythonNumpyDet = "Determinant van a" -PythonNumpyEig = "Eigenwaarden en rechter eigenvectoren van a" -PythonNumpyCholesky = "Cholesky-decompositie" -PythonNumpyInv = "Inverse matrix a" -PythonNumpyNorm = "Matrix- of vectorstandaard" PythonOct = "Integer omzetten naar octaal" PythonPhase = "Fase van z in radialen" PythonPlot = "Plot y versus x als lijnen" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index be87d2285..513297365 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -102,100 +102,6 @@ PythonMonotonic = "Devolve o valor do relógio" PythonNumpyFunction = "Prefixo do módulo numpy" PythonNumpyFftFunction = "Prefixo do módulo numpy.fft" PythonNumpyLinalgFunction = "Prefixo do módulo numpy.linalg" -PythonNumpyArray = "Converter uma matriz em ndarray" -PythonNumpyArange = "Faça uma mesa do intervalo (i)" -PythonNumpyConcatenate = "Concatenar a e b" -PythonNumpyDiag = "Extraia ou construa uma matriz diagonal" -PythonNumpyZeros = "Matriz de forma S preenchida com 0" -PythonNumpyOnes = "Matriz em forma de S preenchida com 1" -PythonNumpyEmpty = "Matriz não inicializada de formulários" -PythonNumpyEye = "Tabela com 1s na diagonal e 0s em outros lugares" -PythonNumpyFull = "Matriz de forma S preenchida com v" -PythonNumpyLinspace = "Números espaçados em um intervalo especificado" -PythonNumpyLogspace = "Números espaçados em escala logarítmica" -PythonNumpyCopy = "Cópia da tabela" -PythonNumpyDtype = "Tipo de mesa" -PythonNumpyFlat = "Iterador de matriz plana" -PythonNumpyFlatten = "Versão achatada da mesa" -PythonNumpyShape = "Obtenha a forma da matriz" -PythonNumpyReshape = "Substitua a forma da matriz por s" -PythonNumpySize = "Número de elementos na matriz" -PythonNumpyTranspose = "Versão transposta da tabela" -PythonNumpySortWithArguments = "Versão ordenada da tabela" -PythonNumpyNdinfo = "Imprimir informações sobre um" -PythonNumpyAll = "Teste se todos os elementos de um são trye" -PythonNumpyAny = "Teste se um elemento de a é verdadeiro" -PythonNumpyArgmax = "Índice do valor máximo de um" -PythonNumpyArgmin = "Subscrito do valor mínimo de um" -PythonNumpyArgsort = "Pistas que classificariam um array" -PythonNumpyClip = "Corte os valores em uma matriz" -PythonNumpyConvolve = "Convolução linear discreta de a e b" -PythonNumpyDiff = "Derivado de um" -PythonNumpyInterp = "Valores linearmente interpolados de um" -PythonNumpyDot = "Produto escalar de a e b" -PythonNumpyCross = "Produto cruzado de a e b" -PythonNumpyEqual = "A == um elemento por elemento" -PythonNumpyNot_equal = "A! = Um elemento por elemento" -PythonNumpyFlip = "Mesa giratória" -PythonNumpyIsfinite = "Teste a finitude elemento por elemento" -PythonNumpyIsinf = "Teste o infinito elemento por elemento" -PythonNumpyMean = "D médio" -PythonNumpyMin = "Valor máximo de a" -PythonNumpyMax = "Valor mínimo de a" -PythonNumpyMedian = "Valor mediano de a" -PythonNumpyMinimum = "Elementos mínimos da matriz por elemento" -PythonNumpyMaximum = "Máximo por elemento de elementos da matriz" -PythonNumpyPolyfit = "Ajuste polinomial de mínimos quadrados" -PythonNumpyPolyval = "Avalie um polinômio em valores específicos" -PythonNumpyRoll = "Mudar o conteúdo de a por n" -PythonNumpySort = "Classificar para" -PythonNumpyStd = "Calcule o desvio padrão de um" -PythonNumpySum = "Calcule a soma de um" -PythonNumpyTrace = "Calcule a soma dos elementos diagonais de um" -PythonNumpyTrapz = "Integre usando a régua trapezoidal composta" -PythonNumpyWhere = "Retorna elementos escolhidos de x ou y de acordo com c" -PythonNumpyVectorize = "Vectorize a função python genérica f" -PythonNumpyAcos = "Aplicar acos item por item" -PythonNumpyAcosh = "Aplicar acosh item por item" -PythonNumpyArctan2 = "Aplicar arctan2 elemento por elemento" -PythonNumpyAround = "Aplicar ao redor do elemento" -PythonNumpyAsin = "Aplicar asin elemento a elemento" -PythonNumpyAsinh = "Aplicar asinh elemento por elemento" -PythonNumpyAtan = "Aplicar um item por item" -PythonNumpyAtanh = "Aplicar atanh elemento por elemento" -PythonNumpyCeil = "Aplicar o teto por elemento" -PythonNumpyCos = "Aplicar cos elemento por elemento" -PythonNumpyCosh = "Aplicar cosh elemento por elemento" -PythonNumpyDegrees = "Aplicar graus elemento a elemento" -PythonNumpyExp = "Aplicar exp por item" -PythonNumpyExpm1 = "Aplicar expm1 elemento a elemento" -PythonNumpyFloor = "Aplicar solo por elemento" -PythonNumpyLog = "Aplicar diário por item" -PythonNumpyLog10 = "Aplicar log10 elemento a elemento" -PythonNumpyLog2 = "Aplicar log2 elemento por elemento" -PythonNumpyRadians = "Aplicar radianos por elemento" -PythonNumpySin = "Aplicar pecado por elemento" -PythonNumpySinh = "Aplicar sinh elemento a elemento" -PythonNumpySqrt = "Aplicar sqrt elemento a elemento" -PythonNumpyTan = "Aplicar o bronzeado por elemento" -PythonNumpyTanh = "Aplicar tanh por item" -PythonNumpyBool = "Tipo Bool de entorpecido" -PythonNumpyFloat = "Tipo flutuante de entorpecimento" -PythonNumpyUint8 = "Digite uint8 de numpy" -PythonNumpyInt8 = "Digite int8 de numpy" -PythonNumpyUint16 = "Digite uint16 de numpy" -PythonNumpyInt16 = "Digite int16 de numpy" -PythonNumpyNan = "Representação Nan de numpy" -PythonNumpyInf = "Representação de inf de numpy" -PythonNumpyE = "2.718281828459045" -PythonNumpyPi = "3,141592653589793" -PythonNumpyFft = "Transformada discreta de Fourier unidimensional" -PythonNumpyIfft = "Transformada de Fourier discreta inversa unidimensional" -PythonNumpyDet = "Determinante de um" -PythonNumpyEig = "Valores próprios e vetores próprios direitos de um" -PythonNumpyCholesky = "Decomposição de Cholesky" -PythonNumpyInv = "Matriz inversa a" -PythonNumpyNorm = "Matriz ou padrão vetorial" PythonOct = "Converter número inteiro em octal" PythonPhase = "Argumento de z" PythonPlot = "Desenhar y em função de x" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 7d4c5384f..2a26f98a7 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -136,116 +136,116 @@ const ToolboxMessageTree MatplotlibPyplotModuleChildren[] = { }; const ToolboxMessageTree NumpyNdarrayModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArray, I18n::Message::PythonNumpyArray), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArange, I18n::Message::PythonNumpyArange), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConcatenate, I18n::Message::PythonNumpyConcatenate), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiag, I18n::Message::PythonNumpyDiag), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyZeros, I18n::Message::PythonNumpyZeros), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyOnes, I18n::Message::PythonNumpyOnes), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEmpty, I18n::Message::PythonNumpyEmpty), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEye, I18n::Message::PythonNumpyEye), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFull, I18n::Message::PythonNumpyFull), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinspace, I18n::Message::PythonNumpyLinspace), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLogspace, I18n::Message::PythonNumpyLogspace), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCopy, I18n::Message::PythonNumpyCopy, false, I18n::Message::PythonCommandNumpyCopyWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDtype, I18n::Message::PythonNumpyDtype, false, I18n::Message::PythonCommandNumpyDtypeWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlat, I18n::Message::PythonNumpyFlat, false, I18n::Message::PythonCommandNumpyFlatWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlatten, I18n::Message::PythonNumpyFlatten, false, I18n::Message::PythonCommandNumpyFlattenWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyShape, I18n::Message::PythonNumpyShape, false, I18n::Message::PythonCommandNumpyShapeWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyReshape, I18n::Message::PythonNumpyReshape, false, I18n::Message::PythonCommandNumpyReshapeWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySize, I18n::Message::PythonNumpySize, false, I18n::Message::PythonCommandNumpySizeWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTranspose, I18n::Message::PythonNumpyTranspose, false, I18n::Message::PythonCommandNumpyTransposeWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySort, I18n::Message::PythonNumpySortWithArguments, false, I18n::Message::PythonCommandNumpySortWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArray), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArange), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConcatenate), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiag), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyZeros), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyOnes), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEmpty), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEye), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFull), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinspace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLogspace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCopy), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDtype), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlat), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlatten), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyShape), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyReshape), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySize), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTranspose), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySort), }; const ToolboxMessageTree NumpyFunctionsModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNdinfo, I18n::Message::PythonNumpyNdinfo), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAll, I18n::Message::PythonNumpyAll), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAny, I18n::Message::PythonNumpyAny), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmax, I18n::Message::PythonNumpyArgmax), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmin, I18n::Message::PythonNumpyArgmin), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgsort, I18n::Message::PythonNumpyArgsort), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyClip, I18n::Message::PythonNumpyClip), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConvolve, I18n::Message::PythonNumpyConvolve), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiff, I18n::Message::PythonNumpyDiff), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInterp, I18n::Message::PythonNumpyInterp), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDot, I18n::Message::PythonNumpyDot), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCross, I18n::Message::PythonNumpyCross), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEqual, I18n::Message::PythonNumpyEqual), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNot_equal, I18n::Message::PythonNumpyNot_equal), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlip, I18n::Message::PythonNumpyFlip), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsfinite, I18n::Message::PythonNumpyIsfinite), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsinf, I18n::Message::PythonNumpyIsinf), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMean, I18n::Message::PythonNumpyMean), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMin, I18n::Message::PythonNumpyMin), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMax, I18n::Message::PythonNumpyMax), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMedian, I18n::Message::PythonNumpyMedian), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMinimum, I18n::Message::PythonNumpyMinimum), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMaximum, I18n::Message::PythonNumpyMaximum), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyfit, I18n::Message::PythonNumpyPolyfit), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyval, I18n::Message::PythonNumpyPolyval), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRoll, I18n::Message::PythonNumpyRoll), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySortWithArguments, I18n::Message::PythonNumpySort), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyStd, I18n::Message::PythonNumpyStd), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySum, I18n::Message::PythonNumpySum), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrace, I18n::Message::PythonNumpyTrace), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrapz, I18n::Message::PythonNumpyTrapz), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyWhere, I18n::Message::PythonNumpyWhere), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyVectorize, I18n::Message::PythonNumpyVectorize), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcos, I18n::Message::PythonNumpyAcos), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcosh, I18n::Message::PythonNumpyAcosh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArctan2, I18n::Message::PythonNumpyArctan2), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAround, I18n::Message::PythonNumpyAround), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsin, I18n::Message::PythonNumpyAsin), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsinh, I18n::Message::PythonNumpyAsinh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtan, I18n::Message::PythonNumpyAtan), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtanh, I18n::Message::PythonNumpyAtanh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCeil, I18n::Message::PythonNumpyCeil), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCos, I18n::Message::PythonNumpyCos), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCosh, I18n::Message::PythonNumpyCosh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDegrees, I18n::Message::PythonNumpyDegrees), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExp, I18n::Message::PythonNumpyExp), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExpm1, I18n::Message::PythonNumpyExpm1), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloor, I18n::Message::PythonNumpyFloor), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog, I18n::Message::PythonNumpyLog), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog10, I18n::Message::PythonNumpyLog10), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog2, I18n::Message::PythonNumpyLog2), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRadians, I18n::Message::PythonNumpyRadians), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySin, I18n::Message::PythonNumpySin), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySinh, I18n::Message::PythonNumpySinh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySqrt, I18n::Message::PythonNumpySqrt), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTan, I18n::Message::PythonNumpyTan), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTanh, I18n::Message::PythonNumpyTanh), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyBool, I18n::Message::PythonNumpyBool), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloat, I18n::Message::PythonNumpyFloat), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint8, I18n::Message::PythonNumpyUint8), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt8, I18n::Message::PythonNumpyInt8), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint16, I18n::Message::PythonNumpyUint16), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt16, I18n::Message::PythonNumpyInt16), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNan, I18n::Message::PythonNumpyNan), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInf, I18n::Message::PythonNumpyInf), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyE, I18n::Message::PythonNumpyE), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi, I18n::Message::PythonNumpyPi) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNdinfo), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAll), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAny), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmax), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgmin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArgsort), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyClip), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyConvolve), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDiff), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInterp), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDot), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCross), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEqual), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNot_equal), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFlip), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsfinite), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIsinf), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMean), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMax), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMedian), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMinimum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyMaximum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyfit), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPolyval), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRoll), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySortWithArguments), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyStd), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySum), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrace), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTrapz), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyWhere), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyVectorize), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcos), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAcosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyArctan2), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAround), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAsinh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyAtanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCeil), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCos), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCosh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDegrees), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExp), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyExpm1), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloor), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog10), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLog2), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyRadians), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySinh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySqrt), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyTanh), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyBool), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFloat), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint8), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt8), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyUint16), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInt16), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNan), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInf), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyE), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi) }; const ToolboxMessageTree NumpyFftModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFftFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyFftFunctionWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFft, I18n::Message::PythonNumpyFft), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIfft, I18n::Message::PythonNumpyIfft) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFftFunction, I18n::Message::PythonNumpyFftFunction, false, I18n::Message::PythonCommandNumpyFftFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFft), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyIfft) }; const ToolboxMessageTree NumpyLinalgModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinalgFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyLinalgFunctionWithoutArg), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDet, I18n::Message::PythonNumpyDet), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEig, I18n::Message::PythonNumpyEig), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCholesky, I18n::Message::PythonNumpyCholesky), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInv, I18n::Message::PythonNumpyInv), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNorm, I18n::Message::PythonNumpyNorm) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyLinalgFunction, I18n::Message::PythonNumpyLinalgFunction, false, I18n::Message::PythonCommandNumpyLinalgFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyDet), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyEig), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyCholesky), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInv), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNorm) }; const ToolboxMessageTree NumpyModuleChildren[] = { - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromNumpy, I18n::Message::PythonImportTurtle, false), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFunction, I18n::Message::PythonTurtleFunction, false, I18n::Message::PythonCommandNumpyPythonCommandNumpyFunctionWithoutArgFunction), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromNumpy, I18n::Message::PythonImportNumpy, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyFunction, I18n::Message::PythonNumpyFunction, false, I18n::Message::PythonCommandNumpyFunctionWithoutArg), ToolboxMessageTree::Node(I18n::Message::NumpyNdarray, NumpyNdarrayModuleChildren), ToolboxMessageTree::Node(I18n::Message::Functions, NumpyFunctionsModuleChildren), ToolboxMessageTree::Node(I18n::Message::NumpyFftModule, NumpyFftModuleChildren), @@ -253,7 +253,8 @@ const ToolboxMessageTree NumpyModuleChildren[] = { }; const ToolboxMessageTree UlabModuleChildren[] = { - ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren) + ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren), + ToolboxMessageTree::Leaf(I18n::Message::UlabDocumentation, I18n::Message::UlabDocumentationLink) }; const ToolboxMessageTree TurtleModuleChildren[] = { @@ -622,8 +623,11 @@ KDCoordinate PythonToolbox::rowHeight(int j) { } bool PythonToolbox::selectLeaf(int selectedRow) { - m_selectableTableView.deselectTable(); ToolboxMessageTree * node = (ToolboxMessageTree *)m_messageTreeModel->childAtIndex(selectedRow); + if(node->text() == I18n::Message::UlabDocumentationLink){ + return true; + } + m_selectableTableView.deselectTable(); if(node->insertedText() == I18n::Message::IonSelector){ m_ionKeys.setSender(sender()); Container::activeApp()->displayModalViewController(static_cast(&m_ionKeys), 0.f, 0.f, Metric::PopUpTopMargin, Metric::PopUpLeftMargin, 0, Metric::PopUpRightMargin); diff --git a/apps/code/toolbox.de.i18n b/apps/code/toolbox.de.i18n index 34840329b..82dd2b142 100644 --- a/apps/code/toolbox.de.i18n +++ b/apps/code/toolbox.de.i18n @@ -4,3 +4,4 @@ Modules = "Module" LoopsAndTests = "Schleifen und Tests" Files = "Dateien" Exceptions = "Ausnahmen" +UlabDocumentation = "Dokumentation" diff --git a/apps/code/toolbox.en.i18n b/apps/code/toolbox.en.i18n index 81e60c7da..59eadf403 100644 --- a/apps/code/toolbox.en.i18n +++ b/apps/code/toolbox.en.i18n @@ -4,3 +4,4 @@ Modules = "Modules" LoopsAndTests = "Loops and tests" Files = "Files" Exceptions = "Exceptions" +UlabDocumentation = "Documentation" diff --git a/apps/code/toolbox.es.i18n b/apps/code/toolbox.es.i18n index 81e60c7da..905e28a8e 100644 --- a/apps/code/toolbox.es.i18n +++ b/apps/code/toolbox.es.i18n @@ -4,3 +4,4 @@ Modules = "Modules" LoopsAndTests = "Loops and tests" Files = "Files" Exceptions = "Exceptions" +UlabDocumentation = "Documentación" diff --git a/apps/code/toolbox.fr.i18n b/apps/code/toolbox.fr.i18n index 724abb7a5..077e4550a 100644 --- a/apps/code/toolbox.fr.i18n +++ b/apps/code/toolbox.fr.i18n @@ -4,3 +4,4 @@ Modules = "Modules" LoopsAndTests = "Boucles et tests" Files = "Fichiers" Exceptions = "Exceptions" +UlabDocumentation = "Documentation" diff --git a/apps/code/toolbox.hu.i18n b/apps/code/toolbox.hu.i18n index 890151220..fbdff6f74 100644 --- a/apps/code/toolbox.hu.i18n +++ b/apps/code/toolbox.hu.i18n @@ -4,3 +4,4 @@ Modules = "Modulok" LoopsAndTests = "Hurkok és tesztek" Files = "Fájlok" Exceptions = "Kivételek" +UlabDocumentation = "Dokumentáció" diff --git a/apps/code/toolbox.it.i18n b/apps/code/toolbox.it.i18n index d7b219d87..7069ccb4e 100644 --- a/apps/code/toolbox.it.i18n +++ b/apps/code/toolbox.it.i18n @@ -4,3 +4,4 @@ Modules = "Moduli" LoopsAndTests = "Cicli e test" Files = "Files" Exceptions = "Exceptions" +UlabDocumentation = "Documentazione" diff --git a/apps/code/toolbox.nl.i18n b/apps/code/toolbox.nl.i18n index 849bd76a6..4df9ed1a7 100644 --- a/apps/code/toolbox.nl.i18n +++ b/apps/code/toolbox.nl.i18n @@ -4,3 +4,4 @@ Modules = "Modules" LoopsAndTests = "Herhalingen en testen" Files = "Files" Exceptions = "Exceptions" +UlabDocumentation = "Documentatie" diff --git a/apps/code/toolbox.pt.i18n b/apps/code/toolbox.pt.i18n index f7cfad07b..4ea2d75fd 100644 --- a/apps/code/toolbox.pt.i18n +++ b/apps/code/toolbox.pt.i18n @@ -4,3 +4,4 @@ Modules = "Módulos" LoopsAndTests = "Laços e testes" Files = "Files" Exceptions = "Exceptions" +UlabDocumentation = "Documentação" diff --git a/apps/code/toolbox.universal.i18n b/apps/code/toolbox.universal.i18n index df6a9171d..5a307394c 100644 --- a/apps/code/toolbox.universal.i18n +++ b/apps/code/toolbox.universal.i18n @@ -64,3 +64,4 @@ PythonCommandReturn = "return " RandomModule = "random" IonSelector = "Key selector" PressAKey = "Press a key" +UlabDocumentationLink = "micropython-ulab.readthedocs.io" From 0f4502ebce4e6c23456a55b8719ca27d4d8ef248 Mon Sep 17 00:00:00 2001 From: Laury Date: Sun, 5 Sep 2021 16:27:44 +0200 Subject: [PATCH 5/7] [code/ulab] Added scipy --- apps/code/catalog.de.i18n | 6 +++++ apps/code/catalog.en.i18n | 6 +++++ apps/code/catalog.es.i18n | 6 +++++ apps/code/catalog.fr.i18n | 6 +++++ apps/code/catalog.hu.i18n | 6 +++++ apps/code/catalog.it.i18n | 6 +++++ apps/code/catalog.nl.i18n | 6 +++++ apps/code/catalog.pt.i18n | 6 +++++ apps/code/catalog.universal.i18n | 22 ++++++++++++++++++ apps/code/python_toolbox.cpp | 38 ++++++++++++++++++++++++++++++++ apps/code/toolbox.universal.i18n | 5 +++++ 11 files changed, 113 insertions(+) diff --git a/apps/code/catalog.de.i18n b/apps/code/catalog.de.i18n index da6c16f99..d168f9c13 100644 --- a/apps/code/catalog.de.i18n +++ b/apps/code/catalog.de.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Random-Modul importieren" PythonImportMath = "Math-Modul importieren" PythonImportMatplotlibPyplot = "Matplotlib.pyplot-Modul importieren" PythonImportNumpy = "Ulab.numpy-Modul importieren" +PythonImportScipy = "Ulab.scipy-Modul importieren" PythonImportOs = "OS-Modul importieren" PythonOsUname = "Informationen über das System holen" PythonOsGetlogin = "Benutzernamen holen" @@ -108,6 +109,11 @@ PythonMonotonic = "Wert einer monotonen Uhr" PythonNumpyFunction = "numpy Modul-Präfix" PythonNumpyFftFunction = "numpy.fft Modul-Präfix" PythonNumpyLinalgFunction = "numpy.linalg Modul-Präfix" +PythonScipyFunction = "scipy Modul-Präfix" +PythonScipyLinalgFunction = "scipy.linalg Modul-Präfix" +PythonScipyOptimizeFunction = "scipy.optimize Modul-Präfix" +PythonScipySignalFunction = "scipy.signal Modul-Präfix" +PythonScipySpecialFunction = "scipy.special Modul-Präfix" PythonOct = "Ganzzahl in Oktal umwandeln" PythonPhase = "Phase von z" PythonPlot = "Plotten von y gegen x als Linien" diff --git a/apps/code/catalog.en.i18n b/apps/code/catalog.en.i18n index 363dd820e..3b5a707bf 100644 --- a/apps/code/catalog.en.i18n +++ b/apps/code/catalog.en.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Import random module" PythonImportMath = "Import math module" PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" PythonImportNumpy = "Import ulab.numpy module" +PythonImportScipy = "Import ulab.scipy module" PythonImportTime = "Import time module" PythonImportTurtle = "Import turtle module" PythonIndex = "Index of the first x occurrence" @@ -102,6 +103,11 @@ PythonMonotonic = "Value of a monotonic clock" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonScipyFunction = "scipy module prefix" +PythonScipyLinalgFunction = "scipy.linalg module prefix" +PythonScipyOptimizeFunction = "scipy.optimize module prefix" +PythonScipySignalFunction = "scipy.signal module prefix" +PythonScipySpecialFunction = "scipy.special module prefix" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.es.i18n b/apps/code/catalog.es.i18n index d39456839..09ad6235d 100644 --- a/apps/code/catalog.es.i18n +++ b/apps/code/catalog.es.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Import random module" PythonImportMath = "Import math module" PythonImportMatplotlibPyplot = "Import matplotlib.pyplot module" PythonImportNumpy = "Import ulab.numpy module" +PythonImportScipy = "Import ulab.scipy module" PythonImportTime = "Import time module" PythonImportTurtle = "Import turtle module" PythonIndex = "Index of the first x occurrence" @@ -102,6 +103,11 @@ PythonMonotonic = "Value of a monotonic clock" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonScipyFunction = "scipy module prefix" +PythonScipyLinalgFunction = "scipy.linalg module prefix" +PythonScipyOptimizeFunction = "scipy.optimize module prefix" +PythonScipySignalFunction = "scipy.signal module prefix" +PythonScipySpecialFunction = "scipy.special module prefix" PythonOct = "Convert integer to octal" PythonPhase = "Phase of z" PythonPlot = "Plot y versus x as lines" diff --git a/apps/code/catalog.fr.i18n b/apps/code/catalog.fr.i18n index d8d9daced..af0676142 100644 --- a/apps/code/catalog.fr.i18n +++ b/apps/code/catalog.fr.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Importation du module random" PythonImportMath = "Importation du module math" PythonImportMatplotlibPyplot = "Importation de matplotlib.pyplot" PythonImportNumpy = "Importation de ulab.numpy" +PythonImportScipy = "Importation de ulab.scipy" PythonImportTurtle = "Importation du module turtle" PythonImportTime = "Importation du module time" PythonIndex = "Indice première occurrence de x" @@ -102,6 +103,11 @@ PythonMonotonic = "Renvoie la valeur de l'horloge" PythonNumpyFunction = "Préfixe fonction du module numpy" PythonNumpyFftFunction = "Préfixe fonction du module numpy.fft" PythonNumpyLinalgFunction = "Préfixe fonction du module numpy.linalg" +PythonScipyFunction = "Préfixe fonction du module scipy" +PythonScipyLinalgFunction = "Préfixe fonction du module scipy.linalg" +PythonScipyOptimizeFunction = "Préfixe fonction du module scipy.optimize" +PythonScipySignalFunction = "Préfixe fonction du module scipy.signal" +PythonScipySpecialFunction = "Préfixe fonction du module scipy.special" PythonOct = "Conversion en octal" PythonPhase = "Argument de z" PythonPlot = "Trace y en fonction de x" diff --git a/apps/code/catalog.hu.i18n b/apps/code/catalog.hu.i18n index b2011816b..b64a41192 100644 --- a/apps/code/catalog.hu.i18n +++ b/apps/code/catalog.hu.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Véletlenszerü modul importálása" PythonImportMath = "math modul importálása" PythonImportMatplotlibPyplot = "matplotlib.pyplot modul importálása" PythonImportNumpy = "ulab.numpy modul importálása" +PythonImportScipy = "ulab.scipy modul importálása" PythonImportTurtle = "turtle modul importálása" PythonImportTime = "time modul importálása" PythonIndex = "Az elsö x esemény indexe" @@ -102,6 +103,11 @@ PythonMonotonic = "Az óra értékét adja vissza" PythonNumpyFunction = "numpy elötag" PythonNumpyFftFunction = "numpy.fft elötag" PythonNumpyLinalgFunction = "numpy.linalg elötag" +PythonScipyFunction = "scipy elötag" +PythonScipyLinalgFunction = "scipy.linalg elötag" +PythonScipyOptimizeFunction = "scipy.optimize elötag" +PythonScipySignalFunction = "scipy.signal elötag" +PythonScipySpecialFunction = "scipy.special elötag" PythonOct = "Decimális szám konvertálása octális számra" PythonPhase = "z fázisa" PythonPlot = "y-t jelöli x függvényében" diff --git a/apps/code/catalog.it.i18n b/apps/code/catalog.it.i18n index 8627e679c..2a61d0a5b 100644 --- a/apps/code/catalog.it.i18n +++ b/apps/code/catalog.it.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Importa modulo random" PythonImportMath = "Importa modulo math" PythonImportMatplotlibPyplot = "Importa modulo matplotlib.pyplot" PythonImportNumpy = "Importa modulo ulab.numpy" +PythonImportScipy = "Importa modulo ulab.scipy" PythonImportTurtle = "Importa del modulo turtle" PythonImportTime = "Importa del modulo time" PythonImportOs = "Importa modulo os" @@ -108,6 +109,11 @@ PythonMonotonic = "Restituisce il valore dell'orologio" PythonNumpyFunction = "Prefisso modulo numpy" PythonNumpyFftFunction = "Prefisso modulo numpy.fft" PythonNumpyLinalgFunction = "Prefisso modulo numpy.linalg" +PythonScipyFunction = "Prefisso modulo scipy" +PythonScipyLinalgFunction = "Prefisso modulo scipy.linalg" +PythonScipyOptimizeFunction = "Prefisso modulo scipy.optimize" +PythonScipySignalFunction = "Prefisso modulo scipy.signal" +PythonScipySpecialFunction = "Prefisso modulo scipy.special" PythonOct = "Conversione in ottale" PythonPhase = "Argomento di z" PythonPlot = "Disegna y in f. di x come linee" diff --git a/apps/code/catalog.nl.i18n b/apps/code/catalog.nl.i18n index f46b4606f..1d8349e24 100644 --- a/apps/code/catalog.nl.i18n +++ b/apps/code/catalog.nl.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Importeer random module" PythonImportMath = "Importeer math module" PythonImportMatplotlibPyplot = "Importeer matplotlib.pyplot module" PythonImportNumpy = "Importeer ulab.numpy module" +PythonImportScipy = "Importeer ulab.scipy module" PythonImportTime = "Importeer time module" PythonImportOs = "Importeer os module" PythonOsUname = " Krijg systeeminfo" @@ -108,6 +109,11 @@ PythonMonotonic = "Waarde van een monotone klok" PythonNumpyFunction = "numpy module prefix" PythonNumpyFftFunction = "numpy.fft module prefix" PythonNumpyLinalgFunction = "numpy.linalg module prefix" +PythonScipyFunction = "scipy module prefix" +PythonScipyLinalgFunction = "scipy.linalg module prefix" +PythonScipyOptimizeFunction = "scipy.optimize module prefix" +PythonScipySignalFunction = "scipy.signal module prefix" +PythonScipySpecialFunction = "scipy.special module prefix" PythonOct = "Integer omzetten naar octaal" PythonPhase = "Fase van z in radialen" PythonPlot = "Plot y versus x als lijnen" diff --git a/apps/code/catalog.pt.i18n b/apps/code/catalog.pt.i18n index 513297365..394728507 100644 --- a/apps/code/catalog.pt.i18n +++ b/apps/code/catalog.pt.i18n @@ -75,6 +75,7 @@ PythonImportRandom = "Importar módulo random" PythonImportMath = "Importar módulo math" PythonImportMatplotlibPyplot = "Importar módulo matplotlib.pyplot" PythonImportNumpy = "Importar módulo ulab.numpy" +PythonImportScipy = "Importar módulo ulab.scipy" PythonImportTime = "Importar módulo time" PythonImportTurtle = "Importar módulo turtle" PythonIndex = "Índice da primeira ocorrência de x" @@ -102,6 +103,11 @@ PythonMonotonic = "Devolve o valor do relógio" PythonNumpyFunction = "Prefixo do módulo numpy" PythonNumpyFftFunction = "Prefixo do módulo numpy.fft" PythonNumpyLinalgFunction = "Prefixo do módulo numpy.linalg" +PythonScipyFunction = "Prefixo do módulo scipy" +PythonScipyLinalgFunction = "Prefixo do módulo scipy.linalg" +PythonScipyOptimizeFunction = "Prefixo do módulo scipy.optimize" +PythonScipySignalFunction = "Prefixo do módulo scipy.signal" +PythonScipySpecialFunction = "Prefixo do módulo scipy.special" PythonOct = "Converter número inteiro em octal" PythonPhase = "Argumento de z" PythonPlot = "Desenhar y em função de x" diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 106d57dbb..510fe65a0 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -91,6 +91,7 @@ PythonCommandImportKandinsky = "import kandinsky" PythonCommandImportMath = "import math" PythonCommandImportMatplotlibPyplot = "import matplotlib.pyplot" PythonCommandImportFromNumpy = "from ulab import numpy as np" +PythonCommandImportFromScipy = "from ulab import scipy as spy" PythonCommandImportRandom = "import random" PythonCommandImportOs = "import os" PythonCommandImportFromOs = "from os import *" @@ -306,6 +307,27 @@ PythonCommandReverseWithoutArg = ".reverse()" PythonCommandRound = "round(x,n)" PythonCommandScatter = "scatter(x,y)" PythonCommandSeed = "seed(x)" +PythonCommandScipyFunction = "spy.function" +PythonCommandScipyFunctionWithoutArg = "spy.\x11" +PythonCommandScipyLinalgFunction = "spy.linalg.function" +PythonCommandScipyLinalgFunctionWithoutArg = "spy.linalg.\x11" +PythonCommandScipyOptimizeFunction = "spy.optimize.function" +PythonCommandScipyOptimizeFunctionWithoutArg = "spy.optimize.\x11" +PythonCommandScipySignalFunction = "spy.signal.function" +PythonCommandScipySignalFunctionWithoutArg = "spy.signal.\x11" +PythonCommandScipySpecialFunction = "spy.special.function" +PythonCommandScipySpecialFunctionWithoutArg = "spy.special.\x11" +PythonCommandScipyLinalgChoSolve = "spy.linalg.cho_solve(a, b)" +PythonCommandScipyLinalgSolveTriangular = "spy.linalg.solve_triangular(a, b)" +PythonCommandScipyOptimizeBisect = "spy.optimize.bisect(f, a, b)" +PythonCommandScipyOptimizeFmin = "spy.optimize.fmin(f, x0)" +PythonCommandScipyOptimizeNewton = "spy.optimize.newton(f, x0)" +PythonCommandScipySignalSosfilt = "spy.signal.sosfilt(sos, x)" +PythonCommandScipySignalSpectrogram = "spy.signal.spectrogram(y)" +PythonCommandScipySpecialErf = "spy.erf(a)" +PythonCommandScipySpecialErfc = "spy.erfc(a)" +PythonCommandScipySpecialGamma = "spy.gamma(a)" +PythonCommandScipySpecialGammaln = "spy.gammaln(a)" PythonCommandSetPixel = "set_pixel(x,y,color)" PythonCommandShow = "show()" PythonCommandSin = "sin(x)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index 2a26f98a7..ef64e1b4d 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -252,8 +252,46 @@ const ToolboxMessageTree NumpyModuleChildren[] = { ToolboxMessageTree::Node(I18n::Message::NumpyLinalgModule, NumpyLinalgModuleChildren) }; +const ToolboxMessageTree ScipyLinalgModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgFunction, I18n::Message::PythonScipyLinalgFunction, false, I18n::Message::PythonCommandScipyLinalgFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgChoSolve), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgSolveTriangular) +}; + +const ToolboxMessageTree ScipyOptimizeModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeFunction, I18n::Message::PythonScipyOptimizeFunction, false, I18n::Message::PythonCommandScipyOptimizeFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeBisect), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeFmin), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyOptimizeNewton) +}; + +const ToolboxMessageTree ScipySignalModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalFunction, I18n::Message::PythonScipySignalFunction, false, I18n::Message::PythonCommandScipySignalFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalSosfilt), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySignalSpectrogram) +}; + +const ToolboxMessageTree ScipySpecialModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialFunction, I18n::Message::PythonScipySpecialFunction, false, I18n::Message::PythonCommandScipySpecialFunctionWithoutArg), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialErf), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialErfc), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialGamma), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipySpecialGammaln), +}; + +const ToolboxMessageTree ScipyModuleChildren[] = { + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandImportFromScipy, I18n::Message::PythonImportScipy, false), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyFunction, I18n::Message::PythonScipyFunction, false, I18n::Message::PythonCommandScipyFunctionWithoutArg), + ToolboxMessageTree::Node(I18n::Message::ScipyLinalgModule, ScipyLinalgModuleChildren), + ToolboxMessageTree::Node(I18n::Message::ScipyOptimizeModule, ScipyOptimizeModuleChildren), + ToolboxMessageTree::Node(I18n::Message::ScipySignalModule, ScipySignalModuleChildren), + ToolboxMessageTree::Node(I18n::Message::ScipySpecialModule, ScipySpecialModuleChildren), + +}; + const ToolboxMessageTree UlabModuleChildren[] = { ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren), + ToolboxMessageTree::Node(I18n::Message::ScipyModule, ScipyModuleChildren), ToolboxMessageTree::Leaf(I18n::Message::UlabDocumentation, I18n::Message::UlabDocumentationLink) }; diff --git a/apps/code/toolbox.universal.i18n b/apps/code/toolbox.universal.i18n index 5a307394c..99810151a 100644 --- a/apps/code/toolbox.universal.i18n +++ b/apps/code/toolbox.universal.i18n @@ -6,6 +6,11 @@ MatplotlibPyplotModule = "matplotlib.pyplot" NumpyModule = "numpy" NumpyFftModule = "fft" NumpyLinalgModule = "linalg" +ScipyModule = "scipy" +ScipyLinalgModule = "linalg" +ScipyOptimizeModule = "optimize" +ScipySignalModule = "signal" +ScipySpecialModule = "special" NumpyNdarray = "ndarray" OsModule = "os" TimeModule = "time" From 98b665ac4b0604355cd345a3fb45d3b3de0bae63 Mon Sep 17 00:00:00 2001 From: Laury Date: Sun, 5 Sep 2021 16:57:09 +0200 Subject: [PATCH 6/7] [code/ulab] Disabled scipy in toolbox for n0100 + added 2 forgotten numpy functions --- apps/code/catalog.universal.i18n | 2 ++ apps/code/python_toolbox.cpp | 10 ++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/code/catalog.universal.i18n b/apps/code/catalog.universal.i18n index 510fe65a0..ad07c7ba9 100644 --- a/apps/code/catalog.universal.i18n +++ b/apps/code/catalog.universal.i18n @@ -201,6 +201,8 @@ PythonCommandNumpyTranspose = "ndarray.transpose()" PythonCommandNumpyTransposeWithoutArg = ".transpose()" PythonCommandNumpySort = "ndarray.sort()" PythonCommandNumpySortWithoutArg = ".sort()" +PythonCommandNumpySetPrintOptions = "np.set_printoptions()" +PythonCommandNumpyGetPrintOptions = "np.get_printoptions()" PythonCommandNumpyNdinfo = "np.ndinfo(a)" PythonCommandNumpyAll = "np.all(a)" PythonCommandNumpyAny = "np.any(a)" diff --git a/apps/code/python_toolbox.cpp b/apps/code/python_toolbox.cpp index ef64e1b4d..2dc5a6e81 100644 --- a/apps/code/python_toolbox.cpp +++ b/apps/code/python_toolbox.cpp @@ -225,7 +225,9 @@ const ToolboxMessageTree NumpyFunctionsModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyNan), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyInf), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyE), - ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi) + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyPi), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpySetPrintOptions), + ToolboxMessageTree::Leaf(I18n::Message::PythonCommandNumpyGetPrintOptions) }; const ToolboxMessageTree NumpyFftModuleChildren[] = { @@ -252,6 +254,7 @@ const ToolboxMessageTree NumpyModuleChildren[] = { ToolboxMessageTree::Node(I18n::Message::NumpyLinalgModule, NumpyLinalgModuleChildren) }; +#if !defined(DEVICE_N0100) const ToolboxMessageTree ScipyLinalgModuleChildren[] = { ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgFunction, I18n::Message::PythonScipyLinalgFunction, false, I18n::Message::PythonCommandScipyLinalgFunctionWithoutArg), ToolboxMessageTree::Leaf(I18n::Message::PythonCommandScipyLinalgChoSolve), @@ -286,12 +289,15 @@ const ToolboxMessageTree ScipyModuleChildren[] = { ToolboxMessageTree::Node(I18n::Message::ScipyOptimizeModule, ScipyOptimizeModuleChildren), ToolboxMessageTree::Node(I18n::Message::ScipySignalModule, ScipySignalModuleChildren), ToolboxMessageTree::Node(I18n::Message::ScipySpecialModule, ScipySpecialModuleChildren), - }; +#endif + const ToolboxMessageTree UlabModuleChildren[] = { ToolboxMessageTree::Node(I18n::Message::NumpyModule, NumpyModuleChildren), +#if !defined(DEVICE_N0100) ToolboxMessageTree::Node(I18n::Message::ScipyModule, ScipyModuleChildren), +#endif ToolboxMessageTree::Leaf(I18n::Message::UlabDocumentation, I18n::Message::UlabDocumentationLink) }; From 74c500df015161c475c10dff40a13a692b785fa8 Mon Sep 17 00:00:00 2001 From: Laury Date: Sun, 5 Sep 2021 16:57:50 +0200 Subject: [PATCH 7/7] [code/ulab] removed unnecessary module utils --- python/port/mod/ulab/ulab.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python/port/mod/ulab/ulab.h b/python/port/mod/ulab/ulab.h index 647672d8b..032768542 100644 --- a/python/port/mod/ulab/ulab.h +++ b/python/port/mod/ulab/ulab.h @@ -270,7 +270,7 @@ // frombuffer adds 600 bytes to the firmware #ifndef ULAB_NUMPY_HAS_FROMBUFFER -#define ULAB_NUMPY_HAS_FROMBUFFER (1) +#define ULAB_NUMPY_HAS_FROMBUFFER (0) #endif // functions that create an array @@ -644,7 +644,7 @@ #endif #ifndef ULAB_HAS_UTILS_MODULE -#define ULAB_HAS_UTILS_MODULE (1) +#define ULAB_HAS_UTILS_MODULE (0) #endif #ifndef ULAB_UTILS_HAS_FROM_INT16_BUFFER