/*  Testing  REDUCTION clause
    REDUCTION operations: SUM,PRODUCT,MAX,MIN,AND,OR,MAXLOC,MINLOC and
    their combinations are executed
    for distributed array A(N)
*/

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

static void red1101();
static void red1102();
static void red1103();
static void red1104();
static void red1105();
static void red1106();
static void red1107();
static void red1108();
static void red1111();  /* tests 109-110 are absent */
static void red1112();
static void red1113();
static void red1114();
static void red1115();
static void red1116();

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

static int sersum1(int *AR, int N, int NL);
static int sersum1m(int *AR, int N, int NL);
static float sers1mr(float *RAR, int N, float RNL);
static int serprod1(int *AR, int N, int NL);
static float serprodr1(float *AR, int N, float RNL);
static int serand1(int *AR, int N);
static int seror1(int *AR, int N);

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

    red1101();
    red1102();
    red1103();
    red1104();
    red1105();
    red1106();
    red1107();
    red1108();
    red1111();
    red1112();
    red1113();
    red1114();
    red1115();
    red1116();

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

/* ---------------------------------------------RED1101 */
void red1101()
{
    #define N 32
    #define NL 1000

    int C[N];
    int i, isum1, isumt1;

    char tname[] = "RED1101";

    #pragma dvm array distribute[block]
    int A[N];

    isum1 = sersum1(C, N, NL);
    isumt1=0;

    #pragma dvm actual(isumt1)

    #pragma dvm region inout(A)
    {

    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL+i;

    #pragma dvm parallel([i] on A[i]) reduction(sum(isumt1))
    for (i = 0; i < N; i++)
        isumt1 = isumt1 + A[i];

    } /* end region */

    #pragma dvm get_actual(isumt1)

    if (isum1 == isumt1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("isum1=%d isumt1=%d\n",isum1,isumt1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1102  */
void red1102()
 {
    #define N 15
    #define NL 2

    int C[N];
    int i;
    int iprod1, iprodt1;
    char tname[] = "RED1102";

    #pragma dvm array distribute[block]
    int A[N];

    iprod1 = serprod1(C, N, NL);

    iprodt1 = 1;

    #pragma dvm actual(iprodt1)

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;

    #pragma dvm parallel([i] on A[i]) reduction(product(iprodt1))
    for (i = 0; i < N; i++)
        iprodt1 = iprodt1 * A[i];

    } /* end region */

    #pragma dvm get_actual(iprodt1)

    if (iprod1 == iprodt1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf ("iprod1 = %d, iprodt1 = %d\n", iprod1, iprodt1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1103  */
void red1103()
{
    #define N 30
    #define NL 1003

    int C[N];
    int i, imax1, imaxt1, ni;
    char tname[] = "RED1103";

    #pragma dvm array distribute[block]
    int A[N];

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;

    ni = N / 2 - 1;
    A[ni] = N + 1 + NL;

    #pragma dvm host_section
    {
    #pragma dvm remote_access(A[1])
    {
    imaxt1 = A[1];
    }
    #pragma dvm actual(imaxt1)
    } /* end host_section */

    #pragma dvm parallel([i] on A[i]) reduction(max(imaxt1))
    for (i = 0; i < N; i++)
        if (A[i] > imaxt1) imaxt1 = A[i];

    } /* end region */

    #pragma dvm get_actual(imaxt1)

    imax1 = N + 1 + NL;

    if (imax1 == imaxt1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imax1=%d imaxt1=%d\n",imax1,imaxt1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1104  */
void red1104()
{
    #define N 16
    #define NL 1004
    int C[N];
    int i, imin1, imint1, ni;
    char tname[] = "RED1104";

    #pragma dvm array distribute[block]
    int A[N];

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;

    } /* end region */

    #pragma dvm remote_access(A[1])
    {
    imint1 = A[1];
    }

    ni = N / 2 + 1;
    A[ni] = -(N + 1 + NL);
    imin1 = -(N + 1 + NL);

    #pragma dvm actual(imint1, A[ni])

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(min(imint1))
    for (i = 0; i < N; i++)
        if (A[i] < imint1) imint1 = A[i];
    } /* end region */

    #pragma dvm get_actual(imint1)

    if (imin1 == imint1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imin1=%d imint1=%d\n",imin1,imint1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1105 */
void red1105()
{
    #define N 32
    #define RNL 1005.

    float C[N];
    int i, ni;
    float imax1, imaxt1;
    char tname[] = "RED1105";

    #pragma dvm array distribute[block]
    float A[N];

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = RNL + i;

    ni = N / 2 - 1;
    A[ni] = N + 1. + RNL;
    imax1 = N + 1. + RNL;

    } /* end region */

    #pragma dvm get_actual(imax1)

    #pragma dvm remote_access(A[1])
    {
    imaxt1 = A[1];
    }

    #pragma dvm actual(imaxt1)

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A[i]) reduction(max(imaxt1))
    for (i = 0; i < N; i++)
        if (A[i] > imaxt1) imaxt1=A[i];

    } /* end region */

    #pragma dvm get_actual(imaxt1)

    if (imax1 == imaxt1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imax1=%f imaxt1=%f\n",imax1,imaxt1);
    }

    #undef N
    #undef RNL
}

/* ---------------------------------------------RED1106  */
void red1106()
{
    #define N 11
    float RNL = 1.;

    float C[N];
    int i;
    float iprod1, iprodt1;
    char tname[] = "RED1106";

    #pragma dvm array distribute[block]
    float A[N];

    iprod1 = serprodr1(C, N, RNL);
    iprodt1 = 1.;

    #pragma dvm actual(iprodt1)

    #pragma dvm region out(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = RNL + i;

    #pragma dvm parallel([i] on A[i]) reduction(product(iprodt1))
    for (i = 0; i < N; i++)
       iprodt1 = iprodt1 * A[i];

    } /* end region */

    #pragma dvm get_actual(iprodt1)

    if (iprod1 == iprodt1)
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf ("iprod1 = %f, iprodt1 = %f\n",  iprod1, iprodt1);
    }

    #undef N
}

/* ---------------------------------------------RED1107 */
void red1107()
{
    #define N 31

    int CL[N];
    int i;
    int land1, landt1;
    char tname[] = "RED1107";

    #pragma dvm array distribute[block]
    int A[N];

    land1 = serand1(CL, N);

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i+=2)
        A[i] = 1;

    #pragma dvm parallel([i] on A[i])
    for (i = 1; i < N; i+=2)
        A[i] = 0;

    } /* end region */

