Compare commits
297 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
068da5fc96 | ||
|
|
a0999aba79 | ||
|
|
8eb8eaf5a1 | ||
|
|
66e9eb3ed3 | ||
|
|
844f6e5e1e | ||
|
|
1398a8606f | ||
|
|
88ef893540 | ||
|
|
825ec2b143 | ||
|
|
66daa8960a | ||
|
|
20f7259a47 | ||
|
|
be15d62632 | ||
|
|
903506ca9a | ||
|
|
73ed8cc11f | ||
|
|
303e8d790a | ||
|
|
2b74236c8c | ||
|
|
c0b3262be4 | ||
|
|
45f23ebc82 | ||
|
|
1d3ddd8f52 | ||
|
|
a77022dcd0 | ||
|
|
99cb54a426 | ||
|
|
41c4363f11 | ||
|
|
e40a667e3c | ||
|
|
519c48149f | ||
|
|
6fb60ef9cf | ||
|
|
65c941a805 | ||
|
|
63dfbd178b | ||
|
|
c49110572d | ||
|
|
acfec3e9af | ||
|
|
1c37edbee6 | ||
|
|
9a1d03d90d | ||
|
|
c3d1cbd7c2 | ||
|
|
f2fad82a97 | ||
|
|
7a9370612f | ||
|
|
e32920645c | ||
| 4bde4efa9d | |||
| eacb0c9af4 | |||
| 8c444ef75d | |||
| 9c9e9532ac | |||
| 2df210f87a | |||
|
|
a05ec05351 | ||
|
|
5279de73ab | ||
|
|
84f99f17fc | ||
| d025aa3cf6 | |||
|
|
d072086c56 | ||
| 38caf84b2d | |||
|
|
112d4f82d3 | ||
|
|
319df10cfe | ||
|
|
26051d70d2 | ||
|
|
2cde1280a4 | ||
|
|
ef248b684d | ||
| 38a4976b58 | |||
|
|
73dbbf79bb | ||
|
|
3e996d9bd9 | ||
| 6619c20b3b | |||
| f3e6e1c6d2 | |||
| 6000743c45 | |||
| 1150554ad5 | |||
|
|
ac2e9954ed | ||
|
|
beda4c19f8 | ||
|
|
412b13fb1c | ||
|
|
8c3e1058d4 | ||
|
|
ad1a1c54aa | ||
|
|
afc8e4e165 | ||
|
|
47ad73ab57 | ||
|
|
4407f8c404 | ||
|
|
5fa9b70766 | ||
|
|
8585407df9 | ||
|
|
f2dd2230c4 | ||
|
|
578ca6670d | ||
| 33398e082c | |||
| 20766d16e1 | |||
| 315c988393 | |||
|
|
6fcfeda58d | ||
| 6e6d24ea45 | |||
|
|
7124eaac74 | ||
|
|
5be42be128 | ||
|
|
e68bb707b2 | ||
|
|
42172c6575 | ||
|
|
1a440d7d12 | ||
|
|
25a825e41c | ||
| 155dad9994 | |||
|
|
38e99c69af | ||
|
|
41fcf1d4cf | ||
|
|
5ccfa5cdd9 | ||
|
|
0c807bd912 | ||
|
|
294f9d9ef2 | ||
|
|
42f396a992 | ||
|
|
57de23c1fb | ||
|
|
dfed7a844a | ||
|
|
a2c5ece991 | ||
|
|
2b4292abcc | ||
| d5762fda3c | |||
|
|
99f6fa66a1 | ||
|
|
35b58d0037 | ||
| 770ae31556 | |||
| 346c936e14 | |||
| fc6e200afe | |||
| 308627c9aa | |||
|
|
1347694672 | ||
|
|
1898c2fc71 | ||
|
|
00139bdd96 | ||
|
|
d438344943 | ||
|
|
53bc8d6b0e | ||
|
|
da33f6276a | ||
|
|
a715eed7d9 | ||
|
|
8da81e123e | ||
|
|
8c2cd49ffa | ||
|
|
2772fd8e91 | ||
|
|
10b79f2041 | ||
|
|
dde8d24461 | ||
|
|
48b3b7f641 | ||
|
|
c7cfae9397 | ||
| 15d9df16ee | |||
|
|
4407bec88c | ||
|
|
d2939dbf22 | ||
|
|
ec5d14e8e2 | ||
|
|
607fd303bb | ||
|
|
0ef2341386 | ||
|
|
08cfcbfb46 | ||
|
|
4705c95fb2 | ||
|
|
f2502fa037 | ||
|
|
72f7df520a | ||
|
|
4dc9afc1f8 | ||
|
|
973c1f596d | ||
|
|
cc14841afb | ||
|
|
effbd3cf38 | ||
|
|
e852f7fd42 | ||
|
|
ccd9481969 | ||
|
|
ae9604db21 | ||
|
|
88231bc3a1 | ||
|
|
6dcad4424c | ||
|
|
9ba136acd4 | ||
|
|
f5f42c3643 | ||
|
|
65d6f8e947 | ||
|
|
e8c89935ab | ||
|
|
e980564d64 | ||
|
|
19282b47d1 | ||
|
|
e86b6b8507 | ||
|
|
9d79960ef6 | ||
|
|
67538b0ee0 | ||
|
|
9dc9b776d5 | ||
|
|
80274175ec | ||
|
|
87e5fa3bd9 | ||
|
|
7a09815a84 | ||
|
|
089000df30 | ||
|
|
2530fc7e8b | ||
|
|
bb07482efc | ||
|
|
004f228428 | ||
|
|
f31555044a | ||
|
|
f7b557c6b0 | ||
|
|
9f444dd718 | ||
|
|
a39869c43c | ||
|
|
5395c76d98 | ||
|
|
77a856e84e | ||
|
|
b4802a7f4d | ||
|
|
8d39e5a430 | ||
|
|
d56dd2f921 | ||
|
|
6dfdc44c4e | ||
|
|
26d28166f8 | ||
|
|
0640f90083 | ||
|
|
957ae1c50a | ||
|
|
16b277fe1a | ||
|
|
73fcd895db | ||
|
|
15918fdb89 | ||
|
|
932060afcc | ||
|
|
640a3bf777 | ||
|
|
6092d1d406 | ||
|
|
3f97d7bb84 | ||
|
|
209e7ff251 | ||
|
|
4739e06473 | ||
|
|
67e592670c | ||
|
|
4f828f188d | ||
|
|
74ee335758 | ||
|
|
bd57ac8938 | ||
|
|
b756c36f73 | ||
|
|
024b3ea6e8 | ||
|
|
97d2c2c3c5 | ||
|
|
b9d46c7f92 | ||
|
|
a1f1cd255b | ||
|
|
834ddc8218 | ||
|
|
4b0c3215fd | ||
|
|
acb81aeded | ||
|
|
56b3d800e3 | ||
|
|
030463f7ff | ||
|
|
d8ce4b395f | ||
|
|
fa143c2e63 | ||
|
|
406d9c7407 | ||
|
|
8c7ca97971 | ||
|
|
32ebcb4c06 | ||
|
|
b12f3d0b4d | ||
|
|
d40672d946 | ||
|
|
1fc2f18358 | ||
|
|
74533d18ff | ||
|
|
63ab589b8c | ||
|
|
8154accf1b | ||
|
|
05ad1a5d96 | ||
|
|
a88fbaf8c8 | ||
|
|
aa543d0c57 | ||
|
|
d5ab0cf716 | ||
|
|
4e6b89afd2 | ||
|
|
8e8aa263e9 | ||
|
|
178af9a9fa | ||
|
|
4232a5923f | ||
|
|
d2e6af03d1 | ||
|
|
d3ba090b1a | ||
|
|
e762275a96 | ||
|
|
7672ab9d44 | ||
|
|
66189452ac | ||
|
|
a128762279 | ||
|
|
612d07218e | ||
|
|
45fde86060 | ||
|
|
b5d94e8fdc | ||
|
|
c3d1a5e1ee | ||
|
|
fdf23c9956 | ||
|
|
eecd72de04 | ||
|
|
a09b5bd64e | ||
|
|
ca3bbca1b1 | ||
|
|
17afe29124 | ||
|
|
8e42afe72e | ||
|
|
923cb823a3 | ||
|
|
6eda5ec53c | ||
|
|
34353d7545 | ||
|
|
9d84125232 | ||
|
|
faaae7d2f2 | ||
|
|
97b368412c | ||
|
|
ef4a5b7fd1 | ||
|
|
e5020f8d57 | ||
|
|
3fd60dedf9 | ||
|
|
78ba99f009 | ||
|
|
68f8098016 | ||
|
|
a0dcd1ebab | ||
|
|
25d009587e | ||
|
|
0c7c6b88f3 | ||
|
|
6552cfdc38 | ||
|
|
665c32dbb4 | ||
|
|
6609afd006 | ||
|
|
969afdec7f | ||
|
|
ecaa355bab | ||
|
|
ad9e1e9950 | ||
|
|
d1b3d40b47 | ||
|
|
8efdec785e | ||
|
|
6a7d20dd58 | ||
|
|
d39549e3ac | ||
|
|
cb3f4b3898 | ||
|
|
2b578ae333 | ||
|
|
c11dac322d | ||
|
|
4855baa8cc | ||
|
|
7e13fab911 | ||
|
|
94d6b13f8d | ||
|
|
9eebed2d3a | ||
|
|
e01e547b62 | ||
|
|
4d7e279996 | ||
|
|
7b17796c91 | ||
|
|
ee197ef03f | ||
|
|
dbd570a9fb | ||
|
|
14b5c13d50 | ||
|
|
5b7395d6df | ||
|
|
13cebfeccc | ||
|
|
a99e0b9878 | ||
| 71b3ba15af | |||
|
|
76218f2386 | ||
|
|
8a156fe505 | ||
|
|
cc06735cff | ||
|
|
864ab31766 | ||
|
|
3557e16cd1 | ||
|
|
b275fb303d | ||
|
|
235329c3fb | ||
|
|
ce26a0d76b | ||
|
|
78455afa5d | ||
|
|
93409e759a | ||
|
|
3b3639a560 | ||
|
|
d0b1d40cf1 | ||
|
|
316f84174d | ||
|
|
ef8989ecff | ||
|
|
8a6741b350 | ||
|
|
08313e3f02 | ||
|
|
8db5ee897e | ||
|
|
911fdb4587 | ||
|
|
1013daa902 | ||
|
|
91c01ef5fe | ||
|
|
8e5bbe0955 | ||
|
|
9a2449c0c6 | ||
|
|
322145d3ac | ||
|
|
add4f41b2f | ||
|
|
a1a391b90d | ||
|
|
defecb664f | ||
|
|
b9eea417bd | ||
|
|
cd7c1de441 | ||
|
|
6b85ca08e3 | ||
|
|
c603aff3a0 | ||
|
|
ee3181a1d9 | ||
|
|
5512219777 | ||
|
|
ebcf600b4b | ||
|
|
fc8a9bde85 | ||
|
|
58b0db5171 | ||
|
|
92b3513804 | ||
|
|
3d00480443 |
244 changed files with 21344 additions and 3643 deletions
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
4
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -11,8 +11,8 @@ assignees: ''
|
|||
A clear and concise description of what the bug is. Give the `ulab` version
|
||||
|
||||
```python
|
||||
from ulab import numpy as np
|
||||
print(np.__version__)
|
||||
import ulab
|
||||
print(ulab.__version__)
|
||||
```
|
||||
|
||||
**To Reproduce**
|
||||
|
|
|
|||
34
.github/workflows/build.yml
vendored
34
.github/workflows/build.yml
vendored
|
|
@ -16,10 +16,11 @@ on:
|
|||
|
||||
jobs:
|
||||
micropython:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- ubuntu-24.04
|
||||
- macOS-latest
|
||||
dims: [1, 2, 3, 4]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
@ -28,20 +29,26 @@ jobs:
|
|||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Install requirements
|
||||
run: |
|
||||
if type -path apt-get; then
|
||||
sudo apt update && sudo apt-get install gcc-multilib
|
||||
fi
|
||||
|
||||
- name: Versions
|
||||
run: |
|
||||
gcc --version
|
||||
python3 --version
|
||||
- name: Checkout ulab
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout micropython repo
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: micropython/micropython
|
||||
path: micropython
|
||||
|
|
@ -50,10 +57,11 @@ jobs:
|
|||
run: ./build.sh ${{ matrix.dims }}
|
||||
|
||||
circuitpython:
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-20.04
|
||||
- ubuntu-24.04
|
||||
- macOS-latest
|
||||
dims: [1, 2, 3, 4]
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
|
@ -62,10 +70,10 @@ jobs:
|
|||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v1
|
||||
- name: Set up Python 3.12
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: "3.12"
|
||||
|
||||
- name: Versions
|
||||
run: |
|
||||
|
|
@ -73,18 +81,18 @@ jobs:
|
|||
python3 --version
|
||||
|
||||
- name: Checkout ulab
|
||||
uses: actions/checkout@v1
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install requirements
|
||||
run: |
|
||||
if type -path apt-get; then
|
||||
sudo apt-get install gettext librsvg2-bin
|
||||
sudo apt update && sudo apt-get install gettext librsvg2-bin
|
||||
else
|
||||
brew install gettext librsvg
|
||||
echo >>$GITHUB_PATH /usr/local/opt/gettext/bin
|
||||
echo >>$GITHUB_PATH /usr/local/opt/librsvg/bin
|
||||
fi
|
||||
python3 -mpip install -r requirements_cp_dev.txt
|
||||
python3 -mpip install --upgrade -r requirements_cp_dev.txt
|
||||
|
||||
- name: Run build-cp.sh
|
||||
run: ./build-cp.sh ${{ matrix.dims }}
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -9,3 +9,5 @@
|
|||
/code/.atom-build.yml
|
||||
build/micropython
|
||||
build/ulab
|
||||
|
||||
.idea
|
||||
|
|
@ -16,8 +16,7 @@ sphinx:
|
|||
configuration: docs/manual/source/conf.py
|
||||
|
||||
# If using Sphinx, optionally build your docs in additional formats such as PDF
|
||||
# formats:
|
||||
# - pdf
|
||||
formats: all
|
||||
|
||||
# Optionally declare the Python requirements required to build your docs
|
||||
python:
|
||||
|
|
|
|||
65
README.md
65
README.md
|
|
@ -1,23 +1,27 @@
|
|||
# ulab
|
||||
|
||||
[](https://micropython-ulab-robert.readthedocs.io/en/latest/?badge=latest)
|
||||
[](https://micropython-ulab.readthedocs.io/en/latest/index.html)
|
||||
|
||||
`ulab` is a `numpy`-like array manipulation library for [micropython](http://micropython.org/) and [CircuitPython](https://circuitpython.org/).
|
||||
The module is written in C, defines compact containers for numerical data of one to four
|
||||
The module is written in C, defines compact containers (`ndarray`s) for numerical data of one to four
|
||||
dimensions, 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.
|
||||
i.e., it has no hardware dependencies, and can be compiled for any platform. 8-, and 16-bit signed
|
||||
and unsigned integer `dtypes`, as well as `float`, and, optionally, ` complex` are supported.
|
||||
The `float` implementation of `micropython` (32-bit `float`, or 64-bit `double`) is automatically
|
||||
detected and handled.
|
||||
|
||||
1. [Supported functions and methods](#supported-functions-and-methods)
|
||||
1. [ndarray methods](#ndarray-methods)
|
||||
2. [numpy and scipy functions](#numpy-and-scipy-functions)
|
||||
3. [ulab utilities](#ulab-utilities)
|
||||
4. [user module](#user-module)
|
||||
3. [Customising the firmware](#customising-the-firmware)
|
||||
4. [Usage](#usage)
|
||||
5. [Finding help](#finding-help)
|
||||
6. [Benchmarks](#benchmarks)
|
||||
7. [Firmware](#firmware)
|
||||
1. [Customising the firmware](#customising-the-firmware)
|
||||
1. [Platforms including ulab](#platforms-including-ulab)
|
||||
1. [Compiling](#compiling)
|
||||
1. [UNIX](#unix-port)
|
||||
1. [STM-based boards](#stm-based-boards)
|
||||
1. [ESP32-based boards](#esp32-based-boards)
|
||||
|
|
@ -32,34 +36,30 @@ The `float` implementation of `micropython` (`float`, or `double`) is automatica
|
|||
## ndarray methods
|
||||
|
||||
`ulab` implements `numpy`'s `ndarray` with the `==`, `!=`, `<`, `<=`, `>`, `>=`, `+`, `-`, `/`, `*`, `**`,
|
||||
`+=`, `-=`, `*=`, `/=`, `**=` binary operators, and the `len`, `~`, `-`, `+`, `abs` unary operators that
|
||||
`%`, `+=`, `-=`, `*=`, `/=`, `**=`, `%=` 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 via the `array` constructor, or by means of the `arange`, `concatenate`, `diag`, `eye`,
|
||||
`frombuffer`, `full`, `linspace`, `logspace`, `ones`, or `zeros` functions.
|
||||
|
||||
`ndarray`s can be sliced, and iterated on, and have a number of their own methods, and properties, such as `flatten()`, `itemsize`, `reshape()`,
|
||||
`shape`, `size`, `strides`, `tobytes()`, and `transpose()` and `T`.
|
||||
`shape`, `size`, `strides`, `tobytes()`, `tolist()`, and `transpose()` and `T`. If the firmware is compiled with `complex` support,
|
||||
the `imag`, and `real` properties are automatically included.
|
||||
|
||||
## `numpy` and `scipy` functions
|
||||
|
||||
In addition, `ulab` includes [universal functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-universal.html), [many `numpy` functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-functions.html), and functions from the [`numpy.fft`](https://micropython-ulab.readthedocs.io/en/latest/numpy-fft.html), [`numpy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/numpy-linalg.html), [`scipy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/scipy-linalg.html), [`scipy.optimize`](https://micropython-ulab.readthedocs.io/en/latest/scipy-optimize.html), [`scipy.signal`](https://micropython-ulab.readthedocs.io/en/latest/scipy-signal.html), and [`scipy.special`](https://micropython-ulab.readthedocs.io/en/latest/scipy-special.html) modules. A complete list of available routines can be found under [micropython-ulab](https://micropython-ulab.readthedocs.io/en/latest).
|
||||
In addition, `ulab` includes [universal functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-universal.html), [many `numpy` functions](https://micropython-ulab.readthedocs.io/en/latest/numpy-functions.html), and functions from the [`numpy.fft`](https://micropython-ulab.readthedocs.io/en/latest/numpy-fft.html), [`numpy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/numpy-linalg.html), [`numpy.random`](https://micropython-ulab.readthedocs.io/en/latest/numpy-random.html), [`scipy.linalg`](https://micropython-ulab.readthedocs.io/en/latest/scipy-linalg.html), [`scipy.optimize`](https://micropython-ulab.readthedocs.io/en/latest/scipy-optimize.html), [`scipy.signal`](https://micropython-ulab.readthedocs.io/en/latest/scipy-signal.html), and [`scipy.special`](https://micropython-ulab.readthedocs.io/en/latest/scipy-special.html) modules. A complete list of available routines can be found under [micropython-ulab](https://micropython-ulab.readthedocs.io/en/latest).
|
||||
|
||||
## `ulab` utilities
|
||||
|
||||
The [`utils`](https://micropython-ulab.readthedocs.io/en/latest/ulab-utils.html) module contains functions for interfacing with peripheral devices supporting the buffer protocol.
|
||||
The [`utils`](https://micropython-ulab.readthedocs.io/en/latest/ulab-utils.html) module contains functions for
|
||||
interfacing with peripheral devices supporting the buffer protocol. These functions do not have an obvious
|
||||
`numpy` equivalent, but share a similar programming interface, and allow direct data input-output between
|
||||
numerical arrays and hardware components.
|
||||
|
||||
## `user` module
|
||||
|
||||
User-defined functions operating on numerical data can easily be added via the `user` module. This allows for transparent extensions, without having to change anything in the core. Hints as to how to work with `ndarray`s at the C level can be found in the [programming manual](https://micropython-ulab.readthedocs.io/en/latest/ulab-programming.html).
|
||||
|
||||
# Customising the firmware
|
||||
|
||||
If flash space is a concern, unnecessary functions can be excluded from the compiled firmware with
|
||||
pre-processor switches. In addition, `ulab` also has options for trading execution speed for firmware size.
|
||||
A thorough discussion on how the firmware can be customised can be found in the
|
||||
[corresponding section](https://micropython-ulab.readthedocs.io/en/latest/ulab-intro.html#customising-the-firmware)
|
||||
of the user manual.
|
||||
|
||||
# Usage
|
||||
|
||||
`ulab` sports a `numpy/scipy`-compatible interface, which makes porting of `CPython` code straightforward. The following
|
||||
|
|
@ -84,6 +84,8 @@ Documentation can be found on [readthedocs](https://readthedocs.org/) under
|
|||
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 Jeff Epler's excellent
|
||||
[circuitpython-ulab](https://learn.adafruit.com/ulab-crunch-numbers-fast-with-circuitpython/overview) overview.
|
||||
The [tricks](https://micropython-ulab.readthedocs.io/en/latest/ulab-tricks.html) chapter of the user manual discusses
|
||||
methods by which RAM and speed can be leveraged in particular numerical problems.
|
||||
|
||||
# Benchmarks
|
||||
|
||||
|
|
@ -91,16 +93,17 @@ Representative numbers on performance can be found under [ulab samples](https://
|
|||
|
||||
# Firmware
|
||||
|
||||
## Compiled
|
||||
Pre-built, and up-to-date firmware files for select platforms can be downloaded
|
||||
from [micropython-builder](https://github.com/v923z/micropython-builder).
|
||||
## Customising the firmware
|
||||
|
||||
Compiled firmware for many hardware platforms can be downloaded from Roberto Colistete's
|
||||
gitlab repository: for the [pyboard](https://gitlab.com/rcolistete/micropython-samples/-/tree/master/Pyboard/Firmware/), and
|
||||
for [ESP8266](https://gitlab.com/rcolistete/micropython-samples/-/tree/master/ESP8266/Firmware).
|
||||
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.
|
||||
If flash space is a concern, unnecessary functions can be excluded from the compiled firmware with
|
||||
pre-processor switches. In addition, `ulab` also has options for trading execution speed for firmware size.
|
||||
A thorough discussion on how the firmware can be customised can be found in the
|
||||
[corresponding section](https://micropython-ulab.readthedocs.io/en/latest/ulab-intro.html#customising-the-firmware)
|
||||
of the user manual.
|
||||
|
||||
## Platforms including ulab
|
||||
|
||||
`ulab` is also included in the following compiled `micropython` variants and derivatives:
|
||||
|
||||
|
|
@ -109,7 +112,7 @@ in question.
|
|||
1. `MaixPy` https://github.com/sipeed/MaixPy
|
||||
1. `OpenMV` https://github.com/openmv/openmv
|
||||
1. `pimoroni-pico` https://github.com/pimoroni/pimoroni-pico
|
||||
3. `pycom` https://pycom.io/
|
||||
1. `Tulip Creative Computer` https://github.com/shorepine/tulipcc
|
||||
|
||||
## Compiling
|
||||
|
||||
|
|
@ -126,7 +129,7 @@ git clone https://github.com/v923z/micropython-ulab.git ulab
|
|||
and then run
|
||||
|
||||
```bash
|
||||
./build.sh
|
||||
./build.sh [matrix.dims] # Dimensions is 2 by default
|
||||
```
|
||||
This command will clone `micropython`, and build the `unix` port automatically, as well as run the test scripts. If you want an interactive `unix` session, you can launch it in
|
||||
|
||||
|
|
@ -180,7 +183,9 @@ In case you got stuck somewhere in the process, a bit more detailed instructions
|
|||
|
||||
### ESP32-based boards
|
||||
|
||||
Firmware for `Espressif` boards can be built in two different ways. These are discussed in the next two paragraphs. A solution for issues with the firmware size is outlined in the [last paragraph](#what-to-do-if-the-firmware-is-too-large) in this section.
|
||||
`ulab` can be tested on the ESP32 in [wokwi's micropython emulator](https://wokwi.com/arduino/projects/322114140704342610) without having to compile the C code. This utility also offers the possibility to save and share your `micropython` code.
|
||||
|
||||
Firmware for `Espressif` hardware can be built in two different ways, which are discussed in the next two paragraphs. A solution for issues with the firmware size is outlined in the [last paragraph](#what-to-do-if-the-firmware-is-too-large) of this section.
|
||||
|
||||
#### Compiling with cmake
|
||||
|
||||
|
|
@ -358,7 +363,7 @@ This file can be found in `$BUILD_DIR/micropython/ports/esp32/boards/TINYPICO/`.
|
|||
|
||||
### RP2-based boards
|
||||
|
||||
RP2 firmware can be compiled either by downloading and running the single [build script](https://github.com/v923z/micropython-ulab/blob/master/build/rp2.sh), or executing the commands below.
|
||||
RP2 firmware can be compiled either by downloading and running the single [build script](https://github.com/v923z/micropython-ulab/blob/master/build/rp2.sh)/[build script for Pico W](https://github.com/v923z/micropython-ulab/blob/master/build/rp2w.sh), or executing the commands below.
|
||||
|
||||
First, clone `micropython`:
|
||||
|
||||
|
|
|
|||
|
|
@ -35,16 +35,15 @@ readlinkf_posix() {
|
|||
done
|
||||
return 1
|
||||
}
|
||||
NPROC=$(python -c 'import multiprocessing; print(multiprocessing.cpu_count())')
|
||||
NPROC=$(python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())')
|
||||
HERE="$(dirname -- "$(readlinkf_posix -- "${0}")" )"
|
||||
[ -e circuitpython/py/py.mk ] || (git clone --no-recurse-submodules --depth 100 --branch main https://github.com/adafruit/circuitpython && cd circuitpython && git submodule update --init lib/uzlib tools)
|
||||
[ -e circuitpython/py/py.mk ] || (git clone --branch main https://github.com/adafruit/circuitpython && cd circuitpython && make fetch-all-submodules && git submodule update --init lib/uzlib tools)
|
||||
rm -rf circuitpython/extmod/ulab; ln -s "$HERE" circuitpython/extmod/ulab
|
||||
dims=${1-2}
|
||||
make -C circuitpython/mpy-cross -j$NPROC
|
||||
sed -e '/MICROPY_PY_UHASHLIB/s/1/0/' < circuitpython/ports/unix/mpconfigport.h > circuitpython/ports/unix/mpconfigport_ulab.h
|
||||
make -k -C circuitpython/ports/unix -j$NPROC DEBUG=1 MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 MICROPY_SSL_AXTLS=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-DMP_CONFIGFILE=\"<mpconfigport_ulab.h>\" -Wno-tautological-constant-out-of-range-compare -Wno-unknown-pragmas -DULAB_MAX_DIMS=$dims" BUILD=build-$dims PROG=micropython-$dims
|
||||
make -k -C circuitpython/ports/unix -j$NPROC DEBUG=1 MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 MICROPY_SSL_AXTLS=0 MICROPY_PY_USSL=0 CFLAGS_EXTRA="-Wno-tautological-constant-out-of-range-compare -Wno-unknown-pragmas -DULAB_MAX_DIMS=$dims" BUILD=build-$dims PROG=micropython-$dims
|
||||
|
||||
bash test-common.sh "${dims}" "circuitpython/ports/unix/micropython-$dims"
|
||||
# bash test-common.sh "${dims}" "circuitpython/ports/unix/micropython-$dims"
|
||||
|
||||
# Docs don't depend on the dimensionality, so only do it once
|
||||
if [ "$dims" -eq 2 ]; then
|
||||
|
|
|
|||
33
build.sh
33
build.sh
|
|
@ -1,4 +1,7 @@
|
|||
#!/bin/sh
|
||||
|
||||
GIT_HASH=`git describe --abbrev=8 --always`
|
||||
|
||||
# POSIX compliant version
|
||||
readlinkf_posix() {
|
||||
[ "${1:-}" ] || return 1
|
||||
|
|
@ -35,13 +38,33 @@ readlinkf_posix() {
|
|||
return 1
|
||||
}
|
||||
NPROC=`python3 -c 'import multiprocessing; print(multiprocessing.cpu_count())'`
|
||||
PLATFORM=`python3 -c 'import sys; print(sys.platform)'`
|
||||
set -e
|
||||
HERE="$(dirname -- "$(readlinkf_posix -- "${0}")" )"
|
||||
[ -e micropython/py/py.mk ] || git clone --no-recurse-submodules https://github.com/micropython/micropython
|
||||
[ -e micropython/lib/axtls/README ] || (cd micropython && git submodule update --init lib/axtls )
|
||||
dims=${1-2}
|
||||
if [ ! -d "micropython" ] ; then
|
||||
git clone https://github.com/micropython/micropython
|
||||
else
|
||||
git -C micropython pull
|
||||
fi
|
||||
make -C micropython/mpy-cross -j${NPROC}
|
||||
make -C micropython/ports/unix -j${NPROC} axtls
|
||||
make -C micropython/ports/unix -j${NPROC} USER_C_MODULES="${HERE}" DEBUG=1 STRIP=: MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 CFLAGS_EXTRA=-DULAB_MAX_DIMS=$dims BUILD=build-$dims PROG=micropython-$dims
|
||||
make -C micropython/ports/unix submodules
|
||||
make -C micropython/ports/unix -j${NPROC} USER_C_MODULES="${HERE}" DEBUG=1 STRIP=: MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 CFLAGS_EXTRA=-DULAB_MAX_DIMS=$dims CFLAGS_EXTRA+=-DULAB_HASH=$GIT_HASH BUILD=build-$dims PROG=micropython-$dims
|
||||
|
||||
PROG="micropython/ports/unix/build-$dims/micropython-$dims"
|
||||
if [ ! -e "$PROG" ]; then
|
||||
# Older MicroPython revision, executable is still in ports/unix.
|
||||
PROG="micropython/ports/unix/micropython-$dims"
|
||||
fi
|
||||
|
||||
bash test-common.sh "${dims}" "$PROG"
|
||||
|
||||
# Build with single-precision float.
|
||||
make -C micropython/ports/unix -j${NPROC} USER_C_MODULES="${HERE}" DEBUG=1 STRIP=: MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 CFLAGS_EXTRA=-DMICROPY_FLOAT_IMPL=MICROPY_FLOAT_IMPL_FLOAT CFLAGS_EXTRA+=-DULAB_MAX_DIMS=$dims CFLAGS_EXTRA+=-DULAB_HASH=$GIT_HASH BUILD=build-nanbox-$dims PROG=micropython-nanbox-$dims
|
||||
|
||||
# The unix nanbox variant builds as a 32-bit executable and requires gcc-multilib.
|
||||
# macOS doesn't support i386 builds so only build on linux.
|
||||
if [ $PLATFORM = linux ]; then
|
||||
make -C micropython/ports/unix -j${NPROC} VARIANT=nanbox USER_C_MODULES="${HERE}" DEBUG=1 STRIP=: MICROPY_PY_FFI=0 MICROPY_PY_BTREE=0 CFLAGS_EXTRA=-DULAB_MAX_DIMS=$dims CFLAGS_EXTRA+=-DULAB_HASH=$GIT_HASH BUILD=build-nanbox-$dims PROG=micropython-nanbox-$dims
|
||||
fi
|
||||
|
||||
bash test-common.sh "${dims}" "micropython/ports/unix/micropython-$dims"
|
||||
|
|
|
|||
25
build/rp2w.sh
Normal file
25
build/rp2w.sh
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
|
||||
export BOARD=RPI_PICO_W
|
||||
export BUILD_DIR=$(pwd)
|
||||
export MPY_DIR=$BUILD_DIR/micropython
|
||||
export ULAB_DIR=$BUILD_DIR/../code
|
||||
|
||||
if [ ! -d $ULAB_DIR ]; then
|
||||
printf "Cloning ulab\n"
|
||||
ULAB_DIR=$BUILD_DIR/ulab/code
|
||||
git clone https://github.com/v923z/micropython-ulab.git ulab
|
||||
fi
|
||||
|
||||
if [ ! -d $MPY_DIR ]; then
|
||||
printf "Cloning MicroPython\n"
|
||||
git clone https://github.com/micropython/micropython.git micropython
|
||||
fi
|
||||
|
||||
cd $MPY_DIR
|
||||
git submodule update --init
|
||||
cd ./mpy-cross && make # build cross-compiler (required)
|
||||
|
||||
cd $MPY_DIR/ports/rp2
|
||||
make BOARD=$BOARD clean
|
||||
make USER_C_MODULES=$ULAB_DIR/micropython.cmake BOARD=$BOARD
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
USERMODULES_DIR := $(USERMOD_DIR)
|
||||
|
||||
# Add all C files to SRC_USERMOD.
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/scipy/integrate/integrate.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/scipy/linalg/linalg.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/scipy/optimize/optimize.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/scipy/signal/signal.c
|
||||
|
|
@ -12,15 +13,20 @@ SRC_USERMOD += $(USERMODULES_DIR)/ndarray.c
|
|||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/ndarray/ndarray_iter.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/ndarray_properties.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/approx.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/bitwise.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/compare.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/ulab_create.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/carray/carray.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/carray/carray_tools.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/create.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/fft/fft.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/fft/fft_tools.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/filter.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/io/io.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/linalg/linalg.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/linalg/linalg_tools.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/numerical.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/poly.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/random/random.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/stats.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/transform.c
|
||||
SRC_USERMOD += $(USERMODULES_DIR)/numpy/vector.c
|
||||
|
|
|
|||
954
code/ndarray.c
954
code/ndarray.c
File diff suppressed because it is too large
Load diff
249
code/ndarray.h
249
code/ndarray.h
|
|
@ -33,12 +33,58 @@
|
|||
#define FLOAT_TYPECODE 'd'
|
||||
#endif
|
||||
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_A || MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_B
|
||||
|
||||
// For object representations A and B a Python float object is allocated as a
|
||||
// concrete object in a struct, with the first entry pointing to &mp_type_float.
|
||||
// Constant float objects are a struct in ROM and are referenced via their pointer.
|
||||
|
||||
// Use ULAB_DEFINE_FLOAT_CONST to define a constant float object.
|
||||
// id is the name of the constant, num is its floating point value.
|
||||
// hex32 is computed as: hex(int.from_bytes(array.array('f', [num]), 'little'))
|
||||
// hex64 is computed as: hex(int.from_bytes(array.array('d', [num]), 'little'))
|
||||
|
||||
// Use ULAB_REFERENCE_FLOAT_CONST to reference a constant float object in code.
|
||||
|
||||
#define ULAB_DEFINE_FLOAT_CONST(id, num, hex32, hex64) \
|
||||
const mp_obj_float_t id##_obj = {{&mp_type_float}, (num)}
|
||||
|
||||
#define ULAB_REFERENCE_FLOAT_CONST(id) MP_ROM_PTR(&id##_obj)
|
||||
|
||||
// this typedef is lifted from objfloat.c, because mp_obj_float_t is not exposed
|
||||
typedef struct _mp_obj_float_t {
|
||||
mp_obj_base_t base;
|
||||
mp_float_t value;
|
||||
} mp_obj_float_t;
|
||||
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
|
||||
// For object representation C a Python float object is stored directly in the
|
||||
// mp_obj_t value.
|
||||
|
||||
// See above for how to use ULAB_DEFINE_FLOAT_CONST and ULAB_REFERENCE_FLOAT_CONST.
|
||||
|
||||
#define ULAB_DEFINE_FLOAT_CONST(id, num, hex32, hex64) \
|
||||
enum { \
|
||||
id = (((((uint32_t)hex32) & ~3) | 2) + 0x80800000) \
|
||||
}
|
||||
|
||||
#define ULAB_REFERENCE_FLOAT_CONST(id) ((mp_obj_t)(id))
|
||||
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
|
||||
// For object representation D (nan-boxing) a Python float object is stored
|
||||
// directly in the mp_obj_t value.
|
||||
|
||||
// See above for how to use ULAB_DEFINE_FLOAT_CONST and ULAB_REFERENCE_FLOAT_CONST.
|
||||
|
||||
#define ULAB_DEFINE_FLOAT_CONST(id, num, hex32, hex64) \
|
||||
const uint64_t id = (((uint64_t)hex64) + 0x8004000000000000ULL)
|
||||
|
||||
#define ULAB_REFERENCE_FLOAT_CONST(id) {id}
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(MICROPY_VERSION_MAJOR) && MICROPY_VERSION_MAJOR == 1 && MICROPY_VERSION_MINOR == 11
|
||||
typedef struct _mp_obj_slice_t {
|
||||
mp_obj_base_t base;
|
||||
|
|
@ -49,20 +95,25 @@ typedef struct _mp_obj_slice_t {
|
|||
#define MP_ERROR_TEXT(x) x
|
||||
#endif
|
||||
|
||||
#if !defined(MP_TYPE_FLAG_EXTENDED)
|
||||
#define MP_TYPE_CALL call
|
||||
#define mp_type_get_call_slot(t) t->call
|
||||
#if !defined(MP_OBJ_TYPE_GET_SLOT)
|
||||
#if defined(MP_TYPE_FLAG_EXTENDED)
|
||||
// Provide MP_OBJ_TYPE_{HAS,GET}_SLOT for CircuitPython.
|
||||
#define MP_OBJ_TYPE_HAS_SLOT(t, f) (mp_type_get_##f##_slot(t) != NULL)
|
||||
#define MP_OBJ_TYPE_GET_SLOT(t, f) mp_type_get_##f##_slot(t)
|
||||
#else
|
||||
// Provide MP_OBJ_TYPE_{HAS,GET}_SLOT for older revisions of MicroPython.
|
||||
#define MP_OBJ_TYPE_HAS_SLOT(t, f) ((t)->f != NULL)
|
||||
#define MP_OBJ_TYPE_GET_SLOT(t, f) (t)->f
|
||||
|
||||
// Also allow CiruitPython-style mp_obj_type_t definitions.
|
||||
#define MP_TYPE_FLAG_EXTENDED (0)
|
||||
#define MP_TYPE_EXTENDED_FIELDS(...) __VA_ARGS__
|
||||
#endif
|
||||
|
||||
#if !CIRCUITPY
|
||||
#define translate(x) MP_ERROR_TEXT(x)
|
||||
#define ndarray_set_value(a, b, c, d) mp_binary_set_val_array(a, b, c, d)
|
||||
#else
|
||||
void ndarray_set_value(char , void *, size_t , mp_obj_t );
|
||||
#endif
|
||||
|
||||
#define ndarray_set_value(a, b, c, d) mp_binary_set_val_array(a, b, c, d)
|
||||
void ndarray_set_complex_value(void *, size_t , mp_obj_t );
|
||||
|
||||
#define NDARRAY_NUMERIC 0
|
||||
#define NDARRAY_BOOLEAN 1
|
||||
|
||||
|
|
@ -77,6 +128,9 @@ enum NDARRAY_TYPE {
|
|||
NDARRAY_INT8 = 'b',
|
||||
NDARRAY_UINT16 = 'H',
|
||||
NDARRAY_INT16 = 'h',
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
NDARRAY_COMPLEX = 'c',
|
||||
#endif
|
||||
NDARRAY_FLOAT = FLOAT_TYPECODE,
|
||||
};
|
||||
|
||||
|
|
@ -131,14 +185,16 @@ void ndarray_assign_elements(ndarray_obj_t *, mp_obj_t , uint8_t , size_t *);
|
|||
size_t *ndarray_contract_shape(ndarray_obj_t *, uint8_t );
|
||||
int32_t *ndarray_contract_strides(ndarray_obj_t *, uint8_t );
|
||||
|
||||
ndarray_obj_t *ndarray_from_iterable(mp_obj_t , uint8_t );
|
||||
ndarray_obj_t *ndarray_new_dense_ndarray(uint8_t , size_t *, uint8_t );
|
||||
ndarray_obj_t *ndarray_new_ndarray_from_tuple(mp_obj_tuple_t *, uint8_t );
|
||||
ndarray_obj_t *ndarray_new_ndarray(uint8_t , size_t *, int32_t *, uint8_t );
|
||||
ndarray_obj_t *ndarray_new_ndarray(uint8_t , size_t *, int32_t *, uint8_t , uint8_t *);
|
||||
ndarray_obj_t *ndarray_new_linear_array(size_t , uint8_t );
|
||||
ndarray_obj_t *ndarray_new_view(ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t );
|
||||
bool ndarray_is_dense(ndarray_obj_t *);
|
||||
ndarray_obj_t *ndarray_copy_view(ndarray_obj_t *);
|
||||
void ndarray_copy_array(ndarray_obj_t *, ndarray_obj_t *);
|
||||
ndarray_obj_t *ndarray_copy_view_convert_type(ndarray_obj_t *, uint8_t );
|
||||
void ndarray_copy_array(ndarray_obj_t *, ndarray_obj_t *, uint8_t );
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_array_constructor_obj);
|
||||
mp_obj_t ndarray_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *);
|
||||
|
|
@ -168,11 +224,29 @@ mp_obj_t ndarray_flatten(size_t , const mp_obj_t *, mp_map_t *);
|
|||
MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_flatten_obj);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_DTYPE
|
||||
mp_obj_t ndarray_dtype(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_ITEMSIZE
|
||||
mp_obj_t ndarray_itemsize(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_NDIM
|
||||
mp_obj_t ndarray_ndim(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_SIZE
|
||||
mp_obj_t ndarray_size(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_SHAPE
|
||||
mp_obj_t ndarray_shape(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_STRIDES
|
||||
mp_obj_t ndarray_strides(mp_obj_t );
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_RESHAPE
|
||||
mp_obj_t ndarray_reshape_core(mp_obj_t , mp_obj_t , bool );
|
||||
|
|
@ -185,6 +259,11 @@ mp_obj_t ndarray_tobytes(mp_obj_t );
|
|||
MP_DECLARE_CONST_FUN_OBJ_1(ndarray_tobytes_obj);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_TOLIST
|
||||
mp_obj_t ndarray_tolist(mp_obj_t );
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(ndarray_tolist_obj);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_TRANSPOSE
|
||||
mp_obj_t ndarray_transpose(mp_obj_t );
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(ndarray_transpose_obj);
|
||||
|
|
@ -201,15 +280,15 @@ mp_int_t ndarray_get_buffer(mp_obj_t , mp_buffer_info_t *, mp_uint_t );
|
|||
ndarray_obj_t *ndarray_from_mp_obj(mp_obj_t , uint8_t );
|
||||
|
||||
|
||||
#define BOOLEAN_ASSIGNMENT_LOOP(type_left, type_right, ndarray, iarray, istride, varray, vstride)\
|
||||
#define BOOLEAN_ASSIGNMENT_LOOP(type_left, type_right, ndarray, lstrides, iarray, istride, varray, vstride)\
|
||||
type_left *array = (type_left *)(ndarray)->array;\
|
||||
for(size_t i=0; i < (ndarray)->len; i++) {\
|
||||
if(*(iarray)) {\
|
||||
*array = (type_left)(*((type_right *)(varray)));\
|
||||
}\
|
||||
array += (ndarray)->strides[ULAB_MAX_DIMS - 1] / (ndarray)->itemsize;\
|
||||
(iarray) += (istride);\
|
||||
(varray) += (vstride);\
|
||||
}\
|
||||
array += (lstrides);\
|
||||
(iarray) += (istride);\
|
||||
} while(0)
|
||||
|
||||
#if ULAB_HAS_FUNCTION_ITERATOR
|
||||
|
|
@ -635,104 +714,88 @@ ndarray_obj_t *ndarray_from_mp_obj(mp_obj_t , uint8_t );
|
|||
#endif /* ULAB_HAS_FUNCTION_ITERATOR */
|
||||
|
||||
|
||||
// iterator macro for traversing arrays over all dimensions
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\
|
||||
type_left *larray = (type_left *)(results)->array;\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*larray = (type_left)(*((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
#define ITERATOR_HEAD()\
|
||||
size_t _l_ = 0;\
|
||||
do {
|
||||
|
||||
#define ITERATOR_TAIL(_source_, _source_array_)\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 1];\
|
||||
_l_++;\
|
||||
} while(_l_ < (_source_)->shape[ULAB_MAX_DIMS - 1]);
|
||||
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\
|
||||
type_left *larray = (type_left *)(results)->array;\
|
||||
size_t k = 0;\
|
||||
#define ITERATOR_HEAD()\
|
||||
size_t _k_ = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*larray = (type_left)(*((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
size_t _l_ = 0;\
|
||||
do {
|
||||
|
||||
#define ITERATOR_TAIL(_source_, _source_array_)\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 1];\
|
||||
_l_++;\
|
||||
} while(_l_ < (_source_)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 1] * (_source_)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 2];\
|
||||
_k_++;\
|
||||
} while(_k_ < (_source_)->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\
|
||||
type_left *larray = (type_left *)(results)->array;\
|
||||
size_t j = 0;\
|
||||
#define ITERATOR_HEAD()\
|
||||
size_t _j_ = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
size_t _k_ = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*larray = (type_left)(*((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
size_t _l_ = 0;\
|
||||
do {
|
||||
|
||||
#define ITERATOR_TAIL(_source_, _source_array_)\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 1];\
|
||||
_l_++;\
|
||||
} while(_l_ < (_source_)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 1] * (_source_)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 2];\
|
||||
_k_++;\
|
||||
} while(_k_ < (_source_)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 2] * (_source_)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 3];\
|
||||
_j_++;\
|
||||
} while(_j_ < (_source_)->shape[ULAB_MAX_DIMS - 3]);
|
||||
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define ASSIGNMENT_LOOP(results, type_left, type_right, lstrides, rarray, rstrides)\
|
||||
type_left *larray = (type_left *)(results)->array;\
|
||||
size_t i = 0;\
|
||||
#define ITERATOR_HEAD()\
|
||||
size_t _i_ = 0;\
|
||||
do {\
|
||||
size_t j = 0;\
|
||||
size_t _j_ = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
size_t _k_ = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*larray = (type_left)(*((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS-3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
size_t _l_ = 0;\
|
||||
do {
|
||||
|
||||
#define ITERATOR_TAIL(_source_, _source_array_)\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 1];\
|
||||
_l_++;\
|
||||
} while(_l_ < (_source_)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 1] * (_source_)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 2];\
|
||||
_k_++;\
|
||||
} while(_k_ < (_source_)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 2] * (_source_)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 3];\
|
||||
_j_++;\
|
||||
} while(_j_ < (_source_)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(_source_array_) -= (_source_)->strides[ULAB_MAX_DIMS - 3] * (_source_)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(_source_array_) += (_source_)->strides[ULAB_MAX_DIMS - 4];\
|
||||
_i_++;\
|
||||
} while(_i_ < (_source_)->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "ndarray_operators.h"
|
||||
#include "ulab.h"
|
||||
#include "ulab_tools.h"
|
||||
#include "numpy/carray/carray.h"
|
||||
|
||||
/*
|
||||
This file contains the actual implementations of the various
|
||||
|
|
@ -24,7 +25,8 @@
|
|||
|
||||
These are the upcasting rules of the binary operators
|
||||
|
||||
- if one of the operarands is a float, the result is always float
|
||||
- if complex is supported, and if one of the operarands is a complex, the result is always complex
|
||||
- if both operarands are real one of them is a float, then the result is also a float
|
||||
- operation on identical types preserves type
|
||||
|
||||
uint8 + int8 => int16
|
||||
|
|
@ -39,6 +41,12 @@
|
|||
mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides, mp_binary_op_t op) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
return carray_binary_equal_not_equal(lhs, rhs, ndim, shape, lstrides, rstrides, op);
|
||||
}
|
||||
#endif
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
results->boolean = 1;
|
||||
uint8_t *array = (uint8_t *)results->array;
|
||||
|
|
@ -69,7 +77,7 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, ==);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
|
|
@ -79,7 +87,7 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, ==);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
|
|
@ -87,13 +95,13 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, ==);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, ==);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,7 +131,7 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, !=);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
|
|
@ -133,7 +141,7 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, !=);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
|
|
@ -141,13 +149,13 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, !=);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
EQUALITY_LOOP(results, array, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, !=);
|
||||
} else {
|
||||
return ndarray_binary_op(op, rhs, lhs);
|
||||
return ndarray_binary_op(op, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -161,14 +169,20 @@ mp_obj_t ndarray_binary_equality(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
return carray_binary_add(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
}
|
||||
#endif
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, +);
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, +);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, +);
|
||||
|
|
@ -196,7 +210,7 @@ mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, +);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
|
|
@ -209,7 +223,7 @@ mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, +);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
|
|
@ -219,14 +233,14 @@ mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, +);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, +);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_ADD, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -234,8 +248,8 @@ mp_obj_t ndarray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
}
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_ADD */
|
||||
|
||||
#if NDARRAY_HAS_BINARY_OP_MULTIPLY
|
||||
mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
#if NDARRAY_HAS_BINARY_OP_MODULO
|
||||
mp_obj_t ndarray_binary_modulo(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
|
|
@ -244,8 +258,113 @@ mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, *);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, %);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
MODULO_FLOAT_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_MODULO */
|
||||
|
||||
#if NDARRAY_HAS_BINARY_OP_MULTIPLY
|
||||
mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
return carray_binary_multiply(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
}
|
||||
#endif
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, *);
|
||||
|
|
@ -273,7 +392,7 @@ mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
|
|
@ -286,7 +405,7 @@ mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
|
|
@ -296,14 +415,14 @@ mp_obj_t ndarray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, rhs, lhs);
|
||||
return ndarray_binary_op(MP_BINARY_OP_MULTIPLY, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -460,6 +579,12 @@ mp_obj_t ndarray_binary_more(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
mp_obj_t ndarray_binary_subtract(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
return carray_binary_subtract(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
}
|
||||
#endif
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
|
@ -559,6 +684,12 @@ mp_obj_t ndarray_binary_subtract(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
return carray_binary_divide(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
}
|
||||
#endif
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
|
@ -620,7 +751,7 @@ mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP(results, mp_float_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, /);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides, /);
|
||||
BINARY_LOOP(results, mp_float_t, int16_t, mp_float_t, larray, lstrides, rarray, rstrides, /);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
|
|
@ -641,6 +772,102 @@ mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
}
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE */
|
||||
|
||||
#if NDARRAY_HAS_BINARY_OP_FLOOR_DIVIDE
|
||||
mp_obj_t ndarray_binary_floor_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
FLOOR_DIVIDE_LOOP_UINT(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
FLOOR_DIVIDE_LOOP_UINT(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, uint8_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
FLOOR_DIVIDE_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
FLOOR_DIVIDE_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, int8_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
FLOOR_DIVIDE_LOOP_UINT(results, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
FLOOR_DIVIDE_LOOP(results, uint16_t, uint16_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
FLOOR_DIVIDE_LOOP_UINT(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, int16_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
FLOOR_DIVIDE_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, uint16_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, mp_float_t, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, mp_float_t, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, mp_float_t, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, mp_float_t, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
FLOOR_DIVIDE_LOOP_FLOAT(results, mp_float_t, mp_float_t, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
|
||||
}
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_FLOOR_DIVIDE */
|
||||
|
||||
#if NDARRAY_HAS_BINARY_OP_POWER
|
||||
mp_obj_t ndarray_binary_power(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
|
@ -729,11 +956,199 @@ mp_obj_t ndarray_binary_power(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
|||
}
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_POWER */
|
||||
|
||||
#if NDARRAY_HAS_BINARY_OP_OR | NDARRAY_HAS_BINARY_OP_XOR | NDARRAY_HAS_BINARY_OP_AND
|
||||
mp_obj_t ndarray_binary_logical(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides, mp_binary_op_t op) {
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX) || (lhs->dtype == NDARRAY_FLOAT) || (rhs->dtype == NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("operation not supported for the input types"));
|
||||
}
|
||||
#else
|
||||
if((lhs->dtype == NDARRAY_FLOAT) || (rhs->dtype == NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("operation not supported for the input types"));
|
||||
}
|
||||
#endif
|
||||
|
||||
// bail out, if both inputs are of 16-bit types, but differ in sign;
|
||||
// numpy promotes the result to int32
|
||||
if(((lhs->dtype == NDARRAY_INT16) && (rhs->dtype == NDARRAY_UINT16)) ||
|
||||
((lhs->dtype == NDARRAY_UINT16) && (rhs->dtype == NDARRAY_INT16))) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("dtype of int32 is not supported"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
|
||||
switch(op) {
|
||||
case MP_BINARY_OP_XOR:
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
if(lhs->boolean & rhs->boolean) {
|
||||
results->boolean = 1;
|
||||
}
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_XOR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_XOR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_XOR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BINARY_OP_OR:
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
if(lhs->boolean & rhs->boolean) {
|
||||
results->boolean = 1;
|
||||
}
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_OR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_OR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_OR, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case MP_BINARY_OP_AND:
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
if(lhs->boolean & rhs->boolean) {
|
||||
results->boolean = 1;
|
||||
}
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_AND, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
BINARY_LOOP(results, mp_float_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_AND, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return ndarray_binary_op(MP_BINARY_OP_AND, MP_OBJ_FROM_PTR(rhs), MP_OBJ_FROM_PTR(lhs));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return MP_OBJ_NULL; // op not supported
|
||||
break;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
#endif /* NDARRAY_HAS_BINARY_OP_OR | NDARRAY_HAS_BINARY_OP_XOR | NDARRAY_HAS_BINARY_OP_AND */
|
||||
|
||||
#if NDARRAY_HAS_INPLACE_ADD || NDARRAY_HAS_INPLACE_MULTIPLY || NDARRAY_HAS_INPLACE_SUBTRACT
|
||||
mp_obj_t ndarray_inplace_ams(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides, uint8_t optype) {
|
||||
|
||||
if((lhs->dtype != NDARRAY_FLOAT) && (rhs->dtype == NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(translate("cannot cast output with casting rule"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("cannot cast output with casting rule"));
|
||||
}
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
|
@ -743,7 +1158,7 @@ mp_obj_t ndarray_inplace_ams(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rs
|
|||
UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, +=);
|
||||
}
|
||||
#endif
|
||||
#if NDARRAY_HAS_INPLACE_ADD
|
||||
#if NDARRAY_HAS_INPLACE_MULTIPLY
|
||||
if(optype == MP_BINARY_OP_INPLACE_MULTIPLY) {
|
||||
UNWRAP_INPLACE_OPERATOR(lhs, larray, rarray, rstrides, *=);
|
||||
}
|
||||
|
|
@ -758,11 +1173,34 @@ mp_obj_t ndarray_inplace_ams(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rs
|
|||
}
|
||||
#endif /* NDARRAY_HAS_INPLACE_ADD || NDARRAY_HAS_INPLACE_MULTIPLY || NDARRAY_HAS_INPLACE_SUBTRACT */
|
||||
|
||||
|
||||
#if NDARRAY_HAS_INPLACE_MODULO
|
||||
mp_obj_t ndarray_inplace_modulo(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) {
|
||||
if((lhs->dtype != NDARRAY_FLOAT) && (rhs->dtype == NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("results cannot be cast to specified type"));
|
||||
}
|
||||
if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
INLINE_MODULO_FLOAT_LOOP(lhs, uint8_t, larray, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT8) {
|
||||
INLINE_MODULO_FLOAT_LOOP(lhs, int8_t, larray, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
INLINE_MODULO_FLOAT_LOOP(lhs, uint16_t, larray, rarray, rstrides);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
INLINE_MODULO_FLOAT_LOOP(lhs, int16_t, larray, rarray, rstrides);
|
||||
} else {
|
||||
INLINE_MODULO_FLOAT_LOOP(lhs, mp_float_t, larray, rarray, rstrides);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(lhs);
|
||||
}
|
||||
#endif /* NDARRAY_HAS_INPLACE_MODULO */
|
||||
|
||||
#if NDARRAY_HAS_INPLACE_TRUE_DIVIDE
|
||||
mp_obj_t ndarray_inplace_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) {
|
||||
|
||||
if((lhs->dtype != NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(translate("results cannot be cast to specified type"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("results cannot be cast to specified type"));
|
||||
}
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
|
@ -780,13 +1218,13 @@ mp_obj_t ndarray_inplace_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t
|
|||
}
|
||||
return MP_OBJ_FROM_PTR(lhs);
|
||||
}
|
||||
#endif /* NDARRAY_HAS_INPLACE_DIVIDE */
|
||||
#endif /* NDARRAY_HAS_INPLACE_TRUE_DIVIDE */
|
||||
|
||||
#if NDARRAY_HAS_INPLACE_POWER
|
||||
mp_obj_t ndarray_inplace_power(ndarray_obj_t *lhs, ndarray_obj_t *rhs, int32_t *rstrides) {
|
||||
|
||||
if((lhs->dtype != NDARRAY_FLOAT)) {
|
||||
mp_raise_TypeError(translate("results cannot be cast to specified type"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("results cannot be cast to specified type"));
|
||||
}
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
|
|
|||
|
|
@ -5,20 +5,24 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Zoltán Vörös
|
||||
* Copyright (c) 2020-2023 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include "ndarray.h"
|
||||
|
||||
mp_obj_t ndarray_binary_equality(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t );
|
||||
mp_obj_t ndarray_binary_add(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_modulo(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_multiply(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_more(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t );
|
||||
mp_obj_t ndarray_binary_power(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_subtract(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_true_divide(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t ndarray_binary_logical(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t );
|
||||
mp_obj_t ndarray_binary_floor_divide(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
|
||||
mp_obj_t ndarray_inplace_ams(ndarray_obj_t *, ndarray_obj_t *, int32_t *, uint8_t );
|
||||
mp_obj_t ndarray_inplace_modulo(ndarray_obj_t *, ndarray_obj_t *, int32_t *);
|
||||
mp_obj_t ndarray_inplace_power(ndarray_obj_t *, ndarray_obj_t *, int32_t *);
|
||||
mp_obj_t ndarray_inplace_divide(ndarray_obj_t *, ndarray_obj_t *, int32_t *);
|
||||
|
||||
|
|
@ -275,3 +279,436 @@ mp_obj_t ndarray_inplace_divide(ndarray_obj_t *, ndarray_obj_t *, int32_t *);
|
|||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
})
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
#define FLOOR_DIVIDE_UINT1(results, array, type_left, type_right, larray, lstrides, rarray, rstrides)\
|
||||
({\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = *((type_left *)(larray)) / *((type_right *)(rarray));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
})
|
||||
|
||||
#define FLOOR_DIVIDE1(results, array, type_left, type_right, larray, lstrides, rarray, rstrides)\
|
||||
({\
|
||||
size_t l = 0;\
|
||||
int16_t num;\
|
||||
int16_t denom = (int16_t)*((type_right *)(rarray));\
|
||||
do {\
|
||||
num = (int16_t)*((type_left *)(larray));\
|
||||
if(num >= 0) {\
|
||||
if(denom < 0) {\
|
||||
num += -denom - 1;\
|
||||
}\
|
||||
} else {\
|
||||
if(denom >= 0) {\
|
||||
num += -denom + 1;\
|
||||
}\
|
||||
}\
|
||||
*(array)++ = num / denom;\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
})
|
||||
|
||||
#define FLOOR_DIVIDE_FLOAT1(results, array, type_left, type_right, larray, lstrides, rarray, rstrides)\
|
||||
({\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = MICROPY_FLOAT_C_FUN(floor)(*((type_left *)(larray)) / *((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
})
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define FLOOR_DIVIDE_LOOP_UINT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
FLOOR_DIVIDE_UINT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
FLOOR_DIVIDE1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP_FLOAT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
FLOOR_DIVIDE_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define FLOOR_DIVIDE_LOOP_UINT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_UINT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP_FLOAT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define FLOOR_DIVIDE_LOOP_UINT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_UINT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP_FLOAT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define FLOOR_DIVIDE_LOOP_UINT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_UINT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
|
||||
#define FLOOR_DIVIDE_LOOP_FLOAT(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
FLOOR_DIVIDE_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
#define MODULO_FLOAT1(results, array, type_left, type_right, larray, lstrides, rarray, rstrides)\
|
||||
({\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = MICROPY_FLOAT_C_FUN(fmod)(*((type_left *)(larray)), *((type_right *)(rarray)));\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
})
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define MODULO_FLOAT_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
MODULO_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define MODULO_FLOAT_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
MODULO_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define MODULO_FLOAT_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
MODULO_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define MODULO_FLOAT_LOOP(results, type_out, type_left, type_right, larray, lstrides, rarray, rstrides) do {\
|
||||
type_out *array = (type_out *)(results)->array;\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
MODULO_FLOAT1((results), (array), type_left, type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
|
||||
#define INPLACE_MODULO_FLOAT1(results, type_right, larray, rarray, rstrides)\
|
||||
({\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*((mp_float_t *)larray) = MICROPY_FLOAT_C_FUN(fmod)(*((mp_float_t *)(larray)), *((type_right *)(rarray)));\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
})
|
||||
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define INPLACE_MODULO_FLOAT_LOOP(results, type_right, larray, rarray, rstrides) do {\
|
||||
INPLACE_MODULO_FLOAT1((results), type_right, (larray), (rarray), (rstrides));\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define INLINE_MODULO_FLOAT_LOOP(results, type_right, larray, rarray, rstrides) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
INPLACE_MODULO_FLOAT1((results), type_right, (larray), (rarray), (rstrides));\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define INLINE_MODULO_FLOAT_LOOP(results, type_right, larray, rarray, rstrides) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
INPLACE_MODULO_FLOAT1((results), type_right, (larray), (rarray), (rstrides));\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define INLINE_MODULO_FLOAT_LOOP(results, type_right, larray, rarray, rstrides) do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
INPLACE_MODULO_FLOAT1((results), type_right, (larray), (rarray), (rstrides));\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(larray) -= (results)->strides[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (results)->strides[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021 Zoltán Vörös
|
||||
* Copyright (c) 2021-2025 Zoltán Vörös
|
||||
*
|
||||
*/
|
||||
|
||||
|
|
@ -20,29 +20,9 @@
|
|||
#include "ulab.h"
|
||||
#include "ndarray.h"
|
||||
#include "numpy/ndarray/ndarray_iter.h"
|
||||
|
||||
#ifndef CIRCUITPY
|
||||
|
||||
// a somewhat hackish implementation of property getters/setters;
|
||||
// this functions is hooked into the attr member of ndarray
|
||||
|
||||
STATIC void call_local_method(mp_obj_t obj, qstr attr, mp_obj_t *dest) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(obj);
|
||||
while (type->locals_dict != NULL) {
|
||||
assert(type->locals_dict->base.type == &mp_type_dict); // MicroPython restriction, for now
|
||||
mp_map_t *locals_map = &type->locals_dict->map;
|
||||
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||
if (elem != NULL) {
|
||||
mp_convert_member_lookup(obj, type, elem->value, dest);
|
||||
break;
|
||||
}
|
||||
if (type->parent == NULL) {
|
||||
break;
|
||||
}
|
||||
type = type->parent;
|
||||
}
|
||||
}
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#include "numpy/carray/carray.h"
|
||||
#endif
|
||||
|
||||
void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
||||
if (dest[0] == MP_OBJ_NULL) {
|
||||
|
|
@ -62,6 +42,11 @@ void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
dest[0] = ndarray_itemsize(self_in);
|
||||
break;
|
||||
#endif
|
||||
#if NDARRAY_HAS_NDIM
|
||||
case MP_QSTR_ndim:
|
||||
dest[0] = ndarray_ndim(self_in);
|
||||
break;
|
||||
#endif
|
||||
#if NDARRAY_HAS_SHAPE
|
||||
case MP_QSTR_shape:
|
||||
dest[0] = ndarray_shape(self_in);
|
||||
|
|
@ -82,8 +67,21 @@ void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
dest[0] = ndarray_transpose(self_in);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#if ULAB_NUMPY_HAS_IMAG
|
||||
case MP_QSTR_imag:
|
||||
dest[0] = carray_imag(self_in);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_IMAG
|
||||
case MP_QSTR_real:
|
||||
dest[0] = carray_real(self_in);
|
||||
break;
|
||||
#endif
|
||||
#endif /* ULAB_SUPPORTS_COMPLEX */
|
||||
default:
|
||||
call_local_method(self_in, attr, dest);
|
||||
// forward to locals dict
|
||||
dest[1] = MP_OBJ_SENTINEL;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
|
|
@ -104,5 +102,3 @@ void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* CIRCUITPY */
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
* 2020-2021 Zoltán Vörös
|
||||
* 2020-2025 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _NDARRAY_PROPERTIES_
|
||||
|
|
@ -22,83 +22,34 @@
|
|||
#include "ndarray.h"
|
||||
#include "numpy/ndarray/ndarray_iter.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;
|
||||
void ndarray_properties_attr(mp_obj_t , qstr , mp_obj_t *);
|
||||
|
||||
#if NDARRAY_HAS_DTYPE
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_dtype_obj, ndarray_dtype);
|
||||
STATIC const mp_obj_property_t ndarray_dtype_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_get_dtype_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_DTYPE */
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_dtype_obj, ndarray_dtype);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_FLATITER
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_flatiter_make_new_obj, ndarray_flatiter_make_new);
|
||||
STATIC const mp_obj_property_t ndarray_flat_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_flatiter_make_new_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_FLATITER */
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_ITEMSIZE
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_itemsize_obj, ndarray_itemsize);
|
||||
STATIC const mp_obj_property_t ndarray_itemsize_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_get_itemsize_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_ITEMSIZE */
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_NDIM
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_ndim_obj, ndarray_ndim);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_SHAPE
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_shape_obj, ndarray_shape);
|
||||
STATIC const mp_obj_property_t ndarray_shape_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_get_shape_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_SHAPE */
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_SIZE
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_size_obj, ndarray_size);
|
||||
STATIC const mp_obj_property_t ndarray_size_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_get_size_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_SIZE */
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size);
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_STRIDES
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_get_strides_obj, ndarray_strides);
|
||||
STATIC const mp_obj_property_t ndarray_strides_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&ndarray_get_strides_obj,
|
||||
mp_const_none,
|
||||
mp_const_none },
|
||||
};
|
||||
#endif /* NDARRAY_HAS_STRIDES */
|
||||
|
||||
#else
|
||||
|
||||
void ndarray_properties_attr(mp_obj_t , qstr , mp_obj_t *);
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_dtype_obj, ndarray_dtype);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_flatiter_make_new_obj, ndarray_flatiter_make_new);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_itemsize_obj, ndarray_itemsize);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_shape_obj, ndarray_shape);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_size_obj, ndarray_size);
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(ndarray_strides_obj, ndarray_strides);
|
||||
|
||||
#endif /* CIRCUITPY */
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -19,12 +19,13 @@
|
|||
|
||||
#include "../ulab.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "approx.h"
|
||||
|
||||
//| """Numerical approximation methods"""
|
||||
//|
|
||||
|
||||
const mp_obj_float_t approx_trapz_dx = {{&mp_type_float}, MICROPY_FLOAT_CONST(1.0)};
|
||||
ULAB_DEFINE_FLOAT_CONST(approx_trapz_dx, MICROPY_FLOAT_CONST(1.0), 0x3f800000UL, 0x3ff0000000000000ULL);
|
||||
|
||||
#if ULAB_NUMPY_HAS_INTERP
|
||||
//| def interp(
|
||||
|
|
@ -46,13 +47,13 @@ const mp_obj_float_t approx_trapz_dx = {{&mp_type_float}, MICROPY_FLOAT_CONST(1.
|
|||
//| ...
|
||||
//|
|
||||
|
||||
STATIC mp_obj_t approx_interp(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static mp_obj_t approx_interp(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_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_left, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
|
||||
{ MP_QSTR_right, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_left, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
{ MP_QSTR_right, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
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);
|
||||
|
|
@ -60,8 +61,11 @@ STATIC mp_obj_t approx_interp(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
|||
ndarray_obj_t *x = ndarray_from_mp_obj(args[0].u_obj, 0);
|
||||
ndarray_obj_t *xp = ndarray_from_mp_obj(args[1].u_obj, 0); // xp must hold an increasing sequence of independent values
|
||||
ndarray_obj_t *fp = ndarray_from_mp_obj(args[2].u_obj, 0);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(x->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(xp->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(fp->dtype)
|
||||
if((xp->ndim != 1) || (fp->ndim != 1) || (xp->len < 2) || (fp->len < 2) || (xp->len != fp->len)) {
|
||||
mp_raise_ValueError(translate("interp is defined for 1D iterables of equal length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("interp is defined for 1D iterables of equal length"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *y = ndarray_new_linear_array(x->len, NDARRAY_FLOAT);
|
||||
|
|
@ -147,23 +151,24 @@ MP_DEFINE_CONST_FUN_OBJ_KW(approx_interp_obj, 2, approx_interp);
|
|||
//| ...
|
||||
//|
|
||||
|
||||
STATIC mp_obj_t approx_trapz(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static mp_obj_t approx_trapz(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_x, MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_dx, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&approx_trapz_dx)} },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_x, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_dx, MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(approx_trapz_dx)} },
|
||||
};
|
||||
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);
|
||||
|
||||
ndarray_obj_t *y = ndarray_from_mp_obj(args[0].u_obj, 0);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(y->dtype)
|
||||
ndarray_obj_t *x;
|
||||
mp_float_t mean = MICROPY_FLOAT_CONST(0.0);
|
||||
if(y->len < 2) {
|
||||
return mp_obj_new_float(mean);
|
||||
}
|
||||
if((y->ndim != 1)) {
|
||||
mp_raise_ValueError(translate("trapz is defined for 1D iterables"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("trapz is defined for 1D iterables"));
|
||||
}
|
||||
|
||||
mp_float_t (*funcy)(void *) = ndarray_get_float_function(y->dtype);
|
||||
|
|
@ -174,8 +179,9 @@ STATIC mp_obj_t approx_trapz(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
|
|||
|
||||
if(args[1].u_obj != mp_const_none) {
|
||||
x = ndarray_from_mp_obj(args[1].u_obj, 0); // x must hold an increasing sequence of independent values
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(x->dtype)
|
||||
if((x->ndim != 1) || (y->len != x->len)) {
|
||||
mp_raise_ValueError(translate("trapz is defined for 1D arrays of equal length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("trapz is defined for 1D arrays of equal length"));
|
||||
}
|
||||
|
||||
mp_float_t (*funcx)(void *) = ndarray_get_float_function(x->dtype);
|
||||
|
|
|
|||
431
code/numpy/bitwise.c
Normal file
431
code/numpy/bitwise.c
Normal file
|
|
@ -0,0 +1,431 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Zoltán Vörös
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "bitwise.h"
|
||||
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_AND
|
||||
ndarray_obj_t *bitwise_bitwise_and_loop(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
// AND is commutative, so simply swap the order, if a particular combination has already been inspected
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return bitwise_bitwise_and_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return bitwise_bitwise_and_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, &);
|
||||
} else {
|
||||
return bitwise_bitwise_and_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_OR
|
||||
ndarray_obj_t *bitwise_bitwise_or_loop(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
// OR is commutative, so simply swap the order, if a particular combination has already been inspected
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return bitwise_bitwise_or_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return bitwise_bitwise_or_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, |);
|
||||
} else {
|
||||
return bitwise_bitwise_or_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_XOR
|
||||
ndarray_obj_t *bitwise_bitwise_xor_loop(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
// OR is commutative, so simply swap the order, if a particular combination has already been inspected
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return bitwise_bitwise_xor_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return bitwise_bitwise_xor_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_INT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, ^);
|
||||
} else {
|
||||
return bitwise_bitwise_xor_loop(rhs, lhs, ndim, shape, rstrides, lstrides);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_LEFT_SHIFT
|
||||
ndarray_obj_t *bitwise_left_shift_loop(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, <<);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_RIGHT_SHIFT
|
||||
ndarray_obj_t *bitwise_right_shift_loop(ndarray_obj_t *lhs, ndarray_obj_t *rhs, uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
ndarray_obj_t *results = NULL;
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
BINARY_LOOP(results, uint8_t, uint8_t, uint8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint8_t, uint16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint8_t, int16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, uint8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, int8_t, uint16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int8_t, int16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT8);
|
||||
BINARY_LOOP(results, int8_t, int8_t, int8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, uint16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
}
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, uint8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int8_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, uint16_t, uint16_t, int16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
} else {
|
||||
results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_INT16);
|
||||
BINARY_LOOP(results, int16_t, int16_t, int16_t, larray, lstrides, rarray, rstrides, >>);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t *bitwise_binary_operators(mp_obj_t x1, mp_obj_t x2, uint8_t optype) {
|
||||
ndarray_obj_t *lhs = ndarray_from_mp_obj(x1, 0);
|
||||
ndarray_obj_t *rhs = ndarray_from_mp_obj(x2, 0);
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_FLOAT) || (rhs->dtype == NDARRAY_FLOAT) || (lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("not supported for input types"));
|
||||
}
|
||||
#else
|
||||
if((lhs->dtype == NDARRAY_FLOAT) || (rhs->dtype == NDARRAY_FLOAT)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("not supported for input types"));
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t ndim = 0;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *lstrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
int32_t *rstrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
|
||||
if(!ndarray_can_broadcast(lhs, rhs, &ndim, shape, lstrides, rstrides)) {
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, lstrides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("operands could not be broadcast together"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
|
||||
switch(optype) {
|
||||
#if ULAB_NUMPY_HAS_BITWISE_AND
|
||||
case BITWISE_AND:
|
||||
results = bitwise_bitwise_and_loop(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_BITWISE_OR
|
||||
case BITWISE_OR:
|
||||
results = bitwise_bitwise_or_loop(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_BITWISE_XOR
|
||||
case BITWISE_XOR:
|
||||
results = bitwise_bitwise_xor_loop(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LEFT_SHIFT
|
||||
case BITWISE_LEFT_SHIFT:
|
||||
results = bitwise_left_shift_loop(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
break;
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_RIGHT_SHIFT
|
||||
case BITWISE_RIGHT_SHIFT:
|
||||
results = bitwise_right_shift_loop(lhs, rhs, ndim, shape, lstrides, rstrides);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, lstrides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_AND
|
||||
mp_obj_t bitwise_bitwise_and(mp_obj_t x1, mp_obj_t x2) {
|
||||
return bitwise_binary_operators(x1, x2, BITWISE_AND);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(bitwise_bitwise_and_obj, bitwise_bitwise_and);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_OR
|
||||
mp_obj_t bitwise_bitwise_or(mp_obj_t x1, mp_obj_t x2) {
|
||||
return bitwise_binary_operators(x1, x2, BITWISE_OR);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(bitwise_bitwise_or_obj, bitwise_bitwise_or);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_BITWISE_XOR
|
||||
mp_obj_t bitwise_bitwise_xor(mp_obj_t x1, mp_obj_t x2) {
|
||||
return bitwise_binary_operators(x1, x2, BITWISE_XOR);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(bitwise_bitwise_xor_obj, bitwise_bitwise_xor);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_LEFT_SHIFT
|
||||
mp_obj_t bitwise_left_shift(mp_obj_t x1, mp_obj_t x2) {
|
||||
return bitwise_binary_operators(x1, x2, BITWISE_LEFT_SHIFT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(left_shift_obj, bitwise_left_shift);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_RIGHT_SHIFT
|
||||
mp_obj_t bitwise_right_shift(mp_obj_t x1, mp_obj_t x2) {
|
||||
return bitwise_binary_operators(x1, x2, BITWISE_RIGHT_SHIFT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(right_shift_obj, bitwise_right_shift);
|
||||
#endif
|
||||
32
code/numpy/bitwise.h
Normal file
32
code/numpy/bitwise.h
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2023 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _BITWISE_
|
||||
#define _BITWISE_
|
||||
|
||||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
enum BITWISE_FUNCTION_TYPE {
|
||||
BITWISE_AND,
|
||||
BITWISE_OR,
|
||||
BITWISE_XOR,
|
||||
BITWISE_LEFT_SHIFT,
|
||||
BITWISE_RIGHT_SHIFT,
|
||||
};
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(bitwise_bitwise_and_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(bitwise_bitwise_or_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(bitwise_bitwise_xor_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(left_shift_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(right_shift_obj);
|
||||
|
||||
#endif /* _BITWISE_ */
|
||||
834
code/numpy/carray/carray.c
Normal file
834
code/numpy/carray/carray.c
Normal file
|
|
@ -0,0 +1,834 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021-2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/objint.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/builtin.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "carray.h"
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
|
||||
//| import builtins
|
||||
//|
|
||||
//| import ulab.numpy
|
||||
|
||||
//| def real(val: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| Return the real part of the complex argument, which can be
|
||||
//| either an ndarray, or a scalar."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t carray_real(mp_obj_t _source) {
|
||||
if(mp_obj_is_type(_source, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(_source);
|
||||
if(source->dtype != NDARRAY_COMPLEX) {
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(source->ndim, source->shape, source->dtype);
|
||||
ndarray_copy_array(source, target, 0);
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
} else { // the input is most definitely a complex array
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_FLOAT);
|
||||
ndarray_copy_array(source, target, 0);
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
} else {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("function is implemented for ndarrays only"));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(carray_real_obj, carray_real);
|
||||
|
||||
//| def imag(val: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| Return the imaginary part of the complex argument, which can be
|
||||
//| either an ndarray, or a scalar."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t carray_imag(mp_obj_t _source) {
|
||||
if(mp_obj_is_type(_source, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(_source);
|
||||
if(source->dtype != NDARRAY_COMPLEX) { // if not complex, then the imaginary part is zero
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(source->ndim, source->shape, source->dtype);
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
} else { // the input is most definitely a complex array
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_FLOAT);
|
||||
ndarray_copy_array(source, target, source->itemsize / 2);
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
} else {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("function is implemented for ndarrays only"));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(carray_imag_obj, carray_imag);
|
||||
|
||||
#if ULAB_NUMPY_HAS_CONJUGATE
|
||||
|
||||
//| def conjugate(
|
||||
//| val: builtins.complex | ulab.numpy.ndarray
|
||||
//| ) -> builtins.complex | ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| Return the conjugate of the complex argument, which can be
|
||||
//| either an ndarray, or a scalar."""
|
||||
//| ...
|
||||
//|
|
||||
mp_obj_t carray_conjugate(mp_obj_t _source) {
|
||||
if(mp_obj_is_type(_source, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(_source);
|
||||
ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, source->dtype);
|
||||
ndarray_copy_array(source, ndarray, 0);
|
||||
if(source->dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
array++;
|
||||
for(size_t i = 0; i < ndarray->len; i++) {
|
||||
*array *= MICROPY_FLOAT_CONST(-1.0);
|
||||
array += 2;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
} else {
|
||||
if(mp_obj_is_type(_source, &mp_type_complex)) {
|
||||
mp_float_t real, imag;
|
||||
mp_obj_get_complex(_source, &real, &imag);
|
||||
imag = imag * MICROPY_FLOAT_CONST(-1.0);
|
||||
return mp_obj_new_complex(real, imag);
|
||||
} else if(mp_obj_is_int(_source) || mp_obj_is_float(_source)) {
|
||||
return _source;
|
||||
} else {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be an ndarray, or a scalar"));
|
||||
}
|
||||
}
|
||||
// this should never happen
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(carray_conjugate_obj, carray_conjugate);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_SORT_COMPLEX
|
||||
//| def sort_complex(a: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| .. param: a
|
||||
//| a one-dimensional ndarray
|
||||
//|
|
||||
//| Sort a complex array using the real part first, then the imaginary part.
|
||||
//| Always returns a sorted complex array, even if the input was real."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static void carray_sort_complex_(mp_float_t *array, size_t len) {
|
||||
// array is assumed to be a floating vector containing the real and imaginary parts
|
||||
// of a complex array at alternating positions as
|
||||
// array[0] = real[0]
|
||||
// array[1] = imag[0]
|
||||
// array[2] = real[1]
|
||||
// array[3] = imag[1]
|
||||
|
||||
mp_float_t real, imag;
|
||||
size_t c, q = len, p, r = len >> 1;
|
||||
for (;;) {
|
||||
if (r > 0) {
|
||||
r--;
|
||||
real = array[2 * r];
|
||||
imag = array[2 * r + 1];
|
||||
} else {
|
||||
q--;
|
||||
if(q == 0) {
|
||||
break;
|
||||
}
|
||||
real = array[2 * q];
|
||||
imag = array[2 * q + 1];
|
||||
array[2 * q] = array[0];
|
||||
array[2 * q + 1] = array[1];
|
||||
}
|
||||
p = r;
|
||||
c = r + r + 1;
|
||||
while (c < q) {
|
||||
if(c + 1 < q) {
|
||||
if((array[2 * (c+1)] > array[2 * c]) ||
|
||||
((array[2 * (c+1)] == array[2 * c]) && (array[2 * (c+1) + 1] > array[2 * c + 1]))) {
|
||||
c++;
|
||||
}
|
||||
}
|
||||
if((array[2 * c] > real) ||
|
||||
((array[2 * c] == real) && (array[2 * c + 1] > imag))) {
|
||||
array[2 * p] = array[2 * c]; // real part
|
||||
array[2 * p + 1] = array[2 * c + 1]; // imag part
|
||||
p = c;
|
||||
c = p + p + 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
array[2 * p] = real;
|
||||
array[2 * p + 1] = imag;
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t carray_sort_complex(mp_obj_t _source) {
|
||||
if(!mp_obj_is_type(_source, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be a 1D ndarray"));
|
||||
}
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(_source);
|
||||
if(source->ndim != 1) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be a 1D ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = ndarray_copy_view_convert_type(source, NDARRAY_COMPLEX);
|
||||
|
||||
if(ndarray->len != 0) {
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
carray_sort_complex_(array, ndarray->len);
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(carray_sort_complex_obj, carray_sort_complex);
|
||||
#endif
|
||||
|
||||
//| def abs(a: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| .. param: a
|
||||
//| a one-dimensional ndarray
|
||||
//|
|
||||
//| Return the absolute value of complex ndarray."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t carray_abs(ndarray_obj_t *source, ndarray_obj_t *target) {
|
||||
// calculates the absolute value of a complex array and returns a dense array
|
||||
uint8_t *sarray = (uint8_t *)source->array;
|
||||
mp_float_t *tarray = (mp_float_t *)target->array;
|
||||
uint8_t itemsize = mp_binary_get_size('@', NDARRAY_FLOAT, NULL);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
mp_float_t rvalue = *(mp_float_t *)sarray;
|
||||
mp_float_t ivalue = *(mp_float_t *)(sarray + itemsize);
|
||||
*tarray++ = MICROPY_FLOAT_C_FUN(sqrt)(rvalue * rvalue + ivalue * ivalue);
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < source->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < source->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < source->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < source->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
|
||||
static void carray_copy_part(uint8_t *tarray, uint8_t *sarray, size_t *shape, int32_t *strides) {
|
||||
// copies the real or imaginary part of an array
|
||||
// into the respective part of a dense complex array
|
||||
uint8_t sz = sizeof(mp_float_t);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
memcpy(tarray, sarray, sz);
|
||||
tarray += 2 * sz;
|
||||
sarray += strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
sarray -= strides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS-1];
|
||||
sarray += strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
sarray -= strides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS-2];
|
||||
sarray += strides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
sarray -= strides[ULAB_MAX_DIMS - 3] * shape[ULAB_MAX_DIMS-3];
|
||||
sarray += strides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
}
|
||||
|
||||
mp_obj_t carray_binary_equal_not_equal(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides, mp_binary_op_t op) {
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_UINT8);
|
||||
results->boolean = 1;
|
||||
uint8_t *array = (uint8_t *)results->array;
|
||||
|
||||
if(op == MP_BINARY_OP_NOT_EQUAL) {
|
||||
memset(array, 1, results->len);
|
||||
}
|
||||
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) && (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
|
||||
ulab_rescale_float_strides(lstrides);
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
if((larray[0] == rarray[0]) && (larray[1] == rarray[1])) {
|
||||
*array ^= 0x01;
|
||||
}
|
||||
array++;
|
||||
larray += lstrides[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < results->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < results->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < results->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < results->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
} else { // only one of the operands is complex
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
// align the complex array to the left
|
||||
uint8_t rdtype = rhs->dtype;
|
||||
int32_t *lstrides_ = lstrides;
|
||||
int32_t *rstrides_ = rstrides;
|
||||
|
||||
if(rhs->dtype == NDARRAY_COMPLEX) {
|
||||
larray = (mp_float_t *)rhs->array;
|
||||
rarray = (uint8_t *)lhs->array;
|
||||
lstrides_ = rstrides;
|
||||
rstrides_ = lstrides;
|
||||
rdtype = lhs->dtype;
|
||||
}
|
||||
|
||||
ulab_rescale_float_strides(lstrides_);
|
||||
|
||||
if(rdtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX_EQUAL(results, array, uint8_t, larray, lstrides_, rarray, rstrides_);
|
||||
} else if(rdtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX_EQUAL(results, array, int8_t, larray, lstrides_, rarray, rstrides_);
|
||||
} else if(rdtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX_EQUAL(results, array, uint16_t, larray, lstrides_, rarray, rstrides_);
|
||||
} else if(rdtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX_EQUAL(results, array, int16_t, larray, lstrides_, rarray, rstrides_);
|
||||
} else if(rdtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX_EQUAL(results, array, mp_float_t, larray, lstrides_, rarray, rstrides_);
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
mp_obj_t carray_binary_add(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_COMPLEX);
|
||||
mp_float_t *resarray = (mp_float_t *)results->array;
|
||||
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) && (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
|
||||
ulab_rescale_float_strides(lstrides);
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
// real part
|
||||
*resarray++ = larray[0] + rarray[0];
|
||||
// imaginary part
|
||||
*resarray++ = larray[1] + rarray[1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < results->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < results->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < results->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < results->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
} else { // only one of the operands is complex
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
|
||||
// align the complex array to the left
|
||||
uint8_t rdtype = rhs->dtype;
|
||||
int32_t *lstrides_ = lstrides;
|
||||
int32_t *rstrides_ = rstrides;
|
||||
|
||||
if(rhs->dtype == NDARRAY_COMPLEX) {
|
||||
larray = (uint8_t *)rhs->array;
|
||||
rarray = (uint8_t *)lhs->array;
|
||||
lstrides_ = rstrides;
|
||||
rstrides_ = lstrides;
|
||||
rdtype = lhs->dtype;
|
||||
}
|
||||
|
||||
if(rdtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint8_t, larray, lstrides_, rarray, rstrides_, +);
|
||||
} else if(rdtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int8_t, larray, lstrides_, rarray, rstrides_, +);
|
||||
} else if(rdtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint16_t, larray, lstrides_, rarray, rstrides_, +);
|
||||
} else if(rdtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int16_t, larray, lstrides_, rarray, rstrides_, +);
|
||||
} else if(rdtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, mp_float_t, larray, lstrides_, rarray, rstrides_, +);
|
||||
}
|
||||
|
||||
// simply copy the imaginary part
|
||||
uint8_t *tarray = (uint8_t *)results->array;
|
||||
tarray += sizeof(mp_float_t);
|
||||
|
||||
if(lhs->dtype == NDARRAY_COMPLEX) {
|
||||
rarray = (uint8_t *)lhs->array;
|
||||
rstrides = lstrides;
|
||||
} else {
|
||||
rarray = (uint8_t *)rhs->array;
|
||||
}
|
||||
rarray += sizeof(mp_float_t);
|
||||
carray_copy_part(tarray, rarray, results->shape, rstrides);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
static void carray_binary_multiply_(ndarray_obj_t *results, mp_float_t *resarray, uint8_t *larray, uint8_t *rarray,
|
||||
int32_t *lstrides, int32_t *rstrides, uint8_t rdtype) {
|
||||
|
||||
if(rdtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint8_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else if(rdtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int8_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else if(rdtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint16_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else if(rdtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int16_t, larray, lstrides, rarray, rstrides, *);
|
||||
} else if(rdtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, mp_float_t, larray, lstrides, rarray, rstrides, *);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t carray_binary_multiply(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_COMPLEX);
|
||||
mp_float_t *resarray = (mp_float_t *)results->array;
|
||||
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) && (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
|
||||
ulab_rescale_float_strides(lstrides);
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
// real part
|
||||
*resarray++ = larray[0] * rarray[0] - larray[1] * rarray[1];
|
||||
// imaginary part
|
||||
*resarray++ = larray[0] * rarray[1] + larray[1] * rarray[0];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < results->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < results->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < results->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < results->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
} else { // only one of the operands is complex
|
||||
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
uint8_t *lo = larray, *ro = rarray;
|
||||
int32_t *left_strides = lstrides;
|
||||
int32_t *right_strides = rstrides;
|
||||
uint8_t rdtype = rhs->dtype;
|
||||
|
||||
// align the complex array to the left
|
||||
if(rhs->dtype == NDARRAY_COMPLEX) {
|
||||
lo = (uint8_t *)rhs->array;
|
||||
ro = (uint8_t *)lhs->array;
|
||||
rdtype = lhs->dtype;
|
||||
left_strides = rstrides;
|
||||
right_strides = lstrides;
|
||||
}
|
||||
|
||||
larray = lo;
|
||||
rarray = ro;
|
||||
// real part
|
||||
carray_binary_multiply_(results, resarray, larray, rarray, left_strides, right_strides, rdtype);
|
||||
|
||||
larray = lo + sizeof(mp_float_t);
|
||||
rarray = ro;
|
||||
resarray = (mp_float_t *)results->array;
|
||||
resarray++;
|
||||
// imaginary part
|
||||
carray_binary_multiply_(results, resarray, larray, rarray, left_strides, right_strides, rdtype);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
mp_obj_t carray_binary_subtract(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_COMPLEX);
|
||||
mp_float_t *resarray = (mp_float_t *)results->array;
|
||||
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) && (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
|
||||
ulab_rescale_float_strides(lstrides);
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
// real part
|
||||
*resarray++ = larray[0] - rarray[0];
|
||||
// imaginary part
|
||||
*resarray++ = larray[1] - rarray[1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < results->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < results->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < results->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < results->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
} else {
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
if(lhs->dtype == NDARRAY_COMPLEX) {
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
if(rhs->dtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint8_t, larray, lstrides, rarray, rstrides, -);
|
||||
} else if(rhs->dtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int8_t, larray, lstrides, rarray, rstrides, -);
|
||||
} else if(rhs->dtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint16_t, larray, lstrides, rarray, rstrides, -);
|
||||
} else if(rhs->dtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int16_t, larray, lstrides, rarray, rstrides, -);
|
||||
} else if(rhs->dtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, mp_float_t, larray, lstrides, rarray, rstrides, -);
|
||||
}
|
||||
// copy the imaginary part
|
||||
uint8_t *tarray = (uint8_t *)results->array;
|
||||
tarray += sizeof(mp_float_t);
|
||||
|
||||
larray = (uint8_t *)lhs->array;
|
||||
larray += sizeof(mp_float_t);
|
||||
|
||||
carray_copy_part(tarray, larray, results->shape, lstrides);
|
||||
} else if(rhs->dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT(results, resarray, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT(results, resarray, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT(results, resarray, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT(results, resarray, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT(results, resarray, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
static void carray_binary_left_divide_(ndarray_obj_t *results, mp_float_t *resarray, uint8_t *larray, uint8_t *rarray,
|
||||
int32_t *lstrides, int32_t *rstrides, uint8_t rdtype) {
|
||||
|
||||
if(rdtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint8_t, larray, lstrides, rarray, rstrides, /);
|
||||
} else if(rdtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int8_t, larray, lstrides, rarray, rstrides, /);
|
||||
} else if(rdtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, uint16_t, larray, lstrides, rarray, rstrides, /);
|
||||
} else if(rdtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, int16_t, larray, lstrides, rarray, rstrides, /);
|
||||
} else if(rdtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX(results, resarray, mp_float_t, larray, lstrides, rarray, rstrides, /);
|
||||
}
|
||||
}
|
||||
|
||||
mp_obj_t carray_binary_divide(ndarray_obj_t *lhs, ndarray_obj_t *rhs,
|
||||
uint8_t ndim, size_t *shape, int32_t *lstrides, int32_t *rstrides) {
|
||||
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_COMPLEX);
|
||||
mp_float_t *resarray = (mp_float_t *)results->array;
|
||||
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) && (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
mp_float_t *larray = (mp_float_t *)lhs->array;
|
||||
mp_float_t *rarray = (mp_float_t *)rhs->array;
|
||||
|
||||
ulab_rescale_float_strides(lstrides);
|
||||
ulab_rescale_float_strides(rstrides);
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
// (a + bi) / (c + di) =
|
||||
// (ac + bd) / (c^2 + d^2) + i (bc - ad) / (c^2 + d^2)
|
||||
// denominator
|
||||
mp_float_t denom = rarray[0] * rarray[0] + rarray[1] * rarray[1];
|
||||
|
||||
// real part
|
||||
*resarray++ = (larray[0] * rarray[0] + larray[1] * rarray[1]) / denom;
|
||||
// imaginary part
|
||||
*resarray++ = (larray[1] * rarray[0] - larray[0] * rarray[1]) / denom;
|
||||
larray += lstrides[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < results->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * results->shape[ULAB_MAX_DIMS-1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < results->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * results->shape[ULAB_MAX_DIMS-2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < results->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif /* ULAB_MAX_DIMS > 2 */
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
larray -= lstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
larray += lstrides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * results->shape[ULAB_MAX_DIMS-3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < results->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif /* ULAB_MAX_DIMS > 3 */
|
||||
} else {
|
||||
uint8_t *larray = (uint8_t *)lhs->array;
|
||||
uint8_t *rarray = (uint8_t *)rhs->array;
|
||||
if(lhs->dtype == NDARRAY_COMPLEX) {
|
||||
// real part
|
||||
carray_binary_left_divide_(results, resarray, larray, rarray, lstrides, rstrides, rhs->dtype);
|
||||
// imaginary part
|
||||
resarray = (mp_float_t *)results->array;
|
||||
resarray++;
|
||||
larray = (uint8_t *)lhs->array;
|
||||
larray += sizeof(mp_float_t);
|
||||
rarray = (uint8_t *)rhs->array;
|
||||
carray_binary_left_divide_(results, resarray, larray, rarray, lstrides, rstrides, rhs->dtype);
|
||||
} else {
|
||||
if(lhs->dtype == NDARRAY_UINT8) {
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE(results, resarray, uint8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_INT8) {
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE(results, resarray, int8_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_UINT16) {
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE(results, resarray, uint16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_INT16) {
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE(results, resarray, int16_t, larray, lstrides, rarray, rstrides);
|
||||
} else if(lhs->dtype == NDARRAY_FLOAT) {
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE(results, resarray, mp_float_t, larray, lstrides, rarray, rstrides);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
#endif
|
||||
237
code/numpy/carray/carray.h
Normal file
237
code/numpy/carray/carray.h
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2021-2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _CARRAY_
|
||||
#define _CARRAY_
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(carray_real_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(carray_imag_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(carray_conjugate_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(carray_sort_complex_obj);
|
||||
|
||||
|
||||
mp_obj_t carray_imag(mp_obj_t );
|
||||
mp_obj_t carray_real(mp_obj_t );
|
||||
|
||||
mp_obj_t carray_abs(ndarray_obj_t *, ndarray_obj_t *);
|
||||
mp_obj_t carray_binary_add(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t carray_binary_multiply(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t carray_binary_subtract(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t carray_binary_divide(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *);
|
||||
mp_obj_t carray_binary_equal_not_equal(ndarray_obj_t *, ndarray_obj_t *, uint8_t , size_t *, int32_t *, int32_t *, mp_binary_op_t );
|
||||
|
||||
#define BINARY_LOOP_COMPLEX1(results, resarray, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(resarray) = *((mp_float_t *)(larray)) OPERATOR *((type_right *)(rarray));\
|
||||
(resarray) += 2;\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX2(results, resarray, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX1((results), (resarray), type_right, (larray), (lstrides), (rarray), (rstrides), OPERATOR);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX3(results, resarray, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX2((results), (resarray), type_right, (larray), (lstrides), (rarray), (rstrides), OPERATOR);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX4(results, resarray, type_right, larray, lstrides, rarray, rstrides, OPERATOR)\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX3((results), (resarray), type_right, (larray), (lstrides), (rarray), (rstrides), OPERATOR);\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT1(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(resarray)++ = *((type_left *)(larray)) - (rarray)[0];\
|
||||
*(resarray)++ = -(rarray)[1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT2(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT1((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS-1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT3(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT2((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT4(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT3((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE1(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
mp_float_t *c = (mp_float_t *)(rarray);\
|
||||
mp_float_t denom = c[0] * c[0] + c[1] * c[1];\
|
||||
mp_float_t a = *((type_left *)(larray)) / denom;\
|
||||
*(resarray)++ = a * c[0];\
|
||||
*(resarray)++ = -a * c[1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE2(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE1((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE3(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE2((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE4(results, resarray, type_left, larray, lstrides, rarray, rstrides)\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_RIGHT_DIVIDE3((results), (resarray), type_left, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL1(results, array, type_right, larray, lstrides, rarray, rstrides)\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
if((*(larray) == *((type_right *)(rarray))) && ((larray)[1] == MICROPY_FLOAT_CONST(0.0))) {\
|
||||
*(array) ^= 0x01;\
|
||||
}\
|
||||
(array)++;\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (results)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL2(results, array, type_right, larray, lstrides, rarray, rstrides)\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_EQUAL1((results), (array), type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 1] * (results)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (results)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL3(results, array, type_right, larray, lstrides, rarray, rstrides)\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_EQUAL2((results), (array), type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 2] * (results)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (results)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL4(results, array, type_right, larray, lstrides, rarray, rstrides)\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
BINARY_LOOP_COMPLEX_EQUAL3((results), (array), type_right, (larray), (lstrides), (rarray), (rstrides));\
|
||||
(larray) -= (lstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(larray) += (lstrides)[ULAB_MAX_DIMS - 4];\
|
||||
(rarray) -= (rstrides)[ULAB_MAX_DIMS - 3] * (results)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(rarray) += (rstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (results)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define BINARY_LOOP_COMPLEX BINARY_LOOP_COMPLEX1
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT1
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE BINARY_LOOP_COMPLEX_RIGHT_DIVIDE1
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL BINARY_LOOP_COMPLEX_EQUAL1
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define BINARY_LOOP_COMPLEX BINARY_LOOP_COMPLEX2
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT2
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE BINARY_LOOP_COMPLEX_RIGHT_DIVIDE2
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL BINARY_LOOP_COMPLEX_EQUAL2
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define BINARY_LOOP_COMPLEX BINARY_LOOP_COMPLEX3
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT3
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE BINARY_LOOP_COMPLEX_RIGHT_DIVIDE3
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL BINARY_LOOP_COMPLEX_EQUAL3
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define BINARY_LOOP_COMPLEX BINARY_LOOP_COMPLEX4
|
||||
#define BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT BINARY_LOOP_COMPLEX_REVERSED_SUBTRACT4
|
||||
#define BINARY_LOOP_COMPLEX_RIGHT_DIVIDE BINARY_LOOP_COMPLEX_RIGHT_DIVIDE4
|
||||
#define BINARY_LOOP_COMPLEX_EQUAL BINARY_LOOP_COMPLEX_EQUAL4
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
#endif
|
||||
28
code/numpy/carray/carray_tools.c
Normal file
28
code/numpy/carray/carray_tools.c
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
|
||||
void raise_complex_NotImplementedError(void) {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("not implemented for complex dtype"));
|
||||
}
|
||||
|
||||
#endif
|
||||
25
code/numpy/carray/carray_tools.h
Normal file
25
code/numpy/carray/carray_tools.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _CARRAY_TOOLS_
|
||||
#define _CARRAY_TOOLS_
|
||||
|
||||
void raise_complex_NotImplementedError(void);
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#define NOT_IMPLEMENTED_FOR_COMPLEX() raise_complex_NotImplementedError();
|
||||
#define COMPLEX_DTYPE_NOT_IMPLEMENTED(dtype) if((dtype) == NDARRAY_COMPLEX) raise_complex_NotImplementedError();
|
||||
#else
|
||||
#define NOT_IMPLEMENTED_FOR_COMPLEX() // do nothing
|
||||
#define COMPLEX_DTYPE_NOT_IMPLEMENTED(dtype) // do nothing
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -20,17 +20,23 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray_operators.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "compare.h"
|
||||
|
||||
static mp_obj_t compare_function(mp_obj_t x1, mp_obj_t x2, uint8_t op) {
|
||||
ndarray_obj_t *lhs = ndarray_from_mp_obj(x1, 0);
|
||||
ndarray_obj_t *rhs = ndarray_from_mp_obj(x2, 0);
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((lhs->dtype == NDARRAY_COMPLEX) || (rhs->dtype == NDARRAY_COMPLEX)) {
|
||||
NOT_IMPLEMENTED_FOR_COMPLEX()
|
||||
}
|
||||
#endif
|
||||
uint8_t ndim = 0;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *lstrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
if(!ndarray_can_broadcast(lhs, rhs, &ndim, shape, lstrides, rstrides)) {
|
||||
mp_raise_ValueError(translate("operands could not be broadcast together"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("operands could not be broadcast together"));
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, lstrides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
|
|
@ -119,6 +125,7 @@ static mp_obj_t compare_function(mp_obj_t x1, mp_obj_t x2, uint8_t op) {
|
|||
return mp_const_none; // we should never reach this point
|
||||
}
|
||||
|
||||
#if ULAB_NUMPY_HAS_EQUAL | ULAB_NUMPY_HAS_NOTEQUAL
|
||||
static mp_obj_t compare_equal_helper(mp_obj_t x1, mp_obj_t x2, uint8_t comptype) {
|
||||
// scalar comparisons should return a single object of mp_obj_t type
|
||||
mp_obj_t result = compare_function(x1, x2, comptype);
|
||||
|
|
@ -130,9 +137,26 @@ static mp_obj_t compare_equal_helper(mp_obj_t x1, mp_obj_t x2, uint8_t comptype)
|
|||
}
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_CLIP
|
||||
|
||||
//| def clip(
|
||||
//| a: _ScalarOrArrayLike,
|
||||
//| a_min: _ScalarOrArrayLike,
|
||||
//| a_max: _ScalarOrArrayLike,
|
||||
//| ) -> _ScalarOrNdArray:
|
||||
//| """
|
||||
//| Clips (limits) the values in an array.
|
||||
//|
|
||||
//| :param a: Scalar or array containing elements to clip.
|
||||
//| :param a_min: Minimum value, it will be broadcast against ``a``.
|
||||
//| :param a_max: Maximum value, it will be broadcast against ``a``.
|
||||
//| :return:
|
||||
//| A scalar or array with the elements of ``a``, but where
|
||||
//| values < ``a_min`` are replaced with ``a_min``, and those
|
||||
//| > ``a_max`` with ``a_max``.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_clip(mp_obj_t x1, mp_obj_t x2, mp_obj_t x3) {
|
||||
// Note: this function could be made faster by implementing a single-loop comparison in
|
||||
// RUN_COMPARE_LOOP. However, that would add around 2 kB of compile size, while we
|
||||
|
|
@ -158,7 +182,18 @@ MP_DEFINE_CONST_FUN_OBJ_3(compare_clip_obj, compare_clip);
|
|||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_EQUAL
|
||||
|
||||
//| def equal(x: _ScalarOrArrayLike, y: _ScalarOrArrayLike) -> _ScalarOrNdArray:
|
||||
//| """
|
||||
//| Returns ``x == y`` element-wise.
|
||||
//|
|
||||
//| :param x, y:
|
||||
//| Input scalar or array. If ``x.shape != y.shape`` they must
|
||||
//| be broadcastable to a common shape (which becomes the
|
||||
//| shape of the output.)
|
||||
//| :return:
|
||||
//| A boolean scalar or array with the element-wise result of ``x == y``.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_equal(mp_obj_t x1, mp_obj_t x2) {
|
||||
return compare_equal_helper(x1, x2, COMPARE_EQUAL);
|
||||
}
|
||||
|
|
@ -167,7 +202,21 @@ MP_DEFINE_CONST_FUN_OBJ_2(compare_equal_obj, compare_equal);
|
|||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_NOTEQUAL
|
||||
|
||||
//| def not_equal(
|
||||
//| x: _ScalarOrArrayLike,
|
||||
//| y: _ScalarOrArrayLike,
|
||||
//| ) -> Union[_bool, ulab.numpy.ndarray]:
|
||||
//| """
|
||||
//| Returns ``x != y`` element-wise.
|
||||
//|
|
||||
//| :param x, y:
|
||||
//| Input scalar or array. If ``x.shape != y.shape`` they must
|
||||
//| be broadcastable to a common shape (which becomes the
|
||||
//| shape of the output.)
|
||||
//| :return:
|
||||
//| A boolean scalar or array with the element-wise result of ``x != y``.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_not_equal(mp_obj_t x1, mp_obj_t x2) {
|
||||
return compare_equal_helper(x1, x2, COMPARE_NOT_EQUAL);
|
||||
}
|
||||
|
|
@ -197,6 +246,7 @@ static mp_obj_t compare_isinf_isfinite(mp_obj_t _x, uint8_t mask) {
|
|||
}
|
||||
} else if(mp_obj_is_type(_x, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *x = MP_OBJ_TO_PTR(_x);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(x->dtype)
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(x->ndim, x->shape, NDARRAY_BOOL);
|
||||
// At this point, results is all False
|
||||
uint8_t *rarray = (uint8_t *)results->array;
|
||||
|
|
@ -206,61 +256,37 @@ static mp_obj_t compare_isinf_isfinite(mp_obj_t _x, uint8_t mask) {
|
|||
// ...so flip all values in the array, if the function was called from isfinite
|
||||
memset(rarray, 1, results->len);
|
||||
}
|
||||
return results;
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
uint8_t *xarray = (uint8_t *)x->array;
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
ITERATOR_HEAD();
|
||||
mp_float_t value = *(mp_float_t *)xarray;
|
||||
if(isnan(value)) {
|
||||
*rarray++ = 0;
|
||||
} else {
|
||||
*rarray++ = isinf(value) ? mask : 1 - mask;
|
||||
}
|
||||
xarray += x->strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < x->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
xarray -= x->strides[ULAB_MAX_DIMS - 1] * x->shape[ULAB_MAX_DIMS-1];
|
||||
xarray += x->strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < x->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
xarray -= x->strides[ULAB_MAX_DIMS - 2] * x->shape[ULAB_MAX_DIMS-2];
|
||||
xarray += x->strides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < x->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
xarray -= x->strides[ULAB_MAX_DIMS - 3] * x->shape[ULAB_MAX_DIMS-3];
|
||||
xarray += x->strides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < x->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
|
||||
return results;
|
||||
ITERATOR_TAIL(x, xarray);
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
} else {
|
||||
mp_raise_TypeError(translate("wrong input type"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong input type"));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ISFINITE
|
||||
//| def isfinite(x: _ScalarOrNdArray) -> Union[_bool, ulab.numpy.ndarray]:
|
||||
//| """
|
||||
//| Tests element-wise for finiteness (i.e., it should not be infinity or a NaN).
|
||||
//|
|
||||
//| :param x: Input scalar or ndarray.
|
||||
//| :return:
|
||||
//| A boolean scalar or array with True where ``x`` is finite, and
|
||||
//| False otherwise.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_isfinite(mp_obj_t _x) {
|
||||
return compare_isinf_isfinite(_x, 0);
|
||||
}
|
||||
|
|
@ -269,6 +295,16 @@ MP_DEFINE_CONST_FUN_OBJ_1(compare_isfinite_obj, compare_isfinite);
|
|||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ISINF
|
||||
//| def isinf(x: _ScalarOrNdArray) -> Union[_bool, ulab.numpy.ndarray]:
|
||||
//| """
|
||||
//| Tests element-wise for positive or negative infinity.
|
||||
//|
|
||||
//| :param x: Input scalar or ndarray.
|
||||
//| :return:
|
||||
//| A boolean scalar or array with True where ``x`` is positive or
|
||||
//| negative infinity, and False otherwise.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_isinf(mp_obj_t _x) {
|
||||
return compare_isinf_isfinite(_x, 1);
|
||||
}
|
||||
|
|
@ -277,6 +313,18 @@ MP_DEFINE_CONST_FUN_OBJ_1(compare_isinf_obj, compare_isinf);
|
|||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_MAXIMUM
|
||||
//| def maximum(x1: _ScalarOrArrayLike, x2: _ScalarOrArrayLike) -> _ScalarOrNdArray:
|
||||
//| """
|
||||
//| Returns the element-wise maximum.
|
||||
//|
|
||||
//| :param x1, x2:
|
||||
//| Input scalar or array. If ``x.shape != y.shape`` they must
|
||||
//| be broadcastable to a common shape (which becomes the
|
||||
//| shape of the output.)
|
||||
//| :return:
|
||||
//| A scalar or array with the element-wise maximum of ``x1`` and ``x2``.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_maximum(mp_obj_t x1, mp_obj_t x2) {
|
||||
// extra round, so that we can return maximum(3, 4) properly
|
||||
mp_obj_t result = compare_function(x1, x2, COMPARE_MAXIMUM);
|
||||
|
|
@ -292,6 +340,18 @@ MP_DEFINE_CONST_FUN_OBJ_2(compare_maximum_obj, compare_maximum);
|
|||
|
||||
#if ULAB_NUMPY_HAS_MINIMUM
|
||||
|
||||
//| def minimum(x1: _ScalarOrArrayLike, x2: _ScalarOrArrayLike) -> _ScalarOrNdArray:
|
||||
//| """
|
||||
//| Returns the element-wise minimum.
|
||||
//|
|
||||
//| :param x1, x2:
|
||||
//| Input scalar or array. If ``x.shape != y.shape`` they must
|
||||
//| be broadcastable to a common shape (which becomes the
|
||||
//| shape of the output.)
|
||||
//| :return:
|
||||
//| A scalar or array with the element-wise minimum of ``x1`` and ``x2``.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_minimum(mp_obj_t x1, mp_obj_t x2) {
|
||||
// extra round, so that we can return minimum(3, 4) properly
|
||||
mp_obj_t result = compare_function(x1, x2, COMPARE_MINIMUM);
|
||||
|
|
@ -305,14 +365,180 @@ mp_obj_t compare_minimum(mp_obj_t x1, mp_obj_t x2) {
|
|||
MP_DEFINE_CONST_FUN_OBJ_2(compare_minimum_obj, compare_minimum);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_NONZERO
|
||||
|
||||
//| def nonzero(x: _ScalarOrArrayLike) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| Returns the indices of elements that are non-zero.
|
||||
//|
|
||||
//| :param x:
|
||||
//| Input scalar or array. If ``x`` is a scalar, it is treated
|
||||
//| as a single-element 1-d array.
|
||||
//| :return:
|
||||
//| An array of indices that are non-zero.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_nonzero(mp_obj_t x) {
|
||||
ndarray_obj_t *ndarray_x = ndarray_from_mp_obj(x, 0);
|
||||
// since ndarray_new_linear_array calls m_new0, the content of zero is a single zero
|
||||
ndarray_obj_t *zero = ndarray_new_linear_array(1, NDARRAY_UINT8);
|
||||
|
||||
uint8_t ndim = 0;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *x_strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
int32_t *zero_strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
// we don't actually have to inspect the outcome of ndarray_can_broadcast,
|
||||
// because the right hand side is a linear array with a single element
|
||||
ndarray_can_broadcast(ndarray_x, zero, &ndim, shape, x_strides, zero_strides);
|
||||
|
||||
// equal_obj is a Boolean ndarray
|
||||
mp_obj_t equal_obj = ndarray_binary_equality(ndarray_x, zero, ndim, shape, x_strides, zero_strides, MP_BINARY_OP_NOT_EQUAL);
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(equal_obj);
|
||||
|
||||
// these are no longer needed, get rid of them
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, x_strides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, zero_strides, ULAB_MAX_DIMS);
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
uint8_t *origin = (uint8_t *)ndarray->array;
|
||||
|
||||
// First, count the number of Trues:
|
||||
uint16_t count = 0;
|
||||
size_t indices[ULAB_MAX_DIMS];
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
indices[3] = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
indices[2] = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
indices[1] = 0;
|
||||
do {
|
||||
#endif
|
||||
indices[0] = 0;
|
||||
do {
|
||||
if(*array != 0) {
|
||||
count++;
|
||||
}
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 1];
|
||||
indices[0]++;
|
||||
} while(indices[0] < ndarray->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 2];
|
||||
indices[1]++;
|
||||
} while(indices[1] < ndarray->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 2] * ndarray->shape[ULAB_MAX_DIMS-2];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 3];
|
||||
indices[2]++;
|
||||
} while(indices[2] < ndarray->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 3] * ndarray->shape[ULAB_MAX_DIMS-3];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 4];
|
||||
indices[3]++;
|
||||
} while(indices[3] < ndarray->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
|
||||
mp_obj_t *items = m_new(mp_obj_t, ndarray->ndim);
|
||||
uint16_t *arrays[ULAB_MAX_DIMS];
|
||||
|
||||
for(uint8_t i = 0; i < ndarray->ndim; i++) {
|
||||
ndarray_obj_t *item_array = ndarray_new_linear_array(count, NDARRAY_UINT16);
|
||||
uint16_t *iarray = (uint16_t *)item_array->array;
|
||||
arrays[ULAB_MAX_DIMS - 1 - i] = iarray;
|
||||
items[ndarray->ndim - 1 - i] = MP_OBJ_FROM_PTR(item_array);
|
||||
}
|
||||
array = origin;
|
||||
count = 0;
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
indices[3] = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
indices[2] = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
indices[1] = 0;
|
||||
do {
|
||||
#endif
|
||||
indices[0] = 0;
|
||||
do {
|
||||
if(*array != 0) {
|
||||
for(uint8_t d = 0; d < ndarray->ndim; d++) {
|
||||
arrays[ULAB_MAX_DIMS - 1 - d][count] = indices[d];
|
||||
}
|
||||
count++;
|
||||
}
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 1];
|
||||
indices[0]++;
|
||||
} while(indices[0] < ndarray->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 2];
|
||||
indices[1]++;
|
||||
} while(indices[1] < ndarray->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 2] * ndarray->shape[ULAB_MAX_DIMS-2];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 3];
|
||||
indices[2]++;
|
||||
} while(indices[2] < ndarray->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 3] * ndarray->shape[ULAB_MAX_DIMS-3];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 4];
|
||||
indices[3]++;
|
||||
} while(indices[3] < ndarray->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
|
||||
return mp_obj_new_tuple(ndarray->ndim, items);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(compare_nonzero_obj, compare_nonzero);
|
||||
#endif /* ULAB_NUMPY_HAS_NONZERO */
|
||||
|
||||
#if ULAB_NUMPY_HAS_WHERE
|
||||
|
||||
//| def where(
|
||||
//| condition: _ScalarOrArrayLike,
|
||||
//| x: _ScalarOrArrayLike,
|
||||
//| y: _ScalarOrArrayLike,
|
||||
//| ) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| Returns elements from ``x`` or ``y`` depending on ``condition``.
|
||||
//|
|
||||
//| :param condition:
|
||||
//| Input scalar or array. If an element (or scalar) is truthy,
|
||||
//| the corresponding element from ``x`` is chosen, otherwise
|
||||
//| ``y`` is used. ``condition``, ``x`` and ``y`` must also be
|
||||
//| broadcastable to the same shape (which becomes the output
|
||||
//| shape.)
|
||||
//| :param x, y:
|
||||
//| Input scalar or array.
|
||||
//| :return:
|
||||
//| An array with elements from ``x`` when ``condition`` is
|
||||
//| truthy, and ``y`` elsewhere.
|
||||
//| """
|
||||
//| ...
|
||||
mp_obj_t compare_where(mp_obj_t _condition, mp_obj_t _x, mp_obj_t _y) {
|
||||
// this implementation will work with ndarrays, and scalars only
|
||||
ndarray_obj_t *c = ndarray_from_mp_obj(_condition, 0);
|
||||
ndarray_obj_t *x = ndarray_from_mp_obj(_x, 0);
|
||||
ndarray_obj_t *y = ndarray_from_mp_obj(_y, 0);
|
||||
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(c->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(x->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(y->dtype)
|
||||
|
||||
int32_t *cstrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
int32_t *xstrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
int32_t *ystrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
|
|
@ -327,7 +553,7 @@ mp_obj_t compare_where(mp_obj_t _condition, mp_obj_t _x, mp_obj_t _y) {
|
|||
if(!ndarray_can_broadcast(c, x, &ndim, oshape, cstrides, ystrides) ||
|
||||
!ndarray_can_broadcast(c, y, &ndim, oshape, cstrides, ystrides) ||
|
||||
!ndarray_can_broadcast(x, y, &ndim, oshape, xstrides, ystrides)) {
|
||||
mp_raise_ValueError(translate("operands could not be broadcast together"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("operands could not be broadcast together"));
|
||||
}
|
||||
|
||||
ndim = MAX(MAX(c->ndim, x->ndim), y->ndim);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ MP_DECLARE_CONST_FUN_OBJ_2(compare_isfinite_obj);
|
|||
MP_DECLARE_CONST_FUN_OBJ_2(compare_isinf_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(compare_minimum_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(compare_maximum_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(compare_nonzero_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(compare_not_equal_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_3(compare_where_obj);
|
||||
|
||||
|
|
|
|||
1079
code/numpy/create.c
Normal file
1079
code/numpy/create.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,14 +12,19 @@
|
|||
#ifndef _CREATE_
|
||||
#define _CREATE_
|
||||
|
||||
#include "ulab.h"
|
||||
#include "ndarray.h"
|
||||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_ARANGE
|
||||
mp_obj_t create_arange(size_t , const mp_obj_t *, mp_map_t *);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_arange_obj);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ASARRAY
|
||||
mp_obj_t create_arange(size_t , const mp_obj_t *, mp_map_t *);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_asarray_obj);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_CONCATENATE
|
||||
mp_obj_t create_concatenate(size_t , const mp_obj_t *, mp_map_t *);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_concatenate_obj);
|
||||
|
|
@ -57,6 +62,11 @@ mp_obj_t create_ones(size_t , const mp_obj_t *, mp_map_t *);
|
|||
MP_DECLARE_CONST_FUN_OBJ_KW(create_ones_obj);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_TAKE
|
||||
mp_obj_t create_take(size_t , const mp_obj_t *, mp_map_t *);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_take_obj);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ZEROS
|
||||
mp_obj_t create_zeros(size_t , const mp_obj_t *, mp_map_t *);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(create_zeros_obj);
|
||||
|
|
@ -67,12 +77,13 @@ mp_obj_t create_frombuffer(size_t , const mp_obj_t *, mp_map_t *);
|
|||
MP_DECLARE_CONST_FUN_OBJ_KW(create_frombuffer_obj);
|
||||
#endif
|
||||
|
||||
#define ARANGE_LOOP(type_, ndarray, len, step) \
|
||||
#define ARANGE_LOOP(type_, ndarray, len, step, stop) \
|
||||
({\
|
||||
type_ *array = (type_ *)(ndarray)->array;\
|
||||
for (size_t i = 0; i < (len); i++, (value) += (step)) {\
|
||||
*array++ = (type_)value;\
|
||||
for (size_t i = 0; i < (len) - 1; i++, (value) += (step)) {\
|
||||
*array++ = (type_)(value);\
|
||||
}\
|
||||
*array = (type_)(stop);\
|
||||
})
|
||||
|
||||
#endif
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Zoltán Vörös
|
||||
* Copyright (c) 2019-2024 Zoltán Vörös
|
||||
* 2020 Scott Shawcroft for Adafruit Industries
|
||||
* 2020 Taku Fukada
|
||||
*/
|
||||
|
|
@ -20,11 +20,13 @@
|
|||
#include "py/obj.h"
|
||||
#include "py/objarray.h"
|
||||
|
||||
#include "../carray/carray_tools.h"
|
||||
#include "fft.h"
|
||||
|
||||
//| """Frequency-domain functions"""
|
||||
//|
|
||||
//| import ulab.numpy
|
||||
//| import ulab.utils
|
||||
|
||||
|
||||
//| def fft(r: ulab.numpy.ndarray, c: Optional[ulab.numpy.ndarray] = None) -> Tuple[ulab.numpy.ndarray, ulab.numpy.ndarray]:
|
||||
|
|
@ -35,19 +37,27 @@
|
|||
//|
|
||||
//| Perform a Fast Fourier Transform from the time domain into the frequency domain
|
||||
//|
|
||||
//| See also ~ulab.extras.spectrum, which computes the magnitude of the fft,
|
||||
//| See also `ulab.utils.spectrogram`, which computes the magnitude of the fft,
|
||||
//| rather than separately returning its real and imaginary parts."""
|
||||
//| ...
|
||||
//|
|
||||
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
static mp_obj_t fft_fft(mp_obj_t arg) {
|
||||
return fft_fft_ifft(arg, FFT_FFT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(fft_fft_obj, fft_fft);
|
||||
#else
|
||||
static mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {
|
||||
if(n_args == 2) {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_FFT);
|
||||
return fft_fft_ifft(n_args, args[0], args[1], FFT_FFT);
|
||||
} else {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_FFT);
|
||||
return fft_fft_ifft(n_args, args[0], mp_const_none, FFT_FFT);
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
|
||||
#endif
|
||||
|
||||
//| def ifft(r: ulab.numpy.ndarray, c: Optional[ulab.numpy.ndarray] = None) -> Tuple[ulab.numpy.ndarray, ulab.numpy.ndarray]:
|
||||
//| """
|
||||
|
|
@ -59,25 +69,37 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);
|
|||
//| ...
|
||||
//|
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
static mp_obj_t fft_ifft(mp_obj_t arg) {
|
||||
return fft_fft_ifft(arg, FFT_IFFT);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(fft_ifft_obj, fft_ifft);
|
||||
#else
|
||||
static mp_obj_t fft_ifft(size_t n_args, const mp_obj_t *args) {
|
||||
NOT_IMPLEMENTED_FOR_COMPLEX()
|
||||
if(n_args == 2) {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_IFFT);
|
||||
return fft_fft_ifft(n_args, args[0], args[1], FFT_IFFT);
|
||||
} else {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_IFFT);
|
||||
return fft_fft_ifft(n_args, args[0], mp_const_none, FFT_IFFT);
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj, 1, 2, fft_ifft);
|
||||
#endif
|
||||
|
||||
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 },
|
||||
static const mp_rom_map_elem_t ulab_fft_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_fft) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&fft_fft_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ifft), MP_ROM_PTR(&fft_ifft_obj) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table);
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_fft_globals, ulab_fft_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_fft_module = {
|
||||
const mp_obj_module_t ulab_fft_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_fft_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_numpy_dot_fft, ulab_fft_module);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -17,8 +17,14 @@
|
|||
#include "../../ndarray.h"
|
||||
#include "fft_tools.h"
|
||||
|
||||
extern mp_obj_module_t ulab_fft_module;
|
||||
extern const mp_obj_module_t ulab_fft_module;
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
MP_DECLARE_CONST_FUN_OBJ_3(fft_fft_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_3(fft_ifft_obj);
|
||||
#else
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(fft_ifft_obj);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,14 +5,16 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Zoltán Vörös
|
||||
* Copyright (c) 2019-2024 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "../../ndarray.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "../carray/carray_tools.h"
|
||||
#include "fft_tools.h"
|
||||
|
||||
#ifndef MP_PI
|
||||
|
|
@ -22,7 +24,8 @@
|
|||
#define MP_E MICROPY_FLOAT_CONST(2.71828182845904523536)
|
||||
#endif
|
||||
|
||||
/*
|
||||
/* Kernel implementation for the case, when ulab has no complex support
|
||||
|
||||
* The following function takes two arrays, namely, the real and imaginary
|
||||
* parts of a complex array, and calculates the Fourier transform in place.
|
||||
*
|
||||
|
|
@ -31,6 +34,118 @@
|
|||
* and can be used independent of ulab.
|
||||
*/
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
/* Kernel implementation for the complex case. Data are contained in data as
|
||||
|
||||
data[0], data[1], data[2], data[3], .... , data[2n - 2], data[2n-1]
|
||||
real[0], imag[0], real[1], imag[1], .... , real[n-1], imag[n-1]
|
||||
|
||||
In general
|
||||
real[i] = data[2i]
|
||||
imag[i] = data[2i+1]
|
||||
|
||||
*/
|
||||
void fft_kernel(mp_float_t *data, size_t n, int isign) {
|
||||
size_t j, m, mmax, istep;
|
||||
mp_float_t tempr, tempi;
|
||||
mp_float_t wtemp, wr, wpr, wpi, wi, theta;
|
||||
|
||||
j = 0;
|
||||
for(size_t i = 0; i < n; i++) {
|
||||
if (j > i) {
|
||||
SWAP(mp_float_t, data[2*i], data[2*j]);
|
||||
SWAP(mp_float_t, data[2*i+1], data[2*j+1]);
|
||||
}
|
||||
m = n >> 1;
|
||||
while (j >= m && m > 0) {
|
||||
j -= m;
|
||||
m >>= 1;
|
||||
}
|
||||
j += m;
|
||||
}
|
||||
|
||||
mmax = 1;
|
||||
while (n > mmax) {
|
||||
istep = mmax << 1;
|
||||
theta = MICROPY_FLOAT_CONST(-2.0)*isign*MP_PI/istep;
|
||||
wtemp = MICROPY_FLOAT_C_FUN(sin)(MICROPY_FLOAT_CONST(0.5) * theta);
|
||||
wpr = MICROPY_FLOAT_CONST(-2.0) * wtemp * wtemp;
|
||||
wpi = MICROPY_FLOAT_C_FUN(sin)(theta);
|
||||
wr = MICROPY_FLOAT_CONST(1.0);
|
||||
wi = MICROPY_FLOAT_CONST(0.0);
|
||||
for(m = 0; m < mmax; m++) {
|
||||
for(size_t i = m; i < n; i += istep) {
|
||||
j = i + mmax;
|
||||
tempr = wr * data[2*j] - wi * data[2*j+1];
|
||||
tempi = wr * data[2*j+1] + wi * data[2*j];
|
||||
data[2*j] = data[2*i] - tempr;
|
||||
data[2*j+1] = data[2*i+1] - tempi;
|
||||
data[2*i] += tempr;
|
||||
data[2*i+1] += tempi;
|
||||
}
|
||||
wtemp = wr;
|
||||
wr = wr*wpr - wi*wpi + wr;
|
||||
wi = wi*wpr + wtemp*wpi + wi;
|
||||
}
|
||||
mmax = istep;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function is a helper interface to the python side.
|
||||
* It has been factored out from fft.c, so that the same argument parsing
|
||||
* routine can be called from utils.spectrogram.
|
||||
*/
|
||||
mp_obj_t fft_fft_ifft(mp_obj_t data_in, uint8_t type) {
|
||||
if(!mp_obj_is_type(data_in, &ulab_ndarray_type)) {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("FFT is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *in = MP_OBJ_TO_PTR(data_in);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(in->ndim != 1) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("FFT is implemented for linear arrays only"));
|
||||
}
|
||||
#endif
|
||||
size_t len = in->len;
|
||||
// Check if input is of length of power of 2
|
||||
if((len & (len-1)) != 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input array length must be power of 2"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *out = ndarray_new_linear_array(len, NDARRAY_COMPLEX);
|
||||
mp_float_t *data = (mp_float_t *)out->array;
|
||||
uint8_t *array = (uint8_t *)in->array;
|
||||
|
||||
if(in->dtype == NDARRAY_COMPLEX) {
|
||||
uint8_t sz = 2 * sizeof(mp_float_t);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
memcpy(data, array, sz);
|
||||
data += 2;
|
||||
array += in->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
} else {
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(in->dtype);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
// real part; the imaginary part is 0, no need to assign
|
||||
*data = func(array);
|
||||
data += 2;
|
||||
array += in->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
}
|
||||
data -= 2 * len;
|
||||
|
||||
if(type == FFT_FFT) {
|
||||
fft_kernel(data, len, 1);
|
||||
} else { // inverse transform
|
||||
fft_kernel(data, len, -1);
|
||||
// TODO: numpy accepts the norm keyword argument
|
||||
for(size_t i = 0; i < 2 * len; i++) {
|
||||
*data++ /= len;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(out);
|
||||
}
|
||||
#else /* ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE */
|
||||
void fft_kernel(mp_float_t *real, mp_float_t *imag, size_t n, int isign) {
|
||||
size_t j, m, mmax, istep;
|
||||
mp_float_t tempr, tempi;
|
||||
|
|
@ -77,31 +192,26 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, size_t n, int isign) {
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The following function is a helper interface to the python side.
|
||||
* It has been factored out from fft.c, so that the same argument parsing
|
||||
* routine can be called from scipy.signal.spectrogram.
|
||||
*/
|
||||
|
||||
mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) {
|
||||
mp_obj_t fft_fft_ifft(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im, uint8_t type) {
|
||||
if(!mp_obj_is_type(arg_re, &ulab_ndarray_type)) {
|
||||
mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("FFT is defined for ndarrays only"));
|
||||
}
|
||||
if(n_args == 2) {
|
||||
if(!mp_obj_is_type(arg_im, &ulab_ndarray_type)) {
|
||||
mp_raise_NotImplementedError(translate("FFT is defined for ndarrays only"));
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("FFT is defined for ndarrays only"));
|
||||
}
|
||||
}
|
||||
ndarray_obj_t *re = MP_OBJ_TO_PTR(arg_re);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(re->ndim != 1) {
|
||||
mp_raise_TypeError(translate("FFT is implemented for linear arrays only"));
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(re->dtype)
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("FFT is implemented for linear arrays only"));
|
||||
}
|
||||
#endif
|
||||
size_t len = re->len;
|
||||
// Check if input is of length of power of 2
|
||||
if((len & (len-1)) != 0) {
|
||||
mp_raise_ValueError(translate("input array length must be power of 2"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input array length must be power of 2"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *out_re = ndarray_new_linear_array(len, NDARRAY_FLOAT);
|
||||
|
|
@ -122,11 +232,12 @@ mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_i
|
|||
ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(im->ndim != 1) {
|
||||
mp_raise_TypeError(translate("FFT is implemented for linear arrays only"));
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(im->dtype)
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("FFT is implemented for linear arrays only"));
|
||||
}
|
||||
#endif
|
||||
if (re->len != im->len) {
|
||||
mp_raise_ValueError(translate("real and imaginary parts must be of equal length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("real and imaginary parts must be of equal length"));
|
||||
}
|
||||
array = (uint8_t *)im->array;
|
||||
func = ndarray_get_float_function(im->dtype);
|
||||
|
|
@ -137,15 +248,8 @@ mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_i
|
|||
data_im -= len;
|
||||
}
|
||||
|
||||
if((type == FFT_FFT) || (type == FFT_SPECTROGRAM)) {
|
||||
if(type == FFT_FFT) {
|
||||
fft_kernel(data_re, data_im, len, 1);
|
||||
if(type == FFT_SPECTROGRAM) {
|
||||
for(size_t i=0; i < len; i++) {
|
||||
*data_re = MICROPY_FLOAT_C_FUN(sqrt)(*data_re * *data_re + *data_im * *data_im);
|
||||
data_re++;
|
||||
data_im++;
|
||||
}
|
||||
}
|
||||
} else { // inverse transform
|
||||
fft_kernel(data_re, data_im, len, -1);
|
||||
// TODO: numpy accepts the norm keyword argument
|
||||
|
|
@ -154,12 +258,9 @@ mp_obj_t fft_fft_ifft_spectrogram(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_i
|
|||
*data_im++ /= len;
|
||||
}
|
||||
}
|
||||
if(type == FFT_SPECTROGRAM) {
|
||||
return MP_OBJ_TO_PTR(out_re);
|
||||
} else {
|
||||
mp_obj_t tuple[2];
|
||||
tuple[0] = out_re;
|
||||
tuple[1] = out_im;
|
||||
tuple[0] = MP_OBJ_FROM_PTR(out_re);
|
||||
tuple[1] = MP_OBJ_FROM_PTR(out_im);
|
||||
return mp_obj_new_tuple(2, tuple);
|
||||
}
|
||||
}
|
||||
#endif /* ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE */
|
||||
|
|
|
|||
|
|
@ -14,10 +14,14 @@
|
|||
enum FFT_TYPE {
|
||||
FFT_FFT,
|
||||
FFT_IFFT,
|
||||
FFT_SPECTROGRAM,
|
||||
};
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
void fft_kernel(mp_float_t *, size_t , int );
|
||||
mp_obj_t fft_fft_ifft(mp_obj_t , uint8_t );
|
||||
#else
|
||||
void fft_kernel(mp_float_t *, mp_float_t *, size_t , int );
|
||||
mp_obj_t fft_fft_ifft_spectrogram(size_t , mp_obj_t , mp_obj_t , uint8_t );
|
||||
mp_obj_t fft_fft_ifft(size_t , mp_obj_t , mp_obj_t , uint8_t );
|
||||
#endif /* ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE */
|
||||
|
||||
#endif /* _FFT_TOOLS_ */
|
||||
|
|
|
|||
|
|
@ -21,21 +21,22 @@
|
|||
|
||||
#include "../ulab.h"
|
||||
#include "../scipy/signal/signal.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "filter.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_CONVOLVE
|
||||
|
||||
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_QSTR_a, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_v, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("convolve arguments must be ndarrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("convolve arguments must be ndarrays"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *a = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
|
@ -43,40 +44,87 @@ mp_obj_t filter_convolve(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_a
|
|||
// deal with linear arrays only
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if((a->ndim != 1) || (c->ndim != 1)) {
|
||||
mp_raise_TypeError(translate("convolve arguments must be linear arrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("convolve arguments must be linear arrays"));
|
||||
}
|
||||
#endif
|
||||
size_t len_a = a->len;
|
||||
size_t len_c = c->len;
|
||||
if(len_a == 0 || len_c == 0) {
|
||||
mp_raise_TypeError(translate("convolve arguments must not be empty"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("convolve arguments must not be empty"));
|
||||
}
|
||||
|
||||
int len = len_a + len_c - 1; // convolve mode "full"
|
||||
ndarray_obj_t *out = ndarray_new_linear_array(len, NDARRAY_FLOAT);
|
||||
mp_float_t *outptr = (mp_float_t *)out->array;
|
||||
int32_t off = len_c - 1;
|
||||
uint8_t dtype = NDARRAY_FLOAT;
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if((a->dtype == NDARRAY_COMPLEX) || (c->dtype == NDARRAY_COMPLEX)) {
|
||||
dtype = NDARRAY_COMPLEX;
|
||||
}
|
||||
#endif
|
||||
ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype);
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
|
||||
uint8_t *aarray = (uint8_t *)a->array;
|
||||
uint8_t *carray = (uint8_t *)c->array;
|
||||
|
||||
int32_t off = len_c - 1;
|
||||
int32_t as = a->strides[ULAB_MAX_DIMS - 1] / a->itemsize;
|
||||
int32_t cs = c->strides[ULAB_MAX_DIMS - 1] / c->itemsize;
|
||||
|
||||
for(int32_t k=-off; k < len-off; k++) {
|
||||
mp_float_t accum = (mp_float_t)0.0;
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t a_real, a_imag;
|
||||
mp_float_t c_real, c_imag = MICROPY_FLOAT_CONST(0.0);
|
||||
for(int32_t k = -off; k < len-off; k++) {
|
||||
mp_float_t accum_real = MICROPY_FLOAT_CONST(0.0);
|
||||
mp_float_t accum_imag = MICROPY_FLOAT_CONST(0.0);
|
||||
|
||||
int32_t top_n = MIN(len_c, len_a - k);
|
||||
int32_t bot_n = MAX(-k, 0);
|
||||
for(int32_t n=bot_n; n < top_n; n++) {
|
||||
|
||||
for(int32_t n = bot_n; n < top_n; n++) {
|
||||
int32_t idx_c = (len_c - n - 1) * cs;
|
||||
int32_t idx_a = (n + k) * as;
|
||||
if(a->dtype != NDARRAY_COMPLEX) {
|
||||
a_real = ndarray_get_float_index(aarray, a->dtype, idx_a);
|
||||
a_imag = MICROPY_FLOAT_CONST(0.0);
|
||||
} else {
|
||||
a_real = ndarray_get_float_index(aarray, NDARRAY_FLOAT, 2 * idx_a);
|
||||
a_imag = ndarray_get_float_index(aarray, NDARRAY_FLOAT, 2 * idx_a + 1);
|
||||
}
|
||||
|
||||
if(c->dtype != NDARRAY_COMPLEX) {
|
||||
c_real = ndarray_get_float_index(carray, c->dtype, idx_c);
|
||||
c_imag = MICROPY_FLOAT_CONST(0.0);
|
||||
} else {
|
||||
c_real = ndarray_get_float_index(carray, NDARRAY_FLOAT, 2 * idx_c);
|
||||
c_imag = ndarray_get_float_index(carray, NDARRAY_FLOAT, 2 * idx_c + 1);
|
||||
}
|
||||
accum_real += a_real * c_real - a_imag * c_imag;
|
||||
accum_imag += a_real * c_imag + a_imag * c_real;
|
||||
}
|
||||
*array++ = accum_real;
|
||||
*array++ = accum_imag;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
#endif
|
||||
|
||||
for(int32_t k = -off; k < len-off; k++) {
|
||||
mp_float_t accum = MICROPY_FLOAT_CONST(0.0);
|
||||
int32_t top_n = MIN(len_c, len_a - k);
|
||||
int32_t bot_n = MAX(-k, 0);
|
||||
for(int32_t n = bot_n; n < top_n; n++) {
|
||||
int32_t idx_c = (len_c - n - 1) * cs;
|
||||
int32_t idx_a = (n + k) * as;
|
||||
mp_float_t ai = ndarray_get_float_index(aarray, a->dtype, idx_a);
|
||||
mp_float_t ci = ndarray_get_float_index(carray, c->dtype, idx_c);
|
||||
accum += ai * ci;
|
||||
}
|
||||
*outptr++ = accum;
|
||||
*array++ = accum;
|
||||
}
|
||||
|
||||
return out;
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(filter_convolve_obj, 2, filter_convolve);
|
||||
|
|
|
|||
806
code/numpy/io/io.c
Normal file
806
code/numpy/io/io.c
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/builtin.h"
|
||||
#include "py/formatfloat.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/parsenum.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/stream.h"
|
||||
#include "extmod/vfs.h"
|
||||
|
||||
#include "../../ndarray.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "io.h"
|
||||
|
||||
#define ULAB_IO_BUFFER_SIZE 128
|
||||
#define ULAB_IO_CLIPBOARD_SIZE 32
|
||||
#define ULAB_IO_MAX_ROWS 65535
|
||||
|
||||
#define ULAB_IO_NULL_ENDIAN 0
|
||||
#define ULAB_IO_LITTLE_ENDIAN 1
|
||||
#define ULAB_IO_BIG_ENDIAN 2
|
||||
|
||||
#if ULAB_NUMPY_HAS_LOAD
|
||||
static void io_read_(mp_obj_t stream, const mp_stream_p_t *stream_p, char *buffer, const char *string, uint16_t len, int *error) {
|
||||
size_t read = stream_p->read(stream, buffer, len, error);
|
||||
bool fail = false;
|
||||
if(read == len) {
|
||||
if(string != NULL) {
|
||||
if(memcmp(buffer, string, len) != 0) {
|
||||
fail = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fail = true;
|
||||
}
|
||||
if(fail) {
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, error);
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("corrupted file"));
|
||||
}
|
||||
}
|
||||
|
||||
static mp_obj_t io_load(mp_obj_t file) {
|
||||
if(!mp_obj_is_str(file)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong input type"));
|
||||
}
|
||||
|
||||
int error;
|
||||
char *buffer = m_new(char, ULAB_IO_BUFFER_SIZE);
|
||||
|
||||
// test for endianness
|
||||
uint16_t x = 1;
|
||||
int8_t native_endianness = (x >> 8) == 1 ? ULAB_IO_BIG_ENDIAN : ULAB_IO_LITTLE_ENDIAN;
|
||||
|
||||
mp_obj_t open_args[2] = {
|
||||
file,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_rb)
|
||||
};
|
||||
|
||||
mp_obj_t stream = mp_builtin_open_obj.fun.kw(2, open_args, (mp_map_t *)&mp_const_empty_map);
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(stream);
|
||||
|
||||
// read header
|
||||
// magic string
|
||||
io_read_(stream, stream_p, buffer, "\x93NUMPY", 6, &error);
|
||||
// simply discard the version number
|
||||
io_read_(stream, stream_p, buffer, NULL, 2, &error);
|
||||
// header length, represented as a little endian uint16 (0x76, 0x00)
|
||||
io_read_(stream, stream_p, buffer, NULL, 2, &error);
|
||||
|
||||
uint16_t header_length = buffer[1];
|
||||
header_length <<= 8;
|
||||
header_length += buffer[0];
|
||||
|
||||
// beginning of the dictionary describing the array
|
||||
io_read_(stream, stream_p, buffer, "{'descr': '", 11, &error);
|
||||
uint8_t dtype;
|
||||
|
||||
io_read_(stream, stream_p, buffer, NULL, 1, &error);
|
||||
uint8_t endianness = ULAB_IO_NULL_ENDIAN;
|
||||
if(*buffer == '<') {
|
||||
endianness = ULAB_IO_LITTLE_ENDIAN;
|
||||
} else if(*buffer == '>') {
|
||||
endianness = ULAB_IO_BIG_ENDIAN;
|
||||
}
|
||||
|
||||
io_read_(stream, stream_p, buffer, NULL, 2, &error);
|
||||
if(memcmp(buffer, "u1", 2) == 0) {
|
||||
dtype = NDARRAY_UINT8;
|
||||
} else if(memcmp(buffer, "i1", 2) == 0) {
|
||||
dtype = NDARRAY_INT8;
|
||||
} else if(memcmp(buffer, "u2", 2) == 0) {
|
||||
dtype = NDARRAY_UINT16;
|
||||
} else if(memcmp(buffer, "i2", 2) == 0) {
|
||||
dtype = NDARRAY_INT16;
|
||||
}
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
else if(memcmp(buffer, "f4", 2) == 0) {
|
||||
dtype = NDARRAY_FLOAT;
|
||||
}
|
||||
#else
|
||||
else if(memcmp(buffer, "f8", 2) == 0) {
|
||||
dtype = NDARRAY_FLOAT;
|
||||
}
|
||||
#endif
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
else if(memcmp(buffer, "c8", 2) == 0) {
|
||||
dtype = NDARRAY_COMPLEX;
|
||||
}
|
||||
#else
|
||||
else if(memcmp(buffer, "c16", 3) == 0) {
|
||||
dtype = NDARRAY_COMPLEX;
|
||||
}
|
||||
#endif
|
||||
#endif /* ULAB_SUPPORT_COPMLEX */
|
||||
else {
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong dtype"));
|
||||
}
|
||||
|
||||
io_read_(stream, stream_p, buffer, "', 'fortran_order': False, 'shape': (", 37, &error);
|
||||
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
|
||||
uint16_t bytes_to_read = MIN(ULAB_IO_BUFFER_SIZE, header_length - 51);
|
||||
// bytes_to_read is 128 at most. This should be enough to contain a
|
||||
// maximum of 4 size_t numbers plus the delimiters
|
||||
io_read_(stream, stream_p, buffer, NULL, bytes_to_read, &error);
|
||||
char *needle = buffer;
|
||||
uint8_t ndim = 0;
|
||||
|
||||
// find out the number of dimensions by counting the commas in the string
|
||||
while(1) {
|
||||
if(*needle == ',') {
|
||||
ndim++;
|
||||
if(needle[1] == ')') {
|
||||
break;
|
||||
}
|
||||
} else if((*needle == ')') && (ndim > 0)) {
|
||||
ndim++;
|
||||
break;
|
||||
}
|
||||
needle++;
|
||||
}
|
||||
|
||||
needle = buffer;
|
||||
for(uint8_t i = 0; i < ndim; i++) {
|
||||
size_t number = 0;
|
||||
// trivial number parsing here
|
||||
while(1) {
|
||||
if((*needle == ' ') || (*needle == '\t')) {
|
||||
needle++;
|
||||
}
|
||||
if((*needle > 47) && (*needle < 58)) {
|
||||
number = number * 10 + (*needle - 48);
|
||||
} else if((*needle == ',') || (*needle == ')')) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("corrupted file"));
|
||||
}
|
||||
needle++;
|
||||
}
|
||||
needle++;
|
||||
shape[ULAB_MAX_DIMS - ndim + i] = number;
|
||||
}
|
||||
|
||||
// strip the rest of the header
|
||||
if((bytes_to_read + 51) < header_length) {
|
||||
io_read_(stream, stream_p, buffer, NULL, header_length - (bytes_to_read + 51), &error);
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(ndim, shape, dtype);
|
||||
char *array = (char *)ndarray->array;
|
||||
|
||||
size_t read = stream_p->read(stream, array, ndarray->len * ndarray->itemsize, &error);
|
||||
if(read != ndarray->len * ndarray->itemsize) {
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
mp_raise_msg(&mp_type_RuntimeError, MP_ERROR_TEXT("corrupted file"));
|
||||
}
|
||||
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
m_del(char, buffer, ULAB_IO_BUFFER_SIZE);
|
||||
|
||||
// swap the bytes, if necessary
|
||||
if((native_endianness != endianness) && (dtype != NDARRAY_UINT8) && (dtype != NDARRAY_INT8)) {
|
||||
uint8_t sz = ndarray->itemsize;
|
||||
char *tmpbuff = NULL;
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(dtype == NDARRAY_COMPLEX) {
|
||||
// work with the floating point real and imaginary parts
|
||||
sz /= 2;
|
||||
tmpbuff = m_new(char, sz);
|
||||
for(size_t i = 0; i < ndarray->len; i++) {
|
||||
for(uint8_t k = 0; k < 2; k++) {
|
||||
tmpbuff += sz;
|
||||
for(uint8_t j = 0; j < sz; j++) {
|
||||
memcpy(--tmpbuff, array++, 1);
|
||||
}
|
||||
memcpy(array-sz, tmpbuff, sz);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
tmpbuff = m_new(char, sz);
|
||||
for(size_t i = 0; i < ndarray->len; i++) {
|
||||
tmpbuff += sz;
|
||||
for(uint8_t j = 0; j < sz; j++) {
|
||||
memcpy(--tmpbuff, array++, 1);
|
||||
}
|
||||
memcpy(array-sz, tmpbuff, sz);
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
}
|
||||
#endif
|
||||
m_del(char, tmpbuff, sz);
|
||||
}
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(io_load_obj, io_load);
|
||||
#endif /* ULAB_NUMPY_HAS_LOAD */
|
||||
|
||||
#if ULAB_NUMPY_HAS_LOADTXT
|
||||
static void io_assign_value(const char *clipboard, uint8_t len, ndarray_obj_t *ndarray, size_t *idx, uint8_t dtype) {
|
||||
#if MICROPY_PY_BUILTINS_COMPLEX
|
||||
mp_obj_t value = mp_parse_num_decimal(clipboard, len, false, false, NULL);
|
||||
#else
|
||||
mp_obj_t value = mp_parse_num_float(clipboard, len, false, NULL);
|
||||
#endif
|
||||
if(dtype != NDARRAY_FLOAT) {
|
||||
mp_float_t _value = mp_obj_get_float(value);
|
||||
value = mp_obj_new_int((int32_t)MICROPY_FLOAT_C_FUN(round)(_value));
|
||||
}
|
||||
ndarray_set_value(dtype, ndarray->array, (*idx)++, value);
|
||||
}
|
||||
|
||||
static mp_obj_t io_loadtxt(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_ROM_NONE } },
|
||||
{ MP_QSTR_delimiter, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_comments, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_max_rows, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = -1 } },
|
||||
{ MP_QSTR_usecols, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_dtype, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = NDARRAY_FLOAT } },
|
||||
{ MP_QSTR_skiprows, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 0 } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t open_args[2] = {
|
||||
args[0].u_obj,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_r)
|
||||
};
|
||||
|
||||
mp_obj_t stream = mp_builtin_open_obj.fun.kw(2, open_args, (mp_map_t *)&mp_const_empty_map);
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(stream);
|
||||
|
||||
char *buffer = m_new(char, ULAB_IO_BUFFER_SIZE);
|
||||
int error;
|
||||
|
||||
char delimiter = ' ';
|
||||
if(args[1].u_obj != mp_const_none) {
|
||||
size_t _len;
|
||||
char *_delimiter = m_new(char, 8);
|
||||
_delimiter = (char *)mp_obj_str_get_data(args[1].u_obj, &_len);
|
||||
delimiter = _delimiter[0];
|
||||
}
|
||||
|
||||
char comment_char = '#';
|
||||
if(args[2].u_obj != mp_const_none) {
|
||||
size_t _len;
|
||||
char *_comment_char = m_new(char, 8);
|
||||
_comment_char = (char *)mp_obj_str_get_data(args[2].u_obj, &_len);
|
||||
comment_char = _comment_char[0];
|
||||
}
|
||||
|
||||
uint16_t skiprows = args[6].u_int;
|
||||
uint16_t max_rows = ULAB_IO_MAX_ROWS;
|
||||
if((args[3].u_int > 0) && (args[3].u_int < ULAB_IO_MAX_ROWS)) {
|
||||
max_rows = args[3].u_int + skiprows;
|
||||
}
|
||||
|
||||
uint16_t *cols = NULL;
|
||||
uint8_t used_columns = 0;
|
||||
if(args[4].u_obj != mp_const_none) {
|
||||
if(mp_obj_is_int(args[4].u_obj)) {
|
||||
used_columns = 1;
|
||||
cols = m_new(uint16_t, used_columns);
|
||||
cols[0] = (uint16_t)mp_obj_get_int(args[4].u_obj);
|
||||
} else {
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("usecols keyword must be specified"));
|
||||
#else
|
||||
// assume that the argument is an iterable
|
||||
used_columns = (uint16_t)mp_obj_get_int(mp_obj_len(args[4].u_obj));
|
||||
cols = m_new(uint16_t, used_columns);
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t item, iterable = mp_getiter(args[4].u_obj, &iter_buf);
|
||||
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
*cols++ = (uint16_t)mp_obj_get_int(item);
|
||||
}
|
||||
cols -= used_columns;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t dtype = args[5].u_int;
|
||||
|
||||
// count the columns and rows
|
||||
// we actually count only the rows and the items, and assume that
|
||||
// the number of columns can be gotten by means of a simple division,
|
||||
// i.e., that each row has the same number of columns
|
||||
char *offset;
|
||||
uint16_t rows = 0, items = 0, all_rows = 0;
|
||||
uint8_t read;
|
||||
uint8_t len = 0;
|
||||
|
||||
do {
|
||||
read = (uint8_t)stream_p->read(stream, buffer, ULAB_IO_BUFFER_SIZE - 1, &error);
|
||||
buffer[read] = '\0';
|
||||
offset = buffer;
|
||||
while(*offset != '\0') {
|
||||
while(*offset == comment_char) {
|
||||
// clear the line till the end, or the buffer's end
|
||||
while((*offset != '\0')) {
|
||||
offset++;
|
||||
if(*offset == '\n') {
|
||||
offset++;
|
||||
all_rows++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// catch whitespaces here: if these are not on a comment line, then they delimit a number
|
||||
if(*offset == '\n') {
|
||||
all_rows++;
|
||||
if(all_rows > skiprows) {
|
||||
rows++;
|
||||
items++;
|
||||
len = 0;
|
||||
}
|
||||
if(all_rows == max_rows) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if((*offset == ' ') || (*offset == '\t') || (*offset == '\v') ||
|
||||
(*offset == '\f') || (*offset == '\r') || (*offset == delimiter)) {
|
||||
offset++;
|
||||
while((*offset == ' ') || (*offset == '\t') || (*offset == '\v') || (*offset == '\f') || (*offset == '\r')) {
|
||||
offset++;
|
||||
}
|
||||
if(len > 0) {
|
||||
if(all_rows >= skiprows) {
|
||||
items++;
|
||||
}
|
||||
len = 0;
|
||||
}
|
||||
} else {
|
||||
offset++;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
} while((read > 0) && (all_rows < max_rows));
|
||||
|
||||
if(rows == 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("empty file"));
|
||||
}
|
||||
uint16_t columns = items / rows;
|
||||
|
||||
if(columns < used_columns) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("usecols is too high"));
|
||||
}
|
||||
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
shape[0] = rows;
|
||||
ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(1, shape, dtype);
|
||||
#else
|
||||
if(args[4].u_obj == mp_const_none) {
|
||||
shape[ULAB_MAX_DIMS - 1] = columns;
|
||||
} else {
|
||||
shape[ULAB_MAX_DIMS - 1] = used_columns;
|
||||
}
|
||||
shape[ULAB_MAX_DIMS - 2] = rows;
|
||||
ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(2, shape, dtype);
|
||||
#endif
|
||||
|
||||
struct mp_stream_seek_t seek_s;
|
||||
seek_s.offset = 0;
|
||||
seek_s.whence = MP_SEEK_SET;
|
||||
stream_p->ioctl(stream, MP_STREAM_SEEK, (mp_uint_t)(uintptr_t)&seek_s, &error);
|
||||
|
||||
char *clipboard = m_new(char, ULAB_IO_CLIPBOARD_SIZE);
|
||||
char *clipboard_origin = clipboard;
|
||||
|
||||
rows = 0;
|
||||
columns = 0;
|
||||
len = 0;
|
||||
|
||||
size_t idx = 0;
|
||||
do {
|
||||
read = stream_p->read(stream, buffer, ULAB_IO_BUFFER_SIZE - 1, &error);
|
||||
buffer[read] = '\0';
|
||||
offset = buffer;
|
||||
|
||||
while(*offset != '\0') {
|
||||
while(*offset == comment_char) {
|
||||
// clear the line till the end, or the buffer's end
|
||||
while((*offset != '\0')) {
|
||||
offset++;
|
||||
if(*offset == '\n') {
|
||||
rows++;
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(rows == max_rows) {
|
||||
break;
|
||||
}
|
||||
|
||||
if((*offset == ' ') || (*offset == '\t') || (*offset == '\v') ||
|
||||
(*offset == '\f') || (*offset == '\r') || (*offset == '\n') || (*offset == delimiter)) {
|
||||
offset++;
|
||||
while((*offset == ' ') || (*offset == '\t') || (*offset == '\v') ||
|
||||
(*offset == '\f') || (*offset == '\r') || (*offset == '\n')) {
|
||||
offset++;
|
||||
}
|
||||
if(len > 0) {
|
||||
clipboard = clipboard_origin;
|
||||
if(rows >= skiprows) {
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
if(columns == cols[0]) {
|
||||
io_assign_value(clipboard, len, ndarray, &idx, dtype);
|
||||
}
|
||||
#else
|
||||
if(args[4].u_obj == mp_const_none) {
|
||||
io_assign_value(clipboard, len, ndarray, &idx, dtype);
|
||||
} else {
|
||||
for(uint8_t c = 0; c < used_columns; c++) {
|
||||
if(columns == cols[c]) {
|
||||
io_assign_value(clipboard, len, ndarray, &idx, dtype);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
columns++;
|
||||
len = 0;
|
||||
|
||||
if(offset[-1] == '\n') {
|
||||
columns = 0;
|
||||
rows++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
*clipboard++ = *offset++;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
} while((read > 0) && (rows < max_rows));
|
||||
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(char, buffer, ULAB_IO_BUFFER_SIZE);
|
||||
m_del(char, clipboard, ULAB_IO_CLIPBOARD_SIZE);
|
||||
m_del(uint16_t, cols, used_columns);
|
||||
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(io_loadtxt_obj, 1, io_loadtxt);
|
||||
#endif /* ULAB_NUMPY_HAS_LOADTXT */
|
||||
|
||||
|
||||
#if ULAB_NUMPY_HAS_SAVE
|
||||
static uint8_t io_sprintf(char *buffer, const char *comma, size_t x) {
|
||||
uint8_t offset = 1;
|
||||
char *buf = buffer;
|
||||
// our own minimal implementation of sprintf for size_t types
|
||||
// this is required on systems, where sprintf is not available
|
||||
|
||||
// find out, how many characters are required
|
||||
// we could call log10 here...
|
||||
for(size_t i = 10; i < 100000000; i *= 10) {
|
||||
if(x < i) {
|
||||
break;
|
||||
}
|
||||
buf++;
|
||||
}
|
||||
|
||||
while(x > 0) {
|
||||
uint8_t rem = x % 10;
|
||||
*buf-- = '0' + rem;
|
||||
x /= 10;
|
||||
offset++;
|
||||
}
|
||||
|
||||
buf += offset;
|
||||
while(*comma != '\0') {
|
||||
*buf++ = *comma++;
|
||||
offset++;
|
||||
}
|
||||
return offset - 1;
|
||||
}
|
||||
|
||||
static mp_obj_t io_save(mp_obj_t file, mp_obj_t ndarray_) {
|
||||
if(!mp_obj_is_str(file) || !mp_obj_is_type(ndarray_, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong input type"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(ndarray_);
|
||||
int error;
|
||||
char *buffer = m_new(char, ULAB_IO_BUFFER_SIZE);
|
||||
uint8_t offset = 0;
|
||||
|
||||
// test for endianness
|
||||
uint16_t x = 1;
|
||||
int8_t native_endianness = (x >> 8) == 1 ? '>' : '<';
|
||||
|
||||
mp_obj_t open_args[2] = {
|
||||
file,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_wb)
|
||||
};
|
||||
|
||||
mp_obj_t stream = mp_builtin_open_obj.fun.kw(2, open_args, (mp_map_t *)&mp_const_empty_map);
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(stream);
|
||||
|
||||
// write header;
|
||||
// magic string + header length, which is always 128 - 10 = 118, represented as a little endian uint16 (0x76, 0x00)
|
||||
// + beginning of the dictionary describing the array
|
||||
memcpy(buffer, "\x93NUMPY\x01\x00\x76\x00{'descr': '", 21);
|
||||
offset += 21;
|
||||
|
||||
buffer[offset] = native_endianness;
|
||||
if((ndarray->dtype == NDARRAY_UINT8) || (ndarray->dtype == NDARRAY_INT8)) {
|
||||
// for single-byte data, the endianness doesn't matter
|
||||
buffer[offset] = '|';
|
||||
}
|
||||
offset++;
|
||||
switch(ndarray->dtype) {
|
||||
case NDARRAY_UINT8:
|
||||
memcpy(buffer+offset, "u1", 2);
|
||||
break;
|
||||
case NDARRAY_INT8:
|
||||
memcpy(buffer+offset, "i1", 2);
|
||||
break;
|
||||
case NDARRAY_UINT16:
|
||||
memcpy(buffer+offset, "u2", 2);
|
||||
break;
|
||||
case NDARRAY_INT16:
|
||||
memcpy(buffer+offset, "i2", 2);
|
||||
break;
|
||||
case NDARRAY_FLOAT:
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
memcpy(buffer+offset, "f4", 2);
|
||||
#else
|
||||
memcpy(buffer+offset, "f8", 2);
|
||||
#endif
|
||||
break;
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
case NDARRAY_COMPLEX:
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
memcpy(buffer+offset, "c8", 2);
|
||||
#else
|
||||
memcpy(buffer+offset, "c16", 3);
|
||||
offset++;
|
||||
#endif
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
offset += 2;
|
||||
memcpy(buffer+offset, "', 'fortran_order': False, 'shape': (", 37);
|
||||
offset += 37;
|
||||
|
||||
if(ndarray->ndim == 1) {
|
||||
offset += io_sprintf(buffer+offset, ",\0", ndarray->shape[ULAB_MAX_DIMS - 1]);
|
||||
} else {
|
||||
for(uint8_t i = ndarray->ndim; i > 1; i--) {
|
||||
offset += io_sprintf(buffer+offset, ", \0", ndarray->shape[ULAB_MAX_DIMS - i]);
|
||||
}
|
||||
offset += io_sprintf(buffer+offset, "\0", ndarray->shape[ULAB_MAX_DIMS - 1]);
|
||||
}
|
||||
memcpy(buffer+offset, "), }", 4);
|
||||
offset += 4;
|
||||
// pad with space till the very end
|
||||
memset(buffer+offset, 32, ULAB_IO_BUFFER_SIZE - offset - 1);
|
||||
buffer[ULAB_IO_BUFFER_SIZE - 1] = '\n';
|
||||
stream_p->write(stream, buffer, ULAB_IO_BUFFER_SIZE, &error);
|
||||
|
||||
// write the array data
|
||||
uint8_t sz = ndarray->itemsize;
|
||||
offset = 0;
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
|
||||
ITERATOR_HEAD();
|
||||
memcpy(buffer+offset, array, sz);
|
||||
offset += sz;
|
||||
if(offset == ULAB_IO_BUFFER_SIZE) {
|
||||
stream_p->write(stream, buffer, offset, &error);
|
||||
offset = 0;
|
||||
}
|
||||
ITERATOR_TAIL(ndarray, array);
|
||||
stream_p->write(stream, buffer, offset, &error);
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
|
||||
m_del(char, buffer, ULAB_IO_BUFFER_SIZE);
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(io_save_obj, io_save);
|
||||
#endif /* ULAB_NUMPY_HAS_SAVE */
|
||||
|
||||
#if ULAB_NUMPY_HAS_SAVETXT
|
||||
static int8_t io_format_float(ndarray_obj_t *ndarray, mp_float_t (*func)(void *), uint8_t *array, char *buffer, const char *delimiter) {
|
||||
// own implementation of float formatting for platforms that don't have sprintf
|
||||
int8_t offset = 0;
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
const int precision = 6;
|
||||
#else
|
||||
const int precision = 7;
|
||||
#endif
|
||||
#else
|
||||
const int precision = 16;
|
||||
#endif
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(ndarray->dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t real = func(array);
|
||||
mp_float_t imag = func(array + ndarray->itemsize / 2);
|
||||
offset = mp_format_float(real, buffer, ULAB_IO_BUFFER_SIZE, 'f', precision, 'j');
|
||||
if(imag >= MICROPY_FLOAT_CONST(0.0)) {
|
||||
buffer[offset++] = '+';
|
||||
} else {
|
||||
buffer[offset++] = '-';
|
||||
}
|
||||
offset += mp_format_float(-imag, &buffer[offset], ULAB_IO_BUFFER_SIZE, 'f', precision, 'j');
|
||||
}
|
||||
#endif
|
||||
offset = (uint8_t)mp_format_float(func(array), buffer, ULAB_IO_BUFFER_SIZE, 'f', precision, '\0');
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(ndarray->dtype != NDARRAY_COMPLEX) {
|
||||
// complexes end with a 'j', floats with a '\0', so we have to wind back by one character
|
||||
offset--;
|
||||
}
|
||||
#endif
|
||||
|
||||
while(*delimiter != '\0') {
|
||||
buffer[offset++] = *delimiter++;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static mp_obj_t io_savetxt(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_delimiter, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_header, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_footer, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_comments, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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_str(args[0].u_obj) || !mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong input type"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
if(ndarray->ndim > 2) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("array has too many dimensions"));
|
||||
}
|
||||
#endif
|
||||
|
||||
mp_obj_t open_args[2] = {
|
||||
args[0].u_obj,
|
||||
MP_OBJ_NEW_QSTR(MP_QSTR_w)
|
||||
};
|
||||
|
||||
mp_obj_t stream = mp_builtin_open_obj.fun.kw(2, open_args, (mp_map_t *)&mp_const_empty_map);
|
||||
const mp_stream_p_t *stream_p = mp_get_stream(stream);
|
||||
|
||||
char *buffer = m_new(char, ULAB_IO_BUFFER_SIZE);
|
||||
int error;
|
||||
|
||||
size_t len_comment;
|
||||
char *comments;
|
||||
|
||||
if(mp_obj_is_str(args[5].u_obj)) {
|
||||
const char *_comments = mp_obj_str_get_data(args[5].u_obj, &len_comment);
|
||||
comments = (char *)_comments;
|
||||
} else {
|
||||
len_comment = 2;
|
||||
comments = m_new(char, len_comment);
|
||||
comments[0] = '#';
|
||||
comments[1] = ' ';
|
||||
}
|
||||
|
||||
if(mp_obj_is_str(args[3].u_obj)) {
|
||||
size_t _len;
|
||||
const char *header = mp_obj_str_get_data(args[3].u_obj, &_len);
|
||||
|
||||
stream_p->write(stream, comments, len_comment, &error);
|
||||
|
||||
// We can't write the header in the single chunk, for it might contain line breaks
|
||||
for(size_t i = 0; i < _len; header++, i++) {
|
||||
stream_p->write(stream, header, 1, &error);
|
||||
if((*header == '\n') && (i < _len)) {
|
||||
stream_p->write(stream, comments, len_comment, &error);
|
||||
}
|
||||
}
|
||||
stream_p->write(stream, "\n", 1, &error);
|
||||
}
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype);
|
||||
char *delimiter = m_new(char, 8);
|
||||
|
||||
if(ndarray->ndim == 1) {
|
||||
delimiter[0] = '\n';
|
||||
delimiter[1] = '\0';
|
||||
} else if(args[2].u_obj == mp_const_none) {
|
||||
delimiter[0] = ' ';
|
||||
delimiter[1] = '\0';
|
||||
} else {
|
||||
size_t delimiter_len;
|
||||
delimiter = (char *)mp_obj_str_get_data(args[2].u_obj, &delimiter_len);
|
||||
}
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
int8_t chars = io_format_float(ndarray, func, array, buffer, l == ndarray->shape[ULAB_MAX_DIMS - 1] - 1 ? "\n" : delimiter);
|
||||
if(chars > 0) {
|
||||
stream_p->write(stream, buffer, chars, &error);
|
||||
}
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < ndarray->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
array -= ndarray->strides[ULAB_MAX_DIMS - 1] * ndarray->shape[ULAB_MAX_DIMS-1];
|
||||
array += ndarray->strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < ndarray->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
|
||||
if(mp_obj_is_str(args[4].u_obj)) { // footer string
|
||||
size_t _len;
|
||||
const char *footer = mp_obj_str_get_data(args[4].u_obj, &_len);
|
||||
|
||||
stream_p->write(stream, comments, len_comment, &error);
|
||||
|
||||
// We can't write the header in the single chunk, for it might contain line breaks
|
||||
for(size_t i = 0; i < _len; footer++, i++) {
|
||||
stream_p->write(stream, footer, 1, &error);
|
||||
if((*footer == '\n') && (i < _len)) {
|
||||
stream_p->write(stream, comments, len_comment, &error);
|
||||
}
|
||||
}
|
||||
stream_p->write(stream, "\n", 1, &error);
|
||||
}
|
||||
|
||||
stream_p->ioctl(stream, MP_STREAM_CLOSE, 0, &error);
|
||||
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(io_savetxt_obj, 2, io_savetxt);
|
||||
#endif /* ULAB_NUMPY_HAS_SAVETXT */
|
||||
19
code/numpy/io/io.h
Normal file
19
code/numpy/io/io.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _ULAB_IO_
|
||||
#define _ULAB_IO_
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(io_load_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(io_loadtxt_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(io_save_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(io_savetxt_obj);
|
||||
|
||||
#endif
|
||||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "../carray/carray_tools.h"
|
||||
#include "linalg.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_LINALG_MODULE
|
||||
|
|
@ -44,6 +45,7 @@
|
|||
|
||||
static mp_obj_t linalg_cholesky(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
ndarray_obj_t *L = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, ndarray->shape[ULAB_MAX_DIMS - 1], ndarray->shape[ULAB_MAX_DIMS - 1]), NDARRAY_FLOAT);
|
||||
mp_float_t *Larray = (mp_float_t *)L->array;
|
||||
|
||||
|
|
@ -65,7 +67,7 @@ static mp_obj_t linalg_cholesky(mp_obj_t oin) {
|
|||
for(size_t n=m+1; n < N; n++) { // columns
|
||||
// compare entry (m, n) to (n, m)
|
||||
if(LINALG_EPSILON < MICROPY_FLOAT_C_FUN(fabs)(Larray[m * N + n] - Larray[n * N + m])) {
|
||||
mp_raise_ValueError(translate("input matrix is asymmetric"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input matrix is asymmetric"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,7 +87,7 @@ static mp_obj_t linalg_cholesky(mp_obj_t oin) {
|
|||
}
|
||||
if(i == j) {
|
||||
if(sum <= MICROPY_FLOAT_CONST(0.0)) {
|
||||
mp_raise_ValueError(translate("matrix is not positive definite"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("matrix is not positive definite"));
|
||||
} else {
|
||||
Larray[i * N + i] = MICROPY_FLOAT_C_FUN(sqrt)(sum);
|
||||
}
|
||||
|
|
@ -110,6 +112,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky);
|
|||
|
||||
static mp_obj_t linalg_det(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
size_t N = ndarray->shape[ULAB_MAX_DIMS - 1];
|
||||
mp_float_t *tmp = m_new(mp_float_t, N * N);
|
||||
|
|
@ -182,6 +185,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);
|
|||
|
||||
static mp_obj_t linalg_eig(mp_obj_t oin) {
|
||||
ndarray_obj_t *in = tools_object_is_square(oin);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(in->dtype)
|
||||
uint8_t *iarray = (uint8_t *)in->array;
|
||||
size_t S = in->shape[ULAB_MAX_DIMS - 1];
|
||||
mp_float_t *array = m_new(mp_float_t, S*S);
|
||||
|
|
@ -200,7 +204,7 @@ static mp_obj_t linalg_eig(mp_obj_t oin) {
|
|||
// compare entry (m, n) to (n, m)
|
||||
// TODO: this must probably be scaled!
|
||||
if(LINALG_EPSILON < MICROPY_FLOAT_C_FUN(fabs)(array[m * S + n] - array[n * S + m])) {
|
||||
mp_raise_ValueError(translate("input matrix is asymmetric"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input matrix is asymmetric"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -215,7 +219,7 @@ static mp_obj_t linalg_eig(mp_obj_t oin) {
|
|||
if(iterations == 0) {
|
||||
// the computation did not converge; numpy raises LinAlgError
|
||||
m_del(mp_float_t, array, in->len);
|
||||
mp_raise_ValueError(translate("iterations did not converge"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("iterations did not converge"));
|
||||
}
|
||||
ndarray_obj_t *eigenvalues = ndarray_new_linear_array(S, NDARRAY_FLOAT);
|
||||
mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array;
|
||||
|
|
@ -227,7 +231,7 @@ static mp_obj_t linalg_eig(mp_obj_t oin) {
|
|||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
|
||||
tuple->items[0] = MP_OBJ_FROM_PTR(eigenvalues);
|
||||
tuple->items[1] = MP_OBJ_FROM_PTR(eigenvectors);
|
||||
return tuple;
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
||||
|
|
@ -243,6 +247,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);
|
|||
//|
|
||||
static mp_obj_t linalg_inv(mp_obj_t o_in) {
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(o_in);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
size_t N = ndarray->shape[ULAB_MAX_DIMS - 1];
|
||||
ndarray_obj_t *inverted = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, N, N), NDARRAY_FLOAT);
|
||||
|
|
@ -262,7 +267,7 @@ static mp_obj_t linalg_inv(mp_obj_t o_in) {
|
|||
iarray -= N*N;
|
||||
|
||||
if(!linalg_invert_matrix(iarray, N)) {
|
||||
mp_raise_ValueError(translate("input matrix is singular"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input matrix is singular"));
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(inverted);
|
||||
}
|
||||
|
|
@ -280,8 +285,8 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
|
|||
|
||||
static mp_obj_t linalg_norm(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 } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE} } ,
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -305,6 +310,7 @@ static mp_obj_t linalg_norm(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(sqrt)(dot * (count - 1)));
|
||||
} else if(mp_obj_is_type(x, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(x);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
// always get a float, so that we don't have to resolve the dtype later
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype);
|
||||
|
|
@ -358,7 +364,7 @@ static mp_obj_t linalg_norm(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
if(results->ndim == 0) {
|
||||
return mp_obj_new_float(*rarray);
|
||||
}
|
||||
return results;
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
return mp_const_none; // we should never reach this point
|
||||
}
|
||||
|
|
@ -378,7 +384,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(linalg_norm_obj, 1, linalg_norm);
|
|||
|
||||
static mp_obj_t linalg_qr(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_ROM_NONE } },
|
||||
{ MP_QSTR_mode, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_QSTR(MP_QSTR_reduced) } },
|
||||
};
|
||||
|
||||
|
|
@ -387,11 +393,11 @@ static mp_obj_t linalg_qr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
|
|||
|
||||
|
||||
if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("operation is defined for ndarrays only"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("operation is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
if(source->ndim != 2) {
|
||||
mp_raise_ValueError(translate("operation is defined for 2D arrays only"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("operation is defined for 2D arrays only"));
|
||||
}
|
||||
|
||||
size_t m = source->shape[ULAB_MAX_DIMS - 2]; // rows
|
||||
|
|
@ -429,22 +435,22 @@ static mp_obj_t linalg_qr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
|
|||
// [[c s],
|
||||
// [s -c]]
|
||||
if(MICROPY_FLOAT_C_FUN(fabs)(rarray[i * n + j]) < LINALG_EPSILON) { // r[i, j]
|
||||
c = (rarray[(i - 1) * n + j] >= 0.0) ? 1.0 : -1.0; // r[i-1, j]
|
||||
c = (rarray[(i - 1) * n + j] >= MICROPY_FLOAT_CONST(0.0)) ? MICROPY_FLOAT_CONST(1.0) : MICROPY_FLOAT_CONST(-1.0); // r[i-1, j]
|
||||
s = 0.0;
|
||||
} else if(MICROPY_FLOAT_C_FUN(fabs)(rarray[(i - 1) * n + j]) < LINALG_EPSILON) { // r[i-1, j]
|
||||
c = 0.0;
|
||||
s = (rarray[i * n + j] >= 0.0) ? -1.0 : 1.0; // r[i, j]
|
||||
s = (rarray[i * n + j] >= MICROPY_FLOAT_CONST(0.0)) ? MICROPY_FLOAT_CONST(-1.0) : MICROPY_FLOAT_CONST(1.0); // r[i, j]
|
||||
} else {
|
||||
mp_float_t t, u;
|
||||
if(MICROPY_FLOAT_C_FUN(fabs)(rarray[(i - 1) * n + j]) > MICROPY_FLOAT_C_FUN(fabs)(rarray[i * n + j])) { // r[i-1, j], r[i, j]
|
||||
t = rarray[i * n + j] / rarray[(i - 1) * n + j]; // r[i, j]/r[i-1, j]
|
||||
u = MICROPY_FLOAT_C_FUN(sqrt)(1 + t * t);
|
||||
c = -1.0 / u;
|
||||
c = MICROPY_FLOAT_CONST(-1.0) / u;
|
||||
s = c * t;
|
||||
} else {
|
||||
t = rarray[(i - 1) * n + j] / rarray[i * n + j]; // r[i-1, j]/r[i, j]
|
||||
u = MICROPY_FLOAT_C_FUN(sqrt)(1 + t * t);
|
||||
s = -1.0 / u;
|
||||
s = MICROPY_FLOAT_CONST(-1.0) / u;
|
||||
c = s * t;
|
||||
}
|
||||
}
|
||||
|
|
@ -492,43 +498,45 @@ static mp_obj_t linalg_qr(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
|
|||
tuple->items[0] = MP_OBJ_FROM_PTR(q);
|
||||
tuple->items[1] = MP_OBJ_FROM_PTR(r);
|
||||
} else {
|
||||
mp_raise_ValueError(translate("mode must be complete, or reduced"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("mode must be complete, or reduced"));
|
||||
}
|
||||
return tuple;
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(linalg_qr_obj, 1, linalg_qr);
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t ulab_linalg_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) },
|
||||
static const mp_rom_map_elem_t ulab_linalg_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_linalg) },
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_LINALG_HAS_CHOLESKY
|
||||
{ MP_ROM_QSTR(MP_QSTR_cholesky), (mp_obj_t)&linalg_cholesky_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cholesky), MP_ROM_PTR(&linalg_cholesky_obj) },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_DET
|
||||
{ MP_ROM_QSTR(MP_QSTR_det), (mp_obj_t)&linalg_det_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_det), MP_ROM_PTR(&linalg_det_obj) },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_EIG
|
||||
{ MP_ROM_QSTR(MP_QSTR_eig), (mp_obj_t)&linalg_eig_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_eig), MP_ROM_PTR(&linalg_eig_obj) },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_INV
|
||||
{ MP_ROM_QSTR(MP_QSTR_inv), (mp_obj_t)&linalg_inv_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_inv), MP_ROM_PTR(&linalg_inv_obj) },
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_QR
|
||||
{ MP_ROM_QSTR(MP_QSTR_qr), (mp_obj_t)&linalg_qr_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_qr), MP_ROM_PTR(&linalg_qr_obj) },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_LINALG_HAS_NORM
|
||||
{ MP_ROM_QSTR(MP_QSTR_norm), (mp_obj_t)&linalg_norm_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_norm), MP_ROM_PTR(&linalg_norm_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table);
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_linalg_globals, ulab_linalg_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_linalg_module = {
|
||||
const mp_obj_module_t ulab_linalg_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_linalg_globals,
|
||||
};
|
||||
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_numpy_dot_linalg, ulab_linalg_module);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
#include "../../ndarray.h"
|
||||
#include "linalg_tools.h"
|
||||
|
||||
extern mp_obj_module_t ulab_linalg_module;
|
||||
extern const mp_obj_module_t ulab_linalg_module;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_cholesky_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(linalg_det_obj);
|
||||
|
|
|
|||
|
|
@ -26,10 +26,9 @@ bool linalg_invert_matrix(mp_float_t *data, size_t N) {
|
|||
|
||||
// initially, this is the unit matrix: the contents of this matrix is what
|
||||
// will be returned after all the transformations
|
||||
mp_float_t *unit = m_new(mp_float_t, N*N);
|
||||
mp_float_t *unit = m_new0(mp_float_t, N*N);
|
||||
mp_float_t elem = 1.0;
|
||||
// initialise the unit matrix
|
||||
memset(unit, 0, sizeof(mp_float_t)*N*N);
|
||||
|
||||
for(size_t m=0; m < N; m++) {
|
||||
memcpy(&unit[m * (N+1)], &elem, sizeof(mp_float_t));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ mp_obj_t ndarray_flatiter_make_new(mp_obj_t self_in) {
|
|||
ndarray_flatiter_t *flatiter = m_new_obj(ndarray_flatiter_t);
|
||||
flatiter->base.type = &ndarray_flatiter_type;
|
||||
flatiter->iternext = ndarray_flatiter_next;
|
||||
flatiter->ndarray = MP_OBJ_TO_PTR(self_in);
|
||||
flatiter->ndarray = self_in;
|
||||
flatiter->cur = 0;
|
||||
return flatiter;
|
||||
return MP_OBJ_FROM_PTR(flatiter);
|
||||
}
|
||||
|
||||
mp_obj_t ndarray_flatiter_next(mp_obj_t self_in) {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "../ulab.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "./carray/carray_tools.h"
|
||||
#include "numerical.h"
|
||||
|
||||
enum NUMERICAL_FUNCTION_TYPE {
|
||||
|
|
@ -44,15 +45,14 @@ enum NUMERICAL_FUNCTION_TYPE {
|
|||
//| from typing import Dict
|
||||
//|
|
||||
//| _ArrayLike = Union[ndarray, List[_float], Tuple[_float], range]
|
||||
//| _ScalarOrArrayLike = Union[int, _float, _ArrayLike]
|
||||
//| _ScalarOrNdArray = Union[int, _float, ndarray]
|
||||
//|
|
||||
//| _DType = int
|
||||
//| """`ulab.numpy.int8`, `ulab.numpy.uint8`, `ulab.numpy.int16`, `ulab.numpy.uint16`, `ulab.numpy.float` or `ulab.numpy.bool`"""
|
||||
//|
|
||||
//| _float = float
|
||||
//| """Type alias of the bulitin float"""
|
||||
//|
|
||||
//| _bool = bool
|
||||
//| """Type alias of the bulitin bool"""
|
||||
//| from builtins import float as _float
|
||||
//| from builtins import bool as _bool
|
||||
//|
|
||||
//| int8: _DType
|
||||
//| """Type code for signed integers in the range -128 .. 127 inclusive, like the 'b' typecode of `array.array`"""
|
||||
|
|
@ -133,6 +133,19 @@ static mp_obj_t numerical_all_any(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
|||
size_t l = 0;
|
||||
if(axis == mp_const_none) {
|
||||
do {
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(ndarray->dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t real = *((mp_float_t *)array);
|
||||
mp_float_t imag = *((mp_float_t *)(array + sizeof(mp_float_t)));
|
||||
if(((real != MICROPY_FLOAT_CONST(0.0)) | (imag != MICROPY_FLOAT_CONST(0.0))) & !anytype) {
|
||||
// optype = NUMERICAL_ANY
|
||||
return mp_const_true;
|
||||
} else if(((real == MICROPY_FLOAT_CONST(0.0)) & (imag == MICROPY_FLOAT_CONST(0.0))) & anytype) {
|
||||
// optype == NUMERICAL_ALL
|
||||
return mp_const_false;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
mp_float_t value = func(array);
|
||||
if((value != MICROPY_FLOAT_CONST(0.0)) & !anytype) {
|
||||
// optype = NUMERICAL_ANY
|
||||
|
|
@ -141,11 +154,33 @@ static mp_obj_t numerical_all_any(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
|||
// optype == NUMERICAL_ALL
|
||||
return mp_const_false;
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
}
|
||||
#endif
|
||||
array += _shape_strides.strides[0];
|
||||
l++;
|
||||
} while(l < _shape_strides.shape[0]);
|
||||
} else { // a scalar axis keyword was supplied
|
||||
do {
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(ndarray->dtype == NDARRAY_COMPLEX) {
|
||||
mp_float_t real = *((mp_float_t *)array);
|
||||
mp_float_t imag = *((mp_float_t *)(array + sizeof(mp_float_t)));
|
||||
if(((real != MICROPY_FLOAT_CONST(0.0)) | (imag != MICROPY_FLOAT_CONST(0.0))) & !anytype) {
|
||||
// optype = NUMERICAL_ANY
|
||||
*rarray = 1;
|
||||
// since we are breaking out of the loop, move the pointer forward
|
||||
array += _shape_strides.strides[0] * (_shape_strides.shape[0] - l);
|
||||
break;
|
||||
} else if(((real == MICROPY_FLOAT_CONST(0.0)) & (imag == MICROPY_FLOAT_CONST(0.0))) & anytype) {
|
||||
// optype == NUMERICAL_ALL
|
||||
*rarray = 0;
|
||||
// since we are breaking out of the loop, move the pointer forward
|
||||
array += _shape_strides.strides[0] * (_shape_strides.shape[0] - l);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
mp_float_t value = func(array);
|
||||
if((value != MICROPY_FLOAT_CONST(0.0)) & !anytype) {
|
||||
// optype == NUMERICAL_ANY
|
||||
|
|
@ -160,6 +195,9 @@ static mp_obj_t numerical_all_any(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
|||
array += _shape_strides.strides[0] * (_shape_strides.shape[0] - l);
|
||||
break;
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
}
|
||||
#endif
|
||||
array += _shape_strides.strides[0];
|
||||
l++;
|
||||
} while(l < _shape_strides.shape[0]);
|
||||
|
|
@ -183,7 +221,15 @@ static mp_obj_t numerical_all_any(mp_obj_t oin, mp_obj_t axis, uint8_t optype) {
|
|||
i++;
|
||||
} while(i < _shape_strides.shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
return results;
|
||||
if(axis == mp_const_none) {
|
||||
// the innermost loop fell through, so return the result here
|
||||
if(!anytype) {
|
||||
return mp_const_false;
|
||||
} else {
|
||||
return mp_const_true;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
} else if(mp_obj_is_int(oin) || mp_obj_is_float(oin)) {
|
||||
return mp_obj_is_true(oin) ? mp_const_true : mp_const_false;
|
||||
} else {
|
||||
|
|
@ -228,7 +274,8 @@ static mp_obj_t numerical_sum_mean_std_iterable(mp_obj_t oin, uint8_t optype, si
|
|||
}
|
||||
}
|
||||
|
||||
static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, uint8_t optype, size_t ddof) {
|
||||
static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t axis, mp_obj_t keepdims, uint8_t optype, size_t ddof) {
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
shape_strides _shape_strides = tools_reduce_axes(ndarray, axis);
|
||||
|
||||
|
|
@ -239,7 +286,7 @@ static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
return mp_obj_new_float(MICROPY_FLOAT_CONST(0.0));
|
||||
}
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(ndarray->dtype);
|
||||
mp_float_t M =MICROPY_FLOAT_CONST(0.0);
|
||||
mp_float_t M = MICROPY_FLOAT_CONST(0.0);
|
||||
mp_float_t m = MICROPY_FLOAT_CONST(0.0);
|
||||
mp_float_t S = MICROPY_FLOAT_CONST(0.0);
|
||||
mp_float_t s = MICROPY_FLOAT_CONST(0.0);
|
||||
|
|
@ -325,7 +372,7 @@ static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
mp_float_t norm = (mp_float_t)_shape_strides.shape[0];
|
||||
// re-wind the array here
|
||||
farray = (mp_float_t *)results->array;
|
||||
for(size_t i=0; i < results->len; i++) {
|
||||
for(size_t i = 0; i < results->len; i++) {
|
||||
*farray++ *= norm;
|
||||
}
|
||||
}
|
||||
|
|
@ -333,7 +380,7 @@ static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
bool isStd = optype == NUMERICAL_STD ? 1 : 0;
|
||||
results = ndarray_new_dense_ndarray(_shape_strides.ndim, _shape_strides.shape, NDARRAY_FLOAT);
|
||||
farray = (mp_float_t *)results->array;
|
||||
// we can return the 0 array here, if the degrees of freedom is larger than the length of the axis
|
||||
// we can return the 0 array here, if the degrees of freedom are larger than the length of the axis
|
||||
if((optype == NUMERICAL_STD) && (_shape_strides.shape[0] <= ddof)) {
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
|
@ -350,11 +397,9 @@ static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
RUN_MEAN_STD(mp_float_t, array, farray, _shape_strides, div, isStd);
|
||||
}
|
||||
}
|
||||
if(results->ndim == 0) { // return a scalar here
|
||||
return mp_binary_get_val_array(results->dtype, results->array, 0);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
return ulab_tools_restore_dims(ndarray, results, keepdims, _shape_strides);
|
||||
}
|
||||
// we should never get to this point
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -362,7 +407,7 @@ static mp_obj_t numerical_sum_mean_std_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
#if ULAB_NUMPY_HAS_ARGMINMAX
|
||||
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"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("attempt to get argmin/argmax of an empty sequence"));
|
||||
}
|
||||
size_t idx = 0, best_idx = 0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
|
|
@ -394,10 +439,10 @@ static mp_obj_t numerical_argmin_argmax_iterable(mp_obj_t oin, uint8_t optype) {
|
|||
}
|
||||
}
|
||||
|
||||
static 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 keepdims, mp_obj_t axis, uint8_t optype) {
|
||||
// TODO: treat the flattened array
|
||||
if(ndarray->len == 0) {
|
||||
mp_raise_ValueError(translate("attempt to get (arg)min/(arg)max of empty sequence"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("attempt to get (arg)min/(arg)max of empty sequence"));
|
||||
}
|
||||
|
||||
if(axis == mp_const_none) {
|
||||
|
|
@ -467,19 +512,16 @@ static mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
}
|
||||
}
|
||||
} else {
|
||||
int8_t ax = mp_obj_get_int(axis);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("axis is out of bounds"));
|
||||
}
|
||||
int8_t ax = tools_get_axis(axis, ndarray->ndim);
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS);
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
uint8_t index = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
shape_strides _shape_strides = tools_reduce_axes(ndarray, axis);
|
||||
|
||||
uint8_t index = _shape_strides.axis;
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
|
||||
|
|
@ -502,19 +544,20 @@ static mp_obj_t numerical_argmin_argmax_ndarray(ndarray_obj_t *ndarray, mp_obj_t
|
|||
} else {
|
||||
RUN_ARGMIN(ndarray, mp_float_t, array, results, rarray, shape, strides, index, optype);
|
||||
}
|
||||
if(results->len == 1) {
|
||||
return mp_binary_get_val_array(results->dtype, results->array, 0);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
return ulab_tools_restore_dims(ndarray, results, keepdims, _shape_strides);
|
||||
}
|
||||
// we should never get to this point
|
||||
return mp_const_none;
|
||||
}
|
||||
#endif
|
||||
|
||||
static mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t optype) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = mp_const_none} } ,
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE} } ,
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_keepdims, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_FALSE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -522,13 +565,17 @@ static mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
|
||||
mp_obj_t oin = args[0].u_obj;
|
||||
mp_obj_t axis = args[1].u_obj;
|
||||
mp_obj_t keepdims = args[2].u_obj;
|
||||
|
||||
if((axis != mp_const_none) && (!mp_obj_is_int(axis))) {
|
||||
mp_raise_TypeError(translate("axis must be None, or an integer"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("axis must be None, or an integer"));
|
||||
}
|
||||
|
||||
#if ULAB_NUMPY_HAS_ALL | ULAB_NUMPY_HAS_ANY
|
||||
if((optype == NUMERICAL_ALL) || (optype == NUMERICAL_ANY)) {
|
||||
return numerical_all_any(oin, axis, optype);
|
||||
}
|
||||
#endif
|
||||
if(mp_obj_is_type(oin, &mp_type_tuple) || mp_obj_is_type(oin, &mp_type_list) ||
|
||||
mp_obj_is_type(oin, &mp_type_range)) {
|
||||
switch(optype) {
|
||||
|
|
@ -550,15 +597,18 @@ static mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
case NUMERICAL_MAX:
|
||||
case NUMERICAL_ARGMIN:
|
||||
case NUMERICAL_ARGMAX:
|
||||
return numerical_argmin_argmax_ndarray(ndarray, axis, optype);
|
||||
case NUMERICAL_SUM:
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
return numerical_argmin_argmax_ndarray(ndarray, keepdims, axis, optype);
|
||||
case NUMERICAL_MEAN:
|
||||
return numerical_sum_mean_std_ndarray(ndarray, axis, optype, 0);
|
||||
case NUMERICAL_STD:
|
||||
case NUMERICAL_SUM:
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
return numerical_sum_mean_std_ndarray(ndarray, axis, keepdims, optype, 0);
|
||||
default:
|
||||
mp_raise_NotImplementedError(translate("operation is not implemented on ndarrays"));
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("operation is not implemented on ndarrays"));
|
||||
}
|
||||
} else {
|
||||
mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be tuple, list, range, or ndarray"));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
|
@ -566,7 +616,7 @@ static mp_obj_t numerical_function(size_t n_args, const mp_obj_t *pos_args, mp_m
|
|||
#if ULAB_NUMPY_HAS_SORT | NDARRAY_HAS_SORT
|
||||
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"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("sort argument must be an ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray;
|
||||
|
|
@ -575,6 +625,7 @@ static mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inpla
|
|||
} else {
|
||||
ndarray = ndarray_copy_view(MP_OBJ_TO_PTR(oin));
|
||||
}
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
|
||||
int8_t ax = 0;
|
||||
if(axis == mp_const_none) {
|
||||
|
|
@ -589,30 +640,30 @@ static mp_obj_t numerical_sort_helper(mp_obj_t oin, mp_obj_t axis, uint8_t inpla
|
|||
ndarray->ndim = 1;
|
||||
#endif
|
||||
} else {
|
||||
ax = mp_obj_get_int(axis);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
}
|
||||
ax = tools_get_axis(axis, ndarray->ndim);
|
||||
}
|
||||
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS);
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
// we work with the typed array, so re-scale the stride
|
||||
int32_t increment = ndarray->strides[ax] / ndarray->itemsize;
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
if(ndarray->shape[ax]) {
|
||||
if((ndarray->dtype == NDARRAY_UINT8) || (ndarray->dtype == NDARRAY_INT8)) {
|
||||
HEAPSORT(ndarray, uint8_t, array, shape, strides, ax, increment, ndarray->shape[ax]);
|
||||
} else if((ndarray->dtype == NDARRAY_INT16) || (ndarray->dtype == NDARRAY_INT16)) {
|
||||
} else if((ndarray->dtype == NDARRAY_UINT16) || (ndarray->dtype == NDARRAY_INT16)) {
|
||||
HEAPSORT(ndarray, uint16_t, array, shape, strides, ax, increment, ndarray->shape[ax]);
|
||||
} else {
|
||||
HEAPSORT(ndarray, mp_float_t, array, shape, strides, ax, increment, ndarray->shape[ax]);
|
||||
}
|
||||
}
|
||||
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
|
||||
if(inplace == 1) {
|
||||
return mp_const_none;
|
||||
} else {
|
||||
|
|
@ -667,43 +718,39 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
|
|||
|
||||
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_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
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("argsort argument must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("argsort argument must be an ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
if(args[1].u_obj == mp_const_none) {
|
||||
// bail out, though dense arrays could still be sorted
|
||||
mp_raise_NotImplementedError(translate("argsort is not implemented for flattened arrays"));
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("argsort is not implemented for flattened arrays"));
|
||||
}
|
||||
// Since we are returning an NDARRAY_UINT16 array, bail out,
|
||||
// if the axis is longer than what we can hold
|
||||
for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) {
|
||||
if(ndarray->shape[i] > 65535) {
|
||||
mp_raise_ValueError(translate("axis too long"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("axis too long"));
|
||||
}
|
||||
}
|
||||
int8_t ax = mp_obj_get_int(args[1].u_obj);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
}
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS);
|
||||
int8_t ax = tools_get_axis(args[1].u_obj, ndarray->ndim);
|
||||
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
|
||||
// We could return an NDARRAY_UINT8 array, if all lengths are shorter than 256
|
||||
ndarray_obj_t *indices = ndarray_new_ndarray(ndarray->ndim, ndarray->shape, NULL, NDARRAY_UINT16);
|
||||
int32_t *istrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(istrides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS);
|
||||
ndarray_obj_t *indices = ndarray_new_ndarray(ndarray->ndim, ndarray->shape, NULL, NDARRAY_UINT16, NULL);
|
||||
int32_t *istrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(indices, ax, shape, istrides);
|
||||
|
||||
for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) {
|
||||
istrides[i] /= sizeof(uint16_t);
|
||||
}
|
||||
|
|
@ -755,6 +802,7 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
|
|||
// reset the array
|
||||
iarray = indices->array;
|
||||
|
||||
if(ndarray->shape[ax]) {
|
||||
if((ndarray->dtype == NDARRAY_UINT8) || (ndarray->dtype == NDARRAY_INT8)) {
|
||||
HEAP_ARGSORT(ndarray, uint8_t, array, shape, strides, ax, increment, ndarray->shape[ax], iarray, istrides, iincrement);
|
||||
} else if((ndarray->dtype == NDARRAY_UINT16) || (ndarray->dtype == NDARRAY_INT16)) {
|
||||
|
|
@ -762,6 +810,12 @@ mp_obj_t numerical_argsort(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
|
|||
} else {
|
||||
HEAP_ARGSORT(ndarray, mp_float_t, array, shape, strides, ax, increment, ndarray->shape[ax], iarray, istrides, iincrement);
|
||||
}
|
||||
}
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, istrides, ULAB_MAX_DIMS);
|
||||
|
||||
return MP_OBJ_FROM_PTR(indices);
|
||||
}
|
||||
|
||||
|
|
@ -776,12 +830,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
|
|||
|
||||
static mp_obj_t numerical_cross(mp_obj_t _a, mp_obj_t _b) {
|
||||
if (!mp_obj_is_type(_a, &ulab_ndarray_type) || !mp_obj_is_type(_b, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("arguments must be ndarrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("arguments must be ndarrays"));
|
||||
}
|
||||
ndarray_obj_t *a = MP_OBJ_TO_PTR(_a);
|
||||
ndarray_obj_t *b = MP_OBJ_TO_PTR(_b);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(a->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(b->dtype)
|
||||
if((a->ndim != 1) || (b->ndim != 1) || (a->len != b->len) || (a->len != 3)) {
|
||||
mp_raise_ValueError(translate("cross is defined for 1D arrays of length 3"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("cross is defined for 1D arrays of length 3"));
|
||||
}
|
||||
|
||||
mp_float_t *results = m_new(mp_float_t, 3);
|
||||
|
|
@ -855,7 +911,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(numerical_cross_obj, numerical_cross);
|
|||
|
||||
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_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_n, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 1 } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = -1 } },
|
||||
};
|
||||
|
|
@ -864,35 +920,35 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
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"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("diff argument must be an ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
int8_t ax = args[2].u_int;
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("index out of range"));
|
||||
}
|
||||
|
||||
if((args[1].u_int < 0) || (args[1].u_int > 9)) {
|
||||
mp_raise_ValueError(translate("differentiation order out of range"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("differentiation order out of range"));
|
||||
}
|
||||
uint8_t N = (uint8_t)args[1].u_int;
|
||||
uint8_t index = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
if(N > ndarray->shape[index]) {
|
||||
mp_raise_ValueError(translate("differentiation order out of range"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("differentiation order out of range"));
|
||||
}
|
||||
|
||||
int8_t *stencil = m_new(int8_t, N+1);
|
||||
stencil[0] = 1;
|
||||
for(uint8_t i=1; i < N+1; i++) {
|
||||
for(uint8_t i = 1; i < N+1; i++) {
|
||||
stencil[i] = -stencil[i-1]*(N-i+1)/i;
|
||||
}
|
||||
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
for(uint8_t i=0; i < ULAB_MAX_DIMS; i++) {
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) {
|
||||
shape[i] = ndarray->shape[i];
|
||||
if(i == index) {
|
||||
shape[i] -= N;
|
||||
|
|
@ -903,8 +959,7 @@ mp_obj_t numerical_diff(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
uint8_t *rarray = (uint8_t *)results->array;
|
||||
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(int32_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
|
||||
if(ndarray->dtype == NDARRAY_UINT8) {
|
||||
|
|
@ -936,40 +991,37 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
|
|||
|
||||
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_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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("flip argument must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("flip argument must be an ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *results = NULL;
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
if(args[1].u_obj == mp_const_none) { // flip the flattened array
|
||||
results = ndarray_new_linear_array(ndarray->len, ndarray->dtype);
|
||||
ndarray_copy_array(ndarray, results);
|
||||
ndarray_copy_array(ndarray, results, 0);
|
||||
uint8_t *rarray = (uint8_t *)results->array;
|
||||
rarray += (results->len - 1) * results->itemsize;
|
||||
results->array = rarray;
|
||||
results->strides[ULAB_MAX_DIMS - 1] = -results->strides[ULAB_MAX_DIMS - 1];
|
||||
} else if(mp_obj_is_int(args[1].u_obj)){
|
||||
int8_t ax = mp_obj_get_int(args[1].u_obj);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
}
|
||||
int8_t ax = tools_get_axis(args[1].u_obj, ndarray->ndim);
|
||||
|
||||
ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
int32_t offset = (ndarray->shape[ax] - 1) * ndarray->strides[ax];
|
||||
results = ndarray_new_view(ndarray, ndarray->ndim, ndarray->shape, ndarray->strides, offset);
|
||||
results->strides[ax] = -results->strides[ax];
|
||||
} else {
|
||||
mp_raise_TypeError(translate("wrong axis index"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong axis index"));
|
||||
}
|
||||
return results;
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_flip_obj, 1, numerical_flip);
|
||||
|
|
@ -1009,14 +1061,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
|
|||
|
||||
mp_obj_t numerical_median(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_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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("median argument must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("median argument must be an ndarray"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
|
@ -1024,7 +1076,7 @@ mp_obj_t numerical_median(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
|
|||
return mp_obj_new_float(MICROPY_FLOAT_C_FUN(nan)(""));
|
||||
}
|
||||
|
||||
ndarray = numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0);
|
||||
ndarray = MP_OBJ_TO_PTR(numerical_sort_helper(args[0].u_obj, args[1].u_obj, 0));
|
||||
|
||||
if((args[1].u_obj == mp_const_none) || (ndarray->ndim == 1)) {
|
||||
// at this point, the array holding the sorted values should be flat
|
||||
|
|
@ -1039,17 +1091,16 @@ mp_obj_t numerical_median(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_
|
|||
}
|
||||
return mp_obj_new_float(median);
|
||||
} else {
|
||||
int8_t ax = mp_obj_get_int(args[1].u_obj);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
// here we can save the exception, because if the axis is out of range,
|
||||
// then numerical_sort_helper has already taken care of the issue
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(uint32_t)*ULAB_MAX_DIMS);
|
||||
int8_t ax = tools_get_axis(args[1].u_obj, ndarray->ndim);
|
||||
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
|
||||
ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim-1, shape, NDARRAY_FLOAT);
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
|
||||
mp_float_t *rarray = (mp_float_t *)results->array;
|
||||
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
|
|
@ -1124,25 +1175,31 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
|
|||
|
||||
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 } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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("roll argument must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("roll argument must be an ndarray"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
uint8_t *array = ndarray->array;
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndarray->ndim, ndarray->shape, ndarray->dtype);
|
||||
|
||||
int32_t shift = mp_obj_get_int(args[1].u_obj);
|
||||
|
||||
if(shift == 0) {
|
||||
ndarray_copy_array(ndarray, results, 0);
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
int32_t _shift = shift < 0 ? -shift : shift;
|
||||
|
||||
size_t counter;
|
||||
uint8_t *array = ndarray->array;
|
||||
uint8_t *rarray = (uint8_t *)results->array;
|
||||
|
||||
if(args[2].u_obj == mp_const_none) { // roll the flattened array
|
||||
|
|
@ -1195,21 +1252,14 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
} while(i < ndarray->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
} else if(mp_obj_is_int(args[2].u_obj)){
|
||||
int8_t ax = mp_obj_get_int(args[2].u_obj);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
}
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(strides, 0, sizeof(int32_t)*ULAB_MAX_DIMS);
|
||||
int8_t ax = tools_get_axis(args[2].u_obj, ndarray->ndim);
|
||||
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *strides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(ndarray, ax, shape, strides);
|
||||
|
||||
size_t *rshape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(rshape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
int32_t *rstrides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memset(rstrides, 0, sizeof(int32_t)*ULAB_MAX_DIMS);
|
||||
size_t *rshape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
int32_t *rstrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
numerical_reduce_axes(results, ax, rshape, rstrides);
|
||||
|
||||
ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
|
|
@ -1270,10 +1320,17 @@ mp_obj_t numerical_roll(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
i++;
|
||||
} while(i < shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
m_del(size_t, rshape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
|
||||
} else {
|
||||
mp_raise_TypeError(translate("wrong axis index"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong axis index"));
|
||||
}
|
||||
return results;
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
|
||||
|
|
@ -1288,8 +1345,8 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
|
|||
|
||||
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_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -1305,7 +1362,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_obj, 1, numerical_sort);
|
|||
// method of an ndarray
|
||||
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_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_int = -1 } },
|
||||
};
|
||||
|
||||
|
|
@ -1326,9 +1383,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_sort_inplace_obj, 1, numerical_sort_inplace
|
|||
|
||||
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 } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } } ,
|
||||
{ MP_QSTR_axis, MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_ddof, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
|
||||
{ MP_QSTR_keepdims, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_FALSE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -1337,17 +1395,19 @@ mp_obj_t numerical_std(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_arg
|
|||
mp_obj_t oin = args[0].u_obj;
|
||||
mp_obj_t axis = args[1].u_obj;
|
||||
size_t ddof = args[2].u_int;
|
||||
mp_obj_t keepdims = args[3].u_obj;
|
||||
|
||||
if((axis != mp_const_none) && (mp_obj_get_int(axis) != 0) && (mp_obj_get_int(axis) != 1)) {
|
||||
// this seems to pass with False, and True...
|
||||
mp_raise_ValueError(translate("axis must be None, or an integer"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("axis must be None, or an integer"));
|
||||
}
|
||||
if(mp_obj_is_type(oin, &mp_type_tuple) || mp_obj_is_type(oin, &mp_type_list) || mp_obj_is_type(oin, &mp_type_range)) {
|
||||
return numerical_sum_mean_std_iterable(oin, NUMERICAL_STD, ddof);
|
||||
} else if(mp_obj_is_type(oin, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(oin);
|
||||
return numerical_sum_mean_std_ndarray(ndarray, axis, NUMERICAL_STD, ddof);
|
||||
return numerical_sum_mean_std_ndarray(ndarray, axis, keepdims, NUMERICAL_STD, ddof);
|
||||
} else {
|
||||
mp_raise_TypeError(translate("input must be tuple, list, range, or ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be tuple, list, range, or ndarray"));
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -57,35 +57,9 @@
|
|||
(rarray) += (results)->itemsize;\
|
||||
})
|
||||
|
||||
// The mean could be calculated by simply dividing the sum by
|
||||
// the number of elements, but that method is numerically unstable
|
||||
#define RUN_MEAN1(type, array, rarray, ss)\
|
||||
({\
|
||||
mp_float_t M = 0.0;\
|
||||
for(size_t i=0; i < (ss).shape[0]; i++) {\
|
||||
mp_float_t value = (mp_float_t)(*(type *)(array));\
|
||||
M = M + (value - M) / (mp_float_t)(i+1);\
|
||||
(array) += (ss).strides[0];\
|
||||
}\
|
||||
*(rarray)++ = M;\
|
||||
})
|
||||
|
||||
// Instead of the straightforward implementation of the definition,
|
||||
// we take the numerically stable Welford algorithm here
|
||||
// https://www.johndcook.com/blog/2008/09/26/comparing-three-methods-of-computing-standard-deviation/
|
||||
#define RUN_STD1(type, array, rarray, ss, div)\
|
||||
({\
|
||||
mp_float_t M = 0.0, m = 0.0, S = 0.0;\
|
||||
for(size_t i=0; i < (ss).shape[0]; i++) {\
|
||||
mp_float_t value = (mp_float_t)(*(type *)(array));\
|
||||
m = M + (value - M) / (mp_float_t)(i+1);\
|
||||
S = S + (value - M) * (value - m);\
|
||||
M = m;\
|
||||
(array) += (ss).strides[0];\
|
||||
}\
|
||||
*(rarray)++ = MICROPY_FLOAT_C_FUN(sqrt)(S / (div));\
|
||||
})
|
||||
|
||||
#define RUN_MEAN_STD1(type, array, rarray, ss, div, isStd)\
|
||||
({\
|
||||
mp_float_t M = 0.0, m = 0.0, S = 0.0;\
|
||||
|
|
@ -155,6 +129,7 @@
|
|||
type *_array = (type *)array;\
|
||||
type tmp;\
|
||||
uint16_t itmp, c, q = (N), p, r = (N) >> 1;\
|
||||
assert(N);\
|
||||
for (;;) {\
|
||||
if (r > 0) {\
|
||||
r--;\
|
||||
|
|
@ -192,14 +167,6 @@
|
|||
RUN_SUM1(type, (array), (results), (rarray), (ss));\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN(type, array, rarray, ss) do {\
|
||||
RUN_MEAN1(type, (array), (rarray), (ss));\
|
||||
} while(0)
|
||||
|
||||
#define RUN_STD(type, array, rarray, ss, div) do {\
|
||||
RUN_STD1(type, (array), (results), (rarray), (ss), (div));\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\
|
||||
RUN_MEAN_STD1(type, (array), (rarray), (ss), (div), (isStd));\
|
||||
} while(0)
|
||||
|
|
@ -233,26 +200,6 @@
|
|||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN(type, array, rarray, ss) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_MEAN1(type, (array), (rarray), (ss));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_STD(type, array, rarray, ss, div) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_STD1(type, (array), (rarray), (ss), (div));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
|
|
@ -324,38 +271,6 @@
|
|||
} while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN(type, array, rarray, ss) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_MEAN1(type, (array), (rarray), (ss));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_STD(type, array, rarray, ss, div) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_STD1(type, (array), (rarray), (ss), (div));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
|
|
@ -466,50 +381,6 @@
|
|||
} while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN(type, array, rarray, ss) do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_MEAN1(type, (array), (rarray), (ss));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_STD(type, array, rarray, ss, div) do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
RUN_STD1(type, (array), (rarray), (ss), (div));\
|
||||
(array) -= (ss).strides[0] * (ss).shape[0];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (ss).shape[ULAB_MAX_DIMS - 1]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 1] * (ss).shape[ULAB_MAX_DIMS - 1];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (ss).shape[ULAB_MAX_DIMS - 2]);\
|
||||
(array) -= (ss).strides[ULAB_MAX_DIMS - 2] * (ss).shape[ULAB_MAX_DIMS - 2];\
|
||||
(array) += (ss).strides[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (ss).shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
|
||||
#define RUN_MEAN_STD(type, array, rarray, ss, div, isStd) do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
|
||||
* 2020 Scott Shawcroft for Adafruit Industries
|
||||
* 2020-2021 Zoltán Vörös
|
||||
* 2020-2022 Zoltán Vörös
|
||||
* 2020 Taku Fukada
|
||||
*/
|
||||
|
||||
|
|
@ -17,13 +17,17 @@
|
|||
#include "py/runtime.h"
|
||||
|
||||
#include "numpy.h"
|
||||
#include "../ulab_create.h"
|
||||
#include "approx.h"
|
||||
#include "bitwise.h"
|
||||
#include "carray/carray.h"
|
||||
#include "compare.h"
|
||||
#include "create.h"
|
||||
#include "fft/fft.h"
|
||||
#include "filter.h"
|
||||
#include "io/io.h"
|
||||
#include "linalg/linalg.h"
|
||||
#include "numerical.h"
|
||||
#include "random/random.h"
|
||||
#include "stats.h"
|
||||
#include "transform.h"
|
||||
#include "poly.h"
|
||||
|
|
@ -55,68 +59,40 @@
|
|||
|
||||
// math constants
|
||||
#if ULAB_NUMPY_HAS_E
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
#define ulab_const_float_e MP_ROM_PTR((mp_obj_t)(((0x402df854 & ~3) | 2) + 0x80800000))
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
#define ulab_const_float_e {((mp_obj_t)((uint64_t)0x4005bf0a8b145769 + 0x8004000000000000))}
|
||||
#else
|
||||
mp_obj_float_t ulab_const_float_e_obj = {{&mp_type_float}, MP_E};
|
||||
#define ulab_const_float_e MP_ROM_PTR(&ulab_const_float_e_obj)
|
||||
#endif
|
||||
ULAB_DEFINE_FLOAT_CONST(ulab_const_float_e, MP_E, 0x402df854UL, 0x4005bf0a8b145769ULL);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_INF
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
#define numpy_const_float_inf MP_ROM_PTR((mp_obj_t)(0x7f800002 + 0x80800000))
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
#define numpy_const_float_inf {((mp_obj_t)((uint64_t)0x7ff0000000000000 + 0x8004000000000000))}
|
||||
#else
|
||||
mp_obj_float_t numpy_const_float_inf_obj = {{&mp_type_float}, (mp_float_t)INFINITY};
|
||||
#define numpy_const_float_inf MP_ROM_PTR(&numpy_const_float_inf_obj)
|
||||
#endif
|
||||
ULAB_DEFINE_FLOAT_CONST(numpy_const_float_inf, (mp_float_t)INFINITY, 0x7f800000UL, 0x7ff0000000000000ULL);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_NAN
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
#define numpy_const_float_nan MP_ROM_PTR((mp_obj_t)(0x7fc00002 + 0x80800000))
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
#define numpy_const_float_nan {((mp_obj_t)((uint64_t)0x7ff8000000000000 + 0x8004000000000000))}
|
||||
#else
|
||||
mp_obj_float_t numpy_const_float_nan_obj = {{&mp_type_float}, (mp_float_t)NAN};
|
||||
#define numpy_const_float_nan MP_ROM_PTR(&numpy_const_float_nan_obj)
|
||||
#endif
|
||||
ULAB_DEFINE_FLOAT_CONST(numpy_const_float_nan, (mp_float_t)NAN, 0x7fc00000UL, 0x7ff8000000000000ULL);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_PI
|
||||
#if MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_C
|
||||
#define ulab_const_float_pi MP_ROM_PTR((mp_obj_t)(((0x40490fdb & ~3) | 2) + 0x80800000))
|
||||
#elif MICROPY_OBJ_REPR == MICROPY_OBJ_REPR_D
|
||||
#define ulab_const_float_pi {((mp_obj_t)((uint64_t)0x400921fb54442d18 + 0x8004000000000000))}
|
||||
#else
|
||||
mp_obj_float_t ulab_const_float_pi_obj = {{&mp_type_float}, MP_PI};
|
||||
#define ulab_const_float_pi MP_ROM_PTR(&ulab_const_float_pi_obj)
|
||||
#endif
|
||||
ULAB_DEFINE_FLOAT_CONST(ulab_const_float_pi, MP_PI, 0x40490fdbUL, 0x400921fb54442d18ULL);
|
||||
#endif
|
||||
|
||||
static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_numpy) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ndarray), (mp_obj_t)&ulab_ndarray_type },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_array), MP_ROM_PTR(&ndarray_array_constructor_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_numpy) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ndarray), MP_ROM_PTR(&ulab_ndarray_type) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_array), MP_ROM_PTR(&ndarray_array_constructor_obj) },
|
||||
#if ULAB_NUMPY_HAS_FROMBUFFER
|
||||
{ MP_ROM_QSTR(MP_QSTR_frombuffer), MP_ROM_PTR(&create_frombuffer_obj) },
|
||||
#endif
|
||||
// math constants
|
||||
#if ULAB_NUMPY_HAS_E
|
||||
{ MP_ROM_QSTR(MP_QSTR_e), ulab_const_float_e },
|
||||
{ MP_ROM_QSTR(MP_QSTR_e), ULAB_REFERENCE_FLOAT_CONST(ulab_const_float_e) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_INF
|
||||
{ MP_ROM_QSTR(MP_QSTR_inf), numpy_const_float_inf },
|
||||
{ MP_ROM_QSTR(MP_QSTR_inf), ULAB_REFERENCE_FLOAT_CONST(numpy_const_float_inf) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_NAN
|
||||
{ MP_ROM_QSTR(MP_QSTR_nan), numpy_const_float_nan },
|
||||
{ MP_ROM_QSTR(MP_QSTR_nan), ULAB_REFERENCE_FLOAT_CONST(numpy_const_float_nan) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_PI
|
||||
{ MP_ROM_QSTR(MP_QSTR_pi), ulab_const_float_pi },
|
||||
{ MP_ROM_QSTR(MP_QSTR_pi), ULAB_REFERENCE_FLOAT_CONST(ulab_const_float_pi) },
|
||||
#endif
|
||||
// class constants, always included
|
||||
{ MP_ROM_QSTR(MP_QSTR_bool), MP_ROM_INT(NDARRAY_BOOL) },
|
||||
|
|
@ -125,6 +101,9 @@ static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
|
|||
{ MP_ROM_QSTR(MP_QSTR_uint16), MP_ROM_INT(NDARRAY_UINT16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_int16), MP_ROM_INT(NDARRAY_INT16) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_float), MP_ROM_INT(NDARRAY_FLOAT) },
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
{ MP_ROM_QSTR(MP_QSTR_complex), MP_ROM_INT(NDARRAY_COMPLEX) },
|
||||
#endif
|
||||
// modules of numpy
|
||||
#if ULAB_NUMPY_HAS_FFT_MODULE
|
||||
{ MP_ROM_QSTR(MP_QSTR_fft), MP_ROM_PTR(&ulab_fft_module) },
|
||||
|
|
@ -132,230 +111,298 @@ static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
|
|||
#if ULAB_NUMPY_HAS_LINALG_MODULE
|
||||
{ MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_linalg_module) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_RANDOM_MODULE
|
||||
{ MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&ulab_numpy_random_module) },
|
||||
#endif
|
||||
#if ULAB_HAS_PRINTOPTIONS
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_printoptions), (mp_obj_t)&ndarray_set_printoptions_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_printoptions), (mp_obj_t)&ndarray_get_printoptions_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_set_printoptions), MP_ROM_PTR(&ndarray_set_printoptions_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_get_printoptions), MP_ROM_PTR(&ndarray_get_printoptions_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_NDINFO
|
||||
{ MP_ROM_QSTR(MP_QSTR_ndinfo), (mp_obj_t)&ndarray_info_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ndinfo), MP_ROM_PTR(&ndarray_info_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ARANGE
|
||||
{ MP_ROM_QSTR(MP_QSTR_arange), (mp_obj_t)&create_arange_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_arange), MP_ROM_PTR(&create_arange_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_COMPRESS
|
||||
{ MP_ROM_QSTR(MP_QSTR_compress), MP_ROM_PTR(&transform_compress_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_CONCATENATE
|
||||
{ MP_ROM_QSTR(MP_QSTR_concatenate), (mp_obj_t)&create_concatenate_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_concatenate), MP_ROM_PTR(&create_concatenate_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DELETE
|
||||
{ MP_ROM_QSTR(MP_QSTR_delete), MP_ROM_PTR(&transform_delete_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DIAG
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
{ MP_ROM_QSTR(MP_QSTR_diag), (mp_obj_t)&create_diag_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_diag), MP_ROM_PTR(&create_diag_obj) },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_EMPTY
|
||||
{ MP_ROM_QSTR(MP_QSTR_empty), (mp_obj_t)&create_zeros_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_empty), MP_ROM_PTR(&create_zeros_obj) },
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_NUMPY_HAS_EYE
|
||||
{ MP_ROM_QSTR(MP_QSTR_eye), (mp_obj_t)&create_eye_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_eye), MP_ROM_PTR(&create_eye_obj) },
|
||||
#endif
|
||||
#endif /* ULAB_MAX_DIMS */
|
||||
// functions of the approx sub-module
|
||||
#if ULAB_NUMPY_HAS_INTERP
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_interp), (mp_obj_t)&approx_interp_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_interp), MP_ROM_PTR(&approx_interp_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TRAPZ
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_trapz), (mp_obj_t)&approx_trapz_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_trapz), MP_ROM_PTR(&approx_trapz_obj) },
|
||||
#endif
|
||||
// functions of the create sub-module
|
||||
#if ULAB_NUMPY_HAS_FULL
|
||||
{ MP_ROM_QSTR(MP_QSTR_full), (mp_obj_t)&create_full_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_full), MP_ROM_PTR(&create_full_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LINSPACE
|
||||
{ MP_ROM_QSTR(MP_QSTR_linspace), (mp_obj_t)&create_linspace_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_linspace), MP_ROM_PTR(&create_linspace_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOGSPACE
|
||||
{ MP_ROM_QSTR(MP_QSTR_logspace), (mp_obj_t)&create_logspace_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_logspace), MP_ROM_PTR(&create_logspace_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ONES
|
||||
{ MP_ROM_QSTR(MP_QSTR_ones), (mp_obj_t)&create_ones_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ones), MP_ROM_PTR(&create_ones_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ZEROS
|
||||
{ MP_ROM_QSTR(MP_QSTR_zeros), (mp_obj_t)&create_zeros_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_zeros), MP_ROM_PTR(&create_zeros_obj) },
|
||||
#endif
|
||||
// functions of the compare sub-module
|
||||
#if ULAB_NUMPY_HAS_CLIP
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_clip), (mp_obj_t)&compare_clip_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_clip), MP_ROM_PTR(&compare_clip_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_EQUAL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_equal), (mp_obj_t)&compare_equal_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_equal), MP_ROM_PTR(&compare_equal_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_NOTEQUAL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_not_equal), (mp_obj_t)&compare_not_equal_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_not_equal), MP_ROM_PTR(&compare_not_equal_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ISFINITE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isfinite), (mp_obj_t)&compare_isfinite_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isfinite), MP_ROM_PTR(&compare_isfinite_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ISINF
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_isinf), (mp_obj_t)&compare_isinf_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_isinf), MP_ROM_PTR(&compare_isinf_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MAXIMUM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_maximum), (mp_obj_t)&compare_maximum_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_maximum), MP_ROM_PTR(&compare_maximum_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MINIMUM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_minimum), (mp_obj_t)&compare_minimum_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_minimum), MP_ROM_PTR(&compare_minimum_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_NONZERO
|
||||
{ MP_ROM_QSTR(MP_QSTR_nonzero), MP_ROM_PTR(&compare_nonzero_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_WHERE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_where), (mp_obj_t)&compare_where_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_where), MP_ROM_PTR(&compare_where_obj) },
|
||||
#endif
|
||||
// bitwise operators
|
||||
#if ULAB_NUMPY_HAS_BITWISE_AND
|
||||
{ MP_ROM_QSTR(MP_QSTR_bitwise_and), MP_ROM_PTR(&bitwise_bitwise_and_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_BITWISE_OR
|
||||
{ MP_ROM_QSTR(MP_QSTR_bitwise_or), MP_ROM_PTR(&bitwise_bitwise_or_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_BITWISE_XOR
|
||||
{ MP_ROM_QSTR(MP_QSTR_bitwise_xor), MP_ROM_PTR(&bitwise_bitwise_xor_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LEFT_SHIFT
|
||||
{ MP_ROM_QSTR(MP_QSTR_left_shift), MP_ROM_PTR(&left_shift_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_RIGHT_SHIFT
|
||||
{ MP_ROM_QSTR(MP_QSTR_right_shift), MP_ROM_PTR(&right_shift_obj) },
|
||||
#endif
|
||||
// functions of the filter sub-module
|
||||
#if ULAB_NUMPY_HAS_CONVOLVE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_convolve), (mp_obj_t)&filter_convolve_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_convolve), MP_ROM_PTR(&filter_convolve_obj) },
|
||||
#endif
|
||||
// functions of the numerical sub-module
|
||||
#if ULAB_NUMPY_HAS_ALL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_all), (mp_obj_t)&numerical_all_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_all), MP_ROM_PTR(&numerical_all_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ANY
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_any), (mp_obj_t)&numerical_any_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&numerical_any_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ARGMINMAX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmax), (mp_obj_t)&numerical_argmax_obj },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_argmin), (mp_obj_t)&numerical_argmin_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_argmax), MP_ROM_PTR(&numerical_argmax_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_argmin), MP_ROM_PTR(&numerical_argmin_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ARGSORT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_argsort), (mp_obj_t)&numerical_argsort_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_argsort), MP_ROM_PTR(&numerical_argsort_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ASARRAY
|
||||
{ MP_ROM_QSTR(MP_QSTR_asarray), MP_ROM_PTR(&create_asarray_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_CROSS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_cross), (mp_obj_t)&numerical_cross_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cross), MP_ROM_PTR(&numerical_cross_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DIFF
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_diff), (mp_obj_t)&numerical_diff_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_diff), MP_ROM_PTR(&numerical_diff_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DOT
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dot), (mp_obj_t)&transform_dot_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_dot), MP_ROM_PTR(&transform_dot_obj) },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TRACE
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
{ MP_ROM_QSTR(MP_QSTR_trace), (mp_obj_t)&stats_trace_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_trace), MP_ROM_PTR(&stats_trace_obj) },
|
||||
#endif
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_FLIP
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_flip), (mp_obj_t)&numerical_flip_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_flip), MP_ROM_PTR(&numerical_flip_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOAD
|
||||
{ MP_ROM_QSTR(MP_QSTR_load), MP_ROM_PTR(&io_load_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOADTXT
|
||||
{ MP_ROM_QSTR(MP_QSTR_loadtxt), MP_ROM_PTR(&io_loadtxt_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MINMAX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_max), (mp_obj_t)&numerical_max_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_max), MP_ROM_PTR(&numerical_max_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MEAN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_mean), (mp_obj_t)&numerical_mean_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_mean), MP_ROM_PTR(&numerical_mean_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MEDIAN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_median), (mp_obj_t)&numerical_median_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_median), MP_ROM_PTR(&numerical_median_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_MINMAX
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_min), (mp_obj_t)&numerical_min_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_min), MP_ROM_PTR(&numerical_min_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ROLL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_roll), (mp_obj_t)&numerical_roll_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_roll), MP_ROM_PTR(&numerical_roll_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SAVE
|
||||
{ MP_ROM_QSTR(MP_QSTR_save), MP_ROM_PTR(&io_save_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SAVETXT
|
||||
{ MP_ROM_QSTR(MP_QSTR_savetxt), MP_ROM_PTR(&io_savetxt_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SIZE
|
||||
{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&transform_size_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SORT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sort), (mp_obj_t)&numerical_sort_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_STD
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_std), (mp_obj_t)&numerical_std_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_std), MP_ROM_PTR(&numerical_std_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SUM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sum), (mp_obj_t)&numerical_sum_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sum), MP_ROM_PTR(&numerical_sum_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TAKE
|
||||
{ MP_ROM_QSTR(MP_QSTR_take), MP_ROM_PTR(&create_take_obj) },
|
||||
#endif
|
||||
// functions of the poly sub-module
|
||||
#if ULAB_NUMPY_HAS_POLYFIT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyfit), (mp_obj_t)&poly_polyfit_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_polyfit), MP_ROM_PTR(&poly_polyfit_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_POLYVAL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_polyval), (mp_obj_t)&poly_polyval_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_polyval), MP_ROM_PTR(&poly_polyval_obj) },
|
||||
#endif
|
||||
// functions of the vector sub-module
|
||||
#if ULAB_NUMPY_HAS_ACOS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_acos), (mp_obj_t)&vectorise_acos_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_acos), MP_ROM_PTR(&vector_acos_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ACOSH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_acosh), (mp_obj_t)&vectorise_acosh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_acosh), MP_ROM_PTR(&vector_acosh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ARCTAN2
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_arctan2), (mp_obj_t)&vectorise_arctan2_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_arctan2), MP_ROM_PTR(&vector_arctan2_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_AROUND
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_around), (mp_obj_t)&vectorise_around_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_around), MP_ROM_PTR(&vector_around_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ASIN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_asin), (mp_obj_t)&vectorise_asin_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_asin), MP_ROM_PTR(&vector_asin_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ASINH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_asinh), (mp_obj_t)&vectorise_asinh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_asinh), MP_ROM_PTR(&vector_asinh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ATAN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_atan), (mp_obj_t)&vectorise_atan_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_atan), MP_ROM_PTR(&vector_atan_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_ATANH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_atanh), (mp_obj_t)&vectorise_atanh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_atanh), MP_ROM_PTR(&vector_atanh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_CEIL
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_ceil), (mp_obj_t)&vectorise_ceil_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_ceil), MP_ROM_PTR(&vector_ceil_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_COS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_cos), (mp_obj_t)&vectorise_cos_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cos), MP_ROM_PTR(&vector_cos_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_COSH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_cosh), (mp_obj_t)&vectorise_cosh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cosh), MP_ROM_PTR(&vector_cosh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_DEGREES
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_degrees), (mp_obj_t)&vectorise_degrees_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_degrees), MP_ROM_PTR(&vector_degrees_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_EXP
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_exp), (mp_obj_t)&vectorise_exp_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_exp), MP_ROM_PTR(&vector_exp_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_EXPM1
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_expm1), (mp_obj_t)&vectorise_expm1_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_expm1), MP_ROM_PTR(&vector_expm1_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_FLOOR
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_floor), (mp_obj_t)&vectorise_floor_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_floor), MP_ROM_PTR(&vector_floor_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOG
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_log), (mp_obj_t)&vectorise_log_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_log), MP_ROM_PTR(&vector_log_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOG10
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_log10), (mp_obj_t)&vectorise_log10_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_log10), MP_ROM_PTR(&vector_log10_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_LOG2
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_log2), (mp_obj_t)&vectorise_log2_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_log2), MP_ROM_PTR(&vector_log2_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_RADIANS
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_radians), (mp_obj_t)&vectorise_radians_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_radians), MP_ROM_PTR(&vector_radians_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SIN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sin), (mp_obj_t)&vectorise_sin_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sin), MP_ROM_PTR(&vector_sin_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SINC
|
||||
{ MP_ROM_QSTR(MP_QSTR_sinc), MP_ROM_PTR(&vector_sinc_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SINH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sinh), (mp_obj_t)&vectorise_sinh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sinh), MP_ROM_PTR(&vector_sinh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SQRT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sqrt), (mp_obj_t)&vectorise_sqrt_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_sqrt), MP_ROM_PTR(&vector_sqrt_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TAN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_tan), (mp_obj_t)&vectorise_tan_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_tan), MP_ROM_PTR(&vector_tan_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_TANH
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_tanh), (mp_obj_t)&vectorise_tanh_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_tanh), MP_ROM_PTR(&vector_tanh_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_VECTORIZE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_vectorize), (mp_obj_t)&vectorise_vectorize_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_vectorize), MP_ROM_PTR(&vector_vectorize_obj) },
|
||||
#endif
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#if ULAB_NUMPY_HAS_REAL
|
||||
{ MP_ROM_QSTR(MP_QSTR_real), MP_ROM_PTR(&carray_real_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_IMAG
|
||||
{ MP_ROM_QSTR(MP_QSTR_imag), MP_ROM_PTR(&carray_imag_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_CONJUGATE
|
||||
{ MP_ROM_QSTR(MP_QSTR_conjugate), MP_ROM_PTR(&carray_conjugate_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_HAS_SORT_COMPLEX
|
||||
{ MP_ROM_QSTR(MP_QSTR_sort_complex), MP_ROM_PTR(&carray_sort_complex_obj) },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_numpy_globals, ulab_numpy_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_numpy_module = {
|
||||
const mp_obj_module_t ulab_numpy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_numpy_globals,
|
||||
};
|
||||
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_numpy, ulab_numpy_module);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_numpy_module;
|
||||
extern const mp_obj_module_t ulab_numpy_module;
|
||||
|
||||
#endif /* _NUMPY_ */
|
||||
|
|
|
|||
|
|
@ -19,14 +19,21 @@
|
|||
#include "../ulab.h"
|
||||
#include "linalg/linalg_tools.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "poly.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_POLYFIT
|
||||
|
||||
mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
||||
if(!ndarray_object_is_array_like(args[0])) {
|
||||
mp_raise_ValueError(translate("input data must be an iterable"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input data must be an iterable"));
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(mp_obj_is_type(args[0], &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0]);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
}
|
||||
#endif
|
||||
size_t lenx = 0, leny = 0;
|
||||
uint8_t deg = 0;
|
||||
mp_float_t *x, *XT, *y, *prod;
|
||||
|
|
@ -37,7 +44,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
leny = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
|
||||
deg = (uint8_t)mp_obj_get_int(args[1]);
|
||||
if(leny < deg) {
|
||||
mp_raise_ValueError(translate("more degrees of freedom than data points"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("more degrees of freedom than data points"));
|
||||
}
|
||||
lenx = leny;
|
||||
x = m_new(mp_float_t, lenx); // assume uniformly spaced data points
|
||||
|
|
@ -48,16 +55,16 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
fill_array_iterable(y, args[0]);
|
||||
} else /* n_args == 3 */ {
|
||||
if(!ndarray_object_is_array_like(args[1])) {
|
||||
mp_raise_ValueError(translate("input data must be an iterable"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input data must be an iterable"));
|
||||
}
|
||||
lenx = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[0]));
|
||||
leny = (size_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"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input vectors must be of equal length"));
|
||||
}
|
||||
deg = (uint8_t)mp_obj_get_int(args[2]);
|
||||
if(leny < deg) {
|
||||
mp_raise_ValueError(translate("more degrees of freedom than data points"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("more degrees of freedom than data points"));
|
||||
}
|
||||
x = m_new(mp_float_t, lenx);
|
||||
fill_array_iterable(x, args[0]);
|
||||
|
|
@ -97,7 +104,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
m_del(mp_float_t, x, lenx);
|
||||
m_del(mp_float_t, y, lenx);
|
||||
m_del(mp_float_t, prod, (deg+1)*(deg+1));
|
||||
mp_raise_ValueError(translate("could not invert Vandermonde matrix"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("could not invert Vandermonde matrix"));
|
||||
}
|
||||
// at this point, we have the inverse of X^T * X
|
||||
// y is a column vector; x is free now, we can use it for storing intermediate values
|
||||
|
|
@ -114,7 +121,7 @@ mp_obj_t poly_polyfit(size_t n_args, const mp_obj_t *args) {
|
|||
ndarray_obj_t *beta = ndarray_new_linear_array(deg+1, NDARRAY_FLOAT);
|
||||
mp_float_t *betav = (mp_float_t *)beta->array;
|
||||
// x[0..(deg+1)] contains now the product X^T * y; we can get rid of y
|
||||
m_del(float, y, leny);
|
||||
m_del(mp_float_t, y, leny);
|
||||
|
||||
// now, we calculate beta, i.e., we apply prod = (X^T * X)^(-1) on x = X^T * y; x is a column vector now
|
||||
for(uint8_t i=0; i < deg+1; i++) {
|
||||
|
|
@ -138,12 +145,32 @@ MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(poly_polyfit_obj, 2, 3, poly_polyfit);
|
|||
|
||||
#if ULAB_NUMPY_HAS_POLYVAL
|
||||
|
||||
mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
||||
if(!ndarray_object_is_array_like(o_p) || !ndarray_object_is_array_like(o_x)) {
|
||||
mp_raise_TypeError(translate("inputs are not iterable"));
|
||||
static mp_float_t poly_eval(mp_float_t x, mp_float_t *p, uint8_t plen) {
|
||||
mp_float_t y = p[0];
|
||||
for(uint8_t j=0; j < plen-1; j++) {
|
||||
y *= x;
|
||||
y += p[j+1];
|
||||
}
|
||||
return y;
|
||||
}
|
||||
|
||||
mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
||||
if(!ndarray_object_is_array_like(o_p)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input is not iterable"));
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
ndarray_obj_t *input;
|
||||
if(mp_obj_is_type(o_p, &ulab_ndarray_type)) {
|
||||
input = MP_OBJ_TO_PTR(o_p);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(input->dtype)
|
||||
}
|
||||
if(mp_obj_is_type(o_x, &ulab_ndarray_type)) {
|
||||
input = MP_OBJ_TO_PTR(o_x);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(input->dtype)
|
||||
}
|
||||
#endif
|
||||
// p had better be a one-dimensional standard iterable
|
||||
uint8_t plen = mp_obj_get_int(mp_obj_len_maybe(o_p));
|
||||
size_t plen = (size_t)mp_obj_get_int(mp_obj_len_maybe(o_p));
|
||||
mp_float_t *p = m_new(mp_float_t, plen);
|
||||
mp_obj_iter_buf_t p_buf;
|
||||
mp_obj_t p_item, p_iterable = mp_getiter(o_p, &p_buf);
|
||||
|
|
@ -153,6 +180,10 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
|||
i++;
|
||||
}
|
||||
|
||||
if(!ndarray_object_is_array_like(o_x)) {
|
||||
return mp_obj_new_float(poly_eval(mp_obj_get_float(o_x), p, plen));
|
||||
}
|
||||
|
||||
// polynomials are going to be of type float, except, when both
|
||||
// the coefficients and the independent variable are integers
|
||||
ndarray_obj_t *ndarray;
|
||||
|
|
@ -166,48 +197,9 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
|||
|
||||
// TODO: these loops are really nothing, but the re-impplementation of
|
||||
// ITERATE_VECTOR from vectorise.c. We could pass a function pointer here
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
mp_float_t y = p[0];
|
||||
mp_float_t _x = func(sarray);
|
||||
for(uint8_t m=0; m < plen-1; m++) {
|
||||
y *= _x;
|
||||
y += p[m+1];
|
||||
}
|
||||
*array++ = y;
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < source->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < source->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < source->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < source->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
ITERATOR_HEAD();
|
||||
*array++ = poly_eval(func(sarray), p, plen);
|
||||
ITERATOR_TAIL(source, sarray);
|
||||
} else {
|
||||
// o_x had better be a one-dimensional standard iterable
|
||||
ndarray = ndarray_new_linear_array(mp_obj_get_int(mp_obj_len_maybe(o_x)), NDARRAY_FLOAT);
|
||||
|
|
@ -215,13 +207,7 @@ mp_obj_t poly_polyval(mp_obj_t o_p, mp_obj_t o_x) {
|
|||
mp_obj_iter_buf_t x_buf;
|
||||
mp_obj_t x_item, x_iterable = mp_getiter(o_x, &x_buf);
|
||||
while ((x_item = mp_iternext(x_iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
mp_float_t _x = mp_obj_get_float(x_item);
|
||||
mp_float_t y = p[0];
|
||||
for(uint8_t j=0; j < plen-1; j++) {
|
||||
y *= _x;
|
||||
y += p[j+1];
|
||||
}
|
||||
*array++ = y;
|
||||
*array++ = poly_eval(mp_obj_get_float(x_item), p, plen);
|
||||
}
|
||||
}
|
||||
m_del(mp_float_t, p, plen);
|
||||
|
|
|
|||
361
code/numpy/random/random.c
Normal file
361
code/numpy/random/random.c
Normal file
|
|
@ -0,0 +1,361 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "py/builtin.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "random.h"
|
||||
|
||||
ULAB_DEFINE_FLOAT_CONST(random_zero, MICROPY_FLOAT_CONST(0.0), 0UL, 0ULL);
|
||||
ULAB_DEFINE_FLOAT_CONST(random_one, MICROPY_FLOAT_CONST(1.0), 0x3f800000UL, 0x3ff0000000000000ULL);
|
||||
|
||||
// methods of the Generator object
|
||||
static const mp_rom_map_elem_t random_generator_locals_dict_table[] = {
|
||||
#if ULAB_NUMPY_RANDOM_HAS_NORMAL
|
||||
{ MP_ROM_QSTR(MP_QSTR_normal), MP_ROM_PTR(&random_normal_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_RANDOM_HAS_RANDOM
|
||||
{ MP_ROM_QSTR(MP_QSTR_random), MP_ROM_PTR(&random_random_obj) },
|
||||
#endif
|
||||
#if ULAB_NUMPY_RANDOM_HAS_UNIFORM
|
||||
{ MP_ROM_QSTR(MP_QSTR_uniform), MP_ROM_PTR(&random_uniform_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(random_generator_locals_dict, random_generator_locals_dict_table);
|
||||
|
||||
// random's Generator object is defined here
|
||||
#if defined(MP_DEFINE_CONST_OBJ_TYPE)
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
random_generator_type,
|
||||
MP_QSTR_generator,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
print, random_generator_print,
|
||||
make_new, random_generator_make_new,
|
||||
locals_dict, &random_generator_locals_dict
|
||||
);
|
||||
#else
|
||||
const mp_obj_type_t random_generator_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_generator,
|
||||
.print = random_generator_print,
|
||||
.make_new = random_generator_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&random_generator_locals_dict
|
||||
};
|
||||
#endif
|
||||
|
||||
void random_generator_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
random_generator_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
mp_printf(MP_PYTHON_PRINTER, "Generator() at 0x%p", self);
|
||||
}
|
||||
|
||||
mp_obj_t random_generator_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, 0, 1, true);
|
||||
mp_map_t kw_args;
|
||||
mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
|
||||
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
mp_arg_val_t _args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, args, &kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, _args);
|
||||
|
||||
|
||||
if(args[0] == mp_const_none) {
|
||||
#ifndef MICROPY_PY_RANDOM_SEED_INIT_FUNC
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("no default seed"));
|
||||
#else
|
||||
random_generator_obj_t *generator = m_new_obj(random_generator_obj_t);
|
||||
generator->base.type = &random_generator_type;
|
||||
generator->state = MICROPY_PY_RANDOM_SEED_INIT_FUNC;
|
||||
return MP_OBJ_FROM_PTR(generator);
|
||||
#endif
|
||||
} else if(mp_obj_is_int(args[0])) {
|
||||
random_generator_obj_t *generator = m_new_obj(random_generator_obj_t);
|
||||
generator->base.type = &random_generator_type;
|
||||
generator->state = (size_t)mp_obj_get_int(args[0]);
|
||||
return MP_OBJ_FROM_PTR(generator);
|
||||
} else if(mp_obj_is_type(args[0], &mp_type_tuple)){
|
||||
mp_obj_tuple_t *seeds = MP_OBJ_TO_PTR(args[0]);
|
||||
mp_obj_t *items = m_new(mp_obj_t, seeds->len);
|
||||
|
||||
for(uint8_t i = 0; i < seeds->len; i++) {
|
||||
random_generator_obj_t *generator = m_new_obj(random_generator_obj_t);
|
||||
generator->base.type = &random_generator_type;
|
||||
generator->state = (size_t)mp_obj_get_int(seeds->items[i]);
|
||||
items[i] = generator;
|
||||
}
|
||||
return mp_obj_new_tuple(seeds->len, items);
|
||||
} else {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("argument must be None, an integer or a tuple of integers"));
|
||||
}
|
||||
// we should never end up here
|
||||
return mp_const_none;
|
||||
}
|
||||
// END OF GENERATOR COMPONENTS
|
||||
|
||||
|
||||
static inline uint32_t pcg32_next(uint64_t *state) {
|
||||
uint64_t old_state = *state;
|
||||
*state = old_state * PCG_MULTIPLIER_64 + PCG_INCREMENT_64;
|
||||
uint32_t value = (uint32_t)((old_state ^ (old_state >> 18)) >> 27);
|
||||
int rot = old_state >> 59;
|
||||
return rot ? (value >> rot) | (value << (32 - rot)) : value;
|
||||
}
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
static inline uint64_t pcg32_next64(uint64_t *state) {
|
||||
uint64_t value = pcg32_next(state);
|
||||
value <<= 32;
|
||||
value |= pcg32_next(state);
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_RANDOM_HAS_NORMAL
|
||||
static mp_obj_t random_normal(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_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_loc, MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(random_zero) } },
|
||||
{ MP_QSTR_scale, MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(random_one) } },
|
||||
{ MP_QSTR_size, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
random_generator_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
mp_float_t loc = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t scale = mp_obj_get_float(args[2].u_obj);
|
||||
mp_obj_t size = args[3].u_obj;
|
||||
|
||||
ndarray_obj_t *ndarray = NULL;
|
||||
mp_float_t u, v, value;
|
||||
|
||||
if(size != mp_const_none) {
|
||||
if(mp_obj_is_int(size)) {
|
||||
ndarray = ndarray_new_linear_array((size_t)mp_obj_get_int(size), NDARRAY_FLOAT);
|
||||
} else if(mp_obj_is_type(size, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *_shape = MP_OBJ_TO_PTR(size);
|
||||
ndarray = ndarray_new_ndarray_from_tuple(_shape, NDARRAY_FLOAT);
|
||||
} else { // input type not supported
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("shape must be None, an integer or a tuple of integers"));
|
||||
}
|
||||
} else {
|
||||
// return single value
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
u = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
x = pcg32_next(&self->state);
|
||||
v = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
u = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
x = pcg32_next64(&self->state);
|
||||
v = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
mp_float_t sqrt_log = MICROPY_FLOAT_C_FUN(sqrt)(-MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_C_FUN(log)(u));
|
||||
value = sqrt_log * MICROPY_FLOAT_C_FUN(cos)(MICROPY_FLOAT_CONST(2.0) * MP_PI * v);
|
||||
return mp_obj_new_float(loc + scale * value);
|
||||
}
|
||||
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
|
||||
// numpy's random supports only dense output arrays, so we can simply
|
||||
// loop through the elements in a linear fashion
|
||||
for(size_t i = 0; i < ndarray->len; i = i + 2) {
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
u = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
x = pcg32_next(&self->state);
|
||||
v = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
u = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
x = pcg32_next64(&self->state);
|
||||
v = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
mp_float_t sqrt_log = MICROPY_FLOAT_C_FUN(sqrt)(-MICROPY_FLOAT_CONST(2.0) * MICROPY_FLOAT_C_FUN(log)(u));
|
||||
value = sqrt_log * MICROPY_FLOAT_C_FUN(cos)(MICROPY_FLOAT_CONST(2.0) * MP_PI * v);
|
||||
*array++ = loc + scale * value;
|
||||
if((i & 1) == 0) {
|
||||
value = sqrt_log * MICROPY_FLOAT_C_FUN(sin)(MICROPY_FLOAT_CONST(2.0) * MP_PI * v);
|
||||
*array++ = loc + scale * value;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(random_normal_obj, 1, random_normal);
|
||||
#endif /* ULAB_NUMPY_RANDOM_HAS_NORMAL */
|
||||
|
||||
#if ULAB_NUMPY_RANDOM_HAS_RANDOM
|
||||
static mp_obj_t random_random(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_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_size, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_out, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
random_generator_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
||||
mp_obj_t size = args[1].u_obj;
|
||||
mp_obj_t out = args[2].u_obj;
|
||||
|
||||
ndarray_obj_t *ndarray = NULL;
|
||||
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
|
||||
|
||||
if(size != mp_const_none) {
|
||||
if(mp_obj_is_int(size)) {
|
||||
shape[ULAB_MAX_DIMS - 1] = (size_t)mp_obj_get_int(size);
|
||||
} else if(mp_obj_is_type(size, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *_shape = MP_OBJ_TO_PTR(size);
|
||||
ndarray = ndarray_new_ndarray_from_tuple(_shape, NDARRAY_FLOAT);
|
||||
} else { // input type not supported
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("shape must be None, an integer or a tuple of integers"));
|
||||
}
|
||||
}
|
||||
|
||||
if(out != mp_const_none) {
|
||||
if(!mp_obj_is_type(out, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("out has wrong type"));
|
||||
}
|
||||
|
||||
ndarray = MP_OBJ_TO_PTR(out);
|
||||
|
||||
if(ndarray->dtype != NDARRAY_FLOAT) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("output array has wrong type"));
|
||||
}
|
||||
if(size != mp_const_none) {
|
||||
for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) {
|
||||
if(ndarray->shape[i] != shape[i]) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("size must match out.shape when used together"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!ndarray_is_dense(ndarray)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("output array must be contiguous"));
|
||||
}
|
||||
} else { // out == None
|
||||
if(size != mp_const_none) {
|
||||
mp_obj_tuple_t *_shape = MP_OBJ_TO_PTR(size);
|
||||
ndarray = ndarray_new_ndarray_from_tuple(_shape, NDARRAY_FLOAT);
|
||||
} else {
|
||||
// return single value
|
||||
mp_float_t value;
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
value = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
value = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
return mp_obj_new_float(value);
|
||||
}
|
||||
}
|
||||
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
|
||||
// numpy's random supports only dense output arrays, so we can simply
|
||||
// loop through the elements in a linear fashion
|
||||
for(size_t i = 0; i < ndarray->len; i++) {
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
*array = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
*array = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
|
||||
array++;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(random_random_obj, 1, random_random);
|
||||
#endif /* ULAB_NUMPY_RANDOM_HAS_RANDOM */
|
||||
|
||||
#if ULAB_NUMPY_RANDOM_HAS_UNIFORM
|
||||
static mp_obj_t random_uniform(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_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_low, MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(random_zero) } },
|
||||
{ MP_QSTR_high, MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(random_one) } },
|
||||
{ MP_QSTR_size, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
random_generator_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
mp_float_t low = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t high = mp_obj_get_float(args[2].u_obj);
|
||||
mp_obj_t size = args[3].u_obj;
|
||||
|
||||
ndarray_obj_t *ndarray = NULL;
|
||||
|
||||
if(size == mp_const_none) {
|
||||
// return single value
|
||||
mp_float_t value;
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
value = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
value = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
return mp_obj_new_float(value);
|
||||
} else if(mp_obj_is_type(size, &mp_type_tuple)) {
|
||||
mp_obj_tuple_t *_shape = MP_OBJ_TO_PTR(size);
|
||||
ndarray = ndarray_new_ndarray_from_tuple(_shape, NDARRAY_FLOAT);
|
||||
} else { // input type not supported
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("shape must be None, an integer or a tuple of integers"));
|
||||
}
|
||||
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
mp_float_t diff = high - low;
|
||||
for(size_t i = 0; i < ndarray->len; i++) {
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
|
||||
uint32_t x = pcg32_next(&self->state);
|
||||
*array = (float)(int32_t)(x >> 8) * 0x1.0p-24f;
|
||||
#else
|
||||
uint64_t x = pcg32_next64(&self->state);
|
||||
*array = (double)(int64_t)(x >> 11) * 0x1.0p-53;
|
||||
#endif
|
||||
*array = low + diff * *array;
|
||||
array++;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(random_uniform_obj, 1, random_uniform);
|
||||
#endif /* ULAB_NUMPY_RANDOM_HAS_UNIFORM */
|
||||
|
||||
|
||||
static const mp_rom_map_elem_t ulab_numpy_random_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_random) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_Generator), MP_ROM_PTR(&random_generator_type) },
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_numpy_random_globals, ulab_numpy_random_globals_table);
|
||||
|
||||
const mp_obj_module_t ulab_numpy_random_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_numpy_random_globals,
|
||||
};
|
||||
37
code/numpy/random/random.h
Normal file
37
code/numpy/random/random.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include "../../ndarray.h"
|
||||
|
||||
#ifndef _NUMPY_RANDOM_
|
||||
#define _NUMPY_RANDOM_
|
||||
|
||||
|
||||
#define PCG_MULTIPLIER_64 6364136223846793005ULL
|
||||
#define PCG_INCREMENT_64 1442695040888963407ULL
|
||||
|
||||
extern const mp_obj_module_t ulab_numpy_random_module;
|
||||
|
||||
extern const mp_obj_type_t random_generator_type;
|
||||
|
||||
typedef struct _random_generator_obj_t {
|
||||
mp_obj_base_t base;
|
||||
uint64_t state;
|
||||
} random_generator_obj_t;
|
||||
|
||||
mp_obj_t random_generator_make_new(const mp_obj_type_t *, size_t , size_t , const mp_obj_t *);
|
||||
void random_generator_print(const mp_print_t *, mp_obj_t , mp_print_kind_t );
|
||||
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(random_normal_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(random_random_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(random_uniform_obj);
|
||||
|
||||
#endif
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include "../ulab.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "stats.h"
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
|
|
@ -36,6 +37,7 @@
|
|||
|
||||
static mp_obj_t stats_trace(mp_obj_t oin) {
|
||||
ndarray_obj_t *ndarray = tools_object_is_square(oin);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
mp_float_t trace = 0.0;
|
||||
for(size_t i=0; i < ndarray->shape[ULAB_MAX_DIMS - 1]; i++) {
|
||||
int32_t pos = i * (ndarray->strides[ULAB_MAX_DIMS - 1] + ndarray->strides[ULAB_MAX_DIMS - 2]);
|
||||
|
|
|
|||
|
|
@ -9,17 +9,343 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/misc.h"
|
||||
|
||||
#include "../ulab.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "carray/carray_tools.h"
|
||||
#include "numerical.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_COMPRESS
|
||||
static mp_obj_t transform_compress(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t condition = args[0].u_obj;
|
||||
|
||||
if(!mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong input type"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
|
||||
mp_obj_t axis = args[2].u_obj;
|
||||
|
||||
size_t len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(condition));
|
||||
int8_t ax, shift_ax = 0;
|
||||
|
||||
if(axis != mp_const_none) {
|
||||
ax = tools_get_axis(axis, ndarray->ndim);
|
||||
shift_ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
}
|
||||
|
||||
if(((axis == mp_const_none) && (len != ndarray->len)) ||
|
||||
((axis != mp_const_none) && (len != ndarray->shape[shift_ax]))) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wrong length of condition array"));
|
||||
}
|
||||
|
||||
size_t true_count = 0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t item, iterable = mp_getiter(condition, &iter_buf);
|
||||
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if(mp_obj_is_true(item)) {
|
||||
true_count++;
|
||||
}
|
||||
}
|
||||
|
||||
iterable = mp_getiter(condition, &iter_buf);
|
||||
|
||||
ndarray_obj_t *result = NULL;
|
||||
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memcpy(shape, ndarray->shape, ULAB_MAX_DIMS * sizeof(size_t));
|
||||
|
||||
size_t *rshape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memcpy(rshape, ndarray->shape, ULAB_MAX_DIMS * sizeof(size_t));
|
||||
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memcpy(strides, ndarray->strides, ULAB_MAX_DIMS * sizeof(int32_t));
|
||||
|
||||
int32_t *rstrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
|
||||
if(axis == mp_const_none) {
|
||||
result = ndarray_new_linear_array(true_count, ndarray->dtype);
|
||||
|
||||
rstrides[ULAB_MAX_DIMS - 1] = ndarray->itemsize;
|
||||
rshape[ULAB_MAX_DIMS - 1] = 0;
|
||||
} else {
|
||||
rshape[shift_ax] = true_count;
|
||||
|
||||
result = ndarray_new_dense_ndarray(ndarray->ndim, rshape, ndarray->dtype);
|
||||
|
||||
SWAP(size_t, shape[shift_ax], shape[ULAB_MAX_DIMS - 1]);
|
||||
SWAP(size_t, rshape[shift_ax], rshape[ULAB_MAX_DIMS - 1]);
|
||||
SWAP(int32_t, strides[shift_ax], strides[ULAB_MAX_DIMS - 1]);
|
||||
|
||||
memcpy(rstrides, result->strides, ULAB_MAX_DIMS * sizeof(int32_t));
|
||||
SWAP(int32_t, rstrides[shift_ax], rstrides[ULAB_MAX_DIMS - 1]);
|
||||
}
|
||||
|
||||
uint8_t *rarray = (uint8_t *)result->array;
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
if(axis != mp_const_none) {
|
||||
iterable = mp_getiter(condition, &iter_buf);
|
||||
}
|
||||
do {
|
||||
item = mp_iternext(iterable);
|
||||
if(mp_obj_is_true(item)) {
|
||||
memcpy(rarray, array, ndarray->itemsize);
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
array += strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
array -= strides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS - 1];
|
||||
array += strides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * rshape[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
array -= strides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS - 2];
|
||||
array += strides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * rshape[ULAB_MAX_DIMS - 2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
array -= strides[ULAB_MAX_DIMS - 3] * shape[ULAB_MAX_DIMS - 3];
|
||||
array += strides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * rshape[ULAB_MAX_DIMS - 2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
i++;
|
||||
} while(i < shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
|
||||
m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(size_t, rshape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
|
||||
return MP_OBJ_FROM_PTR(result);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(transform_compress_obj, 2, transform_compress);
|
||||
#endif /* ULAB_NUMPY_HAS_COMPRESS */
|
||||
|
||||
#if ULAB_NUMPY_HAS_DELETE
|
||||
static mp_obj_t transform_delete(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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(MP_ERROR_TEXT("first argument must be an ndarray"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
|
||||
mp_obj_t indices = args[1].u_obj;
|
||||
|
||||
mp_obj_t axis = args[2].u_obj;
|
||||
|
||||
int8_t shift_ax;
|
||||
|
||||
size_t axis_len;
|
||||
|
||||
if(axis != mp_const_none) {
|
||||
int8_t ax = tools_get_axis(axis, ndarray->ndim);
|
||||
shift_ax = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
axis_len = ndarray->shape[shift_ax];
|
||||
} else {
|
||||
axis_len = ndarray->len;
|
||||
}
|
||||
|
||||
size_t index_len;
|
||||
if(mp_obj_is_int(indices)) {
|
||||
index_len = 1;
|
||||
} else {
|
||||
if(mp_obj_len_maybe(indices) == MP_OBJ_NULL) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("wrong index type"));
|
||||
}
|
||||
index_len = MP_OBJ_SMALL_INT_VALUE(mp_obj_len_maybe(indices));
|
||||
if (index_len == 0){
|
||||
// if the second positional argument is empty
|
||||
// return the original array
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
}
|
||||
|
||||
if(index_len > axis_len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("wrong length of index array"));
|
||||
}
|
||||
|
||||
size_t *index_array = m_new(size_t, index_len);
|
||||
|
||||
if(mp_obj_is_int(indices)) {
|
||||
ssize_t value = (ssize_t)mp_obj_get_int(indices);
|
||||
if(value < 0) {
|
||||
value += axis_len;
|
||||
}
|
||||
if((value < 0) || (value > (ssize_t)axis_len)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("index is out of bounds"));
|
||||
} else {
|
||||
*index_array++ = (size_t)value;
|
||||
}
|
||||
} else {
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t item, iterable = mp_getiter(indices, &iter_buf);
|
||||
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
ssize_t value = (ssize_t)mp_obj_get_int(item);
|
||||
if(value < 0) {
|
||||
value += axis_len;
|
||||
}
|
||||
if((value < 0) || (value > (ssize_t)axis_len)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("index is out of bounds"));
|
||||
} else {
|
||||
*index_array++ = (size_t)value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort the array, since it is not guaranteed that the input is sorted
|
||||
HEAPSORT1(size_t, index_array, 1, index_len);
|
||||
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memcpy(shape, ndarray->shape, ULAB_MAX_DIMS * sizeof(size_t));
|
||||
|
||||
size_t *rshape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memcpy(rshape, ndarray->shape, ULAB_MAX_DIMS * sizeof(size_t));
|
||||
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
|
||||
memcpy(strides, ndarray->strides, ULAB_MAX_DIMS * sizeof(int32_t));
|
||||
|
||||
int32_t *rstrides = m_new0(int32_t, ULAB_MAX_DIMS);
|
||||
|
||||
ndarray_obj_t *result = NULL;
|
||||
|
||||
if(axis == mp_const_none) {
|
||||
result = ndarray_new_linear_array(ndarray->len - index_len, ndarray->dtype);
|
||||
rstrides[ULAB_MAX_DIMS - 1] = ndarray->itemsize;
|
||||
memset(rshape, 0, sizeof(size_t) * ULAB_MAX_DIMS);
|
||||
} else {
|
||||
rshape[shift_ax] = shape[shift_ax] - index_len;
|
||||
|
||||
result = ndarray_new_dense_ndarray(ndarray->ndim, rshape, ndarray->dtype);
|
||||
|
||||
SWAP(size_t, shape[shift_ax], shape[ULAB_MAX_DIMS - 1]);
|
||||
SWAP(size_t, rshape[shift_ax], rshape[ULAB_MAX_DIMS - 1]);
|
||||
SWAP(int32_t, strides[shift_ax], strides[ULAB_MAX_DIMS - 1]);
|
||||
|
||||
memcpy(rstrides, result->strides, ULAB_MAX_DIMS * sizeof(int32_t));
|
||||
SWAP(int32_t, rstrides[shift_ax], rstrides[ULAB_MAX_DIMS - 1]);
|
||||
}
|
||||
|
||||
uint8_t *rarray = (uint8_t *)result->array;
|
||||
index_array -= index_len;
|
||||
size_t count = 0;
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
if(count == *index_array) {
|
||||
index_array++;
|
||||
} else {
|
||||
memcpy(rarray, array, ndarray->itemsize);
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
array += strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
count++;
|
||||
} while(l < shape[ULAB_MAX_DIMS - 1]);
|
||||
if(axis != mp_const_none) {
|
||||
index_array -= index_len;
|
||||
count = 0;
|
||||
}
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
array -= strides[ULAB_MAX_DIMS - 1] * shape[ULAB_MAX_DIMS - 1];
|
||||
array += strides[ULAB_MAX_DIMS - 2];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 1] * rshape[ULAB_MAX_DIMS - 1];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
array -= strides[ULAB_MAX_DIMS - 2] * shape[ULAB_MAX_DIMS - 2];
|
||||
array += strides[ULAB_MAX_DIMS - 3];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 2] * rshape[ULAB_MAX_DIMS - 2];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
array -= strides[ULAB_MAX_DIMS - 3] * shape[ULAB_MAX_DIMS - 3];
|
||||
array += strides[ULAB_MAX_DIMS - 4];
|
||||
rarray -= rstrides[ULAB_MAX_DIMS - 3] * rshape[ULAB_MAX_DIMS - 3];
|
||||
rarray += rstrides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
|
||||
// TODO: deleting shape generates a seg fault
|
||||
// m_del(size_t, shape, ULAB_MAX_DIMS);
|
||||
m_del(size_t, rshape, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, strides, ULAB_MAX_DIMS);
|
||||
m_del(int32_t, rstrides, ULAB_MAX_DIMS);
|
||||
|
||||
return MP_OBJ_FROM_PTR(result);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(transform_delete_obj, 2, transform_delete);
|
||||
#endif /* ULAB_NUMPY_HAS_DELETE */
|
||||
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_NUMPY_HAS_DOT
|
||||
//| def dot(m1: ulab.numpy.ndarray, m2: ulab.numpy.ndarray) -> Union[ulab.numpy.ndarray, _float]:
|
||||
|
|
@ -35,10 +361,13 @@ mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
|||
// TODO: should the results be upcast?
|
||||
// This implements 2D operations only!
|
||||
if(!mp_obj_is_type(_m1, &ulab_ndarray_type) || !mp_obj_is_type(_m2, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("arguments must be ndarrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("arguments must be ndarrays"));
|
||||
}
|
||||
ndarray_obj_t *m1 = MP_OBJ_TO_PTR(_m1);
|
||||
ndarray_obj_t *m2 = MP_OBJ_TO_PTR(_m2);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(m1->dtype)
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(m2->dtype)
|
||||
|
||||
uint8_t *array1 = (uint8_t *)m1->array;
|
||||
uint8_t *array2 = (uint8_t *)m2->array;
|
||||
|
||||
|
|
@ -46,7 +375,7 @@ mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
|||
mp_float_t (*func2)(void *) = ndarray_get_float_function(m2->dtype);
|
||||
|
||||
if(m1->shape[ULAB_MAX_DIMS - 1] != m2->shape[ULAB_MAX_DIMS - m2->ndim]) {
|
||||
mp_raise_ValueError(translate("dimensions do not match"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("dimensions do not match"));
|
||||
}
|
||||
uint8_t ndim = MIN(m1->ndim, m2->ndim);
|
||||
size_t shape1 = m1->ndim == 2 ? m1->shape[ULAB_MAX_DIMS - m1->ndim] : 1;
|
||||
|
|
@ -56,7 +385,7 @@ mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
|||
if(ndim == 2) { // matrix times matrix -> matrix
|
||||
shape = ndarray_shape_vector(0, 0, shape1, shape2);
|
||||
} else { // matrix times vector -> vector, vector times vector -> vector (size 1)
|
||||
shape = ndarray_shape_vector(0, 0, 0, shape1);
|
||||
shape = ndarray_shape_vector(0, 0, 0, shape1 * shape2);
|
||||
}
|
||||
ndarray_obj_t *results = ndarray_new_dense_ndarray(ndim, shape, NDARRAY_FLOAT);
|
||||
mp_float_t *rarray = (mp_float_t *)results->array;
|
||||
|
|
@ -86,5 +415,42 @@ mp_obj_t transform_dot(mp_obj_t _m1, mp_obj_t _m2) {
|
|||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(transform_dot_obj, transform_dot);
|
||||
#endif
|
||||
#endif /* ULAB_NUMPY_HAS_DOT */
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
|
||||
#if ULAB_NUMPY_HAS_SIZE
|
||||
static mp_obj_t transform_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_ROM_NONE } },
|
||||
{ MP_QSTR_axis, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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(ulab_tools_mp_obj_is_scalar(args[0].u_obj)) {
|
||||
return mp_obj_new_int(1);
|
||||
}
|
||||
|
||||
if(!ndarray_object_is_array_like(args[0].u_obj)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be an ndarray"));
|
||||
}
|
||||
if(!mp_obj_is_type(args[0].u_obj, &ulab_ndarray_type)) {
|
||||
return mp_obj_len_maybe(args[0].u_obj);
|
||||
}
|
||||
|
||||
// at this point, the args[0] is most certainly an ndarray
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
mp_obj_t axis = args[1].u_obj;
|
||||
size_t len;
|
||||
if(axis != mp_const_none) {
|
||||
int8_t ax = tools_get_axis(axis, ndarray->ndim);
|
||||
len = ndarray->shape[ULAB_MAX_DIMS - ndarray->ndim + ax];
|
||||
} else {
|
||||
len = ndarray->len;
|
||||
}
|
||||
|
||||
return mp_obj_new_int(len);
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(transform_size_obj, 1, transform_size);
|
||||
#endif
|
||||
|
|
@ -21,8 +21,10 @@
|
|||
|
||||
#include "../ulab.h"
|
||||
#include "../ulab_tools.h"
|
||||
#include "transform.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(transform_compress_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(transform_delete_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(transform_dot_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(transform_size_obj);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -15,35 +15,73 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_acosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(vectorise_arctan2_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vectorise_around_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_asinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_atanh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_ceil_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_cos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_cosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_degrees_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erf_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_erfc_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_exp_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_expm1_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_floor_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_gamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_lgamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log10_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_log2_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_radians_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_sqrt_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vectorise_tanh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vectorise_vectorize_obj);
|
||||
|
||||
#if ULAB_MATH_FUNCTIONS_OUT_KEYWORD
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_acos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_acosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_asin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_asinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_atan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_atanh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_ceil_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_cos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_cosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_degrees_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_erf_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_erfc_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_exp_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_expm1_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_floor_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_gamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_lgamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_log_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_log10_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_log2_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_radians_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_sin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_sinc_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_sinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_tan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_tanh_obj);
|
||||
#else
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_acos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_acosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_asin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_asinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_atan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_atanh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_ceil_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_cos_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_cosh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_degrees_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_erf_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_erfc_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_exp_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_expm1_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_floor_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_gamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_lgamma_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_log_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_log10_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_log2_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_radians_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_sin_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_sinc_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_sinh_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_tan_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_tanh_obj);
|
||||
#endif
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(vector_arctan2_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_around_obj);
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX | ULAB_MATH_FUNCTIONS_OUT_KEYWORD
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_sqrt_obj);
|
||||
#else
|
||||
MP_DECLARE_CONST_FUN_OBJ_1(vector_sqrt_obj);
|
||||
#endif
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(vector_vectorize_obj);
|
||||
|
||||
typedef struct _vectorized_function_obj_t {
|
||||
mp_obj_base_t base;
|
||||
|
|
@ -52,13 +90,17 @@ typedef struct _vectorized_function_obj_t {
|
|||
const mp_obj_type_t *type;
|
||||
} vectorized_function_obj_t;
|
||||
|
||||
|
||||
#if ULAB_MATH_FUNCTIONS_OUT_KEYWORD
|
||||
|
||||
#if ULAB_HAS_FUNCTION_ITERATOR
|
||||
#define ITERATE_VECTOR(type, array, source, sarray)\
|
||||
#define ITERATE_VECTOR(type, target, tarray, tstrides, source, sarray)\
|
||||
({\
|
||||
size_t *scoords = ndarray_new_coords((source)->ndim);\
|
||||
for(size_t i=0; i < (source)->len/(source)->shape[ULAB_MAX_DIMS -1]; i++) {\
|
||||
for(size_t l=0; l < (source)->shape[ULAB_MAX_DIMS - 1]; l++) {\
|
||||
*(array)++ = f(*((type *)(sarray)));\
|
||||
for(size_t i = 0; i < (source)->len / (source)->shape[ULAB_MAX_DIMS - 1]; i++) {\
|
||||
for(size_t l = 0; l < (source)->shape[ULAB_MAX_DIMS - 1]; l++) {\
|
||||
*(tarray) = f(*((type *)(sarray)));\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
}\
|
||||
ndarray_rewind_array((source)->ndim, sarray, (source)->shape, (source)->strides, scoords);\
|
||||
|
|
@ -67,34 +109,153 @@ typedef struct _vectorized_function_obj_t {
|
|||
|
||||
#else
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define ITERATE_VECTOR(type, target, tarray, tstrides, source, sarray) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(tarray) = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define ITERATE_VECTOR(type, target, tarray, tstrides, source, sarray) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(tarray) = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 1] * (target)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define ITERATE_VECTOR(type, target, tarray, tstrides, source, sarray) do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(tarray) = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 1] * (target)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS-2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 2] * (target)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
size_t i=0;\
|
||||
#define ITERATE_VECTOR(type, target, tshape, tstrides, source, sarray) do {\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(tarray) = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 1] * (target)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS-2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 2] * (target)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 3] * (source)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 4];\
|
||||
(tarray) -= (tstrides)[ULAB_MAX_DIMS - 3] * (target)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(tarray) += (tstrides)[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (source)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
#endif /* ULAB_HAS_FUNCTION_ITERATOR */
|
||||
|
||||
#define MATH_FUN_1(py_name, c_name) \
|
||||
static mp_obj_t vector_ ## py_name(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) { \
|
||||
return vector_generic_vector(n_args, pos_args, kw_args, MICROPY_FLOAT_C_FUN(c_name)); \
|
||||
}
|
||||
|
||||
#else /* ULAB_MATH_FUNCTIONS_OUT_KEYWORD */
|
||||
|
||||
#if ULAB_HAS_FUNCTION_ITERATOR
|
||||
#define ITERATE_VECTOR(type, array, source, sarray, shift)\
|
||||
({\
|
||||
size_t *scoords = ndarray_new_coords((source)->ndim);\
|
||||
for(size_t i=0; i < (source)->len / (source)->shape[ULAB_MAX_DIMS - 1]; i++) {\
|
||||
for(size_t l = 0; l < (source)->shape[ULAB_MAX_DIMS - 1]; l++) {\
|
||||
*(array) = f(*((type *)(sarray)));\
|
||||
(array)++;\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
}\
|
||||
ndarray_rewind_array((source)->ndim, sarray, (source)->shape, (source)->strides, scoords);\
|
||||
}\
|
||||
})
|
||||
|
||||
#else
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS-2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS-2];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS-3]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 3] * (source)->shape[ULAB_MAX_DIMS-3];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (source)->shape[ULAB_MAX_DIMS-4]);\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 3
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
|
|
@ -107,20 +268,24 @@ typedef struct _vectorized_function_obj_t {
|
|||
*(array)++ = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS-2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS-2];\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS-3]);\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 3 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 2
|
||||
#if ULAB_MAX_DIMS == 4
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
size_t i = 0;\
|
||||
do {\
|
||||
size_t j = 0;\
|
||||
do {\
|
||||
size_t k = 0;\
|
||||
do {\
|
||||
size_t l = 0;\
|
||||
|
|
@ -128,29 +293,27 @@ typedef struct _vectorized_function_obj_t {
|
|||
*(array)++ = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS-1];\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS - 1]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 1] * (source)->shape[ULAB_MAX_DIMS - 1];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 2];\
|
||||
k++;\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS-2]);\
|
||||
} while(k < (source)->shape[ULAB_MAX_DIMS - 2]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 2] * (source)->shape[ULAB_MAX_DIMS - 2];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 3];\
|
||||
j++;\
|
||||
} while(j < (source)->shape[ULAB_MAX_DIMS - 3]);\
|
||||
(sarray) -= (source)->strides[ULAB_MAX_DIMS - 3] * (source)->shape[ULAB_MAX_DIMS - 3];\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 4];\
|
||||
i++;\
|
||||
} while(i < (source)->shape[ULAB_MAX_DIMS - 4]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 2 */
|
||||
#endif /* ULAB_MAX_DIMS == 4 */
|
||||
|
||||
#if ULAB_MAX_DIMS == 1
|
||||
#define ITERATE_VECTOR(type, array, source, sarray) do {\
|
||||
size_t l = 0;\
|
||||
do {\
|
||||
*(array)++ = f(*((type *)(sarray)));\
|
||||
(sarray) += (source)->strides[ULAB_MAX_DIMS - 1];\
|
||||
l++;\
|
||||
} while(l < (source)->shape[ULAB_MAX_DIMS-1]);\
|
||||
} while(0)
|
||||
#endif /* ULAB_MAX_DIMS == 1 */
|
||||
#endif /* ULAB_HAS_FUNCTION_ITERATOR */
|
||||
|
||||
#define MATH_FUN_1(py_name, c_name) \
|
||||
static mp_obj_t vectorise_ ## py_name(mp_obj_t x_obj) { \
|
||||
return vectorise_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
|
||||
static mp_obj_t vector_ ## py_name(mp_obj_t x_obj) { \
|
||||
return vector_generic_vector(x_obj, MICROPY_FLOAT_C_FUN(c_name)); \
|
||||
}
|
||||
|
||||
#endif /* ULAB_MATH_FUNCTIONS_OUT_KEYWORD */
|
||||
#endif /* _VECTOR_ */
|
||||
|
|
|
|||
701
code/scipy/integrate/integrate.c
Normal file
701
code/scipy/integrate/integrate.c
Normal file
|
|
@ -0,0 +1,701 @@
|
|||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Harald Milz <hm@seneca.muc.de>
|
||||
*
|
||||
* References:
|
||||
* - Dr. Robert van Engelen, Improving the mp_float_t Exponential Quadrature Tanh-Sinh, Sinh-Sinh and Exp-Sinh Formulas,
|
||||
* 2021, https://www.genivia.com/qthsh.html
|
||||
* - Borwein, Bailey & Girgensohn, "Experimentation in Mathematics - Computational Paths to Discovery", A K Peters,
|
||||
* 2003, pages 312-313
|
||||
* - Joren Vanherck, Bart Sorée, Wim Magnus, Tanh-sinh quadrature for single and multiple integration using
|
||||
* floating-point arithmetic, 2020, https://arxiv.org/abs/2007.15057
|
||||
* - Tanh-Sinh quadrature, Wikipedia, https://en.wikipedia.org/wiki/Tanh-sinh_quadrature
|
||||
* - Romberg's method, Wikipedia, https://en.wikipedia.org/wiki/Romberg%27s_method
|
||||
* - Adaptive Simpson's method, Wikipedia, https://en.wikipedia.org/wiki/Adaptive_Simpson%27s_method
|
||||
* - Gauss–Kronrod quadrature formula, Wikipedia, https://en.wikipedia.org/wiki/Gauss%E2%80%93Kronrod_quadrature_formula
|
||||
*
|
||||
* This module provides four integration methods, and thus deviates from scipy.integrate a bit.
|
||||
* As for the pros and cons of the different methods please consult the literature above.
|
||||
* The code was ported to Micropython from Dr. Engelen's paper and used with his written kind permission
|
||||
* - quad - Tanh-Sinh, Sinh-Sinh and Exp-Sinh quadrature
|
||||
* - romberg - Romberg quadrature
|
||||
* - simpson - Adaptive Simpson quadrature
|
||||
* - quadgk - Adaptive Gauss-Kronrod (G10,K21) quadrature
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
#include "py/misc.h"
|
||||
#include "py/objtuple.h"
|
||||
|
||||
#include "../../ndarray.h"
|
||||
#include "../../ulab.h"
|
||||
#include "../../ulab_tools.h"
|
||||
#include "integrate.h"
|
||||
|
||||
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
|
||||
ULAB_DEFINE_FLOAT_CONST(etolerance, MICROPY_FLOAT_CONST(1e-14), 0x283424dcUL, 0x3e901b2b29a4692bULL);
|
||||
#define ULAB_MACHEPS MICROPY_FLOAT_CONST(1e-17)
|
||||
#else
|
||||
ULAB_DEFINE_FLOAT_CONST(etolerance, MICROPY_FLOAT_CONST(1e-8), 0x358637cfUL, 0x3e7010c6f7d42d18ULL);
|
||||
#define ULAB_MACHEPS MICROPY_FLOAT_CONST(1e-8)
|
||||
#endif
|
||||
|
||||
#define ULAB_ZERO MICROPY_FLOAT_CONST(0.0)
|
||||
#define ULAB_POINT_TWO_FIVE MICROPY_FLOAT_CONST(0.25)
|
||||
#define ULAB_ONE MICROPY_FLOAT_CONST(1.0)
|
||||
#define ULAB_TWO MICROPY_FLOAT_CONST(2.0)
|
||||
#define ULAB_FOUR MICROPY_FLOAT_CONST(4.0)
|
||||
#define ULAB_SIX MICROPY_FLOAT_CONST(6.0)
|
||||
#define ULAB_TEN MICROPY_FLOAT_CONST(10.0)
|
||||
#define ULAB_FIFTEEN MICROPY_FLOAT_CONST(15.0)
|
||||
#define ULAB_EPSILON_5 MICROPY_FLOAT_CONST(1e-5)
|
||||
|
||||
|
||||
static mp_float_t integrate_python_call(const mp_obj_type_t *type, mp_obj_t fun, mp_float_t x, mp_obj_t *fargs, uint8_t nparams) {
|
||||
// Helper function for calculating the value of f(x, a, b, c, ...),
|
||||
// where f is defined in python. Takes a float, returns a float.
|
||||
// The array of mp_obj_t type must be supplied, as must the number of parameters (a, b, c...) in nparams
|
||||
fargs[0] = mp_obj_new_float(x);
|
||||
return mp_obj_get_float(MP_OBJ_TYPE_GET_SLOT(type, call)(fun, nparams+1, 0, fargs));
|
||||
}
|
||||
|
||||
// sign helper function
|
||||
int sign(mp_float_t x) {
|
||||
if (x >= ULAB_ZERO)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
#if ULAB_INTEGRATE_HAS_TANHSINH
|
||||
// Tanh-Sinh, Sinh-Sinh and Exp-Sinh quadrature
|
||||
// https://www.genivia.com/qthsh.html
|
||||
|
||||
// return optimized Exp-Sinh integral split point d
|
||||
mp_float_t exp_sinh_opt_d(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t eps, mp_float_t d) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t h2 = integrate_python_call(type, fun, a + d/2, fargs, 0) - integrate_python_call(type, fun, (a + d*2)*4, fargs, 0);
|
||||
int i = 1, j = 32; // j=32 is optimal to find r
|
||||
if (isfinite(h2) && MICROPY_FLOAT_C_FUN(fabs)(h2) > ULAB_EPSILON_5) { // if |h2| > 2^-16
|
||||
mp_float_t r, fl, fr, h, s = 0, lfl, lfr, lr = 2;
|
||||
do { // find max j such that fl and fr are finite
|
||||
j /= 2;
|
||||
r = 1 << (i + j);
|
||||
fl = integrate_python_call(type, fun, a + d/r, fargs, 0);
|
||||
fr = integrate_python_call(type, fun, (a + d*r)*r*r, fargs, 0);
|
||||
h = fl - fr;
|
||||
} while (j > 1 && !isfinite(h));
|
||||
if (j > 1 && isfinite(h) && sign(h) != sign(h2)) {
|
||||
lfl = fl; // last fl=f(a+d/r)
|
||||
lfr = fr; // last fr=f(a+d*r)*r*r
|
||||
do { // bisect in 4 iterations
|
||||
j /= 2;
|
||||
r = 1 << (i + j);
|
||||
fl = integrate_python_call(type, fun, a + d/r, fargs, 0);
|
||||
fr = integrate_python_call(type, fun, (a + d*r)*r*r, fargs, 0);
|
||||
h = fl - fr;
|
||||
if (isfinite(h)) {
|
||||
s += MICROPY_FLOAT_C_FUN(fabs)(h); // sum |h| to remove noisy cases
|
||||
if (sign(h) == sign(h2)) {
|
||||
i += j; // search right half
|
||||
}
|
||||
else { // search left half
|
||||
lfl = fl; // record last fl=f(a+d/r)
|
||||
lfr = fr; // record last fl=f(a+d*r)*r*r
|
||||
lr = r; // record last r
|
||||
}
|
||||
}
|
||||
} while (j > 1);
|
||||
if (s > eps) { // if sum of |h| > eps
|
||||
h = lfl - lfr; // use last fl and fr before the sign change
|
||||
r = lr; // use last r before the sign change
|
||||
if (h != ULAB_ZERO) // if last diff != 0, back up r by one step
|
||||
r /= ULAB_TWO;
|
||||
if (MICROPY_FLOAT_C_FUN(fabs)(lfl) < MICROPY_FLOAT_C_FUN(fabs)(lfr))
|
||||
d /= r; // move d closer to the finite endpoint
|
||||
else
|
||||
d *= r; // move d closer to the infinite endpoint
|
||||
}
|
||||
}
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
// integrate function f, range a..b, max levels n, error tolerance eps
|
||||
mp_float_t tanhsinh(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t b, uint16_t n, mp_float_t eps, mp_float_t *e) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
const mp_float_t tol = ULAB_TEN * eps;
|
||||
mp_float_t c = ULAB_ZERO, d = ULAB_ONE, s, sign = ULAB_ONE, v, h = ULAB_TWO;
|
||||
int k = 0, mode = 0; // Tanh-Sinh = 0, Exp-Sinh = 1, Sinh-Sinh = 2
|
||||
if (b < a) { // swap bounds
|
||||
v = b;
|
||||
b = a;
|
||||
a = v;
|
||||
sign = -1;
|
||||
}
|
||||
if (isfinite(a) && isfinite(b)) {
|
||||
c = (a+b) / ULAB_TWO;
|
||||
d = (b-a) / ULAB_TWO;
|
||||
v = c;
|
||||
}
|
||||
else if (isfinite(a)) {
|
||||
mode = 1; // Exp-Sinh
|
||||
d = exp_sinh_opt_d(fun, a, eps, d);
|
||||
c = a;
|
||||
v = a+d;
|
||||
}
|
||||
else if (isfinite(b)) {
|
||||
mode = 1; // Exp-Sinh
|
||||
// d = -d;
|
||||
d = exp_sinh_opt_d(fun, b, eps, -d);
|
||||
sign = -sign;
|
||||
c = b;
|
||||
v = b+d;
|
||||
}
|
||||
else {
|
||||
mode = 2; // Sinh-Sinh
|
||||
v = ULAB_ZERO;
|
||||
}
|
||||
s = integrate_python_call(type, fun, v, fargs, 0);
|
||||
do {
|
||||
mp_float_t p = ULAB_ZERO, q, fp = ULAB_ZERO, fm = ULAB_ZERO, t, eh;
|
||||
h /= ULAB_TWO;
|
||||
t = eh = MICROPY_FLOAT_C_FUN(exp)(h);
|
||||
if (k > ULAB_ZERO)
|
||||
eh *= eh;
|
||||
if (mode == 0) { // Tanh-Sinh
|
||||
do {
|
||||
mp_float_t u = MICROPY_FLOAT_C_FUN(exp)(ULAB_ONE / t - t); // = exp(-2*sinh(j*h)) = 1/exp(sinh(j*h))^2
|
||||
mp_float_t r = ULAB_TWO * u / (ULAB_ONE + u); // = 1 - tanh(sinh(j*h))
|
||||
mp_float_t w = (t + ULAB_ONE / t) * r / (ULAB_ONE + u); // = cosh(j*h)/cosh(sinh(j*h))^2
|
||||
mp_float_t x = d*r;
|
||||
if (a+x > a) { // if too close to a then reuse previous fp
|
||||
mp_float_t y = integrate_python_call(type, fun, a+x, fargs, 0);
|
||||
if (isfinite(y))
|
||||
fp = y; // if f(x) is finite, add to local sum
|
||||
}
|
||||
if (b-x < b) { // if too close to a then reuse previous fp
|
||||
mp_float_t y = integrate_python_call(type, fun, b-x, fargs, 0);
|
||||
if (isfinite(y))
|
||||
fm = y; // if f(x) is finite, add to local sum
|
||||
}
|
||||
q = w*(fp+fm);
|
||||
p += q;
|
||||
t *= eh;
|
||||
} while (MICROPY_FLOAT_C_FUN(fabs)(q) > eps*MICROPY_FLOAT_C_FUN(fabs)(p));
|
||||
}
|
||||
else {
|
||||
t /= ULAB_TWO;
|
||||
do {
|
||||
mp_float_t r = MICROPY_FLOAT_C_FUN(exp)(t - ULAB_POINT_TWO_FIVE / t); // = exp(sinh(j*h))
|
||||
mp_float_t x, y, w = r;
|
||||
q = ULAB_ZERO;
|
||||
if (mode == 1) { // Exp-Sinh
|
||||
x = c + d/r;
|
||||
if (x == c) // if x hit the finite endpoint then break
|
||||
break;
|
||||
y = integrate_python_call(type, fun, x, fargs, 0);
|
||||
if (isfinite(y)) // if f(x) is finite, add to local sum
|
||||
q += y/w;
|
||||
}
|
||||
else { // Sinh-Sinh
|
||||
r = (r - ULAB_ONE / r) / ULAB_TWO; // = sinh(sinh(j*h))
|
||||
w = (w + ULAB_ONE / w) / ULAB_TWO; // = cosh(sinh(j*h))
|
||||
x = c - d*r;
|
||||
y = integrate_python_call(type, fun, x, fargs, 0);
|
||||
if (isfinite(y)) // if f(x) is finite, add to local sum
|
||||
q += y*w;
|
||||
}
|
||||
x = c + d*r;
|
||||
y = integrate_python_call(type, fun, x, fargs, 0);
|
||||
if (isfinite(y)) // if f(x) is finite, add to local sum
|
||||
q += y*w;
|
||||
q *= t + ULAB_POINT_TWO_FIVE / t; // q *= cosh(j*h)
|
||||
p += q;
|
||||
t *= eh;
|
||||
} while (MICROPY_FLOAT_C_FUN(fabs)(q) > eps*MICROPY_FLOAT_C_FUN(fabs)(p));
|
||||
}
|
||||
v = s-p;
|
||||
s += p;
|
||||
++k;
|
||||
} while (MICROPY_FLOAT_C_FUN(fabs)(v) > tol*MICROPY_FLOAT_C_FUN(fabs)(s) && k <= n);
|
||||
// return the error estimate by reference
|
||||
*e = MICROPY_FLOAT_C_FUN(fabs)(v)/(MICROPY_FLOAT_C_FUN(fabs)(s)+eps);
|
||||
return sign*d*s*h; // result with estimated relative error e
|
||||
}
|
||||
|
||||
//| def tanhsinh(
|
||||
//| fun: Callable[[float], float],
|
||||
//| a: float,
|
||||
//| b: float,
|
||||
//| *,
|
||||
//| levels: int = 6
|
||||
//| eps: float = etolerance
|
||||
//| ) -> float:
|
||||
//| """
|
||||
//| :param callable f: The function to integrate
|
||||
//| :param float a: The lower integration limit
|
||||
//| :param float b: The upper integration limit
|
||||
//| :param float levels: The number of levels to perform (6..7 is optimal)
|
||||
//| :param float eps: The error tolerance value
|
||||
//|
|
||||
//| Find a quadrature of the function ``f(x)`` on the interval
|
||||
//| (``a``..``b``) using an optimized double exponential. The result is accurate to within
|
||||
//| ``eps`` unless more than ``levels`` levels are required."""
|
||||
//|
|
||||
|
||||
|
||||
static mp_obj_t integrate_tanhsinh(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_levels, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 6} },
|
||||
{ MP_QSTR_eps, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(etolerance)} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a callable"));
|
||||
}
|
||||
|
||||
// iterate over args 1, 2, and 4
|
||||
// arg 3 will be handled by MP_ARG_INT above.
|
||||
for (int i=1; i<=4; i*=2) {
|
||||
type = mp_obj_get_type(args[i].u_obj);
|
||||
if (type != &mp_type_float && type != &mp_type_int) {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
MP_ERROR_TEXT("can't convert arg %d from %s to float"), i, mp_obj_get_type_str(args[i].u_obj));
|
||||
}
|
||||
}
|
||||
mp_float_t a = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t b = mp_obj_get_float(args[2].u_obj);
|
||||
uint16_t n = (uint16_t)args[3].u_int;
|
||||
if (n < 1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("levels needs to be a positive integer"));
|
||||
}
|
||||
mp_float_t eps = mp_obj_get_float(args[4].u_obj);
|
||||
|
||||
mp_obj_t res[2];
|
||||
mp_float_t e;
|
||||
res[0] = mp_obj_new_float(tanhsinh(fun, a, b, n, eps, &e));
|
||||
res[1] = mp_obj_new_float(e);
|
||||
return mp_obj_new_tuple(2, res);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(integrate_tanhsinh_obj, 2, integrate_tanhsinh);
|
||||
#endif /* ULAB_INTEGRATE_HAS_TANHSINH */
|
||||
|
||||
#if ULAB_INTEGRATE_HAS_ROMBERG
|
||||
// Romberg quadrature
|
||||
// This function is deprecated as of SciPy 1.12.0 and will be removed in SciPy 1.15.0. Please use scipy.integrate.quad instead.
|
||||
// https://en.wikipedia.org/wiki/Romberg%27s_method, https://www.genivia.com/qthsh.html,
|
||||
// https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.romberg.html (which is different
|
||||
// insofar as the latter expects an array of function values).
|
||||
|
||||
mp_float_t qromb(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t b, uint16_t n, mp_float_t eps) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t R1[n], R2[n];
|
||||
mp_float_t *Ro = &R1[0], *Ru = &R2[0];
|
||||
mp_float_t h = b-a;
|
||||
uint16_t i, j;
|
||||
Ro[0] = (integrate_python_call(type, fun, a, fargs, 0) + integrate_python_call(type, fun, b, fargs, 0)) * h/2;
|
||||
for (i = 1; i < n; ++i) {
|
||||
unsigned long long k = 1UL << i;
|
||||
unsigned long long s = 1;
|
||||
mp_float_t sum = ULAB_ZERO;
|
||||
mp_float_t *Rt;
|
||||
h /= ULAB_TWO;
|
||||
for (j = 1; j < k; j += 2)
|
||||
sum += integrate_python_call(type, fun, a+j*h, fargs, 0);
|
||||
Ru[0] = h*sum + Ro[0] / ULAB_TWO;
|
||||
for (j = 1; j <= i; ++j) {
|
||||
s <<= 2;
|
||||
Ru[j] = (s*Ru[j-1] - Ro[j-1])/(s-1);
|
||||
}
|
||||
if (i > 2 && MICROPY_FLOAT_C_FUN(fabs)(Ro[i-1]-Ru[i]) <= eps*MICROPY_FLOAT_C_FUN(fabs)(Ru[i])+eps)
|
||||
return Ru[i];
|
||||
Rt = Ro;
|
||||
Ro = Ru;
|
||||
Ru = Rt;
|
||||
}
|
||||
return Ro[n-1];
|
||||
}
|
||||
|
||||
//| def romberg(
|
||||
//| fun: Callable[[float], float],
|
||||
//| a: float,
|
||||
//| b: float,
|
||||
//| *,
|
||||
//| steps: int = 100
|
||||
//| eps: float = etolerance
|
||||
//| ) -> float:
|
||||
//| """
|
||||
//| :param callable f: The function to integrate
|
||||
//| :param float a: The lower integration limit
|
||||
//| :param float b: The upper integration limit
|
||||
//| :param float steps: The number of equidistant steps
|
||||
//| :param float eps: The tolerance value
|
||||
//|
|
||||
//| Find a quadrature of the function ``f(x)`` on the interval
|
||||
//| (``a``..``b``) using the Romberg method. The result is accurate to within
|
||||
//| ``eps`` unless more than ``steps`` steps are required."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t integrate_romberg(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_steps, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100} },
|
||||
{ MP_QSTR_eps, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(etolerance)} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a callable"));
|
||||
}
|
||||
|
||||
// iterate over args 1, 2, and 4
|
||||
// arg 3 will be handled by MP_ARG_INT above.
|
||||
for (int i=1; i<=4; i*=2) {
|
||||
type = mp_obj_get_type(args[i].u_obj);
|
||||
if (type != &mp_type_float && type != &mp_type_int) {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
MP_ERROR_TEXT("can't convert arg %d from %s to float"), i, mp_obj_get_type_str(args[i].u_obj));
|
||||
}
|
||||
}
|
||||
mp_float_t a = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t b = mp_obj_get_float(args[2].u_obj);
|
||||
uint16_t steps = (uint16_t)args[3].u_int;
|
||||
if (steps < 1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("steps needs to be a positive integer"));
|
||||
}
|
||||
mp_float_t eps = mp_obj_get_float(args[4].u_obj);
|
||||
|
||||
return mp_obj_new_float(qromb(fun, a, b, steps, eps));
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(integrate_romberg_obj, 2, integrate_romberg);
|
||||
#endif /* ULAB_INTEGRATE_HAS_ROMBERG */
|
||||
|
||||
#if ULAB_INTEGRATE_HAS_SIMPSON
|
||||
// Adaptive Simpson quadrature
|
||||
// https://en.wikipedia.org/wiki/Adaptive_Simpson%27s_method, https://www.genivia.com/qthsh.html
|
||||
|
||||
mp_float_t as(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t b, mp_float_t fa, mp_float_t fm,
|
||||
mp_float_t fb, mp_float_t v, mp_float_t eps, int n, mp_float_t t) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t h = (b-a) / ULAB_TWO;
|
||||
mp_float_t f1 = integrate_python_call(type, fun, a + h / ULAB_TWO, fargs, 0);
|
||||
mp_float_t f2 = integrate_python_call(type, fun, b - h / ULAB_TWO, fargs, 0);
|
||||
mp_float_t sl = h*(fa + ULAB_FOUR * f1 + fm) / ULAB_SIX;
|
||||
mp_float_t sr = h*(fm + ULAB_FOUR * f2 + fb) / ULAB_SIX;
|
||||
mp_float_t s = sl+sr;
|
||||
mp_float_t d = (s-v) / ULAB_FIFTEEN;
|
||||
mp_float_t m = a+h;
|
||||
if (n <= 0 || MICROPY_FLOAT_C_FUN(fabs)(d) < eps)
|
||||
return t + s + d; // note: fabs(d) can be used as error estimate
|
||||
eps /= ULAB_TWO;
|
||||
--n;
|
||||
t = as(fun, a, m, fa, f1, fm, sl, eps, n, t);
|
||||
return as(fun, m, b, fm, f2, fb, sr, eps, n, t);
|
||||
}
|
||||
|
||||
mp_float_t qasi(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t b, int n, mp_float_t eps) {
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t fa = integrate_python_call(type, fun, a, fargs, 0);
|
||||
mp_float_t fm = integrate_python_call(type, fun, (a+b)/2, fargs, 0);
|
||||
mp_float_t fb = integrate_python_call(type, fun, b, fargs, 0);
|
||||
mp_float_t v = (fa + ULAB_FOUR * fm + fb) * (b-a) / ULAB_SIX;
|
||||
return as(fun, a, b, fa, fm, fb, v, eps, n, 0);
|
||||
}
|
||||
|
||||
//| def simpson(
|
||||
//| fun: Callable[[float], float],
|
||||
//| a: float,
|
||||
//| b: float,
|
||||
//| *,
|
||||
//| steps: int = 100
|
||||
//| eps: float = etolerance
|
||||
//| ) -> float:
|
||||
//| """
|
||||
//| :param callable f: The function to integrate
|
||||
//| :param float a: The lower integration limit
|
||||
//| :param float b: The upper integration limit
|
||||
//| :param float steps: The number of equidistant steps
|
||||
//| :param float eps: The tolerance value
|
||||
//|
|
||||
//| Find a quadrature of the function ``f(x)`` on the interval
|
||||
//| (``a``..``b``) using the Adaptive Simpson's method. The result is accurate to within
|
||||
//| ``eps`` unless more than ``steps`` steps are required."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t integrate_simpson(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_steps, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100} },
|
||||
{ MP_QSTR_eps, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(etolerance)} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a function"));
|
||||
}
|
||||
|
||||
// iterate over args 1, 2, and 4
|
||||
// arg 3 will be handled by MP_ARG_INT above.
|
||||
for (int i=1; i<=4; i*=2) {
|
||||
type = mp_obj_get_type(args[i].u_obj);
|
||||
if (type != &mp_type_float && type != &mp_type_int) {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
MP_ERROR_TEXT("can't convert arg %d from %s to float"), i, mp_obj_get_type_str(args[i].u_obj));
|
||||
}
|
||||
}
|
||||
mp_float_t a = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t b = mp_obj_get_float(args[2].u_obj);
|
||||
uint16_t steps = (uint16_t)args[3].u_int;
|
||||
if (steps < 1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("steps needs to be a positive integer"));
|
||||
}
|
||||
mp_float_t eps = mp_obj_get_float(args[4].u_obj);
|
||||
|
||||
return mp_obj_new_float(qasi(fun, a, b, steps, eps));
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(integrate_simpson_obj, 2, integrate_simpson);
|
||||
#endif /* ULAB_INTEGRATE_HAS_SIMPSON */
|
||||
|
||||
#if ULAB_INTEGRATE_HAS_QUAD
|
||||
// Adaptive Gauss-Kronrod (G10,K21) quadrature
|
||||
// https://en.wikipedia.org/wiki/Gauss%E2%80%93Kronrod_quadrature_formula, https://www.genivia.com/qthsh.html
|
||||
|
||||
mp_float_t gk(mp_float_t (*fun)(mp_float_t), mp_float_t c, mp_float_t d, mp_float_t *err) {
|
||||
// abscissas and weights pre-calculated with Legendre Stieltjes polynomials
|
||||
static const mp_float_t abscissas[21] = {
|
||||
MICROPY_FLOAT_CONST(0.00000000000000000e+00),
|
||||
MICROPY_FLOAT_CONST(7.65265211334973338e-02),
|
||||
MICROPY_FLOAT_CONST(1.52605465240922676e-01),
|
||||
MICROPY_FLOAT_CONST(2.27785851141645078e-01),
|
||||
MICROPY_FLOAT_CONST(3.01627868114913004e-01),
|
||||
MICROPY_FLOAT_CONST(3.73706088715419561e-01),
|
||||
MICROPY_FLOAT_CONST(4.43593175238725103e-01),
|
||||
MICROPY_FLOAT_CONST(5.10867001950827098e-01),
|
||||
MICROPY_FLOAT_CONST(5.75140446819710315e-01),
|
||||
MICROPY_FLOAT_CONST(6.36053680726515025e-01),
|
||||
MICROPY_FLOAT_CONST(6.93237656334751385e-01),
|
||||
MICROPY_FLOAT_CONST(7.46331906460150793e-01),
|
||||
MICROPY_FLOAT_CONST(7.95041428837551198e-01),
|
||||
MICROPY_FLOAT_CONST(8.39116971822218823e-01),
|
||||
MICROPY_FLOAT_CONST(8.78276811252281976e-01),
|
||||
MICROPY_FLOAT_CONST(9.12234428251325906e-01),
|
||||
MICROPY_FLOAT_CONST(9.40822633831754754e-01),
|
||||
MICROPY_FLOAT_CONST(9.63971927277913791e-01),
|
||||
MICROPY_FLOAT_CONST(9.81507877450250259e-01),
|
||||
MICROPY_FLOAT_CONST(9.93128599185094925e-01),
|
||||
MICROPY_FLOAT_CONST(9.98859031588277664e-01),
|
||||
};
|
||||
static const mp_float_t weights[21] = {
|
||||
MICROPY_FLOAT_CONST(7.66007119179996564e-02),
|
||||
MICROPY_FLOAT_CONST(7.63778676720807367e-02),
|
||||
MICROPY_FLOAT_CONST(7.57044976845566747e-02),
|
||||
MICROPY_FLOAT_CONST(7.45828754004991890e-02),
|
||||
MICROPY_FLOAT_CONST(7.30306903327866675e-02),
|
||||
MICROPY_FLOAT_CONST(7.10544235534440683e-02),
|
||||
MICROPY_FLOAT_CONST(6.86486729285216193e-02),
|
||||
MICROPY_FLOAT_CONST(6.58345971336184221e-02),
|
||||
MICROPY_FLOAT_CONST(6.26532375547811680e-02),
|
||||
MICROPY_FLOAT_CONST(5.91114008806395724e-02),
|
||||
MICROPY_FLOAT_CONST(5.51951053482859947e-02),
|
||||
MICROPY_FLOAT_CONST(5.09445739237286919e-02),
|
||||
MICROPY_FLOAT_CONST(4.64348218674976747e-02),
|
||||
MICROPY_FLOAT_CONST(4.16688733279736863e-02),
|
||||
MICROPY_FLOAT_CONST(3.66001697582007980e-02),
|
||||
MICROPY_FLOAT_CONST(3.12873067770327990e-02),
|
||||
MICROPY_FLOAT_CONST(2.58821336049511588e-02),
|
||||
MICROPY_FLOAT_CONST(2.03883734612665236e-02),
|
||||
MICROPY_FLOAT_CONST(1.46261692569712530e-02),
|
||||
MICROPY_FLOAT_CONST(8.60026985564294220e-03),
|
||||
MICROPY_FLOAT_CONST(3.07358371852053150e-03),
|
||||
};
|
||||
static const mp_float_t gauss_weights[10] = {
|
||||
MICROPY_FLOAT_CONST(1.52753387130725851e-01),
|
||||
MICROPY_FLOAT_CONST(1.49172986472603747e-01),
|
||||
MICROPY_FLOAT_CONST(1.42096109318382051e-01),
|
||||
MICROPY_FLOAT_CONST(1.31688638449176627e-01),
|
||||
MICROPY_FLOAT_CONST(1.18194531961518417e-01),
|
||||
MICROPY_FLOAT_CONST(1.01930119817240435e-01),
|
||||
MICROPY_FLOAT_CONST(8.32767415767047487e-02),
|
||||
MICROPY_FLOAT_CONST(6.26720483341090636e-02),
|
||||
MICROPY_FLOAT_CONST(4.06014298003869413e-02),
|
||||
MICROPY_FLOAT_CONST(1.76140071391521183e-02),
|
||||
};
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t p = ULAB_ZERO; // kronrod quadrature sum
|
||||
mp_float_t q = ULAB_ZERO; // gauss quadrature sum
|
||||
mp_float_t fp, fm;
|
||||
mp_float_t e;
|
||||
int i;
|
||||
fp = integrate_python_call(type, fun, c, fargs, 0);
|
||||
p = fp * weights[0];
|
||||
for (i = 1; i < 21; i += 2) {
|
||||
fp = integrate_python_call(type, fun, c + d * abscissas[i], fargs, 0);
|
||||
fm = integrate_python_call(type, fun, c - d * abscissas[i], fargs, 0);
|
||||
p += (fp + fm) * weights[i];
|
||||
q += (fp + fm) * gauss_weights[i/2];
|
||||
}
|
||||
for (i = 2; i < 21; i += 2) {
|
||||
fp = integrate_python_call(type, fun, c + d * abscissas[i], fargs, 0);
|
||||
fm = integrate_python_call(type, fun, c - d * abscissas[i], fargs, 0);
|
||||
p += (fp + fm) * weights[i];
|
||||
}
|
||||
*err = MICROPY_FLOAT_C_FUN(fabs)(p - q);
|
||||
e = MICROPY_FLOAT_C_FUN(fabs)(2 * p * ULAB_MACHEPS); // optional, to take 1e-17 MachEps prec. into account
|
||||
if (*err < e)
|
||||
*err = e;
|
||||
return p;
|
||||
}
|
||||
|
||||
mp_float_t qakro(mp_float_t (*fun)(mp_float_t), mp_float_t a, mp_float_t b, int n, mp_float_t tol, mp_float_t eps, mp_float_t *err) {
|
||||
mp_float_t c = (a+b) / ULAB_TWO;
|
||||
mp_float_t d = (b-a) / ULAB_TWO;
|
||||
mp_float_t e;
|
||||
mp_float_t r = gk(fun, c, d, &e);
|
||||
mp_float_t s = d*r;
|
||||
mp_float_t t = MICROPY_FLOAT_C_FUN(fabs)(s*tol);
|
||||
if (tol == ULAB_ZERO)
|
||||
tol = t;
|
||||
if (n > 0 && t < e && tol < e) {
|
||||
s = qakro(fun, a, c, n-1, t / ULAB_TWO, eps, err);
|
||||
s += qakro(fun, c, b, n-1, t / ULAB_TWO, eps, &e);
|
||||
*err += e;
|
||||
return s;
|
||||
}
|
||||
*err = e;
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
//| def quad(
|
||||
//| fun: Callable[[float], float],
|
||||
//| a: float,
|
||||
//| b: float,
|
||||
//| *,
|
||||
//| order: int = 5
|
||||
//| eps: float = etolerance
|
||||
//| ) -> float:
|
||||
//| """
|
||||
//| :param callable f: The function to integrate
|
||||
//| :param float a: The lower integration limit
|
||||
//| :param float b: The upper integration limit
|
||||
//| :param float order: Order of quadrature integration. Default is 5.
|
||||
//| :param float eps: The tolerance value
|
||||
//|
|
||||
//| Find a quadrature of the function ``f(x)`` on the interval
|
||||
//| (``a``..``b``) using the Adaptive Gauss-Kronrod method. The result is accurate to within
|
||||
//| ``eps`` unless a higher order than ``order`` is required."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
static mp_obj_t integrate_quad(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_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_order, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5} },
|
||||
{ MP_QSTR_eps, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(etolerance)} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a callable"));
|
||||
}
|
||||
|
||||
// iterate over args 1, 2, and 4
|
||||
// arg 3 will be handled by MP_ARG_INT above.
|
||||
for (int i=1; i<=4; i*=2) {
|
||||
type = mp_obj_get_type(args[i].u_obj);
|
||||
if (type != &mp_type_float && type != &mp_type_int) {
|
||||
mp_raise_msg_varg(&mp_type_TypeError,
|
||||
MP_ERROR_TEXT("can't convert arg %d from %s to float"), i, mp_obj_get_type_str(args[i].u_obj));
|
||||
}
|
||||
}
|
||||
mp_float_t a = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t b = mp_obj_get_float(args[2].u_obj);
|
||||
uint16_t order = (uint16_t)args[3].u_int;
|
||||
if (order < 1) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("order needs to be a positive integer"));
|
||||
}
|
||||
mp_float_t eps = mp_obj_get_float(args[4].u_obj);
|
||||
|
||||
mp_obj_t res[2];
|
||||
mp_float_t e;
|
||||
res[0] = mp_obj_new_float(qakro(fun, a, b, order, 0, eps, &e));
|
||||
res[1] = mp_obj_new_float(e);
|
||||
return mp_obj_new_tuple(2, res);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(integrate_quad_obj, 2, integrate_quad);
|
||||
#endif /* ULAB_INTEGRATE_HAS_QUAD */
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_integrate_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_integrate) },
|
||||
#if ULAB_INTEGRATE_HAS_TANHSINH
|
||||
{ MP_ROM_QSTR(MP_QSTR_tanhsinh), MP_ROM_PTR(&integrate_tanhsinh_obj) },
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_ROMBERG
|
||||
{ MP_ROM_QSTR(MP_QSTR_romberg), MP_ROM_PTR(&integrate_romberg_obj) },
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_SIMPSON
|
||||
{ MP_ROM_QSTR(MP_QSTR_simpson), MP_ROM_PTR(&integrate_simpson_obj) },
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_QUAD
|
||||
{ MP_ROM_QSTR(MP_QSTR_quad), MP_ROM_PTR(&integrate_quad_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_integrate_globals, ulab_scipy_integrate_globals_table);
|
||||
|
||||
const mp_obj_module_t ulab_scipy_integrate_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_integrate_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy_dot_integrate, ulab_scipy_integrate_module);
|
||||
#endif
|
||||
|
||||
34
code/scipy/integrate/integrate.h
Normal file
34
code/scipy/integrate/integrate.h
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
* https://github.com/v923z/micropython-ulab
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2024 Harald Milz <hm@seneca.muc.de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _SCIPY_INTEGRATE_
|
||||
#define _SCIPY_INTEGRATE_
|
||||
|
||||
#include "../../ulab_tools.h"
|
||||
|
||||
extern const mp_obj_module_t ulab_scipy_integrate_module;
|
||||
|
||||
#if ULAB_INTEGRATE_HAS_TANHSINH
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_tanhsinh_obj);
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_ROMBERG
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_romberg_obj);
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_SIMPSON
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_simpson_obj);
|
||||
#endif
|
||||
#if ULAB_INTEGRATE_HAS_QUAD
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_quad_obj);
|
||||
#endif
|
||||
|
||||
#endif /* _SCIPY_INTEGRATE_ */
|
||||
|
||||
|
|
@ -50,23 +50,23 @@ static mp_obj_t solve_triangular(size_t n_args, const mp_obj_t *pos_args, mp_map
|
|||
size_t i, j;
|
||||
|
||||
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_lower, MP_ARG_OBJ, { .u_rom_obj = mp_const_false } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE} } ,
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE} } ,
|
||||
{ MP_QSTR_lower, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_TRUE } },
|
||||
};
|
||||
|
||||
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_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("first two arguments must be ndarrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first two arguments must be ndarrays"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *A = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
ndarray_obj_t *b = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
|
||||
if(!ndarray_is_dense(A) || !ndarray_is_dense(b)) {
|
||||
mp_raise_TypeError(translate("input must be a dense ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be a dense ndarray"));
|
||||
}
|
||||
|
||||
size_t A_rows = A->shape[ULAB_MAX_DIMS - 2];
|
||||
|
|
@ -83,7 +83,7 @@ static mp_obj_t solve_triangular(size_t n_args, const mp_obj_t *pos_args, mp_map
|
|||
// check if input matrix A is singular
|
||||
for (i = 0; i < A_rows; i++) {
|
||||
if (MICROPY_FLOAT_C_FUN(fabs)(get_A_ele(A_arr)) < LINALG_EPSILON)
|
||||
mp_raise_ValueError(translate("input matrix is singular"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input matrix is singular"));
|
||||
A_arr += A->strides[ULAB_MAX_DIMS - 2];
|
||||
A_arr += A->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
|
|
@ -161,14 +161,14 @@ MP_DEFINE_CONST_FUN_OBJ_KW(linalg_solve_triangular_obj, 2, solve_triangular);
|
|||
static mp_obj_t cho_solve(mp_obj_t _L, mp_obj_t _b) {
|
||||
|
||||
if(!mp_obj_is_type(_L, &ulab_ndarray_type) || !mp_obj_is_type(_b, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("first two arguments must be ndarrays"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first two arguments must be ndarrays"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *L = MP_OBJ_TO_PTR(_L);
|
||||
ndarray_obj_t *b = MP_OBJ_TO_PTR(_b);
|
||||
|
||||
if(!ndarray_is_dense(L) || !ndarray_is_dense(b)) {
|
||||
mp_raise_TypeError(translate("input must be a dense ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be a dense ndarray"));
|
||||
}
|
||||
|
||||
mp_float_t (*get_L_ele)(void *) = ndarray_get_float_function(L->dtype);
|
||||
|
|
@ -258,22 +258,24 @@ MP_DEFINE_CONST_FUN_OBJ_2(linalg_cho_solve_obj, cho_solve);
|
|||
#endif
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_linalg_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_linalg) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_linalg) },
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_SCIPY_LINALG_HAS_SOLVE_TRIANGULAR
|
||||
{ MP_ROM_QSTR(MP_QSTR_solve_triangular), (mp_obj_t)&linalg_solve_triangular_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_solve_triangular), MP_ROM_PTR(&linalg_solve_triangular_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_LINALG_HAS_CHO_SOLVE
|
||||
{ MP_ROM_QSTR(MP_QSTR_cho_solve), (mp_obj_t)&linalg_cho_solve_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_cho_solve), MP_ROM_PTR(&linalg_cho_solve_obj) },
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_linalg_globals, ulab_scipy_linalg_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_scipy_linalg_module = {
|
||||
const mp_obj_module_t ulab_scipy_linalg_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_linalg_globals,
|
||||
};
|
||||
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy_dot_linalg, ulab_scipy_linalg_module);
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#ifndef _SCIPY_LINALG_
|
||||
#define _SCIPY_LINALG_
|
||||
|
||||
extern mp_obj_module_t ulab_scipy_linalg_module;
|
||||
extern const mp_obj_module_t ulab_scipy_linalg_module;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(linalg_solve_triangular_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_2(linalg_cho_solve_obj);
|
||||
|
|
|
|||
|
|
@ -22,15 +22,15 @@
|
|||
#include "../../ulab_tools.h"
|
||||
#include "optimize.h"
|
||||
|
||||
const mp_obj_float_t xtolerance = {{&mp_type_float}, MICROPY_FLOAT_CONST(2.4e-7)};
|
||||
const mp_obj_float_t rtolerance = {{&mp_type_float}, MICROPY_FLOAT_CONST(0.0)};
|
||||
ULAB_DEFINE_FLOAT_CONST(xtolerance, MICROPY_FLOAT_CONST(2.4e-7), 0x3480d959UL, 0x3e901b2b29a4692bULL);
|
||||
ULAB_DEFINE_FLOAT_CONST(rtolerance, MICROPY_FLOAT_CONST(0.0), 0UL, 0ULL);
|
||||
|
||||
static mp_float_t optimize_python_call(const mp_obj_type_t *type, mp_obj_t fun, mp_float_t x, mp_obj_t *fargs, uint8_t nparams) {
|
||||
// Helper function for calculating the value of f(x, a, b, c, ...),
|
||||
// where f is defined in python. Takes a float, returns a float.
|
||||
// The array of mp_obj_t type must be supplied, as must the number of parameters (a, b, c...) in nparams
|
||||
fargs[0] = mp_obj_new_float(x);
|
||||
return mp_obj_get_float(type->MP_TYPE_CALL(fun, nparams+1, 0, fargs));
|
||||
return mp_obj_get_float(MP_OBJ_TYPE_GET_SLOT(type, call)(fun, nparams+1, 0, fargs));
|
||||
}
|
||||
|
||||
#if ULAB_SCIPY_OPTIMIZE_HAS_BISECT
|
||||
|
|
@ -55,13 +55,13 @@ static mp_float_t optimize_python_call(const mp_obj_type_t *type, mp_obj_t fun,
|
|||
//| ...
|
||||
//|
|
||||
|
||||
STATIC mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// Simple bisection routine
|
||||
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_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_xtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_xtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(xtolerance)} },
|
||||
{ MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 100} },
|
||||
};
|
||||
|
||||
|
|
@ -70,11 +70,11 @@ STATIC mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
|||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(mp_type_get_call_slot(type) == NULL) {
|
||||
mp_raise_TypeError(translate("first argument must be a function"));
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a function"));
|
||||
}
|
||||
mp_float_t xtol = mp_obj_get_float(args[3].u_obj);
|
||||
mp_obj_t *fargs = m_new(mp_obj_t, 1);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t left, right;
|
||||
mp_float_t x_mid;
|
||||
mp_float_t a = mp_obj_get_float(args[1].u_obj);
|
||||
|
|
@ -82,12 +82,12 @@ STATIC mp_obj_t optimize_bisect(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
|||
left = optimize_python_call(type, fun, a, fargs, 0);
|
||||
right = optimize_python_call(type, fun, b, fargs, 0);
|
||||
if(left * right > 0) {
|
||||
mp_raise_ValueError(translate("function has the same sign at the ends of interval"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("function has the same sign at the ends of interval"));
|
||||
}
|
||||
mp_float_t rtb = left < MICROPY_FLOAT_CONST(0.0) ? a : b;
|
||||
mp_float_t dx = left < MICROPY_FLOAT_CONST(0.0) ? b - a : a - b;
|
||||
if(args[4].u_int < 0) {
|
||||
mp_raise_ValueError(translate("maxiter should be > 0"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("maxiter should be > 0"));
|
||||
}
|
||||
for(uint16_t i=0; i < args[4].u_int; i++) {
|
||||
dx *= MICROPY_FLOAT_CONST(0.5);
|
||||
|
|
@ -125,13 +125,13 @@ MP_DEFINE_CONST_FUN_OBJ_KW(optimize_bisect_obj, 3, optimize_bisect);
|
|||
//| ...
|
||||
//|
|
||||
|
||||
STATIC mp_obj_t optimize_fmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static mp_obj_t optimize_fmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
// downhill simplex method in 1D
|
||||
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_xatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} },
|
||||
{ MP_QSTR_fatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_xatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(xtolerance)} },
|
||||
{ MP_QSTR_fatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(xtolerance)} },
|
||||
{ MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 200} },
|
||||
};
|
||||
|
||||
|
|
@ -140,21 +140,21 @@ STATIC mp_obj_t optimize_fmin(size_t n_args, const mp_obj_t *pos_args, mp_map_t
|
|||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(mp_type_get_call_slot(type) == NULL) {
|
||||
mp_raise_TypeError(translate("first argument must be a function"));
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a function"));
|
||||
}
|
||||
|
||||
// parameters controlling convergence conditions
|
||||
mp_float_t xatol = mp_obj_get_float(args[2].u_obj);
|
||||
mp_float_t fatol = mp_obj_get_float(args[3].u_obj);
|
||||
if(args[4].u_int <= 0) {
|
||||
mp_raise_ValueError(translate("maxiter must be > 0"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("maxiter must be > 0"));
|
||||
}
|
||||
uint16_t maxiter = (uint16_t)args[4].u_int;
|
||||
|
||||
mp_float_t x0 = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t x1 = MICROPY_FLOAT_C_FUN(fabs)(x0) > OPTIMIZE_EPSILON ? (MICROPY_FLOAT_CONST(1.0) + OPTIMIZE_NONZDELTA) * x0 : OPTIMIZE_ZDELTA;
|
||||
mp_obj_t *fargs = m_new(mp_obj_t, 1);
|
||||
mp_obj_t fargs[1];
|
||||
mp_float_t f0 = optimize_python_call(type, fun, x0, fargs, 0);
|
||||
mp_float_t f1 = optimize_python_call(type, fun, x1, fargs, 0);
|
||||
if(f1 < f0) {
|
||||
|
|
@ -262,13 +262,13 @@ mp_obj_t optimize_curve_fit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
// Levenberg-Marquardt non-linear fit
|
||||
// The implementation follows the introductory discussion in Mark Tanstrum's paper, https://arxiv.org/abs/1201.5885
|
||||
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_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_p0, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_p0, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_xatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} },
|
||||
{ MP_QSTR_fatol, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_PTR(&xtolerance)} },
|
||||
{ MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none} },
|
||||
{ MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE} },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -276,23 +276,23 @@ mp_obj_t optimize_curve_fit(size_t n_args, const mp_obj_t *pos_args, mp_map_t *k
|
|||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(mp_type_get_call_slot(type) == NULL) {
|
||||
mp_raise_TypeError(translate("first argument must be a function"));
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a function"));
|
||||
}
|
||||
|
||||
mp_obj_t x_obj = args[1].u_obj;
|
||||
mp_obj_t y_obj = args[2].u_obj;
|
||||
mp_obj_t p0_obj = args[3].u_obj;
|
||||
if(!ndarray_object_is_array_like(x_obj) || !ndarray_object_is_array_like(y_obj)) {
|
||||
mp_raise_TypeError(translate("data must be iterable"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("data must be iterable"));
|
||||
}
|
||||
if(!ndarray_object_is_nditerable(p0_obj)) {
|
||||
mp_raise_TypeError(translate("initial values must be iterable"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("initial values must be iterable"));
|
||||
}
|
||||
size_t len = (size_t)mp_obj_get_int(mp_obj_len_maybe(x_obj));
|
||||
uint8_t lenp = (uint8_t)mp_obj_get_int(mp_obj_len_maybe(p0_obj));
|
||||
if(len != (uint16_t)mp_obj_get_int(mp_obj_len_maybe(y_obj))) {
|
||||
mp_raise_ValueError(translate("data must be of equal length"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("data must be of equal length"));
|
||||
}
|
||||
|
||||
mp_float_t *x = m_new(mp_float_t, len);
|
||||
|
|
@ -353,10 +353,10 @@ static mp_obj_t optimize_newton(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
|||
// is not accepted as an argument. The function whose root we want to solve for
|
||||
// must depend on a single variable without parameters, i.e., f(x)
|
||||
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_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&xtolerance) } },
|
||||
{ MP_QSTR_rtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&rtolerance) } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_tol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(xtolerance) } },
|
||||
{ MP_QSTR_rtol, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = ULAB_REFERENCE_FLOAT_CONST(rtolerance) } },
|
||||
{ MP_QSTR_maxiter, MP_ARG_KW_ONLY | MP_ARG_INT, { .u_int = 50 } },
|
||||
};
|
||||
|
||||
|
|
@ -365,17 +365,17 @@ static mp_obj_t optimize_newton(size_t n_args, const mp_obj_t *pos_args, mp_map_
|
|||
|
||||
mp_obj_t fun = args[0].u_obj;
|
||||
const mp_obj_type_t *type = mp_obj_get_type(fun);
|
||||
if(mp_type_get_call_slot(type) == NULL) {
|
||||
mp_raise_TypeError(translate("first argument must be a function"));
|
||||
if(!MP_OBJ_TYPE_HAS_SLOT(type, call)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("first argument must be a function"));
|
||||
}
|
||||
mp_float_t x = mp_obj_get_float(args[1].u_obj);
|
||||
mp_float_t tol = mp_obj_get_float(args[2].u_obj);
|
||||
mp_float_t rtol = mp_obj_get_float(args[3].u_obj);
|
||||
mp_float_t dx, df, fx;
|
||||
dx = x > MICROPY_FLOAT_CONST(0.0) ? OPTIMIZE_EPS * x : -OPTIMIZE_EPS * x;
|
||||
mp_obj_t *fargs = m_new(mp_obj_t, 1);
|
||||
mp_obj_t fargs[1];
|
||||
if(args[4].u_int <= 0) {
|
||||
mp_raise_ValueError(translate("maxiter must be > 0"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("maxiter must be > 0"));
|
||||
}
|
||||
for(uint16_t i=0; i < args[4].u_int; i++) {
|
||||
fx = optimize_python_call(type, fun, x, fargs, 0);
|
||||
|
|
@ -391,24 +391,27 @@ MP_DEFINE_CONST_FUN_OBJ_KW(optimize_newton_obj, 2, optimize_newton);
|
|||
#endif
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_optimize_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_optimize) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_optimize) },
|
||||
#if ULAB_SCIPY_OPTIMIZE_HAS_BISECT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bisect), (mp_obj_t)&optimize_bisect_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_bisect), MP_ROM_PTR(&optimize_bisect_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_OPTIMIZE_HAS_CURVE_FIT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_curve_fit), (mp_obj_t)&optimize_curve_fit_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_curve_fit), MP_ROM_PTR(&optimize_curve_fit_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_OPTIMIZE_HAS_FMIN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_fmin), (mp_obj_t)&optimize_fmin_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_fmin), MP_ROM_PTR(&optimize_fmin_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_OPTIMIZE_HAS_NEWTON
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_newton), (mp_obj_t)&optimize_newton_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_newton), MP_ROM_PTR(&optimize_newton_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_optimize_globals, ulab_scipy_optimize_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_scipy_optimize_module = {
|
||||
const mp_obj_module_t ulab_scipy_optimize_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_optimize_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy_dot_optimize, ulab_scipy_optimize_module);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@
|
|||
#define OPTIMIZE_GAMMA MICROPY_FLOAT_CONST(0.5)
|
||||
#define OPTIMIZE_DELTA MICROPY_FLOAT_CONST(0.5)
|
||||
|
||||
extern mp_obj_module_t ulab_scipy_optimize_module;
|
||||
extern const mp_obj_module_t ulab_scipy_optimize_module;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_bisect_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(optimize_curve_fit_obj);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
|
||||
/*
|
||||
* This file is part of the micropython-ulab project,
|
||||
*
|
||||
|
|
@ -20,6 +19,8 @@
|
|||
#include "signal/signal.h"
|
||||
#include "special/special.h"
|
||||
#include "linalg/linalg.h"
|
||||
#include "integrate/integrate.h"
|
||||
|
||||
|
||||
#if ULAB_HAS_SCIPY
|
||||
|
||||
|
|
@ -27,7 +28,10 @@
|
|||
//|
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_scipy) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_scipy) },
|
||||
#if ULAB_SCIPY_HAS_INTEGRATE_MODULE
|
||||
{ MP_ROM_QSTR(MP_QSTR_integrate), MP_ROM_PTR(&ulab_scipy_integrate_module) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_HAS_LINALG_MODULE
|
||||
{ MP_ROM_QSTR(MP_QSTR_linalg), MP_ROM_PTR(&ulab_scipy_linalg_module) },
|
||||
#endif
|
||||
|
|
@ -44,8 +48,11 @@ static const mp_rom_map_elem_t ulab_scipy_globals_table[] = {
|
|||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_globals, ulab_scipy_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_scipy_module = {
|
||||
const mp_obj_module_t ulab_scipy_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy, ulab_scipy_module);
|
||||
#endif
|
||||
#endif /* ULAB_HAS_SCIPY */
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_scipy_module;
|
||||
extern const mp_obj_module_t ulab_scipy_module;
|
||||
|
||||
#endif /* _SCIPY_ */
|
||||
|
|
|
|||
|
|
@ -18,32 +18,9 @@
|
|||
|
||||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
#include "../../numpy/fft/fft_tools.h"
|
||||
#include "../../numpy/carray/carray_tools.h"
|
||||
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM
|
||||
//| import ulab.numpy
|
||||
//|
|
||||
//| def spectrogram(r: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| :param ulab.numpy.ndarray r: A 1-dimension array of values whose size is a power of 2
|
||||
//|
|
||||
//| Computes the spectrum of the input signal. This is the absolute value of the (complex-valued) fft of the signal.
|
||||
//| This function is similar to scipy's ``scipy.signal.spectrogram``."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t signal_spectrogram(size_t n_args, const mp_obj_t *args) {
|
||||
if(n_args == 2) {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], args[1], FFT_SPECTROGRAM);
|
||||
} else {
|
||||
return fft_fft_ifft_spectrogram(n_args, args[0], mp_const_none, FFT_SPECTROGRAM);
|
||||
}
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(signal_spectrogram_obj, 1, 2, signal_spectrogram);
|
||||
#endif /* ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM */
|
||||
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SOSFILT
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SOSFILT & ULAB_MAX_DIMS > 1
|
||||
static void signal_sosfilt_array(mp_float_t *x, const mp_float_t *coeffs, mp_float_t *zf, const size_t len) {
|
||||
for(size_t i=0; i < len; i++) {
|
||||
mp_float_t xn = *x;
|
||||
|
|
@ -57,17 +34,23 @@ static void signal_sosfilt_array(mp_float_t *x, const mp_float_t *coeffs, mp_flo
|
|||
|
||||
mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_sos, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_zi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_sos, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_zi, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_rom_obj = MP_ROM_NONE } },
|
||||
};
|
||||
|
||||
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(!ndarray_object_is_array_like(args[0].u_obj) || !ndarray_object_is_array_like(args[1].u_obj)) {
|
||||
mp_raise_TypeError(translate("sosfilt requires iterable arguments"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("sosfilt requires iterable arguments"));
|
||||
}
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
COMPLEX_DTYPE_NOT_IMPLEMENTED(ndarray->dtype)
|
||||
}
|
||||
#endif
|
||||
size_t lenx = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[1].u_obj));
|
||||
ndarray_obj_t *y = ndarray_new_linear_array(lenx, NDARRAY_FLOAT);
|
||||
mp_float_t *yarray = (mp_float_t *)y->array;
|
||||
|
|
@ -76,7 +59,7 @@ mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
ndarray_obj_t *inarray = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(inarray->ndim > 1) {
|
||||
mp_raise_ValueError(translate("input must be one-dimensional"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input must be one-dimensional"));
|
||||
}
|
||||
#endif
|
||||
uint8_t *iarray = (uint8_t *)inarray->array;
|
||||
|
|
@ -99,14 +82,14 @@ mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
|
||||
if(args[2].u_obj != mp_const_none) {
|
||||
if(!mp_obj_is_type(args[2].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("zi must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("zi must be an ndarray"));
|
||||
} else {
|
||||
ndarray_obj_t *zi = MP_OBJ_TO_PTR(args[2].u_obj);
|
||||
if((zi->shape[ULAB_MAX_DIMS - 1] != lensos) || (zi->shape[ULAB_MAX_DIMS - 1] != 2)) {
|
||||
mp_raise_ValueError(translate("zi must be of shape (n_section, 2)"));
|
||||
if((zi->shape[ULAB_MAX_DIMS - 2] != lensos) || (zi->shape[ULAB_MAX_DIMS - 1] != 2)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("zi must be of shape (n_section, 2)"));
|
||||
}
|
||||
if(zi->dtype != NDARRAY_FLOAT) {
|
||||
mp_raise_ValueError(translate("zi must be of float type"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("zi must be of float type"));
|
||||
}
|
||||
// TODO: this won't work with sparse arrays
|
||||
memcpy(zf_array, zi->array, 2*lensos*sizeof(mp_float_t));
|
||||
|
|
@ -114,11 +97,11 @@ mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
}
|
||||
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
|
||||
if(mp_obj_get_int(mp_obj_len_maybe(item)) != 6) {
|
||||
mp_raise_ValueError(translate("sos array must be of shape (n_section, 6)"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("sos array must be of shape (n_section, 6)"));
|
||||
} else {
|
||||
fill_array_iterable(coeffs, item);
|
||||
if(coeffs[3] != MICROPY_FLOAT_CONST(1.0)) {
|
||||
mp_raise_ValueError(translate("sos[:, 3] should be all ones"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("sos[:, 3] should be all ones"));
|
||||
}
|
||||
signal_sosfilt_array(yarray, coeffs, zf_array, lenx);
|
||||
zf_array += 2;
|
||||
|
|
@ -130,7 +113,7 @@ mp_obj_t signal_sosfilt(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_ar
|
|||
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
|
||||
tuple->items[0] = MP_OBJ_FROM_PTR(y);
|
||||
tuple->items[1] = MP_OBJ_FROM_PTR(zf);
|
||||
return tuple;
|
||||
return MP_OBJ_FROM_PTR(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -138,18 +121,18 @@ MP_DEFINE_CONST_FUN_OBJ_KW(signal_sosfilt_obj, 2, signal_sosfilt);
|
|||
#endif /* ULAB_SCIPY_SIGNAL_HAS_SOSFILT */
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_signal_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_signal) },
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_spectrogram), (mp_obj_t)&signal_spectrogram_obj },
|
||||
#endif
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SOSFILT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_sosfilt), (mp_obj_t)&signal_sosfilt_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_signal) },
|
||||
#if ULAB_SCIPY_SIGNAL_HAS_SOSFILT & ULAB_MAX_DIMS > 1
|
||||
{ MP_ROM_QSTR(MP_QSTR_sosfilt), MP_ROM_PTR(&signal_sosfilt_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_signal_globals, ulab_scipy_signal_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_scipy_signal_module = {
|
||||
const mp_obj_module_t ulab_scipy_signal_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_signal_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy_dot_signal, ulab_scipy_signal_module);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,9 +16,8 @@
|
|||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_scipy_signal_module;
|
||||
extern const mp_obj_module_t ulab_scipy_signal_module;
|
||||
|
||||
MP_DECLARE_CONST_FUN_OBJ_VAR_BETWEEN(signal_spectrogram_obj);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(signal_sosfilt_obj);
|
||||
|
||||
#endif /* _SCIPY_SIGNAL_ */
|
||||
|
|
|
|||
|
|
@ -19,24 +19,27 @@
|
|||
#include "../../numpy/vector.h"
|
||||
|
||||
static const mp_rom_map_elem_t ulab_scipy_special_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_special) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_special) },
|
||||
#if ULAB_SCIPY_SPECIAL_HAS_ERF
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_erf), (mp_obj_t)&vectorise_erf_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_erf), MP_ROM_PTR(&vector_erf_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_SPECIAL_HAS_ERFC
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_erfc), (mp_obj_t)&vectorise_erfc_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_erfc), MP_ROM_PTR(&vector_erfc_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_SPECIAL_HAS_GAMMA
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gamma), (mp_obj_t)&vectorise_gamma_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_gamma), MP_ROM_PTR(&vector_gamma_obj) },
|
||||
#endif
|
||||
#if ULAB_SCIPY_SPECIAL_HAS_GAMMALN
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_gammaln), (mp_obj_t)&vectorise_lgamma_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_gammaln), MP_ROM_PTR(&vector_lgamma_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_scipy_special_globals, ulab_scipy_special_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_scipy_special_module = {
|
||||
const mp_obj_module_t ulab_scipy_special_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_scipy_special_globals,
|
||||
};
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_scipy_dot_special, ulab_scipy_special_module);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -16,6 +16,6 @@
|
|||
#include "../../ulab.h"
|
||||
#include "../../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_scipy_special_module;
|
||||
extern const mp_obj_module_t ulab_scipy_special_module;
|
||||
|
||||
#endif /* _SCIPY_SPECIAL_ */
|
||||
|
|
|
|||
125
code/ulab.c
125
code/ulab.c
|
|
@ -20,9 +20,9 @@
|
|||
#include "py/objarray.h"
|
||||
|
||||
#include "ulab.h"
|
||||
#include "ulab_create.h"
|
||||
#include "ndarray.h"
|
||||
#include "ndarray_properties.h"
|
||||
#include "numpy/create.h"
|
||||
#include "numpy/ndarray/ndarray_iter.h"
|
||||
|
||||
#include "numpy/numpy.h"
|
||||
|
|
@ -33,15 +33,23 @@
|
|||
#include "user/user.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#define ULAB_VERSION 3.3.7
|
||||
#define ULAB_VERSION 6.9.0
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
#define ULAB_VERSION_STRING xstr(ULAB_VERSION) xstr(-) xstr(ULAB_MAX_DIMS) xstr(D-c)
|
||||
#else
|
||||
#define ULAB_VERSION_STRING xstr(ULAB_VERSION) xstr(-) xstr(ULAB_MAX_DIMS) xstr(D)
|
||||
#endif
|
||||
|
||||
STATIC MP_DEFINE_STR_OBJ(ulab_version_obj, ULAB_VERSION_STRING);
|
||||
static MP_DEFINE_STR_OBJ(ulab_version_obj, ULAB_VERSION_STRING);
|
||||
|
||||
#ifdef ULAB_HASH
|
||||
static MP_DEFINE_STR_OBJ(ulab_sha_obj, xstr(ULAB_HASH));
|
||||
#endif
|
||||
|
||||
STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
|
||||
static const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if NDARRAY_HAS_RESHAPE
|
||||
{ MP_ROM_QSTR(MP_QSTR_reshape), MP_ROM_PTR(&ndarray_reshape_obj) },
|
||||
|
|
@ -62,39 +70,66 @@ STATIC const mp_rom_map_elem_t ulab_ndarray_locals_dict_table[] = {
|
|||
#if NDARRAY_HAS_TOBYTES
|
||||
{ MP_ROM_QSTR(MP_QSTR_tobytes), MP_ROM_PTR(&ndarray_tobytes_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_TOLIST
|
||||
{ MP_ROM_QSTR(MP_QSTR_tolist), MP_ROM_PTR(&ndarray_tolist_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_SORT
|
||||
{ MP_ROM_QSTR(MP_QSTR_sort), MP_ROM_PTR(&numerical_sort_inplace_obj) },
|
||||
#endif
|
||||
#ifdef CIRCUITPY
|
||||
#if NDARRAY_HAS_DTYPE
|
||||
{ MP_ROM_QSTR(MP_QSTR_dtype), MP_ROM_PTR(&ndarray_dtype_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_FLATITER
|
||||
{ MP_ROM_QSTR(MP_QSTR_flat), MP_ROM_PTR(&ndarray_flat_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_ITEMSIZE
|
||||
{ MP_ROM_QSTR(MP_QSTR_itemsize), MP_ROM_PTR(&ndarray_itemsize_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_SHAPE
|
||||
{ MP_ROM_QSTR(MP_QSTR_shape), MP_ROM_PTR(&ndarray_shape_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_SIZE
|
||||
{ MP_ROM_QSTR(MP_QSTR_size), MP_ROM_PTR(&ndarray_size_obj) },
|
||||
#endif
|
||||
#if NDARRAY_HAS_STRIDES
|
||||
{ MP_ROM_QSTR(MP_QSTR_strides), MP_ROM_PTR(&ndarray_strides_obj) },
|
||||
#endif
|
||||
#endif /* CIRCUITPY */
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
|
||||
static MP_DEFINE_CONST_DICT(ulab_ndarray_locals_dict, ulab_ndarray_locals_dict_table);
|
||||
|
||||
#if defined(MP_DEFINE_CONST_OBJ_TYPE)
|
||||
// MicroPython after-b41aaaa (Sept 19 2022).
|
||||
|
||||
#if NDARRAY_IS_SLICEABLE
|
||||
#define NDARRAY_TYPE_SUBSCR subscr, ndarray_subscr,
|
||||
#else
|
||||
#define NDARRAY_TYPE_SUBSCR
|
||||
#endif
|
||||
#if NDARRAY_IS_ITERABLE
|
||||
#define NDARRAY_TYPE_ITER iter, ndarray_getiter,
|
||||
#define NDARRAY_TYPE_ITER_FLAGS MP_TYPE_FLAG_ITER_IS_GETITER
|
||||
#else
|
||||
#define NDARRAY_TYPE_ITER
|
||||
#define NDARRAY_TYPE_ITER_FLAGS 0
|
||||
#endif
|
||||
#if NDARRAY_HAS_UNARY_OPS
|
||||
#define NDARRAY_TYPE_UNARY_OP unary_op, ndarray_unary_op,
|
||||
#else
|
||||
#define NDARRAY_TYPE_UNARY_OP
|
||||
#endif
|
||||
#if NDARRAY_HAS_BINARY_OPS
|
||||
#define NDARRAY_TYPE_BINARY_OP binary_op, ndarray_binary_op,
|
||||
#else
|
||||
#define NDARRAY_TYPE_BINARY_OP
|
||||
#endif
|
||||
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
ulab_ndarray_type,
|
||||
MP_QSTR_ndarray,
|
||||
MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST | NDARRAY_TYPE_ITER_FLAGS,
|
||||
print, ndarray_print,
|
||||
make_new, ndarray_make_new,
|
||||
locals_dict, &ulab_ndarray_locals_dict,
|
||||
NDARRAY_TYPE_SUBSCR
|
||||
NDARRAY_TYPE_ITER
|
||||
NDARRAY_TYPE_UNARY_OP
|
||||
NDARRAY_TYPE_BINARY_OP
|
||||
attr, ndarray_properties_attr,
|
||||
buffer, ndarray_get_buffer
|
||||
);
|
||||
|
||||
#else
|
||||
// CircuitPython and earlier MicroPython revisions.
|
||||
const mp_obj_type_t ulab_ndarray_type = {
|
||||
{ &mp_type_type },
|
||||
.flags = MP_TYPE_FLAG_EXTENDED
|
||||
#if defined(MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE) && defined(MP_TYPE_FLAG_EQ_HAS_NEQ_TEST)
|
||||
| MP_TYPE_FLAG_EQ_CHECKS_OTHER_TYPE | MP_TYPE_FLAG_EQ_HAS_NEQ_TEST,
|
||||
| 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,
|
||||
|
|
@ -112,14 +147,23 @@ const mp_obj_type_t ulab_ndarray_type = {
|
|||
#if NDARRAY_HAS_BINARY_OPS
|
||||
.binary_op = ndarray_binary_op,
|
||||
#endif
|
||||
#ifndef CIRCUITPY
|
||||
.attr = ndarray_properties_attr,
|
||||
#endif
|
||||
.buffer_p = { .get_buffer = ndarray_get_buffer, },
|
||||
)
|
||||
};
|
||||
#endif
|
||||
|
||||
#if ULAB_HAS_DTYPE_OBJECT
|
||||
|
||||
#if defined(MP_DEFINE_CONST_OBJ_TYPE)
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
ulab_dtype_type,
|
||||
MP_QSTR_dtype,
|
||||
MP_TYPE_FLAG_NONE,
|
||||
print, ndarray_dtype_print,
|
||||
make_new, ndarray_dtype_make_new
|
||||
);
|
||||
#else
|
||||
const mp_obj_type_t ulab_dtype_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_dtype,
|
||||
|
|
@ -127,8 +171,17 @@ const mp_obj_type_t ulab_dtype_type = {
|
|||
.make_new = ndarray_dtype_make_new,
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if NDARRAY_HAS_FLATITER
|
||||
#if defined(MP_DEFINE_CONST_OBJ_TYPE)
|
||||
MP_DEFINE_CONST_OBJ_TYPE(
|
||||
ndarray_flatiter_type,
|
||||
MP_QSTR_flatiter,
|
||||
MP_TYPE_FLAG_ITER_IS_GETITER,
|
||||
iter, ndarray_get_flatiterator
|
||||
);
|
||||
#else
|
||||
const mp_obj_type_t ndarray_flatiter_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_flatiter,
|
||||
|
|
@ -137,15 +190,19 @@ const mp_obj_type_t ndarray_flatiter_type = {
|
|||
)
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
STATIC const mp_map_elem_t ulab_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_ulab) },
|
||||
static const mp_rom_map_elem_t ulab_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_ulab) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___version__), MP_ROM_PTR(&ulab_version_obj) },
|
||||
#ifdef ULAB_HASH
|
||||
{ MP_ROM_QSTR(MP_QSTR___sha__), MP_ROM_PTR(&ulab_sha_obj) },
|
||||
#endif
|
||||
#if ULAB_HAS_DTYPE_OBJECT
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dtype), (mp_obj_t)&ulab_dtype_type },
|
||||
{ MP_ROM_QSTR(MP_QSTR_dtype), MP_ROM_PTR(&ulab_dtype_type) },
|
||||
#else
|
||||
#if NDARRAY_HAS_DTYPE
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_dtype), (mp_obj_t)&ndarray_dtype_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_dtype), MP_ROM_PTR(&ndarray_dtype_obj) },
|
||||
#endif /* NDARRAY_HAS_DTYPE */
|
||||
#endif /* ULAB_HAS_DTYPE_OBJECT */
|
||||
{ MP_ROM_QSTR(MP_QSTR_numpy), MP_ROM_PTR(&ulab_numpy_module) },
|
||||
|
|
@ -160,7 +217,7 @@ STATIC const mp_map_elem_t ulab_globals_table[] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT (
|
||||
static MP_DEFINE_CONST_DICT (
|
||||
mp_module_ulab_globals,
|
||||
ulab_globals_table
|
||||
);
|
||||
|
|
@ -174,4 +231,4 @@ const mp_obj_module_t ulab_user_cmodule = {
|
|||
.globals = (mp_obj_dict_t*)&mp_module_ulab_globals,
|
||||
};
|
||||
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule, MODULE_ULAB_ENABLED);
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab, ulab_user_cmodule);
|
||||
|
|
|
|||
200
code/ulab.h
200
code/ulab.h
|
|
@ -6,7 +6,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019-2021 Zoltán Vörös
|
||||
* Copyright (c) 2019-2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef __ULAB__
|
||||
|
|
@ -18,9 +18,9 @@
|
|||
//
|
||||
// - how many dimensions ulab can handle
|
||||
// - which functions are included in the compiled firmware
|
||||
// - whether the python syntax is numpy-like, or modular
|
||||
// - whether arrays can be sliced and iterated over
|
||||
// - which binary/unary operators are supported
|
||||
// - whether ulab can deal with complex numbers
|
||||
//
|
||||
// A considerable amount of flash space can be saved by removing (setting
|
||||
// the corresponding constants to 0) the unnecessary functions and features.
|
||||
|
|
@ -31,6 +31,10 @@
|
|||
#include ULAB_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
// Adds support for complex ndarrays
|
||||
#ifndef ULAB_SUPPORTS_COMPLEX
|
||||
#define ULAB_SUPPORTS_COMPLEX (1)
|
||||
#endif
|
||||
|
||||
// Determines, whether scipy is defined in ulab. The sub-modules and functions
|
||||
// of scipy have to be defined separately
|
||||
|
|
@ -93,10 +97,18 @@
|
|||
#define NDARRAY_HAS_BINARY_OP_ADD (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_AND
|
||||
#define NDARRAY_HAS_BINARY_OP_AND (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_EQUAL
|
||||
#define NDARRAY_HAS_BINARY_OP_EQUAL (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_FLOOR_DIVIDE
|
||||
#define NDARRAY_HAS_BINARY_OP_FLOOR_DIVIDE (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_LESS
|
||||
#define NDARRAY_HAS_BINARY_OP_LESS (1)
|
||||
#endif
|
||||
|
|
@ -105,6 +117,10 @@
|
|||
#define NDARRAY_HAS_BINARY_OP_LESS_EQUAL (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_MODULO
|
||||
#define NDARRAY_HAS_BINARY_OP_MODULO (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_MORE
|
||||
#define NDARRAY_HAS_BINARY_OP_MORE (1)
|
||||
#endif
|
||||
|
|
@ -121,6 +137,10 @@
|
|||
#define NDARRAY_HAS_BINARY_OP_NOT_EQUAL (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_OR
|
||||
#define NDARRAY_HAS_BINARY_OP_OR (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_POWER
|
||||
#define NDARRAY_HAS_BINARY_OP_POWER (1)
|
||||
#endif
|
||||
|
|
@ -133,6 +153,10 @@
|
|||
#define NDARRAY_HAS_BINARY_OP_TRUE_DIVIDE (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_BINARY_OP_XOR
|
||||
#define NDARRAY_HAS_BINARY_OP_XOR (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_INPLACE_OPS
|
||||
#define NDARRAY_HAS_INPLACE_OPS (1)
|
||||
#endif
|
||||
|
|
@ -141,6 +165,10 @@
|
|||
#define NDARRAY_HAS_INPLACE_ADD (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_INPLACE_MODULO
|
||||
#define NDARRAY_HAS_INPLACE_MODU (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_INPLACE_MULTIPLY
|
||||
#define NDARRAY_HAS_INPLACE_MULTIPLY (1)
|
||||
#endif
|
||||
|
|
@ -157,6 +185,27 @@
|
|||
#define NDARRAY_HAS_INPLACE_TRUE_DIVIDE (1)
|
||||
#endif
|
||||
|
||||
// bitwise operators
|
||||
#ifndef ULAB_NUMPY_HAS_BITWISE_AND
|
||||
#define ULAB_NUMPY_HAS_BITWISE_AND (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_BITWISE_OR
|
||||
#define ULAB_NUMPY_HAS_BITWISE_OR (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_BITWISE_XOR
|
||||
#define ULAB_NUMPY_HAS_BITWISE_XOR (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_LEFT_SHIFT
|
||||
#define ULAB_NUMPY_HAS_LEFT_SHIFT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_RIGHT_SHIFT
|
||||
#define ULAB_NUMPY_HAS_RIGHT_SHIFT (1)
|
||||
#endif
|
||||
|
||||
// the ndarray unary operators
|
||||
#ifndef NDARRAY_HAS_UNARY_OPS
|
||||
#define NDARRAY_HAS_UNARY_OPS (1)
|
||||
|
|
@ -204,6 +253,10 @@
|
|||
#define NDARRAY_HAS_ITEMSIZE (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_NDIM
|
||||
#define NDARRAY_HAS_NDIM (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_RESHAPE
|
||||
#define NDARRAY_HAS_RESHAPE (1)
|
||||
#endif
|
||||
|
|
@ -228,6 +281,10 @@
|
|||
#define NDARRAY_HAS_TOBYTES (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_TOLIST
|
||||
#define NDARRAY_HAS_TOLIST (1)
|
||||
#endif
|
||||
|
||||
#ifndef NDARRAY_HAS_TRANSPOSE
|
||||
#define NDARRAY_HAS_TRANSPOSE (1)
|
||||
#endif
|
||||
|
|
@ -341,6 +398,10 @@
|
|||
#define ULAB_NUMPY_HAS_MINIMUM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_NONZERO
|
||||
#define ULAB_NUMPY_HAS_NONZERO (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_NOTEQUAL
|
||||
#define ULAB_NUMPY_HAS_NOTEQUAL (1)
|
||||
#endif
|
||||
|
|
@ -349,6 +410,28 @@
|
|||
#define ULAB_NUMPY_HAS_WHERE (1)
|
||||
#endif
|
||||
|
||||
// the integrate module; functions of the integrate module still have
|
||||
// to be defined separately
|
||||
#ifndef ULAB_SCIPY_HAS_INTEGRATE_MODULE
|
||||
#define ULAB_SCIPY_HAS_INTEGRATE_MODULE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_INTEGRATE_HAS_TANHSINH
|
||||
#define ULAB_INTEGRATE_HAS_TANHSINH (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_INTEGRATE_HAS_ROMBERG
|
||||
#define ULAB_INTEGRATE_HAS_ROMBERG (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_INTEGRATE_HAS_SIMPSON
|
||||
#define ULAB_INTEGRATE_HAS_SIMPSON (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_INTEGRATE_HAS_QUAD
|
||||
#define ULAB_INTEGRATE_HAS_QUAD (1)
|
||||
#endif
|
||||
|
||||
// the linalg module; functions of the linalg module still have
|
||||
// to be defined separately
|
||||
#ifndef ULAB_NUMPY_HAS_LINALG_MODULE
|
||||
|
|
@ -385,6 +468,15 @@
|
|||
#define ULAB_NUMPY_HAS_FFT_MODULE (1)
|
||||
#endif
|
||||
|
||||
// By setting this constant to 1, the FFT routine will behave in a
|
||||
// numpy-compatible way, i.e., it will output a complex array
|
||||
// This setting has no effect, if ULAB_SUPPORTS_COMPLEX is 0
|
||||
// Note that in this case, the input also must be numpythonic,
|
||||
// i.e., the real an imaginary parts cannot be passed as two arguments
|
||||
#ifndef ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
#define ULAB_FFT_IS_NUMPY_COMPATIBLE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_FFT_HAS_FFT
|
||||
#define ULAB_FFT_HAS_FFT (1)
|
||||
#endif
|
||||
|
|
@ -409,6 +501,14 @@
|
|||
#define ULAB_NUMPY_HAS_ARGSORT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_ASARRAY
|
||||
#define ULAB_NUMPY_HAS_ASARRAY (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_COMPRESS
|
||||
#define ULAB_NUMPY_HAS_COMPRESS (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_CONVOLVE
|
||||
#define ULAB_NUMPY_HAS_CONVOLVE (1)
|
||||
#endif
|
||||
|
|
@ -417,6 +517,10 @@
|
|||
#define ULAB_NUMPY_HAS_CROSS (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_DELETE
|
||||
#define ULAB_NUMPY_HAS_DELETE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_DIFF
|
||||
#define ULAB_NUMPY_HAS_DIFF (1)
|
||||
#endif
|
||||
|
|
@ -433,6 +537,14 @@
|
|||
#define ULAB_NUMPY_HAS_INTERP (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_LOAD
|
||||
#define ULAB_NUMPY_HAS_LOAD (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_LOADTXT
|
||||
#define ULAB_NUMPY_HAS_LOADTXT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_MEAN
|
||||
#define ULAB_NUMPY_HAS_MEAN (1)
|
||||
#endif
|
||||
|
|
@ -457,6 +569,18 @@
|
|||
#define ULAB_NUMPY_HAS_ROLL (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SAVE
|
||||
#define ULAB_NUMPY_HAS_SAVE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SAVETXT
|
||||
#define ULAB_NUMPY_HAS_SAVETXT (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SIZE
|
||||
#define ULAB_NUMPY_HAS_SIZE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SORT
|
||||
#define ULAB_NUMPY_HAS_SORT (1)
|
||||
#endif
|
||||
|
|
@ -469,6 +593,10 @@
|
|||
#define ULAB_NUMPY_HAS_SUM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_TAKE
|
||||
#define ULAB_NUMPY_HAS_TAKE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_TRACE
|
||||
#define ULAB_NUMPY_HAS_TRACE (1)
|
||||
#endif
|
||||
|
|
@ -479,6 +607,12 @@
|
|||
|
||||
// vectorised versions of the functions of the math python module, with
|
||||
// the exception of the functions listed in scipy.special
|
||||
|
||||
// if this constant is set, math functions support the out keyword argument
|
||||
#ifndef ULAB_MATH_FUNCTIONS_OUT_KEYWORD
|
||||
#define ULAB_MATH_FUNCTIONS_OUT_KEYWORD (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_ACOS
|
||||
#define ULAB_NUMPY_HAS_ACOS (1)
|
||||
#endif
|
||||
|
|
@ -559,6 +693,10 @@
|
|||
#define ULAB_NUMPY_HAS_SIN (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SINC
|
||||
#define ULAB_NUMPY_HAS_SINC (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SINH
|
||||
#define ULAB_NUMPY_HAS_SINH (1)
|
||||
#endif
|
||||
|
|
@ -579,6 +717,43 @@
|
|||
#define ULAB_NUMPY_HAS_VECTORIZE (1)
|
||||
#endif
|
||||
|
||||
// Complex functions. The implementations are compiled into
|
||||
// the firmware, only if ULAB_SUPPORTS_COMPLEX is set to 1
|
||||
#ifndef ULAB_NUMPY_HAS_CONJUGATE
|
||||
#define ULAB_NUMPY_HAS_CONJUGATE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_IMAG
|
||||
#define ULAB_NUMPY_HAS_IMAG (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_REAL
|
||||
#define ULAB_NUMPY_HAS_REAL (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_HAS_SORT_COMPLEX
|
||||
#define ULAB_NUMPY_HAS_SORT_COMPLEX (1)
|
||||
#endif
|
||||
|
||||
// random module
|
||||
#ifndef ULAB_NUMPY_HAS_RANDOM_MODULE
|
||||
#define ULAB_NUMPY_HAS_RANDOM_MODULE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_RANDOM_HAS_NORMAL
|
||||
#define ULAB_NUMPY_RANDOM_HAS_NORMAL (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_RANDOM_HAS_RANDOM
|
||||
#define ULAB_NUMPY_RANDOM_HAS_RANDOM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_NUMPY_RANDOM_HAS_UNIFORM
|
||||
#define ULAB_NUMPY_RANDOM_HAS_UNIFORM (1)
|
||||
#endif
|
||||
|
||||
|
||||
// scipy modules
|
||||
#ifndef ULAB_SCIPY_HAS_LINALG_MODULE
|
||||
#define ULAB_SCIPY_HAS_LINALG_MODULE (1)
|
||||
#endif
|
||||
|
|
@ -595,10 +770,6 @@
|
|||
#define ULAB_SCIPY_HAS_SIGNAL_MODULE (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM
|
||||
#define ULAB_SCIPY_SIGNAL_HAS_SPECTROGRAM (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_SCIPY_SIGNAL_HAS_SOSFILT
|
||||
#define ULAB_SCIPY_SIGNAL_HAS_SOSFILT (1)
|
||||
#endif
|
||||
|
|
@ -643,12 +814,7 @@
|
|||
#define ULAB_SCIPY_SPECIAL_HAS_GAMMALN (1)
|
||||
#endif
|
||||
|
||||
// user-defined module; source of the module and
|
||||
// its sub-modules should be placed in code/user/
|
||||
#ifndef ULAB_HAS_USER_MODULE
|
||||
#define ULAB_HAS_USER_MODULE (0)
|
||||
#endif
|
||||
|
||||
// functions of the utils module
|
||||
#ifndef ULAB_HAS_UTILS_MODULE
|
||||
#define ULAB_HAS_UTILS_MODULE (1)
|
||||
#endif
|
||||
|
|
@ -669,4 +835,14 @@
|
|||
#define ULAB_UTILS_HAS_FROM_UINT32_BUFFER (1)
|
||||
#endif
|
||||
|
||||
#ifndef ULAB_UTILS_HAS_SPECTROGRAM
|
||||
#define ULAB_UTILS_HAS_SPECTROGRAM (1)
|
||||
#endif
|
||||
|
||||
// user-defined module; source of the module and
|
||||
// its sub-modules should be placed in code/user/
|
||||
#ifndef ULAB_HAS_USER_MODULE
|
||||
#define ULAB_HAS_USER_MODULE (0)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,568 +0,0 @@
|
|||
/*
|
||||
* 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-2021 Zoltán Vörös
|
||||
* 2020 Taku Fukada
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "ulab.h"
|
||||
#include "ulab_create.h"
|
||||
|
||||
#if ULAB_NUMPY_HAS_ONES | ULAB_NUMPY_HAS_ZEROS | ULAB_NUMPY_HAS_FULL | ULAB_NUMPY_HAS_EMPTY
|
||||
static mp_obj_t create_zeros_ones_full(mp_obj_t oshape, uint8_t dtype, mp_obj_t value) {
|
||||
if(!mp_obj_is_int(oshape) && !mp_obj_is_type(oshape, &mp_type_tuple) && !mp_obj_is_type(oshape, &mp_type_list)) {
|
||||
mp_raise_TypeError(translate("input argument must be an integer, a tuple, or a list"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = NULL;
|
||||
if(mp_obj_is_int(oshape)) {
|
||||
size_t n = mp_obj_get_int(oshape);
|
||||
ndarray = ndarray_new_linear_array(n, dtype);
|
||||
} else if(mp_obj_is_type(oshape, &mp_type_tuple) || mp_obj_is_type(oshape, &mp_type_list)) {
|
||||
uint8_t len = (uint8_t)mp_obj_get_int(mp_obj_len_maybe(oshape));
|
||||
if(len > ULAB_MAX_DIMS) {
|
||||
mp_raise_TypeError(translate("too many dimensions"));
|
||||
}
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, ULAB_MAX_DIMS * sizeof(size_t));
|
||||
size_t i = 0;
|
||||
mp_obj_iter_buf_t iter_buf;
|
||||
mp_obj_t item, iterable = mp_getiter(oshape, &iter_buf);
|
||||
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION){
|
||||
shape[ULAB_MAX_DIMS - len + i] = (size_t)mp_obj_get_int(item);
|
||||
i++;
|
||||
}
|
||||
ndarray = ndarray_new_dense_ndarray(len, shape, dtype);
|
||||
}
|
||||
if(value != mp_const_none) {
|
||||
if(dtype == NDARRAY_BOOL) {
|
||||
dtype = NDARRAY_UINT8;
|
||||
if(mp_obj_is_true(value)) {
|
||||
value = mp_obj_new_int(1);
|
||||
} else {
|
||||
value = mp_obj_new_int(0);
|
||||
}
|
||||
}
|
||||
for(size_t i=0; i < ndarray->len; i++) {
|
||||
ndarray_set_value(dtype, ndarray->array, i, value);
|
||||
}
|
||||
}
|
||||
// if zeros calls the function, we don't have to do anything
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ARANGE | ULAB_NUMPY_HAS_LINSPACE
|
||||
static ndarray_obj_t *create_linspace_arange(mp_float_t start, mp_float_t step, size_t len, uint8_t dtype) {
|
||||
mp_float_t value = start;
|
||||
|
||||
ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype);
|
||||
if(ndarray->boolean == NDARRAY_BOOLEAN) {
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
for(size_t i=0; i < len; i++, value += step) {
|
||||
*array++ = value == MICROPY_FLOAT_CONST(0.0) ? 0 : 1;
|
||||
}
|
||||
} else if(dtype == NDARRAY_UINT8) {
|
||||
ARANGE_LOOP(uint8_t, ndarray, len, step);
|
||||
} else if(dtype == NDARRAY_INT8) {
|
||||
ARANGE_LOOP(int8_t, ndarray, len, step);
|
||||
} else if(dtype == NDARRAY_UINT16) {
|
||||
ARANGE_LOOP(uint16_t, ndarray, len, step);
|
||||
} else if(dtype == NDARRAY_INT16) {
|
||||
ARANGE_LOOP(int16_t, ndarray, len, step);
|
||||
} else {
|
||||
ARANGE_LOOP(mp_float_t, ndarray, len, step);
|
||||
}
|
||||
return ndarray;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ARANGE
|
||||
mp_obj_t create_arange(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_OBJ, { .u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_dtype, 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(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
uint8_t dtype = NDARRAY_FLOAT;
|
||||
mp_float_t start, stop, step;
|
||||
if(n_args == 1) {
|
||||
start = 0.0;
|
||||
stop = mp_obj_get_float(args[0].u_obj);
|
||||
step = 1.0;
|
||||
if(mp_obj_is_int(args[0].u_obj)) dtype = NDARRAY_INT16;
|
||||
} else if(n_args == 2) {
|
||||
start = mp_obj_get_float(args[0].u_obj);
|
||||
stop = mp_obj_get_float(args[1].u_obj);
|
||||
step = 1.0;
|
||||
if(mp_obj_is_int(args[0].u_obj) && mp_obj_is_int(args[1].u_obj)) dtype = NDARRAY_INT16;
|
||||
} else if(n_args == 3) {
|
||||
start = mp_obj_get_float(args[0].u_obj);
|
||||
stop = mp_obj_get_float(args[1].u_obj);
|
||||
step = mp_obj_get_float(args[2].u_obj);
|
||||
if(mp_obj_is_int(args[0].u_obj) && mp_obj_is_int(args[1].u_obj) && mp_obj_is_int(args[2].u_obj)) dtype = NDARRAY_INT16;
|
||||
} else {
|
||||
mp_raise_TypeError(translate("wrong number of arguments"));
|
||||
}
|
||||
if((MICROPY_FLOAT_C_FUN(fabs)(stop) > 32768) || (MICROPY_FLOAT_C_FUN(fabs)(start) > 32768) || (MICROPY_FLOAT_C_FUN(fabs)(step) > 32768)) {
|
||||
dtype = NDARRAY_FLOAT;
|
||||
}
|
||||
if(args[3].u_obj != mp_const_none) {
|
||||
dtype = (uint8_t)mp_obj_get_int(args[3].u_obj);
|
||||
}
|
||||
ndarray_obj_t *ndarray;
|
||||
if((stop - start)/step < 0) {
|
||||
ndarray = ndarray_new_linear_array(0, dtype);
|
||||
} else {
|
||||
size_t len = (size_t)(MICROPY_FLOAT_C_FUN(ceil)((stop - start)/step));
|
||||
ndarray = create_linspace_arange(start, step, len, dtype);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_arange_obj, 1, create_arange);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_CONCATENATE
|
||||
mp_obj_t create_concatenate(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_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, &mp_type_tuple)) {
|
||||
mp_raise_TypeError(translate("first argument must be a tuple of ndarrays"));
|
||||
}
|
||||
int8_t axis = (int8_t)args[1].u_int;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
memset(shape, 0, sizeof(size_t)*ULAB_MAX_DIMS);
|
||||
mp_obj_tuple_t *ndarrays = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
||||
// first check, whether the arrays are compatible
|
||||
ndarray_obj_t *_ndarray = MP_OBJ_TO_PTR(ndarrays->items[0]);
|
||||
uint8_t dtype = _ndarray->dtype;
|
||||
uint8_t ndim = _ndarray->ndim;
|
||||
if(axis < 0) {
|
||||
axis += ndim;
|
||||
}
|
||||
if((axis < 0) || (axis >= ndim)) {
|
||||
mp_raise_ValueError(translate("wrong axis specified"));
|
||||
}
|
||||
// shift axis
|
||||
axis = ULAB_MAX_DIMS - ndim + axis;
|
||||
for(uint8_t j=0; j < ULAB_MAX_DIMS; j++) {
|
||||
shape[j] = _ndarray->shape[j];
|
||||
}
|
||||
|
||||
for(uint8_t i=1; i < ndarrays->len; i++) {
|
||||
_ndarray = MP_OBJ_TO_PTR(ndarrays->items[i]);
|
||||
// check, whether the arrays are compatible
|
||||
if((dtype != _ndarray->dtype) || (ndim != _ndarray->ndim)) {
|
||||
mp_raise_ValueError(translate("input arrays are not compatible"));
|
||||
}
|
||||
for(uint8_t j=0; j < ULAB_MAX_DIMS; j++) {
|
||||
if(j == axis) {
|
||||
shape[j] += _ndarray->shape[j];
|
||||
} else {
|
||||
if(shape[j] != _ndarray->shape[j]) {
|
||||
mp_raise_ValueError(translate("input arrays are not compatible"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(ndim, shape, dtype);
|
||||
uint8_t *tpos = (uint8_t *)target->array;
|
||||
uint8_t *tarray;
|
||||
|
||||
for(uint8_t p=0; p < ndarrays->len; p++) {
|
||||
// reset the pointer along the axis
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(ndarrays->items[p]);
|
||||
uint8_t *sarray = (uint8_t *)source->array;
|
||||
tarray = tpos;
|
||||
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
size_t i = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
size_t j = 0;
|
||||
do {
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
size_t k = 0;
|
||||
do {
|
||||
#endif
|
||||
size_t l = 0;
|
||||
do {
|
||||
memcpy(tarray, sarray, source->itemsize);
|
||||
tarray += target->strides[ULAB_MAX_DIMS - 1];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 1];
|
||||
l++;
|
||||
} while(l < source->shape[ULAB_MAX_DIMS - 1]);
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
tarray -= target->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1];
|
||||
tarray += target->strides[ULAB_MAX_DIMS - 2];
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 1] * source->shape[ULAB_MAX_DIMS-1];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 2];
|
||||
k++;
|
||||
} while(k < source->shape[ULAB_MAX_DIMS - 2]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 2
|
||||
tarray -= target->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2];
|
||||
tarray += target->strides[ULAB_MAX_DIMS - 3];
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 2] * source->shape[ULAB_MAX_DIMS-2];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 3];
|
||||
j++;
|
||||
} while(j < source->shape[ULAB_MAX_DIMS - 3]);
|
||||
#endif
|
||||
#if ULAB_MAX_DIMS > 3
|
||||
tarray -= target->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3];
|
||||
tarray += target->strides[ULAB_MAX_DIMS - 4];
|
||||
sarray -= source->strides[ULAB_MAX_DIMS - 3] * source->shape[ULAB_MAX_DIMS-3];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 4];
|
||||
i++;
|
||||
} while(i < source->shape[ULAB_MAX_DIMS - 4]);
|
||||
#endif
|
||||
if(p < ndarrays->len - 1) {
|
||||
tpos += target->strides[axis] * source->shape[axis];
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_concatenate_obj, 1, create_concatenate);
|
||||
#endif
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
#if ULAB_NUMPY_HAS_DIAG
|
||||
mp_obj_t create_diag(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_k, 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("input must be an ndarray"));
|
||||
}
|
||||
ndarray_obj_t *source = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
if(source->ndim == 1) { // return a rank-2 tensor with the prescribed diagonal
|
||||
ndarray_obj_t *target = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, source->len, source->len), source->dtype);
|
||||
uint8_t *sarray = (uint8_t *)source->array;
|
||||
uint8_t *tarray = (uint8_t *)target->array;
|
||||
for(size_t i=0; i < source->len; i++) {
|
||||
memcpy(tarray, sarray, source->itemsize);
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 1];
|
||||
tarray += (source->len + 1) * target->itemsize;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
if(source->ndim > 2) {
|
||||
mp_raise_TypeError(translate("input must be a tensor of rank 2"));
|
||||
}
|
||||
int32_t k = args[1].u_int;
|
||||
size_t len = 0;
|
||||
uint8_t *sarray = (uint8_t *)source->array;
|
||||
if(k < 0) { // move the pointer "vertically"
|
||||
if(-k < (int32_t)source->shape[ULAB_MAX_DIMS - 2]) {
|
||||
sarray -= k * source->strides[ULAB_MAX_DIMS - 2];
|
||||
len = MIN(source->shape[ULAB_MAX_DIMS - 2] + k, source->shape[ULAB_MAX_DIMS - 1]);
|
||||
}
|
||||
} else { // move the pointer "horizontally"
|
||||
if(k < (int32_t)source->shape[ULAB_MAX_DIMS - 1]) {
|
||||
sarray += k * source->strides[ULAB_MAX_DIMS - 1];
|
||||
len = MIN(source->shape[ULAB_MAX_DIMS - 1] - k, source->shape[ULAB_MAX_DIMS - 2]);
|
||||
}
|
||||
}
|
||||
|
||||
if(len == 0) {
|
||||
mp_raise_ValueError(translate("offset is too large"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *target = ndarray_new_linear_array(len, source->dtype);
|
||||
uint8_t *tarray = (uint8_t *)target->array;
|
||||
|
||||
for(size_t i=0; i < len; i++) {
|
||||
memcpy(tarray, sarray, source->itemsize);
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 2];
|
||||
sarray += source->strides[ULAB_MAX_DIMS - 1];
|
||||
tarray += source->itemsize;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(target);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_diag_obj, 1, create_diag);
|
||||
#endif /* ULAB_NUMPY_HAS_DIAG */
|
||||
|
||||
#if ULAB_NUMPY_HAS_EYE
|
||||
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 > 0 ? (size_t)args[2].u_int : (size_t)(-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 = ndarray_new_dense_ndarray(2, ndarray_shape_vector(0, 0, n, m), dtype);
|
||||
if(dtype == NDARRAY_BOOL) {
|
||||
dtype = NDARRAY_UINT8;
|
||||
}
|
||||
mp_obj_t one = mp_obj_new_int(1);
|
||||
size_t i = 0;
|
||||
if((args[2].u_int >= 0)) {
|
||||
while(k < m) {
|
||||
ndarray_set_value(dtype, ndarray->array, i*m+k, one);
|
||||
k++;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
while(k < n) {
|
||||
ndarray_set_value(dtype, ndarray->array, k*m+i, one);
|
||||
k++;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_eye_obj, 1, create_eye);
|
||||
#endif /* ULAB_NUMPY_HAS_EYE */
|
||||
#endif /* ULAB_MAX_DIMS > 1 */
|
||||
|
||||
#if ULAB_NUMPY_HAS_FULL
|
||||
mp_obj_t create_full(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_obj = MP_OBJ_NULL } },
|
||||
{ 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[2].u_int;
|
||||
|
||||
return create_zeros_ones_full(args[0].u_obj, dtype, args[1].u_obj);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_full_obj, 0, create_full);
|
||||
#endif
|
||||
|
||||
|
||||
#if ULAB_NUMPY_HAS_LINSPACE
|
||||
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);
|
||||
|
||||
if(args[2].u_int < 2) {
|
||||
mp_raise_ValueError(translate("number of points must be at least 2"));
|
||||
}
|
||||
size_t len = (size_t)args[2].u_int;
|
||||
mp_float_t start, step;
|
||||
start = 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)-start)/(len-1);
|
||||
else step = (mp_obj_get_float(args[1].u_obj)-start)/len;
|
||||
ndarray_obj_t *ndarray = create_linspace_arange(start, step, len, typecode);
|
||||
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);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_LOGSPACE
|
||||
const mp_obj_float_t create_float_const_ten = {{&mp_type_float}, MICROPY_FLOAT_CONST(10.0)};
|
||||
|
||||
mp_obj_t create_logspace(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_base, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_PTR(&create_float_const_ten) } },
|
||||
{ MP_QSTR_endpoint, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = mp_const_true } },
|
||||
{ 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);
|
||||
|
||||
if(args[2].u_int < 2) {
|
||||
mp_raise_ValueError(translate("number of points must be at least 2"));
|
||||
}
|
||||
size_t len = (size_t)args[2].u_int;
|
||||
mp_float_t start, step, quotient;
|
||||
start = mp_obj_get_float(args[0].u_obj);
|
||||
uint8_t dtype = args[5].u_int;
|
||||
mp_float_t base = mp_obj_get_float(args[3].u_obj);
|
||||
if(args[4].u_obj == mp_const_true) step = (mp_obj_get_float(args[1].u_obj) - start)/(len - 1);
|
||||
else step = (mp_obj_get_float(args[1].u_obj) - start) / len;
|
||||
quotient = MICROPY_FLOAT_C_FUN(pow)(base, step);
|
||||
ndarray_obj_t *ndarray = ndarray_new_linear_array(len, dtype);
|
||||
|
||||
mp_float_t value = MICROPY_FLOAT_C_FUN(pow)(base, start);
|
||||
if(ndarray->dtype == NDARRAY_UINT8) {
|
||||
uint8_t *array = (uint8_t *)ndarray->array;
|
||||
if(ndarray->boolean) {
|
||||
memset(array, 1, len);
|
||||
} else {
|
||||
for(size_t i=0; i < len; i++, value *= quotient) *array++ = (uint8_t)value;
|
||||
}
|
||||
} else if(ndarray->dtype == NDARRAY_INT8) {
|
||||
int8_t *array = (int8_t *)ndarray->array;
|
||||
for(size_t i=0; i < len; i++, value *= quotient) *array++ = (int8_t)value;
|
||||
} else if(ndarray->dtype == NDARRAY_UINT16) {
|
||||
uint16_t *array = (uint16_t *)ndarray->array;
|
||||
for(size_t i=0; i < len; i++, value *= quotient) *array++ = (uint16_t)value;
|
||||
} else if(ndarray->dtype == NDARRAY_INT16) {
|
||||
int16_t *array = (int16_t *)ndarray->array;
|
||||
for(size_t i=0; i < len; i++, value *= quotient) *array++ = (int16_t)value;
|
||||
} else {
|
||||
mp_float_t *array = (mp_float_t *)ndarray->array;
|
||||
for(size_t i=0; i < len; i++, value *= quotient) *array++ = value;
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_logspace_obj, 2, create_logspace);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ONES
|
||||
|
||||
mp_obj_t create_ones(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_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;
|
||||
mp_obj_t one = mp_obj_new_int(1);
|
||||
return create_zeros_ones_full(args[0].u_obj, dtype, one);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_ZEROS
|
||||
|
||||
mp_obj_t create_zeros(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_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;
|
||||
return create_zeros_ones_full(args[0].u_obj, dtype, mp_const_none);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_zeros_obj, 0, create_zeros);
|
||||
#endif
|
||||
|
||||
#if ULAB_NUMPY_HAS_FROMBUFFER
|
||||
mp_obj_t create_frombuffer(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_dtype, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(NDARRAY_FLOAT) } },
|
||||
{ MP_QSTR_count, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(-1) } },
|
||||
{ MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_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);
|
||||
|
||||
uint8_t dtype = mp_obj_get_int(args[1].u_obj);
|
||||
size_t offset = mp_obj_get_int(args[3].u_obj);
|
||||
|
||||
mp_buffer_info_t bufinfo;
|
||||
if(mp_get_buffer(args[0].u_obj, &bufinfo, MP_BUFFER_READ)) {
|
||||
size_t sz = 1;
|
||||
if(dtype != NDARRAY_BOOL) { // mp_binary_get_size doesn't work with Booleans
|
||||
sz = mp_binary_get_size('@', dtype, NULL);
|
||||
}
|
||||
if(bufinfo.len < offset) {
|
||||
mp_raise_ValueError(translate("offset must be non-negative and no greater than buffer length"));
|
||||
}
|
||||
size_t len = (bufinfo.len - offset) / sz;
|
||||
if((len * sz) != (bufinfo.len - offset)) {
|
||||
mp_raise_ValueError(translate("buffer size must be a multiple of element size"));
|
||||
}
|
||||
if(mp_obj_get_int(args[2].u_obj) > 0) {
|
||||
size_t count = mp_obj_get_int(args[2].u_obj);
|
||||
if(len < count) {
|
||||
mp_raise_ValueError(translate("buffer is smaller than requested size"));
|
||||
} else {
|
||||
len = count;
|
||||
}
|
||||
}
|
||||
ndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t);
|
||||
ndarray->base.type = &ulab_ndarray_type;
|
||||
ndarray->dtype = dtype == NDARRAY_BOOL ? NDARRAY_UINT8 : dtype;
|
||||
ndarray->boolean = dtype == NDARRAY_BOOL ? NDARRAY_BOOLEAN : NDARRAY_NUMERIC;
|
||||
ndarray->ndim = 1;
|
||||
ndarray->len = len;
|
||||
ndarray->itemsize = sz;
|
||||
ndarray->shape[ULAB_MAX_DIMS - 1] = len;
|
||||
ndarray->strides[ULAB_MAX_DIMS - 1] = sz;
|
||||
|
||||
uint8_t *buffer = bufinfo.buf;
|
||||
ndarray->array = buffer + offset;
|
||||
return MP_OBJ_FROM_PTR(ndarray);
|
||||
}
|
||||
return mp_const_none;
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(create_frombuffer_obj, 1, create_frombuffer);
|
||||
#endif
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Zoltán Vörös
|
||||
* Copyright (c) 2020-2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -162,48 +162,55 @@ void *ndarray_set_float_function(uint8_t dtype) {
|
|||
}
|
||||
#endif /* NDARRAY_BINARY_USES_FUN_POINTER */
|
||||
|
||||
int8_t tools_get_axis(mp_obj_t axis, uint8_t ndim) {
|
||||
int8_t ax = mp_obj_get_int(axis);
|
||||
if(ax < 0) ax += ndim;
|
||||
if((ax < 0) || (ax > ndim - 1)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("axis is out of bounds"));
|
||||
}
|
||||
return ax;
|
||||
}
|
||||
|
||||
shape_strides tools_reduce_axes(ndarray_obj_t *ndarray, mp_obj_t axis) {
|
||||
// TODO: replace numerical_reduce_axes with this function, wherever applicable
|
||||
// This function should be used, whenever a tensor is contracted;
|
||||
// The shape and strides at `axis` are moved to the zeroth position,
|
||||
// everything else is aligned to the right
|
||||
if(!mp_obj_is_int(axis) & (axis != mp_const_none)) {
|
||||
mp_raise_TypeError(translate("axis must be None, or an integer"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("axis must be None, or an integer"));
|
||||
}
|
||||
shape_strides _shape_strides;
|
||||
|
||||
_shape_strides.increment = 0;
|
||||
// this is the contracted dimension (won't be overwritten for axis == None)
|
||||
_shape_strides.ndim = 0;
|
||||
|
||||
if(axis == mp_const_none) {
|
||||
_shape_strides.shape = ndarray->shape;
|
||||
_shape_strides.strides = ndarray->strides;
|
||||
return _shape_strides;
|
||||
}
|
||||
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS + 1);
|
||||
_shape_strides.shape = shape;
|
||||
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS + 1);
|
||||
_shape_strides.strides = strides;
|
||||
|
||||
_shape_strides.increment = 0;
|
||||
// this is the contracted dimension (won't be overwritten for axis == None)
|
||||
_shape_strides.ndim = 0;
|
||||
|
||||
memcpy(_shape_strides.shape, ndarray->shape, sizeof(size_t) * ULAB_MAX_DIMS);
|
||||
memcpy(_shape_strides.strides, ndarray->strides, sizeof(int32_t) * ULAB_MAX_DIMS);
|
||||
|
||||
if(axis == mp_const_none) {
|
||||
return _shape_strides;
|
||||
}
|
||||
|
||||
uint8_t index = ULAB_MAX_DIMS - 1; // value of index for axis == mp_const_none (won't be overwritten)
|
||||
_shape_strides.axis = ULAB_MAX_DIMS - 1; // value of index for axis == mp_const_none (won't be overwritten)
|
||||
|
||||
if(axis != mp_const_none) { // i.e., axis is an integer
|
||||
int8_t ax = mp_obj_get_int(axis);
|
||||
if(ax < 0) ax += ndarray->ndim;
|
||||
if((ax < 0) || (ax > ndarray->ndim - 1)) {
|
||||
mp_raise_ValueError(translate("index out of range"));
|
||||
}
|
||||
index = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
int8_t ax = tools_get_axis(axis, ndarray->ndim);
|
||||
_shape_strides.axis = ULAB_MAX_DIMS - ndarray->ndim + ax;
|
||||
_shape_strides.ndim = ndarray->ndim - 1;
|
||||
}
|
||||
|
||||
// move the value stored at index to the leftmost position, and align everything else to the right
|
||||
_shape_strides.shape[0] = ndarray->shape[index];
|
||||
_shape_strides.strides[0] = ndarray->strides[index];
|
||||
for(uint8_t i = 0; i < index; i++) {
|
||||
_shape_strides.shape[0] = ndarray->shape[_shape_strides.axis];
|
||||
_shape_strides.strides[0] = ndarray->strides[_shape_strides.axis];
|
||||
for(uint8_t i = 0; i < _shape_strides.axis; i++) {
|
||||
// entries to the right of index must be shifted by one position to the left
|
||||
_shape_strides.shape[i + 1] = ndarray->shape[i];
|
||||
_shape_strides.strides[i + 1] = ndarray->strides[i];
|
||||
|
|
@ -213,21 +220,113 @@ shape_strides tools_reduce_axes(ndarray_obj_t *ndarray, mp_obj_t axis) {
|
|||
_shape_strides.increment = 1;
|
||||
}
|
||||
|
||||
if(_shape_strides.ndim == 0) {
|
||||
_shape_strides.ndim = 1;
|
||||
_shape_strides.shape[ULAB_MAX_DIMS - 1] = 1;
|
||||
_shape_strides.strides[ULAB_MAX_DIMS - 1] = ndarray->itemsize;
|
||||
}
|
||||
|
||||
return _shape_strides;
|
||||
}
|
||||
|
||||
mp_obj_t ulab_tools_restore_dims(ndarray_obj_t *ndarray, ndarray_obj_t *results, mp_obj_t keepdims, shape_strides _shape_strides) {
|
||||
// restores the contracted dimension, if keepdims is True
|
||||
if((ndarray->ndim == 1) && (keepdims != mp_const_true)) {
|
||||
// since the original array has already been contracted and
|
||||
// we don't want to keep the dimensions here, we have to return a scalar
|
||||
return mp_binary_get_val_array(results->dtype, results->array, 0);
|
||||
}
|
||||
|
||||
if(keepdims == mp_const_true) {
|
||||
results->ndim += 1;
|
||||
for(int8_t i = 0; i < ULAB_MAX_DIMS; i++) {
|
||||
results->shape[i] = ndarray->shape[i];
|
||||
}
|
||||
results->shape[_shape_strides.axis] = 1;
|
||||
|
||||
results->strides[ULAB_MAX_DIMS - 1] = ndarray->itemsize;
|
||||
for(uint8_t i = ULAB_MAX_DIMS; i > 1; i--) {
|
||||
results->strides[i - 2] = results->strides[i - 1] * results->shape[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(results);
|
||||
}
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
ndarray_obj_t *tools_object_is_square(mp_obj_t obj) {
|
||||
// Returns an ndarray, if the object is a square ndarray,
|
||||
// raises the appropriate exception otherwise
|
||||
if(!mp_obj_is_type(obj, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("size is defined for ndarrays only"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("size is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(obj);
|
||||
if((ndarray->shape[ULAB_MAX_DIMS - 1] != ndarray->shape[ULAB_MAX_DIMS - 2]) || (ndarray->ndim != 2)) {
|
||||
mp_raise_ValueError(translate("input must be square matrix"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input must be square matrix"));
|
||||
}
|
||||
return ndarray;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint8_t ulab_binary_get_size(uint8_t dtype) {
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(dtype == NDARRAY_COMPLEX) {
|
||||
return 2 * (uint8_t)sizeof(mp_float_t);
|
||||
}
|
||||
#endif
|
||||
return dtype == NDARRAY_BOOL ? 1 : mp_binary_get_size('@', dtype, NULL);
|
||||
}
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
void ulab_rescale_float_strides(int32_t *strides) {
|
||||
// re-scale the strides, so that we can work with floats, when iterating
|
||||
uint8_t sz = sizeof(mp_float_t);
|
||||
for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) {
|
||||
strides[i] /= sz;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ulab_tools_mp_obj_is_scalar(mp_obj_t obj) {
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
if(mp_obj_is_int(obj) || mp_obj_is_float(obj) || mp_obj_is_type(obj, &mp_type_complex)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
if(mp_obj_is_int(obj) || mp_obj_is_float(obj)) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ndarray_obj_t *ulab_tools_inspect_out(mp_obj_t out, uint8_t dtype, uint8_t ndim, size_t *shape, bool dense_only) {
|
||||
if(!mp_obj_is_type(out, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("out has wrong type"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(out);
|
||||
|
||||
if(ndarray->dtype != dtype) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("out array has wrong dtype"));
|
||||
}
|
||||
|
||||
if(ndarray->ndim != ndim) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("out array has wrong dimension"));
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) {
|
||||
if(ndarray->shape[i] != shape[i]) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("out array has wrong shape"));
|
||||
}
|
||||
}
|
||||
|
||||
if(dense_only) {
|
||||
if(!ndarray_is_dense(ndarray)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("output array must be contiguous"));
|
||||
}
|
||||
}
|
||||
return ndarray;
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Zoltán Vörös
|
||||
* Copyright (c) 2020-2022 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#ifndef _TOOLS_
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
typedef struct _shape_strides_t {
|
||||
uint8_t increment;
|
||||
uint8_t axis;
|
||||
uint8_t ndim;
|
||||
size_t *shape;
|
||||
int32_t *strides;
|
||||
|
|
@ -33,5 +34,18 @@ uint8_t ndarray_upcast_dtype(uint8_t , uint8_t );
|
|||
void *ndarray_set_float_function(uint8_t );
|
||||
|
||||
shape_strides tools_reduce_axes(ndarray_obj_t *, mp_obj_t );
|
||||
int8_t tools_get_axis(mp_obj_t , uint8_t );
|
||||
mp_obj_t ulab_tools_restore_dims(ndarray_obj_t * , ndarray_obj_t * , mp_obj_t , shape_strides );
|
||||
ndarray_obj_t *tools_object_is_square(mp_obj_t );
|
||||
|
||||
uint8_t ulab_binary_get_size(uint8_t );
|
||||
|
||||
#if ULAB_SUPPORTS_COMPLEX
|
||||
void ulab_rescale_float_strides(int32_t *);
|
||||
#endif
|
||||
|
||||
bool ulab_tools_mp_obj_is_scalar(mp_obj_t );
|
||||
|
||||
ndarray_obj_t *ulab_tools_inspect_out(mp_obj_t , uint8_t , uint8_t , size_t *, bool );
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -28,13 +28,13 @@ static mp_obj_t user_square(mp_obj_t arg) {
|
|||
|
||||
// raise a TypeError exception, if the input is not an ndarray
|
||||
if(!mp_obj_is_type(arg, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(translate("input must be an ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be an ndarray"));
|
||||
}
|
||||
ndarray_obj_t *ndarray = MP_OBJ_TO_PTR(arg);
|
||||
|
||||
// make sure that the input is a dense array
|
||||
if(!ndarray_is_dense(ndarray)) {
|
||||
mp_raise_TypeError(translate("input must be a dense ndarray"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input must be a dense ndarray"));
|
||||
}
|
||||
|
||||
// if the input is a dense array, create `results` with the same number of
|
||||
|
|
@ -87,9 +87,12 @@ static const mp_rom_map_elem_t ulab_user_globals_table[] = {
|
|||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_user_globals, ulab_user_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_user_module = {
|
||||
const mp_obj_module_t ulab_user_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_user_globals,
|
||||
};
|
||||
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_user, ulab_user_module);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,6 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_user_module;
|
||||
extern const mp_obj_module_t ulab_user_module;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020-2021 Zoltán Vörös
|
||||
* Copyright (c) 2020-2024 Zoltán Vörös
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
|
@ -16,6 +16,9 @@
|
|||
#include "py/misc.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include "../ulab_tools.h"
|
||||
#include "../numpy/fft/fft_tools.h"
|
||||
|
||||
#if ULAB_HAS_UTILS_MODULE
|
||||
|
||||
enum UTILS_BUFFER_TYPE {
|
||||
|
|
@ -28,11 +31,11 @@ enum UTILS_BUFFER_TYPE {
|
|||
#if ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER | ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER
|
||||
static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args, uint8_t buffer_type) {
|
||||
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_ROM_NONE } } ,
|
||||
{ MP_QSTR_count, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(-1) } },
|
||||
{ MP_QSTR_offset, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_INT(0) } },
|
||||
{ MP_QSTR_out, MP_ARG_OBJ, { .u_rom_obj = mp_const_none } },
|
||||
{ MP_QSTR_byteswap, MP_ARG_OBJ, { .u_rom_obj = mp_const_false } },
|
||||
{ MP_QSTR_out, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_byteswap, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_FALSE } },
|
||||
};
|
||||
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
|
|
@ -43,7 +46,7 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a
|
|||
if(args[3].u_obj != mp_const_none) {
|
||||
ndarray = MP_OBJ_TO_PTR(args[3].u_obj);
|
||||
if((ndarray->dtype != NDARRAY_FLOAT) || !ndarray_is_dense(ndarray)) {
|
||||
mp_raise_TypeError(translate("out must be a float dense array"));
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("out must be a float dense array"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +55,7 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a
|
|||
mp_buffer_info_t bufinfo;
|
||||
if(mp_get_buffer(args[0].u_obj, &bufinfo, MP_BUFFER_READ)) {
|
||||
if(bufinfo.len < offset) {
|
||||
mp_raise_ValueError(translate("offset is too large"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("offset is too large"));
|
||||
}
|
||||
uint8_t sz = sizeof(int16_t);
|
||||
#if ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER
|
||||
|
|
@ -63,12 +66,12 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a
|
|||
|
||||
size_t len = (bufinfo.len - offset) / sz;
|
||||
if((len * sz) != (bufinfo.len - offset)) {
|
||||
mp_raise_ValueError(translate("buffer size must be a multiple of element size"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("buffer size must be a multiple of element size"));
|
||||
}
|
||||
if(mp_obj_get_int(args[1].u_obj) > 0) {
|
||||
size_t count = mp_obj_get_int(args[1].u_obj);
|
||||
if(len < count) {
|
||||
mp_raise_ValueError(translate("buffer is smaller than requested size"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("buffer is smaller than requested size"));
|
||||
} else {
|
||||
len = count;
|
||||
}
|
||||
|
|
@ -77,7 +80,7 @@ static mp_obj_t utils_from_intbuffer_helper(size_t n_args, const mp_obj_t *pos_a
|
|||
ndarray = ndarray_new_linear_array(len, NDARRAY_FLOAT);
|
||||
} else {
|
||||
if(ndarray->len < len) {
|
||||
mp_raise_ValueError(translate("out array is too small"));
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("out array is too small"));
|
||||
}
|
||||
}
|
||||
uint8_t *buffer = bufinfo.buf;
|
||||
|
|
@ -187,29 +190,225 @@ static mp_obj_t utils_from_uint32_buffer(size_t n_args, const mp_obj_t *pos_args
|
|||
MP_DEFINE_CONST_FUN_OBJ_KW(utils_from_uint32_buffer_obj, 1, utils_from_uint32_buffer);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#endif /* ULAB_UTILS_HAS_FROM_INT16_BUFFER | ULAB_UTILS_HAS_FROM_UINT16_BUFFER | ULAB_UTILS_HAS_FROM_INT32_BUFFER | ULAB_UTILS_HAS_FROM_UINT32_BUFFER */
|
||||
|
||||
#if ULAB_UTILS_HAS_SPECTROGRAM
|
||||
//| import ulab.numpy
|
||||
//|
|
||||
//| def spectrogram(r: ulab.numpy.ndarray) -> ulab.numpy.ndarray:
|
||||
//| """
|
||||
//| :param ulab.numpy.ndarray r: A 1-dimension array of values whose size is a power of 2
|
||||
//|
|
||||
//| Computes the spectrum of the input signal. This is the absolute value of the (complex-valued) fft of the signal.
|
||||
//| This function is similar to scipy's ``scipy.signal.welch`` https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.welch.html."""
|
||||
//| ...
|
||||
//|
|
||||
|
||||
mp_obj_t utils_spectrogram(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_ROM_NONE }} ,
|
||||
#if !ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
{ MP_QSTR_, MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
#endif
|
||||
{ MP_QSTR_scratchpad, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_out, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_NONE } },
|
||||
{ MP_QSTR_log, MP_ARG_KW_ONLY | MP_ARG_OBJ, { .u_rom_obj = MP_ROM_FALSE } },
|
||||
};
|
||||
|
||||
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_NotImplementedError(MP_ERROR_TEXT("spectrogram is defined for ndarrays only"));
|
||||
}
|
||||
ndarray_obj_t *in = MP_OBJ_TO_PTR(args[0].u_obj);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(in->ndim != 1) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("spectrogram is implemented for 1D arrays only"));
|
||||
}
|
||||
#endif
|
||||
|
||||
size_t len = in->len;
|
||||
// Check if input is of length of power of 2
|
||||
if((len & (len-1)) != 0) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input array length must be power of 2"));
|
||||
}
|
||||
|
||||
ndarray_obj_t *out = NULL;
|
||||
|
||||
#if ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
mp_obj_t scratchpad_object = args[1].u_obj;
|
||||
mp_obj_t out_object = args[2].u_obj;
|
||||
mp_obj_t log_object = args[3].u_obj;
|
||||
#else
|
||||
mp_obj_t scratchpad_object = args[2].u_obj;
|
||||
mp_obj_t out_object = args[3].u_obj;
|
||||
mp_obj_t log_object = args[4].u_obj;
|
||||
#endif
|
||||
|
||||
if(out_object != mp_const_none) {
|
||||
if(!mp_obj_is_type(out_object, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("out must be an ndarray"));
|
||||
}
|
||||
|
||||
out = MP_OBJ_TO_PTR(out_object);
|
||||
if((out->dtype != NDARRAY_FLOAT) || (out->ndim != 1)){
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("out array must be a 1D array of float type"));
|
||||
}
|
||||
if(len != out->len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("input and out arrays must have same length"));
|
||||
}
|
||||
} else {
|
||||
out = ndarray_new_linear_array(len, NDARRAY_FLOAT);
|
||||
}
|
||||
|
||||
ndarray_obj_t *scratchpad = NULL;
|
||||
mp_float_t *tmp = NULL;
|
||||
|
||||
if(scratchpad_object != mp_const_none) {
|
||||
if(!mp_obj_is_type(scratchpad_object, &ulab_ndarray_type)) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("scratchpad must be an ndarray"));
|
||||
}
|
||||
|
||||
scratchpad = MP_OBJ_TO_PTR(scratchpad_object);
|
||||
if(!ndarray_is_dense(scratchpad) || (scratchpad->ndim != 1) || (scratchpad->dtype != NDARRAY_FLOAT)) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("scratchpad must be a 1D dense float array"));
|
||||
}
|
||||
if(scratchpad->len != 2 * len) {
|
||||
mp_raise_ValueError(MP_ERROR_TEXT("scratchpad must be twice as long as input"));
|
||||
}
|
||||
|
||||
tmp = (mp_float_t *)scratchpad->array;
|
||||
} else {
|
||||
tmp = m_new0(mp_float_t, 2 * len);
|
||||
}
|
||||
|
||||
uint8_t *array = (uint8_t *)in->array;
|
||||
|
||||
#if ULAB_FFT_IS_NUMPY_COMPATIBLE & ULAB_SUPPORTS_COMPLEX
|
||||
if(in->dtype == NDARRAY_COMPLEX) {
|
||||
uint8_t sz = 2 * sizeof(mp_float_t);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
memcpy(tmp, array, sz);
|
||||
tmp += 2;
|
||||
array += in->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
} else {
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(in->dtype);
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
*tmp++ = func(array); // real part
|
||||
*tmp++ = 0; // imaginary part, clear
|
||||
array += in->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
}
|
||||
|
||||
tmp -= 2 * len;
|
||||
fft_kernel(tmp, len, 1);
|
||||
#else // we might have two real input vectors
|
||||
|
||||
ndarray_obj_t *in2 = NULL;
|
||||
|
||||
if(n_args == 2) {
|
||||
if(!mp_obj_is_type(args[1].u_obj, &ulab_ndarray_type)) {
|
||||
mp_raise_NotImplementedError(MP_ERROR_TEXT("spectrogram is defined for ndarrays only"));
|
||||
}
|
||||
in2 = MP_OBJ_TO_PTR(args[1].u_obj);
|
||||
|
||||
#if ULAB_MAX_DIMS > 1
|
||||
if(in2->ndim != 1) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("spectrogram is implemented for 1D arrays only"));
|
||||
}
|
||||
#endif
|
||||
if(len != in2->len) {
|
||||
mp_raise_TypeError(MP_ERROR_TEXT("input arrays are not compatible"));
|
||||
}
|
||||
}
|
||||
|
||||
mp_float_t (*func)(void *) = ndarray_get_float_function(in->dtype);
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
*tmp++ = func(array); // real part; imageinary will be cleared later
|
||||
array += in->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
|
||||
if(n_args == 2) {
|
||||
mp_float_t (*func2)(void *) = ndarray_get_float_function(in2->dtype);
|
||||
array = (uint8_t *)in2->array;
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
*tmp++ = func2(array);
|
||||
array += in2->strides[ULAB_MAX_DIMS - 1];
|
||||
}
|
||||
tmp -= len;
|
||||
} else {
|
||||
// if there is only one input argument, clear the imaginary part
|
||||
memset(tmp, 0, len * sizeof(mp_float_t));
|
||||
}
|
||||
|
||||
tmp -= len;
|
||||
|
||||
fft_kernel(tmp, tmp + len, len, 1);
|
||||
#endif /* ULAB_FFT_IS_NUMPY_COMPATIBLE */
|
||||
|
||||
mp_float_t *spectrum = (mp_float_t *)out->array;
|
||||
uint8_t spectrum_sz = out->strides[ULAB_MAX_DIMS - 1] / sizeof(mp_float_t);
|
||||
|
||||
for(size_t i = 0; i < len; i++) {
|
||||
#if ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
*spectrum = MICROPY_FLOAT_C_FUN(sqrt)(*tmp * *tmp + *(tmp + 1) * *(tmp + 1));
|
||||
tmp += 2;
|
||||
#else
|
||||
*spectrum = MICROPY_FLOAT_C_FUN(sqrt)(*tmp * *tmp + *(tmp + len) * *(tmp + len));
|
||||
tmp++;
|
||||
#endif
|
||||
if(log_object == mp_const_true) {
|
||||
*spectrum = MICROPY_FLOAT_C_FUN(log)(*spectrum);
|
||||
}
|
||||
spectrum += spectrum_sz;
|
||||
}
|
||||
|
||||
if(scratchpad_object == mp_const_none) {
|
||||
tmp -= len;
|
||||
#if ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
tmp -= len;
|
||||
#endif
|
||||
m_del(mp_float_t, tmp, 2 * len);
|
||||
}
|
||||
return MP_OBJ_FROM_PTR(out);
|
||||
}
|
||||
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(utils_spectrogram_obj, 1, utils_spectrogram);
|
||||
|
||||
#endif /* ULAB_UTILS_HAS_SPECTROGRAM */
|
||||
|
||||
|
||||
static const mp_rom_map_elem_t ulab_utils_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_utils) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_utils) },
|
||||
#if ULAB_UTILS_HAS_FROM_INT16_BUFFER
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_from_int16_buffer), (mp_obj_t)&utils_from_int16_buffer_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_from_int16_buffer), MP_ROM_PTR(&utils_from_int16_buffer_obj) },
|
||||
#endif
|
||||
#if ULAB_UTILS_HAS_FROM_UINT16_BUFFER
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_from_uint16_buffer), (mp_obj_t)&utils_from_uint16_buffer_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_from_uint16_buffer), MP_ROM_PTR(&utils_from_uint16_buffer_obj) },
|
||||
#endif
|
||||
#if ULAB_UTILS_HAS_FROM_INT32_BUFFER
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_from_int32_buffer), (mp_obj_t)&utils_from_int32_buffer_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_from_int32_buffer), MP_ROM_PTR(&utils_from_int32_buffer_obj) },
|
||||
#endif
|
||||
#if ULAB_UTILS_HAS_FROM_UINT32_BUFFER
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_from_uint32_buffer), (mp_obj_t)&utils_from_uint32_buffer_obj },
|
||||
{ MP_ROM_QSTR(MP_QSTR_from_uint32_buffer), MP_ROM_PTR(&utils_from_uint32_buffer_obj) },
|
||||
#endif
|
||||
#if ULAB_UTILS_HAS_SPECTROGRAM
|
||||
{ MP_ROM_QSTR(MP_QSTR_spectrogram), MP_ROM_PTR(&utils_spectrogram_obj) },
|
||||
#endif
|
||||
};
|
||||
|
||||
static MP_DEFINE_CONST_DICT(mp_module_ulab_utils_globals, ulab_utils_globals_table);
|
||||
|
||||
mp_obj_module_t ulab_utils_module = {
|
||||
const mp_obj_module_t ulab_utils_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&mp_module_ulab_utils_globals,
|
||||
};
|
||||
|
||||
#if CIRCUITPY_ULAB
|
||||
MP_REGISTER_MODULE(MP_QSTR_ulab_dot_utils, ulab_utils_module);
|
||||
#endif
|
||||
|
||||
#endif /* ULAB_HAS_UTILS_MODULE */
|
||||
|
|
|
|||
|
|
@ -14,6 +14,6 @@
|
|||
#include "../ulab.h"
|
||||
#include "../ndarray.h"
|
||||
|
||||
extern mp_obj_module_t ulab_utils_module;
|
||||
extern const mp_obj_module_t ulab_utils_module;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ from sphinx import addnodes
|
|||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'The ulab book'
|
||||
copyright = '2019-2021, Zoltán Vörös and contributors'
|
||||
copyright = '2019-2025, Zoltán Vörös and contributors'
|
||||
author = 'Zoltán Vörös'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '3.3.4'
|
||||
release = '6.9.0'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ Welcome to the ulab book!
|
|||
numpy-universal
|
||||
numpy-fft
|
||||
numpy-linalg
|
||||
numpy-random
|
||||
scipy-integrate
|
||||
scipy-linalg
|
||||
scipy-optimize
|
||||
scipy-signal
|
||||
|
|
|
|||
|
|
@ -74,6 +74,35 @@ parts of the transform separately.
|
|||
|
||||
|
||||
|
||||
ulab with complex support
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the ``ULAB_SUPPORTS_COMPLEX``, and ``ULAB_FFT_IS_NUMPY_COMPATIBLE``
|
||||
pre-processor constants are set to 1 in
|
||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__
|
||||
as
|
||||
|
||||
.. code:: c
|
||||
|
||||
// Adds support for complex ndarrays
|
||||
#ifndef ULAB_SUPPORTS_COMPLEX
|
||||
#define ULAB_SUPPORTS_COMPLEX (1)
|
||||
#endif
|
||||
|
||||
.. code:: c
|
||||
|
||||
#ifndef ULAB_FFT_IS_NUMPY_COMPATIBLE
|
||||
#define ULAB_FFT_IS_NUMPY_COMPATIBLE (1)
|
||||
#endif
|
||||
|
||||
then the FFT routine will behave in a ``numpy``-compatible way: the
|
||||
single input array can either be real, in which case the imaginary part
|
||||
is assumed to be zero, or complex. The output is also complex.
|
||||
|
||||
While ``numpy``-compatibility might be a desired feature, it has one
|
||||
side effect, namely, the FFT routine consumes approx. 50% more RAM. The
|
||||
reason for this lies in the implementation details.
|
||||
|
||||
ifft
|
||||
----
|
||||
|
||||
|
|
@ -115,6 +144,13 @@ Note that unlike in ``numpy``, the length of the array on which the
|
|||
Fourier transform is carried out must be a power of 2. If this is not
|
||||
the case, the function raises a ``ValueError`` exception.
|
||||
|
||||
ulab with complex support
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The ``fft.ifft`` function can also be made ``numpy``-compatible by
|
||||
setting the ``ULAB_SUPPORTS_COMPLEX``, and
|
||||
``ULAB_FFT_IS_NUMPY_COMPATIBLE`` pre-processor constants to 1.
|
||||
|
||||
Computation and storage costs
|
||||
-----------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -3,38 +3,58 @@ Numpy functions
|
|||
===============
|
||||
|
||||
This section of the manual discusses those functions that were adapted
|
||||
from ``numpy``.
|
||||
from ``numpy``. Functions with an asterisk accept complex arrays as
|
||||
arguments, if the firmware was compiled with complex support.
|
||||
|
||||
1. `numpy.all <#all>`__
|
||||
2. `numpy.any <#any>`__
|
||||
1. `numpy.all\* <#all>`__
|
||||
2. `numpy.any\* <#any>`__
|
||||
3. `numpy.argmax <#argmax>`__
|
||||
4. `numpy.argmin <#argmin>`__
|
||||
5. `numpy.argsort <#argsort>`__
|
||||
6. `numpy.clip <#clip>`__
|
||||
7. `numpy.convolve <#convolve>`__
|
||||
8. `numpy.diff <#diff>`__
|
||||
9. `numpy.dot <#dot>`__
|
||||
10. `numpy.equal <#equal>`__
|
||||
11. `numpy.flip <#flip>`__
|
||||
12. `numpy.interp <#interp>`__
|
||||
13. `numpy.isfinite <#isfinite>`__
|
||||
14. `numpy.isinf <#isinf>`__
|
||||
15. `numpy.max <#max>`__
|
||||
16. `numpy.maximum <#maximum>`__
|
||||
17. `numpy.mean <#mean>`__
|
||||
18. `numpy.median <#median>`__
|
||||
19. `numpy.min <#min>`__
|
||||
20. `numpy.minimum <#minimum>`__
|
||||
21. `numpy.not_equal <#equal>`__
|
||||
22. `numpy.polyfit <#polyfit>`__
|
||||
23. `numpy.polyval <#polyval>`__
|
||||
24. `numpy.roll <#roll>`__
|
||||
25. `numpy.sort <#sort>`__
|
||||
26. `numpy.std <#std>`__
|
||||
27. `numpy.sum <#sum>`__
|
||||
28. `numpy.trace <#trace>`__
|
||||
29. `numpy.trapz <#trapz>`__
|
||||
30. `numpy.where <#where>`__
|
||||
6. `numpy.asarray\* <#asarray>`__
|
||||
7. `numpy.bitwise_and <#bitwise_and>`__
|
||||
8. `numpy.bitwise_or <#bitwise_and>`__
|
||||
9. `numpy.bitwise_xor <#bitwise_and>`__
|
||||
10. `numpy.clip <#clip>`__
|
||||
11. `numpy.compress\* <#compress>`__
|
||||
12. `numpy.conjugate\* <#conjugate>`__
|
||||
13. `numpy.convolve\* <#convolve>`__
|
||||
14. `numpy.delete <#delete>`__
|
||||
15. `numpy.diff <#diff>`__
|
||||
16. `numpy.dot <#dot>`__
|
||||
17. `numpy.equal <#equal>`__
|
||||
18. `numpy.flip\* <#flip>`__
|
||||
19. `numpy.imag\* <#imag>`__
|
||||
20. `numpy.interp <#interp>`__
|
||||
21. `numpy.isfinite <#isfinite>`__
|
||||
22. `numpy.isinf <#isinf>`__
|
||||
23. `numpy.left_shift <#left_shift>`__
|
||||
24. `numpy.load <#load>`__
|
||||
25. `numpy.loadtxt <#loadtxt>`__
|
||||
26. `numpy.max <#max>`__
|
||||
27. `numpy.maximum <#maximum>`__
|
||||
28. `numpy.mean <#mean>`__
|
||||
29. `numpy.median <#median>`__
|
||||
30. `numpy.min <#min>`__
|
||||
31. `numpy.minimum <#minimum>`__
|
||||
32. `numpy.nozero <#nonzero>`__
|
||||
33. `numpy.not_equal <#equal>`__
|
||||
34. `numpy.polyfit <#polyfit>`__
|
||||
35. `numpy.polyval <#polyval>`__
|
||||
36. `numpy.real\* <#real>`__
|
||||
37. `numpy.right_shift <#right_shift>`__
|
||||
38. `numpy.roll <#roll>`__
|
||||
39. `numpy.save <#save>`__
|
||||
40. `numpy.savetxt <#savetxt>`__
|
||||
41. `numpy.size <#size>`__
|
||||
42. `numpy.sort <#sort>`__
|
||||
43. `numpy.sort_complex\* <#sort_complex>`__
|
||||
44. `numpy.std <#std>`__
|
||||
45. `numpy.sum <#sum>`__
|
||||
46. `numpy.take\* <#take>`__
|
||||
47. `numpy.trace <#trace>`__
|
||||
48. `numpy.trapz <#trapz>`__
|
||||
49. `numpy.where <#where>`__
|
||||
|
||||
all
|
||||
---
|
||||
|
|
@ -51,6 +71,9 @@ Elements of an array evaluate to ``True``, if they are not equal to
|
|||
zero, or the Boolean ``False``. The return value if a Boolean
|
||||
``ndarray``.
|
||||
|
||||
If the firmware was compiled with complex support, the function can
|
||||
accept complex arrays.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -105,6 +128,9 @@ Elements of an array evaluate to ``True``, if they are not equal to
|
|||
zero, or the Boolean ``False``. The return value if a Boolean
|
||||
``ndarray``.
|
||||
|
||||
If the firmware was compiled with complex support, the function can
|
||||
accept complex arrays.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -256,6 +282,105 @@ example:
|
|||
|
||||
|
||||
|
||||
asarray
|
||||
-------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.asarray.html
|
||||
|
||||
The function takes a single positional argument, and an optional keyword
|
||||
argument, ``dtype``, with a default value of ``None``.
|
||||
|
||||
If the positional argument is an ``ndarray``, and its ``dtypes`` is
|
||||
identical to the value of the keyword argument, or if the keyword
|
||||
argument is ``None``, then the positional argument is simply returned.
|
||||
If the original ``dtype``, and the value of the keyword argument are
|
||||
different, then a copy is returned, with appropriate ``dtype``
|
||||
conversion.
|
||||
|
||||
If the positional argument is an iterable, then the function is simply
|
||||
an alias for ``array``.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(9), dtype=np.uint8)
|
||||
b = np.asarray(a)
|
||||
c = np.asarray(a, dtype=np.int8)
|
||||
print('a:{}'.format(a))
|
||||
print('b:{}'.format(b))
|
||||
print('a == b: {}'.format(a is b))
|
||||
|
||||
print('\nc:{}'.format(c))
|
||||
print('a == c: {}'.format(a is c))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a:array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=uint8)
|
||||
b:array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=uint8)
|
||||
a == b: True
|
||||
|
||||
c:array([0, 1, 2, 3, 4, 5, 6, 7, 8], dtype=int8)
|
||||
a == c: False
|
||||
|
||||
|
||||
|
||||
|
||||
bitwise_and
|
||||
-----------
|
||||
|
||||
``numpy``: https://numpy.org/doc/stable/reference/routines.bitwise.html
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.bitwise_and.html
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.bitwise_or.html
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.bitwise_xor.html
|
||||
|
||||
Each of ``bitwise_and``, ``bitwise_or``, and ``bitwise_xor`` takes two
|
||||
integer-type ``ndarray``\ s as arguments, and returns the element-wise
|
||||
results of the ``AND``, ``OR``, and ``XOR`` operators. Broadcasting is
|
||||
supported. If the ``dtype`` of the input arrays is not an integer, and
|
||||
exception will be raised.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(8), dtype=np.uint8)
|
||||
b = a + 1
|
||||
|
||||
print(a)
|
||||
print(b)
|
||||
print('\nbitwise_and:\n', np.bitwise_and(a, b))
|
||||
print('\nbitwise_or:\n', np.bitwise_or(a, b))
|
||||
print('\nbitwise_xor:\n', np.bitwise_xor(a, b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([0, 1, 2, 3, 4, 5, 6, 7], dtype=uint8)
|
||||
array([1, 2, 3, 4, 5, 6, 7, 8], dtype=uint8)
|
||||
|
||||
bitwise_and:
|
||||
array([0, 0, 2, 0, 4, 4, 6, 0], dtype=uint8)
|
||||
|
||||
bitwise_or:
|
||||
array([1, 3, 3, 7, 5, 7, 7, 15], dtype=uint8)
|
||||
|
||||
bitwise_xor:
|
||||
array([1, 3, 1, 7, 1, 3, 1, 15], dtype=uint8)
|
||||
|
||||
|
||||
|
||||
|
||||
clip
|
||||
----
|
||||
|
||||
|
|
@ -295,6 +420,78 @@ the output is upcast as in `Binary operators <#Binary-operators>`__.
|
|||
|
||||
|
||||
|
||||
compress
|
||||
--------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.compress.html
|
||||
|
||||
The function returns selected slices of an array along given axis. If
|
||||
the axis keyword is ``None``, the flattened array is used.
|
||||
|
||||
If the firmware was compiled with complex support, the function can
|
||||
accept complex arguments.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(6)).reshape((2, 3))
|
||||
|
||||
print('a:\n', a)
|
||||
print('\ncompress(a):\n', np.compress([0, 1], a, axis=0))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a:
|
||||
array([[0.0, 1.0, 2.0],
|
||||
[3.0, 4.0, 5.0]], dtype=float64)
|
||||
|
||||
compress(a):
|
||||
array([[3.0, 4.0, 5.0]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
conjugate
|
||||
---------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.conjugate.html
|
||||
|
||||
If the firmware was compiled with complex support, the function
|
||||
calculates the complex conjugate of the input array. If the input array
|
||||
is of real ``dtype``, then the output is simply a copy, preserving the
|
||||
``dtype``.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3, 4], dtype=np.uint8)
|
||||
b = np.array([1+1j, 2-2j, 3+3j, 4-4j], dtype=np.complex)
|
||||
|
||||
print('a:\t\t', a)
|
||||
print('conjugate(a):\t', np.conjugate(a))
|
||||
print()
|
||||
print('b:\t\t', b)
|
||||
print('conjugate(b):\t', np.conjugate(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 2, 3, 4], dtype=uint8)
|
||||
conjugate(a): array([1, 2, 3, 4], dtype=uint8)
|
||||
|
||||
b: array([1.0+1.0j, 2.0-2.0j, 3.0+3.0j, 4.0-4.0j], dtype=complex)
|
||||
conjugate(b): array([1.0-1.0j, 2.0+2.0j, 3.0-3.0j, 4.0+4.0j], dtype=complex)
|
||||
|
||||
|
||||
|
||||
|
||||
convolve
|
||||
--------
|
||||
|
||||
|
|
@ -307,6 +504,9 @@ Only the ``full`` mode is supported, and the ``mode`` named parameter is
|
|||
not accepted. Note that all other modes can be had by slicing a ``full``
|
||||
result.
|
||||
|
||||
If the firmware was compiled with complex support, the function can
|
||||
accept complex arrays.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -325,6 +525,67 @@ result.
|
|||
|
||||
|
||||
|
||||
delete
|
||||
------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.delete.html
|
||||
|
||||
The function returns a new array with sub-arrays along an axis deleted.
|
||||
It takes two positional arguments, the array, and the indices, which
|
||||
will be removed, as well as the ``axis`` keyword argument with a default
|
||||
value of ``None``. If the ``axis`` is ``None``, the will be flattened
|
||||
first.
|
||||
|
||||
The second positional argument can be a scalar, or any ``micropython``
|
||||
iterable. Since ``range`` can also be passed in place of the indices,
|
||||
slicing can be emulated. If the indices are negative, the elements are
|
||||
counted from the end of the axis.
|
||||
|
||||
Note that the function creates a copy of the indices first, because it
|
||||
is not guaranteed that the indices are ordered. Keep this in mind, when
|
||||
working with large arrays.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(25), dtype=np.uint8).reshape((5,5))
|
||||
print('a:\n', a)
|
||||
print('\naxis = 0\n', np.delete(a, 2, axis=0))
|
||||
print('\naxis = 1\n', np.delete(a, -2, axis=1))
|
||||
print('\naxis = None\n', np.delete(a, [0, 1, 2, 22]))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a:
|
||||
array([[0, 1, 2, 3, 4],
|
||||
[5, 6, 7, 8, 9],
|
||||
[10, 11, 12, 13, 14],
|
||||
[15, 16, 17, 18, 19],
|
||||
[20, 21, 22, 23, 24]], dtype=uint8)
|
||||
|
||||
axis = 0
|
||||
array([[0, 1, 2, 3, 4],
|
||||
[5, 6, 7, 8, 9],
|
||||
[15, 16, 17, 18, 19],
|
||||
[20, 21, 22, 23, 24]], dtype=uint8)
|
||||
|
||||
axis = 1
|
||||
array([[0, 1, 2, 4],
|
||||
[5, 6, 7, 9],
|
||||
[10, 11, 12, 14],
|
||||
[15, 16, 17, 19],
|
||||
[20, 21, 22, 24]], dtype=uint8)
|
||||
|
||||
axis = None
|
||||
array([3, 4, 5, ..., 21, 23, 24], dtype=uint8)
|
||||
|
||||
|
||||
|
||||
|
||||
diff
|
||||
----
|
||||
|
||||
|
|
@ -544,6 +805,9 @@ along the given axis. If the keyword argument is ``None``, the matrix’
|
|||
entries are flipped along all axes. ``flip`` returns a new copy of the
|
||||
array.
|
||||
|
||||
If the firmware was compiled with complex support, the function can
|
||||
accept complex arrays.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -580,6 +844,41 @@ array.
|
|||
|
||||
|
||||
|
||||
imag
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.imag.html
|
||||
|
||||
The ``imag`` function returns the imaginary part of an array, or scalar.
|
||||
It cannot accept a generic iterable as its argument. The function is
|
||||
defined only, if the firmware was compiled with complex support.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3], dtype=np.uint16)
|
||||
print("a:\t\t", a)
|
||||
print("imag(a):\t", np.imag(a))
|
||||
|
||||
b = np.array([1, 2+1j, 3-1j], dtype=np.complex)
|
||||
print("\nb:\t\t", b)
|
||||
print("imag(b):\t", np.imag(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 2, 3], dtype=uint16)
|
||||
imag(a): array([0, 0, 0], dtype=uint16)
|
||||
|
||||
b: array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)
|
||||
imag(b): array([0.0, 1.0, -1.0], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
interp
|
||||
------
|
||||
|
||||
|
|
@ -746,6 +1045,160 @@ positions, where the input is infinite. Integer types return the
|
|||
|
||||
|
||||
|
||||
left_shift
|
||||
----------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.left_shift.html
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.right_shift.html
|
||||
|
||||
``left_shift``, and ``right_shift`` both take two integer-type
|
||||
``ndarray``\ s, and bit-wise shift the elements of the first array by an
|
||||
amount given by the second array to the left, and right, respectively.
|
||||
Broadcasting is supported. If the ``dtype`` of the input arrays is not
|
||||
an integer, and exception will be raised.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.ones(7, dtype=np.uint8)
|
||||
b = np.zeros(7, dtype=np.uint8) + 255
|
||||
c = np.array(range(7), dtype=np.uint8) + 1
|
||||
|
||||
print('a: ', a)
|
||||
print('b: ', b)
|
||||
print('c: ', c)
|
||||
print('\na left shifted by c:\n', np.left_shift(a, c))
|
||||
print('\nb right shifted by c:\n', np.right_shift(b, c))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 1, 1, 1, 1, 1, 1], dtype=uint8)
|
||||
b: array([255, 255, 255, 255, 255, 255, 255], dtype=uint8)
|
||||
c: array([1, 2, 3, 4, 5, 6, 7], dtype=uint8)
|
||||
|
||||
a left shifted by c:
|
||||
array([2, 4, 8, 16, 32, 64, 128], dtype=uint8)
|
||||
|
||||
b right shifted by c:
|
||||
array([127, 63, 31, 15, 7, 3, 1], dtype=uint8)
|
||||
|
||||
|
||||
|
||||
|
||||
load
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.load.html
|
||||
|
||||
The function reads data from a file in ``numpy``\ ’s
|
||||
`platform-independent
|
||||
format <https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html#module-numpy.lib.format>`__,
|
||||
and returns the generated array. If the endianness of the data in the
|
||||
file and the microcontroller differ, the bytes are automatically
|
||||
swapped.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.load('a.npy')
|
||||
print(a)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([[0.0, 1.0, 2.0, 3.0, 4.0],
|
||||
[5.0, 6.0, 7.0, 8.0, 9.0],
|
||||
[10.0, 11.0, 12.0, 13.0, 14.0],
|
||||
[15.0, 16.0, 17.0, 18.0, 19.0],
|
||||
[20.0, 21.0, 22.0, 23.0, 24.0]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
loadtxt
|
||||
-------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.loadtxt.html
|
||||
|
||||
The function reads data from a text file, and returns the generated
|
||||
array. It takes a file name as the single positional argument, and the
|
||||
following keyword arguments:
|
||||
|
||||
1. ``comments='#'``
|
||||
2. ``dtype=float``
|
||||
3. ``delimiter=','``
|
||||
4. ``max_rows`` (with a default of all rows)
|
||||
5. ``skip_rows=0``
|
||||
6. ``usecols`` (with a default of all columns)
|
||||
|
||||
If ``dtype`` is supplied and is not ``float``, the data entries will be
|
||||
converted to the appropriate integer type by rounding the values.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
print('read all data')
|
||||
print(np.loadtxt('loadtxt.dat'))
|
||||
|
||||
print('\nread maximum 5 rows (first row is a comment line)')
|
||||
print(np.loadtxt('loadtxt.dat', max_rows=5))
|
||||
|
||||
print('\nread maximum 5 rows, convert dtype (first row is a comment line)')
|
||||
print(np.loadtxt('loadtxt.dat', max_rows=5, dtype=np.uint8))
|
||||
|
||||
print('\nskip the first 3 rows, convert dtype (first row is a comment line)')
|
||||
print(np.loadtxt('loadtxt.dat', skiprows=3, dtype=np.uint8))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
read all data
|
||||
array([[0.0, 1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0, 7.0],
|
||||
[8.0, 9.0, 10.0, 11.0],
|
||||
[12.0, 13.0, 14.0, 15.0],
|
||||
[16.0, 17.0, 18.0, 19.0],
|
||||
[20.0, 21.0, 22.0, 23.0],
|
||||
[24.0, 25.0, 26.0, 27.0],
|
||||
[28.00000000000001, 29.0, 30.0, 31.0],
|
||||
[32.0, 33.0, 34.00000000000001, 35.0]], dtype=float64)
|
||||
|
||||
read maximum 5 rows (first row is a comment line)
|
||||
array([[0.0, 1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0, 7.0],
|
||||
[8.0, 9.0, 10.0, 11.0],
|
||||
[12.0, 13.0, 14.0, 15.0]], dtype=float64)
|
||||
|
||||
read maximum 5 rows, convert dtype (first row is a comment line)
|
||||
array([[0, 1, 2, 3],
|
||||
[4, 5, 6, 7],
|
||||
[8, 9, 10, 11],
|
||||
[12, 13, 14, 15]], dtype=uint8)
|
||||
|
||||
skip the first 3 rows, convert dtype (first row is a comment line)
|
||||
array([[8, 9, 10, 11],
|
||||
[12, 13, 14, 15],
|
||||
[16, 17, 18, 19],
|
||||
[20, 21, 22, 23],
|
||||
[24, 25, 26, 27],
|
||||
[28, 29, 30, 31],
|
||||
[32, 33, 34, 35]], dtype=uint8)
|
||||
|
||||
|
||||
|
||||
|
||||
mean
|
||||
----
|
||||
|
||||
|
|
@ -941,6 +1394,46 @@ implemented.
|
|||
|
||||
|
||||
|
||||
nonzero
|
||||
-------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.nonzero.html
|
||||
|
||||
``nonzero`` returns the indices of the elements of an array that are not
|
||||
zero. If the number of dimensions of the array is larger than one, a
|
||||
tuple of arrays is returned, one for each dimension, containing the
|
||||
indices of the non-zero elements in that dimension.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(9)) - 5
|
||||
print('a:\n', a)
|
||||
print(np.nonzero(a))
|
||||
|
||||
a = a.reshape((3,3))
|
||||
print('\na:\n', a)
|
||||
print(np.nonzero(a))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a:
|
||||
array([-5.0, -4.0, -3.0, -2.0, -1.0, 0.0, 1.0, 2.0, 3.0], dtype=float64)
|
||||
(array([0, 1, 2, 3, 4, 6, 7, 8], dtype=uint16),)
|
||||
|
||||
a:
|
||||
array([[-5.0, -4.0, -3.0],
|
||||
[-2.0, -1.0, 0.0],
|
||||
[1.0, 2.0, 3.0]], dtype=float64)
|
||||
(array([0, 0, 0, 1, 1, 2, 2, 2], dtype=uint16), array([0, 1, 2, 0, 1, 0, 1, 2], dtype=uint16))
|
||||
|
||||
|
||||
|
||||
|
||||
not_equal
|
||||
---------
|
||||
|
||||
|
|
@ -952,11 +1445,12 @@ polyfit
|
|||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.polyfit.html
|
||||
|
||||
polyfit takes two, or three arguments. The last one is the degree of the
|
||||
polynomial that will be fitted, the last but one is an array or iterable
|
||||
with the ``y`` (dependent) values, and the first one, an array or
|
||||
iterable with the ``x`` (independent) values, can be dropped. If that is
|
||||
the case, ``x`` will be generated in the function as ``range(len(y))``.
|
||||
``polyfit`` takes two, or three arguments. The last one is the degree of
|
||||
the polynomial that will be fitted, the last but one is an array or
|
||||
iterable with the ``y`` (dependent) values, and the first one, an array
|
||||
or iterable with the ``x`` (independent) values, can be dropped. If that
|
||||
is the case, ``x`` will be generated in the function as
|
||||
``range(len(y))``.
|
||||
|
||||
If the lengths of ``x``, and ``y`` are not the same, the function raises
|
||||
a ``ValueError``.
|
||||
|
|
@ -1059,6 +1553,41 @@ iterables returning scalars.
|
|||
|
||||
|
||||
|
||||
real
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.real.html
|
||||
|
||||
The ``real`` function returns the real part of an array, or scalar. It
|
||||
cannot accept a generic iterable as its argument. The function is
|
||||
defined only, if the firmware was compiled with complex support.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3], dtype=np.uint16)
|
||||
print("a:\t\t", a)
|
||||
print("real(a):\t", np.real(a))
|
||||
|
||||
b = np.array([1, 2+1j, 3-1j], dtype=np.complex)
|
||||
print("\nb:\t\t", b)
|
||||
print("real(b):\t", np.real(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 2, 3], dtype=uint16)
|
||||
real(a): array([1, 2, 3], dtype=uint16)
|
||||
|
||||
b: array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)
|
||||
real(b): array([1.0, 2.0, 3.0], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
roll
|
||||
----
|
||||
|
||||
|
|
@ -1159,6 +1688,108 @@ Vertical rolls require two internal copies of single columns.
|
|||
|
||||
|
||||
|
||||
save
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.save.html
|
||||
|
||||
With the help of this function, numerical array can be saved in
|
||||
``numpy``\ ’s `platform-independent
|
||||
format <https://numpy.org/doc/stable/reference/generated/numpy.lib.format.html#module-numpy.lib.format>`__.
|
||||
|
||||
The function takes two positional arguments, the name of the output
|
||||
file, and the array.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in CPython
|
||||
|
||||
a = np.array(range(25)).reshape((5, 5))
|
||||
np.save('a.npy', a)
|
||||
savetxt
|
||||
-------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.savetxt.html
|
||||
|
||||
With the help of this function, numerical array can be saved in a text
|
||||
file. The function takes two positional arguments, the name of the
|
||||
output file, and the array, and also implements the ``comments='#'``
|
||||
``delimiter=' '``, the ``header=''``, and ``footer=''`` keyword
|
||||
arguments. The input is treated as of type ``float``, i.e., the output
|
||||
is always in the floating point representation.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(12), dtype=np.uint8).reshape((3, 4))
|
||||
np.savetxt('savetxt.dat', a)
|
||||
|
||||
with open('savetxt.dat', 'r') as fin:
|
||||
print(fin.read())
|
||||
|
||||
np.savetxt('savetxt.dat', a,
|
||||
comments='!',
|
||||
delimiter=';',
|
||||
header='col1;col2;col3;col4',
|
||||
footer='saved data')
|
||||
|
||||
with open('savetxt.dat', 'r') as fin:
|
||||
print(fin.read())
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
0.000000000000000 1.000000000000000 2.000000000000000 3.000000000000000
|
||||
4.000000000000000 5.000000000000000 6.000000000000000 7.000000000000000
|
||||
8.000000000000000 9.000000000000000 10.000000000000000 11.000000000000000
|
||||
|
||||
!col1;col2;col3;col4
|
||||
0.000000000000000;1.000000000000000;2.000000000000000;3.000000000000000
|
||||
4.000000000000000;5.000000000000000;6.000000000000000;7.000000000000000
|
||||
8.000000000000000;9.000000000000000;10.000000000000000;11.000000000000000
|
||||
!saved data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
size
|
||||
----
|
||||
|
||||
The function takes a single positional argument, and an optional keyword
|
||||
argument, ``axis``, with a default value of ``None``, and returns the
|
||||
size of an array along that axis. If ``axis`` is ``None``, the total
|
||||
length of the array (the product of the elements of its shape) is
|
||||
returned.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.ones((2, 3))
|
||||
|
||||
print(a)
|
||||
print('size(a, axis=0): ', np.size(a, axis=0))
|
||||
print('size(a, axis=1): ', np.size(a, axis=1))
|
||||
print('size(a, axis=None): ', np.size(a, axis=None))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([[1.0, 1.0, 1.0],
|
||||
[1.0, 1.0, 1.0]], dtype=float64)
|
||||
size(a, axis=0): 2
|
||||
size(a, axis=1): 3
|
||||
size(a, axis=None): 6
|
||||
|
||||
|
||||
|
||||
|
||||
sort
|
||||
----
|
||||
|
||||
|
|
@ -1237,18 +1868,53 @@ spaced numbers between 0, and two pi, and sort them:
|
|||
|
||||
# code to be run in micropython
|
||||
|
||||
import ulab as np
|
||||
from ulab import vector
|
||||
from ulab import numerical
|
||||
from ulab import numpy as np
|
||||
|
||||
@timeit
|
||||
def sort_time(array):
|
||||
return numerical.sort(array)
|
||||
return nup.sort(array)
|
||||
|
||||
b = vector.sin(np.linspace(0, 6.28, num=1000))
|
||||
b = np.sin(np.linspace(0, 6.28, num=1000))
|
||||
print('b: ', b)
|
||||
sort_time(b)
|
||||
print('\nb sorted:\n', b)
|
||||
sort_complex
|
||||
------------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.sort_complex.html
|
||||
|
||||
If the firmware was compiled with complex support, the functions sorts
|
||||
the input array first according to its real part, and then the imaginary
|
||||
part. The input must be a one-dimensional array. The output is always of
|
||||
``dtype`` complex, even if the input was real integer.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([5, 4, 3, 2, 1], dtype=np.int16)
|
||||
print('a:\t\t\t', a)
|
||||
print('sort_complex(a):\t', np.sort_complex(a))
|
||||
print()
|
||||
|
||||
b = np.array([5, 4+3j, 4-2j, 0, 1j], dtype=np.complex)
|
||||
print('b:\t\t\t', b)
|
||||
print('sort_complex(b):\t', np.sort_complex(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([5, 4, 3, 2, 1], dtype=int16)
|
||||
sort_complex(a): array([1.0+0.0j, 2.0+0.0j, 3.0+0.0j, 4.0+0.0j, 5.0+0.0j], dtype=complex)
|
||||
|
||||
b: array([5.0+0.0j, 4.0+3.0j, 4.0-2.0j, 0.0+0.0j, 0.0+1.0j], dtype=complex)
|
||||
sort_complex(b): array([0.0+0.0j, 0.0+1.0j, 4.0-2.0j, 4.0+3.0j, 5.0+0.0j], dtype=complex)
|
||||
|
||||
|
||||
|
||||
|
||||
std
|
||||
---
|
||||
|
||||
|
|
@ -1320,6 +1986,66 @@ array. Otherwise, the calculation is along the given axis.
|
|||
|
||||
|
||||
|
||||
take
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.take.html
|
||||
|
||||
The ``take`` method takes elements from an array along an axis. The
|
||||
function accepts two positional arguments, the array, and the indices,
|
||||
which is either a ``python`` iterable, or a one-dimensional ``ndarray``,
|
||||
as well as three keyword arguments, the ``axis``, which can be ``None``,
|
||||
or an integer, ``out``, which can be ``None``, or an ``ndarray`` with
|
||||
the proper dimensions, and ``mode``, which can be one of the strings
|
||||
``raise``, ``wrap``, or ``clip``. This last argument determines how
|
||||
out-of-bounds indices will be treated. The default value is ``raise``,
|
||||
which raises an exception. ``wrap`` takes the indices modulo the length
|
||||
of the ``axis``, while ``clip`` pegs the values at the 0, and the length
|
||||
of the ``axis``. If ``axis`` is ``None``, then ``take`` operates on the
|
||||
flattened array.
|
||||
|
||||
The function can be regarded as a method of advanced slicing: as opposed
|
||||
to standard slicing, where the indices are distributed uniformly and in
|
||||
either increasing or decreasing order, ``take`` can take indices in an
|
||||
arbitrary order.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(12)).reshape((3, 4))
|
||||
print('\na:', a)
|
||||
|
||||
print('\nslices taken along first axis')
|
||||
print(np.take(a, (0, 2, 2, 1), axis=0))
|
||||
|
||||
print('\nslices taken along second axis')
|
||||
print(np.take(a, (0, 2, 2, 1), axis=1))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
||||
a: array([[0.0, 1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0, 7.0],
|
||||
[8.0, 9.0, 10.0, 11.0]], dtype=float64)
|
||||
|
||||
slices taken along first axis
|
||||
array([[0.0, 1.0, 2.0, 3.0],
|
||||
[8.0, 9.0, 10.0, 11.0],
|
||||
[8.0, 9.0, 10.0, 11.0],
|
||||
[4.0, 5.0, 6.0, 7.0]], dtype=float64)
|
||||
|
||||
slices taken along second axis
|
||||
array([[0.0, 2.0, 2.0, 1.0],
|
||||
[2.0, 3.0, 4.0, 5.0],
|
||||
[6.0, 7.0, 8.0, 9.0]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
trace
|
||||
-----
|
||||
|
||||
|
|
|
|||
183
docs/manual/source/numpy-random.rst
Normal file
183
docs/manual/source/numpy-random.rst
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
|
||||
numpy.random
|
||||
============
|
||||
|
||||
Random numbers drawn specific distributions can be generated by
|
||||
instantiating a ``Generator`` object, and calling its methods. The
|
||||
module defines the following three functions:
|
||||
|
||||
1. `numpy.random.Generator.normal <#normal>`__
|
||||
2. `numpy.random.Generator.random <#random>`__
|
||||
3. `numpy.random.Generator.uniform <#uniform>`__
|
||||
|
||||
The ``Generator`` object, when instantiated, takes a single integer as
|
||||
its argument. This integer is the seed, which will be fed to the 32-bit
|
||||
or 64-bit routine. More details can be found under
|
||||
https://www.pcg-random.org/index.html. The generator is a standard
|
||||
``python`` object that keeps track of its state.
|
||||
|
||||
``numpy``: https://numpy.org/doc/stable/reference/random/index.html
|
||||
|
||||
normal
|
||||
------
|
||||
|
||||
A random set of number from the ``normal`` distribution can be generated
|
||||
by calling the generator’s ``normal`` method. The method takes three
|
||||
optional arguments, ``loc=0.0``, the centre of the distribution,
|
||||
``scale=1.0``, the width of the distribution, and ``size=None``, a tuple
|
||||
containing the shape of the returned array. In case ``size`` is
|
||||
``None``, a single floating point number is returned.
|
||||
|
||||
The ``normal`` method of the ``Generator`` object is based on the
|
||||
`Box-Muller
|
||||
transform <https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform>`__.
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.normal.html
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
rng = np.random.Generator(123456)
|
||||
print(rng)
|
||||
|
||||
# return single number from a distribution of scale 1, and location 0
|
||||
print(rng.normal())
|
||||
|
||||
print(rng.normal(loc=20.0, scale=10.0, size=(3,3)))
|
||||
# same as above, with positional arguments
|
||||
print(rng.normal(20.0, 10.0, (3,3)))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
Gnerator() at 0x7fa9dae05340
|
||||
-6.285246229407202
|
||||
array([[24.95816273705659, 15.2670302229426, 14.81001577336041],
|
||||
[20.17589833056986, 23.14539083787544, 26.37772041367461],
|
||||
[41.94894234387275, 37.11027030608206, 25.65889562100477]], dtype=float64)
|
||||
array([[21.52562779033434, 12.74685887865834, 24.08404670765186],
|
||||
[4.728112596365396, 7.667757906857082, 21.61576094228444],
|
||||
[2.432338873595267, 27.75945683572574, 5.730827584659245]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
random
|
||||
------
|
||||
|
||||
A random set of number from the uniform distribution in the interval [0,
|
||||
1] can be generated by calling the generator’s ``random`` method. The
|
||||
method takes two optional arguments, ``size=None``, a tuple containing
|
||||
the shape of the returned array, and ``out``. In case ``size`` is
|
||||
``None``, a single floating point number is returned.
|
||||
|
||||
``out`` can be used, if a floating point array is available. An
|
||||
exception will be raised, if the array is not of ``float`` ``dtype``, or
|
||||
if both ``size`` and ``out`` are supplied, and there is a conflict in
|
||||
their shapes.
|
||||
|
||||
If ``size`` is ``None``, a single floating point number will be
|
||||
returned.
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.random.html
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
rng = np.random.Generator(123456)
|
||||
print(rng)
|
||||
|
||||
# returning new objects
|
||||
print(rng.random())
|
||||
print('\n', rng.random(size=(3,3)))
|
||||
|
||||
# supplying a buffer
|
||||
a = np.array(range(9), dtype=np.float).reshape((3,3))
|
||||
print('\nbuffer array before:\n', a)
|
||||
rng.random(out=a)
|
||||
print('\nbuffer array after:\n', a)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
Gnerator() at 0x7f299de05340
|
||||
6.384615058863119e-11
|
||||
|
||||
array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],
|
||||
[0.8738606263361598, 0.4946080034142021, 0.7765890156101152],
|
||||
[0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)
|
||||
|
||||
buffer array before:
|
||||
array([[0.0, 1.0, 2.0],
|
||||
[3.0, 4.0, 5.0],
|
||||
[6.0, 7.0, 8.0]], dtype=float64)
|
||||
|
||||
buffer array after:
|
||||
array([[0.8508024287393201, 0.9848489829156055, 0.7598167589604003],
|
||||
[0.782995698302952, 0.2866337782847831, 0.7915884498022229],
|
||||
[0.4614071706315902, 0.4792657443088592, 0.1581582066230718]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
uniform
|
||||
-------
|
||||
|
||||
``uniform`` is similar to ``random``, except that the interval over
|
||||
which the numbers are distributed can be specified, while the ``out``
|
||||
argument cannot. In addition to ``size`` specifying the shape of the
|
||||
output, ``low=0.0``, and ``high=1.0`` are accepted arguments. With the
|
||||
indicated defaults, ``uniform`` is identical to ``random``, which can be
|
||||
seen from the fact that the first 3-by-3 tensor below is the same as the
|
||||
one produced by ``rng.random(size=(3,3))`` above.
|
||||
|
||||
If ``size`` is ``None``, a single floating point number will be
|
||||
returned.
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.uniform.html
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
rng = np.random.Generator(123456)
|
||||
print(rng)
|
||||
|
||||
print(rng.uniform())
|
||||
# returning numbers between 0, and 1
|
||||
print('\n', rng.uniform(size=(3,3)))
|
||||
|
||||
# returning numbers between 10, and 20
|
||||
print('\n', rng.uniform(low=10, high=20, size=(3,3)))
|
||||
|
||||
# same as above, without the keywords
|
||||
print('\n', rng.uniform(10, 20, (3,3)))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
Gnerator() at 0x7f1891205340
|
||||
6.384615058863119e-11
|
||||
|
||||
array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],
|
||||
[0.8738606263361598, 0.4946080034142021, 0.7765890156101152],
|
||||
[0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)
|
||||
|
||||
array([[18.5080242873932, 19.84848982915605, 17.598167589604],
|
||||
[17.82995698302952, 12.86633778284783, 17.91588449802223],
|
||||
[14.6140717063159, 14.79265744308859, 11.58158206623072]], dtype=float64)
|
||||
|
||||
array([[14.3380400319162, 12.72487657409978, 15.77119643621117],
|
||||
[13.61835831436355, 18.96062889255558, 15.78847796795966],
|
||||
[12.59435855187034, 17.68262037443622, 14.77943040598734]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
|
@ -6,19 +6,31 @@ Standard mathematical functions can be calculated on any scalar,
|
|||
scalar-valued iterable (ranges, lists, tuples containing numbers), and
|
||||
on ``ndarray``\ s without having to change the call signature. In all
|
||||
cases the functions return a new ``ndarray`` of typecode ``float``
|
||||
(since these functions usually generate float values, anyway). The
|
||||
functions execute faster with ``ndarray`` arguments than with iterables,
|
||||
because the values of the input vector can be extracted faster.
|
||||
(since these functions usually generate float values, anyway). The only
|
||||
exceptions to this rule are the ``exp``, and ``sqrt`` functions, which,
|
||||
if ``ULAB_SUPPORTS_COMPLEX`` is set to 1 in
|
||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__,
|
||||
can return complex arrays, depending on the argument. All functions
|
||||
execute faster with ``ndarray`` arguments than with iterables, because
|
||||
the values of the input vector can be extracted faster.
|
||||
|
||||
At present, the following functions are supported:
|
||||
At present, the following functions are supported (starred functions can
|
||||
operate on, or can return complex arrays):
|
||||
|
||||
``acos``, ``acosh``, ``arctan2``, ``around``, ``asin``, ``asinh``,
|
||||
``atan``, ``arctan2``, ``atanh``, ``ceil``, ``cos``, ``degrees``,
|
||||
``exp``, ``expm1``, ``floor``, ``log``, ``log10``, ``log2``,
|
||||
``radians``, ``sin``, ``sinh``, ``sqrt``, ``tan``, ``tanh``.
|
||||
``exp*``, ``expm1``, ``floor``, ``log``, ``log10``, ``log2``,
|
||||
``radians``, ``sin``, ``sinc``, ``sinh``, ``sqrt*``, ``tan``, ``tanh``.
|
||||
|
||||
These functions are applied element-wise to the arguments, thus, e.g.,
|
||||
the exponential of a matrix cannot be calculated in this way.
|
||||
the exponential of a matrix cannot be calculated in this way, only the
|
||||
exponential of the matrix entries.
|
||||
|
||||
In order to avoid repeated memory allocations, functions can take the
|
||||
``out=None`` optional argument, which must be a floating point
|
||||
``ndarray`` of the same size as the input ``array``. If these conditions
|
||||
are not fulfilled, and exception will be raised. If ``out=None``, a new
|
||||
array will be created upon each invocation of the function.
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
@ -42,6 +54,13 @@ the exponential of a matrix cannot be calculated in this way.
|
|||
print('\n=============\nc:\n', c)
|
||||
print('exp(c):\n', np.exp(c))
|
||||
|
||||
# using the `out` argument
|
||||
d = np.array(range(9)).reshape((3, 3))
|
||||
|
||||
print('\nd before invoking the function:\n', d)
|
||||
np.exp(c, out=d)
|
||||
print('\nd afteri nvoking the function:\n', d)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: range(0, 9)
|
||||
|
|
@ -63,6 +82,16 @@ the exponential of a matrix cannot be calculated in this way.
|
|||
[20.08553692318767, 54.59815003314424, 148.4131591025766],
|
||||
[403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)
|
||||
|
||||
d before invoking the function:
|
||||
array([[0.0, 1.0, 2.0],
|
||||
[3.0, 4.0, 5.0],
|
||||
[6.0, 7.0, 8.0]], dtype=float64)
|
||||
|
||||
d afteri nvoking the function:
|
||||
array([[1.0, 2.718281828459045, 7.38905609893065],
|
||||
[20.08553692318767, 54.59815003314424, 148.4131591025766],
|
||||
[403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -199,6 +228,71 @@ returns an ndarray of type ``mp_float_t``.
|
|||
|
||||
|
||||
|
||||
exp
|
||||
---
|
||||
|
||||
If ``ULAB_SUPPORTS_COMPLEX`` is set to 1 in
|
||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__,
|
||||
the exponential function can also take complex arrays as its argument,
|
||||
in which case the return value is also complex.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3])
|
||||
print('a:\t\t', a)
|
||||
print('exp(a):\t\t', np.exp(a))
|
||||
print()
|
||||
|
||||
b = np.array([1+1j, 2+2j, 3+3j], dtype=np.complex)
|
||||
print('b:\t\t', b)
|
||||
print('exp(b):\t\t', np.exp(b))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1.0, 2.0, 3.0], dtype=float64)
|
||||
exp(a): array([2.718281828459045, 7.38905609893065, 20.08553692318767], dtype=float64)
|
||||
|
||||
b: array([1.0+1.0j, 2.0+2.0j, 3.0+3.0j], dtype=complex)
|
||||
exp(b): array([1.468693939915885+2.287355287178842j, -3.074932320639359+6.71884969742825j, -19.88453084414699+2.834471132487004j], dtype=complex)
|
||||
|
||||
|
||||
|
||||
|
||||
sqrt
|
||||
----
|
||||
|
||||
If ``ULAB_SUPPORTS_COMPLEX`` is set to 1 in
|
||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__,
|
||||
the exponential function can also take complex arrays as its argument,
|
||||
in which case the return value is also complex. If the input is real,
|
||||
but the results might be complex, the user is supposed to specify the
|
||||
output ``dtype`` in the function call. Otherwise, the square roots of
|
||||
negative numbers will result in ``NaN``.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, -1])
|
||||
print('a:\t\t', a)
|
||||
print('sqrt(a):\t\t', np.sqrt(a))
|
||||
print('sqrt(a):\t\t', np.sqrt(a, dtype=np.complex))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1.0, -1.0], dtype=float64)
|
||||
sqrt(a): array([1.0, nan], dtype=float64)
|
||||
sqrt(a): array([1.0+0.0j, 0.0+1.0j], dtype=complex)
|
||||
|
||||
|
||||
|
||||
|
||||
Vectorising generic python functions
|
||||
------------------------------------
|
||||
|
||||
|
|
|
|||
220
docs/manual/source/scipy-integrate.rst
Normal file
220
docs/manual/source/scipy-integrate.rst
Normal file
|
|
@ -0,0 +1,220 @@
|
|||
|
||||
scipy.integrate
|
||||
===============
|
||||
|
||||
This module provides a simplified subset of CPython’s
|
||||
``scipy.integrate`` module. The algorithms were not ported from
|
||||
CPython’s ``scipy.integrate`` for the sake of resource usage, but
|
||||
derived from a paper found in https://www.genivia.com/qthsh.html. There
|
||||
are four numerical integration algorithms:
|
||||
|
||||
1. `scipy.integrate.quad <#quad>`__
|
||||
2. `scipy.integrate.romberg <#romberg>`__
|
||||
3. `scipy.integrate.simpson <#simpson>`__
|
||||
4. `scipy.integrate.tanhsinh <#tanhsinh>`__
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Numerical integration works best with float64 math enabled. If you
|
||||
require float64 math, be sure to set ``MICROPY_OBJ_REPR_A`` and
|
||||
``MICROPY_FLOAT_IMPL_DOUBLE``. This being said, the modules work equally
|
||||
well using float32, albeit with reduced precision. The required error
|
||||
tolerance can be specified for each of the function calls using the
|
||||
“eps=” option, defaulting to the compiled in ``etolerance`` value (1e-14
|
||||
for fp64, 1e-8 for fp32).
|
||||
|
||||
The submodule can be enabled by setting
|
||||
``ULAB_SCIPY_HAS_INTEGRATE_MODULE`` in ``code/ulab.h``. As for the
|
||||
individual integration algorithms, you can select which to include by
|
||||
setting one or more of ``ULAB_INTEGRATE_HAS_QUAD``,
|
||||
``ULAB_INTEGRATE_HAS_ROMBERG``, ``ULAB_INTEGRATE_HAS_SIMPSON``, and
|
||||
``ULAB_INTEGRATE_HAS_TANHSINH``.
|
||||
|
||||
Also note that these algorithms do not support complex numbers, although
|
||||
it is certainly possible to implement complex integration in MicroPython
|
||||
on top of this module, e.g. as in
|
||||
https://stackoverflow.com/questions/5965583/use-scipy-integrate-quad-to-integrate-complex-numbers.
|
||||
|
||||
quad
|
||||
----
|
||||
|
||||
``scipy``:
|
||||
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html
|
||||
|
||||
In CPython ``scipy.integrate``, ``quad`` is a wrapper implementing many
|
||||
algorithms based on the Fortran QUADPACK package. Gauss-Kronrod is just
|
||||
one of them, and it is useful for most general-purpose tasks. This
|
||||
particular function implements an Adaptive Gauss-Kronrod (G10,K21)
|
||||
quadrature algorithm. The Gauss–Kronrod quadrature formula is a variant
|
||||
of Gaussian quadrature, in which the evaluation points are chosen so
|
||||
that an accurate approximation can be computed by re-using the
|
||||
information produced by the computation of a less accurate approximation
|
||||
(https://en.wikipedia.org/wiki/Gauss%E2%80%93Kronrod_quadrature_formula).
|
||||
|
||||
The function takes three to five arguments:
|
||||
|
||||
- f, a callable,
|
||||
- a and b, the lower and upper integration limit,
|
||||
- order=, the order of integration (default 5),
|
||||
- eps=, the error tolerance (default etolerance)
|
||||
|
||||
The function returns the result and the error estimate as a tuple of
|
||||
floats.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import scipy
|
||||
|
||||
f = lambda x: x**2 + 2*x + 1
|
||||
result = scipy.integrate.quad(f, 0, 5, order=5, eps=1e-10)
|
||||
print (f"result = {result}")
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
UsageError: Cell magic `%%micropython` not found.
|
||||
|
||||
|
||||
romberg
|
||||
-------
|
||||
|
||||
``scipy``:
|
||||
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.romberg.html
|
||||
|
||||
This function implements the Romberg quadrature algorithm. Romberg’s
|
||||
method is a Newton–Cotes formula – it evaluates the integrand at equally
|
||||
spaced points. The integrand must have continuous derivatives, though
|
||||
fairly good results may be obtained if only a few derivatives exist. If
|
||||
it is possible to evaluate the integrand at unequally spaced points,
|
||||
then other methods such as Gaussian quadrature and Clenshaw–Curtis
|
||||
quadrature are generally more accurate
|
||||
(https://en.wikipedia.org/wiki/Romberg%27s_method).
|
||||
|
||||
Please note: This function is deprecated as of SciPy 1.12.0 and will be
|
||||
removed in SciPy 1.15.0. Please use ``scipy.integrate.quad`` instead.
|
||||
|
||||
The function takes three to five arguments:
|
||||
|
||||
- f, a callable,
|
||||
- a and b, the lower and upper integration limit,
|
||||
- steps=, the number of steps taken to calculate (default 100),
|
||||
- eps=, the error tolerance (default etolerance)
|
||||
|
||||
The function returns the result as a float.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import scipy
|
||||
|
||||
f = lambda x: x**2 + 2*x + 1
|
||||
result = scipy.integrate.romberg(f, 0, 5)
|
||||
print (f"result = {result}")
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
UsageError: Cell magic `%%micropython` not found.
|
||||
|
||||
|
||||
simpson
|
||||
-------
|
||||
|
||||
``scipy``:
|
||||
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.simpson.html
|
||||
|
||||
This function is different from CPython’s ``simpson`` method in that it
|
||||
does not take an array of function values but determines the optimal
|
||||
spacing of samples itself. Adaptive Simpson’s method, also called
|
||||
adaptive Simpson’s rule, is a method of numerical integration proposed
|
||||
by G.F. Kuncir in 1962. It is probably the first recursive adaptive
|
||||
algorithm for numerical integration to appear in print, although more
|
||||
modern adaptive methods based on Gauss–Kronrod quadrature and
|
||||
Clenshaw–Curtis quadrature are now generally preferred
|
||||
(https://en.wikipedia.org/wiki/Adaptive_Simpson%27s_method).
|
||||
|
||||
The function takes three to five arguments:
|
||||
|
||||
- f, a callable,
|
||||
- a and b, the lower and upper integration limit,
|
||||
- steps=, the number of steps taken to calculate (default 100),
|
||||
- eps=, the error tolerance (default etolerance)
|
||||
|
||||
The function returns the result as a float.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import scipy
|
||||
|
||||
f = lambda x: x**2 + 2*x + 1
|
||||
result = scipy.integrate.simpson(f, 0, 5)
|
||||
print (f"result = {result}")
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
UsageError: Cell magic `%%micropython` not found.
|
||||
|
||||
|
||||
tanhsinh
|
||||
--------
|
||||
|
||||
``scipy``:
|
||||
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html
|
||||
|
||||
In CPython ``scipy.integrate``, ``tanhsinh`` is written in Python
|
||||
(https://github.com/scipy/scipy/blob/main/scipy/integrate/\_tanhsinh.py).
|
||||
It is used in cases where Newton-Cotes, Gauss-Kronrod, and other
|
||||
formulae do not work due to properties of the integrand or the
|
||||
integration limits. (In SciPy v1.14.1, it is not a public function but
|
||||
it has been marked as public in SciPy v1.15.0rc1).
|
||||
|
||||
This particular function implements an optimized Tanh-Sinh, Sinh-Sinh
|
||||
and Exp-Sinh quadrature algorithm. It is especially applied where
|
||||
singularities or infinite derivatives exist at one or both endpoints.
|
||||
The method uses hyperbolic functions in a change of variables to
|
||||
transform an integral on the interval x ∈ (−1, 1) to an integral on the
|
||||
entire real line t ∈ (−∞, ∞), the two integrals having the same value.
|
||||
After this transformation, the integrand decays with a double
|
||||
exponential rate, and thus, this method is also known as the double
|
||||
exponential (DE) formula
|
||||
(https://en.wikipedia.org/wiki/Tanh-sinh_quadrature).
|
||||
|
||||
As opposed to the three algorithms mentioned before, it also supports
|
||||
integrals with infinite limits like the Gaussian integral
|
||||
(https://en.wikipedia.org/wiki/Gaussian_integral), as shown below.
|
||||
|
||||
The function takes three to five arguments:
|
||||
|
||||
- f, a callable,
|
||||
- a and b, the lower and upper integration limit,
|
||||
- levels=, the number of loops taken to calculate (default 6),
|
||||
- eps=, the error tolerance (default: etolerance)
|
||||
|
||||
The function returns the result and the error estimate as a tuple of
|
||||
floats.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import scipy, numpy as np
|
||||
from math import *
|
||||
f = lambda x: exp(- x**2)
|
||||
result = scipy.integrate.tanhsinh(f, -np.inf, np.inf)
|
||||
print (f"result = {result}")
|
||||
exact = sqrt(pi) # which is the exact value
|
||||
print (f"exact value = {exact}")
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
UsageError: Cell magic `%%micropython` not found.
|
||||
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in CPython
|
||||
|
||||
|
|
@ -2,11 +2,9 @@
|
|||
scipy.signal
|
||||
============
|
||||
|
||||
Functions in the ``signal`` module can be called by prepending them by
|
||||
``scipy.signal.``. The module defines the following two functions:
|
||||
This module defines the single function:
|
||||
|
||||
1. `scipy.signal.sosfilt <#sosfilt>`__
|
||||
2. `scipy.signal.spectrogram <#spectrogram>`__
|
||||
|
||||
sosfilt
|
||||
-------
|
||||
|
|
@ -69,67 +67,3 @@ initial values are assumed to be 0.
|
|||
|
||||
|
||||
|
||||
|
||||
spectrogram
|
||||
-----------
|
||||
|
||||
In addition to the Fourier transform and its inverse, ``ulab`` also
|
||||
sports a function called ``spectrogram``, which returns the absolute
|
||||
value of the Fourier transform. This could be used to find the dominant
|
||||
spectral component in a time series. The arguments are treated in the
|
||||
same way as in ``fft``, and ``ifft``.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
from ulab import scipy as spy
|
||||
|
||||
x = np.linspace(0, 10, num=1024)
|
||||
y = np.sin(x)
|
||||
|
||||
a = spy.signal.spectrogram(y)
|
||||
|
||||
print('original vector:\t', y)
|
||||
print('\nspectrum:\t', a)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
original vector: array([0.0, 0.009775015390171337, 0.01954909674625918, ..., -0.5275140569487312, -0.5357931822978732, -0.5440211108893639], dtype=float64)
|
||||
|
||||
spectrum: array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
As such, ``spectrogram`` is really just a shorthand for
|
||||
``np.sqrt(a*a + b*b)``:
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
from ulab import scipy as spy
|
||||
|
||||
x = np.linspace(0, 10, num=1024)
|
||||
y = np.sin(x)
|
||||
|
||||
a, b = np.fft.fft(y)
|
||||
|
||||
print('\nspectrum calculated the hard way:\t', np.sqrt(a*a + b*b))
|
||||
|
||||
a = spy.signal.spectrogram(y)
|
||||
|
||||
print('\nspectrum calculated the lazy way:\t', a)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
||||
spectrum calculated the hard way: array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)
|
||||
|
||||
spectrum calculated the lazy way: array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,9 +8,10 @@ Enter ulab
|
|||
``ulab`` is a ``numpy``-like module for ``micropython`` and its
|
||||
derivatives, meant to simplify and speed up common mathematical
|
||||
operations on arrays. ``ulab`` implements a small subset of ``numpy``
|
||||
and ``scipy``. The functions were chosen such that they might be useful
|
||||
in the context of a microcontroller. However, the project is a living
|
||||
one, and suggestions for new features are always welcome.
|
||||
and ``scipy``, as well as a number of functions manipulating byte
|
||||
arrays. The functions were chosen such that they might be useful in the
|
||||
context of a microcontroller. However, the project is a living one, and
|
||||
suggestions for new features are always welcome.
|
||||
|
||||
This document discusses how you can use the library, starting from
|
||||
building your own firmware, through questions like what affects the
|
||||
|
|
@ -93,14 +94,15 @@ The main points of ``ulab`` are
|
|||
- fast Fourier transforms
|
||||
- filtering of data (convolution and second-order filters)
|
||||
- function minimisation, fitting, and numerical approximation routines
|
||||
- interfacing between numerical data and peripheral hardware devices
|
||||
|
||||
``ulab`` implements close to a hundred functions and array methods. At
|
||||
the time of writing this manual (for version 2.1.0), the library adds
|
||||
the time of writing this manual (for version 4.0.0), the library adds
|
||||
approximately 120 kB of extra compiled code to the ``micropython``
|
||||
(pyboard.v.11) firmware. However, if you are tight with flash space, you
|
||||
can easily shave tens of kB off the firmware. In fact, if only a small
|
||||
sub-set of functions are needed, you can get away with less than 10 kB
|
||||
of flash space. See the section on `customising
|
||||
(pyboard.v.1.17) firmware. However, if you are tight with flash space,
|
||||
you can easily shave tens of kB off the firmware. In fact, if only a
|
||||
small sub-set of functions are needed, you can get away with less than
|
||||
10 kB of flash space. See the section on `customising
|
||||
ulab <#Customising-the-firmware>`__.
|
||||
|
||||
Resources and legal matters
|
||||
|
|
@ -136,13 +138,13 @@ Differences between micropython-ulab and circuitpython-ulab
|
|||
-----------------------------------------------------------
|
||||
|
||||
``ulab`` has originally been developed for ``micropython``, but has
|
||||
since been integrated into a number of its flavours. Most of these
|
||||
flavours are simply forks of ``micropython`` itself, with some
|
||||
additional functionality. One of the notable exceptions is
|
||||
``circuitpython``, which has slightly diverged at the core level, and
|
||||
this has some minor consequences. Some of these concern the C
|
||||
implementation details only, which all have been sorted out with the
|
||||
generous and enthusiastic support of Jeff Epler from `Adafruit
|
||||
since been integrated into a number of its flavours. Most of these are
|
||||
simply forks of ``micropython`` itself, with some additional
|
||||
functionality. One of the notable exceptions is ``circuitpython``, which
|
||||
has slightly diverged at the core level, and this has some minor
|
||||
consequences. Some of these concern the C implementation details only,
|
||||
which all have been sorted out with the generous and enthusiastic
|
||||
support of Jeff Epler from `Adafruit
|
||||
Industries <http://www.adafruit.com>`__.
|
||||
|
||||
There are, however, a couple of instances, where the two environments
|
||||
|
|
@ -176,6 +178,17 @@ fine-tuned. The first couple of lines of the file look like this
|
|||
// A considerable amount of flash space can be saved by removing (setting
|
||||
// the corresponding constants to 0) the unnecessary functions and features.
|
||||
|
||||
// Values defined here can be overridden by your own config file as
|
||||
// make -DULAB_CONFIG_FILE="my_ulab_config.h"
|
||||
#if defined(ULAB_CONFIG_FILE)
|
||||
#include ULAB_CONFIG_FILE
|
||||
#endif
|
||||
|
||||
// Adds support for complex ndarrays
|
||||
#ifndef ULAB_SUPPORTS_COMPLEX
|
||||
#define ULAB_SUPPORTS_COMPLEX (1)
|
||||
#endif
|
||||
|
||||
// Determines, whether scipy is defined in ulab. The sub-modules and functions
|
||||
// of scipy have to be defined separately
|
||||
#define ULAB_HAS_SCIPY (1)
|
||||
|
|
@ -240,9 +253,9 @@ everything else, you get away with less than 5 kB extra.
|
|||
Compatibility with numpy
|
||||
------------------------
|
||||
|
||||
The functions implemented in ``ulab`` are organised in three sub-modules
|
||||
at the C level, namely, ``numpy``, ``scipy``, and ``user``. This
|
||||
modularity is elevated to ``python``, meaning that in order to use
|
||||
The functions implemented in ``ulab`` are organised in four sub-modules
|
||||
at the C level, namely, ``numpy``, ``scipy``, ``utils``, and ``user``.
|
||||
This modularity is elevated to ``python``, meaning that in order to use
|
||||
functions that are part of ``numpy``, you have to import ``numpy`` as
|
||||
|
||||
.. code:: python
|
||||
|
|
@ -253,9 +266,9 @@ functions that are part of ``numpy``, you have to import ``numpy`` as
|
|||
p = np.array([1, 2, 3])
|
||||
np.polyval(p, x)
|
||||
|
||||
There are a couple of exceptions to this rule, namely ``fft``, and
|
||||
``linalg``, which are sub-modules even in ``numpy``, thus you have to
|
||||
write them out as
|
||||
There are a couple of exceptions to this rule, namely ``fft``,
|
||||
``linalg``, and ``random``, which are sub-modules even in ``numpy``,
|
||||
thus you have to write them out as
|
||||
|
||||
.. code:: python
|
||||
|
||||
|
|
@ -463,6 +476,29 @@ from the version string in the following way:
|
|||
|
||||
|
||||
|
||||
ulab with complex arrays
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
If the firmware supports complex arrays, ``-c`` is appended to the
|
||||
version string as can be seen below.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
import ulab
|
||||
|
||||
version = ulab.__version__
|
||||
|
||||
print('version string: ', version)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
version string: 4.0.0-2D-c
|
||||
|
||||
|
||||
|
||||
|
||||
Finding out what your firmware supports
|
||||
---------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -117,7 +117,9 @@ types can be mixed in the initialisation function.
|
|||
If the ``dtype`` keyword with the possible
|
||||
``uint8/int8/uint16/int16/float`` values is supplied, the new
|
||||
``ndarray`` will have that type, otherwise, it assumes ``float`` as
|
||||
default.
|
||||
default. In addition, if ``ULAB_SUPPORTS_COMPLEX`` is set to 1 in
|
||||
`ulab.h <https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h>`__,
|
||||
the ``dtype`` can also take on the value of ``complex``.
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
@ -248,24 +250,26 @@ and will, therefore, be faster. Keep this in mind, whenever the output
|
|||
type, or performance is important.
|
||||
|
||||
Array initialisation functions
|
||||
------------------------------
|
||||
==============================
|
||||
|
||||
There are nine functions that can be used for initialising an array.
|
||||
Starred functions accept ``complex`` as the value of the ``dtype``, if
|
||||
the firmware was compiled with complex support.
|
||||
|
||||
1. `numpy.arange <#arange>`__
|
||||
2. `numpy.concatenate <#concatenate>`__
|
||||
3. `numpy.diag <#diag>`__
|
||||
4. `numpy.empty <#empty>`__
|
||||
5. `numpy.eye <#eye>`__
|
||||
3. `numpy.diag\* <#diag>`__
|
||||
4. `numpy.empty\* <#empty>`__
|
||||
5. `numpy.eye\* <#eye>`__
|
||||
6. `numpy.frombuffer <#frombuffer>`__
|
||||
7. `numpy.full <#full>`__
|
||||
8. `numpy.linspace <#linspace>`__
|
||||
7. `numpy.full\* <#full>`__
|
||||
8. `numpy.linspace\* <#linspace>`__
|
||||
9. `numpy.logspace <#logspace>`__
|
||||
10. `numpy.ones <#ones>`__
|
||||
11. `numpy.zeros <#zeros>`__
|
||||
10. `numpy.ones\* <#ones>`__
|
||||
11. `numpy.zeros\* <#zeros>`__
|
||||
|
||||
arange
|
||||
~~~~~~
|
||||
------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.arange.html
|
||||
|
|
@ -296,7 +300,7 @@ keyword argument.
|
|||
|
||||
|
||||
concatenate
|
||||
~~~~~~~~~~~
|
||||
-----------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.concatenate.html
|
||||
|
|
@ -383,14 +387,22 @@ https://numpy.org/doc/stable/reference/generated/numpy.diag.html
|
|||
|
||||
Extract a diagonal, or construct a diagonal array.
|
||||
|
||||
The function takes two arguments, an ``ndarray``, and a shift. If the
|
||||
first argument is a two-dimensional array, the function returns a
|
||||
one-dimensional array containing the diagonal entries. The diagonal can
|
||||
be shifted by an amount given in the second argument.
|
||||
The function takes a positional argument, an ``ndarray``, or any
|
||||
``micropython`` iterable, and an optional keyword argument, a shift,
|
||||
with a default value of 0. If the first argument is a two-dimensional
|
||||
array (or a two-dimensional iterable, e.g., a list of lists), the
|
||||
function returns a one-dimensional array containing the diagonal
|
||||
entries. The diagonal can be shifted by an amount given in the second
|
||||
argument. If the shift is larger than the length of the corresponding
|
||||
axis, an empty array is returned.
|
||||
|
||||
If the first argument is a one-dimensional array, the function returns a
|
||||
two-dimensional tensor with its diagonal elements given by the first
|
||||
argument.
|
||||
two-dimensional square tensor with its diagonal elements given by the
|
||||
first argument. Again, the diagonal be shifted by an amount given by the
|
||||
keyword argument.
|
||||
|
||||
The ``diag`` function can accept a complex array, if the firmware was
|
||||
compiled with complex support.
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
@ -398,15 +410,34 @@ argument.
|
|||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3, 4])
|
||||
a = np.array([1, 2, 3], dtype=np.uint8)
|
||||
print(np.diag(a))
|
||||
|
||||
print('\ndiagonal shifted by 2')
|
||||
print(np.diag(a, k=2))
|
||||
|
||||
print('\ndiagonal shifted by -2')
|
||||
print(np.diag(a, k=-2))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
array([[1.0, 0.0, 0.0, 0.0],
|
||||
[0.0, 2.0, 0.0, 0.0],
|
||||
[0.0, 0.0, 3.0, 0.0],
|
||||
[0.0, 0.0, 0.0, 4.0]], dtype=float64)
|
||||
array([[1, 0, 0],
|
||||
[0, 2, 0],
|
||||
[0, 0, 3]], dtype=uint8)
|
||||
|
||||
diagonal shifted by 2
|
||||
array([[0, 0, 1, 0, 0],
|
||||
[0, 0, 0, 2, 0],
|
||||
[0, 0, 0, 0, 3],
|
||||
[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0]], dtype=uint8)
|
||||
|
||||
diagonal shifted by -2
|
||||
array([[0, 0, 0, 0, 0],
|
||||
[0, 0, 0, 0, 0],
|
||||
[1, 0, 0, 0, 0],
|
||||
[0, 2, 0, 0, 0],
|
||||
[0, 0, 3, 0, 0]], dtype=uint8)
|
||||
|
||||
|
||||
|
||||
|
|
@ -417,19 +448,38 @@ argument.
|
|||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(16)).reshape((4, 4))
|
||||
print('a: ', a)
|
||||
print()
|
||||
print('diagonal of a: ', np.diag(a))
|
||||
a = np.arange(16).reshape((4, 4))
|
||||
print(a)
|
||||
print('\ndiagonal of a:')
|
||||
print(np.diag(a))
|
||||
|
||||
print('\ndiagonal of a:')
|
||||
print(np.diag(a))
|
||||
|
||||
print('\ndiagonal of a, shifted by 2')
|
||||
print(np.diag(a, k=2))
|
||||
|
||||
print('\ndiagonal of a, shifted by 5')
|
||||
print(np.diag(a, k=5))
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([[0.0, 1.0, 2.0, 3.0],
|
||||
[4.0, 5.0, 6.0, 7.0],
|
||||
[8.0, 9.0, 10.0, 11.0],
|
||||
[12.0, 13.0, 14.0, 15.0]], dtype=float64)
|
||||
array([[0, 1, 2, 3],
|
||||
[4, 5, 6, 7],
|
||||
[8, 9, 10, 11],
|
||||
[12, 13, 14, 15]], dtype=int16)
|
||||
|
||||
diagonal of a: array([0.0, 5.0, 10.0, 15.0], dtype=float64)
|
||||
diagonal of a:
|
||||
array([0, 5, 10, 15], dtype=int16)
|
||||
|
||||
diagonal of a:
|
||||
array([0, 5, 10, 15], dtype=int16)
|
||||
|
||||
diagonal of a, shifted by 2
|
||||
array([2, 7], dtype=int16)
|
||||
|
||||
diagonal of a, shifted by 5
|
||||
array([], dtype=int16)
|
||||
|
||||
|
||||
|
||||
|
|
@ -443,8 +493,11 @@ https://numpy.org/doc/stable/reference/generated/numpy.empty.html
|
|||
``empty`` is simply an alias for ``zeros``, i.e., as opposed to
|
||||
``numpy``, the entries of the tensor will be initialised to zero.
|
||||
|
||||
The ``empty`` function can accept complex as the value of the dtype, if
|
||||
the firmware was compiled with complex support.
|
||||
|
||||
eye
|
||||
~~~
|
||||
---
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.eye.html
|
||||
|
|
@ -461,8 +514,11 @@ is supplied, then we get a square matrix, otherwise one with ``M`` rows,
|
|||
and ``N`` columns), and ``k`` is the shift of the ones (the main
|
||||
diagonal corresponds to ``k=0``). Here are a couple of examples.
|
||||
|
||||
The ``eye`` function can accept ``complex`` as the value of the
|
||||
``dtype``, if the firmware was compiled with complex support.
|
||||
|
||||
With a single argument
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
@ -484,7 +540,7 @@ With a single argument
|
|||
|
||||
|
||||
Specifying the dimensions of the matrix
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. code::
|
||||
|
||||
|
|
@ -523,7 +579,7 @@ Specifying the dimensions of the matrix
|
|||
|
||||
|
||||
frombuffer
|
||||
~~~~~~~~~~
|
||||
----------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.frombuffer.html
|
||||
|
|
@ -569,7 +625,7 @@ a default of -1, meaning that all data are taken in.
|
|||
|
||||
|
||||
full
|
||||
~~~~
|
||||
----
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.full.html
|
||||
|
|
@ -579,6 +635,9 @@ all equal to the second positional argument. The first argument is a
|
|||
tuple describing the shape of the tensor. The ``dtype`` keyword argument
|
||||
with a default value of ``float`` can also be supplied.
|
||||
|
||||
The ``full`` function can accept a complex scalar, or ``complex`` as the
|
||||
value of ``dtype``, if the firmware was compiled with complex support.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -606,7 +665,7 @@ with a default value of ``float`` can also be supplied.
|
|||
|
||||
|
||||
linspace
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html
|
||||
|
|
@ -621,6 +680,11 @@ be supplied to force type conversion of the output. The default is
|
|||
not necessarily evenly spaced. This is not an error, rather a
|
||||
consequence of rounding. (This is also the ``numpy`` behaviour.)
|
||||
|
||||
The ``linspace`` function can accept ``complex`` as the value of the
|
||||
``dtype``, if the firmware was compiled with complex support. The output
|
||||
``dtype`` is automatically complex, if either of the endpoints is a
|
||||
complex scalar.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -650,7 +714,7 @@ consequence of rounding. (This is also the ``numpy`` behaviour.)
|
|||
|
||||
|
||||
logspace
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
``linspace``\ ’ equivalent for logarithmically spaced data is
|
||||
``logspace``. This function produces a sequence of numbers, in which the
|
||||
|
|
@ -702,7 +766,7 @@ also accepts the ``base`` argument. The default value is 10.
|
|||
|
||||
|
||||
ones, zeros
|
||||
~~~~~~~~~~~
|
||||
-----------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html
|
||||
|
|
@ -721,6 +785,9 @@ calling one of the ``ones``, or ``zeros`` functions. ``ones`` and
|
|||
|
||||
where shape is either an integer, or a tuple specifying the shape.
|
||||
|
||||
The ``ones/zeros`` functions can accept complex as the value of the
|
||||
dtype, if the firmware was compiled with complex support.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
|
@ -769,7 +836,7 @@ larger than the maximum dimension of your firmware.
|
|||
|
||||
|
||||
Customising array printouts
|
||||
---------------------------
|
||||
===========================
|
||||
|
||||
``ndarray``\ s are pretty-printed, i.e., if the number of entries along
|
||||
the last axis is larger than 10 (default value), then only the first and
|
||||
|
|
@ -793,7 +860,7 @@ last three entries will be printed. Also note that, as opposed to
|
|||
|
||||
|
||||
set_printoptions
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
The default values can be overwritten by means of the
|
||||
``set_printoptions`` function
|
||||
|
|
@ -831,7 +898,7 @@ the ellipsis, if the array is longer than ``threshold``.
|
|||
|
||||
|
||||
get_printoptions
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
The set value of the ``threshold`` and ``edgeitems`` can be retrieved by
|
||||
calling the ``get_printoptions`` function with no arguments. The
|
||||
|
|
@ -854,28 +921,34 @@ function returns a *dictionary* with two keys.
|
|||
|
||||
|
||||
Methods and properties of ndarrays
|
||||
----------------------------------
|
||||
==================================
|
||||
|
||||
Arrays have several *properties* that can queried, and some methods that
|
||||
can be called. With the exception of the flatten and transpose
|
||||
operators, properties return an object that describe some feature of the
|
||||
array, while the methods return a new array-like object.
|
||||
array, while the methods return a new array-like object. The ``imag``,
|
||||
and ``real`` properties are included in the firmware only, when it was
|
||||
compiled with complex support.
|
||||
|
||||
1. `.byteswap <#.byteswap>`__
|
||||
2. `.copy <#.copy>`__
|
||||
3. `.dtype <#.dtype>`__
|
||||
4. `.flat <#.flat>`__
|
||||
5. `.flatten <#.flatten>`__
|
||||
6. `.itemsize <#.itemsize>`__
|
||||
7. `.reshape <#.reshape>`__
|
||||
8. `.shape <#.shape>`__
|
||||
9. `.size <#.size>`__
|
||||
10. `.T <#.transpose>`__
|
||||
11. `.transpose <#.transpose>`__
|
||||
12. `.sort <#.sort>`__
|
||||
6. `.imag\* <#.imag>`__
|
||||
7. `.itemsize <#.itemsize>`__
|
||||
8. `.real\* <#.real>`__
|
||||
9. `.reshape <#.reshape>`__
|
||||
10. `.shape <#.shape>`__
|
||||
11. `.size <#.size>`__
|
||||
12. `.T <#.transpose>`__
|
||||
13. `.tobytes <#.tobytes>`__
|
||||
14. `.tolist <#.tolist>`__
|
||||
15. `.transpose <#.transpose>`__
|
||||
16. `.sort <#.sort>`__
|
||||
|
||||
.byteswap
|
||||
~~~~~~~~~
|
||||
---------
|
||||
|
||||
``numpy``
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.char.chararray.byteswap.html
|
||||
|
|
@ -921,7 +994,7 @@ value of ``inplace``.
|
|||
|
||||
|
||||
.copy
|
||||
~~~~~
|
||||
-----
|
||||
|
||||
The ``.copy`` method creates a new *deep copy* of an array, i.e., the
|
||||
entries of the source array are *copied* into the target array.
|
||||
|
|
@ -948,7 +1021,7 @@ entries of the source array are *copied* into the target array.
|
|||
|
||||
|
||||
.dtype
|
||||
~~~~~~
|
||||
------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.dtype.htm
|
||||
|
|
@ -1018,7 +1091,7 @@ the type code for signed 8-bit integers. The object definition adds
|
|||
around 600 bytes to the firmware.
|
||||
|
||||
.flat
|
||||
~~~~~
|
||||
-----
|
||||
|
||||
numpy:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flat.htm
|
||||
|
|
@ -1073,7 +1146,7 @@ iterator itself, while flattening produces a new copy.
|
|||
|
||||
|
||||
.flatten
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flatten.htm
|
||||
|
|
@ -1111,8 +1184,45 @@ https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flatten.htm
|
|||
|
||||
|
||||
|
||||
.imag
|
||||
-----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.imag.html
|
||||
|
||||
The ``.imag`` property is defined only, if the firmware was compiled
|
||||
with complex support, and returns a copy with the imaginary part of an
|
||||
array. If the array is real, then the output is straight zeros with the
|
||||
``dtype`` of the input. If the input is complex, the output ``dtype`` is
|
||||
always ``float``, irrespective of the values.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3], dtype=np.uint16)
|
||||
print("a:\t", a)
|
||||
print("a.imag:\t", a.imag)
|
||||
|
||||
b = np.array([1, 2+1j, 3-1j], dtype=np.complex)
|
||||
print("\nb:\t", b)
|
||||
print("b.imag:\t", b.imag)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 2, 3], dtype=uint16)
|
||||
a.imag: array([0, 0, 0], dtype=uint16)
|
||||
|
||||
b: array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)
|
||||
b.imag: array([0.0, 1.0, -1.0], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
.itemsize
|
||||
~~~~~~~~~
|
||||
---------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.itemsize.html
|
||||
|
|
@ -1128,11 +1238,11 @@ the array.
|
|||
|
||||
a = np.array([1, 2, 3], dtype=np.int8)
|
||||
print("a:\n", a)
|
||||
print("itemsize of a:", a.itemsize
|
||||
print("itemsize of a:", a.itemsize)
|
||||
|
||||
b= np.array([[1, 2], [3, 4]], dtype=np.float)
|
||||
print("\nb:\n", b)
|
||||
print("itemsize of b:", b.itemsize
|
||||
print("itemsize of b:", b.itemsize)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
|
|
@ -1148,8 +1258,42 @@ the array.
|
|||
|
||||
|
||||
|
||||
.real
|
||||
-----
|
||||
|
||||
numpy:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.real.html
|
||||
|
||||
The ``.real`` property is defined only, if the firmware was compiled
|
||||
with complex support, and returns a copy with the real part of an array.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array([1, 2, 3], dtype=np.uint16)
|
||||
print("a:\t", a)
|
||||
print("a.real:\t", a.real)
|
||||
|
||||
b = np.array([1, 2+1j, 3-1j], dtype=np.complex)
|
||||
print("\nb:\t", b)
|
||||
print("b.real:\t", b.real)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([1, 2, 3], dtype=uint16)
|
||||
a.real: array([1, 2, 3], dtype=uint16)
|
||||
|
||||
b: array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)
|
||||
b.real: array([1.0, 2.0, 3.0], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
.reshape
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html
|
||||
|
|
@ -1190,7 +1334,7 @@ consistent with the old, a ``ValueError`` exception will be raised.
|
|||
|
||||
Note that `ndarray.reshape()` can also be called by assigning to `ndarray.shape`.
|
||||
.shape
|
||||
~~~~~~
|
||||
------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html
|
||||
|
|
@ -1255,7 +1399,7 @@ By assigning a tuple to the ``.shape`` property, the array can be
|
|||
|
||||
|
||||
.size
|
||||
~~~~~
|
||||
-----
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.size.html
|
||||
|
|
@ -1297,7 +1441,7 @@ The ``.T`` property of the ``ndarray`` is equivalent to
|
|||
`.transpose <#.transpose>`__.
|
||||
|
||||
.tobytes
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tobytes.html
|
||||
|
|
@ -1342,8 +1486,46 @@ not dense (i.e., it has already been sliced).
|
|||
|
||||
|
||||
|
||||
.tolist
|
||||
-------
|
||||
|
||||
``numpy``:
|
||||
https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tolist.html
|
||||
|
||||
The ``.tolist`` method can be used for converting the numerical array
|
||||
into a (nested) ``python`` lists.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
a = np.array(range(4), dtype=np.uint8)
|
||||
print('a: ', a)
|
||||
b = a.tolist()
|
||||
print('b: ', b)
|
||||
|
||||
c = a.reshape((2, 2))
|
||||
print('='*20)
|
||||
print('c: ', c)
|
||||
d = c.tolist()
|
||||
print('d: ', d)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([0, 1, 2, 3], dtype=uint8)
|
||||
b: [0, 1, 2, 3]
|
||||
====================
|
||||
c: array([[0, 1],
|
||||
[2, 3]], dtype=uint8)
|
||||
d: [[0, 1], [2, 3]]
|
||||
|
||||
|
||||
|
||||
|
||||
.transpose
|
||||
~~~~~~~~~~
|
||||
----------
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html
|
||||
|
|
@ -1411,7 +1593,7 @@ property:
|
|||
|
||||
|
||||
.sort
|
||||
~~~~~
|
||||
-----
|
||||
|
||||
``numpy``:
|
||||
https://docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html
|
||||
|
|
@ -1466,13 +1648,13 @@ In-place sorting of an ``ndarray``. For a more detailed exposition, see
|
|||
|
||||
|
||||
Unary operators
|
||||
---------------
|
||||
===============
|
||||
|
||||
With the exception of ``len``, which returns a single number, all unary
|
||||
operators manipulate the underlying data element-wise.
|
||||
|
||||
len
|
||||
~~~
|
||||
---
|
||||
|
||||
This operator takes a single argument, the array, and returns either the
|
||||
length of the first axis.
|
||||
|
|
@ -1513,7 +1695,7 @@ The number returned by ``len`` is also the length of the iterations,
|
|||
when the array supplies the elements for an iteration (see later).
|
||||
|
||||
invert
|
||||
~~~~~~
|
||||
------
|
||||
|
||||
The function is defined for integer data types (``uint8``, ``int8``,
|
||||
``uint16``, and ``int16``) only, takes a single argument, and returns
|
||||
|
|
@ -1549,7 +1731,7 @@ unexpected, as in the example below:
|
|||
|
||||
|
||||
abs
|
||||
~~~
|
||||
---
|
||||
|
||||
This function takes a single argument, and returns the
|
||||
element-by-element absolute value of the array. When the data type is
|
||||
|
|
@ -1575,7 +1757,7 @@ returned immediately, and no calculation takes place.
|
|||
|
||||
|
||||
neg
|
||||
~~~
|
||||
---
|
||||
|
||||
This operator takes a single argument, and changes the sign of each
|
||||
element in the array. Unsigned values are wrapped.
|
||||
|
|
@ -1606,7 +1788,7 @@ element in the array. Unsigned values are wrapped.
|
|||
|
||||
|
||||
pos
|
||||
~~~
|
||||
---
|
||||
|
||||
This function takes a single argument, and simply returns a copy of the
|
||||
array.
|
||||
|
|
@ -1630,16 +1812,21 @@ array.
|
|||
|
||||
|
||||
Binary operators
|
||||
----------------
|
||||
================
|
||||
|
||||
``ulab`` implements the ``+``, ``-``, ``*``, ``/``, ``**``, ``<``,
|
||||
``>``, ``<=``, ``>=``, ``==``, ``!=``, ``+=``, ``-=``, ``*=``, ``/=``,
|
||||
``**=`` binary operators that work element-wise. Broadcasting is
|
||||
available, meaning that the two operands do not even have to have the
|
||||
same shape. If the lengths along the respective axes are equal, or one
|
||||
of them is 1, or the axis is missing, the element-wise operation can
|
||||
still be carried out. A thorough explanation of broadcasting can be
|
||||
found under https://numpy.org/doc/stable/user/basics.broadcasting.html.
|
||||
``ulab`` implements the ``+``, ``-``, ``*``, ``/``, ``**``, ``%``,
|
||||
``<``, ``>``, ``<=``, ``>=``, ``==``, ``!=``, ``+=``, ``-=``, ``*=``,
|
||||
``/=``, ``**=``, ``%=`` binary operators, as well as the ``AND``,
|
||||
``OR``, ``XOR`` bit-wise operators that work element-wise. Note that the
|
||||
bit-wise operators will raise an exception, if either of the operands is
|
||||
of ``float`` or ``complex`` type.
|
||||
|
||||
Broadcasting is available, meaning that the two operands do not even
|
||||
have to have the same shape. If the lengths along the respective axes
|
||||
are equal, or one of them is 1, or the axis is missing, the element-wise
|
||||
operation can still be carried out. A thorough explanation of
|
||||
broadcasting can be found under
|
||||
https://numpy.org/doc/stable/user/basics.broadcasting.html.
|
||||
|
||||
**WARNING**: note that relational operators (``<``, ``>``, ``<=``,
|
||||
``>=``, ``==``, ``!=``) should have the ``ndarray`` on their left hand
|
||||
|
|
@ -1687,7 +1874,7 @@ exception:
|
|||
on `array comparison <#Comparison-of-arrays>`__ for details.
|
||||
|
||||
Upcasting
|
||||
~~~~~~~~~
|
||||
---------
|
||||
|
||||
Binary operations require special attention, because two arrays with
|
||||
different typecodes can be the operands of an operation, in which case
|
||||
|
|
@ -1710,7 +1897,9 @@ conventions.
|
|||
``dtype``. Thus, e.g., if the scalar is 123, it will be converted
|
||||
into an array of ``dtype`` ``uint8``, while -1000 will be converted
|
||||
into ``int16``. An ``mp_obj_float``, will always be promoted to
|
||||
``dtype`` ``float``. Other micropython types (e.g., lists, tuples,
|
||||
``dtype`` ``float``. Similarly, if ``ulab`` supports complex arrays,
|
||||
the result of a binary operation involving a ``complex`` array is
|
||||
always complex. Other ``micropython`` types (e.g., lists, tuples,
|
||||
etc.) raise a ``TypeError`` exception.
|
||||
|
||||
4.
|
||||
|
|
@ -1766,7 +1955,7 @@ Upcasting can be seen in action in the following snippet:
|
|||
|
||||
|
||||
Benchmarks
|
||||
~~~~~~~~~~
|
||||
----------
|
||||
|
||||
The following snippet compares the performance of binary operations to a
|
||||
possible implementation in python. For the time measurement, we will
|
||||
|
|
@ -1859,7 +2048,7 @@ on graphical
|
|||
displays <https://forum.micropython.org/viewtopic.php?f=15&t=5815&p=33362&hilit=ufont#p33383>`__.
|
||||
|
||||
Comparison operators
|
||||
--------------------
|
||||
====================
|
||||
|
||||
The smaller than, greater than, smaller or equal, and greater or equal
|
||||
operators return a vector of Booleans indicating the positions
|
||||
|
|
@ -1907,7 +2096,7 @@ following code will not work:
|
|||
|
||||
|
||||
Iterating over arrays
|
||||
---------------------
|
||||
=====================
|
||||
|
||||
``ndarray``\ s are iterable, which means that their elements can also be
|
||||
accessed as can the elements of a list, tuple, etc. If the array is
|
||||
|
|
@ -1955,10 +2144,10 @@ reduced-dimensional *view* is created and returned.
|
|||
|
||||
|
||||
Slicing and indexing
|
||||
--------------------
|
||||
====================
|
||||
|
||||
Views vs. copies
|
||||
~~~~~~~~~~~~~~~~
|
||||
----------------
|
||||
|
||||
``numpy`` has a very important concept called *views*, which is a
|
||||
powerful extension of ``python``\ ’s own notion of slicing. Slices are
|
||||
|
|
@ -2071,7 +2260,7 @@ section `Slicing and assigning to
|
|||
slices <#Slicing-and-assigning-to-slices>`__ should clarify the issue.
|
||||
|
||||
Indexing
|
||||
~~~~~~~~
|
||||
--------
|
||||
|
||||
The simplest form of indexing is specifying a single integer between the
|
||||
square brackets as in
|
||||
|
|
@ -2141,12 +2330,12 @@ future version of ``ulab``.
|
|||
|
||||
a = np.array(range(9), dtype=np.float)
|
||||
print("a:\t", a)
|
||||
print("a < 5:\t", a[a < 5])
|
||||
print("a[a < 5]:\t", a[a < 5])
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
a: array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], dtype=float)
|
||||
a < 5: array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
|
||||
a[a < 5]: array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)
|
||||
|
||||
|
||||
|
||||
|
|
@ -2234,7 +2423,7 @@ On the right hand side of the assignment we can even have another array.
|
|||
|
||||
|
||||
Slicing and assigning to slices
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
-------------------------------
|
||||
|
||||
You can also generate sub-arrays by specifying slices as the index of an
|
||||
array. Slices are special python objects of the form
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ in the ``vector_arctan2`` function:
|
|||
|
||||
.. code:: c
|
||||
|
||||
mp_obj_t vectorise_arctan2(mp_obj_t y, mp_obj_t x) {
|
||||
mp_obj_t vector_arctan2(mp_obj_t y, mp_obj_t x) {
|
||||
...
|
||||
uint8_t ndim = 0;
|
||||
size_t *shape = m_new(size_t, ULAB_MAX_DIMS);
|
||||
|
|
@ -896,7 +896,7 @@ the ``user`` module:
|
|||
|
||||
.. code:: c
|
||||
|
||||
STATIC const mp_rom_map_elem_t ulab_user_globals_table[] = {
|
||||
static const mp_rom_map_elem_t ulab_user_globals_table[] = {
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_user) },
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_square), (mp_obj_t)&user_square_obj },
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ Here is an example without keyword arguments
|
|||
a = bytearray([1, 1, 0, 0, 0, 0, 0, 255])
|
||||
print('a: ', a)
|
||||
print()
|
||||
print('unsigned integers: ', utils.from_uint32_buffer(a))
|
||||
print('unsigned integers: ', utils.from_uint32_buffe
|
||||
print('original vector:\n', y)
|
||||
print('\nspectrum:\n', a)r(a))
|
||||
|
||||
b = bytearray([1, 1, 0, 0, 0, 0, 0, 255])
|
||||
print('\nb: ', b)
|
||||
|
|
@ -137,7 +139,136 @@ These two functions are identical to ``utils.from_int32_buffer``, and
|
|||
``utils.from_uint32_buffer``, with the exception that they convert
|
||||
16-bit integers to floating point ``ndarray``\ s.
|
||||
|
||||
spectrogram
|
||||
-----------
|
||||
|
||||
In addition to the Fourier transform and its inverse, ``ulab`` also
|
||||
sports a function called ``spectrogram``, which returns the absolute
|
||||
value of the Fourier transform, also known as the power spectrum. This
|
||||
could be used to find the dominant spectral component in a time series.
|
||||
The positional arguments are treated in the same way as in ``fft``, and
|
||||
``ifft``. This means that, if the firmware was compiled with complex
|
||||
support and ``ULAB_FFT_IS_NUMPY_COMPATIBLE`` is defined to be 1 in
|
||||
``ulab.h``, the input can also be a complex array.
|
||||
|
||||
And easy way to find out if the FFT is ``numpy``-compatible is to check
|
||||
the number of values ``fft.fft`` returns, when called with a single real
|
||||
argument of length other than 2:
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in CPython
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
|
||||
if len(np.fft.fft(np.zeros(4))) == 2:
|
||||
print('FFT is NOT numpy compatible (real and imaginary parts are treated separately)')
|
||||
else:
|
||||
print('FFT is numpy compatible (complex inputs/outputs)')
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
FFT is numpy compatible (complex inputs/outputs)
|
||||
|
||||
|
||||
|
||||
|
||||
Depending on the ``numpy``-compatibility of the FFT, the ``spectrogram``
|
||||
function takes one or two positional arguments, and three keyword
|
||||
arguments. If the FFT is ``numpy`` compatible, one positional argument
|
||||
is allowed, and it is a 1D real or complex ``ndarray``. If the FFT is
|
||||
not ``numpy``-compatible, if a single argument is supplied, it will be
|
||||
treated as the real part of the input, and if two positional arguments
|
||||
are supplied, they are treated as the real and imaginary parts of the
|
||||
signal.
|
||||
|
||||
The keyword arguments are as follows:
|
||||
|
||||
1. ``scratchpad = None``: must be a 1D, dense, floating point array,
|
||||
twice as long as the input array; the ``scratchpad`` will be used as
|
||||
a temporary internal buffer to perform the Fourier transform; the
|
||||
``scratchpad`` can repeatedly be re-used.
|
||||
2. ``out = None``: must be a 1D, not necessarily dense, floating point
|
||||
array that will store the results
|
||||
3. ``log = False``: must be either ``True``, or ``False``; if ``True``,
|
||||
the ``spectrogram`` returns the logarithm of the absolute values of
|
||||
the Fourier transform.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
from ulab import utils as utils
|
||||
|
||||
x = np.linspace(0, 10, num=1024)
|
||||
y = np.sin(x)
|
||||
|
||||
a = utils.spectrogram(y)
|
||||
|
||||
print('original vector:\n', y)
|
||||
print('\nspectrum:\n', a)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
original vector:
|
||||
array([0.0, 0.009775015390171337, 0.01954909674625918, ..., -0.5275140569487312, -0.5357931822978732, -0.5440211108893697], dtype=float64)
|
||||
|
||||
spectrum:
|
||||
array([187.8635087634578, 315.3112063607119, 347.8814873399375, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
As such, ``spectrogram`` is really just a shorthand for
|
||||
``np.abs(np.fft.fft(signal))``, if the FFT is ``numpy``-compatible, or
|
||||
``np.sqrt(a*a + b*b)`` if the FFT returns the real (``a``) and imaginary
|
||||
(``b``) parts separately. However, ``spectrogram`` saves significant
|
||||
amounts of RAM: the expression ``a*a + b*b`` has to allocate memory for
|
||||
``a*a``, ``b*b``, and finally, their sum. Similarly, ``np.abs`` returns
|
||||
a new array. This issue is compounded even more, if ``np.log()`` is used
|
||||
on the absolute value.
|
||||
|
||||
In contrast, ``spectrogram`` handles all calculations in the same
|
||||
internal arrays, and allows one to re-use previously reserved RAM. This
|
||||
can be especially useful in cases, when ``spectogram`` is called
|
||||
repeatedly, as in the snippet below.
|
||||
|
||||
.. code::
|
||||
|
||||
# code to be run in micropython
|
||||
|
||||
from ulab import numpy as np
|
||||
from ulab import utils as utils
|
||||
|
||||
n = 1024
|
||||
t = np.linspace(0, 2 * np.pi, num=1024)
|
||||
scratchpad = np.zeros(2 * n)
|
||||
|
||||
for _ in range(10):
|
||||
signal = np.sin(t)
|
||||
utils.spectrogram(signal, out=signal, scratchpad=scratchpad, log=True)
|
||||
|
||||
print('signal: ', signal)
|
||||
|
||||
for _ in range(10):
|
||||
signal = np.sin(t)
|
||||
out = np.log(utils.spectrogram(signal))
|
||||
|
||||
print('out: ', out)
|
||||
|
||||
.. parsed-literal::
|
||||
|
||||
signal: array([-27.38260169844543, 6.237834411021073, -0.4038327279002965, ..., -0.9795967096969854, -0.4038327279002969, 6.237834411021073], dtype=float64)
|
||||
out: array([-27.38260169844543, 6.237834411021073, -0.4038327279002965, ..., -0.9795967096969854, -0.4038327279002969, 6.237834411021073], dtype=float64)
|
||||
|
||||
|
||||
|
||||
|
||||
Note that ``scratchpad`` is reserved only once, and then is re-used in
|
||||
the first loop. By assigning ``signal`` to the output, we save
|
||||
additional RAM. This approach avoids the usual problem of memory
|
||||
fragmentation, which would happen in the second loop, where both
|
||||
``spectrogram``, and ``np.log`` must reserve RAM in each iteration.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -31,11 +31,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-08-03T18:32:45.342280Z",
|
||||
"start_time": "2020-08-03T18:32:45.338442Z"
|
||||
"end_time": "2022-01-07T18:24:48.499467Z",
|
||||
"start_time": "2022-01-07T18:24:48.488004Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -315,6 +315,31 @@
|
|||
"print('\\nimaginary part:\\t', d)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ulab with complex support\n",
|
||||
"\n",
|
||||
"If the `ULAB_SUPPORTS_COMPLEX`, and `ULAB_FFT_IS_NUMPY_COMPATIBLE` pre-processor constants are set to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h) as \n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"// Adds support for complex ndarrays\n",
|
||||
"#ifndef ULAB_SUPPORTS_COMPLEX\n",
|
||||
"#define ULAB_SUPPORTS_COMPLEX (1)\n",
|
||||
"#endif\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"#ifndef ULAB_FFT_IS_NUMPY_COMPATIBLE\n",
|
||||
"#define ULAB_FFT_IS_NUMPY_COMPATIBLE (1)\n",
|
||||
"#endif\n",
|
||||
"```\n",
|
||||
"then the FFT routine will behave in a `numpy`-compatible way: the single input array can either be real, in which case the imaginary part is assumed to be zero, or complex. The output is also complex. \n",
|
||||
"\n",
|
||||
"While `numpy`-compatibility might be a desired feature, it has one side effect, namely, the FFT routine consumes approx. 50% more RAM. The reason for this lies in the implementation details."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -373,6 +398,15 @@
|
|||
"Note that unlike in `numpy`, the length of the array on which the Fourier transform is carried out must be a power of 2. If this is not the case, the function raises a `ValueError` exception."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ulab with complex support\n",
|
||||
"\n",
|
||||
"The `fft.ifft` function can also be made `numpy`-compatible by setting the `ULAB_SUPPORTS_COMPLEX`, and `ULAB_FFT_IS_NUMPY_COMPATIBLE` pre-processor constants to 1."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
492
docs/numpy-random.ipynb
Normal file
492
docs/numpy-random.ipynb
Normal file
|
|
@ -0,0 +1,492 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-01T09:27:13.438054Z",
|
||||
"start_time": "2020-05-01T09:27:13.191491Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Populating the interactive namespace from numpy and matplotlib\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%pylab inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Notebook magic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T18:24:48.499467Z",
|
||||
"start_time": "2022-01-07T18:24:48.488004Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.core.magic import Magics, magics_class, line_cell_magic\n",
|
||||
"from IPython.core.magic import cell_magic, register_cell_magic, register_line_magic\n",
|
||||
"from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring\n",
|
||||
"import subprocess\n",
|
||||
"import os"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-07-23T20:31:25.296014Z",
|
||||
"start_time": "2020-07-23T20:31:25.265937Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"@magics_class\n",
|
||||
"class PyboardMagic(Magics):\n",
|
||||
" @cell_magic\n",
|
||||
" @magic_arguments()\n",
|
||||
" @argument('-skip')\n",
|
||||
" @argument('-unix')\n",
|
||||
" @argument('-pyboard')\n",
|
||||
" @argument('-file')\n",
|
||||
" @argument('-data')\n",
|
||||
" @argument('-time')\n",
|
||||
" @argument('-memory')\n",
|
||||
" def micropython(self, line='', cell=None):\n",
|
||||
" args = parse_argstring(self.micropython, line)\n",
|
||||
" if args.skip: # doesn't care about the cell's content\n",
|
||||
" print('skipped execution')\n",
|
||||
" return None # do not parse the rest\n",
|
||||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
" return None\n",
|
||||
" if args.file: # can be used to copy the cell content onto the pyboard's flash\n",
|
||||
" spaces = \" \"\n",
|
||||
" try:\n",
|
||||
" with open(args.file, 'w') as fout:\n",
|
||||
" fout.write(cell.replace('\\t', spaces))\n",
|
||||
" printf('written cell to {}'.format(args.file))\n",
|
||||
" except:\n",
|
||||
" print('Failed to write to disc!')\n",
|
||||
" return None # do not parse the rest\n",
|
||||
" if args.data: # can be used to load data from the pyboard directly into kernel space\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" if len(message) == 0:\n",
|
||||
" print('pyboard >>>')\n",
|
||||
" else:\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
" # register new variable in user namespace\n",
|
||||
" self.shell.user_ns[args.data] = string_to_matrix(message.decode(\"utf-8\"))\n",
|
||||
" \n",
|
||||
" if args.time: # measures the time of executions\n",
|
||||
" pyb.exec('import utime')\n",
|
||||
" message = pyb.exec('t = utime.ticks_us()\\n' + cell + '\\ndelta = utime.ticks_diff(utime.ticks_us(), t)' + \n",
|
||||
" \"\\nprint('execution time: {:d} us'.format(delta))\")\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
" \n",
|
||||
" if args.memory: # prints out memory information \n",
|
||||
" message = pyb.exec('from micropython import mem_info\\nprint(mem_info())\\n')\n",
|
||||
" print(\"memory before execution:\\n========================\\n\", message.decode('utf-8'))\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" print(\">>> \", message.decode('utf-8'))\n",
|
||||
" message = pyb.exec('print(mem_info())')\n",
|
||||
" print(\"memory after execution:\\n========================\\n\", message.decode('utf-8'))\n",
|
||||
"\n",
|
||||
" if args.pyboard:\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
"\n",
|
||||
"ip = get_ipython()\n",
|
||||
"ip.register_magics(PyboardMagic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## pyboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 57,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-07T07:35:35.126401Z",
|
||||
"start_time": "2020-05-07T07:35:35.105824Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pyboard\n",
|
||||
"pyb = pyboard.Pyboard('/dev/ttyACM0')\n",
|
||||
"pyb.enter_raw_repl()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-19T19:11:18.145548Z",
|
||||
"start_time": "2020-05-19T19:11:18.137468Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pyb.exit_raw_repl()\n",
|
||||
"pyb.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 58,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-07T07:35:38.725924Z",
|
||||
"start_time": "2020-05-07T07:35:38.645488Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -pyboard 1\n",
|
||||
"\n",
|
||||
"import utime\n",
|
||||
"import ulab as np\n",
|
||||
"\n",
|
||||
"def timeit(n=1000):\n",
|
||||
" def wrapper(f, *args, **kwargs):\n",
|
||||
" func_name = str(f).split(' ')[1]\n",
|
||||
" def new_func(*args, **kwargs):\n",
|
||||
" run_times = np.zeros(n, dtype=np.uint16)\n",
|
||||
" for i in range(n):\n",
|
||||
" t = utime.ticks_us()\n",
|
||||
" result = f(*args, **kwargs)\n",
|
||||
" run_times[i] = utime.ticks_diff(utime.ticks_us(), t)\n",
|
||||
" print('{}() execution times based on {} cycles'.format(func_name, n, (delta2-delta1)/n))\n",
|
||||
" print('\\tbest: %d us'%np.min(run_times))\n",
|
||||
" print('\\tworst: %d us'%np.max(run_times))\n",
|
||||
" print('\\taverage: %d us'%np.mean(run_times))\n",
|
||||
" print('\\tdeviation: +/-%.3f us'%np.std(run_times)) \n",
|
||||
" return result\n",
|
||||
" return new_func\n",
|
||||
" return wrapper\n",
|
||||
"\n",
|
||||
"def timeit(f, *args, **kwargs):\n",
|
||||
" func_name = str(f).split(' ')[1]\n",
|
||||
" def new_func(*args, **kwargs):\n",
|
||||
" t = utime.ticks_us()\n",
|
||||
" result = f(*args, **kwargs)\n",
|
||||
" print('execution time: ', utime.ticks_diff(utime.ticks_us(), t), ' us')\n",
|
||||
" return result\n",
|
||||
" return new_func"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"__END_OF_DEFS__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# numpy.random\n",
|
||||
"\n",
|
||||
"Random numbers drawn specific distributions can be generated by instantiating a `Generator` object, and calling its methods. The module defines the following three functions:\n",
|
||||
"\n",
|
||||
"1. [numpy.random.Generator.normal](#normal)\n",
|
||||
"1. [numpy.random.Generator.random](#random)\n",
|
||||
"1. [numpy.random.Generator.uniform](#uniform)\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"The `Generator` object, when instantiated, takes a single integer as its argument. This integer is the seed, which will be fed to the 32-bit or 64-bit routine. More details can be found under https://www.pcg-random.org/index.html. The generator is a standard `python` object that keeps track of its state.\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/random/index.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## normal\n",
|
||||
"\n",
|
||||
"A random set of number from the `normal` distribution can be generated by calling the generator's `normal` method. The method takes three optional arguments, `loc=0.0`, the centre of the distribution, `scale=1.0`, the width of the distribution, and `size=None`, a tuple containing the shape of the returned array. In case `size` is `None`, a single floating point number is returned.\n",
|
||||
"\n",
|
||||
"The `normal` method of the `Generator` object is based on the [Box-Muller transform](https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform).\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.normal.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-19T13:08:17.647416Z",
|
||||
"start_time": "2019-10-19T13:08:17.597456Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Gnerator() at 0x7fa9dae05340\n",
|
||||
"-6.285246229407202\n",
|
||||
"array([[24.95816273705659, 15.2670302229426, 14.81001577336041],\n",
|
||||
" [20.17589833056986, 23.14539083787544, 26.37772041367461],\n",
|
||||
" [41.94894234387275, 37.11027030608206, 25.65889562100477]], dtype=float64)\n",
|
||||
"array([[21.52562779033434, 12.74685887865834, 24.08404670765186],\n",
|
||||
" [4.728112596365396, 7.667757906857082, 21.61576094228444],\n",
|
||||
" [2.432338873595267, 27.75945683572574, 5.730827584659245]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"rng = np.random.Generator(123456)\n",
|
||||
"print(rng)\n",
|
||||
"\n",
|
||||
"# return single number from a distribution of scale 1, and location 0\n",
|
||||
"print(rng.normal())\n",
|
||||
"\n",
|
||||
"print(rng.normal(loc=20.0, scale=10.0, size=(3,3)))\n",
|
||||
"# same as above, with positional arguments\n",
|
||||
"print(rng.normal(20.0, 10.0, (3,3)))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## random\n",
|
||||
"\n",
|
||||
"A random set of number from the uniform distribution in the interval [0, 1] can be generated by calling the generator's `random` method. The method takes two optional arguments, `size=None`, a tuple containing the shape of the returned array, and `out`. In case `size` is `None`, a single floating point number is returned. \n",
|
||||
"\n",
|
||||
"`out` can be used, if a floating point array is available. An exception will be raised, if the array is not of `float` `dtype`, or if both `size` and `out` are supplied, and there is a conflict in their shapes.\n",
|
||||
"\n",
|
||||
"If `size` is `None`, a single floating point number will be returned.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.random.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Gnerator() at 0x7f299de05340\n",
|
||||
"6.384615058863119e-11\n",
|
||||
"\n",
|
||||
" array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],\n",
|
||||
" [0.8738606263361598, 0.4946080034142021, 0.7765890156101152],\n",
|
||||
" [0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)\n",
|
||||
"\n",
|
||||
"buffer array before:\n",
|
||||
" array([[0.0, 1.0, 2.0],\n",
|
||||
" [3.0, 4.0, 5.0],\n",
|
||||
" [6.0, 7.0, 8.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"buffer array after:\n",
|
||||
" array([[0.8508024287393201, 0.9848489829156055, 0.7598167589604003],\n",
|
||||
" [0.782995698302952, 0.2866337782847831, 0.7915884498022229],\n",
|
||||
" [0.4614071706315902, 0.4792657443088592, 0.1581582066230718]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"rng = np.random.Generator(123456)\n",
|
||||
"print(rng)\n",
|
||||
"\n",
|
||||
"# returning new objects\n",
|
||||
"print(rng.random())\n",
|
||||
"print('\\n', rng.random(size=(3,3)))\n",
|
||||
"\n",
|
||||
"# supplying a buffer\n",
|
||||
"a = np.array(range(9), dtype=np.float).reshape((3,3))\n",
|
||||
"print('\\nbuffer array before:\\n', a)\n",
|
||||
"rng.random(out=a)\n",
|
||||
"print('\\nbuffer array after:\\n', a)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## uniform\n",
|
||||
"\n",
|
||||
"`uniform` is similar to `random`, except that the interval over which the numbers are distributed can be specified, while the `out` argument cannot. In addition to `size` specifying the shape of the output, `low=0.0`, and `high=1.0` are accepted arguments. With the indicated defaults, `uniform` is identical to `random`, which can be seen from the fact that the first 3-by-3 tensor below is the same as the one produced by `rng.random(size=(3,3))` above.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"If `size` is `None`, a single floating point number will be returned.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.uniform.html"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Gnerator() at 0x7f1891205340\n",
|
||||
"6.384615058863119e-11\n",
|
||||
"\n",
|
||||
" array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],\n",
|
||||
" [0.8738606263361598, 0.4946080034142021, 0.7765890156101152],\n",
|
||||
" [0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)\n",
|
||||
"\n",
|
||||
" array([[18.5080242873932, 19.84848982915605, 17.598167589604],\n",
|
||||
" [17.82995698302952, 12.86633778284783, 17.91588449802223],\n",
|
||||
" [14.6140717063159, 14.79265744308859, 11.58158206623072]], dtype=float64)\n",
|
||||
"\n",
|
||||
" array([[14.3380400319162, 12.72487657409978, 15.77119643621117],\n",
|
||||
" [13.61835831436355, 18.96062889255558, 15.78847796795966],\n",
|
||||
" [12.59435855187034, 17.68262037443622, 14.77943040598734]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"rng = np.random.Generator(123456)\n",
|
||||
"print(rng)\n",
|
||||
"\n",
|
||||
"print(rng.uniform())\n",
|
||||
"# returning numbers between 0, and 1\n",
|
||||
"print('\\n', rng.uniform(size=(3,3)))\n",
|
||||
"\n",
|
||||
"# returning numbers between 10, and 20\n",
|
||||
"print('\\n', rng.uniform(low=10, high=20, size=(3,3)))\n",
|
||||
"\n",
|
||||
"# same as above, without the keywords\n",
|
||||
"print('\\n', rng.uniform(10, 20, (3,3)))"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.9.13"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {
|
||||
"height": "calc(100% - 180px)",
|
||||
"left": "10px",
|
||||
"top": "150px",
|
||||
"width": "382.797px"
|
||||
},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": true
|
||||
},
|
||||
"varInspector": {
|
||||
"cols": {
|
||||
"lenName": 16,
|
||||
"lenType": 16,
|
||||
"lenVar": 40
|
||||
},
|
||||
"kernels_config": {
|
||||
"python": {
|
||||
"delete_cmd_postfix": "",
|
||||
"delete_cmd_prefix": "del ",
|
||||
"library": "var_list.py",
|
||||
"varRefreshCmd": "print(var_dic_list())"
|
||||
},
|
||||
"r": {
|
||||
"delete_cmd_postfix": ") ",
|
||||
"delete_cmd_prefix": "rm(",
|
||||
"library": "var_list.r",
|
||||
"varRefreshCmd": "cat(var_dic_list()) "
|
||||
}
|
||||
},
|
||||
"types_to_exclude": [
|
||||
"module",
|
||||
"function",
|
||||
"builtin_function_or_method",
|
||||
"instance",
|
||||
"_Feature"
|
||||
],
|
||||
"window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
|
@ -34,8 +34,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-13T18:55:01.909310Z",
|
||||
"start_time": "2021-01-13T18:55:01.903634Z"
|
||||
"end_time": "2022-01-07T19:10:30.696795Z",
|
||||
"start_time": "2022-01-07T19:10:30.690003Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -52,8 +52,8 @@
|
|||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-13T18:55:02.434518Z",
|
||||
"start_time": "2021-01-13T18:55:02.382296Z"
|
||||
"end_time": "2022-01-07T19:10:30.785887Z",
|
||||
"start_time": "2022-01-07T19:10:30.710912Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -225,18 +225,20 @@
|
|||
"source": [
|
||||
"# Universal functions\n",
|
||||
"\n",
|
||||
"Standard mathematical functions can be calculated on any scalar, scalar-valued iterable (ranges, lists, tuples containing numbers), and on `ndarray`s without having to change the call signature. In all cases the functions return a new `ndarray` of typecode `float` (since these functions usually generate float values, anyway). The functions execute faster with `ndarray` arguments than with iterables, because the values of the input vector can be extracted faster. \n",
|
||||
"Standard mathematical functions can be calculated on any scalar, scalar-valued iterable (ranges, lists, tuples containing numbers), and on `ndarray`s without having to change the call signature. In all cases the functions return a new `ndarray` of typecode `float` (since these functions usually generate float values, anyway). The only exceptions to this rule are the `exp`, and `sqrt` functions, which, if `ULAB_SUPPORTS_COMPLEX` is set to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h), can return complex arrays, depending on the argument. All functions execute faster with `ndarray` arguments than with iterables, because the values of the input vector can be extracted faster. \n",
|
||||
"\n",
|
||||
"At present, the following functions are supported:\n",
|
||||
"At present, the following functions are supported (starred functions can operate on, or can return complex arrays):\n",
|
||||
"\n",
|
||||
"`acos`, `acosh`, `arctan2`, `around`, `asin`, `asinh`, `atan`, `arctan2`, `atanh`, `ceil`, `cos`, `degrees`, `exp`, `expm1`, `floor`, `log`, `log10`, `log2`, `radians`, `sin`, `sinh`, `sqrt`, `tan`, `tanh`.\n",
|
||||
"`acos`, `acosh`, `arctan2`, `around`, `asin`, `asinh`, `atan`, `arctan2`, `atanh`, `ceil`, `cos`, `degrees`, `exp*`, `expm1`, `floor`, `log`, `log10`, `log2`, `radians`, `sin`, `sinc`, `sinh`, `sqrt*`, `tan`, `tanh`.\n",
|
||||
"\n",
|
||||
"These functions are applied element-wise to the arguments, thus, e.g., the exponential of a matrix cannot be calculated in this way."
|
||||
"These functions are applied element-wise to the arguments, thus, e.g., the exponential of a matrix cannot be calculated in this way, only the exponential of the matrix entries.\n",
|
||||
"\n",
|
||||
"In order to avoid repeated memory allocations, functions can take the `out=None` optional argument, which must be a floating point `ndarray` of the same size as the input `array`. If these conditions are not fulfilled, and exception will be raised. If `out=None`, a new array will be created upon each invocation of the function."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 13,
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-13T19:11:07.579601Z",
|
||||
|
|
@ -267,6 +269,16 @@
|
|||
" [20.08553692318767, 54.59815003314424, 148.4131591025766],\n",
|
||||
" [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)\n",
|
||||
"\n",
|
||||
"d before invoking the function:\n",
|
||||
" array([[0.0, 1.0, 2.0],\n",
|
||||
" [3.0, 4.0, 5.0],\n",
|
||||
" [6.0, 7.0, 8.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"d afteri nvoking the function:\n",
|
||||
" array([[1.0, 2.718281828459045, 7.38905609893065],\n",
|
||||
" [20.08553692318767, 54.59815003314424, 148.4131591025766],\n",
|
||||
" [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
|
|
@ -290,7 +302,14 @@
|
|||
"# as well as with matrices\n",
|
||||
"c = np.array(range(9)).reshape((3, 3))\n",
|
||||
"print('\\n=============\\nc:\\n', c)\n",
|
||||
"print('exp(c):\\n', np.exp(c))"
|
||||
"print('exp(c):\\n', np.exp(c))\n",
|
||||
"\n",
|
||||
"# using the `out` argument\n",
|
||||
"d = np.array(range(9)).reshape((3, 3))\n",
|
||||
"\n",
|
||||
"print('\\nd before invoking the function:\\n', d)\n",
|
||||
"np.exp(c, out=d)\n",
|
||||
"print('\\nd afteri nvoking the function:\\n', d)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -459,6 +478,96 @@
|
|||
"print('\\ndecimals = -1\\t', np.around(a, decimals=-1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## exp\n",
|
||||
"\n",
|
||||
"If `ULAB_SUPPORTS_COMPLEX` is set to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h), the exponential function can also take complex arrays as its argument, in which case the return value is also complex."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T18:41:51.865779Z",
|
||||
"start_time": "2022-01-07T18:41:51.843897Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\t\t array([1.0, 2.0, 3.0], dtype=float64)\n",
|
||||
"exp(a):\t\t array([2.718281828459045, 7.38905609893065, 20.08553692318767], dtype=float64)\n",
|
||||
"\n",
|
||||
"b:\t\t array([1.0+1.0j, 2.0+2.0j, 3.0+3.0j], dtype=complex)\n",
|
||||
"exp(b):\t\t array([1.468693939915885+2.287355287178842j, -3.074932320639359+6.71884969742825j, -19.88453084414699+2.834471132487004j], dtype=complex)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3])\n",
|
||||
"print('a:\\t\\t', a)\n",
|
||||
"print('exp(a):\\t\\t', np.exp(a))\n",
|
||||
"print()\n",
|
||||
"\n",
|
||||
"b = np.array([1+1j, 2+2j, 3+3j], dtype=np.complex)\n",
|
||||
"print('b:\\t\\t', b)\n",
|
||||
"print('exp(b):\\t\\t', np.exp(b))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## sqrt\n",
|
||||
"\n",
|
||||
"If `ULAB_SUPPORTS_COMPLEX` is set to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h), the exponential function can also take complex arrays as its argument, in which case the return value is also complex. If the input is real, but the results might be complex, the user is supposed to specify the output `dtype` in the function call. Otherwise, the square roots of negative numbers will result in `NaN`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T18:45:26.554520Z",
|
||||
"start_time": "2022-01-07T18:45:26.543552Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\t\t array([1.0, -1.0], dtype=float64)\n",
|
||||
"sqrt(a):\t\t array([1.0, nan], dtype=float64)\n",
|
||||
"sqrt(a):\t\t array([1.0+0.0j, 0.0+1.0j], dtype=complex)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, -1])\n",
|
||||
"print('a:\\t\\t', a)\n",
|
||||
"print('sqrt(a):\\t\\t', np.sqrt(a))\n",
|
||||
"print('sqrt(a):\\t\\t', np.sqrt(a, dtype=np.complex))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -724,7 +833,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
"version": "3.9.13"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
|
|
|
|||
510
docs/scipy-integrate.ipynb
Normal file
510
docs/scipy-integrate.ipynb
Normal file
|
|
@ -0,0 +1,510 @@
|
|||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-12T16:11:12.111639Z",
|
||||
"start_time": "2021-01-12T16:11:11.914041Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Populating the interactive namespace from numpy and matplotlib\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%pylab inline"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Notebook magic"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-29T20:50:20.813162Z",
|
||||
"start_time": "2022-01-29T20:50:20.794562Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"from IPython.core.magic import Magics, magics_class, line_cell_magic\n",
|
||||
"from IPython.core.magic import cell_magic, register_cell_magic, register_line_magic\n",
|
||||
"from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring\n",
|
||||
"import subprocess\n",
|
||||
"import os"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-29T20:50:21.613220Z",
|
||||
"start_time": "2022-01-29T20:50:21.557819Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"@magics_class\n",
|
||||
"class PyboardMagic(Magics):\n",
|
||||
" @cell_magic\n",
|
||||
" @magic_arguments()\n",
|
||||
" @argument('-skip')\n",
|
||||
" @argument('-unix')\n",
|
||||
" @argument('-pyboard')\n",
|
||||
" @argument('-file')\n",
|
||||
" @argument('-data')\n",
|
||||
" @argument('-time')\n",
|
||||
" @argument('-memory')\n",
|
||||
" def micropython(self, line='', cell=None):\n",
|
||||
" args = parse_argstring(self.micropython, line)\n",
|
||||
" if args.skip: # doesn't care about the cell's content\n",
|
||||
" print('skipped execution')\n",
|
||||
" return None # do not parse the rest\n",
|
||||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
" return None\n",
|
||||
" if args.file: # can be used to copy the cell content onto the pyboard's flash\n",
|
||||
" spaces = \" \"\n",
|
||||
" try:\n",
|
||||
" with open(args.file, 'w') as fout:\n",
|
||||
" fout.write(cell.replace('\\t', spaces))\n",
|
||||
" printf('written cell to {}'.format(args.file))\n",
|
||||
" except:\n",
|
||||
" print('Failed to write to disc!')\n",
|
||||
" return None # do not parse the rest\n",
|
||||
" if args.data: # can be used to load data from the pyboard directly into kernel space\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" if len(message) == 0:\n",
|
||||
" print('pyboard >>>')\n",
|
||||
" else:\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
" # register new variable in user namespace\n",
|
||||
" self.shell.user_ns[args.data] = string_to_matrix(message.decode(\"utf-8\"))\n",
|
||||
" \n",
|
||||
" if args.time: # measures the time of executions\n",
|
||||
" pyb.exec('import utime')\n",
|
||||
" message = pyb.exec('t = utime.ticks_us()\\n' + cell + '\\ndelta = utime.ticks_diff(utime.ticks_us(), t)' + \n",
|
||||
" \"\\nprint('execution time: {:d} us'.format(delta))\")\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
" \n",
|
||||
" if args.memory: # prints out memory information \n",
|
||||
" message = pyb.exec('from micropython import mem_info\\nprint(mem_info())\\n')\n",
|
||||
" print(\"memory before execution:\\n========================\\n\", message.decode('utf-8'))\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" print(\">>> \", message.decode('utf-8'))\n",
|
||||
" message = pyb.exec('print(mem_info())')\n",
|
||||
" print(\"memory after execution:\\n========================\\n\", message.decode('utf-8'))\n",
|
||||
"\n",
|
||||
" if args.pyboard:\n",
|
||||
" message = pyb.exec(cell)\n",
|
||||
" print(message.decode('utf-8'))\n",
|
||||
"\n",
|
||||
"ip = get_ipython()\n",
|
||||
"ip.register_magics(PyboardMagic)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## pyboard"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 57,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-07T07:35:35.126401Z",
|
||||
"start_time": "2020-05-07T07:35:35.105824Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import pyboard\n",
|
||||
"pyb = pyboard.Pyboard('/dev/ttyACM0')\n",
|
||||
"pyb.enter_raw_repl()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-19T19:11:18.145548Z",
|
||||
"start_time": "2020-05-19T19:11:18.137468Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"pyb.exit_raw_repl()\n",
|
||||
"pyb.close()"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 58,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-07T07:35:38.725924Z",
|
||||
"start_time": "2020-05-07T07:35:38.645488Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -pyboard 1\n",
|
||||
"\n",
|
||||
"import utime\n",
|
||||
"import ulab as np\n",
|
||||
"\n",
|
||||
"def timeit(n=1000):\n",
|
||||
" def wrapper(f, *args, **kwargs):\n",
|
||||
" func_name = str(f).split(' ')[1]\n",
|
||||
" def new_func(*args, **kwargs):\n",
|
||||
" run_times = np.zeros(n, dtype=np.uint16)\n",
|
||||
" for i in range(n):\n",
|
||||
" t = utime.ticks_us()\n",
|
||||
" result = f(*args, **kwargs)\n",
|
||||
" run_times[i] = utime.ticks_diff(utime.ticks_us(), t)\n",
|
||||
" print('{}() execution times based on {} cycles'.format(func_name, n, (delta2-delta1)/n))\n",
|
||||
" print('\\tbest: %d us'%np.min(run_times))\n",
|
||||
" print('\\tworst: %d us'%np.max(run_times))\n",
|
||||
" print('\\taverage: %d us'%np.mean(run_times))\n",
|
||||
" print('\\tdeviation: +/-%.3f us'%np.std(run_times)) \n",
|
||||
" return result\n",
|
||||
" return new_func\n",
|
||||
" return wrapper\n",
|
||||
"\n",
|
||||
"def timeit(f, *args, **kwargs):\n",
|
||||
" func_name = str(f).split(' ')[1]\n",
|
||||
" def new_func(*args, **kwargs):\n",
|
||||
" t = utime.ticks_us()\n",
|
||||
" result = f(*args, **kwargs)\n",
|
||||
" print('execution time: ', utime.ticks_diff(utime.ticks_us(), t), ' us')\n",
|
||||
" return result\n",
|
||||
" return new_func"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"__END_OF_DEFS__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# scipy.integrate\n",
|
||||
"\n",
|
||||
"This module provides a simplified subset of CPython's `scipy.integrate` module. The algorithms were not ported from CPython's `scipy.integrate` for the sake of resource usage, but derived from a paper found in https://www.genivia.com/qthsh.html. There are four numerical integration algorithms:\n",
|
||||
"\n",
|
||||
"1. [scipy.integrate.quad](#quad)\n",
|
||||
"2. [scipy.integrate.romberg](#romberg)\n",
|
||||
"3. [scipy.integrate.simpson](#simpson)\n",
|
||||
"4. [scipy.integrate.tanhsinh](#tanhsinh)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Introduction\n",
|
||||
"\n",
|
||||
"Numerical integration works best with float64 math enabled. If you require float64 math, be sure to set `MICROPY_OBJ_REPR_A` and `MICROPY_FLOAT_IMPL_DOUBLE`. This being said, the modules work equally well using float32, albeit with reduced precision. The required error tolerance can be specified for each of the function calls using the \"eps=\" option, defaulting to the compiled in `etolerance` value (1e-14 for fp64, 1e-8 for fp32).\n",
|
||||
"\n",
|
||||
"The submodule can be enabled by setting `ULAB_SCIPY_HAS_INTEGRATE_MODULE` in `code/ulab.h`. As for the individual integration algorithms, you can select which to include by setting one or more of `ULAB_INTEGRATE_HAS_QUAD`, `ULAB_INTEGRATE_HAS_ROMBERG`, `ULAB_INTEGRATE_HAS_SIMPSON`, and `ULAB_INTEGRATE_HAS_TANHSINH`.\n",
|
||||
"\n",
|
||||
"Also note that these algorithms do not support complex numbers, although it is certainly possible to implement complex integration in MicroPython on top of this module, e.g. as in https://stackoverflow.com/questions/5965583/use-scipy-integrate-quad-to-integrate-complex-numbers. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## quad\n",
|
||||
"\n",
|
||||
"`scipy`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html \n",
|
||||
"\n",
|
||||
"In CPython `scipy.integrate`, `quad` is a wrapper implementing many algorithms based on the Fortran QUADPACK package. Gauss-Kronrod is just one of them, and it is useful for most general-purpose tasks. This particular function implements an Adaptive Gauss-Kronrod (G10,K21) quadrature algorithm. The Gauss–Kronrod quadrature formula is a variant of Gaussian quadrature, in which the evaluation points are chosen so that an accurate approximation can be computed by re-using the information produced by the computation of a less accurate approximation (https://en.wikipedia.org/wiki/Gauss%E2%80%93Kronrod_quadrature_formula). \n",
|
||||
"\n",
|
||||
"The function takes three to five arguments: \n",
|
||||
"\n",
|
||||
"* f, a callable,\n",
|
||||
"* a and b, the lower and upper integration limit, \n",
|
||||
"* order=, the order of integration (default 5),\n",
|
||||
"* eps=, the error tolerance (default etolerance) \n",
|
||||
"\n",
|
||||
"The function returns the result and the error estimate as a tuple of floats. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-06-19T20:24:10.529668Z",
|
||||
"start_time": "2020-06-19T20:24:10.520389Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"UsageError: Cell magic `%%micropython` not found.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import scipy\n",
|
||||
"\n",
|
||||
"f = lambda x: x**2 + 2*x + 1\n",
|
||||
"result = scipy.integrate.quad(f, 0, 5, order=5, eps=1e-10)\n",
|
||||
"print (f\"result = {result}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## romberg\n",
|
||||
"\n",
|
||||
"`scipy`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.romberg.html \n",
|
||||
"\n",
|
||||
"This function implements the Romberg quadrature algorithm. Romberg's method is a Newton–Cotes formula – it evaluates the integrand at equally spaced points. The integrand must have continuous derivatives, though fairly good results may be obtained if only a few derivatives exist. If it is possible to evaluate the integrand at unequally spaced points, then other methods such as Gaussian quadrature and Clenshaw–Curtis quadrature are generally more accurate (https://en.wikipedia.org/wiki/Romberg%27s_method). \n",
|
||||
"\n",
|
||||
"Please note: This function is deprecated as of SciPy 1.12.0 and will be removed in SciPy 1.15.0. Please use `scipy.integrate.quad` instead. \n",
|
||||
"\n",
|
||||
"The function takes three to five arguments: \n",
|
||||
"\n",
|
||||
"* f, a callable,\n",
|
||||
"* a and b, the lower and upper integration limit, \n",
|
||||
"* steps=, the number of steps taken to calculate (default 100),\n",
|
||||
"* eps=, the error tolerance (default etolerance) \n",
|
||||
"\n",
|
||||
"The function returns the result as a float.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"UsageError: Cell magic `%%micropython` not found.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import scipy\n",
|
||||
"\n",
|
||||
"f = lambda x: x**2 + 2*x + 1\n",
|
||||
"result = scipy.integrate.romberg(f, 0, 5)\n",
|
||||
"print (f\"result = {result}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## simpson\n",
|
||||
"\n",
|
||||
"`scipy`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.simpson.html \n",
|
||||
"\n",
|
||||
"This function is different from CPython's `simpson` method in that it does not take an array of function values but determines the optimal spacing of samples itself. Adaptive Simpson's method, also called adaptive Simpson's rule, is a method of numerical integration proposed by G.F. Kuncir in 1962. It is probably the first recursive adaptive algorithm for numerical integration to appear in print, although more modern adaptive methods based on Gauss–Kronrod quadrature and Clenshaw–Curtis quadrature are now generally preferred (https://en.wikipedia.org/wiki/Adaptive_Simpson%27s_method). \n",
|
||||
"\n",
|
||||
"The function takes three to five arguments: \n",
|
||||
"\n",
|
||||
"* f, a callable,\n",
|
||||
"* a and b, the lower and upper integration limit, \n",
|
||||
"* steps=, the number of steps taken to calculate (default 100),\n",
|
||||
"* eps=, the error tolerance (default etolerance) \n",
|
||||
"\n",
|
||||
"The function returns the result as a float."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"UsageError: Cell magic `%%micropython` not found.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import scipy\n",
|
||||
"\n",
|
||||
"f = lambda x: x**2 + 2*x + 1\n",
|
||||
"result = scipy.integrate.simpson(f, 0, 5)\n",
|
||||
"print (f\"result = {result}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## tanhsinh\n",
|
||||
"\n",
|
||||
"`scipy`: https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html \n",
|
||||
"\n",
|
||||
"In CPython `scipy.integrate`, `tanhsinh` is written in Python (https://github.com/scipy/scipy/blob/main/scipy/integrate/_tanhsinh.py). It is used in cases where Newton-Cotes, Gauss-Kronrod, and other formulae do not work due to properties of the integrand or the integration limits. (In SciPy v1.14.1, it is not a public function but it has been marked as public in SciPy v1.15.0rc1). \n",
|
||||
"\n",
|
||||
"This particular function implements an optimized Tanh-Sinh, Sinh-Sinh and Exp-Sinh quadrature algorithm. It is especially applied where singularities or infinite derivatives exist at one or both endpoints. The method uses hyperbolic functions in a change of variables to transform an integral on the interval x ∈ (−1, 1) to an integral on the entire real line t ∈ (−∞, ∞), the two integrals having the same value. After this transformation, the integrand decays with a double exponential rate, and thus, this method is also known as the double exponential (DE) formula (https://en.wikipedia.org/wiki/Tanh-sinh_quadrature). \n",
|
||||
"\n",
|
||||
"As opposed to the three algorithms mentioned before, it also supports integrals with infinite limits like the Gaussian integral (https://en.wikipedia.org/wiki/Gaussian_integral), as shown below. \n",
|
||||
"\n",
|
||||
"The function takes three to five arguments: \n",
|
||||
"\n",
|
||||
"* f, a callable,\n",
|
||||
"* a and b, the lower and upper integration limit, \n",
|
||||
"* levels=, the number of loops taken to calculate (default 6),\n",
|
||||
"* eps=, the error tolerance (default: etolerance)\n",
|
||||
"\n",
|
||||
"The function returns the result and the error estimate as a tuple of floats.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"UsageError: Cell magic `%%micropython` not found.\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import scipy, numpy as np\n",
|
||||
"from math import *\n",
|
||||
"f = lambda x: exp(- x**2)\n",
|
||||
"result = scipy.integrate.tanhsinh(f, -np.inf, np.inf)\n",
|
||||
"print (f\"result = {result}\")\n",
|
||||
"exact = sqrt(pi) # which is the exact value\n",
|
||||
"print (f\"exact value = {exact}\")\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3 (ipykernel)",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.3"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {
|
||||
"height": "calc(100% - 180px)",
|
||||
"left": "10px",
|
||||
"top": "150px",
|
||||
"width": "382.797px"
|
||||
},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": true
|
||||
},
|
||||
"varInspector": {
|
||||
"cols": {
|
||||
"lenName": 16,
|
||||
"lenType": 16,
|
||||
"lenVar": 40
|
||||
},
|
||||
"kernels_config": {
|
||||
"python": {
|
||||
"delete_cmd_postfix": "",
|
||||
"delete_cmd_prefix": "del ",
|
||||
"library": "var_list.py",
|
||||
"varRefreshCmd": "print(var_dic_list())"
|
||||
},
|
||||
"r": {
|
||||
"delete_cmd_postfix": ") ",
|
||||
"delete_cmd_prefix": "rm(",
|
||||
"library": "var_list.r",
|
||||
"varRefreshCmd": "cat(var_dic_list()) "
|
||||
}
|
||||
},
|
||||
"types_to_exclude": [
|
||||
"module",
|
||||
"function",
|
||||
"builtin_function_or_method",
|
||||
"instance",
|
||||
"_Feature"
|
||||
],
|
||||
"window_display": false
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
|
@ -31,11 +31,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-12T16:11:13.416714Z",
|
||||
"start_time": "2021-01-12T16:11:13.404067Z"
|
||||
"end_time": "2022-01-29T20:50:20.813162Z",
|
||||
"start_time": "2022-01-29T20:50:20.794562Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -49,11 +49,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-12T16:11:13.920842Z",
|
||||
"start_time": "2021-01-12T16:11:13.863737Z"
|
||||
"end_time": "2022-01-29T20:50:21.613220Z",
|
||||
"start_time": "2022-01-29T20:50:21.557819Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -225,10 +225,9 @@
|
|||
"source": [
|
||||
"# scipy.signal\n",
|
||||
"\n",
|
||||
"Functions in the `signal` module can be called by prepending them by `scipy.signal.`. The module defines the following two functions:\n",
|
||||
"This module defines the single function:\n",
|
||||
"\n",
|
||||
"1. [scipy.signal.sosfilt](#sosfilt)\n",
|
||||
"1. [scipy.signal.spectrogram](#spectrogram)"
|
||||
"1. [scipy.signal.sosfilt](#sosfilt)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -315,100 +314,6 @@
|
|||
"print('y: ', y)\n",
|
||||
"print('\\n' + '='*40 + '\\nzf: ', zf)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## spectrogram\n",
|
||||
"\n",
|
||||
"In addition to the Fourier transform and its inverse, `ulab` also sports a function called `spectrogram`, which returns the absolute value of the Fourier transform. This could be used to find the dominant spectral component in a time series. The arguments are treated in the same way as in `fft`, and `ifft`."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-12T16:12:06.573408Z",
|
||||
"start_time": "2021-01-12T16:12:06.560558Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"original vector:\t array([0.0, 0.009775015390171337, 0.01954909674625918, ..., -0.5275140569487312, -0.5357931822978732, -0.5440211108893639], dtype=float64)\n",
|
||||
"\n",
|
||||
"spectrum:\t array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"from ulab import scipy as spy\n",
|
||||
"\n",
|
||||
"x = np.linspace(0, 10, num=1024)\n",
|
||||
"y = np.sin(x)\n",
|
||||
"\n",
|
||||
"a = spy.signal.spectrogram(y)\n",
|
||||
"\n",
|
||||
"print('original vector:\\t', y)\n",
|
||||
"print('\\nspectrum:\\t', a)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As such, `spectrogram` is really just a shorthand for `np.sqrt(a*a + b*b)`:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-12T16:13:36.726662Z",
|
||||
"start_time": "2021-01-12T16:13:36.705036Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\n",
|
||||
"spectrum calculated the hard way:\t array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)\n",
|
||||
"\n",
|
||||
"spectrum calculated the lazy way:\t array([187.8635087634579, 315.3112063607119, 347.8814873399374, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"from ulab import scipy as spy\n",
|
||||
"\n",
|
||||
"x = np.linspace(0, 10, num=1024)\n",
|
||||
"y = np.sin(x)\n",
|
||||
"\n",
|
||||
"a, b = np.fft.fft(y)\n",
|
||||
"\n",
|
||||
"print('\\nspectrum calculated the hard way:\\t', np.sqrt(a*a + b*b))\n",
|
||||
"\n",
|
||||
"a = spy.signal.spectrogram(y)\n",
|
||||
"\n",
|
||||
"print('\\nspectrum calculated the lazy way:\\t', a)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,367 @@
|
|||
Fri, 06 Jun 2025
|
||||
|
||||
version 6.8.0
|
||||
|
||||
expose ndim property
|
||||
|
||||
Fri, 06 Jun 2025
|
||||
|
||||
version 6.7.7
|
||||
|
||||
fix ndarray type inference for micropython objects
|
||||
|
||||
Thu, 29 May 2025
|
||||
|
||||
version 6.7.6
|
||||
|
||||
loadtxt can deal with multi-line comments
|
||||
|
||||
Thu, 29 May 2025
|
||||
|
||||
version 6.7.5
|
||||
|
||||
fix typo and shape in radnom module
|
||||
|
||||
Sun, 16 Mar 2025
|
||||
|
||||
version 6.7.4
|
||||
|
||||
re-name integration constants to avoid name clash with EPS ports
|
||||
|
||||
Sun, 26 Jan 2025
|
||||
|
||||
version 6.7.3
|
||||
|
||||
fix keepdims for min, max, argmin, argmax
|
||||
|
||||
Sun, 19 Jan 2025
|
||||
|
||||
version 6.7.2
|
||||
|
||||
fix keepdims for std, remove redundant macros from numerical.h, update documentation
|
||||
|
||||
Mon, 30 Dec 2024
|
||||
|
||||
version 6.7.1
|
||||
|
||||
add keepdims keyword argument to numerical functions
|
||||
|
||||
Sun, 15 Dec 2024
|
||||
|
||||
version 6.7.0
|
||||
|
||||
add scipy.integrate module
|
||||
|
||||
Sun, 24 Nov 2024
|
||||
|
||||
version 6.6.1
|
||||
|
||||
fix compilation error, for complexes
|
||||
|
||||
Wed, 9 Oct 2024
|
||||
|
||||
version 6.6.0
|
||||
|
||||
add numpy.take
|
||||
|
||||
Sat, 14 Sep 2024
|
||||
|
||||
version 6.5.5
|
||||
|
||||
add scratchpad, out, log keyword arguments to spectrum
|
||||
|
||||
Sat, 14 Sep 2024
|
||||
|
||||
version 6.5.4
|
||||
|
||||
fix roll, when shift is 0
|
||||
|
||||
Wed, 6 Mar 2024
|
||||
|
||||
version 6.5.2
|
||||
|
||||
allow loadtxt to parse numbers, even if built-in complexes are not supported
|
||||
|
||||
Tue, 9 Jan 2024
|
||||
|
||||
version 6.5.0
|
||||
|
||||
add random module
|
||||
|
||||
Mon, 25 Dec 2023
|
||||
|
||||
version 6.4.3
|
||||
|
||||
fix the 'np.delete' error that occurs when passing an empty iterable object as the second positional argument (#653)
|
||||
|
||||
Thu, 11 Dec 2023
|
||||
|
||||
version 6.4.2
|
||||
|
||||
fix upcasting with two uint8 operands (#650)
|
||||
|
||||
Thu, 10 Aug 2023
|
||||
|
||||
version 6.4.1
|
||||
|
||||
fix BOOLEAN issue, which would cause numpy.where funciton abnormally on RP2040(#643)
|
||||
|
||||
Thu, 20 Jul 2023
|
||||
|
||||
version 6.4.0
|
||||
|
||||
implement AND, OR, and XOR binary operators
|
||||
|
||||
Sat, 1 Jul 2023
|
||||
|
||||
version 6.3.5
|
||||
|
||||
allow function itertor in math functions with the out keyword
|
||||
|
||||
Fri, 12 May 2023
|
||||
|
||||
version 6.3.4
|
||||
|
||||
fix compile error when COMPLEX support not enabled
|
||||
|
||||
version 6.3.3
|
||||
|
||||
Polyval handles non-array as second argument (#601)
|
||||
|
||||
version 6.3.2
|
||||
|
||||
fix out of bound read
|
||||
|
||||
version 6.3.1
|
||||
|
||||
fix integer overflows
|
||||
|
||||
version 6.3.0
|
||||
|
||||
add bitwise operators
|
||||
|
||||
Wed, 17 May 2023
|
||||
|
||||
version 6.1.1
|
||||
|
||||
fix ndarray subscription, when value is NULL
|
||||
|
||||
Tue, 16 May 2023
|
||||
|
||||
version 6.1.0
|
||||
|
||||
add sinc function
|
||||
|
||||
Fri, 12 May 2023
|
||||
|
||||
version 6.0.13
|
||||
|
||||
add bitwise operators
|
||||
|
||||
Sun, 7 May 2023
|
||||
|
||||
version 6.0.12
|
||||
|
||||
ndarray_from_mp_obj correctly treats Boolean arguments
|
||||
|
||||
Sat, 6 May 2023
|
||||
|
||||
version 6.0.11
|
||||
|
||||
.reshape can now interpret unknown shape dimension
|
||||
|
||||
Sat, 6 May 2023
|
||||
|
||||
version 6.0.10
|
||||
|
||||
fix binary division
|
||||
|
||||
Sun, 21 Jan 2023
|
||||
|
||||
version 6.0.6
|
||||
|
||||
raise proper exception in arange
|
||||
|
||||
Sun, 21 Jan 2023
|
||||
|
||||
version 6.0.7
|
||||
|
||||
treat empty arrays in sort_complex correctly
|
||||
|
||||
Sun, 21 Jan 2023
|
||||
|
||||
version 6.0.5
|
||||
|
||||
fix ones()/zeros() method when the amount of memory to allocate overflows
|
||||
|
||||
Sun, 15 Jan 2023
|
||||
|
||||
version 6.0.4
|
||||
|
||||
fix dot function
|
||||
|
||||
Sat, 14 Jan 2023
|
||||
|
||||
version 6.0.3
|
||||
|
||||
fix how concatenate deals with scalar inputs
|
||||
|
||||
Tue, 3 Jan 2023
|
||||
|
||||
version 6.0.2
|
||||
|
||||
fix vectorize
|
||||
|
||||
Sat, 5 Nov 2022
|
||||
|
||||
version 6.0.1
|
||||
|
||||
fix fft.ifft
|
||||
|
||||
Wed, 21 Sep 2022
|
||||
|
||||
version 6.0.0
|
||||
|
||||
bring ulab in line with the latest version of micropython
|
||||
|
||||
Thu, 4 Aug 2022
|
||||
|
||||
version 5.1.1
|
||||
|
||||
fix how arctan2 treats scalars
|
||||
|
||||
Mon, 25 July 2022
|
||||
|
||||
version 5.1.0
|
||||
|
||||
add nonzero
|
||||
|
||||
Mon, 16 May 2022
|
||||
|
||||
version 5.0.7
|
||||
|
||||
fix in-place assignment from slices
|
||||
|
||||
Thu, 14 Apr 2022
|
||||
|
||||
version 5.0.6
|
||||
|
||||
use m_new0 conditionally
|
||||
|
||||
Thu, 14 Apr 2022
|
||||
|
||||
version 5.0.5
|
||||
|
||||
fix sorting on empty arrays
|
||||
|
||||
Fri, 18 Feb 2022
|
||||
|
||||
version 5.0.4
|
||||
|
||||
fix the handling of empty arrays in binary_op
|
||||
|
||||
Thu, 10 Feb 2022
|
||||
|
||||
version 5.0.3
|
||||
|
||||
fix complex slicing
|
||||
|
||||
Tue, 8 Feb 2022
|
||||
|
||||
version 5.0.2
|
||||
|
||||
fix np.diag
|
||||
|
||||
Thu, 3 Feb 2022
|
||||
|
||||
version 5.0.1
|
||||
|
||||
add optional ULAB_HASH string
|
||||
|
||||
Tue, 1 Feb 2022
|
||||
|
||||
version 5.0.0
|
||||
|
||||
move scipy.signal.spectrogram to utils.spectrogram
|
||||
|
||||
Tue, 1 Feb 2022
|
||||
|
||||
version 4.4.2
|
||||
|
||||
add skiprows keyword to loadtxt
|
||||
|
||||
Sat, 29 Jan 2022
|
||||
|
||||
version 4.4.1
|
||||
|
||||
add dtype keyword to loadtxt
|
||||
|
||||
Thu, 27 Jan 2022
|
||||
|
||||
version 4.4.0
|
||||
|
||||
implement numpy.savetxt, numpy.loadtxt
|
||||
|
||||
Tue, 15 Jan 2022
|
||||
|
||||
version 4.3.2
|
||||
|
||||
fix rp2 port compilation
|
||||
|
||||
Wed, 19 Jan 2022
|
||||
|
||||
version 4.3.1
|
||||
|
||||
fix signal.sosfilt
|
||||
|
||||
Wed, 19 Jan 2022
|
||||
|
||||
version 4.3.0
|
||||
|
||||
implement numpy.save, numpy.load
|
||||
|
||||
Tue, 18 Jan 2022
|
||||
|
||||
version 4.2.1
|
||||
|
||||
fix ndarray_copy_view for Boolean dtypes
|
||||
|
||||
Fri, 14 Jan 2022
|
||||
|
||||
version 4.2.0
|
||||
|
||||
add numpy.size, asarray
|
||||
|
||||
Wed, 12 Jan 2022
|
||||
|
||||
version 4.2.0
|
||||
|
||||
implement numpy.save, numpy.load
|
||||
|
||||
Wed, 12 Jan 2022
|
||||
|
||||
version 4.1.1
|
||||
|
||||
fix complex printout for long arrays
|
||||
|
||||
Wed, 12 Jan 2022
|
||||
|
||||
version 4.1.0
|
||||
|
||||
add numpy.delete
|
||||
|
||||
Sat, 8 Jan 2022
|
||||
|
||||
version 4.0.0
|
||||
|
||||
add complex support, .tolist() method, .imag, .real array properties, compress, conjugate, imag, real, sort_complex functions
|
||||
|
||||
Fri, 3 Dec 2021
|
||||
|
||||
version 3.3.8
|
||||
|
||||
fix any/all function
|
||||
|
||||
Tue, 30 Nov 2021
|
||||
|
||||
version 3.3.7
|
||||
|
|
|
|||
|
|
@ -2,19 +2,34 @@
|
|||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"source": [
|
||||
"# conf.py"
|
||||
],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-05-01T09:27:13.438054Z",
|
||||
"start_time": "2020-05-01T09:27:13.191491Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
"source": [
|
||||
"# conf.py"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-02-09T06:27:15.118699Z",
|
||||
"start_time": "2022-02-09T06:27:15.100980Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting manual/source/conf.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile manual/source/conf.py\n",
|
||||
"# Configuration file for the Sphinx documentation builder.\n",
|
||||
|
|
@ -42,11 +57,11 @@
|
|||
"# -- Project information -----------------------------------------------------\n",
|
||||
"\n",
|
||||
"project = 'The ulab book'\n",
|
||||
"copyright = '2019-2021, Zoltán Vörös and contributors'\n",
|
||||
"copyright = '2019-2025, Zoltán Vörös and contributors'\n",
|
||||
"author = 'Zoltán Vörös'\n",
|
||||
"\n",
|
||||
"# The full version, including alpha/beta/rc tags\n",
|
||||
"release = '3.3.4'\n",
|
||||
"release = '6.9.0'\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"# -- General configuration ---------------------------------------------------\n",
|
||||
|
|
@ -129,26 +144,26 @@
|
|||
" html_theme_path = ['.']\n",
|
||||
"else:\n",
|
||||
" html_theme_path = ['.']"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Overwriting manual/source/conf.py\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-05-09T06:05:50.855683Z",
|
||||
"start_time": "2021-05-09T06:05:50.838482Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-05-09T06:06:28.491158Z",
|
||||
"start_time": "2021-05-09T06:06:28.477127Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting manual/source/index.rst\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile manual/source/index.rst\n",
|
||||
"\n",
|
||||
|
|
@ -175,6 +190,8 @@
|
|||
" numpy-universal\n",
|
||||
" numpy-fft\n",
|
||||
" numpy-linalg\n",
|
||||
" numpy-random\n",
|
||||
" scipy-integrate\n",
|
||||
" scipy-linalg\n",
|
||||
" scipy-optimize\n",
|
||||
" scipy-signal\n",
|
||||
|
|
@ -189,33 +206,25 @@
|
|||
"* :ref:`genindex`\n",
|
||||
"* :ref:`modindex`\n",
|
||||
"* :ref:`search`"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Overwriting manual/source/index.rst\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-05-09T06:06:28.491158Z",
|
||||
"start_time": "2021-05-09T06:06:28.477127Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Notebook conversion"
|
||||
],
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-02-09T06:27:21.647179Z",
|
||||
"start_time": "2022-02-09T06:27:20.019520Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import nbformat as nb\n",
|
||||
"import nbformat.v4.nbbase as nb4\n",
|
||||
|
|
@ -245,18 +254,55 @@
|
|||
" # it's a bit odd, but even an emtpy notebook is converted into a \"None\" string\n",
|
||||
" rst = rst.lstrip('None')\n",
|
||||
" fout.write(rst)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-05-09T06:06:35.839960Z",
|
||||
"start_time": "2021-05-09T06:06:33.112686Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-02-09T06:27:42.024028Z",
|
||||
"start_time": "2022-02-09T06:27:36.109093Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n",
|
||||
"/home/v923z/anaconda3/lib/python3.11/site-packages/nbconvert/exporters/exporter.py:349: MissingIDFieldWarning: Code cell is missing an id field, this will become a hard error in future nbformat versions. You may want to use `normalize()` on your notebooks before validations (available since nbformat 5.1.4). Previous versions of nbformat are fixing this issue transparently, and will stop doing so in the future.\n",
|
||||
" _, nbc = validator.normalize(nbc)\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"files = ['ulab-intro',\n",
|
||||
" 'ulab-ndarray',\n",
|
||||
|
|
@ -264,6 +310,8 @@
|
|||
" 'numpy-universal',\n",
|
||||
" 'numpy-fft',\n",
|
||||
" 'numpy-linalg',\n",
|
||||
" 'numpy-random',\n",
|
||||
" 'scipy-integrate',\n",
|
||||
" 'scipy-linalg',\n",
|
||||
" 'scipy-optimize',\n",
|
||||
" 'scipy-signal',\n",
|
||||
|
|
@ -274,25 +322,33 @@
|
|||
"\n",
|
||||
"for file in files:\n",
|
||||
" convert_notebook(file)"
|
||||
],
|
||||
"outputs": [],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-05-09T06:07:00.143083Z",
|
||||
"start_time": "2021-05-09T06:06:56.719659Z"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Template"
|
||||
],
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-30T19:04:50.295563Z",
|
||||
"start_time": "2020-10-30T19:04:50.227535Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Overwriting ./templates/manual.tpl\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile ./templates/manual.tpl\n",
|
||||
"\n",
|
||||
|
|
@ -408,35 +464,21 @@
|
|||
"{% block unknowncell scoped %}\n",
|
||||
"unknown type {{cell.type}}\n",
|
||||
"{% endblock unknowncell %}\n"
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"Overwriting ./templates/manual.tpl\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-30T19:04:50.295563Z",
|
||||
"start_time": "2020-10-30T19:04:50.227535Z"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"source": [],
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"metadata": {}
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3.8.5 64-bit ('base': conda)"
|
||||
"display_name": "base",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
|
|
@ -448,7 +490,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
"version": "3.11.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
|
|
@ -496,9 +538,6 @@
|
|||
"_Feature"
|
||||
],
|
||||
"window_display": false
|
||||
},
|
||||
"interpreter": {
|
||||
"hash": "ce9a02f9f7db620716422019cafa4bc1786ca85daa298b819f6da075e7993842"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
|
|||
|
|
@ -10,13 +10,6 @@
|
|||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stderr",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Matplotlib is building the font cache; this may take a moment.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
|
|
@ -41,8 +34,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-08T12:07:56.746059Z",
|
||||
"start_time": "2021-01-08T12:07:56.737187Z"
|
||||
"end_time": "2022-01-07T18:13:14.590799Z",
|
||||
"start_time": "2022-01-07T18:13:14.585845Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -56,11 +49,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-01-08T12:08:00.405800Z",
|
||||
"start_time": "2021-01-08T12:08:00.382869Z"
|
||||
"end_time": "2022-01-07T18:20:56.550047Z",
|
||||
"start_time": "2022-01-07T18:20:56.527475Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -84,7 +77,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -239,7 +232,7 @@
|
|||
"source": [
|
||||
"## Enter ulab\n",
|
||||
"\n",
|
||||
"`ulab` is a `numpy`-like module for `micropython` and its derivatives, meant to simplify and speed up common mathematical operations on arrays. `ulab` implements a small subset of `numpy` and `scipy`. The functions were chosen such that they might be useful in the context of a microcontroller. However, the project is a living one, and suggestions for new features are always welcome. \n",
|
||||
"`ulab` is a `numpy`-like module for `micropython` and its derivatives, meant to simplify and speed up common mathematical operations on arrays. `ulab` implements a small subset of `numpy` and `scipy`, as well as a number of functions manipulating byte arrays. The functions were chosen such that they might be useful in the context of a microcontroller. However, the project is a living one, and suggestions for new features are always welcome. \n",
|
||||
"\n",
|
||||
"This document discusses how you can use the library, starting from building your own firmware, through questions like what affects the firmware size, what are the trade-offs, and what are the most important differences to `numpy` and `scipy`, respectively. The document is organised as follows:\n",
|
||||
"\n",
|
||||
|
|
@ -276,8 +269,9 @@
|
|||
"- fast Fourier transforms\n",
|
||||
"- filtering of data (convolution and second-order filters)\n",
|
||||
"- function minimisation, fitting, and numerical approximation routines\n",
|
||||
"- interfacing between numerical data and peripheral hardware devices\n",
|
||||
"\n",
|
||||
"`ulab` implements close to a hundred functions and array methods. At the time of writing this manual (for version 2.1.0), the library adds approximately 120 kB of extra compiled code to the `micropython` (pyboard.v.11) firmware. However, if you are tight with flash space, you can easily shave tens of kB off the firmware. In fact, if only a small sub-set of functions are needed, you can get away with less than 10 kB of flash space. See the section on [customising ulab](#Customising-the-firmware).\n",
|
||||
"`ulab` implements close to a hundred functions and array methods. At the time of writing this manual (for version 4.0.0), the library adds approximately 120 kB of extra compiled code to the `micropython` (pyboard.v.1.17) firmware. However, if you are tight with flash space, you can easily shave tens of kB off the firmware. In fact, if only a small sub-set of functions are needed, you can get away with less than 10 kB of flash space. See the section on [customising ulab](#Customising-the-firmware).\n",
|
||||
"\n",
|
||||
"## Resources and legal matters\n",
|
||||
"\n",
|
||||
|
|
@ -295,7 +289,7 @@
|
|||
"\n",
|
||||
"## Differences between micropython-ulab and circuitpython-ulab\n",
|
||||
"\n",
|
||||
"`ulab` has originally been developed for `micropython`, but has since been integrated into a number of its flavours. Most of these flavours are simply forks of `micropython` itself, with some additional functionality. One of the notable exceptions is `circuitpython`, which has slightly diverged at the core level, and this has some minor consequences. Some of these concern the C implementation details only, which all have been sorted out with the generous and enthusiastic support of Jeff Epler from [Adafruit Industries](http://www.adafruit.com).\n",
|
||||
"`ulab` has originally been developed for `micropython`, but has since been integrated into a number of its flavours. Most of these are simply forks of `micropython` itself, with some additional functionality. One of the notable exceptions is `circuitpython`, which has slightly diverged at the core level, and this has some minor consequences. Some of these concern the C implementation details only, which all have been sorted out with the generous and enthusiastic support of Jeff Epler from [Adafruit Industries](http://www.adafruit.com).\n",
|
||||
"\n",
|
||||
"There are, however, a couple of instances, where the two environments differ at the python level in how the class properties can be accessed. We will point out the differences and possible workarounds at the relevant places in this document."
|
||||
]
|
||||
|
|
@ -323,6 +317,17 @@
|
|||
"// A considerable amount of flash space can be saved by removing (setting\n",
|
||||
"// the corresponding constants to 0) the unnecessary functions and features.\n",
|
||||
"\n",
|
||||
"// Values defined here can be overridden by your own config file as\n",
|
||||
"// make -DULAB_CONFIG_FILE=\"my_ulab_config.h\"\n",
|
||||
"#if defined(ULAB_CONFIG_FILE)\n",
|
||||
"#include ULAB_CONFIG_FILE\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
"// Adds support for complex ndarrays\n",
|
||||
"#ifndef ULAB_SUPPORTS_COMPLEX\n",
|
||||
"#define ULAB_SUPPORTS_COMPLEX (1)\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
"// Determines, whether scipy is defined in ulab. The sub-modules and functions\n",
|
||||
"// of scipy have to be defined separately\n",
|
||||
"#define ULAB_HAS_SCIPY (1)\n",
|
||||
|
|
@ -382,7 +387,7 @@
|
|||
"\n",
|
||||
"## Compatibility with numpy\n",
|
||||
"\n",
|
||||
"The functions implemented in `ulab` are organised in three sub-modules at the C level, namely, `numpy`, `scipy`, and `user`. This modularity is elevated to `python`, meaning that in order to use functions that are part of `numpy`, you have to import `numpy` as\n",
|
||||
"The functions implemented in `ulab` are organised in four sub-modules at the C level, namely, `numpy`, `scipy`, `utils`, and `user`. This modularity is elevated to `python`, meaning that in order to use functions that are part of `numpy`, you have to import `numpy` as\n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from ulab import numpy as np\n",
|
||||
|
|
@ -392,7 +397,7 @@
|
|||
"np.polyval(p, x)\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"There are a couple of exceptions to this rule, namely `fft`, and `linalg`, which are sub-modules even in `numpy`, thus you have to write them out as \n",
|
||||
"There are a couple of exceptions to this rule, namely `fft`, `linalg`, and `random`, which are sub-modules even in `numpy`, thus you have to write them out as \n",
|
||||
"\n",
|
||||
"```python\n",
|
||||
"from ulab import numpy as np\n",
|
||||
|
|
@ -607,6 +612,45 @@
|
|||
"print('numerical value of dimensions: ', version_num)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ulab with complex arrays\n",
|
||||
"\n",
|
||||
"If the firmware supports complex arrays, `-c` is appended to the version string as can be seen below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T18:21:04.079894Z",
|
||||
"start_time": "2022-01-07T18:21:04.058855Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"version string: 4.0.0-2D-c\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab\n",
|
||||
"\n",
|
||||
"version = ulab.__version__\n",
|
||||
"\n",
|
||||
"print('version string: ', version)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
|
|
@ -791,7 +835,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
"version": "3.9.13"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
"execution_count": 1,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-15T15:55:00.261542Z",
|
||||
"start_time": "2021-02-15T15:55:00.255639Z"
|
||||
"end_time": "2022-02-09T06:10:18.391925Z",
|
||||
"start_time": "2022-02-09T06:10:18.388146Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -52,8 +52,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-02-15T15:55:02.228409Z",
|
||||
"start_time": "2021-02-15T15:55:02.207636Z"
|
||||
"end_time": "2022-02-09T06:10:19.000982Z",
|
||||
"start_time": "2022-02-09T06:10:18.979322Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -312,7 +312,7 @@
|
|||
"\n",
|
||||
"If the iterable is one-dimensional, i.e., one whose elements are numbers, then a row vector will be created and returned. If the iterable is two-dimensional, i.e., one whose elements are again iterables, a matrix will be created. If the lengths of the iterables are not consistent, a `ValueError` will be raised. Iterables of different types can be mixed in the initialisation function. \n",
|
||||
"\n",
|
||||
"If the `dtype` keyword with the possible `uint8/int8/uint16/int16/float` values is supplied, the new `ndarray` will have that type, otherwise, it assumes `float` as default. "
|
||||
"If the `dtype` keyword with the possible `uint8/int8/uint16/int16/float` values is supplied, the new `ndarray` will have that type, otherwise, it assumes `float` as default. In addition, if `ULAB_SUPPORTS_COMPLEX` is set to 1 in [ulab.h](https://github.com/v923z/micropython-ulab/blob/master/code/ulab.h), the `dtype` can also take on the value of `complex`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -505,28 +505,28 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Array initialisation functions\n",
|
||||
"# Array initialisation functions\n",
|
||||
"\n",
|
||||
"There are nine functions that can be used for initialising an array.\n",
|
||||
"There are nine functions that can be used for initialising an array. Starred functions accept `complex` as the value of the `dtype`, if the firmware was compiled with complex support.\n",
|
||||
"\n",
|
||||
"1. [numpy.arange](#arange)\n",
|
||||
"1. [numpy.concatenate](#concatenate)\n",
|
||||
"1. [numpy.diag](#diag)\n",
|
||||
"1. [numpy.empty](#empty)\n",
|
||||
"1. [numpy.eye](#eye)\n",
|
||||
"1. [numpy.diag*](#diag)\n",
|
||||
"1. [numpy.empty*](#empty)\n",
|
||||
"1. [numpy.eye*](#eye)\n",
|
||||
"1. [numpy.frombuffer](#frombuffer)\n",
|
||||
"1. [numpy.full](#full)\n",
|
||||
"1. [numpy.linspace](#linspace)\n",
|
||||
"1. [numpy.full*](#full)\n",
|
||||
"1. [numpy.linspace*](#linspace)\n",
|
||||
"1. [numpy.logspace](#logspace)\n",
|
||||
"1. [numpy.ones](#ones)\n",
|
||||
"1. [numpy.zeros](#zeros)"
|
||||
"1. [numpy.ones*](#ones)\n",
|
||||
"1. [numpy.zeros*](#zeros)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### arange\n",
|
||||
"## arange\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.arange.html\n",
|
||||
"\n",
|
||||
|
|
@ -571,7 +571,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### concatenate\n",
|
||||
"## concatenate\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.concatenate.html\n",
|
||||
"\n",
|
||||
|
|
@ -675,6 +675,8 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## diag\n",
|
||||
"\n",
|
||||
|
|
@ -682,75 +684,137 @@
|
|||
"\n",
|
||||
"Extract a diagonal, or construct a diagonal array.\n",
|
||||
"\n",
|
||||
"The function takes two arguments, an `ndarray`, and a shift. If the first argument is a two-dimensional array, the function returns a one-dimensional array containing the diagonal entries. The diagonal can be shifted by an amount given in the second argument.\n",
|
||||
"The function takes a positional argument, an `ndarray`, or any `micropython` iterable, and an optional keyword argument, a shift, with a default value of 0. If the first argument is a two-dimensional array (or a two-dimensional iterable, e.g., a list of lists), the function returns a one-dimensional array containing the diagonal entries. The diagonal can be shifted by an amount given in the second argument. If the shift is larger than the length of the corresponding axis, an empty array is returned.\n",
|
||||
"\n",
|
||||
"If the first argument is a one-dimensional array, the function returns a two-dimensional tensor with its diagonal elements given by the first argument.\n"
|
||||
"If the first argument is a one-dimensional array, the function returns a two-dimensional square tensor with its diagonal elements given by the first argument. Again, the diagonal be shifted by an amount given by the keyword argument.\n",
|
||||
"\n",
|
||||
"The `diag` function can accept a complex array, if the firmware was compiled with complex support."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-02-09T06:24:38.290495Z",
|
||||
"start_time": "2022-02-09T06:24:38.273075Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"array([[1, 0, 0],\n",
|
||||
" [0, 2, 0],\n",
|
||||
" [0, 0, 3]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"diagonal shifted by 2\n",
|
||||
"array([[0, 0, 1, 0, 0],\n",
|
||||
" [0, 0, 0, 2, 0],\n",
|
||||
" [0, 0, 0, 0, 3],\n",
|
||||
" [0, 0, 0, 0, 0],\n",
|
||||
" [0, 0, 0, 0, 0]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"diagonal shifted by -2\n",
|
||||
"array([[0, 0, 0, 0, 0],\n",
|
||||
" [0, 0, 0, 0, 0],\n",
|
||||
" [1, 0, 0, 0, 0],\n",
|
||||
" [0, 2, 0, 0, 0],\n",
|
||||
" [0, 0, 3, 0, 0]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3], dtype=np.uint8)\n",
|
||||
"print(np.diag(a))\n",
|
||||
"\n",
|
||||
"print('\\ndiagonal shifted by 2')\n",
|
||||
"print(np.diag(a, k=2))\n",
|
||||
"\n",
|
||||
"print('\\ndiagonal shifted by -2')\n",
|
||||
"print(np.diag(a, k=-2))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-02-09T06:26:39.213828Z",
|
||||
"start_time": "2022-02-09T06:26:39.199294Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"array([[0, 1, 2, 3],\n",
|
||||
" [4, 5, 6, 7],\n",
|
||||
" [8, 9, 10, 11],\n",
|
||||
" [12, 13, 14, 15]], dtype=int16)\n",
|
||||
"\n",
|
||||
"diagonal of a:\n",
|
||||
"array([0, 5, 10, 15], dtype=int16)\n",
|
||||
"\n",
|
||||
"diagonal of a:\n",
|
||||
"array([0, 5, 10, 15], dtype=int16)\n",
|
||||
"\n",
|
||||
"diagonal of a, shifted by 2\n",
|
||||
"array([2, 7], dtype=int16)\n",
|
||||
"\n",
|
||||
"diagonal of a, shifted by 5\n",
|
||||
"array([], dtype=int16)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.arange(16).reshape((4, 4))\n",
|
||||
"print(a)\n",
|
||||
"print('\\ndiagonal of a:')\n",
|
||||
"print(np.diag(a))\n",
|
||||
"\n",
|
||||
"print('\\ndiagonal of a:')\n",
|
||||
"print(np.diag(a))\n",
|
||||
"\n",
|
||||
"print('\\ndiagonal of a, shifted by 2')\n",
|
||||
"print(np.diag(a, k=2))\n",
|
||||
"\n",
|
||||
"print('\\ndiagonal of a, shifted by 5')\n",
|
||||
"print(np.diag(a, k=5))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"array([[1.0, 0.0, 0.0, 0.0],\n [0.0, 2.0, 0.0, 0.0],\n [0.0, 0.0, 3.0, 0.0],\n [0.0, 0.0, 0.0, 4.0]], dtype=float64)\n\n\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3, 4])\n",
|
||||
"print(np.diag(a))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"text": [
|
||||
"a: array([[0.0, 1.0, 2.0, 3.0],\n [4.0, 5.0, 6.0, 7.0],\n [8.0, 9.0, 10.0, 11.0],\n [12.0, 13.0, 14.0, 15.0]], dtype=float64)\n\ndiagonal of a: array([0.0, 5.0, 10.0, 15.0], dtype=float64)\n\n\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array(range(16)).reshape((4, 4))\n",
|
||||
"print('a: ', a)\n",
|
||||
"print()\n",
|
||||
"print('diagonal of a: ', np.diag(a))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"source": [
|
||||
"## empty\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.empty.html\n",
|
||||
"\n",
|
||||
"`empty` is simply an alias for `zeros`, i.e., as opposed to `numpy`, the entries of the tensor will be initialised to zero."
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
"`empty` is simply an alias for `zeros`, i.e., as opposed to `numpy`, the entries of the tensor will be initialised to zero. \n",
|
||||
"\n",
|
||||
"The `empty` function can accept complex as the value of the dtype, if the firmware was compiled with complex support."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### eye\n",
|
||||
"## eye\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.eye.html\n",
|
||||
"\n",
|
||||
|
|
@ -759,14 +823,16 @@
|
|||
"```python\n",
|
||||
"eye(N, M, k=0, dtype=float)\n",
|
||||
"```\n",
|
||||
"where `N` (`M`) specify the dimensions of the matrix (if only `N` is supplied, then we get a square matrix, otherwise one with `M` rows, and `N` columns), and `k` is the shift of the ones (the main diagonal corresponds to `k=0`). Here are a couple of examples."
|
||||
"where `N` (`M`) specify the dimensions of the matrix (if only `N` is supplied, then we get a square matrix, otherwise one with `M` rows, and `N` columns), and `k` is the shift of the ones (the main diagonal corresponds to `k=0`). Here are a couple of examples.\n",
|
||||
"\n",
|
||||
"The `eye` function can accept `complex` as the value of the `dtype`, if the firmware was compiled with complex support."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### With a single argument"
|
||||
"### With a single argument"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -805,7 +871,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"#### Specifying the dimensions of the matrix"
|
||||
"### Specifying the dimensions of the matrix"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -874,7 +940,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### frombuffer\n",
|
||||
"## frombuffer\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.frombuffer.html\n",
|
||||
"\n",
|
||||
|
|
@ -928,11 +994,13 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### full\n",
|
||||
"## full\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.full.html\n",
|
||||
"\n",
|
||||
"The function returns an array of arbitrary dimension, whose elements are all equal to the second positional argument. The first argument is a tuple describing the shape of the tensor. The `dtype` keyword argument with a default value of `float` can also be supplied."
|
||||
"The function returns an array of arbitrary dimension, whose elements are all equal to the second positional argument. The first argument is a tuple describing the shape of the tensor. The `dtype` keyword argument with a default value of `float` can also be supplied.\n",
|
||||
"\n",
|
||||
"The `full` function can accept a complex scalar, or `complex` as the value of `dtype`, if the firmware was compiled with complex support."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -978,11 +1046,13 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### linspace\n",
|
||||
"## linspace\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html\n",
|
||||
"\n",
|
||||
"This function returns an array, whose elements are uniformly spaced between the `start`, and `stop` points. The number of intervals is determined by the `num` keyword argument, whose default value is 50. With the `endpoint` keyword argument (defaults to `True`) one can include `stop` in the sequence. In addition, the `dtype` keyword can be supplied to force type conversion of the output. The default is `float`. Note that, when `dtype` is of integer type, the sequence is not necessarily evenly spaced. This is not an error, rather a consequence of rounding. (This is also the `numpy` behaviour.)"
|
||||
"This function returns an array, whose elements are uniformly spaced between the `start`, and `stop` points. The number of intervals is determined by the `num` keyword argument, whose default value is 50. With the `endpoint` keyword argument (defaults to `True`) one can include `stop` in the sequence. In addition, the `dtype` keyword can be supplied to force type conversion of the output. The default is `float`. Note that, when `dtype` is of integer type, the sequence is not necessarily evenly spaced. This is not an error, rather a consequence of rounding. (This is also the `numpy` behaviour.)\n",
|
||||
"\n",
|
||||
"The `linspace` function can accept `complex` as the value of the `dtype`, if the firmware was compiled with complex support. The output `dtype` is automatically complex, if either of the endpoints is a complex scalar."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1030,7 +1100,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### logspace\n",
|
||||
"## logspace\n",
|
||||
"\n",
|
||||
"`linspace`' equivalent for logarithmically spaced data is `logspace`. This function produces a sequence of numbers, in which the quotient of consecutive numbers is constant. This is a geometric sequence.\n",
|
||||
"\n",
|
||||
|
|
@ -1086,7 +1156,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### ones, zeros\n",
|
||||
"## ones, zeros\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.zeros.html\n",
|
||||
"\n",
|
||||
|
|
@ -1098,7 +1168,9 @@
|
|||
"ones(shape, dtype=float)\n",
|
||||
"zeros(shape, dtype=float)\n",
|
||||
"```\n",
|
||||
"where shape is either an integer, or a tuple specifying the shape."
|
||||
"where shape is either an integer, or a tuple specifying the shape.\n",
|
||||
"\n",
|
||||
"The `ones/zeros` functions can accept complex as the value of the dtype, if the firmware was compiled with complex support."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1183,7 +1255,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Customising array printouts"
|
||||
"# Customising array printouts"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1226,7 +1298,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### set_printoptions\n",
|
||||
"## set_printoptions\n",
|
||||
"\n",
|
||||
"The default values can be overwritten by means of the `set_printoptions` function [numpy.set_printoptions](https://numpy.org/doc/1.18/reference/generated/numpy.set_printoptions.html), which accepts two keywords arguments, the `threshold`, and the `edgeitems`. The first of these arguments determines the length of the longest array that will be printed in full, while the second is the number of items that will be printed on the left and right hand side of the ellipsis, if the array is longer than `threshold`."
|
||||
]
|
||||
|
|
@ -1274,7 +1346,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### get_printoptions\n",
|
||||
"## get_printoptions\n",
|
||||
"\n",
|
||||
"The set value of the `threshold` and `edgeitems` can be retrieved by calling the `get_printoptions` function with no arguments. The function returns a *dictionary* with two keys."
|
||||
]
|
||||
|
|
@ -1312,20 +1384,24 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Methods and properties of ndarrays\n",
|
||||
"# Methods and properties of ndarrays\n",
|
||||
"\n",
|
||||
"Arrays have several *properties* that can queried, and some methods that can be called. With the exception of the flatten and transpose operators, properties return an object that describe some feature of the array, while the methods return a new array-like object. \n",
|
||||
"Arrays have several *properties* that can queried, and some methods that can be called. With the exception of the flatten and transpose operators, properties return an object that describe some feature of the array, while the methods return a new array-like object. The `imag`, and `real` properties are included in the firmware only, when it was compiled with complex support.\n",
|
||||
"\n",
|
||||
"1. [.byteswap](#.byteswap)\n",
|
||||
"1. [.copy](#.copy)\n",
|
||||
"1. [.dtype](#.dtype)\n",
|
||||
"1. [.flat](#.flat)\n",
|
||||
"1. [.flatten](#.flatten)\n",
|
||||
"1. [.imag*](#.imag)\n",
|
||||
"1. [.itemsize](#.itemsize)\n",
|
||||
"1. [.real*](#.real)\n",
|
||||
"1. [.reshape](#.reshape)\n",
|
||||
"1. [.shape](#.shape)\n",
|
||||
"1. [.size](#.size)\n",
|
||||
"1. [.T](#.transpose)\n",
|
||||
"1. [.tobytes](#.tobytes)\n",
|
||||
"1. [.tolist](#.tolist)\n",
|
||||
"1. [.transpose](#.transpose)\n",
|
||||
"1. [.sort](#.sort)"
|
||||
]
|
||||
|
|
@ -1334,7 +1410,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .byteswap\n",
|
||||
"## .byteswap\n",
|
||||
"\n",
|
||||
"`numpy` https://numpy.org/doc/stable/reference/generated/numpy.char.chararray.byteswap.html\n",
|
||||
"\n",
|
||||
|
|
@ -1385,7 +1461,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .copy\n",
|
||||
"## .copy\n",
|
||||
"\n",
|
||||
"The `.copy` method creates a new *deep copy* of an array, i.e., the entries of the source array are *copied* into the target array."
|
||||
]
|
||||
|
|
@ -1428,7 +1504,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .dtype\n",
|
||||
"## .dtype\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.dtype.htm\n",
|
||||
"\n",
|
||||
|
|
@ -1525,15 +1601,15 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .flat\n",
|
||||
"## .flat\n",
|
||||
"\n",
|
||||
"numpy: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flat.htm\n",
|
||||
"\n",
|
||||
"`.flat` returns the array's flat iterator. For one-dimensional objects the flat iterator is equivalent to the standart iterator, while for higher dimensional tensors, it amounts to first flattening the array, and then iterating over it. Note, however, that the flat iterator does not consume RAM beyond what is required for holding the position of the iterator itself, while flattening produces a new copy."
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
|
@ -1541,10 +1617,28 @@
|
|||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"1\n2\n3\n4\na:\n array([[1, 2, 3, 4],\n [5, 6, 7, 8]], dtype=int8)\narray([1, 2, 3, 4], dtype=int8)\narray([5, 6, 7, 8], dtype=int8)\n1\n2\n3\n4\n5\n6\n7\n8\n\n\n"
|
||||
"1\n",
|
||||
"2\n",
|
||||
"3\n",
|
||||
"4\n",
|
||||
"a:\n",
|
||||
" array([[1, 2, 3, 4],\n",
|
||||
" [5, 6, 7, 8]], dtype=int8)\n",
|
||||
"array([1, 2, 3, 4], dtype=int8)\n",
|
||||
"array([5, 6, 7, 8], dtype=int8)\n",
|
||||
"1\n",
|
||||
"2\n",
|
||||
"3\n",
|
||||
"4\n",
|
||||
"5\n",
|
||||
"6\n",
|
||||
"7\n",
|
||||
"8\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1571,7 +1665,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .flatten\n",
|
||||
"## .flatten\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.ndarray.flatten.htm\n",
|
||||
"\n",
|
||||
|
|
@ -1624,7 +1718,56 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .itemsize\n",
|
||||
"## .imag\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.imag.html\n",
|
||||
"\n",
|
||||
"The `.imag` property is defined only, if the firmware was compiled with complex support, and returns a copy with the imaginary part of an array. If the array is real, then the output is straight zeros with the `dtype` of the input. If the input is complex, the output `dtype` is always `float`, irrespective of the values."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T19:07:26.171208Z",
|
||||
"start_time": "2022-01-07T19:07:26.152633Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\t array([1, 2, 3], dtype=uint16)\n",
|
||||
"a.imag:\t array([0, 0, 0], dtype=uint16)\n",
|
||||
"\n",
|
||||
"b:\t array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)\n",
|
||||
"b.imag:\t array([0.0, 1.0, -1.0], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3], dtype=np.uint16)\n",
|
||||
"print(\"a:\\t\", a)\n",
|
||||
"print(\"a.imag:\\t\", a.imag)\n",
|
||||
"\n",
|
||||
"b = np.array([1, 2+1j, 3-1j], dtype=np.complex)\n",
|
||||
"print(\"\\nb:\\t\", b)\n",
|
||||
"print(\"b.imag:\\t\", b.imag)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## .itemsize\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.itemsize.html\n",
|
||||
"\n",
|
||||
|
|
@ -1665,18 +1808,67 @@
|
|||
"\n",
|
||||
"a = np.array([1, 2, 3], dtype=np.int8)\n",
|
||||
"print(\"a:\\n\", a)\n",
|
||||
"print(\"itemsize of a:\", a.itemsize\n",
|
||||
"print(\"itemsize of a:\", a.itemsize)\n",
|
||||
"\n",
|
||||
"b= np.array([[1, 2], [3, 4]], dtype=np.float)\n",
|
||||
"print(\"\\nb:\\n\", b)\n",
|
||||
"print(\"itemsize of b:\", b.itemsize"
|
||||
"print(\"itemsize of b:\", b.itemsize)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .reshape\n",
|
||||
"## .real\n",
|
||||
"\n",
|
||||
"numpy: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.real.html\n",
|
||||
"\n",
|
||||
"The `.real` property is defined only, if the firmware was compiled with complex support, and returns a copy with the real part of an array."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T19:10:01.870921Z",
|
||||
"start_time": "2022-01-07T19:10:01.860071Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\t array([1, 2, 3], dtype=uint16)\n",
|
||||
"a.real:\t array([1, 2, 3], dtype=uint16)\n",
|
||||
"\n",
|
||||
"b:\t array([1.0+0.0j, 2.0+1.0j, 3.0-1.0j], dtype=complex)\n",
|
||||
"b.real:\t array([1.0, 2.0, 3.0], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3], dtype=np.uint16)\n",
|
||||
"print(\"a:\\t\", a)\n",
|
||||
"print(\"a.real:\\t\", a.real)\n",
|
||||
"\n",
|
||||
"b = np.array([1, 2+1j, 3-1j], dtype=np.complex)\n",
|
||||
"print(\"\\nb:\\t\", b)\n",
|
||||
"print(\"b.real:\\t\", b.real)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## .reshape\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.reshape.html\n",
|
||||
"\n",
|
||||
|
|
@ -1733,7 +1925,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .shape\n",
|
||||
"## .shape\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.shape.html\n",
|
||||
"\n",
|
||||
|
|
@ -1782,11 +1974,11 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"By assigning a tuple to the `.shape` property, the array can be `reshape`d:"
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
|
@ -1794,10 +1986,18 @@
|
|||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\n array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], dtype=float64)\n\na:\n array([[1.0, 2.0, 3.0],\n [4.0, 5.0, 6.0],\n [7.0, 8.0, 9.0]], dtype=float64)\n\n\n"
|
||||
"a:\n",
|
||||
" array([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0], dtype=float64)\n",
|
||||
"\n",
|
||||
"a:\n",
|
||||
" array([[1.0, 2.0, 3.0],\n",
|
||||
" [4.0, 5.0, 6.0],\n",
|
||||
" [7.0, 8.0, 9.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -1817,7 +2017,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .size\n",
|
||||
"## .size\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.size.html\n",
|
||||
"\n",
|
||||
|
|
@ -1866,19 +2066,19 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
".T\n",
|
||||
"\n",
|
||||
"The `.T` property of the `ndarray` is equivalent to [.transpose](#.transpose)."
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .tobytes\n",
|
||||
"## .tobytes\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tobytes.html\n",
|
||||
"\n",
|
||||
|
|
@ -1933,7 +2133,60 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .transpose\n",
|
||||
"## .tolist\n",
|
||||
"\n",
|
||||
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.ndarray.tolist.html\n",
|
||||
"\n",
|
||||
"The `.tolist` method can be used for converting the numerical array into a (nested) `python` lists."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-07T19:01:28.671234Z",
|
||||
"start_time": "2022-01-07T19:01:28.568786Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: array([0, 1, 2, 3], dtype=uint8)\n",
|
||||
"b: [0, 1, 2, 3]\n",
|
||||
"====================\n",
|
||||
"c: array([[0, 1],\n",
|
||||
" [2, 3]], dtype=uint8)\n",
|
||||
"d: [[0, 1], [2, 3]]\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array(range(4), dtype=np.uint8)\n",
|
||||
"print('a: ', a)\n",
|
||||
"b = a.tolist()\n",
|
||||
"print('b: ', b)\n",
|
||||
"\n",
|
||||
"c = a.reshape((2, 2))\n",
|
||||
"print('='*20)\n",
|
||||
"print('c: ', c)\n",
|
||||
"d = c.tolist()\n",
|
||||
"print('d: ', d)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## .transpose\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.transpose.html\n",
|
||||
"\n",
|
||||
|
|
@ -1985,11 +2238,11 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"The transpose of the array can also be gotten through the `T` property:"
|
||||
],
|
||||
"cell_type": "markdown",
|
||||
"metadata": {}
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
|
|
@ -1997,10 +2250,20 @@
|
|||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\n array([[1, 2, 3],\n [4, 5, 6],\n [7, 8, 9]], dtype=uint8)\n\ntranspose of a:\n array([[1, 4, 7],\n [2, 5, 8],\n [3, 6, 9]], dtype=uint8)\n\n\n"
|
||||
"a:\n",
|
||||
" array([[1, 2, 3],\n",
|
||||
" [4, 5, 6],\n",
|
||||
" [7, 8, 9]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"transpose of a:\n",
|
||||
" array([[1, 4, 7],\n",
|
||||
" [2, 5, 8],\n",
|
||||
" [3, 6, 9]], dtype=uint8)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -2018,7 +2281,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### .sort\n",
|
||||
"## .sort\n",
|
||||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.sort.html\n",
|
||||
"\n",
|
||||
|
|
@ -2088,7 +2351,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Unary operators\n",
|
||||
"# Unary operators\n",
|
||||
"\n",
|
||||
"With the exception of `len`, which returns a single number, all unary operators manipulate the underlying data element-wise. "
|
||||
]
|
||||
|
|
@ -2097,7 +2360,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### len\n",
|
||||
"## len\n",
|
||||
"\n",
|
||||
"This operator takes a single argument, the array, and returns either the length of the first axis."
|
||||
]
|
||||
|
|
@ -2158,7 +2421,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### invert\n",
|
||||
"## invert\n",
|
||||
"\n",
|
||||
"The function is defined for integer data types (`uint8`, `int8`, `uint16`, and `int16`) only, takes a single argument, and returns the element-by-element, bit-wise inverse of the array. If a `float` is supplied, the function raises a `ValueError` exception.\n",
|
||||
"\n",
|
||||
|
|
@ -2207,7 +2470,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### abs\n",
|
||||
"## abs\n",
|
||||
"\n",
|
||||
"This function takes a single argument, and returns the element-by-element absolute value of the array. When the data type is unsigned (`uint8`, or `uint16`), a copy of the array will be returned immediately, and no calculation takes place."
|
||||
]
|
||||
|
|
@ -2247,7 +2510,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### neg\n",
|
||||
"## neg\n",
|
||||
"\n",
|
||||
"This operator takes a single argument, and changes the sign of each element in the array. Unsigned values are wrapped. "
|
||||
]
|
||||
|
|
@ -2294,7 +2557,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### pos\n",
|
||||
"## pos\n",
|
||||
"\n",
|
||||
"This function takes a single argument, and simply returns a copy of the array."
|
||||
]
|
||||
|
|
@ -2334,9 +2597,11 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Binary operators\n",
|
||||
"# Binary operators\n",
|
||||
"\n",
|
||||
"`ulab` implements the `+`, `-`, `*`, `/`, `**`, `<`, `>`, `<=`, `>=`, `==`, `!=`, `+=`, `-=`, `*=`, `/=`, `**=` binary operators that work element-wise. Broadcasting is available, meaning that the two operands do not even have to have the same shape. If the lengths along the respective axes are equal, or one of them is 1, or the axis is missing, the element-wise operation can still be carried out. \n",
|
||||
"`ulab` implements the `+`, `-`, `*`, `/`, `**`, `%`, `<`, `>`, `<=`, `>=`, `==`, `!=`, `+=`, `-=`, `*=`, `/=`, `**=`, `%=` binary operators, as well as the `AND`, `OR`, `XOR` bit-wise operators that work element-wise. Note that the bit-wise operators will raise an exception, if either of the operands is of `float` or `complex` type.\n",
|
||||
"\n",
|
||||
"Broadcasting is available, meaning that the two operands do not even have to have the same shape. If the lengths along the respective axes are equal, or one of them is 1, or the axis is missing, the element-wise operation can still be carried out. \n",
|
||||
"A thorough explanation of broadcasting can be found under https://numpy.org/doc/stable/user/basics.broadcasting.html. \n",
|
||||
"\n",
|
||||
"**WARNING**: note that relational operators (`<`, `>`, `<=`, `>=`, `==`, `!=`) should have the `ndarray` on their left hand side, when compared to scalars. This means that the following works"
|
||||
|
|
@ -2389,10 +2654,14 @@
|
|||
},
|
||||
"outputs": [
|
||||
{
|
||||
"output_type": "stream",
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"\nTraceback (most recent call last):\n File \"/dev/shm/micropython.py\", line 5, in <module>\nTypeError: unsupported types for __lt__: 'int', 'ndarray'\n\n"
|
||||
"\n",
|
||||
"Traceback (most recent call last):\n",
|
||||
" File \"/dev/shm/micropython.py\", line 5, in <module>\n",
|
||||
"TypeError: unsupported types for __lt__: 'int', 'ndarray'\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
|
|
@ -2416,7 +2685,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Upcasting\n",
|
||||
"## Upcasting\n",
|
||||
"\n",
|
||||
"Binary operations require special attention, because two arrays with different typecodes can be the operands of an operation, in which case it is not trivial, what the typecode of the result is. This decision on the result's typecode is called upcasting. Since the number of typecodes in `ulab` is significantly smaller than in `numpy`, we have to define new upcasting rules. Where possible, I followed `numpy`'s conventions. \n",
|
||||
"\n",
|
||||
|
|
@ -2426,7 +2695,7 @@
|
|||
"\n",
|
||||
"2. if either of the operands is a float, the result is automatically a float\n",
|
||||
"\n",
|
||||
"3. When one of the operands is a scalar, it will internally be turned into a single-element `ndarray` with the *smallest* possible `dtype`. Thus, e.g., if the scalar is 123, it will be converted into an array of `dtype` `uint8`, while -1000 will be converted into `int16`. An `mp_obj_float`, will always be promoted to `dtype` `float`. Other micropython types (e.g., lists, tuples, etc.) raise a `TypeError` exception. \n",
|
||||
"3. When one of the operands is a scalar, it will internally be turned into a single-element `ndarray` with the *smallest* possible `dtype`. Thus, e.g., if the scalar is 123, it will be converted into an array of `dtype` `uint8`, while -1000 will be converted into `int16`. An `mp_obj_float`, will always be promoted to `dtype` `float`. Similarly, if `ulab` supports complex arrays, the result of a binary operation involving a `complex` array is always complex. Other `micropython` types (e.g., lists, tuples, etc.) raise a `TypeError` exception. \n",
|
||||
"\n",
|
||||
"4. \n",
|
||||
" \n",
|
||||
|
|
@ -2493,7 +2762,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Benchmarks\n",
|
||||
"## Benchmarks\n",
|
||||
"\n",
|
||||
"The following snippet compares the performance of binary operations to a possible implementation in python. For the time measurement, we will take the following snippet from the micropython manual:"
|
||||
]
|
||||
|
|
@ -2611,7 +2880,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Comparison operators\n",
|
||||
"# Comparison operators\n",
|
||||
"\n",
|
||||
"The smaller than, greater than, smaller or equal, and greater or equal operators return a vector of Booleans indicating the positions (`True`), where the condition is satisfied. "
|
||||
]
|
||||
|
|
@ -2684,7 +2953,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Iterating over arrays\n",
|
||||
"# Iterating over arrays\n",
|
||||
"\n",
|
||||
"`ndarray`s are iterable, which means that their elements can also be accessed as can the elements of a list, tuple, etc. If the array is one-dimensional, the iterator returns scalars, otherwise a new reduced-dimensional *view* is created and returned."
|
||||
]
|
||||
|
|
@ -2746,10 +3015,10 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Slicing and indexing\n",
|
||||
"# Slicing and indexing\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"### Views vs. copies\n",
|
||||
"## Views vs. copies\n",
|
||||
"\n",
|
||||
"`numpy` has a very important concept called *views*, which is a powerful extension of `python`'s own notion of slicing. Slices are special python objects of the form\n",
|
||||
"\n",
|
||||
|
|
@ -2895,7 +3164,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Indexing\n",
|
||||
"## Indexing\n",
|
||||
"\n",
|
||||
"The simplest form of indexing is specifying a single integer between the square brackets as in "
|
||||
]
|
||||
|
|
@ -3001,7 +3270,7 @@
|
|||
"output_type": "stream",
|
||||
"text": [
|
||||
"a:\t array([0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0], dtype=float)\n",
|
||||
"a < 5:\t array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)\n",
|
||||
"a[a < 5]:\t array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
|
|
@ -3014,7 +3283,7 @@
|
|||
"\n",
|
||||
"a = np.array(range(9), dtype=np.float)\n",
|
||||
"print(\"a:\\t\", a)\n",
|
||||
"print(\"a < 5:\\t\", a[a < 5])"
|
||||
"print(\"a[a < 5]:\\t\", a[a < 5])"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3154,7 +3423,7 @@
|
|||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Slicing and assigning to slices\n",
|
||||
"## Slicing and assigning to slices\n",
|
||||
"\n",
|
||||
"You can also generate sub-arrays by specifying slices as the index of an array. Slices are special python objects of the form "
|
||||
]
|
||||
|
|
@ -3462,9 +3731,13 @@
|
|||
}
|
||||
],
|
||||
"metadata": {
|
||||
"interpreter": {
|
||||
"hash": "ce9a02f9f7db620716422019cafa4bc1786ca85daa298b819f6da075e7993842"
|
||||
},
|
||||
"kernelspec": {
|
||||
"name": "python3",
|
||||
"display_name": "Python 3.8.5 64-bit ('base': conda)"
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
|
|
@ -3524,9 +3797,6 @@
|
|||
"_Feature"
|
||||
],
|
||||
"window_display": false
|
||||
},
|
||||
"interpreter": {
|
||||
"hash": "ce9a02f9f7db620716422019cafa4bc1786ca85daa298b819f6da075e7993842"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"%pylab is deprecated, use %matplotlib inline and import the required libraries.\n",
|
||||
"Populating the interactive namespace from numpy and matplotlib\n"
|
||||
]
|
||||
}
|
||||
|
|
@ -34,8 +35,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-11-03T19:50:51.340719Z",
|
||||
"start_time": "2020-11-03T19:50:51.330015Z"
|
||||
"end_time": "2022-01-07T19:16:29.118001Z",
|
||||
"start_time": "2022-01-07T19:16:29.114692Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -52,8 +53,8 @@
|
|||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-11-03T19:50:52.899529Z",
|
||||
"start_time": "2020-11-03T19:50:52.837604Z"
|
||||
"end_time": "2022-01-07T19:16:37.453883Z",
|
||||
"start_time": "2022-01-07T19:16:37.422478Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -77,7 +78,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -182,7 +183,7 @@
|
|||
"%%micropython -pyboard 1\n",
|
||||
"\n",
|
||||
"import utime\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"def timeit(n=1000):\n",
|
||||
" def wrapper(f, *args, **kwargs):\n",
|
||||
|
|
@ -225,7 +226,7 @@
|
|||
"source": [
|
||||
"# Numerical\n",
|
||||
"\n",
|
||||
"Function in the `numerical` sub-module can be called by importing the sub-module first. "
|
||||
"Function in this section can be used for calculating statistical properties, or manipulating the arrangement of array elements."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -244,145 +245,14 @@
|
|||
"\n",
|
||||
"**WARNING:** Difference to `numpy`: the `out` keyword argument is not implemented.\n",
|
||||
"\n",
|
||||
"These functions follow the same pattern, and work with generic iterables, and `ndarray`s. `min`, and `max` return the minimum or maximum of a sequence. If the input array is two-dimensional, the `axis` keyword argument can be supplied, in which case the minimum/maximum along the given axis will be returned. If `axis=None` (this is also the default value), the minimum/maximum of the flattened array will be determined.\n",
|
||||
"These functions follow the same pattern, and work with generic iterables, and `ndarray`s. `min`, and `max` return the minimum or maximum of a sequence. If the input array is two-dimensional, the `axis` keyword argument can be supplied, in which case the minimum/maximum along the given axis will be returned. If `axis=None` (this is also the default value), the minimum/maximum of the flattened array will be determined. The functions also accept the `keepdims=True` or `keepdims=False` keyword argument. The latter case is the default, while the former keeps the dimensions (the number of axes) of the supplied array. \n",
|
||||
"\n",
|
||||
"`argmin/argmax` return the position (index) of the minimum/maximum in the sequence."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 108,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-17T21:26:22.507996Z",
|
||||
"start_time": "2020-10-17T21:26:22.492543Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"array([1.0, 2.0, 3.0], dtype=float)\n",
|
||||
"array([], dtype=float)\n",
|
||||
"[] 0\n",
|
||||
"array([1.0, 2.0, 3.0], dtype=float)\n",
|
||||
"array([], dtype=float)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3])\n",
|
||||
"print(a)\n",
|
||||
"print(a[-1:-1:-3])\n",
|
||||
"try:\n",
|
||||
" sa = list(a[-1:-1:-3])\n",
|
||||
" la = len(sa)\n",
|
||||
"except IndexError as e:\n",
|
||||
" sa = str(e)\n",
|
||||
" la = -1\n",
|
||||
" \n",
|
||||
"print(sa, la)\n",
|
||||
"\n",
|
||||
"a[-1:-1:-3] = np.ones(0)\n",
|
||||
"print(a)\n",
|
||||
"\n",
|
||||
"b = np.ones(0) + 1\n",
|
||||
"print(b)\n",
|
||||
"# print('b', b.shape())"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 122,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-17T21:54:49.123748Z",
|
||||
"start_time": "2020-10-17T21:54:49.093819Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"0, 1, -3array([], dtype=float)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"a = np.array([1, 2, 3])\n",
|
||||
"print(a[0:1:-3])"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 127,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-17T21:57:01.482277Z",
|
||||
"start_time": "2020-10-17T21:57:01.477362Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"[0]"
|
||||
]
|
||||
},
|
||||
"execution_count": 127,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"l = list(range(13))\n",
|
||||
"\n",
|
||||
"l[0:10:113]"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 81,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2020-10-17T20:59:58.285134Z",
|
||||
"start_time": "2020-10-17T20:59:58.263605Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"(0,)"
|
||||
]
|
||||
},
|
||||
"execution_count": 81,
|
||||
"metadata": {},
|
||||
"output_type": "execute_result"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"a = np.array([1, 2, 3])\n",
|
||||
"np.ones(0, dtype=uint8) / np.zeros(0, dtype=uint16)\n",
|
||||
"np.ones(0).shape"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 375,
|
||||
"execution_count": 10,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-18T13:08:28.113525Z",
|
||||
|
|
@ -394,16 +264,16 @@
|
|||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: array([1.0, 2.0, 0.0, 1.0, 10.0], dtype=float)\n",
|
||||
"a: array([1.0, 2.0, 0.0, 1.0, 10.0], dtype=float64)\n",
|
||||
"min of a: 0.0\n",
|
||||
"argmin of a: 2\n",
|
||||
"\n",
|
||||
"b:\n",
|
||||
" array([[1.0, 2.0, 0.0],\n",
|
||||
"\t [1.0, 10.0, -1.0]], dtype=float)\n",
|
||||
" [1.0, 10.0, -1.0]], dtype=float64)\n",
|
||||
"min of b (flattened): -1.0\n",
|
||||
"min of b (axis=0): array([1.0, 2.0, -1.0], dtype=float)\n",
|
||||
"min of b (axis=1): array([0.0, -1.0], dtype=float)\n",
|
||||
"min of b (axis=0): array([1.0, 2.0, -1.0], dtype=float64)\n",
|
||||
"min of b (axis=1): array([0.0, -1.0], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
|
|
@ -412,19 +282,55 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 0, 1, 10])\n",
|
||||
"print('a:', a)\n",
|
||||
"print('min of a:', numerical.min(a))\n",
|
||||
"print('argmin of a:', numerical.argmin(a))\n",
|
||||
"print('min of a:', np.min(a))\n",
|
||||
"print('argmin of a:', np.argmin(a))\n",
|
||||
"\n",
|
||||
"b = np.array([[1, 2, 0], [1, 10, -1]])\n",
|
||||
"print('\\nb:\\n', b)\n",
|
||||
"print('min of b (flattened):', numerical.min(b))\n",
|
||||
"print('min of b (axis=0):', numerical.min(b, axis=0))\n",
|
||||
"print('min of b (axis=1):', numerical.min(b, axis=1))"
|
||||
"print('min of b (flattened):', np.min(b))\n",
|
||||
"print('min of b (axis=0):', np.min(b, axis=0))\n",
|
||||
"print('min of b (axis=1):', np.min(b, axis=1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: array([[0.0, 1.0, 2.0, 3.0],\n",
|
||||
" [4.0, 5.0, 6.0, 7.0],\n",
|
||||
" [8.0, 9.0, 10.0, 11.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"min of a (axis=1):\n",
|
||||
" array([[0.0],\n",
|
||||
" [4.0],\n",
|
||||
" [8.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"min of a (axis=0):\n",
|
||||
" array([[0.0, 1.0, 2.0, 3.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array(range(12)).reshape((3, 4))\n",
|
||||
"\n",
|
||||
"print('a:', a)\n",
|
||||
"print('\\nmin of a (axis=1):\\n', np.min(a, axis=1, keepdims=True))\n",
|
||||
"print('\\nmin of a (axis=0):\\n', np.min(a, axis=0, keepdims=True))"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -439,12 +345,14 @@
|
|||
"\n",
|
||||
"`numpy`: https://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html\n",
|
||||
"\n",
|
||||
"These three functions follow the same pattern: if the axis keyword is not specified, it assumes the default value of `None`, and returns the result of the computation for the flattened array. Otherwise, the calculation is along the given axis."
|
||||
"These three functions follow the same pattern: if the `axis` keyword is not specified, they assume the default value of `None`, and return the result of the computation for the flattened array. Otherwise, the calculation is along the given axis. \n",
|
||||
"\n",
|
||||
"If the `axis` keyword argument is a number (this can also be negative to signify counting from the rightmost axis) the functions contract the arrays, i.e., the results will have one axis fewer than the input array. The only exception to this rule is when the `keepdims` keyword argument is supplied with a value `True`, in which case, the results will have the same number of axis as the input, but the axis specified in `axis` will have a length of 1. This is useful in cases, when the output is to be broadcast with the input in subsequent computations."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 527,
|
||||
"execution_count": 12,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2019-10-20T06:51:58.845076Z",
|
||||
|
|
@ -458,29 +366,73 @@
|
|||
"text": [
|
||||
"a: \n",
|
||||
" array([[1.0, 2.0, 3.0],\n",
|
||||
"\t [4.0, 5.0, 6.0],\n",
|
||||
"\t [7.0, 8.0, 9.0]], dtype=float)\n",
|
||||
" [4.0, 5.0, 6.0],\n",
|
||||
" [7.0, 8.0, 9.0]], dtype=float64)\n",
|
||||
"sum, flat array: 45.0\n",
|
||||
"mean, horizontal: array([2.0, 5.0, 8.0], dtype=float)\n",
|
||||
"std, vertical: array([2.44949, 2.44949, 2.44949], dtype=float)\n",
|
||||
"mean, horizontal: array([2.0, 5.0, 8.0], dtype=float64)\n",
|
||||
"std, vertical: array([2.449489742783178, 2.449489742783178, 2.449489742783178], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -pyboard 1\n",
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
|
||||
"print('a: \\n', a)\n",
|
||||
"\n",
|
||||
"print('sum, flat array: ', numerical.sum(a))\n",
|
||||
"print('sum, flat array: ', np.sum(a))\n",
|
||||
"\n",
|
||||
"print('mean, horizontal: ', numerical.mean(a, axis=1))\n",
|
||||
"print('mean, horizontal: ', np.mean(a, axis=1))\n",
|
||||
"\n",
|
||||
"print('std, vertical: ', numerical.std(a, axis=0))"
|
||||
"print('std, vertical: ', np.std(a, axis=0))"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 52,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"a: \n",
|
||||
" array([[1.0, 2.0, 3.0],\n",
|
||||
" [4.0, 5.0, 6.0],\n",
|
||||
" [7.0, 8.0, 9.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"std, along 0th axis:\n",
|
||||
" array([2.449489742783178, 2.449489742783178, 2.449489742783178], dtype=float64)\n",
|
||||
"\n",
|
||||
"a: \n",
|
||||
" array([[1.0, 2.0, 3.0],\n",
|
||||
" [4.0, 5.0, 6.0],\n",
|
||||
" [7.0, 8.0, 9.0]], dtype=float64)\n",
|
||||
"\n",
|
||||
"std, along 1st axis, keeping dimensions:\n",
|
||||
" array([[0.8164965809277261],\n",
|
||||
" [0.8164965809277261],\n",
|
||||
" [0.8164965809277261]], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])\n",
|
||||
"print('a: \\n', a)\n",
|
||||
"print('\\nstd, along 0th axis:\\n', np.std(a, axis=0))\n",
|
||||
"\n",
|
||||
"print('\\na: \\n', a)\n",
|
||||
"print('\\nstd, along 1st axis, keeping dimensions:\\n', np.std(a, axis=1, keepdims=True))"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -519,13 +471,12 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3, 4, 5, 6, 7, 8])\n",
|
||||
"print(\"a:\\t\\t\\t\", a)\n",
|
||||
"\n",
|
||||
"numerical.roll(a, 2)\n",
|
||||
"np.roll(a, 2)\n",
|
||||
"print(\"a rolled to the left:\\t\", a)\n",
|
||||
"\n",
|
||||
"# this should be the original vector\n",
|
||||
|
|
@ -581,19 +532,18 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 2, 3, 4], [5, 6, 7, 8]])\n",
|
||||
"print(\"a:\\n\", a)\n",
|
||||
"\n",
|
||||
"numerical.roll(a, 2)\n",
|
||||
"np.roll(a, 2)\n",
|
||||
"print(\"\\na rolled to the left:\\n\", a)\n",
|
||||
"\n",
|
||||
"numerical.roll(a, -1, axis=1)\n",
|
||||
"np.roll(a, -1, axis=1)\n",
|
||||
"print(\"\\na rolled up:\\n\", a)\n",
|
||||
"\n",
|
||||
"numerical.roll(a, 1, axis=None)\n",
|
||||
"np.roll(a, 1, axis=None)\n",
|
||||
"print(\"\\na rolled with None:\\n\", a)"
|
||||
]
|
||||
},
|
||||
|
|
@ -649,9 +599,7 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import vector\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"def dummy_adc():\n",
|
||||
" # dummy adc function, so that the results are reproducible\n",
|
||||
|
|
@ -659,8 +607,8 @@
|
|||
" \n",
|
||||
"n = 10\n",
|
||||
"# These are the normalised weights; the last entry is the most dominant\n",
|
||||
"weight = vector.exp([1, 2, 3, 4, 5])\n",
|
||||
"weight = weight/numerical.sum(weight)\n",
|
||||
"weight = np.exp([1, 2, 3, 4, 5])\n",
|
||||
"weight = weight/np.sum(weight)\n",
|
||||
"\n",
|
||||
"print(weight)\n",
|
||||
"# initial array of samples\n",
|
||||
|
|
@ -669,10 +617,10 @@
|
|||
"for i in range(n):\n",
|
||||
" # a new datum is inserted on the right hand side. This simply overwrites whatever was in the last slot\n",
|
||||
" samples[-1] = dummy_adc()\n",
|
||||
" print(numerical.mean(samples[-5:]*weight))\n",
|
||||
" print(np.mean(samples[-5:]*weight))\n",
|
||||
" print(samples[-5:])\n",
|
||||
" # the data are shifted by one position to the left\n",
|
||||
" numerical.roll(samples, 1)"
|
||||
" numerical.np(samples, 1)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -725,17 +673,16 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([1, 2, 3, 4, 5])\n",
|
||||
"print(\"a: \\t\", a)\n",
|
||||
"print(\"a flipped:\\t\", np.flip(a))\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], dtype=np.uint8)\n",
|
||||
"print(\"\\na flipped horizontally\\n\", numerical.flip(a, axis=1))\n",
|
||||
"print(\"\\na flipped vertically\\n\", numerical.flip(a, axis=0))\n",
|
||||
"print(\"\\na flipped horizontally+vertically\\n\", numerical.flip(a))"
|
||||
"print(\"\\na flipped horizontally\\n\", np.flip(a, axis=1))\n",
|
||||
"print(\"\\na flipped vertically\\n\", np.flip(a, axis=0))\n",
|
||||
"print(\"\\na flipped horizontally+vertically\\n\", np.flip(a))"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -800,19 +747,18 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array(range(9), dtype=np.uint8)\n",
|
||||
"print('a:\\n', a)\n",
|
||||
"\n",
|
||||
"print('\\nfirst derivative:\\n', numerical.diff(a, n=1))\n",
|
||||
"print('\\nsecond derivative:\\n', numerical.diff(a, n=2))\n",
|
||||
"print('\\nfirst derivative:\\n', np.diff(a, n=1))\n",
|
||||
"print('\\nsecond derivative:\\n', np.diff(a, n=2))\n",
|
||||
"\n",
|
||||
"c = np.array([[1, 2, 3, 4], [4, 3, 2, 1], [1, 4, 9, 16], [0, 0, 0, 0]])\n",
|
||||
"print('\\nc:\\n', c)\n",
|
||||
"print('\\nfirst derivative, first axis:\\n', numerical.diff(c, axis=0))\n",
|
||||
"print('\\nfirst derivative, second axis:\\n', numerical.diff(c, axis=1))"
|
||||
"print('\\nfirst derivative, first axis:\\n', np.diff(c, axis=0))\n",
|
||||
"print('\\nfirst derivative, second axis:\\n', np.diff(c, axis=1))"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -858,7 +804,7 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array(range(12), dtype=np.int8).reshape((3, 4))\n",
|
||||
"print('a:\\n', a)\n",
|
||||
|
|
@ -925,18 +871,17 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 12, 3, 0], [5, 3, 4, 1], [9, 11, 1, 8], [7, 10, 0, 1]], dtype=np.float)\n",
|
||||
"print('\\na:\\n', a)\n",
|
||||
"b = numerical.sort(a, axis=0)\n",
|
||||
"b = np.sort(a, axis=0)\n",
|
||||
"print('\\na sorted along vertical axis:\\n', b)\n",
|
||||
"\n",
|
||||
"c = numerical.sort(a, axis=1)\n",
|
||||
"c = np.sort(a, axis=1)\n",
|
||||
"print('\\na sorted along horizontal axis:\\n', c)\n",
|
||||
"\n",
|
||||
"c = numerical.sort(a, axis=None)\n",
|
||||
"c = np.sort(a, axis=None)\n",
|
||||
"print('\\nflattened a sorted:\\n', c)"
|
||||
]
|
||||
},
|
||||
|
|
@ -955,15 +900,13 @@
|
|||
"source": [
|
||||
"%%micropython -pyboard 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import vector\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"@timeit\n",
|
||||
"def sort_time(array):\n",
|
||||
" return numerical.sort(array)\n",
|
||||
" return np.sort(array)\n",
|
||||
"\n",
|
||||
"b = vector.sin(np.linspace(0, 6.28, num=1000))\n",
|
||||
"b = np.sin(np.linspace(0, 6.28, num=1000))\n",
|
||||
"print('b: ', b)\n",
|
||||
"sort_time(b)\n",
|
||||
"print('\\nb sorted:\\n', b)"
|
||||
|
|
@ -1025,18 +968,17 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([[1, 12, 3, 0], [5, 3, 4, 1], [9, 11, 1, 8], [7, 10, 0, 1]], dtype=np.float)\n",
|
||||
"print('\\na:\\n', a)\n",
|
||||
"b = numerical.argsort(a, axis=0)\n",
|
||||
"b = np.argsort(a, axis=0)\n",
|
||||
"print('\\na sorted along vertical axis:\\n', b)\n",
|
||||
"\n",
|
||||
"c = numerical.argsort(a, axis=1)\n",
|
||||
"c = np.argsort(a, axis=1)\n",
|
||||
"print('\\na sorted along horizontal axis:\\n', c)\n",
|
||||
"\n",
|
||||
"c = numerical.argsort(a, axis=None)\n",
|
||||
"c = np.argsort(a, axis=None)\n",
|
||||
"print('\\nflattened a sorted:\\n', c)"
|
||||
]
|
||||
},
|
||||
|
|
@ -1078,12 +1020,11 @@
|
|||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"import ulab as np\n",
|
||||
"from ulab import numerical\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"a = np.array([0, 5, 1, 3, 2, 4], dtype=np.uint8)\n",
|
||||
"print('\\na:\\n', a)\n",
|
||||
"b = numerical.argsort(a, axis=1)\n",
|
||||
"b = np.argsort(a, axis=1)\n",
|
||||
"print('\\nsorting indices:\\n', b)\n",
|
||||
"print('\\nthe original array:\\n', a)"
|
||||
]
|
||||
|
|
@ -1091,7 +1032,7 @@
|
|||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"display_name": "base",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
|
|
@ -1105,7 +1046,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
"version": "3.11.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
|
|
|
|||
|
|
@ -275,7 +275,7 @@
|
|||
"A good example of how the function would be called can be found in [vector.c](https://github.com/v923z/micropython-ulab/blob/master/code/numpy/vector/vector.c), in the `vector_arctan2` function:\n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"mp_obj_t vectorise_arctan2(mp_obj_t y, mp_obj_t x) {\n",
|
||||
"mp_obj_t vector_arctan2(mp_obj_t y, mp_obj_t x) {\n",
|
||||
" ...\n",
|
||||
" uint8_t ndim = 0;\n",
|
||||
" size_t *shape = m_new(size_t, ULAB_MAX_DIMS);\n",
|
||||
|
|
@ -718,7 +718,7 @@
|
|||
"Finally, we have to bind this function object in the globals table of the `user` module: \n",
|
||||
"\n",
|
||||
"```c\n",
|
||||
"STATIC const mp_rom_map_elem_t ulab_user_globals_table[] = {\n",
|
||||
"static const mp_rom_map_elem_t ulab_user_globals_table[] = {\n",
|
||||
" { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_user) },\n",
|
||||
" { MP_OBJ_NEW_QSTR(MP_QSTR_square), (mp_obj_t)&user_square_obj },\n",
|
||||
"};\n",
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@
|
|||
"execution_count": 2,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-03-05T06:53:22.506665Z",
|
||||
"start_time": "2021-03-05T06:53:22.499658Z"
|
||||
"end_time": "2022-01-29T16:53:11.972661Z",
|
||||
"start_time": "2022-01-29T16:53:11.965952Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -49,11 +49,11 @@
|
|||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"execution_count": 7,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2021-03-05T06:53:23.127314Z",
|
||||
"start_time": "2021-03-05T06:53:23.103181Z"
|
||||
"end_time": "2022-01-29T16:59:24.652277Z",
|
||||
"start_time": "2022-01-29T16:59:24.639828Z"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
|
|
@ -77,7 +77,7 @@
|
|||
" if args.unix: # tests the code on the unix port. Note that this works on unix only\n",
|
||||
" with open('/dev/shm/micropython.py', 'w') as fout:\n",
|
||||
" fout.write(cell)\n",
|
||||
" proc = subprocess.Popen([\"../../micropython/ports/unix/micropython\", \"/dev/shm/micropython.py\"], \n",
|
||||
" proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n",
|
||||
" stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n",
|
||||
" print(proc.stdout.read().decode(\"utf-8\"))\n",
|
||||
" print(proc.stderr.read().decode(\"utf-8\"))\n",
|
||||
|
|
@ -291,7 +291,9 @@
|
|||
"a = bytearray([1, 1, 0, 0, 0, 0, 0, 255])\n",
|
||||
"print('a: ', a)\n",
|
||||
"print()\n",
|
||||
"print('unsigned integers: ', utils.from_uint32_buffer(a))\n",
|
||||
"print('unsigned integers: ', utils.from_uint32_buffe\n",
|
||||
"print('original vector:\\n', y)\n",
|
||||
"print('\\nspectrum:\\n', a)r(a))\n",
|
||||
"\n",
|
||||
"b = bytearray([1, 1, 0, 0, 0, 0, 0, 255])\n",
|
||||
"print('\\nb: ', b)\n",
|
||||
|
|
@ -393,10 +395,157 @@
|
|||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## spectrogram\n",
|
||||
"\n",
|
||||
"In addition to the Fourier transform and its inverse, `ulab` also sports a function called `spectrogram`, which returns the absolute value of the Fourier transform, also known as the power spectrum. This could be used to find the dominant spectral component in a time series. The positional arguments are treated in the same way as in `fft`, and `ifft`. This means that, if the firmware was compiled with complex support and `ULAB_FFT_IS_NUMPY_COMPATIBLE` is defined to be 1 in `ulab.h`, the input can also be a complex array. \n",
|
||||
"\n",
|
||||
"And easy way to find out if the FFT is `numpy`-compatible is to check the number of values `fft.fft` returns, when called with a single real argument of length other than 2: "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 12,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"FFT is numpy compatible (complex inputs/outputs)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"\n",
|
||||
"if len(np.fft.fft(np.zeros(4))) == 2:\n",
|
||||
" print('FFT is NOT numpy compatible (real and imaginary parts are treated separately)')\n",
|
||||
"else:\n",
|
||||
" print('FFT is numpy compatible (complex inputs/outputs)')"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Depending on the `numpy`-compatibility of the FFT, the `spectrogram` function takes one or two positional arguments, and three keyword arguments. If the FFT is `numpy` compatible, one positional argument is allowed, and it is a 1D real or complex `ndarray`. If the FFT is not `numpy`-compatible, if a single argument is supplied, it will be treated as the real part of the input, and if two positional arguments are supplied, they are treated as the real and imaginary parts of the signal.\n",
|
||||
"\n",
|
||||
"The keyword arguments are as follows:\n",
|
||||
"\n",
|
||||
"1. `scratchpad = None`: must be a 1D, dense, floating point array, twice as long as the input array; the `scratchpad` will be used as a temporary internal buffer to perform the Fourier transform; the `scratchpad` can repeatedly be re-used.\n",
|
||||
"1. `out = None`: must be a 1D, not necessarily dense, floating point array that will store the results\n",
|
||||
"1. `log = False`: must be either `True`, or `False`; if `True`, the `spectrogram` returns the logarithm of the absolute values of the Fourier transform."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-29T16:59:56.400603Z",
|
||||
"start_time": "2022-01-29T16:59:56.374748Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"original vector:\n",
|
||||
" array([0.0, 0.009775015390171337, 0.01954909674625918, ..., -0.5275140569487312, -0.5357931822978732, -0.5440211108893697], dtype=float64)\n",
|
||||
"\n",
|
||||
"spectrum:\n",
|
||||
" array([187.8635087634578, 315.3112063607119, 347.8814873399375, ..., 84.45888934298905, 347.8814873399374, 315.3112063607118], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"from ulab import utils as utils\n",
|
||||
"\n",
|
||||
"x = np.linspace(0, 10, num=1024)\n",
|
||||
"y = np.sin(x)\n",
|
||||
"\n",
|
||||
"a = utils.spectrogram(y)\n",
|
||||
"\n",
|
||||
"print('original vector:\\n', y)\n",
|
||||
"print('\\nspectrum:\\n', a)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"As such, `spectrogram` is really just a shorthand for `np.abs(np.fft.fft(signal))`, if the FFT is `numpy`-compatible, or `np.sqrt(a*a + b*b)` if the FFT returns the real (`a`) and imaginary (`b`) parts separately. However, `spectrogram` saves significant amounts of RAM: the expression `a*a + b*b` has to allocate memory for `a*a`, `b*b`, and finally, their sum. Similarly, `np.abs` returns a new array. This issue is compounded even more, if `np.log()` is used on the absolute value. \n",
|
||||
"\n",
|
||||
"In contrast, `spectrogram` handles all calculations in the same internal arrays, and allows one to re-use previously reserved RAM. This can be especially useful in cases, when `spectogram` is called repeatedly, as in the snippet below."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 34,
|
||||
"metadata": {
|
||||
"ExecuteTime": {
|
||||
"end_time": "2022-01-29T16:59:48.485610Z",
|
||||
"start_time": "2022-01-29T16:59:48.462593Z"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"signal: array([-27.38260169844543, 6.237834411021073, -0.4038327279002965, ..., -0.9795967096969854, -0.4038327279002969, 6.237834411021073], dtype=float64)\n",
|
||||
"out: array([-27.38260169844543, 6.237834411021073, -0.4038327279002965, ..., -0.9795967096969854, -0.4038327279002969, 6.237834411021073], dtype=float64)\n",
|
||||
"\n",
|
||||
"\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%micropython -unix 1\n",
|
||||
"\n",
|
||||
"from ulab import numpy as np\n",
|
||||
"from ulab import utils as utils\n",
|
||||
"\n",
|
||||
"n = 1024\n",
|
||||
"t = np.linspace(0, 2 * np.pi, num=1024)\n",
|
||||
"scratchpad = np.zeros(2 * n)\n",
|
||||
"\n",
|
||||
"for _ in range(10):\n",
|
||||
" signal = np.sin(t)\n",
|
||||
" utils.spectrogram(signal, out=signal, scratchpad=scratchpad, log=True)\n",
|
||||
"\n",
|
||||
"print('signal: ', signal)\n",
|
||||
"\n",
|
||||
"for _ in range(10):\n",
|
||||
" signal = np.sin(t)\n",
|
||||
" out = np.log(utils.spectrogram(signal))\n",
|
||||
"\n",
|
||||
"print('out: ', out)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Note that `scratchpad` is reserved only once, and then is re-used in the first loop. By assigning `signal` to the output, we save additional RAM. This approach avoids the usual problem of memory fragmentation, which would happen in the second loop, where both `spectrogram`, and `np.log` must reserve RAM in each iteration."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
}
|
||||
],
|
||||
|
|
@ -416,7 +565,7 @@
|
|||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.8.5"
|
||||
"version": "3.11.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
# for extract-pyi
|
||||
isort
|
||||
black
|
||||
|
||||
# For docs
|
||||
Sphinx<4
|
||||
sphinx-rtd-theme
|
||||
myst-parser
|
||||
mypy
|
||||
black
|
||||
isort
|
||||
astroid
|
||||
setuptools
|
||||
setuptools_scm
|
||||
|
||||
Sphinx>=4.0.0
|
||||
sphinx-autoapi
|
||||
sphinx-rtd-theme
|
||||
sphinxcontrib-svg2pdfconverter
|
||||
readthedocs-sphinx-search
|
||||
myst-parser
|
||||
|
||||
# for check-stubs
|
||||
mypy
|
||||
|
||||
# For stubs and annotations
|
||||
adafruit-circuitpython-typing
|
||||
build
|
||||
|
|
|
|||
85
snippets/json_to_ndarray.py
Normal file
85
snippets/json_to_ndarray.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# This file is part of the micropython-ulab project, https://github.com/v923z/micropython-ulab
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2022 Zoltán Vörös
|
||||
|
||||
import sys
|
||||
|
||||
use_ulab = False
|
||||
|
||||
try:
|
||||
from ubinascii import a2b_base64 as b64decode
|
||||
from ubinascii import unhexlify
|
||||
import ujson as json
|
||||
from ulab import numpy as np
|
||||
use_ulab = True
|
||||
except:
|
||||
from base64 import b64decode
|
||||
import json
|
||||
import numpy as np
|
||||
from numpy.lib.format import descr_to_dtype
|
||||
|
||||
def ulab_descr_to_dtype(descriptor):
|
||||
descriptor = descriptor[1:]
|
||||
|
||||
if descriptor == 'u1':
|
||||
return np.uint8
|
||||
elif descriptor == 'i1':
|
||||
return np.int8
|
||||
if descriptor == 'u2':
|
||||
return np.uint16
|
||||
if descriptor == 'i2':
|
||||
return np.int16
|
||||
elif descriptor == 'f8':
|
||||
if np.float != ord('d'):
|
||||
raise TypeError('doubles are not supported')
|
||||
else:
|
||||
return np.float
|
||||
elif descriptor == 'f16':
|
||||
if np.float != ord('f'):
|
||||
raise TypeError('')
|
||||
else:
|
||||
return np.float
|
||||
else:
|
||||
raise TypeError('descriptor could not be decoded')
|
||||
|
||||
|
||||
def json_to_ndarray(json_string, b64=True):
|
||||
"""
|
||||
Turn a json string into an ndarray
|
||||
The string must be the representation of a dictionary with the three keys
|
||||
|
||||
- dtype: a valid numpy dtype string (one of |u1, |i1, <u2, <i2, <f4, <f8, <c8, <c16, >u2, >i2, >f4, >f8, >c8, >c16)
|
||||
- array: the hexified, or base64-encoded raw data array
|
||||
- shape: the shape of the array (a list or tuple of integers)
|
||||
|
||||
Usage:
|
||||
str = '{"dtype": "<f8", "array": "AAAAAAAAAAAAAAAAAADwPwAAAAAAAABAAAAAAAAACEAAAAAAAAAQQAAAAAAAABRAAAAAAAAAGEAAAAAAAAAcQAAAAAAAACBA\n", "shape": [3, 3]}'
|
||||
json_to_ndarray(str, b64=True)
|
||||
"""
|
||||
obj = json.loads(json_string)
|
||||
|
||||
if not isinstance(obj, dict):
|
||||
raise TypeError('input argument must be a dictionary')
|
||||
if set(obj.keys()) != {'array', 'dtype', 'shape'}:
|
||||
raise ValueError('input must have the keys "array", "dtype", "shape"')
|
||||
|
||||
descriptor = obj['dtype']
|
||||
if use_ulab:
|
||||
dtype = ulab_descr_to_dtype(descriptor)
|
||||
else:
|
||||
dtype = descr_to_dtype(descriptor)
|
||||
|
||||
if not b64:
|
||||
data = unhexlify(obj['array'])
|
||||
else:
|
||||
data = b64decode(obj['array'])
|
||||
|
||||
ndarray = np.frombuffer(data, dtype=dtype).reshape(tuple(obj['shape']))
|
||||
|
||||
if dtype in (np.uint16, np.int16, np.float):
|
||||
if sys.byteorder != descriptor[1]:
|
||||
ndarray.byteswap()
|
||||
|
||||
return ndarray
|
||||
74
snippets/ndarray_to_json.py
Normal file
74
snippets/ndarray_to_json.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
# This file is part of the micropython-ulab project, https://github.com/v923z/micropython-ulab
|
||||
#
|
||||
# The MIT License (MIT)
|
||||
#
|
||||
# Copyright (c) 2022 Zoltán Vörös
|
||||
|
||||
import sys
|
||||
|
||||
use_ulab = False
|
||||
|
||||
try:
|
||||
from ubinascii import b2a_base64 as b64encode
|
||||
from ubinascii import hexlify
|
||||
import ujson as json
|
||||
from ulab import numpy as np
|
||||
use_ulab = True
|
||||
except:
|
||||
from base64 import b64encode
|
||||
import json
|
||||
import numpy as np
|
||||
from numpy.lib.format import dtype_to_descr
|
||||
|
||||
def ulab_dtype_to_descr(dtype):
|
||||
desc = '>'
|
||||
if sys.byteorder == 'little':
|
||||
desc = '<'
|
||||
|
||||
if dtype == ord('B'):
|
||||
desc = '|u1'
|
||||
elif dtype == ord('b'):
|
||||
desc = '|i1'
|
||||
elif dtype == ord('H'):
|
||||
desc = desc + 'u2'
|
||||
elif dtype == ord('h'):
|
||||
desc = desc + 'i2'
|
||||
elif dtype == ord('d'):
|
||||
desc = desc + 'f8'
|
||||
elif dtype == ord('f'):
|
||||
desc = desc + 'f4'
|
||||
elif dtype == ord('c'):
|
||||
desc = desc + 'c16'
|
||||
if np.array([1], dtype=np.float).itemsize == 4:
|
||||
desc = desc + 'c8'
|
||||
|
||||
return desc
|
||||
|
||||
def ndarray_to_json(obj, b64=True):
|
||||
"""
|
||||
Turn an ndarray into a json string, using either base64 encoding or hexify
|
||||
Returns a serialised dictionary with three keys:
|
||||
|
||||
- dtype: a valid numpy dtype string (one of |u1, |i1, <u2, <i2, <f4, <f8, <c8, <c16, >u2, >i2, >f4, >f8, >c8, >c16)
|
||||
- array: the hexified, or base64-encoded raw data array
|
||||
- shape: the shape of the array (a list or tuple of integers)
|
||||
|
||||
Usage:
|
||||
ndarray = np.array([1, 2, 3], dtype=np.uint8)
|
||||
ndarray_to_json(ndarray, b64=True)
|
||||
"""
|
||||
|
||||
if not isinstance(obj, np.ndarray):
|
||||
raise TypeError('input argument must be an ndarray')
|
||||
|
||||
if use_ulab:
|
||||
dtype_desciptor = ulab_dtype_to_descr(obj.dtype)
|
||||
else:
|
||||
dtype_desciptor = dtype_to_descr(obj.dtype)
|
||||
|
||||
if not b64:
|
||||
data = hexlify(obj.tobytes())
|
||||
else:
|
||||
data = b64encode(obj.tobytes())
|
||||
|
||||
return json.dumps({'array': data, 'dtype': dtype_desciptor, 'shape': obj.shape})
|
||||
5
snippets/numpy/__init__.py
Normal file
5
snippets/numpy/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
from . import core
|
||||
from .core import *
|
||||
from . import lib
|
||||
from .lib import *
|
||||
5
snippets/numpy/core/__init__.py
Normal file
5
snippets/numpy/core/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
from .multiarray import *
|
||||
from .numeric import *
|
||||
from .fromnumeric import *
|
||||
from .shape_base import *
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue