Compare commits

..

No commits in common. "2dim" and "fix-undef-errors-mpy" have entirely different histories.

28 changed files with 6015 additions and 1815 deletions

View file

@ -1,58 +0,0 @@
name: Build CI
on:
push:
pull_request:
release:
types: [published]
check_suite:
types: [rerequested]
jobs:
test:
runs-on: ubuntu-16.04
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Set up Python 3.5
uses: actions/setup-python@v1
with:
python-version: 3.5
- name: Versions
run: |
gcc --version
python3 --version
- name: Checkout ulab
uses: actions/checkout@v1
- name: Checkout micropython repo
uses: actions/checkout@v2
with:
repository: micropython/micropython
path: micropython
- name: Checkout micropython submodules
run: (cd micropython && git submodule update --init)
- name: Build mpy-cross
run: make -C micropython/mpy-cross -j2
- name: Build micropython unix port
run: |
make -C micropython/ports/unix -j2 deplibs
make -C micropython/ports/unix -j2 USER_C_MODULES=$(readlink -f .)
- name: Run tests
run: env MICROPYTHON_CPYTHON3=python3.5 MICROPY_MICROPYTHON=micropython/ports/unix/micropython micropython/tests/run-tests -d tests
- name: Print failure info
run: |
for exp in *.exp;
do testbase=$(basename $exp .exp);
echo -e "\nFAILURE $testbase";
diff -u $testbase.exp $testbase.out;
done
if: failure()

View file

@ -1,33 +0,0 @@
/*
* This file is part of the micropython-ulab project,
*
* https://github.com/v923z/micropython-ulab
*
* The MIT License (MIT)
*
* Copyright (c) 2020 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 "extras.h"
#if ULAB_EXTRAS_MODULE
STATIC const mp_rom_map_elem_t ulab_filter_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_extras) },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_extras_globals, ulab_extras_globals_table);
mp_obj_module_t ulab_filter_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_extras_globals,
};
#endif

View file

@ -1,23 +0,0 @@
/*
* This file is part of the micropython-ulab project,
*
* https://github.com/v923z/micropython-ulab
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Zoltán Vörös
*/
#ifndef _EXTRA_
#define _EXTRA_
#include "ulab.h"
#include "ndarray.h"
#if ULAB_EXTRAS_MODULE
mp_obj_module_t ulab_extras_module;
#endif
#endif

View file

@ -14,14 +14,13 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "py/runtime.h" #include "py/runtime.h"
#include "py/builtin.h"
#include "py/binary.h" #include "py/binary.h"
#include "py/obj.h" #include "py/obj.h"
#include "py/objarray.h" #include "py/objarray.h"
#include "ndarray.h" #include "ndarray.h"
#include "fft.h" #include "fft.h"
#if ULAB_FFT_MODULE #if ULAB_FFT_FFT || ULAB_FFT_IFFT || ULAB_FFT_SPECTRUM
enum FFT_TYPE { enum FFT_TYPE {
FFT_FFT, FFT_FFT,
@ -79,11 +78,11 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) {
} }
mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { mp_obj_t fft_fft_ifft_spectrum(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)) { if(!mp_obj_is_type(arg_re, &ulab_ndarray_type)) {
mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
} }
if(n_args == 2) { if(n_args == 2) {
if(!MP_OBJ_IS_TYPE(arg_im, &ulab_ndarray_type)) { if(!mp_obj_is_type(arg_im, &ulab_ndarray_type)) {
mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only")); mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
} }
} }
@ -103,9 +102,8 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
memcpy((mp_float_t *)out_re->array->items, (mp_float_t *)re->array->items, re->bytes); memcpy((mp_float_t *)out_re->array->items, (mp_float_t *)re->array->items, re->bytes);
} else { } else {
for(size_t i=0; i < len; i++) { for(size_t i=0; i < len; i++) {
*data_re++ = ndarray_get_float_value(re->array->items, re->array->typecode, i); data_re[i] = ndarray_get_float_value(re->array->items, re->array->typecode, i);
} }
data_re -= len;
} }
ndarray_obj_t *out_im = create_new_ndarray(1, len, NDARRAY_FLOAT); ndarray_obj_t *out_im = create_new_ndarray(1, len, NDARRAY_FLOAT);
mp_float_t *data_im = (mp_float_t *)out_im->array->items; mp_float_t *data_im = (mp_float_t *)out_im->array->items;
@ -119,27 +117,23 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
memcpy((mp_float_t *)out_im->array->items, (mp_float_t *)im->array->items, im->bytes); memcpy((mp_float_t *)out_im->array->items, (mp_float_t *)im->array->items, im->bytes);
} else { } else {
for(size_t i=0; i < len; i++) { for(size_t i=0; i < len; i++) {
*data_im++ = ndarray_get_float_value(im->array->items, im->array->typecode, i); data_im[i] = ndarray_get_float_value(im->array->items, im->array->typecode, i);
} }
data_im -= len;
} }
} }
if((type == FFT_FFT) || (type == FFT_SPECTRUM)) { if((type == FFT_FFT) || (type == FFT_SPECTRUM)) {
fft_kernel(data_re, data_im, len, 1); fft_kernel(data_re, data_im, len, 1);
if(type == FFT_SPECTRUM) { if(type == FFT_SPECTRUM) {
for(size_t i=0; i < len; i++) { 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[i] = MICROPY_FLOAT_C_FUN(sqrt)(data_re[i]*data_re[i] + data_im[i]*data_im[i]);
data_re++;
data_im++;
} }
} }
} else { // inverse transform } else { // inverse transform
fft_kernel(data_re, data_im, len, -1); fft_kernel(data_re, data_im, len, -1);
// TODO: numpy accepts the norm keyword argument // TODO: numpy accepts the norm keyword argument
for(size_t i=0; i < len; i++) { for(size_t i=0; i < len; i++) {
*data_re++ /= len; data_re[i] /= len;
*data_im++ /= len; data_im[i] /= len;
} }
} }
if(type == FFT_SPECTRUM) { if(type == FFT_SPECTRUM) {
@ -152,6 +146,7 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
} }
} }
#if ULAB_FFT_FFT
mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) { mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) { if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_FFT); return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_FFT);
@ -161,7 +156,9 @@ mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
#endif
#if ULAB_FFT_IFFT
mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) { mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) { if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_IFFT); return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_IFFT);
@ -171,7 +168,9 @@ mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft);
#endif
#if ULAB_FFT_SPECTRUM
mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) { mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) { if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM); return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM);
@ -181,21 +180,6 @@ mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum);
#if !CIRCUITPY
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 },
{ MP_OBJ_NEW_QSTR(MP_QSTR_spectrum), (mp_obj_t)&fft_spectrum_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,
};
#endif #endif
#endif #endif

View file

@ -19,13 +19,19 @@
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; } #define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
#if ULAB_FFT_MODULE #if ULAB_FFT_FFT
mp_obj_t fft_fft(size_t , const mp_obj_t *);
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_fft_obj);
#endif
#if ULAB_FFT_IFFT
mp_obj_t fft_ifft(size_t , const mp_obj_t *);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj);
#endif
#if ULAB_FFT_SPECTRUM
mp_obj_t fft_spectrum(size_t , const mp_obj_t *);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj);
#endif
#endif #endif
#endif

View file

@ -17,17 +17,17 @@
#include "py/misc.h" #include "py/misc.h"
#include "filter.h" #include "filter.h"
#if ULAB_FILTER_MODULE #if ULAB_FILTER_CONVOLVE
mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { 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[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_v, 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_ROM_NONE } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(2, 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)) { 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")); mp_raise_TypeError(translate("convolve arguments must be ndarrays"));
} }
@ -47,55 +47,27 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
ndarray_obj_t *out = create_new_ndarray(1, len, NDARRAY_FLOAT); ndarray_obj_t *out = create_new_ndarray(1, len, NDARRAY_FLOAT);
mp_float_t *outptr = out->array->items; mp_float_t *outptr = out->array->items;
int off = len_c-1; int off = len_c-1;
for(int k=-off; k<len-off; k++) {
if(a->array->typecode == NDARRAY_FLOAT && c->array->typecode == NDARRAY_FLOAT) { mp_float_t accum = (mp_float_t)0;
mp_float_t* a_items = (mp_float_t*)a->array->items; int top_n = MIN(len_c, len_a - k);
mp_float_t* c_items = (mp_float_t*)c->array->items; int bot_n = MAX(-k, 0);
for(int k=-off; k<len-off; k++) { for(int n=bot_n; n<top_n; n++) {
mp_float_t accum = (mp_float_t)0; int idx_c = len_c - n - 1;
int top_n = MIN(len_c, len_a - k); int idx_a = n+k;
int bot_n = MAX(-k, 0); mp_float_t ai = (mp_float_t)0, ci = (mp_float_t)0;
mp_float_t* a_ptr = a_items + bot_n + k; if(idx_a >= 0 && idx_a < len_a) {
mp_float_t* a_end = a_ptr + (top_n - bot_n); ai = ndarray_get_float_value(a->array->items, a->array->typecode, idx_a);
mp_float_t* c_ptr = c_items + len_c - bot_n - 1;
for(; a_ptr != a_end;) {
accum += *a_ptr++ * *c_ptr--;
} }
*outptr++ = accum; if(idx_c >= 0 && idx_c < len_c) {
} ci = ndarray_get_float_value(c->array->items, c->array->typecode, idx_c);
} else {
for(int k=-off; k<len-off; k++) {
mp_float_t accum = (mp_float_t)0;
int top_n = MIN(len_c, len_a - k);
int bot_n = MAX(-k, 0);
for(int n=bot_n; n<top_n; n++) {
int idx_c = len_c - n - 1;
int idx_a = n+k;
mp_float_t ai = ndarray_get_float_value(a->array->items, a->array->typecode, idx_a);
mp_float_t ci = ndarray_get_float_value(c->array->items, c->array->typecode, idx_c);
accum += ai * ci;
} }
*outptr++ = accum; accum += ai * ci;
} }
*outptr++ = accum;
} }
return out; return out;
} }
MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve); MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_filter_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_filter) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_filter_globals, ulab_filter_globals_table);
mp_obj_module_t ulab_filter_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_filter_globals,
};
#endif
#endif #endif

View file

@ -15,11 +15,9 @@
#include "ulab.h" #include "ulab.h"
#include "ndarray.h" #include "ndarray.h"
#if ULAB_FILTER_MODULE #if ULAB_FILTER_CONVOLVE
mp_obj_t filter_convolve(size_t , const mp_obj_t *, mp_map_t *);
extern mp_obj_module_t ulab_filter_module;
MP_DECLARE_CONST_FUN_OBJ_KW(filter_convolve_obj); MP_DECLARE_CONST_FUN_OBJ_KW(filter_convolve_obj);
#endif
#endif #endif
#endif

View file

