Example #1
0
/*-----------------------------------------------------------------
  cvLsSetup

  This conditionally calls the LS 'setup' routine.

  When using a SUNMatrix object, this determines whether
  to update a Jacobian matrix (or use a stored version), based
  on heuristics regarding previous convergence issues, the number
  of time steps since it was last updated, etc.; it then creates
  the system matrix from this, the 'gamma' factor and the
  identity matrix, A = I-gamma*J.

  This routine then calls the LS 'setup' routine with A.
  -----------------------------------------------------------------*/
int cvLsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
              N_Vector fpred, booleantype *jcurPtr,
              N_Vector vtemp1, N_Vector vtemp2, N_Vector vtemp3)
{
  CVLsMem  cvls_mem;
  realtype dgamma;
  int      retval;

  /* access CVLsMem structure */
  if (cv_mem->cv_lmem==NULL) {
    cvProcessError(cv_mem, CVLS_LMEM_NULL, "CVLS",
                   "cvLsSetup", MSG_LS_LMEM_NULL);
    return(CVLS_LMEM_NULL);
  }
  cvls_mem = (CVLsMem) cv_mem->cv_lmem;

  /* Set CVLs N_Vector pointers to current solution and rhs */
  cvls_mem->ycur = ypred;
  cvls_mem->fcur = fpred;

  /* Use nst, gamma/gammap, and convfail to set J/P eval. flag jok */
  dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE);
  cvls_mem->jbad = (cv_mem->cv_nst == 0) ||
    (cv_mem->cv_nst > cvls_mem->nstlj + cvls_mem->msbj) ||
    ((convfail == CV_FAIL_BAD_J) && (dgamma < CVLS_DGMAX)) ||
    (convfail == CV_FAIL_OTHER);

  /* If using a NULL SUNMatrix, set jcur to jbad; otherwise update J as appropriate */
  if (cvls_mem->A == NULL) {

    *jcurPtr = cvls_mem->jbad;

  } else {

    /* If jbad = SUNFALSE, use saved copy of J */
    if (!cvls_mem->jbad) {

      *jcurPtr = SUNFALSE;
      retval = SUNMatCopy(cvls_mem->savedJ, cvls_mem->A);
      if (retval) {
        cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS",
                       "cvLsSetup",  MSG_LS_SUNMAT_FAILED);
        cvls_mem->last_flag = CVLS_SUNMAT_FAIL;
        return(cvls_mem->last_flag);
      }

    /* If jbad = SUNTRUE, call jac routine for new J value */
    } else {

      cvls_mem->nje++;
      cvls_mem->nstlj = cv_mem->cv_nst;
      *jcurPtr = SUNTRUE;
      retval = SUNMatZero(cvls_mem->A);
      if (retval) {
        cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS",
                       "cvLsSetup",  MSG_LS_SUNMAT_FAILED);
        cvls_mem->last_flag = CVLS_SUNMAT_FAIL;
        return(cvls_mem->last_flag);
      }

      retval = cvls_mem->jac(cv_mem->cv_tn, ypred, fpred, cvls_mem->A,
                             cvls_mem->J_data, vtemp1, vtemp2, vtemp3);
      if (retval < 0) {
        cvProcessError(cv_mem, CVLS_JACFUNC_UNRECVR, "CVLS",
                       "cvLsSetup",  MSG_LS_JACFUNC_FAILED);
        cvls_mem->last_flag = CVLS_JACFUNC_UNRECVR;
        return(-1);
      }
      if (retval > 0) {
        cvls_mem->last_flag = CVLS_JACFUNC_RECVR;
        return(1);
      }

      retval = SUNMatCopy(cvls_mem->A, cvls_mem->savedJ);
      if (retval) {
        cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS",
                       "cvLsSetup",  MSG_LS_SUNMAT_FAILED);
        cvls_mem->last_flag = CVLS_SUNMAT_FAIL;
        return(cvls_mem->last_flag);
      }

    }

    /* Scale and add I to get A = I - gamma*J */
    retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvls_mem->A);
    if (retval) {
      cvProcessError(cv_mem, CVLS_SUNMAT_FAIL, "CVLS",
                     "cvLsSetup",  MSG_LS_SUNMAT_FAILED);
      cvls_mem->last_flag = CVLS_SUNMAT_FAIL;
      return(cvls_mem->last_flag);
    }

  }

  /* Call LS setup routine -- the LS may call cvLsPSetup, who will
     pass the heuristic suggestions above to the user code(s) */
  cvls_mem->last_flag = SUNLinSolSetup(cvls_mem->LS, cvls_mem->A);

  /* If the SUNMatrix was NULL, update heuristics flags */
  if (cvls_mem->A == NULL) {

    /* If user set jcur to SUNTRUE, increment npe and save nst value */
    if (*jcurPtr) {
      cvls_mem->npe++;
      cvls_mem->nstlj = cv_mem->cv_nst;
    }

    /* Update jcur flag if we suggested an update */
    if (cvls_mem->jbad) *jcurPtr = SUNTRUE;
  }

  return(cvls_mem->last_flag);
}
Example #2
0
/*-----------------------------------------------------------------
  cvDlsSetup
  -----------------------------------------------------------------
  This routine determines whether to update a Jacobian matrix (or
  use a stored version), based on heuristics regarding previous 
  convergence issues, the number of time steps since it was last
  updated, etc.; it then creates the system matrix from this, the
  'gamma' factor and the identity matrix, 
    A = I-gamma*J.
  This routine then calls the LS 'setup' routine with A.
  -----------------------------------------------------------------*/
