Skip to content

Commit

Permalink
Merge branch 'master' into take
Browse files Browse the repository at this point in the history
  • Loading branch information
v923z authored Oct 8, 2024
2 parents d3b665b + c0b3262 commit 341393d
Show file tree
Hide file tree
Showing 25 changed files with 459 additions and 180 deletions.
20 changes: 11 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ on:

jobs:
micropython:
continue-on-error: true
strategy:
matrix:
os:
Expand All @@ -28,10 +29,10 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Set up Python 3.10
uses: actions/setup-python@v1
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Install requirements
run: |
Expand All @@ -44,10 +45,10 @@ jobs:
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
Expand All @@ -56,6 +57,7 @@ jobs:
run: ./build.sh ${{ matrix.dims }}

circuitpython:
continue-on-error: true
strategy:
matrix:
os:
Expand All @@ -68,18 +70,18 @@ jobs:
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Set up Python 3.10
uses: actions/setup-python@v1
- name: Set up Python 3.12
uses: actions/setup-python@v5
with:
python-version: "3.10"
python-version: "3.12"

- name: Versions
run: |
gcc --version
python3 --version
- name: Checkout ulab
uses: actions/checkout@v1
uses: actions/checkout@v4

- name: Install requirements
run: |
Expand Down
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# ulab

[![Documentation Status](https://readthedocs.org/projects/micropython-ulab-robert/badge/?version=latest)](https://micropython-ulab-robert.readthedocs.io/en/latest/?badge=latest)
[![Documentation Status](https://readthedocs.org/projects/micropython-ulab/badge/?version=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 (`ndarray`s) for numerical data of one to four
Expand Down Expand Up @@ -112,7 +112,6 @@ of the user manual.
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/

## Compiling

Expand Down
3 changes: 1 addition & 2 deletions build-cp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,7 @@ HERE="$(dirname -- "$(readlinkf_posix -- "${0}")" )"
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"

Expand Down
31 changes: 18 additions & 13 deletions code/ndarray.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
*
* The MIT License (MIT)
*
* Copyright (c) 2019-2022 Zoltán Vörös
* Copyright (c) 2019-2024 Zoltán Vörös
* 2020 Jeff Epler for Adafruit Industries
* 2020 Taku Fukada
*/
Expand Down Expand Up @@ -509,8 +509,9 @@ static size_t multiply_size(size_t a, size_t b) {
return result;
}

ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype) {
ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides, uint8_t dtype, uint8_t *buffer) {
// Creates the base ndarray with shape, and initialises the values to straight 0s
// optionally, values can be supplied via the last argument
ndarray_obj_t *ndarray = m_new_obj(ndarray_obj_t);
ndarray->base.type = &ulab_ndarray_type;
ndarray->dtype = dtype == NDARRAY_BOOL ? NDARRAY_UINT8 : dtype;
Expand All @@ -536,9 +537,13 @@ ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides

// if the length is 0, still allocate a single item, so that contractions can be handled
size_t len = multiply_size(ndarray->itemsize, MAX(1, ndarray->len));
uint8_t *array = m_new0(byte, len);
// this should set all elements to 0, irrespective of the of the dtype (all bits are zero)
// we could, perhaps, leave this step out, and initialise the array only, when needed
uint8_t *array;
array = buffer;
if(array == NULL) {
// this should set all elements to 0, irrespective of the of the dtype (all bits are zero)
// we could, perhaps, leave this step out, and initialise the array only, when needed
array = m_new0(byte, len);
}
ndarray->array = array;
ndarray->origin = array;
return ndarray;
Expand All @@ -547,12 +552,12 @@ ndarray_obj_t *ndarray_new_ndarray(uint8_t ndim, size_t *shape, int32_t *strides
ndarray_obj_t *ndarray_new_dense_ndarray(uint8_t ndim, size_t *shape, uint8_t dtype) {
// creates a dense array, i.e., one, where the strides are derived directly from the shapes
// the function should work in the general n-dimensional case
int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
strides[ULAB_MAX_DIMS-1] = (int32_t)ulab_binary_get_size(dtype);
for(size_t i=ULAB_MAX_DIMS; i > 1; i--) {
strides[i-2] = strides[i-1] * MAX(1, shape[i-1]);
}
return ndarray_new_ndarray(ndim, shape, strides, dtype);
// int32_t *strides = m_new(int32_t, ULAB_MAX_DIMS);
// strides[ULAB_MAX_DIMS - 1] = (int32_t)ulab_binary_get_size(dtype);
// for(size_t i = ULAB_MAX_DIMS; i > 1; i--) {
// strides[i-2] = strides[i-1] * MAX(1, shape[i-1]);
// }
return ndarray_new_ndarray(ndim, shape, NULL, dtype, NULL);
}

ndarray_obj_t *ndarray_new_ndarray_from_tuple(mp_obj_tuple_t *_shape, uint8_t dtype) {
Expand Down Expand Up @@ -650,7 +655,7 @@ ndarray_obj_t *ndarray_copy_view(ndarray_obj_t *source) {
if(source->boolean) {
dtype = NDARRAY_BOOL;
}
ndarray_obj_t *ndarray = ndarray_new_ndarray(source->ndim, source->shape, strides, dtype);
ndarray_obj_t *ndarray = ndarray_new_ndarray(source->ndim, source->shape, strides, dtype, NULL);
ndarray_copy_array(source, ndarray, 0);
return ndarray;
}
Expand Down Expand Up @@ -1884,7 +1889,7 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) {
#if ULAB_SUPPORTS_COMPLEX
if(self->dtype == NDARRAY_COMPLEX) {
int32_t *strides = strides_from_shape(self->shape, NDARRAY_FLOAT);
ndarray_obj_t *target = ndarray_new_ndarray(self->ndim, self->shape, strides, NDARRAY_FLOAT);
ndarray_obj_t *target = ndarray_new_ndarray(self->ndim, self->shape, strides, NDARRAY_FLOAT, NULL);
ndarray = MP_OBJ_TO_PTR(carray_abs(self, target));
} else {
#endif
Expand Down
2 changes: 1 addition & 1 deletion code/ndarray.h
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,7 @@ 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 *);
Expand Down
10 changes: 7 additions & 3 deletions code/numpy/carray/carray.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@

#if ULAB_SUPPORTS_COMPLEX

//| import builtins
//|
//| import ulab.numpy

//| def real(val):
//| 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."""
Expand All @@ -54,7 +56,7 @@ mp_obj_t carray_real(mp_obj_t _source) {

MP_DEFINE_CONST_FUN_OBJ_1(carray_real_obj, carray_real);

//| def imag(val):
//| 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."""
Expand Down Expand Up @@ -82,7 +84,9 @@ MP_DEFINE_CONST_FUN_OBJ_1(carray_imag_obj, carray_imag);

#if ULAB_NUMPY_HAS_CONJUGATE

//| def conjugate(val):
//| 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."""
Expand Down
13 changes: 2 additions & 11 deletions code/numpy/create.c
Original file line number Diff line number Diff line change
Expand Up @@ -1073,19 +1073,10 @@ mp_obj_t create_frombuffer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw
len = count;
}
}
ndarray_obj_t *ndarray = 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;

size_t *shape = ndarray_shape_vector(0, 0, 0, len);
uint8_t *buffer = bufinfo.buf;
ndarray->array = buffer + offset;
return MP_OBJ_FROM_PTR(ndarray);
return ndarray_new_ndarray(1, shape, NULL, dtype, buffer + offset);
}
return mp_const_none;
}
Expand Down
14 changes: 7 additions & 7 deletions code/numpy/fft/fft.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/
Expand Down Expand Up @@ -43,16 +43,16 @@
//|
#if ULAB_SUPPORTS_COMPLEX & ULAB_FFT_IS_NUMPY_COMPATIBLE
static mp_obj_t fft_fft(mp_obj_t arg) {
return fft_fft_ifft_spectrogram(arg, FFT_FFT);
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);
}
}

Expand All @@ -71,17 +71,17 @@ 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_spectrogram(arg, FFT_IFFT);
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);
}
}

