| 1 | /* VerifyThis 2017, Challenge 3: part 2: the concurrent algorithm.
|
|---|
| 2 | * I have implemented the algorithm using MPI, the standard message-passing interface.
|
|---|
| 3 | * It follows the pseudo-code almost exactly.
|
|---|
| 4 | * Verification succeeds for up to N=5 (N=number of procs=length of array).
|
|---|
| 5 | * Author: Stephen Siegel.
|
|---|
| 6 | */
|
|---|
| 7 | #include <mpi.h>
|
|---|
| 8 | #define T double
|
|---|
| 9 | #define MPI_T MPI_DOUBLE
|
|---|
| 10 | $input int N = 4; // size of array: can be specified on command line with -inputN=...
|
|---|
| 11 | $input T A[N]; // input array : constant, fixed forever
|
|---|
| 12 | T myvalue; // this is a local variable for each process in MPI
|
|---|
| 13 |
|
|---|
| 14 | /* Counts the number of occurences of val in the array
|
|---|
| 15 | * starting at p consisting of n ints */
|
|---|
| 16 | int count(int n, T *p, T val) {
|
|---|
| 17 | int result = 0;
|
|---|
| 18 | for (int i=0; i < n; i++) if ((p[i]) == val) result++;
|
|---|
| 19 | return result;
|
|---|
| 20 | }
|
|---|
| 21 |
|
|---|
| 22 | /* Asserts the sequence starting at p2 is the permutation of that
|
|---|
| 23 | * starting at p1 with elements occurring in nondecreasing order */
|
|---|
| 24 | void assertSortOf(int n, T *p1, T *p2) {
|
|---|
| 25 | $assert($forall (int i : 0..n-2) p2[i]<=p2[i+1]);
|
|---|
| 26 | $assert($forall (int i : 0..n-1)
|
|---|
| 27 | $exists (int j : 0..n-1) p1[i]==p2[j]);
|
|---|
| 28 | for (int i=0; i<n; i++)
|
|---|
| 29 | $assert(count(n, p1, p2[i]) == count(n, p2, p2[i]));
|
|---|
| 30 | }
|
|---|
| 31 |
|
|---|
| 32 | void oddEvenPar(int n, int id) {
|
|---|
| 33 | T othervalue;
|
|---|
| 34 | for (int i=0; i<n; i++) {
|
|---|
| 35 | if ((i+id)%2 == 0) {
|
|---|
| 36 | if (id<n-1) {
|
|---|
| 37 | MPI_Send(&myvalue, 1, MPI_T, id+1, 0, MPI_COMM_WORLD);
|
|---|
| 38 | MPI_Recv(&othervalue, 1, MPI_T, id+1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|---|
| 39 | if (othervalue < myvalue)
|
|---|
| 40 | myvalue = othervalue;
|
|---|
| 41 | }
|
|---|
| 42 | } else { // odd
|
|---|
| 43 | if (id>0) {
|
|---|
| 44 | MPI_Send(&myvalue, 1, MPI_T, id-1, 0, MPI_COMM_WORLD);
|
|---|
| 45 | MPI_Recv(&othervalue, 1, MPI_T, id-1, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
|
|---|
| 46 | if (othervalue > myvalue)
|
|---|
| 47 | myvalue = othervalue;
|
|---|
| 48 | }
|
|---|
| 49 | }
|
|---|
| 50 | }
|
|---|
| 51 | }
|
|---|
| 52 |
|
|---|
| 53 | int main() {
|
|---|
| 54 | int nprocs, rank;
|
|---|
| 55 | MPI_Init(NULL, NULL); // initialize MPI
|
|---|
| 56 | MPI_Comm_size(MPI_COMM_WORLD, &nprocs); // get the number of procs
|
|---|
| 57 | MPI_Comm_rank(MPI_COMM_WORLD, &rank); // get my "rank" (id)
|
|---|
| 58 | $assert(nprocs == N); // number of procs must equal N
|
|---|
| 59 | myvalue = A[rank]; // get my value from the global input array A
|
|---|
| 60 | oddEvenPar(nprocs, rank); // call the function that does the work
|
|---|
| 61 | if (rank == 0) { // proc 0 will gather all data and check it is correct
|
|---|
| 62 | T a[N]; // used for verification---gather all elements into one array on proc 0
|
|---|
| 63 | MPI_Gather(&myvalue, 1, MPI_T, a, 1, MPI_T, 0, MPI_COMM_WORLD);
|
|---|
| 64 | assertSortOf(N, A, a);
|
|---|
| 65 | } else {
|
|---|
| 66 | MPI_Gather(&myvalue, 1, MPI_T, NULL, 0, MPI_T, 0, MPI_COMM_WORLD);
|
|---|
| 67 | }
|
|---|
| 68 | MPI_Finalize();
|
|---|
| 69 | }
|
|---|