function calculateQR() {
// Clear previous errors and results
document.getElementById('error-message').innerHTML = ";
document.getElementById('results').style.display = 'none';
// 1. Get Input Values
var a11 = parseFloat(document.getElementById('a11').value);
var a12 = parseFloat(document.getElementById('a12').value);
var a13 = parseFloat(document.getElementById('a13').value);
var a21 = parseFloat(document.getElementById('a21').value);
var a22 = parseFloat(document.getElementById('a22').value);
var a23 = parseFloat(document.getElementById('a23').value);
var a31 = parseFloat(document.getElementById('a31').value);
var a32 = parseFloat(document.getElementById('a32').value);
var a33 = parseFloat(document.getElementById('a33').value);
// Validation
if (isNaN(a11) || isNaN(a12) || isNaN(a13) ||
isNaN(a21) || isNaN(a22) || isNaN(a23) ||
isNaN(a31) || isNaN(a32) || isNaN(a33)) {
document.getElementById('error-message').innerText = "Please fill in all matrix cells with valid numbers.";
return;
}
// Define Columns of A as vectors
var v1 = [a11, a21, a31];
var v2 = [a12, a22, a32];
var v3 = [a13, a23, a33];
// 2. Gram-Schmidt Process
// — Step 1: u1 = v1 —
var u1 = v1;
var magU1 = Math.sqrt(u1[0]*u1[0] + u1[1]*u1[1] + u1[2]*u1[2]);
if (magU1 === 0) {
document.getElementById('error-message').innerText = "Matrix is singular or column vectors are linearly dependent (First column is zero).";
return;
}
// e1 = u1 / ||u1||
var e1 = [u1[0]/magU1, u1[1]/magU1, u1[2]/magU1];
// — Step 2: u2 = v2 – proj_u1(v2) —
// Ideally use e1 for simpler calculation: u2 = v2 – (v2 . e1) * e1
var dotV2E1 = v2[0]*e1[0] + v2[1]*e1[1] + v2[2]*e1[2];
var u2 = [
v2[0] – dotV2E1 * e1[0],
v2[1] – dotV2E1 * e1[1],
v2[2] – dotV2E1 * e1[2]
];
var magU2 = Math.sqrt(u2[0]*u2[0] + u2[1]*u2[1] + u2[2]*u2[2]);
// Check linear dependence
if (magU2 < 1e-10) {
document.getElementById('error-message').innerText = "Columns are linearly dependent. QR Decomposition requires linearly independent columns for unique results.";
return;
}
var e2 = [u2[0]/magU2, u2[1]/magU2, u2[2]/magU2];
// — Step 3: u3 = v3 – proj_u1(v3) – proj_u2(v3) —
// u3 = v3 – (v3 . e1)e1 – (v3 . e2)e2
var dotV3E1 = v3[0]*e1[0] + v3[1]*e1[1] + v3[2]*e1[2];
var dotV3E2 = v3[0]*e2[0] + v3[1]*e2[1] + v3[2]*e2[2];
var u3 = [
v3[0] – (dotV3E1 * e1[0]) – (dotV3E2 * e2[0]),
v3[1] – (dotV3E1 * e1[1]) – (dotV3E2 * e2[1]),
v3[2] – (dotV3E1 * e1[2]) – (dotV3E2 * e2[2])
];
var magU3 = Math.sqrt(u3[0]*u3[0] + u3[1]*u3[1] + u3[2]*u3[2]);
if (magU3 < 1e-10) {
document.getElementById('error-message').innerText = "Columns are linearly dependent.";
return;
}
var e3 = [u3[0]/magU3, u3[1]/magU3, u3[2]/magU3];
// 3. Construct Matrix Q
// Columns of Q are e1, e2, e3
var Q = [
[e1[0], e2[0], e3[0]],
[e1[1], e2[1], e3[1]],
[e1[2], e2[2], e3[2]]
];
// 4. Construct Matrix R
// R is upper triangular. R_ij = e_i . v_j
// R11 = e1 . v1, R12 = e1 . v2, R13 = e1 . v3
// R21 = 0, R22 = e2 . v2, R23 = e2 . v3
// R31 = 0, R32 = 0, R33 = e3 . v3
var r11 = v1[0]*e1[0] + v1[1]*e1[1] + v1[2]*e1[2];
var r12 = v2[0]*e1[0] + v2[1]*e1[1] + v2[2]*e1[2];
var r13 = v3[0]*e1[0] + v3[1]*e1[1] + v3[2]*e1[2];
var r22 = v2[0]*e2[0] + v2[1]*e2[1] + v2[2]*e2[2];
var r23 = v3[0]*e2[0] + v3[1]*e2[1] + v3[2]*e2[2];
var r33 = v3[0]*e3[0] + v3[1]*e3[1] + v3[2]*e3[2];
var R = [
[r11, r12, r13],
[0, r22, r23],
[0, 0, r33]
];
// 5. Verification (Check = Q * R)
var check = [
[0,0,0], [0,0,0], [0,0,0]
];
for(var i=0; i<3; i++) {
for(var j=0; j<3; j++) {
var sum = 0;
for(var k=0; k<3; k++) {
sum += Q[i][k] * R[k][j];
}
check[i][j] = sum;
}
}
// 6. Display Results
function renderMatrix(matrix, elementId) {
var html = '';
for(var row=0; row<3; row++) {
html += '
';
for(var col=0; col<3; col++) {
// Handle small floating point errors near zero
var val = matrix[row][col];
if(Math.abs(val) < 1e-10) val = 0;
html += '
QR Decomposition (also known as QR factorization) is a fundamental linear algebra operation that factors a matrix A into a product A = QR of two specific matrices:
Q: An orthogonal matrix (meaning its columns are orthogonal unit vectors, and $Q^T = Q^{-1}$).
R: An upper triangular matrix (all entries below the main diagonal are zero).
This calculator specifically handles 3×3 square matrices, utilizing the Gram-Schmidt process to orthogonalize the columns of the input matrix.
How the Gram-Schmidt Process Works
To calculate the QR decomposition, we treat the columns of matrix A as vectors $(a_1, a_2, a_3)$. The goal is to create an orthonormal basis $(e_1, e_2, e_3)$ which forms the columns of Q.
Once the orthogonal matrix Q is found, the upper triangular matrix R is calculated by projecting the original columns of A onto the new basis vectors. The entry $R_{ij}$ is the dot product of $e_i$ and $a_j$.
Applications of QR Decomposition
QR decomposition is widely used in numerical linear algebra for several critical tasks:
Solving Linear Systems: It helps solve systems of linear equations ($Ax = b$) more numerically stably than Gaussian elimination in certain cases.
Least Squares Problems: It is the standard method for solving linear least squares problems, often used in regression analysis and data fitting.
Eigenvalues: It is the basis of the QR algorithm, an iterative method used to calculate the eigenvalues and eigenvectors of a matrix.
Understanding the Results
When you use the calculator above, you will see:
Matrix Q: Look for the property that the dot product of any two distinct columns is zero, and the magnitude of each column is 1.
Matrix R: You will notice zeros in the bottom-left corner ($r_{21}, r_{31}, r_{32}$), confirming the upper triangular structure.
Verification: The product of Q and R should reconstruct your original Matrix A (within floating-point rounding errors).