@ -17,24 +17,85 @@
#include "py/misc.h" #include "py/misc.h"
#include "linalg.h" #include "linalg.h"
#if ULAB_LINALG_MODULE #if ULAB_LINALG_TRANSPOSE
mp_obj_t linalg_transpose(mp_obj_t self_in) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
// the size of a single item in the array
uint8_t _sizeof = mp_binary_get_size('@', self->array->typecode, NULL);
// NOTE:
// if the matrices are square, we can simply swap items, but
// generic matrices can't be transposed in place, so we have to
// declare a temporary variable
// NOTE:
// In the old matrix, the coordinate (m, n) is m*self->n + n
// We have to assign this to the coordinate (n, m) in the new
// matrix, i.e., to n*self->m + m (since the new matrix has self->m columns)
// one-dimensional arrays can be transposed by simply swapping the dimensions
if((self->m != 1) && (self->n != 1)) {
uint8_t *c = (uint8_t *)self->array->items;
// self->bytes is the size of the bytearray, irrespective of the typecode
uint8_t *tmp = m_new(uint8_t, self->bytes);
for(size_t m=0; m < self->m; m++) {
for(size_t n=0; n < self->n; n++) {
memcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof);
}
}
memcpy(self->array->items, tmp, self->bytes);
m_del(uint8_t, tmp, self->bytes);
}
SWAP(size_t, self->m, self->n);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(linalg_transpose_obj, linalg_transpose);
#endif
#if ULAB_LINALG_RESHAPE
mp_obj_t linalg_reshape(mp_obj_t self_in, mp_obj_t shape) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
if(!mp_obj_is_type(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) {
mp_raise_ValueError(translate("shape must be a 2-tuple"));
}
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(shape, &iter_buf);
uint16_t m, n;
item = mp_iternext(iterable);
m = mp_obj_get_int(item);
item = mp_iternext(iterable);
n = mp_obj_get_int(item);
if(m*n != self->m*self->n) {
// TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)"
mp_raise_ValueError(translate("cannot reshape array (incompatible input/output shape)"));
}
self->m = m;
self->n = n;
return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_FUN_OBJ_2(linalg_reshape_obj, linalg_reshape);
#endif
#if ULAB_LINALG_SIZE
mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("size is defined for ndarrays only")); mp_raise_TypeError(translate("size is defined for ndarrays only"));
} else { } else {
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
if(args[1].u_obj == mp_const_none) { if(args[1].u_obj == mp_const_none) {
return mp_obj_new_int(ndarray->array->len); return mp_obj_new_int(ndarray->array->len);
} else if(MP_OBJ_IS_INT(args[1].u_obj)) { } else if(mp_obj_is_int(args[1].u_obj)) {
uint8_t ax = mp_obj_get_int(args[1].u_obj); uint8_t ax = mp_obj_get_int(args[1].u_obj);
if(ax == 0) { if(ax == 0) {
if(ndarray->m == 1) { if(ndarray->m == 1) {
@ -58,7 +119,9 @@ mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
} }
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size); MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size);
#endif
#if ULAB_LINALG_INV || ULAB_POLY_POLYFIT
bool linalg_invert_matrix(mp_float_t *data, size_t N) { bool linalg_invert_matrix(mp_float_t *data, size_t N) {
// returns true, of the inversion was successful, // returns true, of the inversion was successful,
// false, if the matrix is singular // false, if the matrix is singular
@ -100,14 +163,16 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) {
m_del(mp_float_t, unit, N*N); m_del(mp_float_t, unit, N*N);
return true; return true;
} }
#endif
#if ULAB_LINALG_INV
mp_obj_t linalg_inv(mp_obj_t o_in) { mp_obj_t linalg_inv(mp_obj_t o_in) {
// since inv is not a class method, we have to inspect the input argument first // since inv is not a class method, we have to inspect the input argument first
if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { if(!mp_obj_is_type(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("only ndarrays can be inverted")); mp_raise_TypeError(translate("only ndarrays can be inverted"));
} }
ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in); ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);
if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { if(!mp_obj_is_type(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("only ndarray objects can be inverted")); mp_raise_TypeError(translate("only ndarray objects can be inverted"));
} }
if(o->m != o->n) { if(o->m != o->n) {
@ -135,10 +200,12 @@ mp_obj_t linalg_inv(mp_obj_t o_in) {
} }
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv); MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
#endif
#if ULAB_LINALG_DOT
mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) { mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
// TODO: should the results be upcast? // TODO: should the results be upcast?
if(!MP_OBJ_IS_TYPE(_m1, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(_m2, &ulab_ndarray_type)) { 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")); mp_raise_TypeError(translate("arguments must be ndarrays"));
} }
ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1); ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1);
@ -166,7 +233,9 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
} }
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot); MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
#endif
#if ULAB_LINALG_ZEROS || ULAB_LINALG_ONES
mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) { mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) {
static const mp_arg_t allowed_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} } ,
@ -177,14 +246,14 @@ mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, 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; uint8_t dtype = args[1].u_int;
if(!MP_OBJ_IS_INT(args[0].u_obj) && !MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) { if(!mp_obj_is_int(args[0].u_obj) && !mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple")); mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
} }
ndarray_obj_t *ndarray = NULL; ndarray_obj_t *ndarray = NULL;
if(MP_OBJ_IS_INT(args[0].u_obj)) { if(mp_obj_is_int(args[0].u_obj)) {
size_t n = mp_obj_get_int(args[0].u_obj); size_t n = mp_obj_get_int(args[0].u_obj);
ndarray = create_new_ndarray(1, n, dtype); ndarray = create_new_ndarray(1, n, dtype);
} else if(MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) { } else if(mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj);
if(tuple->len != 2) { if(tuple->len != 2) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple")); mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
@ -200,23 +269,29 @@ mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
} }
return MP_OBJ_FROM_PTR(ndarray); return MP_OBJ_FROM_PTR(ndarray);
} }
#endif
#if ULAB_LINALG_ZEROS
mp_obj_t linalg_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t linalg_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return linalg_zeros_ones(n_args, pos_args, kw_args, 0); return linalg_zeros_ones(n_args, pos_args, kw_args, 0);
} }
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros); MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros);
#endif
#if ULAB_LINALG_ONES
mp_obj_t linalg_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t linalg_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return linalg_zeros_ones(n_args, pos_args, kw_args, 1); return linalg_zeros_ones(n_args, pos_args, kw_args, 1);
} }
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones); MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones);
#endif
#if ULAB_LINALG_EYE
mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} }, { 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_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { 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_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
}; };
@ -255,9 +330,11 @@ mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
} }
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye); MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye);
#endif
#if ULAB_LINALG_DET
mp_obj_t linalg_det(mp_obj_t oin) { mp_obj_t linalg_det(mp_obj_t oin) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { if(!mp_obj_is_type(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("function defined for ndarrays only")); mp_raise_TypeError(translate("function defined for ndarrays only"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
@ -294,9 +371,11 @@ mp_obj_t linalg_det(mp_obj_t oin) {
} }
MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det); MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
#endif
#if ULAB_LINALG_EIG
mp_obj_t linalg_eig(mp_obj_t oin) { mp_obj_t linalg_eig(mp_obj_t oin) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { if(!mp_obj_is_type(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("function defined for ndarrays only")); mp_raise_TypeError(translate("function defined for ndarrays only"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
@ -423,26 +502,4 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
} }
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig); MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
#if !CIRCUITPY
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) },
{ MP_ROM_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
{ MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&linalg_zeros_obj },
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&linalg_ones_obj },
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&linalg_eye_obj },
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
};
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
#endif #endif

View file

@ -15,6 +15,8 @@
#include "ulab.h" #include "ulab.h"
#include "ndarray.h" #include "ndarray.h"
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT #if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#define epsilon 1.2e-7 #define epsilon 1.2e-7
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE #elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
@ -23,13 +25,59 @@
#define JACOBI_MAX 20 #define JACOBI_MAX 20
#if ULAB_LINALG_MODULE || ULAB_POLY_MODULE // TODO: transpose, reshape and size should probably be part of ndarray.c
#if ULAB_LINALG_TRANSPOSE
mp_obj_t linalg_transpose(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(linalg_transpose_obj);
#endif
#if ULAB_LINALG_RESHAPE
mp_obj_t linalg_reshape(mp_obj_t , mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_2(linalg_reshape_obj);
#endif
#if ULAB_LINALG_SIZE
mp_obj_t linalg_size(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_size_obj);
#endif
#if ULAB_LINALG_INV || ULAB_POLY_POLYFIT
bool linalg_invert_matrix(mp_float_t *, size_t ); bool linalg_invert_matrix(mp_float_t *, size_t );
#endif #endif
#if ULAB_LINALG_MODULE #if ULAB_LINALG_INV
mp_obj_t linalg_inv(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(linalg_inv_obj);
#endif
extern mp_obj_module_t ulab_linalg_module; #if ULAB_LINALG_DOT
mp_obj_t linalg_dot(mp_obj_t , mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_2(linalg_dot_obj);
#endif
#if ULAB_LINALG_ZEROS
mp_obj_t linalg_zeros(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_zeros_obj);
#endif
#if ULAB_LINALG_ONES
mp_obj_t linalg_ones(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_ones_obj);
#endif
#if ULAB_LINALG_EYE
mp_obj_t linalg_eye(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_eye_obj);
#endif
#if ULAB_LINALG_DET
mp_obj_t linalg_det(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj);
#endif
#if ULAB_LINALG_EIG
mp_obj_t linalg_eig(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(linalg_eig_obj);
#endif
#endif #endif
#endif

View file

@ -7,13 +7,10 @@ SRC_USERMOD += $(USERMODULES_DIR)/linalg.c
SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c
SRC_USERMOD += $(USERMODULES_DIR)/poly.c SRC_USERMOD += $(USERMODULES_DIR)/poly.c
SRC_USERMOD += $(USERMODULES_DIR)/fft.c SRC_USERMOD += $(USERMODULES_DIR)/fft.c
SRC_USERMOD += $(USERMODULES_DIR)/numerical.c
SRC_USERMOD += $(USERMODULES_DIR)/filter.c SRC_USERMOD += $(USERMODULES_DIR)/filter.c
SRC_USERMOD += $(USERMODULES_DIR)/extras.c SRC_USERMOD += $(USERMODULES_DIR)/numerical.c
SRC_USERMOD += $(USERMODULES_DIR)/ulab.c SRC_USERMOD += $(USERMODULES_DIR)/ulab.c
# We can add our module folder to include paths if needed # We can add our module folder to include paths if needed
# This is not actually needed in this example. # This is not actually needed in this example.
CFLAGS_USERMOD += -I$(USERMODULES_DIR) CFLAGS_USERMOD += -I$(USERMODULES_DIR)
CFLAGS_EXTRA = -DMODULE_ULAB_ENABLED=1

View file

@ -154,7 +154,7 @@ mp_obj_t ndarray_copy(mp_obj_t self_in) {
STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT } }, { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT } },
}; };
@ -165,8 +165,11 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m
return dtype; return dtype;
} }
STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) { mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
uint8_t dtype = ndarray_init_helper(n_args, args, kw_args); mp_arg_check_num(n_args, n_kw, 1, 2, true);
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
uint8_t dtype = ndarray_init_helper(n_args, args, &kw_args);
size_t len1, len2=0, i=0; size_t len1, len2=0, i=0;
mp_obj_t len_in = mp_obj_len_maybe(args[0]); mp_obj_t len_in = mp_obj_len_maybe(args[0]);
@ -212,25 +215,6 @@ STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args,
return MP_OBJ_FROM_PTR(self); return MP_OBJ_FROM_PTR(self);
} }
#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) {
mp_arg_check_num(n_args, kw_args, 1, 2, true);
size_t n_kw = 0;
if (kw_args != 0) {
n_kw = kw_args->used;
}
mp_map_init_fixed_table(kw_args, n_kw, args + n_args);
return ndarray_make_new_core(type, n_args, n_kw, args, kw_args);
}
#else
mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
mp_arg_check_num(n_args, n_kw, 1, 2, true);
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
return ndarray_make_new_core(type, n_args, n_kw, args, &kw_args);
}
#endif
size_t slice_length(mp_bound_slice_t slice) { size_t slice_length(mp_bound_slice_t slice) {
int32_t len, correction = 1; int32_t len, correction = 1;
if(slice.step > 0) correction = -1; if(slice.step > 0) correction = -1;
@ -246,7 +230,7 @@ size_t true_length(mp_obj_t bool_list) {
mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf); mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf);
size_t trues = 0; size_t trues = 0;
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if(!MP_OBJ_IS_TYPE(item, &mp_type_bool)) { if(!mp_obj_is_type(item, &mp_type_bool)) {
// numpy seems to be a little bit inconsistent in when an index is considered // numpy seems to be a little bit inconsistent in when an index is considered
// to be True/False. Bail out immediately, if the items are not True/False // to be True/False. Bail out immediately, if the items are not True/False
return 0; return 0;
@ -261,9 +245,9 @@ size_t true_length(mp_obj_t bool_list) {
mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) { mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) {
// micropython seems to have difficulties with negative steps // micropython seems to have difficulties with negative steps
mp_bound_slice_t slice; mp_bound_slice_t slice;
if(MP_OBJ_IS_TYPE(index, &mp_type_slice)) { if(mp_obj_is_type(index, &mp_type_slice)) {
mp_seq_get_fast_slice_indexes(n, index, &slice); mp_seq_get_fast_slice_indexes(n, index, &slice);
} else if(MP_OBJ_IS_INT(index)) { } else if(mp_obj_is_int(index)) {
int32_t _index = mp_obj_get_int(index); int32_t _index = mp_obj_get_int(index);
if(_index < 0) { if(_index < 0) {
_index += n; _index += n;
@ -304,7 +288,7 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
mp_obj_t row_list, mp_obj_t column_list, mp_obj_t row_list, mp_obj_t column_list,
ndarray_obj_t *values) { ndarray_obj_t *values) {
if((m != values->m) && (n != values->n)) { if((m != values->m) && (n != values->n)) {
if(values->array->len != 1) { // not a single item if((values->array->len != 1)) { // not a single item
mp_raise_ValueError(translate("could not broadast input array from shape")); mp_raise_ValueError(translate("could not broadast input array from shape"));
} }
} }
@ -477,7 +461,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1); mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1);
size_t m = 0, n = 0; size_t m = 0, n = 0;
if(MP_OBJ_IS_INT(index) && (ndarray->m == 1) && (values == NULL)) { if(mp_obj_is_int(index) && (ndarray->m == 1) && (values == NULL)) {
// we have a row vector, and don't want to assign // we have a row vector, and don't want to assign
column_slice = generate_slice(ndarray->n, index); column_slice = generate_slice(ndarray->n, index);
if(slice_length(column_slice) == 1) { // we were asked for a single item if(slice_length(column_slice) == 1) { // we were asked for a single item
@ -486,7 +470,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
} }
} }
if(MP_OBJ_IS_INT(index) || MP_OBJ_IS_TYPE(index, &mp_type_slice)) { if(mp_obj_is_int(index) || mp_obj_is_type(index, &mp_type_slice)) {
if(ndarray->m == 1) { // we have a row vector if(ndarray->m == 1) { // we have a row vector
column_slice = generate_slice(ndarray->n, index); column_slice = generate_slice(ndarray->n, index);
row_slice = simple_slice(0, 1, 1); row_slice = simple_slice(0, 1, 1);
@ -497,7 +481,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
m = slice_length(row_slice); m = slice_length(row_slice);
n = slice_length(column_slice); n = slice_length(column_slice);
return iterate_slice_list(ndarray, m, n, row_slice, column_slice, mp_const_none, mp_const_none, values); return iterate_slice_list(ndarray, m, n, row_slice, column_slice, mp_const_none, mp_const_none, values);
} else if(MP_OBJ_IS_TYPE(index, &mp_type_list)) { } else if(mp_obj_is_type(index, &mp_type_list)) {
n = true_length(index); n = true_length(index);
if(ndarray->m == 1) { // we have a flat array if(ndarray->m == 1) { // we have a flat array
// we might have to separate the n == 1 case // we might have to separate the n == 1 case
@ -512,17 +496,17 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
if(tuple->len != 2) { if(tuple->len != 2) {
mp_raise_msg(&mp_type_IndexError, translate("too many indices")); mp_raise_msg(&mp_type_IndexError, translate("too many indices"));
} }
if(!(MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_list) || if(!(mp_obj_is_type(tuple->items[0], &mp_type_list) ||
MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_slice) || mp_obj_is_type(tuple->items[0], &mp_type_slice) ||
MP_OBJ_IS_INT(tuple->items[0])) || mp_obj_is_int(tuple->items[0])) ||
!(MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_list) || !(mp_obj_is_type(tuple->items[1], &mp_type_list) ||
MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_slice) || mp_obj_is_type(tuple->items[1], &mp_type_slice) ||
MP_OBJ_IS_INT(tuple->items[1]))) { mp_obj_is_int(tuple->items[1]))) {
mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists")); mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists"));
} }
if(MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_list)) { // rows are indexed by Boolean list if(mp_obj_is_type(tuple->items[0], &mp_type_list)) { // rows are indexed by Boolean list
m = true_length(tuple->items[0]); m = true_length(tuple->items[0]);
if(MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_list)) { if(mp_obj_is_type(tuple->items[1], &mp_type_list)) {
n = true_length(tuple->items[1]); n = true_length(tuple->items[1]);
return iterate_slice_list(ndarray, m, n, row_slice, column_slice, return iterate_slice_list(ndarray, m, n, row_slice, column_slice,
tuple->items[0], tuple->items[1], values); tuple->items[0], tuple->items[1], values);
@ -536,7 +520,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
} else { // rows are indexed by a slice, or an integer } else { // rows are indexed by a slice, or an integer
row_slice = generate_slice(ndarray->m, tuple->items[0]); row_slice = generate_slice(ndarray->m, tuple->items[0]);
m = slice_length(row_slice); m = slice_length(row_slice);
if(MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_list)) { // columns are indexed by a Boolean list if(mp_obj_is_type(tuple->items[1], &mp_type_list)) { // columns are indexed by a Boolean list
n = true_length(tuple->items[1]); n = true_length(tuple->items[1]);
return iterate_slice_list(ndarray, m, n, row_slice, column_slice, return iterate_slice_list(ndarray, m, n, row_slice, column_slice,
mp_const_none, tuple->items[1], values); mp_const_none, tuple->items[1], values);
@ -557,12 +541,12 @@ mp_obj_t ndarray_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) { // return value(s) if (value == MP_OBJ_SENTINEL) { // return value(s)
return ndarray_get_slice(self, index, NULL); return ndarray_get_slice(self, index, NULL);
} else { // assignment to slices; the value must be an ndarray, or a scalar } else { // assignment to slices; the value must be an ndarray, or a scalar
if(!MP_OBJ_IS_TYPE(value, &ulab_ndarray_type) && if(!mp_obj_is_type(value, &ulab_ndarray_type) &&
!MP_OBJ_IS_INT(value) && !mp_obj_is_float(value)) { !mp_obj_is_int(value) && !mp_obj_is_float(value)) {
mp_raise_ValueError(translate("right hand side must be an ndarray, or a scalar")); mp_raise_ValueError(translate("right hand side must be an ndarray, or a scalar"));
} else { } else {
ndarray_obj_t *values = NULL; ndarray_obj_t *values = NULL;
if(MP_OBJ_IS_INT(value)) { if(mp_obj_is_int(value)) {
values = create_new_ndarray(1, 1, self->array->typecode); values = create_new_ndarray(1, 1, self->array->typecode);
mp_binary_set_val_array(values->array->typecode, values->array->items, 0, value); mp_binary_set_val_array(values->array->typecode, values->array->items, 0, value);
} else if(mp_obj_is_float(value)) { } else if(mp_obj_is_float(value)) {
@ -595,7 +579,7 @@ mp_obj_t ndarray_iternext(mp_obj_t self_in) {
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(self->ndarray); ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(self->ndarray);
// TODO: in numpy, ndarrays are iterated with respect to the first axis. // TODO: in numpy, ndarrays are iterated with respect to the first axis.
size_t iter_end = 0; size_t iter_end = 0;
if(ndarray->m == 1) { if((ndarray->m == 1)) {
iter_end = ndarray->array->len; iter_end = ndarray->array->len;
} else { } else {
iter_end = ndarray->m; iter_end = ndarray->m;
@ -640,14 +624,22 @@ mp_obj_t ndarray_shape(mp_obj_t self_in) {
return mp_obj_new_tuple(2, tuple); return mp_obj_new_tuple(2, tuple);
} }
mp_obj_t ndarray_size(mp_obj_t self_in) { mp_obj_t ndarray_rawsize(mp_obj_t self_in) {
// returns a 5-tuple with the
//
// 0. number of rows
// 1. number of columns
// 2. length of the storage (should be equal to the product of 1. and 2.)
// 3. length of the data storage in bytes
// 4. datum size in bytes
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
return mp_obj_new_int(self->array->len); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
} tuple->items[0] = MP_OBJ_NEW_SMALL_INT(self->m);
tuple->items[1] = MP_OBJ_NEW_SMALL_INT(self->n);
mp_obj_t ndarray_itemsize(mp_obj_t self_in) { tuple->items[2] = MP_OBJ_NEW_SMALL_INT(self->array->len);
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); tuple->items[3] = MP_OBJ_NEW_SMALL_INT(self->bytes);
return MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->array->typecode, NULL)); tuple->items[4] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->array->typecode, NULL));
return tuple;
} }
mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
@ -696,7 +688,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
// TODO: implement in-place operators // TODO: implement in-place operators
mp_obj_t RHS = MP_OBJ_NULL; mp_obj_t RHS = MP_OBJ_NULL;
bool rhs_is_scalar = true; bool rhs_is_scalar = true;
if(MP_OBJ_IS_INT(rhs)) { if(mp_obj_is_int(rhs)) {
int32_t ivalue = mp_obj_get_int(rhs); int32_t ivalue = mp_obj_get_int(rhs);
if((ivalue > 0) && (ivalue < 256)) { if((ivalue > 0) && (ivalue < 256)) {
CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue); CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue);
@ -717,7 +709,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
rhs_is_scalar = false; rhs_is_scalar = false;
} }
//else //else
if(MP_OBJ_IS_TYPE(lhs, &ulab_ndarray_type) && MP_OBJ_IS_TYPE(RHS, &ulab_ndarray_type)) { if(mp_obj_is_type(lhs, &ulab_ndarray_type) && mp_obj_is_type(RHS, &ulab_ndarray_type)) {
// next, the ndarray stuff // next, the ndarray stuff
ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs); ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs);
ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS); ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS);
@ -890,12 +882,12 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
return ndarray_copy(self_in); return ndarray_copy(self_in);
} }
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in)); ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
if(self->array->typecode == NDARRAY_INT8) { if((self->array->typecode == NDARRAY_INT8)) {
int8_t *array = (int8_t *)ndarray->array->items; int8_t *array = (int8_t *)ndarray->array->items;
for(size_t i=0; i < self->array->len; i++) { for(size_t i=0; i < self->array->len; i++) {
if(array[i] < 0) array[i] = -array[i]; if(array[i] < 0) array[i] = -array[i];
} }
} else if(self->array->typecode == NDARRAY_INT16) { } else if((self->array->typecode == NDARRAY_INT16)) {
int16_t *array = (int16_t *)ndarray->array->items; int16_t *array = (int16_t *)ndarray->array->items;
for(size_t i=0; i < self->array->len; i++) { for(size_t i=0; i < self->array->len; i++) {
if(array[i] < 0) array[i] = -array[i]; if(array[i] < 0) array[i] = -array[i];
@ -912,64 +904,6 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
} }
} }
mp_obj_t ndarray_transpose(mp_obj_t self_in) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
// the size of a single item in the array
uint8_t _sizeof = mp_binary_get_size('@', self->array->typecode, NULL);
// NOTE:
// if the matrices are square, we can simply swap items, but
// generic matrices can't be transposed in place, so we have to
// declare a temporary variable
// NOTE:
// In the old matrix, the coordinate (m, n) is m*self->n + n
// We have to assign this to the coordinate (n, m) in the new
// matrix, i.e., to n*self->m + m (since the new matrix has self->m columns)
// one-dimensional arrays can be transposed by simply swapping the dimensions
if((self->m != 1) && (self->n != 1)) {
uint8_t *c = (uint8_t *)self->array->items;
// self->bytes is the size of the bytearray, irrespective of the typecode
uint8_t *tmp = m_new(uint8_t, self->bytes);
for(size_t m=0; m < self->m; m++) {
for(size_t n=0; n < self->n; n++) {
memcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof);
}
}
memcpy(self->array->items, tmp, self->bytes);
m_del(uint8_t, tmp, self->bytes);
}
SWAP(size_t, self->m, self->n);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_transpose_obj, ndarray_transpose);
mp_obj_t ndarray_reshape(mp_obj_t self_in, mp_obj_t shape) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
if(!MP_OBJ_IS_TYPE(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) {
mp_raise_ValueError(translate("shape must be a 2-tuple"));
}
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(shape, &iter_buf);
uint16_t m, n;
item = mp_iternext(iterable);
m = mp_obj_get_int(item);
item = mp_iternext(iterable);
n = mp_obj_get_int(item);
if(m*n != self->m*self->n) {
// TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)"
mp_raise_ValueError(translate("cannot reshape array (incompatible input/output shape)"));
}
self->m = m;
self->n = n;
return MP_OBJ_FROM_PTR(self);
}
MP_DEFINE_CONST_FUN_OBJ_2(ndarray_reshape_obj, ndarray_reshape);
mp_int_t ndarray_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) { mp_int_t ndarray_get_buffer(mp_obj_t self_in, mp_buffer_info_t *bufinfo, mp_uint_t flags) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
// buffer_p.get_buffer() returns zero for success, while mp_get_buffer returns true for success // buffer_p.get_buffer() returns zero for success, while mp_get_buffer returns true for success

View file

@ -29,8 +29,6 @@
#define translate(x) x #define translate(x) x
#endif #endif
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
extern const mp_obj_type_t ulab_ndarray_type; extern const mp_obj_type_t ulab_ndarray_type;
enum NDARRAY_TYPE { enum NDARRAY_TYPE {
@ -60,30 +58,16 @@ void ndarray_assign_elements(mp_obj_array_t *, mp_obj_t , uint8_t , size_t *);
ndarray_obj_t *create_new_ndarray(size_t , size_t , uint8_t ); ndarray_obj_t *create_new_ndarray(size_t , size_t , uint8_t );
mp_obj_t ndarray_copy(mp_obj_t ); mp_obj_t ndarray_copy(mp_obj_t );
#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 *); 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_subscr(mp_obj_t , mp_obj_t , mp_obj_t );
mp_obj_t ndarray_getiter(mp_obj_t , mp_obj_iter_buf_t *); mp_obj_t ndarray_getiter(mp_obj_t , mp_obj_iter_buf_t *);
mp_obj_t ndarray_binary_op(mp_binary_op_t , mp_obj_t , mp_obj_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 ); mp_obj_t ndarray_unary_op(mp_unary_op_t , mp_obj_t );
mp_obj_t ndarray_shape(mp_obj_t ); mp_obj_t ndarray_shape(mp_obj_t );
mp_obj_t ndarray_size(mp_obj_t ); mp_obj_t ndarray_rawsize(mp_obj_t );
mp_obj_t ndarray_itemsize(mp_obj_t );
mp_obj_t ndarray_flatten(size_t , const mp_obj_t *, mp_map_t *); mp_obj_t ndarray_flatten(size_t , const mp_obj_t *, mp_map_t *);
mp_obj_t ndarray_reshape(mp_obj_t , mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_2(ndarray_reshape_obj);
mp_obj_t ndarray_transpose(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(ndarray_transpose_obj);
mp_int_t ndarray_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags); mp_int_t ndarray_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t flags);
//void ndarray_attributes(mp_obj_t , qstr , mp_obj_t *);
#define CREATE_SINGLE_ITEM(outarray, type, typecode, value) do {\ #define CREATE_SINGLE_ITEM(outarray, type, typecode, value) do {\
ndarray_obj_t *tmp = create_new_ndarray(1, 1, (typecode));\ ndarray_obj_t *tmp = create_new_ndarray(1, 1, (typecode));\

View file

@ -1,62 +0,0 @@
/*
* 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 "ndarray.h"
typedef struct _mp_obj_property_t {
mp_obj_base_t base;
mp_obj_t proxy[3]; // getter, setter, deleter
} mp_obj_property_t;
/* v923z: it is not at all clear to me, why this must be declared; it should already be in obj.h */
typedef struct _mp_obj_none_t {
mp_obj_base_t base;
} mp_obj_none_t;
const mp_obj_type_t mp_type_NoneType;
const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}};
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_shape_obj, ndarray_shape);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_size_obj, ndarray_size);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_itemsize_obj, ndarray_itemsize);
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten);
STATIC const mp_obj_property_t ndarray_shape_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_shape_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
STATIC const mp_obj_property_t ndarray_size_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_size_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
STATIC const mp_obj_property_t ndarray_itemsize_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_itemsize_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
};
#endif

