Compare commits

..

124 commits

Author SHA1 Message Date
d0b11a6081 polyfit: Argument handling improvements
* In the 3-args case, the lengths of the arguments were not checked
 * in the 3-args case, the type of the 2nd argument was not checked
 * gcc falsely diagnosed a `maybe-uninitialized` variable because it
   did not see that the branches of the if() statement were mutually
   exclusive

It's this third issue that originally drew my attention to this code,
adafruit/circuitpython#2787
2020-04-20 07:58:30 -05:00
Zoltán Vörös
434211d401
updated README.md
added a short comment on the `numerical` sub-module
2020-04-18 11:45:41 +02:00
Zoltán Vörös
778c7e9bd8
Merge pull request #99 from v923z/compile
fixed compilation error in issue #98
2020-04-18 09:08:27 +02:00
Zoltán Vörös
d1f2d80581 fixed compilation error in issue #98 2020-04-18 09:05:47 +02:00
Zoltán Vörös
a746bd8e09
Merge pull request #96 from v923z/dot
fix indexing error in linalg.dot
2020-04-14 09:08:11 +02:00
Zoltán Vörös
2b7d96f25d fix indexing error in linalg.dot 2020-04-14 09:05:22 +02:00
Jeff Epler
22813d6736
Merge pull request #91 from v923z/argmax
fixed argmin/argmax function for iterables
2020-04-13 15:33:48 -05:00
470ea6578a add expected-output of tests 2020-04-13 15:29:45 -05:00
5fefea4871 add test 2020-04-13 15:28:49 -05:00
Zoltán Vörös
e83ef7a31d fixed another indexing error in argmin/argmax 2020-04-13 21:56:55 +02:00
Zoltán Vörös
1a4ac564d4 fixed indexing error in argmin/argmax 2020-04-13 21:27:41 +02:00
Zoltán Vörös
78ae57005c argmin/argmax raises ValueError with empty iterables 2020-04-12 19:32:08 +02:00
Zoltán Vörös
12d2c9127e
Merge pull request #92 from v923z/transpose
fix transpose function to conform to numpy
2020-04-09 21:27:43 +02:00
Zoltán Vörös
84150d4166 fix transpose function to conform to numpy 2020-04-09 12:38:19 +02:00
Zoltán Vörös
7b8d894413
extended readme 2020-04-09 10:18:52 +02:00
Zoltán Vörös
7ec8a25a84 fixed argmin/argmax function for iterables 2020-04-07 23:06:41 +02:00
Zoltán Vörös
a09c5f4c25
Merge pull request #90 from v923z/argsort
fix error in argsort
2020-04-07 22:35:59 +02:00
Zoltán Vörös
ab9a26dc98 fix error in argsort 2020-04-07 22:34:00 +02:00
Zoltán Vörös
55fb2e073b
Merge pull request #88 from jepler/fix-compiler-diagnostics
Fix compiler diagnostics normally enabled in CircuitPython; fix arg parsing bugs
2020-04-06 23:54:54 +02:00
86e7155ab7 generate_slice: Properly fix -Wsign-compare diagnostic
Instead of making the local unsigned--it must be permitted to
contain negative values--make the function parameter signed.
2020-04-06 16:38:51 -05:00
Zoltán Vörös
280f04660e
Merge pull request #86 from jepler/mp-flags-compat
Restore circuitpython compatibility after #84
2020-04-06 21:07:00 +02:00
f1f10c27a8 Fix -Wsign-compare diagnostics
.. by adding casts or changing the type of a local variable.
2020-04-06 08:38:43 -05:00
d41fb86fd0 add test of linspace 2020-04-06 08:36:25 -05:00
daf4b07ef7 Fix -Wunused-parameter diagnostics
Here we actually get bugs fixed!  At many sites, mp_parse_arg_all's
first argument was the number of positional arguments required, rather
than the number actually supplied.

This fixes e.g., the bug where the linspace third positional argument
was not used as the "num" argmuent, and where too many positional args
were not treated as an error:

    >>> ulab.linspace(0, 1, 9)
    array([0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0], dtype=float)
    >>> ulab.linspace(0, 1, 1, 1)
    TypeError: extra positional arguments given

In the case of argmin/argmax of an iterable, it is now signaled to the user
that only the axis=None case is supported, instead of giving a wrong
result.
2020-04-06 08:33:18 -05:00
22605c6fe9 Fix -Wshadow diagnostics
A declaration of a local variable can "shadow" a parameter or another
local variable declared in an outer scope.

Since this can create confusion about which variable is referred to, it
is better to fix these diagnostics.

A variety of changes were made:
 - Add curly braces to reduce the scope of a variable (ndarray_unary_op)
   so that its scope has ended before the next scope where it is used
 - be consistent about whether a variable is declared with for-loop scope
   or not (ndarray_print_row)
 - remove a declaration so that the outer variable is used, after verifying
   this will function properly (insert_slice_list)
 - rename a variable introduced by a macro (RUN_SUM, RUN_STD) so it does
   not shadow another variable
2020-04-06 08:12:47 -05:00
8aebfd9f4e remove unused function get_nditerable_len 2020-04-06 08:06:33 -05:00
be1e2b28e0 Fix -Wmissing-prototypes diagnostics
These functions need prototypes in a header, as they are defined in one
source file and used in another.
2020-04-06 08:05:43 -05:00
11ed69dacf Fix -Wmissing-prototypes diagnostics
This diagnostic flag, enabled by default in CircuitPython, requires that
nonstatic functions have a previous prototype.  Since placing prototypes
in header files is the only way that mismatched arguments between function
definition and use sites can be detected, this is a valuable warning.

In the case of ulab, the majority of the  changes required were to mark
functions as "static" that were used only in a single C source file.
2020-04-06 08:05:20 -05:00
59cc5ed6c6 circuitpython compatibility 2020-04-06 07:38:12 -05:00
Zoltán Vörös
ae7cadee8a
Merge pull request #84 from v923z/equal 2020-04-06 09:14:42 +02:00
Zoltán Vörös
1001ed44f5 fixed small glitch in == and != 2020-04-06 09:08:44 +02:00
Zoltán Vörös
c69f2d9256 implemented the ==, and != binary operators 2020-04-04 22:14:36 +02:00
Zoltán Vörös
8b072b7c0d
Merge pull request #83 from v923z/trace
This PR adds the trace function to linalg, and fixes a couple of glitches in the documentation.
2020-04-03 22:31:40 +02:00
Zoltán Vörös
acfd1d0760 added documentation to the trace function, and cleaned up other bits 2020-04-03 13:01:04 +02:00
Zoltán Vörös
ceaede8cb8 added trace to linalg, trimmed other code 2020-04-03 12:07:11 +02:00
Zoltán Vörös
034cdaf7e3
Merge pull request #82 from v923z/sort
another attempt at fixing issue #79
2020-04-02 21:27:57 +02:00
Zoltán Vörös
32e0bf5bde
Merge branch 'master' into sort 2020-04-02 21:26:06 +02:00
Zoltán Vörös
89d73974e3 another attempt at fixing issue #79 2020-04-02 21:22:45 +02:00
Zoltán Vörös
89579b6e36
Merge pull request #75 from v923z/power
adds an implementation of the `**` binary operator, and the reversed binary operators
2020-04-02 19:10:06 +02:00
Zoltán Vörös
b4f83997e7
Merge branch 'master' into power 2020-04-02 19:08:00 +02:00
Jeff Epler
0d5dc6b0d4
Merge pull request #78 from v923z/argmax
contraction returns scalar, if dimension is 0
2020-04-02 08:56:08 -05:00
Zoltán Vörös
411a5ffbd2
Merge pull request #81 from v923z/unistd
added unistd.h to ndarray.c to fix issue #73
2020-04-02 11:06:56 +02:00
Zoltán Vörös
2e27a356f5 added unistd.h to ndarray.c to fix issue #73 2020-04-02 11:04:23 +02:00
Zoltán Vörös
26d740ef77
Merge pull request #80 from v923z/copy
added fast initialisation option to ndarray_make_new_core, and updated docs
2020-04-02 09:55:33 +02:00
Zoltán Vörös
a3d77a3fa1 updated docs for ndarray_make_new_core 2020-04-02 09:52:04 +02:00
Zoltán Vörös
1648325d69 added fast ndarray initialisation option 2020-04-02 09:41:13 +02:00
Zoltán Vörös
272685dc50
Merge pull request #79 from v923z/sort
fixed indexing error in sort function
2020-04-01 23:46:38 +02:00
Zoltán Vörös
04422f3da5 fixed indexing error in sort function 2020-04-01 23:43:31 +02:00
Zoltán Vörös
c2c525247c contraction returns scalar, if dimension is 0 2020-04-01 22:56:07 +02:00
Zoltán Vörös
2517d8be25 incremented version number, modified change log 2020-03-31 23:14:54 +02:00
Zoltán Vörös
3153c86f09 fixed empty array error 2020-03-31 23:02:14 +02:00
Zoltán Vörös
ae0dfbc126 fixed binary error with empty arrays 2020-03-31 22:52:06 +02:00
Zoltán Vörös
a2d52b6454 implemented the ** operator, and the reversed binary operators 2020-03-31 21:38:47 +02:00
Zoltán Vörös
ac3f03c3ba
Merge pull request #70 from v923z/testfix
added slicing2.py.exp to the test suite
2020-03-30 23:34:13 +02:00
Zoltán Vörös
d55df3d4a0 added slicing2.py.exp to the test suite 2020-03-30 23:31:14 +02:00
Zoltán Vörös
3ec9f5a5bb
Merge pull request #69 from jepler/boolean-cpy
Add to #68 for CircuitPython compatibility
2020-03-30 22:36:54 +02:00
c66509f66e add test of boolean slicing 2020-03-30 15:34:26 -05:00
53c158bde3 ndarray.c: circuitpython needs translate() for mp_raise 2020-03-30 15:34:01 -05:00
cbe41034a3 ndarray.h: provide mp_obj_is_bool for circuitpython 2020-03-30 15:33:45 -05:00
Zoltán Vörös
b3562ae78c Boolean indexing raises TypeError, if index is not of Boolean type 2020-03-30 12:58:04 +02:00
Zoltán Vörös
ea4a7422ef fixing Boolean indexing issue 2020-03-30 12:45:54 +02:00
Zoltán Vörös
97f23da0c1
removed warning about missing roundf.c
The file has been appended to the makefile upstream.
2020-03-25 08:57:00 +01:00
Zoltán Vörös
84558f9447
added a workaround for a linker error 2020-03-20 22:14:58 +01:00
Zoltán Vörös
a91b36986d
Merge pull request #65 from jepler/slice-length-crash
slice_length: avoid implementation-defined division by negative number
2020-03-17 08:15:48 +01:00
3dc52575f0 slice_length: avoid implementation-defined division by negative number
In CircuitPython (only), a the slice assignment to [-1👎-3] of an
ndarray of length 1 caused a crash.  This appears to be because in
CircuitPython, the internal pointer of an empty array was NULL rather than
pointing at some memory which happened to be valid and assignable.

This appears to be a corner case of how integer promotion rules work in C.
The expression `slice.stop - slice.start + (slice.step + correction)`
is type `unsigned long` and on a LP64 platform its value is
18446744073709551614.  This led to the function returning that this slice
had length 1 instead, during the automated tests.

By casting to signed types capable of holding indices and sizes, the
problem is corrected on both platforms.
2020-03-16 22:09:39 -05:00
Zoltán Vörös
155e6eea60
Merge pull request #63 from v923z/round
added around and arctan2 to the vector sub-module, and extended ndarray initialisation options
2020-03-16 22:19:05 +01:00
Zoltán Vörös
94e5b304d2 added arctan2 to vectorise.c 2020-03-16 19:36:37 +01:00
Zoltán Vörös
49e2e68f9b added around to vectorise.c, and implemented array initialiation from another ndarray 2020-03-12 17:28:23 +01:00
Zoltán Vörös
3e53136a93 ndarrays can now be initialised from ndarrays 2020-03-12 07:17:54 +01:00
Zoltán Vörös
7ec399c58b
Merge pull request #62 from v923z/cholesky-test
added tests for linalg, and poly
2020-03-11 21:38:35 +01:00
Zoltán Vörös
47fd7964e8 generated .exp test files 2020-03-11 21:31:36 +01:00
Zoltán Vörös
e3a74453a8 trying to fix test routines 2020-03-11 18:53:06 +01:00
Zoltán Vörös
18d13e4252 added tests for inv, and det 2020-03-11 17:15:30 +01:00
Zoltán Vörös
cb1b1d352b added test files for the poly sub-module 2020-03-11 07:31:00 +01:00
Zoltán Vörös
c354657eda added test files for the Cholesky decomposition 2020-03-11 07:04:26 +01:00
Zoltán Vörös
037cd6e733 re-named spectrum->spectrogram, updated manual 2020-03-10 21:11:44 +01:00
Jeff Epler
1095994a4a
Merge pull request #59 from v923z/cholesky
added Cholesky decomposition to linalg.c, updated documentation
2020-03-10 14:51:48 -05:00
Jeff Epler
ea2bf3c236
Merge pull request #57 from v923z/spectrum
moved spectrum to extras module
2020-03-10 14:51:37 -05:00
Zoltán Vörös
525fbb6527 added Cholesky decomposition to linalg.c, updated documentation 2020-03-10 20:40:11 +01:00
Zoltán Vörös
5d0eab244b added function declarations to linalg.h 2020-03-09 21:22:31 +01:00
Zoltán Vörös
6b3d43846f moved spectrum to extras module 2020-03-09 20:47:58 +01:00
Jeff Epler
8241546378
Merge pull request #56 from v923z/workflow
include only code changes in workflow file
2020-03-07 20:31:00 -06:00
Zoltán Vörös
0434045293
Update README.md
Clarified statement on CP builds.
2020-03-07 09:46:50 +01:00
Zoltán Vörös
34c2355a2a tried to fix workflow file 2020-03-07 09:36:10 +01:00
Zoltán Vörös
0faa89e3a5 tried to fix workflow file 2020-03-07 09:33:48 +01:00
Zoltán Vörös
c0979509b4 run CI only for changes in code/, and tests/ 2020-03-07 09:31:30 +01:00
Zoltán Vörös
ef2c91c1fb
Merge pull request #55 from v923z/readme
updated readme
2020-03-06 21:18:54 +01:00
Zoltán Vörös
fb1153d3b3 updated readme 2020-03-06 21:15:49 +01:00
Zoltán Vörös
847c7f9d63
Merge pull request #54 from v923z/readme
updated readme
2020-03-06 18:31:04 +01:00
Zoltán Vörös
ab8b5fe4b1 updated readme 2020-03-06 18:27:59 +01:00
Zoltán Vörös
700e3ff1ac
Merge pull request #53 from v923z/jepler-patch-1
Update README.md with circuitpython mentions
2020-03-05 19:24:42 +01:00
Jeff Epler
a35c4ff1d8
Update README.md with circuitpython mentions 2020-03-05 07:22:22 -06:00
Zoltán Vörös
a6ebfc1ade
Merge pull request #52 from codemee/master
Deleting "#define MODULE_ULAB_ENABLED (1)"
2020-03-02 07:57:33 +01:00
codemee
882294dabf
Deleting "#define MODULE_ULAB_ENABLED (1)"
Since the micropython.mk file has added the following line

```
CFLAGS_EXTRA = -DMODULE_ULAB_ENABLED=1
```

There's no need to add #define MODULE_ULAB_ENABLED (1) in the mpconfigport.h.Or it would make redefined errors while compiling code.
2020-03-02 12:26:19 +08:00
Zoltán Vörös
adda973b56
Merge pull request #50 from jepler/slicing-fixes
Slicing fixes
2020-03-01 18:47:59 +01:00
Jeff Epler
903016ec44 slicing: add test of slice assignment
This tests that ulab and python3/numpy match on various slice assignments
that preserve the length of the array.  slice assignments that change
the length of the array are not tested.

Unlike the case of "load slice", this case of "modify slice" is not
compared to the built in list type, since "modify slice" is only
implemented in micropython for simple (stride=1) slices.
2020-02-29 17:11:56 -06:00
Jeff Epler
380b8b0347 Add new test of slicing
Closes: #32
2020-02-29 17:00:53 -06:00
Jeff Epler
f9fabc5079 Fix handling of negative indices
I don't know why, but mp_seq_get_fast_slice_indexes adjusts "stop" in a
surprising way, and that led to the (remaining) differences in slicing
between ulab and built-in lists.

    // If the index is negative then stop points to the last item, not after it
    if (indexes->step < 0) {
        indexes->stop++;
    }

Call the underlying routine, mp_obj_slice_indices, instead.
2020-02-29 17:00:42 -06:00
Jeff Epler
585513ce76 Return empty slices as empty ndarrays, not exceptions
This matches the behavior of built-in lists as well as numpy
2020-02-29 16:57:59 -06:00
Jeff Epler
2ea9656d3f build: include debug information (may also disable optimization)
.. this makes it much more pleasant to trace down problems using gdb.
2020-02-29 16:57:09 -06:00
Jeff Epler
66b89de8c7 Always include creation functions 2020-02-27 14:07:04 -06:00
Jeff Epler
844b85018b
Merge pull request #49 from jepler/gitignore
ignore files created by ./build.sh
2020-02-27 13:58:25 -06:00
Jeff Epler
1c1a693a2b
Merge pull request #48 from v923z/create
created new create sub-module for ndarray initialisation functions
2020-02-27 13:58:14 -06:00
Jeff Epler
f81e950513 ignore files created by ./build.sh 2020-02-27 13:56:09 -06:00
Jeff Epler
ffff7606c8 fix tests after 'eye' was moved 2020-02-27 13:53:29 -06:00
Zoltán Vörös
bee25781b9 added new source file... 2020-02-27 20:46:52 +01:00
Zoltán Vörös
47bf2ec9a7 created new create sub-module for ndarray initialisation functions 2020-02-27 20:39:13 +01:00
Jeff Epler
badeee48df
Merge pull request #47 from jepler/local-build-script
a script to build and run tests locally
2020-02-27 10:12:03 -06:00
Jeff Epler
e370e56a15 a script to build and run tests locally 2020-02-27 10:11:34 -06:00
Jeff Epler
db5f1f85bb
Merge pull request #46 from jepler/ndarray-properties-sort
Ndarray properties sort
2020-02-27 10:11:17 -06:00
Jeff Epler
2bddc94df5
Merge pull request #45 from jepler/move-ones-zeros
Move zeros(), ones() to base ulab module
2020-02-27 10:08:29 -06:00
Jeff Epler
aa5ef4afb9 Enable sort method in circuitpython 2020-02-27 10:06:33 -06:00
Jeff Epler
d99d834d87 Enable properties in circuitpython
I verified that these work for us as coded.
2020-02-27 10:06:27 -06:00
Jeff Epler
83479f115b Move zeros(), ones() to base ulab module 2020-02-27 10:05:50 -06:00
924dc7012a
Merge pull request #44 from jepler/circuitpy-fixes
Circuitpy fixes
2020-02-27 09:29:43 -06:00
Jeff Epler
daaacac16f Remove CIRCUITPY special cases 2020-02-27 08:56:07 -06:00
Jeff Epler
aa4d53e292 Use circuitpy-compat for none 2020-02-27 08:56:04 -06:00
3febd79aa0
Merge pull request #41 from v923z/2dim
Split ulab into multiple modules
2020-02-26 11:29:17 -06:00
Zoltán Vörös
7e2be88dff Merge branch '2dim' of github.com:v923z/micropython-ulab into 2dim
added circuitpython-related stuff to code and manual
2020-02-26 18:06:19 +01:00
Zoltán Vörös
e0e840f6d5 added circuitpython-related stuff to the manual 2020-02-26 18:05:49 +01:00
102ba5032e add missing expected-file 2020-02-18 21:40:31 -06:00
b83ed3e2ca add more tests 2020-02-18 21:36:49 -06:00
1e5ebe739d numerical: add __name__ 2020-02-18 21:27:05 -06:00
Zoltán Vörös
8300de7f11 backup commit, absolutely nothing essential 2020-02-16 19:53:30 +01:00
46 changed files with 4174 additions and 6713 deletions

