{"id":18233304,"url":"https://github.com/grimmerk/numjs","last_synced_at":"2025-03-23T23:32:08.136Z","repository":{"id":45996219,"uuid":"397778648","full_name":"grimmerk/numjs","owner":"grimmerk","description":"Like NumPy, in JavaScript. It's a modification of the numjs project. Improvement: TypeScript/ES6/Documentation, etc. Published a new npm package, @d4c/numjs, used by alphago-zero-tictactoe-js.","archived":false,"fork":false,"pushed_at":"2023-09-04T06:21:54.000Z","size":4845,"stargazers_count":23,"open_issues_count":2,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-17T22:03:12.458Z","etag":null,"topics":["browser","javascript","linear-algebra","math","matrix","ndarray","nodejs","numpy","typescript","vector"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grimmerk.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2021-08-19T01:19:08.000Z","updated_at":"2025-03-15T17:45:21.000Z","dependencies_parsed_at":"2023-11-28T17:18:02.356Z","dependency_job_id":null,"html_url":"https://github.com/grimmerk/numjs","commit_stats":{"total_commits":253,"total_committers":6,"mean_commits":"42.166666666666664","dds":0.4980237154150198,"last_synced_commit":"751b1020b2000aabec2777cd4bd9626e0d16795c"},"previous_names":["grimmerk/numjs","grimmer0125/numjs"],"tags_count":64,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmerk%2Fnumjs","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmerk%2Fnumjs/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmerk%2Fnumjs/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmerk%2Fnumjs/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grimmerk","download_url":"https://codeload.github.com/grimmerk/numjs/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245186882,"owners_count":20574553,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","javascript","linear-algebra","math","matrix","ndarray","nodejs","numpy","typescript","vector"],"created_at":"2024-11-04T15:03:58.753Z","updated_at":"2025-03-23T23:32:08.105Z","avatar_url":"https://github.com/grimmerk.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @d4c/numjs\n\n[![npm version](https://img.shields.io/npm/v/%40d4c/numjs.svg)](https://www.npmjs.com/package/@d4c/numjs) ![example workflow](https://github.com/grimmer0125/numjs/actions/workflows/node.js.yml/badge.svg)\n\n__NumJs__ is built on top of [ndarray](https://scijs.net/packages/#scijs/ndarray) and uses many [scijs packages](https://scijs.net/packages/). `ndarray` is exported as `nj.ndarray`, and any `NdArray` instance's property `selection` is a `ndarray` object.\n\nThis project is modified from https://github.com/nicolaspanel/numjs and does below modifications \n- Remove the feature of images manipulation whose dependencies may result in some installation failure on Mac M1 ARM machine. You could consider [ndarray-pixels](https://github.com/donmccurdy/ndarray-pixels) if you need this feature. \n- Add TypeScript typings and `.d.ts` is out of box, JavaScript is supported, too. Also, it includes \n    - ES6 build (ES2015) with CommonJS module for main build in package.json.\n    - ES6 build (ES2015) with ES6 module for module build. Some tools will follow the module field in package.json, like Rollup, Webpack, or Parcel.\n- Refactor internal code via ES6 syntax and does not change the core algorithm code.\n- Add \"uint8_clamped\" (Uint8ClampedArray) support. \n- Other improvements.\n\nYou can check the [changelog](https://github.com/grimmer0125/numjs/blob/master/CHANGELOG.md).\n\n## Features\n\n__NumJs__ is a npm package for scientific computing with JavaScript. It contains among other things:\n - a powerful N-dimensional array object, `NdArray`\n - linear algebra function\n - fast Fourier transform\n\nBesides its obvious scientific uses, __NumJs__ can also be used as an efficient multi-dimensional container of generic data.\n\nIt works both in node.js and in the browser.\n\n__NumJs__ is licensed under the [MIT license](https://github.com/grimmer0125/numjs/blob/master/LICENSE), enabling reuse with almost no restrictions.\n\nTry this [jsfiddle](https://jsfiddle.net/grimmer0125/8jft09q3) to play around with the library.\n## Installation\n\n```sh\nnpm install @d4c/numjs \n# or \nyarn add @d4c/numjs\n```\n\nthen using ES6 import: \n\n```ts\nimport nj from \"@d4c/numjs\"; \n```\nOr CommonJS require:\n\n```ts\n// TypeScript users will not get typings when using require\nconst nj = require('@d4c/numjs').default; \n```\n\nOr download from CDN: \n```html\n\u003cscript type=\"module\"\u003e\n    import nj from 'https://cdn.jsdelivr.net/npm/@d4c/numjs/build/module/numjs.min.js';\n    // optional: assign to global to let other code can use: globalThis.nj = nj;\n\u003c/script\u003e\n```\n\nIf using `ES6 import` or `CommonJS require` resuls in some errors, please try to use `import nj from \"@d4c/numjs/build/module/numjs.min.js` in your environments. \n## Basics\n\n### Array Creation\n\n```ts\n\u003e const a = nj.array([2,3,4]);\n\u003e a\narray([ 2, 3, 4])\n\u003e const b = nj.array([[1,2,3], [4,5,6]]);\n\u003e b\narray([[ 1, 2, 3],\n       [ 4, 5, 6]])\n```\n\n__Note__: Default data container is JavaScript `Array` object. If needed, you can also use typed array such as `Uint8Array`:\n\n```ts\n\u003e const a = nj.uint8([1,2,3]);\n\u003e a\narray([ 1, 2, 3], dtype=uint8)\n```\n\nBelow are alternative ways to create same `NdArray`.\n\n```ts\nconst a = nj.array([1, 2, 3], \"uint8\");\nconst b = nj.array([1, 2, 3], Uint8Array);\nconst c = nj.array(new Uint8Array([1, 2, 3]));\nconst d = nj.arange(3,\"uint8\"); // results in array([ 0, 1, 2], dtype=uint8) \n// but we want [1,2,3], how?  \n// we can manually create a scijs/ndarray object, then assign it as selection property \nd.selection = nj.ndarray(new Uint8Array([1, 2, 3]));\n// d.selection.data is the stored raw Uint8Array([1, 2, 3])\n```\n\n__Note__: possible types are int8, uint8, int16, uint16, int32, uint32, float32, float64, uint8_clamped and array (the default)\n\nTo create arrays with a given shape, you can use `zeros`, `ones` or `random` functions:\n\n```ts\n\u003e nj.zeros([2,3]);\narray([[ 0, 0, 0],\n       [ 0, 0, 0]])\n\u003e nj.ones([2,3,4], 'int32')     // dtype can also be specified\narray([[[ 1, 1, 1, 1],\n        [ 1, 1, 1, 1],\n        [ 1, 1, 1, 1]],\n       [[ 1, 1, 1, 1],\n        [ 1, 1, 1, 1],\n        [ 1, 1, 1, 1]]], dtype=int32)\n\n\u003e nj.random([4,3])\narray([[ 0.9182 , 0.85176, 0.22587],\n       [ 0.50088, 0.74376, 0.84024],\n       [ 0.74045, 0.23345, 0.20289],\n       [ 0.00612, 0.37732, 0.06932]])\n```\n\nTo create sequences of numbers, __NumJs__ provides a function called `arange`:\n\n```ts\n\u003e nj.arange(4);\narray([ 0, 1, 2, 3])\n\n\u003e nj.arange( 10, 30, 5 )\narray([ 10, 15, 20, 25])\n\n\u003e nj.arange(1, 5, 'uint8');\narray([ 1, 2, 3, 4], dtype=uint8)\n```\n\n#### Optional NdArray constructor parameters, stride and offset\n\nThe code is like \n\n```ts\n// pass data, shape, stride, offset arguments.\n// this will call nj.ndarray([2, 3, 4], [3], [1], 0) and assign it to NdArray's selection property\nconst a = new nj.NdArray([2, 3, 4], [3], [1], 0);\n```\n\nOr you want to apply on a raw scijs ndarray object\n\n```ts\n// scijs ndarray object\nconst a = nj.ndarray([2, 3, 4], [3], [1], 0);\n```\n\n\n`NdArray and ndarray` are also exported. You can also use \n```ts\nimport { NdArray, ndarray } from \"@d4c/numjs\"\n// or CommonJS:\nconst NdArray = require('numjs').NdArray;\nconst ndarray = require('numjs').ndarray;\n```\nto reduce typing \"`nj.`\".\n\n### More info about the array\n\n__NumJs__’s array class is called `NdArray`. It is also known by the alias `array`. The more important properties of an `NdArray` object are:\n - `NdArray#ndim`: the number of axes (dimensions) of the array.\n - `NdArray#shape`: the dimensions of the array. This is a list of integers indicating the size of the array in each dimension. For a matrix with n rows and m columns, shape will be [n,m]. The length of the shape is therefore the number of dimensions, ndim.\n - `NdArray#size`: the total number of elements of the array. This is equal to the product of the elements of shape.\n - `NdArray#dtype`: a string describing the type of the elements in the array. `int32`, `int16`, and `float64` are some examples. Default dtype is `array`.\n\nAn `NdArray` can always be converted to a native JavaScript `Array` using `NdArray#tolist()` method.\n\n\nExample:\n```ts\n\u003e a = nj.arange(15).reshape(3, 5);\narray([[  0,  1,  2,  3,  4],\n       [  5,  6,  7,  8,  9],\n       [ 10, 11, 12, 13, 14]])\n\n\u003e a.shape\n[ 3, 5]\n\u003e a.ndim\n2\n\u003e a.dtype\n'array'\n\u003e a instanceof nj.NdArray\ntrue\n\u003e a.tolist() instanceof Array\ntrue\n\u003e a.get(1,1)\n6\n\u003e a.set(0,0,1)\n\u003e a\narray([[  1,  1,  2,  3,  4],\n       [  5,  6,  7,  8,  9],\n       [ 10, 11, 12, 13, 14]])\n\n```\n\n### Printing arrays\n\nUse `nj.array([2,3,4]` as an example. In Node.js, `console.log(nj.array([2,3,4])` will print beautified content, `array([ 2, 3, 4])`. In browser or using debugger in Node.js, please use `console.log(nj.array([2,3,4].toString())` to print its beautified content. `toString()` is working in browser/Node.js.\n\nWhen you print the beautified content of an array, __NumJs__ displays it in a similar way to nested lists, but with the following layout:\n - the last axis is printed from left to right,\n - the second-to-last is printed from top to bottom,\n - the rest are also printed from top to bottom, with each slice separated from the next by an empty line.\n\nOne-dimensional arrays are then printed as rows, bidimensionals as matrices and tridimensionals as lists of matrices.\n\n```ts\n\u003e const a = nj.arange(6);                 // 1d array\n\u003e console.log(a);\narray([ 0, 1, 2, 3, 4, 5])\n\u003e\n\u003e const b = nj.arange(12).reshape(4,3);   // 2d array\n\u003e console.log(b);\narray([[  0,  1,  2],\n       [  3,  4,  5],\n       [  6,  7,  8],\n       [  9, 10, 11]])\n\u003e\n\u003e const c = nj.arange(24).reshape(2,3,4); // 3d array\n\u003e console.log(c);\narray([[[  0,  1,  2,  3],\n        [  4,  5,  6,  7],\n        [  8,  9, 10, 11]],\n       [[ 12, 13, 14, 15],\n        [ 16, 17, 18, 19],\n        [ 20, 21, 22, 23]]])\n\n```\n\nIf an array is too large to be printed, __NumJs__ automatically skips the central part of the array and only prints the corners:\n\n```ts\n\u003e console.log(nj.arange(10000).reshape(100,100))\narray([[    0,    1, ...,   98,   99],\n       [  100,  101, ...,  198,  199],\n        ...\n       [ 9800, 9801, ..., 9898, 9899],\n       [ 9900, 9901, ..., 9998, 9999]])\n```\n\nTo customize this behaviour, you can change the printing options using `nj.config.printThreshold` (default is `7`):\n```ts\n\u003e nj.config.printThreshold = 9;\n\u003e console.log(nj.arange(10000).reshape(100,100))\narray([[    0,    1,    2,    3, ...,   96,   97,   98,   99],\n       [  100,  101,  102,  103, ...,  196,  197,  198,  199],\n       [  200,  201,  202,  203, ...,  296,  297,  298,  299],\n       [  300,  301,  302,  303, ...,  396,  397,  398,  399],\n        ...\n       [ 9600, 9601, 9602, 9603, ..., 9696, 9697, 9698, 9699],\n       [ 9700, 9701, 9702, 9703, ..., 9796, 9797, 9798, 9799],\n       [ 9800, 9801, 9802, 9803, ..., 9896, 9897, 9898, 9899],\n       [ 9900, 9901, 9902, 9903, ..., 9996, 9997, 9998, 9999]])\n\n```\n\n### Indexing\n\nSingle element indexing  uses `get` and `set` methods. It is 0-based, and accepts negative indices for indexing from the end of the array:\n```ts\n\u003e const a = nj.array([0,1,2]);\n\u003e a.get(1)\n1\n\u003e\n\u003e a.get(-1)\n2\n\u003e\n\u003e const b = nj.arange(3*3).reshape(3,3);\n\u003e b\narray([[  0,  1,  2],\n       [  3,  4,  5],\n       [  6,  7,  8])\n\u003e\n\u003e b.get(1, 1);\n4\n\u003e\n\u003e b.get(-1, -1);\n8\n\u003e b.set(0,0,1);\n\u003e b\narray([[ 1, 1, 2],\n       [ 3, 4, 5],\n       [ 6, 7, 8]])\n```\n\n\n### Slicing and Striding\n\nIt is possible to slice and stride arrays to extract arrays of the same number of dimensions, but of different sizes than the original. The slicing and striding works exactly the same way it does in NumPy:\n\n```ts\n\u003e const a = nj.arange(5);\n\u003e a\narray([  0,  1,  2,  3,  4])\n\u003e\n\u003e a.slice(1) // skip the first item, same as a[1:]\narray([ 1, 2, 3, 4])\n\u003e\n\u003e a.slice(-3) // takes the last 3 items, same as a[-3:]\narray([ 2, 3, 4])\n\u003e\n\u003e a.slice([4]) // takes the first 4 items, same as a[:4]\narray([ 0, 1, 2, 3])\n\u003e\n\u003e a.slice([-2]) // skip the last 2 items, same as a[:-2]\narray([ 0, 1, 2])\n\u003e\n\u003e a.slice([1,4]) // same as a[1:4]\narray([ 1, 2, 3])\n\u003e\n\u003e a.slice([1,4,-1]) // same as a[1:4:-1]\narray([ 3, 2, 1])\n\u003e\n\u003e a.slice([null,null,-1]) // same as a[::-1]\narray([ 4, 3, 2, 1, 0])\n\u003e\n\u003e const b = nj.arange(5*5).reshape(5,5);\n\u003e b\narray([[  0,  1,  2,  3,  4],\n       [  5,  6,  7,  8,  9],\n       [ 10, 11, 12, 13, 14],\n       [ 15, 16, 17, 18, 19],\n       [ 20, 21, 22, 23, 24]])\n\u003e\n\u003e b.slice(1,2) //  skip the first row and the 2 first  columns, same as b[1:,2:]\narray([[  7,  8,  9],\n       [ 12, 13, 14],\n       [ 17, 18, 19],\n       [ 22, 23, 24]])\n\u003e\n\u003e b.slice(null, [null, null, -1]) // reverse rows, same as b[:, ::-1]\narray([[  4,  3,  2,  1,  0],\n       [  9,  8,  7,  6,  5],\n       [ 14, 13, 12, 11, 10],\n       [ 19, 18, 17, 16, 15],\n       [ 24, 23, 22, 21, 20]])\n```\n\nNote that slices do not copy the internal array data, it produces a new views of the original data.\n\n### Basic operations\n\nArithmetic operators such as `*` (`multiply`), `+` (`add`), `-` (`subtract`), `/` (`divide`), `**` (`pow`), `=` (`assign`) apply elemen-twise. A new array is created and filled with the result:\n\n```ts\n\u003e zeros = nj.zeros([3,4]);\narray([[ 0, 0, 0, 0],\n       [ 0, 0, 0, 0],\n       [ 0, 0, 0, 0]])\n\u003e\n\u003e ones = nj.ones([3,4]);\narray([[ 1, 1, 1, 1],\n       [ 1, 1, 1, 1],\n       [ 1, 1, 1, 1]])\n\u003e\n\u003e ones.add(ones)\narray([[ 2, 2, 2, 2],\n       [ 2, 2, 2, 2],\n       [ 2, 2, 2, 2]])\n\u003e\n\u003e ones.subtract(ones)\narray([[ 0, 0, 0, 0],\n       [ 0, 0, 0, 0],\n       [ 0, 0, 0, 0]])\n\u003e\n\u003e zeros.pow(zeros)\narray([[ 1, 1, 1, 1],\n       [ 1, 1, 1, 1],\n       [ 1, 1, 1, 1]])\n\u003e\n```\n\nTo modify an existing array rather than create a new one you can set the `copy` parameter to `false`:\n\n```ts\n\u003e ones = nj.ones([3,4]);\narray([[ 1, 1, 1, 1],\n       [ 1, 1, 1, 1],\n       [ 1, 1, 1, 1]])\n\u003e\n\u003e ones.add(ones, false)\narray([[ 2, 2, 2, 2],\n       [ 2, 2, 2, 2],\n       [ 2, 2, 2, 2]])\n\u003e\n\u003e ones\narray([[ 2, 2, 2, 2],\n       [ 2, 2, 2, 2],\n       [ 2, 2, 2, 2]])\n\u003e\n\u003e zeros = nj.zeros([3,4])\n\u003e zeros.slice([1,-1],[1,-1]).assign(1, false);\n\u003e zeros\narray([[ 0, 0, 0, 0],\n       [ 0, 1, 1, 0],\n       [ 0, 0, 0, 0]])\n```\n__Note__: available for `add`, `subtract`, `multiply`, `divide`, `assign` and `pow` methods.\n\n\nThe matrix product can be performed using the `dot` function:\n\n```ts\n\u003e a = nj.arange(12).reshape(3,4);\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e\n\u003e nj.dot(a.T, a)\narray([[  80,  92, 104, 116],\n       [  92, 107, 122, 137],\n       [ 104, 122, 140, 158],\n       [ 116, 137, 158, 179]])\n\u003e\n\u003e nj.dot(a, a.T)\narray([[  14,  38,  62],\n       [  38, 126, 214],\n       [  62, 214, 366]])\n```\n\nMany unary operations, such as computing the sum of all the elements in the array, are implemented as methods of the `NdArray` class:\n\n```ts\n\u003e a = nj.random([2,3])\narray([[0.62755, 0.8278,0.21384],\n       [ 0.7029,0.27584,0.46472]])\n\u003e a.sum()\n3.1126488673035055\n\u003e\n\u003e a.min()\n0.2138431086204946\n\u003e\n\u003e a.max()\n0.8278025290928781\n\u003e\n\u003e a.mean()\n0.5187748112172509\n\u003e\n\u003e a.std()\n0.22216977543691244\n```\n\n### Universal Functions\n__NumJs__ provides familiar mathematical functions such as `sin`, `cos`, and `exp`. These functions operate element-wise on an array, producing an `NdArray` as output:\n\n```ts\n\u003e a = nj.array([-1, 0, 1])\narray([-1, 0, 1])\n\u003e\n\u003e nj.negative(a)\narray([ 1, 0,-1])\n\u003e\n\u003e nj.abs(a)\narray([ 1, 0, 1])\n\u003e\n\u003e nj.exp(a)\narray([ 0.36788,       1, 2.71828])\n\u003e\n\u003e nj.tanh(a)\narray([-0.76159,       0, 0.76159])\n\u003e\n\u003e nj.softmax(a)\narray([ 0.09003, 0.24473, 0.66524])\n\u003e\n\u003e nj.sigmoid(a)\narray([ 0.26894,     0.5, 0.73106])\n\u003e\n\u003e nj.exp(a)\narray([ 0.36788,       1, 2.71828])\n\u003e\n\u003e nj.log(nj.exp(a))\narray([-1, 0, 1])\n\u003e\n\u003e nj.sqrt(nj.abs(a))\narray([ 1, 0, 1])\n\u003e\n\u003e nj.sin(nj.arcsin(a))\narray([-1, 0, 1])\n\u003e\n\u003e nj.cos(nj.arccos(a))\narray([-1, 0, 1])\n\u003e\n\u003e nj.tan(nj.arctan(a))\narray([-1, 0, 1])\n```\n\n### Shape Manipulation\nAn array has a shape given by the number of elements along each axis:\n\n```ts\n\u003e a = nj.array([[  0,  1,  2,  3], [  4,  5,  6,  7], [  8,  9, 10, 11]]);\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\n\u003e a.shape\n[ 3, 4 ]\n```\n\nThe shape of an array can be changed with constious commands:\n```ts\n\u003e a.flatten();\narray([  0,  1,  2, ...,  9, 10, 11])\n\u003e\n\u003e a.T                   // equivalent to a.transpose(1,0)\narray([[  0,  4,  8],\n       [  1,  5,  9],\n       [  2,  6, 10],\n       [  3,  7, 11]])\n\u003e\n\u003e a.reshape(4,3)\narray([[  0,  1,  2],\n       [  3,  4,  5],\n       [  6,  7,  8],\n       [  9, 10, 11]])\n\u003e\n```\n\nSince `a` is matrix we may want its diagonal:\n```ts\n\u003e nj.diag(a)\narray([  0,  5, 10])\n\u003e\n```\n\n### Identity matrix\nThe identity array is a square array with ones on the main diagonal:\n\n```ts\n\u003e nj.identity(3)\narray([[ 1, 0, 0],\n       [ 0, 1, 0],\n       [ 0, 0, 1]])\n```\n\n### Concatenate different arrays\n\nSeveral arrays can be stacked together using `concatenate` function:\n\n```ts\n\u003e a = nj.arange(12).reshape(3,4)\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e\n\u003e b = nj.arange(3)\narray([ 0, 1, 2])\n\u003e\n\u003e nj.concatenate(a,b.reshape(3,1))\narray([[  0,  1,  2,  3,  0],\n       [  4,  5,  6,  7,  1],\n       [  8,  9, 10, 11,  2]])\n```\n\n__Notes__:\n - the arrays must have the same shape, except in the last dimension\n - arrays are concatenated along the last axis\n\nIt is still possible to concatenate along other dimensions using transpositions:\n\n```ts\n\u003e a = nj.arange(12).reshape(3,4)\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e\n\u003e b = nj.arange(4)\narray([ 0, 1, 2, 3])\n\u003e\n\u003e nj.concatenate(a.T,b.reshape(4,1)).T\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11],\n       [  0,  1,  2,  3]])\n```\n\n\n### Stack multiple arrays\n\n```ts\n\u003e a = nj.array([1, 2, 3])\n\u003e b = nj.array([2, 3, 4])\n\n\u003e nj.stack([a, b])\narray([[1, 2, 3],\n       [2, 3, 4]])\n\u003e nj.stack([a, b], -1)\narray([[1, 2],\n       [2, 3],\n       [3, 4]])\n```\n\n__Notes__:\n - the arrays must have the same shape\n - take an optional axis argument which can be negative\n\n### Deep Copy\nThe `clone` method makes a complete copy of the array and its data.\n\n```ts\n\u003e a = nj.arange(12).reshape(3,4)\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e\n\u003e b = a.clone()\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e\n\u003e a === b\nfalse\n\u003e\n\u003e a.set(0,0,1)\n\u003e a\narray([[  1,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n\u003e b\narray([[  0,  1,  2,  3],\n       [  4,  5,  6,  7],\n       [  8,  9, 10, 11]])\n```\n\n### Fast Fourier Transform (FFT)\n`fft` and `ifft` functions can be used to compute the N-dimensional discrete Fourier Transform and its inverse.\n\nExample:\n```ts\n\u003e RI = nj.concatenate(nj.ones([10,1]), nj.zeros([10,1]))\narray([[ 1, 0],\n       [ 1, 0],\n       [ 1, 0],\n        ...\n       [ 1, 0],\n       [ 1, 0],\n       [ 1, 0]])\n\u003e\n\u003e fft = nj.fft(RI)\narray([[ 10,  0],\n       [  0,  0],\n       [  0,  0],\n        ...\n       [  0,  0],\n       [  0,  0],\n       [  0,  0]])\n\u003e\n\u003e nj.ifft(fft)\narray([[ 1, 0],\n       [ 1, 0],\n       [ 1, 0],\n        ...\n       [ 1, 0],\n       [ 1, 0],\n       [ 1, 0]])\n```\n__Note__: both `fft` and `ifft` expect last dimension of the array to contain 2 values: the real and the imaginary value\n\n\n### Convolution\n\n`convolve` function compute the discrete, linear convolution of two multi-dimensional arrays.\n\n__Note__: The convolution product is only given for points where the signals overlap completely. Values outside the signal boundary have no effect. This behaviour is also known as the 'valid' mode.\n\n\nExample:\n```ts\n\u003e x = nj.array([0,0,1,2,1,0,0])\narray([ 0, 0, 1, 2, 1, 0, 0])\n\u003e\n\u003e nj.convolve(x, [-1,0,1])\narray([-1,-2, 0, 2, 1])\n\u003e\n\u003e const a = nj.arange(25).reshape(5,5)\n\u003e a\narray([[  0,  1,  2,  3,  4],\n       [  5,  6,  7,  8,  9],\n       [ 10, 11, 12, 13, 14],\n       [ 15, 16, 17, 18, 19],\n       [ 20, 21, 22, 23, 24]])\n\u003e nj.convolve(a, [[ 1, 2, 1], [ 0, 0, 0], [-1,-2,-1]])\narray([[ 40, 40, 40],\n       [ 40, 40, 40],\n       [ 40, 40, 40]])\n\u003e nj.convolve(nj.convolve(a, [[1, 2, 1]]), [[1],[0],[-1]])\narray([[ 40, 40, 40],\n       [ 40, 40, 40],\n       [ 40, 40, 40]])\n```\n\n__Note__: `convolve` uses Fast Fourier Transform (FFT) to speed up computation on large arrays.\n\n\n### Other utils\n`rot90`\n```ts\n\u003e m = nj.array([[1,2],[3,4]], 'int8')\n\u003e m\narray([[1, 2],\n       [3, 4]])\n\u003e nj.rot90(m)\narray([[2, 4],\n       [1, 3]])\n\u003e nj.rot90(m, 2)\narray([[4, 3],\n       [2, 1]])\n\u003e m = nj.arange(8).reshape([2,2,2])\n\u003e nj.rot90(m, 1, [1,2])\narray([[[1, 3],\n        [0, 2]],\n      [[5, 7],\n       [4, 6]]])\n```\n\n`mod` (since v0.16.0)\n```ts\n\u003e nj.mod(nj.arange(7), 5)\n\u003e m\narray([0, 1, 2, 3, 4, 0, 1])\n```\n\n## Documentation\n- [@d4c/numjs](https://grimmer0125.github.io/numjs/)\n    - [numjs module (nj) doc](https://grimmer0125.github.io/numjs/modules/)\n    - [NdArray doc](https://grimmer0125.github.io/numjs/classes/ndarray.NdArray.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrimmerk%2Fnumjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrimmerk%2Fnumjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrimmerk%2Fnumjs/lists"}