View file

@ -19,8 +19,6 @@
#include "py/misc.h" #include "py/misc.h"
#include "numerical.h" #include "numerical.h"
#if ULAB_NUMERICAL_MODULE
enum NUMERICAL_FUNCTION_TYPE { enum NUMERICAL_FUNCTION_TYPE {
NUMERICAL_MIN, NUMERICAL_MIN,
NUMERICAL_MAX, NUMERICAL_MAX,
@ -31,13 +29,14 @@ enum NUMERICAL_FUNCTION_TYPE {
NUMERICAL_STD, NUMERICAL_STD,
}; };
#if ULAB_NUMERICAL_LINSPACE
mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_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_ROM_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_ROM_NONE } },
{ MP_QSTR_num, MP_ARG_INT, {.u_int = 50} }, { 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_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_TRUE} },
{ MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_false} }, { MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_FALSE} },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} }, { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
}; };
@ -81,6 +80,7 @@ mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace);
#endif
void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, size_t *N, void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, size_t *N,
size_t *increment, size_t *len, size_t *start_inc) { size_t *increment, size_t *len, size_t *start_inc) {
@ -255,10 +255,11 @@ mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis,
return MP_OBJ_FROM_PTR(results); return MP_OBJ_FROM_PTR(results);
} }
STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) { STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE} } ,
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -343,8 +344,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } } ,
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
{ MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} }, { MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
}; };
@ -371,11 +372,12 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
#if ULAB_NUMERICAL_ROLL
mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -452,17 +454,19 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
#endif
#if ULAB_NUMERICAL_FLIP
mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("flip argument must be an ndarray")); mp_raise_TypeError(translate("flip argument must be an ndarray"));
} }
if((args[1].u_obj != mp_const_none) && if((args[1].u_obj != mp_const_none) &&
@ -501,10 +505,12 @@ mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
#endif
#if ULAB_NUMERICAL_DIFF
mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } }, { MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } },
}; };
@ -512,7 +518,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("diff argument must be an ndarray")); mp_raise_TypeError(translate("diff argument must be an ndarray"));
} }
@ -571,9 +577,11 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
#endif
#if ULAB_NUMERICAL_SORT
mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) { mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) { if(!mp_obj_is_type(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("sort argument must be an ndarray")); mp_raise_TypeError(translate("sort argument must be an ndarray"));
} }
@ -631,7 +639,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
// numpy function // numpy function
mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
}; };
@ -646,7 +654,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
// method of an ndarray // method of an ndarray
mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
}; };
@ -657,15 +665,17 @@ mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace);
#endif
#if ULAB_NUMERICAL_ARGSORT
mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = { 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_ROM_NONE } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } }, { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
}; };
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)]; mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) { if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("argsort argument must be an ndarray")); mp_raise_TypeError(translate("argsort argument must be an ndarray"));
} }
@ -729,30 +739,4 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
} }
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort); MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_numerical_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_linspace), (mp_obj_t)&numerical_linspace_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_numerical_globals, ulab_numerical_globals_table);
mp_obj_module_t ulab_numerical_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_numerical_globals,
};
#endif
#endif #endif

