* add numpy.take
This commit is contained in:
Zoltán Vörös 2024-10-09 21:10:25 +02:00 committed by GitHub
parent c0b3262be4
commit 2b74236c8c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 544 additions and 19 deletions

View file

@ -6,7 +6,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2020 Jeff Epler for Adafruit Industries
* 2019-2021 Zoltán Vörös
* 2019-2024 Zoltán Vörös
* 2020 Taku Fukada
*/
@ -776,6 +776,235 @@ mp_obj_t create_ones(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
MP_DEFINE_CONST_FUN_OBJ_KW(create_ones_obj, 0, create_ones);
#endif
#if ULAB_NUMPY_HAS_TAKE
//| def take(
//| a: ulab.numpy.ndarray,
//| indices: _ArrayLike,
//| axis: Optional[int] = None,
//| out: Optional[ulab.numpy.ndarray] = None,
//| mode: Optional[str] = None) -> ulab.numpy.ndarray:
//| """
//| .. param: a
//| The source array.
//| .. param: indices
//| The indices of the values to extract.
//| .. param: axis
//| The axis over which to select values. By default, the flattened input array is used.
//| .. param: out
//| If provided, the result will be placed in this array. It should be of the appropriate shape and dtype.
//| .. param: mode
//| Specifies how out-of-bounds indices will behave.
//| - `raise`: raise an error (default)
//| - `wrap`: wrap around
//| - `clip`: clip to the range
//| `clip` mode means that all indices that are too large are replaced by the
//| index that addresses the last element along that axis. Note that this disables
//| indexing with negative numbers.
//|
//| Return a new array."""
//| ...
//|
enum CREATE_TAKE_MODE {
CREATE_TAKE_RAISE,
CREATE_TAKE_WRAP,
CREATE_TAKE_CLIP,
};
mp_obj_t create_take(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_axis, 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_mode, 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("input is not an array"));
}
ndarray_obj_t *a = MP_OBJ_TO_PTR(args[0].u_obj);
int8_t axis = 0;
int8_t axis_index = 0;
int32_t axis_len;
uint8_t mode = CREATE_TAKE_RAISE;
uint8_t ndim;
// axis keyword argument
if(args[2].u_obj == mp_const_none) {
// work with the flattened array
axis_len = a->len;
ndim = 1;
} else { // i.e., axis is an integer
// TODO: this pops up at quite a few places, write it as a function
axis = mp_obj_get_int(args[2].u_obj);
ndim = a->ndim;
if(axis < 0) axis += a->ndim;
if((axis < 0) || (axis > a->ndim - 1)) {
mp_raise_ValueError(MP_ERROR_TEXT("index out of range"));
}
axis_index = ULAB_MAX_DIMS - a->ndim + axis;
axis_len = (int32_t)a->shape[axis_index];
}
size_t _len;
// mode keyword argument
if(mp_obj_is_str(args[4].u_obj)) {
const char *_mode = mp_obj_str_get_data(args[4].u_obj, &_len);
if(memcmp(_mode, "raise", 5) == 0) {
mode = CREATE_TAKE_RAISE;
} else if(memcmp(_mode, "wrap", 4) == 0) {
mode = CREATE_TAKE_WRAP;
} else if(memcmp(_mode, "clip", 4) == 0) {
mode = CREATE_TAKE_CLIP;
} else {
mp_raise_ValueError(MP_ERROR_TEXT("mode should be raise, wrap or clip"));
}
}
size_t indices_len = (size_t)mp_obj_get_int(mp_obj_len_maybe(args[1].u_obj));
size_t *indices = m_new(size_t, indices_len);
mp_obj_iter_buf_t buf;
mp_obj_t item, iterable = mp_getiter(args[1].u_obj, &buf);
size_t z = 0;
while((item = mp_iternext(iterable)) != MP_OBJ_STOP_ITERATION) {
int32_t index = mp_obj_get_int(item);
if(mode == CREATE_TAKE_RAISE) {
if(index < 0) {
index += axis_len;
}
if((index < 0) || (index > axis_len - 1)) {
m_del(size_t, indices, indices_len);
mp_raise_ValueError(MP_ERROR_TEXT("index out of range"));
}
} else if(mode == CREATE_TAKE_WRAP) {
index %= axis_len;
} else { // mode == CREATE_TAKE_CLIP
if(index < 0) {
m_del(size_t, indices, indices_len);
mp_raise_ValueError(MP_ERROR_TEXT("index must not be negative"));
}
if(index > axis_len - 1) {
index = axis_len - 1;
}
}
indices[z++] = (size_t)index;
}
size_t *shape = m_new0(size_t, ULAB_MAX_DIMS);
if(args[2].u_obj == mp_const_none) { // flattened array
shape[ULAB_MAX_DIMS - 1] = indices_len;
} else {
for(uint8_t i = 0; i < ULAB_MAX_DIMS; i++) {
shape[i] = a->shape[i];
if(i == axis_index) {
shape[i] = indices_len;
}
}
}
ndarray_obj_t *out = NULL;
if(args[3].u_obj == mp_const_none) {
// no output was supplied
out = ndarray_new_dense_ndarray(ndim, shape, a->dtype);
} else {
// TODO: deal with last argument being false!
out = ulab_tools_inspect_out(args[3].u_obj, a->dtype, ndim, shape, true);
}
#if ULAB_MAX_DIMS > 1 // we can save the hassle, if there is only one possible dimension
if((args[2].u_obj == mp_const_none) || (a->ndim == 1)) { // flattened array
#endif
uint8_t *out_array = (uint8_t *)out->array;
for(size_t x = 0; x < indices_len; x++) {
uint8_t *a_array = (uint8_t *)a->array;
size_t remainder = indices[x];
uint8_t q = ULAB_MAX_DIMS - 1;
do {
size_t div = (remainder / a->shape[q]);
a_array += remainder * a->strides[q];
remainder -= div * a->shape[q];
q--;
} while(q > ULAB_MAX_DIMS - a->ndim);
// NOTE: for floats and complexes, this might be
// better with memcpy(out_array, a_array, a->itemsize)
for(uint8_t p = 0; p < a->itemsize; p++) {
out_array[p] = a_array[p];
}
out_array += a->itemsize;
}
#if ULAB_MAX_DIMS > 1
} else {
// move the axis shape/stride to the leftmost position:
SWAP(size_t, a->shape[0], a->shape[axis_index]);
SWAP(size_t, out->shape[0], out->shape[axis_index]);
SWAP(int32_t, a->strides[0], a->strides[axis_index]);
SWAP(int32_t, out->strides[0], out->strides[axis_index]);
for(size_t x = 0; x < indices_len; x++) {
uint8_t *a_array = (uint8_t *)a->array;
uint8_t *out_array = (uint8_t *)out->array;
a_array += indices[x] * a->strides[0];
out_array += x * out->strides[0];
#if ULAB_MAX_DIMS > 3
size_t j = 0;
do {
#endif
#if ULAB_MAX_DIMS > 2
size_t k = 0;
do {
#endif
size_t l = 0;
do {
// NOTE: for floats and complexes, this might be
// better with memcpy(out_array, a_array, a->itemsize)
for(uint8_t p = 0; p < a->itemsize; p++) {
out_array[p] = a_array[p];
}
out_array += out->strides[ULAB_MAX_DIMS - 1];
a_array += a->strides[ULAB_MAX_DIMS - 1];
l++;
} while(l < a->shape[ULAB_MAX_DIMS - 1]);
#if ULAB_MAX_DIMS > 2
out_array -= out->strides[ULAB_MAX_DIMS - 1] * out->shape[ULAB_MAX_DIMS - 1];
out_array += out->strides[ULAB_MAX_DIMS - 2];
a_array -= a->strides[ULAB_MAX_DIMS - 1] * a->shape[ULAB_MAX_DIMS - 1];
a_array += a->strides[ULAB_MAX_DIMS - 2];
k++;
} while(k < a->shape[ULAB_MAX_DIMS - 2]);
#endif
#if ULAB_MAX_DIMS > 3
out_array -= out->strides[ULAB_MAX_DIMS - 2] * out->shape[ULAB_MAX_DIMS - 2];
out_array += out->strides[ULAB_MAX_DIMS - 3];
a_array -= a->strides[ULAB_MAX_DIMS - 2] * a->shape[ULAB_MAX_DIMS - 2];
a_array += a->strides[ULAB_MAX_DIMS - 3];
j++;
} while(j < a->shape[ULAB_MAX_DIMS - 3]);
#endif
}
// revert back to the original order
SWAP(size_t, a->shape[0], a->shape[axis_index]);
SWAP(size_t, out->shape[0], out->shape[axis_index]);
SWAP(int32_t, a->strides[0], a->strides[axis_index]);
SWAP(int32_t, out->strides[0], out->strides[axis_index]);
}
#endif /* ULAB_MAX_DIMS > 1 */
m_del(size_t, indices, indices_len);
return MP_OBJ_FROM_PTR(out);
}
MP_DEFINE_CONST_FUN_OBJ_KW(create_take_obj, 2, create_take);
#endif /* ULAB_NUMPY_HAS_TAKE */
#if ULAB_NUMPY_HAS_ZEROS
//| def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: _DType = ulab.numpy.float) -> ulab.numpy.ndarray:
//| """

