use axb::Matrix;
fn main() {
println!("=== Matrix Decompositions ===\n");
let m = Matrix::<3, 3>::new([[4.0, 2.0, 1.0], [2.0, 5.0, 3.0], [1.0, 3.0, 6.0]]);
println!("Original matrix A:");
println!("{}", m);
println!("Determinant: {:.4}", m.determinant().unwrap());
println!("\n{}", "=".repeat(50));
println!("1. LU Decomposition (A = LU)");
println!("{}", "=".repeat(50));
match m.lu() {
Ok((l, u)) => {
println!("\nL (lower triangular with 1s on diagonal):");
println!("{}", l);
println!("U (upper triangular):");
println!("{}", u);
println!("Verification: L * U =");
println!("{}", (&l * &u).unwrap());
}
Err(e) => println!("LU decomposition failed: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("2. PLU Decomposition (PA = LU) - More Stable");
println!("{}", "=".repeat(50));
let m2 = Matrix::<3, 3>::new([[0.0, 1.0, 2.0], [1.0, 2.0, 3.0], [2.0, 3.0, 5.0]]);
println!("\nMatrix with zero pivot:");
println!("{}", m2);
match m2.plu() {
Ok((p, l, u)) => {
println!("P (permutation matrix):");
println!("{}", p);
println!("L (lower triangular):");
println!("{}", l);
println!("U (upper triangular):");
println!("{}", u);
let pa = (&p * &m2).unwrap();
let lu = (&l * &u).unwrap();
println!("Verification: P * A =");
println!("{}", pa);
println!("L * U =");
println!("{}", lu);
}
Err(e) => println!("PLU decomposition failed: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("3. LDU Decomposition (A = LDU)");
println!("{}", "=".repeat(50));
match m.ldu() {
Ok((l, d, u)) => {
println!("\nL (unit lower triangular):");
println!("{}", l);
println!("D (diagonal):");
println!("{}", d);
println!("U (unit upper triangular):");
println!("{}", u);
let ld = (&l * &d).unwrap();
let ldu = (&ld * &u).unwrap();
println!("Verification: L * D * U =");
println!("{}", ldu);
}
Err(e) => println!("LDU decomposition failed: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("4. QR Decomposition (A = QR)");
println!("{}", "=".repeat(50));
match m.qr() {
Ok((q, r)) => {
println!("\nQ (orthogonal matrix):");
println!("{}", q);
println!("R (upper triangular):");
println!("{}", r);
println!("Verification: Q * R =");
println!("{}", (&q * &r).unwrap());
println!("Q^T * Q (should be identity):");
println!("{}", (&q.transpose() * &q).unwrap());
println!("Is Q orthogonal? {}", q.is_orthogonal());
}
Err(e) => println!("QR decomposition failed: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("5. Cholesky Decomposition (A = LL^T)");
println!("{}", "=".repeat(50));
let spd = Matrix::<3, 3>::new([[4.0, 2.0, 2.0], [2.0, 5.0, 1.0], [2.0, 1.0, 6.0]]);
println!("\nSymmetric positive-definite matrix:");
println!("{}", spd);
println!("Is symmetric? {}", spd.is_symmetric());
match spd.cholesky() {
Ok(l) => {
println!("\nL (lower triangular):");
println!("{}", l);
let lt = l.transpose();
println!("L^T:");
println!("{}", lt);
println!("Verification: L * L^T =");
println!("{}", (&l * <).unwrap());
}
Err(e) => println!("Cholesky decomposition failed: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("6. Application: Solving Ax = b using LU");
println!("{}", "=".repeat(50));
let b = Matrix::<3, 1>::new([[1.0], [2.0], [3.0]]);
println!("\nSolving Ax = b where b =");
println!("{}", b);
match m.solve(&b) {
Ok(x) => {
println!("Solution x:");
println!("{}", x);
println!("Verification: A * x =");
println!("{}", (&m * &x).unwrap());
}
Err(e) => println!("Failed to solve: {}", e),
}
println!("\n{}", "=".repeat(50));
println!("7. Handling Singular Matrices");
println!("{}", "=".repeat(50));
let singular = Matrix::<3, 3>::new([
[1.0, 2.0, 3.0],
[4.0, 5.0, 6.0],
[7.0, 8.0, 9.0], ]);
println!("\nSingular matrix (rank deficient):");
println!("{}", singular);
println!("Determinant: {:.6}", singular.determinant().unwrap());
println!("Rank: {} (should be 2, not 3)", singular.rank());
match singular.inverse() {
Ok(_) => println!("Inverse exists (unexpected)"),
Err(e) => println!("Cannot invert: {} (expected)", e),
}
println!("\n=== Decompositions Complete ===");
}