View file

@ -3,6 +3,10 @@ name: Build CI
on:
push:
pull_request:
paths:
- 'code/'
- 'tests/'
- '.github/workflows/'
release:
types: [published]
check_suite:

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/micropython
/*.exp
/*.out

View file

@ -1,25 +1,76 @@
# micropython-ulab
# ulab
ulab is a numpy-like array manipulation library for micropython.
The module is written in C, defines compact containers for numerical
data, and is fast.
`ulab` is a `numpy`-like array manipulation library for `micropython` and `CircuitPython`.
The module is written in C, defines compact containers for numerical
data, and is fast. The library is a software-only standard `micropython` user module,
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.
Documentation can be found under https://micropython-ulab.readthedocs.io/en/latest/
The source for the manual is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab-manual.ipynb,
while developer help is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab.ipynb.
# Supported functions
## ndarray
`ulab` implements `numpy`'s `ndarray` with the `==`, `!=`, `<`, `<=`, `>`, `>=`, `+`, `-`, `/`, `*`, and `**` binary operators, and the `len`, `~`, `-`, `+`, `abs` unary operators that operate element-wise. Type-aware `ndarray`s can be initialised from any `micropython` iterable, lists of iterables, or by means of the `ones`, `zeros`, `eye`, or `linspace` functions.
`ndarray`s can be iterated on, and have a number of their own methods, such as `shape`, `reshape`, `transpose`, `size`, and `itemsize`.
## Modules
In addition to the `ndarray`'s operators and methods, seven modules define a great number of functions that can take `ndarray`s or `micropython` iterables as their arguments. If flash space is a concern, unnecessary sub-modules can be excluded from the compiled firmware with a pre-processor switch.
### vector
The `vector` sub-module implements all functions of the `math` package (e.g., `acos`, `acosh`, ..., `tan`, `tanh`) of `micropython` for `ndarray`s and iterables.
### numerical
The `numerical` sub-module defines the `roll`, `flip`, `diff`, `sort` and `argsort` functions for `ndarray`s, and, in addition, the `min`, `max`, `argmin`, `argmax`, `sum`, `mean`, `std` functions that work with `ndarray`s, as well as generic one-dimensional iterables.
### linalg
The `linalg` sub-module implements functions for matrix inversion, dot product, and the calculation of the determinant, eigenvalues, eigenvectors, Cholesky decomposition, and trace.
### poly
The `poly` sub-module defines the `polyval`, and `polyfit` functions from `numpy`.
### fft
The `fft` sub-module implements the fast Fourier transform, and its inverse for one-dimensional `ndarray`s.
### filter
The `filter` sub-module implements one-dimensional convolution.
### extras
The `extras` sub-module is meant as a user-extendable module, and currently implements the `spectrogram` function of `scipy`.
# Finding help
Documentation can be found on [readthedocs](readthedocs.org/) under [micropython-ulab](https://micropython-ulab.readthedocs.io/en/latest), as well as at [circuitpython-ulab](
https://circuitpython.readthedocs.io/en/latest/shared-bindings/ulab/__init__.html). A number of practical examples are listed in the excellent [circuitpython-ulab](https://learn.adafruit.com/ulab-crunch-numbers-fast-with-circuitpython/overview) overview.
# Firmware
Firmware for pyboard.v.1.1, and PYBD_SF6 is updated once in a while, and can be downloaded
from https://github.com/v923z/micropython-ulab/releases.
Firmware for pyboard.v.1.1, and PYBD_SF6 is released once in a while, and can be downloaded
from https://github.com/v923z/micropython-ulab/releases. Since a number of features can be
set in the firmware (threading, support for SD card, LEDs, user switch etc.), and it is
impossible to create something that suits everyone, these releases should only be used for
quick testing of `ulab`. Otherwise, compilation from the source is required with
the appropriate settings, which are usually defined in the `mpconfigboard.h` file of the port
in question.
`ulab` is also included in most development builds of `CircuitPython` for SAMD51 and nRF microcontrollers.
## Compiling
If you want to try the latest version of `ulab`, or your hardware is
If you want to try the latest version of `ulab` on micropython, or your hardware is
different to pyboard.v.1.1, or PYBD_SF6, the firmware can be compiled
from the source by following these steps:
First, you have to clone the micropython repository by running
First, you have to clone the `micropython` repository by running
```
git clone https://github.com/micropython/micropython.git
@ -30,18 +81,13 @@ on the command line. This will create a new repository with the name `micropytho
git clone https://github.com/v923z/micropython-ulab.git ulab
```
Then you have to include `ulab` in the compilation process by editing `mpconfigport.h` of the directory of the port for which you want to compile, so, still on the command line, navigate to `micropython/ports/unix`, or `micropython/ports/stm32`, or whichever port is your favourite, and edit the `mpconfigport.h` file there. All you have to do is add a single line at the end:
```
#define MODULE_ULAB_ENABLED (1)
```
This line will inform the compiler that you want `ulab` in the resulting firmware. If you don't have the cross-compiler installed, your might want to do that now, for instance on Linux by executing
If you don't have the cross-compiler installed, your might want to do that now, for instance on Linux by executing
```
sudo apt-get install gcc-arm-none-eabi
```
If that was successful, you can try to run the make command in the port's directory as
If this step was successful, you can try to run the `make` command in the port's directory as
```
make BOARD=PYBV11 USER_C_MODULES=../../../ulab all
```
@ -49,8 +95,9 @@ which will prepare the firmware for pyboard.v.11. Similarly,
```
make BOARD=PYBD_SF6 USER_C_MODULES=../../../ulab all
```
will compile for the SF6 member of the PYBD series. Provided that you managed to compile the firmware, you would upload that by running
either
will compile for the SF6 member of the PYBD series. If your target is `unix`, you don't need to specify the `BOARD` parameter.
Provided that you managed to compile the firmware, you would upload that by running either
```
dfu-util --alt 0 -D firmware.dfu
```

17
build.sh Executable file
View file

@ -0,0 +1,17 @@
#!/bin/sh
set -e
HERE="$(dirname -- "$(readlink -f -- "${0}")" )"
[ -e micropython/py/py.mk ] || git clone https://github.com/micropython/micropython
[ -e micropython/lib/libffi/autogen.sh ] || (cd micropython && git submodule update --init lib/libffi )
#git clone https://github.com/micropython/micropython
make -C micropython/mpy-cross -j$(nproc)
make -C micropython/ports/unix -j$(nproc) deplibs
make -C micropython/ports/unix -j$(nproc) USER_C_MODULES="${HERE}" DEBUG=1 STRIP=:
if ! env MICROPY_MICROPYTHON=micropython/ports/unix/micropython micropython/tests/run-tests -d tests; then
for exp in *.exp; do
testbase=$(basename $exp .exp);
echo -e "\nFAILURE $testbase";
diff -u $testbase.exp $testbase.out;
done
fi

155
code/create.c Normal file
View file

@ -0,0 +1,155 @@
/*
* This file is part of the micropython-ulab project,
*
* https://github.com/v923z/micropython-ulab
*
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
* 2019-2020 Zoltán Vörös
*/
#include "py/obj.h"
#include "py/runtime.h"
#include "create.h"
static mp_obj_t create_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } ,
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t dtype = args[1].u_int;
if(!MP_OBJ_IS_INT(args[0].u_obj) && !MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
}
ndarray_obj_t *ndarray = NULL;
if(MP_OBJ_IS_INT(args[0].u_obj)) {
size_t n = mp_obj_get_int(args[0].u_obj);
ndarray = create_new_ndarray(1, n, dtype);
} else if(MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj);
if(tuple->len != 2) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
}
ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]),
mp_obj_get_int(tuple->items[1]), dtype);
}
if(kind == 1) {
mp_obj_t one = mp_obj_new_int(1);
for(size_t i=0; i < ndarray->array->len; i++) {
mp_binary_set_val_array(dtype, ndarray->array->items, i, one);
}
}
return MP_OBJ_FROM_PTR(ndarray);
}
mp_obj_t create_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return create_zeros_ones(n_args, pos_args, kw_args, 0);
}
MP_DEFINE_CONST_FUN_OBJ_KW(create_zeros_obj, 0, create_zeros);
mp_obj_t create_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return create_zeros_ones(n_args, pos_args, kw_args, 1);
}
MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones);
mp_obj_t create_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
size_t n = args[0].u_int, m;
size_t k = args[2].u_int;
uint8_t dtype = args[3].u_int;
if(args[1].u_rom_obj == mp_const_none) {
m = n;
} else {
m = mp_obj_get_int(args[1].u_rom_obj);
}
ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype);
mp_obj_t one = mp_obj_new_int(1);
size_t i = 0;
if((k >= 0) && (k < n)) {
while(k < n) {
mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one);
k++;
i++;
}
} else if((k < 0) && (-k < m)) {
k = -k;
i = 0;
while(k < m) {
mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one);
k++;
i++;
}
}
return MP_OBJ_FROM_PTR(ndarray);
}
MP_DEFINE_CONST_FUN_OBJ_KW(create_eye_obj, 0, create_eye);
mp_obj_t create_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_num, MP_ARG_INT, {.u_int = 50} },
{ MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_true} },
{ MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_false} },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint16_t len = args[2].u_int;
if(len < 2) {
mp_raise_ValueError(translate("number of points must be at least 2"));
}
mp_float_t value, step;
value = mp_obj_get_float(args[0].u_obj);
uint8_t typecode = args[5].u_int;
if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1);
else step = (mp_obj_get_float(args[1].u_obj)-value)/len;
ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode);
if(typecode == NDARRAY_UINT8) {
uint8_t *array = (uint8_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value;
} else if(typecode == NDARRAY_INT8) {
int8_t *array = (int8_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value;
} else if(typecode == NDARRAY_UINT16) {
uint16_t *array = (uint16_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value;
} else if(typecode == NDARRAY_INT16) {
int16_t *array = (int16_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value;
} else {
mp_float_t *array = (mp_float_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = value;
}
if(args[4].u_obj == mp_const_false) {
return MP_OBJ_FROM_PTR(ndarray);
} else {
mp_obj_t tuple[2];
tuple[0] = ndarray;
tuple[1] = mp_obj_new_float(step);
return mp_obj_new_tuple(2, tuple);
}
}
MP_DEFINE_CONST_FUN_OBJ_KW(create_linspace_obj, 2, create_linspace);

28
code/create.h Normal file
View 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) 2020 Jeff Epler for Adafruit Industries
* 2019-2020 Zoltán Vörös
*/
#ifndef _CREATE_
#define _CREATE_
#include "ulab.h"
#include "ndarray.h"
mp_obj_t create_zeros(size_t , const mp_obj_t *, mp_map_t *);
mp_obj_t create_ones(size_t , const mp_obj_t *, mp_map_t *);
mp_obj_t create_eye(size_t , const mp_obj_t *, mp_map_t *);
mp_obj_t create_linspace(size_t , const mp_obj_t *, mp_map_t *);
MP_DECLARE_CONST_FUN_OBJ_KW(create_ones_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(create_zeros_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(create_eye_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(create_linspace_obj);
#endif

View file

@ -19,13 +19,24 @@
#if ULAB_EXTRAS_MODULE
STATIC const mp_rom_map_elem_t ulab_filter_globals_table[] = {
static mp_obj_t extras_spectrogram(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM);
} else {
return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM);
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(extras_spectrogram_obj, 1, 2, extras_spectrogram);
STATIC const mp_rom_map_elem_t ulab_extras_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_extras) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_spectrogram), (mp_obj_t)&extras_spectrogram_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_extras_globals, ulab_extras_globals_table);
mp_obj_module_t ulab_filter_module = {
mp_obj_module_t ulab_extras_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_extras_globals,
};

View file

@ -14,6 +14,7 @@
#include "ulab.h"
#include "ndarray.h"
#include "fft.h"
#if ULAB_EXTRAS_MODULE

View file

@ -23,13 +23,7 @@
#if ULAB_FFT_MODULE
enum FFT_TYPE {
FFT_FFT,
FFT_IFFT,
FFT_SPECTRUM,
};
void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) {
static void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) {
// This is basically a modification of four1 from Numerical Recipes
// The main difference is that this function takes two arrays, one
// for the real, and one for the imaginary parts.
@ -152,7 +146,7 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
}
}
mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
static mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_FFT);
} else {
@ -162,7 +156,7 @@ mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
static mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_IFFT);
} else {
@ -172,22 +166,10 @@ mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft);
mp_obj_t fft_spectrum(size_t n_args, const mp_obj_t *args) {
if(n_args == 2) {
return fft_fft_ifft_spectrum(n_args, args[0], args[1], FFT_SPECTRUM);
} else {
return fft_fft_ifft_spectrum(n_args, args[0], mp_const_none, FFT_SPECTRUM);
}
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj, 1, 2, fft_spectrum);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_fft_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_fft) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_fft), (mp_obj_t)&fft_fft_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_ifft), (mp_obj_t)&fft_ifft_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_spectrum), (mp_obj_t)&fft_spectrum_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table);
@ -196,6 +178,5 @@ mp_obj_module_t ulab_fft_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_fft_globals,
};
#endif
#endif

View file

@ -19,6 +19,12 @@
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
enum FFT_TYPE {
FFT_FFT,
FFT_IFFT,
FFT_SPECTRUM,
};
#if ULAB_FFT_MODULE
extern mp_obj_module_t ulab_fft_module;
@ -27,5 +33,7 @@ MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj);
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_spectrum_obj);
mp_obj_t fft_fft_ifft_spectrum(size_t , mp_obj_t , mp_obj_t , uint8_t );
#endif
#endif

View file

@ -18,14 +18,14 @@
#include "filter.h"
#if ULAB_FILTER_MODULE
mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_v, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type) || !MP_OBJ_IS_TYPE(args[1].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("convolve arguments must be ndarrays"));
@ -33,8 +33,8 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
ndarray_obj_t *a = MP_OBJ_TO_PTR(args[0].u_obj);
ndarray_obj_t *c = MP_OBJ_TO_PTR(args[1].u_obj);
int len_a = a->array->len;
int len_c = c->array->len;
size_t len_a = a->array->len;
size_t len_c = c->array->len;
// deal with linear arrays only
if(a->m*a->n != len_a || c->m*c->n != len_c) {
mp_raise_TypeError(translate("convolve arguments must be linear arrays"));
@ -84,7 +84,6 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_filter_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_filter) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj },
@ -96,6 +95,5 @@ mp_obj_module_t ulab_filter_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_filter_globals,
};
#endif
#endif

View file

