C bug of 0.00 and -0.00 - c

C program to find the rank of the matrix.
I used the Gaussian elimination to determine the rank of the matrix. This is the method which I have used.
My code in c:
#include<stdio.h>
#include<stdlib.h>
#define min(x,y) x>y?y:x
float** create_matrix(int,int);
void input(float**,int,int);
void display(float**,int,int);
void matrix_op(float**,int,int,int,float);
void row_trans(float**,int,int);
void row_swap(float**,int,int,int);
int rank(float**,int,int);
int main()
{
int row,col;
printf("Enter number of rows and columns: ");
scanf("%d %d",&row,&col);
float** matrix=create_matrix(row,col);
input(matrix,row,col);
printf("The rank of the matrix is: %d\n",rank(matrix,row,col));
return 0;
}
float** create_matrix(int r,int c)
{
int i;
float** matrix=(float**)calloc(r,sizeof(float*));
for(i=0;i<r;i++)
*(matrix+i)=(float*)calloc(c,sizeof(float));
return matrix;
}
void input(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
scanf("%f",&matrix[i][j]);
}
}
void display(float** matrix,int r,int c)
{
int i,j;
for(i=0;i<r;i++)
{
for(j=0;j<c;j++)
printf("%.2f ",matrix[i][j]);
printf("\n");
}
}
void matrix_op(float** matrix,int c,int j,int i,float scalar)
{
int k;
for(k=0;k<c;k++)
{
matrix[j][k]+=matrix[i][k]*scalar;
}
}
void row_trans(float** matrix,int r,int i)
{
if(matrix[i][i]!=0)
{
for(int j=i+1;j<r;j++)
{
if(j==i)
continue;
if(matrix[j][i]!=0)
matrix_op(matrix,r,j,i,(-1.00)*(matrix[j][i]/matrix[i][i]));
}
}
else
{
int j=i+1;
while(j<r)
{
if(matrix[j][i]==0)
j+=1;
else
break;
}
if(j!=r)
{
row_swap(matrix,r,i,j);
row_trans(matrix,r,i);
}
}
}
void row_swap(float** matrix,int c,int i,int j)
{
for(int k=0;k<c;k++)
{
float temp=matrix[i][k];
matrix[i][k]=matrix[j][k];
matrix[j][k]=temp;
}
}
int rank(float** matrix,int r,int c)
{
int i;
int l=min(r,c);
for(i=0;i<l;i++)
{
row_trans(matrix,r,i);
display(matrix,r,c);
printf("\n");
}
i=r-1;
while(i>=0)
{
if(matrix[i][l-1]==0)
i-=1;
else
break;
}
return i+1;
}
When I input this:
Enter number of rows and columns: 5 5
3 -1 -2 3 -1
4 1 2 5 4
7 10 10 2 -3
2 -3 -6 1 -6
3 9 8 -3 -7
I get this:
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 12.33 14.67 -5.00 -0.67
0.00 -2.33 -4.67 -1.00 -5.33
0.00 10.00 10.00 -6.00 -6.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 -10.00 -10.29 -28.86
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 -0.00 -0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
3.00 -1.00 -2.00 3.00 -1.00
0.00 2.33 4.67 1.00 5.33
0.00 0.00 -10.00 -10.29 -28.86
0.00 0.00 0.00 -0.00 -0.00
0.00 0.00 0.00 0.00 0.00
The rank of the matrix is: 4
Notice that -0.00 and 0.00 are considered different.
And that is why I get rank as 4, whereas the rank should be 3.
Edit 1: In the final display we can see that, in the last column the second last row is -0.00 and the last row is 0.00. In the function rank() , the i is iterating over the zeroes of the last column and then it will return the rows- #(zeroes). But it is not considering -0.00=0.00.
Edit 2: After using double I got the same problem. After debugging I got this,
115 while(i>=0)
(gdb) p i
$4 = 3
(gdb) n
117 if(matrix[i][l-1]==0)
(gdb) p matrix[i][l-1]
$5 = 8.8817841970012523e-16
(gdb) p matrix[i][l-1]==0
$6 = 0
Edit 3:
The problem is solved after introducing precision.
double set_prec(double n)
{
return floor(pow(10,3)*n)/pow(10,3);
}
Any help will be appreciated.
Thanks in anticipation.

When you print a number in C using %.2f, the C implementation rounds it to two decimal places. Numbers such as 0.003… or −0.0001… will be printed as 0.00 or -0.00. So the fact that a number is printed as 0.00 does not mean it is 0. From the behavior you report, it is clear the numbers you have in your program are not 0 or −0. (IEEE 754 arithmetic has a −0 that is mathematically 0 but retains the sign as information the programmer may use. It compares equal to +0.)
Floating-point arithmetic only approximates real-number arithmetic. When you use floating-point arithmetic in an ordinary way, any computed result x is only an approximation of the result x you would get using real-number arithmetic. Since you have only computed x and not x, you do not have complete information about what x is, and therefore it is impossible, without special analysis and design, to know exactly what x is. Therefore, if some result x is near 0, you cannot know whether x is 0 or not.
In general, the difference between the floating-pount result x and the raal-number result x can range from 0 to infinity or can even be “not a number.” In the particular case of doing Gaussian elimination with small matrices of small integer inputs, it might be possible to prove that floating-point results sufficiently near 0 correspond to results that would be 0 if computed with real-number arithmetic. In that case, treating results close to 0 as if they were 0 could produce correct results.
This is not a correct solution in general, and rounding floating-point results to 0 or comparing with a tolerance should not be recommended in general. It is only useful in particlar limited circumstances.

Instead of comparing to 0, compare to epsilon
double epsilon = 1E-12; // tweak as you deem fit
//if (a != 0)
if (fabs(a) > epsilon)
//if (a == 0)
if (fabs(a) < epsilon)
//if (a == b)
if (fabs(a - b) < epsilon)

Related

How should I make this logic in C?

