Represent a tridiagonal sparse matrix in column major order - c
Main Question:-
If the elements in the band formed by the three diagonals of a tridiagonal matrix X are represented column-wise in an array Y, with X[1,1] being stored in Y[1], then write an algorithm to determine the value of X[i, j], 1 <= i, j <= n from array Y.
I did some calculation in rough and found the size of 1D array required and index to row and column index for main diagonal and upper diagonal but failing to do so for lower diagonal
CONSIDERING A MATRIX WITH 5 ROWS AND 5 COLUMNS
|A11 A12 0 0 0 |
|A21 A22 A23 0 0 |
| 0 A32 A33 A34 0 |
| 0 0 A43 A44 A45|
| 0 0 0 A54 A55|
Size of the array (3*n - 2),
here size of the array = (3*5 - 2) = 13
0 1 2 3 4 5 6 7 8 9 10 11 12
A11 A21 A12 A22 A32 A23 A33 A43 A34 A44 A54 A45 A55
i=row index, 1<=i<=N
j=column index, 1<=j<=N
k=array index
Now for main diagonal
i j k
1 1 0
2 2 3
3 3 6
4 4 9
5 5 12
I got the relation as 3i - 3
For Upper diagonal
i j k
1 2 2
2 3 5
3 4 8
4 5 11
I got the relation as 4i - j
Now for lower diagonal(question)
i j k
2 1 1
3 2 4
4 3 7
5 4 10
Relation ??
Summary
You'll find that (indexing from 1), for an NxN tridiagonal matrix X
linearized in column-major order into an array Z, the entry in row r:
On the main diagonal of X is at index (3 * c - 2) of Y for c = 1..N;
On the upper-diagonal of X is at (3 * c - 3) of Y (for c = 1..N-1);
On the lower-diagonal of X is at (3 * c - 1) of Y (for c = 2..N).
For an element with row r, column c (both in the range 1..N):
if |r - c| > 1 then the value is zero;
if c == r then it is on the leading diagonal;
if c = r + 1 then it is on the upper diagonal;
if c = r - 1 then it is on the lower diagonal.
Of course, in C, arrays are indexed from zero, not one.
Cogitations
NxN tri-diagonal matrix X
Linearized in row-major order into array Y with 3*N-2 entries
Linearized in column-major order into array Z with 3*N-2 entries
Non-zero elements have c = r + { -1, 0, +1 }
Equivalently they have r = c + { -1, 0, +1 }
With one-based indexing, the first row with an element on the lower
diagonal is r = 2 and the last row with an element on the upper
diagonal is r = N - 1.
With zero-based indexing, the first row with an element on the lower
diagonal is r = 1 and the last rows with an element on the upper
diagonal is r = N - 2.
In the linearized vectors, the notation is:
D = diagonal, L = lower diagonal, U = upper diagonal
Row-Major Order with Zero-Based Indexing
X c = 0 1 2 3 4 5
+----------------------
r = 0 | 1 2 0 0 0 0
r = 1 | 3 4 5 0 0 0
r = 2 | 0 6 7 8 0 0
r = 3 | 0 0 9 10 11 0
r = 4 | 0 0 0 12 13 14
r = 5 | 0 0 0 0 15 16
D U L D U L D U L D U L D U L D
Y = { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 }
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Elements on main diagonal at indexes: 0, 3, 6, 9, 12, 15
Elements on upper diagonal at indexes: 1, 4, 7, 10, 13
Elements on lower diagonal at indexes: 2, 5, 8, 11, 14
Function get_rm_0():
X[r,c] = 0 if |r - c| > 1
X[r,c] = 3 * r + 0 if r == c + 0 — Main diagonal
X[r,c] = 3 * r + 1 if r == c - 1 — Upper diagonal
X[r,c] = 3 * r - 1 if r == c + 1 — Lower diagonal
Always subject to 0 <= r < N; 0 <= c < N
Row-Major Order with One-Based Indexing
X c = 1 2 3 4 5 6
+----------------------
r = 1 | 1 2 0 0 0 0
r = 2 | 3 4 5 0 0 0
r = 3 | 0 6 7 8 0 0
r = 4 | 0 0 9 10 11 0
r = 5 | 0 0 0 12 13 14
r = 6 | 0 0 0 0 15 16
D U L D U L D U L D U L D U L D
Y = { 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 }
Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Elements on main diagonal at indexes: 1, 4, 7, 10, 13, 16
Elements on upper diagonal at indexes: 2, 5, 8, 11, 14
Elements on lower diagonal at indexes: 3, 6, 9, 12, 15
Function get_rm_1():
X[r,c] = 0 if |r - c| > 1
X[r,c] = 3 * r - 2 if r == c + 0 — Main diagonal
X[r,c] = 3 * r - 1 if r == c - 1 — Upper diagonal
X[r,c] = 3 * r - 3 if r == c + 1 — Lower diagonal
Always subject to 0 < r <= N; 0 <= c <= N
Column-major instead of row-major order
You are correct. Here you are considering row-major order. I
wanted to store the elements in the array as:
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
as per your example
Column-Major Order with One-Based Indexing
So, you can make a parallel argument to the one I gave. Annotate
your column-major array Z similarly to the way I annotated the
row-major array Y:
D L U D L U D L U D L U D L U D
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
Index 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Elements on main diagonal at indexes: 1, 4, 7, 10, 13, 16
Elements on upper diagonal at indexes: 3, 6, 9, 12, 15
Elements on lower diagonal at indexes: 2, 5, 8, 11, 14
Function get_cm_1():
X[r,c] = 0 if |c - r| > 1
X[r,c] = 3 * c - 2 if c == r + 0 — Main diagonal
X[r,c] = 3 * c - 3 if c == r + 1 — Upper diagonal
X[r,c] = 3 * c - 1 if c == r - 1 — Lower diagonal
Always subject to 0 < r <= N; 0 < c <= N.
Column-Major Order with Zero-Based Indexing
D L U D L U D L U D L U D L U D
Z = { 1, 3, 2, 4, 6, 5, 7, 9, 8, 10, 12, 11, 13, 15, 14, 16 }
Index 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Elements on main diagonal at indexes: 0, 3, 6, 9, 12, 15
Elements on upper diagonal at indexes: 2, 5, 8, 11, 14
Elements on lower diagonal at indexes: 1, 4, 7, 10, 13
Function get_cm_0():
X[r,c] = 0 if |c - r| > 1
X[r,c] = 3 * c + 0 if c == r + 0 — Main diagonal
X[r,c] = 3 * c - 1 if c == r + 1 — Upper diagonal
X[r,c] = 3 * c + 1 if c == r - 1 — Lower diagonal
Always subject to 0 <= r < N; 0 <= c < N.
Code
Source file td59.c:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
enum { N = 6 };
static const int X[N][N] =
{
{ 1, 2, 0, 0, 0, 0 },
{ 3, 4, 5, 0, 0, 0 },
{ 0, 6, 7, 8, 0, 0 },
{ 0, 0, 9, 10, 11, 0 },
{ 0, 0, 0, 12, 13, 14 },
{ 0, 0, 0, 0, 15, 16 },
};
static const int Y[3*N-2] =
{
1, 2, 3, 4, 5, 6, 7, 8,
9, 10, 11, 12, 13, 14, 15, 16,
};
static const int Z[3*N-2] =
{
1, 3, 2, 4, 6, 5, 7, 9,
8, 10, 12, 11, 13, 15, 14, 16,
};
/* rm = row major, cm = column major, 0 = zero-based, 1 = one-based */
static int get_rm_0(int r, int c)
{
assert(r >= 0 && r < N);
assert(c >= 0 && c < N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (r == c) /* Main diagonal */
index = 3 * r + 0;
else if (r == c - 1) /* Upper diagonal */
index = 3 * r + 1;
else
{
assert(r == c + 1);
index = 3 * r - 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Y[index]);
return Y[index];
}
static int get_rm_1(int r, int c)
{
assert(r > 0 && r <= N);
assert(c > 0 && c <= N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (r == c) /* Main diagonal */
index = 3 * r - 2;
else if (r == c - 1) /* Upper diagonal */
index = 3 * r - 1;
else
{
assert(r == c + 1);
index = 3 * r - 3; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Y[index-1]);
return Y[index-1];
}
static int get_cm_0(int r, int c)
{
assert(r >= 0 && r < N);
assert(c >= 0 && c < N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (c == r) /* Main diagonal */
index = 3 * c + 0;
else if (c == r + 1) /* Upper diagonal */
index = 3 * c - 1;
else
{
assert(c == r - 1);
index = 3 * c + 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Z[index]);
return Z[index];
}
static int get_cm_1(int r, int c)
{
assert(r > 0 && r <= N);
assert(c > 0 && c <= N);
//printf("%s(): r = %d, c = %d\n", __func__, r, c);
if (abs(r - c) > 1) /* Off tridiagonal */
return 0;
int index;
if (c == r) /* Main diagonal */
index = 3 * c - 2;
else if (c == r + 1) /* Upper diagonal */
index = 3 * c - 3;
else
{
assert(c == r - 1);
index = 3 * c - 1; /* Lower diagonal */
}
//printf("%s(): r = %d, c = %d, i = %d, v = %d\n", __func__, r, c, index, Z[index-1]);
return Z[index-1];
}
static void dump_matrix(const char *tag, int rows, int cols,
const int matrix[rows][cols], int base)
{
printf("%s (%dx%d) %d-based:\n", tag, rows, cols, base);
printf(" c =");
for (int c = 0; c < cols; c++)
printf(" %2d", c + base);
putchar('\n');
for (int r = 0; r < rows; r++)
{
printf("r = %d: {", r + base);
for (int c = 0; c < cols; c++)
printf(" %2d", matrix[r][c]);
puts(" }");
}
putchar('\n');
}
static void dump_vector(const char *tag, int values, const int vector[values], int base)
{
printf("Vector %s (%d) %d-based:\n", tag, values, base);
int len = 0;
const char *pad = "";
for (int i = 0; i < values; i++)
{
len += printf("%s[%2d] = %2d,", pad, i + base, vector[i]);
pad = " ";
if (len > 80)
{
putchar('\n');
len = 0;
pad = "";
}
}
if (len > 0)
putchar('\n');
putchar('\n');
}
static void reconstruct_matrix(const char *matrix_tag, const char *vector_tag,
int values, const int vector[values],
int rows, int cols, int (*getter)(int r, int c), int base)
{
dump_vector(vector_tag, values, vector, base);
printf("%s (%dx%d) %d-based:\n", matrix_tag, rows, cols, base);
for (int r = 0 + base; r < rows + base; r++)
{
printf("r = %d: {", r);
for (int c = 0 + base; c < cols + base; c++)
printf(" %2d", (*getter)(r, c));
puts(" }");
}
putchar('\n');
}
int main(void)
{
dump_matrix("Tridiagonal matrix X", N, N, X, 0);
reconstruct_matrix("Reconstructed Row-Major Matrix", "Y", 3 * N - 2, Y, N, N, get_rm_0, 0);
dump_matrix("Tridiagonal matrix X", N, N, X, 1);
reconstruct_matrix("Reconstructed Row-Major Matrix", "Y", 3 * N - 2, Y, N, N, get_rm_1, 1);
puts("\n\n");
dump_matrix("Tridiagonal matrix X", N, N, X, 0);
reconstruct_matrix("Reconstructed Column-Major Matrix", "Z", 3 * N - 2, Z, N, N, get_cm_0, 0);
dump_matrix("Tridiagonal matrix X", N, N, X, 1);
reconstruct_matrix("Reconstructed Column-Major Matrix", "Z", 3 * N - 2, Z, N, N, get_cm_1, 1);
return 0;
}
There are many possible changes that could be made to this code.
Use functions get_[cr]m_[01]_idx() to get the array index in the vector. They would return -1 when the cell is off the tri-diagonal.
Use a modified vector (Y, Z) which has an extra element with value 0 at the start. Use const int *Y1 = &Y[1]; and then you can use: int val = Y1[get_rm_1_idx(r, c)]; to get the value.
Revise the get_[cr]m_[01]() functions to take the vector instead of using global variables Y and Z.
Rename the functions get_[cr]m_[01]() functions using get_[cr]m_[01]_val() to indicate that they get the value.
Add printing to report the index into the vectors Y and Z at which the value is found.
Output
Tridiagonal matrix X (6x6) 0-based:
c = 0 1 2 3 4 5
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Vector Y (16) 0-based:
[ 0] = 1, [ 1] = 2, [ 2] = 3, [ 3] = 4, [ 4] = 5, [ 5] = 6, [ 6] = 7, [ 7] = 8,
[ 8] = 9, [ 9] = 10, [10] = 11, [11] = 12, [12] = 13, [13] = 14, [14] = 15, [15] = 16,
Reconstructed Row-Major Matrix (6x6) 0-based:
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 1-based:
c = 1 2 3 4 5 6
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Vector Y (16) 1-based:
[ 1] = 1, [ 2] = 2, [ 3] = 3, [ 4] = 4, [ 5] = 5, [ 6] = 6, [ 7] = 7, [ 8] = 8,
[ 9] = 9, [10] = 10, [11] = 11, [12] = 12, [13] = 13, [14] = 14, [15] = 15, [16] = 16,
Reconstructed Row-Major Matrix (6x6) 1-based:
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 0-based:
c = 0 1 2 3 4 5
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Vector Z (16) 0-based:
[ 0] = 1, [ 1] = 3, [ 2] = 2, [ 3] = 4, [ 4] = 6, [ 5] = 5, [ 6] = 7, [ 7] = 9,
[ 8] = 8, [ 9] = 10, [10] = 12, [11] = 11, [12] = 13, [13] = 15, [14] = 14, [15] = 16,
Reconstructed Column-Major Matrix (6x6) 0-based:
r = 0: { 1 2 0 0 0 0 }
r = 1: { 3 4 5 0 0 0 }
r = 2: { 0 6 7 8 0 0 }
r = 3: { 0 0 9 10 11 0 }
r = 4: { 0 0 0 12 13 14 }
r = 5: { 0 0 0 0 15 16 }
Tridiagonal matrix X (6x6) 1-based:
c = 1 2 3 4 5 6
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Vector Z (16) 1-based:
[ 1] = 1, [ 2] = 3, [ 3] = 2, [ 4] = 4, [ 5] = 6, [ 6] = 5, [ 7] = 7, [ 8] = 9,
[ 9] = 8, [10] = 10, [11] = 12, [12] = 11, [13] = 13, [14] = 15, [15] = 14, [16] = 16,
Reconstructed Column-Major Matrix (6x6) 1-based:
r = 1: { 1 2 0 0 0 0 }
r = 2: { 3 4 5 0 0 0 }
r = 3: { 0 6 7 8 0 0 }
r = 4: { 0 0 9 10 11 0 }
r = 5: { 0 0 0 12 13 14 }
r = 6: { 0 0 0 0 15 16 }
Assuming d is the main diagonal, a is the "above" diagonal, and b is the "below" diagonal:
+---+---+---+---+---+---+---+---+
| d | a | 0 | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| b | d | a | 0 | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | b | d | a | 0 | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | b | d | a | 0 | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | b | d | a | 0 | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | b | d | a | 0 |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | b | d | a |
+---+---+---+---+---+---+---+---+
| 0 | 0 | 0 | 0 | 0 | 0 | b | d |
+---+---+---+---+---+---+---+---+
Note that the problem assumes indexes are "origin 1" (e.g. 1 <= i <= n) but C arrays want "origin 0" (e.g. 0 <= i < n)
We can use an "inner" struct to represent the Y array (e.g. elem_t) and the basic functions are:
#include <stdio.h>
#include <stdlib.h>
// sparse matrix Y vector
typedef struct {
int a; // above diagonal
int d; // main diagonal
int b; // below diagonal
} elem_t;
// sparse matrix
typedef struct {
int n;
elem_t *base;
} sparse_t;
// sparse_create -- create sparse tridiagonal matrix
sparse_t *
sparse_create(int n)
{
sparse_t *mtx = malloc(sizeof(*mtx));
mtx->n = n;
mtx->base = calloc(n,sizeof(*mtx->base));
return mtx;
}
// sparse_pointer -- point to sparse matrix element
int *
sparse_pointer(sparse_t *mtx,int coli,int rowi)
{
int n = mtx->n;
elem_t *eptr;
int *iptr = NULL;
// convert to origin 0
coli -= 1;
rowi -= 1;
do {
// check column bounds
if (coli < 0)
break;
if (coli >= n)
break;
// check row bounds
if (rowi < 0)
break;
if (rowi >= n)
break;
eptr = &mtx->base[coli];
// main diagonal
if (rowi == coli) {
iptr = &eptr->d;
break;
}
// above diagnonal
if ((rowi == (coli - 1)) && (coli > 0)) {
iptr = &eptr->a;
break;
}
// below diagnonal
if ((rowi == (coli + 1)) && (coli < (n - 1))) {
iptr = &eptr->b;
break;
}
} while (0);
return iptr;
}
// sparse_getval -- get matrix value
int
sparse_getval(sparse_t *mtx,int coli,int rowi)
{
int *iptr = sparse_pointer(mtx,coli,rowi);
int val;
if (iptr != NULL)
val = *iptr;
else
val = 0;
return val;
}
// sparse_setval -- set matrix value
void
sparse_setval(sparse_t *mtx,int coli,int rowi,int val)
{
int *iptr = sparse_pointer(mtx,coli,rowi);
if (iptr != NULL)
*iptr = val;
}
By contrast, a regular/full matrix would be:
#include <stdio.h>
#include <stdlib.h>
// regular/full matrix
typedef struct {
int n;
int *base;
} regmtx_t;
// regmtx_create -- create regular matrix
regmtx_t *
regmtx_create(int n)
{
regmtx_t *mtx = malloc(sizeof(*mtx));
mtx->n = n;
mtx->base = calloc(n * n,sizeof(*mtx->base));
return mtx;
}
// regmtx_pointer -- point to regular matrix element
int *
regmtx_pointer(regmtx_t *mtx,int coli,int rowi)
{
int *iptr = NULL;
// convert to origin 0
coli -= 1;
rowi -= 1;
do {
// check column bounds
if (coli < 0)
break;
if (coli >= mtx->n)
break;
// check row bounds
if (rowi < 0)
break;
if (rowi >= mtx->n)
break;
iptr = &mtx->base[(coli * mtx->n) + rowi];
} while (0);
return iptr;
}
Related
How can i create proportionnel matrix from an existing matrix
Starting matrix: tab[2][3] Values: 1 0 1 0 1 0 I want to create this matrix (rows and cols are proportionnel to our tab[2][3] by x50): tab[100][150] Values: for row 0 to 50: col 0 to 50 = 1 col 51 to 100 = 0 col 101 to 150 = 1 for row 51 to 100 col 0 to 50 = 0 col 51 to 100 = 1 col 101 to 150 = 0 I need help for creating this matrix in c Thank you
I feel cheap answering this trivial question with a trivial bit of code(but since 101010 is binary for 42, a tribute to Douglas Adams is not to be ignored.) int main() { int base[2][3] = { { 1, 0, 1, }, { 0, 1, 0 } }; int big[2*50][3*50}; for( int r = 0; r < 2 * 50; r++ ) for( int c = 0; c < 3 * 50; c++ ) big[r][c] = base[r/50][c/50]; return 0; } Generalising this (and improving it) is left as an exercise for the reader. (Here is another recent answer (today) involving DNA (Douglas Noel Adams) https://stackoverflow.com/a/74765117/17592432 Merry Christmas!)
Implementing 8-Connectivity Hoshen-Kopelman Algorithm in C
I found here an implementation for Hoshen-Kopelman Algorithm, But it checks neighbors only up and left, meaning that a diagonal connection is not considered a connection. How can I improve this code so that even a diagonal connection will be considered a connection? In the following example I expect 1 object and not 7 objects: 4 5 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 --input-- 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 --output-- 1 0 2 0 3 0 4 0 5 0 6 0 7 0 0 0 0 7 0 0 HK reports 7 clusters found This is the implementation (full code can be found here): #include <stdio.h> #include <stdlib.h> #include <assert.h> /* Implementation of Union-Find Algorithm */ /* The 'labels' array has the meaning that labels[x] is an alias for the label x; by following this chain until x == labels[x], you can find the canonical name of an equivalence class. The labels start at one; labels[0] is a special value indicating the highest label already used. */ int* labels; int n_labels = 0; /* length of the labels array */ /* uf_find returns the canonical label for the equivalence class containing x */ int uf_find(int x) { int y = x; while (labels[y] != y) y = labels[y]; while (labels[x] != x) { int z = labels[x]; labels[x] = y; x = z; } return y; } /* uf_union joins two equivalence classes and returns the canonical label of the resulting class. */ int uf_union(int x, int y) { return labels[uf_find(x)] = uf_find(y); } /* uf_make_set creates a new equivalence class and returns its label */ int uf_make_set(void) { labels[0] ++; assert(labels[0] < n_labels); labels[labels[0]] = labels[0]; return labels[0]; } /* uf_intitialize sets up the data structures needed by the union-find implementation. */ void uf_initialize(int max_labels) { n_labels = max_labels; labels = calloc(sizeof(int), n_labels); labels[0] = 0; } /* uf_done frees the memory used by the union-find data structures */ void uf_done(void) { n_labels = 0; free(labels); labels = 0; } /* End Union-Find implementation */ #define max(a,b) (a>b?a:b) #define min(a,b) (a>b?b:a) /* print_matrix prints out a matrix that is set up in the "pointer to pointers" scheme (aka, an array of arrays); this is incompatible with C's usual representation of 2D arrays, but allows for 2D arrays with dimensions determined at run-time */ void print_matrix(int** matrix, int m, int n) { for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) printf("%3d ", matrix[i][j]); printf("\n"); } } /* Label the clusters in "matrix". Return the total number of clusters found. */ int hoshen_kopelman(int** matrix, int m, int n) { uf_initialize(m * n / 2); /* scan the matrix */ for (int y = 0; y < m; y++) { for (int x = 0; x < n; x++) { if (matrix[y][x]) { // if occupied ... int up = (y == 0 ? 0 : matrix[y - 1][x]); // look up int left = (x == 0 ? 0 : matrix[y][x - 1]); // look left switch (!!up + !!left) { case 0: matrix[y][x] = uf_make_set(); // a new cluster break; case 1: // part of an existing cluster matrix[y][x] = max(up, left); // whichever is nonzero is labelled break; case 2: // this site binds two clusters matrix[y][x] = uf_union(up, left); break; } } } } /* apply the relabeling to the matrix */ /* This is a little bit sneaky.. we create a mapping from the canonical labels determined by union/find into a new set of canonical labels, which are guaranteed to be sequential. */ int* new_labels = calloc(sizeof(int), n_labels); // allocate array, initialized to zero for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (matrix[i][j]) { int x = uf_find(matrix[i][j]); if (new_labels[x] == 0) { new_labels[0]++; new_labels[x] = new_labels[0]; } matrix[i][j] = new_labels[x]; } int total_clusters = new_labels[0]; free(new_labels); uf_done(); return total_clusters; } /* This procedure checks to see that any occupied neighbors of an occupied site have the same label. */ void check_labelling(int** matrix, int m, int n) { int N, S, E, W; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (matrix[i][j]) { N = (i == 0 ? 0 : matrix[i - 1][j]); S = (i == m - 1 ? 0 : matrix[i + 1][j]); E = (j == n - 1 ? 0 : matrix[i][j + 1]); W = (j == 0 ? 0 : matrix[i][j - 1]); assert(N == 0 || matrix[i][j] == N); assert(S == 0 || matrix[i][j] == S); assert(E == 0 || matrix[i][j] == E); assert(W == 0 || matrix[i][j] == W); } } /* The sample program reads in a matrix from standard input, runs the HK algorithm on it, and prints out the results. The form of the input is two integers giving the dimensions of the matrix, followed by the matrix elements (with data separated by whitespace). a sample input file is the following: 8 8 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 1 1 0 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 0 1 this sample input gives the following output: --input-- 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 1 0 0 0 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 0 1 0 1 1 0 0 1 1 1 0 1 1 1 1 1 0 0 0 1 0 0 0 1 1 1 0 1 --output-- 1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 1 2 0 0 0 0 2 0 1 2 0 0 2 0 2 0 1 2 0 0 2 0 2 0 1 2 0 0 2 2 2 0 1 2 2 2 2 0 0 0 1 0 0 0 2 2 2 0 1 HK reports 2 clusters found */ int main(int argc, char** argv) { int m, n; int** matrix; /* Read in the matrix from standard input The whitespace-deliminated matrix input is preceeded by the number of rows and number of columns */ while (2 == scanf_s("%d %d", &m, &n)) { // m = rows, n = columns matrix = (int**)calloc(m, sizeof(int*)); for (int i = 0; i < m; i++) { matrix[i] = (int*)calloc(n, sizeof(int)); for (int j = 0; j < n; j++) scanf_s("%d", &(matrix[i][j])); } printf_s(" --input-- \n"); print_matrix(matrix, m, n); printf(" --output-- \n"); /* Process the matrix */ int clusters = hoshen_kopelman(matrix, m, n); /* Output the result */ print_matrix(matrix, m, n); check_labelling(matrix, m, n); printf("HK reports %d clusters found\n", clusters); for (int i = 0; i < m; i++) free(matrix[i]); free(matrix); } return 0; } I tried to change the function hoshen_kopelman as described below, but I still get 2 objects instead of 1: int hoshen_kopelman(int** matrix, int m, int n) { uf_initialize(m * n / 2); /* scan the matrix */ for (int y = 0; y < m; y++) { for (int x = 0; x < n; x++) { if (matrix[y][x]) { // if occupied ... int up = (y == 0 ? 0 : matrix[y - 1][x]); // look up int left = (x == 0 ? 0 : matrix[y][x - 1]); // look left // ----------- THE NEW CODE ------------- if (x > 0) { if (up == 0 && y > 0) // left+up up = matrix[y - 1][x - 1]; if (left == 0 && y < m - 1) // left+down left = matrix[y + 1][x - 1]; } // ---------- END NEW CODE -------------- switch (!!up + !!left) { case 0: matrix[y][x] = uf_make_set(); // a new cluster break; case 1: // part of an existing cluster matrix[y][x] = max(up, left); // whichever is nonzero is labelled break; case 2: // this site binds two clusters matrix[y][x] = uf_union(up, left); break; } } } } /* apply the relabeling to the matrix */ /* This is a little bit sneaky.. we create a mapping from the canonical labels determined by union/find into a new set of canonical labels, which are guaranteed to be sequential. */ int* new_labels = calloc(sizeof(int), n_labels); // allocate array, initialized to zero for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (matrix[i][j]) { int x = uf_find(matrix[i][j]); if (new_labels[x] == 0) { new_labels[0]++; new_labels[x] = new_labels[0]; } matrix[i][j] = new_labels[x]; } int total_clusters = new_labels[0]; free(new_labels); uf_done(); return total_clusters; } The following output is now obtained (I am expecting 1 and got 2): 4 5 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 --input-- 1 0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 0 --output-- 1 0 1 0 1 0 1 0 1 0 2 0 1 0 0 0 0 1 0 0 HK reports 2 clusters found What is the correct way to correct the code to check all 8 neighbors?
I led you astray saying to check down-left. The algorithm relies on the current node it is examining being after all the neighbors it checks. So you need to check left, up, up-left, and up-right. You can use this in place of your new code: if (y > 0) { if (left == 0 && x > 0) // left+up left = matrix[y - 1][x - 1]; if (up == 0 && x < n-1) // right+up up = matrix[y - 1][x + 1]; }
Loop through 2-dim matrix diagonally, but the other way
I'm having trouble looping through an NxM matrix the other way. This probably isn't everything I could have tried but I already tried finding this on google, and using all kind of different border-values, also tried substracting one index of the other over and over, but I can't seem to get a hang of it. The last thing I did, was create a copy of the matrix, and swap the rows through by for loop until last was first and first was last. this works, but is not what I want. The Loop down there starts at the top Left of the matrix and works through from bottom left to top right. I want anotherone to start at the bottom left and work through from bottom right to top left, or from top left to bottom right. Loop: for(int i = 0; i + 1 < ROWCOUNT + COLCOUNT; i++) { printf("\n"); for(int j = 0; j - 1 < i; j++) { int n = i - j; int m = j; if(n < ROWCOUNT && m < COLCOUNT) { printf(" %d %d ", n, m); } } } Output: 0 0 1 0 0 1 2 0 1 1 0 2 3 0 2 1 1 2 0 3 4 0 3 1 2 2 1 3 0 4 5 0 4 1 3 2 2 3 1 4 0 5 5 1 4 2 3 3 2 4 1 5 5 2 4 3 3 4 2 5 5 3 4 4 3 5 5 4 4 5 5 5 EDIT: I will try to show you what I'm trying to do. A B C D E F G H I J K L M N O P Q R S T U V W X Y Z AA AB AC AD AE AF AG AH AI AJ My loop goes through this 6x6 matrix the following way: A G B M H C S N I D Y T O J E AE Z U P K F AF AA V Q L AG AB W R AH AC X AI AD AJ I am searching for a loop to go trough the other way. Basically somehow like this: AE AF Y AG Z S AH AA T M AI AB U N G AJ AC V O H A AD W P I B R K D L E F EDIT: #pmg provided me with a solution. Thanks!
Not sure about what you are looking for, but just loop on the other way: #include "stdio.h" #define ROWCOUNT 6 #define COLCOUNT 6 int main(void) { for(int i = ROWCOUNT - 1; i >= 0; i--) { for(int j = 0; j < COLCOUNT; j++) { printf(" %d %d ", i, j); } printf("\n"); } } output 5 0 5 1 5 2 5 3 5 4 5 5 4 0 4 1 4 2 4 3 4 4 4 5 3 0 3 1 3 2 3 3 3 4 3 5 2 0 2 1 2 2 2 3 2 4 2 5 1 0 1 1 1 2 1 3 1 4 1 5 0 0 0 1 0 2 0 3 0 4 0 5
Both diagonals have the property that every cell indices add to a constant or their difference is constant. In your case, the indices must add to a constant. Just consider a cell (the first cell to be printed) that is on the diagonal you want, and then as you add to one index, subtract to the other the same quantity, making the sum the same. This way you can begin with an add of zero: i = 0; j = 0; then, add one to the sum and follow: pru.c: #include <stdio.h> #include <getopt.h> #include <stdlib.h> int N = 10; int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "n:")) != EOF) { switch(opt) { case 'n': N = atoi(optarg); break; } } /* while */ int sum; /* maximum value is (N-1) + (N-1) = 2N-2 */ for (sum = 0; sum <= 2*N - 2; sum++) { /* initial values */ int i = sum < N ? sum : N-1; /* will be decremented */ int j = sum - i; /* must add to sum, will be incremented */ char *sep = ""; for (; i >= 0 && j < N; i--, j++) { printf("%sA[%d, %d]", sep, i, j); sep = " -> "; } printf("\n"); } } The example code prints the sequence of indices to print: $ pru -n 5 A[0, 0] A[1, 0] -> A[0, 1] A[2, 0] -> A[1, 1] -> A[0, 2] A[3, 0] -> A[2, 1] -> A[1, 2] -> A[0, 3] A[4, 0] -> A[3, 1] -> A[2, 2] -> A[1, 3] -> A[0, 4] A[4, 1] -> A[3, 2] -> A[2, 3] -> A[1, 4] A[4, 2] -> A[3, 3] -> A[2, 4] A[4, 3] -> A[3, 4] A[4, 4] In the case of the difference of indices, you have: pru2.c #include <stdio.h> #include <getopt.h> #include <stdlib.h> int N = 10; int main(int argc, char **argv) { int opt; while ((opt = getopt(argc, argv, "n:")) != EOF) { switch(opt) { case 'n': N = atoi(optarg); break; } } /* while */ int dif; /* difference ranges from -(N-1) to +(N-1) */ for (dif = -N+1; dif <= N-1; dif++) { /* initial values, dif = i - j */ int i = dif > 0 ? 0 : dif; /* will be incremented */ int j = dif > 0 ? -dif : 0; /* will be incremented */ char *sep = ""; for (; i < N && j < N; i++, j++) { printf("%sA[%d, %d]", sep, i, j); sep = " -> "; } printf("\n"); } } that will give: A[4, 0] A[3, 0] -> A[4, 1] A[2, 0] -> A[3, 1] -> A[4, 2] A[1, 0] -> A[2, 1] -> A[3, 2] -> A[4, 3] A[0, 0] -> A[1, 1] -> A[2, 2] -> A[3, 3] -> A[4, 4] A[0, 1] -> A[1, 2] -> A[2, 3] -> A[3, 4] A[0, 2] -> A[1, 3] -> A[2, 4] A[0, 3] -> A[1, 4] A[0, 4]
Convert COO to CSR format in c++
I have a matrix in the COO format. More specifically, there are three matrices row_index, column_index, value. Can you help me to convert this matrix format in CSR format with an efficient, not computationally expensive way, using C language? Are there libraries for this purpose? Example: COO format: row_index col_index value 1 1 1 1 2 -1 1 3 -3 2 1 -2 2 2 5 3 3 4 3 4 6 3 5 4 4 1 -4 4 3 2 4 4 7 5 2 8 5 5 -5
I know this is an old thread, but, assuming the COO data is (i,j) ordered/sorted, as you show, a sequential algorithm to convert from COO to CSR is: int main() { // Example from Wikipedia (https://en.wikipedia.org/wiki/Sparse_matrix) // Matrix: // 10 20 0 0 0 0 // 0 30 0 40 0 0 // 0 0 50 60 70 0 // 0 0 0 0 0 80 // Expected output: // csr_val: 10 20 30 40 50 60 70 80 // csr_col: 0 1 1 3 2 3 4 5 // csr_row: 0 2 4 7 8 const int nnz = 8; // number of non-zero elements const int rows = 4; // number of matrix rows const int cols = 6; // number of matrix columns // coo data: double coo_val[nnz] = { 10.0, 20.0, 30.0, 40.0, 50.0, 60.0, 70.0, 80.0 }; int coo_row[nnz] = { 0, 0, 1, 1, 2, 2, 2, 3 }; int coo_col[nnz] = { 0, 1, 1, 3, 2, 3, 4, 5 }; // coo to csr: double csr_val[nnz] = { 0 }; int csr_col[nnz] = { 0 }; int csr_row[rows + 1] = { 0 }; for (int i = 0; i < nnz; i++) { csr_val[i] = coo_val[i]; csr_col[i] = coo_col[i]; csr_row[coo_row[i] + 1]++; } for (int i = 0; i < rows; i++) { csr_row[i + 1] += csr_row[i]; } } Notice that, assuming the COO data is (i,j) ordered/sorted, csr_col = coo_col and csr_val = coo_val, so you just need to obtain csr_row, and that is as simples as: int csr_row[rows + 1] = { 0 }; for (int i = 0; i < nnz; i++) csr_row[coo_row[i] + 1]++; for (int i = 0; i < rows; i++) csr_row[i + 1] += csr_row[i]; So, in conclusion, you can easily achieve what you want with the 5 lines of code presented above. Final note: The proposed method has no considerations for duplicated COO entries.
Intel MKL documentation (for mkl_csrcoo) states: Converts a sparse matrix in the CSR format to the coordinate format and vice versa. And according to the above link you should set job: if job(1)=1, the matrix in the coordinate format is converted to the CSR format.
An implementation of this conversion is included in scipy (open source: BSD-licensed), the function coo_tocsr in particular. It is in C++, but this is only in order to template the data and index types, and in order to initialise a data structure, so it can easily be transformed into C code.
How to iterate over the series: 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 7, 8, 8, 9 … without using recursion?
Is am trying to figure out how to generate this sequence of numbers in C. 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 8, 9 … The sequence is generated by forming a triangle of numbers as shown below: 0 1 2 3 4 5 6 7 8 9 ... Next two numbers in series are located as follows: Next number is located directly below Next to next is located one place to the right. 0 |\ 1 2 Series -> 0, 1, 2 0 |\ 1 2 |\|\ 3 4 5 Series -> 0, 1, 2, 3, 4, 4, 5, ........ How can I traverse this number triangle to get this sequence in C? It means that 0 is replaced with 1 and 2 1 is replaced with 3 and 4 2 is replaced with 4 and 5 0 |\ 1 2 |\|\ 3 4 5 |\|\|\ 6 7 8 9 Series -> 0, 1, 2, 3, 4, 4, 5, 6, 7, 7, 8, 7, 8, 8, 9 ........ It means that I. Solving 0 0 leads to 1 and 2 0 -> 1 - 2 0 1 2 II. Solving 1 and 2 1 leads to 3 and 4 1 -> 3 - 4 0 1 2 3 4 2 leads to 4 and 5 2 -> 4 - 5 0 1 2 3 4 4 5 III. Solving 3, 4, 4, 5 3 leads to 6 and 7 3 -> 6 - 7 0 1 2 3 4 4 5 6 7 4 leads to 7 and 8 4 -> 7 - 8 0 1 2 3 4 4 5 6 7 7 8 4 leads to 7 and 8 4 -> 7 - 8 0 1 2 3 4 4 5 6 7 7 8 7 8 5 leads to 8 and 9 5 -> 8 - 9 0 1 2 3 4 4 5 6 7 7 8 7 8 8 9 My apologies for not explaining properly. I hope I explain it this time.
I assume (based on the description) your sequence should be indeed 0 1 2 3 4 4 5 6 7 7 8 8 9 10 11 11 12 12 13 13 14 etc. You can work with it with the code like that: int nextRowStart = 0; int nextRowSize = 1; for (int curr = 0; /*put some ending condition here*/; curr++) { yield(curr) if (curr != nextRowStart - 1 && curr != nextRowStart) yield(curr); if (curr == nextRowStart) { nextRowStart += nextRowSize; nextRowSize++; } } void yield(int x) { printf("%d ", x); } With the changed question, the new one can be done recursively This is the solution in C#: IEnumerable<int> Generate(int level) { if (level == 0) { yield return 0; yield break; } int diff = level; foreach (int n in Generate(level - 1)) { yield return n + diff; yield return n + diff + 1; } } var result = Enumerable.Range(0, maxLevel).SelectMany(Generate); It would take some time to translate it into C... C solution: void Generate(int level, int* resultsize, int** result) { if (level == 0) { *result = (int*)malloc(sizeof(int)); (*result)[0] = 0; *resultsize = 1; } else { int recResultSize; int* recResult; Generate(level - 1, &recResultSize, &recResult); *resultsize = recResultSize * 2; *result = (int*)malloc(*resultsize * sizeof(int)); for (int i = 0; i < recResultSize; i++) { (*result)[2*i] = recResult[i] + level; (*result)[2*i + 1] = recResult[i] + level + 1; } free(recResult); } }
This is the code which gives the exact result and solves the problem. I came at this result just when #Lundin asked me to post my code , I tried again and I was successful. Thanks guys. #include<stdio.h> int in; int main(){ int ik, it, icount = 0, ih, temp, ig = 1; int aisum[100]; aisum[0] = 0; scanf("%d",&in); printf("0\n"); it = 1;ih = 0;temp = 2; for(icount = 0,ig = 1; icount <= in; icount++){ for(ik = 0; ik<2; ik++){ aisum[ig] = aisum[icount] + it + ik ; printf("%d ",aisum[ig]); ig++; } if(aisum[icount] == ih){ printf("\n"); it++; ih += temp; temp++; } } return 0; } /*Input the number of elements to be processed*/ /*icount will account for new elements to be formed like if we look at pascal triangle 0 will form 1 and 2 1 will form 3 and 4 */ /*ig will account for array indices*/ /*it will account for the periodic addition */ /*ih checks for the codnition for it to increement 0 1 2 3 4 5 it will be increemented at 0, 2, 5 ... */
The simplest solution I can give from below triangle to required order is... 0 1 2 3 4 5 6 7 8 9 printing start and end nodes of each line and printing center elements 2 times each... for each line start will be equals to previous end+1... end will be equal to end+1+count... count will be incremented by 1 for each line... CPP Program: #include<iostream> using namespace std; int main() { int start=1,end=2,count=1; cout<<0<<" "; while(count<5) { cout<<start<<" "; for(int i=start+1;i<end;i++) { cout<<i<<" "<<i<<" "; } cout<<end<<" "; count++; start=end+1; end=start+count; } return 0; }