class Matrix { constructor(data) { if (data instanceof Matrix) { this.data = data.data.map(row => [...row]); this.rowCount = data.rowCount; this.columnCount = data.columnCount; } else if (typeof data === 'number') { const rows = data; const cols = arguments[1]; this.rowCount = rows; this.columnCount = cols; this.data = Array(rows).fill(0).map(() => Array(cols).fill(0)); } else { this.rowCount = data.length; this.columnCount = data[0].length; this.data = data.map(row => [...row]); } } add(other) { if (other.rowCount !== this.rowCount || other.columnCount !== this.columnCount) { throw new Error('Incompatible matrix dimensions.'); } const result = new Matrix(this); for (let i = 0; i < this.rowCount; i++) { for (let j = 0; j < this.columnCount; j++) { result.data[i][j] = this.data[i][j] + other.data[i][j]; } } return result; } multiply(other) { if (this.columnCount !== other.rowCount) { throw new Error('Incompatible matrix dimensions.'); } const result = new Matrix(this.rowCount, other.columnCount); for (let i = 0; i < this.rowCount; i++) { for (let j = 0; j < other.columnCount; j++) { for (let k = 0; k < this.rowCount; k++) { result.data[i][j] += this.data[i][k] * other.data[k][j]; } } } return result; } transpose() { const result = new Matrix(this.columnCount, this.rowCount); for (let i = 0; i < this.rowCount; i++) { for (let j = 0; j < this.columnCount; j++) { result.data[j][i] = this.data[i][j]; } } return result; } minor(index) { const result = new Matrix(this.rowCount, this.columnCount); for (let i = 0; i < index; i++) { result.setEntry(i, i, 1.0); } for (let i = index; i < this.rowCount; i++) { for (let j = index; j < this.columnCount; j++) { result.setEntry(i, j, this.data[i][j]); } } return result; } column(index) { const result = new Matrix(this.rowCount, 1); for (let i = 0; i < this.rowCount; i++) { result.setEntry(i, 0, this.data[i][index]); } return result; } scalarMultiply(value) { if (this.columnCount !== 1) { throw new Error('Incompatible matrix dimension.'); } const result = new Matrix(this.rowCount, this.columnCount); for (let i = 0; i < this.rowCount; i++) { result.data[i][0] = this.data[i][0] * value; } return result; } unit() { if (this.columnCount !== 1) { throw new Error('Incompatible matrix dimensions.'); } const magnitude = this.magnitude(); const result = new Matrix(this.rowCount, this.columnCount); for (let i = 0; i < this.rowCount; i++) { result.data[i][0] = this.data[i][0] / magnitude; } return result; } magnitude() { if (this.columnCount !== 1) { throw new Error('Incompatible matrix dimensions.'); } let norm = 0.0; for (let i = 0; i < this.data.length; i++) { norm += this.data[i][0] * this.data[i][0]; } return Math.sqrt(norm); } size() { if (this.columnCount !== 1) { throw new Error('Incompatible matrix dimensions.'); } return this.rowCount; } display(title) { console.log(title); for (let i = 0; i < this.rowCount; i++) { let row = ''; for (let j = 0; j < this.columnCount; j++) { row += this.data[i][j].toFixed(4).padStart(9); } console.log(row); } console.log(); } getEntry(row, column) { return this.data[row][column]; } setEntry(row, column, value) { this.data[row][column] = value; } getRowCount() { return this.rowCount; } getColumnCount() { return this.columnCount; } } function householder(matrix) { const rowCount = matrix.getRowCount(); const columnCount = matrix.getColumnCount(); const versionsOfQ = []; let z = new Matrix(matrix); let z1 = new Matrix(rowCount, columnCount); for (let k = 0; k < columnCount && k < rowCount - 1; k++) { const vectorE = new Matrix(rowCount, 1); z1 = z.minor(k); const vectorX = z1.column(k); let magnitudeX = vectorX.magnitude(); if (matrix.getEntry(k, k) > 0) { magnitudeX = -magnitudeX; } for (let i = 0; i < vectorE.size(); i++) { vectorE.setEntry(i, 0, i === k ? 1 : 0); } const e = vectorE.scalarMultiply(magnitudeX).add(vectorX).unit(); versionsOfQ.push(householderFactor(e)); z = versionsOfQ[k].multiply(z1); } let Q = versionsOfQ[0]; for (let i = 1; i < columnCount && i < rowCount - 1; i++) { Q = versionsOfQ[i].multiply(Q); } const R = Q.multiply(matrix); Q = Q.transpose(); return { r: R, q: Q }; } function householderFactor(vector) { if (vector.getColumnCount() !== 1) { throw new Error('Incompatible matrix dimensions.'); } const size = vector.size(); const result = new Matrix(size, size); for (let i = 0; i < size; i++) { for (let j = 0; j < size; j++) { result.setEntry(i, j, -2 * vector.getEntry(i, 0) * vector.getEntry(j, 0)); } } for (let i = 0; i < size; i++) { result.setEntry(i, i, result.getEntry(i, i) + 1.0); } return result; } function fitPolynomial(x, y, polynomialDegree) { const vandermonde = new Matrix(x.getColumnCount(), polynomialDegree + 1); for (let i = 0; i < x.getColumnCount(); i++) { for (let j = 0; j < polynomialDegree + 1; j++) { vandermonde.setEntry(i, j, Math.pow(x.getEntry(0, i), j)); } } return leastSquares(vandermonde, y.transpose()); } function leastSquares(vandermonde, b) { const pair = householder(vandermonde); return solveUpperTriangular(pair.r, pair.q.transpose().multiply(b)); } function solveUpperTriangular(r, b) { const columnCount = r.getColumnCount(); const result = new Matrix(columnCount, 1); for (let k = columnCount - 1; k >= 0; k--) { let total = 0.0; for (let j = k + 1; j < columnCount; j++) { total += r.getEntry(k, j) * result.getEntry(j, 0); } result.setEntry(k, 0, (b.getEntry(k, 0) - total) / r.getEntry(k, k)); } return result; } // Main execution const data = [ [12.0, -51.0, 4.0], [6.0, 167.0, -68.0], [-4.0, 24.0, -41.0], [-1.0, 1.0, 0.0], [2.0, 0.0, 3.0] ]; // Task 1 const A = new Matrix(data); A.display('Initial matrix A:'); const pair = householder(A); const Q = pair.q; const R = pair.r; Q.display('Matrix Q:'); R.display('Matrix R:'); const result = Q.multiply(R); result.display('Matrix Q * R:'); // Task 2 const x = new Matrix([[0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0]]); const y = new Matrix([[1.0, 6.0, 17.0, 34.0, 57.0, 86.0, 121.0, 162.0, 209.0, 262.0, 321.0]]); const polyResult = fitPolynomial(x, y, 2); polyResult.display('Result of fitting polynomial:');