View file

@ -15,15 +15,78 @@
#include "ulab.h" #include "ulab.h"
#include "ndarray.h" #include "ndarray.h"
#if ULAB_NUMERICAL_MODULE #if ULAB_NUMERICAL_LINSPACE
mp_obj_t numerical_linspace(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_linspace_obj);
#endif
#if ULAB_NUMERICAL_SUM
mp_obj_t numerical_sum(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sum_obj);
#endif
#if ULAB_NUMERICAL_MEAN
mp_obj_t numerical_mean(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_mean_obj);
#endif
#if ULAB_NUMERICAL_STD
mp_obj_t numerical_std(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_std_obj);
#endif
#if ULAB_NUMERICAL_MIN
mp_obj_t numerical_min(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_min_obj);
#endif
#if ULAB_NUMERICAL_MAX
mp_obj_t numerical_max(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_max_obj);
#endif
#if ULAB_NUMERICAL_ARGMIN
mp_obj_t numerical_argmin(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmin_obj);
#endif
#if ULAB_NUMERICAL_ARGMAX
mp_obj_t numerical_argmax(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmax_obj);
#endif
#if ULAB_NUMERICAL_ROLL
mp_obj_t numerical_roll(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_roll_obj);
#endif
extern mp_obj_module_t ulab_numerical_module;
// TODO: implement minimum/maximum, and cumsum // TODO: implement minimum/maximum, and cumsum
//mp_obj_t numerical_minimum(mp_obj_t , mp_obj_t ); //mp_obj_t numerical_minimum(mp_obj_t , mp_obj_t );
//mp_obj_t numerical_maximum(mp_obj_t , mp_obj_t ); //mp_obj_t numerical_maximum(mp_obj_t , mp_obj_t );
//mp_obj_t numerical_cumsum(size_t , const mp_obj_t *, mp_map_t *); //mp_obj_t numerical_cumsum(size_t , const mp_obj_t *, mp_map_t *);
#if ULAB_NUMERICAL_FLIP
mp_obj_t numerical_flip(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_flip_obj);
#endif
#if ULAB_NUMERICAL_DIFF
mp_obj_t numerical_diff(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_diff_obj);
#endif
#if ULAB_NUMERICAL_SORT
mp_obj_t numerical_sort(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_obj);
mp_obj_t numerical_sort_inplace(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj);
mp_obj_t numerical_argsort(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argsort_obj);
#endif
#define RUN_ARGMIN(in, out, typein, typeout, len, start, increment, op, pos) do {\ #define RUN_ARGMIN(in, out, typein, typeout, len, start, increment, op, pos) do {\
typein *array = (typein *)(in)->array->items;\ typein *array = (typein *)(in)->array->items;\
typeout *outarray = (typeout *)(out)->array->items;\ typeout *outarray = (typeout *)(out)->array->items;\
@ -148,20 +211,4 @@ extern mp_obj_module_t ulab_numerical_module;
}\ }\
} while(0) } while(0)
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_linspace_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_min_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_max_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmin_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmax_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sum_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_mean_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_std_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_roll_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_flip_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_diff_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argsort_obj);
#endif
#endif #endif

View file

@ -16,32 +16,34 @@
#include "linalg.h" #include "linalg.h"
#include "poly.h" #include "poly.h"
#if ULAB_POLY_MODULE #if ULAB_POLY_POLYVAL || ULAB_POLY_POLYFIT
bool object_is_nditerable(mp_obj_t o_in) { bool object_is_nditerable(mp_obj_t o_in) {
if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type) || if(mp_obj_is_type(o_in, &ulab_ndarray_type) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || mp_obj_is_type(o_in, &mp_type_tuple) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_list) || mp_obj_is_type(o_in, &mp_type_list) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_range)) { mp_obj_is_type(o_in, &mp_type_range)) {
return true; return true;
} }
return false; return false;
} }
size_t get_nditerable_len(mp_obj_t o_in) { size_t get_nditerable_len(mp_obj_t o_in) {
if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { if(mp_obj_is_type(o_in, &ulab_ndarray_type)) {
ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in); ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in);
return in->array->len; return in->array->len;
} else { } else {
return (size_t)mp_obj_get_int(mp_obj_len_maybe(o_in)); return (size_t)mp_obj_get_int(mp_obj_len_maybe(o_in));
} }
} }
#endif
#if ULAB_POLY_POLYVAL
mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) { mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
// TODO: return immediately, if o_p is not an iterable // TODO: return immediately, if o_p is not an iterable
// TODO: there is a bug here: matrices won't work, // TODO: there is a bug here: matrices won't work,
// because there is a single iteration loop // because there is a single iteration loop
size_t m, n; size_t m, n;
if(MP_OBJ_IS_TYPE(o_x, &ulab_ndarray_type)) { if(mp_obj_is_type(o_x, &ulab_ndarray_type)) {
ndarray_obj_t *ndx = MP_OBJ_TO_PTR(o_x); ndarray_obj_t *ndx = MP_OBJ_TO_PTR(o_x);
m = ndx->m; m = ndx->m;
n = ndx->n; n = ndx->n;
@ -84,7 +86,9 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
} }
MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval); MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval);
#endif
#if ULAB_POLY_POLYFIT
mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) { mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
if((n_args != 2) && (n_args != 3)) { if((n_args != 2) && (n_args != 3)) {
mp_raise_ValueError(translate("number of arguments must be 2, or 3")); mp_raise_ValueError(translate("number of arguments must be 2, or 3"));
@ -92,8 +96,8 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
if(!object_is_nditerable(args[0])) { if(!object_is_nditerable(args[0])) {
mp_raise_ValueError(translate("input data must be an iterable")); mp_raise_ValueError(translate("input data must be an iterable"));
} }
uint16_t lenx = 0, leny = 0; uint16_t lenx, leny;
uint8_t deg = 0; uint8_t deg;
mp_float_t *x, *XT, *y, *prod; mp_float_t *x, *XT, *y, *prod;
if(n_args == 2) { // only the y values are supplied if(n_args == 2) { // only the y values are supplied
@ -196,20 +200,4 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
} }
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit); MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_poly_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_poly) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_poly_globals, ulab_poly_globals_table);
mp_obj_module_t ulab_poly_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_poly_globals,
};
#endif
#endif #endif