There is this linear system given by the following 2d array:
1.0 0.0 -1.0 -4.9 -5.9 -6.9 -7.9
0.0 1.0 2.0 4.4 5.4 6.4 7.4
0.0 0.0 0.0 5.7 5.7 -3.3 -3.3
0.0 0.0 0.0 2.9 2.9 2.9 2.9
0.0 0.0 0.0 7.0 -1.0 -3.0 -3.0
0.0 0.0 -20.0 -65.9 -89.9 -100.9 128.9
Whenever I get a 0 in my main diagonal (when row equals column), I want to change the order of the rows, so there's no zeroes on my main diagonal.
In this case, the row 2(counting from 0) should be traded with row 5 (also counting from 0) because with this, there is no 0s on the main diagonal.
I'm already doing that, but I'm "deleting" the first line and appending it on the end of the linear system. How should I make this logic to know where to exactly trade the rows?
The code is as follows:
void change_order(double linear[6][7], unsigned int qty) {
double aux[100];
// dynamically create an array of pointers of size `m`
double **matrix = (double **)malloc((qty + 1) * sizeof(double *));
// dynamically allocate memory of size `n` for each row
for (int r = 0; r < qty+ 1; r++) {
matrix[r] = (double *)malloc((qty + 1) * sizeof(double));
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == 0)
aux[j] = linear[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
matrix[i][j] = linear[i][j];
}
}
remove_line(matrix, 0, qty);
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
linear[i][j] = matrix[i][j];
}
}
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty+ 1; j++) {
if (i == qty- 1) {
linear[i][j] = aux[j];
}
}
}
}
void remove_line(double ** linear, int row, unsigned int qty) {
qty--;
free(linear[row]);
while (row < qty) {
linear[row] = linear[row + 1];
row++;
}
}
int main() {
double matrix[][7] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
change_order(matrix, 6);
}
Example input:
0 3 2 28
4 0 2 24
2 3 0 16
4 2 1 0
Can be exchanged for:
4 0 2 24
2 3 0 16
4 2 1 0
0 3 2 28
If I'm understanding your requirements correctly, would you please try the following:
#include <stdio.h>
#include <stdlib.h>
#define ROWS 6
#define COLS 7
/*
* search for a trade line to be swapped below the n'th row
*/
int search_trade(double matrix[][COLS], int qty, int n)
{
for (int i = n + 1; i < qty; i++) {
if (matrix[i][n] != 0.0) {
return i; // i'th row is a nice trade
}
}
return -1; // not found
}
/*
* swap m'th row and n'th row
*/
void swap(double matrix[][COLS], int qty, int m, int n)
{
int j;
double tmp;
for (j = 0; j < qty + 1; j++) {
tmp = matrix[m][j];
matrix[m][j] = matrix[n][j];
matrix[n][j] = tmp;
}
}
void change_order(double linear[][COLS], int qty) {
for (int i = 0; i < qty; i++) {
if (linear[i][i] == 0.0) { // found 0 in the diagonal
int k = search_trade(linear, qty, i); // search for the trade row
if (k < 0) { // no applicable trade
fprintf(stderr, "cannot find the row to swap. abort.\n");
exit(1);
} else {
swap(linear, qty, i, k); // swap i'th row and k'th row
}
}
}
}
/*
* print the elements of the matrix
*/
void matprint(double matrix[][COLS], int qty)
{
for (int i = 0; i < qty; i++) {
for (int j = 0; j < qty + 1; j++) {
printf("%.2f%s", matrix[i][j], j == qty ? "\n" : " ");
}
}
printf("\n");
}
int main() {
double matrix[][COLS] = {
{1.0, 0.0, -1.0, -4.9, -5.9, -6.9, -7.9},
{0.0, 1.0, 2.0, 4.4, 5.4, 6.4, 7.4},
{0.0 , 0.0, 0.0, 5.7, 5.7, -3.3, -3.3},
{0.0 , 0.0, 0.0, 2.9, 2.9, 2.9, 2.9},
{0.0 , 0.0, 0.0, 7.0, -1.0, -3.0, -3.0},
{0.0 , 0.0, -20.0, -65.9, -89.9, -100.9, 128.9}
};
matprint(matrix, ROWS);
change_order(matrix, ROWS);
matprint(matrix, ROWS);
}
Output:
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
1.00 0.00 -1.00 -4.90 -5.90 -6.90 -7.90
0.00 1.00 2.00 4.40 5.40 6.40 7.40
0.00 0.00 -20.00 -65.90 -89.90 -100.90 128.90
0.00 0.00 0.00 2.90 2.90 2.90 2.90
0.00 0.00 0.00 7.00 -1.00 -3.00 -3.00
0.00 0.00 0.00 5.70 5.70 -3.30 -3.30
You'll see the 2nd row and the 5th row are swapped.
The main concept is:
Seek the diagonal elements for value 0.
If 0 is found, search for a trade row which has a non-zero value in the same column.
If no trade rows are found, the program prints an error message and aborts.
If a trade row is found, swap the rows.
[Edit]
Answering your comment, the code assumes the count of cols == count of rows + 1.
As your provided example has 4x4 matrix, let me add an extra column as:
double matrix[][COLS] = {
{0, 3, 2, 28, -1},
{4, 0, 2, 24, -1},
{2, 3, 0, 16, -1},
{4, 2, 1, 0, -1}
};
(Please note the value -1 is a dummy value and meaningless so far.)
And modify the #define lines as:
#define ROWS 4
#define COLS 5
Then the program will output:
0.00 3.00 2.00 28.00 -1.00
4.00 0.00 2.00 24.00 -1.00
2.00 3.00 0.00 16.00 -1.00
4.00 2.00 1.00 0.00 -1.00
4.00 0.00 2.00 24.00 -1.00
0.00 3.00 2.00 28.00 -1.00
4.00 2.00 1.00 0.00 -1.00
2.00 3.00 0.00 16.00 -1.00
which shows the rows are properly rearranged having no 0 values in the diagonal.
(BTW your expected result breaks having 0 in the diagonal in the last row.)
**You can make a main function like as follows:
//after passing the linear function
int i,j, temp; // declare i and j as global variables**
for(i=0,i<qty+1,i++)
{
for (j=0;j<qty+1;j++)
{
if(i==j & matrix[i][j]==0)
{
remove_line;
temp = i;
break;
}
}
} // here we are looking for a zero in the diagonal.
for (;i<qty+1;i++)
{
if(matrix[i][j]!=0)
{
matrix[temp][j] = linear[i][j]
}
}
// **here we are increasing the rows till we get a non zero element and then
interchanging the values.**