int cvDlsSetup(CVodeMem cv_mem, int convfail, N_Vector ypred,
               N_Vector fpred, booleantype *jcurPtr, N_Vector vtemp1,
               N_Vector vtemp2, N_Vector vtemp3)
{
  booleantype jbad, jok;
  realtype dgamma;
  CVDlsMem cvdls_mem;
  int retval;

  /* Return immediately if cv_mem or cv_mem->cv_lmem are NULL */
  if (cv_mem == NULL) {
    cvProcessError(NULL, CVDLS_MEM_NULL, "CVDLS", 
                    "cvDlsSetup", MSGD_CVMEM_NULL);
    return(CVDLS_MEM_NULL);
  }
  if (cv_mem->cv_lmem == NULL) {
    cvProcessError(cv_mem, CVDLS_LMEM_NULL, "CVDLS", 
                    "cvDlsSetup", MSGD_LMEM_NULL);
    return(CVDLS_LMEM_NULL);
  }
  cvdls_mem = (CVDlsMem) cv_mem->cv_lmem;

  /* Use nst, gamma/gammap, and convfail to set J eval. flag jok */
  dgamma = SUNRabs((cv_mem->cv_gamma/cv_mem->cv_gammap) - ONE);
  jbad = (cv_mem->cv_nst == 0) || 
    (cv_mem->cv_nst > cvdls_mem->nstlj + CVD_MSBJ) ||
    ((convfail == CV_FAIL_BAD_J) && (dgamma < CVD_DGMAX)) ||
    (convfail == CV_FAIL_OTHER);
  jok = !jbad;
 
  /* If jok = SUNTRUE, use saved copy of J */
  if (jok) {
    *jcurPtr = SUNFALSE;
    retval = SUNMatCopy(cvdls_mem->savedJ, cvdls_mem->A);
    if (retval) {
      cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", 
                      "cvDlsSetup",  MSGD_MATCOPY_FAILED);
      cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL;
      return(-1);
    }

  /* If jok = SUNFALSE, call jac routine for new J value */
  } else {
    cvdls_mem->nje++;
    cvdls_mem->nstlj = cv_mem->cv_nst;
    *jcurPtr = SUNTRUE;
    retval = SUNMatZero(cvdls_mem->A);
    if (retval) {
      cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", 
                      "cvDlsSetup",  MSGD_MATZERO_FAILED);
      cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL;
      return(-1);
    }

    retval = cvdls_mem->jac(cv_mem->cv_tn, ypred, 
                            fpred, cvdls_mem->A, 
                            cvdls_mem->J_data, vtemp1, vtemp2, vtemp3);
    if (retval < 0) {
      cvProcessError(cv_mem, CVDLS_JACFUNC_UNRECVR, "CVDLS", 
                      "cvDlsSetup",  MSGD_JACFUNC_FAILED);
      cvdls_mem->last_flag = CVDLS_JACFUNC_UNRECVR;
      return(-1);
    }
    if (retval > 0) {
      cvdls_mem->last_flag = CVDLS_JACFUNC_RECVR;
      return(1);
    }

    retval = SUNMatCopy(cvdls_mem->A, cvdls_mem->savedJ);
    if (retval) {
      cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", 
                      "cvDlsSetup",  MSGD_MATCOPY_FAILED);
      cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL;
      return(-1);
    }

  }
  
  /* Scale and add I to get A = I - gamma*J */
  retval = SUNMatScaleAddI(-cv_mem->cv_gamma, cvdls_mem->A);
  if (retval) {
    cvProcessError(cv_mem, CVDLS_SUNMAT_FAIL, "CVDLS", 
                   "cvDlsSetup",  MSGD_MATSCALEADDI_FAILED);
    cvdls_mem->last_flag = CVDLS_SUNMAT_FAIL;
    return(-1);
  }

  /* Call generic linear solver 'setup' with this system matrix, and
     return success/failure flag */
  cvdls_mem->last_flag = SUNLinSolSetup(cvdls_mem->LS, cvdls_mem->A);
  return(cvdls_mem->last_flag);
}
/* ----------------------------------------------------------------------
 * Extra ScaleAdd tests for sparse matrices:
 *    A and B should have different sparsity patterns, and neither should
 *      contain sufficient storage to for their sum
 *    y should already equal A*x
 *    z should already equal B*x
 * --------------------------------------------------------------------*/
