Skip to content

Commit 15814a7

Browse files
committed
v.1.2.0
* forEach(),toArray(),toNDArray() support row-major or column-major order * update tests
1 parent 2ff113d commit 15814a7

5 files changed

Lines changed: 94 additions & 40 deletions

File tree

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ View one-dimensional array data, typed array data and/or multi-dimensional array
44

55
![TensorView](/tensorview.jpg)
66

7-
version: **1.1.0** (9.7 kB minified)
7+
version: **1.2.0** (10 kB minified)
88

99
`TensorView` is both memory-efficient and speed-efficient since it only creates ways to view array data as multidimensional tensors **without** actually creating new arrays. One can nevertheless explicitly store a TensorView instance as a single-dimensional or multi-dimensional array using `view.toArray()` or `view.toNDArray()` methods.
1010

@@ -78,8 +78,8 @@ true
7878
const view = TensorView(data, options);
7979

8080
const data = view.data(); // underlying data of view
81-
const array = view.toArray(ArrayClass=Array); // create single-dimensional array or typed array from view
82-
const ndarray = view.toNDArray(); // create multi-dimensional array from view having the same shape
81+
const array = view.toArray(ArrayClass=Array, order="row-major"); // create single-dimensional array or typed array from view
82+
const ndarray = view.toNDArray(order="row-major"); // create multi-dimensional array from view having the same shape
8383
const string = view.toString(); // render view to string
8484
const dim = view.dimension(); // dimension of view, eg 1 for 1d, 2 for 2d, 3 for 3d, ..
8585
const shape = view.shape(); // shape of view along all dimensions
@@ -99,7 +99,7 @@ const value = view.get(indices); // get value based on indices of same dimension
9999
view.set(indices, value); // set value at indices
100100
// NOTE: underlying data will change in all views which use this data and all views which depend on views which use this data
101101

102-
view.forEach(function(data_i, i, data, view) {/*..*/}); // forEach method
102+
view.forEach(function(data_i, i, data, view) {/*..*/}, order="row-major"); // forEach method
103103
for (let [data_i, i] of view) {/*..*/} // similar as iterator protocol
104104

105105
view.op(op, otherView=null); // apply lazy, when requested, pointwise operation op(view, otherView) or op(view)

src/TensorView.js

