Background
I have to implement Cannon's Algorithm which is a parallel algorithm for multiplying matrices that are square in dimension and the dimension is divisible by the square root of the number of processors. I wrote this code which runs perfectly fine but in life running without crashing is just half the story. It doesn't multiply A x B into a new matrix C, correctly. Here is the code, please help me and steer me to helping me solve what I am doing wrong. As it should be obvious this is homework.
Code
void shift_left(datatype** mat, int s, int row, int n, int amount) {
datatype* temp_buffer = malloc(sizeof(datatype) * n);
for(int col = 0; col < n; col++) {
datatype temp = mat[row][(col+amount)%s];
temp_buffer[(col+amount)%s] = mat[row][col];
temp_buffer[col] = temp;
}
memcpy(mat[row], temp_buffer, n);
free(temp_buffer);
}
void shift_up(datatype** mat, int s, int col, int n, int amount) {
datatype* temp_buffer = malloc(sizeof(datatype) * n);
for(int row = 0; row < n; row++) {
datatype temp = mat[(row+amount)%s][col];
temp_buffer[(row+amount)%s] = mat[row][col];
temp_buffer[row] = temp;
}
memcpy(&mat[0][col], temp_buffer, n);
free(temp_buffer);
}
void cannon_mul(int p_sqrt,datatype** a, datatype** b, datatype** c, int n) {
/* 2D matrices and n^2 sized only!*/
int i = 0, j = 0, k = 0;
int s = p_sqrt;
for(i = 0; i < (s-1); i++) {
shift_left(a, s, i, s-1, i); // Skew matrix a
}
for (i = 0; i < (s-1); i++) {
shift_up(b, s, i, s-1, i); // Skew matrix b
}
for(k = 0; k < (s-1); k++) {
for(i = 0; i < (s-1); i++) {
for(j = 0; j < (s-1); j++) {
c[i][j] += a[i][j]*b[i][j];
shift_left(a, s, i, s-1, 1);
shift_up(b, s, i, s-1, 1);
}
}
}
}
What I believe is going wrong?
My hunch is that the shifting is wrong or I am missing an essential portion of the algorithm. My original shift function wasn't using a temp buffer so I figured to use a temp buffer this time but it didn't make a difference. I could show some sample output if it helps but the result is not even remotely close to the desired result. The good news it runs fast :)
Results
1.48 0.14 9.47 8.99 8.06 0.06 6.68 1.04 4.44 7.50
7.26 8.87 2.21 6.27 2.12 7.91 0.65 5.24 0.45 4.94
0.47 4.13 1.87 2.25 6.83 1.52 6.41 9.14 9.22 8.91
7.34 2.70 6.78 2.78 3.51 4.95 5.27 0.85 9.51 6.82
0.28 6.73 0.70 8.88 7.14 9.09 2.36 5.38 6.43 9.00
7.13 6.71 6.92 9.81 5.13 9.35 7.50 5.16 4.68 3.62
1.30 6.26 4.55 4.27 0.51 2.23 3.19 8.75 6.57 9.07
7.49 6.41 1.04 7.78 7.16 2.78 2.25 6.23 9.42 0.32
3.21 3.60 2.04 2.93 4.29 3.88 2.78 8.01 4.57 6.47
7.52 3.77 0.63 5.97 7.32 4.90 9.63 4.90 8.46 1.90
multiplying the matrix above with itself produces with my code this:
2.20 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
50.81 0.00 0.00 0.00 0.00 87.51 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
The sequential program produces this result:
163.41 212.17 144.32 227.10 251.03 205.60 245.63 277.33 368.99 334.11
257.85 230.82 203.60 314.08 246.02 240.12 228.37 197.90 264.38 228.24
234.13 272.10 110.75 294.84 263.16 242.07 209.54 316.13 339.23 260.51
185.33 215.59 192.26 283.31 270.80 208.38 265.08 291.49 312.24 319.73
313.23 301.95 182.04 348.11 283.20 337.49 266.54 284.57 355.28 281.07
293.25 323.29 281.35 393.92 325.24 313.62 313.48 342.95 418.37 401.91
255.88 238.25 122.17 254.52 243.58 204.49 217.69 273.03 314.89 214.45
219.26 239.07 200.18 309.98 262.21 242.68 190.02 245.85 297.96 308.56
209.03 213.11 126.24 266.48 233.88 199.33 193.28 228.92 277.50 202.27
210.31 264.67 227.59 337.79 261.40 250.35 225.77 295.00 331.92 352.17
It is important to note I am showing relevant portions of my program if you feel I need to show more please do so and I will provide more code. Lastly why is the Homework tag missing?
Edit
One person noted that the buffer was to small and was missing sizeof a foolish mistake and now corrected. I tried and I get the same result, so apparently the problem is nothing to do with that. Hopefully in 2 days I can open a bounty to entice some person to at least give me a clue where the issue is. Its a bug that I can't seem to debug, and my understanding I must admit of this algorithm is zero to null. I am relying on web sources that do very little to increase my understanding.
Edit 2
Tried using calloc to zero allocate the buffer but it doesn't change the results. So strange but thanks for suggesting that; I forget memory doesn't allocate zeroed.
Edit 3
I tried this:
void shift_left(datatype** mat, int s, int row, int n, int amount) {
datatype* temp_buffer = calloc(n, sizeof(datatype) * n);
for(int col = 0; col < n; col++) {
/* temp_buffer[(col+amount)%s] = mat[row][col];
temp_buffer[col] = mat[row][(col+amount)%s]; */
temp_buffer[(col+amount)%s] = 0;
temp_buffer[col] = 0;
}
memcpy(mat[row], temp_buffer, sizeof(datatype) * n);
//free(temp_buffer);
}
void shift_up(datatype** mat, int s, int col, int n, int amount) {
datatype* temp_buffer = calloc(n, sizeof(datatype) * n);
for(int row = 0; row < n; row++) {
/* temp_buffer[(row+amount)%s] = mat[row][col];
temp_buffer[row] = mat[(row+amount)%s][col]; */
temp_buffer[(row+amount)%s] = 0;
temp_buffer[row] = 0;
}
memcpy(&mat[0][col], temp_buffer, sizeof(datatype) * n);
free(temp_buffer);
}
And surprisingly the same result. When it should print all zero since I commented the code and replaced it with zero. My guess memcpy isn't working.
Edit 4
I have confirmed that memcpy is the culprit. But why I do not know I am stumped, if it helps datatype is just an alias for double the professor wrote that for some odd reason as it really doesn't help make the code more readable.
But if I do solve it on my own will be glad to show the solution to my issue.
datatype* temp_buffer = malloc(sizeof(datatype) * n);
, this allocated data should work regardless of what data is initially in it. Forcing various patterns into it first and see if you get consistent results. If not, code is not using these allocated buffers correctly. 2) Confident aboutp_sqrt
has the correct value? – Margiemargintemp_buffer[(col+amount)%s] = mat[row][col]; temp_buffer[col] = temp;
looks curious. Code populatestemp_buffer
one at a time withtemp_buffer[col] = temp
, but that overwrites what it did withtemp_buffer[(col+amount)%s] = mat[row][col]
(which has no bounds.) Hmmmm? GTG. – Margiemargina[0][0] * a[0][0]
. See if that works. Maybek < (s-1)
-->k < s
? Also hinted by @AakashM – Margiemargin