js-num
Version:
It provides equivalent of Numpy in JavaScript.Optimized for generics.js
312 lines (273 loc) • 8.01 kB
JavaScript
var miscellaneous = require('./Miscellaneous');
var clone = require('matrix_deep_clone');
var elementMultiply = require('./ElementMultiply.js');
var complexMatrixOperations = function() {
function transpose(data) {
function stackColumns(data) {
var dim = miscellaneous.get_Dimensions(data);
var columns = dim[dim.length - 1];
var accessPattern = formPattern(data);
var newData = [];
for (var i = 0; i < columns; i++) {
var yak = [];
var counter = -1;
var temp = getColumns(data, i);
for (var v of accessPattern) {
yak[++counter] = temp[v];
}
newData = newData.concat(yak);
}
return newData;
}
function getColumns(data, index = 0) {
function innerGetColumns(inner_data, i) {
if (typeof(inner_data) == 'number' && i == index) {
newData[++counter] = inner_data;
} else {
for (var j in inner_data) {
innerGetColumns(inner_data[j], j);
}
}
}
var newData = [];
var counter = -1;
innerGetColumns(data, index);
return newData;
}
function formPattern(data) {
var lastAccessed = 0;
var counter = -1;
var temp = getColumns(data, 0);
var traverse = 0;
var yak = [];
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var columns = dim[dim.length - 1];
for (var k = 0; k < temp.length; k++) {
yak[++counter] = traverse;
traverse = traverse + rows;
if (traverse >= temp.length) {
traverse = lastAccessed + 1;
lastAccessed++;
}
}
return yak;
}
var finalData = stackColumns(data);
var dim = miscellaneous.get_Dimensions(data).reverse();
return miscellaneous.reshape(finalData, dim);
}
function findDeterminant(data) {
function isSquare(data) {
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var columns = dim[dim.length - 1];
if (rows == columns && dim.length == 2) {
return true;
} else {
return false;
}
}
function nCrossNDeterminant(data) {
function twoCrossTwoDeterminant(data) {
return (data[0][0] * data[1][1]) - (data[0][1] * data[1][0]);
}
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var column = dim[dim.length - 1];
if (rows == 2 && column == 2) {
return twoCrossTwoDeterminant(data)
} else {
var toOperate = data[0];
var yui = -1;
var timepass = [];
var ans = 0;
var sign = 1;
for (i in toOperate) {
// starting j from one since at zero toOperate data is there
var newData = [];
var tig = -1;
for (j = 1; j < data.length; j++) {
var temp = [];
var counter = -1;
var yak = data[j];
for (v in yak) {
if (v != i) {
temp[++counter] = yak[v];
} else {
}
}
newData[++tig] = temp;
}
ans = ans + sign * toOperate[i] * nCrossNDeterminant(newData);
sign = sign * -1;
timepass[i] = newData;
}
return ans;
}
}
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var columns = dim[dim.length - 1];
if (rows != columns) {
throw new Error("To calculate Determinant the matrix should be square");
} else {
var res = [];
var counter = -1;
function innerDeterminant(innerData) {
if (isSquare(innerData)) {
res[++counter] = nCrossNDeterminant(innerData);
} else {
for (i in innerData) {
innerDeterminant(innerData[i]);
}
}
}
innerDeterminant(data);
if (res.length == 1) {
return res[0];
} else {
var te = dim.slice(0, dim.length - 2);
if (te.length >= 2) {
return miscellaneous.reshape(res, te);
} else {
return res;
}
}
}
}
function generateIdentityMatrix(dim) {
var rowsNumber = dim[dim.length - 2];
var colNumber = dim[dim.length - 1];
function create2DMatrix(rows, columns) {
var res = [];
for (var i = 0; i < rows; i++) {
var temp = [];
for (var j = 0; j < columns; j++) {
if (i == j) {
temp[j] = 1;
} else {
temp[j] = 0;
}
}
res[i] = temp;
}
return res;
}
if (rowsNumber != colNumber) {
throw new Error("The dimensions should be square dimension");
} else {
if (dim.length == 2) {
return create2DMatrix(rowsNumber, colNumber);
} else {
// it is a higher dimension matrix
var res = [];
var subset = dim.slice(0, dim.length - 2);
for (var i = 0; i < subset.length; i++) {
var temp = [];
for (var j = 0; j < subset[subset.length - 1 - i]; j++) {
if (i == 0) {
temp[j] = create2DMatrix(rowsNumber, colNumber)
}
}
if (i == 0) {
res[i] = temp;
} else {
res[i] = clone.deepCloneMatrix(res[i - 1]);
}
}
if (res.length == 1) {
return res[0];
} else {
return res;
}
}
}
}
function matrixInverse(data) {
function findAdjoint(data) {
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var column = dim[dim.length - 1];
var ansToSave = [];
var yui = -1;
var timepass = [];
var ans = [];
var sign = 1;
for (k in data) {
var toOperate = clone.deepCloneMatrix(data[k]);
for (i in toOperate) {
sign = Math.pow(-1, Number(k) + Number(i));
var newData = [];
var tig = -1;
for (j = 0; j < data.length; j++) {
if (j != k) {
var temp = [];
var counter = -1;
var yak = data[j];
for (v in yak) {
if (v != i) {
temp[++counter] = yak[v];
}
}
newData[++tig] = temp;
}
}
toOperate[i] = sign * findDeterminant(newData);
}
ansToSave[k] = toOperate;
}
return transpose(ansToSave);
}
function isSquare(data) {
var dim = miscellaneous.get_Dimensions(data);
var rows = dim[dim.length - 2];
var columns = dim[dim.length - 1];
if (rows == columns && dim.length == 2) {
return true;
}
return false;
}
function findInverse(data) {
if (findDeterminant(data) == 0) {
throw new Error("Determinant has to be non Zero");
}
var res = elementMultiply.ElementMultiply(findAdjoint(data), 1 / findDeterminant(data));
var dim = miscellaneous.get_Dimensions(res);
var rows = dim[dim.length - 2];
var columns = dim[dim.length - 1];
for (var i = 0; i < rows; i++) {
for (var j = 0; j < columns; j++) {
if (res[i][j] == -0) {
res[i][j] = 0;
}
}
}
return res;
}
function innerMatrixInverse(data) {
if (isSquare(data)) {
res[++counter] = findInverse(data);
} else {
for (i in data) {
innerMatrixInverse(data[i]);
}
}
}
var res = [];
var counter = -1;
innerMatrixInverse(data);
if (res.length == 1) {
return res[0];
} else {
return res;
}
}
return {
transpose: transpose,
findDeterminant: findDeterminant,
generateIdentityMatrix: generateIdentityMatrix,
matrixInverse: matrixInverse
}
}
module.exports = complexMatrixOperations();