int Test_SUNMatScaleAdd2(SUNMatrix A, SUNMatrix B, N_Vector x,
                         N_Vector y, N_Vector z)
{
  int       failure;
  SUNMatrix C, D, E;
  N_Vector  u, v;
  realtype  tol=100*UNIT_ROUNDOFF;

  /* create clones for test */
  C = SUNMatClone(A);
  u = N_VClone(y);
  v = N_VClone(y);

  /* test 1: add A to B (output must be enlarged) */
  failure = SUNMatCopy(A, C);            /* C = A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(C);  N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatScaleAdd(ONE, C, B);   /* C = A+B */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n",
           failure);
    SUNMatDestroy(C);  N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatMatvec(C, x, u);       /* u = Cx = Ax+Bx */
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(C);  N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  N_VLinearSum(ONE,y,ONE,z,v);           /* v = y+z */
  failure = check_vector(u, v, tol);     /* u ?= v */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd2 check 1 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nB =\n");
    SUNSparseMatrix_Print(B,stdout);
    printf("\nC =\n");
    SUNSparseMatrix_Print(C,stdout);
    printf("\nx =\n");
    N_VPrint_Serial(x);
    printf("\ny =\n");
    N_VPrint_Serial(y);
    printf("\nz =\n");
    N_VPrint_Serial(z);
    printf("\nu =\n");
    N_VPrint_Serial(u);
    printf("\nv =\n");
    N_VPrint_Serial(v);
    SUNMatDestroy(C);  N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAdd2 check 1 \n");
  }

  /* test 2: add A to a matrix with sufficient but misplaced storage */
  D = SUNMatClone(A);
  failure = SUNSparseMatrix_Reallocate(D, SM_NNZ_S(A)+SM_NNZ_S(B));
  failure = SUNMatCopy(A, D);            /* D = A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatScaleAdd(ONE, D, B);   /* D = A+B */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatMatvec(D, x, u);       /* u = Cx = Ax+Bx */
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  N_VLinearSum(ONE,y,ONE,z,v);           /* v = y+z */
  failure = check_vector(u, v, tol);     /* u ?= v */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd2 check 2 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nB =\n");
    SUNSparseMatrix_Print(B,stdout);
    printf("\nD =\n");
    SUNSparseMatrix_Print(D,stdout);
    printf("\nx =\n");
    N_VPrint_Serial(x);
    printf("\ny =\n");
    N_VPrint_Serial(y);
    printf("\nz =\n");
    N_VPrint_Serial(z);
    printf("\nu =\n");
    N_VPrint_Serial(u);
    printf("\nv =\n");
    N_VPrint_Serial(v);
    SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAdd2 check 2 \n");
  }


  /* test 3: add A to a matrix with the appropriate structure already in place */
  E = SUNMatClone(C);
  failure = SUNMatCopy(C, E);                /* E = A + B */
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);  SUNMatDestroy(E);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatScaleAdd(NEG_ONE, E, B);   /* E = -A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);  SUNMatDestroy(E);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  failure = SUNMatMatvec(E, x, u);           /* u = Ex = -Ax */
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(C);  SUNMatDestroy(D);  SUNMatDestroy(E);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  N_VLinearSum(NEG_ONE,y,ZERO,z,v);          /* v = -y */
  failure = check_vector(u, v, tol);         /* v ?= u */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAdd2 check 3 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nB =\n");
    SUNSparseMatrix_Print(B,stdout);
    printf("\nC =\n");
    SUNSparseMatrix_Print(C,stdout);
    printf("\nE =\n");
    SUNSparseMatrix_Print(E,stdout);
    printf("\nx =\n");
    N_VPrint_Serial(x);
    printf("\ny =\n");
    N_VPrint_Serial(y);
    printf("\nu =\n");
    N_VPrint_Serial(u);
    printf("\nv =\n");
    N_VPrint_Serial(v);
    SUNMatDestroy(C);  SUNMatDestroy(D);  SUNMatDestroy(E);
    N_VDestroy(u);  N_VDestroy(v);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAdd2 check 3 \n");
  }

  SUNMatDestroy(C);
  SUNMatDestroy(D);
  SUNMatDestroy(E);
  N_VDestroy(u);
  N_VDestroy(v);
  return(0);
}
/* ----------------------------------------------------------------------
 * Extra ScaleAddI tests for sparse matrices:
 *    A should not contain values on the diagonal, nor should it contain
 *      sufficient storage to add those in
 *    y should already equal A*x
 * --------------------------------------------------------------------*/
