diff --git a/code/ndarray.c b/code/ndarray.c index b297b3f1..361d664d 100644 --- a/code/ndarray.c +++ b/code/ndarray.c @@ -1874,28 +1874,110 @@ mp_obj_t ndarray_unary_op(mp_unary_op_t op, mp_obj_t self_in) { #endif /* NDARRAY_HAS_UNARY_OPS */ #if NDARRAY_HAS_TRANSPOSE -mp_obj_t ndarray_transpose(mp_obj_t self_in) { - #if ULAB_MAX_DIMS == 1 - return self_in; - #endif - // TODO: check, what happens to the offset here, if we have a view +// We have to implement the T property separately, for the property can't take keyword arguments + +#if ULAB_MAX_DIMS == 1 +// isolating the one-dimensional case saves space, because the transpose is sort of meaningless +mp_obj_t ndarray_T(mp_obj_t self_in) { + return self_in; +} +#else +mp_obj_t ndarray_T(mp_obj_t self_in) { + // without argument, simply return a view with axes in reverse order ndarray_obj_t *self = MP_OBJ_TO_PTR(self_in); if(self->ndim == 1) { return self_in; } size_t *shape = m_new(size_t, self->ndim); int32_t *strides = m_new(int32_t, self->ndim); - for(uint8_t i=0; i < self->ndim; i++) { + for(uint8_t i = 0; i < self->ndim; i++) { shape[ULAB_MAX_DIMS - 1 - i] = self->shape[ULAB_MAX_DIMS - self->ndim + i]; strides[ULAB_MAX_DIMS - 1 - i] = self->strides[ULAB_MAX_DIMS - self->ndim + i]; } - // TODO: I am not sure ndarray_new_view is OK here... - // should be deep copy... ndarray_obj_t *ndarray = ndarray_new_view(self, self->ndim, shape, strides, 0); return MP_OBJ_FROM_PTR(ndarray); } +#endif /* ULAB_MAX_DIMS == 1 */ + +MP_DEFINE_CONST_FUN_OBJ_1(ndarray_T_obj, ndarray_T); + +# if ULAB_MAX_DIMS == 1 +// again, nothing to do, if there is only one dimension, though, the arguments might still have to be parsed... +mp_obj_t ndarray_transpose(mp_obj_t self_in) { + return self_in; +} MP_DEFINE_CONST_FUN_OBJ_1(ndarray_transpose_obj, ndarray_transpose); +#else +mp_obj_t ndarray_transpose(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_ROM_NONE } }, + { MP_QSTR_axes, 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); + + ndarray_obj_t *self = MP_OBJ_TO_PTR(args[0].u_obj); + + if(self->ndim == 1) { + return args[0].u_obj; + } + + size_t *shape = m_new(size_t, self->ndim); + int32_t *strides = m_new(int32_t, self->ndim); + uint8_t *order = m_new(uint8_t, self->ndim); + + mp_obj_t axes = args[1].u_obj; + + if(axes == mp_const_none) { + // simply swap the order of the axes + for(uint8_t i = 0; i < self->ndim; i++) { + order[i] = self->ndim - 1 - i; + } + } else { + if(!mp_obj_is_type(axes, &mp_type_tuple)) { + mp_raise_TypeError(MP_ERROR_TEXT("keyword argument must be tuple of integers")); + } + // start with the straight array, and then swap only those specified in the argument + for(uint8_t i = 0; i < self->ndim; i++) { + order[i] = i; + } + + mp_obj_tuple_t *axes_tuple = MP_OBJ_TO_PTR(axes); + + if(axes_tuple->len > self->ndim) { + mp_raise_ValueError(MP_ERROR_TEXT("too many axes specified")); + } + + for(uint8_t i = 0; i < axes_tuple->len; i++) { + int32_t ax = mp_obj_get_int(axes_tuple->items[i]); + if((ax >= self->ndim) || (ax < 0)) { + mp_raise_ValueError(MP_ERROR_TEXT("axis index out of bounds")); + } else { + order[i] = (uint8_t)ax; + // TODO: check that no two identical numbers appear in the tuple + for(uint8_t j = 0; j < i; j++) { + if(order[i] == order[j]) { + mp_raise_ValueError(MP_ERROR_TEXT("repeated indices")); + } + } + } + } + } + + uint8_t axis_offset = ULAB_MAX_DIMS - self->ndim; + for(uint8_t i = 0; i < self->ndim; i++) { + shape[axis_offset + i] = self->shape[axis_offset + order[i]]; + strides[axis_offset + i] = self->strides[axis_offset + order[i]]; + } + + ndarray_obj_t *ndarray = ndarray_new_view(self, self->ndim, shape, strides, 0); + return MP_OBJ_FROM_PTR(ndarray); +} + +MP_DEFINE_CONST_FUN_OBJ_KW(ndarray_transpose_obj, 1, ndarray_transpose); +#endif /* ULAB_MAX_DIMS == 1 */ #endif /* NDARRAY_HAS_TRANSPOSE */ #if ULAB_MAX_DIMS > 1 diff --git a/code/ndarray.h b/code/ndarray.h index 8e81773d..af72b1ad 100644 --- a/code/ndarray.h +++ b/code/ndarray.h @@ -265,9 +265,16 @@ MP_DECLARE_CONST_FUN_OBJ_1(ndarray_tolist_obj); #endif #if NDARRAY_HAS_TRANSPOSE +mp_obj_t ndarray_T(mp_obj_t ); +MP_DECLARE_CONST_FUN_OBJ_1(ndarray_T_obj); +#if ULAB_MAX_DIMS == 1 mp_obj_t ndarray_transpose(mp_obj_t ); MP_DECLARE_CONST_FUN_OBJ_1(ndarray_transpose_obj); -#endif +#else +mp_obj_t ndarray_transpose(size_t , const mp_obj_t *, mp_map_t *); +MP_DECLARE_CONST_FUN_OBJ_KW(ndarray_transpose_obj); +#endif /* ULAB_MAX_DIMS == 1 */ +#endif /* NDARRAY_HAS_TRANSPOSE */ #if ULAB_NUMPY_HAS_NDINFO mp_obj_t ndarray_info(mp_obj_t ); diff --git a/code/ndarray_properties.c b/code/ndarray_properties.c index 6c048bda..8200445a 100644 --- a/code/ndarray_properties.c +++ b/code/ndarray_properties.c @@ -64,7 +64,7 @@ void ndarray_properties_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { #endif #if NDARRAY_HAS_TRANSPOSE case MP_QSTR_T: - dest[0] = ndarray_transpose(self_in); + dest[0] = ndarray_T(self_in); break; #endif #if ULAB_SUPPORTS_COMPLEX diff --git a/code/ulab.c b/code/ulab.c index 8a0b50ca..205ddac5 100644 --- a/code/ulab.c +++ b/code/ulab.c @@ -33,7 +33,7 @@ #include "user/user.h" #include "utils/utils.h" -#define ULAB_VERSION 6.10.0 +#define ULAB_VERSION 6.11.0 #define xstr(s) str(s) #define str(s) #s diff --git a/docs/manual/source/conf.py b/docs/manual/source/conf.py index c10faeb2..3feeef88 100644 --- a/docs/manual/source/conf.py +++ b/docs/manual/source/conf.py @@ -27,7 +27,7 @@ author = 'Zoltán Vörös' # The full version, including alpha/beta/rc tags -release = '6.9.0' +release = '6.11.0' # -- General configuration --------------------------------------------------- diff --git a/docs/manual/source/ulab-ndarray.rst b/docs/manual/source/ulab-ndarray.rst index 46288a26..dde9eab0 100644 --- a/docs/manual/source/ulab-ndarray.rst +++ b/docs/manual/source/ulab-ndarray.rst @@ -1564,6 +1564,9 @@ dimensions is larger than 1. +The method also accepts the ``axes`` keyword argument, if permutation of +the returned axes is required. + The transpose of the array can also be gotten through the ``T`` property: diff --git a/docs/ulab-convert.ipynb b/docs/ulab-convert.ipynb index 53f28bcb..1cf66f52 100644 --- a/docs/ulab-convert.ipynb +++ b/docs/ulab-convert.ipynb @@ -14,7 +14,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2022-02-09T06:27:15.118699Z", @@ -61,7 +61,7 @@ "author = 'Zoltán Vörös'\n", "\n", "# The full version, including alpha/beta/rc tags\n", - "release = '6.9.0'\n", + "release = '6.11.0'\n", "\n", "\n", "# -- General configuration ---------------------------------------------------\n", @@ -217,7 +217,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2022-02-09T06:27:21.647179Z", @@ -258,7 +258,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": { "ExecuteTime": { "end_time": "2022-02-09T06:27:42.024028Z", @@ -270,34 +270,6 @@ "name": "stderr", "output_type": "stream", "text": [ - "/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", - "/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", - "/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", - "/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", - "/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" ] diff --git a/docs/ulab-ndarray.ipynb b/docs/ulab-ndarray.ipynb index c7518c26..eca54340 100644 --- a/docs/ulab-ndarray.ipynb +++ b/docs/ulab-ndarray.ipynb @@ -2237,6 +2237,13 @@ "print('shape of a:', a.shape)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The method also accepts the `axes` keyword argument, if permutation of the returned axes is required." + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -3731,11 +3738,8 @@ } ], "metadata": { - "interpreter": { - "hash": "ce9a02f9f7db620716422019cafa4bc1786ca85daa298b819f6da075e7993842" - }, "kernelspec": { - "display_name": "Python 3", + "display_name": "base", "language": "python", "name": "python3" }, @@ -3749,7 +3753,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.11.7" }, "toc": { "base_numbering": 1, diff --git a/tests/1d/numpy/universal_functions.py b/tests/1d/numpy/universal_functions.py index c41cf948..a72d73d1 100644 --- a/tests/1d/numpy/universal_functions.py +++ b/tests/1d/numpy/universal_functions.py @@ -7,142 +7,94 @@ import numpy as np import scipy as spy -result = (np.sin(np.pi/2)) -ref_result = 1.0 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +def test_function(func, reference, expression): + result = expression + print(f'testing {func}') + print(math.isclose(result, reference, rel_tol=1E-6, abs_tol=1E-6)) + print() -result = (np.cos(np.pi/2)) -ref_result = 0.0 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +def test_function_array(func, reference, expression): + print(f'testing {func}') + results = [] + for i in range(len(references)): + results.append(math.isclose(references[i], expression[i], rel_tol=1E-6, abs_tol=1E-6)) + print(results) + print() -result = (np.tan(np.pi/2)) -ref_result = 1.633123935319537e+16 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) -result = (np.sinh(np.pi/2)) -ref_result = 2.3012989023072947 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('sin', 1.0, np.sin(np.pi/2)) -result = (np.cosh(np.pi/2)) -ref_result = 2.5091784786580567 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('cos', 0.0, (np.cos(np.pi/2))) -result = (np.tanh(np.pi/2)) -ref_result = 0.9171523356672744 -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('tan', 1.633123935319537e+16, np.tan(np.pi/2)) -ref_result = np.pi/2 -result = (np.asin(np.sin(np.pi/2))) -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('sinh', 2.3012989023072947, np.sinh(np.pi/2)) -result = (np.acos(np.cos(np.pi/2))) -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('cosh:', 2.5091784786580567, np.cosh(np.pi/2)) -result = (np.atan(np.tan(np.pi/2))) -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('tanh', 0.9171523356672744, np.tanh(np.pi/2)) -result = (np.cosh(np.acosh(np.pi/2))) -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) +test_function('asin', np.pi/2, np.asin(np.sin(np.pi/2))) -result = (np.sinh(np.asinh(np.pi/2))) -print(math.isclose(result, ref_result, rel_tol=1E-6, abs_tol=1E-6)) - -print(np.degrees(np.pi)) -print(np.radians(np.degrees(np.pi))) -print(np.floor(np.pi)) -print(np.ceil(np.pi)) -print(np.sqrt(np.pi)) -print(np.exp(1)) -print(np.log(np.exp(1))) - -print(np.log2(2**1)) - -print(np.log10(10**1)) -print(math.isclose(np.exp(1) - np.expm1(1), 1)) - -x = np.array([-1, +1, +1, -1]) -y = np.array([-1, -1, +1, +1]) -result = (np.arctan2(y, x) * 180 / np.pi) -ref_result = np.array([-135.0, -45.0, 45.0, 135.0], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) +test_function('acos', np.pi/2, np.acos(np.cos(np.pi/2))) + +test_function('atan', np.pi/2, np.atan(np.tan(np.pi/2))) + +test_function('acosh', np.pi/2, np.cosh(np.acosh(np.pi/2))) + +test_function('asinh', np.pi/2, np.sinh(np.asinh(np.pi/2))) + +test_function('degrees', 180.0, np.degrees(np.pi)) + +test_function('radians', np.pi, np.radians(180.0)) + +test_function('floor', 3.0, np.floor(np.pi)) + +test_function('ceil', 4.0, np.ceil(np.pi)) + +test_function('sqrt', 1.7724538509055159, np.sqrt(np.pi)) + +test_function('exp', 2.718281828459045, np.exp(1)) + +test_function('log', 1.0, np.log(2.718281828459045)) + +test_function('log2', 1.0, np.log2(2)) + +test_function('log10', 1.0, np.log10(10.0)) + +test_function('expm1', 1.0, np.exp(1) - np.expm1(1)) + +x = [-1, +1, +1, -1] +y = [-1, -1, +1, +1] +reference = [-135.0, -45.0, 45.0, 135.0] +for i in range(4): + test_function('arctan2', reference[i], np.arctan2(y[i], x[i]) * 180 / np.pi) x = np.linspace(-2*np.pi, 2*np.pi, 5) -result = np.sin(x) -ref_result = np.array([2.4492936e-16, -1.2246468e-16, 0.0000000e+00, 1.2246468e-16, -2.4492936e-16], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.cos(x) -ref_result = np.array([1., -1., 1., -1., 1.], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.tan(x) -ref_result = np.array([2.4492936e-16, 1.2246468e-16, 0.0000000e+00, -1.2246468e-16, -2.4492936e-16], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.sinh(x) -ref_result = np.array([-267.74489404, -11.54873936, 0., 11.54873936, 267.74489404], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.cosh(x) -ref_result = np.array([267.74676148, 11.59195328, 1.0, 11.59195328, 267.74676148], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.tanh(x) -ref_result = np.array([-0.9999930253396107, -0.99627207622075, 0.0, 0.99627207622075, 0.9999930253396107], dtype=np.float) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = np.sinc(x) -ref_result = np.array([0.03935584386392389, -0.04359862862918773, 1.0, -0.04359862862918773, 0.03935584386392389]) -cmp_result = [] -for i in range(len(x)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = (spy.special.erf(np.linspace(-3, 3, num=5))) -ref_result = np.array([-0.9999779095030014, -0.9661051464753108, 0.0, 0.9661051464753108, 0.9999779095030014], dtype=np.float) -cmp_result = [] -for i in range(len(ref_result)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = (spy.special.erfc(np.linspace(-3, 3, num=5))) -ref_result = np.array([1.99997791e+00, 1.96610515e+00, 1.00000000e+00, 3.38948535e-02, 2.20904970e-05], dtype=np.float) -cmp_result = [] -for i in range(len(ref_result)): - cmp_result.append(math.isclose(result[i], ref_result[i], rel_tol=1E-6, abs_tol=1E-6)) -print(cmp_result) - -result = (spy.special.gamma(np.array([0, 0.5, 1, 5]))) -ref_result = np.array([1.77245385, 1.0, 24.0]) -cmp_result = [] -cmp_result.append(math.isinf(result[0])) -for i in range(len(ref_result)): - cmp_result.append(math.isclose(result[i+1], ref_result[i], rel_tol=1E-9, abs_tol=1E-9)) -print(cmp_result) - -result = (spy.special.gammaln([0, -1, -2, -3, -4])) -cmp_result = [] -for i in range(len(ref_result)): - cmp_result.append(math.isinf(result[i])) -print(cmp_result) + +references = [2.4492936e-16, -1.2246468e-16, 0.0000000e+00, 1.2246468e-16, -2.4492936e-16] +test_function_array('sin', references, np.sin(x)) + +references = [1., -1., 1., -1., 1.] +test_function_array('cos', references, np.cos(x)) + +references = [0.0, 0.0, 0.0, 0.0, 0.0] +test_function_array('tan', references, np.tan(x)) + +references = [-267.74489404, -11.54873936, 0., 11.54873936, 267.74489404] +test_function_array('sinh', references, np.sinh(x)) + +references = [267.74676148, 11.59195328, 1.0, 11.59195328, 267.74676148] +test_function_array('cosh', references, np.cosh(x)) + +references = [-0.9999930253396107, -0.99627207622075, 0.0, 0.99627207622075, 0.9999930253396107] +test_function_array('tanh', references, np.tanh(x)) + +references = [0.03935584386392389, -0.04359862862918773, 1.0, -0.04359862862918773, 0.03935584386392389] +test_function_array('sinc', references, np.sinc(x)) + +references = [-0.9999779095030014, -0.9661051464753108, 0.0, 0.9661051464753108, 0.9999779095030014] +test_function_array('erf', references, spy.special.erf(np.linspace(-3, 3, num=5))) + +references = [1.99997791e+00, 1.96610515e+00, 1.00000000e+00, 3.38948535e-02, 2.20904970e-05] +test_function_array('erfc', references, spy.special.erfc(np.linspace(-3, 3, num=5))) \ No newline at end of file diff --git a/tests/1d/numpy/universal_functions.py.exp b/tests/1d/numpy/universal_functions.py.exp index 919c94a4..e6efd3ea 100644 --- a/tests/1d/numpy/universal_functions.py.exp +++ b/tests/1d/numpy/universal_functions.py.exp @@ -1,33 +1,102 @@ +testing sin True + +testing cos True + +testing tan True + +testing sinh True + +testing cosh: True + +testing tanh True + +testing asin True + +testing acos True + +testing atan True + +testing acosh True + +testing asinh True -180.0 -3.141592653589793 -3.0 -4.0 -1.772453850905516 -2.718281828459045 -1.0 -1.0 -1.0 + +testing degrees True -[True, True, True, True] + +testing radians +True + +testing floor +True + +testing ceil +True + +testing sqrt +True + +testing exp +True + +testing log +True + +testing log2 +True + +testing log10 +True + +testing expm1 +True + +testing arctan2 +True + +testing arctan2 +True + +testing arctan2 +True + +testing arctan2 +True + +testing sin [True, True, True, True, True] + +testing cos [True, True, True, True, True] + +testing tan [True, True, True, True, True] + +testing sinh [True, True, True, True, True] + +testing cosh [True, True, True, True, True] + +testing tanh [True, True, True, True, True] + +testing sinc [True, True, True, True, True] + +testing erf [True, True, True, True, True] + +testing erfc [True, True, True, True, True] -[True, True, True, True] -[True, True, True] + diff --git a/tests/2d/numpy/cholesky.py b/tests/2d/numpy/cholesky.py index beab3c1d..368005c8 100644 --- a/tests/2d/numpy/cholesky.py +++ b/tests/2d/numpy/cholesky.py @@ -1,14 +1,27 @@ from ulab import numpy as np +import math + a = np.array([[1, 2], [2, 5]]) -print(np.linalg.cholesky(a)) +reference = np.array([[1.0, 0.0], [2.0, 1.0]]) +result = np.linalg.cholesky(a) +for i in range(2): + for j in range(2): + print(f'({i}, {j}): {math.isclose(result[i][j], reference[i][j], rel_tol=1E-6, abs_tol=1E-6)}') -b = a = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]]) -print(np.linalg.cholesky(b)) +b = np.array([[25, 15, -5], [15, 18, 0], [-5, 0, 11]]) +reference = np.array([[5.0, 0.0, 0.0], [3.0, 3.0, 0.0], [-1.0, 1.0, 3.0]]) +result = np.linalg.cholesky(b) +for i in range(3): + for j in range(3): + print(f'({i}, {j}): {math.isclose(result[i][j], reference[i][j], rel_tol=1E-6, abs_tol=1E-6)}') c = np.array([[18, 22, 54, 42], [22, 70, 86, 62], [54, 86, 174, 134], [42, 62, 134, 106]]) -print(np.linalg.cholesky(c)) - - - - +reference = np.array([[4.242640687119285, 0.0, 0.0, 0.0], + [5.185449728701349, 6.565905201197403, 0.0, 0.0], + [12.727922061357857, 3.0460384954008553, 1.6497422479090682, 0.0], + [9.899494936611665, 1.6245538642137891, 1.8497110052313865, 1.3926212476455826]]) +result = np.linalg.cholesky(c) +for i in range(4): + for j in range(4): + print(f'({i}, {j}): {math.isclose(result[i][j], reference[i][j], rel_tol=1E-6, abs_tol=1E-6)}') diff --git a/tests/2d/numpy/cholesky.py.exp b/tests/2d/numpy/cholesky.py.exp index a8e88ef6..aa2dc3e5 100644 --- a/tests/2d/numpy/cholesky.py.exp +++ b/tests/2d/numpy/cholesky.py.exp @@ -1,9 +1,29 @@ -array([[1.0, 0.0], - [2.0, 1.0]], dtype=float64) -array([[5.0, 0.0, 0.0], - [3.0, 3.0, 0.0], - [-1.0, 1.0, 3.0]], dtype=float64) -array([[4.242640687119285, 0.0, 0.0, 0.0], - [5.185449728701349, 6.565905201197403, 0.0, 0.0], - [12.72792206135786, 3.046038495400855, 1.649742247909068, 0.0], - [9.899494936611665, 1.624553864213789, 1.849711005231386, 1.392621247645583]], dtype=float64) +(0, 0): True +(0, 1): True +(1, 0): True +(1, 1): True +(0, 0): True +(0, 1): True +(0, 2): True +(1, 0): True +(1, 1): True +(1, 2): True +(2, 0): True +(2, 1): True +(2, 2): True +(0, 0): True +(0, 1): True +(0, 2): True +(0, 3): True +(1, 0): True +(1, 1): True +(1, 2): True +(1, 3): True +(2, 0): True +(2, 1): True +(2, 2): True +(2, 3): True +(3, 0): True +(3, 1): True +(3, 2): True +(3, 3): True diff --git a/tests/2d/numpy/logspace.py b/tests/2d/numpy/logspace.py index e6f2047b..7fb1ef26 100644 --- a/tests/2d/numpy/logspace.py +++ b/tests/2d/numpy/logspace.py @@ -3,8 +3,20 @@ except: import numpy as np -dtypes = (np.uint8, np.int8, np.uint16, np.int16, np.float) +import math + +dtypes = (np.uint8, np.int8, np.uint16, np.int16) for dtype in dtypes: print(np.logspace(0, 10, num=5, endpoint=False, dtype=dtype)) - print(np.logspace(0, 10, num=5, endpoint=True, dtype=dtype)) \ No newline at end of file + print(np.logspace(0, 10, num=5, endpoint=True, dtype=dtype)) + + +reference = [1.0, 100.0, 10000.0, 1000000.0, 100000000.0] +result = np.logspace(0, 10, num=5, endpoint=False, dtype=np.float) +print([math.isclose(result[i], reference[i], rel_tol=1E-6, abs_tol=1E-6) for i in range(len(reference))]) + + +reference = [1.0, 316.22776601683796, 100000.00000000001, 31622776.6016838, 10000000000.000002] +result = np.logspace(0, 10, num=5, endpoint=True, dtype=np.float) +print([math.isclose(result[i], reference[i], rel_tol=1E-6, abs_tol=1E-6) for i in range(len(reference))]) diff --git a/tests/2d/numpy/logspace.py.exp b/tests/2d/numpy/logspace.py.exp index 1a09cef4..5e91bbe8 100644 --- a/tests/2d/numpy/logspace.py.exp +++ b/tests/2d/numpy/logspace.py.exp @@ -6,5 +6,5 @@ array([1, 100, 10000, 16960, 57600], dtype=uint16) array([1, 316, 34464, 34424, 0], dtype=uint16) array([1, 100, 10000, 16960, -7936], dtype=int16) array([1, 316, -31072, -31112, 0], dtype=int16) -array([1.0, 100.0, 10000.0, 1000000.0, 100000000.0], dtype=float64) -array([1.0, 316.227766016838, 100000.0, 31622776.6016838, 10000000000.0], dtype=float64) +[True, True, True, True, True] +[True, True, True, True, True] diff --git a/tests/2d/numpy/transpose.py b/tests/2d/numpy/transpose.py new file mode 100644 index 00000000..9ffbfb31 --- /dev/null +++ b/tests/2d/numpy/transpose.py @@ -0,0 +1,58 @@ +try: + from ulab import numpy as np +except ImportError: + import numpy as np + +dtypes = (np.uint8, np.int8, np.uint16, np.int16, np.float) + +print("Basic 2D transpose") +a = np.array(range(6)).reshape((2, 3)) +print("Original array:") +print(a) +print("Transposed (no axes):") +print(a.transpose()) +print() + +print("2D transpose with axes=(1, 0)") +a = np.array(range(6)).reshape((2, 3)) +print("Original array:") +print(a) +print("Transposed with axes=(1, 0):") +print(a.transpose(axes=(1, 0))) +print() + +print("2D transpose with axes=(0, 1)") +a = np.array(range(6)).reshape((2, 3)) +print("Original array:") +print(a) +print("Transposed with axes=(0, 1):") +print(a.transpose(axes=(0, 1))) +print() + +print("1D array transpose") +a = np.array(range(5)) +print("Original array:") +print(a) +print("Transposed array:") +print(a.transpose()) +print() + +print("Transpose of different dtypes") +for dtype in dtypes: + a = np.array(range(4), dtype=dtype).reshape((2, 2)) + print('Original array:') + print(a) + print('Transposed array:') + print(a.transpose()) +print() + +print(".T property vs transpose() method") +a = np.array(range(6)).reshape((2, 3)) +print("Original array:") +print(a) +print("Using .T property:") +print(a.T) +print("Using .transpose():") +print(a.transpose()) +print("Both should be equal:", np.all(a.T == a.transpose())) +print() \ No newline at end of file diff --git a/tests/2d/numpy/transpose.py.exp b/tests/2d/numpy/transpose.py.exp new file mode 100644 index 00000000..87627cb2 --- /dev/null +++ b/tests/2d/numpy/transpose.py.exp @@ -0,0 +1,78 @@ +Basic 2D transpose +Original array: +array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0]], dtype=float64) +Transposed (no axes): +array([[0.0, 3.0], + [1.0, 4.0], + [2.0, 5.0]], dtype=float64) + +2D transpose with axes=(1, 0) +Original array: +array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0]], dtype=float64) +Transposed with axes=(1, 0): +array([[0.0, 3.0], + [1.0, 4.0], + [2.0, 5.0]], dtype=float64) + +2D transpose with axes=(0, 1) +Original array: +array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0]], dtype=float64) +Transposed with axes=(0, 1): +array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0]], dtype=float64) + +1D array transpose +Original array: +array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float64) +Transposed array: +array([0.0, 1.0, 2.0, 3.0, 4.0], dtype=float64) + +Transpose of different dtypes +Original array: +array([[0, 1], + [2, 3]], dtype=uint8) +Transposed array: +array([[0, 2], + [1, 3]], dtype=uint8) +Original array: +array([[0, 1], + [2, 3]], dtype=int8) +Transposed array: +array([[0, 2], + [1, 3]], dtype=int8) +Original array: +array([[0, 1], + [2, 3]], dtype=uint16) +Transposed array: +array([[0, 2], + [1, 3]], dtype=uint16) +Original array: +array([[0, 1], + [2, 3]], dtype=int16) +Transposed array: +array([[0, 2], + [1, 3]], dtype=int16) +Original array: +array([[0.0, 1.0], + [2.0, 3.0]], dtype=float64) +Transposed array: +array([[0.0, 2.0], + [1.0, 3.0]], dtype=float64) + +.T property vs transpose() method +Original array: +array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0]], dtype=float64) +Using .T property: +array([[0.0, 3.0], + [1.0, 4.0], + [2.0, 5.0]], dtype=float64) +Using .transpose(): +array([[0.0, 3.0], + [1.0, 4.0], + [2.0, 5.0]], dtype=float64) +Both should be equal: True + diff --git a/tests/2d/scipy/integrate.py b/tests/2d/scipy/integrate.py index 1d0edb7b..2c176c46 100644 --- a/tests/2d/scipy/integrate.py +++ b/tests/2d/scipy/integrate.py @@ -1,28 +1,30 @@ -import sys -from math import * - try: - from ulab import scipy + from ulab import scipy as spy + from ulab import numpy as np except ImportError: import scipy -f = lambda x: x * sin(x) * exp(x) -a=1 -b=2 +import math + +f = lambda x: x * np.sin(x) * np.exp(x) +a = 1 +b = 2 -(res, err) = scipy.integrate.tanhsinh(f, a, b) -if isclose (res, 7.11263821415851) and isclose (err, 5.438231077315757e-14): - print (res, err) - -res = scipy.integrate.romberg(f, a, b) -if isclose (res, 7.112638214158507): - print (res) +(res, err) = spy.integrate.tanhsinh(f, a, b) +print('testing tanhsinh') +print(math.isclose(res, 7.11263821415851, rel_tol=1E-6, abs_tol=1E-6)) +print() -res = scipy.integrate.simpson(f, a, b) -if isclose (res, 7.112638214158494): - print (res) +print('testing romberg') +res = spy.integrate.romberg(f, a, b) +print(math.isclose(res, 7.112638214158507, rel_tol=1E-6, abs_tol=1E-6)) +print() -(res, err) = scipy.integrate.quad(f, a, b) -if isclose (res, 7.112638214158507) and isclose (err, 7.686723611780195e-14): - print (res, err) +print('testing simpson') +res = spy.integrate.simpson(f, a, b) +print(math.isclose(res, 7.112638214158507, rel_tol=1E-6, abs_tol=1E-6)) +print() +print('testing quad') +(res, err) = spy.integrate.quad(f, a, b) +print(math.isclose(res, 7.112638214158507, rel_tol=1E-6, abs_tol=1E-6)) diff --git a/tests/2d/scipy/integrate.py.exp b/tests/2d/scipy/integrate.py.exp index 10426e6c..d8c790c7 100644 --- a/tests/2d/scipy/integrate.py.exp +++ b/tests/2d/scipy/integrate.py.exp @@ -1,4 +1,11 @@ -7.11263821415851 5.438231077315757e-14 -7.112638214158507 -7.112638214158494 -7.112638214158507 7.686723611780195e-14 +testing tanhsinh +True + +testing romberg +True + +testing simpson +True + +testing quad +True