Learn how to calculate the determinant of a matrix in C using multiple methods, including the recursive Laplace expansion, LU decomposition, and matrix manipulation. Understand the underlying algorithms and their implementation.
Introduction:
The determinant of a matrix is a scalar value that can be computed from its elements and encapsulates important properties of the matrix. This guide covers multiple methods to calculate the determinant of a matrix in C.
Method 1: Laplace Expansion (Recursive)
Algorithm:
Step 1: Start
Step 2: Input: A square matrix A and its size n.
Step 3: Process:
(i) If n is 1, return the single element.
(ii) Initialize det to 0.
(iii) For each element in the first row:
(a) Create a submatrix by excluding the current row and
column.
(b) Recursively calculate the determinant of the submatrix.
(c) Add the product of the element, its cofactor, and the
determinant of the submatrix to det.
Step 4: Output: Return det.
Step 5: Exit
Pseudocode:
function determinant_laplace(A, n):
if n == 1:
return A[0][0]
det = 0
for each element A[0][j] in the first row:
submatrix = get_submatrix(A, 0, j, n)
det += (-1)^j * A[0][j] * determinant_laplace(submatrix, n-1)
return det
C Implementation:
#include <stdio.h>
#include <stdlib.h>
void get_submatrix(int **matrix, int **submatrix, int row, int col, int n) {
int subi = 0;
for (int i = 1; i < n; i++) {
int subj = 0;
for (int j = 0; j < n; j++) {
if (j == col) continue;
submatrix[subi][subj] = matrix[i][j];
subj++;
}
subi++;
}
}
int determinant_laplace(int **matrix, int n) {
if (n == 1) return matrix[0][0];
int det = 0;
for (int col = 0; col < n; col++) {
int **submatrix = (int **)malloc((n - 1) * sizeof(int *));
for (int i = 0; i < n - 1; i++) {
submatrix[i] = (int *)malloc((n - 1) * sizeof(int));
}
get_submatrix(matrix, submatrix, 0, col, n);
det += (col % 2 == 0 ? 1 : -1) * matrix[0][col] * determinant_laplace(submatrix, n - 1);
for (int i = 0; i < n - 1; i++) {
free(submatrix[i]);
}
free(submatrix);
}
return det;
}
int main() {
int n = 3;
int **matrix = (int **)malloc(n * sizeof(int *));
for (int i = 0; i < n; i++) {
matrix[i] = (int *)malloc(n * sizeof(int));
}
matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
matrix[2][0] = 7; matrix[2][1] = 8; matrix[2][2] = 9;
printf("Determinant (Laplace Expansion): %d\n", determinant_laplace(matrix, n));
for (int i = 0; i < n; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}
Step-by-Step Explanation:
- Function get_submatrix:
- Removes the specified row and column from the matrix to create a submatrix.
- Function determinant_laplace:
- Handles the base case for 1×1 matrices.
- Iterates over the first row, calculating the determinant recursively for submatrices.
- Uses the cofactor expansion to sum the determinants of submatrices.
Method 2: LU Decomposition
Algorithm:
Step 1: Start
Step 2: Input: A square matrix A and its size n.
Step 3: Process:
(i) Perform LU decomposition on A to get matrices L and U.
(ii) Calculate the determinant as the product of the diagonal
elements of U.
Step 4: Output: Return the determinant.
Step 5: Exit
Pseudocode:
function determinant_lu(A, n):
L, U = lu_decomposition(A, n)
det = product of diagonal elements of U
return det
C Implementation:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void lu_decomposition(double **matrix, double **L, double **U, int n) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (j < i)
L[j][i] = 0;
else {
L[j][i] = matrix[j][i];
for (int k = 0; k < i; k++) {
L[j][i] = L[j][i] - L[j][k] * U[k][i];
}
}
}
for (int j = 0; j < n; j++) {
if (j < i)
U[i][j] = 0;
else if (j == i)
U[i][j] = 1;
else {
U[i][j] = matrix[i][j] / L[i][i];
for (int k = 0; k < i; k++) {
U[i][j] = U[i][j] - ((L[i][k] * U[k][j]) / L[i][i]);
}
}
}
}
}
double determinant_lu(double **matrix, int n) {
double **L = (double **)malloc(n * sizeof(double *));
double **U = (double **)malloc(n * sizeof(double *));
for (int i = 0; i < n; i++) {
L[i] = (double *)malloc(n * sizeof(double));
U[i] = (double *)malloc(n * sizeof(double));
}
lu_decomposition(matrix, L, U, n);
double det = 1;
for (int i = 0; i < n; i++) {
det *= L[i][i];
}
for (int i = 0; i < n; i++) {
free(L[i]);
free(U[i]);
}
free(L);
free(U);
return det;
}
int main() {
int n = 3;
double **matrix = (double **)malloc(n * sizeof(double *));
for (int i = 0; i < n; i++) {
matrix[i] = (double *)malloc(n * sizeof(double));
}
matrix[0][0] = 1; matrix[0][1] = 2; matrix[0][2] = 3;
matrix[1][0] = 4; matrix[1][1] = 5; matrix[1][2] = 6;
matrix[2][0] = 7; matrix[2][1] = 8; matrix[2][2] = 9;
printf("Determinant (LU Decomposition): %f\n", determinant_lu(matrix, n));
for (int i = 0; i < n; i++) {
free(matrix[i]);
}
free(matrix);
return 0;
}
Step-by-Step Explanation:
- LU Decomposition:
- Decomposes matrix A into lower triangular matrix L and upper triangular matrix U.
- Determinant Calculation:
- The determinant of A is the product of the diagonal elements of L.
Summary
The determinant of a matrix is a fundamental concept in linear algebra with applications in various mathematical and engineering fields. In C programming, we can calculate the determinant using different methods, each suitable for different scenarios. Here, we explored two primary methods: Laplace expansion (recursive) and LU decomposition.
Method 1: Laplace Expansion (Recursive)
- Purpose: Calculate the determinant of a matrix using cofactor expansion.
- Complexity: O(n!), where
n
is the size of the matrix. This makes it inefficient for large matrices due to its exponential time complexity.
- Steps:
- Base case: If the matrix is 1×1, return the single element.
- For each element in the first row, create a submatrix by excluding the current row and column.
- Recursively calculate the determinant of the submatrix.
- Sum the products of each element, its cofactor, and the determinant of the submatrix.
- Use Case: Educational purposes and small matrices due to its simplicity and ease of understanding.
Method 2: LU Decomposition
- Purpose: Efficiently calculate the determinant by decomposing the matrix into lower (L) and upper (U) triangular matrices.
- Complexity: O(n^3), making it more suitable for larger matrices compared to Laplace expansion.
- Steps:
- Decompose the matrix
A
into lower (L) and upper (U) triangular matrices using LU decomposition. - Calculate the determinant as the product of the diagonal elements of the lower triangular matrix
L
.
- Decompose the matrix
- Use Case: Practical applications requiring efficient computation, especially for larger matrices.
Each method has its own advantages and is suitable for different scenarios:
- Laplace Expansion:
- Pros: Simple to understand and implement; useful for educational purposes.
- Cons: Inefficient for large matrices due to exponential time complexity.
- LU Decomposition:
- Pros: Efficient for larger matrices with polynomial time complexity.
- Cons: More complex to implement than Laplace expansion.
For practical applications involving large matrices, LU decomposition is recommended due to its efficiency. Laplace expansion, while not suitable for large matrices, serves as a valuable educational tool for understanding the concept of determinants and cofactor expansion.
Discover more from lounge coder
Subscribe to get the latest posts sent to your email.