@ -19,14 +19,27 @@
#if ULAB_LINALG_MODULE
mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
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->m != ndarray->n) {
mp_raise_ValueError(translate("input must be square matrix"));
}
return ndarray;
}
static mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("size is defined for ndarrays only"));
@ -101,18 +114,8 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) {
return true;
}
mp_obj_t linalg_inv(mp_obj_t o_in) {
// since inv is not a class method, we have to inspect the input argument first
if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("only ndarrays can be inverted"));
}
ndarray_obj_t *o = MP_OBJ_TO_PTR(o_in);
if(!MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("only ndarray objects can be inverted"));
}
if(o->m != o->n) {
mp_raise_ValueError(translate("only square matrices can be inverted"));
}
static mp_obj_t linalg_inv(mp_obj_t o_in) {
ndarray_obj_t *o = linalg_object_is_square(o_in);
ndarray_obj_t *inverted = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT);
mp_float_t *data = (mp_float_t *)inverted->array->items;
mp_obj_t elem;
@ -136,7 +139,7 @@ mp_obj_t linalg_inv(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
static mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
// TODO: should the results be upcast?
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"));
@ -149,17 +152,16 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
// TODO: numpy uses upcasting here
ndarray_obj_t *out = create_new_ndarray(m1->m, m2->n, NDARRAY_FLOAT);
mp_float_t *outdata = (mp_float_t *)out->array->items;
mp_float_t sum, v1, v2;
for(size_t i=0; i < m1->m; i++) { // rows of m1
for(size_t j=0; j < m2->n; j++) { // columns of m2
sum = 0.0;
mp_float_t sum = 0.0, v1, v2;
for(size_t k=0; k < m2->m; k++) {
// (i, k) * (k, j)
v1 = ndarray_get_float_value(m1->array->items, m1->array->typecode, i*m1->n+k);
v2 = ndarray_get_float_value(m2->array->items, m2->array->typecode, k*m2->n+j);
sum += v1 * v2;
}
outdata[j*m1->m+i] = sum;
outdata[i*m2->n+j] = sum;
}
}
return MP_OBJ_FROM_PTR(out);
@ -167,104 +169,8 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);
mp_obj_t linalg_zeros_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t kind) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} } ,
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t dtype = args[1].u_int;
if(!MP_OBJ_IS_INT(args[0].u_obj) && !MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
}
ndarray_obj_t *ndarray = NULL;
if(MP_OBJ_IS_INT(args[0].u_obj)) {
size_t n = mp_obj_get_int(args[0].u_obj);
ndarray = create_new_ndarray(1, n, dtype);
} else if(MP_OBJ_IS_TYPE(args[0].u_obj, &mp_type_tuple)) {
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(args[0].u_obj);
if(tuple->len != 2) {
mp_raise_TypeError(translate("input argument must be an integer or a 2-tuple"));
}
ndarray = create_new_ndarray(mp_obj_get_int(tuple->items[0]),
mp_obj_get_int(tuple->items[1]), dtype);
}
if(kind == 1) {
mp_obj_t one = mp_obj_new_int(1);
for(size_t i=0; i < ndarray->array->len; i++) {
mp_binary_set_val_array(dtype, ndarray->array->items, i, one);
}
}
return MP_OBJ_FROM_PTR(ndarray);
}
mp_obj_t linalg_zeros(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return linalg_zeros_ones(n_args, pos_args, kw_args, 0);
}
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_zeros_obj, 0, linalg_zeros);
mp_obj_t linalg_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return linalg_zeros_ones(n_args, pos_args, kw_args, 1);
}
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_ones_obj, 0, linalg_ones);
mp_obj_t linalg_eye(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_M, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_k, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
size_t n = args[0].u_int, m;
int16_t k = args[2].u_int;
uint8_t dtype = args[3].u_int;
if(args[1].u_rom_obj == mp_const_none) {
m = n;
} else {
m = mp_obj_get_int(args[1].u_rom_obj);
}
ndarray_obj_t *ndarray = create_new_ndarray(m, n, dtype);
mp_obj_t one = mp_obj_new_int(1);
size_t i = 0;
if((k >= 0) && (k < n)) {
while(k < n) {
mp_binary_set_val_array(dtype, ndarray->array->items, i*n+k, one);
k++;
i++;
}
} else if((k < 0) && (-k < m)) {
k = -k;
i = 0;
while(k < m) {
mp_binary_set_val_array(dtype, ndarray->array->items, k*n+i, one);
k++;
i++;
}
}
return MP_OBJ_FROM_PTR(ndarray);
}
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_eye_obj, 0, linalg_eye);
mp_obj_t linalg_det(mp_obj_t oin) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("function defined for ndarrays only"));
}
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
if(in->m != in->n) {
mp_raise_ValueError(translate("input must be square matrix"));
}
static mp_obj_t linalg_det(mp_obj_t oin) {
ndarray_obj_t *in = linalg_object_is_square(oin);
mp_float_t *tmp = m_new(mp_float_t, in->n*in->n);
for(size_t i=0; i < in->array->len; i++){
tmp[i] = ndarray_get_float_value(in->array->items, in->array->typecode, i);
@ -295,14 +201,8 @@ mp_obj_t linalg_det(mp_obj_t oin) {
MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
mp_obj_t linalg_eig(mp_obj_t oin) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("function defined for ndarrays only"));
}
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
if(in->m != in->n) {
mp_raise_ValueError(translate("input must be square matrix"));
}
static mp_obj_t linalg_eig(mp_obj_t oin) {
ndarray_obj_t *in = linalg_object_is_square(oin);
mp_float_t *array = m_new(mp_float_t, in->array->len);
for(size_t i=0; i < in->array->len; i++) {
array[i] = ndarray_get_float_value(in->array->items, in->array->typecode, i);
@ -424,17 +324,80 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
#if !CIRCUITPY
static mp_obj_t linalg_cholesky(mp_obj_t oin) {
ndarray_obj_t *in = MP_OBJ_TO_PTR(oin);
ndarray_obj_t *L = create_new_ndarray(in->n, in->n, NDARRAY_FLOAT);
mp_float_t *array = (mp_float_t *)L->array->items;
size_t pos = 0;
for(size_t m=0; m < in->m; m++) { // rows
for(size_t n=0; n < in->n; n++) { // columns
array[m*in->m+n] = ndarray_get_float_value(in->array->items, in->array->typecode, pos++);
}
}
// make sure the matrix is symmetric
for(size_t m=0; m < in->m; m++) { // rows
for(size_t n=m+1; n < in->n; n++) { // columns
// compare entry (m, n) to (n, m)
if(epsilon < MICROPY_FLOAT_C_FUN(fabs)(array[m*in->n + n] - array[n*in->n + m])) {
mp_raise_ValueError(translate("input matrix is asymmetric"));
}
}
}
// this is actually not needed, but Cholesky in numpy returns the lower triangular matrix
for(size_t i=0; i < in->m; i++) { // rows
for(size_t j=i+1; j < in->n; j++) { // columns
array[i*in->m + j] = 0.0;
}
}
mp_float_t sum = 0.0;
for(size_t i=0; i < in->m; i++) { // rows
for(size_t j=0; j <= i; j++) { // columns
sum = array[i*in->m + j];
for(size_t k=0; k < j; k++) {
sum -= array[i*in->n + k] * array[j*in->n + k];
}
if(i == j) {
if(sum <= 0.0) {
mp_raise_ValueError(translate("matrix is not positive definite"));
} else {
array[i*in->m+i] = MICROPY_FLOAT_C_FUN(sqrt)(sum);
}
} else {
array[i*in->m + j] = sum / array[j*in->m+j];
}
}
}
return MP_OBJ_FROM_PTR(L);
}
MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky);
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 pos=0; pos < ndarray->array->len; pos+=(ndarray->m+1)) {
trace += ndarray_get_float_value(ndarray->array->items, ndarray->array->typecode, pos);
}
if(ndarray->array->typecode == NDARRAY_FLOAT) {
return mp_obj_new_float(trace);
}
return mp_obj_new_int(trace);
}
MP_DEFINE_CONST_FUN_OBJ_1(linalg_trace_obj, linalg_trace);
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) },
{ MP_ROM_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
{ MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&linalg_zeros_obj },
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&linalg_ones_obj },
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&linalg_eye_obj },
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) },
{ MP_ROM_QSTR(MP_QSTR_size), (mp_obj_t)&linalg_size_obj },
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
{ MP_ROM_QSTR(MP_QSTR_dot), (mp_obj_t)&linalg_dot_obj },
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
{ MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj },
{ MP_ROM_QSTR(MP_QSTR_trace), (mp_obj_t)&linalg_trace_obj },
};
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table);
@ -443,6 +406,5 @@ mp_obj_module_t ulab_linalg_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_linalg_globals,
};
#endif
#endif

View file

@ -31,5 +31,11 @@ bool linalg_invert_matrix(mp_float_t *, size_t );
extern mp_obj_module_t ulab_linalg_module;
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_size_obj);
MP_DECLARE_CONST_FUN_OBJ_1(linalg_inv_obj);
MP_DECLARE_CONST_FUN_OBJ_2(linalg_dot_obj);
MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj);
MP_DECLARE_CONST_FUN_OBJ_1(linalg_eig_obj);
#endif
#endif

View file

@ -3,6 +3,7 @@ USERMODULES_DIR := $(USERMOD_DIR)
# Add all C files to SRC_USERMOD.
SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c
SRC_USERMOD += $(USERMODULES_DIR)/create.c
SRC_USERMOD += $(USERMODULES_DIR)/linalg.c
SRC_USERMOD += $(USERMODULES_DIR)/vectorise.c
SRC_USERMOD += $(USERMODULES_DIR)/poly.c

View file

@ -9,6 +9,7 @@
* Copyright (c) 2019-2020 Zoltán Vörös
*/
#include <unistd.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
@ -64,16 +65,15 @@ void fill_array_iterable(mp_float_t *array, mp_obj_t iterable) {
void ndarray_print_row(const mp_print_t *print, mp_obj_array_t *data, size_t n0, size_t n) {
mp_print_str(print, "[");
size_t i;
if(n < PRINT_MAX) { // if the array is short, print everything
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
for(i=1; i<n; i++) {
for(size_t i=1; i<n; i++) {
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
}
} else {
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0), PRINT_REPR);
for(i=1; i<3; i++) {
for(size_t i=1; i<3; i++) {
mp_print_str(print, ", ");
mp_obj_print_helper(print, mp_binary_get_val_array(data->typecode, data->items, n0+i), PRINT_REPR);
}
@ -159,16 +159,38 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint8_t dtype = args[1].u_int;
return dtype;
}
STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) {
STATIC mp_obj_t ndarray_make_new_core(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
uint8_t dtype = ndarray_init_helper(n_args, args, kw_args);
if(MP_OBJ_IS_TYPE(args[0], &ulab_ndarray_type)) {
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0]);
if(dtype == ndarray->array->typecode) {
return ndarray_copy(args[0]);
}
ndarray_obj_t *ndarray_new = create_new_ndarray(ndarray->m, ndarray->n, dtype);
mp_obj_t item;
if((ndarray->array->typecode == NDARRAY_FLOAT) &&(dtype != NDARRAY_FLOAT)) {
for(size_t i=0; i < ndarray->array->len; i++) {
mp_float_t f = ndarray_get_float_value(ndarray->array->items, ndarray->array->typecode, i);
item = mp_obj_new_int((int32_t)MICROPY_FLOAT_C_FUN(floor)(f));
mp_binary_set_val_array(dtype, ndarray_new->array->items, i, item);
}
} else {
for(size_t i=0; i < ndarray->array->len; i++) {
item = mp_binary_get_val_array(ndarray->array->typecode, ndarray->array->items, i);
mp_binary_set_val_array(dtype, ndarray_new->array->items, i, item);
}
}
return MP_OBJ_FROM_PTR(ndarray_new);
}
size_t len1, len2=0, i=0;
size_t len1, len2 = 0, i = 0;
mp_obj_t len_in = mp_obj_len_maybe(args[0]);
if (len_in == MP_OBJ_NULL) {
mp_raise_ValueError(translate("first argument must be an iterable"));
@ -186,7 +208,7 @@ STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args,
if(len_in != MP_OBJ_NULL) { // indeed, this seems to be an iterable
// Next, we have to check, whether all elements in the outer loop have the same length
if(i > 0) {
if(len2 != MP_OBJ_SMALL_INT_VALUE(len_in)) {
if(len2 != (size_t)MP_OBJ_SMALL_INT_VALUE(len_in)) {
mp_raise_ValueError(translate("iterables are not of the same length"));
}
}
@ -214,42 +236,44 @@ STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args,
#ifdef CIRCUITPY
mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void) type;
mp_arg_check_num(n_args, kw_args, 1, 2, true);
size_t n_kw = 0;
if (kw_args != 0) {
n_kw = kw_args->used;
}
mp_map_init_fixed_table(kw_args, n_kw, args + n_args);
return ndarray_make_new_core(type, n_args, n_kw, args, kw_args);
return ndarray_make_new_core(n_args, args, kw_args);
}
#else
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) {
(void) type;
mp_arg_check_num(n_args, n_kw, 1, 2, true);
mp_map_t kw_args;
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
return ndarray_make_new_core(type, n_args, n_kw, args, &kw_args);
return ndarray_make_new_core(n_args, args, &kw_args);
}
#endif
size_t slice_length(mp_bound_slice_t slice) {
int32_t len, correction = 1;
static size_t slice_length(mp_bound_slice_t slice) {
ssize_t len, correction = 1;
if(slice.step > 0) correction = -1;
len = (slice.stop - slice.start + (slice.step + correction)) / slice.step;
len = (ssize_t)(slice.stop - slice.start + (slice.step + correction)) / slice.step;
if(len < 0) return 0;
return (size_t)len;
}
size_t true_length(mp_obj_t bool_list) {
static size_t true_length(mp_obj_t bool_list) {
// returns the number of Trues in a Boolean list
// I wonder, wouldn't this be faster, if we looped through bool_list->items instead?
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(bool_list, &iter_buf);
size_t trues = 0;
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if(!MP_OBJ_IS_TYPE(item, &mp_type_bool)) {
// numpy seems to be a little bit inconsistent in when an index is considered
// to be True/False. Bail out immediately, if the items are not True/False
return 0;
if(!mp_obj_is_bool(item)) {
// numpy seems to be a little bit inconsistent in when an index is considered
// to be True/False. Bail out immediately, if the items are not True/False
mp_raise_TypeError(translate("wrong index type"));
}
if(mp_obj_is_true(item)) {
trues++;
@ -258,13 +282,13 @@ size_t true_length(mp_obj_t bool_list) {
return trues;
}
mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) {
static mp_bound_slice_t generate_slice(mp_int_t n, mp_obj_t index) {
// micropython seems to have difficulties with negative steps
mp_bound_slice_t slice;
if(MP_OBJ_IS_TYPE(index, &mp_type_slice)) {
mp_seq_get_fast_slice_indexes(n, index, &slice);
mp_obj_slice_indices(index, n, &slice);
} else if(MP_OBJ_IS_INT(index)) {
int32_t _index = mp_obj_get_int(index);
mp_int_t _index = mp_obj_get_int(index);
if(_index < 0) {
_index += n;
}
@ -280,7 +304,7 @@ mp_bound_slice_t generate_slice(mp_uint_t n, mp_obj_t index) {
return slice;
}
mp_bound_slice_t simple_slice(int16_t start, int16_t stop, int16_t step) {
static mp_bound_slice_t simple_slice(int16_t start, int16_t stop, int16_t step) {
mp_bound_slice_t slice;
slice.start = start;
slice.stop = stop;
@ -288,7 +312,7 @@ mp_bound_slice_t simple_slice(int16_t start, int16_t stop, int16_t step) {
return slice;
}
void insert_binary_value(ndarray_obj_t *ndarray, size_t nd_index, ndarray_obj_t *values, size_t value_index) {
static void insert_binary_value(ndarray_obj_t *ndarray, size_t nd_index, ndarray_obj_t *values, size_t value_index) {
// there is probably a more elegant implementation...
mp_obj_t tmp = mp_binary_get_val_array(values->array->typecode, values->array->items, value_index);
if((values->array->typecode == NDARRAY_FLOAT) && (ndarray->array->typecode != NDARRAY_FLOAT)) {
@ -299,7 +323,7 @@ void insert_binary_value(ndarray_obj_t *ndarray, size_t nd_index, ndarray_obj_t
mp_binary_set_val_array(ndarray->array->typecode, ndarray->array->items, nd_index, tmp);
}
mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
static mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
mp_bound_slice_t row, mp_bound_slice_t column,
mp_obj_t row_list, mp_obj_t column_list,
ndarray_obj_t *values) {
@ -367,7 +391,8 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
} else { // columns are indexed by a list
mp_obj_iter_buf_t column_iter_buf;
mp_obj_t column_item, column_iterable;
size_t j = 0, cindex = 0;
size_t j = 0;
cindex = 0;
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
if(mp_obj_is_true(row_item)) {
column_iterable = mp_getiter(column_list, &column_iter_buf);
@ -387,14 +412,10 @@ mp_obj_t insert_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
return mp_const_none;
}
mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
static mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
mp_bound_slice_t row, mp_bound_slice_t column,
mp_obj_t row_list, mp_obj_t column_list,
ndarray_obj_t *values) {
if((m == 0) || (n == 0)) {
mp_raise_msg(&mp_type_IndexError, translate("empty index range"));
}
if(values != NULL) {
return insert_slice_list(ndarray, m, n, row, column, row_list, column_list, values);
}
@ -453,7 +474,8 @@ mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
} else { // columns are indexed by a list
mp_obj_iter_buf_t column_iter_buf;
mp_obj_t column_item, column_iterable;
size_t j = 0, cindex = 0;
size_t j = 0;
cindex = 0;
while((row_item = mp_iternext(row_iterable)) != MP_OBJ_STOP_ITERATION) {
if(mp_obj_is_true(row_item)) {
column_iterable = mp_getiter(column_list, &column_iter_buf);
@ -473,7 +495,7 @@ mp_obj_t iterate_slice_list(ndarray_obj_t *ndarray, size_t m, size_t n,
return MP_OBJ_FROM_PTR(out);
}
mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t *values) {
static mp_obj_t ndarray_get_slice(ndarray_obj_t *ndarray, mp_obj_t index, ndarray_obj_t *values) {
mp_bound_slice_t row_slice = simple_slice(0, 0, 1), column_slice = simple_slice(0, 0, 1);
size_t m = 0, n = 0;
@ -590,7 +612,7 @@ typedef struct _mp_obj_ndarray_it_t {
size_t cur;
} mp_obj_ndarray_it_t;
mp_obj_t ndarray_iternext(mp_obj_t self_in) {
static mp_obj_t ndarray_iternext(mp_obj_t self_in) {
mp_obj_ndarray_it_t *self = MP_OBJ_TO_PTR(self_in);
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(self->ndarray);
// TODO: in numpy, ndarrays are iterated with respect to the first axis.
@ -686,155 +708,176 @@ mp_obj_t ndarray_flatten(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
}
// Binary operations
static ndarray_obj_t *ndarray_from_mp_obj(mp_obj_t obj) {
// creates an ndarray from an micropython int or float
// if the input is an ndarray, it is returned
ndarray_obj_t *ndarray;
if(MP_OBJ_IS_INT(obj)) {
int32_t ivalue = mp_obj_get_int(obj);
if((ivalue > 0) && (ivalue < 256)) {
CREATE_SINGLE_ITEM(ndarray, uint8_t, NDARRAY_UINT8, ivalue);
} else if((ivalue > 255) && (ivalue < 65535)) {
CREATE_SINGLE_ITEM(ndarray, uint16_t, NDARRAY_UINT16, ivalue);
} else if((ivalue < 0) && (ivalue > -128)) {
CREATE_SINGLE_ITEM(ndarray, int8_t, NDARRAY_INT8, ivalue);
} else if((ivalue < -127) && (ivalue > -32767)) {
CREATE_SINGLE_ITEM(ndarray, int16_t, NDARRAY_INT16, ivalue);
} else { // the integer value clearly does not fit the ulab types, so move on to float
CREATE_SINGLE_ITEM(ndarray, mp_float_t, NDARRAY_FLOAT, ivalue);
}
} else if(mp_obj_is_float(obj)) {
mp_float_t fvalue = mp_obj_get_float(obj);
CREATE_SINGLE_ITEM(ndarray, mp_float_t, NDARRAY_FLOAT, fvalue);
} else if(MP_OBJ_IS_TYPE(obj, &ulab_ndarray_type)){
ndarray = MP_OBJ_TO_PTR(obj);
} else {
mp_raise_TypeError(translate("wrong operand type"));
}
return ndarray;
}
mp_obj_t ndarray_binary_op(mp_binary_op_t op, mp_obj_t lhs, mp_obj_t rhs) {
// if(op == MP_BINARY_OP_REVERSE_ADD) {
// return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs);
// }
mp_obj_t ndarray_binary_op(mp_binary_op_t _op, mp_obj_t lhs, mp_obj_t rhs) {
// if the ndarray stands on the right hand side of the expression, simply swap the operands
ndarray_obj_t *ol, *or;
mp_binary_op_t op = _op;
if((op == MP_BINARY_OP_REVERSE_ADD) || (op == MP_BINARY_OP_REVERSE_MULTIPLY) ||
(op == MP_BINARY_OP_REVERSE_POWER) || (op == MP_BINARY_OP_REVERSE_SUBTRACT) ||
(op == MP_BINARY_OP_REVERSE_TRUE_DIVIDE)) {
ol = ndarray_from_mp_obj(rhs);
or = ndarray_from_mp_obj(lhs);
} else {
ol = ndarray_from_mp_obj(lhs);
or = ndarray_from_mp_obj(rhs);
}
if(op == MP_BINARY_OP_REVERSE_ADD) {
op = MP_BINARY_OP_ADD;
} else if(op == MP_BINARY_OP_REVERSE_MULTIPLY) {
op = MP_BINARY_OP_MULTIPLY;
} else if(op == MP_BINARY_OP_REVERSE_POWER) {
op = MP_BINARY_OP_POWER;
} else if(op == MP_BINARY_OP_REVERSE_SUBTRACT) {
op = MP_BINARY_OP_SUBTRACT;
} else if(op == MP_BINARY_OP_REVERSE_TRUE_DIVIDE) {
op = MP_BINARY_OP_TRUE_DIVIDE;
}
// One of the operands is a scalar
// TODO: conform to numpy with the upcasting
// TODO: implement in-place operators
mp_obj_t RHS = MP_OBJ_NULL;
bool rhs_is_scalar = true;
if(MP_OBJ_IS_INT(rhs)) {
int32_t ivalue = mp_obj_get_int(rhs);
if((ivalue > 0) && (ivalue < 256)) {
CREATE_SINGLE_ITEM(RHS, uint8_t, NDARRAY_UINT8, ivalue);
} else if((ivalue > 255) && (ivalue < 65535)) {
CREATE_SINGLE_ITEM(RHS, uint16_t, NDARRAY_UINT16, ivalue);
} else if((ivalue < 0) && (ivalue > -128)) {
CREATE_SINGLE_ITEM(RHS, int8_t, NDARRAY_INT8, ivalue);
} else if((ivalue < -127) && (ivalue > -32767)) {
CREATE_SINGLE_ITEM(RHS, int16_t, NDARRAY_INT16, ivalue);
} else { // the integer value clearly does not fit the ulab types, so move on to float
CREATE_SINGLE_ITEM(RHS, mp_float_t, NDARRAY_FLOAT, ivalue);
}
} else if(mp_obj_is_float(rhs)) {
mp_float_t fvalue = mp_obj_get_float(rhs);
CREATE_SINGLE_ITEM(RHS, mp_float_t, NDARRAY_FLOAT, fvalue);
} else {
RHS = rhs;
rhs_is_scalar = false;
}
//else
if(MP_OBJ_IS_TYPE(lhs, &ulab_ndarray_type) && MP_OBJ_IS_TYPE(RHS, &ulab_ndarray_type)) {
// next, the ndarray stuff
ndarray_obj_t *ol = MP_OBJ_TO_PTR(lhs);
ndarray_obj_t *or = MP_OBJ_TO_PTR(RHS);
if(!rhs_is_scalar && ((ol->m != or->m) || (ol->n != or->n))) {
// these are partial broadcasting rules: either the two arrays
// are of the same shape, or one of them is of length 1
if(((ol->m != or->m) || (ol->n != or->n))) {
if((ol->array->len != 1) && (or->array->len != 1)) {
if(op == MP_BINARY_OP_EQUAL) {
return mp_const_false;
} else if(op == MP_BINARY_OP_NOT_EQUAL) {
return mp_const_true;
}
mp_raise_ValueError(translate("operands could not be broadcast together"));
}
// At this point, the operands should have the same shape
switch(op) {
case MP_BINARY_OP_EQUAL:
// Two arrays are equal, if their shape, typecode, and elements are equal
if((ol->m != or->m) || (ol->n != or->n) || (ol->array->typecode != or->array->typecode)) {
return mp_const_false;
} else {
size_t i = ol->bytes;
uint8_t *l = (uint8_t *)ol->array->items;
uint8_t *r = (uint8_t *)or->array->items;
while(i) { // At this point, we can simply compare the bytes, the type is irrelevant
if(*l++ != *r++) {
return mp_const_false;
}
i--;
}
return mp_const_true;
}
break;
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
case MP_BINARY_OP_ADD:
case MP_BINARY_OP_SUBTRACT:
case MP_BINARY_OP_TRUE_DIVIDE:
case MP_BINARY_OP_MULTIPLY:
// TODO: I believe, this part can be made significantly smaller (compiled size)
// by doing only the typecasting in the large ifs, and moving the loops outside
// These are the upcasting rules
// float always becomes float
// operation on identical types preserves type
// uint8 + int8 => int16
// uint8 + int16 => int16
// uint8 + uint16 => uint16
// int8 + int16 => int16
// int8 + uint16 => uint16
// uint16 + int16 => float
// The parameters of RUN_BINARY_LOOP are
// typecode of result, type_out, type_left, type_right, lhs operand, rhs operand, operator
if(ol->array->typecode == NDARRAY_UINT8) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_UINT8, uint8_t, uint8_t, uint8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, uint8_t, int8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint8_t, uint16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, uint8_t, int16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, ol, or, op);
}
} else if(ol->array->typecode == NDARRAY_INT8) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, uint8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT8, int8_t, int8_t, int8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, uint16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, int16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, int8_t, mp_float_t, ol, or, op);
}
} else if(ol->array->typecode == NDARRAY_UINT16) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, int8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, int16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, ol, or, op);
}
} else if(ol->array->typecode == NDARRAY_INT16) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, uint8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, int8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, int16_t, uint16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, int16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, mp_float_t, ol, or, op);
}
} else if(ol->array->typecode == NDARRAY_FLOAT) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int8_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int16_t, ol, or, op);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, ol, or, op);
}
} else { // this should never happen
mp_raise_TypeError(translate("wrong input type"));
}
// this instruction should never be reached, but we have to make the compiler happy
return MP_OBJ_NULL;
default:
return MP_OBJ_NULL; // op not supported
}
} else {
mp_raise_TypeError(translate("wrong operand type on the right hand side"));
}
}
}
uint8_t linc = ol->array->len == 1 ? 0 : 1;
uint8_t rinc = or->array->len == 1 ? 0 : 1;
// do the partial broadcasting here
size_t m = MAX(ol->m, or->m);
size_t n = MAX(ol->n, or->n);
size_t len = MAX(ol->array->len, or->array->len);
if((ol->array->len == 0) || (or->array->len == 0)) {
len = 0;
}
switch(op) {
case MP_BINARY_OP_EQUAL:
case MP_BINARY_OP_NOT_EQUAL:
case MP_BINARY_OP_LESS:
case MP_BINARY_OP_LESS_EQUAL:
case MP_BINARY_OP_MORE:
case MP_BINARY_OP_MORE_EQUAL:
case MP_BINARY_OP_ADD:
case MP_BINARY_OP_SUBTRACT:
case MP_BINARY_OP_TRUE_DIVIDE:
case MP_BINARY_OP_MULTIPLY:
case MP_BINARY_OP_POWER:
// TODO: I believe, this part can be made significantly smaller (compiled size)
// by doing only the typecasting in the large ifs, and moving the loops outside
// These are the upcasting rules
// float always becomes float
// operation on identical types preserves type
// uint8 + int8 => int16
// uint8 + int16 => int16
// uint8 + uint16 => uint16
// int8 + int16 => int16
// int8 + uint16 => uint16
// uint16 + int16 => float
// The parameters of RUN_BINARY_LOOP are
// typecode of result, type_out, type_left, type_right, lhs operand, rhs operand, operator
if(ol->array->typecode == NDARRAY_UINT8) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_UINT8, uint8_t, uint8_t, uint8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, uint8_t, int8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint8_t, uint16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, uint8_t, int16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, ol, or, op, m, n, len, linc, rinc);
}
} else if(ol->array->typecode == NDARRAY_INT8) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, uint8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT8, int8_t, int8_t, int8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, uint16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int8_t, int16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, int8_t, mp_float_t, ol, or, op, m, n, len, linc, rinc);
}
} else if(ol->array->typecode == NDARRAY_UINT16) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, int8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_UINT16, uint16_t, uint16_t, uint16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, int16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint8_t, mp_float_t, ol, or, op, m, n, len, linc, rinc);
}
} else if(ol->array->typecode == NDARRAY_INT16) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, uint8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, int8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, int16_t, uint16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_INT16, int16_t, int16_t, int16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, uint16_t, mp_float_t, ol, or, op, m, n, len, linc, rinc);
}
} else if(ol->array->typecode == NDARRAY_FLOAT) {
if(or->array->typecode == NDARRAY_UINT8) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT8) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int8_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_UINT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, uint16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_INT16) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, int16_t, ol, or, op, m, n, len, linc, rinc);
} else if(or->array->typecode == NDARRAY_FLOAT) {
RUN_BINARY_LOOP(NDARRAY_FLOAT, mp_float_t, mp_float_t, mp_float_t, ol, or, op, m, n, len, linc, rinc);
}
}
// this instruction should never be reached, but we have to make the compiler happy
return MP_OBJ_NULL;
break;
default:
return MP_OBJ_NULL; // op not supported
break;
}
return MP_OBJ_NULL;
}
mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
@ -856,9 +899,11 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
// we can invert the content byte by byte, there is no need to distinguish
// between different typecodes
ndarray = MP_OBJ_TO_PTR(ndarray_copy(self_in));
uint8_t *array = (uint8_t *)ndarray->array->items;
for(size_t i=0; i < self->bytes; i++) array[i] = ~array[i];
return MP_OBJ_FROM_PTR(ndarray);
{
uint8_t *array = (uint8_t *)ndarray->array->items;
for(size_t i=0; i < self->bytes; i++) array[i] = ~array[i];
return MP_OBJ_FROM_PTR(ndarray);
}
break;
case MP_UNARY_OP_NEGATIVE:
@ -914,34 +959,28 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
mp_obj_t ndarray_transpose(mp_obj_t self_in) {
ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in);
// the size of a single item in the array
uint8_t _sizeof = mp_binary_get_size('@', self->array->typecode, NULL);
// NOTE:
// if the matrices are square, we can simply swap items, but
// generic matrices can't be transposed in place, so we have to
// declare a temporary variable
// NOTE:
// In the old matrix, the coordinate (m, n) is m*self->n + n
// We have to assign this to the coordinate (n, m) in the new
// matrix, i.e., to n*self->m + m (since the new matrix has self->m columns)
ndarray_obj_t *ndarray = create_new_ndarray(self->n, self->m, self->array->typecode);
// one-dimensional arrays can be transposed by simply swapping the dimensions
if((self->m != 1) && (self->n != 1)) {
uint8_t *c = (uint8_t *)self->array->items;
// self->bytes is the size of the bytearray, irrespective of the typecode
uint8_t *tmp = m_new(uint8_t, self->bytes);
if((self->m == 1) || (self->n == 1)) {
memcpy(ndarray->array->items, self->array->items, self->bytes);
} else {
// the size of a single item in the array
uint8_t itemsize = mp_binary_get_size('@', self->array->typecode, NULL);
uint8_t *sarray = (uint8_t *)self->array->items;
uint8_t *narray = (uint8_t *)ndarray->array->items;
for(size_t m=0; m < self->m; m++) {
for(size_t n=0; n < self->n; n++) {
memcpy(tmp+_sizeof*(n*self->m + m), c+_sizeof*(m*self->n + n), _sizeof);
memcpy(narray+itemsize*(n*self->m + m), sarray, itemsize);
sarray += itemsize;
}
}
memcpy(self->array->items, tmp, self->bytes);
m_del(uint8_t, tmp, self->bytes);
}
SWAP(size_t, self->m, self->n);
return mp_const_none;
return MP_OBJ_FROM_PTR(ndarray);
}
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_transpose_obj, ndarray_transpose);

