/*    DISTRGEN3
TESTING distribute and redistribute CLAUSE
for arrays distributed with GEN-block*/

#include <math.h>
#include <stdlib.h>
#include <stdio.h>

#define Min(a, b) ((a) < (b) ? (a) : (b))

#ifndef _DVMH
#define dvmh_get_num_procs(X) 1
#endif

static void distrg31();
static void distrg32();
static void distrg33();
static void distrg34();
static void distrg35();
static void distrg36();
static void distrg37();
static void distrg38();
static void distrg39();
static void distrg310();
static void distrg311();

static void ansyes(const char tname[]);
static void ansno(const char tname[]);

static int NL = 1000;
static int ER = 10000;
static int erria, errib, i, j, k, ia, ib;

int main(int an, char **as)
{
    printf("=== START OF DISTRGEN3 ===================\n");
    /* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK] other blocks*/
    distrg31();

    /* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [BLOCK][BLOCK][BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]*/
    distrg32();

    /* DISTRIBUTE arrA3[BLOCK][GEN_BLOCK][GEN_BLOCK]   allocatable
       DISTRIBUTE arrB3[BLOCK][GEN_BLOCK][GEN_BLOCK]   static
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][BLOCK]*/
    distrg33();

    /* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]  !static
                REDISTRIBUTE [GEN_BLOCK][*][BLOCK]
       DISTRIBUTE arrB3[GEN_BLOCK][*][BLOCK]            !static
                REDISTRIBUTE [BLOCK][GEN_BLOCK][*]*/
    distrg34();

    /* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE arrA2[*][*][*]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]*/
    distrg35();

    /* 36 DISTRIBUTE arrA3[GEN_BLOCK][BLOCK][GEN_BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][BLOCK]*/
    distrg36();

    /* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][BLOCK][GEN_BLOCK]*/
    distrg37();

    /* DISTRIBUTE arrA3 [GEN_BLOCK][*][GEN_BLOCK]
                REDISTRIBUTE [*][GEN_BLOCK][*]
                REDISTRIBUTE[GEN_BLOCK][GEN_BLOCK][*]
                REDISTRIBUTE[*][GEN_BLOCK][GEN_BLOCK]*/
    distrg38();

    /* 39 DISTRIBUTE arrA3 [*][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][*][*]
                REDISTRIBUTE[GEN_BLOCK][*][GEN_BLOCK]*/
    distrg39();

    /* 310 DISTRIBUTE arrA3 [GEN_BLOCK][GEN_BLOCK][*]
                REDISTRIBUTE [*][*][GEN_BLOCK]
                REDISTRIBUTE[*][GEN_BLOCK][BLOCK]*/
    distrg310();

    /* 311 DISTRIBUTE arrA3 [GEN_BLOCK][*][*]
                REDISTRIBUTE [*][*][*]
                REDISTRIBUTE[*][*][GEN_BLOCK]*/
    distrg311();

    printf("=== END OF DISTRGEN3 =====================\n");
    return 0;
}

static int myRand() {
    const unsigned a = 1103515245U;
    const unsigned c = 12345U;
    const unsigned m = ((unsigned)RAND_MAX) + 1U;
    static unsigned prev = 5;
    prev = (a * prev + c) % m;
    return prev;
}

static void genBlocksAxis(const int procCount, const int weight, const int withoutZero, int **blocks) {
    *blocks = (int *)malloc(procCount * sizeof(int));
    int restWeight = weight, i, zeroind = -1;
    if (!withoutZero && procCount != 1)
        zeroind = myRand() % (procCount - 1);
    for (i = 0; i < (procCount - 1); i++) {
        if (i == zeroind)
            (*blocks)[i] = 0;
        else
            (*blocks)[i] = 1 * withoutZero + myRand() % (restWeight - (procCount - (i + 1)));
        restWeight -= (*blocks)[i];
    }
    (*blocks)[i] = restWeight;
}

/* ---------------------------------------------DISTR31*/
/* DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK] other blocks*/
void distrg31()
{
    #define AN1 12
    #define AN2 17
    #define AN3 16
    int *BS1i, *BS1j, *BS1k, *BS2i, *BS2j, *BS2k;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1i);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1j);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1k);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2i);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2j);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS2k);
    #pragma dvm array distribute[genblock(BS1i)][genblock(BS1j)][genblock(BS1k)]
    int A3[AN1][AN2][AN3];
    char tname[] = "distrg31";

    erria = ER;

    #pragma dvm region out(A3)
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }
    #pragma dvm redistribute(A3[genblock(BS2i)][genblock(BS2j)][genblock(BS2k)])

    #pragma dvm region in(A3)
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(BS1i);
    free(BS1j);
    free(BS1k);
    free(BS2i);
    free(BS2j);
    free(BS2k);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ---------------------------------------------DISTR32*/