View file

@ -14,12 +14,14 @@
#include "ulab.h" #include "ulab.h"
#if ULAB_POLY_MODULE #if ULAB_POLY_POLYVAL
mp_obj_t poly_polyval(mp_obj_t , mp_obj_t );
extern mp_obj_module_t ulab_poly_module;
MP_DECLARE_CONST_FUN_OBJ_2(poly_polyval_obj); MP_DECLARE_CONST_FUN_OBJ_2(poly_polyval_obj);
#endif
#if ULAB_POLY_POLYFIT
mp_obj_t poly_polyfit(size_t , const mp_obj_t *);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj); MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj);
#endif
#endif #endif
#endif

View file

@ -20,25 +20,30 @@
#include "ulab.h" #include "ulab.h"
#include "ndarray.h" #include "ndarray.h"
#include "ndarray_properties.h"
#include "linalg.h" #include "linalg.h"
#include "vectorise.h" #include "vectorise.h"
#include "poly.h" #include "poly.h"
#include "fft.h" #include "fft.h"
#include "filter.h" #include "filter.h"
#include "numerical.h" #include "numerical.h"
#include "extras.h"
STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.34.0"); STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.31.0");
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_rawsize_obj, ndarray_rawsize);
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten);
STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = { STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) },
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ndarray_reshape_obj) },
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ndarray_transpose_obj) },
{ MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) }, { MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) },
{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) }, { MP_ROM_QSTR(MP_QSTR_rawsize), MP_ROM_PTR(&ndarray_rawsize_obj) },
{ MP_ROM_QSTR(MP_QSTR_itemsize), MP_ROM_PTR(&ndarray_itemsize_obj) }, { MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) },
// { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) }, #if ULAB_LINALG_TRANSPOSE
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&linalg_transpose_obj) },
#endif
#if ULAB_LINALG_RESHAPE
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&linalg_reshape_obj) },
#endif
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
}; };
STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table); STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
@ -56,31 +61,159 @@ const mp_obj_type_t ulab_ndarray_type = {
.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict, .locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,
}; };
#if !CIRCUITPY
STATIC const mp_map_elem_t ulab_globals_table[] = { STATIC const mp_map_elem_t ulab_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) }, { 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) }, { MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&ulab_ndarray_type }, { MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&ulab_ndarray_type },
#if ULAB_LINALG_MODULE #if ULAB_LINALG_SIZE
{ MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) }, { MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
#endif #endif
#if ULAB_VECTORISE_MODULE #if ULAB_LINALG_INV
{ MP_ROM_QSTR(MP_QSTR_vector), MP_ROM_PTR(&ulab_vectorise_module) }, { MP_OBJ_NEW_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
#endif #endif
#if ULAB_NUMERICAL_MODULE #if ULAB_LINALG_DOT
{ MP_ROM_QSTR(MP_QSTR_numerical), MP_ROM_PTR(&ulab_numerical_module) }, { MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
#endif #endif
#if ULAB_POLY_MODULE #if ULAB_LINALG_ZEROS
{ MP_ROM_QSTR(MP_QSTR_poly), MP_ROM_PTR(&ulab_poly_module) }, { MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&linalg_zeros_obj },
#endif #endif
#if ULAB_FFT_MODULE #if ULAB_LINALG_ONES
{ MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&ulab_fft_module) }, { MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&linalg_ones_obj },
#endif #endif
#if ULAB_FILTER_MODULE #if ULAB_LINALG_EYE
{ MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&ulab_filter_module) }, { MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&linalg_eye_obj },
#endif #endif
#if ULAB_EXTRAS_MODULE #if ULAB_LINALG_DET
{ MP_ROM_QSTR(MP_QSTR_extras), MP_ROM_PTR(&ulab_extras_module) }, { MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
#endif
#if ULAB_LINALG_EIG
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
#endif
#if ULAB_VECTORISE_ACOS
{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj },
#endif
#if ULAB_VECTORISE_ACOSH
{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj },
#endif
#if ULAB_VECTORISE_ASIN
{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj },
#endif
#if ULAB_VECTORISE_ASINH
{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj },
#endif
#if ULAB_VECTORISE_ATAN
{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj },
#endif
#if ULAB_VECTORISE_ATANH
{ MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj },
#endif
#if ULAB_VECTORISE_CEIL
{ MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj },
#endif
#if ULAB_VECTORISE_COS
{ MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj },
#endif
#if ULAB_VECTORISE_ERF
{ MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj },
#endif
#if ULAB_VECTORISE_ERFC
{ MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj },
#endif
#if ULAB_VECTORISE_EXP
{ MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj },
#endif
#if ULAB_VECTORISE_EXPM1
{ MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj },
#endif
#if ULAB_VECTORISE_FLOOR
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj },
#endif
#if ULAB_VECTORISE_GAMMA
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj },
#endif
#if ULAB_VECTORISE_LGAMMA
{ MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&vectorise_lgamma_obj },
#endif
#if ULAB_VECTORISE_LOG
{ MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj },
#endif
#if ULAB_VECTORISE_LOG10
{ MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj },
#endif
#if ULAB_VECTORISE_LOG2
{ MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj },
#endif
#if ULAB_VECTORISE_SIN
{ MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj },
#endif
#if ULAB_VECTORISE_SINH
{ MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj },
#endif
#if ULAB_VECTORISE_SQRT
{ MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj },
#endif
#if ULAB_VECTORISE_TAN
{ MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj },
#endif
#if ULAB_VECTORISE_TANH
{ MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj },
#endif
#if ULAB_NUMERICAL_LINSPACE
{ MP_OBJ_NEW_QSTR(MP_QSTR_linspace), (mp_obj_t)&numerical_linspace_obj },
#endif
#if ULAB_NUMERICAL_SUM
{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj },
#endif
#if ULAB_NUMERICAL_MEAN
{ MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj },
#endif
#if ULAB_NUMERICAL_STD
{ MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj },
#endif
#if ULAB_NUMERICAL_MIN
{ MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj },
#endif
#if ULAB_NUMERICAL_MAX
{ MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj },
#endif
#if ULAB_NUMERICAL_ARGMIN
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj },
#endif
#if ULAB_NUMERICAL_ARGMAX
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj },
#endif
#if ULAB_NUMERICAL_ROLL
{ MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj },
#endif
#if ULAB_NUMERICAL_FLIP
{ MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj },
#endif
#if ULAB_NUMERICAL_DIFF
{ MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj },
#endif
#if ULAB_NUMERICAL_SORT
{ MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj },
#endif
#if ULAB_NUMERICAL_ARGSORT
{ MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj },
#endif
#if ULAB_POLY_POLYVAL
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj },
#endif
#if ULAB_POLY_POLYFIT
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj },
#endif
#if ULAB_FFT_FFT
{ MP_OBJ_NEW_QSTR(MP_QSTR_fft), (mp_obj_t)&fft_fft_obj },
#endif
#if ULAB_FFT_IFFT
{ MP_OBJ_NEW_QSTR(MP_QSTR_ifft), (mp_obj_t)&fft_ifft_obj },
#endif
#if ULAB_FFT_SPECTRUM
{ MP_OBJ_NEW_QSTR(MP_QSTR_spectrum), (mp_obj_t)&fft_spectrum_obj },
#endif
#if ULAB_FILTER_CONVOLVE
{ MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj },
#endif #endif
// class constants // class constants
{ MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) }, { MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) },
@ -95,10 +228,9 @@ STATIC MP_DEFINE_CONST_DICT (
ulab_globals_table ulab_globals_table
); );
mp_obj_module_t ulab_user_cmodule = { const mp_obj_module_t ulab_user_cmodule = {
.base = { &mp_type_module }, .base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_globals, .globals = (mp_obj_dict_t*)&mp_module_ulab_globals,
}; };
MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED); MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED);
#endif

View file

@ -13,24 +13,67 @@
#define __ULAB__ #define __ULAB__
// vectorise (all functions) takes approx. 3 kB of flash space // vectorise (all functions) takes approx. 3 kB of flash space
#define ULAB_VECTORISE_MODULE (1) #define ULAB_VECTORISE_ACOS (1)
#define ULAB_VECTORISE_ACOSH (1)
#define ULAB_VECTORISE_ASIN (1)
#define ULAB_VECTORISE_ASINH (1)
#define ULAB_VECTORISE_ATAN (1)
#define ULAB_VECTORISE_ATANH (1)
#define ULAB_VECTORISE_CEIL (1)
#define ULAB_VECTORISE_COS (1)
#define ULAB_VECTORISE_ERF (1)
#define ULAB_VECTORISE_ERFC (1)
#define ULAB_VECTORISE_EXP (1)
#define ULAB_VECTORISE_EXPM1 (1)
#define ULAB_VECTORISE_FLOOR (1)
#define ULAB_VECTORISE_GAMMA (1)
#define ULAB_VECTORISE_LGAMMA (1)
#define ULAB_VECTORISE_LOG (1)
#define ULAB_VECTORISE_LOG10 (1)
#define ULAB_VECTORISE_LOG2 (1)
#define ULAB_VECTORISE_SIN (1)
#define ULAB_VECTORISE_SINH (1)
#define ULAB_VECTORISE_SQRT (1)
#define ULAB_VECTORISE_TAN (1)
#define ULAB_VECTORISE_TANH (1)
// linalg adds around 6 kB // linalg adds around 6 kB
#define ULAB_LINALG_MODULE (1) #define ULAB_LINALG_TRANSPOSE (1)
#define ULAB_LINALG_RESHAPE (1)
#define ULAB_LINALG_SIZE (1)
#define ULAB_LINALG_INV (1)
#define ULAB_LINALG_DOT (1)
#define ULAB_LINALG_ZEROS (1)
#define ULAB_LINALG_ONES (1)
#define ULAB_LINALG_EYE (1)
#define ULAB_LINALG_DET (1)
#define ULAB_LINALG_EIG (1)
// poly is approx. 2.5 kB // poly is approx. 2.5 kB
#define ULAB_POLY_MODULE (1) #define ULAB_POLY_POLYVAL (1)
#define ULAB_POLY_POLYFIT (1)
// numerical is about 12 kB //
#define ULAB_NUMERICAL_MODULE (1) #define ULAB_NUMERICAL_ARGSORT (1)
#define ULAB_NUMERICAL_LINSPACE (1)
#define ULAB_NUMERICAL_SUM (1)
#define ULAB_NUMERICAL_MEAN (1)
#define ULAB_NUMERICAL_STD (1)
#define ULAB_NUMERICAL_MIN (1)
#define ULAB_NUMERICAL_MAX (1)
#define ULAB_NUMERICAL_ARGMIN (1)
#define ULAB_NUMERICAL_ARGMAX (1)
#define ULAB_NUMERICAL_ROLL (1)
#define ULAB_NUMERICAL_FLIP (1)
#define ULAB_NUMERICAL_DIFF (1)
#define ULAB_NUMERICAL_SORT (1)
// FFT costs about 2 kB of flash space // FFT costs about 2 kB of flash space
#define ULAB_FFT_MODULE (1) #define ULAB_FFT_FFT (1)
#define ULAB_FFT_IFFT (1)
#define ULAB_FFT_SPECTRUM (1)
// the filter module takes about 1 kB of flash space // the filter module takes about 0.8 kB of flash space
#define ULAB_FILTER_MODULE (1) #define ULAB_FILTER_CONVOLVE (1)
// user-defined modules
#define ULAB_EXTRAS_MODULE (0)
#endif #endif