View file

@ -25,8 +25,10 @@
#define FLOAT_TYPECODE 'd'
#endif
#if !CIRCUITPY
#define translate(x) x
#if CIRCUITPY
#define mp_obj_is_bool(o) (MP_OBJ_IS_TYPE((o), &mp_type_bool))
#else
#define translate(x) MP_ERROR_TEXT(x)
#endif
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
@ -99,45 +101,38 @@ mp_int_t ndarray_get_buffer(mp_obj_t obj, mp_buffer_info_t *bufinfo, mp_uint_t f
should work outside the loop, but it doesn't. Go figure!
*/
#define RUN_BINARY_LOOP(typecode, type_out, type_left, type_right, ol, or, op) do {\
#define RUN_BINARY_LOOP(typecode, type_out, type_left, type_right, ol, or, op, m, n, len, linc, rinc) do {\
type_left *left = (type_left *)(ol)->array->items;\
type_right *right = (type_right *)(or)->array->items;\
uint8_t inc = 0;\
if((or)->array->len > 1) inc = 1;\
if(((op) == MP_BINARY_OP_ADD) || ((op) == MP_BINARY_OP_SUBTRACT) || ((op) == MP_BINARY_OP_MULTIPLY)) {\
ndarray_obj_t *out = create_new_ndarray(ol->m, ol->n, typecode);\
if(((op) == MP_BINARY_OP_ADD) || ((op) == MP_BINARY_OP_SUBTRACT) || ((op) == MP_BINARY_OP_MULTIPLY) || ((op) == MP_BINARY_OP_POWER)) {\
ndarray_obj_t *out = create_new_ndarray((m), (n), (typecode));\
type_out *(odata) = (type_out *)out->array->items;\
if((op) == MP_BINARY_OP_ADD) { for(size_t i=0, j=0; i < (ol)->array->len; i++, j+=inc) odata[i] = left[i] + right[j];}\
if((op) == MP_BINARY_OP_SUBTRACT) { for(size_t i=0, j=0; i < (ol)->array->len; i++, j+=inc) odata[i] = left[i] - right[j];}\
if((op) == MP_BINARY_OP_MULTIPLY) { for(size_t i=0, j=0; i < (ol)->array->len; i++, j+=inc) odata[i] = left[i] * right[j];}\
if((op) == MP_BINARY_OP_ADD) { for(size_t i=0; i < (len); i++, left+=linc, right+=rinc) *odata++ = *left + *right; }\
else if((op) == MP_BINARY_OP_MULTIPLY) { for(size_t i=0; i < (len); i++, left+=linc, right+=rinc) *odata++ = *left * *right; }\
else if((op) == MP_BINARY_OP_POWER) { for(size_t i=0; i < (len); i++, left+=linc, right+=rinc) *odata++ = MICROPY_FLOAT_C_FUN(pow)(*left, *right); }\
else if((op) == MP_BINARY_OP_SUBTRACT) { for(size_t i=0; i < (len); i++, left+=linc, right+=rinc) *odata++ = *left - *right; }\
return MP_OBJ_FROM_PTR(out);\
} else if((op) == MP_BINARY_OP_TRUE_DIVIDE) {\
ndarray_obj_t *out = create_new_ndarray(ol->m, ol->n, NDARRAY_FLOAT);\
} else if((op) == MP_BINARY_OP_TRUE_DIVIDE) {\
ndarray_obj_t *out = create_new_ndarray((m), (n), NDARRAY_FLOAT);\
mp_float_t *odata = (mp_float_t *)out->array->items;\
for(size_t i=0, j=0; i < (ol)->array->len; i++, j+=inc) odata[i] = (mp_float_t)left[i]/(mp_float_t)right[j];\
for(size_t i=0; i < (len); i++, left+=linc, right+=rinc) {*odata++ = (mp_float_t)(*left)/(mp_float_t)(*right);}\
return MP_OBJ_FROM_PTR(out);\
} else if(((op) == MP_BINARY_OP_LESS) || ((op) == MP_BINARY_OP_LESS_EQUAL) || \
((op) == MP_BINARY_OP_MORE) || ((op) == MP_BINARY_OP_MORE_EQUAL)) {\
} else if(((op) == MP_BINARY_OP_LESS) || ((op) == MP_BINARY_OP_LESS_EQUAL) || \
((op) == MP_BINARY_OP_MORE) || ((op) == MP_BINARY_OP_MORE_EQUAL) || \
((op) == MP_BINARY_OP_EQUAL) || ((op) == MP_BINARY_OP_NOT_EQUAL)) {\
mp_obj_t out_list = mp_obj_new_list(0, NULL);\
size_t m = (ol)->m, n = (ol)->n;\
for(size_t i=0, r=0; i < m; i++, r+=inc) {\
for(size_t i=0; i < m; i++) {\
mp_obj_t row = mp_obj_new_list(n, NULL);\
mp_obj_list_t *row_ptr = MP_OBJ_TO_PTR(row);\
for(size_t j=0, s=0; j < n; j++, s+=inc) {\
row_ptr->items[j] = mp_const_false;\
if((op) == MP_BINARY_OP_LESS) {\
if(left[i*n+j] < right[r*n+s]) row_ptr->items[j] = mp_const_true;\
} else if((op) == MP_BINARY_OP_LESS_EQUAL) {\
if(left[i*n+j] <= right[r*n+s]) row_ptr->items[j] = mp_const_true;\
} else if((op) == MP_BINARY_OP_MORE) {\
if(left[i*n+j] > right[r*n+s]) row_ptr->items[j] = mp_const_true;\
} else if((op) == MP_BINARY_OP_MORE_EQUAL) {\
if(left[i*n+j] >= right[r*n+s]) row_ptr->items[j] = mp_const_true;\
}\
}\
if((op) == MP_BINARY_OP_LESS) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left < *right ? mp_const_true : mp_const_false; }\
else if((op) == MP_BINARY_OP_LESS_EQUAL) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left <= *right ? mp_const_true : mp_const_false; }\
else if((op) == MP_BINARY_OP_MORE) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left > *right ? mp_const_true : mp_const_false; }\
else if((op) == MP_BINARY_OP_MORE_EQUAL) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left >= *right ? mp_const_true : mp_const_false; }\
else if((op) == MP_BINARY_OP_EQUAL) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left == *right ? mp_const_true : mp_const_false; }\
else if((op) == MP_BINARY_OP_NOT_EQUAL) { for(size_t j=0; j < n; j++, left+=linc, right+=rinc) row_ptr->items[j] = *left != *right ? mp_const_true : mp_const_false; }\
if(m == 1) return row;\
mp_obj_list_append(out_list, row);\
}\
}\
return out_list;\
}\
} while(0)

View file

@ -20,43 +20,42 @@
#include "ndarray.h"
#if CIRCUITPY
typedef struct _mp_obj_property_t {
mp_obj_base_t base;
mp_obj_t proxy[3]; // getter, setter, deleter
} mp_obj_property_t;
/* v923z: it is not at all clear to me, why this must be declared; it should already be in obj.h */
typedef struct _mp_obj_none_t {
mp_obj_base_t base;
} mp_obj_none_t;
const mp_obj_type_t mp_type_NoneType;
const mp_obj_none_t mp_const_none_obj = {{&mp_type_NoneType}};
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_shape_obj, ndarray_shape);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_size_obj, ndarray_size);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_itemsize_obj, ndarray_itemsize);
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten);
STATIC const mp_obj_property_t ndarray_shape_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_shape_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
mp_const_none,
mp_const_none },
};
STATIC const mp_obj_property_t ndarray_size_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_size_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
mp_const_none,
mp_const_none },
};
STATIC const mp_obj_property_t ndarray_itemsize_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&ndarray_get_itemsize_obj,
(mp_obj_t)&mp_const_none_obj,
(mp_obj_t)&mp_const_none_obj},
mp_const_none,
mp_const_none },
};
#else
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize);
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);
#endif
#endif

View file

