/* PARALLEL1
Testing PARALLEL directive */

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

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

static void parallel11();
static void parallel12();
static void parallel13();
static void parallel131();
static void parallel14();
static void parallel15();


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;

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

    /* arrA1[BLOCK] PARALLEL ON arrA[i+4] normal */
    parallel11();
    /* arrA1[BLOCK] PARALLEL ON arrA[-i+8] reverse */
//  parallel12();
    /* arrA1[BLOCK] PARALLEL ON arrA[2*i+8] stretch */
    parallel13();
    /* arrA1[BLOCK] PARALLEL ON arrA[2*i+1] small array */
    parallel131();
    /* arrA1[BLOCK] PARALLEL ON arrA[] */
    parallel14();
    /* arrA1[BLOCK] PARALLEL ON arrA[2] */
    parallel15();

    printf ("=== END OF PARALLEL1 ===================\n");
    return 0;
}
/* ---------------------------------------------parallel11 */
    /* arrA1[BLOCK]  PARALLEL ON arrA[i+4] normal */
void parallel11()
{
    #define AN1 8

/*  parameters for PARALLEL arrA1[k1i * i + li] */
    int k1i = 1;
    int li = 4;

    #pragma dvm array distribute[block]
    int A1[AN1];
    char tname[] = "paral11 ";

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region local(A1)
    {
    #pragma dvm parallel([i] on A1[i])
    for (i = 0; i < AN1; i++)
        A1[i] = i;

    #pragma dvm parallel([i] on A1[k1i * i + li]) private(ia), reduction(min(erri))
    for (i = 0; i < ((AN1-li)/k1i); i++)
    {
        ia = k1i * i + li;
        if (A1[ia] != ia)
              erri = Min(erri, i);
    }
    } /* end region */

    #pragma dvm get_actual(erri)

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

    #undef AN1
}

/* ---------------------------------------------parallel12 */
    /* arrA1[BLOCK]  PARALLEL ON arrA[-i+8]  reverse */
void parallel12()
{
    #define AN1 7

/*  parameters for PARALLEL arrA1[k1i * i + li] */
    int k1i = -1;
    int li = 8;

    #pragma dvm array distribute[block]
    int *A1;
    char tname[] = "paral12 ";

    A1 = (int*)malloc(AN1*sizeof(int));

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A1[i])
    for (i = 0; i < AN1; i++)
        A1[i] = i * 2;

    #pragma dvm parallel([i] on A1[k1i * i + li]) private(ia), reduction(min(erri))
    for (i = 0; i < ((AN1-li)/k1i); i++)
    {
        ia = k1i * i + li;
        if (A1[ia] != (ia*2))
              erri = Min(erri, i);
    }
    } /* end region */

    #pragma dvm get_actual(erri)

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

    free (A1);

    #undef AN1
}

/* ---------------------------------------------parallel13 */
    /* arrA1[BLOCK]  PARALLEL ON arrA[2*i+8] stretch */
void parallel13()
{
    #define AN1 20

/*  parameters for PARALLEL arrA1[k1i * i + li]*/
    int k1i = 2;
    int li = 8;

    #pragma dvm array distribute[block]
    int *A1;
    char tname[] = "paral13 ";

    A1 = (int*)malloc(sizeof(int[AN1]));

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A1[i])
    for (i = 0; i < AN1; i++)
        A1[i] = i + 5;

    #pragma dvm parallel([i] on A1[k1i * i + li]) private(ia), reduction(min(erri))
    for (i = 0; i < ((AN1-li)/k1i); i++)
    {
        ia = k1i * i + li;
        if (A1[ia] != (ia + 5))
              erri = Min(erri, i);
    }
    } /* end region */

    #pragma dvm get_actual(erri)

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

    free(A1);
    #undef AN1
}

/* ---------------------------------------------parallel131 */
    /* arrA1[BLOCK]  PARALLEL ON arrA[2*i+1] small array */
void parallel131()
{
    #define AN1 5

/*  parameters for PARALLEL arrA1[k1i * i + li] */
    int k1i = 2;
    int li = 1;

    #pragma dvm array distribute[block]
    int *A1;
    char tname[] = "paral131";

    A1 = (int*)malloc(AN1*sizeof(int));

    erri = ER;

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A1[i])
    for (i = 0; i < AN1; i++)
        A1[i] = i;
    } /* end region */

    #pragma dvm actual(erri)

    #pragma dvm region local(A1)
    {
    #pragma dvm parallel([i] on A1[k1i * i + li]) private(ia), reduction(min(erri))
    for (i = 0; i < ((AN1-li)/k1i); i++)
    {
        ia=k1i * i + li;
        if (A1[ia] != ia)
              erri = Min(erri, i);
    }
    } /* end region */

    #pragma dvm get_actual(erri)

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

    free (A1);

    #undef AN1
}

/* ---------------------------------------------parallel14 */
    /* arrA1[BLOCK]  PARALLEL ON arrA[] */
void parallel14()
{
    #define AN1 20
    #define BN1 10

/*  parameters for PARALLEL arrA1[*] */
    #define k1i 0
    #define li 0

    #pragma dvm array distribute[block]
    int *A1;
    #pragma dvm array distribute[*]
    int *B1;

    char tname[] = "paral14 ";

    A1 = (int*)malloc(AN1*sizeof(int));
    B1 = (int*)malloc(BN1*sizeof(int));

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region local(A1, B1)
    {
    #pragma dvm parallel([i] on A1[i])
    for (i = 0; i < AN1; i++)
        A1[i] = i;

    for (i = 0; i < BN1; i++)
        B1[i] = i;

    #pragma dvm parallel([i] on A1[]) reduction(min(erri))
    for (i = 0; i < BN1; i++)
        if (B1[i] != i)
              erri = Min(erri, i);
    } /* end region */

    #pragma dvm get_actual(erri)

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

    free (A1);
    free (B1);

    #undef AN1
    #undef BN1
    #undef k1i
    #undef li
}

/* ---------------------------------------------parallel15 */
/* arrA1[BLOCK] PARALLEL ON arrA[2] */
void parallel15()
{
    #define AN1 15

/*  parameters for PARALLEL arrA1[li] */
    #define k1i 0
    #define li 2

    #pragma dvm array distribute[block]
    int *A1;

    char tname[] = "paral15 ";

    A1 = (int(*))malloc(AN1*sizeof(int));

    erri = ER;
    #pragma dvm actual(erri)

    #pragma dvm region local(A1)
    {
    #pragma dvm parallel([i] on A1[i])
    for(i = 0; i < AN1; i++)
        A1[i] = i;

    #pragma dvm parallel ([i] on  A1[li]) reduction(min(erri)), private(ia)
    for(i = 0; i < AN1; i++) {
        ia = li;
        if (A1[ia] != ia)
           erri = Min(erri, i);
    }
    } /* end region */

    #pragma dvm get_actual(erri)

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

    free(A1);
    #undef AN1
    #undef k1i
    #undef li
}

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

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