removed old stuff from ulab.ipynb
This commit is contained in:
parent
3ed5e1a651
commit
f11ec26b93
1 changed files with 0 additions and 832 deletions
832
docs/ulab.ipynb
832
docs/ulab.ipynb
|
|
@ -2502,838 +2502,6 @@
|
|||
"print(a)\n",
|
||||
"print(a.shape())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Containers\n",
|
||||
"\n",
|
||||
"The basic container, `ndarray` is built on top of the micropython array object, and is declared as\n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"typedef struct _ndarray_obj_t {\n",
|
||||
"\tmp_obj_base_t base;\n",
|
||||
"\tsize_t m, n;\n",
|
||||
"\tmp_obj_array_t *data;\n",
|
||||
"\tsize_t bytes;\n",
|
||||
"} ndarray_obj_t;\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In turn, the declaration of `mp_obj_array_t` can be found in `objarray.h`, and reads as \n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"typedef struct _mp_obj_array_t {\n",
|
||||
" mp_obj_base_t base;\n",
|
||||
" size_t typecode : 8;\n",
|
||||
" size_t free : (8 * sizeof(size_t) - 8);\n",
|
||||
" size_t len; // in elements\n",
|
||||
" void *items;\n",
|
||||
"} mp_obj_array_t;\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In order to economise on space and gain on speed while performing computations on data, values in `ndarray` are stored in binary format in `*items`, and not in standard micropython objects. The interpretation of these binary objects is determined by the `typecode`, while the \"layout\" of the data is given by the `m`, and `n` `size_t` members. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Initialising containers\n",
|
||||
"\n",
|
||||
"An `ndarray` can be initialised by passing an iterable (linear arrays), or an iterable of iterables (matrices) into the constructor\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"\n",
|
||||
"from ulab import ndarray\n",
|
||||
"\n",
|
||||
"a = ndarray([1, 2, 3, 4])\n",
|
||||
"a = ndarray([[1, 2, 3, 4], [2, 3, 4, 5]])\n",
|
||||
"a = ndarray([range(10), range(10)])\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In addition, the constructor can take a keyword argument, `dtype`, that will force type conversion."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Standard operations\n",
|
||||
"\n",
|
||||
"## mathematical functions\n",
|
||||
"\n",
|
||||
"The usual mathematical functions of micropython can be called with either a micropython object, or with ndarrays."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Special methods\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"`ndarray` objects support a number of special methods. In particular, if they are of the same shape, two `ndarray`s can be summed, multiplied, divided, subtracted, and raised to a power. These operations work also, if the second operand is an micropython variable. As an example, \n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"from ulab import ndarray\n",
|
||||
"\n",
|
||||
"a = 10\n",
|
||||
"b = ndarray([[1, 2, 3], [11, 12, 13]])\n",
|
||||
"\n",
|
||||
"c = b + b\n",
|
||||
"d = b + a\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"In addition, bitwise operations work on the underlying byte array (i.e., the `typecode` is not taken into account, the bytearrays are simply `or`ed, `and`ed, etc. If the length of the second operand smaller than that of the first operand, then "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Old stuff"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"#include <math.h>\n",
|
||||
"#include <stdio.h>\n",
|
||||
"#include <stdlib.h>\n",
|
||||
"#include <string.h>\n",
|
||||
"#include \"py/runtime.h\"\n",
|
||||
"#include \"py/binary.h\"\n",
|
||||
"#include \"py/obj.h\"\n",
|
||||
"#include \"py/objarray.h\"\n",
|
||||
"\n",
|
||||
"#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }\n",
|
||||
"#define PRINT_MAX\t10\n",
|
||||
"#define epsilon\t\t1e-6\n",
|
||||
"\n",
|
||||
"#if 0\n",
|
||||
"STATIC mp_obj_array_t *array_new(char typecode, size_t n) {\n",
|
||||
" int typecode_size = mp_binary_get_size('@', typecode, NULL);\n",
|
||||
" mp_obj_array_t *o = m_new_obj(mp_obj_array_t);\n",
|
||||
" // this step could probably be skipped: we are never going to store a bytearray per se\n",
|
||||
" #if MICROPY_PY_BUILTINS_BYTEARRAY && MICROPY_PY_ARRAY\n",
|
||||
" o->base.type = (typecode == BYTEARRAY_TYPECODE) ? &mp_type_bytearray : &mp_type_array;\n",
|
||||
" #elif MICROPY_PY_BUILTINS_BYTEARRAY\n",
|
||||
" o->base.type = &mp_type_bytearray;\n",
|
||||
" #else\n",
|
||||
" o->base.type = &mp_type_array;\n",
|
||||
" #endif\n",
|
||||
" o->typecode = typecode;\n",
|
||||
" o->free = 0;\n",
|
||||
" o->len = n;\n",
|
||||
" o->items = m_new(byte, typecode_size * o->len);\n",
|
||||
" return o;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"enum NDARRAY_TYPE {\n",
|
||||
"\tNDARRAY_UINT8 = 'b',\n",
|
||||
"\tNDARRAY_INT8 = 'B',\n",
|
||||
"\tNDARRAY_UINT16 = 'i', \n",
|
||||
"\tNDARRAY_INT16 = 'I',\n",
|
||||
"\tNDARRAY_FLOAT = 'f'\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"// I think, we could work with a different construct (see below)\n",
|
||||
"// Basically, we do not use any of the array utilities...\n",
|
||||
"typedef struct _ndarray_obj_t {\n",
|
||||
"\tmp_obj_base_t base;\n",
|
||||
"\tsize_t m, n;\n",
|
||||
"\tmp_obj_array_t *data;\n",
|
||||
"\tsize_t bytes;\n",
|
||||
"} ndarray_obj_t;\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"typedef struct _ndarray_obj_t {\n",
|
||||
"\tmp_obj_base_t base;\n",
|
||||
"\tuint8_t typecode;\n",
|
||||
"\tvoid *data;\n",
|
||||
"\tsize_t m, n, len, bytes;\n",
|
||||
"} ndarray_obj_t;\n",
|
||||
"*/\n",
|
||||
"\n",
|
||||
"STATIC void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data, size_t n0, size_t n) {\n",
|
||||
"\tmp_print_str(print, \"[\");\n",
|
||||
"\tsize_t i;\n",
|
||||
"\tif(n < PRINT_MAX) { // if the array is short, print everything\n",
|
||||
"\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);\n",
|
||||
"\t\tfor(i=1; i<n; i++) {\n",
|
||||
"\t\t\tmp_print_str(print, \", \");\n",
|
||||
"\t\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);\n",
|
||||
"\t\t}\n",
|
||||
"\t} else {\n",
|
||||
"\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);\n",
|
||||
"\t\tfor(i=1; i<3; i++) {\n",
|
||||
"\t\t\tmp_print_str(print, \", \");\n",
|
||||
"\t\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);\n",
|
||||
"\t\t}\n",
|
||||
"\t\tmp_printf(print, \", ..., \");\n",
|
||||
"\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+n-3), PRINT_REPR);\n",
|
||||
"\t\tfor(size_t i=1; i<3; i++) {\n",
|
||||
"\t\t\tmp_print_str(print, \", \");\n",
|
||||
"\t\t\tmp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+n-3+i), PRINT_REPR);\n",
|
||||
"\t\t}\t\t\n",
|
||||
"\t}\n",
|
||||
"\tmp_print_str(print, \"]\");\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC void ulab_ndarray_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {\n",
|
||||
"\t(void)kind;\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tmp_print_str(print, \"ndarray(\");\t\n",
|
||||
"\tif((self->m == 1) || (self->n == 1)) {\n",
|
||||
"\t\tndarray_print_row(print, self->data, 0, self->data->len);\n",
|
||||
"\t} else {\n",
|
||||
"\t\t// TODO: add vertical ellipses for the case, when self->m > PRINT_MAX\n",
|
||||
"\t\tmp_print_str(print, \"[\");\n",
|
||||
"\t\tndarray_print_row(print, self->data, 0, self->n);\n",
|
||||
"\t\tfor(size_t i=1; i < self->m; i++) {\n",
|
||||
"\t\t\tmp_print_str(print, \",\\n\\t \");\n",
|
||||
"\t\t\tndarray_print_row(print, self->data, i*self->n, self->n);\n",
|
||||
"\t\t}\n",
|
||||
"\t\tmp_print_str(print, \"]\");\n",
|
||||
"\t}\n",
|
||||
"\t// TODO: print typecode\n",
|
||||
"\tmp_print_str(print, \")\\n\");\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"const mp_obj_type_t ulab_ndarray_type;\n",
|
||||
"\n",
|
||||
"STATIC void assign_elements(mp_obj_array_t *data, mp_obj_t iterable, uint8_t bytecode, size_t *idx) {\n",
|
||||
"\t// assigns a single row in the matrix\n",
|
||||
"\tmp_obj_t item;\n",
|
||||
"\twhile ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n",
|
||||
"\t\tmp_binary_set_val_array(bytecode, data->items, (*idx)++, item);\n",
|
||||
"\t}\t\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC ndarray_obj_t *create_new_ndarray(size_t m, size_t n, uint8_t typecode) {\n",
|
||||
"\t// Creates the base ndarray with shape (m, n), and initialises the values to straight 0s\n",
|
||||
"\tndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t);\n",
|
||||
"\tndarray->base.type = &ulab_ndarray_type;\n",
|
||||
"\tndarray->m = m;\n",
|
||||
"\tndarray->n = n;\n",
|
||||
"\tmp_obj_array_t *data = array_new(typecode, m*n);\n",
|
||||
"\tndarray->bytes = m * n * mp_binary_get_size('@', typecode, NULL);\n",
|
||||
"\t// this should set all elements to 0, irrespective of the of the typecode (all bits are zero)\n",
|
||||
"\t// we could, perhaps, leave this step out, and initialise the array, only, when needed\n",
|
||||
"\tmemset(data->items, 0, ndarray->bytes); \n",
|
||||
"\tndarray->data = data;\n",
|
||||
"\treturn ndarray;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_copy(mp_obj_t self_in) {\n",
|
||||
"\t// returns a verbatim (shape and typecode) copy of self_in\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tndarray_obj_t *out = create_new_ndarray(self->m, self->n, self->data->typecode);\n",
|
||||
"\tint typecode_size = mp_binary_get_size('@', self->data->typecode, NULL);\n",
|
||||
"\tmemcpy(out->data->items, self->data->items, self->data->len*typecode_size);\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(out);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC 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",
|
||||
"\tmp_arg_check_num(n_args, n_kw, 1, 3, true);\n",
|
||||
"\t\n",
|
||||
"\tsize_t len1, len2=0, i=0;\n",
|
||||
"\tmp_obj_t len_in = mp_obj_len_maybe(args[0]);\n",
|
||||
" if (len_in == MP_OBJ_NULL) {\n",
|
||||
"\t\tmp_raise_ValueError(\"first argument must be an iterable\");\n",
|
||||
" } else {\n",
|
||||
" len1 = MP_OBJ_SMALL_INT_VALUE(len_in);\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
"\t// We have to figure out, whether the first element of the iterable is an iterable\n",
|
||||
"\t// Perhaps, there is a more elegant way of handling this\n",
|
||||
"\tmp_obj_iter_buf_t iter_buf1;\n",
|
||||
"\tmp_obj_t item1, iterable1 = mp_getiter(args[0], &iter_buf1);\n",
|
||||
"\twhile ((item1 = mp_iternext(iterable1)) != MP_OBJ_STOP_ITERATION) {\n",
|
||||
"\t\tlen_in = mp_obj_len_maybe(item1);\n",
|
||||
"\t\tif(len_in != MP_OBJ_NULL) { // indeed, this seems to be an iterable\n",
|
||||
"\t\t\t// Next, we have to check, whether all elements in the outer loop have the same length\n",
|
||||
"\t\t\tif(i > 0) {\n",
|
||||
"\t\t\t\tif(len2 != MP_OBJ_SMALL_INT_VALUE(len_in)) {\n",
|
||||
"\t\t\t\t\tmp_raise_ValueError(\"iterables are not of the same length\");\n",
|
||||
"\t\t\t\t}\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t\tlen2 = MP_OBJ_SMALL_INT_VALUE(len_in);\n",
|
||||
"\t\t\ti++;\n",
|
||||
"\t\t}\n",
|
||||
"\t}\n",
|
||||
"\t// By this time, it should be established, what the shape is, so we can now create the array\n",
|
||||
"\t// set the typecode to float, if the format specifier is missing\n",
|
||||
"\t// TODO: this would probably be more elegant with keyword arguments... \n",
|
||||
"\tuint8_t typecode;\n",
|
||||
"\tif(n_args == 1) {\n",
|
||||
"\t\ttypecode = NDARRAY_FLOAT;\n",
|
||||
"\t} else {\n",
|
||||
"\t\ttypecode = (uint8_t)mp_obj_get_int(args[1]);\n",
|
||||
"\t}\n",
|
||||
"\tndarray_obj_t *self = create_new_ndarray(len1, (len2 == 0) ? 1 : len2, typecode);\n",
|
||||
"\titerable1 = mp_getiter(args[0], &iter_buf1);\n",
|
||||
"\ti = 0;\n",
|
||||
"\tif(len2 == 0) { // the first argument is a single iterable\n",
|
||||
"\t\tassign_elements(self->data, iterable1, typecode, &i);\n",
|
||||
"\t} else {\n",
|
||||
"\t\tmp_obj_iter_buf_t iter_buf2;\n",
|
||||
"\t\tmp_obj_t iterable2; \n",
|
||||
"\n",
|
||||
"\t\twhile ((item1 = mp_iternext(iterable1)) != MP_OBJ_STOP_ITERATION) {\n",
|
||||
"\t\t\titerable2 = mp_getiter(item1, &iter_buf2);\n",
|
||||
"\t\t\tassign_elements(self->data, iterable2, typecode, &i);\n",
|
||||
"\t\t}\n",
|
||||
"\t}\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(self);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_transpose(mp_obj_t self_in) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\t// the size of a single item in the array\n",
|
||||
"\tuint8_t _sizeof = mp_binary_get_size('@', self->data->typecode, NULL);\n",
|
||||
"\t\n",
|
||||
"\t// NOTE: In principle, we could simply specify the stride direction, and then we wouldn't \n",
|
||||
"\t// even have to shuffle the elements. The downside of that approach is that we would have \n",
|
||||
"\t// to implement two versions of the matrix multiplication and inversion functions\n",
|
||||
"\t\n",
|
||||
"\t// NOTE: \n",
|
||||
"\t// if the matrices are square, we can simply swap items, but \n",
|
||||
"\t// generic matrices can't be transposed in place, so we have to \n",
|
||||
"\t// declare a temporary variable\n",
|
||||
"\t\n",
|
||||
"\t// NOTE: \n",
|
||||
"\t// In the old matrix, the coordinate (m, n) is m*self->n + n\n",
|
||||
"\t// We have to assign this to the coordinate (n, m) in the new \n",
|
||||
"\t// matrix, i.e., to n*self->m + m\n",
|
||||
"\t\n",
|
||||
"\t// one-dimensional arrays can be transposed by simply swapping the dimensions\n",
|
||||
"\tif((self->m != 1) && (self->n != 1)) {\n",
|
||||
"\t\tuint8_t *c = (uint8_t *)self->data->items;\n",
|
||||
"\t\t// self->bytes is the size of the bytearray, irrespective of the typecode\n",
|
||||
"\t\tuint8_t *tmp = (uint8_t *)malloc(self->bytes);\n",
|
||||
"\t\tfor(size_t m=0; m < self->m; m++) {\n",
|
||||
"\t\t\tfor(size_t n=0; n < self->n; n++) {\n",
|
||||
"\t\t\t\tmemcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof);\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t}\n",
|
||||
"\t\tmemcpy(self->data->items, tmp, self->bytes);\n",
|
||||
"\t\tfree(tmp);\n",
|
||||
"\t} \n",
|
||||
"\tSWAP(size_t, self->m, self->n);\n",
|
||||
"\treturn mp_const_none;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_1(ulab_ndarray_transpose_obj, ulab_ndarray_transpose);\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_shape(mp_obj_t self_in) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tmp_obj_t tuple[2] = {\n",
|
||||
"\t\tmp_obj_new_int(self->m),\n",
|
||||
"\t\tmp_obj_new_int(self->n)\n",
|
||||
"\t};\n",
|
||||
"\treturn mp_obj_new_tuple(2, tuple);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_1(ulab_ndarray_shape_obj, ulab_ndarray_shape);\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_size(mp_obj_t self_in, mp_obj_t axis) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tuint8_t ax = mp_obj_get_int(axis);\n",
|
||||
"\tif(ax == 0) {\n",
|
||||
"\t\treturn mp_obj_new_int(self->data->len);\n",
|
||||
"\t} else if(ax == 1) {\n",
|
||||
"\t\treturn mp_obj_new_int(self->m);\t\t\n",
|
||||
"\t} else if(ax == 2) {\n",
|
||||
"\t\treturn mp_obj_new_int(self->n);\n",
|
||||
"\t} else {\n",
|
||||
"\t\treturn mp_const_none;\n",
|
||||
"\t}\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_2(ulab_ndarray_size_obj, ulab_ndarray_size);\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_rawsize(mp_obj_t self_in) {\n",
|
||||
"\t// returns a 5-tuple with the \n",
|
||||
"\t// \n",
|
||||
"\t// 1. number of rows\n",
|
||||
"\t// 2. number of columns\n",
|
||||
"\t// 3. length of the storage (should be equal to the product of 1. and 2.)\n",
|
||||
"\t// 4. length of the data storage in bytes\n",
|
||||
"\t// 5. datum size in bytes\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tmp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));\n",
|
||||
"\ttuple->items[0] = MP_OBJ_NEW_SMALL_INT(self->m);\n",
|
||||
"\ttuple->items[1] = MP_OBJ_NEW_SMALL_INT(self->n);\n",
|
||||
"\ttuple->items[2] = MP_OBJ_NEW_SMALL_INT(self->bytes);\n",
|
||||
"\ttuple->items[3] = MP_OBJ_NEW_SMALL_INT(self->data->len);\n",
|
||||
"\ttuple->items[4] = MP_OBJ_NEW_SMALL_INT(mp_binary_get_size('@', self->data->typecode, NULL));\n",
|
||||
"\treturn tuple;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_1(ulab_ndarray_rawsize_obj, ulab_ndarray_rawsize);\n",
|
||||
"\n",
|
||||
"ndarray_obj_t *invert_matrix(mp_obj_array_t *data, size_t N) {\n",
|
||||
"\t// After inversion the matrix is most certainly a float\n",
|
||||
"\tndarray_obj_t *tmp = create_new_ndarray(N, N, NDARRAY_FLOAT);\n",
|
||||
"\t// initially, this is the unit matrix: this is what will be returned a\n",
|
||||
"\t// after all the transformations\n",
|
||||
"\tndarray_obj_t *unitm = create_new_ndarray(N, N, NDARRAY_FLOAT);\n",
|
||||
"\t\n",
|
||||
"\tfloat *c = (float *)tmp->data->items;\n",
|
||||
"\tfloat *unit = (float *)unitm->data->items;\n",
|
||||
"\tmp_obj_t elem;\n",
|
||||
"\tfloat elemf;\n",
|
||||
"\tfor(size_t m=0; m < N; m++) { // rows first\n",
|
||||
"\t\tfor(size_t n=0; n < N; n++) { // columns next\n",
|
||||
"\t\t\telem = mp_binary_get_val_array(data->typecode, data->items, m*N+n);\n",
|
||||
"\t\t\telemf = (float)mp_obj_get_float(elem);\n",
|
||||
"\t\t\tmemcpy(&c[m*N+n], &elemf, sizeof(float));\n",
|
||||
"\t\t}\n",
|
||||
"\t\t// initialise the unit matrix\n",
|
||||
"\t\telemf = 1.0;\n",
|
||||
"\t\tmemcpy(&unit[m*(N+1)], &elemf, sizeof(float));\n",
|
||||
"\t}\n",
|
||||
"\tfor(size_t m=0; m < N; m++){\n",
|
||||
"\t\t// this could be faster with ((c < epsilon) && (c > -epsilon))\n",
|
||||
"\t\tif(abs(c[m*(N+1)]) < epsilon) {\n",
|
||||
"\t\t\t// TODO: check what kind of exception numpy raises\n",
|
||||
"\t\t\tmp_raise_ValueError(\"input matrix is singular\");\n",
|
||||
"\t\t}\n",
|
||||
"\t\tfor(size_t n=0; n < N; n++){\n",
|
||||
"\t\t\tif(m != n){\n",
|
||||
"\t\t\t\telemf = c[N*n+m] / c[m*(N+1)];\n",
|
||||
"\t\t\t\tfor(size_t k=0; k < N; k++){\n",
|
||||
"\t\t\t\t\tc[N*n+k] -= elemf * c[N*m+k];\n",
|
||||
"\t\t\t\t\tunit[N*n+k] -= elemf * unit[N*m+k];\t\t\t\t\t\n",
|
||||
"\t\t\t\t}\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t}\n",
|
||||
"\t}\n",
|
||||
" for(size_t m=0; m < N; m++){ \n",
|
||||
" elemf = c[m*(N+1)];\n",
|
||||
" for(size_t n=0; n < N; n++){\n",
|
||||
" c[N*m+n] /= elemf;\n",
|
||||
" unit[N*m+n] /= elemf;\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"\treturn unitm;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_inv(mp_obj_t o_in) {\n",
|
||||
"\tndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);\n",
|
||||
"\tif(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {\n",
|
||||
"\t\tmp_raise_TypeError(\"only ndarray objects can be inverted\");\n",
|
||||
"\t}\n",
|
||||
"\tif(o->m != o->n) {\n",
|
||||
"\t\tmp_raise_ValueError(\"only square matrices can be inverted\");\n",
|
||||
"\t}\n",
|
||||
"\tndarray_obj_t *inverted = invert_matrix(o->data, o->m);\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(inverted);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_1(ulab_ndarray_inv_obj, ulab_ndarray_inv);\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_reshape(mp_obj_t self_in, mp_obj_t shape) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tif(!MP_OBJ_IS_TYPE(shape, &mp_type_tuple) || (MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(shape)) != 2)) {\n",
|
||||
"\t\tmp_raise_ValueError(\"shape must be a 2-tuple\");\n",
|
||||
"\t}\n",
|
||||
"\t\n",
|
||||
"\tmp_obj_iter_buf_t iter_buf;\n",
|
||||
"\tmp_obj_t item, iterable = mp_getiter(shape, &iter_buf);\n",
|
||||
"\tuint16_t m, n;\n",
|
||||
"\titem = mp_iternext(iterable);\n",
|
||||
"\tm = mp_obj_get_int(item);\n",
|
||||
"\titem = mp_iternext(iterable);\n",
|
||||
"\tn = mp_obj_get_int(item);\n",
|
||||
"\tif(m*n != self->m*self->n) {\n",
|
||||
"\t\t// TODO: the proper error message would be \"cannot reshape array of size %d into shape (%d, %d)\"\n",
|
||||
"\t\tmp_raise_ValueError(\"cannot reshape array\");\n",
|
||||
"\t}\n",
|
||||
"\tself->m = m;\n",
|
||||
"\tself->n = n;\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(self);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_2(ulab_ndarray_reshape_obj, ulab_ndarray_reshape);\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_dot(mp_obj_t self_in, mp_obj_t other_in) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\t// TODO: check for type of other_in\n",
|
||||
"\tndarray_obj_t *other = MP_OBJ_TO_PTR(other_in);\n",
|
||||
"\t// both inputs are vectors\n",
|
||||
"\tif(((self->m == 1) || (self->n == 1)) && ((other->m == 1) || (other->n == 1))) {\n",
|
||||
"\t\tif(self->_size != other->_size) {\n",
|
||||
"\t\t\tmp_raise_ValueError(\"inputs must be of same length\");\n",
|
||||
"\t\t} else {\n",
|
||||
"\t\t\t// what should happen with overflow?\n",
|
||||
"\t\t\treturn mp_const_none;\n",
|
||||
"\t\t}\n",
|
||||
"\t}\n",
|
||||
"\treturn mp_const_true;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_2(ulab_ndarray_dot_obj, ulab_ndarray_dot);\n",
|
||||
"*/\n",
|
||||
"\n",
|
||||
"// Copied the range object from objrange.c The problem is that objrange.c \n",
|
||||
"// can't be included directly (there is no header file)\n",
|
||||
"typedef struct _mp_obj_range_t {\n",
|
||||
" mp_obj_base_t base;\n",
|
||||
" // TODO make these values generic objects or something\n",
|
||||
" mp_int_t start;\n",
|
||||
" mp_int_t stop;\n",
|
||||
" mp_int_t step;\n",
|
||||
"} mp_obj_range_t;\n",
|
||||
"\n",
|
||||
"// getter method till I figure out how to implement slicing\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_get(mp_obj_t self_in, mp_obj_t rangem_in, mp_obj_t rangen_in) {\n",
|
||||
"\t// the positional arguments beyond self_in should be range objects, or integers\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tuint8_t *data = (uint8_t *)self->data->items;\n",
|
||||
"\t\n",
|
||||
"\t// This is not quite safe: here we should use MP_OBJ_IS_TYPE(rangem_in, &mp_type_int), \n",
|
||||
"\t// but for some mysterious reason that simply doesn't work\n",
|
||||
"\tif(!MP_OBJ_IS_TYPE(rangem_in, &mp_type_range)) {\n",
|
||||
"\t\tsize_t m = mp_obj_get_int(rangem_in);\n",
|
||||
"\t\tif((m < 0) || (m >= self->m)) {\n",
|
||||
"\t\t\tmp_raise_ValueError(\"indices are out of range\");\t\t\n",
|
||||
"\t\t}\n",
|
||||
"\t\tif(!MP_OBJ_IS_TYPE(rangen_in, &mp_type_range)) { // return a singe value\n",
|
||||
"\t\t\t// Note that this case can actually be gotten from a[m][n], too\n",
|
||||
"\t\t\tsize_t n = mp_obj_get_int(rangen_in);\n",
|
||||
"\t\t\tif((n < 0) || (n >= self->n)) {\n",
|
||||
"\t\t\t\tmp_raise_ValueError(\"indices are out of range\");\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t\tmp_obj_t value = mp_binary_get_val_array(self->data->typecode, self->data->items, m*self->n+n);\n",
|
||||
"\t\t\treturn MP_OBJ_FROM_PTR(value);\n",
|
||||
"\t\t\t\n",
|
||||
"\t\t} else { // At least the second argument is a range object\n",
|
||||
"\t\t\t// TODO: get length of range\n",
|
||||
"\t\t\t// Unfortunately, range_len in objrange.c is static, so we have to re-implement the function here\n",
|
||||
"\t\t\tmp_obj_range_t *rangen = MP_OBJ_TO_PTR(rangen_in);\n",
|
||||
"\t\t\tif((rangen->start < 0) || (rangen->start > self->n) || (rangen->stop < 0) || (rangen->stop > self->n)) {\n",
|
||||
"\t\t\t\tmp_raise_ValueError(\"indices are out of range\");\t\t\t\t\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t\tmp_int_t idx = rangen->start;\n",
|
||||
"\t\t\tmp_int_t len_n = (rangen->stop - rangen->start) / abs(rangen->step);\n",
|
||||
"\t\t\tndarray_obj_t *array = create_new_ndarray(1, len_n, self->data->typecode);\n",
|
||||
"\t\t\tuint8_t *c = (uint8_t *)array->data->items;\n",
|
||||
"\t\t\tint _sizeof = mp_binary_get_size('@', self->data->typecode, NULL);\n",
|
||||
"\t\t\tsize_t pos, i=0;\n",
|
||||
"\t\t\twhile(i < len_n) {\n",
|
||||
"\t\t\t\tpos = _sizeof*(m*self->n + idx);\n",
|
||||
"\t\t\t\tmemcpy(&c[i*_sizeof], &data[pos], _sizeof);\n",
|
||||
"\t\t\t\tidx += rangen->step;\n",
|
||||
"\t\t\t\ti++;\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t\treturn MP_OBJ_FROM_PTR(array);\n",
|
||||
"\t\t}\n",
|
||||
"\t\t// TODO: now do the same for m, and then for (m, n)\n",
|
||||
"\t}\n",
|
||||
"\tndarray_obj_t *array = create_new_ndarray(self->m, self->n, self->data->typecode);\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(array);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"MP_DEFINE_CONST_FUN_OBJ_3(ulab_ndarray_get_obj, ulab_ndarray_get);\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"// setter method till I figure out how to implement slicing\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_set(const mp_obj_t self_in, const mp_obj_t *args) {\n",
|
||||
"\t// the positional arguments beyond self_in should be range objects, or integers\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tndarray_obj_t *array = create_new_ndarray(self->m, self->n, self->data->typecode);\n",
|
||||
"\treturn MP_OBJ_FROM_PTR(array);\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC MP_DEFINE_CONST_FUN_OBJ_3(ulab_ndarray_set_obj, ulab_ndarray_set);\n",
|
||||
"*/\n",
|
||||
"\n",
|
||||
"STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ulab_ndarray_transpose_obj) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ulab_ndarray_shape_obj) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ulab_ndarray_size_obj) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_rawsize), MP_ROM_PTR(&ulab_ndarray_rawsize_obj) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ulab_ndarray_reshape_obj) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_get), MP_ROM_PTR(&ulab_ndarray_get_obj) },\t\n",
|
||||
"//\t{ MP_ROM_QSTR(MP_QSTR_dot), MP_ROM_PTR(&ulab_ndarray_dot_obj) },\n",
|
||||
"\t// class constants\n",
|
||||
" { MP_ROM_QSTR(MP_QSTR_uint8), MP_ROM_INT(NDARRAY_UINT8) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_int8), MP_ROM_INT(NDARRAY_INT8) },\n",
|
||||
" { MP_ROM_QSTR(MP_QSTR_uint16), MP_ROM_INT(NDARRAY_UINT16) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_int16), MP_ROM_INT(NDARRAY_INT16) },\n",
|
||||
"\t{ MP_ROM_QSTR(MP_QSTR_float), MP_ROM_INT(NDARRAY_FLOAT) },\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"mp_obj_t ulab_ndarray_binary_op_helper(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n",
|
||||
"\t// TODO: support scalar operations\n",
|
||||
"\tif (MP_OBJ_IS_TYPE(rhs, &mp_type_int) || MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {\n",
|
||||
"\t\treturn MP_OBJ_NULL; // op not supported\n",
|
||||
"\t} else if(MP_OBJ_IS_TYPE(rhs, &ulab_ndarray_type)) {\n",
|
||||
"\t\t// At this point, the operands should have the same shape\n",
|
||||
"\t\tndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs);\n",
|
||||
"\t\tndarray_obj_t *or = MP_OBJ_TO_PTR(rhs);\n",
|
||||
"\t\tndarray_obj_t *array;\n",
|
||||
"\t\tif((ol->m != or->m) || (ol->n != or->n)) {\n",
|
||||
"\t\t\tmp_raise_ValueError(\"operands could not be broadcast together\");\n",
|
||||
"\t\t}\n",
|
||||
"\t\t// do not convert types, if they are identical\n",
|
||||
"\t\t// do not convert either, if the left hand side is a float\n",
|
||||
"\t\tif((ol->data->typecode == or->data->typecode) || ol->data->typecode == NDARRAY_FLOAT) {\n",
|
||||
"\t\t\tarray = ulab_ndarray_copy(ol);\t\t\n",
|
||||
"\t\t} else {\n",
|
||||
"\t\t\t// the types are not equal, we have to do some conversion here\n",
|
||||
"\t\t\tif(or->data->typecode == NDARRAY_FLOAT) {\n",
|
||||
"\t\t\t\tarray = ulab_ndarray_copy(ol);\n",
|
||||
"\t\t\t} else if((ol->data->typecode == NDARRAY_INT16) || (or->data->typecode == NDARRAY_INT16)) {\n",
|
||||
"\t\t\t\tarray = create_new_ndarray(ol->m, ol->n, NDARRAY_INT16);\n",
|
||||
"\t\t\t} else if((ol->data->typecode == NDARRAY_UINT16) || (or->data->typecode == NDARRAY_UINT16)) {\n",
|
||||
"\t\t\t\tarray = create_new_ndarray(ol->m, ol->n, NDARRAY_INT16);\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t}\n",
|
||||
"\t\tswitch(op) {\n",
|
||||
"\t\t\tcase MP_BINARY_OP_ADD:\n",
|
||||
"//\t\t\t\tfor(size_t i=0; i < ol->data->len; i++) {\n",
|
||||
"\t\t\t\t\t\n",
|
||||
"\t\t\t\t//}\n",
|
||||
"\t\t\t\treturn MP_OBJ_FROM_PTR(array);\t\n",
|
||||
"\t\t\t\tbreak;\n",
|
||||
"\t\t\tdefault:\n",
|
||||
"\t\t\t\tbreak;\n",
|
||||
"\t\t}\n",
|
||||
"\n",
|
||||
"\t}\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {\n",
|
||||
" ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs);\n",
|
||||
"\tndarray_obj_t *or = MP_OBJ_TO_PTR(rhs);\n",
|
||||
"\n",
|
||||
"\tndarray_obj_t *array = ulab_ndarray_copy(ol); \n",
|
||||
"\tswitch (op) {\n",
|
||||
"\t\tcase MP_BINARY_OP_EQUAL:\n",
|
||||
"\t\t\tif(!MP_OBJ_IS_TYPE(rhs, &ulab_ndarray_type)) {\n",
|
||||
"\t\t\t\treturn mp_const_false;\n",
|
||||
"\t\t\t} else {\n",
|
||||
"\t\t\t\t// Two arrays are equal, if their shape, typecode, and elements are equal\n",
|
||||
"\t\t\t\tif((ol->m != or->m) || (ol->n != or->n) || (ol->data->typecode != or->data->typecode)) {\n",
|
||||
"\t\t\t\t\treturn mp_const_false;\n",
|
||||
"\t\t\t\t} else {\n",
|
||||
"\t\t\t\t\tsize_t i = ol->bytes;\n",
|
||||
"\t\t\t\t\tuint8_t *l = (uint8_t *)ol->data->items;\n",
|
||||
"\t\t\t\t\tuint8_t *r = (uint8_t *)or->data->items;\t\t\t\t\t\n",
|
||||
"\t\t\t\t\twhile(i) { // At this point, we can simply compare the bytes, the types is irrelevant\n",
|
||||
"\t\t\t\t\t\tif(*l++ != *r++) {\n",
|
||||
"\t\t\t\t\t\t\treturn mp_const_false;\n",
|
||||
"\t\t\t\t\t\t}\n",
|
||||
"\t\t\t\t\t\ti--;\n",
|
||||
"\t\t\t\t\t}\n",
|
||||
"\t\t\t\t\treturn mp_const_true;\n",
|
||||
"\t\t\t\t}\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t\tbreak;\n",
|
||||
"\t\tcase MP_BINARY_OP_ADD:\n",
|
||||
"\t\tcase MP_BINARY_OP_MULTIPLY: \n",
|
||||
"\t\t\treturn MP_OBJ_FROM_PTR(array);\t\n",
|
||||
"\t\t\tbreak;\n",
|
||||
"\t\t\t\n",
|
||||
"\t\tdefault:\n",
|
||||
" return MP_OBJ_NULL; // op not supported\n",
|
||||
"\t}\n",
|
||||
"}\n",
|
||||
"*/\n",
|
||||
"\n",
|
||||
"/*\n",
|
||||
"STATIC mp_obj_t ndarray_iterator_new(mp_obj_t array_in, mp_obj_iter_buf_t *iter_buf) {\n",
|
||||
" assert(sizeof(mp_obj_array_t) <= sizeof(mp_obj_iter_buf_t));\n",
|
||||
" ndarray_obj_t *array = MP_OBJ_TO_PTR(array_in);\n",
|
||||
" mp_obj_array_it_t *o = (mp_obj_array_it_t*)iter_buf;\n",
|
||||
" o->base.type = &array_it_type;\n",
|
||||
" o->array = array->data;\n",
|
||||
" o->offset = 0;\n",
|
||||
" o->cur = 0;\n",
|
||||
" return MP_OBJ_FROM_PTR(o);\n",
|
||||
"}\n",
|
||||
"*/\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ndarray_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) {\n",
|
||||
" if (value == MP_OBJ_NULL) {\n",
|
||||
" return MP_OBJ_NULL;\n",
|
||||
" } \n",
|
||||
" ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\tif(MP_OBJ_IS_TYPE(index_in, &mp_type_tuple)) {\n",
|
||||
"\t\tprintf(\"tuple!!!\");\n",
|
||||
"\t}\n",
|
||||
"\tif (MP_OBJ_IS_TYPE(index_in, &mp_type_slice)) {\n",
|
||||
"\t\tprintf(\"slice: \");\n",
|
||||
"\t\tmp_bound_slice_t slice;\n",
|
||||
"\t\tif (!mp_seq_get_fast_slice_indexes(self->data->len, index_in, &slice)) {\n",
|
||||
"\t\t\tmp_raise_NotImplementedError(\"only slices with step=1 (aka None) are supported\");\n",
|
||||
"\t\t}\n",
|
||||
"\t\tndarray_obj_t *array = ulab_ndarray_copy(self_in);\n",
|
||||
"\t\tprintf(\"%lu, %lu, %ld\\n\", slice.start, slice.stop, slice.step);\n",
|
||||
"\t\treturn MP_OBJ_FROM_PTR(array);\n",
|
||||
"\t} else {\n",
|
||||
"\t\t// Now that we know that we haven't a slice, let's attempt to extract the index\n",
|
||||
"\t\tsize_t idx = mp_get_index(self->base.type, (self->m == 1) ? self->n : self->m, index_in, false);\n",
|
||||
"\t\t\n",
|
||||
"\t\t// TODO: treat the setter here\n",
|
||||
"//\t\tmp_obj_list_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
"\t\t//self->items[i] = value;\n",
|
||||
"\n",
|
||||
"\t\tif(self->m > 1) {\n",
|
||||
"\t\t\tndarray_obj_t *row = create_new_ndarray(1, self->n, self->data->typecode);\n",
|
||||
"\t\t\trow->bytes = self->n * mp_binary_get_size('@', self->data->typecode, NULL);\n",
|
||||
"\t\t\tuint8_t *c = (uint8_t *)self->data->items;\n",
|
||||
"\t\t\tmemcpy(row->data->items, &c[idx*self->n], row->bytes);\n",
|
||||
"\t\t\treturn MP_OBJ_FROM_PTR(row);\n",
|
||||
"\t\t} \n",
|
||||
"\t}\n",
|
||||
"\treturn mp_const_none;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {\n",
|
||||
"\tndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);\n",
|
||||
" switch (op) {\n",
|
||||
" case MP_UNARY_OP_BOOL: return mp_obj_new_bool(self->data->len != 0);\n",
|
||||
" case MP_UNARY_OP_LEN: return MP_OBJ_NEW_SMALL_INT(self->data->len);\n",
|
||||
" default: return MP_OBJ_NULL; // op not supported\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"const mp_obj_type_t ulab_ndarray_type = {\n",
|
||||
"\t{ &mp_type_type },\n",
|
||||
"\t.name = MP_QSTR_ndarray,\n",
|
||||
"\t.print = ulab_ndarray_print,\n",
|
||||
"\t.make_new = ulab_ndarray_make_new,\n",
|
||||
"\t.unary_op = ulab_ndarray_unary_op,\n",
|
||||
"\t.subscr = ndarray_subscr,\n",
|
||||
"//\t.getiter = ndarray_iterator_new,\n",
|
||||
"//\t.binary_op = ulab_ndarray_binary_op,\n",
|
||||
"\t.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t kw_test(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n",
|
||||
" static const mp_arg_t allowed_args[] = {\n",
|
||||
"\t\t{ MP_QSTR_input, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} }, \n",
|
||||
" { MP_QSTR_base, MP_ARG_INT, {.u_int = 12} },\n",
|
||||
" { MP_QSTR_mode, MP_ARG_INT, {.u_int = 555} },\n",
|
||||
" { MP_QSTR_addr, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 33} },\n",
|
||||
" { MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 33} }, \n",
|
||||
" };\n",
|
||||
"\n",
|
||||
" // parse args\n",
|
||||
" mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n",
|
||||
" mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n",
|
||||
" if(MP_OBJ_IS_TYPE(args[0].u_rom_obj, &mp_type_tuple)) {\n",
|
||||
"\t\tprintf(\"tuple!!!\");\n",
|
||||
"\t}\n",
|
||||
" printf(\"base: %lu\\n\\r\", args[1].u_int);\n",
|
||||
" printf(\"mode: %lu\\n\\r\", args[2].u_int);\n",
|
||||
" printf(\"address: %lu\\n\\r\", args[3].u_int); \n",
|
||||
" printf(\"dtypes: %lu\\n\\r\", args[4].u_int);\n",
|
||||
" return mp_const_none;\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC MP_DEFINE_CONST_FUN_OBJ_KW(kw_test_obj, 1, kw_test);\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"STATIC mp_obj_t ulab_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {\n",
|
||||
" static const mp_arg_t allowed_args[] = {\n",
|
||||
" { MP_QSTR_array, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&mp_const_none_obj)} },\n",
|
||||
" { MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },\n",
|
||||
" };\n",
|
||||
" mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];\n",
|
||||
" mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);\n",
|
||||
"\tmp_obj_t *array = MP_OBJ_TO_PTR(args[0].u_obj);\n",
|
||||
" if(MP_OBJ_IS_TYPE(array, &mp_type_NoneType)) {\n",
|
||||
"\t\tmp_raise_ValueError(\"missing first argument\");\n",
|
||||
"\t}\n",
|
||||
" // TODO: it would be great, if we could pass a range as the first argument\n",
|
||||
"\tif(MP_OBJ_IS_TYPE(array, &mp_type_tuple) || MP_OBJ_IS_TYPE(array, &mp_type_list)) {\n",
|
||||
"\t\tmp_float_t _sum = 0.0;\n",
|
||||
"\t\tmp_obj_iter_buf_t iter_buf;\n",
|
||||
"\t\tmp_obj_t item, iterable = mp_getiter(array, &iter_buf);\n",
|
||||
"\t\twhile ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {\n",
|
||||
"\t\t\t_sum += mp_obj_get_float(item);\n",
|
||||
"\t\t}\n",
|
||||
"\t\treturn mp_obj_new_float(_sum);\t\t\n",
|
||||
"\t} else if(MP_OBJ_IS_TYPE(array, &ulab_ndarray_type)) {\n",
|
||||
"\t\tndarray_obj_t *array_in = MP_OBJ_TO_PTR(array);\n",
|
||||
"\t\tsize_t m, n;\n",
|
||||
"\t\tif(args[1].u_int == 0) {\n",
|
||||
"\t\t\tm = 1;\n",
|
||||
"\t\t\tn = array_in->n;\n",
|
||||
"\t\t} else if(args[1].u_int == 1) {\n",
|
||||
"\t\t\tm = array_in->m;\n",
|
||||
"\t\t\tn = 1;\n",
|
||||
"\t\t} else {\n",
|
||||
"\t\t\tmp_raise_ValueError(\"axis must be 0, or 1\");\n",
|
||||
"\t\t}\n",
|
||||
"\t\tndarray_obj_t *array_out = create_new_ndarray(m, n, NDARRAY_FLOAT);\n",
|
||||
"\t\tfloat *c = (float *)array_out->data->items;\n",
|
||||
"\t\tmp_obj_t elem;\n",
|
||||
"\t\t// I believe, these loops could be combined\n",
|
||||
"\t\tif(m == 1) {\n",
|
||||
"\t\t\t// contract along the first axis\n",
|
||||
"\t\t\tfor(size_t i=0; i < array_in->n; i++) {\n",
|
||||
"\t\t\t\tfor(size_t j=0; j < array_in->m; j++) {\n",
|
||||
"\t\t\t\t\telem = mp_binary_get_val_array(array_in->data->typecode, array_in->data->items, j*array_in->n+i);\n",
|
||||
"\t\t\t\t\tc[i] += (float)mp_obj_get_float(elem);\n",
|
||||
"\t\t\t\t}\n",
|
||||
"\t\t\t}\n",
|
||||
"\t\t} else if(n == 1) {\n",
|
||||
"\t\t\t// contract along the second axis\n",
|
||||
"\t\t\tfor(size_t i=0; i < array_in->m; i++) {\n",
|
||||
"\t\t\t\tfor(size_t j=0; j < array_in->n; j++) {\n",
|
||||
"\t\t\t\t\telem = mp_binary_get_val_array(array_in->data->typecode, array_in->data->items, i*array_in->n+j);\n",
|
||||
"\t\t\t\t\tc[i] += (float)mp_obj_get_float(elem);\n",
|
||||
"\t\t\t\t}\n",
|
||||
"\t\t\t}\t\t\t\n",
|
||||
"\t\t}\n",
|
||||
"\t\treturn MP_OBJ_FROM_PTR(array_out);\n",
|
||||
"\t}\n",
|
||||
"\tmp_raise_TypeError(\"wrong input type\");\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"STATIC MP_DEFINE_CONST_FUN_OBJ_KW(ulab_sum_obj, 1, ulab_sum);\n",
|
||||
"\n",
|
||||
"STATIC const mp_map_elem_t ulab_globals_table[] = {\n",
|
||||
"\t{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) },\n",
|
||||
"\t{ MP_OBJ_NEW_QSTR(MP_QSTR_kw_test), (mp_obj_t)&kw_test_obj },\t\n",
|
||||
"\t{ MP_OBJ_NEW_QSTR(MP_QSTR_ndarray), (mp_obj_t)&ulab_ndarray_type },\t\n",
|
||||
"\t{ MP_OBJ_NEW_QSTR(MP_QSTR_inv), (mp_obj_t)&ulab_ndarray_inv_obj },\n",
|
||||
"\t{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&ulab_sum_obj },\t\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"STATIC MP_DEFINE_CONST_DICT (\n",
|
||||
"\tmp_module_ulab_globals,\n",
|
||||
"\tulab_globals_table\n",
|
||||
");\n",
|
||||
"\n",
|
||||
"const mp_obj_module_t ulab_user_cmodule = {\n",
|
||||
"\t.base = { &mp_type_module },\n",
|
||||
"\t.globals = (mp_obj_dict_t*)&mp_module_ulab_globals,\n",
|
||||
"};\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED);\n",
|
||||
"#endif\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
|
|
|||
Loading…
Reference in a new issue