@ -31,58 +31,7 @@ enum NUMERICAL_FUNCTION_TYPE {
NUMERICAL_STD,
};
mp_obj_t numerical_linspace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_num, MP_ARG_INT, {.u_int = 50} },
{ MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_true} },
{ MP_QSTR_retstep, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_false} },
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = NDARRAY_FLOAT} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
uint16_t len = args[2].u_int;
if(len < 2) {
mp_raise_ValueError(translate("number of points must be at least 2"));
}
mp_float_t value, step;
value = mp_obj_get_float(args[0].u_obj);
uint8_t typecode = args[5].u_int;
if(args[3].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj)-value)/(len-1);
else step = (mp_obj_get_float(args[1].u_obj)-value)/len;
ndarray_obj_t *ndarray = create_new_ndarray(1, len, typecode);
if(typecode == NDARRAY_UINT8) {
uint8_t *array = (uint8_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (uint8_t)value;
} else if(typecode == NDARRAY_INT8) {
int8_t *array = (int8_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (int8_t)value;
} else if(typecode == NDARRAY_UINT16) {
uint16_t *array = (uint16_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (uint16_t)value;
} else if(typecode == NDARRAY_INT16) {
int16_t *array = (int16_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = (int16_t)value;
} else {
mp_float_t *array = (mp_float_t *)ndarray->array->items;
for(size_t i=0; i < len; i++, value += step) array[i] = value;
}
if(args[4].u_obj == mp_const_false) {
return MP_OBJ_FROM_PTR(ndarray);
} else {
mp_obj_t tuple[2];
tuple[0] = ndarray;
tuple[1] = mp_obj_new_float(step);
return mp_obj_new_tuple(2, tuple);
}
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_linspace_obj, 2, numerical_linspace);
void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, size_t *N,
static void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, size_t *N,
size_t *increment, size_t *len, size_t *start_inc) {
if(axis == mp_const_none) { // flatten the array
*m = 1;
@ -108,7 +57,7 @@ void axis_sorter(ndarray_obj_t *ndarray, mp_obj_t axis, size_t *m, size_t *n, si
}
}
mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, size_t ddof) {
static mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, size_t ddof) {
mp_float_t value, sum = 0.0, sq_sum = 0.0;
mp_obj_iter_buf_t iter_buf;
mp_obj_t item, iterable = mp_getiter(oin, &iter_buf);
@ -166,7 +115,7 @@ STATIC mp_obj_t numerical_sum_mean_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis
return MP_OBJ_FROM_PTR(results);
}
mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddof) {
static mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddof) {
size_t m, n, increment, start, start_inc, N, len;
mp_float_t sum, sum_sq;
@ -199,20 +148,32 @@ mp_obj_t numerical_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, size_t ddo
return MP_OBJ_FROM_PTR(results);
}
mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
static mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, uint8_t optype) {
if(MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(oin)) == 0) {
mp_raise_ValueError(translate("attempt to get argmin/argmax of an empty sequence"));
}
size_t idx = 0, best_idx = 0;
mp_obj_iter_buf_t iter_buf;
mp_obj_t iterable = mp_getiter(oin, &iter_buf);
mp_obj_t best_obj = MP_OBJ_NULL;
mp_obj_t item;
mp_uint_t op = MP_BINARY_OP_LESS;
if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = MP_BINARY_OP_MORE;
while ((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
if ((best_obj == MP_OBJ_NULL) || (mp_binary_op(op, item, best_obj) == mp_const_true)) {
best_obj = item;
best_idx = idx;
}
idx++;
uint8_t op = 0; // argmin, min
if((optype == NUMERICAL_ARGMAX) || (optype == NUMERICAL_MAX)) op = 1;
item = mp_iternext(iterable);
mp_obj_t best_obj = item;
mp_float_t value, best_value = mp_obj_get_float(item);
value = best_value;
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
idx++;
value = mp_obj_get_float(item);
if((op == 0) && (value < best_value)) {
best_obj = item;
best_idx = idx;
best_value = value;
} else if((op == 1) && (value > best_value)) {
best_obj = item;
best_idx = idx;
best_value = value;
}
}
if((optype == NUMERICAL_ARGMIN) || (optype == NUMERICAL_ARGMAX)) {
return MP_OBJ_NEW_SMALL_INT(best_idx);
@ -221,7 +182,7 @@ mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, mp_obj_t axis, uint8_t o
}
}
mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) {
static mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype) {
size_t m, n, increment, start, start_inc, N, len;
axis_sorter(ndarray, axis, &m, &n, &N, &increment, &len, &start_inc);
ndarray_obj_t *results;
@ -229,6 +190,9 @@ mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis,
// we could save some RAM by taking NDARRAY_UINT8, if the dimensions
// are smaller than 256, but the code would become more involving
// (we would also need extra flash space)
if(ndarray->array->len == 0) {
mp_raise_ValueError(translate("attempt to get argmin/argmax of an empty sequence"));
}
results = create_new_ndarray(m, n, NDARRAY_UINT16);
} else {
results = create_new_ndarray(m, n, ndarray->array->typecode);
@ -252,6 +216,9 @@ mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis,
}
}
}
if(results->array->len == 1) {
return mp_binary_get_val_array(results->array->typecode, results->array->items, 0);
}
return MP_OBJ_FROM_PTR(results);
}
@ -278,7 +245,7 @@ STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
case NUMERICAL_ARGMIN:
case NUMERICAL_MAX:
case NUMERICAL_ARGMAX:
return numerical_argmin_argmax_iterable(oin, axis, optype);
return numerical_argmin_argmax_iterable(oin, optype);
case NUMERICAL_SUM:
case NUMERICAL_MEAN:
return numerical_sum_mean_std_iterable(oin, optype, 0);
@ -305,43 +272,43 @@ STATIC mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
return mp_const_none;
}
mp_obj_t numerical_min(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_min(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MIN);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_max(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MAX);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_max_obj, 1, numerical_max);
mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_argmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMIN);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_argmax(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_ARGMAX);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmax_obj, 1, numerical_argmax);
mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_sum(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_SUM);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sum_obj, 1, numerical_sum);
mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_mean(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
return numerical_function(n_args, pos_args, kw_args, NUMERICAL_MEAN);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } } ,
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
@ -371,7 +338,7 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
@ -379,7 +346,7 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(2, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_obj_t oin = args[0].u_obj;
int16_t shift = mp_obj_get_int(args[1].u_obj);
@ -453,14 +420,14 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("flip argument must be an ndarray"));
@ -502,7 +469,7 @@ mp_obj_t numerical_flip(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } },
@ -510,7 +477,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("diff argument must be an ndarray"));
@ -572,7 +539,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
static mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
if(!MP_OBJ_IS_TYPE(oin, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("sort argument must be an ndarray"));
}
@ -602,7 +569,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
} else if(mp_obj_get_int(axis) == 0) { // sort along vertical axis
increment = ndarray->n;
start_inc = 1;
end = ndarray->m;
end = ndarray->n;
N = ndarray->m;
} else {
mp_raise_ValueError(translate("axis must be -1, 0, None, or 1"));
@ -611,7 +578,7 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
size_t q, k, p, c;
for(size_t start=0; start < end; start+=start_inc) {
q = N;
q = N;
k = (q >> 1);
if((ndarray->array->typecode == NDARRAY_UINT8) || (ndarray->array->typecode == NDARRAY_INT8)) {
HEAPSORT(uint8_t, ndarray);
@ -629,14 +596,14 @@ mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inplace) {
}
// numpy function
mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0);
}
@ -644,27 +611,27 @@ mp_obj_t numerical_sort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
// method of an ndarray
mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_sort_inplace(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
return numerical_sort_helper(args[0].u_obj, args[1].u_obj, 1);
}
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace);
mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(1, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("argsort argument must be an ndarray"));
}
@ -674,8 +641,6 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
if(args[1].u_obj == mp_const_none) { // flatten the array
m = 1;
n = ndarray->array->len;
ndarray->m = m;
ndarray->n = n;
increment = 1;
start_inc = ndarray->n;
end = ndarray->n;
@ -693,7 +658,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
n = ndarray->n;
increment = n;
start_inc = 1;
end = m;
end = n;
N = m;
} else {
mp_raise_ValueError(translate("axis must be -1, 0, None, or 1"));
@ -730,9 +695,8 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_numerical_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_linspace), (mp_obj_t)&numerical_linspace_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_numerical) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj },
@ -753,6 +717,5 @@ mp_obj_module_t ulab_numerical_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_numerical_globals,
};
#endif
#endif

View file

@ -46,8 +46,8 @@ extern mp_obj_module_t ulab_numerical_module;
#define RUN_SUM(ndarray, type, optype, len, start, increment) do {\
type *array = (type *)(ndarray)->array->items;\
type value;\
for(size_t j=0; j < (len); j++) {\
value = array[(start)+j*(increment)];\
for(size_t k=0; k < (len); k++) {\
value = array[(start)+k*(increment)];\
sum += value;\
}\
} while(0)
@ -55,12 +55,12 @@ extern mp_obj_module_t ulab_numerical_module;
#define RUN_STD(ndarray, type, len, start, increment) do {\
type *array = (type *)(ndarray)->array->items;\
mp_float_t value;\
for(size_t j=0; j < (len); j++) {\
sum += array[(start)+j*(increment)];\
for(size_t k=0; k < (len); k++) {\
sum += array[(start)+k*(increment)];\
}\
sum /= (len);\
for(size_t j=0; j < (len); j++) {\
value = (array[(start)+j*(increment)] - sum);\
for(size_t k=0; k < (len); k++) {\
value = (array[(start)+k*(increment)] - sum);\
sum_sq += value * value;\
}\
} while(0)
@ -79,33 +79,34 @@ extern mp_obj_module_t ulab_numerical_module;
#define HEAPSORT(type, ndarray) do {\
type *array = (type *)(ndarray)->array->items;\
array += start;\
type tmp;\
for (;;) {\
if (k > 0) {\
tmp = array[start+(--k)*increment];\
tmp = array[(--k)*increment];\
} else {\
q--;\
if(q == 0) {\
break;\
}\
tmp = array[start+q*increment];\
array[start+q*increment] = array[start];\
tmp = array[q*increment];\
array[q*increment] = array[0];\
}\
p = k;\
c = k + k + 1;\
while (c < q) {\
if((c + 1 < q) && (array[start+(c+1)*increment] > array[start+c*increment])) {\
if((c + 1 < q) && (array[(c+1)*increment] > array[c*increment])) {\
c++;\
}\
if(array[start+c*increment] > tmp) {\
array[start+p*increment] = array[start+c*increment];\
if(array[c*increment] > tmp) {\
array[p*increment] = array[c*increment];\
p = c;\
c = p + p + 1;\
} else {\
break;\
}\
}\
array[start+p*increment] = tmp;\
array[p*increment] = tmp;\
}\
} while(0)
@ -148,7 +149,6 @@ extern mp_obj_module_t ulab_numerical_module;
}\
} while(0)
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_linspace_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_min_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_max_obj);
MP_DECLARE_CONST_FUN_OBJ_KW(numerical_argmin_obj);

View file

@ -17,7 +17,7 @@
#include "poly.h"
#if ULAB_POLY_MODULE
bool object_is_nditerable(mp_obj_t o_in) {
static bool object_is_nditerable(mp_obj_t o_in) {
if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_tuple) ||
MP_OBJ_IS_TYPE(o_in, &mp_type_list) ||
@ -27,16 +27,7 @@ bool object_is_nditerable(mp_obj_t o_in) {
return false;
}
size_t get_nditerable_len(mp_obj_t o_in) {
if(MP_OBJ_IS_TYPE(o_in, &ulab_ndarray_type)) {
ndarray_obj_t *in = MP_OBJ_TO_PTR(o_in);
return in->array->len;
} else {
return (size_t)mp_obj_get_int(mp_obj_len_maybe(o_in));
}
}
mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
static mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
// TODO: return immediately, if o_p is not an iterable
// TODO: there is a bug here: matrices won't work,
// because there is a single iteration loop
@ -85,7 +76,7 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
MP_DEFINE_CONST_FUN_OBJ_2(poly_polyval_obj, poly_polyval);
mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
static mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
if((n_args != 2) && (n_args != 3)) {
mp_raise_ValueError(translate("number of arguments must be 2, or 3"));
}
@ -111,9 +102,12 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
}
y = m_new(mp_float_t, leny);
fill_array_iterable(y, args[0]);
} else if(n_args == 3) {
} else /* n_args == 3 */ {
if(!object_is_nditerable(args[1])) {
mp_raise_ValueError(translate("input data must be an iterable"));
}
lenx = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
leny = (uint16_t)mp_obj_get_int(mp_obj_len_maybe(args[1]));
if(lenx != leny) {
mp_raise_ValueError(translate("input vectors must be of equal length"));
}
@ -197,7 +191,6 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
#if !CIRCUITPY
STATIC const mp_rom_map_elem_t ulab_poly_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_poly) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj },
@ -210,6 +203,5 @@ mp_obj_module_t ulab_poly_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_poly_globals,
};
#endif
#endif

View file

@ -21,6 +21,7 @@
#include "ulab.h"
#include "ndarray.h"
#include "ndarray_properties.h"
#include "create.h"
#include "linalg.h"
#include "vectorise.h"
#include "poly.h"
@ -29,22 +30,29 @@
#include "numerical.h"
#include "extras.h"
STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.34.0");
STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, "0.41.4");
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_flatten_obj, 1, ndarray_flatten);
STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) },
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ndarray_reshape_obj) },
{ MP_ROM_QSTR(MP_QSTR_transpose), MP_ROM_PTR(&ndarray_transpose_obj) },
{ MP_ROM_QSTR(MP_QSTR_flatten), MP_ROM_PTR(&ndarray_flatten_obj) },
{ MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) },
{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) },
{ MP_ROM_QSTR(MP_QSTR_itemsize), MP_ROM_PTR(&ndarray_itemsize_obj) },
// { MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
#if CIRCUITPY
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
#endif
};
STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
const mp_obj_type_t ulab_ndarray_type = {
{ &mp_type_type },
#if defined(MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) && defined(MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)
.flags = MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST,
#endif
.name = MP_QSTR_ndarray,
.print = ndarray_print,
.make_new = ndarray_make_new,
@ -56,11 +64,14 @@ const mp_obj_type_t ulab_ndarray_type = {
.locals_dict = (mp_obj_dict_t*)&ulab_ndarray_locals_dict,
};
#if !CIRCUITPY
STATIC const mp_map_elem_t ulab_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) },
{ MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), (mp_obj_t)&ulab_ndarray_type },
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&create_zeros_obj },
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&create_ones_obj },
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&create_eye_obj },
{ MP_ROM_QSTR(MP_QSTR_linspace), (mp_obj_t)&create_linspace_obj },
#if ULAB_LINALG_MODULE
{ MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) },
#endif
@ -101,4 +112,3 @@ mp_obj_module_t ulab_user_cmodule = {
};
MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED);
#endif

View file

@ -12,6 +12,9 @@
#ifndef __ULAB__
#define __ULAB__
// create
#define ULAB_CREATE_MODULE (1)
// vectorise (all functions) takes approx. 3 kB of flash space
#define ULAB_VECTORISE_MODULE (1)
@ -31,6 +34,6 @@
#define ULAB_FILTER_MODULE (1)
// user-defined modules
#define ULAB_EXTRAS_MODULE (0)
#define ULAB_EXTRAS_MODULE (1)
#endif

View file

@ -23,7 +23,7 @@
#endif
#if ULAB_VECTORISE_MODULE
mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) {
static mp_obj_t vectorise_generic_vector(mp_obj_t o_in, mp_float_t (*f)(mp_float_t)) {
// Return a single value, if o_in is not iterable
if(mp_obj_is_float(o_in) || MP_OBJ_IS_INT(o_in)) {
return mp_obj_new_float(f(mp_obj_get_float(o_in)));
@ -135,11 +135,90 @@ MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tan_obj, vectorise_tan);
MATH_FUN_1(tanh, tanh);
MP_DEFINE_CONST_FUN_OBJ_1(vectorise_tanh_obj, vectorise_tanh);
#if !CIRCUITPY
static mp_obj_t vectorise_around(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
{ MP_QSTR_decimals, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0 } }
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
if(!MP_OBJ_IS_TYPE(args[0].u_obj, &ulab_ndarray_type)) {
mp_raise_TypeError(translate("first argument must be an ndarray"));
}
int8_t n = args[1].u_int;
mp_float_t mul = MICROPY_FLOAT_C_FUN(pow)(10.0, n);
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
ndarray_obj_t *result = create_new_ndarray(ndarray->m, ndarray->n, NDARRAY_FLOAT);
mp_float_t *array = (mp_float_t *)result->array->items;
for(size_t i=0; i < ndarray->array->len; i++) {
mp_float_t f = ndarray_get_float_value(ndarray->array->items, ndarray->array->typecode, i);
*array++ = MICROPY_FLOAT_C_FUN(round)(f * mul) / mul;
}
return MP_OBJ_FROM_PTR(result);
}
MP_DEFINE_CONST_FUN_OBJ_KW(vectorise_around_obj, 1, vectorise_around);
static mp_obj_t vectorise_arctan2(mp_obj_t x, mp_obj_t y) {
// the function is implemented for scalars and ndarrays only, with partial
// broadcasting: arguments must be either scalars, or ndarrays of equal size/shape
if(!(MP_OBJ_IS_INT(x) || mp_obj_is_float(x) || MP_OBJ_IS_TYPE(x, &ulab_ndarray_type)) &&
!(MP_OBJ_IS_INT(y) || mp_obj_is_float(y) || MP_OBJ_IS_TYPE(y, &ulab_ndarray_type))) {
mp_raise_TypeError(translate("arctan2 is implemented for scalars and ndarrays only"));
}
ndarray_obj_t *ndarray_x, *ndarray_y;
if(MP_OBJ_IS_INT(x) || mp_obj_is_float(x)) {
ndarray_x = create_new_ndarray(1, 1, NDARRAY_FLOAT);
mp_float_t *array_x = (mp_float_t *)ndarray_x->array->items;
*array_x = mp_obj_get_float(x);
} else {
ndarray_x = MP_OBJ_TO_PTR(x);
}
if(MP_OBJ_IS_INT(y) || mp_obj_is_float(y)) {
ndarray_y = create_new_ndarray(1, 1, NDARRAY_FLOAT);
mp_float_t *array_y = (mp_float_t *)ndarray_y->array->items;
*array_y = mp_obj_get_float(y);
} else {
ndarray_y = MP_OBJ_TO_PTR(y);
}
// check, whether partial broadcasting is possible here
if((ndarray_x->m != ndarray_y->m) || (ndarray_x->n != ndarray_y->n)) {
if((ndarray_x->array->len != 1) && (ndarray_y->array->len != 1)) {
mp_raise_ValueError(translate("operands could not be broadcast together"));
}
}
size_t xinc = 0, yinc = 0;
size_t m = MAX(ndarray_x->m, ndarray_y->m);
size_t n = MAX(ndarray_x->n, ndarray_y->n);
size_t len = MAX(ndarray_x->array->len, ndarray_y->array->len);
if(ndarray_x->array->len != 1) {
xinc = 1;
}
if(ndarray_y->array->len != 1) {
yinc = 1;
}
size_t posx = 0, posy = 0;
ndarray_obj_t *result = create_new_ndarray(m, n, NDARRAY_FLOAT);
mp_float_t *array_r = (mp_float_t *)result->array->items;
for(size_t i=0; i < len; i++) {
mp_float_t value_x = ndarray_get_float_value(ndarray_x->array->items, ndarray_x->array->typecode, posx);
mp_float_t value_y = ndarray_get_float_value(ndarray_y->array->items, ndarray_y->array->typecode, posy);
*array_r++ = MICROPY_FLOAT_C_FUN(atan2)(value_x, value_y);
posx += xinc;
posy += yinc;
}
return MP_OBJ_FROM_PTR(result);
}
MP_DEFINE_CONST_FUN_OBJ_2(vectorise_arctan2_obj, vectorise_arctan2);
STATIC const mp_rom_map_elem_t ulab_vectorise_globals_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_vector) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_arctan2), (mp_obj_t)&vectorise_arctan2_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_around), (mp_obj_t)&vectorise_around_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj },
@ -169,6 +248,5 @@ mp_obj_module_t ulab_vectorise_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t*)&mp_module_ulab_vectorise_globals,
};
#endif
#endif

View file

@ -27,7 +27,7 @@ mp_obj_module_t ulab_vectorise_module;
} while(0)
#define MATH_FUN_1(py_name, c_name) \
mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \
static mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \
return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
}

View file

@ -18,11 +18,11 @@
# -- Project information -----------------------------------------------------
project = 'micropython-ulab'
copyright = '2019, Zoltán Vörös'
copyright = '2019-2020, Zoltán Vörös'
author = 'Zoltán Vörös'
# The full version, including alpha/beta/rc tags
release = '0.32'
release = '0.41.2'
# -- General configuration ---------------------------------------------------

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,80 @@
Sat, 18 Apr 2020
version 0.41.4
fix compilation error on hardware ports
Tue, 14 Apr 2020
version 0.41.3
fix indexing error in dot function
Thu, 9 Apr 2020
version 0.41.2
fix transpose function
Tue, 7 Apr 2020
version 0.41.2
fix discrepancy in argmin/argmax behaviour
Tue, 7 Apr 2020
version 0.41.1
fix error in argsort
Sat, 4 Apr 2020
version 0.41.0
implemented == and != binary operators
Fri, 3 Apr 2020
version 0.40.0
added trace to linalg
Thu, 2 Apr 2020
version 0.39.0
added the ** operator, and operand swapping in binary operators
Thu, 2 Apr 2020
version 0.38.1
added fast option, when initialising from ndarray_properties
Thu, 12 Mar 2020
version 0.38.0
added initialisation from ndarray, and the around function
Tue, 10 Mar 2020
version 0.37.0
added Cholesky decomposition to linalg.c
Thu, 27 Feb 2020
version 0.36.0
moved zeros, ones, eye and linspace into separate module (they are still bound at the top level)
Thu, 27 Feb 2020
version 0.35.0
Move zeros, ones back into top level ulab module
Tue, 18 Feb 2020

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,2 +1,2 @@
from ulab import linalg
print(linalg.eye(3))
import ulab
print(ulab.eye(3))