int Test_SUNMatScaleAddI2(SUNMatrix A, N_Vector x, N_Vector y)
{
  int       failure;
  SUNMatrix B, C, D;
  N_Vector  w, z;
  realtype  tol=100*UNIT_ROUNDOFF;

  /* create clones for test */
  B = SUNMatClone(A);
  z = N_VClone(x);
  w = N_VClone(x);

  /* test 1: add I to a matrix with insufficient storage */
  failure = SUNMatCopy(A, B);
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(B);  N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatScaleAddI(NEG_ONE, B);   /* B = I-A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n",
           failure);
    SUNMatDestroy(B);  N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatMatvec(B, x, z);
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(B);  N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  N_VLinearSum(ONE,x,NEG_ONE,y,w);
  failure = check_vector(z, w, tol);
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI2 check 1 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nB =\n");
    SUNSparseMatrix_Print(B,stdout);
    printf("\nz =\n");
    N_VPrint_Serial(z);
    printf("\nw =\n");
    N_VPrint_Serial(w);
    SUNMatDestroy(B);  N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAddI2 check 1 \n");
  }

  /* test 2: add I to a matrix with sufficient but misplaced
     storage */
  C = SUNMatClone(A);
  failure = SUNSparseMatrix_Reallocate(C, SM_NNZ_S(A)+SM_ROWS_S(A));
  failure = SUNMatCopy(A, C);
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatScaleAddI(NEG_ONE, C);   /* C = I-A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatMatvec(C, x, z);
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  N_VLinearSum(ONE,x,NEG_ONE,y,w);
  failure = check_vector(z, w, tol);
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI2 check 2 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nC =\n");
    SUNSparseMatrix_Print(C,stdout);
    printf("\nz =\n");
    N_VPrint_Serial(z);
    printf("\nw =\n");
    N_VPrint_Serial(w);
    SUNMatDestroy(B);  SUNMatDestroy(C);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAddI2 check 2 \n");
  }


  /* test 3: add I to a matrix with appropriate structure already in place */
  D = SUNMatClone(C);
  failure = SUNMatCopy(C, D);
  if (failure) {
    printf(">>> FAILED test -- SUNMatCopy returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatScaleAddI(NEG_ONE, D);   /* D = A */
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = SUNMatMatvec(D, x, z);
  if (failure) {
    printf(">>> FAILED test -- SUNMatMatvec returned %d \n",
           failure);
    SUNMatDestroy(B);  SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  failure = check_vector(z, y, tol);
  if (failure) {
    printf(">>> FAILED test -- SUNMatScaleAddI2 check 3 \n");
    printf("\nA =\n");
    SUNSparseMatrix_Print(A,stdout);
    printf("\nD =\n");
    SUNSparseMatrix_Print(D,stdout);
    printf("\nz =\n");
    N_VPrint_Serial(z);
    printf("\ny =\n");
    N_VPrint_Serial(y);
    SUNMatDestroy(B);  SUNMatDestroy(C);  SUNMatDestroy(D);
    N_VDestroy(z);  N_VDestroy(w);  return(1);
  }
  else {
    printf("    PASSED test -- SUNMatScaleAddI2 check 3 \n");
  }

  SUNMatDestroy(B);
  SUNMatDestroy(C);
  SUNMatDestroy(D);
  N_VDestroy(z);
  N_VDestroy(w);
  return(0);
}
/* ----------------------------------------------------------------------
 * SUNLinSol_Dense Testing Routine
 * --------------------------------------------------------------------*/
int main(int argc, char *argv[]) 
{
  int             fails = 0;          /* counter for test failures  */
  sunindextype    cols, rows;         /* matrix columns, rows       */
  SUNLinearSolver LS;                 /* solver object              */
  SUNMatrix       A, B, I;            /* test matrices              */
  N_Vector        x, y, b;            /* test vectors               */
  int             print_timing;
  sunindextype    j, k;
  realtype        *colj, *xdata, *colIj;

  /* check input and set matrix dimensions */
  if (argc < 3){
    printf("ERROR: TWO (2) Inputs required: matrix cols, print timing \n");
    return(-1);
  }

  cols = atol(argv[1]); 
  if (cols <= 0) {
    printf("ERROR: number of matrix columns must be a positive integer \n");
    return(-1); 
  }

  rows = cols;

  print_timing = atoi(argv[2]);
  SetTiming(print_timing);

  printf("\nDense linear solver test: size %ld\n\n",
         (long int) cols);

  /* Create matrices and vectors */
  A = SUNDenseMatrix(rows, cols);
  B = SUNDenseMatrix(rows, cols);
  I = SUNDenseMatrix(rows, cols);
  x = N_VNew_Serial(cols);
  y = N_VNew_Serial(cols);
  b = N_VNew_Serial(cols);

  /* Fill A matrix with uniform random data in [0,1/cols] */
  for (j=0; j<cols; j++) {
    colj = SUNDenseMatrix_Column(A, j);
    for (k=0; k<rows; k++)
      colj[k] = (realtype) rand() / (realtype) RAND_MAX / cols;    
  }

  /* Create anti-identity matrix */
  j=cols-1;
  for (k=0; k<rows; k++) {
    colj = SUNDenseMatrix_Column(I,j);
    colj[k] = 1;
    j = j-1;
  }    
  
  /* Add anti-identity to ensure the solver needs to do row-swapping */
  for (k=0; k<rows; k++){
    for(j=0; j<cols; j++){
      colj = SUNDenseMatrix_Column(A,j);
      colIj = SUNDenseMatrix_Column(I,j);
      colj[k]  = colj[k] + colIj[k]; 
   }
  }

  /* Fill x vector with uniform random data in [0,1] */
  xdata = N_VGetArrayPointer(x);
  for (j=0; j<cols; j++) {
    xdata[j] = (realtype) rand() / (realtype) RAND_MAX;
  } 

  /* copy A and x into B and y to print in case of solver failure */
  SUNMatCopy(A, B);
  N_VScale(ONE, x, y);

  /* create right-hand side vector for linear solve */
  fails = SUNMatMatvec(A, x, b);
  if (fails) {
    printf("FAIL: SUNLinSol SUNMatMatvec failure\n");

    /* Free matrices and vectors */
    SUNMatDestroy(A);
    SUNMatDestroy(B);
    SUNMatDestroy(I);
    N_VDestroy(x);
    N_VDestroy(y);
    N_VDestroy(b);

    return(1);
  }

  /* Create dense linear solver */
  LS = SUNLinSol_Dense(x, A);
  
  /* Run Tests */
  fails += Test_SUNLinSolInitialize(LS, 0);
  fails += Test_SUNLinSolSetup(LS, A, 0);
  fails += Test_SUNLinSolSolve(LS, A, x, b, 10*UNIT_ROUNDOFF, 0);
 
  fails += Test_SUNLinSolGetType(LS, SUNLINEARSOLVER_DIRECT, 0);
  fails += Test_SUNLinSolLastFlag(LS, 0);
  fails += Test_SUNLinSolSpace(LS, 0);

  /* Print result */
  if (fails) {
    printf("FAIL: SUNLinSol module failed %i tests \n \n", fails);
    printf("\nA (original) =\n");
    SUNDenseMatrix_Print(B,stdout);
    printf("\nA (factored) =\n");
    SUNDenseMatrix_Print(A,stdout);
    printf("\nx (original) =\n");
    N_VPrint_Serial(y);
    printf("\nx (computed) =\n");
    N_VPrint_Serial(x);
  } else {
    printf("SUCCESS: SUNLinSol module passed all tests \n \n");
  }

  /* Free solver, matrix and vectors */
  SUNLinSolFree(LS);
  SUNMatDestroy(A);
  SUNMatDestroy(B);
  SUNMatDestroy(I);
  N_VDestroy(x);
  N_VDestroy(y);
  N_VDestroy(b);

  return(fails);
}