View file

@ -22,14 +22,13 @@
#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846) #define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
#endif #endif
#if ULAB_VECTORISE_MODULE
mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) { 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 // Return a single value, if o_in is not iterable
if(mp_obj_is_float(o_in) || MP_OBJ_IS_INT(o_in)) { if(mp_obj_is_float(o_in) || mp_obj_is_integer(o_in)) {
return mp_obj_new_float(f(mp_obj_get_float(o_in))); return mp_obj_new_float(f(mp_obj_get_float(o_in)));
} }
mp_float_t x; mp_float_t x;
if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { if(mp_obj_is_type(o_in, &ulab_ndarray_type)) {
ndarray_obj_t *source = MP_OBJ_TO_PTR(o_in); ndarray_obj_t *source = MP_OBJ_TO_PTR(o_in);
ndarray_obj_t *ndarray = create_new_ndarray(source->m, source->n, NDARRAY_FLOAT); ndarray_obj_t *ndarray = create_new_ndarray(source->m, source->n, NDARRAY_FLOAT);
mp_float_t *dataout = (mp_float_t *)ndarray->array->items; mp_float_t *dataout = (mp_float_t *)ndarray->array->items;
@ -45,8 +44,8 @@ mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) {
ITERATE_VECTOR(mp_float_t, source, dataout); ITERATE_VECTOR(mp_float_t, source, dataout);
} }
return MP_OBJ_FROM_PTR(ndarray); return MP_OBJ_FROM_PTR(ndarray);
} else if(MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(o_in, &mp_type_list) || } else if(mp_obj_is_type(o_in, &mp_type_tuple) || mp_obj_is_type(o_in, &mp_type_list) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_range)) { // i.e., the input is a generic iterable mp_obj_is_type(o_in, &mp_type_range)) { // i.e., the input is a generic iterable
mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in); mp_obj_array_t *o = MP_OBJ_TO_PTR(o_in);
ndarray_obj_t *out = create_new_ndarray(1, o->len, NDARRAY_FLOAT); ndarray_obj_t *out = create_new_ndarray(1, o->len, NDARRAY_FLOAT);
mp_float_t *dataout = (mp_float_t *)out->array->items; mp_float_t *dataout = (mp_float_t *)out->array->items;
@ -63,112 +62,117 @@ mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) {
} }
#if ULAB_VECTORISE_ACOS
MATH_FUN_1(acos, acos); MATH_FUN_1(acos, acos);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos);
#endif
#if ULAB_VECTORISE_ACOSH
MATH_FUN_1(acosh, acosh); MATH_FUN_1(acosh, acosh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh);
#endif
#if ULAB_VECTORISE_ASIN
MATH_FUN_1(asin, asin); MATH_FUN_1(asin, asin);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin);
#endif
#if ULAB_VECTORISE_ASINH
MATH_FUN_1(asinh, asinh); MATH_FUN_1(asinh, asinh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh);
#endif
#if ULAB_VECTORISE_ATAN
MATH_FUN_1(atan, atan); MATH_FUN_1(atan, atan);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan);
#endif
#if ULAB_VECTORISE_ATANH
MATH_FUN_1(atanh, atanh); MATH_FUN_1(atanh, atanh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh);
#endif
#if ULAB_VECTORISE_CEIL
MATH_FUN_1(ceil, ceil); MATH_FUN_1(ceil, ceil);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil);
#endif
#if ULAB_VECTORISE_COS
MATH_FUN_1(cos, cos); MATH_FUN_1(cos, cos);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos);
#endif
MATH_FUN_1(cosh, cosh); #if ULAB_VECTORISE_ERF
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cosh_obj, vectorise_cosh);
MATH_FUN_1(erf, erf); MATH_FUN_1(erf, erf);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf);
#endif
#if ULAB_VECTORISE_ERFC
MATH_FUN_1(erfc, erfc); MATH_FUN_1(erfc, erfc);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc);
#endif
#if ULAB_VECTORISE_EXP
MATH_FUN_1(exp, exp); MATH_FUN_1(exp, exp);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp);
#endif
#if ULAB_VECTORISE_EXPM1
MATH_FUN_1(expm1, expm1); MATH_FUN_1(expm1, expm1);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1);
#endif
#if ULAB_VECTORISE_FLOOR
MATH_FUN_1(floor, floor); MATH_FUN_1(floor, floor);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor);
#endif
#if ULAB_VECTORISE_GAMMA
MATH_FUN_1(gamma, tgamma); MATH_FUN_1(gamma, tgamma);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma);
#endif
#if ULAB_VECTORISE_LGAMMA
MATH_FUN_1(lgamma, lgamma); MATH_FUN_1(lgamma, lgamma);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma);
#endif
#if ULAB_VECTORISE_LOG
MATH_FUN_1(log, log); MATH_FUN_1(log, log);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log);
#endif
#if ULAB_VECTORISE_LOG10
MATH_FUN_1(log10, log10); MATH_FUN_1(log10, log10);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10);
#endif
#if ULAB_VECTORISE_LOG2
MATH_FUN_1(log2, log2); MATH_FUN_1(log2, log2);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2);
#endif
#if ULAB_VECTORISE_SIN
MATH_FUN_1(sin, sin); MATH_FUN_1(sin, sin);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin);
#endif
#if ULAB_VECTORISE_SINH
MATH_FUN_1(sinh, sinh); MATH_FUN_1(sinh, sinh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh);
#endif
#if ULAB_VECTORISE_SQRT
MATH_FUN_1(sqrt, sqrt); MATH_FUN_1(sqrt, sqrt);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt);
#endif
#if ULAB_VECTORISE_TAN
MATH_FUN_1(tan, tan); MATH_FUN_1(tan, tan);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);
#endif
#if ULAB_VECTORISE_TANH
MATH_FUN_1(tanh, tanh); MATH_FUN_1(tanh, tanh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_vectorise_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_vector) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&vectorise_lgamma_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_vectorise_globals, ulab_vectorise_globals_table);
mp_obj_module_t ulab_vectorise_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_vectorise_globals,
};
#endif
#endif #endif

View file

@ -15,9 +15,121 @@
#include "ulab.h" #include "ulab.h"
#include "ndarray.h" #include "ndarray.h"
#if ULAB_VECTORISE_MODULE
mp_obj_module_t ulab_vectorise_module; #if ULAB_VECTORISE_ACOS
mp_obj_t vectorise_acos(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acos_obj);
#endif
#if ULAB_VECTORISE_ACOSH
mp_obj_t vectorise_acosh(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acosh_obj);
#endif
#if ULAB_VECTORISE_ASIN
mp_obj_t vectorise_asin(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asin_obj);
#endif
#if ULAB_VECTORISE_ASINH
mp_obj_t vectorise_asinh(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asinh_obj);
#endif
#if ULAB_VECTORISE_ATANH
mp_obj_t vectorise_atan(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atan_obj);
#endif
#if ULAB_VECTORISE_ATANH
mp_obj_t vectorise_atanh(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atanh_obj);
#endif
#if ULAB_VECTORISE_CEIL
mp_obj_t vectorise_ceil(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_ceil_obj);
#endif
#if ULAB_VECTORISE_COS
mp_obj_t vectorise_cos(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_cos_obj);
#endif
#if ULAB_VECTORISE_ERF
mp_obj_t vectorise_erf(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erf_obj);
#endif
#if ULAB_VECTORISE_ERFC
mp_obj_t vectorise_erfc(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erfc_obj);
#endif
#if ULAB_VECTORISE_EXP
mp_obj_t vectorise_exp(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_exp_obj);
#endif
#if ULAB_VECTORISE_EXPM1
mp_obj_t vectorise_expm1(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_expm1_obj);
#endif
#if ULAB_VECTORISE_FLOOR
mp_obj_t vectorise_floor(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_floor_obj);
#endif
#if ULAB_VECTORISE_GAMMA
mp_obj_t vectorise_gamma(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_gamma_obj);
#endif
#if ULAB_VECTORISE_LGAMMA
mp_obj_t vectorise_lgamma(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_lgamma_obj);
#endif
#if ULAB_VECTORISE_LOG
mp_obj_t vectorise_log(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log_obj);
#endif
#if ULAB_VECTORISE_LOG10
mp_obj_t vectorise_log10(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log10_obj);
#endif
#if ULAB_VECTORISE_LOG2
mp_obj_t vectorise_log2(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log2_obj);
#endif
#if ULAB_VECTORISE_SIN
mp_obj_t vectorise_sin(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sin_obj);
#endif
#if ULAB_VECTORISE_SINH
mp_obj_t vectorise_sinh(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sinh_obj);
#endif
#if ULAB_VECTORISE_SQRT
mp_obj_t vectorise_sqrt(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sqrt_obj);
#endif
#if ULAB_VECTORISE_TAN
mp_obj_t vectorise_tan(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tan_obj);
#endif
#if ULAB_VECTORISE_TANH
mp_obj_t vectorise_tanh(mp_obj_t );
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tanh_obj);
#endif
#define ITERATE_VECTOR(type, source, out) do {\ #define ITERATE_VECTOR(type, source, out) do {\
type *input = (type *)(source)->array->items;\ type *input = (type *)(source)->array->items;\
@ -29,7 +141,6 @@ mp_obj_module_t ulab_vectorise_module;
#define MATH_FUN_1(py_name, c_name) \ #define MATH_FUN_1(py_name, c_name) \
mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \ mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \
return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \ return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
} }
#endif #endif
#endif

View file

@ -22,7 +22,7 @@ copyright = '2019, Zoltán Vörös'
author = 'Zoltán Vörös' author = 'Zoltán Vörös'
# The full version, including alpha/beta/rc tags # The full version, including alpha/beta/rc tags
release = '0.32' release = '0.31'
# -- General configuration --------------------------------------------------- # -- General configuration ---------------------------------------------------

View file

