void amd_order1(int n, int A_ptr[], int A_ind[], int P_per[]) { /* approximate minimum degree ordering (AMD) */ int k, ret; double Control[AMD_CONTROL], Info[AMD_INFO]; /* get the default parameters */ amd_defaults(Control); #if 0 /* and print them */ amd_control(Control); #endif /* make all indices 0-based */ for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]--; for (k = 1; k <= n+1; k++) A_ptr[k]--; /* call the ordering routine */ ret = amd_order(n, &A_ptr[1], &A_ind[1], &P_per[1], Control, Info) ; #if 0 amd_info(Info); #endif xassert(ret == AMD_OK || ret == AMD_OK_BUT_JUMBLED); /* retsore 1-based indices */ for (k = 1; k <= n+1; k++) A_ptr[k]++; for (k = 1; k < A_ptr[n+1]; k++) A_ind[k]++; /* patch up permutation matrix */ memset(&P_per[n+1], 0, n * sizeof(int)); for (k = 1; k <= n; k++) { P_per[k]++; xassert(1 <= P_per[k] && P_per[k] <= n); xassert(P_per[n+P_per[k]] == 0); P_per[n+P_per[k]] = k; } return; }
static scs_int factorize(const ScsMatrix *A, const ScsSettings *stgs, ScsLinSysWork *p) { scs_float *info; scs_int *Pinv, amd_status, ldl_status; cs *C, *K = form_kkt(A, stgs); if (!K) { return -1; } amd_status = _ldl_init(K, p->P, &info); if (amd_status < 0) { return (amd_status); } #if EXTRA_VERBOSE > 0 if (stgs->verbose) { scs_printf("Matrix factorization info:\n"); #ifdef DLONG amd_l_info(info); #else amd_info(info); #endif } #endif Pinv = SCS(cs_pinv)(p->P, A->n + A->m); C = SCS(cs_symperm)(K, Pinv, 1); ldl_status = _ldl_factor(C, SCS_NULL, SCS_NULL, &p->L, &p->D); SCS(cs_spfree)(C); SCS(cs_spfree)(K); scs_free(Pinv); scs_free(info); return (ldl_status); }
scs_int factorize(const AMatrix * A, const Settings * stgs, Priv * p) { scs_float *info; scs_int *Pinv, amd_status, ldl_status; cs *C, *K = formKKT(A, stgs); if (!K) { return -1; } amd_status = LDLInit(K, p->P, &info); if (amd_status < 0) return (amd_status); #if EXTRAVERBOSE > 0 if(stgs->verbose) { scs_printf("Matrix factorization info:\n"); #ifdef DLONG amd_l_info(info); #else amd_info(info); #endif } #endif Pinv = cs_pinv(p->P, A->n + A->m); C = cs_symperm(K, Pinv, 1); ldl_status = LDLFactor(C, NULL, NULL, &p->L, &p->D); cs_spfree(C); cs_spfree(K); scs_free(Pinv); scs_free(info); return (ldl_status); }
PETSC_EXTERN PetscErrorCode MatGetOrdering_AMD(Mat mat,MatOrderingType type,IS *row,IS *col) { PetscErrorCode ierr; PetscInt nrow,*perm; const PetscInt *ia,*ja; int status; PetscReal val; double Control[AMD_CONTROL],Info[AMD_INFO]; PetscBool tval,done; PetscFunctionBegin; /* AMD does not require that the matrix be symmetric (it does so internally, at least in so far as computing orderings for A+A^T. */ ierr = MatGetRowIJ(mat,0,PETSC_FALSE,PETSC_TRUE,&nrow,&ia,&ja,&done);CHKERRQ(ierr); if (!done) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot get rows for matrix type %s",((PetscObject)mat)->type_name); amd_AMD_defaults(Control); ierr = PetscOptionsBegin(PetscObjectComm((PetscObject)mat),((PetscObject)mat)->prefix,"AMD Options","Mat");CHKERRQ(ierr); /* We have to use temporary values here because AMD always uses double, even though PetscReal may be single */ val = (PetscReal)Control[AMD_DENSE]; ierr = PetscOptionsReal("-mat_ordering_amd_dense","threshold for \"dense\" rows/columns","None",val,&val,NULL);CHKERRQ(ierr); Control[AMD_DENSE] = (double)val; tval = (PetscBool)Control[AMD_AGGRESSIVE]; ierr = PetscOptionsBool("-mat_ordering_amd_aggressive","use aggressive absorption","None",tval,&tval,NULL);CHKERRQ(ierr); Control[AMD_AGGRESSIVE] = (double)tval; ierr = PetscOptionsEnd();CHKERRQ(ierr); ierr = PetscMalloc(nrow*sizeof(PetscInt),&perm);CHKERRQ(ierr); status = amd_AMD_order(nrow,ia,ja,perm,Control,Info); switch (status) { case AMD_OK: break; case AMD_OK_BUT_JUMBLED: /* The result is fine, but PETSc matrices are supposed to satisfy stricter preconditions, so PETSc considers a * matrix that triggers this error condition to be invalid. */ SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"According to AMD, the matrix has unsorted and/or duplicate row indices"); case AMD_INVALID: amd_info(Info); SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_PLIB,"According to AMD, the matrix is invalid"); case AMD_OUT_OF_MEMORY: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_MEM,"AMD could not compute ordering"); default: SETERRQ(PetscObjectComm((PetscObject)mat),PETSC_ERR_LIB,"Unexpected return value"); } ierr = MatRestoreRowIJ(mat,0,PETSC_FALSE,PETSC_TRUE,NULL,&ia,&ja,&done);CHKERRQ(ierr); ierr = ISCreateGeneral(PETSC_COMM_SELF,nrow,perm,PETSC_COPY_VALUES,row);CHKERRQ(ierr); ierr = ISCreateGeneral(PETSC_COMM_SELF,nrow,perm,PETSC_OWN_POINTER,col);CHKERRQ(ierr); PetscFunctionReturn(0); }
int main (void) #endif { /* ---------------------------------------------------------------------- */ /* local variables */ /* ---------------------------------------------------------------------- */ #ifdef USE_AMD double Info [AMD_INFO] ; #endif double r, rnorm, flops, maxrnorm = 0. ; double *Ax, *Lx, *B, *D, *X, *Y ; LDL_int matrix, *Ai, *Ap, *Li, *Lp, *P, *Pinv, *Perm, *PermInv, n, i, j, p, nz, *Flag, *Pattern, *Lnz, *Parent, trial, lnz, d, jumbled ; FILE *f ; char s [LEN] ; /* ---------------------------------------------------------------------- */ /* check the error-checking routines with null matrices */ /* ---------------------------------------------------------------------- */ i = 1 ; n = -1 ; if (LDL_valid_perm (n, (LDL_int *) NULL, &i) || !LDL_valid_perm (0, (LDL_int *) NULL, &i) || LDL_valid_matrix (n, (LDL_int *) NULL, (LDL_int *) NULL) || LDL_valid_matrix (0, &i, &i)) { printf (PROGRAM ": ldl error-checking routine failed\n") ; EXIT_ERROR ; } /* ---------------------------------------------------------------------- */ /* read in a factorize a set of matrices */ /* ---------------------------------------------------------------------- */ for (matrix = 1 ; matrix <= NMATRICES ; matrix++) { /* ------------------------------------------------------------------ */ /* read in the matrix and the permutation */ /* ------------------------------------------------------------------ */ sprintf (s, "../Matrix/A%02d", (int) matrix) ; if ((f = fopen (s, "r")) == (FILE *) NULL) { printf (PROGRAM ": could not open file: %s\n", s) ; EXIT_ERROR ; } fgets (s, LEN, f) ; printf ("\n\n--------------------------------------------------------"); printf ("\nInput matrix: %s", s) ; printf ("--------------------------------------------------------\n\n"); fscanf (f, LDL_ID " " LDL_ID, &n, &jumbled) ; n = (n < 0) ? (0) : (n) ; ALLOC_MEMORY (P, LDL_int, n) ; ALLOC_MEMORY (Ap, LDL_int, n+1) ; for (j = 0 ; j <= n ; j++) { fscanf (f, LDL_ID, &Ap [j]) ; } nz = Ap [n] ; ALLOC_MEMORY (Ai, LDL_int, nz) ; ALLOC_MEMORY (Ax, double, nz) ; for (p = 0 ; p < nz ; p++) { fscanf (f, LDL_ID , &Ai [p]) ; } for (p = 0 ; p < nz ; p++) { fscanf (f, "%lg", &Ax [p]) ; } for (j = 0 ; j < n ; j++) { fscanf (f, LDL_ID , &P [j]) ; } fclose (f) ; /* ------------------------------------------------------------------ */ /* check the matrix A and the permutation P */ /* ------------------------------------------------------------------ */ ALLOC_MEMORY (Flag, LDL_int, n) ; /* To test the error-checking routines, some of the input matrices * are not valid. So this error is expected to occur. */ if (!LDL_valid_matrix (n, Ap, Ai) || !LDL_valid_perm (n, P, Flag)) { printf (PROGRAM ": invalid matrix and/or permutation\n") ; FREE_MEMORY (P, LDL_int) ; FREE_MEMORY (Ap, LDL_int) ; FREE_MEMORY (Ai, LDL_int) ; FREE_MEMORY (Ax, double) ; FREE_MEMORY (Flag, LDL_int) ; continue ; } /* ------------------------------------------------------------------ */ /* get the AMD permutation, if available */ /* ------------------------------------------------------------------ */ #ifdef USE_AMD /* recompute the permutation with AMD */ /* Assume that AMD produces a valid permutation P. */ #ifdef LDL_LONG if (amd_l_order (n, Ap, Ai, P, (double *) NULL, Info) < AMD_OK) { printf (PROGRAM ": call to AMD failed\n") ; EXIT_ERROR ; } amd_l_control ((double *) NULL) ; amd_l_info (Info) ; #else if (amd_order (n, Ap, Ai, P, (double *) NULL, Info) < AMD_OK) { printf (PROGRAM ": call to AMD failed\n") ; EXIT_ERROR ; } amd_control ((double *) NULL) ; amd_info (Info) ; #endif #endif /* ------------------------------------------------------------------ */ /* allocate workspace and the first part of LDL factorization */ /* ------------------------------------------------------------------ */ ALLOC_MEMORY (Pinv, LDL_int, n) ; ALLOC_MEMORY (Y, double, n) ; ALLOC_MEMORY (Pattern, LDL_int, n) ; ALLOC_MEMORY (Lnz, LDL_int, n) ; ALLOC_MEMORY (Lp, LDL_int, n+1) ; ALLOC_MEMORY (Parent, LDL_int, n) ; ALLOC_MEMORY (D, double, n) ; ALLOC_MEMORY (B, double, n) ; ALLOC_MEMORY (X, double, n) ; /* ------------------------------------------------------------------ */ /* factorize twice, with and without permutation */ /* ------------------------------------------------------------------ */ for (trial = 1 ; trial <= 2 ; trial++) { if (trial == 1) { printf ("Factorize PAP'=LDL' and solve Ax=b\n") ; Perm = P ; PermInv = Pinv ; } else { printf ("Factorize A=LDL' and solve Ax=b\n") ; Perm = (LDL_int *) NULL ; PermInv = (LDL_int *) NULL ; } /* -------------------------------------------------------------- */ /* symbolic factorization to get Lp, Parent, Lnz, and Pinv */ /* -------------------------------------------------------------- */ LDL_symbolic (n, Ap, Ai, Lp, Parent, Lnz, Flag, Perm, PermInv) ; lnz = Lp [n] ; /* find # of nonzeros in L, and flop count for LDL_numeric */ flops = 0 ; for (j = 0 ; j < n ; j++) { flops += ((double) Lnz [j]) * (Lnz [j] + 2) ; } printf ("Nz in L: "LDL_ID" Flop count: %g\n", lnz, flops) ; /* -------------------------------------------------------------- */ /* allocate remainder of L, of size lnz */ /* -------------------------------------------------------------- */ ALLOC_MEMORY (Li, LDL_int, lnz) ; ALLOC_MEMORY (Lx, double, lnz) ; /* -------------------------------------------------------------- */ /* numeric factorization to get Li, Lx, and D */ /* -------------------------------------------------------------- */ d = LDL_numeric (n, Ap, Ai, Ax, Lp, Parent, Lnz, Li, Lx, D, Y, Flag, Pattern, Perm, PermInv) ; /* -------------------------------------------------------------- */ /* solve, or report singular case */ /* -------------------------------------------------------------- */ if (d != n) { printf ("Ax=b not solved since D("LDL_ID","LDL_ID") is zero.\n", d, d) ; } else { /* construct the right-hand-side, B */ for (i = 0 ; i < n ; i++) { B [i] = 1 + ((double) i) / 100 ; } /* solve Ax=b */ if (trial == 1) { /* the factorization is LDL' = PAP' */ LDL_perm (n, Y, B, P) ; /* y = Pb */ LDL_lsolve (n, Y, Lp, Li, Lx) ; /* y = L\y */ LDL_dsolve (n, Y, D) ; /* y = D\y */ LDL_ltsolve (n, Y, Lp, Li, Lx) ; /* y = L'\y */ LDL_permt (n, X, Y, P) ; /* x = P'y */ } else { /* the factorization is LDL' = A */ for (i = 0 ; i < n ; i++) /* x = b */ { X [i] = B [i] ; } LDL_lsolve (n, X, Lp, Li, Lx) ; /* x = L\x */ LDL_dsolve (n, X, D) ; /* x = D\x */ LDL_ltsolve (n, X, Lp, Li, Lx) ; /* x = L'\x */ } /* compute the residual y = Ax-b */ /* note that this code can tolerate a jumbled matrix */ for (i = 0 ; i < n ; i++) { Y [i] = -B [i] ; } for (j = 0 ; j < n ; j++) { for (p = Ap [j] ; p < Ap [j+1] ; p++) { Y [Ai [p]] += Ax [p] * X [j] ; } } /* rnorm = norm (y, inf) */ rnorm = 0 ; for (i = 0 ; i < n ; i++) { r = (Y [i] > 0) ? (Y [i]) : (-Y [i]) ; rnorm = (r > rnorm) ? (r) : (rnorm) ; } maxrnorm = (rnorm > maxrnorm) ? (rnorm) : (maxrnorm) ; printf ("relative maxnorm of residual: %g\n", rnorm) ; } /* -------------------------------------------------------------- */ /* free the size-lnz part of L */ /* -------------------------------------------------------------- */ FREE_MEMORY (Li, LDL_int) ; FREE_MEMORY (Lx, double) ; } /* free everything */ FREE_MEMORY (P, LDL_int) ; FREE_MEMORY (Ap, LDL_int) ; FREE_MEMORY (Ai, LDL_int) ; FREE_MEMORY (Ax, double) ; FREE_MEMORY (Pinv, LDL_int) ; FREE_MEMORY (Y, double) ; FREE_MEMORY (Flag, LDL_int) ; FREE_MEMORY (Pattern, LDL_int) ; FREE_MEMORY (Lnz, LDL_int) ; FREE_MEMORY (Lp, LDL_int) ; FREE_MEMORY (Parent, LDL_int) ; FREE_MEMORY (D, double) ; FREE_MEMORY (B, double) ; FREE_MEMORY (X, double) ; } printf ("\nLargest residual during all tests: %g\n", maxrnorm) ; if (maxrnorm < 1e-8) { printf ("\n" PROGRAM ": all tests passed\n") ; EXIT_OK ; } else { printf ("\n" PROGRAM ": one more tests failed (residual too high)\n") ; EXIT_ERROR ; } }
int amd_demo_1 (void) { /* The symmetric can_24 Harwell/Boeing matrix, including upper and lower * triangular parts, and the diagonal entries. Note that this matrix is * 0-based, with row and column indices in the range 0 to n-1. */ int n = 24, nz, Ap [ ] = { 0, 9, 15, 21, 27, 33, 39, 48, 57, 61, 70, 76, 82, 88, 94, 100, 106, 110, 119, 128, 137, 143, 152, 156, 160 }, Ai [ ] = { /* column 0: */ 0, 5, 6, 12, 13, 17, 18, 19, 21, /* column 1: */ 1, 8, 9, 13, 14, 17, /* column 2: */ 2, 6, 11, 20, 21, 22, /* column 3: */ 3, 7, 10, 15, 18, 19, /* column 4: */ 4, 7, 9, 14, 15, 16, /* column 5: */ 0, 5, 6, 12, 13, 17, /* column 6: */ 0, 2, 5, 6, 11, 12, 19, 21, 23, /* column 7: */ 3, 4, 7, 9, 14, 15, 16, 17, 18, /* column 8: */ 1, 8, 9, 14, /* column 9: */ 1, 4, 7, 8, 9, 13, 14, 17, 18, /* column 10: */ 3, 10, 18, 19, 20, 21, /* column 11: */ 2, 6, 11, 12, 21, 23, /* column 12: */ 0, 5, 6, 11, 12, 23, /* column 13: */ 0, 1, 5, 9, 13, 17, /* column 14: */ 1, 4, 7, 8, 9, 14, /* column 15: */ 3, 4, 7, 15, 16, 18, /* column 16: */ 4, 7, 15, 16, /* column 17: */ 0, 1, 5, 7, 9, 13, 17, 18, 19, /* column 18: */ 0, 3, 7, 9, 10, 15, 17, 18, 19, /* column 19: */ 0, 3, 6, 10, 17, 18, 19, 20, 21, /* column 20: */ 2, 10, 19, 20, 21, 22, /* column 21: */ 0, 2, 6, 10, 11, 19, 20, 21, 22, /* column 22: */ 2, 20, 21, 22, /* column 23: */ 6, 11, 12, 23 } ; int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; double Control [AMD_CONTROL], Info [AMD_INFO] ; char A [24][24] ; /* here is an example of how to use AMD_VERSION. This code will work in * any version of AMD. */ #if defined(AMD_VERSION) && (AMD_VERSION >= AMD_VERSION_CODE(1,2)) printf ("AMD version %d.%d, date: %s\n", AMD_MAIN_VERSION, AMD_SUB_VERSION, AMD_DATE) ; #else printf ("AMD version: 1.1 or earlier\n") ; #endif printf ("AMD demo, with the 24-by-24 Harwell/Boeing matrix, can_24:\n") ; /* get the default parameters, and print them */ amd_defaults (Control) ; amd_control (Control) ; /* print the input matrix */ nz = Ap [n] ; printf ("\nInput matrix: %d-by-%d, with %d entries.\n" " Note that for a symmetric matrix such as this one, only the\n" " strictly lower or upper triangular parts would need to be\n" " passed to AMD, since AMD computes the ordering of A+A'. The\n" " diagonal entries are also not needed, since AMD ignores them.\n" , n, n, nz) ; for (j = 0 ; j < n ; j++) { printf ("\nColumn: %d, number of entries: %d, with row indices in" " Ai [%d ... %d]:\n row indices:", j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; printf (" %d", i) ; } printf ("\n") ; } /* print a character plot of the input matrix. This is only reasonable * because the matrix is small. */ printf ("\nPlot of input matrix pattern:\n") ; for (j = 0 ; j < n ; j++) { for (i = 0 ; i < n ; i++) A [i][j] = '.' ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; A [i][j] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf ("\n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf ("\n") ; } /* order the matrix */ result = amd_order (n, Ap, Ai, P, Control, Info) ; printf ("return value from amd_order: %d (should be %d)\n", result, AMD_OK) ; /* print the statistics */ amd_info (Info) ; if (result != AMD_OK) { printf ("AMD failed\n") ; ElEXIT (1,"AMD DEMO") ; } /* print the permutation vector, P, and compute the inverse permutation */ printf ("Permutation vector:\n") ; for (k = 0 ; k < n ; k++) { /* row/column j is the kth row/column in the permuted matrix */ j = P [k] ; Pinv [j] = k ; printf (" %2d", j) ; } printf ("\n\n") ; printf ("Inverse permutation vector:\n") ; for (j = 0 ; j < n ; j++) { k = Pinv [j] ; printf (" %2d", k) ; } printf ("\n\n") ; /* print a character plot of the permuted matrix. */ printf ("\nPlot of permuted matrix pattern:\n") ; for (jnew = 0 ; jnew < n ; jnew++) { j = P [jnew] ; for (inew = 0 ; inew < n ; inew++) A [inew][jnew] = '.' ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { inew = Pinv [Ai [p]] ; A [inew][jnew] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf ("\n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf ("\n") ; } return (0) ; }
int main (int argc, char **argv) { int i, j, k, n, nz, *Ap, *Ai, *Ti, *Tj, status, *Pamd, nrow, ncol, rhs ; double *Ax, *b, *x, Control [UMFPACK_CONTROL], Info [UMFPACK_INFO], aij, *Tx, *r, amd_Control [AMD_CONTROL], amd_Info [AMD_INFO], tamd [2], stats [2], droptol ; void *Symbolic, *Numeric ; FILE *f, *f2 ; char s [SMAX] ; /* ---------------------------------------------------------------------- */ /* set controls */ /* ---------------------------------------------------------------------- */ printf ("\n===========================================================\n" "=== UMFPACK v%d.%d.%d ========================================\n" "===========================================================\n", UMFPACK_MAIN_VERSION, UMFPACK_SUB_VERSION, UMFPACK_SUBSUB_VERSION) ; umfpack_di_defaults (Control) ; Control [UMFPACK_PRL] = 3 ; Control [UMFPACK_BLOCK_SIZE] = 32 ; f = fopen ("tmp/control.umf4", "r") ; if (f != (FILE *) NULL) { printf ("Reading control file tmp/control.umf4\n") ; for (i = 0 ; i < UMFPACK_CONTROL ; i++) { fscanf (f, "%lg\n", & Control [i]) ; } fclose (f) ; } if (argc > 1) { char *t = argv [1] ; /* get the strategy */ if (t [0] == 'u') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_UNSYMMETRIC ; } else if (t [0] == 'a') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_AUTO ; } else if (t [0] == 's') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_SYMMETRIC ; } else if (t [0] == '2') { printf ("unrecognized strategy: %s\n", argv [1]) ; } else if (t [0] == 'U') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_UNSYMMETRIC ; Control [UMFPACK_SCALE] = UMFPACK_SCALE_MAX ; } else if (t [0] == 'A') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_AUTO ; Control [UMFPACK_SCALE] = UMFPACK_SCALE_MAX ; } else if (t [0] == 'S') { Control [UMFPACK_STRATEGY] = UMFPACK_STRATEGY_SYMMETRIC ; Control [UMFPACK_SCALE] = UMFPACK_SCALE_MAX ; } else if (t [0] == 'T') { printf ("unrecognized strategy: %s\n", argv [1]) ; } else { printf ("unrecognized strategy: %s\n", argv [1]) ; } if (t [1] == 'n') { /* no aggressive absorption */ Control [UMFPACK_AGGRESSIVE] = FALSE ; } } if (argc > 2) { /* get the drop tolerance */ sscanf (argv [2], "%lg", &droptol) ; printf ("droptol %g\n", droptol) ; Control [UMFPACK_DROPTOL] = droptol ; } umfpack_di_report_control (Control) ; /* ---------------------------------------------------------------------- */ /* open the matrix file (tmp/A) */ /* ---------------------------------------------------------------------- */ printf ("File: tmp/A\n") ; f = fopen ("tmp/A", "r") ; if (!f) { printf ("Unable to open file\n") ; exit (1) ; } /* ---------------------------------------------------------------------- */ /* get n and nz */ /* ---------------------------------------------------------------------- */ printf ("File: tmp/Asize\n") ; f2 = fopen ("tmp/Asize", "r") ; if (f2) { fscanf (f2, "%d %d %d\n", &nrow, &ncol, &nz) ; fclose (f2) ; } else { nrow = 1 ; ncol = 1 ; } nz = 0 ; while (fgets (s, SMAX, f) != (char *) NULL) { sscanf (s, "%d %d %lg", &i, &j, &aij) ; #ifdef ZERO_BASED /* matrix is zero based */ i++ ; j++ ; #endif nrow = MAX (nrow, i) ; ncol = MAX (ncol, j) ; nz++ ; } fclose (f) ; n = MAX (nrow, ncol) ; printf ("n %d nrow %d ncol %d nz %d\n", n, nrow, ncol, nz) ; /* ---------------------------------------------------------------------- */ /* allocate space for the input triplet form */ /* ---------------------------------------------------------------------- */ Ti = (int *) malloc (nz * sizeof (int)) ; Tj = (int *) malloc (nz * sizeof (int)) ; Tx = (double *) malloc (nz * sizeof (double)) ; if (!Ti || !Tj || !Tx) { printf ("out of memory for input matrix\n") ; exit (1) ; } /* ---------------------------------------------------------------------- */ /* read in the triplet form */ /* ---------------------------------------------------------------------- */ f2 = fopen ("tmp/A", "r") ; if (!f2) { printf ("Unable to open file\n") ; exit (1) ; } k = 0 ; while (fgets (s, SMAX, f2) != (char *) NULL) { sscanf (s, "%d %d %lg", &i, &j, &aij) ; #ifndef ZERO_BASED i-- ; /* convert to 0-based */ j-- ; #endif if (k >= nz) { printf ("Error! Matrix size is wrong\n") ; exit (1) ; } Ti [k] = i ; Tj [k] = j ; Tx [k] = aij ; k++ ; } fclose (f2) ; (void) umfpack_di_report_triplet (nrow, ncol, nz, Ti, Tj, Tx, Control) ; /* ---------------------------------------------------------------------- */ /* convert to column form */ /* ---------------------------------------------------------------------- */ /* convert to column form */ Ap = (int *) malloc ((n+1) * sizeof (int)) ; Ai = (int *) malloc (nz * sizeof (int)) ; Ax = (double *) malloc (nz * sizeof (double)) ; b = (double *) malloc (n * sizeof (double)) ; r = (double *) malloc (n * sizeof (double)) ; x = (double *) malloc (n * sizeof (double)) ; if (!Ap || !Ai || !Ax || !b || !r) { printf ("out of memory") ; exit (1) ; } umfpack_tic (stats) ; status = umfpack_di_triplet_to_col (nrow, ncol, nz, Ti, Tj, Tx, Ap, Ai, Ax, (int *) NULL) ; umfpack_toc (stats) ; printf ("triplet-to-col time: wall %g cpu %g\n", stats [0], stats [1]) ; if (status != UMFPACK_OK) { umfpack_di_report_status (Control, status) ; printf ("umfpack_di_triplet_to_col failed") ; exit (1) ; } /* print the column-form of A */ (void) umfpack_di_report_matrix (nrow, ncol, Ap, Ai, Ax, 1, Control) ; /* b = A * xtrue */ rhs = FALSE ; if (nrow == ncol) { f = fopen ("tmp/b", "r") ; if (f != (FILE *) NULL) { printf ("Reading tmp/b\n") ; rhs = TRUE ; for (i = 0 ; i < n ; i++) { fscanf (f, "%lg\n", &b [i]) ; } fclose (f) ; } else { Atimesx (n, Ap, Ai, Ax, b, FALSE) ; } } /* ---------------------------------------------------------------------- */ /* free the triplet form */ /* ---------------------------------------------------------------------- */ free (Ti) ; free (Tj) ; free (Tx) ; /* ---------------------------------------------------------------------- */ /* symbolic factorization */ /* ---------------------------------------------------------------------- */ status = umfpack_di_symbolic (nrow, ncol, Ap, Ai, Ax, &Symbolic, Control, Info) ; umfpack_di_report_info (Control, Info) ; if (status != UMFPACK_OK) { umfpack_di_report_status (Control, status) ; printf ("umfpack_di_symbolic failed") ; exit (1) ; } /* print the symbolic factorization */ (void) umfpack_di_report_symbolic (Symbolic, Control) ; /* ---------------------------------------------------------------------- */ /* numeric factorization */ /* ---------------------------------------------------------------------- */ status = umfpack_di_numeric (Ap, Ai, Ax, Symbolic, &Numeric, Control, Info); if (status < UMFPACK_OK) { umfpack_di_report_info (Control, Info) ; umfpack_di_report_status (Control, status) ; fprintf (stderr, "umfpack_di_numeric failed: %d\n", status) ; printf ("umfpack_di_numeric failed\n") ; exit (1) ; } /* print the numeric factorization */ (void) umfpack_di_report_numeric (Numeric, Control) ; /* ---------------------------------------------------------------------- */ /* solve Ax=b */ /* ---------------------------------------------------------------------- */ if (nrow == ncol && status == UMFPACK_OK) { status = umfpack_di_solve (UMFPACK_A, Ap, Ai, Ax, x, b, Numeric, Control, Info) ; umfpack_di_report_info (Control, Info) ; umfpack_di_report_status (Control, status) ; if (status < UMFPACK_OK) { printf ("umfpack_di_solve failed\n") ; exit (1) ; } (void) umfpack_di_report_vector (n, x, Control) ; printf ("relative maxnorm of residual, ||Ax-b||/||b||: %g\n", resid (n, Ap, Ai, Ax, x, r, b, FALSE)) ; if (!rhs) { printf ("relative maxnorm of error, ||x-xtrue||/||xtrue||: %g\n\n", err (n, x)) ; } f = fopen ("tmp/x", "w") ; if (f != (FILE *) NULL) { printf ("Writing tmp/x\n") ; for (i = 0 ; i < n ; i++) { fprintf (f, "%30.20e\n", x [i]) ; } fclose (f) ; } else { printf ("Unable to write output x!\n") ; exit (1) ; } f = fopen ("tmp/info.umf4", "w") ; if (f != (FILE *) NULL) { printf ("Writing tmp/info.umf4\n") ; for (i = 0 ; i < UMFPACK_INFO ; i++) { fprintf (f, "%30.20e\n", Info [i]) ; } fclose (f) ; } else { printf ("Unable to write output info!\n") ; exit (1) ; } } else { /* don't solve, just report the results */ umfpack_di_report_info (Control, Info) ; umfpack_di_report_status (Control, status) ; } /* ---------------------------------------------------------------------- */ /* free the Symbolic and Numeric factorization */ /* ---------------------------------------------------------------------- */ umfpack_di_free_symbolic (&Symbolic) ; umfpack_di_free_numeric (&Numeric) ; printf ("umf4 done, strategy: %g\n", Control [UMFPACK_STRATEGY]) ; /* ---------------------------------------------------------------------- */ /* test just AMD ordering (not part of UMFPACK, but a separate test) */ /* ---------------------------------------------------------------------- */ /* first make the matrix square */ if (ncol < n) { for (j = ncol+1 ; j <= n ; j++) { Ap [j] = Ap [ncol] ; } } printf ( "\n\n===========================================================\n" "=== AMD ===================================================\n" "===========================================================\n") ; printf ("\n\n------- Now trying the AMD ordering. This not part of\n" "the UMFPACK analysis or factorization, above, but a separate\n" "test of just the AMD ordering routine.\n") ; Pamd = (int *) malloc (n * sizeof (int)) ; if (!Pamd) { printf ("out of memory\n") ; exit (1) ; } amd_defaults (amd_Control) ; amd_control (amd_Control) ; umfpack_tic (tamd) ; status = amd_order (n, Ap, Ai, Pamd, amd_Control, amd_Info) ; umfpack_toc (tamd) ; printf ("AMD ordering time: cpu %10.2f wall %10.2f\n", tamd [1], tamd [0]) ; if (status != AMD_OK) { printf ("amd failed: %d\n", status) ; exit (1) ; } amd_info (amd_Info) ; free (Pamd) ; printf ("AMD test done\n") ; free (Ap) ; free (Ai) ; free (Ax) ; free (b) ; free (r) ; free (x) ; return (0) ; }
int main (int argc, char **argv) { /* The symmetric can_24 Harwell/Boeing matrix (jumbled, and not symmetric). * Since AMD operates on A+A', only A(i,j) or A(j,i) need to be specified, * or both. The diagonal entries are optional (some are missing). * There are many duplicate entries, which must be removed. */ int n = 24, nz, Ap [ ] = { 0, 9, 14, 20, 28, 33, 37, 44, 53, 58, 63, 63, 66, 69, 72, 75, 78, 82, 86, 91, 97, 101, 112, 112, 116 }, Ai [ ] = { /* column 0: */ 0, 17, 18, 21, 5, 12, 5, 0, 13, /* column 1: */ 14, 1, 8, 13, 17, /* column 2: */ 2, 20, 11, 6, 11, 22, /* column 3: */ 3, 3, 10, 7, 18, 18, 15, 19, /* column 4: */ 7, 9, 15, 14, 16, /* column 5: */ 5, 13, 6, 17, /* column 6: */ 5, 0, 11, 6, 12, 6, 23, /* column 7: */ 3, 4, 9, 7, 14, 16, 15, 17, 18, /* column 8: */ 1, 9, 14, 14, 14, /* column 9: */ 7, 13, 8, 1, 17, /* column 10: */ /* column 11: */ 2, 12, 23, /* column 12: */ 5, 11, 12, /* column 13: */ 0, 13, 17, /* column 14: */ 1, 9, 14, /* column 15: */ 3, 15, 16, /* column 16: */ 16, 4, 4, 15, /* column 17: */ 13, 17, 19, 17, /* column 18: */ 15, 17, 19, 9, 10, /* column 19: */ 17, 19, 20, 0, 6, 10, /* column 20: */ 22, 10, 20, 21, /* column 21: */ 6, 2, 10, 19, 20, 11, 21, 22, 22, 22, 22, /* column 22: */ /* column 23: */ 12, 11, 12, 23 } ; int Rp [25], Ri [116] ; int P [24], Pinv [24], i, j, k, jnew, p, inew, result ; double Control [AMD_CONTROL], Info [AMD_INFO] ; char A [24][24] ; printf ("AMD demo, with a jumbled version of the 24-by-24\n") ; printf ("Harwell/Boeing matrix, can_24:\n") ; /* get the default parameters, and print them */ amd_defaults (Control) ; amd_control (Control) ; /* print the input matrix */ nz = Ap [n] ; printf ("\nJumbled input matrix: %d-by-%d, with %d entries.\n" " Note that for a symmetric matrix such as this one, only the\n" " strictly lower or upper triangular parts would need to be\n" " passed to AMD, since AMD computes the ordering of A+A'. The\n" " diagonal entries are also not needed, since AMD ignores them.\n" " This version of the matrix has jumbled columns and duplicate\n" " row indices, and must be fixed by amd_preprocess prior to\n" " ordering it with amd_order.\n" , n, n, nz) ; for (j = 0 ; j < n ; j++) { printf ("\nColumn: %d, number of entries: %d, with row indices in" " Ai [%d ... %d]:\n row indices:", j, Ap [j+1] - Ap [j], Ap [j], Ap [j+1]-1) ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; printf (" %d", i) ; } printf ("\n") ; } /* print a character plot of the input matrix. This is only reasonable * because the matrix is small. */ printf ("\nPlot of (jumbled) input matrix pattern:\n") ; for (j = 0 ; j < n ; j++) { for (i = 0 ; i < n ; i++) A [i][j] = '.' ; for (p = Ap [j] ; p < Ap [j+1] ; p++) { i = Ai [p] ; A [i][j] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf ("\n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf ("\n") ; } /* sort, remove duplicates, and transpose A to get R */ result = amd_preprocess (n, Ap, Ai, Rp, Ri) ; printf ("return value from amd_preprocess: %d (should be %d)\n", result, AMD_OK) ; if (result != AMD_OK) { printf ("AMD failed\n") ; exit (1) ; } /* print the sorted/transposed matrix R */ printf ("\nThe column-oriented form of the sorted/transposed matrix R:\n"); for (j = 0 ; j < n ; j++) { printf ("\nColumn: %d, number of entries: %d, with row indices in" " Ri [%d ... %d]:\n row indices:", j, Rp [j+1] - Rp [j], Rp [j], Rp [j+1]-1) ; for (p = Rp [j] ; p < Rp [j+1] ; p++) { i = Ri [p] ; printf (" %d", i) ; } printf ("\n") ; } /* print a character plot of the matrix R. */ printf ("\nPlot of the sorted/transposed matrix R:\n") ; for (j = 0 ; j < n ; j++) { for (i = 0 ; i < n ; i++) A [i][j] = '.' ; for (p = Rp [j] ; p < Rp [j+1] ; p++) { i = Ri [p] ; A [i][j] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf (" \n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf (" \n") ; } /* print a character plot of the matrix R+R'. */ printf ("\nPlot of symmetric matrix to be ordered by amd_order:\n") ; for (j = 0 ; j < n ; j++) { for (i = 0 ; i < n ; i++) A [i][j] = '.' ; } for (j = 0 ; j < n ; j++) { A [j][j] = 'X' ; for (p = Rp [j] ; p < Rp [j+1] ; p++) { i = Ri [p] ; A [i][j] = 'X' ; A [j][i] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf ("\n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf ("\n") ; } /* order the matrix */ result = amd_order (n, Rp, Ri, P, Control, Info) ; printf ("return value from amd_order: %d (should be %d)\n", result, AMD_OK) ; /* print the statistics */ amd_info (Info) ; if (result != AMD_OK) { printf ("AMD failed\n") ; exit (1) ; } /* print the permutation vector, P, and compute the inverse permutation */ printf ("Permutation vector:\n") ; for (k = 0 ; k < n ; k++) { /* row/column j is the kth row/column in the permuted matrix */ j = P [k] ; Pinv [j] = k ; printf (" %2d", j) ; } printf ("\n\n") ; printf ("Inverse permutation vector:\n") ; for (j = 0 ; j < n ; j++) { k = Pinv [j] ; printf (" %2d", k) ; } printf ("\n\n") ; /* print a character plot of the permuted matrix. */ printf ("\nPlot of (symmetrized) permuted matrix pattern:\n") ; for (j = 0 ; j < n ; j++) { for (i = 0 ; i < n ; i++) A [i][j] = '.' ; } for (jnew = 0 ; jnew < n ; jnew++) { j = P [jnew] ; A [jnew][jnew] = 'X' ; for (p = Rp [j] ; p < Rp [j+1] ; p++) { inew = Pinv [Ri [p]] ; A [inew][jnew] = 'X' ; A [jnew][inew] = 'X' ; } } printf (" ") ; for (j = 0 ; j < n ; j++) printf (" %1d", j % 10) ; printf ("\n") ; for (i = 0 ; i < n ; i++) { printf ("%2d: ", i) ; for (j = 0 ; j < n ; j++) { printf (" %c", A [i][j]) ; } printf ("\n") ; } return (0) ; }