Convert COO to CSR format in c++ - 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.

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!)

Represent a tridiagonal sparse matrix in column major order

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;
}

Loop through a nested loop two-by two in C

I would like to loop through two arrays in a semi-zipped fashion, such that for as many entries as possible, the following pattern is observed:
arr1[i] arr2[j]
arr1[i] arr2[j+1]
arr1[i+1] arr2[j+2]
arr1[i+1] arr2[j+3]
....
For example, if len arr1 is 96 and len arr2 is 3, I would like to see
0 0
0 1
1 2
1 0
2 1
2 2
3 0
3 1
4 2
4 0
5 1
5 2
I'm having a little trouble getting the logic exactly right; any help would be greatly appreciated
Pseudocode:
i = 0;
for (x = 0; i < arr1.len; ++x) {
i = x / 2; // integer division
j = x % arr2.len;
// use arr1[i] and arr2[j]
}
Use integer division to repeat a value multiple times before moving on to the next value (e.g. 0 0 1 1 2 2 3 3 ...), where the number of times you want to repeat a value is equal to the denominator.
Use modulo division to repeat a sequence of values indefinitely (e.g. 0 1 2 0 1 2 0 1 2 ...), where the number of items in the sequence is equal to the denominator.
If I have understood you correctly you need a loop like the one shown in the demonstrative program below.
#include <stdio.h>
#define N 10
#define M 3
int main( void )
{
int a[N];
int b[N];
for ( int i = 0; i < N; i++ ) a[i] = i;
for ( int i = 0; i < M; i++ ) b[i] = i;
for (int i = 0, j = 0, k = 1; i < N; i += k ^= 1, j = ( j + 1 ) % M)
{
printf( "%d %d\n", a[i] , b[j] );
}
}
The program output is
0 0
0 1
1 2
1 0
2 1
2 2
3 0
3 1
4 2
4 0
5 1
5 2
6 0
6 1
7 2
7 0
8 1
8 2
9 0
9 1

Creating a 2D array board

I am trying to create a 2d matrix board which side is determined by the user input. I created the two D array but it is not printing the right numbers. For example if the user enters 3, it is suppose to create a 3 * 3 board with the number 8, 7, 6, 5, 4, 3, 2, 1, 0.
However it keeps printing the same numbers in each row eg 876, 876, 876
I know it is doing what I have written but I cant figure out how to correct it...I am thinking that I need a counter that resets to zero and perhaps the [i][j] = counter's value.
Anyway here is the code that is giving the trouble.
for (i =0; i< row; i++)
{
for (j =0; j < col; j++)
{
game [i][j] = ((row * row)-1) - j;
printf( "%i", game[i][j] );
}
How can I populate the board so it prints from (row * col) - 1 to zero. Thanks a million.
for ((i=0, k=0); i< row; i++)
{
for (j =0; j < col; j++)
{
game [i][j] = ((row * col)-1) - (k++);
printf( "%i", game[i][j] );
}
}
The basic mistake in the code is that, in each iteration, the value getting subtracted from the game[i][j] gets re-initialized to 0. Since, the value of (row * col) is constant for a given value of both, subtracting (0, 1, 2) each time from the sum results in the reproduction of the same numbers.
As given in the example, row=3, col=3, so 3*3 = 9 (Indexed from 0 to 8).
So, we do :
8 - 0 = 8
8 - 1 = 7
8 - 2 = 6
again j gets re-init to 0, so again we have,
8 - 0 = 8
8 - 1 = 7
8 - 2 = 6
.
The solution is, the value getting subtracted should get uniformly reduced, such that it doesn't get re-init inside the loop.
Result :
8 - 0 = 8
8 - 1 = 7
8 - 2 = 6
8 - 3 = 5
.
.
.
.
8 - 8 = 0.
Hope this clears the problem.
As suggested by "self", using a third variable is the easiest way (and actually the most efficient : only one decrement per iteration)
int count = row * col - 1;
for (size_t i =0; i< row; i++)
{
for (size_t j =0; j < col; j++)
{
game [i][j] = count--;
printf( "%i", game[i][j] );
}
}
Output:
24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0

Optimize a summing of array (subset problem)

In the hottest part of my program (90% of time according to gprof), I need to sum one array A into another B. Both arrays are 2^n (n is 18..24) sized and holds an integer (for simplicity, actually the element stored is mpz_t or small int array). The rule of summing: for each i in 0..2^n-1, set B[i] = sum (A[j]), where j is bit vector, and j & ~ i == 0 (in other words, k-th bit of any j can't be set to 1 if k-th bit of i is not 1).
My current code (this is a body of innermost loop) does this in the time of 2^(1.5 * n) sums, because I will iterate for each i on (in average) 2^(n/2) elements of A.
int A[1<<n]; // have some data
int B[1<<n]; // empty
for (int i = 0; i < (1<<n); i++ ) {
/* Iterate over subsets */
for (int j = i; ; j=(j-1) & i ) {
B[i] += A[j]; /* it is an `sum`, actually it can be a mpz_add here */
if(j==0) break;
}
}
My I mentioned, that almost any sum is recomputed from the values, summed earlier. I suggest, there can be code, doing the same task in the time of n* 2^n sums.
My first idea is that B[i] = B[i_without_the_most_significant_bit] + A[j_new]; where j_new is only j's having the most_significant bit from i in '1' state. This halves my time, but this is not enough (still hours and days on real problem size):
int A[1<<n];
int B[1<<n];
B[0] = A[0]; // the i==0 will not work with my idea and clz()
for (int i = 1; i < (1<<n); i++ ) {
int msb_of_i = 1<< ((sizeof(int)*8)-__builtin_clz(i)-1);
int i_wo_msb = i & ~ msb;
B[i] = B[i_wo_msb];
/* Iterate over subsets */
for (int j_new = i; ; j_new=(j_new-1) & i ) {
B[i] += A[j_new];
if(j_new==msb) break; // stop, when we will try to unset msb
}
}
Can you suggest better algorithm?
Additional image, list of i and j summed for each i for n=4:
i j`s summed
0 0
1 0 1
2 0 2
3 0 1 2 3
4 0 4
5 0 1 4 5
6 0 2 4 6
7 0 1 2 3 4 5 6 7
8 0 8
9 0 1 8 9
a 0 2 8 a
b 0 1 2 3 8 9 a b
c 0 4 8 c
d 0 1 4 5 8 9 c d
e 0 2 4 6 8 a c e
f 0 1 2 3 4 5 6 7 8 9 a b c d e f
Note the similarity of figures
PS the msb magic is from here: Unset the most significant bit in a word (int32) [C]
Divide and conquer anyone? Now not in-place.
void sums(int *a, int n, int *b) {
if (n <= 0) {
*b = *a;
return;
}
int m = 1 << (n - 1);
sums(a, n - 1, b);
sums(a + m, n - 1, b + m);
for (int i = 0; i < m; i++) {
b[m + i] += b[i];
}
}

Resources