\documentclass[twocolumn]{article}

\setlength{\oddsidemargin}{-0.5in}
\setlength{\evensidemargin}{-0.5in}
\setlength{\topmargin}{0.0in}
\setlength{\headheight}{0in}
\setlength{\headsep}{0in}
\setlength{\textwidth}{7.0in}
\setlength{\textheight}{9.5in}
\setlength{\parindent}{0in}
\setlength{\parskip}{0.05in}
\setlength{\columnseprule}{0.3pt}

\setlength\columnsep{25pt}

\usepackage{fancyvrb}
\usepackage{relsize}
\usepackage{hyperref}

\usepackage{listings}

\begin{document}

\lstset{xleftmargin=5mm,framexleftmargin=10mm,basicstyle=\footnotesize}

Name: \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_

Directions: {\bf \Large Do NOT turn in this sheet of paper (unless you
lack a laptop or have a laptop failure during the Exam).  You will
submit electronic files to {\bf handin}.} 

{\bf 1.} (70) A method for compressing data is to store only repeat counts
in {\it runs}, where the latter means a set of consecutive, identical
values.  For instance, the sequence 2,2,2,0,0,5,0,0 would be compressed
to 3,2,2,0,1,5,2,0, meaning that the data consist of first three 2s,
then two 0s, then one 5, and finally two 0s.  Note that the compressed
version consists of alternating {\it run counts} and {\it run values},
respectively 2 and 0 at the end of the above example.

Here you will write a function to uncompress an array that uses this type of
storage, in both OpenMP and Snow, submitting files named {\bf
uncomprle.c} and {\bf uncomprle.R}, respectively.  

In both cases, you are \underline{required} to first call a parallel
sum scan, using the functions in {\bf prfx.c} from the (top level of)
our class Web site or in {\bf ParSum.R} in the {\bf Extras} directory in
our Web site.  You will use the output of that operation to decide where
to place the runs in your overall output.  You will then do further
parallel processing.

You may assume that the number of threads divides the number of run
counts, i.e. half of 4 in the above example.

The signature for a C version must be

\begin{lstlisting}
void uncomprle(int *x,int nx,int *tmp,
   int *y,int *ny)
\end{lstlisting}

where {\bf x} is the input array, of length {\bf nx}, {\bf y} is the
output array, and {\bf tmp} is an array for temporary storage to be
explained shortly.  It is assumed for convenience that space has been
preallocated for {\bf y} and {\bf tmp} before the call.  The function
fills in {\bf y} and also sets {\bf *ny}.

The test code I will use for OpenMP is 

\begin{lstlisting}
// test code
int main()
{  int i;
   int x[12] = {2,3,1,9,3,5,2,6,2,88,1,12};
   int nx = 12;
   int tmp[100],y[100];
   int ny;
   uncomprle(x,nx,tmp,y,&ny);
   // y should be {3,3,9,5,5,5,6,6,88,88,12};
   for (i = 0; i < ny; i++) printf("%d\n",y[i]);
}
\end{lstlisting}

In the case of R, your function will have two parameters:  {\bf cls},
the cluster name, and  {\bf x}, the input vector.  The function 
will return {\bf y}.  My test call will be

\begin{lstlisting}
uncomprle(c(2,3,1,9,3,5,2,6,2,88,1,12))
\end{lstlisting}

{\bf 2.} (30) Give code to do the parallel scan operation in Problem 1
using Thrust.  (Use only Thrust functions from our course materials.)
You will fill the blanks:

\begin{lstlisting}
// possibly put material here

int main()
{  int i;
   int x[12] = {2,3,1,9,3,5,2,6,2,88,1,12};
   int nx = 12;
   int tmp[100];
   // compute and print out tmp here
   // (should be 2,3,6,...)
}
\end{lstlisting}

Turn in a file {\bf findtmp.cu} (for compiling with gcc for OpenMP, use
{\bf .c} suffix).  {\bf IT SHOULD BE THE ENTIRE CODE, INCLUDING main()
ABOVE, COMPILABLE AND RUNNABLE.} 

\onecolumn

{\bf Solutions:}

{\bf 1.}  OpenMP code:

\begin{lstlisting}[numbers=left]
void uncomprle(int *x,int nx,int *tmp,int *y,int *ny)
{
   int i,nx2 = nx/2;
   int z[MAXTHREADS];
   for (i = 0; i < nx2; i++) tmp[i+1] = x[2*i]; 
   parprfsum(tmp+1,nx2+1,z);
   tmp[0] = 0;
   #pragma omp parallel
   {  int j,k;
      int me=omp_get_thread_num();  
      #pragma omp for
      for (j = 0; j < nx2; j++) {
         // where to start the j-th run?
         int start = tmp[j];
         // what value is in the run?
         int val = x[2*j+1];
         // how long is the run?
         int nrun = x[2*j];
         for (k = 0; k < nrun; k++) 
            y[start+k] = val;
      }
   }
   *ny = tmp[nx2];
}
\end{lstlisting}

{\bf 2.}

\begin{lstlisting}[numbers=left]
#include <stdio.h>
#include <thrust/host_vector.h>
#include <thrust/scan.h>
#include <thrust/sequence.h>
#include <thrust/remove.h>  

struct iseven {
   bool operator()(const int i)
   {  return (i % 2) == 0;
   }
};

int main()
{  int i;
   int x[12] = {2,3,1,9,3,5,2,6,2,88,1,12};
   int nx = 12;
   int tmp[100];
   int seq[nx];
   thrust::host_vector<int> out(nx);
   thrust::sequence(seq,seq+nx,0);
   thrust::host_vector<int> hx(x,x+nx);
   thrust::host_vector<int>::iterator newend =
      thrust::copy_if(hx.begin(),hx.end(),seq,out.begin(),iseven());
   thrust::inclusive_scan(out.begin(),out.end(),out.begin());
   // compute and print out tmp here
   // (should be 2,3,6,...)
   for (int i = 0; i < newend-out.begin(); i++) printf("%d\n",out[i]);
}
\end{lstlisting}

\end{document}