/* DISTRIBUTE arrA32[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [BLOCK][BLOCK][BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]*/
void distrg32()
{
    #define AN1 8
    #define AN2 14
    #define AN3 6
    int *BS1i, *BS1j, *BS1k, *BS2i, *BS2j, *BS2k;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1i);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1j);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1k);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2i);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2j);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS2k);
    #pragma dvm array distribute[genblock(BS1i)][genblock(BS1j)][genblock(BS1k)]
    int A3[AN1][AN2][AN3];
    char tname[] = "distrg32";

    erria = ER;

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k + 1;
    }

    #pragma dvm redistribute(A3[block][block][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k]++;
    }

    #pragma dvm redistribute(A3[genblock(BS2i)][genblock(BS2j)][genblock(BS2k)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k])  reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 2)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(BS1i);
    free(BS1j);
    free(BS1k);
    free(BS2i);
    free(BS2j);
    free(BS2k);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ---------------------------------------------distrg33*/
/* DISTRIBUTE arrA3[BLOCK][GEN_BLOCK][GEN_BLOCK]   allocatable
     DISTRIBUTE arrB3[BLOCK][GEN_BLOCK][GEN_BLOCK]   static
                REDISTRIBUTE [GEN_BLOCK][BLOCK][BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][BLOCK]*/
void distrg33()
{
    #define AN1 12
    #define AN2 17
    #define AN3 16
    #define BN1 10
    #define BN2 10
    #define BN3 10
    int *BS1aj, *BS1ak, *BS1bi, *BS1bj, *BS1bk, *BS2ai, *BS2aj, *BS2ak, *BS2bi, *BS2bj, *BS2bk;
    genBlocksAxis(dvmh_get_num_procs(1), BN1, 1, &BS1bi);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1ak);
    genBlocksAxis(dvmh_get_num_procs(2), BN2, 1, &BS1bj);
    genBlocksAxis(dvmh_get_num_procs(3), BN3, 1, &BS1bk);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS2ak);
    genBlocksAxis(dvmh_get_num_procs(1), BN1, 1, &BS2bi);
    genBlocksAxis(dvmh_get_num_procs(2), BN2, 1, &BS2bj);
    genBlocksAxis(dvmh_get_num_procs(3), BN3, 1, &BS2bk);
    #pragma dvm array distribute[block][genblock(BS1bj)][genblock(BS1bk)]
    int B3[BN1][BN2][BN3];
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg33";

    erria = ER;
    errib = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[block][genblock(BS1aj)][genblock(BS1ak)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;

        #pragma dvm parallel([i][j][k] on B3[i][j][k]) cuda_block(256)
        for (i = 0; i < BN1; i++)
            for (j = 0; j < BN2; j++)
                for (k = 0; k < BN3; k++)
                    B3[i][j][k] = (i*NL/10 + j*NL/100 + k) * 2;
    }

    #pragma dvm redistribute(A3[genblock(BS2ai)][genblock(BS2aj)][block])
    #pragma dvm redistribute(B3[genblock(BS2bi)][genblock(BS2bj)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k);

        #pragma dvm parallel([i][j][k] on B3[i][j][k]) reduction(min(errib)), cuda_block(256)
        for (i = 0; i < BN1; i++)
            for(j = 0; j < BN2; j++)
                for(k = 0; k < BN3; k++)
                    if (B3[i][j][k] != (i*NL/10 + j*NL/100 + k) * 2)
                        errib = Min(errib, i*NL/10 + j*NL/100 + k);
    }

    #pragma dvm get_actual(erria, errib)
    if (erria == ER && errib == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1aj);
    free(BS1ak);
    free(BS1bi);
    free(BS1bj);
    free(BS1bk);
    free(BS2ai);
    free(BS2aj);
    free(BS2ak);
    free(BS2bi);
    free(BS2bj);
    free(BS2bk);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef BN1
    #undef BN2
    #undef BN3
}

/* ---------------------------------------------distrg34*/
/*DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][*][BLOCK]
     DISTRIBUTE arrB3[GEN_BLOCK][*][BLOCK]
                 REDISTRIBUTE [BLOCK][GEN_BLOCK][*]   */
