/*----------------------------------------------------------------- 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); }
/*----------------------------------------------------------------- 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); }