UNPKG

@progress/kendo-charts

Version:

Kendo UI platform-independent Charts library

189 lines (166 loc) 4.93 kB
// 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;