aboutsummaryrefslogtreecommitdiff
path: root/circuitpython/extmod/ulab/code/numpy/approx.c
diff options
context:
space:
mode:
authorRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
committerRaghuram Subramani <raghus2247@gmail.com>2022-06-19 19:47:51 +0530
commit4fd287655a72b9aea14cdac715ad5b90ed082ed2 (patch)
tree65d393bc0e699dd12d05b29ba568e04cea666207 /circuitpython/extmod/ulab/code/numpy/approx.c
parent0150f70ce9c39e9e6dd878766c0620c85e47bed0 (diff)
add circuitpython code
Diffstat (limited to 'circuitpython/extmod/ulab/code/numpy/approx.c')
-rw-r--r--circuitpython/extmod/ulab/code/numpy/approx.c227
1 files changed, 227 insertions, 0 deletions
diff --git a/circuitpython/extmod/ulab/code/numpy/approx.c b/circuitpython/extmod/ulab/code/numpy/approx.c
new file mode 100644
index 0000000..85cdbf7
--- /dev/null
+++ b/circuitpython/extmod/ulab/code/numpy/approx.c
@@ -0,0 +1,227 @@
+/*
+ * This file is part of the micropython-ulab project,
+ *
+ * https://github.com/v923z/micropython-ulab
+ *
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2020-2021 Zoltán Vörös
+ * 2020 Diego Elio Pettenò
+ * 2020 Taku Fukada
+*/
+
+#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 "../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)};
+
+#if ULAB_NUMPY_HAS_INTERP
+//| def interp(
+//| x: ulab.numpy.ndarray,
+//| xp: ulab.numpy.ndarray,
+//| fp: ulab.numpy.ndarray,
+//| *,
+//| left: Optional[_float] = None,
+//| right: Optional[_float] = None
+//| ) -> ulab.numpy.ndarray:
+//| """
+//| :param ulab.numpy.ndarray x: The x-coordinates at which to evaluate the interpolated values.
+//| :param ulab.numpy.ndarray xp: The x-coordinates of the data points, must be increasing
+//| :param ulab.numpy.ndarray fp: The y-coordinates of the data points, same length as xp
+//| :param left: Value to return for ``x < xp[0]``, default is ``fp[0]``.
+//| :param right: Value to return for ``x > xp[-1]``, default is ``fp[-1]``.
+//|
+//| Returns the one-dimensional piecewise linear interpolant to a function with given discrete data points (xp, fp), evaluated at x."""
+//| ...
+//|
+
+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_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 *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"));
+ }
+
+ ndarray_obj_t *y = ndarray_new_linear_array(x->len, NDARRAY_FLOAT);
+ mp_float_t left_value, right_value;
+ uint8_t *xparray = (uint8_t *)xp->array;
+
+ mp_float_t xp_left = ndarray_get_float_value(xparray, xp->dtype);
+ xparray += (xp->len-1) * xp->strides[ULAB_MAX_DIMS - 1];
+ mp_float_t xp_right = ndarray_get_float_value(xparray, xp->dtype);
+
+ uint8_t *fparray = (uint8_t *)fp->array;
+
+ if(args[3].u_obj == mp_const_none) {
+ left_value = ndarray_get_float_value(fparray, fp->dtype);
+ } else {
+ left_value = mp_obj_get_float(args[3].u_obj);
+ }
+ if(args[4].u_obj == mp_const_none) {
+ fparray += (fp->len-1) * fp->strides[ULAB_MAX_DIMS - 1];
+ right_value = ndarray_get_float_value(fparray, fp->dtype);
+ } else {
+ right_value = mp_obj_get_float(args[4].u_obj);
+ }
+
+ xparray = xp->array;
+ fparray = fp->array;
+
+ uint8_t *xarray = (uint8_t *)x->array;
+ mp_float_t *yarray = (mp_float_t *)y->array;
+ uint8_t *temp;
+
+ for(size_t i=0; i < x->len; i++, yarray++) {
+ mp_float_t x_value = ndarray_get_float_value(xarray, x->dtype);
+ xarray += x->strides[ULAB_MAX_DIMS - 1];
+ if(x_value < xp_left) {
+ *yarray = left_value;
+ } else if(x_value > xp_right) {
+ *yarray = right_value;
+ } else { // do the binary search here
+ mp_float_t xp_left_, xp_right_;
+ mp_float_t fp_left, fp_right;
+ size_t left_index = 0, right_index = xp->len - 1, middle_index;
+ while(right_index - left_index > 1) {
+ middle_index = left_index + (right_index - left_index) / 2;
+ temp = xparray + middle_index * xp->strides[ULAB_MAX_DIMS - 1];
+ mp_float_t xp_middle = ndarray_get_float_value(temp, xp->dtype);
+ if(x_value <= xp_middle) {
+ right_index = middle_index;
+ } else {
+ left_index = middle_index;
+ }
+ }
+ temp = xparray + left_index * xp->strides[ULAB_MAX_DIMS - 1];
+ xp_left_ = ndarray_get_float_value(temp, xp->dtype);
+
+ temp = xparray + right_index * xp->strides[ULAB_MAX_DIMS - 1];
+ xp_right_ = ndarray_get_float_value(temp, xp->dtype);
+
+ temp = fparray + left_index * fp->strides[ULAB_MAX_DIMS - 1];
+ fp_left = ndarray_get_float_value(temp, fp->dtype);
+
+ temp = fparray + right_index * fp->strides[ULAB_MAX_DIMS - 1];
+ fp_right = ndarray_get_float_value(temp, fp->dtype);
+
+ *yarray = fp_left + (x_value - xp_left_) * (fp_right - fp_left) / (xp_right_ - xp_left_);
+ }
+ }
+ return MP_OBJ_FROM_PTR(y);
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(approx_interp_obj, 2, approx_interp);
+#endif
+
+#if ULAB_NUMPY_HAS_TRAPZ
+//| def trapz(y: ulab.numpy.ndarray, x: Optional[ulab.numpy.ndarray] = None, dx: _float = 1.0) -> _float:
+//| """
+//| :param 1D ulab.numpy.ndarray y: the values of the dependent variable
+//| :param 1D ulab.numpy.ndarray x: optional, the coordinates of the independent variable. Defaults to uniformly spaced values.
+//| :param float dx: the spacing between sample points, if x=None
+//|
+//| Returns the integral of y(x) using the trapezoidal rule.
+//| """
+//| ...
+//|
+
+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_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_float_t (*funcy)(void *) = ndarray_get_float_function(y->dtype);
+ uint8_t *yarray = (uint8_t *)y->array;
+
+ size_t count = 1;
+ mp_float_t y1, y2, m;
+
+ 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_float_t (*funcx)(void *) = ndarray_get_float_function(x->dtype);
+ uint8_t *xarray = (uint8_t *)x->array;
+ mp_float_t x1, x2;
+
+ y1 = funcy(yarray);
+ yarray += y->strides[ULAB_MAX_DIMS - 1];
+ x1 = funcx(xarray);
+ xarray += x->strides[ULAB_MAX_DIMS - 1];
+
+ for(size_t i=1; i < y->len; i++) {
+ y2 = funcy(yarray);
+ yarray += y->strides[ULAB_MAX_DIMS - 1];
+ x2 = funcx(xarray);
+ xarray += x->strides[ULAB_MAX_DIMS - 1];
+ mp_float_t value = (x2 - x1) * (y2 + y1);
+ m = mean + (value - mean) / (mp_float_t)count;
+ mean = m;
+ x1 = x2;
+ y1 = y2;
+ count++;
+ }
+ } else {
+ mp_float_t dx = mp_obj_get_float(args[2].u_obj);
+ y1 = funcy(yarray);
+ yarray += y->strides[ULAB_MAX_DIMS - 1];
+
+ for(size_t i=1; i < y->len; i++) {
+ y2 = ndarray_get_float_index(y->array, y->dtype, i);
+ mp_float_t value = (y2 + y1);
+ m = mean + (value - mean) / (mp_float_t)count;
+ mean = m;
+ y1 = y2;
+ count++;
+ }
+ mean *= dx;
+ }
+ return mp_obj_new_float(MICROPY_FLOAT_CONST(0.5)*mean*(y->len-1));
+}
+
+MP_DEFINE_CONST_FUN_OBJ_KW(approx_trapz_obj, 1, approx_trapz);
+#endif