/*    DISTR4
TESTING distribute and redistribute CLAUSE*/

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

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

static void distr44();
static void distr45();
static void distr46();
static void distr47();

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

static int NL = 1000;
static int ER = 10000;
static int erri, i, j, n, m, ia, ib;

int main(int an, char **as)
{
    printf("=== START OF DISTR4 ===================\n");
    /* DISTRIBUTE arrA4[*][*][*][*] REDISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK]*/
    distr44();
    /* DISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK] REDISTRIBUTE arrA4[*][*][*][*]*/
    distr45();
    /* DISTRIBUTE arrA4[*][*][*][*] REDISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK]
     small array*/
    distr46();
    /* DISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK] REDISTRIBUTE arrA4[*][*][*][*]
     small array*/
    distr47();
    printf("=== END OF DISTR4 =====================\n");
    return 0;
}
/* ---------------------------------------------DISTR44*/
/* DISTRIBUTE arrA4[*][*][*][*] REDISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK]*/
void distr44()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    #define AN4 8

    #pragma dvm array distribute[*][*][*][*]
    int A4[AN1][AN2][AN3][AN4];
    char tname[] = "distr44";

    erri = ER;
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        A4[i][j][n][m] = i * NL / 10 + j * NL / 100 + n * NL / 1000 + m;
    }
    #pragma dvm redistribute(A4[block][block][block][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        if (A4[i][j][n][m] != i * NL / 10 + j * NL / 100 + n * NL / 1000 + m)
                            erri = Min(erri, i * NL / 10 + j * NL / 100 + n * NL / 1000 + m);
    }

    #pragma dvm get_actual(erri)
    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef AN4
}
/* ---------------------------------------------DISTR45*/
/* DISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK] REDISTRIBUTE arrA4[*][*][*][*]*/
void distr45()
{
    #define AN1 5
    #define AN2 5
    #define AN3 5
    #define AN4 5

    #pragma dvm array distribute[block][block][block][block]
    float A4[AN1][AN2][AN3][AN4];
    char tname[] = "distr45";

    erri = ER;
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        A4[i][j][n][m] = i * NL / 10 + j * NL / 100 + n * NL / 1000 + m;
    }
    #pragma dvm redistribute(A4[*][*][*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        if (A4[i][j][n][m] != i * NL / 10 + j * NL / 100 + n * NL / 1000 + m)
                            erri = Min(erri, i * NL / 10 + j * NL / 100 + n * NL / 1000 + m);
    }

    #pragma dvm get_actual(erri)
    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef AN4
}
/* ---------------------------------------------DISTR46*/
/* DISTRIBUTE arrA4[*][*][*][*] REDISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK]
   small array*/
void distr46()
{
    #define AN1 5
    #define AN2 4
    #define AN3 3
    #define AN4 2

    #pragma dvm array distribute[*][*][*][*]
    double A4[AN1][AN2][AN3][AN4];
    char tname[] = "distr46";

    erri = ER;
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        A4[i][j][n][m] = i * NL / 10 + j * NL / 100 + n * NL / 1000 + m;
    }
    #pragma dvm redistribute(A4[block][block][block][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        if (A4[i][j][n][m] != i * NL / 10 + j * NL / 100 + n * NL / 1000 + m)
                            erri = Min(erri, i * NL / 10 + j * NL / 100 + n * NL / 1000 + m);
    }

    #pragma dvm get_actual(erri)
    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef AN4
}
/* ---------------------------------------------DISTR47*/
/* DISTRIBUTE arrA4[BLOCK][BLOCK][BLOCK][BLOCK] REDISTRIBUTE arrA4[*][*][*][*]
   small array*/
void distr47()
{
    #define AN1 1
    #define AN2 2
    #define AN3 3
    #define AN4 4

    #pragma dvm array distribute[block][block][block][block]
    int A4[AN1][AN2][AN3][AN4];
    char tname[] = "distr47";

    erri = ER;
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        A4[i][j][n][m] = i * NL / 10 + j * NL / 100 + n * NL / 1000 + m;
    }
    #pragma dvm redistribute(A4[*][*][*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][n][m] on A4[i][j][n][m]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                for (n = 0; n < AN3; n++)
                    for (m = 0; m < AN4; m++)
                        if (A4[i][j][n][m] != i * NL / 10 + j * NL / 100 + n * NL / 1000 + m)
                            erri = Min(erri, i * NL / 10 + j * NL / 100 + n * NL / 1000 + m);
    }

    #pragma dvm get_actual(erri)
    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef AN3
    #undef AN4
}

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

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