/*    ALIGN12
TESTING align CLAUSE*/

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

static void align121();
static void align122();
static void align123();

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

static int NL = 10000;
static int ER = 100000;
static int s, cs, erri, i, j, ia, ja, ib, jb;

int main(int an, char **as)
{
    printf("=== START OF ALIGN12 ======================\n");
/* ALIGN arrB[][i] WITH arrA[i]*/
    align121();
/*  ALIGN arrB[i][] WITH arrA[2 * i + 1]*/
    align122();
/*  ALIGN arrB[][] WITH arrA[]*/
    align123();

    printf("=== END OF ALIGN12 ========================\n");
    return 0;
}
/* ---------------------------------------------ALIGN121*/
/* ALIGN arrB[][i] WITH arrA[i]*/
void align121()
{
/*     parameters for ALIGN arrB[][i] WITH arrA[k1i * i + li]*/
    #define AN1 8
    #define AN2 0
    #define BN1 4
    #define BN2 4
    int k1i = 1;
    int li = 0;

    #pragma dvm array distribute[block]
    int A1[AN1];
    #pragma dvm array align([][i] with A1[k1i * i + li])
    int B2[BN1][BN2];
    char tname[] = "align121";

    erri = ER;
    s = 0;

    #pragma dvm actual(erri, s)
    #pragma dvm region local(A1, B2)
    {
    #pragma dvm parallel([i][j] on B2[i][j])
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
            B2[i][j] = 0;
    #pragma dvm parallel([i] on A1[i]) private(ib, jb, j)
    for (i = 0; i < AN1; i++)
    {
        A1[i] = i;
        for (j = 0; j < BN1; j++)
        {
            if (((i - li) ==(((i - li) / k1i) * k1i)) &&
                (((i - li) / k1i) >= 0)  &&
                (((i - li) / k1i) < BN2))
            {
                ib = j;
                jb = (i - li) / k1i;
                B2[ib][jb] = ib * NL + jb;
            }
        }
    };

    #pragma dvm parallel([i][j] on B2[i][j]) reduction(min(erri), sum(s))
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
        {
            int val = i * NL / 10 + j;
            s = s + B2[i][j];
            if (B2[i][j] != i * NL + j)
                if (erri > val) erri = val;
        }
    }
    #pragma dvm get_actual(erri, s)

    cs = 0;
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
            cs = cs + i * NL + j;
    if ((erri == ER) && (s == cs))
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef BN1
    #undef BN2
}
/* ---------------------------------------------ALIGN122*/
/*  ALIGN arrB[i][] WITH arrA[2 * i + 1]*/
void align122()
{
/*     parameters for ALIGN arrB[i][] WITH arrA[k1i * i + li]*/
    #define AN1 16
    #define AN2 0
    #define BN1 4
    #define BN2 4
    int k1i = 2;
    int li  = 1;

    #pragma dvm array distribute[block]
    int A1[AN1];
    #pragma dvm array align([i][] with A1[k1i * i + li])
    int B2[BN1][BN2];
    char tname[] = "align122";

    erri = ER;
    s = 0;

    #pragma dvm actual(erri, s)
    #pragma dvm region local(A1, B2)
    {
    #pragma dvm parallel([i][j] on B2[i][j])
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
            B2[i][j] = 0;
    #pragma dvm parallel([i] on A1[i]) private(ib, jb, j)
    for (i = 0; i < AN1; i++)
    {
        A1[i] = i;
        for (j = 0; j < BN1; j++)
        {
            if (((i - li) ==(((i - li) / k1i) * k1i)) &&
                (((i - li) / k1i) >= 0)  &&
                (((i - li) / k1i) < BN2))
            {
                jb = j;
                ib = (i - li) / k1i;
                B2[ib][jb] = ib * NL + jb;
            }
        }
    }

    #pragma dvm parallel([i][j] on B2[i][j]) reduction(min(erri), sum(s))
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
        {
            int val = i * NL / 10 + j;
            s = s + B2[i][j];
            if (B2[i][j] != (i * NL + j))
                if (erri > val) erri = val;
        }
    }
    #pragma dvm get_actual(erri, s)

    cs = 0;
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
            cs = cs + i * NL + j;
    if ((erri == ER) && (s == cs))
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef BN1
    #undef BN2
}
/* ---------------------------------------------ALIGN123*/
/*  ALIGN arrB[][] WITH arrA[]*/
void align123()
{
/*     parameters for ALIGN arrB[][] WITH arrA[]*/
    #define AN1 16
    #define AN2 0
    #define BN1 4
    #define BN2 4
    int k1i = 0;
    int li = 0;

    #pragma dvm array distribute[block]
    int A1[AN1];
    #pragma dvm array align([][] with A1[])
    int B2[BN1][BN2];
    char tname[] = "align123";

    erri = ER;

    #pragma dvm actual(erri)
    #pragma dvm region local(A1, B2)
    {
    for (i = 0; i < BN1; i++)
        for (j = 0; j < BN2; j++)
            B2[i][j] = i * NL + j;
    #pragma dvm parallel([i] on A1[i]) reduction(min(erri)), private(ib, jb)
    for (i = 0; i < AN1; i++)
        for (ib = 0; ib < BN1; ib++)
            for (jb = 0; jb < BN2; jb++)
            {
                int val = i * NL / 10 + j;
                if (B2[ib][jb] != ib * NL + jb)
                    if (erri > val) erri = val;
            }
    }
    #pragma dvm get_actual(erri)

    if (erri == ER)
        ansyes(tname);
    else
        ansno(tname);
    #undef AN1
    #undef AN2
    #undef BN1
    #undef BN2
}

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

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