Merge branch 'master' into byteswap
This commit is contained in:
commit
efcfeff790
22 changed files with 584 additions and 511 deletions
33
README.md
33
README.md
|
|
@ -6,6 +6,16 @@ dimensions, and is fast. The library is a software-only standard `micropython` u
|
|||
i.e., it has no hardware dependencies, and can be compiled for any platform.
|
||||
The `float` implementation of `micropython` (`float`, or `double`) is automatically detected.
|
||||
|
||||
1. [Supported functions](#supported-functions)
|
||||
1. [ndarray](#ndarray)
|
||||
1. [Usage](#usage)
|
||||
1. [Customising the firmware](#customising-the-firmware)
|
||||
1. [Finding help](#finding-help)
|
||||
1. [Benchmarks](#benchmarks)
|
||||
1. [Firmware](#firmware)
|
||||
1. [Issues, contributing, and testing](#issues-contributing-and-testing)
|
||||
1. [Testing](#testing)
|
||||
|
||||
# Supported functions
|
||||
|
||||
|
||||
|
|
@ -21,7 +31,7 @@ iterables via the `array` constructor, or by means of the `arange`, `concatenate
|
|||
`shape`, `size`, `strides`, `tobytes`, and `transpose`.
|
||||
|
||||
|
||||
## Customising the firmware
|
||||
# Customising the firmware
|
||||
|
||||
In addition to the `ndarray` operators and methods, `ulab` defines a great number of functions that can
|
||||
take `ndarray`s or `micropython` iterables as their arguments. Most of the functions have been ported from
|
||||
|
|
@ -37,7 +47,7 @@ of the user manual.
|
|||
It is also possible to extend the library with arbitrary user-defined functions operating on numerical arrays, and add them to the namespace, as explaind in the [programming manual](https://micropython-ulab.readthedocs.io/en/latest/ulab-programming.html).
|
||||
|
||||
|
||||
## Usage
|
||||
# Usage
|
||||
|
||||
`ulab` sports a `numpy/scipy`-compatible interface, which makes porting of `CPython` code straightforward. The following
|
||||
snippet should run equally well in `micropython`, or on a PC.
|
||||
|
|
@ -224,3 +234,22 @@ If it compiles without error, you can plug in your ESP32 via USB and then flash
|
|||
```bash
|
||||
make erase && make deploy
|
||||
```
|
||||
|
||||
# Issues, contributing, and testing
|
||||
|
||||
If you find a problem with the code, please, raise an [issue](https://github.com/v923z/micropython-ulab/issues)! An issue should address a single problem, and should contain a minimal code snippet that demonstrates the difference from the expected behaviour. Reducing a problem to the bare minimum significantly increases the chances of a quick fix.
|
||||
|
||||
Feature requests (porting a particular function from `numpy` or `scipy`) should also be posted at [ulab issue](https://github.com/v923z/micropython-ulab/issues).
|
||||
|
||||
Contributions of any kind are always welcome. If you feel like adding to the code, you can simply issue a pull request. If you do so, please, try to adhere to `micropython`'s [coding conventions](https://github.com/micropython/micropython/blob/master/CODECONVENTIONS.md#c-code-conventions).
|
||||
|
||||
However, you can also contribute to the documentation (preferably via the [jupyter notebooks](https://github.com/v923z/micropython-ulab/tree/master/docs), or improve the [tests](https://github.com/v923z/micropython-ulab/tree/master/tests).
|
||||
|
||||
## Testing
|
||||
|
||||
If you decide to lend a hand with testing, here are the steps:
|
||||
|
||||
1. Write a test script that checks a particular function, or a set of related functions!
|
||||
1. Drop this script in one of the folders in [ulab tests](https://github.com/v923z/micropython-ulab/tree/master/tests)!
|
||||
1. Run the [./build.sh](https://github.com/v923z/micropython-ulab/blob/master/build.sh) script in the root directory of `ulab`! This will clone the latest `micropython`, compile the firmware for `unix`, execute all scripts in the `ulab/tests`, and compare the results to those in the expected results files, which are also in `ulab/tests`, and have an extension `.exp`. In case you have a new snippet, i.e., you have no expected results file, or if the results differ from those in the expected file, a new expected file will be generated in the root directory. You should inspect the contents of this file, and if they are satisfactory, then the file can be moved to the `ulab/tests` folder, alongside your snippet.
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ SRC_USERMOD += $(USERMODULES_DIR)/numpy/linalg/linalg_tools.c
|
|||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/numerical/numerical.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/poly/poly.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/stats/stats.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/transform/transform.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/vector/vector.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/user/user.c
|
||||
|
||||
|
|
|
|||
|
|
@ -28,21 +28,6 @@
|
|||
//| """Linear algebra functions"""
|
||||
//|
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
static ndarray_obj_t *linalg_object_is_square(mp_obj_t obj) {
|
||||
// Returns an ndarray, if the object is a square ndarray,
|
||||
// raises the appropriate exception otherwise
|
||||
if(!MP_OBJ_IS_TYPE(obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("size is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(obj);
|
||||
if((ndarray->shape[ULAB_MAX_DIMS - 1] != ndarray->shape[ULAB_MAX_DIMS - 2]) || (ndarray->ndim != 2)) {
|
||||
mp_raise_ValueError(translate("input must be square matrix"));
|
||||
}
|
||||
return ndarray;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
//| def cholesky(A: ulab.array) -> ulab.array:
|
||||
//| """
|
||||
|
|
@ -55,7 +40,7 @@ static ndarray_obj_t *linalg_object_is_square(mp_obj_t obj) {
|
|||
//|
|
||||
|
||||
static mp_obj_t linalg_cholesky(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = linalg_object_is_square(oin);
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
ndarray_obj_t *L = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, ndarray->shape[ULAB_MAX_DIMS - 1], ndarray->shape[ULAB_MAX_DIMS - 1]), NDARRAY_FLOAT);
|
||||
mp_float_t *Larray = (mp_float_t *)L->array;
|
||||
|
||||
|
|
@ -121,7 +106,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky);
|
|||
//|
|
||||
|
||||
static mp_obj_t linalg_det(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = linalg_object_is_square(oin);
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
size_t N = ndarray->shape[ULAB_MAX_DIMS - 1];
|
||||
mp_float_t *tmp = m_new(mp_float_t, N * N);
|
||||
|
|
@ -182,70 +167,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
|
|||
|
||||
#endif
|
||||
|
||||
//| def dot(m1: ulab.array, m2: ulab.array) -> Union[ulab.array, float]:
|
||||
//| """
|
||||
//| :param ~ulab.array m1: a matrix, or a vector
|
||||
//| :param ~ulab.array m2: a matrix, or a vector
|
||||
//|
|
||||
//| Computes the product of two matrices, or two vectors. In the letter case, the inner product is returned."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
||||
// TODO: should the results be upcast?
|
||||
// This implements 2D operations only!
|
||||
if(!MP_OBJ_IS_TYPE(_m1, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(_m2, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("arguments must be ndarrays"));
|
||||
}
|
||||
ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1);
|
||||
ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if ((m1->ndim == 1) && (m2->ndim == 1)) {
|
||||
#endif
|
||||
// 2 vectors
|
||||
if (m1->len != m2->len) {
|
||||
mp_raise_ValueError(translate("vectors must have same lengths"));
|
||||
}
|
||||
mp_float_t dot = 0.0;
|
||||
uint8_t *array1 = (uint8_t *)m1->array;
|
||||
uint8_t *array2 = (uint8_t *)m2->array;
|
||||
for (size_t i=0; i < m1->len; i++) {
|
||||
dot += ndarray_get_float_value(array1, m1->dtype)*ndarray_get_float_value(array2, m2->dtype);
|
||||
array1 += m1->strides[ULAB_MAX_DIMS - 1];
|
||||
array2 += m2->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
return mp_obj_new_float(dot);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
} else {
|
||||
// 2 matrices
|
||||
if(m1->shape[ULAB_MAX_DIMS - 1] != m2->shape[ULAB_MAX_DIMS - 2]) {
|
||||
mp_raise_ValueError(translate("matrix dimensions do not match"));
|
||||
}
|
||||
size_t *shape = ndarray_shape_vector(0, 0, m1->shape[ULAB_MAX_DIMS - 2], m2->shape[ULAB_MAX_DIMS - 1]);
|
||||
ndarray_obj_t *out = ndarray_new_dense_ndarray(2, shape, NDARRAY_FLOAT);
|
||||
mp_float_t *outdata = (mp_float_t *)out->array;
|
||||
for(size_t i=0; i < m1->shape[ULAB_MAX_DIMS - 2]; i++) { // rows of m1
|
||||
for(size_t j=0; j < m2->shape[ULAB_MAX_DIMS - 1]; j++) { // columns of m2
|
||||
mp_float_t sum = 0.0, v1, v2;
|
||||
for(size_t k=0; k < m2->shape[ULAB_MAX_DIMS - 2]; k++) {
|
||||
// (i, k) * (k, j)
|
||||
size_t pos1 = i*m1->shape[ULAB_MAX_DIMS - 1]+k;
|
||||
size_t pos2 = k*m2->shape[ULAB_MAX_DIMS - 1]+j;
|
||||
v1 = ndarray_get_float_index(m1->array, m1->dtype, pos1);
|
||||
v2 = ndarray_get_float_index(m2->array, m2->dtype, pos2);
|
||||
sum += v1 * v2;
|
||||
}
|
||||
*outdata++ = sum;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(out);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
//| def eig(m: ulab.array) -> Tuple[ulab.array, ulab.array]:
|
||||
//| """
|
||||
|
|
@ -257,7 +178,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
|
|||
//|
|
||||
|
||||
static mp_obj_t linalg_eig(mp_obj_t oin) {
|
||||
ndarray_obj_t *in = linalg_object_is_square(oin);
|
||||
ndarray_obj_t *in = tools_object_is_square(oin);
|
||||
uint8_t *iarray = (uint8_t *)in->array;
|
||||
size_t S = in->shape[ULAB_MAX_DIMS - 1];
|
||||
mp_float_t *array = m_new(mp_float_t, S*S);
|
||||
|
|
@ -318,7 +239,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
|||
//| ...
|
||||
//|
|
||||
static mp_obj_t linalg_inv(mp_obj_t o_in) {
|
||||
ndarray_obj_t *ndarray = linalg_object_is_square(o_in);
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(o_in);
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
size_t N = ndarray->shape[ULAB_MAX_DIMS - 1];
|
||||
ndarray_obj_t *inverted = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, N, N), NDARRAY_FLOAT);
|
||||
|
|
@ -442,55 +363,21 @@ static mp_obj_t linalg_norm(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_norm_obj, 1, linalg_norm);
|
||||
// MP_DEFINE_CONST_FUN_OBJ_1(linalg_norm_obj, linalg_norm);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_LINALG_HAS_TRACE
|
||||
|
||||
//| def trace(m: ulab.array) -> float:
|
||||
//| """
|
||||
//| :param m: a square matrix
|
||||
//|
|
||||
//| Compute the trace of the matrix, the sum of its diagonal elements."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t linalg_trace(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = linalg_object_is_square(oin);
|
||||
mp_float_t trace = 0.0;
|
||||
for(size_t i=0; i < ndarray->shape[ULAB_MAX_DIMS - 1]; i++) {
|
||||
int32_t pos = i * (ndarray->strides[ULAB_MAX_DIMS - 1] + ndarray->strides[ULAB_MAX_DIMS - 2]);
|
||||
trace += ndarray_get_float_index(ndarray->array, ndarray->dtype, pos/ndarray->itemsize);
|
||||
}
|
||||
if(ndarray->dtype == NDARRAY_FLOAT) {
|
||||
return mp_obj_new_float(trace);
|
||||
}
|
||||
return mp_obj_new_int_from_float(trace);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(linalg_trace_obj, linalg_trace);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) },
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_LINALG_HAS_CHOLESKY
|
||||
{ MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_DET
|
||||
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_EIG
|
||||
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_INV
|
||||
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_TRACE
|
||||
{ MP_ROM_QSTR(MP_QSTR_trace), (mp_obj_t)&linalg_trace_obj },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_DOT
|
||||
{ MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
|
||||
#if ULAB_LINALG_HAS_CHOLESKY
|
||||
{ MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_DET
|
||||
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_EIG
|
||||
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_INV
|
||||
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_NORM
|
||||
{ MP_ROM_QSTR(MP_QSTR_norm), (mp_obj_t)&linalg_norm_obj },
|
||||
|
|
|
|||
|
|
@ -22,7 +22,5 @@ MP_DECLARE_CONST_FUN_OBJ_1(linalg_cholesky_obj);
|
|||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_eig_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_inv_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_trace_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(linalg_dot_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_norm_obj);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@
|
|||
#include "filter/filter.h"
|
||||
#include "linalg/linalg.h"
|
||||
#include "numerical/numerical.h"
|
||||
#include "stats/stats.h"
|
||||
#include "transform/transform.h"
|
||||
#include "poly/poly.h"
|
||||
#include "vector/vector.h"
|
||||
|
||||
|
|
@ -168,6 +170,12 @@ static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
|
|||
#if ULAB_NUMPY_HAS_DIFF
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DOT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dot), (mp_obj_t)&transform_dot_obj },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TRACE
|
||||
{ MP_ROM_QSTR(MP_QSTR_trace), (mp_obj_t)&stats_trace_obj },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_FLIP
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj },
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,3 +22,31 @@
|
|||
#include "../../ulab.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "stats.h"
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_NUMPY_HAS_TRACE
|
||||
|
||||
//| def trace(m: ulab.array) -> float:
|
||||
//| """
|
||||
//| :param m: a square matrix
|
||||
//|
|
||||
//| Compute the trace of the matrix, the sum of its diagonal elements."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t stats_trace(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
mp_float_t trace = 0.0;
|
||||
for(size_t i=0; i < ndarray->shape[ULAB_MAX_DIMS - 1]; i++) {
|
||||
int32_t pos = i * (ndarray->strides[ULAB_MAX_DIMS - 1] + ndarray->strides[ULAB_MAX_DIMS - 2]);
|
||||
trace += ndarray_get_float_index(ndarray->array, ndarray->dtype, pos/ndarray->itemsize);
|
||||
}
|
||||
if(ndarray->dtype == NDARRAY_FLOAT) {
|
||||
return mp_obj_new_float(trace);
|
||||
}
|
||||
return mp_obj_new_int_from_float(trace);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(stats_trace_obj, stats_trace);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -15,4 +15,6 @@
|
|||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(stats_trace_obj);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
88
code/numpy/transform/transform.c
Normal file
88
code/numpy/transform/transform.c
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Zoltán Vörös
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "transform.h"
|
||||
|
||||
|
||||
#if ULAB_NUMPY_HAS_DOT
|
||||
//| def dot(m1: ulab.array, m2: ulab.array) -> Union[ulab.array, float]:
|
||||
//| """
|
||||
//| :param ~ulab.array m1: a matrix, or a vector
|
||||
//| :param ~ulab.array m2: a matrix, or a vector
|
||||
//|
|
||||
//| Computes the product of two matrices, or two vectors. In the letter case, the inner product is returned."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
||||
// TODO: should the results be upcast?
|
||||
// This implements 2D operations only!
|
||||
if(!MP_OBJ_IS_TYPE(_m1, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(_m2, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("arguments must be ndarrays"));
|
||||
}
|
||||
ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1);
|
||||
ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if ((m1->ndim == 1) && (m2->ndim == 1)) {
|
||||
#endif
|
||||
// 2 vectors
|
||||
if (m1->len != m2->len) {
|
||||
mp_raise_ValueError(translate("vectors must have same lengths"));
|
||||
}
|
||||
mp_float_t dot = 0.0;
|
||||
uint8_t *array1 = (uint8_t *)m1->array;
|
||||
uint8_t *array2 = (uint8_t *)m2->array;
|
||||
for (size_t i=0; i < m1->len; i++) {
|
||||
dot += ndarray_get_float_value(array1, m1->dtype)*ndarray_get_float_value(array2, m2->dtype);
|
||||
array1 += m1->strides[ULAB_MAX_DIMS - 1];
|
||||
array2 += m2->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
return mp_obj_new_float(dot);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
} else {
|
||||
// 2 matrices
|
||||
if(m1->shape[ULAB_MAX_DIMS - 1] != m2->shape[ULAB_MAX_DIMS - 2]) {
|
||||
mp_raise_ValueError(translate("matrix dimensions do not match"));
|
||||
}
|
||||
size_t *shape = ndarray_shape_vector(0, 0, m1->shape[ULAB_MAX_DIMS - 2], m2->shape[ULAB_MAX_DIMS - 1]);
|
||||
ndarray_obj_t *out = ndarray_new_dense_ndarray(2, shape, NDARRAY_FLOAT);
|
||||
mp_float_t *outdata = (mp_float_t *)out->array;
|
||||
for(size_t i=0; i < m1->shape[ULAB_MAX_DIMS - 2]; i++) { // rows of m1
|
||||
for(size_t j=0; j < m2->shape[ULAB_MAX_DIMS - 1]; j++) { // columns of m2
|
||||
mp_float_t sum = 0.0, v1, v2;
|
||||
for(size_t k=0; k < m2->shape[ULAB_MAX_DIMS - 2]; k++) {
|
||||
// (i, k) * (k, j)
|
||||
size_t pos1 = i*m1->shape[ULAB_MAX_DIMS - 1]+k;
|
||||
size_t pos2 = k*m2->shape[ULAB_MAX_DIMS - 1]+j;
|
||||
v1 = ndarray_get_float_index(m1->array, m1->dtype, pos1);
|
||||
v2 = ndarray_get_float_index(m2->array, m2->dtype, pos2);
|
||||
sum += v1 * v2;
|
||||
}
|
||||
*outdata++ = sum;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(out);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(transform_dot_obj, transform_dot);
|
||||
#endif
|
||||
28
code/numpy/transform/transform.h
Normal file
28
code/numpy/transform/transform.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Zoltán Vörös
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TRANSFORM_
|
||||
#define _TRANSFORM_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "transform.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(transform_dot_obj);
|
||||
|
||||
#endif
|
||||
16
code/ulab.h
16
code/ulab.h
|
|
@ -345,10 +345,6 @@
|
|||
#define ULAB_LINALG_HAS_DET (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_LINALG_HAS_DOT
|
||||
#define ULAB_LINALG_HAS_DOT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_LINALG_HAS_EIG
|
||||
#define ULAB_LINALG_HAS_EIG (1)
|
||||
#endif
|
||||
|
|
@ -361,10 +357,6 @@
|
|||
#define ULAB_LINALG_HAS_NORM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_LINALG_HAS_TRACE
|
||||
#define ULAB_LINALG_HAS_TRACE (1)
|
||||
#endif
|
||||
|
||||
// the FFT module; functions of the fft module still have
|
||||
// to be defined separately
|
||||
#ifndef ULAB_NUMPY_HAS_FFT_MODULE
|
||||
|
|
@ -407,6 +399,10 @@
|
|||
#define ULAB_NUMPY_HAS_DIFF (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_DOT
|
||||
#define ULAB_NUMPY_HAS_DOT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_FLIP
|
||||
#define ULAB_NUMPY_HAS_FLIP (1)
|
||||
#endif
|
||||
|
|
@ -451,6 +447,10 @@
|
|||
#define ULAB_NUMPY_HAS_SUM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_TRACE
|
||||
#define ULAB_NUMPY_HAS_TRACE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_TRAPZ
|
||||
#define ULAB_NUMPY_HAS_TRAPZ (1)
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -669,10 +669,13 @@ mp_obj_t create_frombuffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
|
|||
len = count;
|
||||
}
|
||||
}
|
||||
ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype);
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
ndarray_obj_t *ndarray = ndarray_new_linear_array(1, dtype);
|
||||
// at this point, ndarray->len = 1, ndarray->shape[ULAB_MAX_DIMS - 1] = 1
|
||||
uint8_t *buffer = bufinfo.buf;
|
||||
memcpy(array, buffer + offset, len * sz);
|
||||
ndarray->array = buffer + offset;
|
||||
// fix the length and shape here
|
||||
ndarray->len = len;
|
||||
ndarray->shape[ULAB_MAX_DIMS - 1] = len;
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
return mp_const_none;
|
||||
|
|
|
|||
|
|
@ -212,3 +212,19 @@ shape_strides tools_reduce_axes(ndarray_obj_t *ndarray, mp_obj_t axis) {
|
|||
|
||||
return _shape_strides;
|
||||
}
|
||||
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
ndarray_obj_t *tools_object_is_square(mp_obj_t obj) {
|
||||
// Returns an ndarray, if the object is a square ndarray,
|
||||
// raises the appropriate exception otherwise
|
||||
if(!MP_OBJ_IS_TYPE(obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("size is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(obj);
|
||||
if((ndarray->shape[ULAB_MAX_DIMS - 1] != ndarray->shape[ULAB_MAX_DIMS - 2]) || (ndarray->ndim != 2)) {
|
||||
mp_raise_ValueError(translate("input must be square matrix"));
|
||||
}
|
||||
return ndarray;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -33,4 +33,5 @@ uint8_t ndarray_upcast_dtype(uint8_t , uint8_t );
|
|||
void *ndarray_set_float_function(uint8_t );
|
||||
|
||||
shape_strides tools_reduce_axes(ndarray_obj_t *, mp_obj_t );
|
||||
ndarray_obj_t *tools_object_is_square(mp_obj_t );
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ copyright = '2019-2021, Zoltán Vörös and contributors'
|
|||
author = 'Zoltán Vörös'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '2.3.0'
|
||||
release = '2.3.6'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -13,25 +13,27 @@ from ``numpy``.
|
|||
6. `numpy.clip <#clip>`__
|
||||
7. `numpy.convolve <#convolve>`__
|
||||
8. `numpy.diff <#diff>`__
|
||||
9. `numpy.equal <#equal>`__
|
||||
10. `numpy.flip <#flip>`__
|
||||
11. `numpy.interp <#interp>`__
|
||||
12. `numpy.isfinite <#isfinite>`__
|
||||
13. `numpy.isinf <#isinf>`__
|
||||
14. `numpy.max <#max>`__
|
||||
15. `numpy.maximum <#maximum>`__
|
||||
16. `numpy.mean <#mean>`__
|
||||
17. `numpy.median <#median>`__
|
||||
18. `numpy.min <#min>`__
|
||||
19. `numpy.minimum <#minimum>`__
|
||||
20. `numpy.not_equal <#equal>`__
|
||||
21. `numpy.polyfit <#polyfit>`__
|
||||
22. `numpy.polyval <#polyval>`__
|
||||
23. `numpy.roll <#roll>`__
|
||||
24. `numpy.sort <#sort>`__
|
||||
25. `numpy.std <#std>`__
|
||||
26. `numpy.sum <#sum>`__
|
||||
27. `numpy.trapz <#trapz>`__
|
||||
9. `numpy.dot <#dot>`__
|
||||
10. `numpy.equal <#equal>`__
|
||||
11. `numpy.flip <#flip>`__
|
||||
12. `numpy.interp <#interp>`__
|
||||
13. `numpy.isfinite <#isfinite>`__
|
||||
14. `numpy.isinf <#isinf>`__
|
||||
15. `numpy.max <#max>`__
|
||||
16. `numpy.maximum <#maximum>`__
|
||||
17. `numpy.mean <#mean>`__
|
||||
18. `numpy.median <#median>`__
|
||||
19. `numpy.min <#min>`__
|
||||
20. `numpy.minimum <#minimum>`__
|
||||
21. `numpy.not_equal <#equal>`__
|
||||
22. `numpy.polyfit <#polyfit>`__
|
||||
23. `numpy.polyval <#polyval>`__
|
||||
24. `numpy.roll <#roll>`__
|
||||
25. `numpy.sort <#sort>`__
|
||||
26. `numpy.std <#std>`__
|
||||
27. `numpy.sum <#sum>`__
|
||||
28. `numpy.trace <#trace>`__
|
||||
29. `numpy.trapz <#trapz>`__
|
||||
|
||||
all
|
||||
---
|
||||
|
|
@ -399,6 +401,87 @@ and ``append`` keywords that can be found in ``numpy``.
|
|||
|
||||
|
||||
|
||||
dot
|
||||
---
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html
|
||||
|
||||
**WARNING:** numpy applies upcasting rules for the multiplication of
|
||||
matrices, while ``ulab`` simply returns a float matrix.
|
||||
|
||||
Once you can invert a matrix, you might want to know, whether the
|
||||
inversion is correct. You can simply take the original matrix and its
|
||||
inverse, and multiply them by calling the ``dot`` function, which takes
|
||||
the two matrices as its arguments. If the matrix dimensions do not
|
||||
match, the function raises a ``ValueError``. The result of the
|
||||
multiplication is expected to be the unit matrix, which is demonstrated
|
||||
below.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
m = np.array([[1, 2, 3], [4, 5, 6], [7, 10, 9]], dtype=np.uint8)
|
||||
n = np.linalg.inv(m)
|
||||
print("m:\n", m)
|
||||
print("\nm^-1:\n", n)
|
||||
# this should be the unit matrix
|
||||
print("\nm*m^-1:\n", np.dot(m, n))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
m:
|
||||
array([[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 10, 9]], dtype=uint8)
|
||||
|
||||
m^-1:
|
||||
array([[-1.25, 1.0, -0.25],
|
||||
[0.4999999999999998, -1.0, 0.5],
|
||||
[0.4166666666666668, 0.3333333333333333, -0.25]], dtype=float64)
|
||||
|
||||
m*m^-1:
|
||||
array([[1.0, 0.0, 0.0],
|
||||
[4.440892098500626e-16, 1.0, 0.0],
|
||||
[8.881784197001252e-16, 0.0, 1.0]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
Note that for matrix multiplication you don’t necessarily need square
|
||||
matrices, it is enough, if their dimensions are compatible (i.e., the
|
||||
the left-hand-side matrix has as many columns, as does the
|
||||
right-hand-side matrix rows):
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
m = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8)
|
||||
n = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.uint8)
|
||||
print(m)
|
||||
print(n)
|
||||
print(np.dot(m, n))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([[1, 2, 3, 4],
|
||||
[5, 6, 7, 8]], dtype=uint8)
|
||||
array([[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
[7, 8]], dtype=uint8)
|
||||
array([[50.0, 60.0],
|
||||
[114.0, 140.0]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
equal
|
||||
-----
|
||||
|
||||
|
|
@ -1236,6 +1319,52 @@ array. Otherwise, the calculation is along the given axis.
|
|||
|
||||
|
||||
|
||||
trace
|
||||
-----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.trace.html
|
||||
|
||||
The ``trace`` function returns the sum of the diagonal elements of a
|
||||
square matrix. If the input argument is not a square matrix, an
|
||||
exception will be raised.
|
||||
|
||||
The scalar so returned will inherit the type of the input array, i.e.,
|
||||
integer arrays have integer trace, and floating point arrays a floating
|
||||
point trace.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.int8)
|
||||
print('a: ', a)
|
||||
print('\ntrace of a: ', np.trace(a))
|
||||
|
||||
b = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.float)
|
||||
|
||||
print('='*20 + '\nb: ', b)
|
||||
print('\ntrace of b: ', np.trace(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([[25, 15, -5],
|
||||
[15, 18, 0],
|
||||
[-5, 0, 11]], dtype=int8)
|
||||
|
||||
trace of a: 54
|
||||
====================
|
||||
b: array([[25.0, 15.0, -5.0],
|
||||
[15.0, 18.0, 0.0],
|
||||
[-5.0, 0.0, 11.0]], dtype=float64)
|
||||
|
||||
trace of b: 54.0
|
||||
|
||||
|
||||
|
||||
|
||||
trapz
|
||||
-----
|
||||
|
||||
|
|
|
|||
|
|
@ -106,86 +106,6 @@ times are similar:
|
|||
|
||||
|
||||
|
||||
dot
|
||||
---
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html
|
||||
|
||||
**WARNING:** numpy applies upcasting rules for the multiplication of
|
||||
matrices, while ``ulab`` simply returns a float matrix.
|
||||
|
||||
Once you can invert a matrix, you might want to know, whether the
|
||||
inversion is correct. You can simply take the original matrix and its
|
||||
inverse, and multiply them by calling the ``dot`` function, which takes
|
||||
the two matrices as its arguments. If the matrix dimensions do not
|
||||
match, the function raises a ``ValueError``. The result of the
|
||||
multiplication is expected to be the unit matrix, which is demonstrated
|
||||
below.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
m = np.array([[1, 2, 3], [4, 5, 6], [7, 10, 9]], dtype=np.uint8)
|
||||
n = np.linalg.inv(m)
|
||||
print("m:\n", m)
|
||||
print("\nm^-1:\n", n)
|
||||
# this should be the unit matrix
|
||||
print("\nm*m^-1:\n", np.linalg.dot(m, n))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
m:
|
||||
array([[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 10, 9]], dtype=uint8)
|
||||
|
||||
m^-1:
|
||||
array([[-1.25, 1.0, -0.25],
|
||||
[0.5, -1.0, 0.5],
|
||||
[0.4166667, 0.3333334, -0.25]], dtype=float)
|
||||
|
||||
m*m^-1:
|
||||
array([[1.0, 2.384186e-07, -1.490116e-07],
|
||||
[-2.980232e-07, 1.000001, -4.172325e-07],
|
||||
[-3.278255e-07, 1.311302e-06, 0.9999992]], dtype=float)
|
||||
|
||||
|
||||
|
||||
Note that for matrix multiplication you don’t necessarily need square
|
||||
matrices, it is enough, if their dimensions are compatible (i.e., the
|
||||
the left-hand-side matrix has as many columns, as does the
|
||||
right-hand-side matrix rows):
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
m = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8)
|
||||
n = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.uint8)
|
||||
print(m)
|
||||
print(n)
|
||||
print(np.linalg.dot(m, n))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([[1, 2, 3, 4],
|
||||
[5, 6, 7, 8]], dtype=uint8)
|
||||
array([[1, 2],
|
||||
[3, 4],
|
||||
[5, 6],
|
||||
[7, 8]], dtype=uint8)
|
||||
array([[7.0, 10.0],
|
||||
[23.0, 34.0]], dtype=float)
|
||||
|
||||
|
||||
|
||||
|
||||
eig
|
||||
---
|
||||
|
||||
|
|
@ -398,49 +318,3 @@ The function takes a vector or matrix without options, and returns its
|
|||
|
||||
|
||||
|
||||
|
||||
trace
|
||||
-----
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy-1.17.0/reference/generated/numpy.linalg.trace.html
|
||||
|
||||
The ``trace`` function returns the sum of the diagonal elements of a
|
||||
square matrix. If the input argument is not a square matrix, an
|
||||
exception will be raised.
|
||||
|
||||
The scalar so returned will inherit the type of the input array, i.e.,
|
||||
integer arrays have integer trace, and floating point arrays a floating
|
||||
point trace.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.int8)
|
||||
print('a: ', a)
|
||||
print('\ntrace of a: ', np.linalg.trace(a))
|
||||
|
||||
b = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.float)
|
||||
|
||||
print('='*20 + '\nb: ', b)
|
||||
print('\ntrace of b: ', np.linalg.trace(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([[25, 15, -5],
|
||||
[15, 18, 0],
|
||||
[-5, 0, 11]], dtype=int8)
|
||||
|
||||
trace of a: 54
|
||||
====================
|
||||
b: array([[25.0, 15.0, -5.0],
|
||||
[15.0, 18.0, 0.0],
|
||||
[-5.0, 0.0, 11.0]], dtype=float)
|
||||
|
||||
trace of b: 54.0
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@
|
|||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:48:29.443204Z",
|
||||
"start_time": "2021-02-08T16:48:29.246310Z"
|
||||
"end_time": "2021-02-13T08:28:06.727371Z",
|
||||
"start_time": "2021-02-13T08:28:04.925338Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:48:32.087734Z",
|
||||
"start_time": "2021-02-08T16:48:32.079158Z"
|
||||
"end_time": "2021-02-13T08:30:08.058828Z",
|
||||
"start_time": "2021-02-13T08:30:08.052317Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -49,11 +49,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:48:34.384905Z",
|
||||
"start_time": "2021-02-08T16:48:34.333699Z"
|
||||
"end_time": "2021-02-13T08:30:09.684815Z",
|
||||
"start_time": "2021-02-13T08:30:09.647312Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -240,6 +240,7 @@
|
|||
"1. [numpy.clip](#clip)\n",
|
||||
"1. [numpy.convolve](#convolve)\n",
|
||||
"1. [numpy.diff](#diff)\n",
|
||||
"1. [numpy.dot](#dot)\n",
|
||||
"1. [numpy.equal](#equal)\n",
|
||||
"1. [numpy.flip](#flip)\n",
|
||||
"1. [numpy.interp](#interp)\n",
|
||||
|
|
@ -258,6 +259,7 @@
|
|||
"1. [numpy.sort](#sort)\n",
|
||||
"1. [numpy.std](#std)\n",
|
||||
"1. [numpy.sum](#sum)\n",
|
||||
"1. [numpy.trace](#trace)\n",
|
||||
"1. [numpy.trapz](#trapz)"
|
||||
]
|
||||
},
|
||||
|
|
@ -702,6 +704,112 @@
|
|||
"print('\\nfirst derivative, second axis:\\n', np.diff(c, axis=1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## dot\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**WARNING:** numpy applies upcasting rules for the multiplication of matrices, while `ulab` simply returns a float matrix. \n",
|
||||
"\n",
|
||||
"Once you can invert a matrix, you might want to know, whether the inversion is correct. You can simply take the original matrix and its inverse, and multiply them by calling the `dot` function, which takes the two matrices as its arguments. If the matrix dimensions do not match, the function raises a `ValueError`. The result of the multiplication is expected to be the unit matrix, which is demonstrated below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-13T08:32:09.139378Z",
|
||||
"start_time": "2021-02-13T08:32:09.122083Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"m:\n",
|
||||
" array([[1, 2, 3],\n",
|
||||
" [4, 5, 6],\n",
|
||||
" [7, 10, 9]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"m^-1:\n",
|
||||
" array([[-1.25, 1.0, -0.25],\n",
|
||||
" [0.4999999999999998, -1.0, 0.5],\n",
|
||||
" [0.4166666666666668, 0.3333333333333333, -0.25]], dtype=float64)\n",
|
||||
"\n",
|
||||
"m*m^-1:\n",
|
||||
" array([[1.0, 0.0, 0.0],\n",
|
||||
" [4.440892098500626e-16, 1.0, 0.0],\n",
|
||||
" [8.881784197001252e-16, 0.0, 1.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"m = np.array([[1, 2, 3], [4, 5, 6], [7, 10, 9]], dtype=np.uint8)\n",
|
||||
"n = np.linalg.inv(m)\n",
|
||||
"print(\"m:\\n\", m)\n",
|
||||
"print(\"\\nm^-1:\\n\", n)\n",
|
||||
"# this should be the unit matrix\n",
|
||||
"print(\"\\nm*m^-1:\\n\", np.dot(m, n))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that for matrix multiplication you don't necessarily need square matrices, it is enough, if their dimensions are compatible (i.e., the the left-hand-side matrix has as many columns, as does the right-hand-side matrix rows):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-13T08:33:07.630825Z",
|
||||
"start_time": "2021-02-13T08:33:07.608260Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"array([[1, 2, 3, 4],\n",
|
||||
" [5, 6, 7, 8]], dtype=uint8)\n",
|
||||
"array([[1, 2],\n",
|
||||
" [3, 4],\n",
|
||||
" [5, 6],\n",
|
||||
" [7, 8]], dtype=uint8)\n",
|
||||
"array([[50.0, 60.0],\n",
|
||||
" [114.0, 140.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"m = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8)\n",
|
||||
"n = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.uint8)\n",
|
||||
"print(m)\n",
|
||||
"print(n)\n",
|
||||
"print(np.dot(m, n))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -1753,6 +1861,64 @@
|
|||
"print('std, vertical: ', np.sum(a, axis=0))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## trace\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.trace.html\n",
|
||||
"\n",
|
||||
"The `trace` function returns the sum of the diagonal elements of a square matrix. If the input argument is not a square matrix, an exception will be raised.\n",
|
||||
"\n",
|
||||
"The scalar so returned will inherit the type of the input array, i.e., integer arrays have integer trace, and floating point arrays a floating point trace."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-13T08:30:25.211965Z",
|
||||
"start_time": "2021-02-13T08:30:25.195102Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: array([[25, 15, -5],\n",
|
||||
" [15, 18, 0],\n",
|
||||
" [-5, 0, 11]], dtype=int8)\n",
|
||||
"\n",
|
||||
"trace of a: 54\n",
|
||||
"====================\n",
|
||||
"b: array([[25.0, 15.0, -5.0],\n",
|
||||
" [15.0, 18.0, 0.0],\n",
|
||||
" [-5.0, 0.0, 11.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"trace of b: 54.0\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.int8)\n",
|
||||
"print('a: ', a)\n",
|
||||
"print('\\ntrace of a: ', np.trace(a))\n",
|
||||
"\n",
|
||||
"b = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.float)\n",
|
||||
"\n",
|
||||
"print('='*20 + '\\nb: ', b)\n",
|
||||
"print('\\ntrace of b: ', np.trace(b))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
|
|||
|
|
@ -371,111 +371,6 @@
|
|||
"matrix_det(m)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## dot\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.dot.html\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"**WARNING:** numpy applies upcasting rules for the multiplication of matrices, while `ulab` simply returns a float matrix. \n",
|
||||
"\n",
|
||||
"Once you can invert a matrix, you might want to know, whether the inversion is correct. You can simply take the original matrix and its inverse, and multiply them by calling the `dot` function, which takes the two matrices as its arguments. If the matrix dimensions do not match, the function raises a `ValueError`. The result of the multiplication is expected to be the unit matrix, which is demonstrated below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 556,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-20T07:13:30.102776Z",
|
||||
"start_time": "2019-10-20T07:13:30.073704Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"m:\n",
|
||||
" array([[1, 2, 3],\n",
|
||||
"\t [4, 5, 6],\n",
|
||||
"\t [7, 10, 9]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"m^-1:\n",
|
||||
" array([[-1.25, 1.0, -0.25],\n",
|
||||
"\t [0.5, -1.0, 0.5],\n",
|
||||
"\t [0.4166667, 0.3333334, -0.25]], dtype=float)\n",
|
||||
"\n",
|
||||
"m*m^-1:\n",
|
||||
" array([[1.0, 2.384186e-07, -1.490116e-07],\n",
|
||||
"\t [-2.980232e-07, 1.000001, -4.172325e-07],\n",
|
||||
"\t [-3.278255e-07, 1.311302e-06, 0.9999992]], dtype=float)\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"m = np.array([[1, 2, 3], [4, 5, 6], [7, 10, 9]], dtype=np.uint8)\n",
|
||||
"n = np.linalg.inv(m)\n",
|
||||
"print(\"m:\\n\", m)\n",
|
||||
"print(\"\\nm^-1:\\n\", n)\n",
|
||||
"# this should be the unit matrix\n",
|
||||
"print(\"\\nm*m^-1:\\n\", np.linalg.dot(m, n))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that for matrix multiplication you don't necessarily need square matrices, it is enough, if their dimensions are compatible (i.e., the the left-hand-side matrix has as many columns, as does the right-hand-side matrix rows):"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 37,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-10T17:33:17.921324Z",
|
||||
"start_time": "2019-10-10T17:33:17.900587Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"array([[1, 2, 3, 4],\n",
|
||||
"\t [5, 6, 7, 8]], dtype=uint8)\n",
|
||||
"array([[1, 2],\n",
|
||||
"\t [3, 4],\n",
|
||||
"\t [5, 6],\n",
|
||||
"\t [7, 8]], dtype=uint8)\n",
|
||||
"array([[7.0, 10.0],\n",
|
||||
"\t [23.0, 34.0]], dtype=float)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"m = np.array([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=np.uint8)\n",
|
||||
"n = np.array([[1, 2], [3, 4], [5, 6], [7, 8]], dtype=np.uint8)\n",
|
||||
"print(m)\n",
|
||||
"print(n)\n",
|
||||
"print(np.linalg.dot(m, n))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -770,59 +665,6 @@
|
|||
"print('norm of a:', np.linalg.norm(a))\n",
|
||||
"print('norm of b:', np.linalg.norm(b))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## trace\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy-1.17.0/reference/generated/numpy.linalg.trace.html\n",
|
||||
"\n",
|
||||
"The `trace` function returns the sum of the diagonal elements of a square matrix. If the input argument is not a square matrix, an exception will be raised.\n",
|
||||
"\n",
|
||||
"The scalar so returned will inherit the type of the input array, i.e., integer arrays have integer trace, and floating point arrays a floating point trace."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: array([[25, 15, -5],\n",
|
||||
"\t [15, 18, 0],\n",
|
||||
"\t [-5, 0, 11]], dtype=int8)\n",
|
||||
"\n",
|
||||
"trace of a: 54\n",
|
||||
"====================\n",
|
||||
"b: array([[25.0, 15.0, -5.0],\n",
|
||||
"\t [15.0, 18.0, 0.0],\n",
|
||||
"\t [-5.0, 0.0, 11.0]], dtype=float)\n",
|
||||
"\n",
|
||||
"trace of b: 54.0\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.int8)\n",
|
||||
"print('a: ', a)\n",
|
||||
"print('\\ntrace of a: ', np.linalg.trace(a))\n",
|
||||
"\n",
|
||||
"b = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]], dtype=np.float)\n",
|
||||
"\n",
|
||||
"print('='*20 + '\\nb: ', b)\n",
|
||||
"print('\\ntrace of b: ', np.linalg.trace(b))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,12 @@ version 2.4.0
|
|||
|
||||
added byteswap method
|
||||
|
||||
Sun, 14 Feb 2021
|
||||
|
||||
version 2.3.7
|
||||
|
||||
fixed frombuffer implementation glitch
|
||||
|
||||
Wed, 10 Feb 2021
|
||||
|
||||
version 2.3.5
|
||||
|
|
|
|||
|
|
@ -17,8 +17,8 @@
|
|||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:56:25.845993Z",
|
||||
"start_time": "2021-02-08T16:56:25.830627Z"
|
||||
"end_time": "2021-02-13T08:27:23.976552Z",
|
||||
"start_time": "2021-02-13T08:27:23.964444Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
|
|
@ -61,7 +61,7 @@
|
|||
"author = 'Zoltán Vörös'\n",
|
||||
"\n",
|
||||
"# The full version, including alpha/beta/rc tags\n",
|
||||
"release = '2.3.0'\n",
|
||||
"release = '2.3.6'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# -- General configuration ---------------------------------------------------\n",
|
||||
|
|
@ -215,8 +215,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:56:31.525356Z",
|
||||
"start_time": "2021-02-08T16:56:31.354760Z"
|
||||
"end_time": "2021-02-13T08:35:30.625437Z",
|
||||
"start_time": "2021-02-13T08:35:28.173618Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -256,8 +256,8 @@
|
|||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-08T16:57:02.367061Z",
|
||||
"start_time": "2021-02-08T16:56:57.710745Z"
|
||||
"end_time": "2021-02-13T08:35:36.916035Z",
|
||||
"start_time": "2021-02-13T08:35:32.271138Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
|
|||
|
|
@ -5,41 +5,9 @@ try:
|
|||
except ImportError:
|
||||
import numpy as np
|
||||
use_ulab = False
|
||||
|
||||
|
||||
|
||||
|
||||
if use_ulab:
|
||||
a = np.array([1,2,3], dtype=np.int16)
|
||||
b = np.array([4,5,6], dtype=np.int16)
|
||||
ab = np.linalg.dot(a.transpose(), b)
|
||||
print(math.isclose(ab, 32.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
a = np.array([1,2,3], dtype=np.int16)
|
||||
b = np.array([4,5,6], dtype=np.float)
|
||||
ab = np.linalg.dot(a.transpose(), b)
|
||||
print(math.isclose(ab, 32.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
a = np.array([[1., 2.], [3., 4.]])
|
||||
b = np.linalg.inv(a)
|
||||
ab = np.linalg.dot(a, b)
|
||||
m,n = ab.shape()
|
||||
for i in range(m):
|
||||
for j in range(n):
|
||||
if i == j:
|
||||
print(math.isclose(ab[i][j], 1.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
else:
|
||||
print(math.isclose(ab[i][j], 0.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
a = np.array([[1, 2, 3, 4], [4, 5, 6, 4], [7, 8.6, 9, 4], [3, 4, 5, 6]])
|
||||
b = np.linalg.inv(a)
|
||||
ab = np.linalg.dot(a, b)
|
||||
m,n = ab.shape()
|
||||
for i in range(m):
|
||||
for j in range(n):
|
||||
if i == j:
|
||||
print(math.isclose(ab[i][j], 1.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
else:
|
||||
print(math.isclose(ab[i][j], 0.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
else:
|
||||
a = np.array([1,2,3], dtype=np.int16)
|
||||
b = np.array([4,5,6], dtype=np.int16)
|
||||
ab = np.dot(a.transpose(), b)
|
||||
|
|
@ -49,11 +17,14 @@ else:
|
|||
b = np.array([4,5,6], dtype=np.float)
|
||||
ab = np.dot(a.transpose(), b)
|
||||
print(math.isclose(ab, 32.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
|
||||
a = np.array([[1., 2.], [3., 4.]])
|
||||
b = np.linalg.inv(a)
|
||||
ab = np.dot(a, b)
|
||||
m,n = ab.shape
|
||||
if use_ulab:
|
||||
m, n = ab.shape()
|
||||
else:
|
||||
m, n = ab.shape
|
||||
for i in range(m):
|
||||
for j in range(n):
|
||||
if i == j:
|
||||
|
|
@ -64,16 +35,19 @@ else:
|
|||
a = np.array([[1, 2, 3, 4], [4, 5, 6, 4], [7, 8.6, 9, 4], [3, 4, 5, 6]])
|
||||
b = np.linalg.inv(a)
|
||||
ab = np.dot(a, b)
|
||||
m,n = ab.shape
|
||||
if use_ulab:
|
||||
m, n = ab.shape()
|
||||
else:
|
||||
m, n = ab.shape
|
||||
for i in range(m):
|
||||
for j in range(n):
|
||||
if i == j:
|
||||
print(math.isclose(ab[i][j], 1.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
else:
|
||||
print(math.isclose(ab[i][j], 0.0, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
|
||||
a = np.array([[1, 2, 3, 4], [4, 5, 6, 4], [7, 8.6, 9, 4], [3, 4, 5, 6]])
|
||||
result = (np.linalg.det(a))
|
||||
result = (np.linalg.det(a))
|
||||
ref_result = 7.199999999999995
|
||||
print(math.isclose(result, ref_result, rel_tol=1E-9, abs_tol=1E-9))
|
||||
|
||||
|
|
@ -107,19 +81,13 @@ ref_result = 16.881943016134134
|
|||
print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6))
|
||||
|
||||
a = np.array([[0, 1, 2], [3, 4 ,5], [5, 4, 8], [4, 4, 8] ], dtype=np.int16)
|
||||
result = (np.linalg.norm(a,axis=0)) # fails on low tolerance
|
||||
result = (np.linalg.norm(a,axis=0)) # fails on low tolerance
|
||||
ref_result = np.array([7.071068, 7.0, 12.52996])
|
||||
for i in range(3):
|
||||
print(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6))
|
||||
|
||||
a = np.array([[0, 1, 2], [3, 4 ,5], [5, 4, 8], [4, 4, 8] ], dtype=np.int16)
|
||||
result = (np.linalg.norm(a,axis=1)) # fails on low tolerance
|
||||
result = (np.linalg.norm(a,axis=1)) # fails on low tolerance
|
||||
ref_result = np.array([2.236068, 7.071068, 10.24695, 9.797959])
|
||||
for i in range(4):
|
||||
print(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6))
|
||||
|
||||
if use_ulab:
|
||||
print(np.linalg.trace(np.eye(3)))
|
||||
else:
|
||||
print(np.trace(np.eye(3)))
|
||||
|
||||
|
|
|
|||
|
|
@ -51,4 +51,3 @@ True
|
|||
True
|
||||
True
|
||||
True
|
||||
3.0
|
||||
|
|
|
|||
Loading…
Reference in a new issue