Skip to content

[WIP] Fix ndarray constructor #305

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 31 additions & 6 deletions code/ndarray.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,7 +777,7 @@ STATIC uint8_t ndarray_init_helper(size_t n_args, const mp_obj_t *pos_args, mp_m
return _dtype;
}

STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) {
mp_obj_t ndarray_array_constructor(size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
uint8_t dtype = ndarray_init_helper(n_args, args, kw_args);

if(MP_OBJ_IS_TYPE(args[0], &ulab_ndarray_type)) {
Expand Down Expand Up @@ -912,12 +912,38 @@ STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args,
return MP_OBJ_FROM_PTR(self);
}

mp_obj_t ndarray_array_constructor(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
// array constructor for ndarray, equivalent to numpy.array(...)
return ndarray_make_new_core(&ulab_ndarray_type, n_args, kw_args->used, pos_args, kw_args);
}
MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_array_constructor_obj, 1, ndarray_array_constructor);

STATIC mp_obj_t ndarray_make_new_core(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args, mp_map_t *kw_args) {
(void) type;
mp_arg_check_num(n_args, n_kw, 1, 2, true);
uint8_t dtype = ndarray_init_helper(n_args, args, kw_args);

mp_obj_t mp_shape = args[0];
mp_obj_t mp_ndim_maybe = mp_obj_len_maybe(mp_shape);
// single-number shapes "x" are interpreted the same as "(x,)"
mp_int_t ndim;
size_t shape[ULAB_MAX_DIMS];

if (mp_ndim_maybe == MP_OBJ_NULL) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will fail with ndarray(-12.3). You can make it safe by explicitly checking for the input type:

if(MP_OBJ_IS_INT(oshape)) {

ndim = 1;
shape[ULAB_MAX_DIMS - 1] = MP_OBJ_SMALL_INT_VALUE(mp_shape);
} else {
mp_obj_get_int_maybe(mp_ndim_maybe, &ndim);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you have to bail out, if the tuple is longer then ULAB_MAX_DIMS. The loop below is safe, but the user would still be left wondering, why the array is not what they expected.


mp_obj_iter_buf_t iter_buf;
mp_obj_t mp_shape_iter = mp_getiter(mp_shape, &iter_buf);

for (uint8_t i = ULAB_MAX_DIMS - ndim; i < ULAB_MAX_DIMS; i++) {
shape[i] = MP_OBJ_SMALL_INT_VALUE(mp_iternext(mp_shape_iter));
}
}

return MP_OBJ_FROM_PTR(
ndarray_new_dense_ndarray(ndim, shape, dtype)
);
}

#ifdef CIRCUITPY
mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *args, mp_map_t *kw_args) {
(void) type;
Expand All @@ -926,7 +952,6 @@ mp_obj_t ndarray_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj
if (kw_args != 0) {
n_kw = kw_args->used;
}
mp_map_init_fixed_table(kw_args, n_kw, args + n_args);
return ndarray_make_new_core(type, n_args, n_kw, args, kw_args);
}
#else
Expand Down
20 changes: 10 additions & 10 deletions code/numpy/approx/approx.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ const mp_obj_float_t approx_trapz_dx = {{&mp_type_float}, MICROPY_FLOAT_CONST(1.

#if ULAB_NUMPY_HAS_INTERP
//| def interp(
//| x: ulab.array,
//| xp: ulab.array,
//| fp: ulab.array,
//| x: ulab.ndarray,
//| xp: ulab.ndarray,
//| fp: ulab.ndarray,
//| *,
//| left: Optional[float] = None,
//| right: Optional[float] = None
//| ) -> ulab.array:
//| ) -> ulab.ndarray:
//| """
//| :param ulab.array x: The x-coordinates at which to evaluate the interpolated values.
//| :param ulab.array xp: The x-coordinates of the data points, must be increasing
//| :param ulab.array fp: The y-coordinates of the data points, same length as xp
//| :param ulab.ndarray x: The x-coordinates at which to evaluate the interpolated values.
//| :param ulab.ndarray xp: The x-coordinates of the data points, must be increasing
//| :param ulab.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]``.
//|
Expand Down Expand Up @@ -137,10 +137,10 @@ MP_DEFINE_CONST_FUN_OBJ_KW(approx_interp_obj, 2, approx_interp);
#endif

#if ULAB_NUMPY_HAS_TRAPZ
//| def trapz(y: ulab.array, x: Optional[ulab.array] = None, dx: float = 1.0) -> float:
//| def trapz(y: ulab.ndarray, x: Optional[ulab.ndarray] = None, dx: float = 1.0) -> float:
//| """
//| :param 1D ulab.array y: the values of the dependent variable
//| :param 1D ulab.array x: optional, the coordinates of the independent variable. Defaults to uniformly spaced values.
//| :param 1D ulab.ndarray y: the values of the dependent variable
//| :param 1D ulab.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.
Expand Down
12 changes: 6 additions & 6 deletions code/numpy/fft/fft.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@
//|


//| def fft(r: ulab.array, c: Optional[ulab.array] = None) -> Tuple[ulab.array, ulab.array]:
//| def fft(r: ulab.ndarray, c: Optional[ulab.ndarray] = None) -> Tuple[ulab.ndarray, ulab.ndarray]:
//| """
//| :param ulab.array r: A 1-dimension array of values whose size is a power of 2
//| :param ulab.array c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
//| :param ulab.ndarray r: A 1-dimension array of values whose size is a power of 2
//| :param ulab.ndarray c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
//| :return tuple (r, c): The real and complex parts of the FFT
//|
//| Perform a Fast Fourier Transform from the time domain into the frequency domain
Expand All @@ -48,10 +48,10 @@ static mp_obj_t fft_fft(size_t n_args, const mp_obj_t *args) {

MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(fft_fft_obj, 1, 2, fft_fft);

//| def ifft(r: ulab.array, c: Optional[ulab.array] = None) -> Tuple[ulab.array, ulab.array]:
//| def ifft(r: ulab.ndarray, c: Optional[ulab.ndarray] = None) -> Tuple[ulab.ndarray, ulab.ndarray]:
//| """
//| :param ulab.array r: A 1-dimension array of values whose size is a power of 2
//| :param ulab.array c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
//| :param ulab.ndarray r: A 1-dimension array of values whose size is a power of 2
//| :param ulab.ndarray c: An optional 1-dimension array of values whose size is a power of 2, giving the complex part of the value
//| :return tuple (r, c): The real and complex parts of the inverse FFT
//|
//| Perform an Inverse Fast Fourier Transform from the frequeny domain into the time domain"""
Expand Down
26 changes: 13 additions & 13 deletions code/numpy/linalg/linalg.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ static ndarray_obj_t *linalg_object_is_square(mp_obj_t obj) {
#endif

#if ULAB_MAX_DIMS > 1
//| def cholesky(A: ulab.array) -> ulab.array:
//| def cholesky(A: ulab.ndarray) -> ulab.ndarray:
//| """
//| :param ~ulab.array A: a positive definite, symmetric square matrix
//| :return ~ulab.array L: a square root matrix in the lower triangular form
//| :param ~ulab.ndarray A: a positive definite, symmetric square matrix
//| :return ~ulab.ndarray L: a square root matrix in the lower triangular form
//| :raises ValueError: If the input does not fulfill the necessary conditions
//|
//| The returned matrix satisfies the equation m=LL*"""
Expand Down Expand Up @@ -111,7 +111,7 @@ static mp_obj_t linalg_cholesky(mp_obj_t oin) {

MP_DEFINE_CONST_FUN_OBJ_1(linalg_cholesky_obj, linalg_cholesky);

//| def det(m: ulab.array) -> float:
//| def det(m: ulab.ndarray) -> float:
//| """
//| :param: m, a square matrix
//| :return float: The determinant of the matrix
Expand Down Expand Up @@ -182,10 +182,10 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_det_obj, linalg_det);

#endif

//| def dot(m1: ulab.array, m2: ulab.array) -> Union[ulab.array, float]:
//| def dot(m1: ulab.ndarray, m2: ulab.ndarray) -> Union[ulab.ndarray, float]:
//| """
//| :param ~ulab.array m1: a matrix, or a vector
//| :param ~ulab.array m2: a matrix, or a vector
//| :param ~ulab.ndarray m1: a matrix, or a vector
//| :param ~ulab.ndarray m2: a matrix, or a vector
//|
//| Computes the product of two matrices, or two vectors. In the letter case, the inner product is returned."""
//| ...
Expand Down Expand Up @@ -247,7 +247,7 @@ static mp_obj_t linalg_dot(mp_obj_t _m1, mp_obj_t _m2) {
MP_DEFINE_CONST_FUN_OBJ_2(linalg_dot_obj, linalg_dot);

#if ULAB_MAX_DIMS > 1
//| def eig(m: ulab.array) -> Tuple[ulab.array, ulab.array]:
//| def eig(m: ulab.ndarray) -> Tuple[ulab.ndarray, ulab.ndarray]:
//| """
//| :param m: a square matrix
//| :return tuple (eigenvectors, eigenvalues):
Expand Down Expand Up @@ -308,9 +308,9 @@ static mp_obj_t linalg_eig(mp_obj_t oin) {

MP_DEFINE_CONST_FUN_OBJ_1(linalg_eig_obj, linalg_eig);

//| def inv(m: ulab.array) -> ulab.array:
//| def inv(m: ulab.ndarray) -> ulab.ndarray:
//| """
//| :param ~ulab.array m: a square matrix
//| :param ~ulab.ndarray m: a square matrix
//| :return: The inverse of the matrix, if it exists
//| :raises ValueError: if the matrix is not invertible
//|
Expand Down Expand Up @@ -346,9 +346,9 @@ static mp_obj_t linalg_inv(mp_obj_t o_in) {
MP_DEFINE_CONST_FUN_OBJ_1(linalg_inv_obj, linalg_inv);
#endif

//| def norm(x: ulab.array) -> float:
//| def norm(x: ulab.ndarray) -> float:
//| """
//| :param ~ulab.array x: a vector or a matrix
//| :param ~ulab.ndarray x: a vector or a matrix
//|
//| Computes the 2-norm of a vector or a matrix, i.e., ``sqrt(sum(x*x))``, however, without the RAM overhead."""
//| ...
Expand Down Expand Up @@ -388,7 +388,7 @@ MP_DEFINE_CONST_FUN_OBJ_1(linalg_norm_obj, linalg_norm);
#if ULAB_MAX_DIMS > 1
#if ULAB_LINALG_HAS_TRACE

//| def trace(m: ulab.array) -> float:
//| def trace(m: ulab.ndarray) -> float:
//| """
//| :param m: a square matrix
//|
Expand Down
16 changes: 8 additions & 8 deletions code/numpy/numerical/numerical.c
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argmin_obj, 1, numerical_argmin);
#endif

#if ULAB_NUMPY_HAS_ARGSORT
//| def argsort(array: ulab.array, *, axis: int = -1) -> ulab.array:
//| def argsort(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray:
//| """Returns an array which gives indices into the input array from least to greatest."""
//| ...
//|
Expand Down Expand Up @@ -627,7 +627,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_argsort_obj, 1, numerical_argsort);
#endif

#if ULAB_NUMPY_HAS_CROSS
//| def cross(a: ulab.array, b: ulab.array) -> ulab.array:
//| def cross(a: ulab.ndarray, b: ulab.ndarray) -> ulab.ndarray:
//| """Return the cross product of two vectors of length 3"""
//| ...
//|
Expand Down Expand Up @@ -705,7 +705,7 @@ MP_DEFINE_CONST_FUN_OBJ_2(numerical_cross_obj, numerical_cross);
#endif /* ULAB_NUMERICAL_HAS_CROSS */

#if ULAB_NUMPY_HAS_DIFF
//| def diff(array: ulab.array, *, n: int = 1, axis: int = -1) -> ulab.array:
//| def diff(array: ulab.ndarray, *, n: int = 1, axis: int = -1) -> ulab.ndarray:
//| """Return the numerical derivative of successive elements of the array, as
//| an array. axis=None is not supported."""
//| ...
Expand Down Expand Up @@ -786,7 +786,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_diff_obj, 1, numerical_diff);
#endif

#if ULAB_NUMPY_HAS_FLIP
//| def flip(array: ulab.array, *, axis: Optional[int] = None) -> ulab.array:
//| def flip(array: ulab.ndarray, *, axis: Optional[int] = None) -> ulab.ndarray:
//| """Returns a new array that reverses the order of the elements along the
//| given axis, or along all axes if axis is None."""
//| ...
Expand Down Expand Up @@ -860,7 +860,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_mean_obj, 1, numerical_mean);
#endif

#if ULAB_NUMPY_HAS_MEDIAN
//| def median(array: ulab.array, *, axis: int = -1) -> ulab.array:
//| def median(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray:
//| """Find the median value in an array along the given axis, or along all axes if axis is None."""
//| ...
//|
Expand Down Expand Up @@ -968,7 +968,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_min_obj, 1, numerical_min);
#endif

#if ULAB_NUMPY_HAS_ROLL
//| def roll(array: ulab.array, distance: int, *, axis: Optional[int] = None) -> None:
//| def roll(array: ulab.ndarray, distance: int, *, axis: Optional[int] = None) -> None:
//| """Shift the content of a vector by the positions given as the second
//| argument. If the ``axis`` keyword is supplied, the shift is applied to
//| the given axis. The array is modified in place."""
Expand Down Expand Up @@ -1133,7 +1133,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_roll_obj, 2, numerical_roll);
#endif

#if ULAB_NUMPY_HAS_SORT
//| def sort(array: ulab.array, *, axis: int = -1) -> ulab.array:
//| def sort(array: ulab.ndarray, *, axis: int = -1) -> ulab.ndarray:
//| """Sort the array along the given axis, or along all axes if axis is None.
//| The array is modified in place."""
//| ...
Expand Down Expand Up @@ -1209,7 +1209,7 @@ MP_DEFINE_CONST_FUN_OBJ_KW(numerical_std_obj, 1, numerical_std);
#endif

#if ULAB_NUMPY_HAS_SUM
//| def sum(array: _ArrayLike, *, axis: Optional[int] = None) -> Union[float, int, ulab.array]:
//| def sum(array: _ArrayLike, *, axis: Optional[int] = None) -> Union[float, int, ulab.ndarray]:
//| """Return the sum of the array, as a number if axis is None, otherwise as an array."""
//| ...
//|
Expand Down
Loading