From 7d769da4f5c1f31be7f9b5b92e53d1e79ca90be0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zolt=C3=A1n=20V=C3=B6r=C3=B6s?= Date: Thu, 8 Aug 2019 21:27:01 +0200 Subject: [PATCH] added numerical module to ulab --- docs/ulab.ipynb | 692 +++++++++++++++++++++++++++++++------------- ulab/micropython.mk | 1 + ulab/ndarray.c | 6 +- ulab/ndarray.h | 6 +- ulab/numerical.c | 149 ++++++++++ ulab/numerical.h | 19 ++ ulab/ulab.c | 22 +- 7 files changed, 684 insertions(+), 211 deletions(-) create mode 100644 ulab/numerical.c create mode 100644 ulab/numerical.h diff --git a/docs/ulab.ipynb b/docs/ulab.ipynb index 3f8b14a..7db4427 100644 --- a/docs/ulab.ipynb +++ b/docs/ulab.ipynb @@ -11,7 +11,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "ulab is a C module for micropython. The main aim is to implement a small subset of numpy. We chose those functions and methods that might be useful in the context of a microcontroller. This means low-level data processing. " + "ulab is a C module for micropython. The aim was to implement a small subset of numpy. We chose those functions and methods that might be useful in the context of a microcontroller. This means low-level data processing of linear and matrix data.\n", + "\n", + "The main points of ulab are \n", + "\n", + "- compact, iterable and slicable container of numerical data in 1, and 2 dimensions (arrays and matrices). In addition, these containers support all the relevant unary and binary operators (e.g., `len`, `bool`, ==, +, *, etc.)\n", + "- vectorised computations on micropython iterables and numerical arrays/matrices\n", + "- basic linear algebra routines (like matrix inversion, matrix reshaping, and transposition)\n", + "- polynomial first to numerical data\n", + "- fast Fourier transforms\n", + "\n", + "Each section of the implementation part kicks out with a short discussion on what can be done with the module, and what are the tripping points at the C level. I hope that these musings can be used as a starting point for further discussion on the code. Then come the contents of the header and C files of the particular module. " ] }, { @@ -225,6 +235,69 @@ "**NOTE: with a little bit of extra effort, mp_obj_array_t can be replaced by a single void array. We should, perhaps, consider the pros and cons of that. One patent advantage is that we could get rid of the verbatim copy of array_new function in ndarray.c.**" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Most of the functions in ndarray.c are internal (i.e., not exposed to the python interpreter). Exception to this rule are the `shape`, `size`, and `rawsize` functions. This latter on is not standard in numpy, and is meant to return the total number of bytes used by the container. Since the RAM of a microcontroller is limited, I deemed this to be a reasonable addition for optimisation purposes. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialisation\n", + "\n", + "An ndarray can be initialised by passing an iterable (linear arrays), or an iterable of iterables (matrices) into the constructor as" + ] + }, + { + "cell_type": "code", + "execution_count": 205, + "metadata": { + "ExecuteTime": { + "end_time": "2019-08-07T19:42:05.874414Z", + "start_time": "2019-08-07T19:42:05.853846Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ndarray([1.0, 2.0, 3.0, 4.0])\n", + "\n", + "ndarray([[1.0, 2.0, 3.0, 4.0],\n", + "\t [2.0, 3.0, 4.0, 5.0]])\n", + "\n", + "ndarray([[0.0, 1.0, 2.0, ..., 7.0, 8.0, 9.0],\n", + "\t [0.0, 1.0, 2.0, ..., 7.0, 8.0, 9.0]])\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython\n", + "\n", + "from ulab import ndarray\n", + "\n", + "a = ndarray([1, 2, 3, 4])\n", + "print(a)\n", + "a = ndarray([[1, 2, 3, 4], [2, 3, 4, 5]])\n", + "print(a)\n", + "a = ndarray([range(10), range(10)])\n", + "print(a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In addition, the constructor can take a keyword argument, dtype, that will force type conversion." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -234,11 +307,11 @@ }, { "cell_type": "code", - "execution_count": 118, + "execution_count": 198, "metadata": { "ExecuteTime": { - "end_time": "2019-08-07T16:45:07.715837Z", - "start_time": "2019-08-07T16:45:07.708734Z" + "end_time": "2019-08-07T19:13:59.067813Z", + "start_time": "2019-08-07T19:13:59.049895Z" } }, "outputs": [ @@ -246,7 +319,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "written 1505 bytes to ndarray.h\n" + "written 1490 bytes to ndarray.h\n" ] } ], @@ -292,11 +365,11 @@ "*/\n", "\n", "void ndarray_print_row(const mp_print_t *, mp_obj_array_t *, size_t , size_t );\n", - "void ulab_ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t );\n", + "void ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t );\n", "void assign_elements(mp_obj_array_t *, mp_obj_t , uint8_t , size_t *);\n", "ndarray_obj_t *create_new_ndarray(size_t , size_t , uint8_t );\n", - "mp_obj_t ulab_ndarray_copy(mp_obj_t );\n", - "mp_obj_t ulab_ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *);\n", + "mp_obj_t ndarray_copy(mp_obj_t );\n", + "mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *);\n", "\n", "mp_obj_t ndarray_shape(mp_obj_t );\n", "mp_obj_t ndarray_size(mp_obj_t , mp_obj_t );\n", @@ -314,11 +387,11 @@ }, { "cell_type": "code", - "execution_count": 105, + "execution_count": 199, "metadata": { "ExecuteTime": { - "end_time": "2019-08-07T16:38:44.272360Z", - "start_time": "2019-08-07T16:38:44.260534Z" + "end_time": "2019-08-07T19:14:32.169261Z", + "start_time": "2019-08-07T19:14:32.149002Z" } }, "outputs": [ @@ -326,7 +399,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "written 8066 bytes to ndarray.c\n" + "written 8051 bytes to ndarray.c\n" ] } ], @@ -386,10 +459,10 @@ " mp_print_str(print, \"]\");\n", "}\n", "\n", - "void ulab_ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n", + "void ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n", " (void)kind;\n", " ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n", - " mp_print_str(print, \"ndarray(\");\t\n", + " mp_print_str(print, \"ndarray(\");\n", " if((self->m == 1) || (self->n == 1)) {\n", " ndarray_print_row(print, self->data, 0, self->data->len);\n", " } else {\n", @@ -429,7 +502,7 @@ " return ndarray;\n", "}\n", "\n", - "mp_obj_t ulab_ndarray_copy(mp_obj_t self_in) {\n", + "mp_obj_t ndarray_copy(mp_obj_t self_in) {\n", " // returns a verbatim (shape and typecode) copy of self_in\n", " ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n", " ndarray_obj_t *out = create_new_ndarray(self->m, self->n, self->data->typecode);\n", @@ -438,7 +511,7 @@ " return MP_OBJ_FROM_PTR(out);\n", "}\n", "\n", - "mp_obj_t ulab_ndarray_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {\n", + "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) {\n", " mp_arg_check_num(n_args, n_kw, 1, 3, true);\n", " \n", " size_t len1, len2=0, i=0;\n", @@ -539,7 +612,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Linear algebra" + "# Linear algebra\n", + "\n", + "This module contains very basic matrix operators, such as transposing, reshaping, and inverting. The actual inversion is factored out into a helper function, so that the routine can be re-used in other modules. Also note that inversion is based on the notion of a *small number* (epsilon). During the computation of the inverse, a number is treated as 0, if its absolute value is smaller than epsilon. This precaution is required, otherwise, one might run into singular matrices. " ] }, { @@ -748,8 +823,51 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The following module implements the common mathematical functions for scalars, ndarrays (linear or matrix), and iterables. If the input argument is a scalar, a scalar is returned (i.e., for such arguments, these functions are identical to the functions in the `math` module), while for ndarrays, and iterables, the return value is an ndarray. \n", + "## General comments" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The following module implements the common mathematical functions for scalars, ndarrays (linear or matrix), and iterables. If the input argument is a scalar, a scalar is returned (i.e., for such arguments, these functions are identical to the functions in the `math` module), while for ndarrays, and iterables, the return value is an ndarray. " + ] + }, + { + "cell_type": "code", + "execution_count": 208, + "metadata": { + "ExecuteTime": { + "end_time": "2019-08-07T19:44:50.983799Z", + "start_time": "2019-08-07T19:44:50.965600Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ndarray([1.0, 2.718281745910645, 7.389056205749512, 20.08553695678711, 54.59814834594727])\n", + "\n", + "7.38905609893065\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython\n", + "\n", + "import ulab\n", "\n", + "print(ulab.exp(range(5)))\n", + "print(ulab.exp(2.0))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ "Note that ndarrays are linear arrays in memory, even if the `shape` of the ndarray is a matrix. This means that we can treat both cases in a *single* loop." ] }, @@ -872,7 +990,7 @@ " }\n", "/* if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {\n", " ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);\n", - " ndarray_obj_t *array = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT);\n", + " ndarray_obj_t *nd_array = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT);\n", " }*/\n", " if(MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(o_in, &mp_type_list) || \n", " MP_OBJ_IS_TYPE(o_in, &mp_type_range)) {\n", @@ -1088,6 +1206,263 @@ "#include \"fft.h\"" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Numerical\n", + "\n", + "This section contains miscellaneous functions that did not fit in the other submodules. These include `linspace`, `logspace`, `min/max`, `argmin/argmax`, `sum`, `mean`, `std`, and `clip`. These latter functions work with iterables, or ndarrays. When the ndarray is two-dimensional, an `axis` keyword can be supplied, in which case, the function returns a vector, otherwise a scalar." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "numpy.linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None)" + ] + }, + { + "cell_type": "code", + "execution_count": 249, + "metadata": { + "ExecuteTime": { + "end_time": "2019-08-08T05:24:24.356757Z", + "start_time": "2019-08-08T05:24:24.335597Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ndarray([0.0, 1.0, 2.0, ..., 8.0, 9.0, 10.0])\n", + "\n", + "6.0\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython\n", + "\n", + "import ulab\n", + "\n", + "print(ulab.linspace(0, 10, 11))\n", + "print(ulab.sum([1, 2, 3]))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## numerical.h" + ] + }, + { + "cell_type": "code", + "execution_count": 267, + "metadata": { + "ExecuteTime": { + "end_time": "2019-08-08T19:01:22.049275Z", + "start_time": "2019-08-08T19:01:22.027294Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "written 359 bytes to numerical.h\n" + ] + } + ], + "source": [ + "%%ccode numerical.h\n", + "\n", + "#ifndef _NUMERICAL_\n", + "#define _NUMERICAL_\n", + "\n", + "#include \"ndarray.h\"\n", + "\n", + "mp_obj_t numerical_linspace(mp_obj_t , mp_obj_t , mp_obj_t );\n", + "mp_obj_t numerical_sum(mp_obj_t , mp_obj_t );\n", + "\n", + "#endif" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## numerical.c" + ] + }, + { + "cell_type": "code", + "execution_count": 275, + "metadata": { + "ExecuteTime": { + "end_time": "2019-08-08T19:05:43.361531Z", + "start_time": "2019-08-08T19:05:43.352973Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "written 5865 bytes to numerical.c\n" + ] + } + ], + "source": [ + "%%ccode numerical.c\n", + "\n", + "#include \n", + "#include \"py/runtime.h\"\n", + "#include \"numerical.h\"\n", + "\n", + "typedef struct {\n", + " uint8_t uint8;\n", + " int8_t int8;\n", + " uint16_t uint16;\n", + " int16_t int16;\n", + " float float1, float2; // we need two floats, so that the standard deviation can be calculated\n", + "} numerical_results;\n", + "\n", + "numerical_results n_results;\n", + "\n", + "mp_obj_t numerical_linspace(mp_obj_t _start, mp_obj_t _stop, mp_obj_t _len) {\n", + " // TODO: accept keyword argument endpoint=True\n", + " mp_int_t len = mp_obj_get_int_truncated(_len);\n", + " if(len < 2) {\n", + " mp_raise_ValueError(\"number of points must be at least 2\");\n", + " }\n", + " mp_float_t value, step;\n", + " value = mp_obj_get_float(_start);\n", + " step = (mp_obj_get_float(_stop)-value)/(len-1);\n", + " ndarray_obj_t *nd_array = create_new_ndarray(1, len, NDARRAY_FLOAT);\n", + " for(size_t i=0; i < len; i++, value += step) {\n", + " mp_binary_set_val_array('f', nd_array->data->items, i, mp_obj_new_float(value));\n", + " }\n", + " return MP_OBJ_FROM_PTR(nd_array);\n", + "}\n", + "void clear_results(void) {\n", + " n_results.uint8 = 0;\n", + " n_results.int8 = 0;\n", + " n_results.uint16 = 0;\n", + " n_results.int16 = 0;\n", + " n_results.float1 = n_results.float2 = 0.0;\n", + "}\n", + "\n", + "void sum_matrix(void *data, size_t start, size_t stop, size_t stride, unsigned char type) {\n", + " clear_results();\n", + " for(size_t i=start; i < stop; i+= stride) {\n", + " switch(type) {\n", + " case NDARRAY_UINT8:\n", + " n_results.uint8 += ((uint8_t *)data)[i];\n", + " break;\n", + " case NDARRAY_INT8:\n", + " n_results.int8 += ((int8_t *)data)[i];\n", + " break;\n", + " case NDARRAY_UINT16:\n", + " n_results.uint16 += ((uint16_t *)data)[i];\n", + " break;\n", + " case NDARRAY_INT16:\n", + " n_results.int16 += ((int16_t *)data)[i];\n", + " break;\n", + " case NDARRAY_FLOAT:\n", + " n_results.float1 += ((float *)data)[i];\n", + " }\n", + " }\n", + "}\n", + "\n", + "mp_obj_t numerical_sum(mp_obj_t o_in, mp_obj_t axis) {\n", + " // TODO: deal with keyword argument\n", + " if(MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(o_in, &mp_type_list) || \n", + " MP_OBJ_IS_TYPE(o_in, &mp_type_range)) {\n", + " mp_float_t _sum = 0.0;\n", + " mp_obj_iter_buf_t iter_buf;\n", + " mp_obj_t item, iterable = mp_getiter(o_in, &iter_buf);\n", + " while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n", + " _sum += mp_obj_get_float(item);\n", + " }\n", + " return mp_obj_new_float(_sum);\n", + " } else if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {\n", + " ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);\n", + " if((o->m == 1) || (o->n == 1)) {\n", + " sum_matrix(o->data->items, 1, o->data->len, 1, o->data->typecode);\n", + " if(o->data->typecode == NDARRAY_UINT8) {\n", + " return mp_obj_new_int(n_results.uint8);\n", + " } else if(o->data->typecode == NDARRAY_INT8) {\n", + " return mp_obj_new_int(n_results.int8);\n", + " } else if(o->data->typecode == NDARRAY_UINT16) {\n", + " return mp_obj_new_int(n_results.uint16);\n", + " } else if(o->data->typecode == NDARRAY_INT16) {\n", + " return mp_obj_new_int(n_results.int16);\n", + " } else {\n", + " return mp_obj_new_float(n_results.float1);\n", + " }\n", + " } else {\n", + " size_t m = (mp_obj_get_int(axis) == 1) ? 1 : o->m;\n", + " size_t n = (mp_obj_get_int(axis) == 1) ? o->n : 1;\n", + " ndarray_obj_t *out = create_new_ndarray(m, n, o->data->typecode);\n", + " \n", + " if(m == 1) { // sum vertically\n", + " for(size_t i=0; i < n; i++) {\n", + " sum_matrix(o->data->items, i, o->data->len, m, o->data->typecode);\n", + " switch(o->data->typecode) {\n", + " case NDARRAY_UINT8:\n", + " *(uint8_t *)out->data->items[i] = n_results.uint8;\n", + " break;\n", + " case NDARRAY_INT8:\n", + " *(int8_t *)out->data->items[i] = n_results.int8;\n", + " break;\n", + " case NDARRAY_UINT16:\n", + " *(uint16_t *)out->data->items[i] = n_results.uint16;\n", + " break;\n", + " case NDARRAY_INT16:\n", + " *(int16_t *)out->data->items[i] = n_results.int16;\n", + " break;\n", + " case NDARRAY_FLOAT:\n", + " *(float_t *)out->data->items[i] = n_results.float1;\n", + " break;\n", + " }\n", + " }\n", + " } else { // sum horizontally\n", + " for(size_t i=0; i < m; i++) {\n", + " sum_matrix(o->data->items, i*n, o->data->len, n, o->data->typecode);\n", + " switch(o->data->typecode) {\n", + " case NDARRAY_UINT8:\n", + " *(uint8_t *)out->data->items[i] = n_results.uint8;\n", + " break;\n", + " case NDARRAY_INT8:\n", + " *(int8_t *)out->data->items[i] = n_results.int8;\n", + " break;\n", + " case NDARRAY_UINT16:\n", + " *(uint16_t *)out->data->items[i] = n_results.uint16;\n", + " break;\n", + " case NDARRAY_INT16:\n", + " *(int16_t *)out->data->items[i] = n_results.int16;\n", + " break;\n", + " case NDARRAY_FLOAT:\n", + " *(float_t *)out->data->items[i] = n_results.float1;\n", + " break;\n", + " }\n", + " } \n", + " }\n", + " }\n", + " } else {\n", + " mp_raise_TypeError(\"input must be tuple, list, range, or ndarray\");\n", + " }\n", + " return mp_const_none;\n", + "}" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -1104,11 +1479,11 @@ }, { "cell_type": "code", - "execution_count": 195, + "execution_count": 265, "metadata": { "ExecuteTime": { - "end_time": "2019-08-07T18:49:46.336179Z", - "start_time": "2019-08-07T18:49:46.321868Z" + "end_time": "2019-08-08T19:01:02.138430Z", + "start_time": "2019-08-08T19:01:02.129451Z" } }, "outputs": [ @@ -1116,7 +1491,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "written 5923 bytes to ulab.c\n" + "written 6163 bytes to ulab.c\n" ] } ], @@ -1135,7 +1510,9 @@ "#include \"ndarray.h\"\n", "#include \"linalg.h\"\n", "#include \"vectorise.h\"\n", + "#include \"numerical.h\"\n", "\n", + "#define ULAB__VERSION 1.0\n", "\n", "MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);\n", "MP_DEFINE_CONST_FUN_OBJ_2(ndarray_size_obj, ndarray_size);\n", @@ -1143,6 +1520,7 @@ "\n", "MP_DEFINE_CONST_FUN_OBJ_1(linalg_transpose_obj, linalg_transpose);\n", "MP_DEFINE_CONST_FUN_OBJ_2(linalg_reshape_obj, linalg_reshape);\n", + "MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);\n", "\n", "MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos);\n", "MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh);\n", @@ -1168,6 +1546,10 @@ "MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);\n", "MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);\n", "\n", + "MP_DEFINE_CONST_FUN_OBJ_3(numerical_linspace_obj, numerical_linspace);\n", + "MP_DEFINE_CONST_FUN_OBJ_2(numerical_sum_obj, numerical_sum);\n", + "\n", + "\n", "STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {\n", " { MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) },\n", " { MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) },\n", @@ -1189,17 +1571,15 @@ "const mp_obj_type_t ulab_ndarray_type = {\n", " { &mp_type_type },\n", " .name = MP_QSTR_ndarray,\n", - " .print = ulab_ndarray_print,\n", - " .make_new = ulab_ndarray_make_new,\n", - "// .unary_op = ulab_ndarray_unary_op,\n", + " .print = ndarray_print,\n", + " .make_new = ndarray_make_new,\n", + "// .unary_op = ndarray_unary_op,\n", "// .subscr = ndarray_subscr,\n", "// .getiter = ndarray_iterator_new,\n", - "// .binary_op = ulab_ndarray_binary_op,\n", + "// .binary_op = ndarray_binary_op,\n", " .locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,\n", "};\n", "\n", - "MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);\n", - "\n", "STATIC const mp_map_elem_t ulab_globals_table[] = {\n", " { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) },\n", " { MP_OBJ_NEW_QSTR(MP_QSTR_ndarray), (mp_obj_t)&ulab_ndarray_type },\n", @@ -1226,8 +1606,9 @@ " { MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj },\n", " { MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj },\n", " { MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj },\n", - " { MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj }\n", - " // { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&ulab_sum_obj },\n", + " { MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj },\n", + " { MP_OBJ_NEW_QSTR(MP_QSTR_linspace), (mp_obj_t)&numerical_linspace_obj },\n", + " { MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj },\n", "};\n", "\n", "STATIC MP_DEFINE_CONST_DICT (\n", @@ -1253,11 +1634,11 @@ }, { "cell_type": "code", - "execution_count": 166, + "execution_count": 215, "metadata": { "ExecuteTime": { - "end_time": "2019-08-07T17:29:55.173608Z", - "start_time": "2019-08-07T17:29:55.164299Z" + "end_time": "2019-08-08T05:06:05.737230Z", + "start_time": "2019-08-08T05:06:05.729485Z" } }, "outputs": [ @@ -1278,6 +1659,7 @@ "SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c\n", "SRC_USERMOD += $(USERMODULES_DIR)/linalg.c\n", "SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c\n", + "SRC_USERMOD += $(USERMODULES_DIR)/numerical.c\n", "SRC_USERMOD += $(USERMODULES_DIR)/ulab.c\n", "\n", "# We can add our module folder to include paths if needed\n", @@ -1294,11 +1676,11 @@ }, { "cell_type": "code", - "execution_count": 196, + "execution_count": 276, "metadata": { "ExecuteTime": { - "end_time": "2019-08-07T18:50:07.828170Z", - "start_time": "2019-08-07T18:49:50.633892Z" + "end_time": "2019-08-08T19:05:48.682377Z", + "start_time": "2019-08-08T19:05:47.879936Z" }, "scrolled": false }, @@ -1313,167 +1695,83 @@ "GEN build/genhdr/qstr.i.last\n", "GEN build/genhdr/qstr.split\n", "GEN build/genhdr/qstrdefs.collected.h\n", - "QSTR updated\n", - "GEN build/genhdr/qstrdefs.generated.h\n", - "CC ../../py/mpstate.c\n", - "CC ../../py/nlr.c\n", - "CC ../../py/nlrx86.c\n", - "CC ../../py/nlrx64.c\n", - "CC ../../py/nlrthumb.c\n", - "CC ../../py/nlrxtensa.c\n", - "CC ../../py/nlrsetjmp.c\n", - "CC ../../py/malloc.c\n", - "CC ../../py/gc.c\n", - "CC ../../py/pystack.c\n", - "CC ../../py/qstr.c\n", - "CC ../../py/vstr.c\n", - "CC ../../py/mpprint.c\n", - "CC ../../py/reader.c\n", - "CC ../../py/lexer.c\n", - "CC ../../py/parse.c\n", - "CC ../../py/scope.c\n", - "CC ../../py/compile.c\n", - "CC ../../py/emitcommon.c\n", - "CC ../../py/emitbc.c\n", - "CC ../../py/asmbase.c\n", - "CC ../../py/emitnx64.c\n", - "CC ../../py/emitinlinethumb.c\n", - "CC ../../py/emitinlinextensa.c\n", - "CC ../../py/parsenum.c\n", - "CC ../../py/emitglue.c\n", - "CC ../../py/persistentcode.c\n", - "CC ../../py/runtime.c\n", - "CC ../../py/runtime_utils.c\n", - "CC ../../py/scheduler.c\n", - "CC ../../py/nativeglue.c\n", - "CC ../../py/stackctrl.c\n", - "CC ../../py/argcheck.c\n", - "CC ../../py/warning.c\n", - "CC ../../py/map.c\n", - "CC ../../py/obj.c\n", - "CC ../../py/objarray.c\n", - "CC ../../py/objattrtuple.c\n", - "CC ../../py/objbool.c\n", - "CC ../../py/objboundmeth.c\n", - "CC ../../py/objcell.c\n", - "CC ../../py/objclosure.c\n", - "CC ../../py/objcomplex.c\n", - "CC ../../py/objdeque.c\n", - "CC ../../py/objdict.c\n", - "CC ../../py/objenumerate.c\n", - "CC ../../py/objexcept.c\n", - "CC ../../py/objfilter.c\n", - "CC ../../py/objfloat.c\n", - "CC ../../py/objfun.c\n", - "CC ../../py/objgenerator.c\n", - "CC ../../py/objgetitemiter.c\n", - "CC ../../py/objint.c\n", - "CC ../../py/objint_longlong.c\n", - "CC ../../py/objint_mpz.c\n", - "CC ../../py/objlist.c\n", - "CC ../../py/objmap.c\n", + "QSTR not updated\n", "CC ../../py/objmodule.c\n", - "CC ../../py/objobject.c\n", - "CC ../../py/objpolyiter.c\n", - "CC ../../py/objproperty.c\n", - "CC ../../py/objnone.c\n", - "CC ../../py/objnamedtuple.c\n", - "CC ../../py/objrange.c\n", - "CC ../../py/objreversed.c\n", - "CC ../../py/objset.c\n", - "CC ../../py/objsingleton.c\n", - "CC ../../py/objslice.c\n", - "CC ../../py/objstr.c\n", - "CC ../../py/objstrunicode.c\n", - "CC ../../py/objstringio.c\n", - "CC ../../py/objtuple.c\n", - "CC ../../py/objtype.c\n", - "CC ../../py/objzip.c\n", - "CC ../../py/opmethods.c\n", - "CC ../../py/sequence.c\n", - "CC ../../py/stream.c\n", - "CC ../../py/binary.c\n", - "CC ../../py/builtinimport.c\n", - "CC ../../py/builtinevex.c\n", - "CC ../../py/builtinhelp.c\n", - "CC ../../py/modarray.c\n", - "CC ../../py/modbuiltins.c\n", - "CC ../../py/modcollections.c\n", - "CC ../../py/modgc.c\n", - "CC ../../py/modio.c\n", - "CC ../../py/modmath.c\n", - "CC ../../py/modcmath.c\n", - "CC ../../py/modmicropython.c\n", - "CC ../../py/modstruct.c\n", - "CC ../../py/modsys.c\n", - "CC ../../py/moduerrno.c\n", - "CC ../../py/modthread.c\n", - "CC ../../py/vm.c\n", - "CC ../../py/bc.c\n", - "CC ../../py/showbc.c\n", - "CC ../../py/repl.c\n", - "CC ../../py/frozenmod.c\n", - "CC ../../extmod/moductypes.c\n", - "CC ../../extmod/modujson.c\n", - "CC ../../extmod/modure.c\n", - "CC ../../extmod/moduzlib.c\n", - "CC ../../extmod/moduheapq.c\n", - "CC ../../extmod/modutimeq.c\n", - "CC ../../extmod/moduhashlib.c\n", - "CC ../../extmod/moducryptolib.c\n", - "CC ../../extmod/modubinascii.c\n", - "CC ../../extmod/virtpin.c\n", - "CC ../../extmod/machine_mem.c\n", - "CC ../../extmod/machine_pinbase.c\n", - "CC ../../extmod/machine_signal.c\n", - "CC ../../extmod/machine_pulse.c\n", - "CC ../../extmod/machine_i2c.c\n", - "CC ../../extmod/machine_spi.c\n", - "CC ../../extmod/modussl_axtls.c\n", - "CC ../../extmod/modurandom.c\n", - "CC ../../extmod/moduwebsocket.c\n", - "CC ../../extmod/modwebrepl.c\n", - "CC ../../extmod/modframebuf.c\n", - "CC ../../extmod/vfs.c\n", - "CC ../../extmod/vfs_reader.c\n", - "CC ../../extmod/vfs_posix.c\n", - "CC ../../extmod/vfs_posix_file.c\n", - "CC ../../extmod/utime_mphal.c\n", - "CC ../../extmod/uos_dupterm.c\n", - "CC ../../lib/embed/abort_.c\n", - "CC ../../lib/utils/printf.c\n", - "GEN build/frozen.c\n", - "CC build/frozen.c\n", - "GEN build/frozen_mpy.c\n", - "CC build/frozen_mpy.c\n", - "CC main.c\n", - "CC gccollect.c\n", - "CC unix_mphal.c\n", - "CC mpthreadport.c\n", - "CC input.c\n", - "CC file.c\n", - "CC modmachine.c\n", - "CC modos.c\n", - "CC moduos_vfs.c\n", - "CC modtime.c\n", - "CC moduselect.c\n", - "CC alloc.c\n", - "CC coverage.c\n", - "CC ../../../usermod/ulab/ndarray.c\n", - "CC ../../../usermod/ulab/linalg.c\n", - "CC ../../../usermod/ulab/vectorise.c\n", - "CC ../../../usermod/ulab/ulab.c\n", - "CC ../../extmod/modbtree.c\n", - "CC modtermios.c\n", - "CC modusocket.c\n", - "CC modffi.c\n", - "CC ../../lib/mp-readline/readline.c\n", - "CC ../../lib/timeutils/timeutils.c\n", - "LINK micropython\n", - " text\t data\t bss\t dec\t hex\tfilename\n", - " 2085\t 6862\t 0\t 8947\t 22f3\tbuild/build/frozen_mpy.o\n", - " 2\t 0\t 0\t 2\t 2\tbuild/build/frozen.o\n", - " 447069\t 56400\t 2104\t 505573\t 7b6e5\tmicropython\n" + "CC ../../../usermod/ulab/numerical.c\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:\u001b[m\u001b[K In function ‘\u001b[01m\u001b[Knumerical_sum\u001b[m\u001b[K’:\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:106:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(uint8_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.uint8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:106:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:106:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kuint8_t *)out->data->items[i] = n_results.uint8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:109:56:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(int8_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.int8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:109:56:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:109:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kint8_t *)out->data->items[i] = n_results.int8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:112:58:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(uint16_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.uint16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:112:58:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:112:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kuint16_t *)out->data->items[i] = n_results.uint16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:115:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(int16_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.int16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:115:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:115:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kint16_t *)out->data->items[i] = n_results.int16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:118:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(float_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.float1;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:118:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:118:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kfloat_t *)out->data->items[i] = n_results.float1;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:127:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(uint8_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.uint8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:127:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:127:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kuint8_t *)out->data->items[i] = n_results.uint8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:130:56:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(int8_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.int8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:130:56:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:130:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kint8_t *)out->data->items[i] = n_results.int8;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:133:58:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(uint16_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.uint16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:133:58:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:133:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kuint16_t *)out->data->items[i] = n_results.uint16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:136:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(int16_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.int16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:136:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:136:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kint16_t *)out->data->items[i] = n_results.int16;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:139:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kpointer of type ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ used in arithmetic [\u001b[01;31m\u001b[K-Werror=pointer-arith\u001b[m\u001b[K]\n", + " *(float_t *)out->data->items\u001b[01;31m\u001b[K[\u001b[m\u001b[Ki] = n_results.float1;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:139:57:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kdereferencing ‘\u001b[01m\u001b[Kvoid *\u001b[m\u001b[K’ pointer [\u001b[01;31m\u001b[K-Werror\u001b[m\u001b[K]\n", + "\u001b[01m\u001b[K../../../usermod/ulab/numerical.c:139:30:\u001b[m\u001b[K \u001b[01;31m\u001b[Kerror: \u001b[m\u001b[Kinvalid use of void expression\n", + " *\u001b[01;31m\u001b[K(\u001b[m\u001b[Kfloat_t *)out->data->items[i] = n_results.float1;\n", + " \u001b[01;31m\u001b[K^\u001b[m\u001b[K\n", + "cc1: all warnings being treated as errors\n", + "../../py/mkrules.mk:47: recipe for target 'build/ulab/numerical.o' failed\n", + "make: *** [build/ulab/numerical.o] Error 1\n" ] } ], diff --git a/ulab/micropython.mk b/ulab/micropython.mk index d9bb9c9..9d9b35a 100644 --- a/ulab/micropython.mk +++ b/ulab/micropython.mk @@ -5,6 +5,7 @@ USERMODULES_DIR := $(USERMOD_DIR) SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c SRC_USERMOD += $(USERMODULES_DIR)/linalg.c SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c +SRC_USERMOD += $(USERMODULES_DIR)/numerical.c SRC_USERMOD += $(USERMODULES_DIR)/ulab.c # We can add our module folder to include paths if needed diff --git a/ulab/ndarray.c b/ulab/ndarray.c index f32047a..34f8a8d 100644 --- a/ulab/ndarray.c +++ b/ulab/ndarray.c @@ -61,7 +61,7 @@ void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data, size_t n0, mp_print_str(print, "]"); } -void ulab_ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { +void ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) { (void)kind; ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); mp_print_str(print, "ndarray("); @@ -104,7 +104,7 @@ ndarray_obj_t *create_new_ndarray(size_t m, size_t n, uint8_t typecode) { return ndarray; } -mp_obj_t ulab_ndarray_copy(mp_obj_t self_in) { +mp_obj_t ndarray_copy(mp_obj_t self_in) { // returns a verbatim (shape and typecode) copy of self_in ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); ndarray_obj_t *out = create_new_ndarray(self->m, self->n, self->data->typecode); @@ -113,7 +113,7 @@ mp_obj_t ulab_ndarray_copy(mp_obj_t self_in) { return MP_OBJ_FROM_PTR(out); } -mp_obj_t ulab_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, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 3, true); size_t len1, len2=0, i=0; diff --git a/ulab/ndarray.h b/ulab/ndarray.h index be8a282..60848b9 100644 --- a/ulab/ndarray.h +++ b/ulab/ndarray.h @@ -47,11 +47,11 @@ typedef struct _ndarray_obj_t { */ void ndarray_print_row(const mp_print_t *, mp_obj_array_t *, size_t , size_t ); -void ulab_ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t ); +void ndarray_print(const mp_print_t *, mp_obj_t , mp_print_kind_t ); void 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 ulab_ndarray_copy(mp_obj_t ); -mp_obj_t ulab_ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const 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_shape(mp_obj_t ); mp_obj_t ndarray_size(mp_obj_t , mp_obj_t ); diff --git a/ulab/numerical.c b/ulab/numerical.c new file mode 100644 index 0000000..55658e0 --- /dev/null +++ b/ulab/numerical.c @@ -0,0 +1,149 @@ +/* + * 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 +#include "py/runtime.h" +#include "numerical.h" + +typedef struct { + uint8_t uint8; + int8_t int8; + uint16_t uint16; + int16_t int16; + float float1, float2; // we need two floats, so that the standard deviation can be calculated +} numerical_results; + +numerical_results n_results; + +mp_obj_t numerical_linspace(mp_obj_t _start, mp_obj_t _stop, mp_obj_t _len) { + // TODO: accept keyword argument endpoint=True + mp_int_t len = mp_obj_get_int_truncated(_len); + if(len < 2) { + mp_raise_ValueError("number of points must be at least 2"); + } + mp_float_t value, step; + value = mp_obj_get_float(_start); + step = (mp_obj_get_float(_stop)-value)/(len-1); + ndarray_obj_t *nd_array = create_new_ndarray(1, len, NDARRAY_FLOAT); + for(size_t i=0; i < len; i++, value += step) { + mp_binary_set_val_array('f', nd_array->data->items, i, mp_obj_new_float(value)); + } + return MP_OBJ_FROM_PTR(nd_array); +} +void clear_results(void) { + n_results.uint8 = 0; + n_results.int8 = 0; + n_results.uint16 = 0; + n_results.int16 = 0; + n_results.float1 = n_results.float2 = 0.0; +} + +void sum_matrix(void *data, size_t start, size_t stop, size_t stride, unsigned char type) { + clear_results(); + for(size_t i=start; i < stop; i+= stride) { + switch(type) { + case NDARRAY_UINT8: + n_results.uint8 += ((uint8_t *)data)[i]; + break; + case NDARRAY_INT8: + n_results.int8 += ((int8_t *)data)[i]; + break; + case NDARRAY_UINT16: + n_results.uint16 += ((uint16_t *)data)[i]; + break; + case NDARRAY_INT16: + n_results.int16 += ((int16_t *)data)[i]; + break; + case NDARRAY_FLOAT: + n_results.float1 += ((float *)data)[i]; + } + } +} + +mp_obj_t numerical_sum(mp_obj_t o_in, mp_obj_t axis) { + // TODO: deal with keyword argument + if(MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(o_in, &mp_type_list) || + MP_OBJ_IS_TYPE(o_in, &mp_type_range)) { + mp_float_t _sum = 0.0; + mp_obj_iter_buf_t iter_buf; + mp_obj_t item, iterable = mp_getiter(o_in, &iter_buf); + while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) { + _sum += mp_obj_get_float(item); + } + return mp_obj_new_float(_sum); + } else if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) { + ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in); + if((o->m == 1) || (o->n == 1)) { + sum_matrix(o->data->items, 1, o->data->len, 1, o->data->typecode); + if(o->data->typecode == NDARRAY_UINT8) { + return mp_obj_new_int(n_results.uint8); + } else if(o->data->typecode == NDARRAY_INT8) { + return mp_obj_new_int(n_results.int8); + } else if(o->data->typecode == NDARRAY_UINT16) { + return mp_obj_new_int(n_results.uint16); + } else if(o->data->typecode == NDARRAY_INT16) { + return mp_obj_new_int(n_results.int16); + } else { + return mp_obj_new_float(n_results.float1); + } + } else { + size_t m = (mp_obj_get_int(axis) == 1) ? 1 : o->m; + size_t n = (mp_obj_get_int(axis) == 1) ? o->n : 1; + ndarray_obj_t *out = create_new_ndarray(m, n, o->data->typecode); + + if(m == 1) { // sum vertically + for(size_t i=0; i < n; i++) { + sum_matrix(o->data->items, i, o->data->len, m, o->data->typecode); + switch(o->data->typecode) { + case NDARRAY_UINT8: + *(uint8_t *)out->data->items[i] = n_results.uint8; + break; + case NDARRAY_INT8: + *(int8_t *)out->data->items[i] = n_results.int8; + break; + case NDARRAY_UINT16: + *(uint16_t *)out->data->items[i] = n_results.uint16; + break; + case NDARRAY_INT16: + *(int16_t *)out->data->items[i] = n_results.int16; + break; + case NDARRAY_FLOAT: + *(float_t *)out->data->items[i] = n_results.float1; + break; + } + } + } else { // sum horizontally + for(size_t i=0; i < m; i++) { + sum_matrix(o->data->items, i*n, o->data->len, n, o->data->typecode); + switch(o->data->typecode) { + case NDARRAY_UINT8: + *(uint8_t *)out->data->items[i] = n_results.uint8; + break; + case NDARRAY_INT8: + *(int8_t *)out->data->items[i] = n_results.int8; + break; + case NDARRAY_UINT16: + *(uint16_t *)out->data->items[i] = n_results.uint16; + break; + case NDARRAY_INT16: + *(int16_t *)out->data->items[i] = n_results.int16; + break; + case NDARRAY_FLOAT: + *(float_t *)out->data->items[i] = n_results.float1; + break; + } + } + } + } + } else { + mp_raise_TypeError("input must be tuple, list, range, or ndarray"); + } + return mp_const_none; +} diff --git a/ulab/numerical.h b/ulab/numerical.h new file mode 100644 index 0000000..96489ef --- /dev/null +++ b/ulab/numerical.h @@ -0,0 +1,19 @@ +/* + * This file is part of the micropython-ulab project, + * + * https://github.com/v923z/micropython-ulab + * + * The MIT License (MIT) + * + * Copyright (c) 2019 Zoltán Vörös +*/ + +#ifndef _NUMERICAL_ +#define _NUMERICAL_ + +#include "ndarray.h" + +mp_obj_t numerical_linspace(mp_obj_t , mp_obj_t , mp_obj_t ); +mp_obj_t numerical_sum(mp_obj_t , mp_obj_t ); + +#endif diff --git a/ulab/ulab.c b/ulab/ulab.c index 5432d31..352d5bd 100644 --- a/ulab/ulab.c +++ b/ulab/ulab.c @@ -20,7 +20,9 @@ #include "ndarray.h" #include "linalg.h" #include "vectorise.h" +#include "numerical.h" +#define ULAB__VERSION 1.0 MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape); MP_DEFINE_CONST_FUN_OBJ_2(ndarray_size_obj, ndarray_size); @@ -28,6 +30,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(ndarray_rawsize_obj, ndarray_rawsize); 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_1(linalg_inv_obj, linalg_inv); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acos_obj, vectorise_acos); MP_DEFINE_CONST_FUN_OBJ_1(vectorise_acosh_obj, vectorise_acosh); @@ -53,6 +56,10 @@ 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); +MP_DEFINE_CONST_FUN_OBJ_3(numerical_linspace_obj, numerical_linspace); +MP_DEFINE_CONST_FUN_OBJ_2(numerical_sum_obj, numerical_sum); + + 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_size), MP_ROM_PTR(&ndarray_size_obj) }, @@ -74,17 +81,15 @@ STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_t const mp_obj_type_t ulab_ndarray_type = { { &mp_type_type }, .name = MP_QSTR_ndarray, - .print = ulab_ndarray_print, - .make_new = ulab_ndarray_make_new, -// .unary_op = ulab_ndarray_unary_op, + .print = ndarray_print, + .make_new = ndarray_make_new, +// .unary_op = ndarray_unary_op, // .subscr = ndarray_subscr, // .getiter = ndarray_iterator_new, -// .binary_op = ulab_ndarray_binary_op, +// .binary_op = ndarray_binary_op, .locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict, }; -MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv); - STATIC const mp_map_elem_t ulab_globals_table[] = { { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) }, { MP_OBJ_NEW_QSTR(MP_QSTR_ndarray), (mp_obj_t)&ulab_ndarray_type }, @@ -111,8 +116,9 @@ STATIC const mp_map_elem_t ulab_globals_table[] = { { 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_sum), (mp_obj_t)&ulab_sum_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 }, }; STATIC MP_DEFINE_CONST_DICT (