62
tests/argminmax.py Normal file
View file

@ -0,0 +1,62 @@
import ulab
# Adapted from https://docs.python.org/3.8/library/itertools.html#itertools.permutations
def permutations(iterable, r=None):
# permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
# permutations(range(3)) --> 012 021 102 120 201 210
pool = tuple(iterable)
n = len(pool)
r = n if r is None else r
if r > n:
return
indices = list(range(n))
cycles = list(range(n, n-r, -1))
yield tuple(pool[i] for i in indices[:r])
while n:
for i in reversed(range(r)):
cycles[i] -= 1
if cycles[i] == 0:
indices[i:] = indices[i+1:] + indices[i:i+1]
cycles[i] = n - i
else:
j = cycles[i]
indices[i], indices[-j] = indices[-j], indices[i]
yield tuple(pool[i] for i in indices[:r])
break
else:
return
# Combinations expected to throw
try:
print(ulab.numerical.argmin([]))
except ValueError:
print("ValueError")
try:
print(ulab.numerical.argmax([]))
except ValueError:
print("ValueError")
# Combinations expected to succeed
print(ulab.numerical.argmin([1]))
print(ulab.numerical.argmax([1]))
print(ulab.numerical.argmin(ulab.array([1])))
print(ulab.numerical.argmax(ulab.array([1])))
print()
print("max tests")
for p in permutations((100,200,300)):
m1 = ulab.numerical.argmax(p)
m2 = ulab.numerical.argmax(ulab.array(p))
print(p, m1, m2)
if m1 != m2 or p[m1] != max(p):
print("FAIL", p, m1, m2, max(p))
print()
print("min tests")
for p in permutations((100,200,300)):
m1 = ulab.numerical.argmin(p)
m2 = ulab.numerical.argmin(ulab.array(p))
print(p, m1, m2)
if m1 != m2 or p[m1] != min(p):
print("FAIL", p, m1, m2, min(p))

22
tests/argminmax.py.exp Normal file
View file

@ -0,0 +1,22 @@
ValueError
ValueError
0
0
0
0
max tests
(100, 200, 300) 2 2
(100, 300, 200) 1 1
(200, 100, 300) 2 2
(200, 300, 100) 1 1
(300, 100, 200) 0 0
(300, 200, 100) 0 0
min tests
(100, 200, 300) 0 0
(100, 300, 200) 0 0
(200, 100, 300) 1 1
(200, 300, 100) 2 2
(300, 100, 200) 1 1
(300, 200, 100) 2 2

17
tests/cholesky.py Normal file
View file

@ -0,0 +1,17 @@
import ulab
from ulab import linalg
a = ulab.array([[1, 2], [2, 5]])
print(linalg.cholesky(a))
b = a = ulab.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]])
print(linalg.cholesky(b))
c = ulab.array([[18, 22, 54, 42], [22, 70, 86, 62], [54, 86, 174, 134], [42, 62, 134, 106]])
print(linalg.cholesky(c))
# this throw a ValueError exception
d = ulab.array([[25, 15, -5], [15, 18, 0], [-5, 0, 1]])

9
tests/cholesky.py.exp Normal file
View file

@ -0,0 +1,9 @@
array([[1.0, 0.0],
[2.0, 1.0]], dtype=float)
array([[5.0, 0.0, 0.0],
[3.0, 3.0, 0.0],
[-1.0, 1.0, 3.0]], dtype=float)
array([[4.242640687119285, 0.0, 0.0, 0.0],
[5.185449728701349, 6.565905201197403, 0.0, 0.0],
[12.72792206135786, 3.046038495400855, 1.649742247909068, 0.0],
[9.899494936611665, 1.624553864213789, 1.849711005231386, 1.392621247645583]], dtype=float)

13
tests/constructors.py Normal file
View file

@ -0,0 +1,13 @@
from ulab import linalg
import ulab
print(ulab.ones(3))
print(ulab.ones((2,3)))
print(ulab.zeros(3))
print(ulab.zeros((2,3)))
print(ulab.eye(3))
print(ulab.ones(1, dtype=ulab.int8))
print(ulab.ones(2, dtype=ulab.uint8))
print(ulab.ones(3, dtype=ulab.int16))
print(ulab.ones(4, dtype=ulab.uint16))
print(ulab.ones(5, dtype=ulab.float))
print(ulab.linspace(0, 1, 9))

15
tests/constructors.py.exp Normal file
View file

@ -0,0 +1,15 @@
array([1.0, 1.0, 1.0], dtype=float)
array([[1.0, 1.0, 1.0],
[1.0, 1.0, 1.0]], dtype=float)
array([0.0, 0.0, 0.0], dtype=float)
array([[0.0, 0.0, 0.0],
[0.0, 0.0, 0.0]], dtype=float)
array([[1.0, 0.0, 0.0],
[0.0, 1.0, 0.0],
[0.0, 0.0, 1.0]], dtype=float)
array([1], dtype=int8)
array([1, 1], dtype=uint8)
array([1, 1, 1], dtype=int16)
array([1, 1, 1, 1], dtype=uint16)
array([1.0, 1.0, 1.0, 1.0, 1.0], dtype=float)
array([0.0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1.0], dtype=float)

17
tests/linalg.py Normal file
View file

@ -0,0 +1,17 @@
import ulab
from ulab import linalg
a = ulab.array([[1, 2], [3, 4]])
print(linalg.inv(a))
b = ulab.array([[1, 2, 3], [4, 5, 6], [7, 8, 7]])
print(linalg.inv(b))
c = ulab.array([[1, 2, 0, 0], [0, 6, 7, 0], [0, 0, 8, 9], [0, 0, 15, 13]])
print(linalg.inv(c))
print(linalg.det(a))
print(linalg.det(b))
print(linalg.det(c))

12
tests/linalg.py.exp Normal file
View file

@ -0,0 +1,12 @@
array([[-2.0, 1.0],
[1.5, -0.5]], dtype=float)
array([[-2.166666666666667, 1.666666666666667, -0.5],
[2.333333333333333, -2.333333333333333, 1.0],
[-0.5, 1.0, -0.5]], dtype=float)
array([[1.0, -0.3333333333333333, -0.9784946236559136, 0.6774193548387095],
[0.0, 0.1666666666666667, 0.489247311827957, -0.3387096774193548],
[0.0, 0.0, -0.4193548387096775, 0.2903225806451613],
[-0.0, -0.0, 0.4838709677419355, -0.2580645161290323]], dtype=float)
-2.0
6.0
-186.0

20
tests/operators.py Normal file
View file

@ -0,0 +1,20 @@
import ulab
a = ulab.ones(3)
print(a+a)
print(a-a)
print(a*a)
print(a/a)
print(a+2)
print(a-2)
print(a*2)
print(a/2)
print(a<1)
print(a<2)
print(a<=0)
print(a<=1)
print(a>1)
print(a>2)
print(a>=0)
print(a>=1)
#print(a==0) # These print just true or false. Is it right? is it a micropython limitation?
#print(a==1)

16
tests/operators.py.exp Normal file
View file

@ -0,0 +1,16 @@
array([2.0, 2.0, 2.0], dtype=float)
array([0.0, 0.0, 0.0], dtype=float)
array([1.0, 1.0, 1.0], dtype=float)
array([1.0, 1.0, 1.0], dtype=float)
array([3.0, 3.0, 3.0], dtype=float)
array([-1.0, -1.0, -1.0], dtype=float)
array([2.0, 2.0, 2.0], dtype=float)
array([0.5, 0.5, 0.5], dtype=float)
[False, False, False]
[True, True, True]
[False, False, False]
[True, True, True]
[False, False, False]
[False, False, False]
[True, True, True]
[True, True, True]

27
tests/poly.py Normal file
View file

@ -0,0 +1,27 @@
import ulab
from ulab import poly
from ulab import vector
# polynom evaluation
x = ulab.linspace(0, 10, num=9)
p = [1, 2, 3]
y = poly.polyval(p, x)
print(y)
# linear fit
x = ulab.linspace(-5, 5, num=11)
y = x + vector.sin(x)
p = poly.polyfit(x, y, 1)
print(p)
# quadratic fit
x = ulab.linspace(-5, 5, num=11)
y = x*x + vector.sin(x)*3.0
p = poly.polyfit(x, y, 2)
print(p)
# cubic fit
x = ulab.linspace(-5, 5, num=11)
y = x*x*x + vector.sin(x)*10.0
p = poly.polyfit(x, y, 3)
print(p)

4
tests/poly.py.exp Normal file
View file

@ -0,0 +1,4 @@
array([3.0, 7.0625, 14.25, 24.5625, 38.0, 54.56250000000001, 74.25000000000001, 97.06250000000001, 123.0], dtype=float)
array([0.9138471728743898, -8.074349270001139e-17], dtype=float)
array([1.0, -0.2584584813768293, 3.552713678800501e-15], dtype=float)
array([0.766798803225857, 0.0, 3.289453031323674, 0.0], dtype=float)

25
tests/slicing.py Normal file
View file

@ -0,0 +1,25 @@
try:
import ulab as np
except:
import numpy as np
for num in range(1,4):
for start in range(-num, num+1):
for end in range(-num, num+1):
for stride in (-3, -2, -1, 1, 2, 3):
l = list(range(num))
a = np.array(l, dtype=np.int8)
sl = l[start:end:stride]
ll = len(sl)
try:
sa = list(a[start:end:stride])
la = len(sa)
except IndexError as e:
sa = str(e)
la = -1
print("%2d [% d:% d:% d] %-24r %-24r%s" % (
num, start, end, stride, sl, sa, " ***" if sa != sl else ""))
a[start:end:stride] = np.ones(len(sl)) * -1
print("%2d [% d:% d:% d] %r" % (
num, start, end, stride, list(a)))

996
tests/slicing.py.exp Normal file
View file

