Merge pull request #2 from ArtichOwO/uLab

This commit is contained in:
Lauryy06
2021-09-01 18:03:06 +02:00
committed by GitHub
56 changed files with 13053 additions and 0 deletions

View File

@@ -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 \
)

View File

@@ -601,3 +601,120 @@ Q(username)
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)

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 <math.h>
#include <py/runtime.h>
#include <py/objtuple.h>
#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 */

View File

@@ -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 */

View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#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 */

View File

@@ -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 <py/runtime.h>
#include <py/binary.h>
#include <py/obj.h>
#include <py/objarray.h>
#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

View File

@@ -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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <py/runtime.h>
#include <py/builtin.h>
#include <py/binary.h>
#include <py/obj.h>
#include <py/objarray.h>
#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,
};

View File

@@ -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

View File

@@ -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 <math.h>
#include <py/runtime.h>
#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);
}
}

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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 <math.h>
#include <string.h>
#include <py/runtime.h>
#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;
}

View File

@@ -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_ */

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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 <math.h>
#include <string.h>
#include <py/runtime.h>
#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,
};

View File

@@ -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_ */

View File

@@ -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 <py/obj.h>
#include <py/runtime.h>
#include <py/objarray.h>
#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

View File

@@ -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

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#include "../../ulab.h"
#include "../../ulab_tools.h"
#include "transform.h"
MP_DECLARE_CONST_FUN_OBJ_2(transform_dot_obj);
#endif

View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <py/runtime.h>
#include <py/binary.h>
#include <py/obj.h>
#include <py/objarray.h>
#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

View File

@@ -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_ */

View File

@@ -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 <stdlib.h>
#include <string.h>
#include <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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,
};

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <py/runtime.h>
#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

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <string.h>
#include <py/runtime.h>
#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,
};

View File

@@ -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_ */

View File

@@ -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 <math.h>
#include <py/runtime.h>
#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,
};

View File

@@ -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_ */

162
python/port/mod/ulab/ulab.c Normal file
View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <py/runtime.h>
#include <py/binary.h>
#include <py/obj.h>
#include <py/objarray.h>
#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);

666
python/port/mod/ulab/ulab.h Normal file
View File

@@ -0,0 +1,666 @@
/*
* 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
#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
// 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
#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)
#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

View File

@@ -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 <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#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

View File

@@ -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

View File

@@ -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 <string.h>
#include <py/runtime.h>
#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

View File

@@ -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

View File

@@ -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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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 <math.h>
#include <stdlib.h>
#include <string.h>
#include <py/obj.h>
#include <py/runtime.h>
#include <py/misc.h>
#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

View File

@@ -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

View File

@@ -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

View File

@@ -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 <escher/palette.h>