//    # pragma dvm get_actual(A)

    #pragma dvm remote_access(A[1])
    {
    landt1 = A[1];
    }

    #pragma dvm actual(landt1)

    #pragma dvm region inlocal(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(and(landt1))
    for (i = 0; i < N; i++)
       landt1 = landt1 && A[i];

    } /* end region */

    #pragma dvm get_actual(landt1)

    if (land1 == landt1)
        ansyes(tname);
    else
        ansno(tname);

    #undef N
}

/* ---------------------------------------------RED1108  */
void red1108()
{
    #define N 17

    int CL[N];
    int i;
    int lor1,lort1;
    char tname[] = "RED1108";

    #pragma dvm array distribute[block]
    int A[N];

    lor1 = seror1(CL, N);

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = i % 2;
    #pragma dvm host_section
    {
    #pragma dvm remote_access(A[1])
    {
    lort1 = A[1];
    }
    #pragma dvm actual(lort1)
    }

    #pragma dvm parallel([i] on A[i]) reduction(or(lort1))
    for (i = 0; i < N; i++)
       lort1 = lort1 || A[i];

    } /* end region */

    #pragma dvm get_actual(lort1)

    if (lor1 == lort1)
        ansyes(tname);
    else
        ansno(tname);

    #undef N
}

/* ---------------------------------------------RED1111 */
void red1111()
{
    #define N 32
    #define NL 1000

    int C[N];
    int i, imaxloc1, imaxloct1, it1, ni;
    char tname[] = "RED1111";

    #pragma dvm array distribute[block]
    int A[N];

    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;

    ni = N / 2 + 1;
    A[ni] = N + 1 + NL;
    imaxloc1 = N + 1 + NL;

    #pragma dvm remote_access(A[0])
    {
    imaxloct1 = A[0];
    }

    #pragma dvm actual(imaxloct1)

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(maxloc(imaxloct1, it1))
    for (i = 0; i < N; i++)
        if (A[i] > imaxloct1) {
            imaxloct1 = A[i];
            it1 = i;
        }
    } /* end region */

    #pragma dvm get_actual(imaxloct1,it1)

    if ((imaxloct1 == imaxloc1) && (it1 == ni))
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imax1=%d imaxt1=%d imaxloct1=%d it1=%d ni=%d\n",
//             imax1,imaxt1,imaxloct1,it1,ni);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1112  */
void red1112()
{
    #define N 27
    int NL = 1012;
    int C[N];
    int i, ni, iminloc1, iminloct1,it2;
    char tname[] = "RED1112";

    #pragma dvm array distribute[block]
    int A[N];

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;
    } /* end region */

    #pragma dvm get_actual(A)

    ni = N / 2 + 2;
    A[ni] = - (N + 1 + NL);
    #pragma dvm actual(A[ni])
    iminloc1 = -(N + 1 + NL);

    #pragma dvm remote_access(A[3])
    {
    iminloct1=A[3];
    }

    #pragma dvm actual(iminloct1)

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(minloc(iminloct1, it2))
    for (i = 0; i < N; i++)
        if (A[i] < iminloct1) {
           iminloct1 = A[i];
           it2 = i;
        }
    } /* end region */

    #pragma dvm get_actual(iminloct1, it2)

    if ((iminloct1 == iminloc1) && (it2 == ni))
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imin1=%d imint1=%d iminloct1=%d it2=%d ni=%d\n",
//              imin1,imint1,iminloct1,it2,ni);
    }

    #undef N
}

