Sparse Matrix - Transpose and Addition
A sparse matrix is a special type of matrix in which most of the elements are zero or have some default value. In contrast, a dense matrix is one in which most of the elements are non-zero. Sparse matrices are used in various fields, including computer science, numerical analysis, and scientific computing, when dealing with large datasets or systems where efficiency and memory usage are crucial. As a rule of thumb, if 2/3 of the total elements in a matrix are zeros, it can be called a sparse matrix. Using a sparse matrix representation — where only the non-zero values are stored — the space used for representing data and the time for scanning the matrix are reduced significantly.
In many real-world problems — like graphs, networks, or scientific simulations — the majority of elements in the matrix are zero.
Such a matrix is called a Sparse Matrix.
Formally:
A matrix in which the number of zero elements is significantly greater than the number of non-zero elements.
The opposite of a sparse matrix is a Dense Matrix, where most of the elements are non-zero.
Sparsity
Sparsity is simply a way of describing how many zero elements a matrix has compared to its total size.
In other words:
Sparsity = the proportion of zero elements in the matrix.
It’s a measure of “how sparse” the matrix is.
A matrix with high sparsity has mostly zero entries.
Formula
If:
-
= number of rows
-
= number of columns
-
= number of non-zero elements
Then:
Since total elements = and zero elements =
Example
Matrix:
-
Dimensions: total elements
-
Non-zero elements: 2 (5 and 8)
-
Zero elements:
This means 83% of the matrix is zeros — a highly sparse matrix.
Interpretation
-
High sparsity (close to 1 or 100%) → very few non-zero elements → a sparse matrix.
-
Low sparsity (close to 0) → many non-zero elements → a dense matrix.
-
We waste memory storing zeros.
-
We waste computation time when processing useless zero elements.
Instead, we can store only the non-zero elements and their positions — saving memory and making computations faster.
The following is a 3 tuple(triplet) representation.The first row of sparse matrix always specifies the number of rows, number of columns and number of non zero elements in the sparse matrix.The second row onwards , non zero elements are represented with corresponding row and column.
Advantages:
- Memory Efficiency: Store only non-zero values.
- Speed: Skip useless zero-element computations.
- Scalability: Handle large problems (e.g., adjacency matrices in graphs).
Disadvantages:
- Random access to elements is slower.
- Still requires space for three integers per non-zero value.
- Some algorithms need to be redesigned to work efficiently.
- Graph Representations: Adjacency matrices for large sparse graphs.
- Finite Element Analysis: Physics and engineering simulations.
- Image Processing: Large images with mostly blank pixels.
- Search Engines: Term-document matrices in NLP.
Triplet Representation
Algorithm idea:
-
Scan the entire matrix element by element.
-
For each non-zero element, store its
(row, column, value)
in the sparse list.
Steps:
-
Total elements to check =
-
Checking each element takes .
-
Therefore, the scanning step =
-
Storing the non-zero elements also takes , where is the number of non-zero elements, but since , the total complexity is still
Conclusion
-
Time Complexity:
-
Space Complexity:
(plus a small overhead for metadata like rows, columns, and count).
C program - 3-Tuple(Triplet) Representation
#include <stdio.h>struct Sparse {
int row;
int col;
int value;
};
int main() {
// Original 4x5 matrix
int matrix[4][5] = {
{0, 0, 0, 5, 0},
{0, 8, 0, 0, 0},
{0, 0, 0, 0, 0},
{1, 0, 0, 0, 4}
};
struct Sparse sparse[20]; // Enough space
int rows = 4, cols = 5, k = 1; // k starts from 1 (0 for metadata)
// Metadata: dimensions and number of non-zero elements
sparse[0].row = rows;
sparse[0].col = cols;
sparse[0].value = 0; // Will be updated later
// Store non-zero elements
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (matrix[i][j] != 0) {
sparse[k].row = i;
sparse[k].col = j;
sparse[k].value = matrix[i][j];
k++;
}
}
}
sparse[0].value = k - 1; // Total non-zero count
// Print sparse representation
printf("Row Col Value\n");
for (int i = 0; i < k; i++) {
printf("%d %d %d\n", sparse[i].row, sparse[i].col, sparse[i].value);
}
return 0;
}
Operations on Sparse Matrices
When stored efficiently, we can still perform:
Transpose: Swap row and column indices in each triplet.
- Addition: Merge two triplet lists, adding matching positions.
Transpose of a Sparse Matrix
Transpose of a matrix means rows become columns and columns become rows.
In sparse matrix representation, for each term, swap row and column.
Example:
Consider a 3x3 matrix
0 5 0
3 0 0
0 0 6
(First row is metadata: rows, columns, total non-zero elements.)
Index | Row | Column | Value |
---|---|---|---|
0 | 3 | 3 | 3 |
1 | 0 | 1 | 5 |
2 | 1 | 0 | 3 |
3 | 2 | 2 | 6 |
Transpose means swapping the row and column for each element.
Metadata for transpose:
-
Rows become Columns
-
Columns become Rows
So metadata: (3, 3, 3)
So the transposed sparse matrix (with metadata):
Index | Row | Column | Value |
---|---|---|---|
0 | 3 | 3 | 3 |
1 | 0 | 1 | 3 |
2 | 1 | 0 | 5 |
3 | 2 | 2 | 6 |
And if you reconstruct the full matrix from this sparse data, it will look like:
0 3 0
5 0 0
0 0 6
-
A sparse matrix
sparse[]
in 3-tuple form where:-
sparse[0]
stores (number of rows, number of columns, number of non-zero elements). -
sparse[1..n]
store (row, column, value) of non-zero elements.
-
-
transpose[]
array representing the transposed matrix.
Steps:
-
Read the
sparse[]
array, including metadata and non-zero elements. -
Initialize the first element (
transpose[0]
) of transposed matrix:-
transpose[0].row = sparse[0].col
-
transpose[0].col = sparse[0].row
-
transpose[0].value = sparse[0].value
-
-
For each column
i
(0 to number of columns - 1) of the original matrix:-
For each non-zero element (from index 1 to n):
-
If the column index j of the element is
i
:-
Create a new entry in
transpose[]
:-
transpose[k].row = sparse[j].col
-
transpose[k].col = sparse[j].row
-
transpose[k].value = sparse[j].value
-
-
Increment
k
.
-
-
-
-
End
🔔 Key Notes:
-
We scan column-wise to maintain the order of the transposed sparse matrix.
-
The metadata must be swapped (rows ↔ columns) at the start.
-
The number of non-zero elements remains the same after transpose.
Time Complexity:
-
For each of the columns, we scan all triplets.
-
Complexity: — which can be quite large if is big.
Implementation of Transpose in C
A:
Index | Row | Column | Value |
---|---|---|---|
0 | 3 | 3 | 3 |
1 | 0 | 0 | 5 |
2 | 0 | 2 | 7 |
3 | 2 | 1 | 6 |
B:
Index | Row | Column | Value |
---|---|---|---|
0 | 3 | 3 | 2 |
1 | 0 | 0 | 3 |
2 | 2 | 2 | 8 |
-
Compare A[1] and B[1]:
-
Same position (0,0). Add values: 5 + 3 = 8 → (0,0,8) copy the result
Note if the sum is zero, do not copy
-
-
Compare A[2] and B[2]:
-
A[2] (0,2) comes before B[2] (2,2). Copy A[2] → (0,2,7)
-
-
Now A[3] and B[2]:
-
A[3] (2,1) comes before B[2] (2,2). Copy A[3] → (2,1,6)
-
-
No more A. Now copy remaining B[2] → (2,2,8)
Index | Row | Column | Value |
---|---|---|---|
0 | 3 | 3 | 4 |
1 | 0 | 0 | 8 |
2 | 0 | 2 | 7 |
3 | 2 | 1 | 6 |
4 | 2 | 2 | 8 |
Input:
-
Two sparse matrices
A[]
andB[]
(both in 3-tuple form with metadata in the first row). -
Each row of
A[]
andB[]
has(row, column, value)
.
-
A sparse matrix
C[]
representingA + B
.
Steps
-
Initialize pointers
i = 1
for A andj = 1
for B (metadata is in index 0). -
Compare
(row, col)
ofA[i]
andB[j]
. -
If positions are equal → sum values and store if non-zero, increment both
i
andj
. -
If
A[i]
comes beforeB[j]
→ copyA[i]
to result, incrementi
. -
If
B[j]
comes beforeA[i]
→ copyB[j]
to result, incrementj
. -
Append any remaining terms from A or B.
-
Check if the matrices have the same dimensions:
-
If
A[0].row != B[0].row
orA[0].col != B[0].col
,
then Addition is not possible. Stop.
-
-
Initialize pointers:
-
i = 1
(for A[]) -
j = 1
(for B[]) -
k = 1
(for C[])
-
-
Set C[0] metadata:
-
C[0].row = A[0].row
-
C[0].col = A[0].col
-
C[0].value = 0
(for now; update later)
-
-
Compare and Merge:
-
While
i <= A[0].value
andj <= B[0].value
, do:-
If
(A[i].row < B[j].row)
or
(A[i].row == B[j].row and A[i].col < B[j].col)
:-
Copy
A[i]
toC[k]
-
Increment
i
andk
-
-
Else if
(B[j].row < A[i].row)
or
(B[j].row == A[i].row and B[j].col < A[i].col)
:-
Copy
B[j]
toC[k]
-
Increment
j
andk
-
-
Else (Same position):
-
Add the values:
sum = A[i].value + B[j].value
-
If
sum != 0
:-
C[k].row = A[i].row
-
C[k].col = A[i].col
-
C[k].value = sum
-
Increment
k
-
-
Increment both
i
andj
-
-
-
-
Copy Remaining Elements:
-
While
i <= A[0].value
:-
Copy
A[i]
toC[k]
-
Increment
i
andk
-
-
While
j <= B[0].value
:-
Copy
B[j]
toC[k]
-
Increment
j
andk
-
-
-
Update Metadata:
-
Set
C[0].value = k - 1
-
-
End
🧠Key Points:
-
Matrices must be sorted by (row, column).
-
If two elements overlap (same row and column), add their values.
-
If the result of addition is zero, do not insert it into the result sparse matrix.
Time Complexity
Let:
-
= number of non-zero elements in matrix A
-
= number of non-zero elements in matrix B
When both triplet lists are sorted by row, then column, addition is done by merging them — similar to merging two sorted arrays.
Time Complexity:
-
Each non-zero element is compared at most once.
-
Comparisons and insertions are .
Comments
Post a Comment