Compare commits

...

6 commits

Author SHA1 Message Date
fb89d90fa1
Trim README to just the basics 2020-02-07 08:03:16 -06:00
cfbf5f4e84 remove files that should not be tracked 2020-02-04 11:35:36 -06:00
b4974825c6 Merge remote-tracking branch 'upstream/master' into HEAD 2020-02-04 11:28:29 -06:00
50957ec120 ndarray: Fix compile error 2020-02-04 10:31:38 -06:00
Andrew Gatherer
e7243ce38a added __init__ files 2020-01-01 16:18:52 -06:00
Andrew Gatherer
58ee495e6b initial edit to CP 2019-12-31 09:18:23 -06:00
12 changed files with 368 additions and 187 deletions

View file

@ -1,62 +1,12 @@
# micropython-ulab # circuitpython-ulab
ulab is a numpy-like array manipulation library for micropython. ulab is a numpy-like array manipulation library for micropython.
The module is written in C, defines compact containers for numerical The module is written in C, defines compact containers for numerical
data, and is fast. data, and is fast.
Documentation can be found under https://micropython-ulab.readthedocs.io/en/latest/ ulab will be incorporated in builds of most CircuitPython supported
The source for the manual is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab-manual.ipynb, devices, so there's usually no need to use the files here directly.
while developer help is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab.ipynb. If you've encountered a problem with circuitpython-ulab, please
file an issue [in the circuitpython issue tracker](https://github.com/adafruit/circuitpython).
# Firmware circuitpython-ulab is based on [micropython-ulab](https://github.com/v923z/micropython-ulab).
Firmware for pyboard.v.1.1, and PYBD_SF6 is updated once in a while, and can be downloaded
from https://github.com/v923z/micropython-ulab/releases.
## Compiling
If you want to try the latest version of `ulab`, or your hardware is
different to pyboard.v.1.1, or PYBD_SF6, the firmware can be compiled
from the source by following these steps:
First, you have to clone the micropython repository by running
```
git clone https://github.com/micropython/micropython.git
```
on the command line. This will create a new repository with the name `micropython`. Staying there, clone the `ulab` repository with
```
git clone https://github.com/v923z/micropython-ulab.git ulab
```
Then you have to include `ulab` in the compilation process by editing `mpconfigport.h` of the directory of the port for which you want to compile, so, still on the command line, navigate to `micropython/ports/unix`, or `micropython/ports/stm32`, or whichever port is your favourite, and edit the `mpconfigport.h` file there. All you have to do is add a single line at the end:
```
#define MODULE_ULAB_ENABLED (1)
```
This line will inform the compiler that you want `ulab` in the resulting firmware. If you don't have the cross-compiler installed, your might want to do that now, for instance on Linux by executing
```
sudo apt-get install gcc-arm-none-eabi
```
If that was successful, you can try to run the make command in the port's directory as
```
make BOARD=PYBV11 USER_C_MODULES=../../../ulab all
```
which will prepare the firmware for pyboard.v.11. Similarly,
```
make BOARD=PYBD_SF6 USER_C_MODULES=../../../ulab all
```
will compile for the SF6 member of the PYBD series. Provided that you managed to compile the firmware, you would upload that by running
either
```
dfu-util --alt 0 -D firmware.dfu
```
or
```
python pydfu.py -u firmware.dfu
```
In case you got stuck somewhere in the process, a bit more detailed instructions can be found under https://github.com/micropython/micropython/wiki/Getting-Started, and https://github.com/micropython/micropython/wiki/Pyboard-Firmware-Update.

193
code/__init__.c Normal file
View 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
View 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

13
code/compat.h Normal file
View file

@ -0,0 +1,13 @@
#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_ROM_NONE (MP_ROM_PTR(&mp_const_none_obj))
#define MP_ROM_FALSE (mp_const_false)
#define MP_ROM_TRUE (mp_const_true)
#endif // MICROPY_INCLUDED_ULAB_COMPAT_H

View file

@ -16,6 +16,7 @@
#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"
@ -75,19 +76,19 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) {
} }
mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) { mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) {
if(!mp_obj_is_type(arg_re, &ulab_ndarray_type)) { if(!MP_OBJ_IS_TYPE(arg_re, &ulab_ndarray_type)) {
mp_raise_NotImplementedError("FFT is defined for ndarrays only"); mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
} }
if(n_args == 2) { if(n_args == 2) {
if(!mp_obj_is_type(arg_im, &ulab_ndarray_type)) { if(!MP_OBJ_IS_TYPE(arg_im, &ulab_ndarray_type)) {
mp_raise_NotImplementedError("FFT is defined for ndarrays only"); mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
} }
} }
// Check if input is of length of power of 2 // Check if input is of length of power of 2
ndarray_obj_t *re = MP_OBJ_TO_PTR(arg_re); ndarray_obj_t *re = MP_OBJ_TO_PTR(arg_re);
uint16_t len = re->array->len; uint16_t len = re->array->len;
if((len & (len-1)) != 0) { if((len & (len-1)) != 0) {
mp_raise_ValueError("input array length must be power of 2"); mp_raise_ValueError(translate("input array length must be power of 2"));
} }
ndarray_obj_t *out_re = create_new_ndarray(1, len, NDARRAY_FLOAT); ndarray_obj_t *out_re = create_new_ndarray(1, len, NDARRAY_FLOAT);
@ -108,7 +109,7 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
if(n_args == 2) { if(n_args == 2) {
ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im); ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im);
if (re->array->len != im->array->len) { if (re->array->len != im->array->len) {
mp_raise_ValueError("real and imaginary parts must be of equal length"); mp_raise_ValueError(translate("real and imaginary parts must be of equal length"));
} }
if(im->array->typecode == NDARRAY_FLOAT) { if(im->array->typecode == NDARRAY_FLOAT) {
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);

View file

@ -14,6 +14,7 @@
#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"
mp_obj_t linalg_transpose(mp_obj_t self_in) { mp_obj_t linalg_transpose(mp_obj_t self_in) {
@ -50,8 +51,8 @@ mp_obj_t linalg_transpose(mp_obj_t self_in) {
mp_obj_t linalg_reshape(mp_obj_t self_in, mp_obj_t shape) { mp_obj_t linalg_reshape(mp_obj_t self_in, mp_obj_t shape) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); 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)) { if(!MP_OBJ_IS_TYPE(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) {
mp_raise_ValueError("shape must be a 2-tuple"); mp_raise_ValueError(translate("shape must be a 2-tuple"));
} }
mp_obj_iter_buf_t iter_buf; mp_obj_iter_buf_t iter_buf;
@ -63,7 +64,7 @@ mp_obj_t linalg_reshape(mp_obj_t self_in, mp_obj_t shape) {
n = mp_obj_get_int(item); n = mp_obj_get_int(item);
if(m*n != self->m*self->n) { if(m*n != self->m*self->n) {
// TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)" // TODO: the proper error message would be "cannot reshape array of size %d into shape (%d, %d)"
mp_raise_ValueError("cannot reshape array (incompatible input/output shape)"); mp_raise_ValueError(translate("cannot reshape array (incompatible input/output shape)"));
} }
self->m = m; self->m = m;
self->n = n; self->n = n;
@ -79,13 +80,13 @@ mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
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("size is defined for ndarrays only"); mp_raise_TypeError(translate("size is defined for ndarrays only"));
} else { } else {
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
if(args[1].u_obj == mp_const_none) { if(args[1].u_obj == mp_const_none) {
return mp_obj_new_int(ndarray->array->len); return mp_obj_new_int(ndarray->array->len);
} else if(mp_obj_is_int(args[1].u_obj)) { } else if(MP_OBJ_IS_INT(args[1].u_obj)) {
uint8_t ax = mp_obj_get_int(args[1].u_obj); uint8_t ax = mp_obj_get_int(args[1].u_obj);
if(ax == 0) { if(ax == 0) {
if(ndarray->m == 1) { if(ndarray->m == 1) {
@ -95,15 +96,15 @@ mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
} }
} else if(ax == 1) { } else if(ax == 1) {
if(ndarray->m == 1) { if(ndarray->m == 1) {
mp_raise_ValueError("tuple index out of range"); mp_raise_ValueError(translate("tuple index out of range"));
} else { } else {
return mp_obj_new_int(ndarray->n); return mp_obj_new_int(ndarray->n);
} }
} else { } else {
mp_raise_ValueError("tuple index out of range"); mp_raise_ValueError(translate("tuple index out of range"));
} }
} else { } else {
mp_raise_TypeError("wrong argument type"); mp_raise_TypeError(translate("wrong argument type"));
} }
} }
} }
@ -152,15 +153,15 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) {
mp_obj_t linalg_inv(mp_obj_t o_in) { mp_obj_t linalg_inv(mp_obj_t o_in) {
// since inv is not a class method, we have to inspect the input argument first // since inv is not a class method, we have to inspect the input argument first
if(!mp_obj_is_type(o_in, &ulab_ndarray_type)) { if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError("only ndarrays can be inverted"); mp_raise_TypeError(translate("only ndarrays can be inverted"));
} }
ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in); ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);
if(!mp_obj_is_type(o_in, &ulab_ndarray_type)) { if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError("only ndarray objects can be inverted"); mp_raise_TypeError(translate("only ndarray objects can be inverted"));
} }
if(o->m != o->n) { if(o->m != o->n) {
mp_raise_ValueError("only square matrices can be inverted"); mp_raise_ValueError(translate("only square matrices can be inverted"));
} }
ndarray_obj_t *inverted = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT); ndarray_obj_t *inverted = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT);
mp_float_t *data = (mp_float_t *)inverted->array->items; mp_float_t *data = (mp_float_t *)inverted->array->items;
@ -178,7 +179,7 @@ mp_obj_t linalg_inv(mp_obj_t o_in) {
// TODO: I am not sure this is needed here. Otherwise, // TODO: I am not sure this is needed here. Otherwise,
// how should we free up the unused RAM of inverted? // how should we free up the unused RAM of inverted?
m_del(mp_float_t, inverted->array->items, o->n*o->n); m_del(mp_float_t, inverted->array->items, o->n*o->n);
mp_raise_ValueError("input matrix is singular"); mp_raise_ValueError(translate("input matrix is singular"));
} }
return MP_OBJ_FROM_PTR(inverted); return MP_OBJ_FROM_PTR(inverted);
} }
@ -188,7 +189,7 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
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) {
mp_raise_ValueError("matrix dimensions do not match"); mp_raise_ValueError(translate("matrix dimensions do not match"));
} }
// TODO: numpy uses upcasting here // TODO: numpy uses upcasting here
ndarray_obj_t *out = create_new_ndarray(m1->m, m2->n, NDARRAY_FLOAT); ndarray_obj_t *out = create_new_ndarray(m1->m, m2->n, NDARRAY_FLOAT);
@ -219,17 +220,17 @@ mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t dtype = args[1].u_int; uint8_t dtype = args[1].u_int;
if(!mp_obj_is_int(args[0].u_obj) && !mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) { if(!MP_OBJ_IS_INT(args[0].u_obj) && !MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_raise_TypeError("input argument must be an integer or a 2-tuple"); mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
} }
ndarray_obj_t *ndarray = NULL; ndarray_obj_t *ndarray = NULL;
if(mp_obj_is_int(args[0].u_obj)) { if(MP_OBJ_IS_INT(args[0].u_obj)) {
size_t n = mp_obj_get_int(args[0].u_obj); size_t n = mp_obj_get_int(args[0].u_obj);
ndarray = create_new_ndarray(1, n, dtype); ndarray = create_new_ndarray(1, n, dtype);
} else if(mp_obj_is_type(args[0].u_obj, &mp_type_tuple)) { } else if(MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj);
if(tuple->len != 2) { if(tuple->len != 2) {
mp_raise_TypeError("input argument must be an integer or a 2-tuple"); mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
} }
ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]), ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]),
mp_obj_get_int(tuple->items[1]), dtype); mp_obj_get_int(tuple->items[1]), dtype);
@ -274,16 +275,16 @@ mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype); ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype);
mp_obj_t one = mp_obj_new_int(1); mp_obj_t one = mp_obj_new_int(1);
size_t i = 0; size_t i = 0;
if((k >= 0) && (k < n)) { if((k >= 0) && (abs(k) < n)) {
while(k < n) { while(abs(k) < n) {
mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one); mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one);
k++; k++;
i++; i++;
} }
} else if((k < 0) && (-k < m)) { } else if((k < 0) && (abs(k) < m)) {
k = -k; k = -k;
i = 0; i = 0;
while(k < m) { while(abs(k) < m) {
mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one); mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one);
k++; k++;
i++; i++;
@ -293,12 +294,12 @@ mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
} }
mp_obj_t linalg_det(mp_obj_t oin) { mp_obj_t linalg_det(mp_obj_t oin) {
if(!mp_obj_is_type(oin, &ulab_ndarray_type)) { if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
mp_raise_TypeError("function defined for ndarrays only"); mp_raise_TypeError(translate("function defined for ndarrays only"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
if(in->m != in->n) { if(in->m != in->n) {
mp_raise_ValueError("input must be square matrix"); mp_raise_ValueError(translate("input must be square matrix"));
} }
mp_float_t *tmp = m_new(mp_float_t, in->n*in->n); mp_float_t *tmp = m_new(mp_float_t, in->n*in->n);
@ -330,12 +331,12 @@ mp_obj_t linalg_det(mp_obj_t oin) {
} }
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("function defined for ndarrays only"); mp_raise_TypeError(translate("function defined for ndarrays only"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
if(in->m != in->n) { if(in->m != in->n) {
mp_raise_ValueError("input must be square matrix"); mp_raise_ValueError(translate("input must be square matrix"));
} }
mp_float_t *array = m_new(mp_float_t, in->array->len); mp_float_t *array = m_new(mp_float_t, in->array->len);
for(size_t i=0; i < in->array->len; i++) { for(size_t i=0; i < in->array->len; i++) {
@ -347,7 +348,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
// compare entry (m, n) to (n, m) // compare entry (m, n) to (n, m)
// TODO: this must probably be scaled! // TODO: this must probably be scaled!
if(epsilon < MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n] - array[n*in->n + m])) { if(epsilon < MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n] - array[n*in->n + m])) {
mp_raise_ValueError("input matrix is asymmetric"); mp_raise_ValueError(translate("input matrix is asymmetric"));
} }
} }
} }
@ -440,7 +441,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
if(iterations == 0) { if(iterations == 0) {
// the computation did not converge; numpy raises LinAlgError // the computation did not converge; numpy raises LinAlgError
m_del(mp_float_t, array, in->array->len); m_del(mp_float_t, array, in->array->len);
mp_raise_ValueError("iterations did not converge"); mp_raise_ValueError(translate("iterations did not converge")) ;
} }
ndarray_obj_t *eigenvalues = create_new_ndarray(1, in->n, NDARRAY_FLOAT); ndarray_obj_t *eigenvalues = create_new_ndarray(1, in->n, NDARRAY_FLOAT);
mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array->items; mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array->items;

