/** \file opennl/superlu/mmd.c * \ingroup opennl */ typedef int shortint; /* prototypes -------------------- */ int genmmd_(int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *, int *); int mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *); int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *); int mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *); int mmdnum_(int *, shortint *, shortint *, shortint *); /* *************************************************************** */ /* *************************************************************** */ /* **** GENMMD ..... MULTIPLE MINIMUM EXTERNAL DEGREE **** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE IMPLEMENTS THE MINIMUM DEGREE */ /* ALGORITHM. IT MAKES USE OF THE IMPLICIT REPRESENTATION */ /* OF ELIMINATION GRAPHS BY QUOTIENT GRAPHS, AND THE */ /* NOTION OF INDISTINGUISHABLE NODES. IT ALSO IMPLEMENTS */ /* THE MODIFICATIONS BY MULTIPLE ELIMINATION AND MINIMUM */ /* EXTERNAL DEGREE. */ /* --------------------------------------------- */ /* CAUTION - THE ADJACENCY VECTOR ADJNCY WILL BE */ /* DESTROYED. */ /* --------------------------------------------- */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - THE ADJACENCY STRUCTURE. */ /* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ /* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) INTEGER */ /* (ANY SMALLER ESTIMATE WILL DO) FOR MARKING */ /* NODES. */ /* OUTPUT PARAMETERS - */ /* PERM - THE MINIMUM DEGREE ORDERING. */ /* INVP - THE INVERSE OF PERM. */ /* NOFSUB - AN UPPER BOUND ON THE NUMBER OF NONZERO */ /* SUBSCRIPTS FOR THE COMPRESSED STORAGE SCHEME. */ /* WORKING PARAMETERS - */ /* DHEAD - VECTOR FOR HEAD OF DEGREE LISTS. */ /* INVP - USED TEMPORARILY FOR DEGREE FORWARD LINK. */ /* PERM - USED TEMPORARILY FOR DEGREE BACKWARD LINK. */ /* QSIZE - VECTOR FOR SIZE OF SUPERNODES. */ /* LLIST - VECTOR FOR TEMPORARY LINKED LISTS. */ /* MARKER - A TEMPORARY MARKER VECTOR. */ /* PROGRAM SUBROUTINES - */ /* MMDELM, MMDINT, MMDNUM, MMDUPD. */ /* *************************************************************** */ /* Subroutine */ int genmmd_(int *neqns, int *xadj, shortint *adjncy, shortint *invp, shortint *perm, int *delta, shortint *dhead, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *nofsub) { /* System generated locals */ int i__1; /* Local variables */ static int mdeg, ehead, i, mdlmt, mdnode; extern /* Subroutine */ int mmdelm_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *), mmdupd_(int *, int *, int *, shortint *, int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, int *, int *), mmdint_(int *, int *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *, shortint *), mmdnum_(int *, shortint *, shortint *, shortint *); static int nextmd, tag, num; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dhead; --perm; --invp; --adjncy; --xadj; /* Function Body */ if (*neqns <= 0) { return 0; } /* ------------------------------------------------ */ /* INITIALIZATION FOR THE MINIMUM DEGREE ALGORITHM. */ /* ------------------------------------------------ */ *nofsub = 0; mmdint_(neqns, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & qsize[1], &llist[1], &marker[1]); /* ---------------------------------------------- */ /* NUM COUNTS THE NUMBER OF ORDERED NODES PLUS 1. */ /* ---------------------------------------------- */ num = 1; /* ----------------------------- */ /* ELIMINATE ALL ISOLATED NODES. */ /* ----------------------------- */ nextmd = dhead[1]; L100: if (nextmd <= 0) { goto L200; } mdnode = nextmd; nextmd = invp[mdnode]; marker[mdnode] = *maxint; invp[mdnode] = -num; ++num; goto L100; L200: /* ---------------------------------------- */ /* SEARCH FOR NODE OF THE MINIMUM DEGREE. */ /* MDEG IS THE CURRENT MINIMUM DEGREE; */ /* TAG IS USED TO FACILITATE MARKING NODES. */ /* ---------------------------------------- */ if (num > *neqns) { goto L1000; } tag = 1; dhead[1] = 0; mdeg = 2; L300: if (dhead[mdeg] > 0) { goto L400; } ++mdeg; goto L300; L400: /* ------------------------------------------------- */ /* USE VALUE OF DELTA TO SET UP MDLMT, WHICH GOVERNS */ /* WHEN A DEGREE UPDATE IS TO BE PERFORMED. */ /* ------------------------------------------------- */ mdlmt = mdeg + *delta; ehead = 0; L500: mdnode = dhead[mdeg]; if (mdnode > 0) { goto L600; } ++mdeg; if (mdeg > mdlmt) { goto L900; } goto L500; L600: /* ---------------------------------------- */ /* REMOVE MDNODE FROM THE DEGREE STRUCTURE. */ /* ---------------------------------------- */ nextmd = invp[mdnode]; dhead[mdeg] = nextmd; if (nextmd > 0) { perm[nextmd] = -mdeg; } invp[mdnode] = -num; *nofsub = *nofsub + mdeg + qsize[mdnode] - 2; if (num + qsize[mdnode] > *neqns) { goto L1000; } /* ---------------------------------------------- */ /* ELIMINATE MDNODE AND PERFORM QUOTIENT GRAPH */ /* TRANSFORMATION. RESET TAG VALUE IF NECESSARY. */ /* ---------------------------------------------- */ ++tag; if (tag < *maxint) { goto L800; } tag = 1; i__1 = *neqns; for (i = 1; i <= i__1; ++i) { if (marker[i] < *maxint) { marker[i] = 0; } /* L700: */ } L800: mmdelm_(&mdnode, &xadj[1], &adjncy[1], &dhead[1], &invp[1], &perm[1], & qsize[1], &llist[1], &marker[1], maxint, &tag); num += qsize[mdnode]; llist[mdnode] = ehead; ehead = mdnode; if (*delta >= 0) { goto L500; } L900: /* ------------------------------------------- */ /* UPDATE DEGREES OF THE NODES INVOLVED IN THE */ /* MINIMUM DEGREE NODES ELIMINATION. */ /* ------------------------------------------- */ if (num > *neqns) { goto L1000; } mmdupd_(&ehead, neqns, &xadj[1], &adjncy[1], delta, &mdeg, &dhead[1], & invp[1], &perm[1], &qsize[1], &llist[1], &marker[1], maxint, &tag) ; goto L300; L1000: mmdnum_(neqns, &perm[1], &invp[1], &qsize[1]); return 0; } /* genmmd_ */ /* *************************************************************** */ /* *************************************************************** */ /* *** MMDINT ..... MULT MINIMUM DEGREE INITIALIZATION *** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE PERFORMS INITIALIZATION FOR THE */ /* MULTIPLE ELIMINATION VERSION OF THE MINIMUM DEGREE */ /* ALGORITHM. */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ /* OUTPUT PARAMETERS - */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE (INITIALIZED TO ONE). */ /* LLIST - LINKED LIST. */ /* MARKER - MARKER VECTOR. */ /* *************************************************************** */ /* Subroutine */ int mmdint_(int *neqns, int *xadj, shortint *adjncy, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker) { /* System generated locals */ int i__1; /* Local variables */ static int ndeg, node, fnode; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { dhead[node] = 0; qsize[node] = 1; marker[node] = 0; llist[node] = 0; /* L100: */ } /* ------------------------------------------ */ /* INITIALIZE THE DEGREE DOUBLY LINKED LISTS. */ /* ------------------------------------------ */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { ndeg = xadj[node + 1] - xadj[node] + 1; fnode = dhead[ndeg]; dforw[node] = fnode; dhead[ndeg] = node; if (fnode > 0) { dbakw[fnode] = node; } dbakw[node] = -ndeg; /* L200: */ } return 0; } /* mmdint_ */ /* *************************************************************** */ /* *************************************************************** */ /* ** MMDELM ..... MULTIPLE MINIMUM DEGREE ELIMINATION *** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE ELIMINATES THE NODE MDNODE OF */ /* MINIMUM DEGREE FROM THE ADJACENCY STRUCTURE, WHICH */ /* IS STORED IN THE QUOTIENT GRAPH FORMAT. IT ALSO */ /* TRANSFORMS THE QUOTIENT GRAPH REPRESENTATION OF THE */ /* ELIMINATION GRAPH. */ /* INPUT PARAMETERS - */ /* MDNODE - NODE OF MINIMUM DEGREE. */ /* MAXINT - ESTIMATE OF MAXIMUM REPRESENTABLE (SHORT) */ /* INT. */ /* TAG - TAG VALUE. */ /* UPDATED PARAMETERS - */ /* (XADJ,ADJNCY) - UPDATED ADJACENCY STRUCTURE. */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE. */ /* MARKER - MARKER VECTOR. */ /* LLIST - TEMPORARY LINKED LIST OF ELIMINATED NABORS. */ /* *************************************************************** */ /* Subroutine */ int mmdelm_(int *mdnode, int *xadj, shortint *adjncy, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *tag) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int node, link, rloc, rlmt, i, j, nabor, rnode, elmnt, xqnbr, istop, jstop, istrt, jstrt, nxnode, pvnode, nqnbrs, npv; /* *************************************************************** */ /* *************************************************************** */ /* ----------------------------------------------- */ /* FIND REACHABLE SET AND PLACE IN DATA STRUCTURE. */ /* ----------------------------------------------- */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ marker[*mdnode] = *tag; istrt = xadj[*mdnode]; istop = xadj[*mdnode + 1] - 1; /* ------------------------------------------------------- */ /* ELMNT POINTS TO THE BEGINNING OF THE LIST OF ELIMINATED */ /* NABORS OF MDNODE, AND RLOC GIVES THE STORAGE LOCATION */ /* FOR THE NEXT REACHABLE NODE. */ /* ------------------------------------------------------- */ elmnt = 0; rloc = istrt; rlmt = istop; i__1 = istop; for (i = istrt; i <= i__1; ++i) { nabor = adjncy[i]; if (nabor == 0) { goto L300; } if (marker[nabor] >= *tag) { goto L200; } marker[nabor] = *tag; if (dforw[nabor] < 0) { goto L100; } adjncy[rloc] = nabor; ++rloc; goto L200; L100: llist[nabor] = elmnt; elmnt = nabor; L200: ; } L300: /* ----------------------------------------------------- */ /* MERGE WITH REACHABLE NODES FROM GENERALIZED ELEMENTS. */ /* ----------------------------------------------------- */ if (elmnt <= 0) { goto L1000; } adjncy[rlmt] = -elmnt; link = elmnt; L400: jstrt = xadj[link]; jstop = xadj[link + 1] - 1; i__1 = jstop; for (j = jstrt; j <= i__1; ++j) { node = adjncy[j]; link = -node; if (node < 0) { goto L400; } else if (node == 0) { goto L900; } else { goto L500; } L500: if (marker[node] >= *tag || dforw[node] < 0) { goto L800; } marker[node] = *tag; /* --------------------------------- */ /* USE STORAGE FROM ELIMINATED NODES */ /* IF NECESSARY. */ /* --------------------------------- */ L600: if (rloc < rlmt) { goto L700; } link = -adjncy[rlmt]; rloc = xadj[link]; rlmt = xadj[link + 1] - 1; goto L600; L700: adjncy[rloc] = node; ++rloc; L800: ; } L900: elmnt = llist[elmnt]; goto L300; L1000: if (rloc <= rlmt) { adjncy[rloc] = 0; } /* -------------------------------------------------------- */ /* FOR EACH NODE IN THE REACHABLE SET, DO THE FOLLOWING ... */ /* -------------------------------------------------------- */ link = *mdnode; L1100: istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { rnode = adjncy[i]; link = -rnode; if (rnode < 0) { goto L1100; } else if (rnode == 0) { goto L1800; } else { goto L1200; } L1200: /* -------------------------------------------- */ /* IF RNODE IS IN THE DEGREE LIST STRUCTURE ... */ /* -------------------------------------------- */ pvnode = dbakw[rnode]; if (pvnode == 0 || pvnode == -(*maxint)) { goto L1300; } /* ------------------------------------- */ /* THEN REMOVE RNODE FROM THE STRUCTURE. */ /* ------------------------------------- */ nxnode = dforw[rnode]; if (nxnode > 0) { dbakw[nxnode] = pvnode; } if (pvnode > 0) { dforw[pvnode] = nxnode; } npv = -pvnode; if (pvnode < 0) { dhead[npv] = nxnode; } L1300: /* ---------------------------------------- */ /* PURGE INACTIVE QUOTIENT NABORS OF RNODE. */ /* ---------------------------------------- */ jstrt = xadj[rnode]; jstop = xadj[rnode + 1] - 1; xqnbr = jstrt; i__2 = jstop; for (j = jstrt; j <= i__2; ++j) { nabor = adjncy[j]; if (nabor == 0) { goto L1500; } if (marker[nabor] >= *tag) { goto L1400; } adjncy[xqnbr] = nabor; ++xqnbr; L1400: ; } L1500: /* ---------------------------------------- */ /* IF NO ACTIVE NABOR AFTER THE PURGING ... */ /* ---------------------------------------- */ nqnbrs = xqnbr - jstrt; if (nqnbrs > 0) { goto L1600; } /* ----------------------------- */ /* THEN MERGE RNODE WITH MDNODE. */ /* ----------------------------- */ qsize[*mdnode] += qsize[rnode]; qsize[rnode] = 0; marker[rnode] = *maxint; dforw[rnode] = -(*mdnode); dbakw[rnode] = -(*maxint); goto L1700; L1600: /* -------------------------------------- */ /* ELSE FLAG RNODE FOR DEGREE UPDATE, AND */ /* ADD MDNODE AS A NABOR OF RNODE. */ /* -------------------------------------- */ dforw[rnode] = nqnbrs + 1; dbakw[rnode] = 0; adjncy[xqnbr] = *mdnode; ++xqnbr; if (xqnbr <= jstop) { adjncy[xqnbr] = 0; } L1700: ; } L1800: return 0; } /* mmdelm_ */ /* *************************************************************** */ /* *************************************************************** */ /* ***** MMDUPD ..... MULTIPLE MINIMUM DEGREE UPDATE ***** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE UPDATES THE DEGREES OF NODES */ /* AFTER A MULTIPLE ELIMINATION STEP. */ /* INPUT PARAMETERS - */ /* EHEAD - THE BEGINNING OF THE LIST OF ELIMINATED */ /* NODES (I.E., NEWLY FORMED ELEMENTS). */ /* NEQNS - NUMBER OF EQUATIONS. */ /* (XADJ,ADJNCY) - ADJACENCY STRUCTURE. */ /* DELTA - TOLERANCE VALUE FOR MULTIPLE ELIMINATION. */ /* MAXINT - MAXIMUM MACHINE REPRESENTABLE (SHORT) */ /* INTEGER. */ /* UPDATED PARAMETERS - */ /* MDEG - NEW MINIMUM DEGREE AFTER DEGREE UPDATE. */ /* (DHEAD,DFORW,DBAKW) - DEGREE DOUBLY LINKED STRUCTURE. */ /* QSIZE - SIZE OF SUPERNODE. */ /* LLIST - WORKING LINKED LIST. */ /* MARKER - MARKER VECTOR FOR DEGREE UPDATE. */ /* TAG - TAG VALUE. */ /* *************************************************************** */ /* Subroutine */ int mmdupd_(int *ehead, int *neqns, int *xadj, shortint *adjncy, int *delta, int *mdeg, shortint *dhead, shortint *dforw, shortint *dbakw, shortint *qsize, shortint *llist, shortint *marker, int *maxint, int *tag) { /* System generated locals */ int i__1, i__2; /* Local variables */ static int node, mtag, link, mdeg0, i, j, enode, fnode, nabor, elmnt, istop, jstop, q2head, istrt, jstrt, qxhead, iq2, deg, deg0; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --marker; --llist; --qsize; --dbakw; --dforw; --dhead; --adjncy; --xadj; /* Function Body */ mdeg0 = *mdeg + *delta; elmnt = *ehead; L100: /* ------------------------------------------------------- */ /* FOR EACH OF THE NEWLY FORMED ELEMENT, DO THE FOLLOWING. */ /* (RESET TAG VALUE IF NECESSARY.) */ /* ------------------------------------------------------- */ if (elmnt <= 0) { return 0; } mtag = *tag + mdeg0; if (mtag < *maxint) { goto L300; } *tag = 1; i__1 = *neqns; for (i = 1; i <= i__1; ++i) { if (marker[i] < *maxint) { marker[i] = 0; } /* L200: */ } mtag = *tag + mdeg0; L300: /* --------------------------------------------- */ /* CREATE TWO LINKED LISTS FROM NODES ASSOCIATED */ /* WITH ELMNT: ONE WITH TWO NABORS (Q2HEAD) IN */ /* ADJACENCY STRUCTURE, AND THE OTHER WITH MORE */ /* THAN TWO NABORS (QXHEAD). ALSO COMPUTE DEG0, */ /* NUMBER OF NODES IN THIS ELEMENT. */ /* --------------------------------------------- */ q2head = 0; qxhead = 0; deg0 = 0; link = elmnt; L400: istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { enode = adjncy[i]; link = -enode; if (enode < 0) { goto L400; } else if (enode == 0) { goto L800; } else { goto L500; } L500: if (qsize[enode] == 0) { goto L700; } deg0 += qsize[enode]; marker[enode] = mtag; /* ---------------------------------- */ /* IF ENODE REQUIRES A DEGREE UPDATE, */ /* THEN DO THE FOLLOWING. */ /* ---------------------------------- */ if (dbakw[enode] != 0) { goto L700; } /* --------------------------------------- */ /* PLACE EITHER IN QXHEAD OR Q2HEAD LISTS. */ /* --------------------------------------- */ if (dforw[enode] == 2) { goto L600; } llist[enode] = qxhead; qxhead = enode; goto L700; L600: llist[enode] = q2head; q2head = enode; L700: ; } L800: /* -------------------------------------------- */ /* FOR EACH ENODE IN Q2 LIST, DO THE FOLLOWING. */ /* -------------------------------------------- */ enode = q2head; iq2 = 1; L900: if (enode <= 0) { goto L1500; } if (dbakw[enode] != 0) { goto L2200; } ++(*tag); deg = deg0; /* ------------------------------------------ */ /* IDENTIFY THE OTHER ADJACENT ELEMENT NABOR. */ /* ------------------------------------------ */ istrt = xadj[enode]; nabor = adjncy[istrt]; if (nabor == elmnt) { nabor = adjncy[istrt + 1]; } /* ------------------------------------------------ */ /* IF NABOR IS UNELIMINATED, INCREASE DEGREE COUNT. */ /* ------------------------------------------------ */ link = nabor; if (dforw[nabor] < 0) { goto L1000; } deg += qsize[nabor]; goto L2100; L1000: /* -------------------------------------------- */ /* OTHERWISE, FOR EACH NODE IN THE 2ND ELEMENT, */ /* DO THE FOLLOWING. */ /* -------------------------------------------- */ istrt = xadj[link]; istop = xadj[link + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { node = adjncy[i]; link = -node; if (node == enode) { goto L1400; } if (node < 0) { goto L1000; } else if (node == 0) { goto L2100; } else { goto L1100; } L1100: if (qsize[node] == 0) { goto L1400; } if (marker[node] >= *tag) { goto L1200; } /* ----------------------------------- -- */ /* CASE WHEN NODE IS NOT YET CONSIDERED . */ /* ----------------------------------- -- */ marker[node] = *tag; deg += qsize[node]; goto L1400; L1200: /* ---------------------------------------- */ /* CASE WHEN NODE IS INDISTINGUISHABLE FROM */ /* ENODE. MERGE THEM INTO A NEW SUPERNODE. */ /* ---------------------------------------- */ if (dbakw[node] != 0) { goto L1400; } if (dforw[node] != 2) { goto L1300; } qsize[enode] += qsize[node]; qsize[node] = 0; marker[node] = *maxint; dforw[node] = -enode; dbakw[node] = -(*maxint); goto L1400; L1300: /* -------------------------------------- */ /* CASE WHEN NODE IS OUTMATCHED BY ENODE. */ /* -------------------------------------- */ if (dbakw[node] == 0) { dbakw[node] = -(*maxint); } L1400: ; } goto L2100; L1500: /* ------------------------------------------------ */ /* FOR EACH ENODE IN THE QX LIST, DO THE FOLLOWING. */ /* ------------------------------------------------ */ enode = qxhead; iq2 = 0; L1600: if (enode <= 0) { goto L2300; } if (dbakw[enode] != 0) { goto L2200; } ++(*tag); deg = deg0; /* --------------------------------- */ /* FOR EACH UNMARKED NABOR OF ENODE, */ /* DO THE FOLLOWING. */ /* --------------------------------- */ istrt = xadj[enode]; istop = xadj[enode + 1] - 1; i__1 = istop; for (i = istrt; i <= i__1; ++i) { nabor = adjncy[i]; if (nabor == 0) { goto L2100; } if (marker[nabor] >= *tag) { goto L2000; } marker[nabor] = *tag; link = nabor; /* ------------------------------ */ /* IF UNELIMINATED, INCLUDE IT IN */ /* DEG COUNT. */ /* ------------------------------ */ if (dforw[nabor] < 0) { goto L1700; } deg += qsize[nabor]; goto L2000; L1700: /* ------------------------------- */ /* IF ELIMINATED, INCLUDE UNMARKED */ /* NODES IN THIS ELEMENT INTO THE */ /* DEGREE COUNT. */ /* ------------------------------- */ jstrt = xadj[link]; jstop = xadj[link + 1] - 1; i__2 = jstop; for (j = jstrt; j <= i__2; ++j) { node = adjncy[j]; link = -node; if (node < 0) { goto L1700; } else if (node == 0) { goto L2000; } else { goto L1800; } L1800: if (marker[node] >= *tag) { goto L1900; } marker[node] = *tag; deg += qsize[node]; L1900: ; } L2000: ; } L2100: /* ------------------------------------------- */ /* UPDATE EXTERNAL DEGREE OF ENODE IN DEGREE */ /* STRUCTURE, AND MDEG (MIN DEG) IF NECESSARY. */ /* ------------------------------------------- */ deg = deg - qsize[enode] + 1; fnode = dhead[deg]; dforw[enode] = fnode; dbakw[enode] = -deg; if (fnode > 0) { dbakw[fnode] = enode; } dhead[deg] = enode; if (deg < *mdeg) { *mdeg = deg; } L2200: /* ---------------------------------- */ /* GET NEXT ENODE IN CURRENT ELEMENT. */ /* ---------------------------------- */ enode = llist[enode]; if (iq2 == 1) { goto L900; } goto L1600; L2300: /* ----------------------------- */ /* GET NEXT ELEMENT IN THE LIST. */ /* ----------------------------- */ *tag = mtag; elmnt = llist[elmnt]; goto L100; } /* mmdupd_ */ /* *************************************************************** */ /* *************************************************************** */ /* ***** MMDNUM ..... MULTI MINIMUM DEGREE NUMBERING ***** */ /* *************************************************************** */ /* *************************************************************** */ /* AUTHOR - JOSEPH W.H. LIU */ /* DEPT OF COMPUTER SCIENCE, YORK UNIVERSITY. */ /* PURPOSE - THIS ROUTINE PERFORMS THE FINAL STEP IN */ /* PRODUCING THE PERMUTATION AND INVERSE PERMUTATION */ /* VECTORS IN THE MULTIPLE ELIMINATION VERSION OF THE */ /* MINIMUM DEGREE ORDERING ALGORITHM. */ /* INPUT PARAMETERS - */ /* NEQNS - NUMBER OF EQUATIONS. */ /* QSIZE - SIZE OF SUPERNODES AT ELIMINATION. */ /* UPDATED PARAMETERS - */ /* INVP - INVERSE PERMUTATION VECTOR. ON INPUT, */ /* IF QSIZE(NODE)=0, THEN NODE HAS BEEN MERGED */ /* INTO THE NODE -INVP(NODE); OTHERWISE, */ /* -INVP(NODE) IS ITS INVERSE LABELLING. */ /* OUTPUT PARAMETERS - */ /* PERM - THE PERMUTATION VECTOR. */ /* *************************************************************** */ /* Subroutine */ int mmdnum_(int *neqns, shortint *perm, shortint *invp, shortint *qsize) { /* System generated locals */ int i__1; /* Local variables */ static int node, root, nextf, father, nqsize, num; /* *************************************************************** */ /* *************************************************************** */ /* Parameter adjustments */ --qsize; --invp; --perm; /* Function Body */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { nqsize = qsize[node]; if (nqsize <= 0) { perm[node] = invp[node]; } if (nqsize > 0) { perm[node] = -invp[node]; } /* L100: */ } /* ------------------------------------------------------ */ /* FOR EACH NODE WHICH HAS BEEN MERGED, DO THE FOLLOWING. */ /* ------------------------------------------------------ */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { if (perm[node] > 0) { goto L500; } /* ----------------------------------------- */ /* TRACE THE MERGED TREE UNTIL ONE WHICH HAS */ /* NOT BEEN MERGED, CALL IT ROOT. */ /* ----------------------------------------- */ father = node; L200: if (perm[father] > 0) { goto L300; } father = -perm[father]; goto L200; L300: /* ----------------------- */ /* NUMBER NODE AFTER ROOT. */ /* ----------------------- */ root = father; num = perm[root] + 1; invp[node] = -num; perm[root] = num; /* ------------------------ */ /* SHORTEN THE MERGED TREE. */ /* ------------------------ */ father = node; L400: nextf = -perm[father]; if (nextf <= 0) { goto L500; } perm[father] = -root; father = nextf; goto L400; L500: ; } /* ---------------------- */ /* READY TO COMPUTE PERM. */ /* ---------------------- */ i__1 = *neqns; for (node = 1; node <= i__1; ++node) { num = -invp[node]; invp[node] = num; perm[num] = node; /* L600: */ } return 0; } /* mmdnum_ */