/*    TEMPL2
TESTING template CLAUSE */

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

static void templ211();
static void templ221();

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, ia, ib, ic, ja, jb, jc, k;

int main(int an, char **as)
{
    printf("=== START OF TEMPL2 ======================\n");
    /* TEMPLATE A2[BLOCK][BLOCK]   ALIGN B1[i] WITH A2[1][i]
                            ALIGN C2[i][j] WITH A2[2*i+2][j] */
    templ211();
    /* TEMPLATE A2[BLOCK][BLOCK]   ALIGN B1[i][j] WITH A2[i+4][j+4]
                            ALIGN C2[i][j] WITH A2[i+1][j+1] */
    templ221();
    printf("=== END OF TEMPL2 ========================\n");
    return 0;
}

/* ---------------------------------------------TEMPL211*/
/* TEMPLATE A2[BLOCK][BLOCK]   ALIGN B1[i] WITH A2[1][i]
                               ALIGN C2[i][j] WITH A2[2*i+2][j] */
void templ211()
{
    #define AN1 14
    #define AN2 14
    #define BN1 8
    #define CN1 4
    #define CN2 4

    int k1i = 0, k2i = 0, li = 1, k1j = 1, k2j = 0, lj = 0;
    int kc1i = 2, kc2i = 0, lci = 2, kc1j = 0, kc2j = 1, lcj = 0;
    char tname[] = "templ211 ";

    #pragma dvm template[AN1][AN2] distribute[block][block]
    void *A2;
    #pragma dvm array align([i] with A2[1][i])
    int B1[BN1];
    #pragma dvm array align([i][j] with A2[kc1i * i + lci][kc2j * j + lcj])
    int C2[CN1][CN1];

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
    #pragma dvm parallel([i] on B1[i])
    for (i = 0; i < BN1; i++)
        B1[i] = i;

    #pragma dvm parallel([j][i] on C2[i][j])
    for (j = 0; j < CN2; j++)
        for (i = 0; i < CN1; i++)
            C2[i][j] = (i*NL+j);

    #pragma dvm parallel([j][i] on A2[j][i]) private(ib, erri, ic, jc)
    for (j = 0; j < AN2; j++)
        for (i = 0; i < AN1; i++)
        {
            if (i == 0)
            {
                if (j < BN1)
                {
                    ib = j;
                    if (B1[ib] != (ib))
                        erri = i;
                }
            }
            if (((i-lci) == (((i-lci)/kc1i) * kc1i)) &&
                    ((j-lcj) == (((j-lcj)/kc2j) * kc2j)) &&
                    (((i-lci)/kc1i) >= 0) &&
                    (((j-lcj)/kc2j) >= 0) &&
                    (((i-lci)/kc1i) < CN1) &&
                    (((j-lcj)/kc2j) < CN2))
            {
                ic = (i-lci)/kc1i;
                jc = (j-lcj)/kc2j;
                if (C2[ic][jc] != (ic*NL+jc))
                    erri = i;
            }
        }
    }
    #pragma dvm get_actual(erri)

    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);

    #undef AN1
    #undef AN2
    #undef BN1
    #undef CN1
    #undef CN2
}

/* ---------------------------------------------TEMPL221*/
/* TEMPLATE A2[BLOCK][BLOCK]   ALIGN B1[i][j] WITH A2[i+4][j+4]
                               ALIGN C2[i][j] WITH A2[i+1][j+1] */
void templ221()
{
    int AN1 = 14, AN2 = 14, CN1 = 4, CN2 = 4, BN1 = 8, BN2 = 8;

    int k1i = 1, k2i = 0, li = 4, k1j = 0, k2j = 1, lj = 4;
    int kc1i = 1, kc2i = 0, lci = 1, kc1j = 0, kc2j = 1, lcj = 1;

    char tname[] = "templ221 ";

    #pragma dvm template[AN1][AN2] distribute[block][block]
    void *A2;
    #pragma dvm array
    int (*B2)[BN2];
    #pragma dvm array
    int (*C2)[CN2];

    B2 = malloc(sizeof(int[BN1][BN2]));
    C2 = malloc(sizeof(int[CN1][CN2]));
    #pragma dvm realign(B2[i][j] with A2[k1i * i + li][k2j * j + lj])
    #pragma dvm realign(C2[i][j] with A2[kc1i * i + lci][kc2j * j + lcj])

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
    #pragma dvm parallel([j][i] on B2[i][j])
    for (j = 0; j < BN2; j++)
        for (i = 0; i < BN1; i++)
            B2[i][j] = i*NL + j;

    #pragma dvm parallel([j][i] on C2[i][j])
    for (j = 0; j < CN2; j++)
        for (i = 0; i < CN1; i++)
            C2[i][j] = i*NL + j;


    #pragma dvm parallel([j][i] on A2[i][j]) private(ib, ic, erri, jb, jc)
    for (j = 0; j < AN2; j++)
        for (i = 0; i < AN1; i++)
        {
            if (((i-li) == (((i-li)/k1i) * k1i)) &&
                    ((j-lj) == (((j-lj)/k2j) * k2j)) &&
                    (((i-li)/k1i) >= 0) &&
                    (((j-lj)/k2j) >= 0) &&
                    (((i-li)/k1i) < BN1) &&
                    (((j-lj)/k2j) < BN2))
            {
                ib = (i-li)/k1i;
                jb = (j-lj)/k2j;
                if (B2[ib][jb] != (ib*NL + jb))
                    erri = i;
            }
            if (((i-lci) == (((i-lci)/kc1i) * kc1i)) &&
                    ((j-lcj) == (((j-lcj)/kc2j) * kc2j)) &&
                    (((i-lci)/kc1i) >= 0) &&
                    (((j-lcj)/kc2j) >= 0) &&
                    (((i-lci)/kc1i) < CN1) &&
                    (((j-lcj)/kc2j) < CN2))
            {
                ic = (i-lci)/kc1i;
                jc = (j-lcj)/kc2j;
                if (C2[ic][jc] != (ic*NL+jc))
                    erri = i;
            }
        }
    }

    #pragma dvm get_actual(erri)

    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);

    free(B2);
    free(C2);
}

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

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