├── README.md
├── examples
└── index.js
└── package.json
/README.md:
--------------------------------------------------------------------------------
1 | # scijs/ndarray for MATLAB users
2 |
3 | > Common [scijs/ndarray](https://github.com/scijs/ndarray) operations for people familar with MATLAB (or at least not familiar with [scijs](https://github.com/scijs))
4 |
5 | ## Introduction
6 |
7 | This document is a work in progress! Inspired by [Numpy for Matlab users](https://docs.scipy.org/doc/numpy-dev/user/numpy-for-matlab-users.html), it aspires to be [NumPy for MATLAB users](http://mathesaurus.sourceforge.net/matlab-numpy.html). The intent is both to communicate what is possible in JavaScript using scijs and to illuminate which parts still need work. I'll be mostly offline until the new year so I may not respond immediately, but comments, question and pull requests are more than welcome.
8 |
9 | ## Memory Management
10 |
11 | First things first, ndarrays are similar to but different to work with than MATLAB arrays. To get a sense for how managing ndarrays differs from managing MATLAB arrays, consider the diagonal of a 5×5 matrix:
12 |
13 | ```javascript
14 | var pool = require('ndarray-scratch')
15 | var diag = require('ndarray-diagonal')
16 |
17 | // A 5x5 matrix of ones:
18 | var a = pool.ones([5,5])
19 |
20 | // A view of the diagonal of a:
21 | var x = diag(a)
22 | ```
23 |
24 | Even though they have different dimensionality and shape, the internal data contained in ndarray `x` is identical by reference to that in `a`. The difference is that the strides and offsets of `x` are set to select only the diagonal elements of `a`. To see this directly, note the data of `x` still has 25 numbers even though it's shape is a vector of length 5:
25 |
26 | ```javascript
27 | console.log(x)
28 | // => View1dfloat64 {
29 | // data:
30 | // Float64Array {'0': 1, '1': 1, '2': 1, ..., '22': 1, '23': 1, '24': 1 },
31 | // shape: [ 5 ],
32 | // stride: [ 6 ],
33 | // offset: 0 }
34 | ```
35 |
36 | Cloning simplifies the representation by allocating new storage and copying only the elements exposed by view `x`:
37 |
38 | ```javascript
39 | console.log(pool.clone(x))
40 | // => View1dfloat64 {
41 | // data: Float64Array { '0': 1, '1': 1, '2': 1, '3': 1, '4': 1 },
42 | // shape: [ 5 ],
43 | // stride: [ 1 ],
44 | // offset: 0 }
45 | ```
46 |
47 | As a result, a nice advantage of ndarrays the ability to manipulate representations without the need to iterate directly or allocate additional storage (beyond the lightweight ndarray wrapper). The example below uses in-place operations of [ndarray-ops](https://github.com/scijs/ndarray-ops) to assign the scalar 3 to the diagonal and double the first two columns of `a`:
48 |
49 | ```javascript
50 | var ops = require('ndarray-ops')
51 | var show = require('ndarray-show')
52 |
53 | // Set each element of the diagonal of a (5x5 matrix of ones) to 3:
54 | ops.assigns(diag(a, 3))
55 |
56 | // Double the first two columns:
57 | ops.mulseq(a.hi(null,2))
58 |
59 | console.log(show(a))
60 | // => 6.000 2.000 1.000 1.000 1.000
61 | // 2.000 6.000 1.000 1.000 1.000
62 | // 2.000 2.000 3.000 1.000 1.000
63 | // 2.000 2.000 1.000 3.000 1.000
64 | // 2.000 2.000 1.000 1.000 3.000
65 | ```
66 |
67 | ## Operations
68 |
69 | The table below collects common matlab operations as well as their ndarray analogs. Not all operations have a counterpart, some because of features and shortcomings of the JavaScript language, some because of differences in memory management, and some because they're simply not yet implemented.
70 |
71 | MATLAB | JavaScript | Notes
72 | :-----------------|:--------------------|:---------------
73 | `ndims(a)` | [`a.dimension`](https://github.com/scijs/ndarray#arraydimension) | get the number of dimensions of `a`
74 | `numel(a)` | [`a.size`](https://github.com/scijs/ndarray#arraysize) | get the number of elements of an arary
75 | `size(a)` | [`a.shape`](https://github.com/scijs/ndarray#members) | get the size of the array
76 | `size(a,n)` | [`a.shape`](https://github.com/scijs/ndarray#members)`[n-1]` | get the number of elements of the n-th dimension of array `a`
77 | `[1 2 3; 4 5 6 ]` | [`ndarray`](https://github.com/scijs/ndarray#constructor)`([1,2,3,4,5,6],[2,3])` | 2×3 matrix literal (using `Array` type)
78 | | [`ndarray`](https://github.com/scijs/ndarray#constructor)`(new Float64Array([1,2,3,4,5,6]),[2,3])` | 2×3 matrix literal (using 64-bit typed array)
79 | | [`pack`](https://github.com/scijs/ndarray-pack)`([[1,2,3],[4,5,6]])` | 2×3 matrix literal from nested array
80 | `a(end)` | [`a.get`](https://github.com/scijs/ndarray#arraygetij)`(a.shape[0]-1)` | access last element in the 1×n matrix `a`
81 | `a(2, 5)` | [`a.get`](https://github.com/scijs/ndarray#arraygetij)`(1, 4)` | access element in second row, fifth column
82 | `a(2, :)` | [`a.pick`](https://github.com/scijs/ndarray#arraypickp0-p1-)`(1, null)` | entire second row of `a`
83 | `a(1:5, :)` | [`a.hi`](https://github.com/scijs/ndarray#arrayhiijk)`(5, null)` | the first five rows of `a`
84 | `a(end-4:end, :)` | [`a.lo`](https://github.com/scijs/ndarray#arrayloijk)`(a.shape[0]-5, null)` | the last five rows of `a`
85 | `a(1:3, 5:9)` | [`a.hi`](https://github.com/scijs/ndarray#arrayhiijk)`(3, 9).lo(0, 4)` | rows one to three and columns five to nine of `a`
86 | `a([2, 4, 5], [1, 3])`| | rows 2, 4, and 5 and columns 1 and 3.
87 | `a(3:2:21, :)` | [`a.hi`](https://github.com/scijs/ndarray#arrayhiijk)`(21, null).`[`lo`](https://github.com/scijs/ndarray#arrayloijk)`(2, null).`[`step`](https://github.com/scijs/ndarray#arraystepijk)`(2, 1)` | every other row of `a`, starting with the third and going to the twenty-first
88 | `a(1:2:end, :)` | [`a.step`](https://github.com/scijs/ndarray#arraystepijk)`(2, 1)` | every other row of `a`, starting with the first
89 | `a(end:-1:1, :)` or `flipup(a)` | [`a.step`](https://github.com/scijs/ndarray#arraystepijk)`(-1, 1)` | `a` with rows in reverse order
90 | `a([1:end 1], :)` | | `a` with copy of the first rows appended to the end
91 | `a.'` | [`a.transpose`](https://github.com/scijs/ndarray#arraytransposep0-p1-)`(1, 0)` | transpose of `a`
92 | `a'` | | conjugate transpose of `a`
93 | `c = a * b` | [`gemm`](https://github.com/scijs/ndarray-gemm)`(c, a, b)`| matrix multiply
94 | `c = a + b` | [`ops.add`](https://github.com/scijs/ndarray-ops)`(c, a, b)` | matrix addition
95 | `c = a + 2` | [`ops.adds`](https://github.com/scijs/ndarray-ops)`(c, a, 2)` | matrix + scalar addition
96 | `a += b` (not available in MATLAB) | [`ops.addeq`](https://github.com/scijs/ndarray-ops)`(a, b)` | in-place matrix addition
97 | `c = a .* b` | [`ops.mul`](https://github.com/scijs/ndarray-ops)`(c, a, b)` | element-wise multiply
98 | `a = a .* b` | [`ops.muleq`](https://github.com/scijs/ndarray-ops)`(a, b)` | element-wise multiply (in-place)
99 | `c = a ./ b` | [`ops.div`](https://github.com/scijs/ndarray-ops)`(c, a, b) ` | element-wise division
100 | `a = a ./ b` | [`ops.diveq`](https://github.com/scijs/ndarray-ops)`(a, b)` | element-wise division (in-place)
101 | `a.^3` | [`ops.pows`](https://github.com/scijs/ndarray-ops)`(a, 3)` | element-wise scalar exponentiation
102 | `(a>0.5)` | | matrix whose i,jth element is (a\_ij > 0.5)
103 | `find(a>0.5)` | | find the indices where (a > 0.5)
104 | `a(:, find(v>0.5))`| | extract the columns of a where vector v > 0.5
105 | `a(a<0.5)=0` | | `a` with elements less than 0.5 zeroed out
106 | `a .* (a>0.5)` | | `a` with elements less than 0.5 zeroed out
107 | `a(:) = 3` | [`ops.assigns`](https://github.com/scijs/ndarray-ops)`(a, 3)` | set all values to the same scalar value
108 | `y = x` | `y =`[`pool.clone`](https://www.npmjs.com/package/ndarray-scratch#pool-clone-array)`(x)` | clone by value
109 | `y = x(2, :)` | `y = x.pick(1, null)`| slices are by reference
110 | `1:10` | | create an increasing vector
111 | `0:9` | | create an increasing vector
112 | `zeros(3, 4)` | [`pool.zeros`](https://github.com/scijs/ndarray-scratch#poolzerosshapedtype)`([3, 4], 'float64')` | 3×4 rand-2 array full of 64-bit floating point zeros
113 | `zeros(3, 4, 5)` | [`pool.zeros`](https://github.com/scijs/ndarray-scratchpoolzerosshapedtype)`([3, 4, 5], 'float64')` | 3×4×5 rank-3 array full of 64-bit floating point zeros
114 | `ones(3, 4)` | [`pool.ones`](https://github.com/scijs/ndarray-scratch#poolonesshapedtype)`([3, 4], 'float64')` | 3×4 rank-2 array full of 64-bit floating point ones
115 | `eye(3)` | [`pool.eye`](https://github.com/scijs/ndarray-scratch#pooleyeshapedtype)`([3, 3], 'float64')` | 3×3 identity matrix with 64-bit floating point precision
116 | `diag(a)` | [`diag`](https://github.com/scijs/ndarray-diagonal)`(a)`| vector of diagonal elements of `a` (returns diagonal by reference)
117 | `diag(a, 0)` | `b = `[`pool.zeros`](https://github.com/scijs/ndarray-scratch)`(a.shape)`
[`ops.assign`](https://github.com/scijs/ndarray-ops)`(`[`diag`](https://github.com/scijs/ndarray-diagonal)`(b), `[`diag`](https://github.com/scijs/ndarray-diagonal)`(a))` | square diagonal matrix whose nonzero values are the elements of a
118 | `rand(3, 4)` | [`fill`](https://www.npmjs.com/package/ndarray-fill)`(`[`pool.zeros`](https://github.com/scijs/ndarray-scratch#poolmallocshape-dtype)`([3, 4]), Math.random)` | random 3×4 matrix
119 | `linspace(1, 3, 4)` | [`linspace`](https://github.com/scijs/ndarray-linspace)`(1, 3, 4)` | 4 equally spaced samples between 1 and 3, inclusive
120 | `[x, y] = meshgrid(0:8, 0:5)` | | two 2D arrays: one of x values, one of y values
121 | `[x, y] = meshgrid([1, 2, 4], [2, 4, 5])` | |
122 | `repmat(a, m, n)` | [`tile`](https://github.com/scijs/ndarray-tile)`(a, [m, n])`| create m×n copies of `a`
123 | `[a b]` | [`concatCols`](https://github.com/scijs/ndarray-concat-cols)`([a, b])` | concatenate columns of `a` and `b`
124 | `[a; b]` | [`concatRows`](https://github.com/scijs/ndarray-concat-rows)`([a, b])` | concatenate rows of `a` and `b`
125 | `max(max(a))` | | maximum element of `a`
126 | `max(a)` | [`ops.max`](https://github.com/scijs/ndarray-ops#map-reduce-aggregate-operators)`(a)` | maximum element in `a`
127 | `norm(v)` | [`ops.norm2`](https://github.com/scijs/ndarray-ops#map-reduce-aggregate-operators)`(v)` | L2 norm of vector `v`
128 | `c = a & b` | [`ops.band`](https://github.com/scijs/ndarray-ops#conventions)`(c, a, b)` | element-by-element AND operator
129 | c = a | b
| [`ops.bor`](https://github.com/scijs/ndarray-ops#conventions)`(c, a, b)` | element-by-element OR operator
130 | `inv(a)` | | inverse of square matrix `a`
131 | `pinv(a)` | | pseudo-inverse of matrix `a`
132 | `rank(a)` | | rank of matrix `a`
133 | `a\b` | [`lup`](https://github.com/scijs/ndarray-lup-factorization)`(a, a, P)`
[`solve`](https://github.com/scijs/ndarray-lup-solve)`(a, a, P, b)` | solution of `a x = b` for `x`
134 | `b/a` | | solution of `x a = b` for `x`
135 | `chol(a)` | [`chol`](https://github.com/scijs/ndarray-cholesky-factorization)`(a, L)` | cholesky factorization of matrix
136 | `[V, D] = eig(a)` | | eigenvalues and eigenvectors of `a`
137 | `[V, D] = eig(a, b)` | | eigenvalues and eigenvectors of `a`, `b`
138 | `[Q, R, P] = qr(a, 0)` | [`qr.factor`](https://github.com/scijs/ndarray-householder-qr#usage)`(A, d)`
[`qr.constructQ`](https://github.com/scijs/ndarray-householder-qr#usage)`(A, Q)` | QR decomposition. (Depending on the use, you can likely use Q without constructing explicitly. [See documentation](https://github.com/scijs/ndarray-householder-qr#usage).)
139 | `[L, U, P] = lu(a)` | [`lup`](https://github.com/scijs/ndarray-lup-factorization#requirendarray-lup-factorization-a-l-p-)`(A, L, P)` | LU decomposition
140 | `fft(a)` | [`fft`](https://github.com/scijs/ndarray-fft#requirendarray-fftdir-x-y)`(1, ar, ai)` | Fourier transform of `a`. Javascript does not have a complex type so real and imaginary parts must be passed separately.
141 | `ifft(a)` | [`fft`](https://github.com/scijs/ndarray-fft#requirendarray-fftdir-x-y)`(-1, ar, ai)`| inverse Fourier transform of `a`
142 | `[b, I] = sortrows(a, i)` | [`sort`](https://github.com/scijs/ndarray-sort)`(a)` | sort the rows of the matrix
143 | | [`sort`](https://github.com/scijs/ndarray-sort)`(a.transpose(1, 0))` | sort the column of the matrix
144 | `regress(y, X)` | [`qr.factor`](https://github.com/scijs/ndarray-householder-qr#factor-a-d-)`( A, d );`
[`qr.solve`](https://github.com/scijs/ndarray-householder-qr#solve-a-d-x-)`( A, d, y );` | multilinear regression
145 | `decimate(x, q)` | [`resample`](https://github.com/scijs/ndarray-resample)`(output, input)` | downsample with low-pass filtering ([`resample`](https://github.com/scijs/ndarray-resample) downsamples by a factor of two)
146 | `unique` | |
147 | `squeeze(a)` | [`squeeze`]()`(a)` | Remove singleton dimensions of `a`
148 |
149 |
150 | ## License
151 |
152 | © 2015 Ricky Reusser. MIT License.
153 |
--------------------------------------------------------------------------------
/examples/index.js:
--------------------------------------------------------------------------------
1 | var ndarray = require('ndarray')
2 | var show = require('ndarray-show')
3 | var iota = require('iota-array')
4 | var diag = require('ndarray-diagonal')
5 | var fill = require('ndarray-fill')
6 | var ops = require('ndarray-ops')
7 | var pool = require('ndarray-scratch')
8 |
9 | var a = ndarray(new Float64Array([1,2,3,4,5,6]),[2,3])
10 |
11 | console.log('a =\n'+show(a))
12 | console.log('\na.dimension = ',a.dimension)
13 |
14 | console.log('a.size =', a.size)
15 | console.log('a.shape =',a.shape)
16 | console.log('a.shape[0] =',a.shape[0])
17 | console.log('a.shape[1] =',a.shape[1])
18 | console.log('\na[:,:-1:]=\n'+show(a.step(-1,1)))
19 |
20 | var b = ndarray(new Float64Array([1,2,3,4,5,6]))
21 | console.log('\nb ='+show(b))
22 | console.log('\nb[-1] =',b.get(b.shape[0]-1))
23 |
24 |
25 | var c = ndarray(iota(56), [8,7])
26 | console.log('\nc =\n'+show(c))
27 |
28 | console.log('\nfirst five rows of c =\n'+show(c.hi(5,null)))
29 | console.log('\nlast five rows of c =\n'+show(c.lo(c.shape[0]-5,null)))
30 | console.log('\nrows one to three and columns five to seven =\n'+show(c.hi(3,7).lo(0,4)))
31 |
32 |
33 | var d = pool.ones([5,5])
34 |
35 | ops.assigns(diag(d),2)
36 | ops.mulseq(d.hi(null,2),2)
37 |
38 | console.log(show(d))
39 |
40 |
41 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "scijs-ndarray-for-matlab-users",
3 | "version": "0.1.0",
4 | "description": "Common scijs/ndarray operations for people familar with MATLAB (or at least not familiar with scijs)",
5 | "main": "index.js",
6 | "directories": {
7 | "example": "examples"
8 | },
9 | "scripts": {
10 | "test": "echo \"Error: no test specified\" && exit 1"
11 | },
12 | "author": "",
13 | "license": "MIT",
14 | "dependencies": {
15 | "iota-array": "^1.0.0",
16 | "ndarray": "^1.0.18",
17 | "ndarray-diagonal": "^1.0.0",
18 | "ndarray-fill": "^1.0.1",
19 | "ndarray-ops": "^1.2.2",
20 | "ndarray-scratch": "^1.2.0",
21 | "ndarray-show": "^2.0.0"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------