-
Notifications
You must be signed in to change notification settings - Fork 3
/
project2_Delaunoy_Crasset_SPARSE.c
359 lines (319 loc) · 9.06 KB
/
project2_Delaunoy_Crasset_SPARSE.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#include <stdlib.h>
#include <mpi.h>
#include <stdio.h>
#include <omp.h>
#include "project2_Delaunoy_Crasset_SPARSE.h"
/**
* Structure representing a sparse matrix
*/
struct SparseMatrix_t{
SparseVector** vectors;
unsigned int begin;
unsigned int end;
};
/**
* Structure representing a sparse vector
*/
struct SparseVector_t{
double* A;
int* indices;
unsigned int maxNbElements;
unsigned int currNbElement;
};
/**
* Allocate a SparseVector structure
*
* Parameters:
* maxNbElements: The maximum number of element this vector can contain
*
* Returns:
* A pointer to the allocated SparseVector structure
*/
SparseVector* createSparseVector(unsigned int maxNbElements){
SparseVector* vec = malloc(sizeof(SparseVector));
if(!vec)
return NULL;
vec->A = malloc(maxNbElements * sizeof(double));
if(!vec->A){
free(vec);
return NULL;
}
vec->indices = malloc(maxNbElements * sizeof(int));
if(!vec->indices){
free(vec->A);
free(vec);
return NULL;
}
vec->maxNbElements = maxNbElements;
vec->currNbElement = 0;
return vec;
}
/**
* Free a SparseVector structure
*
* Parameters:
* vec: A pointer to the structure to free
*/
void freeSparseVector(SparseVector* vec){
free(vec->A);
free(vec->indices);
free(vec);
}
/**
* Allocate a SparseMatrix structure
*
* Parameters:
* begin: The starting row index of the matrix
* end: The ending row index of the matrix
* maxNbElements: The maximum number of elements each of its vectors can contain
*
* Returns:
* A pointer to the allocated structure
*/
SparseMatrix* createSparseMatrix(unsigned int begin, unsigned int end, unsigned int maxNbElements){
SparseMatrix* mat = malloc(sizeof(SparseMatrix));
if(!mat)
return NULL;
mat->vectors = malloc((end-begin+1) * sizeof(SparseVector*));
if(!mat->vectors){
free(mat);
return NULL;
}
for(unsigned int i = 0; i < end-begin+1; i++){
mat->vectors[i] = createSparseVector(maxNbElements);
if(!mat->vectors[i]){
for(int j = i-1; j >= 0; j--){
freeSparseVector(mat->vectors[j]);
free(mat->vectors);
free(mat);
return NULL;
}
}
}
mat->begin = begin;
mat->end = end;
return mat;
}
/**
* Free a SparseMatrix structure
*
* Parameters:
* mat: A pointer to the structure to free
*/
void freeSparseMatrix(SparseMatrix* mat){
for(int i = 0; i < mat->end - mat->begin + 1; i++){
freeSparseVector(mat->vectors[i]);
}
free(mat->vectors);
free(mat);
}
/**
* Print a SparseVector structure
*
* Parameters:
* vec: A pointer to the SparseVector to print
* row: The row this vector is associated with
*/
void printSparseVector(const SparseVector* vec, int row){
for(int i = 0; i < vec->currNbElement; i++)
fprintf(stderr, "(%d, %d) = %lf\n", row, vec->indices[i], vec->A[i]);
}
/**
* Print a SparseMatrix structure
*
* Parameters:
* mat: A pointer to the SparseMatrix to print
*/
void printSparseMatrix(const SparseMatrix* mat){
for(int i = mat->begin; i < mat->end + 1; i++)
printSparseVector(mat->vectors[i - mat->begin], i);
}
/**
* Perform dot product between a SparseVector and an array
*
* Parameters:
* vec1: A pointer to the SparseVector
* vec2: A pointer to the array
*
* Returns:
* The dot product of vec1 and vec2
*/
double vecSparseDotProduct(const SparseVector* vec1, const double* vec2){
double result = 0.0;
for(unsigned int i = 0; i < vec1->currNbElement; i++){
result += vec1->A[i] * vec2[vec1->indices[i]];
}
return result;
}
/**
* Perform dot product between a row of a SparseMatrix and a SparseVector
*
* Parameters:
* mat: A pointer to the sparseMatrix
* row: The row of the SparseMatrix to use
* vector: A pointer to the SparseVector
*
* Returns:
* The dot product between the row 'row' of mat and vector
*/
double sparseDotProduct(const SparseMatrix* mat, unsigned int row, const double* vector){
return vecSparseDotProduct(mat->vectors[row - mat->begin], vector);
}
/**
* Insert an element in a sparse vector
*
* Parameters:
* vec: A pointer to the SparseVector
* j: The indices at which to insert the element
* elem: The value to insert
*/
void sparseVecInsertElement(SparseVector* vec, unsigned int j, double elem){
vec->currNbElement++;
int i;
// Loop while element is high that the one to insert such as to keep the vector sorted
for (i = vec->currNbElement - 1; i >= 1 && vec->indices[i-1] > j; i--){
vec->indices[i] = vec->indices[i-1];
vec->A[i] = vec->A[i-1];
}
vec->indices[i] = j;
vec->A[i] = elem;
}
/**
* Insert an element in a sparse matrix
*
* Parameters:
* mat: A pointer to a SparseMatrix
* i: The row at which to insert the element
* j: The column at which to insert the element
* elem: The value to insert
*/
void sparseInsertElement(SparseMatrix* mat, unsigned int i, unsigned int j, double elem){
sparseVecInsertElement(mat->vectors[i - mat->begin], j, elem);
}
/**
* Reset a SparseVector removing all its elements.
*
* Parameters:
* vec: A pointer to the SparseVector to reset
*/
void resetSparseVector(SparseVector* vec){
vec->currNbElement = 0;
}
/**
* Reset a SparseMatrix removing all its elements.
*
* Parameters:
* mat: A pointer to the SparseMatrix to reset
*/
void resetSparseMatrix(SparseMatrix * mat){
for(int i = 0; i < mat->end - mat->begin + 1; i++)
resetSparseVector(mat->vectors[i]);
}
/**
* Perform dot product between to vectors in parallel
*
* Parameters:
* x: A pointer to the first vector
* y: A pointer to the second vector
* size: The size of the vectors
* startIndex: The starting index the calling process is responsible for
* endIndex: The ending index the calling process is responsible for
* myrank: The rank of the calling process
* nbproc: The number of processes
*
* Returns:
* The dot product between the row 'row' of mat and vector
*/
double MPIDotProduct(const double* x, const double* y, unsigned int size, unsigned int startIndex, unsigned int endIndex, int myrank, int nbproc){
double myResult = 0.0;
// Compute the dot product of the elements this process is responsible for
// Share the computations between each thread of this process
#pragma omp parallel reduction(+: myResult) default(shared)
{
#pragma omp for schedule(static)
for(unsigned int i = startIndex; i <= endIndex; i++){
myResult += x[i] * y[i];
}
}
double totResult;
// Sum the results of all processes
MPI_Allreduce(&myResult, &totResult, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
return totResult;
}
/**
* Perform A matrix multiplication between a SparseMatrix and an array in parallel
*
* Parameters:
* A: A pointer to the SparseMatrix
* x: A pointer to the array
* tmpBuff: A pointer to a buffer used for computation
* result: A pointer to an array which elements will be set to the result.
* startIndex: The starting index the calling process is responsible for
* endIndex: The ending index the calling process is responsible for
* myrank: The rank of the calling process
* nbproc: The number of processes
*
* Returns:
* The dot product between the row 'row' of mat and vector
*/
void MPIMatVecMul(const SparseMatrix* A, const double* x, double* tmpBuff, double* result, unsigned int startIndex, unsigned int endIndex, int myrank, int nbproc, int* recvcounts, int* displs){
// Compute the dot product with each line this process is responsible for
// Share the line betweens the thread of this process
#pragma omp parallel default(shared)
{
#pragma omp for schedule(static)
for(unsigned int i = startIndex ; i <= endIndex; i++){
tmpBuff[i-startIndex] = sparseDotProduct(A, i, x);
}
}
// Gather the result of all processes
MPI_Allgatherv(tmpBuff, (endIndex - startIndex + 1), MPI_DOUBLE, result, recvcounts, displs, MPI_DOUBLE, MPI_COMM_WORLD);
}
/**
* Perform dot product between two SparseVectors
*
* Parameters:
* vec1: A pointer to the first SparseVector
* vec2: A pointer to the second SparseVector
*
* Returns:
* The dot product between the two SparseVectors
*/
double sparseVecVecDotProduct(const SparseVector* vec1, const SparseVector* vec2){
// Initialise variables
double result = 0.0;
int i1 = 0;
int i2 = 0;
// While there are still element in the two vectors
while(i1 < vec1->currNbElement && i2 < vec2->currNbElement){
// If the current index of vec1 is lower than the one of vec2, go to next index of vec1
if(vec1->indices[i1] < vec2->indices[i2]){
i1++;
}
// If the current index of both vectors are the same, multiply both values, add to result and go to next index
else if(vec1->indices[i1] == vec2->indices[i2]){
result += vec1->A[i1] * vec2->A[i2];
i1++;
i2++;
}
// If the current index of vec2 is lower than the one of vec1, go to next index of vec2
else{
i2++;
}
}
return result;
}
/**
* Perform dot product between a row of a SparseMatrix and a SparseVector
*
* Parameters:
* mat: A pointer to the SparseMatrix
* row: The row of the SparseMatrix to use
* vec: A pointer to the SparseVector
*
* Returns:
* The dot product between the row 'row' of mat and vec
*/
double sparseMatVecDotProduct(const SparseMatrix* mat, unsigned int row, const SparseVector* vec){
return sparseVecVecDotProduct(mat->vectors[row - mat->begin], vec);
}