UNPKG

ziko

Version:

a versatile javaScript framework offering a rich set of UI components, advanced mathematical utilities, reactivity, animations, client side routing and graphics capabilities

677 lines (674 loc) 24.3 kB
import ZikoMath from "../absract.js"; import{ pow, min, max, } from "../functions/index.js" import {Utils} from "../utils/index.js"; import {Complex } from "../complex/index.js"; import {Random} from "../random/index.js" import { arr2str } from "../../data/index.js"; class Matrix extends ZikoMath{ constructor(rows, cols, element = [] ) { super() 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(); //Object.seal(this); } toString(){ return arr2str(this.arr,false); } at(i=0,j=undefined){ if(i<0)i=this.rows+i; if(j==undefined) return this.arr[i]; if(j<0)j=this.cols+j; return this.arr[i][j]; } reshape(newRows, newCols) { let check = newRows * newCols === this.rows * this.cols; if (check) return new Matrix(newRows, newCols, this.arr.flat(1)); else console.error("Err"); } 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; } get clone() { return new Matrix(this.rows, this.cols, this.arr.flat(1)); } get size() { return this.rows * this.cols; } get shape() { return [this.rows, this.cols]; } 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); } [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(row = 0, col = 0) { if (col == -1) return this.arr[row]; else if (row == -1) return this.arr.map((n) => n[col]); else return this.arr[row][col]; } set(row = 0, col = 0, value) { if (col == -1) return (this.arr[row] = value); else if (row == -1) { for (let i = 0; i < this.cols; i++) { this.arr[i][col] = value[i] || 0; } return this.arr; } return (this.arr[row][col] = value); } get isSquare() { return this.rows / this.cols === 1; } get isSym() { if (!this.isSquare) return false; const T = this.T; const M = this.clone; return Matrix.sub(M, T).max == 0 && Matrix.sub(M, T).min == 0; } get isAntiSym() { if (!this.isSquare) return false; const T = this.T; const M = this.clone; return Matrix.add(M, T).max == 0 && Matrix.add(M, T).min == 0; } get isDiag() { if (!this.isSquare) return false; const T = this.T; const M = this.clone; const MT = Matrix.mul(M, T); const TM = Matrix.dot(T, M); return Matrix.sub(MT, TM).max == 0 && Matrix.sub(MT, TM).min == 0; } get isOrtho() { if (!this.isSquare) return false; return this.isDiag && (this.det == 1 || this.det == -1); } get isIdemp() { if (!this.isSquare) return false; const M = this.clone; const MM = Matrix.dot(M, M); return Matrix.sub(MM, M).max == 0 && Matrix.sub(MM, M).min == 0; } 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() { if (!this.isSquare) return new Error("is not square matrix"); if (this.rows == 1) return this.arr[0][0]; function determinat(M) { if (M.length == 2) { if (M.flat(1).some((n) => n instanceof Matrix)) { console.warn("Tensors are not completely supported yet ..."); return; } return Utils.sub(Utils.mul(M[0][0],M[1][1]),Utils.mul(M[0][1],M[1][0])) } var answer = 0; for (var i = 0; i < M.length; i++) { //console.log(M[0][i]); /*answer = answer.add( pow(-1, i) .mul(M[0][i]) .mul(determinat(deleteRowAndColumn(M, i))) );*/ //const to_be_added=Utils.add(Utils.mul(pow(-1, i),Utils.mul(M[0][i],determinat(deleteRowAndColumn(M, i))))); const to_be_added=Utils.add(Utils.mul(pow(-1, i),Utils.mul(M[0][i],determinat(deleteRowAndColumn(M, i))))); answer=Utils.add(answer,to_be_added) } return answer; } function deleteRowAndColumn(M, index) { var temp = []; for (let i = 0; i < M.length; i++) temp.push(M[i].slice(0)); temp.splice(0, 1); for (let i = 0; i < temp.length; i++) temp[i].splice(index, 1); return temp; } return determinat(this.arr); } get inv() { if (!this.isSquare) return new Error("is not square matrix"); if (this.det === 0) return "determinat = 0 !!!"; let A = InverseMatrixe(this.arr); return new Matrix(this.rows, this.cols, A.flat(1)); } 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; } 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) { return Utils.map(this, Imin, Imax, Fmin, Fmax); } lerp(min, max) { return Utils.lerp(this, min, max); } norm(min, max) { return Utils.norm(this, min, max); } clamp(min, max) { return Utils.clamp(this, min, max); } static map(matrix, Imin, Imax, Fmin, Fmax) { return Utils.map(matrix, Imin, Imax, Fmin, Fmax); } static lerp(matrix, min, max) { return Utils.lerp(matrix, min, max); } static norm(matrix, min, max) { return Utils.norm(matrix, min, max); } static clamp(m, min, max) { return Utils.clamp(matrix, 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); } #hstack(matrix){ if (this.rows !== matrix.rows) return; let newArr = this.arr; for (let i = 0; i < this.rows; i++) for (let j = this.cols; j < this.cols + matrix.cols; j++) newArr[i][j] = matrix.arr[i][j - this.cols]; this.cols += matrix.cols; return new Matrix(this.rows, this.cols, newArr.flat(1)); } hstack(...matrices) { const M=[this,...matrices].reduce((a,b)=>a.#hstack(b)); Object.assign(this,M) return this; } static hstack(matrix,...matrices) { return matrix.clone.hstack(...matrices); } #vstack(matrix) { if (this.cols !== matrix.cols) return; let newArr = this.arr; for (let i = this.rows; i < this.rows + matrix.rows; i++) { newArr[i] = []; for (let j = 0; j < this.cols; j++) newArr[i][j] = matrix.arr[i - this.rows][j]; } this.rows += matrix.rows; return new Matrix(this.rows, this.cols, newArr.flat(1)); } vstack(...matrices) { const M=[this,...matrices].reduce((a,b)=>a.#vstack(b)); Object.assign(this,M) return this; } static vstack(matrix,...matrices) { return matrix.clone.vstack(...matrices); } hqueue(...matrices){ const M=[this,...matrices].reverse().reduce((a,b)=>a.#hstack(b)); Object.assign(this,M) return this; } vqueue(...matrices){ const M=[this,...matrices].reverse().reduce((a,b)=>a.#vstack(b)); Object.assign(this,M) return this; } static hqueue(matrix,...matrices) { return matrix.clone.hqueue(...matrices); } static vqueue(matrix,...matrices) { return matrix.clone.vqueue(...matrices); } 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); } 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] = Utils.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] = Utils.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] = Utils.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] = Utils.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]=Utils.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] = Utils.add( res[i][j], Utils.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 DoesItContainComplexNumbers() { return this.arr.flat(Infinity).some((n) => n instanceof Complex); } get min() { if (this.DoesItContainComplexNumbers) 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.DoesItContainComplexNumbers) 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.DoesItContainComplexNumbers) 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.DoesItContainComplexNumbers) 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.DoesItContainComplexNumbers) console.error("Complex numbers are not comparable"); return this.T.minRows; } get maxCols() { if (this.DoesItContainComplexNumbers) 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 print() { //"pretty print" the matrix let fstring = "["; for (let i = 0; i < this.arr.length; i++) { fstring += (i != 0 ? " " : "") + ` [${this.arr[i].map((n) => " " + n.toString() + " ")}],\n`; } console.log(fstring.substring(0, fstring.length - 2) + " ]"); document.write(fstring.substring(0, fstring.length - 2) + " ]"); } get table() { console.table(this.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; } toTable() { var table = new DocumentFragment(); var Tr = new Array(this.rows).fill(null).map(() => document?.createElement("tr")); var Td = this.arr.map((n) => n.map(() => document?.createElement("td"))); for (let i = 0; i < Td.length; i++) { for (let j = 0; j < Td[0].length; j++) { Td[i][j].innerHTML = this.arr[i][j]; Tr[i].appendChild(Td[i][j]); } } Tr.map((n) => table.appendChild(n)); return table; } toGrid(element, style = {}) { let a = Grid(); a.append( ...this.map(element) .arr.flat(1) .map((n) => n.style(style)) ); a.Columns(this.cols); return a; } 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; } } function InverseMatrixe(M) { if (M.length !== M[0].length) { return; } var i = 0, ii = 0, j = 0, dim = M.length, e = 0; //t = 0; var I = [], C = []; for (i = 0; i < dim; i += 1) { I[I.length] = []; C[C.length] = []; for (j = 0; j < dim; j += 1) { if (i == j) { I[i][j] = 1; } else { I[i][j] = 0; } C[i][j] = M[i][j]; } } for (i = 0; i < dim; i += 1) { e = C[i][i]; if (e == 0) { for (ii = i + 1; ii < dim; ii += 1) { if (C[ii][i] != 0) { for (j = 0; j < dim; j++) { e = C[i][j]; C[i][j] = C[ii][j]; C[ii][j] = e; e = I[i][j]; I[i][j] = I[ii][j]; I[ii][j] = e; } break; } } e = C[i][i]; if (e == 0) { return; } } for (j = 0; j < dim; j++) { C[i][j] = C[i][j] / e; I[i][j] = I[i][j] / e; } for (ii = 0; ii < dim; ii++) { if (ii == i) { continue; } e = C[ii][i]; for (j = 0; j < dim; j++) { C[ii][j] -= e * C[i][j]; I[ii][j] -= e * I[i][j]; } } } return I; } /** * @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}