View file

@ -16,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
@ -63,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);
} }
@ -164,16 +164,19 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m
return dtype; return dtype;
} }
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_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, n_kw, 1, 2, true); mp_arg_check_num(n_args, kw_args, 1, 2, true);
mp_map_t kw_args; size_t n_kw = 0;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args); if (kw_args != 0) {
uint8_t dtype = ndarray_init_helper(n_args, args, &kw_args); 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);
size_t len1, len2=0, i=0; size_t len1, len2=0, i=0;
mp_obj_t len_in = mp_obj_len_maybe(args[0]); mp_obj_t len_in = mp_obj_len_maybe(args[0]);
if (len_in == MP_OBJ_NULL) { if (len_in == MP_OBJ_NULL) {
mp_raise_ValueError("first argument must be an iterable"); mp_raise_ValueError(translate("first argument must be an iterable"));
} else { } else {
// len1 is either the number of rows (for matrices), or the number of elements (row vectors) // len1 is either the number of rows (for matrices), or the number of elements (row vectors)
len1 = MP_OBJ_SMALL_INT_VALUE(len_in); len1 = MP_OBJ_SMALL_INT_VALUE(len_in);
@ -188,8 +191,9 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
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));
mp_raise_ValueError("iterables are not of the same length"); if(len2 != temp) {
mp_raise_ValueError(translate("iterables are not of the same length"));
} }
} }
len2 = MP_OBJ_SMALL_INT_VALUE(len_in); len2 = MP_OBJ_SMALL_INT_VALUE(len_in);
@ -231,7 +235,7 @@ size_t true_length(mp_obj_t bool_list) {
mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf); mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf);
size_t trues = 0; size_t trues = 0;
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if(!mp_obj_is_type(item, &mp_type_bool)) { if(!MP_OBJ_IS_TYPE(item, &mp_type_bool)) {
// numpy seems to be a little bit inconsistent in when an index is considered // numpy seems to be a little bit inconsistent in when an index is considered
// to be True/False. Bail out immediately, if the items are not True/False // to be True/False. Bail out immediately, if the items are not True/False
return 0; return 0;
@ -248,19 +252,19 @@ mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) {
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;
} }
if((_index >= n) || (_index < 0)) { if((_index >= n) || (_index < 0)) {
mp_raise_msg(&mp_type_IndexError, "index is out of bounds"); mp_raise_msg(&mp_type_IndexError, translate("index is out of bounds"));
} }
slice.start = _index; slice.start = _index;
slice.stop = _index + 1; slice.stop = _index + 1;
slice.step = 1; slice.step = 1;
} else { } else {
mp_raise_msg(&mp_type_IndexError, "indices must be integers, slices, or Boolean lists"); mp_raise_msg(&mp_type_IndexError, translate("indices must be integers, slices, or Boolean lists"));
} }
return slice; return slice;
} }
@ -290,7 +294,7 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
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("could not broadast input array from shape"); mp_raise_ValueError(translate("could not broadast input array from shape"));
} }
} }
size_t cindex, rindex; size_t cindex, rindex;
@ -352,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);
@ -377,7 +382,7 @@ mp_obj_t iterate_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 == 0) || (n == 0)) { if((m == 0) || (n == 0)) {
mp_raise_msg(&mp_type_IndexError, "empty index range"); mp_raise_msg(&mp_type_IndexError, translate("empty index range"));
} }
if(values != NULL) { if(values != NULL) {
@ -438,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);
@ -462,7 +468,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1); mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1);
size_t m = 0, n = 0; size_t m = 0, n = 0;
if(mp_obj_is_int(index) && (ndarray->m == 1) && (values == NULL)) { if(MP_OBJ_IS_INT(index) && (ndarray->m == 1) && (values == NULL)) {
// we have a row vector, and don't want to assign // we have a row vector, and don't want to assign
column_slice = generate_slice(ndarray->n, index); column_slice = generate_slice(ndarray->n, index);
if(slice_length(column_slice) == 1) { // we were asked for a single item if(slice_length(column_slice) == 1) { // we were asked for a single item
@ -471,7 +477,7 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
} }
} }
if(mp_obj_is_int(index) || mp_obj_is_type(index, &mp_type_slice)) { if(MP_OBJ_IS_INT(index) || MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
if(ndarray->m == 1) { // we have a row vector if(ndarray->m == 1) { // we have a row vector
column_slice = generate_slice(ndarray->n, index); column_slice = generate_slice(ndarray->n, index);
row_slice = simple_slice(0, 1, 1); row_slice = simple_slice(0, 1, 1);
@ -495,15 +501,15 @@ mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t
else { // we certainly have a tuple, so let us deal with it else { // we certainly have a tuple, so let us deal with it
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(index); mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(index);
if(tuple->len != 2) { if(tuple->len != 2) {
mp_raise_msg(&mp_type_IndexError, "too many indices"); mp_raise_msg(&mp_type_IndexError, translate("too many indices"));
} }
if(!(mp_obj_is_type(tuple->items[0], &mp_type_list) || if(!(MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_list) ||
mp_obj_is_type(tuple->items[0], &mp_type_slice) || MP_OBJ_IS_TYPE(tuple->items[0], &mp_type_slice) ||
mp_obj_is_int(tuple->items[0])) || MP_OBJ_IS_INT(tuple->items[0])) ||
!(mp_obj_is_type(tuple->items[1], &mp_type_list) || !(MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_list) ||
mp_obj_is_type(tuple->items[1], &mp_type_slice) || MP_OBJ_IS_TYPE(tuple->items[1], &mp_type_slice) ||
mp_obj_is_int(tuple->items[1]))) { MP_OBJ_IS_INT(tuple->items[1]))) {
mp_raise_msg(&mp_type_IndexError, "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]);
@ -542,12 +548,12 @@ mp_obj_t ndarray_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
if (value == MP_OBJ_SENTINEL) { // return value(s) if (value == MP_OBJ_SENTINEL) { // return value(s)
return ndarray_get_slice(self, index, NULL); return ndarray_get_slice(self, index, NULL);
} else { // assignment to slices; the value must be an ndarray, or a scalar } else { // assignment to slices; the value must be an ndarray, or a scalar
if(!mp_obj_is_type(value, &ulab_ndarray_type) && if(!MP_OBJ_IS_TYPE(value, &ulab_ndarray_type) &&
!mp_obj_is_int(value) && !mp_obj_is_float(value)) { !MP_OBJ_IS_INT(value) && !mp_obj_is_float(value)) {
mp_raise_ValueError("right hand side must be an ndarray, or a scalar"); mp_raise_ValueError(translate("right hand side must be an ndarray, or a scalar"));
} else { } else {
ndarray_obj_t *values = NULL; ndarray_obj_t *values = NULL;
if(mp_obj_is_int(value)) { if(MP_OBJ_IS_INT(value)) {
values = create_new_ndarray(1, 1, self->array->typecode); values = create_new_ndarray(1, 1, self->array->typecode);
mp_binary_set_val_array(values->array->typecode, values->array->items, 0, value); mp_binary_set_val_array(values->array->typecode, values->array->items, 0, value);
} else if(mp_obj_is_float(value)) { } else if(mp_obj_is_float(value)) {
@ -655,7 +661,7 @@ mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
GET_STR_DATA_LEN(args[0].u_obj, order, len); GET_STR_DATA_LEN(args[0].u_obj, order, len);
if((len != 1) || ((memcmp(order, "C", 1) != 0) && (memcmp(order, "F", 1) != 0))) { if((len != 1) || ((memcmp(order, "C", 1) != 0) && (memcmp(order, "F", 1) != 0))) {
mp_raise_ValueError("flattening order must be either 'C', or 'F'"); mp_raise_ValueError(translate("flattening order must be either 'C', or 'F'"));
} }
// if order == 'C', we simply have to set m, and n, there is nothing else to do // if order == 'C', we simply have to set m, and n, there is nothing else to do
@ -694,7 +700,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
// TODO: implement in-place operators // TODO: implement in-place operators
mp_obj_t RHS = MP_OBJ_NULL; mp_obj_t RHS = MP_OBJ_NULL;
bool rhs_is_scalar = true; bool rhs_is_scalar = true;
if(mp_obj_is_int(rhs)) { if(MP_OBJ_IS_INT(rhs)) {
int32_t ivalue = mp_obj_get_int(rhs); int32_t ivalue = mp_obj_get_int(rhs);
if((ivalue > 0) && (ivalue < 256)) { if((ivalue > 0) && (ivalue < 256)) {
CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue); CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue);
@ -715,12 +721,12 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
rhs_is_scalar = false; rhs_is_scalar = false;
} }
//else //else
if(mp_obj_is_type(lhs, &ulab_ndarray_type) && mp_obj_is_type(RHS, &ulab_ndarray_type)) { if(MP_OBJ_IS_TYPE(lhs, &ulab_ndarray_type) && MP_OBJ_IS_TYPE(RHS, &ulab_ndarray_type)) {
// next, the ndarray stuff // next, the ndarray stuff
ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs); ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs);
ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS); ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS);
if(!rhs_is_scalar && ((ol->m != or->m) || (ol->n != or->n))) { if(!rhs_is_scalar && ((ol->m != or->m) || (ol->n != or->n))) {
mp_raise_ValueError("operands could not be broadcast together"); mp_raise_ValueError(translate("operands could not be broadcast together"));
} }
// At this point, the operands should have the same shape // At this point, the operands should have the same shape
switch(op) { switch(op) {
@ -823,7 +829,7 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, ol, or, op); RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, ol, or, op);
} }
} else { // this should never happen } else { // this should never happen
mp_raise_TypeError("wrong input type"); mp_raise_TypeError(translate("wrong input type"));
} }
// this instruction should never be reached, but we have to make the compiler happy // this instruction should never be reached, but we have to make the compiler happy
return MP_OBJ_NULL; return MP_OBJ_NULL;
@ -831,13 +837,18 @@ mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
return MP_OBJ_NULL; // op not supported return MP_OBJ_NULL; // op not supported
} }
} else { } else {
mp_raise_TypeError("wrong operand type on the right hand side"); mp_raise_TypeError(translate("wrong operand type on the right hand side"));
} }
} }
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) {
@ -849,33 +860,33 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
case MP_UNARY_OP_INVERT: case MP_UNARY_OP_INVERT:
if(self->array->typecode == NDARRAY_FLOAT) { if(self->array->typecode == NDARRAY_FLOAT) {
mp_raise_ValueError("operation is not supported for given type"); mp_raise_ValueError(translate("operation is not supported for given type"));
} }
// 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;
@ -888,20 +899,20 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
return ndarray_copy(self_in); return ndarray_copy(self_in);
} }
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in)); ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
if((self->array->typecode == NDARRAY_INT8)) { if(self->array->typecode == NDARRAY_INT8) {
int8_t *array = (int8_t *)ndarray->array->items; 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);

View file

@ -24,7 +24,7 @@
#define FLOAT_TYPECODE 'd' #define FLOAT_TYPECODE 'd'
#endif #endif
extern const mp_obj_type_t ulab_ndarray_type; const mp_obj_type_t ulab_ndarray_type;
enum NDARRAY_TYPE { enum NDARRAY_TYPE {
NDARRAY_UINT8 = 'B', NDARRAY_UINT8 = 'B',
@ -53,7 +53,7 @@ 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 );
mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *); mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t, const mp_obj_t *, mp_map_t *);
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 );