Segfault when changing macro values

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#define len 10
#define hi 10
void transpose(double (*matrix)[len][hi]);
int main() {
srand(time(NULL));
double (*matrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
double delimo, delitel;
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
delimo = rand()%(len * hi);
delitel = rand()%(len * hi);
*matrix[i][j] = delimo/++delitel;
printf(" %5.2lf ", *matrix[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
printf(" %5.2lf ", *matrix[i][j]);
}
puts("");
}
free(matrix);
}
void transpose(double (*matrix)[len][hi]){
double (*Tmatrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
*Tmatrix[i][j] = *matrix[j][i];
}
}
for(int i = 0; i < len; i++){
for(int j = 0; j < hi; j++){
*matrix[i][j] = *Tmatrix[i][j];
}
}
free(Tmatrix);
}
Task is to allocate a 2d array and then have a function transpose it and copy the transposed matrix in the original one with one function call. The dimensions of the matrix are set by the macros and they are also used in a few loops and when allocating the 2 matrixes. Yet for some odd reason, there's a segfault if I decide to change them. Only thing that has never crashed is when len = hi = 10 . In any other case the program has an average to above average chance to crash.
The code shown in the question gives my build of Valgrind conniptions because it is not using the pointer-to-matrix notation correctly. When run standalone (not under Valgrind) it appears to work, but the output matrix is not a transpose of the input matrix — because the data has not been accessed correctly. This is an example of the bogus output I get. You can see that the elements with indices 0,1 and 1,0 in the 'transpose' matrix are unrelated to the elements in the original matrix.
1.24 2.64 0.17 0.49 22.25 4.30 0.71 1.12 1.03 2.31
1.39 7.18 0.40 0.44 4.30 0.17 0.62 12.67 0.34 9.10
2.85 0.69 3.50 1.58 0.77 0.04 0.26 0.79 0.24 1.59
16.00 0.14 0.12 0.56 1.68 0.08 0.69 0.13 2.51 1.74
5.50 0.96 0.45 1.00 0.00 0.84 0.97 0.40 2.14 0.67
2.00 0.14 1.84 0.88 1.26 0.21 0.70 0.30 1.74 0.60
2.04 1.00 0.35 0.12 0.00 0.65 1.21 0.18 0.52 9.70
1.19 1.08 0.88 1.71 0.88 0.21 1.74 0.70 0.44 1.23
1.38 0.69 0.12 0.14 4.18 3.17 0.06 7.10 8.00 1.52
0.16 6.07 0.81 0.49 0.14 1.37 4.00 0.93 0.98 1.48
Transpose:
1.24 1.24 2.64 0.17 0.49 22.25 4.30 0.71 1.12 1.03
-2.00 1.39 1.39 2.85 16.00 5.50 2.00 2.04 1.19 1.38
0.17 2.85 0.69 0.69 0.14 0.96 0.14 1.00 1.08 0.69
0.49 16.00 0.14 0.12 0.12 0.45 1.84 0.35 0.88 0.12
22.25 5.50 0.96 0.45 1.00 1.00 0.88 0.12 1.71 0.14
4.30 2.00 0.14 1.84 0.88 1.26 1.26 0.00 0.88 4.18
0.71 2.04 1.00 0.35 0.12 0.00 0.65 0.65 0.21 3.17
1.12 1.19 1.08 0.88 1.71 0.88 0.21 1.74 1.74 0.06
1.03 1.38 0.69 0.12 0.14 4.18 3.17 0.06 7.10 7.10
2.31 0.16 6.07 0.81 0.49 0.14 1.37 4.00 0.93 0.98
The code below works for square matrices. The difference is that the pointer-to-matrix is dereferenced before the subscripting is applied ((*matrix)[i][j]) instead of after (*matrix[i][j]).
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define len 10
#define hi 10
void transpose(double (*matrix)[len][hi]);
int main(void)
{
srand(time(NULL));
double (*matrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
double delimo, delitel;
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
delimo = rand() % (len * hi);
delitel = rand() % (len * hi);
(*matrix)[i][j] = delimo / ++delitel;
printf(" %5.2lf ", (*matrix)[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
printf(" %5.2lf ", (*matrix)[i][j]);
}
puts("");
}
free(matrix);
}
void transpose(double (*matrix)[len][hi])
{
double (*Tmatrix)[len][hi] = (double (*)[len][hi])malloc(sizeof(double[len][hi]));
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
(*Tmatrix)[i][j] = (*matrix)[j][i];
}
}
for (int i = 0; i < len; i++)
{
for (int j = 0; j < hi; j++)
{
(*matrix)[i][j] = (*Tmatrix)[i][j];
}
}
free(Tmatrix);
}
Example output:
0.98 0.90 0.16 0.08 0.48 1.71 0.53 0.24 2.28 1.79
0.73 0.36 2.00 3.27 0.29 1.25 19.40 1.60 0.56 0.00
3.00 10.50 1.81 1.56 1.11 0.78 1.53 0.71 1.27 0.93
2.10 0.56 2.34 1.48 0.81 2.16 0.47 0.16 7.62 0.91
0.93 2.48 0.15 0.71 1.09 0.73 0.58 0.48 1.13 0.99
0.59 0.72 8.75 2.19 61.00 1.41 2.08 0.83 0.65 0.16
0.42 1.13 0.85 1.00 3.00 0.55 0.33 1.67 0.44 0.69
0.08 1.17 0.25 0.92 1.04 0.17 1.77 1.95 0.50 0.90
2.28 0.35 0.41 1.27 0.80 3.36 0.29 0.13 3.88 0.39
0.64 0.50 0.40 0.15 0.45 0.78 0.31 1.48 1.50 1.06
Transpose:
0.98 0.73 3.00 2.10 0.93 0.59 0.42 0.08 2.28 0.64
0.90 0.36 10.50 0.56 2.48 0.72 1.13 1.17 0.35 0.50
0.16 2.00 1.81 2.34 0.15 8.75 0.85 0.25 0.41 0.40
0.08 3.27 1.56 1.48 0.71 2.19 1.00 0.92 1.27 0.15
0.48 0.29 1.11 0.81 1.09 61.00 3.00 1.04 0.80 0.45
1.71 1.25 0.78 2.16 0.73 1.41 0.55 0.17 3.36 0.78
0.53 19.40 1.53 0.47 0.58 2.08 0.33 1.77 0.29 0.31
0.24 1.60 0.71 0.16 0.48 0.83 1.67 1.95 0.13 1.48
2.28 0.56 1.27 7.62 1.13 0.65 0.44 0.50 3.88 1.50
1.79 0.00 0.93 0.91 0.99 0.16 0.69 0.90 0.39 1.06
You can't transpose a non-square matrix in situ. If you have an nxm matrix as input, the transpose is an mxn matrix. It is probably simplest to allocate the transpose matrix where you allocate the non-transpose, and pass both matrices to the transpose function. Note the use of *matrix to pass the pointer-to-matrix as a matrix to the function.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
void transpose(int rows, int cols, double matrix[rows][cols], double result[cols][rows]);
void print_matrix(const char *tag, int rows, int cols, double matrix[rows][cols]);
int main(void)
{
srand(time(NULL));
int cols = 10;
int rows = 8;
double (*matrix)[rows][cols] = malloc(sizeof(double[rows][cols]));
double (*result)[cols][rows] = malloc(sizeof(double[cols][rows]));
if (matrix == 0 || result == 0)
{
fprintf(stderr, "failed to allocate memory\n");
exit(EXIT_FAILURE);
}
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
double delimo = rand() % (rows * cols);
double delitel = rand() % (rows * cols) + 1;
(*matrix)[i][j] = delimo / delitel;
}
}
print_matrix("original", rows, cols, *matrix);
transpose(rows, cols, *matrix, *result);
print_matrix("transpose", cols, rows, *result);
free(matrix);
free(result);
return 0;
}
void print_matrix(const char *tag, int rows, int cols, double matrix[rows][cols])
{
printf("%s (%dx%d):\n", tag, rows, cols);
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
printf(" %5.2f ", matrix[i][j]);
putchar('\n');
}
}
void transpose(int rows, int cols, double matrix[rows][cols], double result[cols][rows])
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < cols; j++)
{
result[j][i] = matrix[i][j];
}
}
}
Sample output:
original (8x10):
0.84 0.92 0.18 1.97 4.54 31.00 1.59 0.11 0.35 0.07
0.96 3.19 1.00 4.86 3.25 3.50 2.65 1.07 0.24 0.77
6.00 0.13 0.40 1.04 0.99 0.88 1.24 0.67 3.07 12.00
1.89 0.48 0.72 0.55 0.26 0.64 0.55 0.09 0.30 0.98
0.51 0.86 0.85 0.33 1.44 0.89 2.38 2.21 0.27 2.12
6.40 1.71 2.83 1.61 0.76 0.13 0.81 1.48 1.13 0.51
0.79 0.69 0.57 1.10 1.00 1.31 0.68 1.95 1.42 0.46
0.00 0.43 1.64 0.88 1.03 0.14 0.35 1.78 0.86 2.82
transpose (10x8):
0.84 0.96 6.00 1.89 0.51 6.40 0.79 0.00
0.92 3.19 0.13 0.48 0.86 1.71 0.69 0.43
0.18 1.00 0.40 0.72 0.85 2.83 0.57 1.64
1.97 4.86 1.04 0.55 0.33 1.61 1.10 0.88
4.54 3.25 0.99 0.26 1.44 0.76 1.00 1.03
31.00 3.50 0.88 0.64 0.89 0.13 1.31 0.14
1.59 2.65 1.24 0.55 2.38 0.81 0.68 0.35
0.11 1.07 0.67 0.09 2.21 1.48 1.95 1.78
0.35 0.24 3.07 0.30 0.27 1.13 1.42 0.86
0.07 0.77 12.00 0.98 2.12 0.51 0.46 2.82
Valgrind gives both of these a clean bill of health. The original code caused Valgrind to report a lot of errors like:
==33404== Signal 11 being dropped from thread 0's queue
I had to kill that run from a different terminal window.
You are trying to transpose a matrix in place, which is problematic. Indeed, transposing a non-square matrix gives a matrix of different dimension. Therefore you will inadvertently write to memory you are not supposed to access, because you try to fit your transposed matrix in an array of incorrect dimension.
I suggest you to modify your transpose function such that it takes two matrices as arguments. The first is your matrix to transpose, the second is the one receiving the transposed matrix and it has the correct dimension.
You are trying too hard. Simply remove all the dynamic allocation stuff as well as pointers. Dynamic memory allocation is totally useless in your case.
Here you go:
#define len 2
#define hi 2
void transpose(double matrix[len][hi]);
int main() {
srand(time(NULL));
double matrix[len][hi];
double delimo, delitel;
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
delimo = rand() % (len * hi);
delitel = rand() % (len * hi);
matrix[i][j] = delimo / ++delitel;
printf(" %5.2lf ", matrix[i][j]);
}
puts("");
}
puts("Transpose: ");
transpose(matrix);
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
printf(" %5.2lf ", matrix[i][j]);
}
puts("");
}
}
void transpose (double matrix[len][hi]) {
double Tmatrix[len][hi];
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
Tmatrix[i][j] = matrix[j][i];
}
}
for (int i = 0; i < len; i++) {
for (int j = 0; j < hi; j++) {
matrix[i][j] = Tmatrix[i][j];
}
}
}
Disclaimer:
this only works for square matrixes.
there may be other problems