void distrg34()
{
    #define AN1 16
    #define AN2 16
    #define AN3 16
    #define BN1 12
    #define BN2 17
    #define BN3 11
    int *BS1ai, *BS1aj, *BS1ak, *BS1bi, *BS2ai, *BS2bj;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1ak);
    genBlocksAxis(dvmh_get_num_procs(1), BN1, 1, &BS1bi);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(2), BN2, 1, &BS2bj);
    #pragma dvm array distribute[genblock(BS1bi)][*][block]
    int B3[BN1][BN2][BN3];
    #pragma dvm array distribute[genblock(BS1ai)][genblock(BS1aj)][genblock(BS1ak)]
    int A3[AN1][AN2][AN3];
    char tname[] = "distrg34";

    erria = ER;
    errib = ER;

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;

        #pragma dvm parallel([i][j][k] on B3[i][j][k]) cuda_block(256)
        for (i = 0; i < BN1; i++)
            for (j = 0; j < BN2; j++)
                for (k = 0; k < BN3; k++)
                    B3[i][j][k] = (i*NL/10 + j*NL/100 + k) * 2;
    }

    #pragma dvm redistribute(A3[genblock(BS2ai)][*][block])
    #pragma dvm redistribute(B3[block][genblock(BS2bj)][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k);

        #pragma dvm parallel([i][j][k] on B3[i][j][k]) reduction(min(errib)), cuda_block(256)
        for (i = 0; i < BN1; i++)
            for(j = 0; j < BN2; j++)
                for(k = 0; k < BN3; k++)
                    if (B3[i][j][k] != (i*NL/10 + j*NL/100 + k) * 2)
                        errib = Min(errib, i*NL/10 + j*NL/100 + k);
    }

    #pragma dvm get_actual(erria, errib)
    if (erria == ER && errib == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(BS1ai);
    free(BS1aj);
    free(BS1ak);
    free(BS1bi);
    free(BS2ai);
    free(BS2bj);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef BN1
    #undef BN2
    #undef BN3
}

/* ----------------------------------------------------distrg35
    DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE arrA2[*][*][*]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][GEN_BLOCK]*/
void distrg35()
{
    #define AN1 16
    #define AN2 16
    #define AN3 16
    int *BS1ai, *BS1aj, *BS1ak, *BS2ai, *BS2aj, *BS2ak;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1ak);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS2ak);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg35";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][genblock(BS1aj)][genblock(BS1ak)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }

    #pragma dvm redistribute(A3[*][*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 3;
    }

    #pragma dvm redistribute(A3[genblock(BS2ai)][genblock(BS2aj)][genblock(BS2ak)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 3;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 6)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 6);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS1aj);
    free(BS1ak);
    free(BS2ai);
    free(BS2aj);
    free(BS2ak);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg36
 36 DISTRIBUTE arrA3[GEN_BLOCK][BLOCK][GEN_BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][GEN_BLOCK][BLOCK]*/
void distrg36()
{
    #define AN1 12
    #define AN2 12
    #define AN3 5
    int *BS1ai, *BS1ak, *BS2aj, *BS3aj, *BS3ak, *BS4ai, *BS4aj;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS1ak);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS4ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS4aj);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS3aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS3ak);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg36";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][block][genblock(BS1ak)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }

    #pragma dvm redistribute(A3[block][genblock(BS2aj)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[block][genblock(BS3aj)][genblock(BS3ak)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[genblock(BS4ai)][genblock(BS3aj)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 3)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 3);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS1ak);
    free(BS2aj);
    free(BS3ak);
    free(BS4ai);
    free(BS4aj);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg37
 37 DISTRIBUTE arrA3[GEN_BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][BLOCK]
                REDISTRIBUTE [BLOCK][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][BLOCK][GEN_BLOCK]*/
void distrg37()
{
    #define AN1 10
    #define AN2 15
    #define AN3 15
    int *BS1ai, *BS1aj, *BS2aj, *BS3aj, *BS3ak, *BS4ai, *BS4ak;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS2aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS4ai);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS4ak);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS3aj);
    genBlocksAxis(dvmh_get_num_procs(3), AN3, 1, &BS3ak);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg37";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][genblock(BS1aj)][block])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }

    #pragma dvm redistribute(A3[block][genblock(BS2aj)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[block][genblock(BS3aj)][genblock(BS3ak)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[genblock(BS4ai)][block][genblock(BS4ak)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 3)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 3);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS1aj);
    free(BS2aj);
    free(BS3aj);
    free(BS3ak);
    free(BS4ai);
    free(BS4ak);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg38
 38  DISTRIBUTE arrA3 [GEN_BLOCK][*][GEN_BLOCK]
                REDISTRIBUTE [*][GEN_BLOCK][*]
                REDISTRIBUTE[GEN_BLOCK][GEN_BLOCK][*]
                REDISTRIBUTE[*][GEN_BLOCK][GEN_BLOCK]*/
