@progress/kendo-charts
Version:
Kendo UI platform-independent Charts library
189 lines (166 loc) • 4.93 kB
JavaScript
// Based on the implementation from kendo-spreadsheet-common/src/calc.js
var Matrix = function Matrix() {
this.height = 0;
this.width = 0;
this.data = [];
};
Matrix.prototype.clone = function clone () {
var m = new Matrix();
m.height = this.height;
m.width = this.width;
m.data = this.data.map(function (row) { return row.slice(); });
return m;
};
Matrix.prototype.get = function get (row, col) {
var line = this.data[row];
var val = line ? line[col] : null;
return val;
};
Matrix.prototype.set = function set (row, col, data) {
var line = this.data[row];
if (line == null) {
line = this.data[row] = [];
}
line[col] = data;
if (row >= this.height) {
this.height = row + 1;
}
if (col >= this.width) {
this.width = col + 1;
}
};
Matrix.prototype.each = function each (f, includeEmpty) {
var this$1 = this;
for (var row = 0; row < this.height; ++row) {
for (var col = 0; col < this.width; ++col) {
var val = this$1.get(row, col);
if (includeEmpty || val != null) {
val = f(val, row, col);
if (val !== undefined) {
return val;
}
}
}
}
};
Matrix.prototype.map = function map (f, includeEmpty) {
var m = new Matrix();
this.each(function(el, row, col) {
m.set(row, col, f(el, row, col));
}, includeEmpty);
return m;
};
Matrix.prototype.transpose = function transpose () {
var m = new Matrix();
this.each(function(el, row, col) {
m.set(col, row, el);
});
return m;
};
Matrix.prototype.unit = function unit (n) {
this.width = this.height = n;
var a = this.data = new Array(n);
for (var i = n; --i >= 0;) {
var row = a[i] = new Array(n);
for (var j = n; --j >= 0;) {
row[j] = i === j ? 1 : 0;
}
}
return this;
};
Matrix.prototype.multiply = function multiply (b) {
var a = this;
var m = new Matrix();
for (var row = 0; row < a.height; ++row) {
for (var col = 0; col < b.width; ++col) {
var s = 0;
for (var i = 0; i < a.width; ++i) {
var va = a.get(row, i);
var vb = b.get(i, col);
if (typeof va === "number" && typeof vb === "number") {
s += va * vb;
}
}
m.set(row, col, s);
}
}
return m;
};
Matrix.prototype.inverse = function inverse () {
var n = this.width;
var m = this.augment(new Matrix().unit(n));
var a = m.data;
// Gaussian elimination
// https://en.wikipedia.org/wiki/Gaussian_elimination#Finding_the_inverse_of_a_matrix
// 1. Get zeros below main diagonal
var loop = function ( k ) {
var imax = argmax(k, n, function(i) { return a[i][k]; });
if (!a[imax][k]) {
return { v: null }; // singular matrix
}
if (k !== imax) {
var tmp = a[k];
a[k] = a[imax];
a[imax] = tmp;
}
for (var i = k + 1; i < n; ++i) {
for (var j = k + 1; j < 2 * n; ++j) {
a[i][j] -= a[k][j] * a[i][k] / a[k][k];
}
a[i][k] = 0;
}
};
for (var k = 0; k < n; ++k) {
var returned = loop( k );
if ( returned ) return returned.v;
}
// 2. Get 1-s on main diagonal, dividing by pivot
for (var i$1 = 0; i$1 < n; ++i$1) {
for (var f = a[i$1][i$1], j$1 = 0; j$1 < 2 * n; ++j$1) {
a[i$1][j$1] /= f;
}
}
// 3. Get zeros above main diagonal. Actually, we only care to compute the right side
// here (that will be the inverse), so in the inner loop below we go while j >= n,
// instead of j >= k.
for (var k$1 = n; --k$1 >= 0;) {
for (var i$2 = k$1; --i$2 >= 0;) {
if (a[i$2][k$1]) {
for (var j$2 = 2 * n; --j$2 >= n;) {
a[i$2][j$2] -= a[k$1][j$2] * a[i$2][k$1];
}
}
}
}
return m.slice(0, n, n, n);
};
Matrix.prototype.augment = function augment (m) {
var ret = this.clone();
var n = ret.width;
m.each(function(val, row, col) {
ret.set(row, col + n, val);
});
return ret;
};
Matrix.prototype.slice = function slice (row, col, height, width) {
var this$1 = this;
var m = new Matrix();
for (var i = 0; i < height; ++i) {
for (var j = 0; j < width; ++j) {
m.set(i, j, this$1.get(row + i, col + j));
}
}
return m;
};
function argmax(start, end, f) {
var max = f(start), pos = start;
for (var i = start + 1; i < end; i++) {
var v = f(start);
if (v > max) {
max = v;
pos = start;
}
}
return pos;
}
export default Matrix;