// matrix transpose, for_each version

#include <stdio.h>
#include <thrust/device_vector.h>

#include "z2.cpp"
// extern struct : thrust::unary_function<int,void> copyelt2xp; 
// extern struct copyelt2xp(thrust::device_vector<int>,
//       thrust::device_vector<int>,int,int); 

// transpose nr x nc inmat to outmat
void transp(int *inmat, int *outmat, int nr, int nc)
{
   thrust::device_vector<int> dmat(inmat,inmat+nr*nc);
   // make space for the transpose
   thrust::device_vector<int> dxp(nr*nc);
   thrust::counting_iterator<int> seqb(0);
   thrust::counting_iterator<int> seqe = seqb + nr*nc;
   // for each i in seq, copy the matrix elt to its spot in the
   // transpose
   copyelt2xp cfnctr(dmat.begin(),dxp.begin(),nr,nc);
   thrust::for_each(seqb,seqe,cfnctr);
   thrust::copy(dxp.begin(),dxp.end(),outmat);
}

int rand16()  // generate random integers mod 16
{  return rand() % 16;  }

// test code:  cmd line args are matrix size, then row, col of elt to be
// checked

int main(int argc, char **argv)
{  int nr = atoi(argv[1]); int nc = nr;
   int *mat = (int *) malloc(nr*nc*sizeof(int));
   int *matxp = (int *) malloc(nr*nc*sizeof(int));
   thrust::generate(mat,mat+nr*nc,rand16);
   int checkrow = atoi(argv[2]);
   int checkcol = atoi(argv[3]);
   printf("%d\n",mat[checkrow*nc+checkcol]);
   transp(mat,matxp,nr,nc);
   printf("%d\n",matxp[checkcol*nc+checkrow]);
}