void distrg38()
{
    #define AN1 5
    #define AN2 6
    #define AN3 12
    int *BS1ai, *BS1aj, *BS2ai, *BS3aj, *BS3ai, *BS4ai, *BS4aj;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN3, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN2, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(1), AN2, 1, &BS4ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN3, 1, &BS4aj);
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS3aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS3ai);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg38";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][*][genblock(BS1aj)])

    #pragma dvm region out(A3)
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }

    #pragma dvm redistribute(A3[*][genblock(BS2ai)][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[genblock(BS3ai)][genblock(BS3aj)][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[*][genblock(BS4ai)][genblock(BS4aj)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 3)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 3);
   }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS1aj);
    free(BS2ai);
    free(BS3aj);
    free(BS3ai);
    free(BS4ai);
    free(BS4aj);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg39
 39 DISTRIBUTE arrA3 [*][GEN_BLOCK][GEN_BLOCK]
                REDISTRIBUTE [GEN_BLOCK][*][*]
                REDISTRIBUTE[GEN_BLOCK][*][GEN_BLOCK]*/
void distrg39()
{
    #define AN1 10
    #define AN2 16
    #define AN3 10
    int *BS1ai, *BS1aj, *BS2ai, *BS3aj, *BS3ai;
    genBlocksAxis(dvmh_get_num_procs(1), AN2, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN3, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(2), AN3, 1, &BS3aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS3ai);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg39";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[*][genblock(BS1ai)][genblock(BS1aj)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }


    #pragma dvm redistribute(A3[genblock(BS2ai)][*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k])
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[genblock(BS3ai)][*][genblock(BS3aj)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 2)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 2);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS1aj);
    free(BS2ai);
    free(BS3aj);
    free(BS3ai);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg310
 310 DISTRIBUTE arrA3 [GEN_BLOCK][GEN_BLOCK][*]
                REDISTRIBUTE [*][*][GEN_BLOCK]
                REDISTRIBUTE[*][GEN_BLOCK][BLOCK]*/
void distrg310()
{
    #define AN1 20
    #define AN2 15
    #define AN3 10
    int *BS1aj, *BS1ai, *BS2ai, *BS3ai;
    genBlocksAxis(dvmh_get_num_procs(2), AN2, 1, &BS1aj);
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(1), AN3, 1, &BS2ai);
    genBlocksAxis(dvmh_get_num_procs(1), AN2, 1, &BS3ai);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg310";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][genblock(BS1aj)][*])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }


    #pragma dvm redistribute(A3[*][*][genblock(BS2ai)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }

    #pragma dvm redistribute(A3[*][genblock(BS3ai)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 2)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 2);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1aj);
    free(BS1ai);
    free(BS2ai);
    free(BS3ai);
    #undef AN1
    #undef AN2
    #undef AN3
}

/* ----------------------------------------------------distrg311
 311 DISTRIBUTE arrA3 [GEN_BLOCK][*][*]
                REDISTRIBUTE [*][*][*]
                REDISTRIBUTE[*][*][GEN_BLOCK]*/
void distrg311()
{
    #define AN1 8
    #define AN2 16
    #define AN3 24
    int *BS1ai, *BS3ai;
    genBlocksAxis(dvmh_get_num_procs(1), AN1, 1, &BS1ai);
    genBlocksAxis(dvmh_get_num_procs(1), AN3, 1, &BS3ai);
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrg311";

    erria = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[genblock(BS1ai)][*][*])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] = i*NL/10 + j*NL/100 + k;
    }

    #pragma dvm redistribute(A3[*][*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;
    }
    #pragma dvm redistribute(A3[*][*][genblock(BS3ai)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (k = 0; k < AN3; k++)
                    A3[i][j][k] += 1;

        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erria)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for(j = 0; j < AN2; j++)
                for(k = 0; k < AN3; k++)
                    if (A3[i][j][k] != i*NL/10 + j*NL/100 + k + 2)
                        erria = Min(erria, i*NL/10 + j*NL/100 + k + 2);
    }

    #pragma dvm get_actual(erria)
    if (erria == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A3);
    free(BS1ai);
    free(BS3ai);
    #undef AN1
    #undef AN2
    #undef AN3
}

void ansyes(const char name[])
{
    printf("%s  -  complete\n", name);
}

void ansno(const char name[])
{
    printf("%s  -  ***error\n", name);
}
