/* Main control of the folding mapping. 1. This routine only folds the 3 true dimensions. T dimension (if in virtual node mode) is handled specifically in the caller of this routine. 2. finished = perm_next( ndims, perm_array[ndims] ) gets the next permutation. It returns 1 when there is no next permutation. For ndims = 3, the permutation sequence is 0,1,2 --> 0,2,1 --> 1,0,2 --> 1,2,0 --> 2,0,1 --> 2,0,1 --> finished. 3. fail = find_fold( dims1[ndims1], dims2[ndims2], fold[3][3] ) searchs a folding schedule, the folding schedule is stored in matrix fold[3][3] e.g. fold[i][j] = 3 indicates to unfold dimension i onto dimension j. fold[i][i] has no meaning. For 3D case as here, there will be at most 2 non-zero, non-diagonal entries. Diagonal entries are useless here. Further more, when the 2 non-zero entries are in the same row, the virtual cartesian is unfolded from the row_id dimension onto the other dimensions in physical cartesian. when the 2 entries are in the same coloum, the virtual cartesian is actually folded from the physical cartesian. 4. perform_fold( vir_coord[], phy_coord[], fold[3][3] ) does the folding following the schedule given by fold[3][3]. */ static int perm_dims_match( int nd1, int d1[], int c1[], int nd2, int d2[], int c2[] ) { int perm[3] = {0,1,2}; int fold[3][3] = {{0,0,0}, {0,0,0}, {0,0,0}}; int fail, finished; int dd2[3], i; fail = 1; finished = 0; while( !finished ) { for (i=0; i<3; i++) dd2[i] = d2[perm[i]]; fail = find_fold( nd1, d1, nd2, dd2, fold ); if (!fail) { break; } finished = perm_next( nd2, perm ); } if (fail) return 1; perform_fold( nd1, d1, c1, nd2, d2, c2, perm, fold ); return 0; }
void test_perm(int n) { int a1[PERM_NMAX], a2[PERM_NMAX], aprev[PERM_NMAX], count[PERM_NMAX]; int i, j, index, eindex; #ifndef QUIET printf("perm enumeration tests, n=%d\n", n); #endif eindex = 0; perm_first(a1, n); do { index = perm_to_index(a1, n); perm_from_index(a2, n, index); #ifndef QUIET { const char *sep; putchar('{'); sep = ""; for (i = 0; i < n; i++) { printf("%s%d", sep, a1[i]); sep = ","; } printf("} -> %d -> {", index); sep = ""; for (i = 0; i < n; i++) { printf("%s%d", sep, a2[i]); sep = ","; } printf("}\n"); } #endif /* * Check that a1 contains the numbers 0..n-1 in some order. */ for (i = 0; i < n; i++) count[i] = 0; for (i = 0; i < n; i++) { LE(0, a1[i]); LT(a1[i], n); EQ(count[i], 0); count[i]++; } /* * Check that a1 is lexicographically strictly greater than * the previous permutation, if any. */ if (eindex > 0) { for (i = 0; i < n; i++) { LE(aprev[i], a1[i]); if (aprev[i] < a1[i]) break; } LT(i, n); } memcpy(aprev, a1, sizeof(*a1) * n); /* * Check that perm_to_index got the answer right. */ EQ(index, eindex); /* * And perm_from_index. */ EQ(memcmp(a2, a1, sizeof(*a1)*n), 0); eindex++; } while (perm_next(a1, n)); #ifndef QUIET printf("perm discontinuous tests, n=%d\n", n); #endif /* * Now do a bunch of these tests again, with the input * permutation _not_ being simple increasing integers. */ eindex = 0; for (i = 0; i < n; i++) a1[i] = i + i*i + i*i*i; do { index = perm_to_index(a1, n); #ifndef QUIET { const char *sep; putchar('{'); sep = ""; for (i = 0; i < n; i++) { printf("%s%d", sep, a1[i]); sep = ","; } printf("} -> %d\n", index); } #endif /* * Check that a1 contains the right numbers in some order. */ for (i = 0; i < n; i++) count[i] = 0; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) if (a1[i] == j + j*j + j*j*j) break; LT(j, n); EQ(count[j], 0); count[j]++; } /* * Check that a1 is lexicographically strictly greater than * the previous permutation, if any. */ if (eindex > 0) { for (i = 0; i < n; i++) { LE(aprev[i], a1[i]); if (aprev[i] < a1[i]) break; } LT(i, n); } memcpy(aprev, a1, sizeof(*a1) * n); /* * Check that perm_to_index got the answer right. */ EQ(index, eindex); eindex++; } while (perm_next(a1, n)); EQ(eindex, perm_count(n)); }