source: CIVL/examples/contracts/contractsMPI/gaussJordan_elimination_mpi.c

main
Last change on this file was ea777aa, checked in by Alex Wilton <awilton@…>, 3 years ago

Moved examples, include, build_default.properties, common.xml, and README out from dev.civl.com into the root of the repo.

git-svn-id: svn://vsl.cis.udel.edu/civl/trunk@5704 fb995dde-84ed-4084-dfe6-e5aef3e2452c

  • Property mode set to 100644
File size: 8.4 KB
Line 
1#include <assert.h>
2#include <mpi.h>
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6
7#define OWNER(index) ((nprocs*(index+1)-1)/numRow)
8
9int numRow, numCol;
10long double data[numRow][numCol]; // input matrix
11int * idx;
12int * loc;
13int localRow; // number of rows owned by the process
14int rank, nprocs;
15int first; // the global index of the first row in original
16 // matrix
17
18
19/* Performs a gaussian elimination on the given matrix, the output
20 * matrix will finally be in row echelon form .
21 */
22
23/*@ requires numRow > 0 && numCol >0;
24 @ requires \valid(loc + (0 .. numRow));
25 @ requires \valid(idx + (0 .. numRow));
26 @ requires 0<= localRow < numRow;
27 @ assigns a[0 .. localRow * numCol], idx[0 .. numRow],
28 @ loc[0 .. numRow];
29 @ \mpi_collective[p2p, MPI_COMM_WORLD]:
30 @ requires \mpi_valid(a, MPI_LONG_DOUBLE, numCol * localRow);
31 @ requires \sum(0, \mpi_comm_size, (\lambda int k;
32 @ \remote(localRow, k))) == numRow; // Requires each process holds a few rows of data
33 @ requires \forall int i; 0 <= i < numRow ==>
34 @ idx[i] == i && loc[i] == i; // loc and idx have initial values
35 @ ensure \forall int i, j; 0 <= i < numRow && 0 <= j < i // Ensures that the matrix a is already done
36 @ ==> \let owner = ((nprocs*(idx[i]+1)-1)/numRow); // gaussian elimination.
37 @ \remote(a, owner)[numCol * (idx[i] - first) + i] == 1
38 @ &&
39 @ \remote(a, owner)[numCol * (idx[i] - first) + j] == 0;
40 @ ensures \forall int i; 0 <= i < numRow ==>
41 @ \exists int j; 0 <= j < numRow ==> // Ensures that loc is valid, i.e. each cell in loc has
42 @ loc[j] == i; // a unique value in [0, numRow).
43 @ ensures \forall int i; 0 <= i < numRow ==>
44 @ \exists int j; 0 <= j < numRow ==> // Ensures that idx is valid, i.e. each cell in idx has
45 @ idx[j] == i; // a unique value in [0, numRow).
46 @ ensures \forall int i; 0 <= i < numRow ==>
47 @ i == loc[idx[i]]; // Ensures that loc[i] = j, then idx[j] = i;
48 @*/
49void gaussianElimination(long double *a) {
50 /* Buffer for the current toppest unprocessed row. */
51 long double top[numCol];
52
53 /* For each row of the matrix, it will be processed once. */
54 for(int i=0; i < numRow; i++) {
55 /* owner of the current unprocessed top row */
56 int owner = OWNER(idx[i]);
57 /* the column of the next leading 1, initial value is numCol
58 * because later it will pick up a minimum number.
59 */
60 int leadCol = numCol;
61 /* the global index of the row the next leading 1 will be in */
62 int rowOfLeadCol = numRow - 1;
63 int rowOfLeadColOwner; // the owner of rowOfLeadCol
64 /* message buffer: [0]:leadCol ;[1]:rowOfLeadCol */
65 int sendbuf[2];
66 /* receive buffer: it will contain lead 1 column candidates from
67 all processes */
68 int recvbuf[2*nprocs];
69 int tmp;
70
71 //step 1: find out the local leftmost nonzero column
72 for(int j=i; j < numCol; j++) {
73 int k, minLoc = numRow - 1;
74
75 for(k = first; k < first + localRow; k++) {
76 // only look at unprocessed rows
77 if(loc[k] >= i && loc[k] <= minLoc) {
78 if(a[(k-first)*numCol+j] != 0.0) {
79 leadCol = j;
80 rowOfLeadCol = k;
81 minLoc = loc[k];
82 }
83 }
84 }
85 if(leadCol < numCol)
86 break;
87 }
88 sendbuf[0] = leadCol;
89 sendbuf[1] = loc[rowOfLeadCol];
90 /* All reduce the smallest column(left-most) of leading 1 to every
91 process */
92 MPI_Allreduce(sendbuf, recvbuf, 1, MPI_2INT, MPI_MINLOC, MPI_COMM_WORLD);
93 leadCol = recvbuf[0];
94 rowOfLeadCol = idx[recvbuf[1]];
95 /* Now the row containing next leading 1 is decided, findout the
96 owner of it. */
97 rowOfLeadColOwner = OWNER(rowOfLeadCol);
98 /* if leadCol is still initial value, it means there is no avaliable
99 column suitable for next leading 1. */
100 if(leadCol == numCol)
101 return;
102 // step 2: reducing the leading number to 1
103 if(rank == rowOfLeadColOwner) {
104 long double denom = a[(rowOfLeadCol - first)*numCol + leadCol];
105
106 if(denom != 0.0)
107 for(int j=leadCol; j < numCol; j++)
108 a[(rowOfLeadCol - first)*numCol + j] = a[(rowOfLeadCol - first)*numCol + j] / denom;
109 memcpy(top, &a[(rowOfLeadCol - first)*numCol
110 ], numCol*sizeof(long double));
111 }
112 MPI_Bcast(top, numCol, MPI_LONG_DOUBLE, rowOfLeadColOwner, MPI_COMM_WORLD);
113 /* swap the row containing next leading 1 to the top location of
114 current submatrix */
115 if(loc[rowOfLeadCol] != i)
116 setLoc(rowOfLeadCol, i);
117 /* step 3: add a suitable value to all unprocessed rows to make
118 all numbers at the same column as leading 1 zeros. */
119 for(int j=0; j < localRow; j++) {
120 if(loc[j+first] > i){
121 long double factor = -a[j*numCol + leadCol];
122
123 for(int k=leadCol; k < numCol; k++) {
124 a[j*numCol + k] += factor * top[k];
125 }
126 }
127 }
128 }
129}
130
131
132
133/* Perform a backward reduction on the given matrix which transforms a
134 row echelon form to a reduced row echelon form */
135
136/*@ requires \valid(loc + (0 .. numRow));
137 @ requires \valid(idx + (0 .. numRow));
138 @ requires 0<= localRow < numRow;
139 @ requires numRow > 0 && numCol >0;
140 @ assigns a[0 .. localRow * numCol];
141 @ \mpi_collective[P2P, MPI_COMM_WORLD]:
142 @ requires \mpi_valid(a, MPI_LONG_DOUBLE, numCol * localRow);
143 @ requires \sum(0, \mpi_comm_size, (\lambda int k;
144 @ \remote(localRow, k))) == numRow; // Requires each process holds a few rows of data
145 @ requires \forall int i; 0 <= i < numRow ==>
146 @ \exists int j; 0 <= j < numRow ==> // loc is valid, i.e. each cell in loc has
147 @ loc[j] == i; // a unique value in [0, numRow).
148 @ requires \forall int i; 0 <= i < numRow ==>
149 @ \exists int j; 0 <= j < numRow ==> // idx is valid, i.e. each cell in idx has
150 @ idx[j] == i; // a unique value in [0, numRow).
151 @ requires \forall int i; 0 <= i < numRow ==> // If loc[i] = j, then idx[j] = i;
152 @ i == loc[idx[i]];
153 @ requires \forall int i, j; 0 <= i < numRow && 0 <= j < i // Requires that the matrix a is already done
154 @ ==> \let owner = ((nprocs*(idx[i]+1)-1)/numRow); // gaussian elimination.
155 @ \remote(a, owner)[numCol * (idx[i] - first) + i] == 1
156 @ &&
157 @ \remote(a, owner)[numCol * (idx[i] - first) + j] == 0;
158 @ ensures \forall int i,j; 0 <= i < numRow &&
159 @ 0 <= j < numCol-1 && i != j // Ensures the result is in row-echlon form
160 @ ==> \let owner = ((nprocs*(idx[i]+1)-1)/numRow);
161 @ \remote(a, owner)[numCol * (idx[i] - first) + i] == 1;
162 @ &&
163 @ \remote(a, owner)[numCol * (idx[i] - first) + j] == 0;
164*/
165void backwardReduce(long double *a) {
166 int leadCol;
167 int owner;
168 int i;
169 long double top[numCol];
170
171 i = (numRow > (numCol - 1))?(numCol-2):numRow-1;
172 for(; i>=1; i--) {
173 leadCol = -1;
174 owner = OWNER(idx[i]);
175 if(rank == owner)
176 memcpy(top, &a[(idx[i] - first)*numCol + i], (numCol-i)*sizeof(long double));
177 MPI_Bcast(top, (numCol-i), MPI_LONG_DOUBLE, owner, MPI_COMM_WORLD);
178 //find out the leading 1 column
179 for(int j=0; j<(numCol-i); j++){
180 if(top[j] != 0.0){
181 leadCol = j+i;
182 break;
183 }
184 }
185 if(leadCol == -1)
186 continue;
187 else {
188 for(int j=first; j<first+localRow; j++){
189 if(loc[j] < i){
190 long double factor = -a[(j-first)*numCol + leadCol];
191
192 for(int k=leadCol; k<numCol; k++)
193 a[(j-first)*numCol + k] += factor*top[k-i];
194 }
195 }
196 }
197 }
198}
Note: See TracBrowser for help on using the repository browser.