Lines changed: 82 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* TensorView
33
* View array data as multidimensional tensors of various shapes efficiently
4-
* @VERSION 1.1.0
4+
* @VERSION 1.2.0
55
* https://github.com/foo123/TensorView
66
*
77
**/
@@ -356,12 +356,12 @@ function TensorView(data, o, _)
356356
set(index, indices, arguments[arguments.length-1]);
357357
return self;
358358
};
359-
self.iterator = function() {
360-
var i = 0 < length ? ndim - 1 : -1,
359+
self.iterator = function(order) {
360+
var i = 0 < length ? ("column-major" === order ? (0) : (ndim-1)) : -1,
361361
indices = null, ind = null, striding = null, index = 0,
362362
value = [null, null], ret = {value: null};
363363
return {next:function next() {
364-
if (0 > i)
364+
if ((0 > i) || (i >= ndim))
365365
{
366366
indices = ind = striding = ret = value = null;
367367
return {done: true};
@@ -372,49 +372,83 @@ function TensorView(data, o, _)
372372
{
373373
indices = (new Array(ndim)).fill(0);
374374
ind = indices.slice();
375-
striding = slicing.map(function(si,i) {return {start:si.start*stride[i], step:si.step*stride[i]};});
376-
index = compute_index(indices, ndim, is_transposed, shape, stride, size, slicing);
375+
striding = slicing.map(function(si, i) {return {start:si.start*stride[i], step:si.step*stride[i]};});
376+
index = compute_index(indices, ndim, "column-major" === order ? !is_transposed : is_transposed, shape, stride, size, slicing);
377377
value[0] = get(index, indices);
378378
value[1] = ind;
379379
ret.value = value;
380380
}
381381
else
382382
{
383-
while (i >= 0 && indices[i]+1 >= size[i])
383+
if ("column-major" === order)
384384
{
385-
index -= striding[i].start + indices[i] * striding[i].step;
386-
--i;
387-
}
388-
if (0 <= i)
389-
{
390-
++indices[i];
391-
ind[i] = indices[i];
392-
index += striding[i].step;
393-
while (i+1 < ndim)
385+
// column-major
386+
while ((i < ndim) && (indices[i]+1 >= size[i]))
394387
{
388+
index -= striding[i].start + indices[i] * striding[i].step;
395389
++i;
396-
indices[i] = 0;
397-
ind[i] = 0;
398-
index += striding[i].start;
399390
}
400-
value[0] = get(index, indices);
401-
value[1] = ind;
402-
ret.value = value;
391+
if (i < ndim)
392+
{
393+
++indices[i];
394+
ind[i] = indices[i];
395+
index += striding[i].step;
396+
while (0 <= i-1)
397+
{
398+
--i;
399+
indices[i] = 0;
400+
ind[i] = 0;
401+
index += striding[i].start;
402+
}
403+
value[0] = get(index, indices);
404+
value[1] = ind;
405+
ret.value = value;
406+
}
407+
else
408+
{
409+
indices = ind = striding = ret = value = null;
410+
return {done: true};
411+
}
403412
}
404413
else
405414
{
406-
indices = ind = striding = ret = value = null;
407-
return {done: true};
415+
// row-major
416+
while ((i >= 0) && (indices[i]+1 >= size[i]))
417+
{
418+
index -= striding[i].start + indices[i] * striding[i].step;
419+
--i;
420+
}
421+
if (0 <= i)
422+
{
423+
++indices[i];
424+
ind[i] = indices[i];
425+
index += striding[i].step;
426+
while (i+1 < ndim)
427+
{
428+
++i;
429+
indices[i] = 0;
430+
ind[i] = 0;
431+
index += striding[i].start;
432+
}
433+
value[0] = get(index, indices);
434+
value[1] = ind;
435+
ret.value = value;
436+
}
437+
else
438+
{
439+
indices = ind = striding = ret = value = null;
440+
return {done: true};
441+
}
408442
}
409443
}
410444
return ret;
411445
}
412446
}};
413447
};
414-
self.forEach = function(f) {
448+
self.forEach = function(f, order) {
415449
if (0 < length && is_function(f))
416450
{
417-
var iter = self.iterator(), next, ret = null;
451+
var iter = self.iterator(order || "row-major"), next, ret = null;
418452
while (true)
419453
{
420454
next = iter.next();
@@ -496,17 +530,31 @@ function TensorView(data, o, _)
496530
}
497531
);
498532
};
499-
self.toArray = function(ArrayClass) {
533+
self.toArray = function(ArrayClass, order) {
534+
if ("string" === typeof ArrayClass)
535+
{
536+
order = ArrayClass;
537+
ArrayClass = Array;
538+
}
500539
var array = new (ArrayClass || Array)(length), index = 0;
501540
self.forEach(function(di/*,i*/) {
502-
// put in row-major order
541+
// put in row-major or column-major order
503542
array[index++] = di;
504-
});
543+
}, order || "row-major");
505544
return array;
506545
};
507-
self.toNDArray = function() {
508-
var ndarray = ndim ? new Array(size[0]) : [];
509-
self.forEach(function(di, i) {
546+
self.toNDArray = function(order) {
547+
var ndarray = ndim ? new Array(size["column-major" === order ? ndim-1 : 0]) : [];
548+
self.forEach("column-major" === order ? function(di, i) {
549+
// put in column-major order
550+
for (var a=ndarray,n=ndim-1,j=n,ij; j>0; --j)
551+
{
552+
ij = i[j];
553+
if (null == a[ij]) a[ij] = new Array(size[j-1]);
554+
a = a[ij];
555+
}
556+
a[i[0]] = di;
557+
} : function(di, i) {
510558
// put in row-major order
511559
for (var a=ndarray,n=ndim-1,j=0,ij; j<n; ++j)
512560
{
@@ -515,7 +563,7 @@ function TensorView(data, o, _)
515563
a = a[ij];
516564
}
517565
a[i[n]] = di;
518-
});
566+
}, order || "row-major");
519567
return ndarray;
520568
};
521569
self.toString = function(maxsize) {
@@ -524,7 +572,7 @@ function TensorView(data, o, _)
524572
return 2 < ndim ? str_nd(ndarray, maxsize) : (2 === ndim ? str_2d(ndarray, maxsize) : str_1d(ndarray, maxsize));
525573
};
526574
}
527-
TensorView.VERSION = '1.1.0';
575+
TensorView.VERSION = '1.2.0';
528576
TensorView[proto] = {
529577
constructor: TensorView,
530578
dispose: null,

0 commit comments

Comments
 (0)