/*    DISTRWGT2
    Testing DISTRIBUTE and REDISTRIBUTE directives
            WGT_BLOCK distribution*/

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

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

static void distrwgt24();
static void distrwgt25();
static void distrwgt26();
static void distrwgt27();
static void distrwgt28();
static void distrwgt29();
static void distrwgt210();
static void distrwgt32();
static void distrwgt33();
static void distrwgt34();
static void distrwgt35();
static void distrwgt36();
static void distrwgt37();
static void distrwgt38();
static void distrwgt41();
static void distrwgt42();

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, k, n, ia, ib;

int main(int an, char **as)
{
    printf("=== START OF DISTRWGT2 ===================\n");
    /* 24  DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]  REDISTRIBUTE arrA2[*][*]*/
    distrwgt24();
    /* 25  DISTRIBUTE arrA2[*][*]  REDISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]*/
    distrwgt25();
    /* 26  DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]
                             REDISTRIBUTE arrA2[BLOCK][BLOCK]*/
    distrwgt26();
    /* 27  DISTRIBUTE arrA2[BLOCK][BLOCK]
                             REDISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]*/
    distrwgt27();
    /* 28  DISTRIBUTE arrA2[WGT_BLOCK][BLOCK]
                         REDISTRIBUTE arrA2[BLOCK][WGT_BLOCK]*/
    distrwgt28();
    /* 29  DISTRIBUTE arrA2[BLOCK][WGT_BLOCK]
                         REDISTRIBUTE arrA2[WGT_BLOCK][BLOCK]*/
    distrwgt29();
    /* 210  DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]    other weigths
                      REDISTRIBUTE [WGT_BLOCK][WGT_BLOCK]*/
    distrwgt210();
    /* 32  DISTRIBUTE  arrA3[WGT_BLOCK][WGT_BLOCK] [*]
                      REDISTRIBUTE arrA3[*][WGT_BLOCK][WGT_BLOCK]*/
    distrwgt32();
    /* 33  DISTRIBUTE  arrA3[WGT_BLOCK][WGT_BLOCK][*]
                     REDISTRIBUTE arrA3[WGT_BLOCK][*][BLOCK]*/
    distrwgt33();
    /* 34  DISTRIBUTE  arrA3[WGT_BLOCK][*][WGT_BLOCK]
                      REDISTRIBUTE arrA3[WGT_BLOCK][WGT_BLOCK][*]*/
    distrwgt34();
    /* 35  DISTRIBUTE  arrA3[WGT_BLOCK][WGT_BLOCK][*]
                      REDISTRIBUTE arrA3[*][*][WGT_BLOCK]*/
    distrwgt35();
    /* 36  DISTRIBUTE  arrA3[WGT_BLOCK][*][BLOCK]
                      REDISTRIBUTE arrA3[BLOCK][*][WGT_BLOCK]*/
    distrwgt36();
   /* 37  DISTRIBUTE  arrA3[WGT_BLOCK][BLOCK][*]
                      REDISTRIBUTE arrA3[BLOCK][*][WGT_BLOCK]*/
    distrwgt37();
    /* 38  DISTRIBUTE  arrA3[BLOCK][*][WGT_BLOCK]
                      REDISTRIBUTE arrA3[*][WGT_BLOCK][BLOCK]*/
    distrwgt38();
    /* 41  DISTRIBUTE arrA4[*][*][WGT_BLOCK][WGT_BLOCK]
                     REDISTRIBUTE arrA4[*][*][*][*]*/
    distrwgt41();
    /* 42  DISTRIBUTE arrA4[WGT_BLOCK][*][WGT_BLOCK][*]
                     REDISTRIBUTE arrA4[*][WGT_BLOCK][WGT_BLOCK][*]*/
    distrwgt42();

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

/* ---------------------------------------------DISTR24*/
/* 24   DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]  REDISTRIBUTE arrA2[*][*]*/
void distrwgt24()
{
    #define AN1 8
    #define AN2 8
    double wb1[4] = {2., 2., 3.0, 1.};
    double wb2[6] = {3.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrwgt24";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[wgtblock(wb1, 4)][wgtblock(wb2, 6)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[*][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR25*/
/* DISTRIBUTE arrA2[*][*]  REDISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]*/
void distrwgt25()
{
    #define AN1 8
    #define AN2 8
    double wb1[5] = {1.0,2.,2.,3.0, 0.};
    double wb2[7] = {1.0,1.,2.,1.0, 1.,1.,1.};
    #pragma dvm array distribute[*][*]
    int (*A2)[AN2];
    char tname[] = "distrwgt25";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[wgtblock(wb1, 5)][wgtblock(wb2, 7)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR26*/
/* DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]  REDISTRIBUTE arrA2[BLOCK][BLOCK]*/
void distrwgt26()
{
    #define AN1 12
    #define AN2 12
    double wb[6] = {1.0, 4., 1., 1.0, 2., 1.};
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrwgt26";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[wgtblock(wb, 6)][wgtblock(wb, 6)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[block][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR27*/
/* DISTRIBUTE arrA2[BLOCK][BLOCK]  REDISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]*/
void distrwgt27()
{
    #define AN1 8
    #define AN2 8
    double wb[6] = {2.0, 1., 3., 2.0, 1., 1.};
    #pragma dvm array distribute[block][block]
    int (*A2)[AN2];
    char tname[] = "distrwgt27";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[wgtblock(wb, 6)][wgtblock(wb, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR28*/
/* DISTRIBUTE arrA2[WGT_BLOCK][BLOCK]  REDISTRIBUTE arrA2[BLOCK][WGT_BLOCK]*/
void distrwgt28()
{
    #define AN1 12
    #define AN2 12
    double wb1[8] = {1.0, 2., 2., 3.0, 1., 1, 2, 4.};
    double wb2[6] = {1.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrwgt28";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[wgtblock(wb1, 8)][block])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[block][wgtblock(wb2, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR29*/
/* DISTRIBUTE arrA2[BLOCK][WGT_BLOCK]  REDISTRIBUTE arrA2[WGT_BLOCK][BLOCK]*/
void distrwgt29()
{
    #define AN1 12
    #define AN2 12
    double wb1[6] = {1.0, 2., 2., 3.0, 3, 1};
    double wb2[6] = {1.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrwgt29";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[block][wgtblock(wb1, 6)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[wgtblock(wb2, 6)][block])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR210*/
/* DISTRIBUTE arrA2[WGT_BLOCK][WGT_BLOCK]
               REDISTRIBUTE [WGT_BLOCK][WGT_BLOCK] with other weigths*/
void distrwgt210()
{
    #define AN1 12
    #define AN2 12
    double wb1[4] = {1.0, 2., 1., 1.0};
    double wb2[6] = {1.0, 1., 2., 1.0, 2., 1.};
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrwgt210";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[wgtblock(wb1, 4)][wgtblock(wb2, 6)])

    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                A2[i][j] = i * NL + j;
    }

    #pragma dvm redistribute(A2[wgtblock(wb2, 6)][wgtblock(wb1, 4)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j] on A2[i][j]) reduction(min(erri)), cuda_block(256)
        for (i = 0; i < AN1; i++)
            for (j = 0; j < AN2; j++)
                if (A2[i][j] != i * NL + j)
                    erri = Min(erri, i * NL + j);
    }

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

/* ---------------------------------------------DISTR32*/
/* DISTRIBUTE  arrA3[WGT_BLOCK][WGT_BLOCK][*]
                 REDISTRIBUTE arrA3[*][WGT_BLOCK][WGT_BLOCK]*/
void distrwgt32()
{
    #define AN1 16
    #define AN2 12
    #define AN3 8
    double wb1[7] = {1., 1., 2., 1.0, 2., 2., 3.0};
    double wb2[8] = {1.0, 2., 2., 3.0, 2, 1, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt32";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb1, 7)][wgtblock(wb2, 6)][*])

    #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[*][wgtblock(wb2, 6)][wgtblock(wb1, 4)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR33*/
/* DISTRIBUTE  arrA3[WGT_BLOCK][WGT_BLOCK][*]
                 REDISTRIBUTE arrA3[WGT_BLOCK][*][WGT_BLOCK]*/
void distrwgt33()
{
    #define AN1 16
    #define AN2 16
    #define AN3 8
    double wb[10] = {1.0, 2., 2., 3.0, 2., 4, 2., 1., 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt33";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb, 6)][wgtblock(wb, 8)][*])

    #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[wgtblock(wb, 10)][*][wgtblock(wb, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR34*/
/* DISTRIBUTE  arrA3[WGT_BLOCK][*][WGT_BLOCK]
                 REDISTRIBUTE arrA3[WGT_BLOCK][WGT_BLOCK][*]*/
void distrwgt34()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    double wb[8] = {1.0, 2., 2., 3.0, 1., 2, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt34";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb, 6)][*][wgtblock(wb, 8)])

    #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[wgtblock(wb, 8)][wgtblock(wb, 6)][*])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR35*/
/* DISTRIBUTE  arrA3[WGT_BLOCK][BLOCK][*]
                         REDISTRIBUTE arrA3[*][*][WGT_BLOCK]*/
void distrwgt35()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    double wb1[6] = {1.0, 2., 2., 3.0, 1.5, 2.5};
    double wb2[6] = {1.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt35";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb1, 6)][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[*][*][wgtblock(wb2, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR36*/
/* DISTRIBUTE  arrA3[WGT_BLOCK][*][BLOCK]
                         REDISTRIBUTE arrA3[BLOCK][*][WGT_BLOCK]*/
void distrwgt36()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    double wb[6] = {.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt36";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb, 6)][*][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][*][wgtblock(wb, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR37*/
/*DISTRIBUTE  arrA3[WGT_BLOCK][BLOCK][*]
                         REDISTRIBUTE arrA3[BLOCK][*][WGT_BLOCK]*/
void distrwgt37()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    double wb1[6] = {0.5, 1, 1.0, 2., 2., 3.0};
    double wb2[8] = {1.0, 2., 2., 3.0, 0.5, 2, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt37";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[wgtblock(wb1, 6)][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][*][wgtblock(wb2, 8)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR38*/
/*DISTRIBUTE  arrA3[BLOCK][*][WGT_BLOCK] REDISTRIBUTE arrA3[*][WGT_BLOCK][WGT_BLOCK]*/
void distrwgt38()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    double wb1[6] = {1.0, 2., 2., 3.0, 4, 5};
    double wb2[6] = {1.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrwgt38";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[block][*][wgtblock(wb1, 6)])

    #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[*][wgtblock(wb1, 6)][wgtblock(wb2, 6)])
    #pragma dvm region
    {
        #pragma dvm parallel([i][j][k] on A3[i][j][k]) reduction(min(erri)), 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)
                        erri = Min(erri, i*NL/10 + j*NL/100 + k);
    }

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

/* ---------------------------------------------DISTR41*/
/*DISTRIBUTE arrA4[*][*][WGT_BLOCK][WGT_BLOCK]
                REDISTRIBUTE arrA4[*][*][*][*]*/
void distrwgt41()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    #define AN4 8
    double wb[8] = {1.0, 2., 2., 3.0, 1., 1., 2, 1};
    #pragma dvm array
    int (*A4)[AN2][AN3][AN4];
    char tname[] = "distrwgt41";

    erri = ER;

    A4 = malloc(AN1 * AN2 * AN3 * AN4 * sizeof(int));
    #pragma dvm redistribute(A4[*][*][wgtblock(wb, 6)][wgtblock(wb, 8)])

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

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

/* ---------------------------------------------DISTR42*/
/*DISTRIBUTE arrA4[WGT_BLOCK][*][WGT_BLOCK][*] REDISTRIBUTE arrA4[*][WGT_BLOCK][WGT_BLOCK][*]*/
void distrwgt42()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    #define AN4 8
    double wb[6] = {1.0, 2., 2., 3.0, 1., 1.};
    #pragma dvm array
    int (*A4)[AN2][AN3][AN4];
    char tname[] = "distrwgt42";

    erri = ER;

    A4 = malloc(AN1 * AN2 * AN3 * AN4 * sizeof(int));
    #pragma dvm redistribute(A4[wgtblock(wb, 6)][*][wgtblock(wb, 6)][*])

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

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

    #pragma dvm get_actual(erri)
    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    free(A4);
    #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);
}
