mirror of
https://github.com/UpsilonNumworks/Upsilon.git
synced 2026-01-18 16:27:34 +01:00
Merge pull request #2 from ArtichOwO/uLab
This commit is contained in:
@@ -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 \
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
2180
python/port/mod/ulab/ndarray.c
Normal file
2180
python/port/mod/ulab/ndarray.c
Normal file
File diff suppressed because it is too large
Load Diff
736
python/port/mod/ulab/ndarray.h
Normal file
736
python/port/mod/ulab/ndarray.h
Normal 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
|
||||
807
python/port/mod/ulab/ndarray_operators.c
Normal file
807
python/port/mod/ulab/ndarray_operators.c
Normal 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 */
|
||||
277
python/port/mod/ulab/ndarray_operators.h
Normal file
277
python/port/mod/ulab/ndarray_operators.h
Normal 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 */
|
||||
100
python/port/mod/ulab/ndarray_properties.c
Normal file
100
python/port/mod/ulab/ndarray_properties.c
Normal 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 */
|
||||
92
python/port/mod/ulab/ndarray_properties.h
Normal file
92
python/port/mod/ulab/ndarray_properties.h
Normal 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
|
||||
221
python/port/mod/ulab/numpy/approx/approx.c
Normal file
221
python/port/mod/ulab/numpy/approx/approx.c
Normal 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
|
||||
29
python/port/mod/ulab/numpy/approx/approx.h
Normal file
29
python/port/mod/ulab/numpy/approx/approx.h
Normal 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_ */
|
||||
417
python/port/mod/ulab/numpy/compare/compare.c
Normal file
417
python/port/mod/ulab/numpy/compare/compare.c
Normal 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
|
||||
150
python/port/mod/ulab/numpy/compare/compare.h
Normal file
150
python/port/mod/ulab/numpy/compare/compare.h
Normal 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
|
||||
82
python/port/mod/ulab/numpy/fft/fft.c
Normal file
82
python/port/mod/ulab/numpy/fft/fft.c
Normal 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,
|
||||
};
|
||||
24
python/port/mod/ulab/numpy/fft/fft.h
Normal file
24
python/port/mod/ulab/numpy/fft/fft.h
Normal 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
|
||||
165
python/port/mod/ulab/numpy/fft/fft_tools.c
Normal file
165
python/port/mod/ulab/numpy/fft/fft_tools.c
Normal 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);
|
||||
}
|
||||
}
|
||||
23
python/port/mod/ulab/numpy/fft/fft_tools.h
Normal file
23
python/port/mod/ulab/numpy/fft/fft_tools.h
Normal 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_ */
|
||||
84
python/port/mod/ulab/numpy/filter/filter.c
Normal file
84
python/port/mod/ulab/numpy/filter/filter.c
Normal 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
|
||||
20
python/port/mod/ulab/numpy/filter/filter.h
Normal file
20
python/port/mod/ulab/numpy/filter/filter.h
Normal 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
|
||||
397
python/port/mod/ulab/numpy/linalg/linalg.c
Normal file
397
python/port/mod/ulab/numpy/linalg/linalg.c
Normal 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
|
||||
26
python/port/mod/ulab/numpy/linalg/linalg.h
Normal file
26
python/port/mod/ulab/numpy/linalg/linalg.h
Normal 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
|
||||
171
python/port/mod/ulab/numpy/linalg/linalg_tools.c
Normal file
171
python/port/mod/ulab/numpy/linalg/linalg_tools.c
Normal 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;
|
||||
}
|
||||
28
python/port/mod/ulab/numpy/linalg/linalg_tools.h
Normal file
28
python/port/mod/ulab/numpy/linalg/linalg_tools.h
Normal 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_ */
|
||||
|
||||
1338
python/port/mod/ulab/numpy/numerical/numerical.c
Normal file
1338
python/port/mod/ulab/numpy/numerical/numerical.c
Normal file
File diff suppressed because it is too large
Load Diff
652
python/port/mod/ulab/numpy/numerical/numerical.h
Normal file
652
python/port/mod/ulab/numpy/numerical/numerical.h
Normal 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
|
||||
336
python/port/mod/ulab/numpy/numpy.c
Normal file
336
python/port/mod/ulab/numpy/numpy.c
Normal 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,
|
||||
};
|
||||
21
python/port/mod/ulab/numpy/numpy.h
Normal file
21
python/port/mod/ulab/numpy/numpy.h
Normal 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_ */
|
||||
232
python/port/mod/ulab/numpy/poly/poly.c
Normal file
232
python/port/mod/ulab/numpy/poly/poly.c
Normal 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
|
||||
21
python/port/mod/ulab/numpy/poly/poly.h
Normal file
21
python/port/mod/ulab/numpy/poly/poly.h
Normal 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
|
||||
52
python/port/mod/ulab/numpy/stats/stats.c
Normal file
52
python/port/mod/ulab/numpy/stats/stats.c
Normal 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
|
||||
20
python/port/mod/ulab/numpy/stats/stats.h
Normal file
20
python/port/mod/ulab/numpy/stats/stats.h
Normal 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
|
||||
89
python/port/mod/ulab/numpy/transform/transform.c
Normal file
89
python/port/mod/ulab/numpy/transform/transform.c
Normal 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
|
||||
28
python/port/mod/ulab/numpy/transform/transform.h
Normal file
28
python/port/mod/ulab/numpy/transform/transform.h
Normal 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
|
||||
635
python/port/mod/ulab/numpy/vector/vector.c
Normal file
635
python/port/mod/ulab/numpy/vector/vector.c
Normal 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
|
||||
156
python/port/mod/ulab/numpy/vector/vector.h
Normal file
156
python/port/mod/ulab/numpy/vector/vector.h
Normal 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_ */
|
||||
279
python/port/mod/ulab/scipy/linalg/linalg.c
Normal file
279
python/port/mod/ulab/scipy/linalg/linalg.c
Normal 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
|
||||
21
python/port/mod/ulab/scipy/linalg/linalg.h
Normal file
21
python/port/mod/ulab/scipy/linalg/linalg.h
Normal 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_ */
|
||||
414
python/port/mod/ulab/scipy/optimize/optimize.c
Normal file
414
python/port/mod/ulab/scipy/optimize/optimize.c
Normal 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,
|
||||
};
|
||||
41
python/port/mod/ulab/scipy/optimize/optimize.h
Normal file
41
python/port/mod/ulab/scipy/optimize/optimize.h
Normal 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_ */
|
||||
51
python/port/mod/ulab/scipy/scipy.c
Normal file
51
python/port/mod/ulab/scipy/scipy.c
Normal 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
|
||||
21
python/port/mod/ulab/scipy/scipy.h
Normal file
21
python/port/mod/ulab/scipy/scipy.h
Normal 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_ */
|
||||
153
python/port/mod/ulab/scipy/signal/signal.c
Normal file
153
python/port/mod/ulab/scipy/signal/signal.c
Normal 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,
|
||||
};
|
||||
24
python/port/mod/ulab/scipy/signal/signal.h
Normal file
24
python/port/mod/ulab/scipy/signal/signal.h
Normal 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_ */
|
||||
42
python/port/mod/ulab/scipy/special/special.c
Normal file
42
python/port/mod/ulab/scipy/special/special.c
Normal 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,
|
||||
};
|
||||
21
python/port/mod/ulab/scipy/special/special.h
Normal file
21
python/port/mod/ulab/scipy/special/special.h
Normal 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
162
python/port/mod/ulab/ulab.c
Normal 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
666
python/port/mod/ulab/ulab.h
Normal 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
|
||||
706
python/port/mod/ulab/ulab_create.c
Normal file
706
python/port/mod/ulab/ulab_create.c
Normal 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
|
||||
78
python/port/mod/ulab/ulab_create.h
Normal file
78
python/port/mod/ulab/ulab_create.h
Normal 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
|
||||
233
python/port/mod/ulab/ulab_tools.c
Normal file
233
python/port/mod/ulab/ulab_tools.c
Normal 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
|
||||
37
python/port/mod/ulab/ulab_tools.h
Normal file
37
python/port/mod/ulab/ulab_tools.h
Normal 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
|
||||
95
python/port/mod/ulab/user/user.c
Normal file
95
python/port/mod/ulab/user/user.c
Normal 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
|
||||
20
python/port/mod/ulab/user/user.h
Normal file
20
python/port/mod/ulab/user/user.h
Normal 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
|
||||
215
python/port/mod/ulab/utils/utils.c
Normal file
215
python/port/mod/ulab/utils/utils.c
Normal 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
|
||||
19
python/port/mod/ulab/utils/utils.h
Normal file
19
python/port/mod/ulab/utils/utils.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user