@ -1,10 +1,10 @@
Introduction Introduction
============ ============
In the `last In
chapter <https://micropython-usermod.readthedocs.io/en/latest/usermods_15.html>`__ https://micropython-usermod.readthedocs.io/en/latest/usermods_14.html, I
of the usermod documentation, I mentioned that I have another story, for mentioned that I have another story, for another day. The day has come,
another day. The day has come, so here is my story. so here is my story.
Enter ulab Enter ulab
---------- ----------
@ -68,11 +68,9 @@ The main points of ``ulab`` are
- polynomial fits to numerical data - polynomial fits to numerical data
- fast Fourier transforms - fast Fourier transforms
At the time of writing this manual (for version 0.32), the library adds At the time of writing this manual (for version 0.26), the library adds
approximately 30 kB of extra compiled code to the micropython approximately 30 kB of extra compiled code to the micropython
(pyboard.v.11) firmware. However, if you are tight with flash space, you (pyboard.v.11) firmware.
can easily shave off a couple of kB. See the section on `customising
ulab <#Custom_builds>`__.
Resources and legal matters Resources and legal matters
--------------------------- ---------------------------
@ -145,35 +143,6 @@ can always be queried as
If you find a bug, please, include this number in your report! If you find a bug, please, include this number in your report!
Customising ``ulab``
--------------------
``ulab`` implements a great number of functions, and it is quite
possible that you do not need all of them in a particular application.
If you want to save some flash space, you can easily exclude arbitrary
functions from the firmware. The
`https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h <ulab.h>`__
header file contains a pre-processor flag for all functions in ``ulab``.
The default setting is 1 for each of them, but if you change that to 0,
the corresponding function will not be part of the compiled firmware.
The first couple of lines of the file look like this
.. code:: c
// vectorise (all functions) takes approx. 3 kB of flash space
#define ULAB_VECTORISE_ACOS (1)
#define ULAB_VECTORISE_ACOSH (1)
#define ULAB_VECTORISE_ASIN (1)
#define ULAB_VECTORISE_ASINH (1)
#define ULAB_VECTORISE_ATAN (1)
#define ULAB_VECTORISE_ATANH (1)
In order to simplify navigation in the file, each flag begins with
``ULAB_``, continues with the sub-module, where the function itself is
implemented, and ends with the functions name. Each section displays a
hint as to how much space you can save by un-setting the flag.
Basic ndarray operations Basic ndarray operations
------------------------ ------------------------
@ -197,6 +166,8 @@ Methods of ndarrays
`.reshape <#.reshape>`__ `.reshape <#.reshape>`__
`.rawsize\*\* <#.rawsize>`__
`.transpose <#.transpose>`__ `.transpose <#.transpose>`__
`.flatten\*\* <#.flatten>`__ `.flatten\*\* <#.flatten>`__
@ -424,8 +395,8 @@ Methods of ndarrays
.shape .shape
~~~~~~ ~~~~~~
The ``.shape`` method (property) returns a 2-tuple with the number of The ``.shape`` method returns a 2-tuple with the number of rows, and
rows, and columns. columns.
.. code:: .. code::
@ -435,11 +406,11 @@ rows, and columns.
a = np.array([1, 2, 3, 4], dtype=np.int8) a = np.array([1, 2, 3, 4], dtype=np.int8)
print("a:\n", a) print("a:\n", a)
print("shape of a:", a.shape) print("shape of a:", a.shape())
b= np.array([[1, 2], [3, 4]], dtype=np.int8) b= np.array([[1, 2], [3, 4]], dtype=np.int8)
print("\nb:\n", b) print("\nb:\n", b)
print("shape of b:", b.shape) print("shape of b:", b.shape())
.. parsed-literal:: .. parsed-literal::
@ -455,74 +426,6 @@ rows, and columns.
.size
~~~~~
The ``.size`` method (property) returns an integer with the number of
elements in the array.
.. code::
# code to be run in micropython
import ulab as np
a = np.array([1, 2, 3], dtype=np.int8)
print("a:\n", a)
print("size of a:", a.size)
b= np.array([[1, 2], [3, 4]], dtype=np.int8)
print("\nb:\n", b)
print("size of b:", b.size)
.. parsed-literal::
a:
array([1, 2, 3], dtype=int8)
size of a: 3
b:
array([[1, 2],
[3, 4]], dtype=int8)
size of b: 4
.itemsize
~~~~~~~~~
The ``.itemsize`` method (property) returns an integer with the siz
enumber of elements in the array.
.. code::
# code to be run in micropython
import ulab as np
a = np.array([1, 2, 3], dtype=np.int8)
print("a:\n", a)
print("itemsize of a:", a.itemsize)
b= np.array([[1, 2], [3, 4]], dtype=np.float)
print("\nb:\n", b)
print("itemsize of b:", b.itemsize)
.. parsed-literal::
a:
array([1, 2, 3], dtype=int8)
itemsize of a: 1
b:
array([[1.0, 2.0],
[3.0, 4.0]], dtype=float)
itemsize of b: 8
.reshape .reshape
~~~~~~~~ ~~~~~~~~
@ -559,6 +462,41 @@ consistent with the old, a ``ValueError`` exception will be raised.
.rawsize
~~~~~~~~
The ``rawsize`` method of the ``ndarray`` returns a 5-tuple with the
following data
1. number of rows
2. number of columns
3. length of the storage (should be equal to the product of 1. and 2.)
4. length of the data storage in bytes
5. datum size in bytes (1 for ``uint8``/``int8``, 2 for
``uint16``/``int16``, and 4, or 8 for ``floats``, see `ndarray, the
basic container <#ndarray,-the-basic-container>`__)
**WARNING:** ``rawsize`` is a ``ulab``-only method; it has no equivalent
in ``numpy``.
.. code::
# code to be run in micropython
import ulab as np
a = np.array([1, 2, 3, 4], dtype=np.float)
print("a: \t\t", a)
print("rawsize of a: \t", a.rawsize())
.. parsed-literal::
a: array([1.0, 2.0, 3.0, 4.0], dtype=float)
rawsize of a: (1, 4, 4, 16, 4)
.flatten .flatten
~~~~~~~~ ~~~~~~~~

View file

@ -1,40 +1,4 @@
Tue, 18 Feb 2020
version 0.34.0
split ulab into multiple modules
Sun, 16 Feb 2020
version 0.33.2
moved properties into ndarray_properties.h, implemented pointer arithmetic in fft.c to save some time
Fri, 14 Feb 2020
version 0.33.1
added the __name__attribute to all sub-modules
Thu, 13 Feb 2020
version 0.33.0
sub-modules are now proper sub-modules of ulab
Mon, 17 Feb 2020
version 0.32.1
temporary fix for issue #40
Tue, 11 Feb 2020
version 0.32.0
added itemsize, size and shape attributes to ndarrays, and removed rawsize
Mon, 10 Feb 2020 Mon, 10 Feb 2020
version 0.31.0 version 0.31.0

View file