View file

@ -62,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);

View file

@ -291,6 +291,9 @@ static const mp_rom_map_elem_t ulab_numpy_globals_table[] = {
#if ULAB_NUMPY_HAS_SUM
{ 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_ROM_QSTR(MP_QSTR_polyfit), MP_ROM_PTR(&poly_polyfit_obj) },

View file

@ -33,7 +33,7 @@
#include "user/user.h"
#include "utils/utils.h"
#define ULAB_VERSION 6.5.5
#define ULAB_VERSION 6.6.0
#define xstr(s) str(s)
#define str(s) #s

View file

@ -559,6 +559,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

View file

@ -274,3 +274,31 @@ bool ulab_tools_mp_obj_is_scalar(mp_obj_t obj) {
}
#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;
}

View file

@ -44,7 +44,6 @@ void ulab_rescale_float_strides(int32_t *);
bool ulab_tools_mp_obj_is_scalar(mp_obj_t );
#if ULAB_NUMPY_HAS_RANDOM_MODULE
ndarray_obj_t *ulab_tools_create_out(mp_obj_tuple_t , mp_obj_t , uint8_t , bool );
#endif
ndarray_obj_t *ulab_tools_inspect_out(mp_obj_t , uint8_t , uint8_t , size_t *, bool );
#endif

