/*    DISTRMULT2
    TESTING distribute and redistribute directive
            MULT_BLOCK distribution*/

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

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

static void distrm24();
static void distrm25();
static void distrm26();
static void distrm27();
static void distrm28();
static void distrm29();
static void distrm210();
static void distrm32();
static void distrm33();
static void distrm34();
static void distrm35();
static void distrm36();
static void distrm37();
static void distrm38();
static void distrm41();
static void distrm42();

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

int main(int an, char **as)
{
    printf("=== START OF DISTRMULT2 ===================\n");

    /* 24  DISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]  REDISTRIBUTE arrA2[*][*]*/
    distrm24();
    /* 25  DISTRIBUTE arrA2[*][*]  REDISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]*/
    distrm25();
    /* 26  DISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]
                             REDISTRIBUTE arrA2[BLOCK][BLOCK]*/
    distrm26();
    /* 27  DISTRIBUTE arrA2[BLOCK][BLOCK]
                             REDISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]*/
    distrm27();
    /* 28  DISTRIBUTE arrA2[MULT_BLOCK][BLOCK]
                         REDISTRIBUTE arrA2[BLOCK][MULT_BLOCK]*/
    distrm28();
    /* 29  DISTRIBUTE arrA2[BLOCK][MULT_BLOCK]
                         REDISTRIBUTE arrA2[MULT_BLOCK][BLOCK]*/
    distrm29();
    /* 210  DISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]
              REDISTRIBUTE [MULT_BLOCK][MULT_BLOCK]  other m1,m2*/
    distrm210();
    /* 32  DISTRIBUTE  arrA3[MULT_BLOCK][MULT_BLOCK] [*]
                         REDISTRIBUTE arrA3[*][MULT_BLOCK][MULT_BLOCK]*/
    distrm32();
    /* 33  DISTRIBUTE  arrA3[MULT_BLOCK][MULT_BLOCK][*]
                          REDISTRIBUTE arrA3[MULT_BLOCK][*][BLOCK]*/
    distrm33();
    /* 34  DISTRIBUTE  arrA3[MULT_BLOCK][*][MULT_BLOCK]
                         REDISTRIBUTE arrA3[MULT_BLOCK][MULT_BLOCK][*]*/
    distrm34();
    /* 35  DISTRIBUTE  arrA3[MULT_BLOCK][MULT_BLOCK][*]
                         REDISTRIBUTE arrA3[*][*]MULT_BLOCK]*/
    distrm35();
    /* 36  DISTRIBUTE  arrA3[MULT_BLOCK][*][BLOCK]
                         REDISTRIBUTE arrA3[BLOCK][*][MULT_BLOCK]*/
    distrm36();
    /* 37  DISTRIBUTE  arrA3[MULT_BLOCK][BLOCK][*]
                         REDISTRIBUTE arrA3[BLOCK][*][MULT_BLOCK]*/
    distrm37();
    /* 38  DISTRIBUTE  arrA3[BLOCK][*][MULT_BLOCK]
                         REDISTRIBUTE arrA3[*][MULT_BLOCK][BLOCK]*/
    distrm38();
    /* 41  DISTRIBUTE arrA4[*][*][MULT_BLOCK][MULT_BLOCK]
                         REDISTRIBUTE arrA4[*][*][*][*]*/
    distrm41();
    /* 42  DISTRIBUTE arrA4[MULT_BLOCK][*][MULT_BLOCK][*]
                        REDISTRIBUTE arrA4[*][MULT_BLOCK][MULT_BLOCK][*]*/
    distrm42();

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

/* ---------------------------------------------DISTR24*/
/* DISTRIBUTE arrA2[MULT_BLOCK][MULT_BLOCK]  REDISTRIBUTE arrA2[*][*] */
void distrm24()
{
    #define AN1 15
    #define AN2 12
    int m1 = 5,m2 = 3;
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrm24";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[multblock(m1)][multblock(m2)])

    #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[MULT_BLOCK][MULT_BLOCK]*/
void distrm25()
{
    #define AN1 18
    #define AN2 8
    int m1 = 3,m2 = 2;
    #pragma dvm array distribute[*][*]
    int (*A2)[AN2];
    char tname[] = "distrm25";

    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[multblock(m1)][multblock(m2)])
    #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[MULT_BLOCK][MULT_BLOCK]
                REDISTRIBUTE arrA2[BLOCK][BLOCK]*/
void distrm26()
{
    #define AN1 49
    #define AN2 12
    int m1 = 7,m2 = 4;
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrm26";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[multblock(m1)][multblock(m2)])

    #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[MULT_BLOCK][MULT_BLOCK]*/
void distrm27()
{
    #define AN1 8
    #define AN2 64
    int m1 = 1,m2 = 8;
    #pragma dvm array distribute[block][block]
    int (*A2)[AN2];
    char tname[] = "distrm27";

    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[multblock(m1)][multblock(m2)])
    #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[MULT_BLOCK][BLOCK]  REDISTRIBUTE arrA2[BLOCK][MULT_BLOCK]*/
void distrm28()
{
    #define AN1 20
    #define AN2 20
    int m1 = 5, m2 = 4;
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrm28";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[multblock(m1)][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][multblock(m2)])
    #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][MULT_BLOCK]
                REDISTRIBUTE arrA2[MULT_BLOCK][BLOCK]*/
void distrm29()
{
    #define AN1 30
    #define AN2 60
    int m1 = 10,m2 = 10;
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrm29";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[block][multblock(m2)])

    #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[multblock(m1)][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[MULT_BLOCK][MULT_BLOCK]
                 REDISTRIBUTE [MULT_BLOCK][MULT_BLOCK]  other m1, m2*/
void distrm210()
{
    #define AN1 24
    #define AN2 24
    int m1 = 3,m2 = 2;
    #pragma dvm array
    int (*A2)[AN2];
    char tname[] = "distrm210";

    erri = ER;

    A2 = malloc(AN1 * AN2 * sizeof(int));
    #pragma dvm redistribute(A2[multblock(m1)][multblock(m2)])

    #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[multblock(m2)][multblock(m1)])
    #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[MULT_BLOCK][MULT_BLOCK] [*]
                 REDISTRIBUTE arrA3[*][MULT_BLOCK][MULT_BLOCK]*/
void distrm32()
{
    #define AN1 16
    #define AN2 12
    #define AN3 8
    int m1 = 2, m2 = 3, m3 = 4;
    #pragma dvm array

    int (*A3)[AN2][AN3];
    char tname[] = "distrm32";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][multblock(m2)][*])

    #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[*][multblock(m2)][multblock(m3)])
    #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[MULT_BLOCK][MULT_BLOCK][*]
                 REDISTRIBUTE arrA3[MULT_BLOCK][*][MULTBLOCK]*/
void distrm33()
{
    #define AN1 16
    #define AN2 16
    #define AN3 8
    int m1 = 4, m2 = 2, m3 = 2;
    #pragma dvm array

    int (*A3)[AN2][AN3];
    char tname[] = "distrm33";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][multblock(m2)][*])

    #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[multblock(m1)][*][multblock(m3)])
    #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[MULT_BLOCK][*][MULT_BLOCK]
                 REDISTRIBUTE arrA3[MULT_BLOCK][MULT_BLOCK][*]*/
void distrm34()
{
    #define AN1 8
    #define AN2 8
    #define AN3 8
    int m1 = 2, m2 = 1, m3 = 4;
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrm34";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][*][multblock(m3)])

    #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[multblock(m1)][multblock(m2)][*])
    #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[MULT_BLOCK][MULT_BLOCK][*]
                         REDISTRIBUTE arrA3[*][*][MULT_BLOCK]*/
void distrm35()
{
    #define AN1 18
    #define AN2 28
    #define AN3 38
    int m1 = 3, m2 = 7, m3 = 19;
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrm35";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][multblock(m2)][*])

    #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[*][*][multblock(m3)])
    #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[MULT_BLOCK][*][BLOCK]
                         REDISTRIBUTE arrA3[BLOCK][*][MULT_BLOCK]*/
void distrm36()
{
    #define AN1 121
    #define AN2 12
    #define AN3 35
    int m1 = 11, m2 = 2, m3 = 7;
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrm36";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][*][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][*][multblock(m3)])
    #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[MULT_BLOCK][BLOCK][*]
                         REDISTRIBUTE arrA3[BLOCK][*][MULT_BLOCK]*/
void distrm37()
{
    #define AN1 8
    #define AN2 28
    #define AN3 8
    int m1 = 2, m2 = 4, m3 = 2;
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrm37";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[multblock(m1)][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][*][multblock(m3)])
    #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][*][MULT_BLOCK] REDISTRIBUTE arrA3[*][MULT_BLOCK][MULT_BLOCK]*/
void distrm38()
{
    #define AN1 8
    #define AN2 28
    #define AN3 8
    int m1 = 2, m2 = 4, m3 = 2;
    #pragma dvm array
    int (*A3)[AN2][AN3];
    char tname[] = "distrm38";

    erri = ER;

    A3 = malloc(AN1 * AN2 * AN3 * sizeof(int));
    #pragma dvm redistribute(A3[block][*][multblock(m3)])

    #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[*][multblock(m2)][multblock(m3)])
    #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[*][*][MULT_BLOCK][MULT_BLOCK] REDISTRIBUTE arrA4[*][*][*][*]*/
void distrm41()
{
    #define AN1 16
    #define AN2 16
    #define AN3 16
    #define AN4 16
    int m1 = 2, m2 = 4, m3 = 2, m4 = 4;
    #pragma dvm array
    int (*A4)[AN2][AN3][AN4];
    char tname[] = "distrm41";

    erri = ER;

    A4 = malloc(AN1 * AN2 * AN3 * AN4 * sizeof(int));
    #pragma dvm redistribute(A4[*][*][multblock(m3)][multblock(m4)])

    #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[MULT_BLOCK][*][MULT_BLOCK][*]
                REDISTRIBUTE arrA4[*][MULT_BLOCK][MULT_BLOCK][*]*/
void distrm42()
{
    #define AN1 28
    #define AN2 25
    #define AN3 27
    #define AN4 21
    int m1 = 7, m2 = 5, m3 = 9, m4 = 3;
    #pragma dvm array
    int (*A4)[AN2][AN3][AN4];
    char tname[] = "distrm42";

    erri = ER;

    A4 = malloc(AN1 * AN2 * AN3 * AN4 * sizeof(int));
    #pragma dvm redistribute(A4[multblock(m1)][*][multblock(m3)][*])

    #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[*][multblock(m2)][multblock(m3)][*])
    #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);
}