@ -0,0 +1,996 @@
1 [-1:-1:-3] [] []
1 [-1:-1:-3] [0]
1 [-1:-1:-2] [] []
1 [-1:-1:-2] [0]
1 [-1:-1:-1] [] []
1 [-1:-1:-1] [0]
1 [-1:-1: 1] [] []
1 [-1:-1: 1] [0]
1 [-1:-1: 2] [] []
1 [-1:-1: 2] [0]
1 [-1:-1: 3] [] []
1 [-1:-1: 3] [0]
1 [-1: 0:-3] [] []
1 [-1: 0:-3] [0]
1 [-1: 0:-2] [] []
1 [-1: 0:-2] [0]
1 [-1: 0:-1] [] []
1 [-1: 0:-1] [0]
1 [-1: 0: 1] [] []
1 [-1: 0: 1] [0]
1 [-1: 0: 2] [] []
1 [-1: 0: 2] [0]
1 [-1: 0: 3] [] []
1 [-1: 0: 3] [0]
1 [-1: 1:-3] [] []
1 [-1: 1:-3] [0]
1 [-1: 1:-2] [] []
1 [-1: 1:-2] [0]
1 [-1: 1:-1] [] []
1 [-1: 1:-1] [0]
1 [-1: 1: 1] [0] [0]
1 [-1: 1: 1] [-1]
1 [-1: 1: 2] [0] [0]
1 [-1: 1: 2] [-1]
1 [-1: 1: 3] [0] [0]
1 [-1: 1: 3] [-1]
1 [ 0:-1:-3] [] []
1 [ 0:-1:-3] [0]
1 [ 0:-1:-2] [] []
1 [ 0:-1:-2] [0]
1 [ 0:-1:-1] [] []
1 [ 0:-1:-1] [0]
1 [ 0:-1: 1] [] []
1 [ 0:-1: 1] [0]
1 [ 0:-1: 2] [] []
1 [ 0:-1: 2] [0]
1 [ 0:-1: 3] [] []
1 [ 0:-1: 3] [0]
1 [ 0: 0:-3] [] []
1 [ 0: 0:-3] [0]
1 [ 0: 0:-2] [] []
1 [ 0: 0:-2] [0]
1 [ 0: 0:-1] [] []
1 [ 0: 0:-1] [0]
1 [ 0: 0: 1] [] []
1 [ 0: 0: 1] [0]
1 [ 0: 0: 2] [] []
1 [ 0: 0: 2] [0]
1 [ 0: 0: 3] [] []
1 [ 0: 0: 3] [0]
1 [ 0: 1:-3] [] []
1 [ 0: 1:-3] [0]
1 [ 0: 1:-2] [] []
1 [ 0: 1:-2] [0]
1 [ 0: 1:-1] [] []
1 [ 0: 1:-1] [0]
1 [ 0: 1: 1] [0] [0]
1 [ 0: 1: 1] [-1]
1 [ 0: 1: 2] [0] [0]
1 [ 0: 1: 2] [-1]
1 [ 0: 1: 3] [0] [0]
1 [ 0: 1: 3] [-1]
1 [ 1:-1:-3] [] []
1 [ 1:-1:-3] [0]
1 [ 1:-1:-2] [] []
1 [ 1:-1:-2] [0]
1 [ 1:-1:-1] [] []
1 [ 1:-1:-1] [0]
1 [ 1:-1: 1] [] []
1 [ 1:-1: 1] [0]
1 [ 1:-1: 2] [] []
1 [ 1:-1: 2] [0]
1 [ 1:-1: 3] [] []
1 [ 1:-1: 3] [0]
1 [ 1: 0:-3] [] []
1 [ 1: 0:-3] [0]
1 [ 1: 0:-2] [] []
1 [ 1: 0:-2] [0]
1 [ 1: 0:-1] [] []
1 [ 1: 0:-1] [0]
1 [ 1: 0: 1] [] []
1 [ 1: 0: 1] [0]
1 [ 1: 0: 2] [] []
1 [ 1: 0: 2] [0]
1 [ 1: 0: 3] [] []
1 [ 1: 0: 3] [0]
1 [ 1: 1:-3] [] []
1 [ 1: 1:-3] [0]
1 [ 1: 1:-2] [] []
1 [ 1: 1:-2] [0]
1 [ 1: 1:-1] [] []
1 [ 1: 1:-1] [0]
1 [ 1: 1: 1] [] []
1 [ 1: 1: 1] [0]
1 [ 1: 1: 2] [] []
1 [ 1: 1: 2] [0]
1 [ 1: 1: 3] [] []
1 [ 1: 1: 3] [0]
2 [-2:-2:-3] [] []
2 [-2:-2:-3] [0, 1]
2 [-2:-2:-2] [] []
2 [-2:-2:-2] [0, 1]
2 [-2:-2:-1] [] []
2 [-2:-2:-1] [0, 1]
2 [-2:-2: 1] [] []
2 [-2:-2: 1] [0, 1]
2 [-2:-2: 2] [] []
2 [-2:-2: 2] [0, 1]
2 [-2:-2: 3] [] []
2 [-2:-2: 3] [0, 1]
2 [-2:-1:-3] [] []
2 [-2:-1:-3] [0, 1]
2 [-2:-1:-2] [] []
2 [-2:-1:-2] [0, 1]
2 [-2:-1:-1] [] []
2 [-2:-1:-1] [0, 1]
2 [-2:-1: 1] [0] [0]
2 [-2:-1: 1] [-1, 1]
2 [-2:-1: 2] [0] [0]
2 [-2:-1: 2] [-1, 1]
2 [-2:-1: 3] [0] [0]
2 [-2:-1: 3] [-1, 1]
2 [-2: 0:-3] [] []
2 [-2: 0:-3] [0, 1]
2 [-2: 0:-2] [] []
2 [-2: 0:-2] [0, 1]
2 [-2: 0:-1] [] []
2 [-2: 0:-1] [0, 1]
2 [-2: 0: 1] [] []
2 [-2: 0: 1] [0, 1]
2 [-2: 0: 2] [] []
2 [-2: 0: 2] [0, 1]
2 [-2: 0: 3] [] []
2 [-2: 0: 3] [0, 1]
2 [-2: 1:-3] [] []
2 [-2: 1:-3] [0, 1]
2 [-2: 1:-2] [] []
2 [-2: 1:-2] [0, 1]
2 [-2: 1:-1] [] []
2 [-2: 1:-1] [0, 1]
2 [-2: 1: 1] [0] [0]
2 [-2: 1: 1] [-1, 1]
2 [-2: 1: 2] [0] [0]
2 [-2: 1: 2] [-1, 1]
2 [-2: 1: 3] [0] [0]
2 [-2: 1: 3] [-1, 1]
2 [-2: 2:-3] [] []
2 [-2: 2:-3] [0, 1]
2 [-2: 2:-2] [] []
2 [-2: 2:-2] [0, 1]
2 [-2: 2:-1] [] []
2 [-2: 2:-1] [0, 1]
2 [-2: 2: 1] [0, 1] [0, 1]
2 [-2: 2: 1] [-1, -1]
2 [-2: 2: 2] [0] [0]
2 [-2: 2: 2] [-1, 1]
2 [-2: 2: 3] [0] [0]
2 [-2: 2: 3] [-1, 1]
2 [-1:-2:-3] [1] [1]
2 [-1:-2:-3] [0, -1]
2 [-1:-2:-2] [1] [1]
2 [-1:-2:-2] [0, -1]
2 [-1:-2:-1] [1] [1]
2 [-1:-2:-1] [0, -1]
2 [-1:-2: 1] [] []
2 [-1:-2: 1] [0, 1]
2 [-1:-2: 2] [] []
2 [-1:-2: 2] [0, 1]
2 [-1:-2: 3] [] []
2 [-1:-2: 3] [0, 1]
2 [-1:-1:-3] [] []
2 [-1:-1:-3] [0, 1]
2 [-1:-1:-2] [] []
2 [-1:-1:-2] [0, 1]
2 [-1:-1:-1] [] []
2 [-1:-1:-1] [0, 1]
2 [-1:-1: 1] [] []
2 [-1:-1: 1] [0, 1]
2 [-1:-1: 2] [] []
2 [-1:-1: 2] [0, 1]
2 [-1:-1: 3] [] []
2 [-1:-1: 3] [0, 1]
2 [-1: 0:-3] [1] [1]
2 [-1: 0:-3] [0, -1]
2 [-1: 0:-2] [1] [1]
2 [-1: 0:-2] [0, -1]
2 [-1: 0:-1] [1] [1]
2 [-1: 0:-1] [0, -1]
2 [-1: 0: 1] [] []
2 [-1: 0: 1] [0, 1]
2 [-1: 0: 2] [] []
2 [-1: 0: 2] [0, 1]
2 [-1: 0: 3] [] []
2 [-1: 0: 3] [0, 1]
2 [-1: 1:-3] [] []
2 [-1: 1:-3] [0, 1]
2 [-1: 1:-2] [] []
2 [-1: 1:-2] [0, 1]
2 [-1: 1:-1] [] []
2 [-1: 1:-1] [0, 1]
2 [-1: 1: 1] [] []
2 [-1: 1: 1] [0, 1]
2 [-1: 1: 2] [] []
2 [-1: 1: 2] [0, 1]
2 [-1: 1: 3] [] []
2 [-1: 1: 3] [0, 1]
2 [-1: 2:-3] [] []
2 [-1: 2:-3] [0, 1]
2 [-1: 2:-2] [] []
2 [-1: 2:-2] [0, 1]
2 [-1: 2:-1] [] []
2 [-1: 2:-1] [0, 1]
2 [-1: 2: 1] [1] [1]
2 [-1: 2: 1] [0, -1]
2 [-1: 2: 2] [1] [1]
2 [-1: 2: 2] [0, -1]
2 [-1: 2: 3] [1] [1]
2 [-1: 2: 3] [0, -1]
2 [ 0:-2:-3] [] []
2 [ 0:-2:-3] [0, 1]
2 [ 0:-2:-2] [] []
2 [ 0:-2:-2] [0, 1]
2 [ 0:-2:-1] [] []
2 [ 0:-2:-1] [0, 1]
2 [ 0:-2: 1] [] []
2 [ 0:-2: 1] [0, 1]
2 [ 0:-2: 2] [] []
2 [ 0:-2: 2] [0, 1]
2 [ 0:-2: 3] [] []
2 [ 0:-2: 3] [0, 1]
2 [ 0:-1:-3] [] []
2 [ 0:-1:-3] [0, 1]
2 [ 0:-1:-2] [] []
2 [ 0:-1:-2] [0, 1]
2 [ 0:-1:-1] [] []
2 [ 0:-1:-1] [0, 1]
2 [ 0:-1: 1] [0] [0]
2 [ 0:-1: 1] [-1, 1]
2 [ 0:-1: 2] [0] [0]
2 [ 0:-1: 2] [-1, 1]
2 [ 0:-1: 3] [0] [0]
2 [ 0:-1: 3] [-1, 1]
2 [ 0: 0:-3] [] []
2 [ 0: 0:-3] [0, 1]
2 [ 0: 0:-2] [] []
2 [ 0: 0:-2] [0, 1]
2 [ 0: 0:-1] [] []
2 [ 0: 0:-1] [0, 1]
2 [ 0: 0: 1] [] []
2 [ 0: 0: 1] [0, 1]
2 [ 0: 0: 2] [] []
2 [ 0: 0: 2] [0, 1]
2 [ 0: 0: 3] [] []
2 [ 0: 0: 3] [0, 1]
2 [ 0: 1:-3] [] []
2 [ 0: 1:-3] [0, 1]
2 [ 0: 1:-2] [] []
2 [ 0: 1:-2] [0, 1]
2 [ 0: 1:-1] [] []
2 [ 0: 1:-1] [0, 1]
2 [ 0: 1: 1] [0] [0]
2 [ 0: 1: 1] [-1, 1]
2 [ 0: 1: 2] [0] [0]
2 [ 0: 1: 2] [-1, 1]
2 [ 0: 1: 3] [0] [0]
2 [ 0: 1: 3] [-1, 1]
2 [ 0: 2:-3] [] []
2 [ 0: 2:-3] [0, 1]
2 [ 0: 2:-2] [] []
2 [ 0: 2:-2] [0, 1]
2 [ 0: 2:-1] [] []
2 [ 0: 2:-1] [0, 1]
2 [ 0: 2: 1] [0, 1] [0, 1]
2 [ 0: 2: 1] [-1, -1]
2 [ 0: 2: 2] [0] [0]
2 [ 0: 2: 2] [-1, 1]
2 [ 0: 2: 3] [0] [0]
2 [ 0: 2: 3] [-1, 1]
2 [ 1:-2:-3] [1] [1]
2 [ 1:-2:-3] [0, -1]
2 [ 1:-2:-2] [1] [1]
2 [ 1:-2:-2] [0, -1]
2 [ 1:-2:-1] [1] [1]
2 [ 1:-2:-1] [0, -1]
2 [ 1:-2: 1] [] []
2 [ 1:-2: 1] [0, 1]
2 [ 1:-2: 2] [] []
2 [ 1:-2: 2] [0, 1]
2 [ 1:-2: 3] [] []
2 [ 1:-2: 3] [0, 1]
2 [ 1:-1:-3] [] []
2 [ 1:-1:-3] [0, 1]
2 [ 1:-1:-2] [] []
2 [ 1:-1:-2] [0, 1]
2 [ 1:-1:-1] [] []
2 [ 1:-1:-1] [0, 1]
2 [ 1:-1: 1] [] []
2 [ 1:-1: 1] [0, 1]
2 [ 1:-1: 2] [] []
2 [ 1:-1: 2] [0, 1]
2 [ 1:-1: 3] [] []
2 [ 1:-1: 3] [0, 1]
2 [ 1: 0:-3] [1] [1]
2 [ 1: 0:-3] [0, -1]
2 [ 1: 0:-2] [1] [1]
2 [ 1: 0:-2] [0, -1]
2 [ 1: 0:-1] [1] [1]
2 [ 1: 0:-1] [0, -1]
2 [ 1: 0: 1] [] []
2 [ 1: 0: 1] [0, 1]
2 [ 1: 0: 2] [] []
2 [ 1: 0: 2] [0, 1]
2 [ 1: 0: 3] [] []
2 [ 1: 0: 3] [0, 1]
2 [ 1: 1:-3] [] []
2 [ 1: 1:-3] [0, 1]
2 [ 1: 1:-2] [] []
2 [ 1: 1:-2] [0, 1]
2 [ 1: 1:-1] [] []
2 [ 1: 1:-1] [0, 1]
2 [ 1: 1: 1] [] []
2 [ 1: 1: 1] [0, 1]
2 [ 1: 1: 2] [] []
2 [ 1: 1: 2] [0, 1]
2 [ 1: 1: 3] [] []
2 [ 1: 1: 3] [0, 1]
2 [ 1: 2:-3] [] []
2 [ 1: 2:-3] [0, 1]
2 [ 1: 2:-2] [] []
2 [ 1: 2:-2] [0, 1]
2 [ 1: 2:-1] [] []
2 [ 1: 2:-1] [0, 1]
2 [ 1: 2: 1] [1] [1]
2 [ 1: 2: 1] [0, -1]
2 [ 1: 2: 2] [1] [1]
2 [ 1: 2: 2] [0, -1]
2 [ 1: 2: 3] [1] [1]
2 [ 1: 2: 3] [0, -1]
2 [ 2:-2:-3] [1] [1]
2 [ 2:-2:-3] [0, -1]
2 [ 2:-2:-2] [1] [1]
2 [ 2:-2:-2] [0, -1]
2 [ 2:-2:-1] [1] [1]
2 [ 2:-2:-1] [0, -1]
2 [ 2:-2: 1] [] []
2 [ 2:-2: 1] [0, 1]
2 [ 2:-2: 2] [] []
2 [ 2:-2: 2] [0, 1]
2 [ 2:-2: 3] [] []
2 [ 2:-2: 3] [0, 1]
2 [ 2:-1:-3] [] []
2 [ 2:-1:-3] [0, 1]
2 [ 2:-1:-2] [] []
2 [ 2:-1:-2] [0, 1]
2 [ 2:-1:-1] [] []
2 [ 2:-1:-1] [0, 1]
2 [ 2:-1: 1] [] []
2 [ 2:-1: 1] [0, 1]
2 [ 2:-1: 2] [] []
2 [ 2:-1: 2] [0, 1]
2 [ 2:-1: 3] [] []
2 [ 2:-1: 3] [0, 1]
2 [ 2: 0:-3] [1] [1]
2 [ 2: 0:-3] [0, -1]
2 [ 2: 0:-2] [1] [1]
2 [ 2: 0:-2] [0, -1]
2 [ 2: 0:-1] [1] [1]
2 [ 2: 0:-1] [0, -1]
2 [ 2: 0: 1] [] []
2 [ 2: 0: 1] [0, 1]
2 [ 2: 0: 2] [] []
2 [ 2: 0: 2] [0, 1]
2 [ 2: 0: 3] [] []
2 [ 2: 0: 3] [0, 1]
2 [ 2: 1:-3] [] []
2 [ 2: 1:-3] [0, 1]
2 [ 2: 1:-2] [] []
2 [ 2: 1:-2] [0, 1]
2 [ 2: 1:-1] [] []
2 [ 2: 1:-1] [0, 1]
2 [ 2: 1: 1] [] []
2 [ 2: 1: 1] [0, 1]
2 [ 2: 1: 2] [] []
2 [ 2: 1: 2] [0, 1]
2 [ 2: 1: 3] [] []
2 [ 2: 1: 3] [0, 1]
2 [ 2: 2:-3] [] []
2 [ 2: 2:-3] [0, 1]
2 [ 2: 2:-2] [] []
2 [ 2: 2:-2] [0, 1]
2 [ 2: 2:-1] [] []
2 [ 2: 2:-1] [0, 1]
2 [ 2: 2: 1] [] []
2 [ 2: 2: 1] [0, 1]
2 [ 2: 2: 2] [] []
2 [ 2: 2: 2] [0, 1]
2 [ 2: 2: 3] [] []
2 [ 2: 2: 3] [0, 1]
3 [-3:-3:-3] [] []
3 [-3:-3:-3] [0, 1, 2]
3 [-3:-3:-2] [] []
3 [-3:-3:-2] [0, 1, 2]
3 [-3:-3:-1] [] []
3 [-3:-3:-1] [0, 1, 2]
3 [-3:-3: 1] [] []
3 [-3:-3: 1] [0, 1, 2]
3 [-3:-3: 2] [] []
3 [-3:-3: 2] [0, 1, 2]
3 [-3:-3: 3] [] []
3 [-3:-3: 3] [0, 1, 2]
3 [-3:-2:-3] [] []
3 [-3:-2:-3] [0, 1, 2]
3 [-3:-2:-2] [] []
3 [-3:-2:-2] [0, 1, 2]
3 [-3:-2:-1] [] []
3 [-3:-2:-1] [0, 1, 2]
3 [-3:-2: 1] [0] [0]
3 [-3:-2: 1] [-1, 1, 2]
3 [-3:-2: 2] [0] [0]
3 [-3:-2: 2] [-1, 1, 2]
3 [-3:-2: 3] [0] [0]
3 [-3:-2: 3] [-1, 1, 2]
3 [-3:-1:-3] [] []
3 [-3:-1:-3] [0, 1, 2]
3 [-3:-1:-2] [] []
3 [-3:-1:-2] [0, 1, 2]
3 [-3:-1:-1] [] []
3 [-3:-1:-1] [0, 1, 2]
3 [-3:-1: 1] [0, 1] [0, 1]
3 [-3:-1: 1] [-1, -1, 2]
3 [-3:-1: 2] [0] [0]
3 [-3:-1: 2] [-1, 1, 2]
3 [-3:-1: 3] [0] [0]
3 [-3:-1: 3] [-1, 1, 2]
3 [-3: 0:-3] [] []
3 [-3: 0:-3] [0, 1, 2]
3 [-3: 0:-2] [] []
3 [-3: 0:-2] [0, 1, 2]
3 [-3: 0:-1] [] []
3 [-3: 0:-1] [0, 1, 2]
3 [-3: 0: 1] [] []
3 [-3: 0: 1] [0, 1, 2]
3 [-3: 0: 2] [] []
3 [-3: 0: 2] [0, 1, 2]
3 [-3: 0: 3] [] []
3 [-3: 0: 3] [0, 1, 2]
3 [-3: 1:-3] [] []
3 [-3: 1:-3] [0, 1, 2]
3 [-3: 1:-2] [] []
3 [-3: 1:-2] [0, 1, 2]
3 [-3: 1:-1] [] []
3 [-3: 1:-1] [0, 1, 2]
3 [-3: 1: 1] [0] [0]
3 [-3: 1: 1] [-1, 1, 2]
3 [-3: 1: 2] [0] [0]
3 [-3: 1: 2] [-1, 1, 2]
3 [-3: 1: 3] [0] [0]
3 [-3: 1: 3] [-1, 1, 2]
3 [-3: 2:-3] [] []
3 [-3: 2:-3] [0, 1, 2]
3 [-3: 2:-2] [] []
3 [-3: 2:-2] [0, 1, 2]
3 [-3: 2:-1] [] []
3 [-3: 2:-1] [0, 1, 2]
3 [-3: 2: 1] [0, 1] [0, 1]
3 [-3: 2: 1] [-1, -1, 2]
3 [-3: 2: 2] [0] [0]
3 [-3: 2: 2] [-1, 1, 2]
3 [-3: 2: 3] [0] [0]
3 [-3: 2: 3] [-1, 1, 2]
3 [-3: 3:-3] [] []
3 [-3: 3:-3] [0, 1, 2]
3 [-3: 3:-2] [] []
3 [-3: 3:-2] [0, 1, 2]
3 [-3: 3:-1] [] []
3 [-3: 3:-1] [0, 1, 2]
3 [-3: 3: 1] [0, 1, 2] [0, 1, 2]
3 [-3: 3: 1] [-1, -1, -1]
3 [-3: 3: 2] [0, 2] [0, 2]
3 [-3: 3: 2] [-1, 1, -1]
3 [-3: 3: 3] [0] [0]
3 [-3: 3: 3] [-1, 1, 2]
3 [-2:-3:-3] [1] [1]
3 [-2:-3:-3] [0, -1, 2]
3 [-2:-3:-2] [1] [1]
3 [-2:-3:-2] [0, -1, 2]
3 [-2:-3:-1] [1] [1]
3 [-2:-3:-1] [0, -1, 2]
3 [-2:-3: 1] [] []
3 [-2:-3: 1] [0, 1, 2]
3 [-2:-3: 2] [] []
3 [-2:-3: 2] [0, 1, 2]
3 [-2:-3: 3] [] []
3 [-2:-3: 3] [0, 1, 2]
3 [-2:-2:-3] [] []
3 [-2:-2:-3] [0, 1, 2]
3 [-2:-2:-2] [] []
3 [-2:-2:-2] [0, 1, 2]
3 [-2:-2:-1] [] []
3 [-2:-2:-1] [0, 1, 2]
3 [-2:-2: 1] [] []
3 [-2:-2: 1] [0, 1, 2]
3 [-2:-2: 2] [] []
3 [-2:-2: 2] [0, 1, 2]
3 [-2:-2: 3] [] []
3 [-2:-2: 3] [0, 1, 2]
3 [-2:-1:-3] [] []
3 [-2:-1:-3] [0, 1, 2]
3 [-2:-1:-2] [] []
3 [-2:-1:-2] [0, 1, 2]
3 [-2:-1:-1] [] []
3 [-2:-1:-1] [0, 1, 2]
3 [-2:-1: 1] [1] [1]
3 [-2:-1: 1] [0, -1, 2]
3 [-2:-1: 2] [1] [1]
3 [-2:-1: 2] [0, -1, 2]
3 [-2:-1: 3] [1] [1]
3 [-2:-1: 3] [0, -1, 2]
3 [-2: 0:-3] [1] [1]
3 [-2: 0:-3] [0, -1, 2]
3 [-2: 0:-2] [1] [1]
3 [-2: 0:-2] [0, -1, 2]
3 [-2: 0:-1] [1] [1]
3 [-2: 0:-1] [0, -1, 2]
3 [-2: 0: 1] [] []
3 [-2: 0: 1] [0, 1, 2]
3 [-2: 0: 2] [] []
3 [-2: 0: 2] [0, 1, 2]
3 [-2: 0: 3] [] []
3 [-2: 0: 3] [0, 1, 2]
3 [-2: 1:-3] [] []
3 [-2: 1:-3] [0, 1, 2]
3 [-2: 1:-2] [] []
3 [-2: 1:-2] [0, 1, 2]
3 [-2: 1:-1] [] []
3 [-2: 1:-1] [0, 1, 2]
3 [-2: 1: 1] [] []
3 [-2: 1: 1] [0, 1, 2]
3 [-2: 1: 2] [] []
3 [-2: 1: 2] [0, 1, 2]
3 [-2: 1: 3] [] []
3 [-2: 1: 3] [0, 1, 2]
3 [-2: 2:-3] [] []
3 [-2: 2:-3] [0, 1, 2]
3 [-2: 2:-2] [] []
3 [-2: 2:-2] [0, 1, 2]
3 [-2: 2:-1] [] []
3 [-2: 2:-1] [0, 1, 2]
3 [-2: 2: 1] [1] [1]
3 [-2: 2: 1] [0, -1, 2]
3 [-2: 2: 2] [1] [1]
3 [-2: 2: 2] [0, -1, 2]
3 [-2: 2: 3] [1] [1]
3 [-2: 2: 3] [0, -1, 2]
3 [-2: 3:-3] [] []
3 [-2: 3:-3] [0, 1, 2]
3 [-2: 3:-2] [] []
3 [-2: 3:-2] [0, 1, 2]
3 [-2: 3:-1] [] []
3 [-2: 3:-1] [0, 1, 2]
3 [-2: 3: 1] [1, 2] [1, 2]
3 [-2: 3: 1] [0, -1, -1]
3 [-2: 3: 2] [1] [1]
3 [-2: 3: 2] [0, -1, 2]
3 [-2: 3: 3] [1] [1]
3 [-2: 3: 3] [0, -1, 2]
3 [-1:-3:-3] [2] [2]
3 [-1:-3:-3] [0, 1, -1]
3 [-1:-3:-2] [2] [2]
3 [-1:-3:-2] [0, 1, -1]
3 [-1:-3:-1] [2, 1] [2, 1]
3 [-1:-3:-1] [0, -1, -1]
3 [-1:-3: 1] [] []
3 [-1:-3: 1] [0, 1, 2]
3 [-1:-3: 2] [] []
3 [-1:-3: 2] [0, 1, 2]
3 [-1:-3: 3] [] []
3 [-1:-3: 3] [0, 1, 2]
3 [-1:-2:-3] [2] [2]
3 [-1:-2:-3] [0, 1, -1]
3 [-1:-2:-2] [2] [2]
3 [-1:-2:-2] [0, 1, -1]
3 [-1:-2:-1] [2] [2]
3 [-1:-2:-1] [0, 1, -1]
3 [-1:-2: 1] [] []
3 [-1:-2: 1] [0, 1, 2]
3 [-1:-2: 2] [] []
3 [-1:-2: 2] [0, 1, 2]
3 [-1:-2: 3] [] []
3 [-1:-2: 3] [0, 1, 2]
3 [-1:-1:-3] [] []
3 [-1:-1:-3] [0, 1, 2]
3 [-1:-1:-2] [] []
3 [-1:-1:-2] [0, 1, 2]
3 [-1:-1:-1] [] []
3 [-1:-1:-1] [0, 1, 2]
3 [-1:-1: 1] [] []
3 [-1:-1: 1] [0, 1, 2]
3 [-1:-1: 2] [] []
3 [-1:-1: 2] [0, 1, 2]
3 [-1:-1: 3] [] []
3 [-1:-1: 3] [0, 1, 2]
3 [-1: 0:-3] [2] [2]
3 [-1: 0:-3] [0, 1, -1]
3 [-1: 0:-2] [2] [2]
3 [-1: 0:-2] [0, 1, -1]
3 [-1: 0:-1] [2, 1] [2, 1]
3 [-1: 0:-1] [0, -1, -1]
3 [-1: 0: 1] [] []
3 [-1: 0: 1] [0, 1, 2]
3 [-1: 0: 2] [] []
3 [-1: 0: 2] [0, 1, 2]
3 [-1: 0: 3] [] []
3 [-1: 0: 3] [0, 1, 2]
3 [-1: 1:-3] [2] [2]
3 [-1: 1:-3] [0, 1, -1]
3 [-1: 1:-2] [2] [2]
3 [-1: 1:-2] [0, 1, -1]
3 [-1: 1:-1] [2] [2]
3 [-1: 1:-1] [0, 1, -1]
3 [-1: 1: 1] [] []
3 [-1: 1: 1] [0, 1, 2]
3 [-1: 1: 2] [] []
3 [-1: 1: 2] [0, 1, 2]
3 [-1: 1: 3] [] []
3 [-1: 1: 3] [0, 1, 2]
3 [-1: 2:-3] [] []
3 [-1: 2:-3] [0, 1, 2]
3 [-1: 2:-2] [] []
3 [-1: 2:-2] [0, 1, 2]
3 [-1: 2:-1] [] []
3 [-1: 2:-1] [0, 1, 2]
3 [-1: 2: 1] [] []
3 [-1: 2: 1] [0, 1, 2]
3 [-1: 2: 2] [] []
3 [-1: 2: 2] [0, 1, 2]
3 [-1: 2: 3] [] []
3 [-1: 2: 3] [0, 1, 2]
3 [-1: 3:-3] [] []
3 [-1: 3:-3] [0, 1, 2]
3 [-1: 3:-2] [] []
3 [-1: 3:-2] [0, 1, 2]
3 [-1: 3:-1] [] []
3 [-1: 3:-1] [0, 1, 2]
3 [-1: 3: 1] [2] [2]
3 [-1: 3: 1] [0, 1, -1]
3 [-1: 3: 2] [2] [2]
3 [-1: 3: 2] [0, 1, -1]
3 [-1: 3: 3] [2] [2]
3 [-1: 3: 3] [0, 1, -1]
3 [ 0:-3:-3] [] []
3 [ 0:-3:-3] [0, 1, 2]
3 [ 0:-3:-2] [] []
3 [ 0:-3:-2] [0, 1, 2]
3 [ 0:-3:-1] [] []
3 [ 0:-3:-1] [0, 1, 2]
3 [ 0:-3: 1] [] []
3 [ 0:-3: 1] [0, 1, 2]
3 [ 0:-3: 2] [] []
3 [ 0:-3: 2] [0, 1, 2]
3 [ 0:-3: 3] [] []
3 [ 0:-3: 3] [0, 1, 2]
3 [ 0:-2:-3] [] []
3 [ 0:-2:-3] [0, 1, 2]
3 [ 0:-2:-2] [] []
3 [ 0:-2:-2] [0, 1, 2]
3 [ 0:-2:-1] [] []
3 [ 0:-2:-1] [0, 1, 2]
3 [ 0:-2: 1] [0] [0]
3 [ 0:-2: 1] [-1, 1, 2]
3 [ 0:-2: 2] [0] [0]
3 [ 0:-2: 2] [-1, 1, 2]
3 [ 0:-2: 3] [0] [0]
3 [ 0:-2: 3] [-1, 1, 2]
3 [ 0:-1:-3] [] []
3 [ 0:-1:-3] [0, 1, 2]
3 [ 0:-1:-2] [] []
3 [ 0:-1:-2] [0, 1, 2]
3 [ 0:-1:-1] [] []
3 [ 0:-1:-1] [0, 1, 2]
3 [ 0:-1: 1] [0, 1] [0, 1]
3 [ 0:-1: 1] [-1, -1, 2]
3 [ 0:-1: 2] [0] [0]
3 [ 0:-1: 2] [-1, 1, 2]
3 [ 0:-1: 3] [0] [0]
3 [ 0:-1: 3] [-1, 1, 2]
3 [ 0: 0:-3] [] []
3 [ 0: 0:-3] [0, 1, 2]
3 [ 0: 0:-2] [] []
3 [ 0: 0:-2] [0, 1, 2]
3 [ 0: 0:-1] [] []
3 [ 0: 0:-1] [0, 1, 2]
3 [ 0: 0: 1] [] []
3 [ 0: 0: 1] [0, 1, 2]
3 [ 0: 0: 2] [] []
3 [ 0: 0: 2] [0, 1, 2]
3 [ 0: 0: 3] [] []
3 [ 0: 0: 3] [0, 1, 2]
3 [ 0: 1:-3] [] []
3 [ 0: 1:-3] [0, 1, 2]
3 [ 0: 1:-2] [] []
3 [ 0: 1:-2] [0, 1, 2]
3 [ 0: 1:-1] [] []
3 [ 0: 1:-1] [0, 1, 2]
3 [ 0: 1: 1] [0] [0]
3 [ 0: 1: 1] [-1, 1, 2]
3 [ 0: 1: 2] [0] [0]
3 [ 0: 1: 2] [-1, 1, 2]
3 [ 0: 1: 3] [0] [0]
3 [ 0: 1: 3] [-1, 1, 2]
3 [ 0: 2:-3] [] []
3 [ 0: 2:-3] [0, 1, 2]
3 [ 0: 2:-2] [] []
3 [ 0: 2:-2] [0, 1, 2]
3 [ 0: 2:-1] [] []
3 [ 0: 2:-1] [0, 1, 2]
3 [ 0: 2: 1] [0, 1] [0, 1]
3 [ 0: 2: 1] [-1, -1, 2]
3 [ 0: 2: 2] [0] [0]
3 [ 0: 2: 2] [-1, 1, 2]
3 [ 0: 2: 3] [0] [0]
3 [ 0: 2: 3] [-1, 1, 2]
3 [ 0: 3:-3] [] []
3 [ 0: 3:-3] [0, 1, 2]
3 [ 0: 3:-2] [] []
3 [ 0: 3:-2] [0, 1, 2]
3 [ 0: 3:-1] [] []
3 [ 0: 3:-1] [0, 1, 2]
3 [ 0: 3: 1] [0, 1, 2] [0, 1, 2]
3 [ 0: 3: 1] [-1, -1, -1]
3 [ 0: 3: 2] [0, 2] [0, 2]
3 [ 0: 3: 2] [-1, 1, -1]
3 [ 0: 3: 3] [0] [0]
3 [ 0: 3: 3] [-1, 1, 2]
3 [ 1:-3:-3] [1] [1]
3 [ 1:-3:-3] [0, -1, 2]
3 [ 1:-3:-2] [1] [1]
3 [ 1:-3:-2] [0, -1, 2]
3 [ 1:-3:-1] [1] [1]
3 [ 1:-3:-1] [0, -1, 2]
3 [ 1:-3: 1] [] []
3 [ 1:-3: 1] [0, 1, 2]
3 [ 1:-3: 2] [] []
3 [ 1:-3: 2] [0, 1, 2]
3 [ 1:-3: 3] [] []
3 [ 1:-3: 3] [0, 1, 2]
3 [ 1:-2:-3] [] []
3 [ 1:-2:-3] [0, 1, 2]
3 [ 1:-2:-2] [] []
3 [ 1:-2:-2] [0, 1, 2]
3 [ 1:-2:-1] [] []
3 [ 1:-2:-1] [0, 1, 2]
3 [ 1:-2: 1] [] []
3 [ 1:-2: 1] [0, 1, 2]
3 [ 1:-2: 2] [] []
3 [ 1:-2: 2] [0, 1, 2]
3 [ 1:-2: 3] [] []
3 [ 1:-2: 3] [0, 1, 2]
3 [ 1:-1:-3] [] []
3 [ 1:-1:-3] [0, 1, 2]
3 [ 1:-1:-2] [] []
3 [ 1:-1:-2] [0, 1, 2]
3 [ 1:-1:-1] [] []
3 [ 1:-1:-1] [0, 1, 2]
3 [ 1:-1: 1] [1] [1]
3 [ 1:-1: 1] [0, -1, 2]
3 [ 1:-1: 2] [1] [1]
3 [ 1:-1: 2] [0, -1, 2]
3 [ 1:-1: 3] [1] [1]
3 [ 1:-1: 3] [0, -1, 2]
3 [ 1: 0:-3] [1] [1]
3 [ 1: 0:-3] [0, -1, 2]
3 [ 1: 0:-2] [1] [1]
3 [ 1: 0:-2] [0, -1, 2]
3 [ 1: 0:-1] [1] [1]
3 [ 1: 0:-1] [0, -1, 2]
3 [ 1: 0: 1] [] []
3 [ 1: 0: 1] [0, 1, 2]
3 [ 1: 0: 2] [] []
3 [ 1: 0: 2] [0, 1, 2]
3 [ 1: 0: 3] [] []
3 [ 1: 0: 3] [0, 1, 2]
3 [ 1: 1:-3] [] []
3 [ 1: 1:-3] [0, 1, 2]
3 [ 1: 1:-2] [] []
3 [ 1: 1:-2] [0, 1, 2]
3 [ 1: 1:-1] [] []
3 [ 1: 1:-1] [0, 1, 2]
3 [ 1: 1: 1] [] []
3 [ 1: 1: 1] [0, 1, 2]
3 [ 1: 1: 2] [] []
3 [ 1: 1: 2] [0, 1, 2]
3 [ 1: 1: 3] [] []
3 [ 1: 1: 3] [0, 1, 2]
3 [ 1: 2:-3] [] []
3 [ 1: 2:-3] [0, 1, 2]
3 [ 1: 2:-2] [] []
3 [ 1: 2:-2] [0, 1, 2]
3 [ 1: 2:-1] [] []
3 [ 1: 2:-1] [0, 1, 2]
3 [ 1: 2: 1] [1] [1]
3 [ 1: 2: 1] [0, -1, 2]
3 [ 1: 2: 2] [1] [1]
3 [ 1: 2: 2] [0, -1, 2]
3 [ 1: 2: 3] [1] [1]
3 [ 1: 2: 3] [0, -1, 2]
3 [ 1: 3:-3] [] []
3 [ 1: 3:-3] [0, 1, 2]
3 [ 1: 3:-2] [] []
3 [ 1: 3:-2] [0, 1, 2]
3 [ 1: 3:-1] [] []
3 [ 1: 3:-1] [0, 1, 2]
3 [ 1: 3: 1] [1, 2] [1, 2]
3 [ 1: 3: 1] [0, -1, -1]
3 [ 1: 3: 2] [1] [1]
3 [ 1: 3: 2] [0, -1, 2]
3 [ 1: 3: 3] [1] [1]
3 [ 1: 3: 3] [0, -1, 2]
3 [ 2:-3:-3] [2] [2]
3 [ 2:-3:-3] [0, 1, -1]
3 [ 2:-3:-2] [2] [2]
3 [ 2:-3:-2] [0, 1, -1]
3 [ 2:-3:-1] [2, 1] [2, 1]
3 [ 2:-3:-1] [0, -1, -1]
3 [ 2:-3: 1] [] []
3 [ 2:-3: 1] [0, 1, 2]
3 [ 2:-3: 2] [] []
3 [ 2:-3: 2] [0, 1, 2]
3 [ 2:-3: 3] [] []
3 [ 2:-3: 3] [0, 1, 2]
3 [ 2:-2:-3] [2] [2]
3 [ 2:-2:-3] [0, 1, -1]
3 [ 2:-2:-2] [2] [2]
3 [ 2:-2:-2] [0, 1, -1]
3 [ 2:-2:-1] [2] [2]
3 [ 2:-2:-1] [0, 1, -1]
3 [ 2:-2: 1] [] []
3 [ 2:-2: 1] [0, 1, 2]
3 [ 2:-2: 2] [] []
3 [ 2:-2: 2] [0, 1, 2]
3 [ 2:-2: 3] [] []
3 [ 2:-2: 3] [0, 1, 2]
3 [ 2:-1:-3] [] []
3 [ 2:-1:-3] [0, 1, 2]
3 [ 2:-1:-2] [] []
3 [ 2:-1:-2] [0, 1, 2]
3 [ 2:-1:-1] [] []
3 [ 2:-1:-1] [0, 1, 2]
3 [ 2:-1: 1] [] []
3 [ 2:-1: 1] [0, 1, 2]
3 [ 2:-1: 2] [] []
3 [ 2:-1: 2] [0, 1, 2]
3 [ 2:-1: 3] [] []
3 [ 2:-1: 3] [0, 1, 2]
3 [ 2: 0:-3] [2] [2]
3 [ 2: 0:-3] [0, 1, -1]
3 [ 2: 0:-2] [2] [2]
3 [ 2: 0:-2] [0, 1, -1]
3 [ 2: 0:-1] [2, 1] [2, 1]
3 [ 2: 0:-1] [0, -1, -1]
3 [ 2: 0: 1] [] []
3 [ 2: 0: 1] [0, 1, 2]
3 [ 2: 0: 2] [] []
3 [ 2: 0: 2] [0, 1, 2]
3 [ 2: 0: 3] [] []
3 [ 2: 0: 3] [0, 1, 2]
3 [ 2: 1:-3] [2] [2]
3 [ 2: 1:-3] [0, 1, -1]
3 [ 2: 1:-2] [2] [2]
3 [ 2: 1:-2] [0, 1, -1]
3 [ 2: 1:-1] [2] [2]
3 [ 2: 1:-1] [0, 1, -1]
3 [ 2: 1: 1] [] []
3 [ 2: 1: 1] [0, 1, 2]
3 [ 2: 1: 2] [] []
3 [ 2: 1: 2] [0, 1, 2]
3 [ 2: 1: 3] [] []
3 [ 2: 1: 3] [0, 1, 2]
3 [ 2: 2:-3] [] []
3 [ 2: 2:-3] [0, 1, 2]
3 [ 2: 2:-2] [] []
3 [ 2: 2:-2] [0, 1, 2]
3 [ 2: 2:-1] [] []
3 [ 2: 2:-1] [0, 1, 2]
3 [ 2: 2: 1] [] []
3 [ 2: 2: 1] [0, 1, 2]
3 [ 2: 2: 2] [] []
3 [ 2: 2: 2] [0, 1, 2]
3 [ 2: 2: 3] [] []
3 [ 2: 2: 3] [0, 1, 2]
3 [ 2: 3:-3] [] []
3 [ 2: 3:-3] [0, 1, 2]
3 [ 2: 3:-2] [] []
3 [ 2: 3:-2] [0, 1, 2]
3 [ 2: 3:-1] [] []
3 [ 2: 3:-1] [0, 1, 2]
3 [ 2: 3: 1] [2] [2]
3 [ 2: 3: 1] [0, 1, -1]
3 [ 2: 3: 2] [2] [2]
3 [ 2: 3: 2] [0, 1, -1]
3 [ 2: 3: 3] [2] [2]
3 [ 2: 3: 3] [0, 1, -1]
3 [ 3:-3:-3] [2] [2]
3 [ 3:-3:-3] [0, 1, -1]
3 [ 3:-3:-2] [2] [2]
3 [ 3:-3:-2] [0, 1, -1]
3 [ 3:-3:-1] [2, 1] [2, 1]
3 [ 3:-3:-1] [0, -1, -1]
3 [ 3:-3: 1] [] []
3 [ 3:-3: 1] [0, 1, 2]
3 [ 3:-3: 2] [] []
3 [ 3:-3: 2] [0, 1, 2]
3 [ 3:-3: 3] [] []
3 [ 3:-3: 3] [0, 1, 2]
3 [ 3:-2:-3] [2] [2]
3 [ 3:-2:-3] [0, 1, -1]
3 [ 3:-2:-2] [2] [2]
3 [ 3:-2:-2] [0, 1, -1]
3 [ 3:-2:-1] [2] [2]
3 [ 3:-2:-1] [0, 1, -1]
3 [ 3:-2: 1] [] []
3 [ 3:-2: 1] [0, 1, 2]
3 [ 3:-2: 2] [] []
3 [ 3:-2: 2] [0, 1, 2]
3 [ 3:-2: 3] [] []
3 [ 3:-2: 3] [0, 1, 2]
3 [ 3:-1:-3] [] []
3 [ 3:-1:-3] [0, 1, 2]
3 [ 3:-1:-2] [] []
3 [ 3:-1:-2] [0, 1, 2]
3 [ 3:-1:-1] [] []
3 [ 3:-1:-1] [0, 1, 2]
3 [ 3:-1: 1] [] []
3 [ 3:-1: 1] [0, 1, 2]
3 [ 3:-1: 2] [] []
3 [ 3:-1: 2] [0, 1, 2]
3 [ 3:-1: 3] [] []
3 [ 3:-1: 3] [0, 1, 2]
3 [ 3: 0:-3] [2] [2]
3 [ 3: 0:-3] [0, 1, -1]
3 [ 3: 0:-2] [2] [2]
3 [ 3: 0:-2] [0, 1, -1]
3 [ 3: 0:-1] [2, 1] [2, 1]
3 [ 3: 0:-1] [0, -1, -1]
3 [ 3: 0: 1] [] []
3 [ 3: 0: 1] [0, 1, 2]
3 [ 3: 0: 2] [] []
3 [ 3: 0: 2] [0, 1, 2]
3 [ 3: 0: 3] [] []
3 [ 3: 0: 3] [0, 1, 2]
3 [ 3: 1:-3] [2] [2]
3 [ 3: 1:-3] [0, 1, -1]
3 [ 3: 1:-2] [2] [2]
3 [ 3: 1:-2] [0, 1, -1]
3 [ 3: 1:-1] [2] [2]
3 [ 3: 1:-1] [0, 1, -1]
3 [ 3: 1: 1] [] []
3 [ 3: 1: 1] [0, 1, 2]
3 [ 3: 1: 2] [] []
3 [ 3: 1: 2] [0, 1, 2]
3 [ 3: 1: 3] [] []
3 [ 3: 1: 3] [0, 1, 2]
3 [ 3: 2:-3] [] []
3 [ 3: 2:-3] [0, 1, 2]
3 [ 3: 2:-2] [] []
3 [ 3: 2:-2] [0, 1, 2]
3 [ 3: 2:-1] [] []
3 [ 3: 2:-1] [0, 1, 2]
3 [ 3: 2: 1] [] []
3 [ 3: 2: 1] [0, 1, 2]
3 [ 3: 2: 2] [] []
3 [ 3: 2: 2] [0, 1, 2]
3 [ 3: 2: 3] [] []
3 [ 3: 2: 3] [0, 1, 2]
3 [ 3: 3:-3] [] []
3 [ 3: 3:-3] [0, 1, 2]
3 [ 3: 3:-2] [] []
3 [ 3: 3:-2] [0, 1, 2]
3 [ 3: 3:-1] [] []
3 [ 3: 3:-1] [0, 1, 2]
3 [ 3: 3: 1] [] []
3 [ 3: 3: 1] [0, 1, 2]
3 [ 3: 3: 2] [] []
3 [ 3: 3: 2] [0, 1, 2]
3 [ 3: 3: 3] [] []
3 [ 3: 3: 3] [0, 1, 2]

8
tests/slicing2.py Normal file
View file

@ -0,0 +1,8 @@
try:
import ulab as np
except:
import numpy as np
a = np.array(range(9), dtype=np.float)
print("a:\t", list(a))
print("a < 5:\t", list(a[a < 5]))

2
tests/slicing2.py.exp Normal file
View file

@ -0,0 +1,2 @@
a: [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0]
a < 5: [0.0, 1.0, 2.0, 3.0, 4.0]