Expand Down
47 changes: 13 additions & 34 deletions code/numpy/fft/fft_tools.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*/

#include <math.h>
Expand Down Expand Up @@ -45,7 +45,7 @@
imag[i] = data[2i+1]
*/
void fft_kernel_complex(mp_float_t *data, size_t n, int isign) {
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;
Expand Down Expand Up @@ -94,9 +94,9 @@ void fft_kernel_complex(mp_float_t *data, 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.
* routine can be called from utils.spectrogram.
*/
mp_obj_t fft_fft_ifft_spectrogram(mp_obj_t data_in, uint8_t type) {
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"));
}
Expand Down Expand Up @@ -134,20 +134,10 @@ mp_obj_t fft_fft_ifft_spectrogram(mp_obj_t data_in, uint8_t type) {
}
data -= 2 * len;

if((type == FFT_FFT) || (type == FFT_SPECTROGRAM)) {
fft_kernel_complex(data, len, 1);
if(type == FFT_SPECTROGRAM) {
ndarray_obj_t *spectrum = ndarray_new_linear_array(len, NDARRAY_FLOAT);
mp_float_t *sarray = (mp_float_t *)spectrum->array;
for(size_t i = 0; i < len; i++) {
*sarray++ = MICROPY_FLOAT_C_FUN(sqrt)(data[0] * data[0] + data[1] * data[1]);
data += 2;
}
m_del(mp_float_t, data, 2 * len);
return MP_OBJ_FROM_PTR(spectrum);
}
if(type == FFT_FFT) {
fft_kernel(data, len, 1);
} else { // inverse transform
fft_kernel_complex(data, len, -1);
fft_kernel(data, len, -1);
// TODO: numpy accepts the norm keyword argument
for(size_t i = 0; i < 2 * len; i++) {
*data++ /= len;
Expand Down Expand Up @@ -202,7 +192,7 @@ void fft_kernel(mp_float_t *real, mp_float_t *imag, size_t n, int isign) {
}
}

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(MP_ERROR_TEXT("FFT is defined for ndarrays only"));
}
Expand Down Expand Up @@ -258,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
Expand All @@ -275,13 +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_FROM_PTR(out_re);
} else {
mp_obj_t tuple[2];
tuple[0] = MP_OBJ_FROM_PTR(out_re);
tuple[1] = MP_OBJ_FROM_PTR(out_im);
return mp_obj_new_tuple(2, tuple);
}
mp_obj_t tuple[2];
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 */
5 changes: 2 additions & 3 deletions code/numpy/fft/fft_tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +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_spectrogram(mp_obj_t , uint8_t );
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_ */
Loading

0 comments on commit 341393d

Please sign in to comment.