UNPKG

ziko

Version:

A versatile JavaScript library offering a rich set of Hyperscript Based UI components, advanced mathematical utilities, interactivity ,animations, client side routing and more ...

596 lines (589 loc) 20.5 kB
import { add, sub, mul, div, modulo } from '../functions/arithmetic/index.js' import { map, lerp, clamp, norm } from '../functions/utils/index.js' import { Complex } from "../complex/index.js"; import { arr2str } from "../../data/index.js"; import { matrix_inverse, matrix_det, hstack, vstack } from "./helpers/index.js"; class Matrix{ constructor(rows, cols, element = [] ) { if(rows instanceof Matrix){ this.arr=rows.arr; this.rows=rows.rows; this.cols=rows.cols; } else { let arr = [], i, j; if (arguments[0] instanceof Array) { rows = arguments[0].length; cols = arguments[0][0].length; arr = arguments[0]; } else { for (i = 0; i < rows; i++) { arr.push([]); arr[i].push(new Array(cols)); for (j = 0; j < cols; j++) { arr[i][j] = element[i * cols + j]; if (element[i * cols + j] == undefined) arr[i][j] = 0; } } } this.rows = rows; this.cols = cols; this.arr = arr; } this.#maintain(); } isMatrix(){ return true } clone() { return new Matrix(this.rows, this.cols, this.arr.flat(1)); } [Symbol.iterator]() { return this.arr[Symbol.iterator](); } #maintain() { for (let i = 0; i < this.arr.length; i++) { Object.defineProperty(this, i, { value: this.arr[i], writable: true, configurable: true, enumerable: false }); } } get size() { return this.rows * this.cols; } get shape() { return [this.rows, this.cols]; } toString(){ return arr2str(this.arr,false); } at(i = 0, j = undefined) { if (i < 0) i += this.rows; if (i < 0 || i >= this.rows) throw new Error('Row index out of bounds'); if (j === undefined) return this.arr[i]; if (j < 0) j += this.cols; if (j < 0 || j >= this.cols) throw new Error('Column index out of bounds'); return this.arr[i][j]; } slice(r0=0, c0=0, r1=this.rows-1, c1=this.cols-1) { let newRow = r1 - r0, newCol = c1 - c0; let newArr = new Array(newCol); for (let i = 0; i < newRow; i++) { newArr[i] = []; for (let j = 0; j < newCol; j++) newArr[i][j] = this.arr[i + r0][j + c0]; } return new Matrix(newRow, newCol, newArr.flat(1)); } static slice(m1,r0=0, c0=0, r1=this.rows-1, c1=this.cols-1) { return m1.slice(r0, c0, r1, c1); } reshape(newRows, newCols) { if(!(newRows * newCols === this.rows * this.cols)) throw Error('size not matched') return new Matrix(newRows, newCols, this.arr.flat(1)); } get T() { let transpose = []; for (let i = 0; i < this.arr[0].length; i++) { transpose[i] = []; for (let j = 0; j < this.arr.length; j++) transpose[i][j] = this.arr[j][i]; } return new Matrix(this.cols, this.rows, transpose.flat(1)); } get det() { return matrix_det(this) } get inv() { return matrix_inverse(this) } static eye(size) { let result = new Matrix(size, size); for (let i = 0; i < size; i++) for (let j = 0; j < size; j++) i === j ? (result.arr[i][j] = 1) : (result.arr[i][j] = 0); return result; } static zeros(rows, cols) { let result = new Matrix(rows, cols); for (let i = 0; i < rows; i++) for (var j = 0; j < cols; j++) result.arr[i][j] = 0; return result; } static ones(rows, cols) { let result = new Matrix(rows, cols); for (let i = 0; i < rows; i++) for (let j = 0; j < cols; j++) result.arr[i][j] = 1; return result; } static nums(rows, cols, number) { let result = new Matrix(rows, cols); for (let i = 0; i < rows; i++) for (let j = 0; j < cols; j++) result.arr[i][j] = number; return result; } hstack(...matrices) { const M=[this, ...matrices].reduce((a,b)=>hstack(a, b)); Object.assign(this, M); this.#maintain(); return this; } static hstack(matrix,...matrices) { return matrix.clone().hstack(...matrices); } vstack(...matrices){ const M=[this, ...matrices].reduce((a,b)=>vstack(a, b)); Object.assign(this, M); this.#maintain(); return this; } static vstack(matrix,...matrices) { return matrix.clone().vstack(...matrices); } hqueue(...matrices){ const M=[this, ...matrices].reverse().reduce((a,b)=>hstack(a, b)); Object.assign(this, M) return this; } static hqueue(matrix,...matrices) { return matrix.clone().hqueue(...matrices); } vqueue(...matrices){ const M=[this,...matrices].reverse().reduce((a, b)=>vstack(a, b)); Object.assign(this, M) return this; } static vqueue(matrix,...matrices) { return matrix.clone().vqueue(...matrices); } shuffle(){ this.arr = this.arr.sort(()=>0.5-Math.random()); return this; } static shuffle(M){ return M.clone().shuffle() } // get reel() { // return new Matrix(this.cols, this.rows, this.arr.flat(1).reel); // } // get imag() { // return new Matrix(this.cols, this.rows, this.arr.flat(1).imag); // } // Checkers get isSquare() { return this.rows === this.cols; } get isSym() { if (!this.isSquare) return false; for (let i = 0; i < this.rows; i++) { for (let j = i + 1; j < this.cols; j++) { if (this.arr[i][j] !== this.arr[j][i]) return false; } } return true; } get isAntiSym() { if (!this.isSquare) return false; const n = this.rows; for (let i = 0; i < n; i++) { if (this.arr[i][i] !== 0) return false; for (let j = i + 1; j < n; j++) { if (this.arr[i][j] !== -this.arr[j][i]) return false; } } return true; } get isDiag() { if (!this.isSquare) return false; const n = this.rows; for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { if (this.arr[i][j] !== 0 || this.arr[j][i] !== 0) return false; } } return true; } get isOrtho() { if (!this.isSquare) return false; return this.isDiag && (this.det == 1 || this.det == -1); } get isIdemp() { if (!this.isSquare) return false; const n = this.rows; const A = this.arr; // Compute A * A const MM = []; for (let i = 0; i < n; i++) { MM[i] = []; for (let j = 0; j < n; j++) { let sum = 0; for (let k = 0; k < n; k++) { sum += A[i][k] * A[k][j]; } MM[i][j] = sum; } } // Check if A * A == A for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { if (MM[i][j] !== A[i][j]) return false; } } return true; } get isUpperTri() { if (!this.isSquare) return false; const n = this.rows; for (let i = 1; i < n; i++) { for (let j = 0; j < i; j++) { if (this.arr[i][j] !== 0) return false; } } return true; } get isLowerTri() { if (!this.isSquare) return false; const n = this.rows; for (let i = 0; i < n - 1; i++) { for (let j = i + 1; j < n; j++) { if (this.arr[i][j] !== 0) return false; } } return true; } // static get rand(){ // return { // int:(rows, cols, a, b)=>{ // let result = new Matrix(rows, cols); // for (let i = 0; i < rows; i++) for (let j = 0; j < cols; j++) result.arr[i][j] = Random.randInt(a, b); // return result; // }, // bin:(rows,cols)=>{ // let result = new Matrix(rows, cols); // for (let i = 0; i < rows; i++) { // for (let j = 0; j < cols; j++) result.arr[i][j] = Random.randBin; // } // return result; // }, // hex:(rows,cols)=>{ // let result = new Matrix(rows, cols); // for (let i = 0; i < rows; i++) { // for (let j = 0; j < cols; j++) result.arr[i][j] = Random.randHex; // } // return result; // }, // choices:(rows, cols, choices, p)=>{ // let result = new Matrix(rows, cols); // for (let i = 0; i < rows; i++) for (let j = 0; j < cols; j++) result.arr[i][j] = Random.choice(choices, p); // return result // }, // permutation:(rows,cols,arr)=>{ // //return new Matrix(rows, cols, Random.permutation(...arr)) // } // } // } // static rands(rows, cols, a = 1, b) { // let result = new Matrix(rows, cols); // for (let i = 0; i < rows; i++) for (let j = 0; j < cols; j++) result.arr[i][j] = Random.rand(a, b); // return result; // } map(Imin, Imax, Fmin, Fmax) { this.arr = map(this.arr, Imin, Imax, Fmin, Fmax) return this; } lerp(min, max) { this.arr = lerp(this.arr, min, max) return this; } norm(min, max) { this.arr = norm(this.arr, min, max) return this; } clamp(min, max) { this.arr = clamp(this.arr, min, max) return this; } static map(M, Imin, Imax, Fmin, Fmax) { return M.clone().map(Imin, Imax, Fmin, Fmax) } static lerp(M, min, max) { return M.clone().lerp(min, max) } static norm(M, min, max) { return M.clone().norm(min, max) } static clamp(M, min, max) { return M.clone().clamp(min, max) } toPrecision(p) { for (let i = 0; i < this.cols; i++) for (let j = 0; j < this.rows; j++) this.arr[i][j] = +this.arr[i][j].toPrecision(p); return this; } // get toBin() { // let newArr = this.arr.flat(1).toBin; // return new Matrix(this.rows, this.cols, newArr); // } // get toOct() { // let newArr = this.arr.flat(1).toOct; // return new Matrix(this.rows, this.cols, newArr); // } // get toHex() { // let newArr = this.arr.flat(1).toHex; // return new Matrix(this.rows, this.cols, newArr); // } /*get isOdd() { let newArr = this.arr.flat(1).isOdd; return new Matrix(this.rows, this.cols, newArr); }*/ max2min() { let newArr = this.arr.flat(1).max2min; return new Matrix(this.rows, this.cols, newArr); } min2max() { let newArr = this.arr.flat(1).min2max; return new Matrix(this.rows, this.cols, newArr); } sortRows(calback=undefined){ let newArr=this.arr.map(n=>n.sort(calback)).flat(1); return new Matrix(this.rows, this.cols, newArr); } sortCols(calback=undefined){ let m=this.T; let newArr=m.arr.map(n=>n.sort(calback)).flat(1); return new Matrix(this.rows, this.cols, newArr).T; } filterByRows(item){ var truth=this.arr.map(n=>n.map(m=>+(""+m).includes(item))) var mask=truth.map(n=>!!Logic.or(...n)) var filtredArray=this.arr.filter((n,i)=>mask[i]===true) if(filtredArray.length===0)filtredArray.push([]) console.log(filtredArray) return new Matrix(filtredArray) } filterByCols(item){ return new Matrix(this.T.arr.filter(n=>n.includes(item))) } sortAll(calback=undefined){ let newArr=this.arr.flat(1).sort(calback); return new Matrix(this.rows, this.cols, newArr); } count(n) { return this.arr.flat(1).count(n); } // toBase(n) { // let newArr = this.arr.flat(1).toBase(n); // return new Matrix(this.rows, this.cols, newArr); // } splice(r0,c0,deleteCount,...items){ } getRows(ri, rf = ri + 1) { return this.slice(ri, 0, rf, this.cols); } getCols(ci, cf = ci + 1) { return this.slice(0, ci, this.rows, cf); } static getRows(m, ri, rf = ri + 1) { return m.slice(ri, 0, rf, m.cols); } static getCols(m, ci, cf = ci + 1) { return m.slice(0, ci, m.rows, cf); } add(...matr) { for (let k = 0; k < matr.length; k++) { if (typeof matr[k] == "number"||matr[k] instanceof Complex) matr[k] = Matrix.nums(this.rows, this.cols, matr[k]); for (let i = 0; i < this.rows; i++) for (var j = 0; j < this.cols; j++) this.arr[i][j] = add(this.arr[i][j],matr[k].arr[i][j]); } return new Matrix(this.rows, this.cols, this.arr.flat(1)); } sub(...matr) { for (let k = 0; k < matr.length; k++) { if (typeof matr[k] == "number") matr[k] = Matrix.nums(this.rows, this.cols, matr[k]); for (let i = 0; i < this.rows; i++) for (var j = 0; j < this.cols; j++) this.arr[i][j] = sub(this.arr[i][j],matr[k].arr[i][j]); } return new Matrix(this.rows, this.cols, this.arr.flat(1)); } static add(m1, ...m2) { return m1.clone().add(...m2); } static sub(m1, ...m2) { return m1.clone().sub(...m2); } mul(...matr) { for (let k = 0; k < matr.length; k++) { if (typeof matr[k] == "number") matr[k] = Matrix.nums(this.rows, this.cols, matr[k]); for (var i = 0; i < this.rows; i++) for (var j = 0; j < this.cols; j++) this.arr[i][j] = mul(this.arr[i][j],matr[k].arr[i][j]); } return new Matrix(this.rows, this.cols, this.arr.flat(1)); } div(...matr) { for (let k = 0; k < matr.length; k++) { if (typeof matr[k] == "number") matr[k] = Matrix.nums(this.rows, this.cols, matr[k]); for (let i = 0; i < this.rows; i++) for (var j = 0; j < this.cols; j++) this.arr[i][j] = div(this.arr[i][j],matr[k].arr[i][j]); } return new Matrix(this.rows, this.cols, this.arr.flat(1)); } static div(m1, ...m2) { return m1.clone().div(...m2); } static mul(m1, ...m2) { return m1.clone().mul(...m2); } modulo(...matr) { for (let k = 0; k < matr.length; k++) { if (typeof matr[k] == "number") matr[k] = Matrix.nums(this.rows, this.cols, matr[k]); for (let i = 0; i < this.rows; i++) for (var j = 0; j < this.cols; j++) this.arr[i][j]=modulo(this.arr[i][j],matr[k].arr[i][j]); } return new Matrix(this.rows, this.cols, this.arr.flat(1)); } static modulo(m1, ...m2) { return m1.clone().modulo(...m2); } dot(matrix) { var res = []; for (var i = 0; i < this.arr.length; i++) { res[i] = []; for (var j = 0; j < matrix.arr[0].length; j++) { res[i][j] = 0; for (var k = 0; k < this.arr[0].length; k++) { res[i][j] = add( res[i][j], mul(this.arr[i][k],matrix.arr[k][j]) ) } } } return new Matrix(this.arr.length, matrix.arr[0].length, res.flat(1)); } static dot(matrix1, matrix2) { return matrix1.dot(matrix2); } pow(n) { let a = this.clone(), p = this.clone(); for (let i = 0; i < n - 1; i++) p = p.dot(a); return p; } static pow(m, n) { return m.clone().pow(n); } get somme() { let S = 0; for (let i = 0; i < this.rows; i++) for (let j = 0; j < this.cols; j++) S += this.arr[i][j]; return S; } get hasComplex() { return this.arr.flat(Infinity).some((n) => n instanceof Complex); } get min() { if (this.hasComplex) console.error("Complex numbers are not comparable"); let minRow = []; for (let i = 0; i < this.rows; i++) minRow.push(min(...this.arr[i])); return min(...minRow); } get max() { if (this.hasComplex) console.error("Complex numbers are not comparable"); let maxRow = []; for (let i = 0; i < this.rows; i++) maxRow.push(max(...this.arr[i])); return max(...maxRow); } get minRows() { if (this.hasComplex) console.error("Complex numbers are not comparable"); let minRow = []; for (let i = 0; i < this.rows; i++) minRow.push(min(...this.arr[i])); return minRow; } get maxRows() { if (this.hasComplex) console.error("Complex numbers are not comparable"); let maxRow = []; for (let i = 0; i < this.rows; i++) maxRow.push(max(...this.arr[i])); return maxRow; } get minCols() { if (this.hasComplex) console.error("Complex numbers are not comparable"); return this.T.minRows; } get maxCols() { if (this.hasComplex) console.error("Complex numbers are not comparable"); return this.T.maxRows; } static fromVector(v) { return new Matrix(v.length, 1, v); } get toArray() { let arr = []; for (let i = 0; i < this.rows; i++) { for (let j = 0; j < this.cols; j++) { arr.push(this.arr[i][j]); } } return arr; } get serialize() { return JSON.stringify(this); } static deserialize(data) { if (typeof data == "string") data = JSON.parse(data); let matrix = new Matrix(data.rows, data.cols); matrix.arr = data.arr; return matrix; } sortTable(n=0,{type="num",order="asc"}={}) { var obj=this.T.arr.map(n=>n.map((n,i)=>Object.assign({},{x:n,y:i}))); var newObj=this.T.arr.map(n=>n.map((n,i)=>Object.assign({},{x:n,y:i}))); if(type==="num"){ if(order==="asc")obj[n].sort((a,b)=>a.x-b.x); else if(order==="desc")obj[n].sort((a,b)=>b.x-a.x); else if(order==="toggle"){ // console.log(obj[n][0]) //console.log(obj[n][1]) if(obj[n][0].x>obj[n][1].x)obj[n].sort((a,b)=>b.x-a.x); else obj[n].sort((a,b)=>a.x-b.x); } } else if(type==="alpha"){ if(order==="asc")obj[n].sort((a,b)=>(""+a.x).localeCompare(""+b.x)); else if(order==="desc")obj[n].sort((a,b)=>(""+b.x).localeCompare(""+a.x)); } //var order=obj[n].map(n=>n.y); order=obj[n].map(n=>n.y); for(let i=0;i<obj.length;i++){ if(i!==n)obj[i].map((n,j)=>n.y=order[j]); } for(let i=0;i<obj.length;i++){ if(i!==n)newObj[i].map((n,j)=>n.x=obj[i][order[j]].x) } newObj[n]=obj[n]; var newArr=newObj.map(n=>n.map(m=>m.x)); return new Matrix(newArr).T; } } /** * @returns {Matrix} */ const matrix=(r, c, element)=>new Matrix(r, c, element); const matrix2=(...element)=>new Matrix(2, 2, element); const matrix3=(...element)=>new Matrix(3, 3, element); const matrix4=(...element)=>new Matrix(4, 4, element); export{Matrix,matrix,matrix2,matrix3,matrix4}