/* ---------------------------------------------RED1113 */
void red1113()
{
    #define N 24
    #define NL 1003

    int C[N];
    int i, isum1, isumt1, imax1, imaxt1, imin1, imint1, ni;
    char tname[] = "RED1113";

    #pragma dvm array distribute[block]
    int A[N];

    isum1 = sersum1m(C, N, NL);

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL+i;
    } /* end region */

    ni = N / 2 - 2;
    A[ni] = N + 1 + NL;
    #pragma dvm actual(A[ni])

    imax1 = N + 1 + NL;

    #pragma dvm remote_access(A[1])
    {
    imaxt1 = A[1];
    }

    ni = N / 2;
    A[ni] = -(N + 1 + NL);
    #pragma dvm actual(A[ni])

    imin1 = -(N + 1 + NL);
    imint1 = imaxt1;

    isumt1 = 0;

    #pragma dvm actual(isumt1, imaxt1, imint1)

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(sum(isumt1), max(imaxt1), min(imint1))
    for (i = 0; i < N; i++)
    {
        isumt1 = isumt1 + A[i];
        if (A[i] > imaxt1) imaxt1 = A[i];
        if (A[i] < imint1) imint1 = A[i];
    }
    } /* end region */

    #pragma dvm get_actual(isumt1, imaxt1, imint1)

    if ((isum1 == isumt1) && (imax1 == imaxt1) && (imin1 == imint1))
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("isum1=%d isumt1=%d\n",isum1,isumt1);
//      printf("imax1=%d imaxt1=%d\n",imax1,imaxt1);
//      printf("imin1=%d imint1=%d\n",imin1,imint1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1114  */
void red1114()
{
    #define N 13
    #define NL 2

    int C[N],CL[N];
    char tname[] = "RED1114";
    int i;
    int iprod1, iprodt1;
    int land1, landt1;

    #pragma dvm array distribute[block]
    int A[N];
    #pragma dvm array align([i] with A[i])
    int B[N];

    iprod1 = serprod1(C, N, NL);
    land1 = serand1(CL, N);

    #pragma dvm region inout(A)
    {

    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL + i;
    #pragma dvm parallel([i] on B[i])
    for (i = 0; i < N; i++)
        B[i] = i%2;
    } /* end region */

//    #pragma dvm get_actual (B[1])

    #pragma dvm remote_access(B[1])
    {
    landt1 = B[1];
    }

    iprodt1 = 1;

    #pragma dvm actual (landt1, iprodt1)

    #pragma dvm region
    {
    #pragma dvm parallel([i] on A[i]) reduction(product(iprodt1), and(landt1))
    for (i = 0; i < N; i++)
    {
       iprodt1 = iprodt1 * A[i];
       landt1 = landt1 && B[i];
    }

    } /* end region */

    #pragma dvm get_actual(iprodt1, landt1)

    if ((iprod1 == iprodt1) && (land1 == landt1))
       ansyes(tname);
    else
    {
       ansno(tname);
//     printf ("iprod1 = %f, iprodt1 = %f\n", iprod1, iprodt1);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1115  */
void red1115()
{
    #define N 22
    #define NL 1015

    int C[N];
    int i, imax1, imaxt1, imin1, ni1, ni2;
    int imaxloct1, iminloct1, it1, it2;
    char tname[] = "RED1115";

    #pragma dvm array distribute[block]
    int A[N];

    #pragma dvm region inout(A)
    {

    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = NL+i;

    } /* end region */

    ni1 = N / 2 - 3;
    A[ni1] = N + 1 + NL;
    imax1 = N + 1 + NL;

    ni2 = N / 2 + 2;
    A[ni2] = -(N + 1 + NL);
    imin1 = -(N + 1 + NL);

    #pragma dvm remote_access(A[1])
    {
    imaxt1=A[1];
    }

    imaxloct1 = imaxt1;
    iminloct1 = imaxloct1;

    #pragma dvm actual(A[ni1], A[ni2], imaxt1, imaxloct1, iminloct1)

    #pragma dvm region inout(A)
    {
    #pragma dvm parallel([i] on A[i]) reduction(max(imaxt1),maxloc(imaxloct1,it1), minloc(iminloct1,it2))
    for (i = 0; i < N; i++)
    {
        if (A[i] > imaxt1) imaxt1 = A[i];
        if (A[i] > imaxloct1)
        {
            imaxloct1 = A[i];
            it1 = i;
        }
        if (A[i] < iminloct1)
        {
            iminloct1 = A[i];
            it2 = i;
        }
    }

    } /* end region */

    #pragma dvm get_actual(imaxt1, imaxloct1, it1, iminloct1, it2)

    if ((imaxloct1 == imax1) && (iminloct1 == imin1) &&
       (imaxt1 == imaxloct1) && (it1 == ni1) && (it2 == ni2))
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("imax1=%d imaxt1=%d imaxloct1=%d it1=%d ni1=%d\n",
//              imax1,imaxt1,imaxloct1,it1,ni1);
//      printf("imin1=%d  iminloct1=%d it2=%d ni2=%d\n",
//              imin1,iminloct1,it2,ni2);
    }

    #undef N
    #undef NL
}

/* ---------------------------------------------RED1116  */
void red1116()
{
    #define N 28
    #define RNL 1016.

    float C[N];
    int i, ni1, ni2, it1, it2;
    float isum1, isumt1, imax1, imin1;
    float imaxloct1, iminloct1;
    char tname[] = "RED1116";

    #pragma dvm array distribute[block]
    float A[N];

    isum1 = sers1mr(C, N, RNL);

/*  printf("c=%d isum1=%d\n",C[1],isum1); */

    imax1 = N + 1. + RNL;
    imin1 = -(N + 1 + RNL);

    #pragma dvm region inout(A, ni1, ni2)
    {
    #pragma dvm parallel([i] on A[i])
    for (i = 0; i < N; i++)
        A[i] = RNL + i;

    ni1 = N / 2 - 1;
    A[ni1] = N + 1. + RNL;

    ni2 = N / 2 + 1;
    A[ni2] = -(N + 1 + RNL);

    #pragma dvm host_section
    {
    #pragma dvm remote_access(A[1])
    {
    imaxloct1 = A[1];
    }
    #pragma dvm actual(imaxloct1)
    }

    iminloct1 = imaxloct1;

    isumt1 = 0.;

    #pragma dvm parallel([i] on A[i]) reduction(sum(isumt1), maxloc(imaxloct1, it1), minloc(iminloct1, it2))
    for (i = 0; i < N; i++)
    {
        isumt1 = isumt1 + A[i];
        if (A[i] > imaxloct1)
        {
            imaxloct1 = A[i];
            it1 = i;
        }
        if (A[i] < iminloct1)
        {
            iminloct1 = A[i];
            it2 = i;
        }
    }

    } /* end region */

    #pragma dvm get_actual(isumt1, imaxloct1, iminloct1)

    if ((isum1 == isumt1) && (imaxloct1 == imax1) && (iminloct1 == imin1) &&
       (it1 == ni1) && (it2 == ni2))
        ansyes(tname);
    else
    {
        ansno(tname);
//      printf("isum1=%f isumt1=%f\n",isum1,isumt1);
//      printf("imax1=%f imaxloct1=%f it1=%d ni1=%d\n",
//          imax1,imaxloct1,it1,ni1);
//      printf("imin1=%f iminloct1=%f it2=%d ni2=%d\n",
//          imin1,iminloct1,it2,ni2);
    }

    #undef N
    #undef RNL
}

/* --------------------------------------------- */

int sersum1(int *AR, int NN, int NL)
{
    int i, s;

    for (i = 0; i < NN; i++)
        AR[i] = NL+i;

    s=0;

    for (i = 0; i < NN; i++)
        s = s + AR[i];

//  printf("s=%d\n",s);

    return s;
}

int sersum1m(int *AR, int NN, int NL)
{
    int i, ni, s;

    for (i = 0; i < NN; i++)
        AR[i] = NL + i;
    ni = NN / 2 - 2;
    AR[ni] = NN + 1 + NL;
    ni= NN / 2;
    AR[ni] = -(NN + 1 + NL);

    s = 0;
    for (i = 0; i < NN; i++)
        s = s + AR[i];

//  printf("s=%d\n",s);

    return s;
}

float sers1mr(float *RAR, int NN, float RNL)
{
    int i, ni;
    float s;

    for (i = 0; i < NN; i++)
        RAR[i] = RNL + i;
    ni = NN / 2 - 1;
    RAR[ni]=NN + 1.+ RNL;
    ni = NN / 2 + 1;
    RAR[ni] = -(NN + 1.+ RNL);

    s = 0;
    for (i = 0; i < NN; i++)
        s = s + RAR[i];
//  printf("s=%d\n",s);

    return s;
}

int serprod1(int *AR, int NN, int NL)
{
    int i, p;

    for (i = 0; i < NN; i++)
        AR[i] = NL + i;

    p = 1;
    for (i = 0; i < NN; i++)
       p = p * AR[i];

    return p;
}

float serprodr1(float *AR, int NN, float RNL)
{
    int i;
    float p;

    for (i = 0; i < NN; i++)
        AR[i] = RNL + i;

    p = 1.;
    for (i = 0; i < NN; i++)
        p = p * AR[i];

    return p;
}

int serand1(int *AR, int NN)
{
    int i, ni, LAND;

    for (i = 0; i < NN; i++)
        AR[i] = i % 2;

    LAND = AR[1];

    for (i = 0; i < NN; i++)
        LAND = LAND && AR[i];

    return LAND;
}

int seror1(int *AR, int NN)
{
    int i, LOR;

    for (i = 0; i < NN; i++)
        AR[i] = i % 2;

    LOR = AR[1];

    for (i = 0; i < NN; i++)
        LOR = LOR || AR[i];

    return LOR;
}

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

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