View file

@ -16,6 +16,7 @@
#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"
enum NUMERICAL_FUNCTION_TYPE { enum NUMERICAL_FUNCTION_TYPE {
@ -43,7 +44,7 @@ mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
uint16_t len = args[2].u_int; uint16_t len = args[2].u_int;
if(len < 2) { if(len < 2) {
mp_raise_ValueError("number of points must be at least 2"); mp_raise_ValueError(translate("number of points must be at least 2"));
} }
mp_float_t value, step; mp_float_t value, step;
value = mp_obj_get_float(args[0].u_obj); value = mp_obj_get_float(args[0].u_obj);
@ -167,7 +168,7 @@ mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddo
axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc); axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc);
if(ddof > len) { if(ddof > len) {
mp_raise_ValueError("ddof must be smaller than length of data set"); mp_raise_ValueError(translate("ddof must be smaller than length of data set"));
} }
ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT); ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT);
mp_float_t *farray = (mp_float_t *)results->array->items; mp_float_t *farray = (mp_float_t *)results->array->items;
@ -263,7 +264,7 @@ STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
mp_obj_t axis = args[1].u_obj; mp_obj_t axis = args[1].u_obj;
if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) { if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) {
// this seems to pass with False, and True... // this seems to pass with False, and True...
mp_raise_ValueError("axis must be None, 0, or 1"); mp_raise_ValueError(translate("axis must be None, 0, or 1"));
} }
if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) ||
@ -292,10 +293,10 @@ STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
case NUMERICAL_MEAN: case NUMERICAL_MEAN:
return numerical_sum_mean_ndarray(ndarray, axis, optype); return numerical_sum_mean_ndarray(ndarray, axis, optype);
default: default:
mp_raise_NotImplementedError("operation is not implemented on ndarrays"); mp_raise_NotImplementedError(translate("operation is not implemented on ndarrays"));
} }
} else { } else {
mp_raise_TypeError("input must be tuple, list, range, or ndarray"); mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray"));
} }
return mp_const_none; return mp_const_none;
} }
@ -339,7 +340,7 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
size_t ddof = args[2].u_int; size_t ddof = args[2].u_int;
if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) { if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) {
// this seems to pass with False, and True... // this seems to pass with False, and True...
mp_raise_ValueError("axis must be None, 0, or 1"); mp_raise_ValueError(translate("axis must be None, 0, or 1"));
} }
if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || MP_OBJ_IS_TYPE(oin, &mp_type_range)) { if(MP_OBJ_IS_TYPE(oin, &mp_type_tuple) || MP_OBJ_IS_TYPE(oin, &mp_type_list) || MP_OBJ_IS_TYPE(oin, &mp_type_range)) {
return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof); return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof);
@ -347,7 +348,7 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin); ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin);
return numerical_std_ndarray(ndarray, axis, ddof); return numerical_std_ndarray(ndarray, axis, ddof);
} else { } else {
mp_raise_TypeError("input must be tuple, list, range, or ndarray"); mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray"));
} }
return mp_const_none; return mp_const_none;
} }
@ -367,7 +368,7 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
if((args[2].u_obj != mp_const_none) && if((args[2].u_obj != mp_const_none) &&
(mp_obj_get_int(args[2].u_obj) != 0) && (mp_obj_get_int(args[2].u_obj) != 0) &&
(mp_obj_get_int(args[2].u_obj) != 1)) { (mp_obj_get_int(args[2].u_obj) != 1)) {
mp_raise_ValueError("axis must be None, 0, or 1"); mp_raise_ValueError(translate("axis must be None, 0, or 1"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin); ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
@ -442,12 +443,12 @@ mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
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("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) &&
(mp_obj_get_int(args[1].u_obj) != 0) && (mp_obj_get_int(args[1].u_obj) != 0) &&
(mp_obj_get_int(args[1].u_obj) != 1)) { (mp_obj_get_int(args[1].u_obj) != 1)) {
mp_raise_ValueError("axis must be None, 0, or 1"); mp_raise_ValueError(translate("axis must be None, 0, or 1"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj); ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj);
@ -490,7 +491,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
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("diff argument must be an ndarray"); mp_raise_TypeError(translate("diff argument must be an ndarray"));
} }
ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj); ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj);
@ -500,10 +501,10 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
} else if(args[2].u_int == 0) { // differtiate along vertical axis } else if(args[2].u_int == 0) { // differtiate along vertical axis
increment = in->n; increment = in->n;
} else { } else {
mp_raise_ValueError("axis must be -1, 0, or 1"); mp_raise_ValueError(translate("axis must be -1, 0, or 1"));
} }
if((args[1].u_int < 0) || (args[1].u_int > 9)) { if((args[1].u_int < 0) || (args[1].u_int > 9)) {
mp_raise_ValueError("n must be between 0, and 9"); mp_raise_ValueError(translate("n must be between 0, and 9"));
} }
uint8_t n = args[1].u_int; uint8_t n = args[1].u_int;
int8_t *stencil = m_new(int8_t, n+1); int8_t *stencil = m_new(int8_t, n+1);
@ -549,7 +550,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
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("sort argument must be an ndarray"); mp_raise_TypeError(translate("sort argument must be an ndarray"));
} }
ndarray_obj_t *ndarray; ndarray_obj_t *ndarray;
@ -580,7 +581,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
end = ndarray->m; end = ndarray->m;
N = ndarray->m; N = ndarray->m;
} else { } else {
mp_raise_ValueError("axis must be -1, 0, None, or 1"); mp_raise_ValueError(translate("axis must be -1, 0, None, or 1"));
} }
size_t q, k, p, c; size_t q, k, p, c;
@ -636,7 +637,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
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("argsort argument must be an ndarray"); mp_raise_TypeError(translate("argsort argument must be an ndarray"));
} }
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj); ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
@ -666,7 +667,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
end = m; end = m;
N = m; N = m;
} else { } else {
mp_raise_ValueError("axis must be -1, 0, None, or 1"); mp_raise_ValueError(translate("axis must be -1, 0, None, or 1"));
} }
// at the expense of flash, we could save RAM by creating // at the expense of flash, we could save RAM by creating

