\documentclass[twocolumn]{article}
% \documentclass{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}
\usepackage{amsmath}

\begin{document}

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

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

Directions: MAKE SURE TO COPY YOUR ANSWERS TO A SEPARATE SHEET FOR SENDING
ME AN ELECTRONIC COPY LATER.

{\bf 1.} (20) Fill in the blank (your answer should have the word {\it
and} in it): According to class discussion, in developing a parallel
program, the hardest sections to write are 
\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_.

{\bf 2.} (20) Suppose we have a symmetric matrix $A$, written in
partitioned form 

\begin{equation}
\left (
\begin{array}{rr}
A_1 & A_2 \\
A_2'& A_3
\end{array}
\right )
\end{equation}

where ' indicates transpose, and $m$, the number of rows of $A_1$ is half
the number of rows of $A$.  We have a column vector 

\begin{equation}
u = \left (
\begin{array}{r}
u_1  \\
u_2
\end{array}
\right )
\end{equation}

with the number of elements in $u_1$ being $m$.  We wish to compute the
{\it quadratic form}

\begin{equation}
q = u'Au
\end{equation}

by exploiting the partitioning (probably in parallel, but not relevant
here).  Show the algebraically simplified form of $q$.  Note: In your
electronic file, write $A_1$ as A1, and so on.

{\bf 3.} (50) Here we will store many long arrays in one big array.  We will
store array $i$ in row $i$ of the big array.  Anticipating having a
great many large arrays, we will use OpenMP to build our big
array.  For convenience here, assume the number of arrays will be a
multiple of the number of threads.  Our function is

\begin{lstlisting}
#include <omp.h>

void fillimage(float **arrs, int r, int narr, 
      float *a) {
   blank (a)
   {  
      int arr; float *arrstart;
      int me = omp_get_thread_num();
      int nth = omp_get_num_threads();
      int block = narr / nth;  
      for (arr = blank (b) ) {
         arrstart = blank (c)
         memcpy( blank (d));
      }
   }
}
\end{lstlisting}

Here {\bf arrs} is the input arrays, each of length {\bf r}, with there
being {\bf narr} arrays in all.  The big array to be filled is {\bf a}.

Here is a test example:

\begin{lstlisting}
int main() {
   float x[4] = {1,2,3,4}, y[4] = {5,6,7,8};
   float *xy[2] = {x,y};
   float z[8];
   int i;
   fillimage(xy,4,2,z);
   // results should be 1,2,...,8
   for (i = 0; i < 8; i++) 
      printf("%f  ",z[i]);
   printf("\n");
}
\end{lstlisting}

Fill in the blanks.  

{\bf 4.} (10) In our NMF tutorial, the approximating matrix can actually
turn out to be of rank larger than the targeted value $k$.  Explain why.
Remember, you are limited to a single line, though it can be rather
long.

\onecolumn

\newpage

{\bf Solutions:}

{\bf 1.}  The start and finish.

{\bf 2.}

\begin{eqnarray}
u'Au&=& \\ 
&=& (u_1', u_2')
\left (
\begin{array}{rr}
A_1 & A_2 \\
A_2'& A_3
\end{array}
\right ) 
\left (
\begin{array}{r}
u_1  \\
u_2
\end{array}
\right ) \\
&=& 
(u_1'A_1+u_2'A_2', ~ u_1'A_2+u_2' A_3)
\left (
\begin{array}{r}
u_1  \\
u_2
\end{array}
\right ) \\
&=& 
(u_1' A_1 u_1 + u_2'A_2' u_1) +
(u_1' A_2 u_2 + u_2'A_3 u_2) \\
&=& u_1' A_1 u_1 + 2 u_1' A_2 u_2 + u_2' A_3 u_2
\end{eqnarray}

Note the fact from linear algebra (and our book's review) that
$(VW)' = W' V'$.

{\bf 3.

\begin{lstlisting}
#include <omp.h>

void fillimage(float **arrs, int r, int narr,
      float *a) {
   #pragma omp parallel
   { 
      int arr; float *arrstart;
      int me = omp_get_thread_num();
      int nth = omp_get_num_threads();
      int block = narr / nth;
      for (arr = me*block; arr < (me+1)*block;
            arr++) {
         arrstart = arrs[arr];
         memcpy(a+r*arr,arrstart,
            r*sizeof(float));
      }
   }
}
\end{lstlisting}}

{\bf 4. Since pixel brightness is in [0,1], we truncate values greater
than 1.  This perturbs some of the data.  So, even though we have set
things up so that no linear combination of more than $k$ colums of the
matrix can be nonzero, that property will be ruined.  It doesn't change
the effectiveness of the operation, though.  

Note by the way that rank(AB) $\leq$ min(rank(a),rank(B), and that W and
H have ranks at most k at any iteration, due to number of columns/rows.

\end{document}

