/* nag_sparse_sym_rcm (f11yec) Example Program.
 *
 * Copyright 2014 Numerical Algorithms Group.
 *
 * Mark 25, 2014.
 */
#include <stdio.h>
#include <nag.h>
#include <nag_stdlib.h>
#include <nagf11.h>

void plot(const Integer n, const Integer nnz, Integer *perm, 
	  Integer *icolzp, Integer *irowix);
void uncompress(Integer n, Integer *icolzp, Integer *icol);

int main(void)
{
  /* Scalars */
  Integer n, nnz, exit_status = 0, doplot = 0, i;
  /* Arrays */
  Integer *icolzp=0, *irowix=0, *mask=0, *perm=0;
  Integer info[4];
  Nag_Boolean lopts[5];
  /* Nag Types */
  NagError fail;
  
  INIT_FAIL(fail);
  printf("nag_sparse_sym_rcm (f11yec) Example Program Results\n");
  /* Skip heading in data file and 
   * read Size of the matrix and Number of non-zero elements 
   */
  scanf("%*[^\n] ");
  scanf("%ld%*[^\n] ", &n);
  scanf("%ld%*[^\n] ", &nnz);
  if ( !(icolzp = NAG_ALLOC((n+1), Integer)) ||
       !(irowix = NAG_ALLOC((nnz), Integer)) ||
       !(mask = NAG_ALLOC((n), Integer)) ||
       !(perm = NAG_ALLOC((n), Integer))) {
    printf("Allocation failure\n");
    exit_status = -1;
    goto END;
  }
  /* Read in data */
  for (i = 0; i < nnz; i+=1) scanf("%ld", &irowix[i]);  
  scanf("%*[^\n] ");
  for (i = 0; i < (n + 1); i+=1) scanf("%ld", &icolzp[i]);  
  scanf("%*[^\n] ");
  /* Set options */
  lopts[0 /* Use Mask                 */] = Nag_FALSE;
  lopts[1 /* Don't reverse            */] = Nag_FALSE;
  lopts[2 /* Check symmetry           */] = Nag_TRUE;
  lopts[3 /* Compute bandwidth before */] = Nag_TRUE;
  lopts[4 /* Compute bandwidth after  */] = Nag_TRUE;
  /* nag_sparse_sym_rcm (f11yec).
   * Reverse Cuthill-McKee reordering of a real sparse symmetric 
   * matrix in CCS format
   */
  nag_sparse_sym_rcm(n, nnz, icolzp, irowix, lopts, mask, perm, info, &fail);
  if (fail.code != NE_NOERROR) {
    printf("Error from nag_sparse_sym_rcm (f11yec).\n%s\n", 
	   fail.message);
    exit_status = 1;
    goto END;
  }
  /* Print results */
  printf("Permutation (perm):\n");
  for (i = 0; i < n; i+=1) {
    printf("    %3ld", perm[i]);
    if (i%6==5) printf("\n");
  }
  printf("\n\nStatistics:\n");
  printf(" %s%6ld\n"," Before:  Bandwidth = ", info[0]);
  printf(" %s%6ld\n"," Before:  Profile   = ", info[1]);
  printf(" %s%6ld\n"," After :  Bandwidth = ", info[2]);
  printf(" %s%6ld\n"," After :  Profile   = ", info[3]);
  /* Print matrix entries and permuted entries in form suitable 
   * for plotting 
   */
  if (doplot) plot(n, nnz, perm, icolzp, irowix);
 END:
  NAG_FREE(icolzp);
  NAG_FREE(irowix);
  NAG_FREE(mask);
  NAG_FREE(perm);
  
  return exit_status;
}

void uncompress(Integer n, Integer *icolzp, Integer *icol)
{
  Integer i, j, col_beg, col_end;
  for (i=0; i< n; i++) {
    col_end = icolzp[i+1] - 1;
    col_beg = icolzp[i];
    for (j = col_beg; j <= col_end; j++) icol[j-1] = i+1;
  }

}
void plot(Integer n, Integer nnz, Integer *perm, Integer *icolzp, 
	  Integer *irowix)
{
  /* Put data, suitable for plotting matrix structure, in data file */
  
  /* Scalars */
  Integer i, nnz2;
    /* Arrays */
  double  *a=0;
  Integer *icolix=0, *ipcolix=0, *iperm=0, *iprowix=0, *istr=0;
  /* Nag Types */
  NagError fail;
  
  INIT_FAIL(fail);
  if ( !(icolix = NAG_ALLOC(nnz, Integer)) ||
       !(ipcolix = NAG_ALLOC(nnz, Integer)) ||
       !(iprowix = NAG_ALLOC(nnz, Integer)) ||
       !(iperm = NAG_ALLOC(n, Integer)) ||
       !(a = NAG_ALLOC(nnz, double)) ||
       !(istr = NAG_ALLOC(n+1, Integer))) {
    printf("Allocation failure\n");
    return;
  }
  /* Decompress icolzp to full set of column indices (icolix) 
   * and compute inverse permutation 
   */
  uncompress(n, icolzp, icolix);
  for (i=0; i< n; i++) {
    iperm[perm[i]-1] = i+1;
  }
  /* Original matrix structure */
  for (i=0; i< nnz; i++) {
    a[i] = icolix[i]*.01 + 1.0 * irowix[i];
    printf("%8ld    ", irowix[i]);
    printf("%8ld    ", icolix[i]);
    printf("%8.2f\n", a[i]);
  }
  printf("\n");
  /* Apply Inverse Permutation */
  for (i=0; i< nnz; i++) {
    ipcolix[i] = iperm[icolix[i]-1];
    iprowix[i] = iperm[irowix[i]-1];
  }
  /* Reorder (in exit: istr contains new CCS icolzp) */
  nnz2 =  nnz;
  nag_sparse_nsym_sort(n, &nnz2, a, ipcolix, iprowix, Nag_SparseNsym_FailDups, 
	 Nag_SparseNsym_KeepZeros, istr, &fail);
  /* Permuted matrix structure */
  for (i=0; i<nnz2; i++) {
    printf("%8ld    ", iprowix[i]);
    printf("%8ld    ", ipcolix[i]);
    printf("%8.2f\n", a[i]);
  }
  NAG_FREE(icolix);
  NAG_FREE(ipcolix);
  NAG_FREE(iprowix);
  NAG_FREE(iperm);
  NAG_FREE(a);
  NAG_FREE(istr);
}