Skip to content

Commit 43cda00

Browse files
authored
Merge pull request v923z#5 from v923z/testing
Testing
2 parents 74a3b17 + 2af876e commit 43cda00

File tree

16 files changed

+946
-395
lines changed

16 files changed

+946
-395
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ Documentation can be found under https://micropython-ulab.readthedocs.io/en/late
88
The source for the manual is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab-manual.ipynb,
99
while developer help is in https://github.com/v923z/micropython-ulab/blob/master/docs/ulab.ipynb.
1010

11-
Firmware for pyboard.v.1.1 is updated once in a while, and can be downloaded
12-
from https://github.com/v923z/micropython-ulab/releases, otherwise, it can
13-
be compiled from the source by following the steps
11+
Firmware for pyboard.v.1.1, as well as for PYBD_SF6 is updated once
12+
in a while, and can be downloaded from https://github.com/v923z/micropython-ulab/releases,
13+
otherwise, it can be compiled from the source by following the steps
1414
https://micropython-usermod.readthedocs.io/en/latest/usermods_05.html#compiling-our-module.
1515

1616

code/fft.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,13 @@ enum FFT_TYPE {
2626
FFT_SPECTRUM,
2727
};
2828

29-
void fft_kernel(float *real, float *imag, int n, int isign) {
29+
void fft_kernel(mp_float_t *real, mp_float_t *imag, int n, int isign) {
3030
// This is basically a modification of four1 from Numerical Recipes
3131
// The main difference is that this function takes two arrays, one
3232
// for the real, and one for the imaginary parts.
3333
int j, m, mmax, istep;
34-
float tempr, tempi;
35-
float wtemp, wr, wpr, wpi, wi, theta;
34+
mp_float_t tempr, tempi;
35+
mp_float_t wtemp, wr, wpr, wpi, wi, theta;
3636

3737
j = 0;
3838
for(int i = 0; i < n; i++) {
@@ -52,9 +52,9 @@ void fft_kernel(float *real, float *imag, int n, int isign) {
5252
while (n > mmax) {
5353
istep = mmax << 1;
5454
theta = -1.0*isign*6.28318530717959/istep;
55-
wtemp = sinf(0.5 * theta);
55+
wtemp = MICROPY_FLOAT_C_FUN(sin)(0.5 * theta);
5656
wpr = -2.0 * wtemp * wtemp;
57-
wpi = sinf(theta);
57+
wpi = MICROPY_FLOAT_C_FUN(sin)(theta);
5858
wr = 1.0;
5959
wi = 0.0;
6060
for(m = 0; m < mmax; m++) {
@@ -92,27 +92,27 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
9292
}
9393

9494
ndarray_obj_t *out_re = create_new_ndarray(1, len, NDARRAY_FLOAT);
95-
float *data_re = (float *)out_re->array->items;
95+
mp_float_t *data_re = (mp_float_t *)out_re->array->items;
9696

9797
if(re->array->typecode == NDARRAY_FLOAT) {
9898
// By treating this case separately, we can save a bit of time.
9999
// I don't know if it is worthwhile, though...
100-
memcpy((float *)out_re->array->items, (float *)re->array->items, re->bytes);
100+
memcpy((mp_float_t *)out_re->array->items, (mp_float_t *)re->array->items, re->bytes);
101101
} else {
102102
for(size_t i=0; i < len; i++) {
103103
data_re[i] = ndarray_get_float_value(re->array->items, re->array->typecode, i);
104104
}
105105
}
106106
ndarray_obj_t *out_im = create_new_ndarray(1, len, NDARRAY_FLOAT);
107-
float *data_im = (float *)out_im->array->items;
107+
mp_float_t *data_im = (mp_float_t *)out_im->array->items;
108108

109109
if(n_args == 2) {
110110
ndarray_obj_t *im = MP_OBJ_TO_PTR(arg_im);
111111
if (re->array->len != im->array->len) {
112112
mp_raise_ValueError("real and imaginary parts must be of equal length");
113113
}
114114
if(im->array->typecode == NDARRAY_FLOAT) {
115-
memcpy((float *)out_im->array->items, (float *)im->array->items, im->bytes);
115+
memcpy((mp_float_t *)out_im->array->items, (mp_float_t *)im->array->items, im->bytes);
116116
} else {
117117
for(size_t i=0; i < len; i++) {
118118
data_im[i] = ndarray_get_float_value(im->array->items, im->array->typecode, i);
@@ -123,7 +123,7 @@ mp_obj_t fft_fft_ifft_spectrum(size_t n_args, mp_obj_t arg_re, mp_obj_t arg_im,
123123
fft_kernel(data_re, data_im, len, 1);
124124
if(type == FFT_SPECTRUM) {
125125
for(size_t i=0; i < len; i++) {
126-
data_re[i] = sqrtf(data_re[i]*data_re[i] + data_im[i]*data_im[i]);
126+
data_re[i] = MICROPY_FLOAT_C_FUN(sqrt)(data_re[i]*data_re[i] + data_im[i]*data_im[i]);
127127
}
128128
}
129129
} else { // inverse transform

code/linalg.c

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -108,24 +108,24 @@ mp_obj_t linalg_size(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
108108
}
109109
}
110110

111-
bool linalg_invert_matrix(float *data, size_t N) {
111+
bool linalg_invert_matrix(mp_float_t *data, size_t N) {
112112
// returns true, of the inversion was successful,
113113
// false, if the matrix is singular
114114

115115
// initially, this is the unit matrix: the contents of this matrix is what
116116
// will be returned after all the transformations
117-
float *unit = m_new(float, N*N);
117+
mp_float_t *unit = m_new(mp_float_t, N*N);
118118

119-
float elem = 1.0;
119+
mp_float_t elem = 1.0;
120120
// initialise the unit matrix
121-
memset(unit, 0, sizeof(float)*N*N);
121+
memset(unit, 0, sizeof(mp_float_t)*N*N);
122122
for(size_t m=0; m < N; m++) {
123-
memcpy(&unit[m*(N+1)], &elem, sizeof(float));
123+
memcpy(&unit[m*(N+1)], &elem, sizeof(mp_float_t));
124124
}
125125
for(size_t m=0; m < N; m++){
126126
// this could be faster with ((c < epsilon) && (c > -epsilon))
127127
if(abs(data[m*(N+1)]) < epsilon) {
128-
m_del(float, unit, N*N);
128+
m_del(mp_float_t, unit, N*N);
129129
return false;
130130
}
131131
for(size_t n=0; n < N; n++){
@@ -145,8 +145,8 @@ bool linalg_invert_matrix(float *data, size_t N) {
145145
unit[N*m+n] /= elem;
146146
}
147147
}
148-
memcpy(data, unit, sizeof(float)*N*N);
149-
m_del(float, unit, N*N);
148+
memcpy(data, unit, sizeof(mp_float_t)*N*N);
149+
m_del(mp_float_t, unit, N*N);
150150
return true;
151151
}
152152

@@ -163,21 +163,21 @@ mp_obj_t linalg_inv(mp_obj_t o_in) {
163163
mp_raise_ValueError("only square matrices can be inverted");
164164
}
165165
ndarray_obj_t *inverted = create_new_ndarray(o->m, o->n, NDARRAY_FLOAT);
166-
float *data = (float *)inverted->array->items;
166+
mp_float_t *data = (mp_float_t *)inverted->array->items;
167167
mp_obj_t elem;
168168
for(size_t m=0; m < o->m; m++) { // rows first
169169
for(size_t n=0; n < o->n; n++) { // columns next
170170
// this could, perhaps, be done in single line...
171171
// On the other hand, we probably spend little time here
172172
elem = mp_binary_get_val_array(o->array->typecode, o->array->items, m*o->n+n);
173-
data[m*o->n+n] = (float)mp_obj_get_float(elem);
173+
data[m*o->n+n] = (mp_float_t)mp_obj_get_float(elem);
174174
}
175175
}
176176

177177
if(!linalg_invert_matrix(data, o->m)) {
178178
// TODO: I am not sure this is needed here. Otherwise,
179179
// how should we free up the unused RAM of inverted?
180-
m_del(float, inverted->array->items, o->n*o->n);
180+
m_del(mp_float_t, inverted->array->items, o->n*o->n);
181181
mp_raise_ValueError("input matrix is singular");
182182
}
183183
return MP_OBJ_FROM_PTR(inverted);
@@ -192,8 +192,8 @@ mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
192192
}
193193
// TODO: numpy uses upcasting here
194194
ndarray_obj_t *out = create_new_ndarray(m1->m, m2->n, NDARRAY_FLOAT);
195-
float *outdata = (float *)out->array->items;
196-
float sum, v1, v2;
195+
mp_float_t *outdata = (mp_float_t *)out->array->items;
196+
mp_float_t sum, v1, v2;
197197
for(size_t i=0; i < m1->n; i++) {
198198
for(size_t j=0; j < m2->m; j++) {
199199
sum = 0.0;
@@ -301,14 +301,14 @@ mp_obj_t linalg_det(mp_obj_t oin) {
301301
mp_raise_ValueError("input must be square matrix");
302302
}
303303

304-
float *tmp = m_new(float, in->n*in->n);
304+
mp_float_t *tmp = m_new(mp_float_t, in->n*in->n);
305305
for(size_t i=0; i < in->array->len; i++){
306306
tmp[i] = ndarray_get_float_value(in->array->items, in->array->typecode, i);
307307
}
308-
float c;
308+
mp_float_t c;
309309
for(size_t m=0; m < in->m-1; m++){
310310
if(abs(tmp[m*(in->n+1)]) < epsilon) {
311-
m_del(float, tmp, in->n*in->n);
311+
m_del(mp_float_t, tmp, in->n*in->n);
312312
return mp_obj_new_float(0.0);
313313
}
314314
for(size_t n=0; n < in->n; n++){
@@ -320,12 +320,12 @@ mp_obj_t linalg_det(mp_obj_t oin) {
320320
}
321321
}
322322
}
323-
float det = 1.0;
323+
mp_float_t det = 1.0;
324324

325325
for(size_t m=0; m < in->m; m++){
326326
det *= tmp[m*(in->n+1)];
327327
}
328-
m_del(float, tmp, in->n*in->n);
328+
m_del(mp_float_t, tmp, in->n*in->n);
329329
return mp_obj_new_float(det);
330330
}
331331

@@ -337,14 +337,15 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
337337
if(in->m != in->n) {
338338
mp_raise_ValueError("input must be square matrix");
339339
}
340-
float *array = m_new(float, in->array->len);
340+
mp_float_t *array = m_new(mp_float_t, in->array->len);
341341
for(size_t i=0; i < in->array->len; i++) {
342342
array[i] = ndarray_get_float_value(in->array->items, in->array->typecode, i);
343343
}
344344
// make sure the matrix is symmetric
345345
for(size_t m=0; m < in->m; m++) {
346346
for(size_t n=m+1; n < in->n; n++) {
347347
// compare entry (m, n) to (n, m)
348+
// TODO: this must probably be scaled!
348349
if(epsilon < abs(array[m*in->n + n] - array[n*in->n + m])) {
349350
mp_raise_ValueError("input matrix is asymmetric");
350351
}
@@ -354,12 +355,12 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
354355
// if we got this far, then the matrix will be symmetric
355356

356357
ndarray_obj_t *eigenvectors = create_new_ndarray(in->m, in->n, NDARRAY_FLOAT);
357-
float *eigvectors = (float *)eigenvectors->array->items;
358+
mp_float_t *eigvectors = (mp_float_t *)eigenvectors->array->items;
358359
// start out with the unit matrix
359360
for(size_t m=0; m < in->m; m++) {
360361
eigvectors[m*(in->n+1)] = 1.0;
361362
}
362-
float largest, w, t, c, s, tau, aMk, aNk, vm, vn;
363+
mp_float_t largest, w, t, c, s, tau, aMk, aNk, vm, vn;
363364
size_t M, N;
364365
size_t iterations = JACOBI_MAX*in->n*in->n;
365366
do {
@@ -387,12 +388,12 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
387388
// The following if/else chooses the smaller absolute value for the tangent
388389
// of the rotation angle. Going with the smaller should be numerically stabler.
389390
if(w > 0) {
390-
t = sqrtf(w*w + 1.0) - w;
391+
t = MICROPY_FLOAT_C_FUN(sqrt)(w*w + 1.0) - w;
391392
} else {
392-
t = -1.0*(sqrtf(w*w + 1.0) + w);
393+
t = -1.0*(MICROPY_FLOAT_C_FUN(sqrt)(w*w + 1.0) + w);
393394
}
394-
s = t / sqrtf(t*t + 1.0); // the sine of the rotation angle
395-
c = 1.0 / sqrtf(t*t + 1.0); // the cosine of the rotation angle
395+
s = t / MICROPY_FLOAT_C_FUN(sqrt)(t*t + 1.0); // the sine of the rotation angle
396+
c = 1.0 / MICROPY_FLOAT_C_FUN(sqrt)(t*t + 1.0); // the cosine of the rotation angle
396397
tau = (1.0-c)/s; // this is equal to the tangent of the half of the rotation angle
397398

398399
// at this point, we have the rotation angles, so we can transform the matrix
@@ -438,15 +439,15 @@ mp_obj_t linalg_eig(mp_obj_t oin) {
438439

439440
if(iterations == 0) {
440441
// the computation did not converge; numpy raises LinAlgError
441-
m_del(float, array, in->array->len);
442+
m_del(mp_float_t, array, in->array->len);
442443
mp_raise_ValueError("iterations did not converge");
443444
}
444445
ndarray_obj_t *eigenvalues = create_new_ndarray(1, in->n, NDARRAY_FLOAT);
445-
float *eigvalues = (float *)eigenvalues->array->items;
446+
mp_float_t *eigvalues = (mp_float_t *)eigenvalues->array->items;
446447
for(size_t i=0; i < in->n; i++) {
447448
eigvalues[i] = array[i*(in->n+1)];
448449
}
449-
m_del(float, array, in->array->len);
450+
m_del(mp_float_t, array, in->array->len);
450451

451452
mp_obj_tuple_t *tuple = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
452453
tuple->items[0] = MP_OBJ_FROM_PTR(eigenvalues);

code/linalg.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,19 @@
1414
#include "ndarray.h"
1515

1616
#define SWAP(t, a, b) { t tmp = a; a = b; b = tmp; }
17-
#define epsilon 1e-6
17+
18+
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
19+
#define epsilon 1.2e-7
20+
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
21+
#define epsilon 2.3e-16
22+
#endif
23+
1824
#define JACOBI_MAX 20
1925

2026
mp_obj_t linalg_transpose(mp_obj_t );
2127
mp_obj_t linalg_reshape(mp_obj_t , mp_obj_t );
2228
mp_obj_t linalg_size(size_t , const mp_obj_t *, mp_map_t *);
23-
bool linalg_invert_matrix(float *, size_t );
29+
bool linalg_invert_matrix(mp_float_t *, size_t );
2430
mp_obj_t linalg_inv(mp_obj_t );
2531
mp_obj_t linalg_dot(mp_obj_t , mp_obj_t );
2632
mp_obj_t linalg_zeros(size_t , const mp_obj_t *, mp_map_t *);

0 commit comments

Comments
 (0)