Compare commits
18 commits
master
...
old-master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b1ca98e813 | ||
| ef4cbfe825 | |||
|
|
5261b0e404 | ||
| d316e65804 | |||
|
|
2e320f488d | ||
| fb89d90fa1 | |||
|
|
d13a58e5f0 | ||
|
|
a03ef91904 | ||
|
|
5216acfb6f | ||
|
|
19e86f85c8 | ||
|
|
e7db2173b1 | ||
| 3aa8897b90 | |||
|
|
467386584f | ||
| cfbf5f4e84 | |||
| b4974825c6 | |||
| 50957ec120 | |||
|
|
e7243ce38a | ||
|
|
58ee495e6b |
39 changed files with 9969 additions and 1958 deletions
58
.github/workflows/build.yml
vendored
58
.github/workflows/build.yml
vendored
|
|
@ -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()
|
|
||||||
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -1,3 +0,0 @@
|
||||||
/micropython
|
|
||||||
/*.exp
|
|
||||||
/*.out
|
|
||||||
17
build.sh
17
build.sh
|
|
@ -1,17 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
set -e
|
|
||||||
HERE="$(dirname -- "$(readlink -f -- "${0}")" )"
|
|
||||||
[ -e micropython/py/py.mk ] || git clone https://github.com/micropython/micropython
|
|
||||||
[ -e micropython/lib/libffi/autogen.sh ] || (cd micropython && git submodule update --init lib/libffi )
|
|
||||||
#git clone https://github.com/micropython/micropython
|
|
||||||
make -C micropython/mpy-cross -j$(nproc)
|
|
||||||
make -C micropython/ports/unix -j$(nproc) deplibs
|
|
||||||
make -C micropython/ports/unix -j$(nproc) USER_C_MODULES="${HERE}"
|
|
||||||
|
|
||||||
if ! env MICROPY_MICROPYTHON=micropython/ports/unix/micropython micropython/tests/run-tests -d tests; then
|
|
||||||
for exp in *.exp; do
|
|
||||||
testbase=$(basename $exp .exp);
|
|
||||||
echo -e "\nFAILURE $testbase";
|
|
||||||
diff -u $testbase.exp $testbase.out;
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
193
code/__init__.c
Normal file
193
code/__init__.c
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
/*
|
||||||
|
* This file is part of the micropython-ulab project,
|
||||||
|
*
|
||||||
|
* https://github.com/v923z/micropython-ulab
|
||||||
|
*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include "py/runtime.h"
|
||||||
|
#include "py/binary.h"
|
||||||
|
#include "py/obj.h"
|
||||||
|
#include "py/objarray.h"
|
||||||
|
|
||||||
|
#include "shared-bindings/ulab/ndarray.h"
|
||||||
|
#include "shared-bindings/ulab/linalg.h"
|
||||||
|
#include "shared-bindings/ulab/vectorise.h"
|
||||||
|
#include "shared-bindings/ulab/poly.h"
|
||||||
|
#include "shared-bindings/ulab/fft.h"
|
||||||
|
#include "shared-bindings/ulab/numerical.h"
|
||||||
|
|
||||||
|
#define ULAB_VERSION 0.262
|
||||||
|
|
||||||
|
typedef struct _mp_obj_float_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
mp_float_t value;
|
||||||
|
} mp_obj_float_t;
|
||||||
|
|
||||||
|
mp_obj_float_t ulab_version = {{&mp_type_float}, ULAB_VERSION};
|
||||||
|
|
||||||
|
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);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_asbytearray_obj, ndarray_asbytearray);
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_transpose_obj, linalg_transpose);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(linalg_reshape_obj, linalg_reshape);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum);
|
||||||
|
|
||||||
|
STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_rawsize), MP_ROM_PTR(&ndarray_rawsize_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_asbytearray), MP_ROM_PTR(&ndarray_asbytearray_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&linalg_transpose_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&linalg_reshape_obj) },
|
||||||
|
{ 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);
|
||||||
|
|
||||||
|
const mp_obj_type_t ulab_ndarray_type = {
|
||||||
|
{ &mp_type_type },
|
||||||
|
.name = MP_QSTR_ndarray,
|
||||||
|
.print = ndarray_print,
|
||||||
|
.make_new = ndarray_make_new,
|
||||||
|
.subscr = ndarray_subscr,
|
||||||
|
.getiter = ndarray_getiter,
|
||||||
|
.unary_op = ndarray_unary_op,
|
||||||
|
.binary_op = ndarray_binary_op,
|
||||||
|
.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC const mp_map_elem_t ulab_globals_table[] = {
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version) },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&ulab_ndarray_type },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
|
||||||
|
{ MP_OBJ_NEW_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 },
|
||||||
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
// class constants
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_uint16), MP_ROM_INT(NDARRAY_UINT16) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_int16), MP_ROM_INT(NDARRAY_INT16) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_float), MP_ROM_INT(NDARRAY_FLOAT) },
|
||||||
|
};
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_DICT (
|
||||||
|
mp_module_ulab_globals,
|
||||||
|
ulab_globals_table
|
||||||
|
);
|
||||||
|
|
||||||
|
const mp_obj_module_t ulab_user_cmodule = {
|
||||||
|
.base = { &mp_type_module },
|
||||||
|
.globals = (mp_obj_dict_t*)&mp_module_ulab_globals,
|
||||||
|
};
|
||||||
|
|
||||||
|
MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED);
|
||||||
8
code/__init__.h
Normal file
8
code/__init__.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_ULAB___INIT___H
|
||||||
|
#define MICROPY_INCLUDED_SHARED_BINDINGS_ULAB___INIT___H
|
||||||
|
|
||||||
|
#include "py/obj.h"
|
||||||
|
|
||||||
|
// Nothing now.
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_ULAB___INIT___H
|
||||||
230
code/compat.h
Normal file
230
code/compat.h
Normal file
|
|
@ -0,0 +1,230 @@
|
||||||
|
#ifndef MICROPY_INCLUDED_ULAB_COMPAT_H
|
||||||
|
#define MICROPY_INCLUDED_ULAB_COMPAT_H
|
||||||
|
|
||||||
|
#pragma GCC diagnostic ignored "-Wshadow"
|
||||||
|
|
||||||
|
#define mp_obj_is_type(obj, type) MP_OBJ_IS_TYPE(obj, type)
|
||||||
|
#define mp_obj_is_int(obj) MP_OBJ_IS_INT(obj)
|
||||||
|
|
||||||
|
#define MP_ROM_NONE (MP_ROM_PTR(&mp_const_none_obj))
|
||||||
|
#define MP_ROM_FALSE (mp_const_false)
|
||||||
|
#define MP_ROM_TRUE (mp_const_true)
|
||||||
|
|
||||||
|
#ifndef ULAB_FFT_FFT
|
||||||
|
#define ULAB_FFT_FFT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_FFT_IFFT
|
||||||
|
#define ULAB_FFT_IFFT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_FFT_SPECTRUM
|
||||||
|
#define ULAB_FFT_SPECTRUM (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_FILTER_CONVOLVE
|
||||||
|
#define ULAB_FILTER_CONVOLVE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_DET
|
||||||
|
#define ULAB_LINALG_DET (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_DOT
|
||||||
|
#define ULAB_LINALG_DOT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_EIG
|
||||||
|
#define ULAB_LINALG_EIG (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_EYE
|
||||||
|
#define ULAB_LINALG_EYE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_INV
|
||||||
|
#define ULAB_LINALG_INV (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_ONES
|
||||||
|
#define ULAB_LINALG_ONES (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_RESHAPE
|
||||||
|
#define ULAB_LINALG_RESHAPE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_SIZE
|
||||||
|
#define ULAB_LINALG_SIZE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_TRANSPOSE
|
||||||
|
#define ULAB_LINALG_TRANSPOSE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_LINALG_ZEROS
|
||||||
|
#define ULAB_LINALG_ZEROS (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_ARGMAX
|
||||||
|
#define ULAB_NUMERICAL_ARGMAX (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_ARGMIN
|
||||||
|
#define ULAB_NUMERICAL_ARGMIN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_ARGSORT
|
||||||
|
#define ULAB_NUMERICAL_ARGSORT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_DIFF
|
||||||
|
#define ULAB_NUMERICAL_DIFF (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_FLIP
|
||||||
|
#define ULAB_NUMERICAL_FLIP (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_LINSPACE
|
||||||
|
#define ULAB_NUMERICAL_LINSPACE (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_MAX
|
||||||
|
#define ULAB_NUMERICAL_MAX (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_MEAN
|
||||||
|
#define ULAB_NUMERICAL_MEAN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_MIN
|
||||||
|
#define ULAB_NUMERICAL_MIN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_ROLL
|
||||||
|
#define ULAB_NUMERICAL_ROLL (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_SORT
|
||||||
|
#define ULAB_NUMERICAL_SORT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_STD
|
||||||
|
#define ULAB_NUMERICAL_STD (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_NUMERICAL_SUM
|
||||||
|
#define ULAB_NUMERICAL_SUM (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_POLY_POLYFIT
|
||||||
|
#define ULAB_POLY_POLYFIT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_POLY_POLYVAL
|
||||||
|
#define ULAB_POLY_POLYVAL (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_
|
||||||
|
#define ULAB_VECTORISE_ (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ACOS
|
||||||
|
#define ULAB_VECTORISE_ACOS (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ACOSH
|
||||||
|
#define ULAB_VECTORISE_ACOSH (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ASIN
|
||||||
|
#define ULAB_VECTORISE_ASIN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ASINH
|
||||||
|
#define ULAB_VECTORISE_ASINH (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ATAN
|
||||||
|
#define ULAB_VECTORISE_ATAN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ATANH
|
||||||
|
#define ULAB_VECTORISE_ATANH (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_CEIL
|
||||||
|
#define ULAB_VECTORISE_CEIL (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_COS
|
||||||
|
#define ULAB_VECTORISE_COS (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ERF
|
||||||
|
#define ULAB_VECTORISE_ERF (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_ERFC
|
||||||
|
#define ULAB_VECTORISE_ERFC (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_EXP
|
||||||
|
#define ULAB_VECTORISE_EXP (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_EXPM1
|
||||||
|
#define ULAB_VECTORISE_EXPM1 (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_FLOOR
|
||||||
|
#define ULAB_VECTORISE_FLOOR (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_GAMMA
|
||||||
|
#define ULAB_VECTORISE_GAMMA (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_LGAMMA
|
||||||
|
#define ULAB_VECTORISE_LGAMMA (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_LOG
|
||||||
|
#define ULAB_VECTORISE_LOG (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_LOG10
|
||||||
|
#define ULAB_VECTORISE_LOG10 (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_LOG2
|
||||||
|
#define ULAB_VECTORISE_LOG2 (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_SIN
|
||||||
|
#define ULAB_VECTORISE_SIN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_SINH
|
||||||
|
#define ULAB_VECTORISE_SINH (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_SQRT
|
||||||
|
#define ULAB_VECTORISE_SQRT (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_TAHN
|
||||||
|
#define ULAB_VECTORISE_TAHN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_TAN
|
||||||
|
#define ULAB_VECTORISE_TAN (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef ULAB_VECTORISE_TANH
|
||||||
|
#define ULAB_VECTORISE_TANH (1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // MICROPY_INCLUDED_ULAB_COMPAT_H
|
||||||
|
|
||||||
155
code/create.c
155
code/create.c
|
|
@ -1,155 +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
|
|
||||||
* 2019-2020 Zoltán Vörös
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include "py/obj.h"
|
|
||||||
#include "py/runtime.h"
|
|
||||||
#include "create.h"
|
|
||||||
|
|
||||||
mp_obj_t create_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[] = {
|
|
||||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } ,
|
|
||||||
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
|
||||||
};
|
|
||||||
|
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
|
||||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
|
||||||
|
|
||||||
uint8_t dtype = args[1].u_int;
|
|
||||||
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"));
|
|
||||||
}
|
|
||||||
ndarray_obj_t *ndarray = NULL;
|
|
||||||
if(MP_OBJ_IS_INT(args[0].u_obj)) {
|
|
||||||
size_t n = mp_obj_get_int(args[0].u_obj);
|
|
||||||
ndarray = create_new_ndarray(1, n, dtype);
|
|
||||||
} 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);
|
|
||||||
if(tuple->len != 2) {
|
|
||||||
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
|
|
||||||
}
|
|
||||||
ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]),
|
|
||||||
mp_obj_get_int(tuple->items[1]), dtype);
|
|
||||||
}
|
|
||||||
if(kind == 1) {
|
|
||||||
mp_obj_t one = mp_obj_new_int(1);
|
|
||||||
for(size_t i=0; i < ndarray->array->len; i++) {
|
|
||||||
mp_binary_set_val_array(dtype, ndarray->array->items, i, one);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_obj_t create_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
|
||||||
return create_zeros_ones(n_args, pos_args, kw_args, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_zeros_obj, 0, create_zeros);
|
|
||||||
|
|
||||||
mp_obj_t create_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
|
||||||
return create_zeros_ones(n_args, pos_args, kw_args, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones);
|
|
||||||
|
|
||||||
mp_obj_t create_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
|
||||||
static const mp_arg_t allowed_args[] = {
|
|
||||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
|
|
||||||
{ MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
|
||||||
{ MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
|
||||||
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
|
||||||
};
|
|
||||||
|
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
|
||||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
|
||||||
|
|
||||||
size_t n = args[0].u_int, m;
|
|
||||||
int16_t k = args[2].u_int;
|
|
||||||
uint8_t dtype = args[3].u_int;
|
|
||||||
if(args[1].u_rom_obj == mp_const_none) {
|
|
||||||
m = n;
|
|
||||||
} else {
|
|
||||||
m = mp_obj_get_int(args[1].u_rom_obj);
|
|
||||||
}
|
|
||||||
|
|
||||||
ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype);
|
|
||||||
mp_obj_t one = mp_obj_new_int(1);
|
|
||||||
size_t i = 0;
|
|
||||||
if((k >= 0) && (k < n)) {
|
|
||||||
while(k < n) {
|
|
||||||
mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one);
|
|
||||||
k++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
} else if((k < 0) && (-k < m)) {
|
|
||||||
k = -k;
|
|
||||||
i = 0;
|
|
||||||
while(k < m) {
|
|
||||||
mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one);
|
|
||||||
k++;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_eye_obj, 0, create_eye);
|
|
||||||
|
|
||||||
mp_obj_t create_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
|
||||||
static const mp_arg_t allowed_args[] = {
|
|
||||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
|
||||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
|
||||||
{ MP_QSTR_num, MP_ARG_INT, {.u_int = 50} },
|
|
||||||
{ MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_true} },
|
|
||||||
{ MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_false} },
|
|
||||||
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
|
||||||
};
|
|
||||||
|
|
||||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
|
||||||
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
|
||||||
|
|
||||||
uint16_t len = args[2].u_int;
|
|
||||||
if(len < 2) {
|
|
||||||
mp_raise_ValueError(translate("number of points must be at least 2"));
|
|
||||||
}
|
|
||||||
mp_float_t value, step;
|
|
||||||
value = mp_obj_get_float(args[0].u_obj);
|
|
||||||
uint8_t typecode = args[5].u_int;
|
|
||||||
if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1);
|
|
||||||
else step = (mp_obj_get_float(args[1].u_obj)-value)/len;
|
|
||||||
ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode);
|
|
||||||
if(typecode == NDARRAY_UINT8) {
|
|
||||||
uint8_t *array = (uint8_t *)ndarray->array->items;
|
|
||||||
for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value;
|
|
||||||
} else if(typecode == NDARRAY_INT8) {
|
|
||||||
int8_t *array = (int8_t *)ndarray->array->items;
|
|
||||||
for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value;
|
|
||||||
} else if(typecode == NDARRAY_UINT16) {
|
|
||||||
uint16_t *array = (uint16_t *)ndarray->array->items;
|
|
||||||
for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value;
|
|
||||||
} else if(typecode == NDARRAY_INT16) {
|
|
||||||
int16_t *array = (int16_t *)ndarray->array->items;
|
|
||||||
for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value;
|
|
||||||
} else {
|
|
||||||
mp_float_t *array = (mp_float_t *)ndarray->array->items;
|
|
||||||
for(size_t i=0; i < len; i++, value += step) array[i] = value;
|
|
||||||
}
|
|
||||||
if(args[4].u_obj == mp_const_false) {
|
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
|
||||||
} else {
|
|
||||||
mp_obj_t tuple[2];
|
|
||||||
tuple[0] = ndarray;
|
|
||||||
tuple[1] = mp_obj_new_float(step);
|
|
||||||
return mp_obj_new_tuple(2, tuple);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_linspace_obj, 2, create_linspace);
|
|
||||||
|
|
@ -1,29 +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
|
|
||||||
* 2019-2020 Zoltán Vörös
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef _CREATE_
|
|
||||||
#define _CREATE_
|
|
||||||
|
|
||||||
#include "ulab.h"
|
|
||||||
#include "ndarray.h"
|
|
||||||
|
|
||||||
/*
|
|
||||||
mp_obj_t create_zeros(size_t , const mp_obj_t *, mp_map_t *);
|
|
||||||
mp_obj_t create_ones(size_t , const mp_obj_t *, mp_map_t *);
|
|
||||||
mp_obj_t create_eye(size_t , const mp_obj_t *, mp_map_t *);
|
|
||||||
mp_obj_t create_linspace(size_t , const mp_obj_t *, mp_map_t *);
|
|
||||||
*/
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_ones_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_zeros_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_eye_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_linspace_obj);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -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
|
|
||||||
|
|
@ -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
|
|
||||||
44
code/fft.c
44
code/fft.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -14,15 +13,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 "compat.h"
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
#include "fft.h"
|
#include "fft.h"
|
||||||
|
|
||||||
#if ULAB_FFT_MODULE
|
|
||||||
|
|
||||||
enum FFT_TYPE {
|
enum FFT_TYPE {
|
||||||
FFT_FFT,
|
FFT_FFT,
|
||||||
FFT_IFFT,
|
FFT_IFFT,
|
||||||
|
|
@ -103,9 +100,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 +115,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) {
|
||||||
|
|
@ -160,8 +152,6 @@ 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_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);
|
||||||
|
|
@ -170,8 +160,6 @@ 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_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);
|
||||||
|
|
@ -179,21 +167,3 @@ mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) {
|
||||||
return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM);
|
return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
||||||
16
code/fft.h
16
code/fft.h
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -6,12 +5,11 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _FFT_
|
#ifndef _FFT_
|
||||||
#define _FFT_
|
#define _FFT_
|
||||||
#include "ulab.h"
|
|
||||||
|
|
||||||
#ifndef MP_PI
|
#ifndef MP_PI
|
||||||
#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
|
#define MP_PI MICROPY_FLOAT_CONST(3.14159265358979323846)
|
||||||
|
|
@ -19,13 +17,7 @@
|
||||||
|
|
||||||
#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
|
mp_obj_t fft_fft(size_t , const mp_obj_t *);
|
||||||
|
mp_obj_t fft_ifft(size_t , const mp_obj_t *);
|
||||||
extern mp_obj_module_t ulab_fft_module;
|
mp_obj_t fft_spectrum(size_t , const mp_obj_t *);
|
||||||
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -14,20 +13,19 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/misc.h"
|
#include "compat.h"
|
||||||
#include "filter.h"
|
#include "filter.h"
|
||||||
|
|
||||||
#if ULAB_FILTER_MODULE
|
|
||||||
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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -35,10 +33,6 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
|
||||||
ndarray_obj_t *c = MP_OBJ_TO_PTR(args[1].u_obj);
|
ndarray_obj_t *c = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||||
int len_a = a->array->len;
|
int len_a = a->array->len;
|
||||||
int len_c = c->array->len;
|
int len_c = c->array->len;
|
||||||
// deal with linear arrays only
|
|
||||||
if(a->m*a->n != len_a || c->m*c->n != len_c) {
|
|
||||||
mp_raise_TypeError(translate("convolve arguments must be linear arrays"));
|
|
||||||
}
|
|
||||||
if(len_a == 0 || len_c == 0) {
|
if(len_a == 0 || len_c == 0) {
|
||||||
mp_raise_TypeError(translate("convolve arguments must not be empty"));
|
mp_raise_TypeError(translate("convolve arguments must not be empty"));
|
||||||
}
|
}
|
||||||
|
|
@ -47,23 +41,6 @@ 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;
|
||||||
|
|
||||||
if(a->array->typecode == NDARRAY_FLOAT && c->array->typecode == NDARRAY_FLOAT) {
|
|
||||||
mp_float_t* a_items = (mp_float_t*)a->array->items;
|
|
||||||
mp_float_t* c_items = (mp_float_t*)c->array->items;
|
|
||||||
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);
|
|
||||||
mp_float_t* a_ptr = a_items + bot_n + k;
|
|
||||||
mp_float_t* a_end = a_ptr + (top_n - bot_n);
|
|
||||||
mp_float_t* c_ptr = c_items + len_c - bot_n - 1;
|
|
||||||
for(; a_ptr != a_end;) {
|
|
||||||
accum += *a_ptr++ * *c_ptr--;
|
|
||||||
}
|
|
||||||
*outptr++ = accum;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for(int k=-off; k<len-off; k++) {
|
for(int k=-off; k<len-off; k++) {
|
||||||
mp_float_t accum = (mp_float_t)0;
|
mp_float_t accum = (mp_float_t)0;
|
||||||
int top_n = MIN(len_c, len_a - k);
|
int top_n = MIN(len_c, len_a - k);
|
||||||
|
|
@ -71,29 +48,12 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
|
||||||
for(int n=bot_n; n<top_n; n++) {
|
for(int n=bot_n; n<top_n; n++) {
|
||||||
int idx_c = len_c - n - 1;
|
int idx_c = len_c - n - 1;
|
||||||
int idx_a = n+k;
|
int idx_a = n+k;
|
||||||
mp_float_t ai = ndarray_get_float_value(a->array->items, a->array->typecode, idx_a);
|
mp_float_t ai = idx_a >= 0 && idx_a < len_a ? ndarray_get_float_value(a->array->items, c->array->typecode, idx_a) : (mp_float_t)0;
|
||||||
mp_float_t ci = ndarray_get_float_value(c->array->items, c->array->typecode, idx_c);
|
mp_float_t ci = idx_c >= 0 && idx_c < len_c ? ndarray_get_float_value(c->array->items, c->array->typecode, idx_c) : (mp_float_t)0;
|
||||||
accum += ai * ci;
|
accum += ai * ci;
|
||||||
}
|
}
|
||||||
*outptr++ = accum;
|
*outptr++ = accum;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -12,14 +11,8 @@
|
||||||
#ifndef _FILTER_
|
#ifndef _FILTER_
|
||||||
#define _FILTER_
|
#define _FILTER_
|
||||||
|
|
||||||
#include "ulab.h"
|
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
|
|
||||||
#if ULAB_FILTER_MODULE
|
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);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
||||||
172
code/linalg.c
172
code/linalg.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -15,14 +14,67 @@
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/misc.h"
|
#include "py/misc.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "linalg.h"
|
#include "linalg.h"
|
||||||
|
|
||||||
#if ULAB_LINALG_MODULE
|
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_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_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)];
|
||||||
|
|
@ -57,8 +109,6 @@ 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);
|
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -134,13 +184,8 @@ mp_obj_t linalg_inv(mp_obj_t o_in) {
|
||||||
return MP_OBJ_FROM_PTR(inverted);
|
return MP_OBJ_FROM_PTR(inverted);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
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);
|
||||||
ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2);
|
ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2);
|
||||||
if(m1->n != m2->m) {
|
if(m1->n != m2->m) {
|
||||||
|
|
@ -165,7 +210,88 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
||||||
return MP_OBJ_FROM_PTR(out);
|
return MP_OBJ_FROM_PTR(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
|
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[] = {
|
||||||
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } ,
|
||||||
|
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
uint8_t dtype = args[1].u_int;
|
||||||
|
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"));
|
||||||
|
}
|
||||||
|
ndarray_obj_t *ndarray = NULL;
|
||||||
|
if(MP_OBJ_IS_INT(args[0].u_obj)) {
|
||||||
|
size_t n = mp_obj_get_int(args[0].u_obj);
|
||||||
|
ndarray = create_new_ndarray(1, n, dtype);
|
||||||
|
} 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);
|
||||||
|
if(tuple->len != 2) {
|
||||||
|
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
|
||||||
|
}
|
||||||
|
ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]),
|
||||||
|
mp_obj_get_int(tuple->items[1]), dtype);
|
||||||
|
}
|
||||||
|
if(kind == 1) {
|
||||||
|
mp_obj_t one = mp_obj_new_int(1);
|
||||||
|
for(size_t i=0; i < ndarray->array->len; i++) {
|
||||||
|
mp_binary_set_val_array(dtype, ndarray->array->items, i, one);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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[] = {
|
||||||
|
{ 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_ROM_NONE } },
|
||||||
|
{ MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||||
|
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
size_t n = args[0].u_int, m;
|
||||||
|
int16_t k = args[2].u_int;
|
||||||
|
uint8_t dtype = args[3].u_int;
|
||||||
|
if(args[1].u_rom_obj == mp_const_none) {
|
||||||
|
m = n;
|
||||||
|
} else {
|
||||||
|
m = mp_obj_get_int(args[1].u_rom_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype);
|
||||||
|
mp_obj_t one = mp_obj_new_int(1);
|
||||||
|
size_t i = 0;
|
||||||
|
if((k >= 0) && (abs(k) < n)) {
|
||||||
|
while(abs(k) < n) {
|
||||||
|
mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one);
|
||||||
|
k++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
} else if((k < 0) && (abs(k) < m)) {
|
||||||
|
k = -k;
|
||||||
|
i = 0;
|
||||||
|
while(abs(k) < m) {
|
||||||
|
mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one);
|
||||||
|
k++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
|
}
|
||||||
|
|
||||||
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)) {
|
||||||
|
|
@ -204,8 +330,6 @@ mp_obj_t linalg_det(mp_obj_t oin) {
|
||||||
return mp_obj_new_float(det);
|
return mp_obj_new_float(det);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
|
|
||||||
|
|
||||||
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"));
|
||||||
|
|
@ -332,23 +456,3 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
|
||||||
return tuple;
|
return tuple;
|
||||||
return MP_OBJ_FROM_PTR(eigenvalues);
|
return MP_OBJ_FROM_PTR(eigenvalues);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
|
||||||
|
|
||||||
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_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
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -6,15 +5,16 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _LINALG_
|
#ifndef _LINALG_
|
||||||
#define _LINALG_
|
#define _LINALG_
|
||||||
|
|
||||||
#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 +23,17 @@
|
||||||
|
|
||||||
#define JACOBI_MAX 20
|
#define JACOBI_MAX 20
|
||||||
|
|
||||||
#if ULAB_LINALG_MODULE || ULAB_POLY_MODULE
|
mp_obj_t linalg_transpose(mp_obj_t );
|
||||||
|
mp_obj_t linalg_reshape(mp_obj_t , mp_obj_t );
|
||||||
|
mp_obj_t linalg_size(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
bool linalg_invert_matrix(mp_float_t *, size_t );
|
bool linalg_invert_matrix(mp_float_t *, size_t );
|
||||||
#endif
|
mp_obj_t linalg_inv(mp_obj_t );
|
||||||
|
mp_obj_t linalg_dot(mp_obj_t , mp_obj_t );
|
||||||
|
mp_obj_t linalg_zeros(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t linalg_ones(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t linalg_eye(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
|
||||||
#if ULAB_LINALG_MODULE
|
mp_obj_t linalg_det(mp_obj_t );
|
||||||
|
mp_obj_t linalg_eig(mp_obj_t );
|
||||||
extern mp_obj_module_t ulab_linalg_module;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -3,18 +3,14 @@ USERMODULES_DIR := $(USERMOD_DIR)
|
||||||
|
|
||||||
# Add all C files to SRC_USERMOD.
|
# Add all C files to SRC_USERMOD.
|
||||||
SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c
|
SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c
|
||||||
SRC_USERMOD += $(USERMODULES_DIR)/create.c
|
|
||||||
SRC_USERMOD += $(USERMODULES_DIR)/linalg.c
|
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
|
|
||||||
|
|
|
||||||
205
code/ndarray.c
205
code/ndarray.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -17,6 +16,7 @@
|
||||||
#include "py/binary.h"
|
#include "py/binary.h"
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/objtuple.h"
|
#include "py/objtuple.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
|
|
||||||
// This function is copied verbatim from objarray.c
|
// This function is copied verbatim from objarray.c
|
||||||
|
|
@ -64,16 +64,15 @@ void fill_array_iterable(mp_float_t *array, mp_obj_t iterable) {
|
||||||
|
|
||||||
void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data, size_t n0, size_t n) {
|
void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data, size_t n0, size_t n) {
|
||||||
mp_print_str(print, "[");
|
mp_print_str(print, "[");
|
||||||
size_t i;
|
|
||||||
if(n < PRINT_MAX) { // if the array is short, print everything
|
if(n < PRINT_MAX) { // if the array is short, print everything
|
||||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
|
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
|
||||||
for(i=1; i<n; i++) {
|
for(size_t i=1; i<n; i++) {
|
||||||
mp_print_str(print, ", ");
|
mp_print_str(print, ", ");
|
||||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
|
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
|
||||||
for(i=1; i<3; i++) {
|
for(size_t i=1; i<3; i++) {
|
||||||
mp_print_str(print, ", ");
|
mp_print_str(print, ", ");
|
||||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
||||||
}
|
}
|
||||||
|
|
@ -154,7 +153,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,7 +164,13 @@ 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, 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);
|
||||||
uint8_t dtype = ndarray_init_helper(n_args, args, kw_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;
|
||||||
|
|
@ -186,7 +191,8 @@ STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args,
|
||||||
if(len_in != MP_OBJ_NULL) { // indeed, this seems to be an iterable
|
if(len_in != MP_OBJ_NULL) { // indeed, this seems to be an iterable
|
||||||
// Next, we have to check, whether all elements in the outer loop have the same length
|
// Next, we have to check, whether all elements in the outer loop have the same length
|
||||||
if(i > 0) {
|
if(i > 0) {
|
||||||
if(len2 != MP_OBJ_SMALL_INT_VALUE(len_in)) {
|
size_t temp = abs(MP_OBJ_SMALL_INT_VALUE(len_in));
|
||||||
|
if(len2 != temp) {
|
||||||
mp_raise_ValueError(translate("iterables are not of the same length"));
|
mp_raise_ValueError(translate("iterables are not of the same length"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -212,31 +218,14 @@ 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;
|
// TODO: check, whether this is true!
|
||||||
if(slice.step > 0) correction = -1;
|
if(slice.step < 0) {
|
||||||
len = (slice.stop - slice.start + (slice.step + correction)) / slice.step;
|
slice.step = -slice.step;
|
||||||
if(len < 0) return 0;
|
return (slice.start - slice.stop) / slice.step;
|
||||||
return (size_t)len;
|
} else {
|
||||||
|
return (slice.stop - slice.start) / slice.step;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t true_length(mp_obj_t bool_list) {
|
size_t true_length(mp_obj_t bool_list) {
|
||||||
|
|
@ -261,10 +250,10 @@ 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);
|
uint32_t _index = mp_obj_get_int(index);
|
||||||
if(_index < 0) {
|
if(_index < 0) {
|
||||||
_index += n;
|
_index += n;
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +293,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"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -367,7 +356,8 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
|
||||||
} else { // columns are indexed by a list
|
} else { // columns are indexed by a list
|
||||||
mp_obj_iter_buf_t column_iter_buf;
|
mp_obj_iter_buf_t column_iter_buf;
|
||||||
mp_obj_t column_item, column_iterable;
|
mp_obj_t column_item, column_iterable;
|
||||||
size_t j = 0, cindex = 0;
|
size_t j = 0;
|
||||||
|
cindex = 0;
|
||||||
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
|
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||||
if(mp_obj_is_true(row_item)) {
|
if(mp_obj_is_true(row_item)) {
|
||||||
column_iterable = mp_getiter(column_list, &column_iter_buf);
|
column_iterable = mp_getiter(column_list, &column_iter_buf);
|
||||||
|
|
@ -453,7 +443,8 @@ mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
|
||||||
} else { // columns are indexed by a list
|
} else { // columns are indexed by a list
|
||||||
mp_obj_iter_buf_t column_iter_buf;
|
mp_obj_iter_buf_t column_iter_buf;
|
||||||
mp_obj_t column_item, column_iterable;
|
mp_obj_t column_item, column_iterable;
|
||||||
size_t j = 0, cindex = 0;
|
size_t j = 0;
|
||||||
|
cindex = 0;
|
||||||
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
|
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||||
if(mp_obj_is_true(row_item)) {
|
if(mp_obj_is_true(row_item)) {
|
||||||
column_iterable = mp_getiter(column_list, &column_iter_buf);
|
column_iterable = mp_getiter(column_list, &column_iter_buf);
|
||||||
|
|
@ -497,7 +488,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
|
||||||
|
|
@ -520,9 +511,9 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
|
||||||
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 +527,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);
|
||||||
|
|
@ -595,7 +586,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 +631,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) {
|
||||||
|
|
@ -685,6 +684,11 @@ mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
|
||||||
return self_copy;
|
return self_copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_obj_t ndarray_asbytearray(mp_obj_t self_in) {
|
||||||
|
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
|
return MP_OBJ_FROM_PTR(self->array);
|
||||||
|
}
|
||||||
|
|
||||||
// Binary operations
|
// Binary operations
|
||||||
|
|
||||||
mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||||
|
|
@ -840,6 +844,11 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
|
||||||
mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
||||||
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||||
ndarray_obj_t *ndarray = NULL;
|
ndarray_obj_t *ndarray = NULL;
|
||||||
|
uint8_t *array8u;
|
||||||
|
int8_t *array8i;
|
||||||
|
uint16_t *array16u;
|
||||||
|
int16_t *array16i;
|
||||||
|
mp_float_t *arraymp;
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case MP_UNARY_OP_LEN:
|
case MP_UNARY_OP_LEN:
|
||||||
if(self->m > 1) {
|
if(self->m > 1) {
|
||||||
|
|
@ -856,28 +865,28 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
||||||
// we can invert the content byte by byte, there is no need to distinguish
|
// we can invert the content byte by byte, there is no need to distinguish
|
||||||
// between different typecodes
|
// between different typecodes
|
||||||
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
|
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
|
||||||
uint8_t *array = (uint8_t *)ndarray->array->items;
|
array8u = (uint8_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->bytes; i++) array[i] = ~array[i];
|
for(size_t i=0; i < self->bytes; i++) array8u[i] = ~array8u[i];
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_UNARY_OP_NEGATIVE:
|
case MP_UNARY_OP_NEGATIVE:
|
||||||
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
|
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
|
||||||
if(self->array->typecode == NDARRAY_UINT8) {
|
if(self->array->typecode == NDARRAY_UINT8) {
|
||||||
uint8_t *array = (uint8_t *)ndarray->array->items;
|
array8u = (uint8_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->array->len; i++) array[i] = -array[i];
|
for(size_t i=0; i < self->array->len; i++) array8u[i] = -array8u[i];
|
||||||
} else if(self->array->typecode == NDARRAY_INT8) {
|
} else if(self->array->typecode == NDARRAY_INT8) {
|
||||||
int8_t *array = (int8_t *)ndarray->array->items;
|
array8i = (int8_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->array->len; i++) array[i] = -array[i];
|
for(size_t i=0; i < self->array->len; i++) array8i[i] = -array8i[i];
|
||||||
} else if(self->array->typecode == NDARRAY_UINT16) {
|
} else if(self->array->typecode == NDARRAY_UINT16) {
|
||||||
uint16_t *array = (uint16_t *)ndarray->array->items;
|
array16u = (uint16_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->array->len; i++) array[i] = -array[i];
|
for(size_t i=0; i < self->array->len; i++) array16u[i] = -array16u[i];
|
||||||
} else if(self->array->typecode == NDARRAY_INT16) {
|
} else if(self->array->typecode == NDARRAY_INT16) {
|
||||||
int16_t *array = (int16_t *)ndarray->array->items;
|
array16i = (int16_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->array->len; i++) array[i] = -array[i];
|
for(size_t i=0; i < self->array->len; i++) array16i[i] = -array16i[i];
|
||||||
} else {
|
} else {
|
||||||
mp_float_t *array = (mp_float_t *)ndarray->array->items;
|
arraymp = (mp_float_t *)ndarray->array->items;
|
||||||
for(size_t i=0; i < self->array->len; i++) array[i] = -array[i];
|
for(size_t i=0; i < self->array->len; i++) arraymp[i] = -arraymp[i];
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
break;
|
break;
|
||||||
|
|
@ -891,19 +900,19 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t 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;
|
array8i = (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(array8i[i] < 0) array8i[i] = -array8i[i];
|
||||||
}
|
}
|
||||||
} else if(self->array->typecode == NDARRAY_INT16) {
|
} else if(self->array->typecode == NDARRAY_INT16) {
|
||||||
int16_t *array = (int16_t *)ndarray->array->items;
|
array16i = (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(array16i[i] < 0) array16i[i] = -array16i[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mp_float_t *array = (mp_float_t *)ndarray->array->items;
|
arraymp = (mp_float_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(arraymp[i] < 0) arraymp[i] = -arraymp[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(ndarray);
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
|
|
@ -911,67 +920,3 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
||||||
default: return MP_OBJ_NULL; // operator not supported
|
default: return MP_OBJ_NULL; // operator not supported
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
return !mp_get_buffer(self->array, bufinfo, flags);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -6,7 +5,7 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _NDARRAY_
|
#ifndef _NDARRAY_
|
||||||
|
|
@ -25,13 +24,7 @@
|
||||||
#define FLOAT_TYPECODE 'd'
|
#define FLOAT_TYPECODE 'd'
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !CIRCUITPY
|
const mp_obj_type_t ulab_ndarray_type;
|
||||||
#define translate(x) x
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
|
|
||||||
|
|
||||||
extern const mp_obj_type_t ulab_ndarray_type;
|
|
||||||
|
|
||||||
enum NDARRAY_TYPE {
|
enum NDARRAY_TYPE {
|
||||||
NDARRAY_UINT8 = 'B',
|
NDARRAY_UINT8 = 'B',
|
||||||
|
|
@ -60,30 +53,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 *, size_t, const mp_obj_t *, mp_map_t *);
|
||||||
mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args);
|
|
||||||
#else
|
|
||||||
mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *);
|
|
||||||
#endif
|
|
||||||
mp_obj_t ndarray_subscr(mp_obj_t , mp_obj_t , mp_obj_t );
|
mp_obj_t ndarray_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_asbytearray(mp_obj_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);
|
|
||||||
//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));\
|
||||||
|
|
|
||||||
|
|
@ -1,61 +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"
|
|
||||||
|
|
||||||
#if CIRCUITPY
|
|
||||||
typedef struct _mp_obj_property_t {
|
|
||||||
mp_obj_base_t base;
|
|
||||||
mp_obj_t proxy[3]; // getter, setter, deleter
|
|
||||||
} mp_obj_property_t;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
STATIC const mp_obj_property_t ndarray_shape_obj = {
|
|
||||||
.base.type = &mp_type_property,
|
|
||||||
.proxy = {(mp_obj_t)&ndarray_get_shape_obj,
|
|
||||||
mp_const_none,
|
|
||||||
mp_const_none },
|
|
||||||
};
|
|
||||||
|
|
||||||
STATIC const mp_obj_property_t ndarray_size_obj = {
|
|
||||||
.base.type = &mp_type_property,
|
|
||||||
.proxy = {(mp_obj_t)&ndarray_get_size_obj,
|
|
||||||
mp_const_none,
|
|
||||||
mp_const_none },
|
|
||||||
};
|
|
||||||
|
|
||||||
STATIC const mp_obj_property_t ndarray_itemsize_obj = {
|
|
||||||
.base.type = &mp_type_property,
|
|
||||||
.proxy = {(mp_obj_t)&ndarray_get_itemsize_obj,
|
|
||||||
mp_const_none,
|
|
||||||
mp_const_none },
|
|
||||||
};
|
|
||||||
#else
|
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size);
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize);
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
||||||
139
code/numerical.c
139
code/numerical.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -17,10 +16,9 @@
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/builtin.h"
|
#include "py/builtin.h"
|
||||||
#include "py/misc.h"
|
#include "py/misc.h"
|
||||||
|
#include "compat.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,6 +29,55 @@ enum NUMERICAL_FUNCTION_TYPE {
|
||||||
NUMERICAL_STD,
|
NUMERICAL_STD,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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[] = {
|
||||||
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||||
|
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||||
|
{ MP_QSTR_num, MP_ARG_INT, {.u_int = 50} },
|
||||||
|
{ 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_ROM_FALSE} },
|
||||||
|
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
|
||||||
|
};
|
||||||
|
|
||||||
|
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||||
|
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||||
|
|
||||||
|
uint16_t len = args[2].u_int;
|
||||||
|
if(len < 2) {
|
||||||
|
mp_raise_ValueError(translate("number of points must be at least 2"));
|
||||||
|
}
|
||||||
|
mp_float_t value, step;
|
||||||
|
value = mp_obj_get_float(args[0].u_obj);
|
||||||
|
uint8_t typecode = args[5].u_int;
|
||||||
|
if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1);
|
||||||
|
else step = (mp_obj_get_float(args[1].u_obj)-value)/len;
|
||||||
|
ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode);
|
||||||
|
if(typecode == NDARRAY_UINT8) {
|
||||||
|
uint8_t *array = (uint8_t *)ndarray->array->items;
|
||||||
|
for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value;
|
||||||
|
} else if(typecode == NDARRAY_INT8) {
|
||||||
|
int8_t *array = (int8_t *)ndarray->array->items;
|
||||||
|
for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value;
|
||||||
|
} else if(typecode == NDARRAY_UINT16) {
|
||||||
|
uint16_t *array = (uint16_t *)ndarray->array->items;
|
||||||
|
for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value;
|
||||||
|
} else if(typecode == NDARRAY_INT16) {
|
||||||
|
int16_t *array = (int16_t *)ndarray->array->items;
|
||||||
|
for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value;
|
||||||
|
} else {
|
||||||
|
mp_float_t *array = (mp_float_t *)ndarray->array->items;
|
||||||
|
for(size_t i=0; i < len; i++, value += step) array[i] = value;
|
||||||
|
}
|
||||||
|
if(args[4].u_obj == mp_const_false) {
|
||||||
|
return MP_OBJ_FROM_PTR(ndarray);
|
||||||
|
} else {
|
||||||
|
mp_obj_t tuple[2];
|
||||||
|
tuple[0] = ndarray;
|
||||||
|
tuple[1] = mp_obj_new_float(step);
|
||||||
|
return mp_obj_new_tuple(2, tuple);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
if(axis == mp_const_none) { // flatten the array
|
if(axis == mp_const_none) { // flatten the array
|
||||||
|
|
@ -206,8 +253,8 @@ mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis,
|
||||||
|
|
||||||
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)];
|
||||||
|
|
@ -258,42 +305,30 @@ mp_obj_t numerical_min(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MIN);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
|
|
||||||
|
|
||||||
mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MAX);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max);
|
|
||||||
|
|
||||||
mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMIN);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
|
|
||||||
|
|
||||||
mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMAX);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax);
|
|
||||||
|
|
||||||
mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_SUM);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_SUM);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum);
|
|
||||||
|
|
||||||
mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||||
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MEAN);
|
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MEAN);
|
||||||
}
|
}
|
||||||
|
|
||||||
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} },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -318,13 +353,11 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
|
|
||||||
|
|
||||||
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)];
|
||||||
|
|
@ -400,18 +433,16 @@ 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_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) &&
|
||||||
|
|
@ -449,11 +480,9 @@ mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
|
|
||||||
|
|
||||||
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 } },
|
||||||
};
|
};
|
||||||
|
|
@ -461,7 +490,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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -519,10 +548,8 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||||
return MP_OBJ_FROM_PTR(out);
|
return MP_OBJ_FROM_PTR(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
|
|
||||||
|
|
||||||
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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -580,7 +607,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 } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -589,13 +616,10 @@ mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
||||||
|
|
||||||
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0);
|
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
|
|
||||||
|
|
||||||
// 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 } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -605,16 +629,14 @@ mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
||||||
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 1);
|
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace);
|
|
||||||
|
|
||||||
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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -676,30 +698,3 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(indices);
|
return MP_OBJ_FROM_PTR(indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
|
|
||||||
|
|
||||||
STATIC const mp_rom_map_elem_t ulab_numerical_globals_table[] = {
|
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_numerical) },
|
|
||||||
{ 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
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -12,17 +11,27 @@
|
||||||
#ifndef _NUMERICAL_
|
#ifndef _NUMERICAL_
|
||||||
#define _NUMERICAL_
|
#define _NUMERICAL_
|
||||||
|
|
||||||
#include "ulab.h"
|
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
|
|
||||||
#if ULAB_NUMERICAL_MODULE
|
mp_obj_t numerical_linspace(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_sum(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
extern mp_obj_module_t ulab_numerical_module;
|
mp_obj_t numerical_mean(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_std(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_min(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_max(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_argmin(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_argmax(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_roll(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
|
||||||
// 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 *);
|
||||||
|
mp_obj_t numerical_flip(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_diff(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_sort(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_sort_inplace(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
mp_obj_t numerical_argsort(size_t , const mp_obj_t *, mp_map_t *);
|
||||||
|
|
||||||
#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;\
|
||||||
|
|
@ -148,19 +157,4 @@ extern mp_obj_module_t ulab_numerical_module;
|
||||||
}\
|
}\
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
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
|
||||||
|
|
|
||||||
29
code/poly.c
29
code/poly.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -12,11 +11,12 @@
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/runtime.h"
|
#include "py/runtime.h"
|
||||||
#include "py/objarray.h"
|
#include "py/objarray.h"
|
||||||
|
#include "compat.h"
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
#include "linalg.h"
|
#include "linalg.h"
|
||||||
#include "poly.h"
|
#include "poly.h"
|
||||||
|
|
||||||
#if ULAB_POLY_MODULE
|
|
||||||
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) ||
|
||||||
|
|
@ -41,7 +41,7 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
||||||
// 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;
|
||||||
|
|
@ -83,8 +83,6 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
||||||
return MP_OBJ_FROM_PTR(out);
|
return MP_OBJ_FROM_PTR(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval);
|
|
||||||
|
|
||||||
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 +90,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
|
||||||
|
|
@ -194,20 +192,3 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
||||||
}
|
}
|
||||||
return MP_OBJ_FROM_PTR(beta);
|
return MP_OBJ_FROM_PTR(beta);
|
||||||
}
|
}
|
||||||
|
|
||||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
||||||
14
code/poly.h
14
code/poly.h
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -6,20 +5,13 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _POLY_
|
#ifndef _POLY_
|
||||||
#define _POLY_
|
#define _POLY_
|
||||||
|
|
||||||
#include "ulab.h"
|
mp_obj_t poly_polyval(mp_obj_t , mp_obj_t );
|
||||||
|
mp_obj_t poly_polyfit(size_t , const mp_obj_t *);
|
||||||
#if ULAB_POLY_MODULE
|
|
||||||
|
|
||||||
extern mp_obj_module_t ulab_poly_module;
|
|
||||||
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_2(poly_polyval_obj);
|
|
||||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
||||||
160
code/ulab.c
160
code/ulab.c
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -18,32 +17,89 @@
|
||||||
#include "py/obj.h"
|
#include "py/obj.h"
|
||||||
#include "py/objarray.h"
|
#include "py/objarray.h"
|
||||||
|
|
||||||
#include "ulab.h"
|
#include "compat.h"
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
#include "ndarray_properties.h"
|
|
||||||
#include "create.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.36.0");
|
STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.27.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);
|
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_asbytearray_obj, ndarray_asbytearray);
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_transpose_obj, linalg_transpose);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(linalg_reshape_obj, linalg_reshape);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_size_obj, 1, linalg_size);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
||||||
|
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erf_obj, vectorise_erf);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);
|
||||||
|
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft);
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum);
|
||||||
|
|
||||||
|
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve);
|
||||||
|
|
||||||
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_reshape), MP_ROM_PTR(&ndarray_reshape_obj) },
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ndarray_transpose_obj) },
|
|
||||||
{ MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_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) },
|
||||||
#if CIRCUITPY
|
{ MP_ROM_QSTR(MP_QSTR_asbytearray), MP_ROM_PTR(&ndarray_asbytearray_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&linalg_transpose_obj) },
|
||||||
|
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&linalg_reshape_obj) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
|
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
|
||||||
#endif
|
|
||||||
};
|
};
|
||||||
|
|
||||||
STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
|
STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
|
||||||
|
|
@ -57,7 +113,6 @@ const mp_obj_type_t ulab_ndarray_type = {
|
||||||
.getiter = ndarray_getiter,
|
.getiter = ndarray_getiter,
|
||||||
.unary_op = ndarray_unary_op,
|
.unary_op = ndarray_unary_op,
|
||||||
.binary_op = ndarray_binary_op,
|
.binary_op = ndarray_binary_op,
|
||||||
.buffer_p = { .get_buffer = ndarray_get_buffer, },
|
|
||||||
.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,
|
.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -65,31 +120,56 @@ 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 },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&create_zeros_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&create_ones_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&create_eye_obj },
|
{ MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_linspace), (mp_obj_t)&create_linspace_obj },
|
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&linalg_zeros_obj },
|
||||||
#if ULAB_LINALG_MODULE
|
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&linalg_ones_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) },
|
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&linalg_eye_obj },
|
||||||
#endif
|
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
|
||||||
#if ULAB_VECTORISE_MODULE
|
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_vector), MP_ROM_PTR(&ulab_vectorise_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj },
|
||||||
#endif
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj },
|
||||||
#if ULAB_NUMERICAL_MODULE
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_numerical), MP_ROM_PTR(&ulab_numerical_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj },
|
||||||
#endif
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj },
|
||||||
#if ULAB_POLY_MODULE
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_poly), MP_ROM_PTR(&ulab_poly_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj },
|
||||||
#endif
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj },
|
||||||
#if ULAB_FFT_MODULE
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&ulab_fft_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj },
|
||||||
#endif
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj },
|
||||||
#if ULAB_FILTER_MODULE
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_filter), MP_ROM_PTR(&ulab_filter_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj },
|
||||||
#endif
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj },
|
||||||
#if ULAB_EXTRAS_MODULE
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_lgamma), (mp_obj_t)&vectorise_lgamma_obj },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_extras), MP_ROM_PTR(&ulab_extras_module) },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj },
|
||||||
#endif
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
{ 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 },
|
||||||
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj },
|
||||||
// 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) },
|
||||||
{ MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) },
|
{ MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) },
|
||||||
|
|
@ -103,7 +183,7 @@ 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,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
39
code/ulab.h
39
code/ulab.h
|
|
@ -1,39 +0,0 @@
|
||||||
|
|
||||||
/*
|
|
||||||
* This file is part of the micropython-ulab project,
|
|
||||||
*
|
|
||||||
* https://github.com/v923z/micropython-ulab
|
|
||||||
*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __ULAB__
|
|
||||||
#define __ULAB__
|
|
||||||
|
|
||||||
// create
|
|
||||||
#define ULAB_CREATE_MODULE (1)
|
|
||||||
|
|
||||||
// vectorise (all functions) takes approx. 3 kB of flash space
|
|
||||||
#define ULAB_VECTORISE_MODULE (1)
|
|
||||||
|
|
||||||
// linalg adds around 6 kB
|
|
||||||
#define ULAB_LINALG_MODULE (1)
|
|
||||||
|
|
||||||
// poly is approx. 2.5 kB
|
|
||||||
#define ULAB_POLY_MODULE (1)
|
|
||||||
|
|
||||||
// numerical is about 12 kB
|
|
||||||
#define ULAB_NUMERICAL_MODULE (1)
|
|
||||||
|
|
||||||
// FFT costs about 2 kB of flash space
|
|
||||||
#define ULAB_FFT_MODULE (1)
|
|
||||||
|
|
||||||
// the filter module takes about 1 kB of flash space
|
|
||||||
#define ULAB_FILTER_MODULE (1)
|
|
||||||
|
|
||||||
// user-defined modules
|
|
||||||
#define ULAB_EXTRAS_MODULE (0)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -16,20 +15,20 @@
|
||||||
#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 "compat.h"
|
||||||
#include "vectorise.h"
|
#include "vectorise.h"
|
||||||
|
|
||||||
#ifndef MP_PI
|
#ifndef MP_PI
|
||||||
#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;
|
||||||
|
|
@ -62,111 +61,26 @@ mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) {
|
||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
MATH_FUN_1(acos, acos);
|
MATH_FUN_1(acos, acos);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos);
|
|
||||||
|
|
||||||
MATH_FUN_1(acosh, acosh);
|
MATH_FUN_1(acosh, acosh);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh);
|
|
||||||
|
|
||||||
MATH_FUN_1(asin, asin);
|
MATH_FUN_1(asin, asin);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asin_obj, vectorise_asin);
|
|
||||||
|
|
||||||
MATH_FUN_1(asinh, asinh);
|
MATH_FUN_1(asinh, asinh);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_asinh_obj, vectorise_asinh);
|
|
||||||
|
|
||||||
MATH_FUN_1(atan, atan);
|
MATH_FUN_1(atan, atan);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atan_obj, vectorise_atan);
|
|
||||||
|
|
||||||
MATH_FUN_1(atanh, atanh);
|
MATH_FUN_1(atanh, atanh);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_atanh_obj, vectorise_atanh);
|
|
||||||
|
|
||||||
MATH_FUN_1(ceil, ceil);
|
MATH_FUN_1(ceil, ceil);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_ceil_obj, vectorise_ceil);
|
|
||||||
|
|
||||||
MATH_FUN_1(cos, cos);
|
MATH_FUN_1(cos, cos);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_cos_obj, vectorise_cos);
|
|
||||||
|
|
||||||
MATH_FUN_1(cosh, cosh);
|
|
||||||
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);
|
|
||||||
|
|
||||||
MATH_FUN_1(erfc, erfc);
|
MATH_FUN_1(erfc, erfc);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_erfc_obj, vectorise_erfc);
|
|
||||||
|
|
||||||
MATH_FUN_1(exp, exp);
|
MATH_FUN_1(exp, exp);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_exp_obj, vectorise_exp);
|
|
||||||
|
|
||||||
MATH_FUN_1(expm1, expm1);
|
MATH_FUN_1(expm1, expm1);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_expm1_obj, vectorise_expm1);
|
|
||||||
|
|
||||||
MATH_FUN_1(floor, floor);
|
MATH_FUN_1(floor, floor);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_floor_obj, vectorise_floor);
|
|
||||||
|
|
||||||
MATH_FUN_1(gamma, tgamma);
|
MATH_FUN_1(gamma, tgamma);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_gamma_obj, vectorise_gamma);
|
|
||||||
|
|
||||||
MATH_FUN_1(lgamma, lgamma);
|
MATH_FUN_1(lgamma, lgamma);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_lgamma_obj, vectorise_lgamma);
|
|
||||||
|
|
||||||
MATH_FUN_1(log, log);
|
MATH_FUN_1(log, log);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log_obj, vectorise_log);
|
|
||||||
|
|
||||||
MATH_FUN_1(log10, log10);
|
MATH_FUN_1(log10, log10);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log10_obj, vectorise_log10);
|
|
||||||
|
|
||||||
MATH_FUN_1(log2, log2);
|
MATH_FUN_1(log2, log2);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_log2_obj, vectorise_log2);
|
|
||||||
|
|
||||||
MATH_FUN_1(sin, sin);
|
MATH_FUN_1(sin, sin);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sin_obj, vectorise_sin);
|
|
||||||
|
|
||||||
MATH_FUN_1(sinh, sinh);
|
MATH_FUN_1(sinh, sinh);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sinh_obj, vectorise_sinh);
|
|
||||||
|
|
||||||
MATH_FUN_1(sqrt, sqrt);
|
MATH_FUN_1(sqrt, sqrt);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_sqrt_obj, vectorise_sqrt);
|
|
||||||
|
|
||||||
MATH_FUN_1(tan, tan);
|
MATH_FUN_1(tan, tan);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);
|
|
||||||
|
|
||||||
MATH_FUN_1(tanh, tanh);
|
MATH_FUN_1(tanh, tanh);
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This file is part of the micropython-ulab project,
|
* This file is part of the micropython-ulab project,
|
||||||
*
|
*
|
||||||
|
|
@ -6,18 +5,37 @@
|
||||||
*
|
*
|
||||||
* The MIT License (MIT)
|
* The MIT License (MIT)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019-2020 Zoltán Vörös
|
* Copyright (c) 2019 Zoltán Vörös
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _VECTORISE_
|
#ifndef _VECTORISE_
|
||||||
#define _VECTORISE_
|
#define _VECTORISE_
|
||||||
|
|
||||||
#include "ulab.h"
|
|
||||||
#include "ndarray.h"
|
#include "ndarray.h"
|
||||||
|
|
||||||
#if ULAB_VECTORISE_MODULE
|
mp_obj_t vectorise_acos(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_acosh(mp_obj_t );
|
||||||
mp_obj_module_t ulab_vectorise_module;
|
mp_obj_t vectorise_asin(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_asinh(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_atan(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_atanh(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_ceil(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_cos(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_erf(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_erfc(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_exp(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_expm1(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_floor(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_gamma(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_lgamma(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_log(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_log10(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_log2(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_sin(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_sinh(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_sqrt(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_tan(mp_obj_t );
|
||||||
|
mp_obj_t vectorise_tanh(mp_obj_t );
|
||||||
|
|
||||||
#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;\
|
||||||
|
|
@ -32,4 +50,3 @@ mp_obj_module_t ulab_vectorise_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
|
||||||
|
|
|
||||||
|
|
@ -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.2'
|
release = '0.26'
|
||||||
|
|
||||||
|
|
||||||
# -- General configuration ---------------------------------------------------
|
# -- General configuration ---------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
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
|
||||||
----------
|
----------
|
||||||
|
|
||||||
``ulab`` is a numpy-like module for ``micropython``, meant to simplify
|
``ulab`` is a numpy-like module for micropython, meant to simplify and
|
||||||
and speed up common mathematical operations on arrays. The primary goal
|
speed up common mathematical operations on arrays. The primary goal was
|
||||||
was to implement a small subset of numpy that might be useful in the
|
to implement a small subset of numpy that might be useful in the context
|
||||||
context of a microcontroller. This means low-level data processing of
|
of a microcontroller. This means low-level data processing of linear
|
||||||
linear (array) and two-dimensional (matrix) data.
|
(array) and two-dimensional (matrix) data.
|
||||||
|
|
||||||
Purpose
|
Purpose
|
||||||
-------
|
-------
|
||||||
|
|
@ -27,9 +27,8 @@ microcontroller, the data volume is probably small, but it might lead to
|
||||||
catastrophic system failure, if these data are not processed in time,
|
catastrophic system failure, if these data are not processed in time,
|
||||||
because the microcontroller is supposed to interact with the outside
|
because the microcontroller is supposed to interact with the outside
|
||||||
world in a timely fashion. In fact, this latter objective was the
|
world in a timely fashion. In fact, this latter objective was the
|
||||||
initiator of this project: I needed the Fourier transform of a signal
|
initiator of this project: I needed the Fourier transform of the ADC
|
||||||
coming from the ADC of the pyboard, and all available options were
|
signal, and all the available options were simply too slow.
|
||||||
simply too slow.
|
|
||||||
|
|
||||||
In addition to speed, another issue that one has to keep in mind when
|
In addition to speed, another issue that one has to keep in mind when
|
||||||
working with embedded systems is the amount of available RAM: I believe,
|
working with embedded systems is the amount of available RAM: I believe,
|
||||||
|
|
@ -43,15 +42,15 @@ matter, whether they are all smaller than 100, or larger than one
|
||||||
hundred million. This is obviously a waste of resources in an
|
hundred million. This is obviously a waste of resources in an
|
||||||
environment, where resources are scarce.
|
environment, where resources are scarce.
|
||||||
|
|
||||||
Finally, there is a reason for using ``micropython`` in the first place.
|
Finally, there is a reason for using micropython in the first place.
|
||||||
Namely, that a microcontroller can be programmed in a very elegant, and
|
Namely, that a microcontroller can be programmed in a very elegant, and
|
||||||
*pythonic* way. But if it is so, why should we not extend this idea to
|
*pythonic* way. But if it is so, why should we not extend this idea to
|
||||||
other tasks and concepts that might come up in this context? If there
|
other tasks and concepts that might come up in this context? If there
|
||||||
was no other reason than this *elegance*, I would find that convincing
|
was no other reason than this *elegance*, I would find that convincing
|
||||||
enough.
|
enough.
|
||||||
|
|
||||||
Based on the above-mentioned considerations, all functions in ``ulab``
|
Based on the above-mentioned considerations, all functions are
|
||||||
are implemented in a way that
|
implemented in a way that
|
||||||
|
|
||||||
1. conforms to ``numpy`` as much as possible
|
1. conforms to ``numpy`` as much as possible
|
||||||
2. is so frugal with RAM as possible,
|
2. is so frugal with RAM as possible,
|
||||||
|
|
@ -63,17 +62,15 @@ The main points of ``ulab`` are
|
||||||
2 dimensions (arrays and matrices). These containers support all the
|
2 dimensions (arrays and matrices). These containers support all the
|
||||||
relevant unary and binary operators (e.g., ``len``, ==, +, \*, etc.)
|
relevant unary and binary operators (e.g., ``len``, ==, +, \*, etc.)
|
||||||
- vectorised computations on micropython iterables and numerical
|
- vectorised computations on micropython iterables and numerical
|
||||||
arrays/matrices (in ``numpy``-speak, universal functions)
|
arrays/matrices (in numpy-speak, universal functions)
|
||||||
- basic linear algebra routines (matrix inversion, multiplication,
|
- basic linear algebra routines (matrix inversion, multiplication,
|
||||||
reshaping, transposition, determinant, and eigenvalues)
|
reshaping, transposition, determinant, and eigenvalues)
|
||||||
- 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.33.2), the library
|
At the time of writing this manual (for version 0.26), the library adds
|
||||||
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
|
||||||
---------------------------
|
---------------------------
|
||||||
|
|
@ -98,9 +95,8 @@ Friendly request
|
||||||
|
|
||||||
If you use ``ulab``, and bump into a bug, or think that a particular
|
If you use ``ulab``, and bump into a bug, or think that a particular
|
||||||
function is missing, or its behaviour does not conform to ``numpy``,
|
function is missing, or its behaviour does not conform to ``numpy``,
|
||||||
please, raise a `ulab
|
please, raise an issue on github, so that the community can profit from
|
||||||
issue <#https://github.com/v923z/micropython-ulab/issues>`__ on github,
|
your experiences.
|
||||||
so that the community can profit from your experiences.
|
|
||||||
|
|
||||||
Even better, if you find the project useful, and think that it could be
|
Even better, if you find the project useful, and think that it could be
|
||||||
made better, faster, tighter, and shinier, please, consider
|
made better, faster, tighter, and shinier, please, consider
|
||||||
|
|
@ -112,89 +108,6 @@ These last comments apply to the documentation, too. If, in your
|
||||||
opinion, the documentation is obscure, misleading, or not detailed
|
opinion, the documentation is obscure, misleading, or not detailed
|
||||||
enough, please, let me know, so that *we* can fix it.
|
enough, please, let me know, so that *we* can fix it.
|
||||||
|
|
||||||
Differences between micropython-ulab and circuitpython-ulab
|
|
||||||
-----------------------------------------------------------
|
|
||||||
|
|
||||||
``ulab`` has originally been developed for ``micropython``, but has
|
|
||||||
since been integrated into a number of its flavours. Most of these
|
|
||||||
flavours are simply forks of ``micropython`` itself, with some
|
|
||||||
additional functionality. One of the notable exceptions is
|
|
||||||
``circuitpython``, which has slightly diverged at the core level, and
|
|
||||||
this has some minor consequences. Some of these concern the C
|
|
||||||
implementation details only, which all have been sorted out with the
|
|
||||||
generous and enthusiastic support of Jeff Epler from `Adafruit
|
|
||||||
Industries <http://www.adafruit.com>`__.
|
|
||||||
|
|
||||||
There are, however, a couple of instances, where the usage in the two
|
|
||||||
environments is slightly different at the python level. These are how
|
|
||||||
the packges can be imported, and how the class properties can be
|
|
||||||
accessed. In both cases, the ``circuitpython`` implementation results in
|
|
||||||
``numpy``-conform code. ``numpy``-compatibility in ``micropython`` will
|
|
||||||
be implemented as soon as ``micropython`` itself has the required tools.
|
|
||||||
Till then we have to live with a workaround, which I will point out at
|
|
||||||
the relevant places.
|
|
||||||
|
|
||||||
Customising ``ulab``
|
|
||||||
====================
|
|
||||||
|
|
||||||
``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
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
import ulab
|
|
||||||
from ulab import fft
|
|
||||||
|
|
||||||
by which point you can get the FFT of your data by calling
|
|
||||||
``fft.fft(...)``.
|
|
||||||
|
|
||||||
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
|
|
||||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__
|
|
||||||
header file contains a pre-processor flag for each sub-module. The
|
|
||||||
default setting is 1 for each of them. Setting them to 0 removes the
|
|
||||||
module from 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_MODULE (1)
|
|
||||||
|
|
||||||
// linalg adds around 6 kB
|
|
||||||
#define ULAB_LINALG_MODULE (1)
|
|
||||||
|
|
||||||
// poly is approx. 2.5 kB
|
|
||||||
#define ULAB_POLY_MODULE (1)
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
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 or sub-module
|
|
||||||
is part of your ``ulab`` firmware, or not. The alternative, namely, that
|
|
||||||
you do not have to import anything beyond ``ulab``, could prove
|
|
||||||
catastrophic: you would learn only at run time (at the moment of calling
|
|
||||||
the function in your code) that a particular function is not in the
|
|
||||||
firmware, and that is most probably too late.
|
|
||||||
|
|
||||||
Except for ``fft``, the standard sub-modules, ``vector``, ``linalg``,
|
|
||||||
``numerical``, ``and poly``\ 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. Hints as to
|
|
||||||
how to do that can be found in the section `Extending
|
|
||||||
ulab <#Extending-ulab>`__.
|
|
||||||
|
|
||||||
Supported functions and methods
|
Supported functions and methods
|
||||||
===============================
|
===============================
|
||||||
|
|
||||||
|
|
@ -249,21 +162,23 @@ calls on general iterables)
|
||||||
Methods of ndarrays
|
Methods of ndarrays
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
`.shape\* <#.shape>`__
|
`.shape <#.shape>`__
|
||||||
|
|
||||||
`size\* <#size>`__
|
|
||||||
|
|
||||||
`itemsize\* <#itemsize>`__
|
|
||||||
|
|
||||||
`.reshape <#.reshape>`__
|
`.reshape <#.reshape>`__
|
||||||
|
|
||||||
|
`.rawsize\*\* <#.rawsize>`__
|
||||||
|
|
||||||
`.transpose <#.transpose>`__
|
`.transpose <#.transpose>`__
|
||||||
|
|
||||||
`.flatten\*\* <#.flatten>`__
|
`.flatten\*\* <#.flatten>`__
|
||||||
|
|
||||||
|
`.asbytearray <#.asbytearray>`__
|
||||||
|
|
||||||
Matrix methods
|
Matrix methods
|
||||||
--------------
|
--------------
|
||||||
|
|
||||||
|
`size <#size>`__
|
||||||
|
|
||||||
`inv <#inv>`__
|
`inv <#inv>`__
|
||||||
|
|
||||||
`dot <#dot>`__
|
`dot <#dot>`__
|
||||||
|
|
@ -324,20 +239,19 @@ FFT routines
|
||||||
|
|
||||||
`spectrum\*\* <#spectrum>`__
|
`spectrum\*\* <#spectrum>`__
|
||||||
|
|
||||||
Filter functions
|
Filter routines
|
||||||
----------------
|
---------------
|
||||||
|
|
||||||
`convolve <#convolve>`__
|
`convolve\* <#convolve>`__
|
||||||
|
|
||||||
ndarray, the basic container
|
ndarray, the basic container
|
||||||
============================
|
============================
|
||||||
|
|
||||||
The ``ndarray`` is the underlying container of numerical data. It is
|
The ``ndarray`` is the underlying container of numerical data. It is
|
||||||
derived from micropython’s own ``array`` object, but has a great number
|
derived from micropython’s own ``array`` object, but has a great number
|
||||||
of extra features starting with how it can be initialised, which
|
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
|
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
|
argument.
|
||||||
proper ``micropython`` iterable.
|
|
||||||
|
|
||||||
Since the ``ndarray`` is a binary container, it is also compact, meaning
|
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
|
that it takes only a couple of bytes of extra RAM in addition to what is
|
||||||
|
|
@ -351,7 +265,7 @@ precision/size of the ``float`` type depends on the definition of
|
||||||
``mp_float_t``. Some platforms, e.g., the PYBD, implement ``double``\ s,
|
``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
|
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
|
float your particular platform implements by looking at the output of
|
||||||
the `.itemsize <#.itemsize>`__ class property.
|
the `.rawsize <#.rawsize>`__ class method.
|
||||||
|
|
||||||
On the following pages, we will see how one can work with
|
On the following pages, we will see how one can work with
|
||||||
``ndarray``\ s. Those familiar with ``numpy`` should find that the
|
``ndarray``\ s. Those familiar with ``numpy`` should find that the
|
||||||
|
|
@ -359,7 +273,7 @@ nomenclature and naming conventions of ``numpy`` are adhered to as
|
||||||
closely as possible. I will point out the few differences, where
|
closely as possible. I will point out the few differences, where
|
||||||
necessary.
|
necessary.
|
||||||
|
|
||||||
For the sake of comparison, in addition to the ``ulab`` code snippets,
|
For the sake of comparison, in addition to ``ulab`` code snippets,
|
||||||
sometimes the equivalent ``numpy`` code is also presented. You can find
|
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,
|
out, where the snippet is supposed to run by looking at its first line,
|
||||||
the header.
|
the header.
|
||||||
|
|
@ -483,11 +397,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.
|
||||||
|
|
||||||
**WARNING:** In ``circuitpython``, you can call the method as a
|
|
||||||
property, i.e.,
|
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
|
|
@ -497,38 +408,7 @@ property, i.e.,
|
||||||
|
|
||||||
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)
|
|
||||||
print("\nb:\n", b)
|
|
||||||
print("shape of b:", b.shape)
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
a:
|
|
||||||
array([1, 2, 3, 4], dtype=int8)
|
|
||||||
shape of a: (1, 4)
|
|
||||||
|
|
||||||
b:
|
|
||||||
array([[1, 2],
|
|
||||||
[3, 4]], dtype=int8)
|
|
||||||
shape of b: (2, 2)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**WARNING:** On the other hand, since properties are not implemented in
|
|
||||||
``micropython``, there you would call the method as a function, i.e.,
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
# code to be run in micropython
|
|
||||||
|
|
||||||
import ulab as np
|
|
||||||
|
|
||||||
a = np.array([1, 2, 3, 4], dtype=np.int8)
|
|
||||||
print("a:\n", a)
|
|
||||||
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)
|
||||||
|
|
@ -548,139 +428,6 @@ property, i.e.,
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.size
|
|
||||||
~~~~~
|
|
||||||
|
|
||||||
The ``.size`` method (property) returns an integer with the number of
|
|
||||||
elements in the array.
|
|
||||||
|
|
||||||
**WARNING:** In ``circuitpython``, the ``numpy`` nomenclature applies,
|
|
||||||
i.e.,
|
|
||||||
|
|
||||||
.. 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**WARNING:** In ``micropython``, ``size`` is a method, i.e.,
|
|
||||||
|
|
||||||
.. 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.
|
|
||||||
|
|
||||||
**WARNING:** In ``circuitpython``:
|
|
||||||
|
|
||||||
.. 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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
**WARNING:** In ``micropython``:
|
|
||||||
|
|
||||||
.. 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
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -717,6 +464,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
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -758,6 +540,83 @@ verbatim copy of the contents.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.asbytearray
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The contents of an ``ndarray`` can be accessed directly by calling the
|
||||||
|
``.asbytearray`` method. This will simply return a pointer to the
|
||||||
|
underlying flat ``array`` object, which can then be manipulated
|
||||||
|
directly.
|
||||||
|
|
||||||
|
**WARNING:** ``asbytearray`` is a ``ulab``-only method; it has no
|
||||||
|
equivalent in ``numpy``.
|
||||||
|
|
||||||
|
In the example below, note the difference between ``a``, and ``buffer``:
|
||||||
|
while both are designated as an array, you recognise the micropython
|
||||||
|
array from the fact that it prints the typecode (``b`` in this
|
||||||
|
particular case). The ``ndarray``, on the other hand, prints out the
|
||||||
|
``dtype`` (``int8`` here).
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
# code to be run in micropython
|
||||||
|
|
||||||
|
import ulab as np
|
||||||
|
|
||||||
|
a = np.array([1, 2, 3, 4], dtype=np.int8)
|
||||||
|
print('a: ', a)
|
||||||
|
buffer = a.asbytearray()
|
||||||
|
print("array content:", buffer)
|
||||||
|
buffer[1] = 123
|
||||||
|
print("array content:", buffer)
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
a: array([1, 2, 3, 4], dtype=int8)
|
||||||
|
array content: array('b', [1, 2, 3, 4])
|
||||||
|
array content: array('b', [1, 123, 3, 4])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
This in itself wouldn’t be very interesting, but since ``buffer`` is a
|
||||||
|
proper micropython ``array``, we can pass it to functions that can
|
||||||
|
employ the buffer protocol. E.g., all the ``ndarray`` facilities can be
|
||||||
|
applied to the results of timed ADC conversions.
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
# code to be run in micropython
|
||||||
|
|
||||||
|
import pyb
|
||||||
|
import ulab as np
|
||||||
|
|
||||||
|
n = 100
|
||||||
|
|
||||||
|
adc = pyb.ADC(pyb.Pin.board.X19)
|
||||||
|
tim = pyb.Timer(6, freq=10)
|
||||||
|
|
||||||
|
a = np.array([0]*n, dtype=np.uint8)
|
||||||
|
buffer = a.asbytearray()
|
||||||
|
adc.read_timed(buffer, tim)
|
||||||
|
|
||||||
|
print("ADC results:\t", a)
|
||||||
|
print("mean of results:\t", np.mean(a))
|
||||||
|
print("std of results:\t", np.std(a))
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
ADC results: array([48, 2, 2, ..., 0, 0, 0], dtype=uint8)
|
||||||
|
mean of results: 1.22
|
||||||
|
std of results: 4.744639
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Likewise, data can be read directly into ``ndarray``\ s from other
|
||||||
|
interfaces, e.g., SPI, I2C etc, and also, by laying bare the
|
||||||
|
``ndarray``, we can pass results of ``ulab`` computations to anything
|
||||||
|
that can read from a buffer.
|
||||||
|
|
||||||
.transpose
|
.transpose
|
||||||
~~~~~~~~~~
|
~~~~~~~~~~
|
||||||
|
|
||||||
|
|
@ -1187,10 +1046,6 @@ take the following snippet from the micropython manual:
|
||||||
return result
|
return result
|
||||||
return new_func
|
return new_func
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. code::
|
.. code::
|
||||||
|
|
||||||
|
|
@ -2193,6 +2048,7 @@ spaced numbers between 0, and two pi, and sort them:
|
||||||
print('b: ', b)
|
print('b: ', b)
|
||||||
sort_time(b)
|
sort_time(b)
|
||||||
print('\nb sorted:\n', b)
|
print('\nb sorted:\n', b)
|
||||||
|
|
||||||
argsort
|
argsort
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
|
@ -2932,20 +2788,16 @@ parts of the transform separately.
|
||||||
# code to be run in micropython
|
# code to be run in micropython
|
||||||
|
|
||||||
import ulab as np
|
import ulab as np
|
||||||
from ulab import numerical
|
|
||||||
from ulab import vector
|
|
||||||
from ulab import fft
|
|
||||||
from ulab import linalg
|
|
||||||
|
|
||||||
x = numerical.linspace(0, 10, num=1024)
|
x = np.linspace(0, 10, num=1024)
|
||||||
y = vector.sin(x)
|
y = np.sin(x)
|
||||||
z = linalg.zeros(len(x))
|
z = np.zeros(len(x))
|
||||||
|
|
||||||
a, b = fft.fft(x)
|
a, b = np.fft(x)
|
||||||
print('real part:\t', a)
|
print('real part:\t', a)
|
||||||
print('\nimaginary part:\t', b)
|
print('\nimaginary part:\t', b)
|
||||||
|
|
||||||
c, d = fft.fft(x, z)
|
c, d = np.fft(x, z)
|
||||||
print('\nreal part:\t', c)
|
print('\nreal part:\t', c)
|
||||||
print('\nimaginary part:\t', d)
|
print('\nimaginary part:\t', d)
|
||||||
|
|
||||||
|
|
@ -3061,6 +2913,33 @@ As such, ``spectrum`` is really just a shorthand for
|
||||||
spectrum calculated the lazy way: array([187.8641, 315.3125, 347.8804, ..., 84.4587, 347.8803, 315.3124], dtype=float)
|
spectrum calculated the lazy way: array([187.8641, 315.3125, 347.8804, ..., 84.4587, 347.8803, 315.3124], dtype=float)
|
||||||
|
|
||||||
|
|
||||||
|
Filter routines
|
||||||
|
===============
|
||||||
|
|
||||||
|
numpy:
|
||||||
|
https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html
|
||||||
|
|
||||||
|
convolve
|
||||||
|
--------
|
||||||
|
Returns the discrete, linear convolution of two one-dimensional sequences.
|
||||||
|
|
||||||
|
Only the ``full`` mode is supported, and the ``mode`` named parameter is not accepted.
|
||||||
|
Note that all other modes can be had by slicing a ``full`` result.
|
||||||
|
|
||||||
|
.. code::
|
||||||
|
|
||||||
|
# code to be run in micropython
|
||||||
|
|
||||||
|
import ulab as np
|
||||||
|
|
||||||
|
x = np.array((1,2,3))
|
||||||
|
y = np.array((1,10,100,1000))
|
||||||
|
|
||||||
|
print(np.convolve(x, y))
|
||||||
|
|
||||||
|
.. parsed-literal::
|
||||||
|
|
||||||
|
array([1.0, 12.0, 123.0, 1230.0, 2300.0, 3000.0], dtype=float)
|
||||||
|
|
||||||
Computation and storage costs
|
Computation and storage costs
|
||||||
-----------------------------
|
-----------------------------
|
||||||
|
|
@ -3131,56 +3010,17 @@ By combining the two observations above, if you place the first signal,
|
||||||
combined signal, then the Fourier transforms of the two components can
|
combined signal, then the Fourier transforms of the two components can
|
||||||
be recovered as
|
be recovered as
|
||||||
|
|
||||||
:raw-latex:`\begin{eqnarray}
|
| :math:`Y_1(k) = \frac{1}{2}\left(Y(k) + Y^*(N-k)\right)`
|
||||||
Y_1(k) &=& \frac{1}{2}\left(Y(k) + Y^*(N-k)\right)
|
| :math:`Y_2(k) = -\frac{i}{2}\left(Y(k) - Y^*(N-k)\right)`
|
||||||
\\
|
|
||||||
Y_2(k) &=& -\frac{i}{2}\left(Y(k) - Y^*(N-k)\right)
|
where :math:`N` is the length of :math:`y_1`, and
|
||||||
\end{eqnarray}` where :math:`N` is the length of :math:`y_1`, and
|
|
||||||
:math:`Y_1, Y_2`, and :math:`Y`, respectively, are the Fourier
|
:math:`Y_1, Y_2`, and :math:`Y`, respectively, are the Fourier
|
||||||
transforms of :math:`y_1, y_2`, and :math:`y = y_1 + iy_2`.
|
transforms of :math:`y_1, y_2`, and :math:`y = y_1 + iy_2`.
|
||||||
|
|
||||||
Filter routines
|
|
||||||
===============
|
|
||||||
|
|
||||||
numpy:
|
|
||||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html
|
|
||||||
|
|
||||||
convolve
|
|
||||||
--------
|
|
||||||
|
|
||||||
Returns the discrete, linear convolution of two one-dimensional
|
|
||||||
sequences.
|
|
||||||
|
|
||||||
Only the ``full`` mode is supported, and the ``mode`` named parameter is
|
|
||||||
not accepted. Note that all other modes can be had by slicing a ``full``
|
|
||||||
result.
|
|
||||||
|
|
||||||
.. code::
|
|
||||||
|
|
||||||
# code to be run in micropython
|
|
||||||
|
|
||||||
import ulab as np
|
|
||||||
|
|
||||||
x = np.array((1,2,3))
|
|
||||||
y = np.array((1,10,100,1000))
|
|
||||||
|
|
||||||
print(np.convolve(x, y))
|
|
||||||
|
|
||||||
.. parsed-literal::
|
|
||||||
|
|
||||||
array([1.0, 12.0, 123.0, 1230.0, 2300.0, 3000.0], dtype=float)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Extending ulab
|
Extending ulab
|
||||||
==============
|
==============
|
||||||
|
|
||||||
As mentioned at the beginning, ``ulab`` is a set of sub-modules, out of
|
New functions can easily be added to ``ulab`` in a couple of simple
|
||||||
which one, ``extra`` is explicitly reserved for user code. You should
|
|
||||||
implement your functions in this sub-module, or sub-modules thereof.
|
|
||||||
|
|
||||||
The new functions can easily be added to ``extra`` in a couple of simple
|
|
||||||
steps. At the C level, the type definition of an ``ndarray`` is as
|
steps. At the C level, the type definition of an ``ndarray`` is as
|
||||||
follows:
|
follows:
|
||||||
|
|
||||||
|
|
@ -3230,7 +3070,7 @@ or
|
||||||
The ambiguity is caused by the fact that not all platforms implement
|
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
|
``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
|
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
|
``ndarray.h``, this is already taken care of: the preprocessor figures
|
||||||
out, what the ``float`` implementation of the hardware platform is, and
|
out, what the ``float`` implementation of the hardware platform is, and
|
||||||
defines the ``NDARRAY_FLOAT`` typecode accordingly. All you have to keep
|
defines the ``NDARRAY_FLOAT`` typecode accordingly. All you have to keep
|
||||||
in mind is that wherever you would use ``float`` or ``double``, you have
|
in mind is that wherever you would use ``float`` or ``double``, you have
|
||||||
|
|
@ -3407,15 +3247,47 @@ and return that, you could work along the following lines:
|
||||||
return MP_PTR_TO_OBJ(ndarray);
|
return MP_PTR_TO_OBJ(ndarray);
|
||||||
}
|
}
|
||||||
|
|
||||||
Once the function implementation is done, you should add the function
|
In the boilerplate above, we cast the pointer to ``array->items`` to the
|
||||||
object to the globals dictionary of the ``extra`` sub-module as
|
required type. There are certain operations, however, when you do not
|
||||||
|
need the casting. If you do not want to change the array’s values, only
|
||||||
|
their position within the array, you can get away with copying the
|
||||||
|
memory content, regardless the type. A good example for such a scenario
|
||||||
|
is the transpose function in
|
||||||
|
https://github.com/v923z/micropython-ulab/blob/master/code/linalg.c.
|
||||||
|
|
||||||
|
Compiling your module
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
Once you have implemented the functionality you wanted, you have to
|
||||||
|
include the source code in the make file by adding it to
|
||||||
|
``micropython.mk``:
|
||||||
|
|
||||||
|
.. code:: makefile
|
||||||
|
|
||||||
|
USERMODULES_DIR := $(USERMOD_DIR)
|
||||||
|
|
||||||
|
# Add all C files to SRC_USERMOD.
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/linalg.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/poly.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/fft.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/numerical.c
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/ulab.c
|
||||||
|
|
||||||
|
SRC_USERMOD += $(USERMODULES_DIR)/your_module.c
|
||||||
|
|
||||||
|
CFLAGS_USERMOD += -I$(USERMODULES_DIR)
|
||||||
|
|
||||||
|
In addition, you also have to add the function objects to ``ulab.c``,
|
||||||
|
and create a ``QString`` for the function name:
|
||||||
|
|
||||||
.. code:: c
|
.. code:: c
|
||||||
|
|
||||||
...
|
...
|
||||||
MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);
|
MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);
|
||||||
...
|
...
|
||||||
STATIC const mp_map_elem_t extra_globals_table[] = {
|
STATIC const mp_map_elem_t ulab_globals_table[] = {
|
||||||
...
|
...
|
||||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_useless), (mp_obj_t)&useless_function_obj },
|
{ MP_OBJ_NEW_QSTR(MP_QSTR_useless), (mp_obj_t)&useless_function_obj },
|
||||||
...
|
...
|
||||||
|
|
@ -3433,18 +3305,24 @@ and so on. For a thorough discussion on how function objects have to be
|
||||||
defined, see, e.g., the `user module programming
|
defined, see, e.g., the `user module programming
|
||||||
manual <#https://micropython-usermod.readthedocs.io/en/latest/>`__.
|
manual <#https://micropython-usermod.readthedocs.io/en/latest/>`__.
|
||||||
|
|
||||||
And with that, you are done. You can simply call the compiler as
|
At this point, you should be able to compile the module with your
|
||||||
|
extension by running ``make`` on the command line
|
||||||
|
|
||||||
.. code:: bash
|
.. code:: bash
|
||||||
|
|
||||||
make BOARD=PYBV11 USER_C_MODULES=../../../ulab all
|
make USER_C_MODULES=../../../ulab all
|
||||||
|
|
||||||
and the rest is taken care of.
|
for the unix port, and
|
||||||
|
|
||||||
In the boilerplate above, we cast the pointer to ``array->items`` to the
|
.. code:: bash
|
||||||
required type. There are certain operations, however, when you do not
|
|
||||||
need the casting. If you do not want to change the array’s values, only
|
make BOARD=PYBV11 CROSS_COMPILE=<arm_tools_path>/bin/arm-none-eabi- USER_C_MODULES=../../../ulab all
|
||||||
their position within the array, you can get away with copying the
|
|
||||||
memory content, regardless the type. A good example for such a scenario
|
for the ``pyboard``, provided that the you have defined
|
||||||
is the transpose function in
|
|
||||||
https://github.com/v923z/micropython-ulab/blob/master/code/linalg.c.
|
.. code:: makefile
|
||||||
|
|
||||||
|
#define MODULE_ULAB_ENABLED (1)
|
||||||
|
|
||||||
|
somewhere in ``micropython/port/unix/mpconfigport.h``, or
|
||||||
|
``micropython/stm32/mpconfigport.h``, respectively.
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1,3 @@
|
||||||
Thu, 27 Feb 2020
|
|
||||||
|
|
||||||
version 0.36.0
|
|
||||||
|
|
||||||
moved zeros, ones, eye and linspace into separate module (they are still bound at the top level)
|
|
||||||
|
|
||||||
Thu, 27 Feb 2020
|
|
||||||
|
|
||||||
version 0.35.0
|
|
||||||
|
|
||||||
Move zeros, ones back into top level ulab module
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
version 0.31.0
|
|
||||||
|
|
||||||
removed asbytearray, and added buffer protocol to ndarrays, fixed bad error in filter.c
|
|
||||||
|
|
||||||
Sun, 09 Feb 2020
|
|
||||||
|
|
||||||
version 0.30.2
|
|
||||||
|
|
||||||
fixed slice_length in ndarray.c
|
|
||||||
|
|
||||||
Sat, 08 Feb 2020
|
|
||||||
|
|
||||||
version 0.30.1
|
|
||||||
|
|
||||||
fixed typecode error, added variable inspection, and replaced ternary operators in filter.c
|
|
||||||
|
|
||||||
Fri, 07 Feb 2020
|
|
||||||
|
|
||||||
version 0.30.0
|
|
||||||
|
|
||||||
ulab functions can arbitrarily be excluded from the firmware via the ulab.h configuration file
|
|
||||||
|
|
||||||
Thu, 06 Feb 2020
|
Thu, 06 Feb 2020
|
||||||
|
|
||||||
version 0.27.0
|
version 0.27.0
|
||||||
|
|
|
||||||
|
|
@ -24,11 +24,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 2,
|
"execution_count": 23,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2020-02-26T17:04:16.562607Z",
|
"end_time": "2019-11-05T16:01:28.817558Z",
|
||||||
"start_time": "2020-02-26T17:04:16.502531Z"
|
"start_time": "2019-11-05T16:01:28.810704Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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.2'\n",
|
"release = '0.26'\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"# -- General configuration ---------------------------------------------------\n",
|
"# -- General configuration ---------------------------------------------------\n",
|
||||||
|
|
@ -120,11 +120,10 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 3,
|
"execution_count": null,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2020-02-26T17:04:49.527515Z",
|
"start_time": "2019-11-06T17:37:29.723Z"
|
||||||
"start_time": "2020-02-26T17:04:21.416456Z"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
|
|
@ -293,11 +292,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 17,
|
"execution_count": 3,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2020-02-16T14:53:49.098172Z",
|
"end_time": "2019-11-04T20:57:36.730820Z",
|
||||||
"start_time": "2020-02-16T14:53:49.093201Z"
|
"start_time": "2019-11-04T20:57:36.723446Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
|
|
@ -311,11 +310,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 18,
|
"execution_count": 4,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2020-02-16T14:53:53.396267Z",
|
"end_time": "2019-11-04T20:57:38.576560Z",
|
||||||
"start_time": "2020-02-16T14:53:53.375754Z"
|
"start_time": "2019-11-04T20:57:38.521927Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
|
|
@ -384,20 +383,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 +401,11 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "code",
|
||||||
"execution_count": 115,
|
"execution_count": 501,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"ExecuteTime": {
|
"ExecuteTime": {
|
||||||
"end_time": "2020-02-16T18:50:42.907664Z",
|
"end_time": "2019-10-19T13:36:42.010602Z",
|
||||||
"start_time": "2020-02-16T18:50:42.903709Z"
|
"start_time": "2019-10-19T13:36:42.003900Z"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"outputs": [],
|
"outputs": [],
|
||||||
|
|
@ -485,21 +477,21 @@
|
||||||
"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",
|
||||||
"`ulab` is a numpy-like module for `micropython`, meant to simplify and speed up common mathematical operations on arrays. The primary goal was to implement a small subset of numpy that might be useful in the context of a microcontroller. This means low-level data processing of linear (array) and two-dimensional (matrix) data.\n",
|
"`ulab` is a numpy-like module for micropython, meant to simplify and speed up common mathematical operations on arrays. The primary goal was to implement a small subset of numpy that might be useful in the context of a microcontroller. This means low-level data processing of linear (array) and two-dimensional (matrix) data.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"## Purpose\n",
|
"## Purpose\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Of course, the first question that one has to answer is, why on Earth one would need a fast math library on a microcontroller. After all, it is not expected that heavy number crunching is going to take place on bare metal. It is not meant to. On a PC, the main reason for writing fast code is the sheer amount of data that one wants to process. On a microcontroller, the data volume is probably small, but it might lead to catastrophic system failure, if these data are not processed in time, because the microcontroller is supposed to interact with the outside world in a timely fashion. In fact, this latter objective was the initiator of this project: I needed the Fourier transform of a signal coming from the ADC of the pyboard, and all available options were simply too slow. \n",
|
"Of course, the first question that one has to answer is, why on Earth one would need a fast math library on a microcontroller. After all, it is not expected that heavy number crunching is going to take place on bare metal. It is not meant to. On a PC, the main reason for writing fast code is the sheer amount of data that one wants to process. On a microcontroller, the data volume is probably small, but it might lead to catastrophic system failure, if these data are not processed in time, because the microcontroller is supposed to interact with the outside world in a timely fashion. In fact, this latter objective was the initiator of this project: I needed the Fourier transform of the ADC signal, and all the available options were simply too slow. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"In addition to speed, another issue that one has to keep in mind when working with embedded systems is the amount of available RAM: I believe, everything here could be implemented in pure python with relatively little effort, but the price we would have to pay for that is not only speed, but RAM, too. python code, if is not frozen, and compiled into the firmware, has to be compiled at runtime, which is not exactly a cheap process. On top of that, if numbers are stored in a list or tuple, which would be the high-level container, then they occupy 8 bytes, no matter, whether they are all smaller than 100, or larger than one hundred million. This is obviously a waste of resources in an environment, where resources are scarce. \n",
|
"In addition to speed, another issue that one has to keep in mind when working with embedded systems is the amount of available RAM: I believe, everything here could be implemented in pure python with relatively little effort, but the price we would have to pay for that is not only speed, but RAM, too. python code, if is not frozen, and compiled into the firmware, has to be compiled at runtime, which is not exactly a cheap process. On top of that, if numbers are stored in a list or tuple, which would be the high-level container, then they occupy 8 bytes, no matter, whether they are all smaller than 100, or larger than one hundred million. This is obviously a waste of resources in an environment, where resources are scarce. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Finally, there is a reason for using `micropython` in the first place. Namely, that a microcontroller can be programmed in a very elegant, and *pythonic* way. But if it is so, why should we not extend this idea to other tasks and concepts that might come up in this context? If there was no other reason than this *elegance*, I would find that convincing enough.\n",
|
"Finally, there is a reason for using micropython in the first place. Namely, that a microcontroller can be programmed in a very elegant, and *pythonic* way. But if it is so, why should we not extend this idea to other tasks and concepts that might come up in this context? If there was no other reason than this *elegance*, I would find that convincing enough.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Based on the above-mentioned considerations, all functions in `ulab` are implemented in a way that \n",
|
"Based on the above-mentioned considerations, all functions are implemented in a way that \n",
|
||||||
"\n",
|
"\n",
|
||||||
"1. conforms to `numpy` as much as possible\n",
|
"1. conforms to `numpy` as much as possible\n",
|
||||||
"2. is so frugal with RAM as possible,\n",
|
"2. is so frugal with RAM as possible,\n",
|
||||||
|
|
@ -508,12 +500,12 @@
|
||||||
"The main points of `ulab` are \n",
|
"The main points of `ulab` are \n",
|
||||||
"\n",
|
"\n",
|
||||||
"- compact, iterable and slicable containers of numerical data in 1, and 2 dimensions (arrays and matrices). These containers support all the relevant unary and binary operators (e.g., `len`, ==, +, *, etc.)\n",
|
"- compact, iterable and slicable containers of numerical data in 1, and 2 dimensions (arrays and matrices). These containers support all the relevant unary and binary operators (e.g., `len`, ==, +, *, etc.)\n",
|
||||||
"- vectorised computations on micropython iterables and numerical arrays/matrices (in `numpy`-speak, universal functions)\n",
|
"- vectorised computations on micropython iterables and numerical arrays/matrices (in numpy-speak, universal functions)\n",
|
||||||
"- basic linear algebra routines (matrix inversion, multiplication, reshaping, transposition, determinant, and eigenvalues)\n",
|
"- basic linear algebra routines (matrix inversion, multiplication, reshaping, transposition, determinant, and eigenvalues)\n",
|
||||||
"- 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.33.2), 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",
|
||||||
|
|
@ -523,53 +515,11 @@
|
||||||
"\n",
|
"\n",
|
||||||
"## Friendly request\n",
|
"## Friendly request\n",
|
||||||
"\n",
|
"\n",
|
||||||
"If you use `ulab`, and bump into a bug, or think that a particular function is missing, or its behaviour does not conform to `numpy`, please, raise a [ulab issue](#https://github.com/v923z/micropython-ulab/issues) on github, so that the community can profit from your experiences. \n",
|
"If you use `ulab`, and bump into a bug, or think that a particular function is missing, or its behaviour does not conform to `numpy`, please, raise an issue on github, so that the community can profit from your experiences. \n",
|
||||||
"\n",
|
"\n",
|
||||||
"Even better, if you find the project useful, and think that it could be made better, faster, tighter, and shinier, please, consider contributing, and issue a pull request with the implementation of your improvements and new features. `ulab` can only become successful, if it offers what the community needs.\n",
|
"Even better, if you find the project useful, and think that it could be made better, faster, tighter, and shinier, please, consider contributing, and issue a pull request with the implementation of your improvements and new features. `ulab` can only become successful, if it offers what the community needs.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"These last comments apply to the documentation, too. If, in your opinion, the documentation is obscure, misleading, or not detailed enough, please, let me know, so that *we* can fix it.\n",
|
"These last comments apply to the documentation, too. If, in your opinion, the documentation is obscure, misleading, or not detailed enough, please, let me know, so that *we* can fix it."
|
||||||
"\n",
|
|
||||||
"## Differences between micropython-ulab and circuitpython-ulab\n",
|
|
||||||
"\n",
|
|
||||||
"`ulab` has originally been developed for `micropython`, but has since been integrated into a number of its flavours. Most of these flavours are simply forks of `micropython` itself, with some additional functionality. One of the notable exceptions is `circuitpython`, which has slightly diverged at the core level, and this has some minor consequences. Some of these concern the C implementation details only, which all have been sorted out with the generous and enthusiastic support of Jeff Epler from [Adafruit Industries](http://www.adafruit.com).\n",
|
|
||||||
"\n",
|
|
||||||
"There are, however, a couple of instances, where the usage in the two environments is slightly different at the python level. These are how the packges can be imported, and how the class properties can be accessed. In both cases, the `circuitpython` implementation results in `numpy`-conform code. `numpy`-compatibility in `micropython` will be implemented as soon as `micropython` itself has the required tools. Till then we have to live with a workaround, which I will point out at the relevant places."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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 [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h) header file contains a pre-processor flag for each sub-module. The default setting is 1 for each of them. Setting them to 0 removes the module from 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 or sub-module is part of your `ulab` firmware, or not. The alternative, namely, that you do not have to import anything beyond `ulab`, could prove catastrophic: you would learn only at run time (at the moment of calling the function in your code) that a particular function is not in the firmware, and that is most probably too late.\n",
|
|
||||||
"\n",
|
|
||||||
"Except for `fft`, the standard sub-modules, `vector`, `linalg`, `numerical`, `and poly`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. Hints as to how to do that can be found in the section [Extending ulab](#Extending-ulab)."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -639,20 +589,22 @@
|
||||||
"\n",
|
"\n",
|
||||||
"## Methods of ndarrays\n",
|
"## Methods of ndarrays\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[.shape<sup>*</sup>](#.shape)\n",
|
"[.shape](#.shape)\n",
|
||||||
"\n",
|
|
||||||
"[size<sup>*</sup>](#size)\n",
|
|
||||||
"\n",
|
|
||||||
"[itemsize<sup>*</sup>](#itemsize)\n",
|
|
||||||
"\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",
|
||||||
"\n",
|
"\n",
|
||||||
|
"[.asbytearray](#.asbytearray)\n",
|
||||||
|
"\n",
|
||||||
"## Matrix methods\n",
|
"## Matrix methods\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
"[size](#size)\n",
|
||||||
|
"\n",
|
||||||
"[inv](#inv)\n",
|
"[inv](#inv)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[dot](#dot)\n",
|
"[dot](#dot)\n",
|
||||||
|
|
@ -707,11 +659,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"[ifft<sup>**</sup>](#ifft)\n",
|
"[ifft<sup>**</sup>](#ifft)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"[spectrum<sup>**</sup>](#spectrum)\n",
|
"[spectrum<sup>**</sup>](#spectrum)"
|
||||||
"\n",
|
|
||||||
"## Filter functions\n",
|
|
||||||
"\n",
|
|
||||||
"[convolve](#convolve)"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -720,13 +668,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`."
|
||||||
]
|
]
|
||||||
|
|
@ -894,18 +842,16 @@
|
||||||
"source": [
|
"source": [
|
||||||
"### .shape\n",
|
"### .shape\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The `.shape` method (property) returns a 2-tuple with the number of rows, and columns. \n",
|
"The `.shape` method returns a 2-tuple with the number of rows, and columns."
|
||||||
"\n",
|
|
||||||
"**WARNING:** In `circuitpython`, you can call the method as a property, i.e., "
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"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": [
|
||||||
|
|
@ -933,261 +879,13 @@
|
||||||
"\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",
|
|
||||||
"b= np.array([[1, 2], [3, 4]], dtype=np.int8)\n",
|
|
||||||
"print(\"\\nb:\\n\", b)\n",
|
|
||||||
"print(\"shape of b:\", b.shape)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**WARNING:** On the other hand, since properties are not implemented in `micropython`, there you would call the method as a function, i.e., "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 12,
|
|
||||||
"metadata": {
|
|
||||||
"ExecuteTime": {
|
|
||||||
"end_time": "2020-02-11T19:01:40.377272Z",
|
|
||||||
"start_time": "2020-02-11T19:01:40.364448Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"a:\n",
|
|
||||||
" array([1, 2, 3, 4], dtype=int8)\n",
|
|
||||||
"shape of a: (1, 4)\n",
|
|
||||||
"\n",
|
|
||||||
"b:\n",
|
|
||||||
" array([[1, 2],\n",
|
|
||||||
"\t [3, 4]], dtype=int8)\n",
|
|
||||||
"shape of b: (2, 2)\n",
|
|
||||||
"\n",
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"%%micropython -unix 1\n",
|
|
||||||
"\n",
|
|
||||||
"import ulab as np\n",
|
|
||||||
"\n",
|
|
||||||
"a = np.array([1, 2, 3, 4], dtype=np.int8)\n",
|
|
||||||
"print(\"a:\\n\", a)\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. \n",
|
|
||||||
"\n",
|
|
||||||
"**WARNING:** In `circuitpython`, the `numpy` nomenclature applies, i.e., "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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": [
|
|
||||||
"**WARNING:** In `micropython`, `size` is a method, i.e., "
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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.\n",
|
|
||||||
"\n",
|
|
||||||
"**WARNING:** In `circuitpython`:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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)"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"**WARNING:** In `micropython`:"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"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())"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|
@ -1236,6 +934,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": {},
|
||||||
|
|
@ -1289,6 +1035,109 @@
|
||||||
"print(\"b flattened (F): \\t\", b.flatten(order='F'))"
|
"print(\"b flattened (F): \\t\", b.flatten(order='F'))"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"### .asbytearray\n",
|
||||||
|
"\n",
|
||||||
|
"The contents of an `ndarray` can be accessed directly by calling the `.asbytearray` method. This will simply return a pointer to the underlying flat `array` object, which can then be manipulated directly.\n",
|
||||||
|
"\n",
|
||||||
|
"**WARNING:** `asbytearray` is a `ulab`-only method; it has no equivalent in `numpy`.\n",
|
||||||
|
"\n",
|
||||||
|
"In the example below, note the difference between `a`, and `buffer`: while both are designated as an array, you recognise the micropython array from the fact that it prints the typecode (`b` in this particular case). The `ndarray`, on the other hand, prints out the `dtype` (`int8` here)."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 211,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2019-11-01T14:25:39.008074Z",
|
||||||
|
"start_time": "2019-11-01T14:25:38.876546Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"a: array([1, 2, 3, 4], dtype=int8)\n",
|
||||||
|
"array content: array('b', [1, 2, 3, 4])\n",
|
||||||
|
"array content: array('b', [1, 123, 3, 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.int8)\n",
|
||||||
|
"print('a: ', a)\n",
|
||||||
|
"buffer = a.asbytearray()\n",
|
||||||
|
"print(\"array content:\", buffer)\n",
|
||||||
|
"buffer[1] = 123\n",
|
||||||
|
"print(\"array content:\", buffer)"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"This in itself wouldn't be very interesting, but since `buffer` is a proper micropython `array`, we can pass it to functions that can employ the buffer protocol. E.g., all the `ndarray` facilities can be applied to the results of timed ADC conversions."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "code",
|
||||||
|
"execution_count": 563,
|
||||||
|
"metadata": {
|
||||||
|
"ExecuteTime": {
|
||||||
|
"end_time": "2019-10-20T07:29:00.153589Z",
|
||||||
|
"start_time": "2019-10-20T07:28:50.210383Z"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
{
|
||||||
|
"name": "stdout",
|
||||||
|
"output_type": "stream",
|
||||||
|
"text": [
|
||||||
|
"ADC results:\t array([48, 2, 2, ..., 0, 0, 0], dtype=uint8)\n",
|
||||||
|
"mean of results:\t 1.22\n",
|
||||||
|
"std of results:\t 4.744639\n",
|
||||||
|
"\n"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"source": [
|
||||||
|
"%%micropython -pyboard 1\n",
|
||||||
|
"\n",
|
||||||
|
"import pyb\n",
|
||||||
|
"import ulab as np\n",
|
||||||
|
"\n",
|
||||||
|
"n = 100\n",
|
||||||
|
"\n",
|
||||||
|
"adc = pyb.ADC(pyb.Pin.board.X19)\n",
|
||||||
|
"tim = pyb.Timer(6, freq=10)\n",
|
||||||
|
"\n",
|
||||||
|
"a = np.array([0]*n, dtype=np.uint8)\n",
|
||||||
|
"buffer = a.asbytearray()\n",
|
||||||
|
"adc.read_timed(buffer, tim)\n",
|
||||||
|
"\n",
|
||||||
|
"print(\"ADC results:\\t\", a)\n",
|
||||||
|
"print(\"mean of results:\\t\", np.mean(a))\n",
|
||||||
|
"print(\"std of results:\\t\", np.std(a))"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"Likewise, data can be read directly into `ndarray`s from other interfaces, e.g., SPI, I2C etc, and also, by laying bare the `ndarray`, we can pass results of `ulab` computations to anything that can read from a buffer."
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
|
|
@ -4139,11 +3988,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": [
|
||||||
|
|
@ -4151,13 +4000,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"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -4166,20 +4015,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)"
|
||||||
]
|
]
|
||||||
|
|
@ -4423,65 +4268,13 @@
|
||||||
"where $N$ is the length of $y_1$, and $Y_1, Y_2$, and $Y$, respectively, are the Fourier transforms of $y_1, y_2$, and $y = y_1 + iy_2$."
|
"where $N$ is the length of $y_1$, and $Y_1, Y_2$, and $Y$, respectively, are the Fourier transforms of $y_1, y_2$, and $y = y_1 + iy_2$."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"# Filter routines"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "markdown",
|
|
||||||
"metadata": {},
|
|
||||||
"source": [
|
|
||||||
"numpy: https://docs.scipy.org/doc/numpy/reference/generated/numpy.convolve.html\n",
|
|
||||||
"\n",
|
|
||||||
"## convolve\n",
|
|
||||||
"Returns the discrete, linear convolution of two one-dimensional sequences.\n",
|
|
||||||
"\n",
|
|
||||||
"Only the ``full`` mode is supported, and the ``mode`` named parameter is not accepted. Note that all other modes can be had by slicing a ``full`` result."
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"cell_type": "code",
|
|
||||||
"execution_count": 5,
|
|
||||||
"metadata": {
|
|
||||||
"ExecuteTime": {
|
|
||||||
"end_time": "2020-02-10T18:46:06.538207Z",
|
|
||||||
"start_time": "2020-02-10T18:46:06.525851Z"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"outputs": [
|
|
||||||
{
|
|
||||||
"name": "stdout",
|
|
||||||
"output_type": "stream",
|
|
||||||
"text": [
|
|
||||||
"array([1.0, 12.0, 123.0, 1230.0, 2300.0, 3000.0], dtype=float)\n",
|
|
||||||
"\n",
|
|
||||||
"\n"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"source": [
|
|
||||||
"%%micropython -unix 1\n",
|
|
||||||
"\n",
|
|
||||||
"import ulab as np\n",
|
|
||||||
"\n",
|
|
||||||
"x = np.array((1,2,3))\n",
|
|
||||||
"y = np.array((1,10,100,1000))\n",
|
|
||||||
"\n",
|
|
||||||
"print(np.convolve(x, y))"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Extending ulab\n",
|
"# Extending ulab\n",
|
||||||
"\n",
|
"\n",
|
||||||
"As mentioned at the beginning, `ulab` is a set of sub-modules, out of which one, `extra` is explicitly reserved for user code. You should implement your functions in this sub-module, or sub-modules thereof.\n",
|
"New functions can easily be added to `ulab` in a couple of simple steps. At the C level, the type definition of an `ndarray` is as follows:\n",
|
||||||
"\n",
|
|
||||||
"The new functions can easily be added to `extra` in a couple of simple steps. At the C level, the type definition of an `ndarray` is as follows:\n",
|
|
||||||
"\n",
|
"\n",
|
||||||
"```c\n",
|
"```c\n",
|
||||||
"typedef struct _ndarray_obj_t {\n",
|
"typedef struct _ndarray_obj_t {\n",
|
||||||
|
|
@ -4520,7 +4313,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",
|
||||||
|
|
@ -4665,13 +4458,46 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"Once the function implementation is done, you should add the function object to the globals dictionary of the `extra` sub-module as \n",
|
"In the boilerplate above, we cast the pointer to `array->items` to the required type. There are certain operations, however, when you do not need the casting. If you do not want to change the array's values, only their position within the array, you can get away with copying the memory content, regardless the type. A good example for such a scenario is the transpose function in https://github.com/v923z/micropython-ulab/blob/master/code/linalg.c."
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"## Compiling your module\n",
|
||||||
|
"\n",
|
||||||
|
"Once you have implemented the functionality you wanted, you have to include the source code in the make file by adding it to `micropython.mk`:\n",
|
||||||
|
"\n",
|
||||||
|
"```makefile\n",
|
||||||
|
"USERMODULES_DIR := $(USERMOD_DIR)\n",
|
||||||
|
"\n",
|
||||||
|
"# Add all C files to SRC_USERMOD.\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/linalg.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/poly.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/fft.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/numerical.c\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/ulab.c\n",
|
||||||
|
"\n",
|
||||||
|
"SRC_USERMOD += $(USERMODULES_DIR)/your_module.c\n",
|
||||||
|
"\n",
|
||||||
|
"CFLAGS_USERMOD += -I$(USERMODULES_DIR)\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cell_type": "markdown",
|
||||||
|
"metadata": {},
|
||||||
|
"source": [
|
||||||
|
"In addition, you also have to add the function objects to `ulab.c`, and create a `QString` for the function name:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"```c\n",
|
"```c\n",
|
||||||
"...\n",
|
"...\n",
|
||||||
" MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);\n",
|
" MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);\n",
|
||||||
"...\n",
|
"...\n",
|
||||||
" STATIC const mp_map_elem_t extra_globals_table[] = {\n",
|
" STATIC const mp_map_elem_t ulab_globals_table[] = {\n",
|
||||||
"...\n",
|
"...\n",
|
||||||
" { MP_OBJ_NEW_QSTR(MP_QSTR_useless), (mp_obj_t)&useless_function_obj },\n",
|
" { MP_OBJ_NEW_QSTR(MP_QSTR_useless), (mp_obj_t)&useless_function_obj },\n",
|
||||||
"...\n",
|
"...\n",
|
||||||
|
|
@ -4683,21 +4509,29 @@
|
||||||
"```c\n",
|
"```c\n",
|
||||||
" MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);\n",
|
" MP_DEFINE_CONST_FUN_OBJ_1(useless_function_obj, userless_function);\n",
|
||||||
"```\n",
|
"```\n",
|
||||||
"depends naturally on what exactly you implemented, i.e., how many arguments the function takes, whether only positional arguments allowed and so on. For a thorough discussion on how function objects have to be defined, see, e.g., the [user module programming manual](#https://micropython-usermod.readthedocs.io/en/latest/).\n",
|
"depends naturally on what exactly you implemented, i.e., how many arguments the function takes, whether only positional arguments allowed and so on. For a thorough discussion on how function objects have to be defined, see, e.g., the [user module programming manual](#https://micropython-usermod.readthedocs.io/en/latest/)."
|
||||||
"\n",
|
|
||||||
"And with that, you are done. You can simply call the compiler as \n",
|
|
||||||
"\n",
|
|
||||||
"```bash\n",
|
|
||||||
"make BOARD=PYBV11 USER_C_MODULES=../../../ulab all\n",
|
|
||||||
"```\n",
|
|
||||||
"and the rest is taken care of."
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"In the boilerplate above, we cast the pointer to `array->items` to the required type. There are certain operations, however, when you do not need the casting. If you do not want to change the array's values, only their position within the array, you can get away with copying the memory content, regardless the type. A good example for such a scenario is the transpose function in https://github.com/v923z/micropython-ulab/blob/master/code/linalg.c."
|
"At this point, you should be able to compile the module with your extension by running `make` on the command line\n",
|
||||||
|
"\n",
|
||||||
|
"```bash\n",
|
||||||
|
"make USER_C_MODULES=../../../ulab all\n",
|
||||||
|
"```\n",
|
||||||
|
"for the unix port, and \n",
|
||||||
|
"\n",
|
||||||
|
"```bash\n",
|
||||||
|
"make BOARD=PYBV11 CROSS_COMPILE=<arm_tools_path>/bin/arm-none-eabi- USER_C_MODULES=../../../ulab all\n",
|
||||||
|
"```\n",
|
||||||
|
"for the `pyboard`, provided that the you have defined \n",
|
||||||
|
"\n",
|
||||||
|
"```makefile\n",
|
||||||
|
"#define MODULE_ULAB_ENABLED (1)\n",
|
||||||
|
"```\n",
|
||||||
|
"somewhere in `micropython/port/unix/mpconfigport.h`, or `micropython/stm32/mpconfigport.h`, respectively."
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
|
||||||
8509
docs/ulab.ipynb
Normal file
8509
docs/ulab.ipynb
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,2 +0,0 @@
|
||||||
import ulab
|
|
||||||
print(ulab.eye(3))
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
from ulab import linalg
|
|
||||||
import ulab
|
|
||||||
print(ulab.ones(3))
|
|
||||||
print(ulab.ones((2,3)))
|
|
||||||
print(ulab.zeros(3))
|
|
||||||
print(ulab.zeros((2,3)))
|
|
||||||
print(ulab.eye(3))
|
|
||||||
print(ulab.ones(1, dtype=ulab.int8))
|
|
||||||
print(ulab.ones(2, dtype=ulab.uint8))
|
|
||||||
print(ulab.ones(3, dtype=ulab.int16))
|
|
||||||
print(ulab.ones(4, dtype=ulab.uint16))
|
|
||||||
print(ulab.ones(5, dtype=ulab.float))
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
array([1.0, 1.0, 1.0], dtype=float)
|
|
||||||
array([[1.0, 1.0, 1.0],
|
|
||||||
[1.0, 1.0, 1.0]], dtype=float)
|
|
||||||
array([0.0, 0.0, 0.0], dtype=float)
|
|
||||||
array([[0.0, 0.0, 0.0],
|
|
||||||
[0.0, 0.0, 0.0]], dtype=float)
|
|
||||||
array([[1.0, 0.0, 0.0],
|
|
||||||
[0.0, 1.0, 0.0],
|
|
||||||
[0.0, 0.0, 1.0]], dtype=float)
|
|
||||||
array([1], dtype=int8)
|
|
||||||
array([1, 1], dtype=uint8)
|
|
||||||
array([1, 1, 1], dtype=int16)
|
|
||||||
array([1, 1, 1, 1], dtype=uint16)
|
|
||||||
array([1.0, 1.0, 1.0, 1.0, 1.0], dtype=float)
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
import ulab
|
|
||||||
a = ulab.ones(3)
|
|
||||||
print(a+a)
|
|
||||||
print(a-a)
|
|
||||||
print(a*a)
|
|
||||||
print(a/a)
|
|
||||||
print(a+2)
|
|
||||||
print(a-2)
|
|
||||||
print(a*2)
|
|
||||||
print(a/2)
|
|
||||||
print(a<1)
|
|
||||||
print(a<2)
|
|
||||||
print(a<=0)
|
|
||||||
print(a<=1)
|
|
||||||
print(a>1)
|
|
||||||
print(a>2)
|
|
||||||
print(a>=0)
|
|
||||||
print(a>=1)
|
|
||||||
#print(a==0) # These print just true or false. Is it right? is it a micropython limitation?
|
|
||||||
#print(a==1)
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
array([2.0, 2.0, 2.0], dtype=float)
|
|
||||||
array([0.0, 0.0, 0.0], dtype=float)
|
|
||||||
array([1.0, 1.0, 1.0], dtype=float)
|
|
||||||
array([1.0, 1.0, 1.0], dtype=float)
|
|
||||||
array([3.0, 3.0, 3.0], dtype=float)
|
|
||||||
array([-1.0, -1.0, -1.0], dtype=float)
|
|
||||||
array([2.0, 2.0, 2.0], dtype=float)
|
|
||||||
array([0.5, 0.5, 0.5], dtype=float)
|
|
||||||
[False, False, False]
|
|
||||||
[True, True, True]
|
|
||||||
[False, False, False]
|
|
||||||
[True, True, True]
|
|
||||||
[False, False, False]
|
|
||||||
[False, False, False]
|
|
||||||
[True, True, True]
|
|
||||||
[True, True, True]
|
|
||||||
Loading…
Reference in a new issue