const Matrix = ( function(){
const padRight = ( num, len ) => {
let str = num.toString();
if( str.length >= ( num >= 0 ? len - 1 : length ) ){
return str;
}
return str + repeat( ' ', len - str.length - Number( num >= 0 ) );
},
{ ceil, round } = Math,
{ defineProperty } = Object,
somethinghacky = ''.repeat.
repeat = ( string, times ) => somethinghacky.call( string, ceil( times ) ).slice( 0, round( times * string.length ) );
/**
* A matrix class, allows you to visualize multiple dimensions.
* @class
* @extends Array
*/
class Matrix extends Array {
/**
* Constructs a new array.
* @param {number} height The number of rows in the matrix.
* @param {number} width The number of collumns in the matrix.
* @constructs Matrix
*/
constructor( height, width ) {
super( height );
defineProperty( this, '__width__', {
value: width,
protected: true
} );
defineProperty( this, '__height__', {
value: height,
protected: true
} );
for( let i = 0; i < this.length; i++ ) {
let item = Array( width ).fill( 0 );
this[i] = item;
}
}
/**
* Invert the matrix.
* @param {Matrix} a The matrix to invert.
* @returns {Matrix} The inverted matrix.
* @throws {Error} You either fed it a non-square matrix, or something else went wrong.
*/
static invert( a ) {
if( a.__width__ !== a.__height__ ){
throw Error( 'Must be a square matrix.' );
}
let res = new Matrix( a.__height__, a.__width__ ),
copy = new Matrix( a.__height__, a.__width__ ),
e = 0, t = 0;
for( let i = 0, height = a.__height__; i < height; i++ ){
for( let j = 0, width = a.__width__; j < width; j++ ){
//if we're on the diagonal, put a 1 (for identity)
if( i == j ){
res[i][j] = 1;
}
copy[i][j] = a[i][j];
}
}
for( let i = 0, height = a.__height__; i < height; i++ ){
e = copy[i][i];
if( e === 0 ){
for( let ii = i + 1; ii < height; ii++ ){
if( copy[ii][i] != 0 ){
for( let j = 0, width = a.__width__; j < width; j++ ){
e = copy[i][j]; //temp store i'th row
copy[i][j] = copy[ii][j]; //replace i'th row by ii'th
copy[ii][j] = e; //repace ii'th by temp
e = res[i][j]; //temp store i'th row
res[i][j] = res[ii][j]; //replace i'th row by ii'th
res[ii][j] = e; //repace ii'th by temp
}
break;
}
}
e = copy[i][i];
if( e == 0 ){
throw Error( 'something went wrong' );
}
}
for( let j = 0, width = a.__width__; j < width; j++ ){
copy[i][j] = copy[i][j] / e; //apply to original matrix
res[i][j] = res[i][j] / e; //apply to identity
}
for( let ii = 0, height = a.__height__; ii < height; ii++ ){
if( ii === i ){
continue;
}
e = copy[ii][i];
for( let j = 0, width = a.__width__; j < width; j++ ){
copy[ii][j] -= e * copy[i][j]; //apply to original matrix
res[ii][j] -= e * res[i][j]; //apply to identity
}
}
}
return res;
}
static product( a, b ) {
if( a.__width__ !== b.__height__ ) {
throw Error( 'The number of collumns in `a` must be the same as the number of rows in `b`' );
}
let res = new Matrix( a.__height__, b.__width__ );
for( let i = 0, height = a.__height__; i < height; i++ ) {
for( let j = 0, width = b.__width__; j < width; j++ ) {
res[i][j] = a[i].reduce( ( a,b )=>{return a + b;},0 ) * b.getCollumn( j + 1 ).reduce( ( a,b )=>{return a + b;}, 0 );
}
}
return res;
}
static entrywiseSum( a, b ) {
if( a.__height__ !== b.__height || a.__width__ !== b.__width__ ) {
throw Error( 'The two matrices must have the same dimensions.' );
}
let res = new Matrix( a.__height__, a.__width__ );
for( let i = 0, hieght = a.__height__; i < height; i++ ) {
for( let j = 0, width = a.__width__; j < width; j++ ) {
res[i][j] = a[i][j] + b[i][j];
}
}
}
static directSum( a, b ) {
let res = new Matrix( a.__height__ + b.__height__, a.__width__ + b.__width__ );
for( let i = 0, height = a.__height__; i < height; i++ ) {
for( let j = 0, width = a.__width__; j < width; j++ ) {
res[i][j] = a[i][j];
}
}
for( let i = 0, height = b.__height__; i < height; i++ ) {
for( let j = 0, width = b.__width__; j < width; j++ ) {
res[i + a.__height__][j + a.__width__] = b[i][j];
}
}
return res;
}
getRow( rowNum ) {
return this[rowNum - 1];
}
print() {
let str = '[',
maxLen = this.reduce( ( ret, item )=>{let len = item.reduce( ( a,b )=>{return b.toString().length > a ? b.toString().length : a;}, 0 ); return len > ret ? len : ret; }, 0 );
this.forEach( ( item, _ ) => {
let res = ( _ ? ', ' : '' ) + '\n [';
item.forEach( ( num, index )=>{
res += ( index ? ', ' : ' ' ) + ( num >= 0 ? ' ' : '' ) + padRight( num, maxLen ) + ' ';
} );
res += ']';
str += res;
} );
return str + '\n]';
}
getCollumn( collumnNum ) {
return this.map( ( item )=>item[collumnNum - 1] );
}
}
return Matrix;
} )();
if ( ( 0, eval )( 'this' ).XtraUtils && ( 0, eval )( 'this' ).XtraUtils.Utility ) {
XtraUtils.Matrix = new XtraUtils.Utility( Matrix );
} else {
console.warn( 'XtraUtils is not defined. For more details, please visit ' +
'https://github.com/FreezePhoenix/XtraUtils/. If your issue still occurs, submit an issue here:' +
'https://github.com/FreezePhoenix/XtraUtils/issues/new' );
}