View file

@ -11,23 +11,24 @@
#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"
bool object_is_nditerable(mp_obj_t o_in) { bool object_is_nditerable(mp_obj_t o_in) {
if(mp_obj_is_type(o_in, &ulab_ndarray_type) || if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type) ||
mp_obj_is_type(o_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) ||
mp_obj_is_type(o_in, &mp_type_list) || MP_OBJ_IS_TYPE(o_in, &mp_type_list) ||
mp_obj_is_type(o_in, &mp_type_range)) { MP_OBJ_IS_TYPE(o_in, &mp_type_range)) {
return true; return true;
} }
return false; return false;
} }
size_t get_nditerable_len(mp_obj_t o_in) { size_t get_nditerable_len(mp_obj_t o_in) {
if(mp_obj_is_type(o_in, &ulab_ndarray_type)) { if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in); ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in);
return in->array->len; return in->array->len;
} else { } else {
@ -84,10 +85,10 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
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("number of arguments must be 2, or 3"); mp_raise_ValueError(translate("number of arguments must be 2, or 3"));
} }
if(!object_is_nditerable(args[0])) { if(!object_is_nditerable(args[0])) {
mp_raise_ValueError("input data must be an iterable"); mp_raise_ValueError(translate("input data must be an iterable"));
} }
uint16_t lenx, leny; uint16_t lenx, leny;
uint8_t deg; uint8_t deg;
@ -99,7 +100,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
deg = (uint8_t)mp_obj_get_int(args[1]); deg = (uint8_t)mp_obj_get_int(args[1]);
if(leny < deg) { if(leny < deg) {
mp_raise_ValueError("more degrees of freedom than data points"); mp_raise_ValueError(translate("more degrees of freedom than data points"));
} }
lenx = leny; lenx = leny;
x = m_new(mp_float_t, lenx); // assume uniformly spaced data points x = m_new(mp_float_t, lenx); // assume uniformly spaced data points
@ -112,11 +113,11 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
lenx = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); lenx = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0])); leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
if(lenx != leny) { if(lenx != leny) {
mp_raise_ValueError("input vectors must be of equal length"); mp_raise_ValueError(translate("input vectors must be of equal length"));
} }
deg = (uint8_t)mp_obj_get_int(args[2]); deg = (uint8_t)mp_obj_get_int(args[2]);
if(leny < deg) { if(leny < deg) {
mp_raise_ValueError("more degrees of freedom than data points"); mp_raise_ValueError(translate("more degrees of freedom than data points"));
} }
x = m_new(mp_float_t, lenx); x = m_new(mp_float_t, lenx);
fill_array_iterable(x, args[0]); fill_array_iterable(x, args[0]);
@ -156,7 +157,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
m_del(mp_float_t, x, lenx); m_del(mp_float_t, x, lenx);
m_del(mp_float_t, y, lenx); m_del(mp_float_t, y, lenx);
m_del(mp_float_t, prod, (deg+1)*(deg+1)); m_del(mp_float_t, prod, (deg+1)*(deg+1));
mp_raise_ValueError("could not invert Vandermonde matrix"); mp_raise_ValueError(translate("could not invert Vandermonde matrix"));
} }
// at this point, we have the inverse of X^T * X // at this point, we have the inverse of X^T * X
// y is a column vector; x is free now, we can use it for storing intermediate values // y is a column vector; x is free now, we can use it for storing intermediate values

View file

@ -17,6 +17,7 @@
#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 "linalg.h" #include "linalg.h"
#include "vectorise.h" #include "vectorise.h"

View file

@ -15,6 +15,7 @@
#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