//------------------------------------------------------------------------------ // CHOLMOD/Tcov/t_test_ops: test CHOLMOD matrix operators //------------------------------------------------------------------------------ // CHOLMOD/Tcov Module. Copyright (C) 2005-2023, Timothy A. Davis. // All Rights Reserved. // SPDX-License-Identifier: GPL-2.0+ //------------------------------------------------------------------------------ // Test CHOLMOD matrix operators. #include "cm.h" //------------------------------------------------------------------------------ // nzdiag //------------------------------------------------------------------------------ // Count the entries on the diagonal Int nzdiag (cholmod_sparse *A) { Int *Ap, *Ai, *Anz ; Int nnzdiag, packed, j, p, i, pend, ncol ; if (A == NULL) { return (EMPTY) ; } nnzdiag = 0 ; ncol = A->ncol ; Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; for (j = 0 ; j < ncol ; j++) { p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; if (i == j) { nnzdiag++ ; } } } return (nnzdiag) ; } //------------------------------------------------------------------------------ // check_partition //------------------------------------------------------------------------------ // Check a node separator, and return the # of nodes in the node separator or // -1 if the separater is invalid. A node j is in the left part if // Part [j] = 0, in the right part if Part [j] = 1, and in the separator if // Part [j] = 2. Int check_partition (cholmod_sparse *A, Int *Part) { Int *Ap, *Ai, *Anz ; Int chek [3], which, i, j, p, n, pend, packed ; if (A == NULL || Part == NULL || A->nrow != A->ncol) { // printf ("A NULL, no Partition, or rectangular\n") ; return (EMPTY) ; } n = A->nrow ; Ap = A->p ; Ai = A->i ; Anz = A->nz ; packed = A->packed ; chek [0] = 0 ; chek [1] = 0 ; chek [2] = 0 ; // printf ("\ncheck partition:\n") ; for (j = 0 ; j < n ; j++) { which = Part [j] ; // printf ("node "ID" in Part "ID"\n", j, which) ; p = Ap [j] ; pend = (packed) ? (Ap [j+1]) : (p + Anz [j]) ; for ( ; p < pend ; p++) { i = Ai [p] ; // printf (" neighbor "ID" in part "ID"\n", i, Part [i]) ; if (which == 0) { if (Part [i] == 1) { // printf (" broken!\n") ; return (EMPTY) ; } } else if (which == 1) { if (Part [i] == 0) { // printf (" broken!\n") ; return (EMPTY) ; } } } if (which < 0 || which > 2) { // printf (" node j, invalid partition, broken!\n") ; return (EMPTY) ; } chek [which]++ ; } // printf ("nodes in left: "ID" right: "ID" separator: "ID"\n", // chek [0], chek [1], chek [2]) ; return (chek [2]) ; } //------------------------------------------------------------------------------ // check_equality //------------------------------------------------------------------------------ // Ensure two sparse matrices are identical. static void check_equality (cholmod_sparse *E, cholmod_sparse *D, Int xtype) { Real *Ex, *Ez, *Dx, *Dz ; Int *Ep, *Ei, *Dp, *Di ; Int j, nz, p, ncol ; if (E == NULL || D == NULL || D->xtype != xtype || E->xtype != xtype) { return ; } Ep = E->p ; Ei = E->i ; Ex = E->x ; Ez = E->z ; Dp = D->p ; Di = D->i ; Dx = D->x ; Dz = D->z ; OK (E->ncol == D->ncol) ; OK (E->nrow == D->nrow) ; OK (E->packed == D->packed) ; ncol = E->ncol ; for (j = 0 ; j <= ncol ; j++) { OK (Ep [j] == Dp [j]) ; } nz = Ep [ncol] ; for (p = 0 ; p < nz ; p++) { OK (Ei [p] == Di [p]) ; } if (xtype == CHOLMOD_REAL) { for (p = 0 ; p < nz ; p++) { OK (Ex [p] == Dx [p]) ; } } else if (xtype == CHOLMOD_COMPLEX) { for (p = 0 ; p < 2*nz ; p++) { OK (Ex [p] == Dx [p]) ; } } else if (xtype == CHOLMOD_ZOMPLEX) { for (p = 0 ; p < nz ; p++) { OK (Ex [p] == Dx [p]) ; OK (Ez [p] == Dz [p]) ; } } } //------------------------------------------------------------------------------ // test_ops //------------------------------------------------------------------------------ // Test various matrix operations. double test_ops (cholmod_sparse *A) { double maxerr = 0, r, x, anorm, r1, rinf ; Real *Sx, *Sz ; Int *Pinv, *P, *Si, *Sj, *Q, *Qinv, *fset, *Partition ; cholmod_triplet *S ; cholmod_sparse *C, *D, *E, *F, *G, *H, *AT, *Zs ; cholmod_dense *X, *Y ; Int n, kk, k, nrow, ncol, len, nz, ok, i, j, stype, nmin, mode, xtype, xtype2, mtype, asym, xmatched, pmatched, nzoffdiag, nz_diag ; size_t nz1, nz2 ; void (*save) (int, const char *, int, const char *) ; double alpha [2], beta [2] ; Real *Xx ; FILE *f ; int option, save3 ; if (A == NULL) { ERROR (CHOLMOD_INVALID, "nothing for test_ops") ; return (1) ; } nrow = A->nrow ; ncol = A->ncol ; H = NULL ; n = MAX (nrow, ncol) ; nmin = MIN (nrow, ncol) ; xtype = A->xtype ; //-------------------------------------------------------------------------- // norm //-------------------------------------------------------------------------- CHOLMOD(print_sparse) (A, "A for testops", cm) ; r1 = CHOLMOD(norm_sparse) (A, 1, cm) ; rinf = CHOLMOD(norm_sparse) (A, 0, cm) ; anorm = r1 ; // E = pattern of A E = CHOLMOD(copy) (A, 0, 0, cm) ; // CHOLMOD(print_sparse) (E, "E = pattern of A", cm) ; // int64_t enz = CHOLMOD (nnz) (E, cm) ; // int64_t anz = CHOLMOD (nnz) (A, cm) ; // if (E->stype == A->stype) { OK (enz == anz) ; } r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; OK (r1 <= nrow) ; OK (rinf <= ncol) ; CHOLMOD(free_sparse) (&E, cm) ; // E = pattern of A, but exclude the diagonal E = CHOLMOD(copy) (A, 0, -1, cm) ; // CHOLMOD(print_sparse) (E, "E = spones (A), excl diag", cm) ; r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; if (nrow < ncol) { OK (r1 <= nrow) ; OK (rinf < MAX (1,ncol)) ; } else { OK (r1 < MAX (1,nrow)) ; OK (rinf <= ncol) ; } CHOLMOD(free_sparse) (&E, cm) ; //-------------------------------------------------------------------------- // copy //-------------------------------------------------------------------------- if (A->stype) { // E = tril (A), no diagonal E = CHOLMOD(copy) (A, -1, -1, cm) ; CHOLMOD(band_inplace) (0, n, 0, E, cm) ; nz = CHOLMOD(nnz) (E, cm) ; if (E != NULL) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&E, cm) ; } // E = -2:2 bands of A nz2 = CHOLMOD(band_nnz) (A, -2, 2, false, cm) ; E = CHOLMOD(band) (A, -2, 2, 0, cm) ; nz = CHOLMOD(nnz) (E, cm) ; if (E != NULL) { OK (nz == nz2) ; } CHOLMOD(free_sparse) (&E, cm) ; //-------------------------------------------------------------------------- // read/write //-------------------------------------------------------------------------- // delete the contents of the temp1.mtx and temp2.mtx file f = fopen ("temp1.mtx", "w") ; fprintf (f, "temp1\n") ; fclose (f) ; f = fopen ("temp3.mtx", "w") ; fprintf (f, "temp3\n") ; fclose (f) ; CHOLMOD(free_work) (cm) ; f = fopen ("temp1.mtx", "w") ; asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; fclose (f) ; // printf ("write_sparse, asym: "ID"\n", asym) ; OK (IMPLIES (A != NULL, asym > EMPTY)) ; f = fopen ("temp1.mtx", "r") ; C = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; fclose (f) ; // printf ("got_sparse\n") ; CHOLMOD(free_sparse) (&C, cm) ; save3 = A->xtype ; A->xtype = CHOLMOD_PATTERN ; f = fopen ("temp3.mtx", "w") ; asym = CHOLMOD(write_sparse) (f, A, NULL, "comments.txt", cm) ; A->xtype = save3 ; fclose (f) ; // printf ("write_sparse3, asym: "ID"\n", asym) ; f = fopen ("temp3.mtx", "r") ; C = CHOLMOD(read_sparse2) (f, DTYPE, cm) ; fclose (f) ; // printf ("got_sparse3\n") ; CHOLMOD(free_sparse) (&C, cm) ; for (i = 0 ; i <= 1 ; i++) { f = fopen ("temp2.mtx", "w") ; fprintf (f, "temp2\n") ; fclose (f) ; X = CHOLMOD(ones) (4, 4, CHOLMOD_REAL + DTYPE, cm) ; if (X != NULL) { Xx = X->x ; Xx [0] = (i == 0) ? 1.1e308 : -1.1e308 ; } f = fopen ("temp2.mtx", "w") ; ok = CHOLMOD(write_dense) (f, X, "comments.txt", cm) ; fclose (f) ; f = fopen ("temp2.mtx", "r") ; Y = CHOLMOD(read_dense2) (f, DTYPE, cm) ; fclose (f) ; CHOLMOD(free_dense) (&X, cm) ; CHOLMOD(free_dense) (&Y, cm) ; } //-------------------------------------------------------------------------- // symmetry //-------------------------------------------------------------------------- CHOLMOD(free_work) (cm) ; xmatched = 0 ; pmatched = 0 ; nzoffdiag = 0 ; nz_diag = 0 ; for (option = 0 ; option <= 2 ; option++) { asym = CHOLMOD(symmetry) (A, option, &xmatched, &pmatched, &nzoffdiag, &nz_diag, cm); printf ("symmetry, asym: "ID" matched "ID" "ID" offdiag "ID" diag "ID"\n", asym, xmatched, pmatched, nzoffdiag, nz_diag) ; } //-------------------------------------------------------------------------- // transpose //-------------------------------------------------------------------------- C = CHOLMOD(allocate_sparse) (A->ncol, A->nrow, A->nzmax, TRUE, TRUE, -(A->stype), A->xtype + DTYPE, cm) ; D = CHOLMOD(allocate_sparse) (A->nrow, A->ncol, A->nzmax, TRUE, TRUE, A->stype, A->xtype + DTYPE, cm) ; CHOLMOD(free_work) (cm) ; ok = (C != NULL && D != NULL) ; // C = A' if (ok) { if (A->stype) { ok = CHOLMOD(transpose_sym) (A, 2, NULL, C, cm) ; } else { ok = CHOLMOD(transpose_unsym) (A, 2, NULL, NULL, 0, C, cm) ; } OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; } // D = C' if (ok) { if (A->stype) { ok = CHOLMOD(transpose_sym) (C, 2, NULL, D, cm) ; } else { ok = CHOLMOD(transpose_unsym) (C, 2, NULL, NULL, 0, D, cm) ; } OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; } if (ok) { ok = CHOLMOD(check_sparse) (D, cm) ; OK (ok || cm->status == CHOLMOD_OUT_OF_MEMORY) ; } CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&D, cm) ; //-------------------------------------------------------------------------- // C = A with jumbled triplets //-------------------------------------------------------------------------- S = CHOLMOD(sparse_to_triplet) (A, cm) ; // [ if (S != NULL && nmin > 0 && S->nnz > 0) { // double the number of entries in S nz1 = S->nzmax ; nz2 = 2*nz1 ; ok = CHOLMOD(reallocate_triplet) (nz2, S, cm) ; if (ok) { // add duplicate entries, but keep the matrix the same OK (S->nzmax == nz2) ; Si = S->i ; Sj = S->j ; Sx = S->x ; Sz = S->z ; for (k = nz1 ; k < ((Int) nz2) ; k++) { kk = nrand (k) ; // RAND Si [k] = Si [kk] ; Sj [k] = Sj [kk] ; if (S->xtype == CHOLMOD_REAL) { x = Sx [kk] * (xrand (4.) - 2) ; // RAND Sx [k] = x ; Sx [kk] -= x ; } else if (S->xtype == CHOLMOD_COMPLEX) { x = Sx [2*kk] * (xrand (4.) - 2) ; // RAND Sx [2*k] = x ; Sx [2*kk] -= x ; x = Sx [2*kk+1] * (xrand (4.) - 2) ; // RAND Sx [2*k+1] = x ; Sx [2*kk+1] -= x ; } else { x = Sx [kk] * (xrand (4.) - 2) ; // RAND Sx [k] = x ; Sx [kk] -= x ; x = Sz [kk] * (xrand (4.) - 2) ; // RAND Sz [k] = x ; Sz [kk] -= x ; } } // randomly jumble the entries for (k = 0 ; k < ((Int) (nz2-1)) ; k++) { kk = k + nrand (nz2-k) ; // RAND i = Si [k] ; Si [k] = Si [kk] ; Si [kk] = i ; j = Sj [k] ; Sj [k] = Sj [kk] ; Sj [kk] = j ; if (S->xtype == CHOLMOD_REAL) { x = Sx [k] ; Sx [k] = Sx [kk] ; Sx [kk] = x ; } else if (S->xtype == CHOLMOD_COMPLEX) { x = Sx [2*k] ; Sx [2*k] = Sx [2*kk] ; Sx [2*kk] = x ; x = Sx [2*k+1] ; Sx [2*k+1] = Sx [2*kk+1] ; Sx [2*kk+1] = x ; } else { x = Sx [k] ; Sx [k] = Sx [kk] ; Sx [kk] = x ; x = Sz [k] ; Sz [k] = Sz [kk] ; Sz [kk] = x ; } } S->nnz = nz2 ; } else { OK (S->nzmax == nz1) ; OK (S->nnz == nz1) ; } } C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; // [ Zs = CHOLMOD(spzeros) (nrow, ncol, 1, xtype + DTYPE, cm) ; // [ G = NULL ; F = NULL ; // G=A+0 G = CHOLMOD(add) (A, Zs, one, one, TRUE, TRUE, cm) ; // [ // F = G-C F = CHOLMOD(add) (G, C, one, minusone, TRUE, TRUE, cm) ; // [ r = CHOLMOD(norm_sparse) (F, 1, cm) ; MAXERR (maxerr, r, anorm) ; r = CHOLMOD(norm_sparse) (F, 0, cm) ; CHOLMOD(drop) (0, F, cm) ; rinf = CHOLMOD(norm_sparse) (F, 0, cm) ; if (F != NULL) { printf ("r %g rinf %g\n", r, rinf) ; OK (r == rinf) ; } MAXERR (maxerr, r, anorm) ; MAXERR (maxerr, rinf, anorm) ; // E = F, with change of type and dropping small entries for (stype = -1 ; stype <= 1 ; stype++) { if (stype != 0 && (F != NULL && F->nrow != F->ncol)) { continue ; } for (mode = 0 ; mode <= 1 ; mode++) { E = CHOLMOD(copy) (F, stype, mode, cm) ; // [ CHOLMOD(drop) (1e-16, E, cm) ; r1 = CHOLMOD(norm_sparse) (E, 1, cm) ; rinf = CHOLMOD(norm_sparse) (E, 0, cm) ; if (E != NULL) { if (mode == 0) { // pattern only OK (r1 <= nrow) ; OK (rinf <= ncol) ; } else { MAXERR (maxerr, r1, anorm) ; MAXERR (maxerr, rinf, anorm) ; } } CHOLMOD(free_sparse) (&E, cm) ; // ] } } CHOLMOD(free_sparse) (&F, cm) ; // ] CHOLMOD(free_sparse) (&G, cm) ; // ] Y = CHOLMOD(ones) (nrow, 1, xtype + DTYPE, cm) ; // [ X = CHOLMOD(ones) (ncol, 1, xtype + DTYPE, cm) ; // [ alpha [0] = 0 ; alpha [1] = 0 ; beta [0] = 2 ; beta [1] = 0 ; // Y = 0*A*X + 2*Y CHOLMOD(sdmult) (A, FALSE, alpha, beta, X, Y, cm) ; r = CHOLMOD(norm_dense) (Y, 0, cm) ; if (Y != NULL && X != NULL && A != NULL) { OK ((nrow == 0) ? (r == 0) : (r == 2)) ; } alpha [0] = 1 ; // Y = 1*(0)*X + 2*Y CHOLMOD(sdmult) (Zs, FALSE, alpha, beta, X, Y, cm) ; r = CHOLMOD(norm_dense) (Y, 0, cm) ; if (Y != NULL && X != NULL && A != NULL) { OK ((nrow == 0) ? (r == 0) : (r == 4)) ; } CHOLMOD(free_dense) (&X, cm) ; // ] CHOLMOD(free_dense) (&Y, cm) ; // ] CHOLMOD(free_sparse) (&Zs, cm) ; // ] CHOLMOD(free_sparse) (&C, cm) ; // ] CHOLMOD(free_triplet) (&S, cm) ; // ] //-------------------------------------------------------------------------- // C = P*A*Q in triplet form //-------------------------------------------------------------------------- S = CHOLMOD(sparse_to_triplet) (A, cm) ; P = prand (nrow) ; // RAND CHOLMOD(print_perm) (P, nrow, nrow, "P", cm) ; if (A->stype == 0) { Q = prand (ncol) ; // RAND CHOLMOD(print_perm) (Q, ncol, ncol, "Q", cm) ; } else { // if A is symmetric, and stored in either upper or lower form, then // the following code only works if P = Q Q = P ; } Pinv = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; Qinv = CHOLMOD(malloc) (ncol, sizeof (Int), cm) ; Partition = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; if (Pinv != NULL && Qinv != NULL && P != NULL && Q != NULL && S != NULL) { Si = S->i ; Sj = S->j ; nz = S->nnz ; for (k = 0 ; k < nrow ; k++) { Pinv [P [k]] = k ; } for (k = 0 ; k < ncol ; k++) { Qinv [Q [k]] = k ; } for (k = 0 ; k < nz ; k++) { Si [k] = Pinv [Si [k]] ; } for (k = 0 ; k < nz ; k++) { Sj [k] = Qinv [Sj [k]] ; } } C = CHOLMOD(triplet_to_sparse) (S, 0, cm) ; D = NULL ; E = NULL ; F = NULL ; G = NULL ; //-------------------------------------------------------------------------- // E = P*A*Q in sparse form //-------------------------------------------------------------------------- D = CHOLMOD(copy) (A, 0, 1, cm) ; E = CHOLMOD(submatrix) (D, P, nrow, Q, ncol, TRUE, FALSE, cm) ; CHOLMOD(sort) (E, cm) ; //-------------------------------------------------------------------------- // F = E-G //-------------------------------------------------------------------------- G = CHOLMOD(copy) (C, 0, 1, cm) ; F = CHOLMOD(add) (E, G, one, minusone, TRUE, TRUE, cm) ; CHOLMOD(drop) (0, F, cm) ; nz = CHOLMOD(nnz) (F, cm) ; if (F != NULL) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&F, cm) ; CHOLMOD(free_sparse) (&G, cm) ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&H, cm) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_triplet) (&S, cm) ; //-------------------------------------------------------------------------- // submatrix //-------------------------------------------------------------------------- if (A->stype == 0) { // E = A(:,:) E = CHOLMOD(submatrix) (A, NULL, -1, NULL, -1, TRUE, TRUE, cm) ; // C = A-E C = CHOLMOD(add) (A, E, one, minusone, TRUE, TRUE, cm) ; ok = CHOLMOD(drop) (0., C, cm) ; nz = CHOLMOD(nnz) (C, cm) ; if (C != NULL) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&E, cm) ; } //-------------------------------------------------------------------------- // test band and add, unsymmetric //-------------------------------------------------------------------------- // E = A E = CHOLMOD(copy) (A, 0, 2, cm) ; // E = triu (E) CHOLMOD(band_inplace) (0, ncol, 1, E, cm) ; // F = A F = CHOLMOD(copy) (A, 0, 2, cm) ; // F = tril(F,-1) CHOLMOD(band_inplace) (-nrow, -1, 1, F, cm) ; // G = E+F G = CHOLMOD(add) (E, F, one, one, 2, true, cm) ; // D = A-G, which should be empty D = CHOLMOD(add) (G, A, one, minusone, 2, true, cm) ; CHOLMOD(drop) (0, D, cm) ; nz = CHOLMOD(nnz) (D, cm) ; if (D != NULL) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&F, cm) ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&G, cm) ; D = CHOLMOD(band) (A, 1, -1, 0, cm) ; nz = CHOLMOD(nnz) (D, cm) ; if (D != NULL) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&D, cm) ; D = CHOLMOD(band) (A, 0, 0, 0, cm) ; nz = CHOLMOD(nnz) (D, cm) ; if (D != NULL) { OK (nz == nzdiag (D)) ; } CHOLMOD(free_sparse) (&D, cm) ; //-------------------------------------------------------------------------- // test band, add and copy_sparse (symmetric) //-------------------------------------------------------------------------- if (A->stype != 0) { // r = norm (imag (diag (A))) r = znorm_diag (A, cm) ; if (r == 0) { // this test requires diag(A) to be real // E = A, in symmetric/upper form E = CHOLMOD(copy) (A, 1, 2, cm) ; // Minus1 = -1 cholmod_dense *Minus1 = CHOLMOD(zeros) (1, 1, A->xtype + DTYPE, cm); if (Minus1 != NULL) { ((Real *) (Minus1->x)) [0] = -1 ; } // E = -E CHOLMOD(scale) (Minus1, CHOLMOD_SCALAR, E, cm) ; // F = A, in symmetric/lower form F = CHOLMOD(copy) (A, -1, 2, cm) ; // C = F (exact copy) C = CHOLMOD(copy_sparse) (F, cm) ; // G = E+C G = CHOLMOD(add) (E, C, one, one, 2, false, cm) ; CHOLMOD(sort) (G, cm) ; CHOLMOD(drop) (0, G, cm) ; nz = CHOLMOD(nnz) (G, cm) ; if (G != NULL) { OK (nz == 0) ; } CHOLMOD(free_dense) (&Minus1, cm) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&F, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&G, cm) ; } } //-------------------------------------------------------------------------- // try a dense identity matrix //-------------------------------------------------------------------------- X = CHOLMOD(eye) (3, 4, CHOLMOD_REAL + DTYPE, cm) ; CHOLMOD(free_dense) (&X, cm) ; //-------------------------------------------------------------------------- // bisector and nested_dissection //-------------------------------------------------------------------------- #ifndef NPARTITION if (A != NULL && A->nrow == A->ncol) { int64_t nc, nc_new ; Int cnz, csep, save2 ; Int *Cnw, *Cew, *Cmember, *CParent, *Perm ; double save1 ; // try CHOLMOD's interface to METIS_ComputeVertexSeparator cm->metis_memory = 2.0 ; // CHOLMOD(print_sparse) (A, "A for bisect", cm) ; csep = CHOLMOD(bisect) (A, NULL, 0, TRUE, Partition, cm) ; if (csep != EMPTY) { Int csep2 ; // printf ("csep %g\n", (double) csep) ; csep2 = check_partition (A, Partition) ; // printf ("csep2 %g\n", (double) csep2) ; OK (csep == csep2) ; } // try the raw interface to METIS_ComputeVertexSeparator // CHOLMOD(print_sparse) (A, "A for metis bisect", cm) ; // C = A+A', remove the diagonal AT = CHOLMOD(transpose) (A, 0, cm) ; E = CHOLMOD(add) (A, AT, one, one, FALSE, TRUE, cm) ; CHOLMOD(free_sparse) (&AT, cm) ; C = CHOLMOD(copy) (E, 0, -1, cm) ; // CHOLMOD(print_sparse) (C, "C for metis bisect", cm) ; cnz = (C != NULL) ? (C->nzmax) : 0 ; Cew = CHOLMOD(malloc) (cnz, sizeof (Int), cm) ; Cnw = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; if (Cnw != NULL) { for (j = 0 ; j < (Int) (A->nrow) ; j++) { Cnw [j] = 1 ; } } if (Cew != NULL) { for (j = 0 ; j < cnz ; j++) { Cew [j] = 1 ; } } csep = CHOLMOD(metis_bisector) (C, Cnw, Cew, Partition, cm) ; if (csep != EMPTY) { OK (csep == check_partition (C, Partition)) ; } CHOLMOD(free) (nrow, sizeof (Int), Cnw, cm) ; CHOLMOD(free) (cnz, sizeof (Int), Cew, cm) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&E, cm) ; Cmember = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; CParent = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; Perm = CHOLMOD(malloc) (nrow, sizeof (Int), cm) ; save1 = cm->method [cm->current].nd_small ; save2 = cm->method [cm->current].nd_oksep ; cm->method [cm->current].nd_small = 1 ; cm->method [cm->current].nd_oksep = 1.0 ; nc = CHOLMOD(nested_dissection) (A, NULL, 0, Perm, CParent, Cmember, cm); if (nc > 0) { OK (CHOLMOD(check_perm) (Perm, n, n, cm)) ; } CHOLMOD(free_work) (cm) ; // collapse the septree if (nc > 0 && n > 0) { nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, CParent, Cmember, cm) ; // error checks save = cm->error_handler ; cm->error_handler = NULL ; nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, CParent, Cmember, NULL) ; OK (nc_new == EMPTY) ; nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, NULL, Cmember, cm) ; OK (nc_new == EMPTY) ; nc_new = CHOLMOD(collapse_septree) (n, nc, 0.1, 400, CParent, NULL, cm) ; OK (nc_new == EMPTY) ; nc_new = CHOLMOD(collapse_septree) (0, 1, 0.1, 400, CParent, Cmember, cm) ; OK (nc_new == EMPTY) ; nc_new = CHOLMOD(collapse_septree) (1, 1, 0.1, 400, CParent, Cmember, cm) ; OK (nc_new == 1 || nc_new == EMPTY) ; nc_new = CHOLMOD(collapse_septree) (SIZE_MAX, SIZE_MAX, 0.1, 400, CParent, Cmember, cm) ; OK (nc_new == EMPTY) ; cm->error_handler = save ; } CHOLMOD(free) (nrow, sizeof (Int), Cmember, cm) ; CHOLMOD(free) (nrow, sizeof (Int), CParent, cm) ; CHOLMOD(free) (nrow, sizeof (Int), Perm, cm) ; cm->method [cm->current].nd_small = save1 ; cm->method [cm->current].nd_oksep = save2 ; } #endif //-------------------------------------------------------------------------- // dense to/from sparse conversions //-------------------------------------------------------------------------- // convert A to real, remove zero entries, and then convert to pattern if (MAX (nrow, ncol) < 1000) { C = CHOLMOD(copy_sparse) (A, cm) ; CHOLMOD(sparse_xtype) (CHOLMOD_REAL + DTYPE, C, cm) ; CHOLMOD(drop) (0., C, cm) ; D = CHOLMOD(copy) (C, 0, 0, cm) ; CHOLMOD(sort) (D, cm) ; // X = dense copy of C CHOLMOD(sparse_xtype) (CHOLMOD_PATTERN + DTYPE, C, cm) ; X = CHOLMOD(sparse_to_dense) (C, cm) ; CHOLMOD(free_sparse) (&C, cm) ; // change X to sparse pattern and then real/complex/zomplex, it should // equal D for (xtype2 = CHOLMOD_REAL ; xtype2 <= CHOLMOD_ZOMPLEX ; xtype2++) { E = CHOLMOD(dense_to_sparse) (X, FALSE, cm) ; ok = CHOLMOD(sparse_xtype) (xtype2 + DTYPE, E, cm) ; ok = CHOLMOD(sparse_xtype) (xtype2 + DTYPE, D, cm) ; if (xtype2 == CHOLMOD_REAL) { F = CHOLMOD(add) (E, D, one, minusone, TRUE, TRUE, cm) ; r = CHOLMOD(norm_sparse) (F, 0, cm) ; if (F != NULL && cm->status == CHOLMOD_OK) { if (r != 0) { printf ("r %g at %d:%s\n", r, __LINE__, __FILE__) ; } OK (r == 0) ; } CHOLMOD(free_sparse) (&F, cm) ; } else { check_equality (E, D, xtype2) ; } CHOLMOD(free_sparse) (&E, cm) ; } CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_dense) (&X, cm) ; } //-------------------------------------------------------------------------- // unsymmetric transpose //-------------------------------------------------------------------------- len = ncol/2 ; fset = prand (ncol) ; // RAND CHOLMOD(print_perm) (fset, ncol, ncol, "fset", cm) ; C = CHOLMOD(copy) (A, 0, 2, cm) ; D = CHOLMOD(ptranspose) (C, 2, P, fset, len, cm) ; E = CHOLMOD(transpose) (D, 1, cm) ; F = CHOLMOD(transpose) (E, 1, cm) ; G = CHOLMOD(add) (D, F, one, minusone, TRUE, FALSE, cm) ; r = CHOLMOD(norm_sparse) (G, 0, cm) ; if (G != NULL && cm->status == CHOLMOD_OK) { OK (r == 0) ; } CHOLMOD(drop) (0, G, cm) ; r = CHOLMOD(norm_sparse) (G, 0, cm) ; if (G != NULL && cm->status == CHOLMOD_OK) { OK (r == 0) ; } nz = CHOLMOD(nnz) (G, cm) ; if (G != NULL && cm->status == CHOLMOD_OK) { OK (nz == 0) ; } CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&F, cm) ; CHOLMOD(free_sparse) (&G, cm) ; //-------------------------------------------------------------------------- // symmetric array transpose //-------------------------------------------------------------------------- if (A->stype != 0) { // C = A(p,p).' C = CHOLMOD(ptranspose) (A, 1, P, NULL, 0, cm) ; // D = C(pinv,pinv).' D = CHOLMOD(ptranspose) (C, 1, Pinv, NULL, 0, cm) ; CHOLMOD(sort) (D, cm) ; CHOLMOD(free_sparse) (&C, cm) ; // C = A, sorted C = CHOLMOD(copy_sparse) (A, cm) ; CHOLMOD(sort) (C, cm) ; int cstype = (C == NULL) ? 0 : C->stype ; E = CHOLMOD(copy) (C, cstype, 1, cm) ; F = CHOLMOD(copy) (D, cstype, 1, cm) ; // C and D should be equal check_equality (E, F, xtype) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&F, cm) ; // C = A.' C = CHOLMOD(transpose) (A, 1, cm) ; // D = C.' D = CHOLMOD(transpose) (C, 1, cm) ; CHOLMOD(sort) (D, cm) ; CHOLMOD(free_sparse) (&C, cm) ; // C = A, sorted C = CHOLMOD(copy_sparse) (A, cm) ; CHOLMOD(sort) (C, cm) ; cstype = (C == NULL) ? 0 : C->stype ; E = CHOLMOD(copy) (C, cstype, 1, cm) ; F = CHOLMOD(copy) (D, cstype, 1, cm) ; // C and D should be equal check_equality (E, F, xtype) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&F, cm) ; } //-------------------------------------------------------------------------- // matrix multiply //-------------------------------------------------------------------------- // this fails for a large arrowhead matrix, so turn off error hanlder save = cm->error_handler ; cm->error_handler = NULL ; AT = CHOLMOD(transpose) (A, 2, cm) ; D = CHOLMOD(copy) (A, 0, 2, cm) ; if (n > NLARGE) progress (1, '.') ; C = CHOLMOD(aat) (D, NULL, 0, 2, cm) ; if (n > NLARGE) progress (1, '.') ; for (stype = -1 ; stype <= 1 ; stype++) { if (n > NLARGE) progress (1, '.') ; E = CHOLMOD(ssmult) (A, AT, stype, 2, false, cm) ; if (n > NLARGE) progress (1, '.') ; G = CHOLMOD(add) (C, E, one, minusone, 2, false, cm) ; if (n > NLARGE) progress (1, '.') ; r = CHOLMOD(norm_sparse) (G, 0, cm) ; if (G != NULL) { MAXERR (maxerr, r, anorm) ; } CHOLMOD(drop) (0, G, cm) ; r = CHOLMOD(norm_sparse) (G, 0, cm) ; if (G != NULL) { MAXERR (maxerr, r, anorm) ; } CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&G, cm) ; } if (nrow == ncol) { // E = pattern of A E = CHOLMOD(copy) (A, 0, 0, cm) ; // G = E*E if (n > NLARGE) progress (1, '.') ; G = CHOLMOD(ssmult) (E, E, 0, FALSE, FALSE, cm) ; if (n > NLARGE) progress (1, '.') ; CHOLMOD(free_sparse) (&E, cm) ; CHOLMOD(free_sparse) (&G, cm) ; } cm->error_handler = save ; CHOLMOD(free_sparse) (&D, cm) ; CHOLMOD(free_sparse) (&C, cm) ; CHOLMOD(free_sparse) (&AT, cm) ; //-------------------------------------------------------------------------- // free P, Q, and their inverses //-------------------------------------------------------------------------- CHOLMOD(free) (ncol, sizeof (Int), fset, cm) ; CHOLMOD(free) (nrow, sizeof (Int), P, cm) ; CHOLMOD(free) (nrow, sizeof (Int), Pinv, cm) ; if (A->stype == 0) { CHOLMOD(free) (ncol, sizeof (Int), Q, cm) ; } CHOLMOD(free) (ncol, sizeof (Int), Qinv, cm) ; CHOLMOD(free) (nrow, sizeof (Int), Partition, cm) ; progress (0, '.') ; return (maxerr) ; }