coulomb's law force calculation using c code

I am trying to write a simple program in C to calculate pairwise interaction (Coulomb force) between two chain of beads.Both chains contain 10 beads but one chain is positively charged and the other one is negatively charged. I am reading the x,y,z coordinates and the charge information from two files (Charge from 7th column of atom.psf and coordinates from 6th 7th and 8th columns of beads.pdb).
Here are the contents of the files:
atom.psf
20 !NATOM
1 A 1 CHN A A 1.000000 0.0000 0
2 A 1 CHN A A 1.000000 0.0000 0
3 A 1 CHN A A 1.000000 0.0000 0
4 A 1 CHN A A 1.000000 0.0000 0
5 A 1 CHN A A 1.000000 0.0000 0
6 A 1 CHN A A 1.000000 0.0000 0
7 A 1 CHN A A 1.000000 0.0000 0
8 A 1 CHN A A 1.000000 0.0000 0
9 A 1 CHN A A 1.000000 0.0000 0
10 A 1 CHN A A 1.000000 0.0000 0
11 A 2 CHN A A -1.000000 0.0000 0
12 A 2 CHN A A -1.000000 0.0000 0
13 A 2 CHN A A -1.000000 0.0000 0
14 A 2 CHN A A -1.000000 0.0000 0
15 A 2 CHN A A -1.000000 0.0000 0
16 A 2 CHN A A -1.000000 0.0000 0
17 A 2 CHN A A -1.000000 0.0000 0
18 A 2 CHN A A -1.000000 0.0000 0
19 A 2 CHN A A -1.000000 0.0000 0
20 A 2 CHN A A -1.000000 0.0000 0
18 !NBOND: bonds
1 2 2 3 3 4 4 5
5 6 6 7 7 8 8 9
9 10 11 12 12 13 13 14
14 15 15 16 16 17 17 18
18 19 19 20
beads.pdb
ATOM 1 A CHN 1 1.000 0.000 0.000 1.00 0.00 A
ATOM 2 A CHN 1 2.000 0.000 0.000 1.00 0.00 A
ATOM 3 A CHN 1 3.000 0.000 0.000 1.00 0.00 A
ATOM 4 A CHN 1 4.000 0.000 0.000 1.00 0.00 A
ATOM 5 A CHN 1 5.000 0.000 0.000 1.00 0.00 A
ATOM 6 A CHN 1 6.000 0.000 0.000 1.00 0.00 A
ATOM 7 A CHN 1 7.000 0.000 0.000 1.00 0.00 A
ATOM 8 A CHN 1 8.000 0.000 0.000 1.00 0.00 A
ATOM 9 A CHN 1 9.000 0.000 0.000 1.00 0.00 A
ATOM 10 A CHN 1 10.000 0.000 0.000 1.00 0.00 A
ATOM 11 A CHN 2 1.000 80.000 0.000 1.00 0.00 A
ATOM 12 A CHN 2 2.000 80.000 0.000 1.00 0.00 A
ATOM 13 A CHN 2 3.000 80.000 0.000 1.00 0.00 A
ATOM 14 A CHN 2 4.000 80.000 0.000 1.00 0.00 A
ATOM 15 A CHN 2 5.000 80.000 0.000 1.00 0.00 A
ATOM 16 A CHN 2 6.000 80.000 0.000 1.00 0.00 A
ATOM 17 A CHN 2 7.000 80.000 0.000 1.00 0.00 A
ATOM 18 A CHN 2 8.000 80.000 0.000 1.00 0.00 A
ATOM 19 A CHN 2 9.000 80.000 0.000 1.00 0.00 A
ATOM 20 A CHN 2 10.000 80.000 0.000 1.00 0.00 A
I am having trouble with my final output. At every timestep (t=0 to 100), I need to write the coordinates of 20 atoms. My trial code is given below.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define Epsilon0 8.85e-12 // Permittivity of free space (C^2/(N m^2))
#define Constant (1/(4*M_PI*Epsilon0)) // Useful constant
#define gamma 100.0
#define ROW 20
int row, col, j, t;
float x[20], y[20], z[20], q[20], dx, dy, dz, R, Fx, Fy, Fz, F, v, shift;
int main()
{
FILE *psf=fopen("atom.psf", "r");
FILE *pdb=fopen("beads.pdb", "r");
FILE *fout=fopen("out.txt", "a");
FILE *fout2=fopen("coord.dump", "a");
fprintf(fout2, "ITEM: TIMESTEP\n 100\n");
fprintf(fout2, "ITEM: NUMBER OF ATOMS\n 20\n");
fprintf(fout2, "ITEM: ATOMS id type x y z\n");
char buffer[1024];
fgets(buffer, 1024, psf);
int i = 0;
for(i=0 ; (i<ROW) && (psf != NULL); i++)
{
fscanf (psf,"%*8d%*4s%*4d%*6s%*5s%*6s%11f%*14f%*12d", &q[i]);
fscanf (pdb,"%*4s%*7d%*5s%*4s%*6d%12f%8f%8f%*6f%*6f%*9s", &x[i], &y[i], &z[i]);
}
for (t=0; t<100; t++)
{
//F = 0.0;
v = F/gamma;
shift = v*t;
x[i] = x[i] + shift;
y[i] = y[i] + shift;
z[i] = z[i] + shift;
for(i=0; i<ROW; i++)
{
Fx = Fy = Fz = F = 0.0;
// Loop over other charges to compute force on this charge
for (j=0 ; j<ROW ; j++)
{
//simply skip this itearation
if(i == j)
continue;
// Compute the components of vector distance between two charges
dx = x[i] - x[j];
dy = y[i] - y[j];
dz = z[i] - z[j];
R = sqrt(dx*dx + dy*dy + dz*dz);
// Compute the x and y components of the force between
// these two charges using Coulomb's law
Fx += Constant*q[i]*q[j]*dx/(R*R*R);
Fy += Constant*q[i]*q[j]*dy/(R*R*R);
Fz += Constant*q[i]*q[j]*dz/(R*R*R);
}
F = sqrt(Fx*Fx + Fy*Fy + Fz*Fz);
fprintf(fout, "%d %3.3g %3.3g %3.3g %3.3g\n", i+1, Fx, Fy, Fz, F);
//fprintf(fout2, "%d %3.3g %3.3g %3.3g\n", i+1, x[i], y[i], z[i]);
}
fprintf(fout2, "%d %3.3g %3.3g %3.3g\n", i, x[i], y[i], z[i]);
}
}
This is probably a situation where instead of attempting to keep track of numerous separate arrays containing various information, life can be made a lot easier if you simply create a struct that captures the needed information for each bead and then create a single array of struct. For example, you want to capture the x,y,z position, charge, and component forces acting on each bead. (I included the total force as well, but that is optional). Your struct for each bead (I called it beads) could be as simple as:
typedef struct {
float x, y, z, chrg, fx, fy, fz, f;
} beads;
In your code, you simply create an array of beads (one for each bead you need information on). For example, creating an array of beads with 20 elements, you could do something like the following:
#define Eo 8.85e-12F
#define KEair (1/(4*M_PI*Eo))
enum { NATM = 20, MAXL = 128 }; /* constants for number of beads/line len */
...
beads atoms[NATM] = {{ .x = 0.0 }};
Now we have an array of struct called atoms to store information in. You can read information from each of your files and store the x, y, z positions for each bead as well as the charge. Then you can compute the force acting on each bead by computing the force due to every other bead and summing the information in the remaining force component and total members of each struct. You may do something like:
for (i = 0; i < NATM; i++) { /* for each bead */
for (size_t j = 0; j < NATM; j++) { /* compute force from every other */
if (i == j) continue; /* excluding itself */
float dx = atoms[j].x - atoms[i].x, /* calculate component distances */
dy = atoms[j].y - atoms[i].y,
dz = atoms[j].z - atoms[i].z,
d = sqrt (dx * dx + dy * dy + dz * dz); /* total distance */
/* compute component and total forces acting on each bead (sum) */
atoms[i].fx += (KEair * atoms[i].chrg *atoms[j].chrg * dx)/(d * d * d);
atoms[i].fy += (KEair * atoms[i].chrg *atoms[j].chrg * dy)/(d * d * d);
atoms[i].fz += (KEair * atoms[i].chrg *atoms[j].chrg * dz)/(d * d * d);
atoms[i].f += (KEair * atoms[i].chrg *atoms[j].chrg)/(d * d);
}
}
(you can confirm the approach to the sum at System of discrete charges)
Putting it altogether, you could do something like the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define Eo 8.85e-12F
#define KEair (1/(4*M_PI*Eo))
enum { NATM = 20, MAXL = 128 };
typedef struct {
float x, y, z, chrg, fx, fy, fz, f;
} beads;
FILE *xfopen (const char *fn, const char *mode);
float sqrt_fisr (float x);
int main (int argc, char **argv) {
beads atoms[NATM] = {{ .x = 0.0 }};
size_t i;
char buf[MAXL] = ""; /* open/read atom.psf */
FILE *fp = xfopen (argc > 1 ? argv[1] : "dat/atom.psf", "r");
fgets (buf, MAXL, fp); /* read/discard 1st line */
for (i = 0; i < NATM && fgets (buf, MAXL, fp); i++) { /* read/parse data */
if (sscanf (buf, "%*s %*s %*s %*s %*s %*s %f", &atoms[i].chrg) != 1) {
fprintf (stderr, "error: read of charge failed, atom[%zu].\n", i);
return 1;
}
}
fclose (fp);
if (i != NATM) { /* validate NATM lines read */
fprintf (stderr, "error: only '%zu' charge values read.\n", i);
return 1;
}
/* open/read beads.pdb */
fp = xfopen (argc > 2 ? argv[2] : "dat/beads.pdb", "r");
for (i = 0; i < NATM && fgets (buf, MAXL, fp); i++) { /* read/parse data */
if (sscanf (buf, "%*s %*s %*s %*s %*s %f %f %f", &atoms[i].x,
&atoms[i].y, &atoms[i].z) != 3) {
fprintf (stderr, "error: read of position failed, atom[%zu].\n", i);
return 1;
}
}
fclose (fp);
if (i != NATM) { /* validate NATM lines read */
fprintf (stderr, "error: only '%zu' position values read.\n", i);
return 1;
}
for (i = 0; i < NATM; i++) { /* for each bead */
for (size_t j = 0; j < NATM; j++) { /* compute force from every other */
if (i == j) continue; /* excluding itself */
float dx = atoms[j].x - atoms[i].x, /* calculate component distances */
dy = atoms[j].y - atoms[i].y,
dz = atoms[j].z - atoms[i].z,
d = sqrt (dx * dx + dy * dy + dz * dz); /* total distance */
/* compute component and total forces acting on each bead (sum) */
atoms[i].fx += (KEair * atoms[i].chrg *atoms[j].chrg * dx)/(d * d * d);
atoms[i].fy += (KEair * atoms[i].chrg *atoms[j].chrg * dy)/(d * d * d);
atoms[i].fz += (KEair * atoms[i].chrg *atoms[j].chrg * dz)/(d * d * d);
atoms[i].f += (KEair * atoms[i].chrg *atoms[j].chrg)/(d * d);
}
}
for (i = 0; i < NATM; i++) /* output forces on each bead (component and total) */
printf (" atom[%2zu] %5.2f %5.2f %5.2f %+.2f %15.2f %15.2f %5.2f %15.2f\n",
i, atoms[i].x, atoms[i].y, atoms[i].z, atoms[i].chrg,
atoms[i].fx, atoms[i].fy, atoms[i].fz, atoms[i].f);
return 0;
}
/** simple fopen with error check */
FILE *xfopen (const char *fn, const char *mode)
{
FILE *fp = fopen (fn, mode);
if (!fp) {
fprintf (stderr, "xfopen() error: file open failed '%s'.\n", fn);
exit (EXIT_FAILURE);
}
return fp;
}
Example Use/Output
$ ./bin/coulomb
atom[ 0] 1.00 0.00 0.00 +1.00 13844509696.00 -13956823.00 0.00 13831302144.00
atom[ 1] 2.00 0.00 0.00 +1.00 4741866496.00 -13982750.00 0.00 22712082432.00
atom[ 2] 3.00 0.00 0.00 +1.00 2353591552.00 -14002249.00 0.00 24819521536.00
atom[ 3] 4.00 0.00 0.00 +1.00 1171170304.00 -14015272.00 0.00 25635096576.00
atom[ 4] 5.00 0.00 0.00 +1.00 359584800.00 -14021791.00 0.00 25947308032.00
atom[ 5] 6.00 0.00 0.00 +1.00 -359584608.00 -14021791.00 0.00 25947308032.00
atom[ 6] 7.00 0.00 0.00 +1.00 -1171170944.00 -14015272.00 0.00 25635096576.00
atom[ 7] 8.00 0.00 0.00 +1.00 -2353592320.00 -14002249.00 0.00 24819521536.00
atom[ 8] 9.00 0.00 0.00 +1.00 -4741866496.00 -13982751.00 0.00 22712082432.00
atom[ 9] 10.00 0.00 0.00 +1.00 -13844510720.00 -13956824.00 0.00 13831303168.00
atom[10] 1.00 80.00 0.00 -1.00 13844507648.00 13956823.00 0.00 13831302144.00
atom[11] 2.00 80.00 0.00 -1.00 4741867008.00 13982750.00 0.00 22712080384.00
atom[12] 3.00 80.00 0.00 -1.00 2353592064.00 14002249.00 0.00 24819521536.00
atom[13] 4.00 80.00 0.00 -1.00 1171170944.00 14015272.00 0.00 25635096576.00
atom[14] 5.00 80.00 0.00 -1.00 359585056.00 14021791.00 0.00 25947308032.00
atom[15] 6.00 80.00 0.00 -1.00 -359584864.00 14021791.00 0.00 25947308032.00
atom[16] 7.00 80.00 0.00 -1.00 -1171170560.00 14015272.00 0.00 25635096576.00
atom[17] 8.00 80.00 0.00 -1.00 -2353591808.00 14002249.00 0.00 24819521536.00
atom[18] 9.00 80.00 0.00 -1.00 -4741867008.00 13982751.00 0.00 22712080384.00
atom[19] 10.00 80.00 0.00 -1.00 -13844509696.00 13956824.00 0.00 13831304192.00
Looking at the output graphically, the forces increase from the end to a maximum in the center of each string or beads -- that checks, and the forces acting upon the beads in the X-direction is the greatest at each end and reverses direction at midpoint -- also a check. For example:
Total Force Acting on Each Bead
Forces acting in the X direction on Each Bead
Look things over and let me know if you have any questions.
Here's what I would change in your code:
Epsilon and Constant should be declared as constants:
"#define Epsilon0 8.85e-12"
"#define Constant (1/(4*pi*Epsilon0))""
Move the "i != j" inside the loop. That would prevent the loop from stopping if you hit that condition. You would just be skipping that iteration instead of stopping completely.
You don't really need the xi, yi , zij, Fx, Fy, Fz, Rij arrays. You can use simple variables as placeholders instead.
During each iteration of the inner loop, you would be calculating the partial force du to bead j. You need to add that force to the cumulative force.
In order to do that you can declare Fx, Fy and Fz outside of the loops, initialize the 3 variable to 0 inside the first loop and then add partial forces inside the inner loop.
Move the fprintf outside of the inner loop (but keep it inside the external loop)
UPDATE
This code does not handle I/O errors
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#define Epsilon0 8.85e-12 // Permittivity of free space (C^2/(N m^2))
#define Constant (1/(4*M_PI*Epsilon0)) // Useful constant
#define ROW 20
int row, col, j;
float x[20], y[20], z[20], q[20], dx, dy, dz, R, Fx, Fy, Fz, F;
int main()
{
FILE *psf=fopen("atom.psf", "r");
FILE *pdb=fopen("beads.pdb", "r");
FILE *fout=fopen("out.txt", "w");
char buffer[1024];
fgets(buffer, 1024, psf);
int i = 0;
for( ; (i<ROW) && (psf != NULL); i++)
{
fscanf (psf,"%*8d%*4s%*4d%*6s%*5s%*6s%11f%*14f%*12d", &q[i]);
fscanf (pdb,"%*4s%*7d%*5s%*4s%*6d%12f%8f%8f%*6f%*6f%*9s", &x[i], &y[i], &z[i]);
}
for(i=0; i<ROW; i++)
{
Fx = Fy = Fz = F = 0.0;
// Loop over other charges to compute force on this charge
for (j=0 ; j<ROW ; j++)
{
//simply skip this itearation
if(i == j)
continue;
// Compute the components of vector distance between two charges
dx = x[i] - x[j];
dy = y[i] - y[j];
dz = z[i] - z[j];
R = sqrt(dx*dx + dy*dy + dz*dz);
// Compute the x and y components of the force between
// these two charges using Coulomb's law
Fx += Constant*q[i]*q[j]*dx/(R*R*R);
Fy += Constant*q[i]*q[j]*dy/(R*R*R);
Fz += Constant*q[i]*q[j]*dz/(R*R*R);
}
F = sqrt(Fx*Fx + Fy*Fy + Fz*Fz);
fprintf(fout, "%d %g %g %g, %g\n", i+1, Fx, Fy, Fz, F);
}
}
Something that may help
The for loop,
`for (j = 0; j<ROW && i != j; j++)`
Will exit when i == j as the loop condition is false. For example when i is 1 will only iterate through the loop once, when j is 0.
Use if statement inside the for loop to skip the current charge, i.e when i == j
for (j = 0; j<ROW ; j++)
{
if (i != j)
{
DO CALCULATION... `
Also, think that Fx[i] will only ever have store the force due to an single j charge as it is assignment for each iteration rather than a sum.
Consider changing to accumlate for each interation, i.e. Fx[i] += then calculate F[i] when this for loop has completed

Array loading with doubles in C

I am trying to load a 3x8 array of doubles but my code keeps outputting 0.00 for all of the values. The code should be outputting the array (same as the input) under the Read#1 Read#2 Read#3 lines, with the average under average.
Here is my code:
#include <stdio.h>
double getAvg(double num1, double num2, double num3);
int main()
{
int numJ,month,day,year,i,j;
double arr[3][8];
scanf("%d %d %d %d",&numJ,&month,&day,&year);
for (i = 0; i < 8; i++)
{
scanf("%f %f %f",&arr[i][0], &arr[i][1], &arr[i][2]);
}
printf("\nJob %d Date: %d/%d/%d",numJ,month,day,year);
printf("\n\nLocation Read#1 Read#2 Read#3 Average");
for (j = 0; j < 8; j++)
{
printf("\n %d %.2f %.2f %.2f %.2f",j+1,arr[j][0],arr[j] [1],arr[j][2],getAvg(arr[j][0],arr[j][1],arr[j][2]));
}
return 0;
}
double getAvg(double num1, double num2, double num3)
{
double avg = (num1 + num2 + num3) / 3;
return avg;
}
Input example:
157932 09 01 2013
0.00 0.00 0.00
0.36 0.27 0.23
0.18 0.16 0.26
0.27 0.00 0.34
0.24 0.00 0.31
0.16 0.33 0.36
0.29 0.36 0.00
0.21 0.36 0.00

Convert a matrix A in a sparse formats CSR, COO, etc

I have a little problem, I would like to convert a matrix 10*10 in a CSR or COO sparse matrix/format. The matrix is:
1.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
-0.45 0.10 -0.45 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 -0.45 0.10 -0.45 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 -0.45 0.10 -0.45 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 -0.45 0.10 -0.45 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 -0.45 0.10 -0.45 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 -0.45 0.10 -0.45 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 -0.45 0.10 -0.45 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 -0.45 0.10 -0.45
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00
I am using the "CUSP" functions but it did not work, once tha matrix A I would like just to convert in other format. Can you help me?
Well I would like also to use this matrix to solve the system Ax=b, using bicgstab:
b=
0.00000
0.34202
0.64279
0.86603
0.98481
0.98481
0.86603
0.64279
0.34202
0.00000
My code for this is:
int n = 10, r;
cusp::coo_matrix<int,float,cusp::device_memory> A(n, n, 3*n - 4);
cusp::array1d<float, cusp::device_memory> x(A.num_rows, 0);
cusp::array1d<float, cusp::device_memory> b(A.num_rows, 1);
b[0]=0.00000;
b[1]=0.34202;
b[2]=0.64279;
b[3]=0.86603;
b[4]=0.98481;
b[5]=0.98481;
b[6]=0.86603;
b[7]=0.64279;
b[8]=0.34202;
b[9]=0.00000;
i=0;
// row 0
A.row_indices[i] = 0.0;
A.column_indices[i] = 0.0;
A.values[i] = 1.00;
++i;
// rows 1 through n - 2
for (r = 1; r != n - 1; ++r) {
A.row_indices[i] = r;
A.column_indices[i] = r - 1;
A.values[i] = -0.45;
++i;
A.row_indices[i] = r;
A.column_indices[i] = r;
A.values[i] = 0.10;
++i;
A.row_indices[i] = r;
A.column_indices[i] = r + 1;
A.values[i] = -0.45;
++i;
}
// row n - 1
A.row_indices[i] = n - 1;
A.column_indices[i] = n - 1;
A.values[i] = 1.00;
++i;
// set stopping criteria:
// iteration_limit = 100
// relative_tolerance = 1e-3
cusp::verbose_monitor<ValueType> monitor(b, 100, 1e-3);
// set preconditioner (identity)
cusp::identity_operator<ValueType, MemorySpace> M(A.num_rows, A.num_rows);
// solve the linear system A x = b
cusp::krylov::bicgstab(A, x, b, monitor, M);
cusp::print(x);
The result using Octave should be something similar to:
0.00000
0.32441
0.60970
0.82144
0.93411
0.93411
0.82144
0.60970
0.32441
0.00000
But is also with negative numbers, so WRONG.
For COO, you have to set three array elements for each entry: the row and column indices as well as the value. You can create a matrix like the one you describe using code like this for COO:
int n = 10, i = 0, r;
cusp::csr_matrix<int,float,cusp::host_memory> A(n, n, 3*n - 4);
// row 0
A.row_indices[i] = 0;
A.column_indices[i] = 0;
A.values[i] = 1.00;
++i;
// rows 1 through n - 2
for (r = 1; r != n - 1; ++r) {
A.row_indices[i] = r;
A.column_indices[i] = r - 1;
A.values[i] = -0.45;
++i;
A.row_indices[i] = r;
A.column_indices[i] = r;
A.values[i] = 0.10;
++i;
A.row_indices[i] = r;
A.column_indices[i] = r + 1;
A.values[i] = -0.45;
++i;
}
// row n - 1
A.row_indices[i] = n - 1;
A.column_indices[i] = n - 1;
A.values[i] = 1.00;
++i;
For CSR you have to specify a column and a value for every entry, and also the index of the first entry for every row including a one-past-the-end index for the one-past-the-end row. A similar piece of code for CSR:
int n = 10, i = 0, r = 0;
cusp::csr_matrix<int,float,cusp::host_memory> A(n, n, 3*n - 4);
// row 0
A.row_offsets[r] = i;
A.column_indices[i] = 0;
A.values[i] = 1.00;
++i;
// rows 1 through n - 2
for (++r; r != n - 1; ++r) {
A.row_offsets[r] = i;
A.column_indices[i] = r - 1;
A.values[i] = -0.45;
++i;
A.column_indices[i] = r;
A.values[i] = 0.10;
++i;
A.column_indices[i] = r + 1;
A.values[i] = -0.45;
++i;
}
// row n - 1
A.row_offsets[r] = i;
A.column_indices[i] = r;
A.values[i] = 1.00;
++i;
++r;
A.row_offsets[r] = i;
To “convert” the matrix from some other format, you have to let us know in what form your original data is stored. Conversion from a cusp::array2d should work by simply passing that array to the constructor. In general, creating the matrix in sparse format in the first place like the code above does will provide better scalability.
Also note that your example matrix is arranged in diagonal bands, so cusp::dia_matrix would be better suited, both in terms of easy encoding and in terms of better performance. To create such a tridiagonal matrix, you can use the following code:
int n = 10, r = 0;
cusp::dia_matrix<int,float,cusp::host_memory> A(n, n, 3*n - 4, 3);
A.diagonal_offsets[0] = -1;
A.diagonal_offsets[1] = 0;
A.diagonal_offsets[2] = 1;
// row 0
A.values(r,0) = A.values(r,2) = 0.00;
A.values(r,1) = 1.00;
// rows 1 through n - 2
for (++r; r != n - 1; ++r) {
A.values(r,0) = A.values(r,2) = -0.45;
A.values(r,1) = 0.10;
}
// row n - 1
A.values(r,0) = A.values(r,2) = 0.00;
A.values(r,1) = 1.00;
About this linear equation you try to solve: could it be that octave is operating on a different matrix than the one you pasted into your question? Because with sage I get negative numbers in the result as well:
n = 10
d = dict()
d[(0,0)] = d[(n-1, n-1)] = 1
for r in range(1, n-1):
d[(r, r-1)] = d[(r, r+1)] = -45/100
d[(r,r)] = 1/10
A = matrix(RDF, n, n, d)
b = vector(RDF, [
0.00000,
0.34202,
0.64279,
0.86603,
0.98481,
0.98481,
0.86603,
0.64279,
0.34202,
0.00000,
])
for i in A.solve_right(b):
print('{:+.5f}'.format(float(i)))
gives the following vector x:
+0.00000
-0.45865
-0.86197
-1.16132
-1.32062
-1.32062
-1.16132
-0.86197
-0.45865
+0.00000

Resources