Compare commits
12 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a725d6067 | ||
|
|
2851d3007a | ||
|
|
ad0531e35e | ||
|
|
50df00546b | ||
|
|
6e0fcd0f6f | ||
|
|
20e97ce7c7 | ||
|
|
03609727ce | ||
|
|
f34cbe885d | ||
|
|
6e4f691a1a | ||
|
|
b62ba12237 | ||
|
|
a2bafa981d | ||
|
|
039d7ec866 |
10 changed files with 888 additions and 543 deletions
|
|
@ -124,7 +124,7 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) {
|
|||
}
|
||||
for(size_t m=0; m < N; m++){
|
||||
// this could be faster with ((c < epsilon) && (c > -epsilon))
|
||||
if(abs(data[m*(N+1)]) < epsilon) {
|
||||
if(MICROPY_FLOAT_C_FUN(fabs)(data[m*(N+1)]) < epsilon) {
|
||||
m_del(mp_float_t, unit, N*N);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -307,7 +307,7 @@ mp_obj_t linalg_det(mp_obj_t oin) {
|
|||
}
|
||||
mp_float_t c;
|
||||
for(size_t m=0; m < in->m-1; m++){
|
||||
if(abs(tmp[m*(in->n+1)]) < epsilon) {
|
||||
if(MICROPY_FLOAT_C_FUN(fabs)(tmp[m*(in->n+1)]) < epsilon) {
|
||||
m_del(mp_float_t, tmp, in->n*in->n);
|
||||
return mp_obj_new_float(0.0);
|
||||
}
|
||||
|
|
@ -346,7 +346,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
|
|||
for(size_t n=m+1; n < in->n; n++) {
|
||||
// compare entry (m, n) to (n, m)
|
||||
// TODO: this must probably be scaled!
|
||||
if(epsilon < abs(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");
|
||||
}
|
||||
}
|
||||
|
|
@ -371,7 +371,7 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
|
|||
largest = 0.0;
|
||||
for(size_t m=0; m < in->m-1; m++) { // -1: no need to inspect last row
|
||||
for(size_t n=m+1; n < in->n; n++) {
|
||||
w = fabs(array[m*in->n + n]);
|
||||
w = MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n]);
|
||||
if((largest < w) && (epsilon < w)) {
|
||||
M = m;
|
||||
N = n;
|
||||
|
|
|
|||
|
|
@ -61,26 +61,40 @@ 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_value(const mp_print_t *print, mp_obj_array_t *data,
|
||||
size_t n, uint8_t boolean) {
|
||||
if(!boolean) {
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n), PRINT_REPR);
|
||||
} else { // the array is a Boolean array, it must be of uint8_t type
|
||||
if(((uint8_t *)data->items)[n]) {
|
||||
mp_print_str(print, "True");
|
||||
} else {
|
||||
mp_print_str(print, "False");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data,
|
||||
size_t n0, size_t n, uint8_t boolean) {
|
||||
mp_print_str(print, "[");
|
||||
size_t i;
|
||||
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);
|
||||
ndarray_print_value(print, data, n0, boolean);
|
||||
for(i=1; i<n; i++) {
|
||||
mp_print_str(print, ", ");
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
||||
ndarray_print_value(print, data, n0+i, boolean);
|
||||
}
|
||||
} else {
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
|
||||
ndarray_print_value(print, data, n0, boolean);
|
||||
for(i=1; i<3; i++) {
|
||||
mp_print_str(print, ", ");
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
|
||||
ndarray_print_value(print, data, n0+i, boolean);
|
||||
}
|
||||
mp_printf(print, ", ..., ");
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+n-3), PRINT_REPR);
|
||||
ndarray_print_value(print, data, n0-3, boolean);
|
||||
for(size_t i=1; i<3; i++) {
|
||||
mp_print_str(print, ", ");
|
||||
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+n-3+i), PRINT_REPR);
|
||||
ndarray_print_value(print, data, n0-3+i, boolean);
|
||||
}
|
||||
}
|
||||
mp_print_str(print, "]");
|
||||
|
|
@ -95,19 +109,21 @@ void ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki
|
|||
mp_print_str(print, "[]");
|
||||
} else {
|
||||
if((self->m == 1) || (self->n == 1)) {
|
||||
ndarray_print_row(print, self->array, 0, self->array->len);
|
||||
ndarray_print_row(print, self->array, 0, self->array->len, self->boolean);
|
||||
} else {
|
||||
// TODO: add vertical ellipses for the case, when self->m > PRINT_MAX
|
||||
mp_print_str(print, "[");
|
||||
ndarray_print_row(print, self->array, 0, self->n);
|
||||
ndarray_print_row(print, self->array, 0, self->n, self->boolean);
|
||||
for(size_t i=1; i < self->m; i++) {
|
||||
mp_print_str(print, ",\n\t ");
|
||||
ndarray_print_row(print, self->array, i*self->n, self->n);
|
||||
ndarray_print_row(print, self->array, i*self->n, self->n, self->boolean);
|
||||
}
|
||||
mp_print_str(print, "]");
|
||||
}
|
||||
}
|
||||
if(self->array->typecode == NDARRAY_UINT8) {
|
||||
if(self->boolean) {
|
||||
mp_print_str(print, ", dtype=bool)");
|
||||
} else if(self->array->typecode == NDARRAY_UINT8) {
|
||||
mp_print_str(print, ", dtype=uint8)");
|
||||
} else if(self->array->typecode == NDARRAY_INT8) {
|
||||
mp_print_str(print, ", dtype=int8)");
|
||||
|
|
@ -120,11 +136,22 @@ void ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t ki
|
|||
}
|
||||
}
|
||||
|
||||
void ndarray_assign_elements(mp_obj_array_t *data, mp_obj_t iterable, uint8_t typecode, size_t *idx) {
|
||||
void ndarray_assign_row(mp_obj_array_t *data, mp_obj_t iterable, uint8_t typecode, size_t *idx) {
|
||||
// assigns a single row in the matrix
|
||||
mp_obj_t item;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_binary_set_val_array(typecode, data->items, (*idx)++, item);
|
||||
if(typecode == NDARRAY_BOOL) {
|
||||
uint8_t *array = (uint8_t *)data->items;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if(mp_obj_is_true(item)) {
|
||||
array[(*idx)] = 1;
|
||||
}
|
||||
// we don't need to set False, because the array is initialised with straight zeros
|
||||
(*idx)++;
|
||||
}
|
||||
} else {
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_binary_set_val_array(typecode, data->items, (*idx)++, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +161,13 @@ ndarray_obj_t *create_new_ndarray(size_t m, size_t n, uint8_t typecode) {
|
|||
ndarray->base.type = &ulab_ndarray_type;
|
||||
ndarray->m = m;
|
||||
ndarray->n = n;
|
||||
mp_obj_array_t *array = array_new(typecode, m*n);
|
||||
if(typecode == NDARRAY_BOOL) {
|
||||
typecode = NDARRAY_UINT8;
|
||||
ndarray->boolean = NDARRAY_BOOLEAN;
|
||||
} else {
|
||||
ndarray->boolean = NDARRAY_NUMERIC;
|
||||
}
|
||||
mp_obj_array_t *array = array_new(typecode, m*n);
|
||||
ndarray->bytes = m * n * mp_binary_get_size('@', typecode, NULL);
|
||||
// this should set all elements to 0, irrespective of the of the typecode (all bits are zero)
|
||||
// we could, perhaps, leave this step out, and initialise the array only, when needed
|
||||
|
|
@ -161,6 +194,7 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
uint8_t dtype = args[1].u_int;
|
||||
// at this point, dtype can still be `?` for Boolean arrays
|
||||
return dtype;
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +204,7 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
|||
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]);
|
||||
if (len_in == MP_OBJ_NULL) {
|
||||
mp_raise_ValueError("first argument must be an iterable");
|
||||
|
|
@ -201,14 +235,14 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw,
|
|||
iterable1 = mp_getiter(args[0], &iter_buf1);
|
||||
i = 0;
|
||||
if(len2 == 0) { // the first argument is a single iterable
|
||||
ndarray_assign_elements(self->array, iterable1, dtype, &i);
|
||||
ndarray_assign_row(self->array, iterable1, dtype, &i);
|
||||
} else {
|
||||
mp_obj_iter_buf_t iter_buf2;
|
||||
mp_obj_t iterable2;
|
||||
|
||||
while ((item1 = mp_iternext(iterable1)) != MP_OBJ_STOP_ITERATION) {
|
||||
iterable2 = mp_getiter(item1, &iter_buf2);
|
||||
ndarray_assign_elements(self->array, iterable2, dtype, &i);
|
||||
ndarray_assign_row(self->array, iterable2, dtype, &i);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
|
|
@ -277,7 +311,7 @@ void insert_binary_value(ndarray_obj_t *ndarray, size_t nd_index, ndarray_obj_t
|
|||
// there is probably a more elegant implementation...
|
||||
mp_obj_t tmp = mp_binary_get_val_array(values->array->typecode, values->array->items, value_index);
|
||||
if((values->array->typecode == NDARRAY_FLOAT) && (ndarray->array->typecode != NDARRAY_FLOAT)) {
|
||||
// workaround: rounding seems not to work in the arm compiler
|
||||
// this is a workaround: rounding seems not to work in the arm compiler
|
||||
int32_t x = (int32_t)floorf(mp_obj_get_float(tmp)+0.5);
|
||||
tmp = mp_obj_new_int(x);
|
||||
}
|
||||
|
|
@ -580,7 +614,7 @@ mp_obj_t ndarray_iternext(mp_obj_t self_in) {
|
|||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(self->ndarray);
|
||||
// TODO: in numpy, ndarrays are iterated with respect to the first axis.
|
||||
size_t iter_end = 0;
|
||||
if((ndarray->m == 1)) {
|
||||
if(ndarray->m == 1) {
|
||||
iter_end = ndarray->array->len;
|
||||
} else {
|
||||
iter_end = ndarray->m;
|
||||
|
|
@ -888,12 +922,12 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
|
|||
return 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;
|
||||
for(size_t i=0; i < self->array->len; i++) {
|
||||
if(array[i] < 0) array[i] = -array[i];
|
||||
}
|
||||
} else if((self->array->typecode == NDARRAY_INT16)) {
|
||||
} else if(self->array->typecode == NDARRAY_INT16) {
|
||||
int16_t *array = (int16_t *)ndarray->array->items;
|
||||
for(size_t i=0; i < self->array->len; i++) {
|
||||
if(array[i] < 0) array[i] = -array[i];
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
#define PRINT_MAX 10
|
||||
|
||||
#define NDARRAY_NUMERIC 0
|
||||
#define NDARRAY_BOOLEAN 1
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#define FLOAT_TYPECODE 'f'
|
||||
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
|
|
@ -27,6 +30,7 @@
|
|||
const mp_obj_type_t ulab_ndarray_type;
|
||||
|
||||
enum NDARRAY_TYPE {
|
||||
NDARRAY_BOOL = '?', // this must never be assigned to the typecode!
|
||||
NDARRAY_UINT8 = 'B',
|
||||
NDARRAY_INT8 = 'b',
|
||||
NDARRAY_UINT16 = 'H',
|
||||
|
|
@ -36,6 +40,7 @@ enum NDARRAY_TYPE {
|
|||
|
||||
typedef struct _ndarray_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint8_t boolean;
|
||||
size_t m, n;
|
||||
size_t len;
|
||||
mp_obj_array_t *array;
|
||||
|
|
@ -47,9 +52,7 @@ mp_obj_t mp_obj_new_ndarray_iterator(mp_obj_t , size_t , mp_obj_iter_buf_t *);
|
|||
mp_float_t ndarray_get_float_value(void *, uint8_t , size_t );
|
||||
void fill_array_iterable(mp_float_t *, mp_obj_t );
|
||||
|
||||
void ndarray_print_row(const mp_print_t *, mp_obj_array_t *, size_t , size_t );
|
||||
void ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t );
|
||||
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 );
|
||||
|
||||
mp_obj_t ndarray_copy(mp_obj_t );
|
||||
|
|
@ -97,27 +100,25 @@ mp_obj_t ndarray_asbytearray(mp_obj_t );
|
|||
return MP_OBJ_FROM_PTR(out);\
|
||||
} else if(((op) == MP_BINARY_OP_LESS) || ((op) == MP_BINARY_OP_LESS_EQUAL) || \
|
||||
((op) == MP_BINARY_OP_MORE) || ((op) == MP_BINARY_OP_MORE_EQUAL)) {\
|
||||
mp_obj_t out_list = mp_obj_new_list(0, NULL);\
|
||||
size_t m = (ol)->m, n = (ol)->n;\
|
||||
ndarray_obj_t *out = create_new_ndarray((ol)->m, (ol)->n, NDARRAY_UINT8);\
|
||||
size_t m = out->m, n = out->n;\
|
||||
out->boolean = NDARRAY_BOOLEAN;\
|
||||
uint8_t *barray = (uint8_t *)out->array->items;\
|
||||
for(size_t i=0, r=0; i < m; i++, r+=inc) {\
|
||||
mp_obj_t row = mp_obj_new_list(n, NULL);\
|
||||
mp_obj_list_t *row_ptr = MP_OBJ_TO_PTR(row);\
|
||||
for(size_t j=0, s=0; j < n; j++, s+=inc) {\
|
||||
row_ptr->items[j] = mp_const_false;\
|
||||
barray[i*n + j] = 0;\
|
||||
if((op) == MP_BINARY_OP_LESS) {\
|
||||
if(left[i*n+j] < right[r*n+s]) row_ptr->items[j] = mp_const_true;\
|
||||
if(left[i*n+j] < right[r*n+s]) barray[i*n + j] = 1;\
|
||||
} else if((op) == MP_BINARY_OP_LESS_EQUAL) {\
|
||||
if(left[i*n+j] <= right[r*n+s]) row_ptr->items[j] = mp_const_true;\
|
||||
if(left[i*n+j] <= right[r*n+s]) barray[i*n + j] = 1;\
|
||||
} else if((op) == MP_BINARY_OP_MORE) {\
|
||||
if(left[i*n+j] > right[r*n+s]) row_ptr->items[j] = mp_const_true;\
|
||||
if(left[i*n+j] > right[r*n+s]) barray[i*n + j] = 1;\
|
||||
} else if((op) == MP_BINARY_OP_MORE_EQUAL) {\
|
||||
if(left[i*n+j] >= right[r*n+s]) row_ptr->items[j] = mp_const_true;\
|
||||
if(left[i*n+j] >= right[r*n+s]) barray[i*n + j] = 1;\
|
||||
}\
|
||||
}\
|
||||
if(m == 1) return row;\
|
||||
mp_obj_list_append(out_list, row);\
|
||||
}\
|
||||
return out_list;\
|
||||
return MP_OBJ_FROM_PTR(out);\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
|
|
|
|||
374
code/numerical.c
374
code/numerical.c
|
|
@ -77,7 +77,33 @@ mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
}
|
||||
}
|
||||
|
||||
mp_obj_t numerical_sum_mean_std_array(mp_obj_t oin, uint8_t optype) {
|
||||
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) {
|
||||
if(axis == mp_const_none) { // flatten the array
|
||||
*m = 1;
|
||||
*n = 1;
|
||||
*len = ndarray->array->len;
|
||||
*N = 1;
|
||||
*increment = 1;
|
||||
*start_inc = ndarray->array->len;
|
||||
} else if((mp_obj_get_int(axis) == 1)) { // along the horizontal axis
|
||||
*m = ndarray->m;
|
||||
*n = 1;
|
||||
*len = ndarray->n;
|
||||
*N = ndarray->m;
|
||||
*increment = 1;
|
||||
*start_inc = ndarray->n;
|
||||
} else { // along vertical axis
|
||||
*m = 1;
|
||||
*n = ndarray->n;
|
||||
*len = ndarray->m;
|
||||
*N = ndarray->n;
|
||||
*increment = ndarray->n;
|
||||
*start_inc = 1;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, size_t ddof) {
|
||||
mp_float_t value, sum = 0.0, sq_sum = 0.0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t item, iterable = mp_getiter(oin, &iter_buf);
|
||||
|
|
@ -85,194 +111,153 @@ mp_obj_t numerical_sum_mean_std_array(mp_obj_t oin, uint8_t optype) {
|
|||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
value = mp_obj_get_float(item);
|
||||
sum += value;
|
||||
if(optype == NUMERICAL_STD) {
|
||||
sq_sum += value*value;
|
||||
}
|
||||
}
|
||||
if(optype == NUMERICAL_SUM) {
|
||||
return mp_obj_new_float(sum);
|
||||
} else if(optype == NUMERICAL_MEAN) {
|
||||
return mp_obj_new_float(sum/len);
|
||||
} else {
|
||||
} else { // this should be the case of the standard deviation
|
||||
// TODO: note that we could get away with a single pass, if we used the Weldorf algorithm
|
||||
// That should save a fair amount of time, because we would have to extract the values only once
|
||||
iterable = mp_getiter(oin, &iter_buf);
|
||||
sum /= len; // this is now the mean!
|
||||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/len-sum*sum));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_float_t numerical_sum_mean_std_single_line(void *data, size_t start, size_t stop,
|
||||
size_t stride, uint8_t typecode, uint8_t optype) {
|
||||
|
||||
mp_float_t sum = 0.0, sq_sum = 0.0, value;
|
||||
size_t len = 0;
|
||||
for(size_t i=start; i < stop; i+=stride, len++) {
|
||||
value = ndarray_get_float_value(data, typecode, i);
|
||||
sum += value;
|
||||
if(optype == NUMERICAL_STD) {
|
||||
sq_sum += value*value;
|
||||
}
|
||||
}
|
||||
if(len == 0) {
|
||||
mp_raise_ValueError("data length is 0!");
|
||||
}
|
||||
if(optype == NUMERICAL_SUM) {
|
||||
return sum;
|
||||
} else if(optype == NUMERICAL_MEAN) {
|
||||
return sum/len;
|
||||
} else {
|
||||
sum /= len; // this is now the mean!
|
||||
return MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/len-sum*sum);
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t numerical_sum_mean_std_matrix(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
||||
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
|
||||
if((axis == mp_const_none) || (in->m == 1) || (in->n == 1)) {
|
||||
// return the value for the flattened array
|
||||
return mp_obj_new_float(numerical_sum_mean_std_single_line(in->array->items, 0,
|
||||
in->array->len, 1, in->array->typecode, optype));
|
||||
} else {
|
||||
uint8_t _axis = mp_obj_get_int(axis);
|
||||
size_t m = (_axis == 0) ? 1 : in->m;
|
||||
size_t n = (_axis == 0) ? in->n : 1;
|
||||
size_t len = in->array->len;
|
||||
mp_float_t sms;
|
||||
// TODO: pass in->array->typcode to create_new_ndarray
|
||||
ndarray_obj_t *out = create_new_ndarray(m, n, NDARRAY_FLOAT);
|
||||
|
||||
// TODO: these two cases could probably be combined in a more elegant fashion...
|
||||
if(_axis == 0) { // vertical
|
||||
for(size_t i=0; i < n; i++) {
|
||||
sms = numerical_sum_mean_std_single_line(in->array->items, i, len,
|
||||
n, in->array->typecode, optype);
|
||||
((float_t *)out->array->items)[i] = sms;
|
||||
}
|
||||
} else { // horizontal
|
||||
for(size_t i=0; i < m; i++) {
|
||||
sms = numerical_sum_mean_std_single_line(in->array->items, i*in->n,
|
||||
(i+1)*in->n, 1, in->array->typecode, optype);
|
||||
((float_t *)out->array->items)[i] = sms;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(out);
|
||||
}
|
||||
}
|
||||
|
||||
size_t numerical_argmin_argmax_array(ndarray_obj_t *in, size_t start,
|
||||
size_t stop, size_t stride, uint8_t op) {
|
||||
size_t best_idx = start;
|
||||
if(in->array->typecode == NDARRAY_UINT8) {
|
||||
ARG_MIN_LOOP(in, uint8_t, start, stop, stride, op);
|
||||
} else if(in->array->typecode == NDARRAY_INT8) {
|
||||
ARG_MIN_LOOP(in, int8_t, start, stop, stride, op);
|
||||
} else if(in->array->typecode == NDARRAY_UINT16) {
|
||||
ARG_MIN_LOOP(in, uint16_t, start, stop, stride, op);
|
||||
} else if(in->array->typecode == NDARRAY_INT16) {
|
||||
ARG_MIN_LOOP(in, uint16_t, start, stop, stride, op);
|
||||
} else if(in->array->typecode == NDARRAY_FLOAT) {
|
||||
ARG_MIN_LOOP(in, mp_float_t, start, stop, stride, op);
|
||||
}
|
||||
return best_idx;
|
||||
}
|
||||
|
||||
void copy_value_into_ndarray(ndarray_obj_t *target, ndarray_obj_t *source, size_t target_idx, size_t source_idx) {
|
||||
// since we are simply copying, it doesn't matter, whether the arrays are signed or unsigned,
|
||||
// we can cast them in any way we like
|
||||
// This could also be done with byte copies. I don't know, whether that would have any benefits
|
||||
if((target->array->typecode == NDARRAY_UINT8) || (target->array->typecode == NDARRAY_INT8)) {
|
||||
((uint8_t *)target->array->items)[target_idx] = ((uint8_t *)source->array->items)[source_idx];
|
||||
} else if((target->array->typecode == NDARRAY_UINT16) || (target->array->typecode == NDARRAY_INT16)) {
|
||||
((uint16_t *)target->array->items)[target_idx] = ((uint16_t *)source->array->items)[source_idx];
|
||||
} else {
|
||||
((float *)target->array->items)[target_idx] = ((float *)source->array->items)[source_idx];
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t numerical_argmin_argmax(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
||||
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)) {
|
||||
// This case will work for single iterables only
|
||||
size_t idx = 0, best_idx = 0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(oin, &iter_buf);
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
mp_obj_t item;
|
||||
mp_uint_t op = MP_BINARY_OP_LESS;
|
||||
if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = MP_BINARY_OP_MORE;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if ((best_obj == MP_OBJ_NULL) || (mp_binary_op(op, item, best_obj) == mp_const_true)) {
|
||||
best_obj = item;
|
||||
best_idx = idx;
|
||||
}
|
||||
idx++;
|
||||
value = mp_obj_get_float(item) - sum;
|
||||
sq_sum += value * value;
|
||||
}
|
||||
if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(best_idx);
|
||||
} else {
|
||||
return best_obj;
|
||||
}
|
||||
} else if(mp_obj_is_type(oin, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
|
||||
size_t best_idx;
|
||||
if((axis == mp_const_none) || (in->m == 1) || (in->n == 1)) {
|
||||
// return the value for the flattened array
|
||||
best_idx = numerical_argmin_argmax_array(in, 0, in->array->len, 1, optype);
|
||||
if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(best_idx);
|
||||
} else {
|
||||
if(in->array->typecode == NDARRAY_FLOAT) {
|
||||
return mp_obj_new_float(ndarray_get_float_value(in->array->items, in->array->typecode, best_idx));
|
||||
} else {
|
||||
return mp_binary_get_val_array(in->array->typecode, in->array->items, best_idx);
|
||||
}
|
||||
}
|
||||
} else { // we have to work with a full matrix here
|
||||
uint8_t _axis = mp_obj_get_int(axis);
|
||||
size_t m = (_axis == 0) ? 1 : in->m;
|
||||
size_t n = (_axis == 0) ? in->n : 1;
|
||||
size_t len = in->array->len;
|
||||
ndarray_obj_t *ndarray = NULL;
|
||||
if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) {
|
||||
ndarray = create_new_ndarray(m, n, in->array->typecode);
|
||||
} else { // argmin/argmax
|
||||
// TODO: one might get away with uint8_t, if both m, and n < 255
|
||||
ndarray = create_new_ndarray(m, n, NDARRAY_UINT16);
|
||||
}
|
||||
|
||||
// TODO: these two cases could probably be combined in a more elegant fashion...
|
||||
if(_axis == 0) { // vertical
|
||||
for(size_t i=0; i < n; i++) {
|
||||
best_idx = numerical_argmin_argmax_array(in, i, len, n, optype);
|
||||
if((optype == NUMERICAL_MIN) || (optype == NUMERICAL_MAX)) {
|
||||
copy_value_into_ndarray(ndarray, in, i, best_idx);
|
||||
} else {
|
||||
((uint16_t *)ndarray->array->items)[i] = (uint16_t)(best_idx / n);
|
||||
}
|
||||
}
|
||||
} else { // horizontal
|
||||
for(size_t i=0; i < m; i++) {
|
||||
best_idx = numerical_argmin_argmax_array(in, i*in->n, (i+1)*in->n, 1, optype);
|
||||
if((optype == NUMERICAL_MIN) || (optype == NUMERICAL_MAX)) {
|
||||
copy_value_into_ndarray(ndarray, in, i, best_idx);
|
||||
} else {
|
||||
((uint16_t *)ndarray->array->items)[i] = (uint16_t)(best_idx - i*in->n);
|
||||
}
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
mp_raise_TypeError("input type is not supported");
|
||||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(sq_sum/(len-ddof)));
|
||||
}
|
||||
}
|
||||
|
||||
STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t type) {
|
||||
STATIC mp_obj_t numerical_sum_mean_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) {
|
||||
size_t m, n, increment, start, start_inc, N, len;
|
||||
axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc);
|
||||
ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT);
|
||||
mp_float_t sum, sq_sum;
|
||||
mp_float_t *farray = (mp_float_t *)results->array->items;
|
||||
for(size_t j=0; j < N; j++) { // result index
|
||||
start = j * start_inc;
|
||||
sum = sq_sum = 0.0;
|
||||
if(ndarray->array->typecode == NDARRAY_UINT8) {
|
||||
RUN_SUM(ndarray, uint8_t, optype, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_INT8) {
|
||||
RUN_SUM(ndarray, int8_t, optype, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_UINT16) {
|
||||
RUN_SUM(ndarray, uint16_t, optype, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_INT16) {
|
||||
RUN_SUM(ndarray, int16_t, optype, len, start, increment);
|
||||
} else { // this will be mp_float_t, no need to check
|
||||
RUN_SUM(ndarray, mp_float_t, optype, len, start, increment);
|
||||
}
|
||||
if(optype == NUMERICAL_SUM) {
|
||||
farray[j] = sum;
|
||||
} else { // this is the case of the mean
|
||||
farray[j] = sum / len;
|
||||
}
|
||||
}
|
||||
if(results->array->len == 1) {
|
||||
return mp_obj_new_float(farray[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddof) {
|
||||
size_t m, n, increment, start, start_inc, N, len;
|
||||
mp_float_t sum, sum_sq;
|
||||
|
||||
axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc);
|
||||
if(ddof > len) {
|
||||
mp_raise_ValueError("ddof must be smaller than length of data set");
|
||||
}
|
||||
ndarray_obj_t *results = create_new_ndarray(m, n, NDARRAY_FLOAT);
|
||||
mp_float_t *farray = (mp_float_t *)results->array->items;
|
||||
for(size_t j=0; j < N; j++) { // result index
|
||||
start = j * start_inc;
|
||||
sum = 0.0;
|
||||
sum_sq = 0.0;
|
||||
if(ndarray->array->typecode == NDARRAY_UINT8) {
|
||||
RUN_STD(ndarray, uint8_t, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_INT8) {
|
||||
RUN_STD(ndarray, int8_t, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_UINT16) {
|
||||
RUN_STD(ndarray, uint16_t, len, start, increment);
|
||||
} else if(ndarray->array->typecode == NDARRAY_INT16) {
|
||||
RUN_STD(ndarray, int16_t, len, start, increment);
|
||||
} else { // this will be mp_float_t, no need to check
|
||||
RUN_STD(ndarray, mp_float_t, len, start, increment);
|
||||
}
|
||||
farray[j] = MICROPY_FLOAT_C_FUN(sqrt)(sum_sq/(len - ddof));
|
||||
}
|
||||
if(results->array->len == 1) {
|
||||
return mp_obj_new_float(farray[0]);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
||||
size_t idx = 0, best_idx = 0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t iterable = mp_getiter(oin, &iter_buf);
|
||||
mp_obj_t best_obj = MP_OBJ_NULL;
|
||||
mp_obj_t item;
|
||||
mp_uint_t op = MP_BINARY_OP_LESS;
|
||||
if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = MP_BINARY_OP_MORE;
|
||||
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if ((best_obj == MP_OBJ_NULL) || (mp_binary_op(op, item, best_obj) == mp_const_true)) {
|
||||
best_obj = item;
|
||||
best_idx = idx;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) {
|
||||
return MP_OBJ_NEW_SMALL_INT(best_idx);
|
||||
} else {
|
||||
return best_obj;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) {
|
||||
size_t m, n, increment, start, start_inc, N, len;
|
||||
axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc);
|
||||
ndarray_obj_t *results;
|
||||
if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) {
|
||||
// we could save some RAM by taking NDARRAY_UINT8, if the dimensions
|
||||
// are smaller than 256, but the code would become more involving
|
||||
// (we would also need extra flash space)
|
||||
results = create_new_ndarray(m, n, NDARRAY_UINT16);
|
||||
} else {
|
||||
results = create_new_ndarray(m, n, ndarray->array->typecode);
|
||||
}
|
||||
|
||||
for(size_t j=0; j < N; j++) { // result index
|
||||
start = j * start_inc;
|
||||
if((ndarray->array->typecode == NDARRAY_UINT8) || (ndarray->array->typecode == NDARRAY_INT8)) {
|
||||
if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) {
|
||||
RUN_ARGMIN(ndarray, results, uint8_t, uint8_t, len, start, increment, optype, j);
|
||||
} else {
|
||||
RUN_ARGMIN(ndarray, results, uint8_t, uint16_t, len, start, increment, optype, j);
|
||||
}
|
||||
} else if((ndarray->array->typecode == NDARRAY_UINT16) || (ndarray->array->typecode == NDARRAY_INT16)) {
|
||||
RUN_ARGMIN(ndarray, results, uint16_t, uint16_t, len, start, increment, optype, j);
|
||||
} else {
|
||||
if((optype == NUMERICAL_MAX) || (optype == NUMERICAL_MIN)) {
|
||||
RUN_ARGMIN(ndarray, results, mp_float_t, mp_float_t, len, start, increment, optype, j);
|
||||
} else {
|
||||
RUN_ARGMIN(ndarray, results, mp_float_t, uint16_t, len, start, increment, optype, j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} } ,
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
};
|
||||
|
||||
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(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t oin = args[0].u_obj;
|
||||
mp_obj_t axis = args[1].u_obj;
|
||||
|
|
@ -283,30 +268,29 @@ STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
|
||||
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)) {
|
||||
switch(type) {
|
||||
switch(optype) {
|
||||
case NUMERICAL_MIN:
|
||||
case NUMERICAL_ARGMIN:
|
||||
case NUMERICAL_MAX:
|
||||
case NUMERICAL_ARGMAX:
|
||||
return numerical_argmin_argmax(oin, axis, type);
|
||||
return numerical_argmin_argmax_iterable(oin, axis, optype);
|
||||
case NUMERICAL_SUM:
|
||||
case NUMERICAL_MEAN:
|
||||
case NUMERICAL_STD:
|
||||
return numerical_sum_mean_std_array(oin, type);
|
||||
return numerical_sum_mean_std_iterable(oin, optype, 0);
|
||||
default: // we should never reach this point, but whatever
|
||||
return mp_const_none;
|
||||
}
|
||||
} else if(MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
|
||||
switch(type) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin);
|
||||
switch(optype) {
|
||||
case NUMERICAL_MIN:
|
||||
case NUMERICAL_MAX:
|
||||
case NUMERICAL_ARGMIN:
|
||||
case NUMERICAL_ARGMAX:
|
||||
return numerical_argmin_argmax(oin, axis, type);
|
||||
return numerical_argmin_argmax_ndarray(ndarray, axis, optype);
|
||||
case NUMERICAL_SUM:
|
||||
case NUMERICAL_MEAN:
|
||||
case NUMERICAL_STD:
|
||||
return numerical_sum_mean_std_matrix(oin, axis, type);
|
||||
return numerical_sum_mean_ndarray(ndarray, axis, optype);
|
||||
default:
|
||||
mp_raise_NotImplementedError("operation is not implemented on ndarrays");
|
||||
}
|
||||
|
|
@ -341,7 +325,31 @@ mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
}
|
||||
|
||||
mp_obj_t numerical_std(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_STD);
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} } ,
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },
|
||||
{ MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t oin = args[0].u_obj;
|
||||
mp_obj_t axis = args[1].u_obj;
|
||||
size_t ddof = args[2].u_int;
|
||||
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...
|
||||
mp_raise_ValueError("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)) {
|
||||
return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof);
|
||||
} else if(MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin);
|
||||
return numerical_std_ndarray(ndarray, axis, ddof);
|
||||
} else {
|
||||
mp_raise_TypeError("input must be tuple, list, range, or ndarray");
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
|
|
|
|||
|
|
@ -33,19 +33,44 @@ 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 *);
|
||||
|
||||
// this macro could be tighter, if we moved the ifs to the argmin function, assigned <, as well as >
|
||||
#define ARG_MIN_LOOP(in, type, start, stop, stride, op) do {\
|
||||
type *array = (type *)(in)->array->items;\
|
||||
#define RUN_ARGMIN(in, out, typein, typeout, len, start, increment, op, pos) do {\
|
||||
typein *array = (typein *)(in)->array->items;\
|
||||
typeout *outarray = (typeout *)(out)->array->items;\
|
||||
size_t best_index = 0;\
|
||||
if(((op) == NUMERICAL_MAX) || ((op) == NUMERICAL_ARGMAX)) {\
|
||||
for(size_t i=(start)+(stride); i < (stop); i+=(stride)) {\
|
||||
if((array)[i] > (array)[best_idx]) {\
|
||||
best_idx = i;\
|
||||
}\
|
||||
for(size_t i=1; i < (len); i++) {\
|
||||
if(array[(start)+i*(increment)] > array[(start)+best_index*(increment)]) best_index = i;\
|
||||
}\
|
||||
if((op) == NUMERICAL_MAX) outarray[(pos)] = array[(start)+best_index*(increment)];\
|
||||
else outarray[(pos)] = best_index;\
|
||||
} else{\
|
||||
for(size_t i=(start)+(stride); i < (stop); i+=(stride)) {\
|
||||
if((array)[i] < (array)[best_idx]) best_idx = i;\
|
||||
for(size_t i=1; i < (len); i++) {\
|
||||
if(array[(start)+i*(increment)] < array[(start)+best_index*(increment)]) best_index = i;\
|
||||
}\
|
||||
if((op) == NUMERICAL_MIN) outarray[(pos)] = array[(start)+best_index*(increment)];\
|
||||
else outarray[(pos)] = best_index;\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
#define RUN_SUM(ndarray, type, optype, len, start, increment) do {\
|
||||
type *array = (type *)(ndarray)->array->items;\
|
||||
type value;\
|
||||
for(size_t j=0; j < (len); j++) {\
|
||||
value = array[(start)+j*(increment)];\
|
||||
sum += value;\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
#define RUN_STD(ndarray, type, len, start, increment) do {\
|
||||
type *array = (type *)(ndarray)->array->items;\
|
||||
mp_float_t value;\
|
||||
for(size_t j=0; j < (len); j++) {\
|
||||
sum += array[(start)+j*(increment)];\
|
||||
}\
|
||||
sum /= (len);\
|
||||
for(size_t j=0; j < (len); j++) {\
|
||||
value = (array[(start)+j*(increment)] - sum);\
|
||||
sum_sq += value * value;\
|
||||
}\
|
||||
} while(0)
|
||||
|
||||
|
|
|
|||
|
|
@ -89,8 +89,8 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
if(!object_is_nditerable(args[0])) {
|
||||
mp_raise_ValueError("input data must be an iterable");
|
||||
}
|
||||
uint16_t lenx, leny;
|
||||
uint8_t deg;
|
||||
uint16_t lenx = 0, leny = 0;
|
||||
uint8_t deg = 0;
|
||||
mp_float_t *x, *XT, *y, *prod;
|
||||
|
||||
if(n_args == 2) { // only the y values are supplied
|
||||
|
|
@ -108,7 +108,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
}
|
||||
y = m_new(mp_float_t, leny);
|
||||
fill_array_iterable(y, args[0]);
|
||||
} else if(n_args == 3) {
|
||||
} else { // n_args == 3
|
||||
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]));
|
||||
if(lenx != leny) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
#include "fft.h"
|
||||
#include "numerical.h"
|
||||
|
||||
#define ULAB_VERSION 0.26
|
||||
#define ULAB_VERSION 0.27
|
||||
|
||||
typedef struct _mp_obj_float_t {
|
||||
mp_obj_base_t base;
|
||||
|
|
@ -173,6 +173,7 @@ STATIC const mp_map_elem_t ulab_globals_table[] = {
|
|||
{ 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_bool), MP_ROM_INT(NDARRAY_BOOL) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_uint16), MP_ROM_INT(NDARRAY_UINT16) },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
|
||||
Fri, 8 Nov 2019
|
||||
|
||||
version 0.27
|
||||
|
||||
cleaned up the sum/mean/std functions in numerical.c, and changed the output of relational operators
|
||||
|
||||
Tue, 6 Nov 2019
|
||||
|
||||
version 0.26
|
||||
|
|
|
|||
|
|
@ -22,6 +22,65 @@
|
|||
"%pylab inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 87,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-11-07T17:11:51.529183Z",
|
||||
"start_time": "2019-11-07T17:11:51.522117Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(array([ True, True, False, True]),\n",
|
||||
" array([1, 1, 1, 1], dtype=int8),\n",
|
||||
" dtype('int16'))"
|
||||
]
|
||||
},
|
||||
"execution_count": 87,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a = array([1, 2, 3, 255], dtype=int16)\n",
|
||||
"b = array([1, 2, 0, 1], dtype=bool)\n",
|
||||
"c = array([1, 2, 1, 1], dtype=bool)\n",
|
||||
"b, c**b, (a+b).dtype"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 100,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-11-08T05:52:22.454175Z",
|
||||
"start_time": "2019-11-08T05:52:22.436159Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"((2,), (2, 4))"
|
||||
]
|
||||
},
|
||||
"execution_count": 100,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a = array([[1, 2, 3, 4], [5, 6,7, 8]], dtype=uint8)\n",
|
||||
"b = array([3, 2, 1, 0], dtype=uint8)\n",
|
||||
"c = array([5, 6], dtype=uint8)\n",
|
||||
"c = transpose(c)\n",
|
||||
"c.shape, a.shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 23,
|
||||
|
|
@ -120,10 +179,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"execution_count": 47,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"start_time": "2019-11-06T17:37:29.723Z"
|
||||
"end_time": "2019-11-06T17:37:33.012936Z",
|
||||
"start_time": "2019-11-06T17:37:29.726772Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -696,7 +756,7 @@
|
|||
"\n",
|
||||
"If the iterable is one-dimensional, i.e., one whose elements are numbers, then a row vector will be created and returned. If the iterable is two-dimensional, i.e., one whose elements are again iterables, a matrix will be created. If the lengths of the iterables is not consistent, a `ValueError` will be raised. Iterables of different types can be mixed in the initialisation function. \n",
|
||||
"\n",
|
||||
"If the `dtype` keyword with the possible `uint8/int8/uint16/int16/float` values is supplied, the new `ndarray` will have that type, otherwise, it assumes `float` as default. "
|
||||
"If the `dtype` keyword with the possible `bool/uint8/int8/uint16/int16/float` values is supplied, the new `ndarray` will have that type, otherwise, it assumes `float` as default. "
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1522,31 +1582,29 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 188,
|
||||
"execution_count": 116,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-11T18:59:35.810060Z",
|
||||
"start_time": "2019-10-11T18:59:35.804683Z"
|
||||
"end_time": "2019-11-14T06:33:04.536515Z",
|
||||
"start_time": "2019-11-14T06:33:04.530675Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"array([[11, 22, 33],\n",
|
||||
" [14, 25, 36],\n",
|
||||
" [17, 28, 36]])"
|
||||
"((24, 8), 8)"
|
||||
]
|
||||
},
|
||||
"execution_count": 188,
|
||||
"execution_count": 116,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a = array([[1, 2, 3], [4, 5, 6], [7, 8, 6]])\n",
|
||||
"b = array([10, 20, 30])\n",
|
||||
"a+b"
|
||||
"a = array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
|
||||
"b = a.reshape((9, ))\n",
|
||||
"a.strides, a.itemsize"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1559,16 +1617,23 @@
|
|||
"\n",
|
||||
"`ulab` observes the following upcasting rules:\n",
|
||||
"\n",
|
||||
"1. Operations with two `ndarray`s of the same `dtype` preserve their `dtype`, even when the results overflow.\n",
|
||||
"1. If one of the operands is a `bool` array, the result inherits the `dtype` of the other.\n",
|
||||
"\n",
|
||||
"2. if either of the operands is a float, the result is automatically a float\n",
|
||||
"2. Operations with two `ndarray`s of the same `dtype` preserve their `dtype`, even when the results overflow.\n",
|
||||
"\n",
|
||||
"3. When the right hand side of a binary operator is a micropython variable, `mp_obj_int`, or `mp_obj_float`, then the result will be promoted to `dtype` `float`. This is necessary, because a micropython integer can be 31 bites wide. Other micropython types (e.g., lists, tuples, etc.) raise a `TypeError` exception. \n",
|
||||
"3. if either of the operands is a float, the result is automatically a float\n",
|
||||
"\n",
|
||||
"4. \n",
|
||||
"4. When the right hand side of a binary operator is a micropython variable, `mp_obj_int`, or `mp_obj_float`, then the result will be promoted to a `dtype` that can still contain the numerical value, i.e., positive integers between 0, and 255 are converted to `dtype=uint8`, negative integers that are larger than -128 are converted to `dtype=int8` and so on. If the integer cannot fit into the constraints of `uint16/int16`, then the scalar will be converted to a `float`. Other micropython types (e.g., lists, tuples, etc.) raise a `TypeError` exception. \n",
|
||||
"\n",
|
||||
"5. \n",
|
||||
" \n",
|
||||
"| left hand side | right hand side | ulab result | numpy result |\n",
|
||||
"|----------------|-----------------|-------------|--------------|\n",
|
||||
"|`bool` |`bool` |`bool` |`bool` |\n",
|
||||
"|`bool` |`uint8` |`uint8` |`uint8` |\n",
|
||||
"|`bool` |`int8` |`int8` |`int8 ` |\n",
|
||||
"|`bool` |`uint16` |`uint16` |`uint16` |\n",
|
||||
"|`bool` |`int16` |`int16` |`int16` |\n",
|
||||
"|`uint8` |`int8` |`int16` |`int16` |\n",
|
||||
"|`uint8` |`int16` |`int16` |`int16` |\n",
|
||||
"|`uint8` |`uint16` |`uint16` |`uint16` |\n",
|
||||
|
|
|
|||
785
docs/ulab.ipynb
785
docs/ulab.ipynb
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue