Advertisement
Guest User

Untitled

a guest
Apr 25th, 2019
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.01 KB | None | 0 0
  1. /*
  2. Matrix Class
  3. Created By Davenchy
  4. twitter: @fadi_davenchy
  5. */
  6.  
  7. const Matrix = (function() {
  8. class Matrix {
  9. constructor(r=3, c=3, i=0) {
  10. // create matrix
  11. if (Array.isArray(r)) this.matrix = r.map(c => c.slice(0));
  12. else if (r instanceof Matrix) this.copyOf(r);
  13. else this.matrix = Matrix.generateArray(r, c, i);
  14.  
  15. // check the matrix
  16. const rows = this.matrix.length;
  17. const columns = this.matrix[0].length;
  18. const columnsLength = this.matrix.filter(c => c.length === columns).length;
  19. if (columnsLength !== rows) throw new Error(`each column must have the same number of values: ${rows}`);
  20. }
  21.  
  22. reset(i=0) {
  23. this.matrix = Matrix.generateArray(this.rows, this.columns, i);
  24. return this;
  25. }
  26.  
  27. copyOf(m) {
  28. this.matrix = m.matrix.map(c => c.slice(0));
  29. return this;
  30. }
  31.  
  32. clone() {
  33. return new Matrix(this.matrix);
  34. }
  35.  
  36. toString() {
  37. return this.matrix.map(c => c.join('\t')).join('\n');
  38. }
  39.  
  40. isEqualTo(m2) {
  41. if (!m2 instanceof Matrix) throw new Error('need matrix to compare to');
  42. const m1 = this;
  43. if (m1.rows !== m2.rows || m1.columns !== m2.columns) return false;
  44. m1.loop(({ i, j, value }) => {
  45. if (m2.getValue(i, j) !== value) return false;
  46. });
  47. return true;
  48. }
  49.  
  50. get isSquare() {
  51. return this.rows === this.columns;
  52. }
  53.  
  54. get isInversable() {
  55. return this.determinate !== 0;
  56. }
  57.  
  58. get determinate() {
  59. const m = this.clone();
  60. if (!m.isSquare) throw new Error('matrix must be a square matrix');
  61. const M = m.getValue.bind(m);
  62. // handle (1x1) Matrix
  63. if (m.rows === 1) return M(1, 1);
  64. // handle (2x2) Matrix
  65. if (m.rows === 2) return M(1, 1) * M(2, 2) - M(1, 2) * M(2, 1);
  66. // handle (3x3) or more Matrices
  67. if (m.rows >= 3) {
  68. let sum = 0;
  69. for (let i = 1; i <= m.rows; i++) {
  70. const det = m.clone().reduce(1, i).determinate;
  71. sum += Math.pow(-1, i - 1) * M(1, i) * det;
  72. }
  73. return sum;
  74. }
  75. return;
  76. }
  77.  
  78. get rows() {
  79. return this.matrix.length;
  80. }
  81.  
  82. get columns() {
  83. return this.matrix[0].length;
  84. }
  85.  
  86. get type() {
  87. return `(${this.rows} x ${this.columns})`
  88. }
  89.  
  90. setColumn(n, c=[]) {
  91. if (c.length !== this.rows) throw new Error(`column must has ${this.rows} value(s)`);
  92. if (n > this.columns || n <= 0) throw new Error(`column number must be in range [1, ${this.columns}]`);
  93. this.matrix.forEach((col, i) => {
  94. col[n - 1] = c[i];
  95. });
  96. return this;
  97. }
  98.  
  99. addColumn(c=[]) {
  100. if (c.length !== this.rows) throw new Error(`column must has ${this.rows} value(s)`);
  101. this.matrix.forEach((col, i) => {
  102. col.push(c[i]);
  103. });
  104. return this;
  105. }
  106.  
  107. getColumn(c=1) {
  108. if (c > this.columns || c <= 0) throw new Error(`column number must be in range [1, ${this.columns}]`);
  109. return this.matrix.map(r => r[c - 1]);
  110. }
  111.  
  112. removeColumn(c) {
  113. if (c > this.columns || c <= 0) throw new Error(`column number must be in range [1, ${this.columns}]`);
  114. this.matrix.forEach(r => r.splice(c - 1, 1));
  115. return this;
  116. }
  117.  
  118. setRow(n, r=[]) {
  119. if (r.length !== this.columns) throw new Error(`row must has ${this.columns} value(s)`);
  120. if (n > this.rows || n <= 0) throw new Error(`row number must be in range [1, ${this.rows}]`);
  121. this.matrix[n - 1] = r;
  122. return this;
  123. }
  124.  
  125. addRow(r=[]) {
  126. if (r.length !== this.columns) throw new Error(`row must has ${this.columns} value(s)`);
  127. this.matrix.push(r);
  128. return this;
  129. }
  130.  
  131. getRow(r=1) {
  132. if (r > this.rows || r <= 0) throw new Error(`row number must be in range [1, ${this.rows}]`);
  133. return this.matrix[r - 1].slice(0);
  134. }
  135.  
  136. removeRow(r) {
  137. if (r > this.rows || r <= 0) throw new Error(`row number must be in range [1, ${this.rows}]`);
  138. this.matrix.splice(r - 1, 1);
  139. return this;
  140. }
  141.  
  142. setValue(r=1, c=1, v) {
  143. this.matrix[r-1][c-1] = v;
  144. return this;
  145. }
  146.  
  147. getValue(r=1, c=1) {
  148. if (r <= 0 || r > this.rows || c <= 0 || c > this.cols) return;
  149. return this.matrix[r-1][c-1];
  150. }
  151.  
  152. loop(cb) {
  153. const self = this;
  154. const { rows, columns } = this;
  155. let counter = 0;
  156. for(let i = 1; i <= rows; i++)
  157. for(let j = 1; j <= columns; j++) {
  158. const tools = {
  159. self, i, j,
  160. clone: self.clone(),
  161. sign: Math.pow(-1, counter),
  162. counter: counter++,
  163. value: self.getValue(i, j),
  164. setValue: v => self.setValue(i, j, v),
  165. column: self.getColumn(j),
  166. row: self.getRow(i),
  167. }
  168.  
  169. try { tools.determinate = self.determinate; }
  170. catch (_) { tools.determinate = null; }
  171. tools.reduce = () => tools.clone.reduce(i, j);
  172. tools.inverse = () => tools.clone.inverse();
  173. tools.transpose = () => tools.clone.transpose();
  174. tools.adjacency = () => tools.clone.adjacency();
  175. tools.identity = () => tools.clone.identity();
  176.  
  177. cb(tools);
  178. }
  179. return this;
  180. }
  181.  
  182. multiply(...matrices) {
  183. const m1 = this;
  184. matrices.forEach(m2 => {
  185. if (m1.columns !== m2.rows) throw new Error('can not multiply the 2 matrices');
  186. const temp = new Matrix(m1.rows, m2.columns);
  187. temp.loop(({i, j, setValue}) => {
  188. const product = Matrix.vectorDotProduct(m1.getRow(i), m2.getColumn(j));
  189. setValue(product);
  190. });
  191. m1.copyOf(temp);
  192. });
  193. return this;
  194. }
  195.  
  196. addNumber (n) {
  197. const self = this;
  198. const { rows, columns } = this;
  199. this.loop(t => t.setValue(t.value + n));
  200. return this;
  201. }
  202.  
  203. subtractNumber (n) {
  204. const self = this;
  205. const { rows, columns } = this;
  206. this.loop(t => t.setValue(t.value - n));
  207. return this;
  208. }
  209.  
  210. multiplyNumber (n) {
  211. const self = this;
  212. const { rows, columns } = this;
  213. this.loop(t => t.setValue(t.value * n));
  214. return this;
  215. }
  216.  
  217. divideNumber (n) {
  218. if (n === 0) throw new Error('can not divide by zero');
  219. const self = this;
  220. const { rows, columns } = this;
  221. this.loop(t => t.setValue(t.value / n));
  222. return this;
  223. }
  224.  
  225. transpose() {
  226. const mat = Array(this.columns).fill(0);
  227. this.matrix = mat.map((r, i) => this.getColumn(i + 1));
  228. return this;
  229. }
  230.  
  231. inverse () {
  232. const delta = Math.pow(this.determinate, -1);
  233. this.adjacency().multiplyNumber(delta);
  234. return this;
  235. }
  236.  
  237. adjacency() {
  238. if (!this.isInversable) throw new Error('matrix determinate value equal to zero');
  239. if (!this.isSquare) throw new Error('must be a square matrix');
  240.  
  241. // 1x1 Matrix
  242. if (this.rows === 1) this.setValue(1, 1, Math.pow(this.getValue(1, 1), -1));
  243. // 2x2 Matrix
  244. else if (this.rows === 2) {
  245. const temp = this.getValue(1, 1);
  246. this.setValue(1, 2, this.getValue(1, 2) * -1);
  247. this.setValue(2, 1, this.getValue(2, 1) * -1);
  248. this.setValue(1, 1, this.getValue(2, 2));
  249. this.setValue(2, 2, temp);
  250. }
  251. // 3x3 or more Matrices
  252. else if (this.rows >= 3) {
  253. const temp = this.clone().reset();
  254. this.loop(({i, j, reduce, sign}) => {
  255. temp.setValue(i, j, reduce().determinate * sign)
  256. }).copyOf(temp.transpose());
  257. }
  258.  
  259. return this;
  260. }
  261.  
  262. identity () {
  263. const m = this;
  264. if (!m.isSquare) throw new Error('must be a square matrix');
  265. const n = m.rows;
  266. const i = new Matrix(n, n);
  267. for (let a = 1; a <= n; a++) {
  268. i.setValue(a, a, 1);
  269. }
  270. return i;
  271. }
  272.  
  273. reduce (r, c) {
  274. this.removeRow(r).removeColumn(c);
  275. return this;
  276. }
  277. }
  278.  
  279. Matrix.generateArray = (r = 3, c = 3, i = 0) => Array(r).fill().map(r => Array(c).fill().map(c => i));
  280. Matrix.vectorDotProduct = (a, b) => {
  281. if (a.length !== b.length) throw new Error(`length of 'a' not equal length of 'b'`)
  282. return a.map((x, i) => x * b[i]).reduce((a, b) => a + b);
  283. }
  284.  
  285. return Matrix;
  286. })();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement