├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE ├── README.md ├── ndarray.js ├── package.json └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* 16 | *.DS_Store -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/* 16 | *.DS_Store 17 | test/* -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | - "0.10" 5 | before_install: 6 | - npm install -g npm@~1.4.6 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2013-2016 Mikola Lysenko 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ndarray 2 | ======= 3 | Modular multidimensional arrays for JavaScript. 4 | 5 | [![browser support](https://ci.testling.com/mikolalysenko/ndarray.png) 6 | ](https://ci.testling.com/mikolalysenko/ndarray) 7 | 8 | [![build status](https://secure.travis-ci.org/scijs/ndarray.png)](http://travis-ci.org/scijs/ndarray) 9 | 10 | [![stable](https://rawgithub.com/hughsk/stability-badges/master/dist/frozen.svg)](http://github.com/hughsk/stability-badges) 11 | 12 | ##### Browse a number of ndarray-compatible modules in the [scijs documentation](http://scijs.net/packages) 13 | ##### Coming from MATLAB or numpy? See: [scijs/ndarray for MATLAB users](https://github.com/scijs/scijs-ndarray-for-matlab-users) 14 | ##### [Big list of ndarray modules](https://github.com/scijs/ndarray/wiki/ndarray-module-list#core-module) 15 | 16 | Introduction 17 | ============ 18 | `ndarrays` provide higher dimensional views of 1D arrays. For example, here is how you can turn a length 4 typed array into an nd-array: 19 | 20 | ```javascript 21 | var mat = ndarray(new Float64Array([1, 0, 0, 1]), [2,2]) 22 | 23 | //Now: 24 | // 25 | // mat = 1 0 26 | // 0 1 27 | // 28 | ``` 29 | 30 | Once you have an nd-array you can access elements using `.set` and `.get`. For example, here is an implementation of [Conway's game of life](http://en.wikipedia.org/wiki/Conway's_Game_of_Life) using ndarrays: 31 | 32 | ```javascript 33 | function stepLife(next_state, cur_state) { 34 | 35 | //Get array shape 36 | var nx = cur_state.shape[0], 37 | ny = cur_state.shape[1] 38 | 39 | //Loop over all cells 40 | for(var i=1; iMath.abs(this.stride[1]))?[1,0]:[0,1]}})") 121 | } else if(dimension === 3) { 122 | code.push( 123 | "var s0=Math.abs(this.stride[0]),s1=Math.abs(this.stride[1]),s2=Math.abs(this.stride[2]);\ 124 | if(s0>s1){\ 125 | if(s1>s2){\ 126 | return [2,1,0];\ 127 | }else if(s0>s2){\ 128 | return [1,2,0];\ 129 | }else{\ 130 | return [1,0,2];\ 131 | }\ 132 | }else if(s0>s2){\ 133 | return [2,0,1];\ 134 | }else if(s2>s1){\ 135 | return [0,1,2];\ 136 | }else{\ 137 | return [0,2,1];\ 138 | }}})") 139 | } 140 | } else { 141 | code.push("ORDER})") 142 | } 143 | } 144 | 145 | //view.set(i0, ..., v): 146 | code.push( 147 | "proto.set=function "+className+"_set("+args.join(",")+",v){") 148 | if(useGetters) { 149 | code.push("return this.data.set("+index_str+",v)}") 150 | } else { 151 | code.push("return this.data["+index_str+"]=v}") 152 | } 153 | 154 | //view.get(i0, ...): 155 | code.push("proto.get=function "+className+"_get("+args.join(",")+"){") 156 | if(useGetters) { 157 | code.push("return this.data.get("+index_str+")}") 158 | } else { 159 | code.push("return this.data["+index_str+"]}") 160 | } 161 | 162 | //view.index: 163 | code.push( 164 | "proto.index=function "+className+"_index(", args.join(), "){return "+index_str+"}") 165 | 166 | //view.hi(): 167 | code.push("proto.hi=function "+className+"_hi("+args.join(",")+"){return new "+className+"(this.data,"+ 168 | indices.map(function(i) { 169 | return ["(typeof i",i,"!=='number'||i",i,"<0)?this.shape[", i, "]:i", i,"|0"].join("") 170 | }).join(",")+","+ 171 | indices.map(function(i) { 172 | return "this.stride["+i + "]" 173 | }).join(",")+",this.offset)}") 174 | 175 | //view.lo(): 176 | var a_vars = indices.map(function(i) { return "a"+i+"=this.shape["+i+"]" }) 177 | var c_vars = indices.map(function(i) { return "c"+i+"=this.stride["+i+"]" }) 178 | code.push("proto.lo=function "+className+"_lo("+args.join(",")+"){var b=this.offset,d=0,"+a_vars.join(",")+","+c_vars.join(",")) 179 | for(var i=0; i=0){\ 182 | d=i"+i+"|0;\ 183 | b+=c"+i+"*d;\ 184 | a"+i+"-=d}") 185 | } 186 | code.push("return new "+className+"(this.data,"+ 187 | indices.map(function(i) { 188 | return "a"+i 189 | }).join(",")+","+ 190 | indices.map(function(i) { 191 | return "c"+i 192 | }).join(",")+",b)}") 193 | 194 | //view.step(): 195 | code.push("proto.step=function "+className+"_step("+args.join(",")+"){var "+ 196 | indices.map(function(i) { 197 | return "a"+i+"=this.shape["+i+"]" 198 | }).join(",")+","+ 199 | indices.map(function(i) { 200 | return "b"+i+"=this.stride["+i+"]" 201 | }).join(",")+",c=this.offset,d=0,ceil=Math.ceil") 202 | for(var i=0; i=0){c=(c+this.stride["+i+"]*i"+i+")|0}else{a.push(this.shape["+i+"]);b.push(this.stride["+i+"])}") 238 | } 239 | code.push("var ctor=CTOR_LIST[a.length+1];return ctor(this.data,a,b,c)}") 240 | 241 | //Add return statement 242 | code.push("return function construct_"+className+"(data,shape,stride,offset){return new "+className+"(data,"+ 243 | indices.map(function(i) { 244 | return "shape["+i+"]" 245 | }).join(",")+","+ 246 | indices.map(function(i) { 247 | return "stride["+i+"]" 248 | }).join(",")+",offset)}") 249 | 250 | //Compile procedure 251 | var procedure = new Function("CTOR_LIST", "ORDER", code.join("\n")) 252 | return procedure(CACHED_CONSTRUCTORS[dtype], order) 253 | } 254 | 255 | function arrayDType(data) { 256 | if(isBuffer(data)) { 257 | return "buffer" 258 | } 259 | if(hasTypedArrays) { 260 | switch(Object.prototype.toString.call(data)) { 261 | case "[object Float64Array]": 262 | return "float64" 263 | case "[object Float32Array]": 264 | return "float32" 265 | case "[object Int8Array]": 266 | return "int8" 267 | case "[object Int16Array]": 268 | return "int16" 269 | case "[object Int32Array]": 270 | return "int32" 271 | case "[object Uint8Array]": 272 | return "uint8" 273 | case "[object Uint16Array]": 274 | return "uint16" 275 | case "[object Uint32Array]": 276 | return "uint32" 277 | case "[object Uint8ClampedArray]": 278 | return "uint8_clamped" 279 | case "[object BigInt64Array]": 280 | return "bigint64" 281 | case "[object BigUint64Array]": 282 | return "biguint64" 283 | } 284 | } 285 | if(Array.isArray(data)) { 286 | return "array" 287 | } 288 | return "generic" 289 | } 290 | 291 | var CACHED_CONSTRUCTORS = { 292 | "float32":[], 293 | "float64":[], 294 | "int8":[], 295 | "int16":[], 296 | "int32":[], 297 | "uint8":[], 298 | "uint16":[], 299 | "uint32":[], 300 | "array":[], 301 | "uint8_clamped":[], 302 | "bigint64": [], 303 | "biguint64": [], 304 | "buffer":[], 305 | "generic":[] 306 | } 307 | 308 | ;(function() { 309 | for(var id in CACHED_CONSTRUCTORS) { 310 | CACHED_CONSTRUCTORS[id].push(compileConstructor(id, -1)) 311 | } 312 | }); 313 | 314 | function wrappedNDArrayCtor(data, shape, stride, offset) { 315 | if(data === undefined) { 316 | var ctor = CACHED_CONSTRUCTORS.array[0] 317 | return ctor([]) 318 | } else if(typeof data === "number") { 319 | data = [data] 320 | } 321 | if(shape === undefined) { 322 | shape = [ data.length ] 323 | } 324 | var d = shape.length 325 | if(stride === undefined) { 326 | stride = new Array(d) 327 | for(var i=d-1, sz=1; i>=0; --i) { 328 | stride[i] = sz 329 | sz *= shape[i] 330 | } 331 | } 332 | if(offset === undefined) { 333 | offset = 0 334 | for(var i=0; i