@ -24,11 +24,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 14, "execution_count": 1,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-11T19:06:35.427133Z", "end_time": "2020-02-10T18:31:42.227494Z",
"start_time": "2020-02-11T19:06:35.418598Z" "start_time": "2020-02-10T18:31:42.222100Z"
} }
}, },
"outputs": [ "outputs": [
@ -66,7 +66,7 @@
"author = 'Zoltán Vörös'\n", "author = 'Zoltán Vörös'\n",
"\n", "\n",
"# The full version, including alpha/beta/rc tags\n", "# The full version, including alpha/beta/rc tags\n",
"release = '0.32'\n", "release = '0.31'\n",
"\n", "\n",
"\n", "\n",
"# -- General configuration ---------------------------------------------------\n", "# -- General configuration ---------------------------------------------------\n",
@ -120,11 +120,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 7,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-11T20:30:43.287360Z", "end_time": "2020-02-10T18:49:03.206016Z",
"start_time": "2020-02-11T20:30:40.308932Z" "start_time": "2020-02-10T18:49:00.047068Z"
} }
}, },
"outputs": [], "outputs": [],
@ -293,11 +293,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 2,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-16T14:53:49.098172Z", "end_time": "2020-02-10T18:34:14.611085Z",
"start_time": "2020-02-16T14:53:49.093201Z" "start_time": "2020-02-10T18:34:14.607299Z"
} }
}, },
"outputs": [], "outputs": [],
@ -311,11 +311,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 3,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-16T14:53:53.396267Z", "end_time": "2020-02-10T18:34:15.995782Z",
"start_time": "2020-02-16T14:53:53.375754Z" "start_time": "2020-02-10T18:34:15.975187Z"
} }
}, },
"outputs": [], "outputs": [],
@ -384,20 +384,13 @@
"ip.register_magics(PyboardMagic)" "ip.register_magics(PyboardMagic)"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## pyboard"
]
},
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 111, "execution_count": 520,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-16T18:36:59.172039Z", "end_time": "2019-10-20T06:48:01.610725Z",
"start_time": "2020-02-16T18:36:59.144651Z" "start_time": "2019-10-20T06:48:00.856261Z"
} }
}, },
"outputs": [], "outputs": [],
@ -409,11 +402,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 110, "execution_count": 501,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-16T17:34:35.250747Z", "end_time": "2019-10-19T13:36:42.010602Z",
"start_time": "2020-02-16T17:34:35.241871Z" "start_time": "2019-10-19T13:36:42.003900Z"
} }
}, },
"outputs": [], "outputs": [],
@ -485,7 +478,7 @@
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
"source": [ "source": [
"In the [last chapter](https://micropython-usermod.readthedocs.io/en/latest/usermods_15.html) of the usermod documentation, I mentioned that I have another story, for another day. The day has come, so here is my story.\n", "In https://micropython-usermod.readthedocs.io/en/latest/usermods_14.html, I mentioned that I have another story, for another day. The day has come, so here is my story.\n",
"\n", "\n",
"## Enter ulab\n", "## Enter ulab\n",
"\n", "\n",
@ -513,7 +506,7 @@
"- polynomial fits to numerical data\n", "- polynomial fits to numerical data\n",
"- fast Fourier transforms\n", "- fast Fourier transforms\n",
"\n", "\n",
"At the time of writing this manual (for version 0.32), the library adds approximately 30 kB of extra compiled code to the micropython (pyboard.v.11) firmware. However, if you are tight with flash space, you can easily shave off a couple of kB. See the section on [customising ulab](#Custom_builds).\n", "At the time of writing this manual (for version 0.26), the library adds approximately 30 kB of extra compiled code to the micropython (pyboard.v.11) firmware. \n",
"\n", "\n",
"## Resources and legal matters\n", "## Resources and legal matters\n",
"\n", "\n",
@ -576,42 +569,6 @@
"If you find a bug, please, include this number in your report!" "If you find a bug, please, include this number in your report!"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Customising `ulab`\n",
"\n",
"`ulab` implements a great number of functions, which are organised in sub-modules. E.g., functions related to Fourier transforms are located in the `ulab.fft` sub-module, so you would import `fft` as\n",
"\n",
"```python\n",
"import ulab\n",
"from ulab import fft\n",
"```\n",
"by which point you can get the FFT of your data by calling `fft.fft(...)`. \n",
"\n",
"The idea of such grouping of functions and methods is to provide a means for granularity: It is quite possible that you do not need all functions in a particular application. If you want to save some flash space, you can easily exclude arbitrary sub-modules from the firmware. The [https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h](ulab.h) header file contains a pre-processor flag for each sub-module. The default setting is 1 for each of them, but if you change that to 0, the corresponding sub-module will not be part of the compiled firmware. \n",
"\n",
"The first couple of lines of the file look like this\n",
"\n",
"```c\n",
"// vectorise (all functions) takes approx. 3 kB of flash space\n",
"#define ULAB_VECTORISE_MODULE (1)\n",
"\n",
"// linalg adds around 6 kB\n",
"#define ULAB_LINALG_MODULE (1)\n",
"\n",
"// poly is approx. 2.5 kB\n",
"#define ULAB_POLY_MODULE (1)\n",
"```\n",
"\n",
"In order to simplify navigation in the header, each flag begins with `ULAB_`, and continues with the name of the sub-module. This name is also the `.c` file, where the sub-module is implemented. So, e.g., the linear algebra routines can be found in `linalg.c`, and the corresponding compiler flag is `ULAB_LINALG_MODULE`. Each section displays a hint as to how much space you can save by un-setting the flag.\n",
"\n",
"At first, having to import everything in this way might appear to be overly complicated, but there is a very good reason behind all this: you can find out at the time of importing, whether a function is part of your `ulab` firmware, or not. The alternative, namely, that you do not have to import anything beyond `ulab`, could be catastrophic: you would learn only at run time that a particular function is not in the firmware, and that is most probably too late.\n",
"\n",
"The standard sub-modules, `vector`, `linalg`, `numerical`, `poly`, and `fft` are all `numpy`-compatible. User-defined functions that accept `ndarray`s as their argument should be implemented in the `extra` sub-module, or its sub-modules."
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
@ -637,6 +594,8 @@
"\n", "\n",
"[.reshape](#.reshape)\n", "[.reshape](#.reshape)\n",
"\n", "\n",
"[.rawsize<sup>**</sup>](#.rawsize)\n",
"\n",
"[.transpose](#.transpose)\n", "[.transpose](#.transpose)\n",
"\n", "\n",
"[.flatten<sup>**</sup>](#.flatten)\n", "[.flatten<sup>**</sup>](#.flatten)\n",
@ -712,13 +671,13 @@
"source": [ "source": [
"# ndarray, the basic container\n", "# ndarray, the basic container\n",
"\n", "\n",
"The `ndarray` is the underlying container of numerical data. It is derived from micropython's own `array` object, but has a great number of extra features starting with how it can be initialised, which operations can be done on it, and which functions can accept it as an argument. One important property of an `ndarray` is that it is also a proper `micropython` iterable.\n", "The `ndarray` is the underlying container of numerical data. It is derived from micropython's own `array` object, but has a great number of extra features starting with how it can be initialised, how operations can be done on it, and which functions can accept it as an argument.\n",
"\n", "\n",
"Since the `ndarray` is a binary container, it is also compact, meaning that it takes only a couple of bytes of extra RAM in addition to what is required for storing the numbers themselves. `ndarray`s are also type-aware, i.e., one can save RAM by specifying a data type, and using the smallest reasonable one. Five such types are defined, namely `uint8`, `int8`, which occupy a single byte of memory per datum, `uint16`, and `int16`, which occupy two bytes per datum, and `float`, which occupies four or eight bytes per datum. The precision/size of the `float` type depends on the definition of `mp_float_t`. Some platforms, e.g., the PYBD, implement `double`s, but some, e.g., the pyboard.v.11, don't. You can find out, what type of float your particular platform implements by looking at the output of the [.itemsize](#.itemsize) class property.\n", "Since the `ndarray` is a binary container, it is also compact, meaning that it takes only a couple of bytes of extra RAM in addition to what is required for storing the numbers themselves. `ndarray`s are also type-aware, i.e., one can save RAM by specifying a data type, and using the smallest reasonable one. Five such types are defined, namely `uint8`, `int8`, which occupy a single byte of memory per datum, `uint16`, and `int16`, which occupy two bytes per datum, and `float`, which occupies four or eight bytes per datum. The precision/size of the `float` type depends on the definition of `mp_float_t`. Some platforms, e.g., the PYBD, implement `double`s, but some, e.g., the pyboard.v.11, don't. You can find out, what type of float your particular platform implements by looking at the output of the [.rawsize](#.rawsize) class method.\n",
"\n", "\n",
"On the following pages, we will see how one can work with `ndarray`s. Those familiar with `numpy` should find that the nomenclature and naming conventions of `numpy` are adhered to as closely as possible. I will point out the few differences, where necessary.\n", "On the following pages, we will see how one can work with `ndarray`s. Those familiar with `numpy` should find that the nomenclature and naming conventions of `numpy` are adhered to as closely as possible. I will point out the few differences, where necessary.\n",
"\n", "\n",
"For the sake of comparison, in addition to the `ulab` code snippets, sometimes the equivalent `numpy` code is also presented. You can find out, where the snippet is supposed to run by looking at its first line, the header.\n", "For the sake of comparison, in addition to `ulab` code snippets, sometimes the equivalent `numpy` code is also presented. You can find out, where the snippet is supposed to run by looking at its first line, the header.\n",
"\n", "\n",
"Hint: you can easily port existing `numpy` code, if you `import ulab as np`." "Hint: you can easily port existing `numpy` code, if you `import ulab as np`."
] ]
@ -886,16 +845,16 @@
"source": [ "source": [
"### .shape\n", "### .shape\n",
"\n", "\n",
"The `.shape` method (property) returns a 2-tuple with the number of rows, and columns." "The `.shape` method returns a 2-tuple with the number of rows, and columns."
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 12, "execution_count": 283,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-11T19:01:40.377272Z", "end_time": "2019-10-16T15:30:33.810628Z",
"start_time": "2020-02-11T19:01:40.364448Z" "start_time": "2019-10-16T15:30:33.796088Z"
} }
}, },
"outputs": [ "outputs": [
@ -923,111 +882,11 @@
"\n", "\n",
"a = np.array([1, 2, 3, 4], dtype=np.int8)\n", "a = np.array([1, 2, 3, 4], dtype=np.int8)\n",
"print(\"a:\\n\", a)\n", "print(\"a:\\n\", a)\n",
"print(\"shape of a:\", a.shape)\n", "print(\"shape of a:\", a.shape())\n",
"\n", "\n",
"b= np.array([[1, 2], [3, 4]], dtype=np.int8)\n", "b= np.array([[1, 2], [3, 4]], dtype=np.int8)\n",
"print(\"\\nb:\\n\", b)\n", "print(\"\\nb:\\n\", b)\n",
"print(\"shape of b:\", b.shape)" "print(\"shape of b:\", b.shape())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### .size\n",
"\n",
"The `.size` method (property) returns an integer with the number of elements in the array."
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {
"ExecuteTime": {
"end_time": "2020-02-11T06:32:22.721112Z",
"start_time": "2020-02-11T06:32:22.713111Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a:\n",
" array([1, 2, 3], dtype=int8)\n",
"size of a: 3\n",
"\n",
"b:\n",
" array([[1, 2],\n",
"\t [3, 4]], dtype=int8)\n",
"size of b: 4\n",
"\n",
"\n"
]
}
],
"source": [
"%%micropython -unix 1\n",
"\n",
"import ulab as np\n",
"\n",
"a = np.array([1, 2, 3], dtype=np.int8)\n",
"print(\"a:\\n\", a)\n",
"print(\"size of a:\", a.size)\n",
"\n",
"b= np.array([[1, 2], [3, 4]], dtype=np.int8)\n",
"print(\"\\nb:\\n\", b)\n",
"print(\"size of b:\", b.size)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### .itemsize\n",
"\n",
"The `.itemsize` method (property) returns an integer with the siz enumber of elements in the array."
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"ExecuteTime": {
"end_time": "2020-02-11T19:05:04.296601Z",
"start_time": "2020-02-11T19:05:04.280669Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a:\n",
" array([1, 2, 3], dtype=int8)\n",
"itemsize of a: 1\n",
"\n",
"b:\n",
" array([[1.0, 2.0],\n",
"\t [3.0, 4.0]], dtype=float)\n",
"itemsize of b: 8\n",
"\n",
"\n"
]
}
],
"source": [
"%%micropython -unix 1\n",
"\n",
"import ulab as np\n",
"\n",
"a = np.array([1, 2, 3], dtype=np.int8)\n",
"print(\"a:\\n\", a)\n",
"print(\"itemsize of a:\", a.itemsize)\n",
"\n",
"b= np.array([[1, 2], [3, 4]], dtype=np.float)\n",
"print(\"\\nb:\\n\", b)\n",
"print(\"itemsize of b:\", b.itemsize)"
] ]
}, },
{ {
@ -1078,6 +937,54 @@
"print('a (1 by 16):', a.reshape((1, 16)))" "print('a (1 by 16):', a.reshape((1, 16)))"
] ]
}, },
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### .rawsize\n",
"\n",
"The `rawsize` method of the `ndarray` returns a 5-tuple with the following data\n",
"\n",
"1. number of rows\n",
"2. number of columns\n",
"3. length of the storage (should be equal to the product of 1. and 2.)\n",
"4. length of the data storage in bytes \n",
"5. datum size in bytes (1 for `uint8`/`int8`, 2 for `uint16`/`int16`, and 4, or 8 for `floats`, see [ndarray, the basic container](#ndarray,-the-basic-container))\n",
"\n",
"**WARNING:** `rawsize` is a `ulab`-only method; it has no equivalent in `numpy`."
]
},
{
"cell_type": "code",
"execution_count": 510,
"metadata": {
"ExecuteTime": {
"end_time": "2019-10-19T17:44:26.983908Z",
"start_time": "2019-10-19T17:44:26.764912Z"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"a: \t\t array([1.0, 2.0, 3.0, 4.0], dtype=float)\n",
"rawsize of a: \t (1, 4, 4, 16, 4)\n",
"\n",
"\n"
]
}
],
"source": [
"%%micropython -unix 1\n",
"\n",
"import ulab as np\n",
"\n",
"a = np.array([1, 2, 3, 4], dtype=np.float)\n",
"print(\"a: \\t\\t\", a)\n",
"print(\"rawsize of a: \\t\", a.rawsize())"
]
},
{ {
"cell_type": "markdown", "cell_type": "markdown",
"metadata": {}, "metadata": {},
@ -3981,11 +3888,11 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 114, "execution_count": 458,
"metadata": { "metadata": {
"ExecuteTime": { "ExecuteTime": {
"end_time": "2020-02-16T18:38:07.294862Z", "end_time": "2019-10-19T13:07:43.168629Z",
"start_time": "2020-02-16T18:38:07.233842Z" "start_time": "2019-10-19T13:07:43.130341Z"
} }
}, },
"outputs": [ "outputs": [
@ -3993,13 +3900,13 @@
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"real part:\t array([5119.996, -5.004663, -5.004798, ..., -5.005482, -5.005643, -5.006577], dtype=float)\r\n", "real part:\t array([5119.996, -5.004663, -5.004798, ..., -5.005482, -5.005643, -5.006577], dtype=float)\n",
"\r\n", "\n",
"imaginary part:\t array([0.0, 1631.333, 815.659, ..., -543.764, -815.6588, -1631.333], dtype=float)\r\n", "imaginary part:\t array([0.0, 1631.333, 815.659, ..., -543.764, -815.6588, -1631.333], dtype=float)\n",
"\r\n", "\n",
"real part:\t array([5119.996, -5.004663, -5.004798, ..., -5.005482, -5.005643, -5.006577], dtype=float)\r\n", "real part:\t array([5119.996, -5.004663, -5.004798, ..., -5.005482, -5.005643, -5.006577], dtype=float)\n",
"\r\n", "\n",
"imaginary part:\t array([0.0, 1631.333, 815.659, ..., -543.764, -815.6588, -1631.333], dtype=float)\r\n", "imaginary part:\t array([0.0, 1631.333, 815.659, ..., -543.764, -815.6588, -1631.333], dtype=float)\n",
"\n" "\n"
] ]
} }
@ -4008,20 +3915,16 @@
"%%micropython -pyboard 1\n", "%%micropython -pyboard 1\n",
"\n", "\n",
"import ulab as np\n", "import ulab as np\n",
"from ulab import numerical\n",
"from ulab import vector\n",
"from ulab import fft\n",
"from ulab import linalg\n",
"\n", "\n",
"x = numerical.linspace(0, 10, num=1024)\n", "x = np.linspace(0, 10, num=1024)\n",
"y = vector.sin(x)\n", "y = np.sin(x)\n",
"z = linalg.zeros(len(x))\n", "z = np.zeros(len(x))\n",
"\n", "\n",
"a, b = fft.fft(x)\n", "a, b = np.fft(x)\n",
"print('real part:\\t', a)\n", "print('real part:\\t', a)\n",
"print('\\nimaginary part:\\t', b)\n", "print('\\nimaginary part:\\t', b)\n",
"\n", "\n",
"c, d = fft.fft(x, z)\n", "c, d = np.fft(x, z)\n",
"print('\\nreal part:\\t', c)\n", "print('\\nreal part:\\t', c)\n",
"print('\\nimaginary part:\\t', d)" "print('\\nimaginary part:\\t', d)"
] ]
@ -4360,7 +4263,7 @@
" NDARRAY_FLOAT = 'd',\n", " NDARRAY_FLOAT = 'd',\n",
"};\n", "};\n",
"```\n", "```\n",
"The ambiguity is caused by the fact that not all platforms implement `double`, and there one has to take `float`s. But you haven't actually got to be concerned by this, because at the very beginning of `ndarray.h`, this is already taken care of: the pre-processor figures out, what the `float` implementation of the hardware platform is, and defines the `NDARRAY_FLOAT` typecode accordingly. All you have to keep in mind is that wherever you would use `float` or `double`, you have to use `mp_float_t`. That type is defined in `py/mpconfig.h` of the micropython code base.\n", "The ambiguity is caused by the fact that not all platforms implement `double`, and there one has to take `float`s. But you haven't actually got to be concerned by this, because at the very beginning of `ndarray.h`, this is already taken care of: the preprocessor figures out, what the `float` implementation of the hardware platform is, and defines the `NDARRAY_FLOAT` typecode accordingly. All you have to keep in mind is that wherever you would use `float` or `double`, you have to use `mp_float_t`. That type is defined in `py/mpconfig.h` of the micropython code base.\n",
"\n", "\n",
"Therefore, a 4-by-5 matrix of type float can be created as\n", "Therefore, a 4-by-5 matrix of type float can be created as\n",
"\n", "\n",

File diff suppressed because it is too large Load diff

View file

@ -1,2 +0,0 @@
from ulab import linalg
print(linalg.eye(3))

View file

@ -1,3 +0,0 @@
array([[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]], dtype=float)