Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Upgrade coll mpich testlist to new mpich
[simgrid.git] / teshsuite / smpi / mpich3-test / coll / allred4.c
1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
2 /*
3  *  (C) 2004 by Argonne National Laboratory.
4  *      See COPYRIGHT in top-level directory.
5  */
6 #include "mpi.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include "mpitest.h"
10 #include <assert.h>
11
12 /*
13 static char MTEST_Descrip[] = "Test MPI_Allreduce with non-commutative user-defined operations using matrix rotations";
14 */
15
16 /* This example is similar to allred3.c, but uses only 3x3 matrics with
17    integer-valued entries.  This is an associative but not commutative
18    operation.
19    The number of matrices is the count argument. The matrix is stored
20    in C order, so that
21      c(i,j) is cin[j+i*3]
22
23    Three different matrices are used:
24    I = identity matrix
25    A = (1 0 0    B = (0 1 0
26         0 0 1         1 0 0
27         0 1 0)        0 0 1)
28
29    The product
30
31          I^k A I^(p-2-k-j) B I^j
32
33    is
34
35    (0 1 0
36      0 0 1
37      1 0 0)
38
39    for all values of k, p, and j.
40  */
41
42 void matmult(void *cinPtr, void *coutPtr, int *count, MPI_Datatype * dtype);
43
44 void matmult(void *cinPtr, void *coutPtr, int *count, MPI_Datatype * dtype)
45 {
46     const int *cin = (const int *) cinPtr;
47     int *cout = (int *) coutPtr;
48     int i, j, k, nmat;
49     int tempcol[3];
50     int offset1, offset2;
51
52     for (nmat = 0; nmat < *count; nmat++) {
53         for (j = 0; j < 3; j++) {
54             for (i = 0; i < 3; i++) {
55                 tempcol[i] = 0;
56                 for (k = 0; k < 3; k++) {
57                     /* col[i] += cin(i,k) * cout(k,j) */
58                     offset1 = k + i * 3;
59                     offset2 = j + k * 3;
60                     tempcol[i] += cin[offset1] * cout[offset2];
61                 }
62             }
63             for (i = 0; i < 3; i++) {
64                 offset1 = j + i * 3;
65                 cout[offset1] = tempcol[i];
66             }
67         }
68         /* Advance to the next matrix */
69         cin += 9;
70         cout += 9;
71     }
72 }
73
74 /* Initialize the integer matrix as one of the
75    above matrix entries, as a function of count.
76    We guarantee that both the A and B matrices are included.
77 */
78 static void initMat(int rank, int size, int nmat, int mat[])
79 {
80     int i, kind;
81
82     /* Zero the matrix */
83     for (i = 0; i < 9; i++) {
84         mat[i] = 0;
85     }
86
87     /* Decide which matrix to create (I, A, or B) */
88     if (size == 2) {
89         /* rank 0 is A, 1 is B */
90         kind = 1 + rank;
91     }
92     else {
93         int tmpA, tmpB;
94         /* Most ranks are identity matrices */
95         kind = 0;
96         /* Make sure exactly one rank gets the A matrix
97          * and one the B matrix */
98         tmpA = size / 4;
99         tmpB = (3 * size) / 4;
100
101         if (rank == tmpA)
102             kind = 1;
103         if (rank == tmpB)
104             kind = 2;
105     }
106
107     switch (kind) {
108     case 0:    /* Identity */
109         mat[0] = 1;
110         mat[4] = 1;
111         mat[8] = 1;
112         break;
113     case 1:    /* A */
114         mat[0] = 1;
115         mat[5] = 1;
116         mat[7] = 1;
117         break;
118     case 2:    /* B */
119         mat[1] = 1;
120         mat[3] = 1;
121         mat[8] = 1;
122         break;
123     }
124 }
125
126 /* Compare a matrix with the known result */
127 static int checkResult(int nmat, int mat[], const char *msg)
128 {
129     int n, k, errs = 0, wrank;
130     static int solution[9] = { 0, 1, 0,
131         0, 0, 1,
132         1, 0, 0
133     };
134
135     MPI_Comm_rank(MPI_COMM_WORLD, &wrank);
136
137     for (n = 0; n < nmat; n++) {
138         for (k = 0; k < 9; k++) {
139             if (mat[k] != solution[k]) {
140                 errs++;
141                 if (errs == 1) {
142                     printf("Errors for communicators %s\n", MTestGetIntracommName());
143                     fflush(stdout);
144
145                 }
146                 if (errs < 10) {
147                     printf("[%d]matrix #%d(%s): Expected mat[%d,%d] = %d, got %d\n",
148                            wrank, n, msg, k / 3, k % 3, solution[k], mat[k]);
149                     fflush(stdout);
150                 }
151             }
152         }
153         /* Advance to the next matrix */
154         mat += 9;
155     }
156     return errs;
157 }
158
159 int main(int argc, char *argv[])
160 {
161     int errs = 0;
162     int size, rank;
163     int minsize = 2, count;
164     MPI_Comm comm;
165     int *buf, *bufout;
166     MPI_Op op;
167     MPI_Datatype mattype;
168     int i;
169
170     MTest_Init(&argc, &argv);
171
172     MPI_Op_create(matmult, 0, &op);
173
174     /* A single rotation matrix (3x3, stored as 9 consequetive elements) */
175     MPI_Type_contiguous(9, MPI_INT, &mattype);
176     MPI_Type_commit(&mattype);
177
178     /* Sanity check: test that our routines work properly */
179     {
180         int one = 1;
181         buf = (int *) malloc(4 * 9 * sizeof(int));
182         initMat(0, 4, 0, &buf[0]);
183         initMat(1, 4, 0, &buf[9]);
184         initMat(2, 4, 0, &buf[18]);
185         initMat(3, 4, 0, &buf[27]);
186         matmult(&buf[0], &buf[9], &one, &mattype);
187         matmult(&buf[9], &buf[18], &one, &mattype);
188         matmult(&buf[18], &buf[27], &one, &mattype);
189         checkResult(1, &buf[27], "Sanity Check");
190         free(buf);
191     }
192
193     while (MTestGetIntracommGeneral(&comm, minsize, 1)) {
194         if (comm == MPI_COMM_NULL)
195             continue;
196
197         MPI_Comm_size(comm, &size);
198         MPI_Comm_rank(comm, &rank);
199
200         for (count = 1; count < size; count++) {
201
202             /* Allocate the matrices */
203             buf = (int *) malloc(count * 9 * sizeof(int));
204             if (!buf) {
205                 MPI_Abort(MPI_COMM_WORLD, 1);
206             }
207
208             bufout = (int *) malloc(count * 9 * sizeof(int));
209             if (!bufout) {
210                 MPI_Abort(MPI_COMM_WORLD, 1);
211             }
212
213             for (i = 0; i < count; i++) {
214                 initMat(rank, size, i, &buf[i * 9]);
215             }
216
217             MPI_Allreduce(buf, bufout, count, mattype, op, comm);
218             errs += checkResult(count, bufout, "");
219
220             /* Try the same test, but using MPI_IN_PLACE */
221             for (i = 0; i < count; i++) {
222                 initMat(rank, size, i, &bufout[i * 9]);
223             }
224             MPI_Allreduce(MPI_IN_PLACE, bufout, count, mattype, op, comm);
225             errs += checkResult(count, bufout, "IN_PLACE");
226
227             free(buf);
228             free(bufout);
229         }
230         MTestFreeComm(&comm);
231     }
232
233     MPI_Op_free(&op);
234     MPI_Type_free(&mattype);
235
236     MTest_Finalize(errs);
237     MPI_Finalize();
238     return 0;
239 }