View file

@ -27,8 +27,7 @@ copyright = '2019-2024, Zoltán Vörös and contributors'
author = 'Zoltán Vörös'
# The full version, including alpha/beta/rc tags
release = '6.5.5'
release = '6.6.0'
# -- General configuration ---------------------------------------------------

View file

@ -3,8 +3,8 @@ Numpy functions
===============
This section of the manual discusses those functions that were adapted
from ``numpy``. Starred functions accept complex arrays as arguments, if
the firmware was compiled with complex support.
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>`__
@ -51,9 +51,10 @@ the firmware was compiled with complex support.
43. `numpy.sort_complex\* <#sort_complex>`__
44. `numpy.std <#std>`__
45. `numpy.sum <#sum>`__
46. `numpy.trace <#trace>`__
47. `numpy.trapz <#trapz>`__
48. `numpy.where <#where>`__
46. `numpy.take\* <#take>`__
47. `numpy.trace <#trace>`__
48. `numpy.trapz <#trapz>`__
49. `numpy.where <#where>`__
all
---
@ -1985,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
-----

View file

@ -31,7 +31,7 @@
},
{
"cell_type": "code",
"execution_count": 3,
"execution_count": 1,
"metadata": {
"ExecuteTime": {
"end_time": "2022-02-01T17:37:25.505687Z",
@ -49,7 +49,7 @@
},
{
"cell_type": "code",
"execution_count": 4,
"execution_count": 2,
"metadata": {
"ExecuteTime": {
"end_time": "2022-02-01T17:37:25.717714Z",
@ -230,7 +230,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"This section of the manual discusses those functions that were adapted from `numpy`. Starred functions accept complex arrays as arguments, if the firmware was compiled with complex support.\n",
"This section of the manual discusses those functions that were adapted from `numpy`. Functions with an asterisk accept complex arrays as arguments, if the firmware was compiled with complex support.\n",
"\n",
"1. [numpy.all*](#all)\n",
"1. [numpy.any*](#any)\n",
@ -277,6 +277,7 @@
"1. [numpy.sort_complex*](#sort_complex)\n",
"1. [numpy.std](#std)\n",
"1. [numpy.sum](#sum)\n",
"1. [numpy.take*](#take)\n",
"1. [numpy.trace](#trace)\n",
"1. [numpy.trapz](#trapz)\n",
"1. [numpy.where](#where)"
@ -2682,6 +2683,63 @@
"print('std, vertical: ', np.sum(a, axis=0))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## take\n",
"\n",
"`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.take.html\n",
"\n",
"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.\n",
"\n",
"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."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"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",
"slices taken along first axis\n",
"array([[0.0, 1.0, 2.0, 3.0],\n",
" [8.0, 9.0, 10.0, 11.0],\n",
" [8.0, 9.0, 10.0, 11.0],\n",
" [4.0, 5.0, 6.0, 7.0]], dtype=float64)\n",
"\n",
"slices taken along second axis\n",
"array([[0.0, 2.0, 2.0, 1.0],\n",
" [2.0, 3.0, 4.0, 5.0],\n",
" [6.0, 7.0, 8.0, 9.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",
"print('\\na:', a)\n",
"\n",
"print('\\nslices taken along first axis')\n",
"print(np.take(a, (0, 2, 2, 1), axis=0))\n",
"\n",
"print('\\nslices taken along second axis')\n",
"print(np.take(a, (0, 2, 2, 1), axis=1))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -2900,7 +2958,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.13"
"version": "3.11.7"
},
"toc": {
"base_numbering": 1,

View file

@ -1,3 +1,9 @@
Wed, 9 Oct 2024
version 6.6.0
add numpy.take
Sat, 14 Sep 2024
version 6.5.5

View file

@ -61,7 +61,7 @@
"author = 'Zoltán Vörös'\n",
"\n",
"# The full version, including alpha/beta/rc tags\n",
"release = '6.5.5'\n",
"release = '6.6.0'\n",
"\n",
"\n",
"# -- General configuration ---------------------------------------------------\n",
@ -294,8 +294,6 @@
"/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"
]
}

30
tests/2d/numpy/take.py Normal file
View file

@ -0,0 +1,30 @@
try:
from ulab import numpy as np
except:
import numpy as np
dtypes = (np.uint8, np.int8, np.uint16, np.int16, np.float)
print('flattened array')
for dtype in dtypes:
a = np.array(range(12), dtype=dtype).reshape((3, 4))
print(np.take(a, (0, 10)))
print('\n1D arrays')
for dtype in dtypes:
a = np.array(range(12), dtype=dtype)
print('\na:', a)
indices = (0, 2, 2, 1)
print(np.take(a, indices))
indices = np.array([0, 2, 2, 1], dtype=np.uint8)
print(np.take(a, indices))
print('\n2D arrays')
for dtype in dtypes:
a = np.array(range(12), dtype=dtype).reshape((3, 4))
print('\na:', a)
print('\nfirst axis')
print(np.take(a, (0, 2, 2, 1), axis=0))
print('\nsecond axis')
print(np.take(a, (0, 2, 2, 1), axis=1))

105
tests/2d/numpy/take.py.exp Normal file
View file

@ -0,0 +1,105 @@
flattened array
array([0, 10], dtype=uint8)
array([0, 10], dtype=int8)
array([0, 10], dtype=uint16)
array([0, 10], dtype=int16)
array([0.0, 10.0], dtype=float64)
1D arrays
a: array([0, 1, 2, ..., 9, 10, 11], dtype=uint8)
array([0, 2, 2, 1], dtype=uint8)
array([0, 2, 2, 1], dtype=uint8)
a: array([0, 1, 2, ..., 9, 10, 11], dtype=int8)
array([0, 2, 2, 1], dtype=int8)
array([0, 2, 2, 1], dtype=int8)
a: array([0, 1, 2, ..., 9, 10, 11], dtype=uint16)
array([0, 2, 2, 1], dtype=uint16)
array([0, 2, 2, 1], dtype=uint16)
a: array([0, 1, 2, ..., 9, 10, 11], dtype=int16)
array([0, 2, 2, 1], dtype=int16)
array([0, 2, 2, 1], dtype=int16)
a: array([0.0, 1.0, 2.0, ..., 9.0, 10.0, 11.0], dtype=float64)
array([0.0, 2.0, 2.0, 1.0], dtype=float64)
array([0.0, 2.0, 2.0, 1.0], dtype=float64)
2D arrays
a: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]], dtype=uint8)
first axis
array([[0, 1, 2, 3],
[8, 9, 10, 11],
[8, 9, 10, 11],
[4, 5, 6, 7]], dtype=uint8)
second axis
array([[0, 2, 2, 1],
[4, 6, 6, 5],
[8, 10, 10, 9]], dtype=uint8)
a: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]], dtype=int8)
first axis
array([[0, 1, 2, 3],
[8, 9, 10, 11],
[8, 9, 10, 11],
[4, 5, 6, 7]], dtype=int8)
second axis
array([[0, 2, 2, 1],
[4, 6, 6, 5],
[8, 10, 10, 9]], dtype=int8)
a: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]], dtype=uint16)
first axis
array([[0, 1, 2, 3],
[8, 9, 10, 11],
[8, 9, 10, 11],
[4, 5, 6, 7]], dtype=uint16)
second axis
array([[0, 2, 2, 1],
[4, 6, 6, 5],
[8, 10, 10, 9]], dtype=uint16)
a: array([[0, 1, 2, 3],
[4, 5, 6, 7],
[8, 9, 10, 11]], dtype=int16)
first axis
array([[0, 1, 2, 3],
[8, 9, 10, 11],
[8, 9, 10, 11],
[4, 5, 6, 7]], dtype=int16)
second axis
array([[0, 2, 2, 1],
[4, 6, 6, 5],
[8, 10, 10, 9]], dtype=int16)
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)
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)
second axis
array([[0.0, 2.0, 2.0, 1.0],
[4.0, 6.0, 6.0, 5.0],
[8.0, 10.0, 10.0, 9.0]], dtype=float64)