diff --git a/code/numpy/vector.c b/code/numpy/vector.c index cd8fef3e..0df3a338 100644 --- a/code/numpy/vector.c +++ b/code/numpy/vector.c @@ -609,9 +609,6 @@ static mp_obj_t vector_exp(mp_obj_t o_in) { mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args); mp_obj_t o_in = args[0].u_obj; mp_obj_t out = args[1].u_obj; - if(out != mp_const_none) { - mp_raise_ValueError(MP_ERROR_TEXT("out keyword is not supported for complex dtype")); - } #endif /* ULAB_MATH_FUNCTIONS_OUT_KEYWORD */ if(mp_obj_is_type(o_in, &mp_type_complex)) { @@ -621,6 +618,13 @@ static mp_obj_t vector_exp(mp_obj_t o_in) { return mp_obj_new_complex(exp_real * MICROPY_FLOAT_C_FUN(cos)(imag), exp_real * MICROPY_FLOAT_C_FUN(sin)(imag)); } else if(mp_obj_is_type(o_in, &ulab_ndarray_type)) { ndarray_obj_t *source = MP_OBJ_TO_PTR(o_in); + + #if ULAB_MATH_FUNCTIONS_OUT_KEYWORD + if((out != mp_const_none) && (source->dtype == NDARRAY_COMPLEX)){ + mp_raise_ValueError(MP_ERROR_TEXT("out keyword is not supported for complex dtype")); + } + #endif /* ULAB_MATH_FUNCTIONS_OUT_KEYWORD */ + if(source->dtype == NDARRAY_COMPLEX) { uint8_t *sarray = (uint8_t *)source->array; ndarray_obj_t *ndarray = ndarray_new_dense_ndarray(source->ndim, source->shape, NDARRAY_COMPLEX); diff --git a/docs/manual/source/conf.py b/docs/manual/source/conf.py index 3f4d5eb4..4a2cea6e 100644 --- a/docs/manual/source/conf.py +++ b/docs/manual/source/conf.py @@ -23,11 +23,11 @@ # -- Project information ----------------------------------------------------- project = 'The ulab book' -copyright = '2019-2022, Zoltán Vörös and contributors' +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 = '5.1.0' +release = '6.5.0' # -- General configuration --------------------------------------------------- diff --git a/docs/manual/source/index.rst b/docs/manual/source/index.rst index 1bae7a3d..40fbc00d 100644 --- a/docs/manual/source/index.rst +++ b/docs/manual/source/index.rst @@ -22,6 +22,7 @@ Welcome to the ulab book! numpy-universal numpy-fft numpy-linalg + numpy-random scipy-linalg scipy-optimize scipy-signal diff --git a/docs/manual/source/numpy-functions.rst b/docs/manual/source/numpy-functions.rst index aac19bde..a2a3e410 100644 --- a/docs/manual/source/numpy-functions.rst +++ b/docs/manual/source/numpy-functions.rst @@ -12,43 +12,48 @@ the firmware was compiled with complex support. 4. `numpy.argmin <#argmin>`__ 5. `numpy.argsort <#argsort>`__ 6. `numpy.asarray\* <#asarray>`__ -7. `numpy.clip <#clip>`__ -8. `numpy.compress\* <#compress>`__ -9. `numpy.conjugate\* <#conjugate>`__ -10. `numpy.convolve\* <#convolve>`__ -11. `numpy.delete <#delete>`__ -12. `numpy.diff <#diff>`__ -13. `numpy.dot <#dot>`__ -14. `numpy.equal <#equal>`__ -15. `numpy.flip\* <#flip>`__ -16. `numpy.imag\* <#imag>`__ -17. `numpy.interp <#interp>`__ -18. `numpy.isfinite <#isfinite>`__ -19. `numpy.isinf <#isinf>`__ -20. `numpy.load <#load>`__ -21. `numpy.loadtxt <#loadtxt>`__ -22. `numpy.max <#max>`__ -23. `numpy.maximum <#maximum>`__ -24. `numpy.mean <#mean>`__ -25. `numpy.median <#median>`__ -26. `numpy.min <#min>`__ -27. `numpy.minimum <#minimum>`__ -28. `numpy.nozero <#nonzero>`__ -29. `numpy.not_equal <#equal>`__ -30. `numpy.polyfit <#polyfit>`__ -31. `numpy.polyval <#polyval>`__ -32. `numpy.real\* <#real>`__ -33. `numpy.roll <#roll>`__ -34. `numpy.save <#save>`__ -35. `numpy.savetxt <#savetxt>`__ -36. `numpy.size <#size>`__ -37. `numpy.sort <#sort>`__ -38. `numpy.sort_complex\* <#sort_complex>`__ -39. `numpy.std <#std>`__ -40. `numpy.sum <#sum>`__ -41. `numpy.trace <#trace>`__ -42. `numpy.trapz <#trapz>`__ -43. `numpy.where <#where>`__ +7. `numpy.bitwise_and <#bitwise_and>`__ +8. `numpy.bitwise_or <#bitwise_and>`__ +9. `numpy.bitwise_xor <#bitwise_and>`__ +10. `numpy.clip <#clip>`__ +11. `numpy.compress\* <#compress>`__ +12. `numpy.conjugate\* <#conjugate>`__ +13. `numpy.convolve\* <#convolve>`__ +14. `numpy.delete <#delete>`__ +15. `numpy.diff <#diff>`__ +16. `numpy.dot <#dot>`__ +17. `numpy.equal <#equal>`__ +18. `numpy.flip\* <#flip>`__ +19. `numpy.imag\* <#imag>`__ +20. `numpy.interp <#interp>`__ +21. `numpy.isfinite <#isfinite>`__ +22. `numpy.isinf <#isinf>`__ +23. `numpy.left_shift <#left_shift>`__ +24. `numpy.load <#load>`__ +25. `numpy.loadtxt <#loadtxt>`__ +26. `numpy.max <#max>`__ +27. `numpy.maximum <#maximum>`__ +28. `numpy.mean <#mean>`__ +29. `numpy.median <#median>`__ +30. `numpy.min <#min>`__ +31. `numpy.minimum <#minimum>`__ +32. `numpy.nozero <#nonzero>`__ +33. `numpy.not_equal <#equal>`__ +34. `numpy.polyfit <#polyfit>`__ +35. `numpy.polyval <#polyval>`__ +36. `numpy.real\* <#real>`__ +37. `numpy.right_shift <#right_shift>`__ +38. `numpy.roll <#roll>`__ +39. `numpy.save <#save>`__ +40. `numpy.savetxt <#savetxt>`__ +41. `numpy.size <#size>`__ +42. `numpy.sort <#sort>`__ +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>`__ all --- @@ -323,6 +328,58 @@ an alias for ``array``. +bitwise_and +----------- + +``numpy``: https://numpy.org/doc/stable/reference/routines.bitwise.html + +``numpy``: +https://numpy.org/doc/stable/reference/generated/numpy.bitwise_and.html + +``numpy``: +https://numpy.org/doc/stable/reference/generated/numpy.bitwise_or.html + +``numpy``: +https://numpy.org/doc/stable/reference/generated/numpy.bitwise_xor.html + +Each of ``bitwise_and``, ``bitwise_or``, and ``bitwise_xor`` takes two +integer-type ``ndarray``\ s as arguments, and returns the element-wise +results of the ``AND``, ``OR``, and ``XOR`` operators. Broadcasting is +supported. If the ``dtype`` of the input arrays is not an integer, and +exception will be raised. + +.. code:: + + # code to be run in micropython + + from ulab import numpy as np + + a = np.array(range(8), dtype=np.uint8) + b = a + 1 + + print(a) + print(b) + print('\nbitwise_and:\n', np.bitwise_and(a, b)) + print('\nbitwise_or:\n', np.bitwise_or(a, b)) + print('\nbitwise_xor:\n', np.bitwise_xor(a, b)) + +.. parsed-literal:: + + array([0, 1, 2, 3, 4, 5, 6, 7], dtype=uint8) + array([1, 2, 3, 4, 5, 6, 7, 8], dtype=uint8) + + bitwise_and: + array([0, 0, 2, 0, 4, 4, 6, 0], dtype=uint8) + + bitwise_or: + array([1, 3, 3, 7, 5, 7, 7, 15], dtype=uint8) + + bitwise_xor: + array([1, 3, 1, 7, 1, 3, 1, 15], dtype=uint8) + + + + clip ---- @@ -987,6 +1044,52 @@ positions, where the input is infinite. Integer types return the +left_shift +---------- + +``numpy``: +https://numpy.org/doc/stable/reference/generated/numpy.left_shift.html + +``numpy``: +https://numpy.org/doc/stable/reference/generated/numpy.right_shift.html + +``left_shift``, and ``right_shift`` both take two integer-type +``ndarray``\ s, and bit-wise shift the elements of the first array by an +amount given by the second array to the left, and right, respectively. +Broadcasting is supported. If the ``dtype`` of the input arrays is not +an integer, and exception will be raised. + +.. code:: + + # code to be run in micropython + + from ulab import numpy as np + + a = np.ones(7, dtype=np.uint8) + b = np.zeros(7, dtype=np.uint8) + 255 + c = np.array(range(7), dtype=np.uint8) + 1 + + print('a: ', a) + print('b: ', b) + print('c: ', c) + print('\na left shifted by c:\n', np.left_shift(a, c)) + print('\nb right shifted by c:\n', np.right_shift(b, c)) + +.. parsed-literal:: + + a: array([1, 1, 1, 1, 1, 1, 1], dtype=uint8) + b: array([255, 255, 255, 255, 255, 255, 255], dtype=uint8) + c: array([1, 2, 3, 4, 5, 6, 7], dtype=uint8) + + a left shifted by c: + array([2, 4, 8, 16, 32, 64, 128], dtype=uint8) + + b right shifted by c: + array([127, 63, 31, 15, 7, 3, 1], dtype=uint8) + + + + load ---- diff --git a/docs/manual/source/numpy-universal.rst b/docs/manual/source/numpy-universal.rst index b9b7f9f1..f39ee173 100644 --- a/docs/manual/source/numpy-universal.rst +++ b/docs/manual/source/numpy-universal.rst @@ -20,12 +20,18 @@ operate on, or can return complex arrays): ``acos``, ``acosh``, ``arctan2``, ``around``, ``asin``, ``asinh``, ``atan``, ``arctan2``, ``atanh``, ``ceil``, ``cos``, ``degrees``, ``exp*``, ``expm1``, ``floor``, ``log``, ``log10``, ``log2``, -``radians``, ``sin``, ``sinh``, ``sqrt*``, ``tan``, ``tanh``. +``radians``, ``sin``, ``sinc``, ``sinh``, ``sqrt*``, ``tan``, ``tanh``. These functions are applied element-wise to the arguments, thus, e.g., the exponential of a matrix cannot be calculated in this way, only the exponential of the matrix entries. +In order to avoid repeated memory allocations, functions can take the +``out=None`` optional argument, which must be a floating point +``ndarray`` of the same size as the input ``array``. If these conditions +are not fulfilled, and exception will be raised. If ``out=None``, a new +array will be created upon each invocation of the function. + .. code:: # code to be run in micropython @@ -47,6 +53,13 @@ exponential of the matrix entries. c = np.array(range(9)).reshape((3, 3)) print('\n=============\nc:\n', c) print('exp(c):\n', np.exp(c)) + + # using the `out` argument + d = np.array(range(9)).reshape((3, 3)) + + print('\nd before invoking the function:\n', d) + np.exp(c, out=d) + print('\nd afteri nvoking the function:\n', d) .. parsed-literal:: @@ -69,6 +82,16 @@ exponential of the matrix entries. [20.08553692318767, 54.59815003314424, 148.4131591025766], [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64) + d before invoking the function: + array([[0.0, 1.0, 2.0], + [3.0, 4.0, 5.0], + [6.0, 7.0, 8.0]], dtype=float64) + + d afteri nvoking the function: + array([[1.0, 2.718281828459045, 7.38905609893065], + [20.08553692318767, 54.59815003314424, 148.4131591025766], + [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64) + diff --git a/docs/manual/source/ulab-ndarray.rst b/docs/manual/source/ulab-ndarray.rst index ff8e6eb7..ef54a242 100644 --- a/docs/manual/source/ulab-ndarray.rst +++ b/docs/manual/source/ulab-ndarray.rst @@ -1816,12 +1816,17 @@ Binary operators ``ulab`` implements the ``+``, ``-``, ``*``, ``/``, ``**``, ``<``, ``>``, ``<=``, ``>=``, ``==``, ``!=``, ``+=``, ``-=``, ``*=``, ``/=``, -``**=`` binary operators that work element-wise. Broadcasting is -available, meaning that the two operands do not even have to have the -same shape. If the lengths along the respective axes are equal, or one -of them is 1, or the axis is missing, the element-wise operation can -still be carried out. A thorough explanation of broadcasting can be -found under https://numpy.org/doc/stable/user/basics.broadcasting.html. +``**=`` binary operators, as well as the ``AND``, ``OR``, ``XOR`` +bit-wise operators that work element-wise. Note that the bit-wise +operators will raise an exception, if either of the operands is of +``float`` or ``complex`` type. + +Broadcasting is available, meaning that the two operands do not even +have to have the same shape. If the lengths along the respective axes +are equal, or one of them is 1, or the axis is missing, the element-wise +operation can still be carried out. A thorough explanation of +broadcasting can be found under +https://numpy.org/doc/stable/user/basics.broadcasting.html. **WARNING**: note that relational operators (``<``, ``>``, ``<=``, ``>=``, ``==``, ``!=``) should have the ``ndarray`` on their left hand diff --git a/docs/numpy-functions.ipynb b/docs/numpy-functions.ipynb index c57225f9..2ef884a2 100644 --- a/docs/numpy-functions.ipynb +++ b/docs/numpy-functions.ipynb @@ -77,7 +77,7 @@ " if args.unix: # tests the code on the unix port. Note that this works on unix only\n", " with open('/dev/shm/micropython.py', 'w') as fout:\n", " fout.write(cell)\n", - " proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n", + " proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n", " stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", " print(proc.stdout.read().decode(\"utf-8\"))\n", " print(proc.stderr.read().decode(\"utf-8\"))\n", @@ -238,6 +238,9 @@ "1. [numpy.argmin](#argmin)\n", "1. [numpy.argsort](#argsort)\n", "1. [numpy.asarray*](#asarray)\n", + "1. [numpy.bitwise_and](#bitwise_and)\n", + "1. [numpy.bitwise_or](#bitwise_and)\n", + "1. [numpy.bitwise_xor](#bitwise_and)\n", "1. [numpy.clip](#clip)\n", "1. [numpy.compress*](#compress)\n", "1. [numpy.conjugate*](#conjugate)\n", @@ -251,6 +254,7 @@ "1. [numpy.interp](#interp)\n", "1. [numpy.isfinite](#isfinite)\n", "1. [numpy.isinf](#isinf)\n", + "1. [numpy.left_shift](#left_shift)\n", "1. [numpy.load](#load)\n", "1. [numpy.loadtxt](#loadtxt)\n", "1. [numpy.max](#max)\n", @@ -264,6 +268,7 @@ "1. [numpy.polyfit](#polyfit)\n", "1. [numpy.polyval](#polyval)\n", "1. [numpy.real*](#real)\n", + "1. [numpy.right_shift](#right_shift)\n", "1. [numpy.roll](#roll)\n", "1. [numpy.save](#save)\n", "1. [numpy.savetxt](#savetxt)\n", @@ -606,6 +611,63 @@ "print('a == c: {}'.format(a is c))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## bitwise_and\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/routines.bitwise.html\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.bitwise_and.html\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.bitwise_or.html\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.bitwise_xor.html\n", + "\n", + "Each of `bitwise_and`, `bitwise_or`, and `bitwise_xor` takes two integer-type `ndarray`s as arguments, and returns the element-wise results of the `AND`, `OR`, and `XOR` operators. Broadcasting is supported. If the `dtype` of the input arrays is not an integer, and exception will be raised." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "array([0, 1, 2, 3, 4, 5, 6, 7], dtype=uint8)\n", + "array([1, 2, 3, 4, 5, 6, 7, 8], dtype=uint8)\n", + "\n", + "bitwise_and:\n", + " array([0, 0, 2, 0, 4, 4, 6, 0], dtype=uint8)\n", + "\n", + "bitwise_or:\n", + " array([1, 3, 3, 7, 5, 7, 7, 15], dtype=uint8)\n", + "\n", + "bitwise_xor:\n", + " array([1, 3, 1, 7, 1, 3, 1, 15], dtype=uint8)\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython -unix 1\n", + "\n", + "from ulab import numpy as np\n", + "\n", + "a = np.array(range(8), dtype=np.uint8)\n", + "b = a + 1\n", + "\n", + "print(a)\n", + "print(b)\n", + "print('\\nbitwise_and:\\n', np.bitwise_and(a, b))\n", + "print('\\nbitwise_or:\\n', np.bitwise_or(a, b))\n", + "print('\\nbitwise_xor:\\n', np.bitwise_xor(a, b))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -1423,6 +1485,58 @@ "print('\\nisinf(c):\\n', np.isinf(c))" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## left_shift\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.left_shift.html\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/generated/numpy.right_shift.html\n", + "\n", + "`left_shift`, and `right_shift` both take two integer-type `ndarray`s, and bit-wise shift the elements of the first array by an amount given by the second array to the left, and right, respectively. Broadcasting is supported. If the `dtype` of the input arrays is not an integer, and exception will be raised." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "a: array([1, 1, 1, 1, 1, 1, 1], dtype=uint8)\n", + "b: array([255, 255, 255, 255, 255, 255, 255], dtype=uint8)\n", + "c: array([1, 2, 3, 4, 5, 6, 7], dtype=uint8)\n", + "\n", + "a left shifted by c:\n", + " array([2, 4, 8, 16, 32, 64, 128], dtype=uint8)\n", + "\n", + "b right shifted by c:\n", + " array([127, 63, 31, 15, 7, 3, 1], dtype=uint8)\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython -unix 1\n", + "\n", + "from ulab import numpy as np\n", + "\n", + "a = np.ones(7, dtype=np.uint8)\n", + "b = np.zeros(7, dtype=np.uint8) + 255\n", + "c = np.array(range(7), dtype=np.uint8) + 1\n", + "\n", + "print('a: ', a)\n", + "print('b: ', b)\n", + "print('c: ', c)\n", + "print('\\na left shifted by c:\\n', np.left_shift(a, c))\n", + "print('\\nb right shifted by c:\\n', np.right_shift(b, c))" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -2786,7 +2900,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" }, "toc": { "base_numbering": 1, diff --git a/docs/numpy-random.ipynb b/docs/numpy-random.ipynb new file mode 100644 index 00000000..4c9aa2a4 --- /dev/null +++ b/docs/numpy-random.ipynb @@ -0,0 +1,492 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-01T09:27:13.438054Z", + "start_time": "2020-05-01T09:27:13.191491Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Populating the interactive namespace from numpy and matplotlib\n" + ] + } + ], + "source": [ + "%pylab inline" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Notebook magic" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2022-01-07T18:24:48.499467Z", + "start_time": "2022-01-07T18:24:48.488004Z" + } + }, + "outputs": [], + "source": [ + "from IPython.core.magic import Magics, magics_class, line_cell_magic\n", + "from IPython.core.magic import cell_magic, register_cell_magic, register_line_magic\n", + "from IPython.core.magic_arguments import argument, magic_arguments, parse_argstring\n", + "import subprocess\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2020-07-23T20:31:25.296014Z", + "start_time": "2020-07-23T20:31:25.265937Z" + } + }, + "outputs": [], + "source": [ + "@magics_class\n", + "class PyboardMagic(Magics):\n", + " @cell_magic\n", + " @magic_arguments()\n", + " @argument('-skip')\n", + " @argument('-unix')\n", + " @argument('-pyboard')\n", + " @argument('-file')\n", + " @argument('-data')\n", + " @argument('-time')\n", + " @argument('-memory')\n", + " def micropython(self, line='', cell=None):\n", + " args = parse_argstring(self.micropython, line)\n", + " if args.skip: # doesn't care about the cell's content\n", + " print('skipped execution')\n", + " return None # do not parse the rest\n", + " if args.unix: # tests the code on the unix port. Note that this works on unix only\n", + " with open('/dev/shm/micropython.py', 'w') as fout:\n", + " fout.write(cell)\n", + " proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n", + " stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", + " print(proc.stdout.read().decode(\"utf-8\"))\n", + " print(proc.stderr.read().decode(\"utf-8\"))\n", + " return None\n", + " if args.file: # can be used to copy the cell content onto the pyboard's flash\n", + " spaces = \" \"\n", + " try:\n", + " with open(args.file, 'w') as fout:\n", + " fout.write(cell.replace('\\t', spaces))\n", + " printf('written cell to {}'.format(args.file))\n", + " except:\n", + " print('Failed to write to disc!')\n", + " return None # do not parse the rest\n", + " if args.data: # can be used to load data from the pyboard directly into kernel space\n", + " message = pyb.exec(cell)\n", + " if len(message) == 0:\n", + " print('pyboard >>>')\n", + " else:\n", + " print(message.decode('utf-8'))\n", + " # register new variable in user namespace\n", + " self.shell.user_ns[args.data] = string_to_matrix(message.decode(\"utf-8\"))\n", + " \n", + " if args.time: # measures the time of executions\n", + " pyb.exec('import utime')\n", + " message = pyb.exec('t = utime.ticks_us()\\n' + cell + '\\ndelta = utime.ticks_diff(utime.ticks_us(), t)' + \n", + " \"\\nprint('execution time: {:d} us'.format(delta))\")\n", + " print(message.decode('utf-8'))\n", + " \n", + " if args.memory: # prints out memory information \n", + " message = pyb.exec('from micropython import mem_info\\nprint(mem_info())\\n')\n", + " print(\"memory before execution:\\n========================\\n\", message.decode('utf-8'))\n", + " message = pyb.exec(cell)\n", + " print(\">>> \", message.decode('utf-8'))\n", + " message = pyb.exec('print(mem_info())')\n", + " print(\"memory after execution:\\n========================\\n\", message.decode('utf-8'))\n", + "\n", + " if args.pyboard:\n", + " message = pyb.exec(cell)\n", + " print(message.decode('utf-8'))\n", + "\n", + "ip = get_ipython()\n", + "ip.register_magics(PyboardMagic)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## pyboard" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-07T07:35:35.126401Z", + "start_time": "2020-05-07T07:35:35.105824Z" + } + }, + "outputs": [], + "source": [ + "import pyboard\n", + "pyb = pyboard.Pyboard('/dev/ttyACM0')\n", + "pyb.enter_raw_repl()" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-19T19:11:18.145548Z", + "start_time": "2020-05-19T19:11:18.137468Z" + } + }, + "outputs": [], + "source": [ + "pyb.exit_raw_repl()\n", + "pyb.close()" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": { + "ExecuteTime": { + "end_time": "2020-05-07T07:35:38.725924Z", + "start_time": "2020-05-07T07:35:38.645488Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + } + ], + "source": [ + "%%micropython -pyboard 1\n", + "\n", + "import utime\n", + "import ulab as np\n", + "\n", + "def timeit(n=1000):\n", + " def wrapper(f, *args, **kwargs):\n", + " func_name = str(f).split(' ')[1]\n", + " def new_func(*args, **kwargs):\n", + " run_times = np.zeros(n, dtype=np.uint16)\n", + " for i in range(n):\n", + " t = utime.ticks_us()\n", + " result = f(*args, **kwargs)\n", + " run_times[i] = utime.ticks_diff(utime.ticks_us(), t)\n", + " print('{}() execution times based on {} cycles'.format(func_name, n, (delta2-delta1)/n))\n", + " print('\\tbest: %d us'%np.min(run_times))\n", + " print('\\tworst: %d us'%np.max(run_times))\n", + " print('\\taverage: %d us'%np.mean(run_times))\n", + " print('\\tdeviation: +/-%.3f us'%np.std(run_times)) \n", + " return result\n", + " return new_func\n", + " return wrapper\n", + "\n", + "def timeit(f, *args, **kwargs):\n", + " func_name = str(f).split(' ')[1]\n", + " def new_func(*args, **kwargs):\n", + " t = utime.ticks_us()\n", + " result = f(*args, **kwargs)\n", + " print('execution time: ', utime.ticks_diff(utime.ticks_us(), t), ' us')\n", + " return result\n", + " return new_func" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "__END_OF_DEFS__" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# numpy.random\n", + "\n", + "Random numbers drawn specific distributions can be generated by instantiating a `Generator` object, and calling its methods. The module defines the following three functions:\n", + "\n", + "1. [numpy.random.Generator.normal](#normal)\n", + "1. [numpy.random.Generator.random](#random)\n", + "1. [numpy.random.Generator.uniform](#uniform)\n", + "\n", + "\n", + "The `Generator` object, when instantiated, takes a single integer as its argument. This integer is the seed, which will be fed to the 32-bit or 64-bit routine. More details can be found under https://www.pcg-random.org/index.html. The generator is a standard `python` object that keeps track of its state.\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/random/index.html" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## normal\n", + "\n", + "A random set of number from the `normal` distribution can be generated by calling the generator's `normal` method. The method takes three optional arguments, `loc=0.0`, the centre of the distribution, `scale=1.0`, the width of the distribution, and `size=None`, a tuple containing the shape of the returned array. In case `size` is `None`, a single floating point number is returned.\n", + "\n", + "The `normal` method of the `Generator` object is based on the [Box-Muller transform](https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform).\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.normal.html" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2019-10-19T13:08:17.647416Z", + "start_time": "2019-10-19T13:08:17.597456Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gnerator() at 0x7fa9dae05340\n", + "-6.285246229407202\n", + "array([[24.95816273705659, 15.2670302229426, 14.81001577336041],\n", + " [20.17589833056986, 23.14539083787544, 26.37772041367461],\n", + " [41.94894234387275, 37.11027030608206, 25.65889562100477]], dtype=float64)\n", + "array([[21.52562779033434, 12.74685887865834, 24.08404670765186],\n", + " [4.728112596365396, 7.667757906857082, 21.61576094228444],\n", + " [2.432338873595267, 27.75945683572574, 5.730827584659245]], dtype=float64)\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython -unix 1\n", + "\n", + "from ulab import numpy as np\n", + "\n", + "rng = np.random.Generator(123456)\n", + "print(rng)\n", + "\n", + "# return single number from a distribution of scale 1, and location 0\n", + "print(rng.normal())\n", + "\n", + "print(rng.normal(loc=20.0, scale=10.0, size=(3,3)))\n", + "# same as above, with positional arguments\n", + "print(rng.normal(20.0, 10.0, (3,3)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## random\n", + "\n", + "A random set of number from the uniform distribution in the interval [0, 1] can be generated by calling the generator's `random` method. The method takes two optional arguments, `size=None`, a tuple containing the shape of the returned array, and `out`. In case `size` is `None`, a single floating point number is returned. \n", + "\n", + "`out` can be used, if a floating point array is available. An exception will be raised, if the array is not of `float` `dtype`, or if both `size` and `out` are supplied, and there is a conflict in their shapes.\n", + "\n", + "If `size` is `None`, a single floating point number will be returned.\n", + "\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.random.html" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gnerator() at 0x7f299de05340\n", + "6.384615058863119e-11\n", + "\n", + " array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],\n", + " [0.8738606263361598, 0.4946080034142021, 0.7765890156101152],\n", + " [0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)\n", + "\n", + "buffer array before:\n", + " array([[0.0, 1.0, 2.0],\n", + " [3.0, 4.0, 5.0],\n", + " [6.0, 7.0, 8.0]], dtype=float64)\n", + "\n", + "buffer array after:\n", + " array([[0.8508024287393201, 0.9848489829156055, 0.7598167589604003],\n", + " [0.782995698302952, 0.2866337782847831, 0.7915884498022229],\n", + " [0.4614071706315902, 0.4792657443088592, 0.1581582066230718]], dtype=float64)\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython -unix 1\n", + "\n", + "from ulab import numpy as np\n", + "\n", + "rng = np.random.Generator(123456)\n", + "print(rng)\n", + "\n", + "# returning new objects\n", + "print(rng.random())\n", + "print('\\n', rng.random(size=(3,3)))\n", + "\n", + "# supplying a buffer\n", + "a = np.array(range(9), dtype=np.float).reshape((3,3))\n", + "print('\\nbuffer array before:\\n', a)\n", + "rng.random(out=a)\n", + "print('\\nbuffer array after:\\n', a)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## uniform\n", + "\n", + "`uniform` is similar to `random`, except that the interval over which the numbers are distributed can be specified, while the `out` argument cannot. In addition to `size` specifying the shape of the output, `low=0.0`, and `high=1.0` are accepted arguments. With the indicated defaults, `uniform` is identical to `random`, which can be seen from the fact that the first 3-by-3 tensor below is the same as the one produced by `rng.random(size=(3,3))` above.\n", + "\n", + "\n", + "If `size` is `None`, a single floating point number will be returned.\n", + "\n", + "\n", + "`numpy`: https://numpy.org/doc/stable/reference/random/generated/numpy.random.Generator.uniform.html" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Gnerator() at 0x7f1891205340\n", + "6.384615058863119e-11\n", + "\n", + " array([[0.4348157846574171, 0.7906325931024071, 0.878697619856133],\n", + " [0.8738606263361598, 0.4946080034142021, 0.7765890156101152],\n", + " [0.1770783715717074, 0.02080447648492112, 0.1053837559005948]], dtype=float64)\n", + "\n", + " array([[18.5080242873932, 19.84848982915605, 17.598167589604],\n", + " [17.82995698302952, 12.86633778284783, 17.91588449802223],\n", + " [14.6140717063159, 14.79265744308859, 11.58158206623072]], dtype=float64)\n", + "\n", + " array([[14.3380400319162, 12.72487657409978, 15.77119643621117],\n", + " [13.61835831436355, 18.96062889255558, 15.78847796795966],\n", + " [12.59435855187034, 17.68262037443622, 14.77943040598734]], dtype=float64)\n", + "\n", + "\n" + ] + } + ], + "source": [ + "%%micropython -unix 1\n", + "\n", + "from ulab import numpy as np\n", + "\n", + "rng = np.random.Generator(123456)\n", + "print(rng)\n", + "\n", + "print(rng.uniform())\n", + "# returning numbers between 0, and 1\n", + "print('\\n', rng.uniform(size=(3,3)))\n", + "\n", + "# returning numbers between 10, and 20\n", + "print('\\n', rng.uniform(low=10, high=20, size=(3,3)))\n", + "\n", + "# same as above, without the keywords\n", + "print('\\n', rng.uniform(10, 20, (3,3)))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.13" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": true, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "382.797px" + }, + "toc_section_display": true, + "toc_window_display": true + }, + "varInspector": { + "cols": { + "lenName": 16, + "lenType": 16, + "lenVar": 40 + }, + "kernels_config": { + "python": { + "delete_cmd_postfix": "", + "delete_cmd_prefix": "del ", + "library": "var_list.py", + "varRefreshCmd": "print(var_dic_list())" + }, + "r": { + "delete_cmd_postfix": ") ", + "delete_cmd_prefix": "rm(", + "library": "var_list.r", + "varRefreshCmd": "cat(var_dic_list()) " + } + }, + "types_to_exclude": [ + "module", + "function", + "builtin_function_or_method", + "instance", + "_Feature" + ], + "window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/docs/numpy-universal.ipynb b/docs/numpy-universal.ipynb index 8934fa6e..1d5764b8 100644 --- a/docs/numpy-universal.ipynb +++ b/docs/numpy-universal.ipynb @@ -31,7 +31,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2022-01-07T19:10:30.696795Z", @@ -49,7 +49,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2022-01-07T19:10:30.785887Z", @@ -77,7 +77,7 @@ " if args.unix: # tests the code on the unix port. Note that this works on unix only\n", " with open('/dev/shm/micropython.py', 'w') as fout:\n", " fout.write(cell)\n", - " proc = subprocess.Popen([\"../micropython/ports/unix/micropython-2\", \"/dev/shm/micropython.py\"], \n", + " proc = subprocess.Popen([\"../micropython/ports/unix/build-2/micropython-2\", \"/dev/shm/micropython.py\"], \n", " stdout=subprocess.PIPE, stderr=subprocess.PIPE)\n", " print(proc.stdout.read().decode(\"utf-8\"))\n", " print(proc.stderr.read().decode(\"utf-8\"))\n", @@ -229,14 +229,16 @@ "\n", "At present, the following functions are supported (starred functions can operate on, or can return complex arrays):\n", "\n", - "`acos`, `acosh`, `arctan2`, `around`, `asin`, `asinh`, `atan`, `arctan2`, `atanh`, `ceil`, `cos`, `degrees`, `exp*`, `expm1`, `floor`, `log`, `log10`, `log2`, `radians`, `sin`, `sinh`, `sqrt*`, `tan`, `tanh`.\n", + "`acos`, `acosh`, `arctan2`, `around`, `asin`, `asinh`, `atan`, `arctan2`, `atanh`, `ceil`, `cos`, `degrees`, `exp*`, `expm1`, `floor`, `log`, `log10`, `log2`, `radians`, `sin`, `sinc`, `sinh`, `sqrt*`, `tan`, `tanh`.\n", + "\n", + "These functions are applied element-wise to the arguments, thus, e.g., the exponential of a matrix cannot be calculated in this way, only the exponential of the matrix entries.\n", "\n", - "These functions are applied element-wise to the arguments, thus, e.g., the exponential of a matrix cannot be calculated in this way, only the exponential of the matrix entries." + "In order to avoid repeated memory allocations, functions can take the `out=None` optional argument, which must be a floating point `ndarray` of the same size as the input `array`. If these conditions are not fulfilled, and exception will be raised. If `out=None`, a new array will be created upon each invocation of the function." ] }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2021-01-13T19:11:07.579601Z", @@ -267,6 +269,16 @@ " [20.08553692318767, 54.59815003314424, 148.4131591025766],\n", " [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)\n", "\n", + "d before invoking the function:\n", + " array([[0.0, 1.0, 2.0],\n", + " [3.0, 4.0, 5.0],\n", + " [6.0, 7.0, 8.0]], dtype=float64)\n", + "\n", + "d afteri nvoking the function:\n", + " array([[1.0, 2.718281828459045, 7.38905609893065],\n", + " [20.08553692318767, 54.59815003314424, 148.4131591025766],\n", + " [403.4287934927351, 1096.633158428459, 2980.957987041728]], dtype=float64)\n", + "\n", "\n" ] } @@ -290,7 +302,14 @@ "# as well as with matrices\n", "c = np.array(range(9)).reshape((3, 3))\n", "print('\\n=============\\nc:\\n', c)\n", - "print('exp(c):\\n', np.exp(c))" + "print('exp(c):\\n', np.exp(c))\n", + "\n", + "# using the `out` argument\n", + "d = np.array(range(9)).reshape((3, 3))\n", + "\n", + "print('\\nd before invoking the function:\\n', d)\n", + "np.exp(c, out=d)\n", + "print('\\nd afteri nvoking the function:\\n', d)" ] }, { @@ -814,7 +833,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.8.5" + "version": "3.9.13" }, "toc": { "base_numbering": 1, diff --git a/docs/ulab-ndarray.ipynb b/docs/ulab-ndarray.ipynb index bf016b1a..0e2bb1b0 100644 --- a/docs/ulab-ndarray.ipynb +++ b/docs/ulab-ndarray.ipynb @@ -2599,7 +2599,9 @@ "source": [ "# Binary operators\n", "\n", - "`ulab` implements the `+`, `-`, `*`, `/`, `**`, `<`, `>`, `<=`, `>=`, `==`, `!=`, `+=`, `-=`, `*=`, `/=`, `**=` binary operators that work element-wise. Broadcasting is available, meaning that the two operands do not even have to have the same shape. If the lengths along the respective axes are equal, or one of them is 1, or the axis is missing, the element-wise operation can still be carried out. \n", + "`ulab` implements the `+`, `-`, `*`, `/`, `**`, `<`, `>`, `<=`, `>=`, `==`, `!=`, `+=`, `-=`, `*=`, `/=`, `**=` binary operators, as well as the `AND`, `OR`, `XOR` bit-wise operators that work element-wise. Note that the bit-wise operators will raise an exception, if either of the operands is of `float` or `complex` type.\n", + "\n", + "Broadcasting is available, meaning that the two operands do not even have to have the same shape. If the lengths along the respective axes are equal, or one of them is 1, or the axis is missing, the element-wise operation can still be carried out. \n", "A thorough explanation of broadcasting can be found under https://numpy.org/doc/stable/user/basics.broadcasting.html. \n", "\n", "**WARNING**: note that relational operators (`<`, `>`, `<=`, `>=`, `==`, `!=`) should have the `ndarray` on their left hand side, when compared to scalars. This means that the following works"