OpenRadioss 2025.1.11
OpenRadioss project
Loading...
Searching...
No Matches
ana_orderings.F
Go to the documentation of this file.
1C =========================================================
2C
3C This file includes various modifications of an original
4C routine MUMPS_ANA_H. The main reference for the approach
5C used in this routine is
6C Patrick Amestoy, Timothy A. Davis, and Iain S. Duff,
7C "An approximate minimum degree ordering algorithm,"
8C SIAM J. Matrix Analysis vol 17, pages=886--905 (1996)
9C MUMPS_ANA_H is based on the original AMD code:
10C
11C AMD, Copyright (c), 1996-2016, Timothy A. Davis,
12C Patrick R. Amestoy, and Iain S. Duff. All Rights Reserved.
13C Used in MUMPS under the BSD 3-clause license.
14C
15C All other routines are modifications of this original routine
16C done by MUMPS developers over the years (1996-2020) and are
17C used in MUMPS under the BSD 3-clause license.
18C
19C BSD 3-clause licence:
20C Redistribution and use in source and binary forms, with or without
21C modification, are permitted provided that the following conditions
22C are met:
23C * Redistributions of source code must retain the above copyright
24C notice, this list of conditions and the following disclaimer.
25C * Redistributions in binary form must reproduce the above
26C copyright notice, this list of conditions and the following
27C disclaimer in the documentation and/or other materials provided
28C with the distribution.
29C * Neither the name of the University of California, Berkeley nor
30C the names of its contributors may be used to endorse or promote
31C products derived from this software without specific prior
32C written permission.
33C THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
34C CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
35C INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
36C MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
37C DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
38C CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
39C SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
40C NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
41C LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42C HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
43C CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
44C OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
45C EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
46C
47C MUMPS_AMD_ELT is a modification
48C designed to handle amalgamated and compressed
49C graphs and was developed in 1999 by Patrick Amestoy
50C in the context of the PARASOL project (1997-1999).
51C
52C MUMPS_HAMD is a modification
53C designed to take into account a halo in the graph.
54C The graph is composed is partitioned in two types of nodes
55C the so called internal nodes and the so called halo nodes.
56C Halo nodes cannot be selected the both the initial degrees
57C and updated degrees of internal node should be taken
58C into account.
59C This routine also referred to as HALOAMD in MUMPS comments
60C is used for both Schur functionality and in the coupling with
61C partitioners such as SCOTCH.
62C This code was developed for MUMPS platform
63C by Patrick Amestoy between 1997 and 1999.
64C
65C MUMPS_HAMF4 is a major modification of MUMPS_HAMD
66C since metric used to select pivots in not anymore the
67C degree but an approximation of the fill-in.
68C In this approximation
69C all cliques of elements adjacent to the variable are deducted.
70C Written by Patrick Amestoy between 1999 and 2000.
71C It is also used by F. Pellegrini in SCOTCH since 2000.
72C
73C MUMPS_QAMD: modified version of reference AMD routine MUMPS_ANA_H
74C designed to automatically detect and exploit dense or quasi dense
75C rows in the reduced matrix at any step of the minimum degree.
76C Written in 1997 by Patrick Amestoy.
77C References:
78C P.R. AMESTOY, Recent progress in parallel multifrontal solvers
79C for unsymmetric sparse matrices,
80C Proceedings of the 15th World Congress on Scientific Computation,
81C Modelling and Applied Mathematics, IMACS, Berlin (1997).
82C P.R. AMESTOY (1999), Methodes directes paralleles de
83C resolution des systemes creux de grande taille.
84C Rapport de these d'habilitation de l'INPT.
85C
86C MUMPS_CST_AMF: modified version of MUMPS_HAMF4 routine
87C implementing constraint minimum fill-in based ordering.
88C Written by Stephane Pralet for MUMPS platform
89C during his post-doctorate at INPT-IRIT (Oct. 2004- Oct. 2005)
90C
91C ----------------------------------------
92C To suppress aggressive absorption in ...
93C MUMPS_ANA_H : Historical AMD
94C define NOAGG1
95C MUMPS_AMD_ELT : (work on compressed graphs)
96C define NOAGG2
97C MUMPS_HAMD : AMD with Halo and used for Schur
98C define NOAGG3
99C MUMPS_HAMF4 : Halo AMF version
100C define NOAGG4
101C MUMPS_QAMD : Quasi dense
102C define NOAGG5
103C MUMPS_SYMQAMD : Symbolic facto based on quasi dense
104C In the case of MUMPS_SYMQAMD, the aggressive absorption
105C is controlled by a parameter, AGG6.
106C
107C-----------------------------------------------------------------------
108C-----------------------------------------------------------------------
109C MUMPS_ANA_H: Approximate Minimum Degree AMD approach.
110C
111C Description of MUMPS_ANA_H
112C Given a representation of the nonzero pattern of a symmetric matrix,
113C A, (excluding the diagonal) perform an approximate minimum
114C degree ordering to compute a pivot order
115C such that fill-in in the Cholesky factors A = LL^T is kept low.
116C Aggressive absorption might be used to
117C tighten the bound on the degree. This can result a
118C significant improvement in the quality of the ordering for
119C some matrices.
120C
121C References and definitions:
122C [1] Timothy A. Davis and Iain Duff, "An unsymmetric-pattern
123C multifrontal method for sparse LU factorization",
124C SIAM J. Matrix Analysis and Applications,
125C volume=18, pages=140-158 (1997)
126C [2] Patrick R. Amestoy, Timothy A. Davis, and Iain S. Duff,
127C "An approximate minimum degree ordering algorithm,"
128C SIAM J. Matrix Analysis vol 17, pages=886--905 (1996)
129C [3] Alan George and Joseph Liu, "The evolution of the
130C minimum degree ordering algorithm," SIAM Review, vol.
131C 31, no. 1, pp. 1-19, March 1989. We list below the
132C features mentioned in that paper that this code
133C includes:
134C mass elimination:
135C Yes. supervariable detection for mass elimination.
136C indistinguishable nodes:
137C Yes (we call these "supervariables").
138C We modified the approach used by Duff and Reid to
139C detect them (the previous hash was the true degree,
140C which we no longer keep track of). A supervariable is
141C a set of rows with identical nonzero pattern. All
142C variables in a supervariable are eliminated together.
143C Each supervariable has as its numerical name that of
144C one of its variables (its principal variable).
145C quotient graph representation:
146C Yes. We use the term "element" for the cliques formed
147C during elimination.
148C The algorithm can operate in place, but it will work
149C more efficiently if given some "elbow room."
150C element absorption:
151C Yes. Similar to Duff,Reid and George,Liu approaches
152C external degree:
153C Yes. Similar to Duff, Reid and George, Liu approaches
154C incomplete degree update and multiple elimination:
155C No implemented. Our method of
156C degree update within MUMPS_ANA_H is element-based, not
157C variable-based. It is thus not well-suited for use
158C with incomplete degree update or multiple elimination.
159C
160C-----------------------------------------------------------------------
161 SUBROUTINE mumps_ana_h(TOTEL, COMPUTE_PERM,
162 & N, IWLEN, PE, PFREE, LEN, IW, NV, ELEN,
163 & LAST, NCMPA, DEGREE, HEAD, NEXT, W, PARENT)
164C
165C Restrictive integer 64 bit variant :
166C it is assumed that IW array size can exceed 32-bit integer
167C
168C Input not modified
169 INTEGER, INTENT(IN) :: TOTEL, N
170 INTEGER(8), INTENT(IN) :: IWLEN
171 LOGICAL, INTENT(IN) :: COMPUTE_PERM
172C Input undefined on output
173 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
174C
175C Output only
176 INTEGER, INTENT(OUT) :: NCMPA
177 INTEGER, INTENT(OUT) :: ELEN(N), LAST(N), PARENT(N)
178C
179C Input/output
180 INTEGER(8), INTENT(INOUT) :: PFREE
181 INTEGER(8), INTENT(INOUT) :: PE(N)
182C NV also meaningful as input to encode compressed graphs
183 INTEGER, INTENT(INOUT) :: NV(N)
184C
185C Internal Workspace only
186 INTEGER :: NEXT(N), DEGREE(N), HEAD(TOTEL), W(N)
187C ---------------------
188C Interface Description
189C ---------------------
190C INPUT ARGUMENTS (unaltered):
191C-----------------------------
192C n : The matrix order.
193C number of supervariables if compress/blocked format
194C Restriction: n .ge. 1
195C totel : Number of variables to eliminate
196C In case of blocked format:
197C each variable i is a supervariable of size nv(i)
198C totel is computed as the sum(nv(i)) for i \in [1:n]
199C the algorithm stops when totel variables are
200C eliminated.
201C compute_perm : indicates if permutations should be computed
202C on output in last/elen
203C iwlen: The length of iw (1..iwlen). On input, the matrix is
204C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
205C slightly larger than what is required to hold the matrix, at
206C least iwlen .ge. pfree + n is recommended. Otherwise,
207C excessive compressions will take place.
208C *** We do not recommend running this algorithm with ***
209C *** iwlen .lt. pfree + n. ***
210C *** Better performance will be obtained if ***
211C *** iwlen .ge. pfree + n ***
212C *** or better yet ***
213C *** iwlen .gt. 1.2 * pfree ***
214C *** (where pfree is its value on input). ***
215C The algorithm will not run at all if iwlen .lt. pfree-1.
216C
217C Restriction: iwlen .ge. pfree-1
218C-----------------------------------------------------------------------
219C INPUT/OUPUT ARGUMENTS:
220C-----------------------------------------------------------------------
221C pe: On input, pe (i) is the index in iw of the start of row i, or
222C zero if row i has no off-diagonal non-zeros.
223C
224C During execution, it is used for both supervariables and
225C elements:
226C
227C * Principal supervariable i: index into iw of the
228C description of supervariable i. A supervariable
229C represents one or more rows of the matrix
230C with identical nonzero pattern.
231C * Non-principal supervariable i: if i has been absorbed
232C into another supervariable j, then pe (i) = -j.
233C That is, j has the same pattern as i.
234C Note that j might later be absorbed into another
235C supervariable j2, in which case pe (i) is still -j,
236C and pe (j) = -j2.
237C * Unabsorbed element e: the index into iw of the description
238C of element e, if e has not yet been absorbed by a
239C subsequent element. Element e is created when
240C the supervariable of the same name is selected as
241C the pivot.
242C * Absorbed element e: if element e is absorbed into element
243C e2, then pe (e) = -e2. This occurs when the pattern of
244C e (that is, Le) is found to be a subset of the pattern
245C of e2 (that is, Le2). If element e is "null" (it has
246C no nonzeros outside its pivot block), then pe (e) = 0.
247C
248C On output, pe holds the assembly tree/forest, which implicitly
249C represents a pivot order with identical fill-in as the actual
250C order (via a depth-first search of the tree).
251C
252C On output: (PE is copied on output into PARENT array)
253C If nv (i) .gt. 0, then i represents a node in the assembly tree,
254C and the parent of i is -pe (i), or zero if i is a root.
255C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
256C subtree, the root of which is a node in the assembly tree.
257C pfree:On input, the matrix is stored in iw (1..pfree-1) and
258C the rest of the array iw is free.
259C During execution, additional data is placed in iw, and pfree
260C is modified so that components of iw from pfree are free.
261C On output, pfree is set equal to the size of iw that
262C would have been needed for no compressions to occur. If
263C ncmpa is zero, then pfree (on output) is less than or equal to
264C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
265C Otherwise, pfree (on output) is greater than iwlen, and all the
266C memory in iw was used.
267C nv: On input, encoding of compressed graph:
268C if nv(1) = -1 then graph is not compressed otherwise
269C nv(I) holds the weight of node I.
270C During execution, abs (nv (i)) is equal to the number of rows
271C that are represented by the principal supervariable i. If i is
272C a nonprincipal variable, then nv (i) = 0.
273C nv (i) .lt. 0 signifies that i is a
274C principal variable in the pattern Lme of the current pivot
275C element me.
276C On output, nv (e) holds the true degree of element
277C e at the time it was created (including the diagonal part).
278C-----------------------------------------------------------------------
279C INPUT/MODIFIED (undefined on output):
280C-----------------------------------------------------------------------
281C len: On input, len (i) holds the number of entries in row i of the
282C matrix, excluding the diagonal. The contents of len (1..n)
283C are undefined on output.
284C iw: On input, iw (1..pfree-1) holds the description of each row i
285C in the matrix. The matrix must be symmetric, and both upper
286C and lower triangular parts must be present. The diagonal must
287C not be present.
288C Row i is held as follows:
289C len (i): the length of the row i data structure
290C iw (pe (i) ... pe (i) + len (i) - 1):
291C the list of column indices for nonzeros
292C in row i (simple supervariables), excluding
293C the diagonal. All supervariables start with
294C one row/column each (supervariable i is just
295C row i).
296C if len (i) is zero on input, then pe (i) is ignored
297C on input.
298C
299C Note that the rows need not be in any particular order,
300C and there may be empty space between the rows.
301C
302C During execution, the supervariable i experiences fill-in.
303C This is represented by placing in i a list of the elements
304C that cause fill-in in supervariable i:
305C
306C len (i): the length of supervariable i
307C iw (pe (i) ... pe (i) + elen (i) - 1):
308C the list of elements that contain i. This list
309C is kept short by removing absorbed elements.
310C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
311C the list of supervariables in i. This list
312C is kept short by removing nonprincipal
313C variables, and any entry j that is also
314C contained in at least one of the elements
315C (j in Le) in the list for i (e in row i).
316C
317C When supervariable i is selected as pivot, we create an
318C element e of the same name (e=i):
319C
320C len (e): the length of element e
321C iw (pe (e) ... pe (e) + len (e) - 1):
322C the list of supervariables in element e.
323C
324C An element represents the fill-in that occurs when supervariable
325C i is selected as pivot (which represents the selection of row i
326C and all non-principal variables whose principal variable is i).
327C We use the term Le to denote the set of all supervariables
328C in element e. Absorbed supervariables and elements are pruned
329C from these lists when computationally convenient.
330C
331C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
332C The contents of iw are undefined on output.
333C-----------------------------------------------------------------------
334C OUTPUT (need not be set on input):
335C-----------------------------------------------------------------------
336C elen:
337C See the description of iw above. At the start of execution,
338C elen (i) is set to zero. During execution, elen (i) is the
339C number of elements in the list for supervariable i. When e
340C becomes an element, elen (e) = -nel is set, where nel is the
341C current step of factorization. elen (i) = 0 is done when i
342C becomes nonprincipal.
343C
344C For variables, elen (i) .ge. 0 holds until just before the
345C permutation vectors are computed. For elements,
346C elen (e) .lt. 0 holds.
347C
348C On output elen (1..n) holds the inverse permutation (the same
349C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
350C then row i is the kth pivot row. Row i of A appears as the
351C (elen(i))-th row in the permuted matrix, PAP^T.
352C last:
353C In a degree list, last (i) is the supervariable preceding i,
354C or zero if i is the head of the list. In a hash bucket,
355C last (i) is the hash key for i. last (head (hash)) is also
356C used as the head of a hash bucket if head (hash) contains a
357C degree list (see head, below).
358C
359C On output, last (1..n) holds the permutation (the same as the
360C 'PERM' argument in Sparspak). That is, if i = last (k), then
361C row i is the kth pivot row. Row last (k) of A is the k-th row
362C in the permuted matrix, PAP^T.
363C ncmpa: The number of times iw was compressed. If this is
364C excessive, then the execution took longer than what could have
365C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
366C larger than the value of pfree on input (or at least
367C iwlen .ge. pfree + n). The fastest performance will be
368C obtained when ncmpa is returned as zero. If iwlen is set to
369C the value returned by pfree on *output*, then no compressions
370C will occur.
371C-----------------------------------------------------------------------
372C LOCAL (not input or output - used only during execution):
373C-----------------------------------------------------------------------
374C degree: If i is a supervariable, then degree (i) holds the
375C current approximation of the external degree of row i (an upper
376C bound). The external degree is the number of nonzeros in row i,
377C minus abs (nv (i)) (the diagonal part). The bound is equal to
378C the external degree if elen (i) is less than or equal to two.
379C
380C We also use the term "external degree" for elements e to refer
381C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
382C which is the degree of the off-diagonal part of the element e
383C (not including the diagonal part).
384C head: head is used for degree lists. head (deg) is the first
385C supervariable in a degree list (all supervariables i in a
386C degree list deg have the same approximate degree, namely,
387C deg = degree (i)). If the list deg is empty then
388C head (deg) = 0.
389C
390C During supervariable detection head (hash) also serves as a
391C pointer to a hash bucket.
392C If head (hash) .gt. 0, there is a degree list of degree hash.
393C The hash bucket head pointer is last (head (hash)).
394C If head (hash) = 0, then the degree list and hash bucket are
395C both empty.
396C If head (hash) .lt. 0, then the degree list is empty, and
397C -head (hash) is the head of the hash bucket.
398C After supervariable detection is complete, all hash buckets
399C are empty, and the (last (head (hash)) = 0) condition is
400C restored for the non-empty degree lists.
401C next: next (i) is the supervariable following i in a link list, or
402C zero if i is the last in the list. Used for two kinds of
403C lists: degree lists and hash buckets (a supervariable can be
404C in only one kind of list at a time).
405C w: The flag array w determines the status of elements and
406C variables, and the external degree of elements.
407C
408C for elements:
409C if w (e) = 0, then the element e is absorbed
410C if w (e) .ge. wflg, then w (e) - wflg is the size of
411C the set |Le \ Lme|, in terms of nonzeros (the
412C sum of abs (nv (i)) for each principal variable i that
413C is both in the pattern of element e and NOT in the
414C pattern of the current pivot element, me).
415C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
416C not yet been seen in the scan of the element lists in
417C the computation of |Le\Lme| in loop 150 below.
418C
419C for variables:
420C during supervariable detection, if w (j) .ne. wflg then j is
421C not in the pattern of variable i
422C
423C The w array is initialized by setting w (i) = 1 for all i,
424C and by setting wflg = 2. It is reinitialized if wflg becomes
425C too large (to ensure that wflg+n does not cause integer
426C overflow).
427C-----------------------------------------------------------------------
428C LOCAL INTEGERS:
429C-----------------------------------------------------------------------
430 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
431 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
432 & lenj, ln, me, mindeg, nel,
433 & nleft, nvi, nvj, nvpiv, slenme, we, wflg, wnvi, x
434 INTEGER KNT1_UPDATED, KNT2_UPDATED
435 INTEGER(8) :: MAXMEM, MEM, NEWMEM
436 INTEGER :: MAXINT_N
437 INTEGER(8) :: HASH, HMOD
438C deg: the degree of a variable or element
439C degme: size, |Lme|, of the current element, me (= degree (me))
440C dext: external degree, |Le \ Lme|, of some element e
441C dmax: largest |Le| seen so far
442C e: an element
443C elenme: the length, elen (me), of element list of pivotal var.
444C eln: the length, elen (...), of an element list
445C hash: the computed value of the hash function
446C hmod: the hash function is computed modulo hmod = max (1,n-1)
447C i: a supervariable
448C ilast: the entry in a link list preceding i
449C inext: the entry in a link list following i
450C j: a supervariable
451C jlast: the entry in a link list preceding j
452C jnext: the entry in a link list, or path, following j
453C k: the pivot order of an element or variable
454C knt1: loop counter used during element construction
455C knt2: loop counter used during element construction
456C knt3: loop counter used during compression
457C lenj: len (j)
458C ln: length of a supervariable list
459C maxint_n large integer to test risk of overflow on wflg
460C maxmem: amount of memory needed for no compressions
461C me: current supervariable being eliminated, and the
462C current element created by eliminating that
463C supervariable
464C mem: memory in use assuming no compressions have occurred
465C mindeg: current minimum degree
466C nel: number of pivots selected so far
467C newmem: amount of new memory needed for current pivot element
468C nleft: n - nel, the number of nonpivotal rows/columns remaining
469C nvi: the number of variables in a supervariable i (= nv (i))
470C nvj: the number of variables in a supervariable j (= nv (j))
471C nvpiv: number of pivots in current element
472C slenme: number of variables in variable list of pivotal variable
473C we: w (e)
474C wflg: used for flagging the w array. See description of iw.
475C wnvi: wflg - nv (i)
476C x: either a supervariable or an element
477C-----------------------------------------------------------------------
478C LOCAL POINTERS:
479C-----------------------------------------------------------------------
480 INTEGER(8) P, P1, P2, P3, PDST, PEND, PJ, PME,
481 & PME1, PME2, PN, PSRC
482C Any parameter (pe (...) or pfree) or local variable
483C starting with "p" (for Pointer) is an index into iw,
484C and all indices into iw use variables starting with
485C "p." The only exception to this rule is the iwlen
486C input argument.
487C p: pointer into lots of things
488C p1: pe (i) for some variable i (start of element list)
489C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
490C p3: index of first supervariable in clean list
491C pdst: destination pointer, for compression
492C pend: end of memory to compress
493C pj: pointer into an element or variable
494C pme: pointer into the current element (pme1...pme2)
495C pme1: the current element, me, is stored in iw (pme1...pme2)
496C pme2: the end of the current element
497C pn: pointer into a "clean" variable, also used to compress
498C psrc: source pointer, for compression
499 LOGICAL COMPRESS
500C-----------------------------------------------------------------------
501C FUNCTIONS CALLED:
502C-----------------------------------------------------------------------
503 INTRINSIC max, min, mod
504C=======================================================================
505C INITIALIZATIONS
506C=======================================================================
507 wflg = 2
508 maxint_n=huge(wflg)-n
509 mindeg = 1
510 ncmpa = 0
511 nel = 0
512 hmod = int(max(1, n-1),kind=8)
513 dmax = 0
514 mem = pfree - 1
515 maxmem = mem
516 DO i = 1, n
517 last(i) = 0
518 head(i) = 0
519 w(i) = 1
520 elen(i) = 0
521 ENDDO
522 DO i = 1, totel
523 head(i) = 0
524 ENDDO
525 IF(nv(1) .LT. 0) THEN
526 compress = .false.
527 ELSE
528 compress = .true.
529 ENDIF
530 IF (compress) THEN
531 DO i=1,n
532 degree(i) = 0
533 DO p= pe(i) , pe(i)+int(len(i)-1,8)
534 degree(i) = degree(i) + nv(iw(p))
535 ENDDO
536 ENDDO
537 ELSE
538 DO i=1,n
539 nv(i) = 1
540 degree(i) = len(i)
541 ENDDO
542 ENDIF
543C
544C ----------------------------------------------------------------
545C initialize degree lists and eliminate rows with no off-diag. nz.
546C ----------------------------------------------------------------
547 DO 20 i = 1, n
548 deg = degree(i)
549 IF (deg .GT. 0) THEN
550C ----------------------------------------------------------
551C place i in the degree list corresponding to its degree
552C ----------------------------------------------------------
553 inext = head(deg)
554 IF (inext .NE. 0) last(inext) = i
555 next(i) = inext
556 head(deg) = i
557 ELSE
558C ----------------------------------------------------------
559C we have a variable that can be eliminated at once because
560C there is no off-diagonal non-zero in its row.
561C ----------------------------------------------------------
562 nel = nel + nv(i)
563 elen(i) = -nel
564 pe(i) = 0
565 w(i) = 0
566 ENDIF
567 20 CONTINUE
568C =====================================================================
569C WHILE (selecting pivots) DO
570C =====================================================================
571 30 IF (nel .LT. totel) THEN
572C =====================================================================
573C GET PIVOT OF MINIMUM DEGREE
574C ======================================================================
575C -------------------------------------------------------------
576C find next supervariable for elimination
577C -------------------------------------------------------------
578 DO 40 deg = mindeg, totel
579 me = head(deg)
580 IF (me .GT. 0) GO TO 50
581 40 CONTINUE
582 50 mindeg = deg
583C -------------------------------------------------------------
584C remove chosen variable from link list
585C -------------------------------------------------------------
586 inext = next(me)
587 IF (inext .NE. 0) last(inext) = 0
588 head(deg) = inext
589C -------------------------------------------------------------
590C me represents the elimination of pivots nel+1 to nel+nv(me).
591C place me itself as the first in this set. It will be moved
592C to the nel+nv(me) position when the permutation vectors are
593C computed.
594C -------------------------------------------------------------
595 elenme = elen(me)
596 elen(me) = - (nel + 1)
597 nvpiv = nv(me)
598 nel = nel + nvpiv
599C=======================================================================
600C CONSTRUCT NEW ELEMENT
601C=======================================================================
602C -------------------------------------------------------------
603C At this point, me is the pivotal supervariable. It will be
604C converted into the current element. Scan list of the
605C pivotal supervariable, me, setting tree pointers and
606C constructing new list of supervariables for the new element,
607C me. p is a pointer to the current position in the old list.
608C -------------------------------------------------------------
609C flag the variable "me" as being in Lme by negating nv (me)
610 nv(me) = -nvpiv
611 degme = 0
612 IF (elenme .EQ. 0) THEN
613C ----------------------------------------------------------
614C construct the new element in place
615C ----------------------------------------------------------
616 pme1 = pe(me)
617 pme2 = pme1 - 1
618 DO 60 p = pme1, pme1 + len(me) - 1
619 i = iw(p)
620 nvi = nv(i)
621 IF (nvi .GT. 0) THEN
622C ----------------------------------------------------
623C i is a principal variable not yet placed in Lme.
624C store i in new list
625C ----------------------------------------------------
626 degme = degme + nvi
627C flag i as being in Lme by negating nv (i)
628 nv(i) = -nvi
629 pme2 = pme2 + 1
630 iw(pme2) = i
631C ----------------------------------------------------
632C remove variable i from degree list.
633C ----------------------------------------------------
634 ilast = last(i)
635 inext = next (i)
636 IF (inext .NE. 0) last(inext) = ilast
637 IF (ilast .NE. 0) THEN
638 next(ilast) = inext
639 ELSE
640C i is at the head of the degree list
641 head(degree(i)) = inext
642 ENDIF
643 ENDIF
644 60 CONTINUE
645C this element takes no new memory in iw:
646 newmem = 0
647 ELSE
648C ----------------------------------------------------------
649C construct the new element in empty space, iw (pfree ...)
650C ----------------------------------------------------------
651 p = pe(me)
652 pme1 = pfree
653 slenme = len(me) - elenme
654 knt1_updated = 0
655 DO 120 knt1 = 1, elenme + 1
656 knt1_updated = knt1_updated +1
657 IF (knt1 .GT. elenme) THEN
658C search the supervariables in me.
659 e = me
660 pj = p
661 ln = slenme
662 ELSE
663C search the elements in me.
664 e = iw(p)
665 p = p + 1
666 pj = pe(e)
667 ln = len(e)
668 ENDIF
669C -------------------------------------------------------
670C search for different supervariables and add them to the
671C new list, compressing when necessary. this loop is
672C executed once for each element in the list and once for
673C all the supervariables in the list.
674C -------------------------------------------------------
675 knt2_updated = 0
676 DO 110 knt2 = 1, ln
677 knt2_updated = knt2_updated+1
678 i = iw(pj)
679 pj = pj + 1
680 nvi = nv(i)
681 IF (nvi .GT. 0) THEN
682C -------------------------------------------------
683C compress iw, if necessary
684C -------------------------------------------------
685 IF (pfree .GT. iwlen) THEN
686C prepare for compressing iw by adjusting
687C pointers and lengths so that the lists being
688C searched in the inner and outer loops contain
689C only the remaining entries.
690 pe(me) = p
691 len(me) = len(me) - knt1_updated
692C Reset KNT1_UPDATED in case of recompress
693C at same iteration of the loop 120
694 knt1_updated = 0
695C Check if anything left in supervariable ME
696 IF (len(me) .EQ. 0) pe(me) = 0
697 pe(e) = pj
698 len(e) = ln - knt2_updated
699C Reset KNT2_UPDATED in case of recompress
700C at same iteration of the loop 110
701 knt2_updated = 0
702C Check if anything left in element E
703 IF (len(e) .EQ. 0) pe(e) = 0
704 ncmpa = ncmpa + 1
705C store first item in pe
706C set first entry to -item
707 DO 70 j = 1, n
708 pn = pe(j)
709 IF (pn .GT. 0) THEN
710 pe(j) = int(iw(pn), 8)
711 iw(pn) = -j
712 ENDIF
713 70 CONTINUE
714C psrc/pdst point to source/destination
715 pdst = 1
716 psrc = 1
717 pend = pme1 - 1
718C while loop:
719 80 CONTINUE
720 IF (psrc .LE. pend) THEN
721C search for next negative entry
722 j = -iw(psrc)
723 psrc = psrc + 1
724 IF (j .GT. 0) THEN
725 iw (pdst) = int(pe(j))
726 pe(j) = pdst
727 pdst = pdst + 1
728C copy from source to destination
729 lenj = len(j)
730 DO 90 knt3 = 0, lenj - 2
731 iw(pdst + knt3) = iw(psrc + knt3)
732 90 CONTINUE
733 pdst = pdst + lenj - 1
734 psrc = psrc + lenj - 1
735 ENDIF
736 GO TO 80
737 ENDIF
738C move the new partially-constructed element
739 p1 = pdst
740 DO 100 psrc = pme1, pfree - 1
741 iw(pdst) = iw (psrc)
742 pdst = pdst + 1
743 100 CONTINUE
744 pme1 = p1
745 pfree = pdst
746 pj = pe(e)
747 p = pe(me)
748 ENDIF
749C -------------------------------------------------
750C i is a principal variable not yet placed in Lme
751C store i in new list
752C -------------------------------------------------
753 degme = degme + nvi
754C flag i as being in Lme by negating nv (i)
755 nv(i) = -nvi
756 iw(pfree) = i
757 pfree = pfree + 1
758C -------------------------------------------------
759C remove variable i from degree link list
760C -------------------------------------------------
761 ilast = last(i)
762 inext = next(i)
763 IF (inext .NE. 0) last(inext) = ilast
764 IF (ilast .NE. 0) THEN
765 next(ilast) = inext
766 ELSE
767C i is at the head of the degree list
768 head(degree(i)) = inext
769 ENDIF
770 ENDIF
771 110 CONTINUE
772 IF (e .NE. me) THEN
773C set tree pointer and flag to indicate element e is
774C absorbed into new element me (the parent of e is me)
775 pe(e) = int(-me,8)
776 w(e) = 0
777 ENDIF
778 120 CONTINUE
779 pme2 = pfree - 1
780C this element takes newmem new memory in iw (possibly zero)
781 newmem = pfree - pme1
782 mem = mem + newmem
783 maxmem = max(maxmem, mem)
784 ENDIF
785C -------------------------------------------------------------
786C me has now been converted into an element in iw (pme1..pme2)
787C -------------------------------------------------------------
788C degme holds the external degree of new element
789 degree(me) = degme
790 pe(me) = pme1
791 len(me) = int(pme2 - pme1 + 1)
792C -------------------------------------------------------------
793C make sure that wflg is not too large. With the current
794C value of wflg, wflg+n must not cause integer overflow
795C -------------------------------------------------------------
796 IF (wflg .GT. maxint_n) THEN
797 DO 130 x = 1, n
798 IF (w(x) .NE. 0) w(x) = 1
799 130 CONTINUE
800 wflg = 2
801 ENDIF
802C=======================================================================
803C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
804C=======================================================================
805C -------------------------------------------------------------
806C Scan 1: compute the external degrees of previous elements
807C with respect to the current element. That is:
808C (w (e) - wflg) = |Le \ Lme|
809C for each element e that appears in any supervariable in Lme.
810C The notation Le refers to the pattern (list of
811C supervariables) of a previous element e, where e is not yet
812C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
813C The notation Lme refers to the pattern of the current element
814C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
815C zero, then the element e will be absorbed in scan 2.
816C -------------------------------------------------------------
817 DO 150 pme = pme1, pme2
818 i = iw(pme)
819 eln = elen(i)
820 IF (eln .GT. 0) THEN
821C note that nv (i) has been negated to denote i in Lme:
822 nvi = -nv(i)
823 wnvi = wflg - nvi
824 DO 140 p = pe(i), pe(i) + eln - 1
825 e = iw(p)
826 we = w(e)
827 IF (we .GE. wflg) THEN
828C unabsorbed element e has been seen in this loop
829 we = we - nvi
830 ELSE IF (we .NE. 0) THEN
831C e is an unabsorbed element
832C this is the first we have seen e in all of Scan 1
833 we = degree(e) + wnvi
834 ENDIF
835 w(e) = we
836 140 CONTINUE
837 ENDIF
838 150 CONTINUE
839C=======================================================================
840C DEGREE UPDATE AND ELEMENT ABSORPTION
841C=======================================================================
842C -------------------------------------------------------------
843C Scan 2: for each i in Lme, sum up the degree of Lme
844C (which is degme),
845C plus the sum of the external degrees of each Le
846C for the elements e appearing within i, plus the
847C supervariables in i. Place i in hash list.
848C -------------------------------------------------------------
849 DO 180 pme = pme1, pme2
850 i = iw(pme)
851 p1 = pe(i)
852 p2 = p1 + elen(i) - 1
853 pn = p1
854 hash = 0_8
855 deg = 0
856C ----------------------------------------------------------
857C scan the element list associated with supervariable i
858C ----------------------------------------------------------
859 DO 160 p = p1, p2
860 e = iw(p)
861C dext = | Le \ Lme |
862 dext = w(e) - wflg
863 IF (dext .GT. 0) THEN
864 deg = deg + dext
865 iw(pn) = e
866 pn = pn + 1
867 hash = hash + int(e,kind=8)
868 ELSE IF (dext .EQ. 0) THEN
869#if defined (NOAGG1)
870 iw(pn) = e
871 pn = pn + 1
872 hash = hash + int(e,kind=8)
873#else
874C aggressive absorption: e is not adjacent to me, but
875C the |Le \ Lme| is 0, so absorb it into me
876 pe(e) = int(-me,8)
877 w(e) = 0
878#endif
879 ENDIF
880 160 CONTINUE
881C count the number of elements in i (including me):
882 elen(i) = int(pn - p1 + 1)
883C ----------------------------------------------------------
884C scan the supervariables in the list associated with i
885C ----------------------------------------------------------
886 p3 = pn
887 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
888 j = iw(p)
889 nvj = nv(j)
890 IF (nvj .GT. 0) THEN
891C j is unabsorbed, and not in Lme.
892C add to degree and add to new list
893 deg = deg + nvj
894 iw(pn) = j
895 pn = pn + 1
896 hash = hash + int(j,kind=8)
897 ENDIF
898 170 CONTINUE
899C ----------------------------------------------------------
900C update the degree and check for mass elimination
901C ----------------------------------------------------------
902#if defined (NOAGG1)
903 IF (deg.EQ.0.AND.(elen(i).GT.1)) THEN
904C When DEG is zero we need to
905C absorb in ME all elements adjacent to I
906 p1 = pe(i)
907C exclude ME --> -2
908 p2 = p1 + int(elen(i),8) - 2_8
909 DO p =p1,p2
910 e = iw(p)
911 pe(e) = int(-me,8)
912 w(e) = 0
913 ENDDO
914 ENDIF
915C .... Ready for mass elimination
916#endif
917 IF (deg .EQ. 0) THEN
918C -------------------------------------------------------
919C mass elimination
920C -------------------------------------------------------
921C There is nothing left of this node except for an
922C edge to the current pivot element. elen (i) is 1,
923C and there are no variables adjacent to node i.
924C Absorb i into the current pivot element, me.
925 pe(i) = int(-me,8)
926 nvi = -nv(i)
927 degme = degme - nvi
928 nvpiv = nvpiv + nvi
929 nel = nel + nvi
930 nv(i) = 0
931 elen(i) = 0
932 ELSE
933C -------------------------------------------------------
934C update the upper-bound degree of i
935C -------------------------------------------------------
936C the following degree does not yet include the size
937C of the current element, which is added later:
938 degree(i) = min(degree(i), deg)
939C -------------------------------------------------------
940C add me to the list for i
941C -------------------------------------------------------
942C move first supervariable to end of list
943 iw(pn) = iw(p3)
944C move first element to end of element part of list
945 iw(p3) = iw(p1)
946C add new element to front of list.
947 iw(p1) = me
948C store the new length of the list in len (i)
949 len(i) = int(pn - p1 + 1)
950C -------------------------------------------------------
951C place in hash bucket. Save hash key of i in last (i).
952C -------------------------------------------------------
953 hash = mod(hash, hmod) + 1_8
954 j = head(hash)
955 IF (j .LE. 0) THEN
956C the degree list is empty, hash head is -j
957 next(i) = -j
958 head(hash) = -i
959 ELSE
960C degree list is not empty
961C use last (head (hash)) as hash head
962 next(i) = last(j)
963 last(j) = i
964 ENDIF
965 last(i) = int(hash,kind=kind(last))
966 ENDIF
967 180 CONTINUE
968 degree(me) = degme
969C -------------------------------------------------------------
970C Clear the counter array, w (...), by incrementing wflg.
971C -------------------------------------------------------------
972 dmax = max(dmax, degme)
973 wflg = wflg + dmax
974C make sure that wflg+n does not cause integer overflow
975 IF (wflg .GT. maxint_n) THEN
976 DO 190 x = 1, n
977 IF (w(x) .NE. 0) w(x) = 1
978 190 CONTINUE
979 wflg = 2
980 ENDIF
981C at this point, w (1..n) .lt. wflg holds
982C=======================================================================
983C SUPERVARIABLE DETECTION
984C=======================================================================
985 DO 250 pme = pme1, pme2
986 i = iw(pme)
987 IF (nv(i) .LT. 0) THEN
988C i is a principal variable in Lme
989C -------------------------------------------------------
990C examine all hash buckets with 2 or more variables. We
991C do this by examing all unique hash keys for super-
992C variables in the pattern Lme of the current element, me
993C -------------------------------------------------------
994 hash = int(last (i),kind=8)
995C let i = head of hash bucket, and empty the hash bucket
996 j = head(hash)
997 IF (j .EQ. 0) GO TO 250
998 IF (j .LT. 0) THEN
999C degree list is empty
1000 i = -j
1001 head(hash) = 0
1002 ELSE
1003C degree list is not empty, restore last () of head
1004 i = last(j)
1005 last(j) = 0
1006 ENDIF
1007 IF (i .EQ. 0) GO TO 250
1008C while loop:
1009 200 CONTINUE
1010 IF (next(i) .NE. 0) THEN
1011C ----------------------------------------------------
1012C this bucket has one or more variables following i.
1013C scan all of them to see if i can absorb any entries
1014C that follow i in hash bucket. Scatter i into w.
1015C ----------------------------------------------------
1016 ln = len(i)
1017 eln = elen(i)
1018C do not flag the first element in the list (me)
1019 DO 210 p = pe(i) + 1, pe(i) + ln - 1
1020 w(iw(p)) = wflg
1021 210 CONTINUE
1022C ----------------------------------------------------
1023C scan every other entry j following i in bucket
1024C ----------------------------------------------------
1025 jlast = i
1026 j = next(i)
1027C while loop:
1028 220 CONTINUE
1029 IF (j .NE. 0) THEN
1030C -------------------------------------------------
1031C check if j and i have identical nonzero pattern
1032C -------------------------------------------------
1033C jump if i and j do not have same size data structure
1034 IF (len(j) .NE. ln) GO TO 240
1035C jump if i and j do not have same number adj elts
1036 IF (elen(j) .NE. eln) GO TO 240
1037C do not flag the first element in the list (me)
1038 DO 230 p = pe(j) + 1, pe(j) + ln - 1
1039C jump if an entry (iw(p)) is in j but not in i
1040 IF (w(iw(p)) .NE. wflg) GO TO 240
1041 230 CONTINUE
1042C -------------------------------------------------
1043C found it! j can be absorbed into i
1044C -------------------------------------------------
1045 pe(j) = int(-i,8)
1046C both nv (i) and nv (j) are negated since they
1047C are in Lme, and the absolute values of each
1048C are the number of variables in i and j:
1049 nv(i) = nv(i) + nv(j)
1050 nv(j) = 0
1051 elen(j) = 0
1052C delete j from hash bucket
1053 j = next(j)
1054 next(jlast) = j
1055 GO TO 220
1056C -------------------------------------------------
1057 240 CONTINUE
1058C j cannot be absorbed into i
1059C -------------------------------------------------
1060 jlast = j
1061 j = next(j)
1062 GO TO 220
1063 ENDIF
1064C ----------------------------------------------------
1065C no more variables can be absorbed into i
1066C go to next i in bucket and clear flag array
1067C ----------------------------------------------------
1068 wflg = wflg + 1
1069 i = next(i)
1070 IF (i .NE. 0) GO TO 200
1071 ENDIF
1072 ENDIF
1073 250 CONTINUE
1074C=======================================================================
1075C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
1076C=======================================================================
1077 p = pme1
1078 nleft = totel - nel
1079 DO 260 pme = pme1, pme2
1080 i = iw(pme)
1081 nvi = -nv(i)
1082 IF (nvi .GT. 0) THEN
1083C i is a principal variable in Lme
1084C restore nv (i) to signify that i is principal
1085 nv(i) = nvi
1086C -------------------------------------------------------
1087C compute the external degree (add size of current elem)
1088C -------------------------------------------------------
1089 deg = min(degree(i) + degme - nvi, nleft - nvi)
1090C -------------------------------------------------------
1091C place the supervariable at the head of the degree list
1092C -------------------------------------------------------
1093 inext = head(deg)
1094 IF (inext .NE. 0) last(inext) = i
1095 next(i) = inext
1096 last(i) = 0
1097 head(deg) = i
1098C -------------------------------------------------------
1099C save the new degree, and find the minimum degree
1100C -------------------------------------------------------
1101 mindeg = min(mindeg, deg)
1102 degree(i) = deg
1103C -------------------------------------------------------
1104C place the supervariable in the element pattern
1105C -------------------------------------------------------
1106 iw(p) = i
1107 p = p + 1
1108 ENDIF
1109 260 CONTINUE
1110C=======================================================================
1111C FINALIZE THE NEW ELEMENT
1112C=======================================================================
1113 nv(me) = nvpiv + degme
1114C nv (me) is now the degree of pivot (including diagonal part)
1115C save the length of the list for the new element me
1116 len(me) = int(p - pme1)
1117 IF (len(me) .EQ. 0) THEN
1118C there is nothing left of the current pivot element
1119 pe(me) = 0_8
1120 w(me) = 0
1121 ENDIF
1122 IF (newmem .NE. 0) THEN
1123C element was not constructed in place: deallocate part
1124C of it (final size is less than or equal to newmem,
1125C since newly nonprincipal variables have been removed).
1126 pfree = p
1127 mem = mem - newmem + len(me)
1128 ENDIF
1129C=======================================================================
1130C END WHILE (selecting pivots)
1131 GO TO 30
1132 ENDIF
1133C=======================================================================
1134C=======================================================================
1135C COMPUTE THE PERMUTATION VECTORS and update TREE
1136C=======================================================================
1137C ----------------------------------------------------------------
1138C The time taken by the following code is O(n). At this
1139C point, elen (e) = -k has been done for all elements e,
1140C and elen (i) = 0 has been done for all nonprincipal
1141C variables i. At this point, there are no principal
1142C supervariables left, and all elements are absorbed.
1143C ----------------------------------------------------------------
1144C ----------------------------------------------------------------
1145C compute the ordering of unordered nonprincipal variables
1146C ----------------------------------------------------------------
1147 DO 290 i = 1, n
1148 IF (elen(i) .EQ. 0) THEN
1149C ----------------------------------------------------------
1150C i is an un-ordered row. Traverse the tree from i until
1151C reaching an element, e. The element, e, was the
1152C principal supervariable of i and all nodes in the path
1153C from i to when e was selected as pivot.
1154C ----------------------------------------------------------
1155 j = int(-pe(i))
1156C while (j is a variable) do:
1157 270 CONTINUE
1158 IF (elen(j) .GE. 0) THEN
1159 j = int(-pe(j))
1160 GO TO 270
1161 ENDIF
1162 e = j
1163C ----------------------------------------------------------
1164C get the current pivot ordering of e
1165C ----------------------------------------------------------
1166 k = -elen(e)
1167C ----------------------------------------------------------
1168C traverse the path again from i to e, and compress the
1169C path (all nodes point to e). Path compression allows
1170C this code to compute in O(n) time. Order the unordered
1171C nodes in the path, and place the element e at the end.
1172C ----------------------------------------------------------
1173 j = i
1174C while (j is a variable) do:
1175 280 CONTINUE
1176 IF (elen(j) .GE. 0) THEN
1177 jnext = int(-pe(j))
1178 pe(j) = int(-e,8)
1179 IF (elen(j) .EQ. 0) THEN
1180C j is an unordered row
1181 elen(j) = k
1182 k = k + 1
1183 ENDIF
1184 j = jnext
1185 GO TO 280
1186 ENDIF
1187C leave elen (e) negative, so we know it is an element
1188 elen(e) = -k
1189 ENDIF
1190 290 CONTINUE
1191C
1192 IF (compute_perm) THEN
1193C ----------------------------------------------------------------
1194C reset the inverse permutation (elen (1..n)) to be positive,
1195C and compute the permutation (last (1..n)).
1196C ----------------------------------------------------------------
1197 IF(compress) THEN
1198 last(1:n) = 0
1199 head(1:totel-n)=0
1200 DO i = 1, n
1201 k = abs(elen(i))
1202 IF ( k <= n ) THEN
1203 last(k) = i
1204 ELSE
1205 head(k-n)=i
1206 ENDIF
1207 ENDDO
1208 i = 1
1209 DO k = 1, n
1210 IF(last(k) .NE. 0) THEN
1211 last(i) = last(k)
1212 elen(last(k)) = i
1213 i = i + 1
1214 ENDIF
1215 ENDDO
1216 DO k = n+1, totel
1217 IF (head(k-n) .NE. 0) THEN
1218 last(i)=head(k-n)
1219 elen(head(k-n)) = i
1220 i = i + 1
1221 ENDIF
1222 END DO
1223 ELSE
1224 DO 300 i = 1, n
1225 k = abs (elen(i))
1226 last(k) = i
1227 elen(i) = k
1228 300 CONTINUE
1229 ENDIF
1230C=======================================================================
1231C END OF COMPUTING PERMUTATIONS
1232C=======================================================================
1233 ENDIF
1234C=======================================================================
1235C RETURN THE MEMORY USAGE IN IW
1236C=======================================================================
1237C If maxmem is less than or equal to iwlen, then no compressions
1238C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
1239C compressions did occur, and iwlen would have had to have been
1240C greater than or equal to maxmem for no compressions to occur.
1241C Return the value of maxmem in the pfree argument.
1242 pfree = maxmem
1243C===============================
1244C Save IPE in PARENT array
1245 DO i=1,n
1246 parent(i) = int(pe(i))
1247 ENDDO
1248C===============================
1249 RETURN
1250 END SUBROUTINE mumps_ana_h
1251C-----------------------------------------------------------------------
1252C MUMPS_AMD_ELT: modified version of reference AMD routine MUMPS_ANA_H
1253C capable of processing already amalgamated or compressed graph.
1254C Used within MUMPS process for the elemental input format of matrices
1255C Input data is in this context modified to be a graph of supervariables.
1256C
1257C Modifications of the interface :
1258C ------------------------------
1259C INPUT:
1260C -----
1261C 1/ LEN(I) < 0 <=> i is a secondary variable whose principal
1262C variable is -LEN(I)
1263C 2/ For all secondary variables the adj list MUST not be provided.
1264C THAT is:
1265C -------
1266C if pe(isecondary) = 0 then
1267C adjacency list of isecondary is not provided
1268C else
1269C pe(isecondary) >0
1270C len(isecondary) must be equal to len(iprincipal_associated)
1271C then the corresponding space wil not be used and
1272C will be freed by amd if necessary.
1273C endif
1274C REMARK:
1275C ------
1276C 1/ N must be still set to the order of the matrix
1277C (not of the amalgamated gragh)
1278C 2/ For each supervariable S only supervariables adjacent to S are provided
1279C len(S) is then the number of such supervariables
1280C NV(S) is however updated during the initialisation phase to represent
1281C the size of the supervariable
1282C ( increment nv(s) for each i / len(i) =-s )
1283C 3/ If (len(i) >=0 for all i ) then we get the classical AMD code
1284C ------------------
1285 SUBROUTINE mumps_amd_elt(N,IWLEN, PE, PFREE, LEN, IW, NV, ELEN,
1286 & LAST, NCMPA, DEGREE, HEAD, NEXT, W, PARENT)
1287C
1288C Restrictive integer 64 bit variant :
1289C it is assumed that IW array size can exceed 32-bit integer
1290C
1291C Input not modified
1292 INTEGER, INTENT(IN) :: N
1293 INTEGER(8), INTENT(IN) :: IWLEN
1294C Input undefined on output
1295 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
1296C
1297C Output only
1298 INTEGER, INTENT(OUT) :: NCMPA
1299 INTEGER, INTENT(OUT) :: NV(N), ELEN(N), LAST(N), PARENT(N)
1300C
1301C Input/output
1302 INTEGER(8), INTENT(INOUT) :: PFREE
1303 INTEGER(8), INTENT(INOUT) :: PE(N)
1304C
1305C Internal Workspace only
1306 INTEGER NEXT(N), DEGREE(N), HEAD(N), W(N)
1307C
1308C Description:
1309C Given a representation of the nonzero pattern of a symmetric matrix,
1310C A, (excluding the diagonal) perform an approximate minimum
1311C degree ordering to compute a pivot order
1312C such that fill-in in the Cholesky factors A = LL^T is kept low.
1313C ---------------------
1314C Interface Description
1315C ---------------------
1316C INPUT ARGUMENTS (unaltered):
1317C-----------------------------
1318C n: The matrix order.
1319C
1320C Restriction: n .ge. 1
1321C iwlen: The length of iw (1..iwlen). On input, the matrix is
1322C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
1323C slightly larger than what is required to hold the matrix, at
1324C least iwlen .ge. pfree + n is recommended. Otherwise,
1325C excessive compressions will take place.
1326C *** We do not recommend running this algorithm with ***
1327C *** iwlen .lt. pfree + n. ***
1328C *** Better performance will be obtained if ***
1329C *** iwlen .ge. pfree + n ***
1330C *** or better yet ***
1331C *** iwlen .gt. 1.2 * pfree ***
1332C *** (where pfree is its value on input). ***
1333C The algorithm will not run at all if iwlen .lt. pfree-1.
1334C
1335C Restriction: iwlen .ge. pfree-1
1336C-----------------------------------------------------------------------
1337C INPUT/OUPUT ARGUMENTS:
1338C-----------------------------------------------------------------------
1339C pe: On input, pe (i) is the index in iw of the start of row i, or
1340C zero if row i has no off-diagonal non-zeros.
1341C
1342C During execution, it is used for both supervariables and
1343C elements:
1344C
1345C * Principal supervariable i: index into iw of the
1346C description of supervariable i. A supervariable
1347C represents one or more rows of the matrix
1348C with identical nonzero pattern.
1349C * Non-principal supervariable i: if i has been absorbed
1350C into another supervariable j, then pe (i) = -j.
1351C That is, j has the same pattern as i.
1352C Note that j might later be absorbed into another
1353C supervariable j2, in which case pe (i) is still -j,
1354C and pe (j) = -j2.
1355C * Unabsorbed element e: the index into iw of the description
1356C of element e, if e has not yet been absorbed by a
1357C subsequent element. Element e is created when
1358C the supervariable of the same name is selected as
1359C the pivot.
1360C * Absorbed element e: if element e is absorbed into element
1361C e2, then pe (e) = -e2. This occurs when the pattern of
1362C e (that is, Le) is found to be a subset of the pattern
1363C of e2 (that is, Le2). If element e is "null" (it has
1364C no nonzeros outside its pivot block), then pe (e) = 0.
1365C
1366C On output, pe holds the assembly tree/forest, which implicitly
1367C represents a pivot order with identical fill-in as the actual
1368C order (via a depth-first search of the tree).
1369C
1370C On output:
1371C If nv (i) .gt. 0, then i represents a node in the assembly tree,
1372C and the parent of i is -pe (i), or zero if i is a root.
1373C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
1374C subtree, the root of which is a node in the assembly tree.
1375C
1376C On output: (PE is copied on output into PARENT array)
1377C pfree: On input, the matrix is stored in iw (1..pfree-1) and
1378C the rest of the array iw is free.
1379C During execution, additional data is placed in iw, and pfree
1380C is modified so that components of iw from pfree are free.
1381C On output, pfree is set equal to the size of iw that
1382C would have been needed for no compressions to occur. If
1383C ncmpa is zero, then pfree (on output) is less than or equal to
1384C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
1385C Otherwise, pfree (on output) is greater than iwlen, and all the
1386C memory in iw was used.
1387C-----------------------------------------------------------------------
1388C INPUT/MODIFIED (undefined on output):
1389C-----------------------------------------------------------------------
1390C len: On input, len (i) holds the number of entries in row i of the
1391C matrix, excluding the diagonal. The contents of len (1..n)
1392C are undefined on output.
1393C iw: On input, iw (1..pfree-1) holds the description of each row i
1394C in the matrix. The matrix must be symmetric, and both upper
1395C and lower triangular parts must be present. The diagonal must
1396C not be present. Row i is held as follows:
1397C
1398C len (i): the length of the row i data structure
1399C iw (pe (i) ... pe (i) + len (i) - 1):
1400C the list of column indices for nonzeros
1401C in row i (simple supervariables), excluding
1402C the diagonal. All supervariables start with
1403C one row/column each (supervariable i is just
1404C row i).
1405C if len (i) is zero on input, then pe (i) is ignored
1406C on input.
1407C
1408C Note that the rows need not be in any particular order,
1409C and there may be empty space between the rows.
1410C
1411C During execution, the supervariable i experiences fill-in.
1412C This is represented by placing in i a list of the elements
1413C that cause fill-in in supervariable i:
1414C
1415C len (i): the length of supervariable i
1416C iw (pe (i) ... pe (i) + elen (i) - 1):
1417C the list of elements that contain i. This list
1418C is kept short by removing absorbed elements.
1419C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
1420C the list of supervariables in i. This list
1421C is kept short by removing nonprincipal
1422C variables, and any entry j that is also
1423C contained in at least one of the elements
1424C (j in Le) in the list for i (e in row i).
1425C
1426C When supervariable i is selected as pivot, we create an
1427C element e of the same name (e=i):
1428C
1429C len (e): the length of element e
1430C iw (pe (e) ... pe (e) + len (e) - 1):
1431C the list of supervariables in element e.
1432C
1433C An element represents the fill-in that occurs when supervariable
1434C i is selected as pivot (which represents the selection of row i
1435C and all non-principal variables whose principal variable is i).
1436C We use the term Le to denote the set of all supervariables
1437C in element e. Absorbed supervariables and elements are pruned
1438C from these lists when computationally convenient.
1439C
1440C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
1441C The contents of iw are undefined on output.
1442C-----------------------------------------------------------------------
1443C OUTPUT (need not be set on input):
1444C-----------------------------------------------------------------------
1445C nv: During execution, abs (nv (i)) is equal to the number of rows
1446C that are represented by the principal supervariable i. If i is
1447C a nonprincipal variable, then nv (i) = 0. Initially,
1448C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
1449C principal variable in the pattern Lme of the current pivot
1450C element me. On output, nv (e) holds the true degree of element
1451C e at the time it was created (including the diagonal part).
1452C elen: See the description of iw above. At the start of execution,
1453C elen (i) is set to zero. During execution, elen (i) is the
1454C number of elements in the list for supervariable i. When e
1455C becomes an element, elen (e) = -nel is set, where nel is the
1456C current step of factorization. elen (i) = 0 is done when i
1457C becomes nonprincipal.
1458C
1459C For variables, elen (i) .ge. 0 holds until just before the
1460C permutation vectors are computed. For elements,
1461C elen (e) .lt. 0 holds.
1462C
1463C On output elen (1..n) holds the inverse permutation (the same
1464C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
1465C then row i is the kth pivot row. Row i of A appears as the
1466C (elen(i))-th row in the permuted matrix, PAP^T.
1467C last: In a degree list, last (i) is the supervariable preceding i,
1468C or zero if i is the head of the list. In a hash bucket,
1469C last (i) is the hash key for i. last (head (hash)) is also
1470C used as the head of a hash bucket if head (hash) contains a
1471C degree list (see head, below).
1472C
1473C On output, last (1..n) holds the permutation (the same as the
1474C 'PERM' argument in Sparspak). That is, if i = last (k), then
1475C row i is the kth pivot row. Row last (k) of A is the k-th row
1476C in the permuted matrix, PAP^T.
1477C ncmpa: The number of times iw was compressed. If this is
1478C excessive, then the execution took longer than what could have
1479C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
1480C larger than the value of pfree on input (or at least
1481C iwlen .ge. pfree + n). The fastest performance will be
1482C obtained when ncmpa is returned as zero. If iwlen is set to
1483C the value returned by pfree on *output*, then no compressions
1484C will occur.
1485C-----------------------------------------------------------------------
1486C LOCAL (not input or output - used only during execution):
1487C-----------------------------------------------------------------------
1488C degree: If i is a supervariable, then degree (i) holds the
1489C current approximation of the external degree of row i (an upper
1490C bound). The external degree is the number of nonzeros in row i,
1491C minus abs (nv (i)) (the diagonal part). The bound is equal to
1492C the external degree if elen (i) is less than or equal to two.
1493C
1494C We also use the term "external degree" for elements e to refer
1495C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
1496C which is the degree of the off-diagonal part of the element e
1497C (not including the diagonal part).
1498C head: head is used for degree lists. head (deg) is the first
1499C supervariable in a degree list (all supervariables i in a
1500C degree list deg have the same approximate degree, namely,
1501C deg = degree (i)). If the list deg is empty then
1502C head (deg) = 0.
1503C
1504C During supervariable detection head (hash) also serves as a
1505C pointer to a hash bucket.
1506C If head (hash) .gt. 0, there is a degree list of degree hash.
1507C The hash bucket head pointer is last (head (hash)).
1508C If head (hash) = 0, then the degree list and hash bucket are
1509C both empty.
1510C If head (hash) .lt. 0, then the degree list is empty, and
1511C -head (hash) is the head of the hash bucket.
1512C After supervariable detection is complete, all hash buckets
1513C are empty, and the (last (head (hash)) = 0) condition is
1514C restored for the non-empty degree lists.
1515C next: next (i) is the supervariable following i in a link list, or
1516C zero if i is the last in the list. Used for two kinds of
1517C lists: degree lists and hash buckets (a supervariable can be
1518C in only one kind of list at a time).
1519C w: The flag array w determines the status of elements and
1520C variables, and the external degree of elements.
1521C
1522C for elements:
1523C if w (e) = 0, then the element e is absorbed
1524C if w (e) .ge. wflg, then w (e) - wflg is the size of
1525C the set |Le \ Lme|, in terms of nonzeros (the
1526C sum of abs (nv (i)) for each principal variable i that
1527C is both in the pattern of element e and NOT in the
1528C pattern of the current pivot element, me).
1529C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
1530C not yet been seen in the scan of the element lists in
1531C the computation of |Le\Lme| in loop 150 below.
1532C
1533C for variables:
1534C during supervariable detection, if w (j) .ne. wflg then j is
1535C not in the pattern of variable i
1536C
1537C The w array is initialized by setting w (i) = 1 for all i,
1538C and by setting wflg = 2. It is reinitialized if wflg becomes
1539C too large (to ensure that wflg+n does not cause integer
1540C overflow).
1541C-----------------------------------------------------------------------
1542C LOCAL INTEGERS:
1543C-----------------------------------------------------------------------
1544 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
1545 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
1546 & LENJ, LN, ME, MINDEG, NEL,
1547 & nleft, nvi, nvj, nvpiv, slenme, we, wflg, wnvi, x,
1548 & nprinc
1549 INTEGER KNT1_UPDATED, KNT2_UPDATED
1550 INTEGER(8) :: MAXMEM, MEM, NEWMEM
1551 INTEGER :: MAXINT_N
1552 INTEGER(8) :: HASH, HMOD
1553C deg: the degree of a variable or element
1554C degme: size, |Lme|, of the current element, me (= degree (me))
1555C dext: external degree, |Le \ Lme|, of some element e
1556C dmax: largest |Le| seen so far
1557C e: an element
1558C elenme: the length, elen (me), of element list of pivotal var.
1559C eln: the length, elen (...), of an element list
1560C hash: the computed value of the hash function
1561C hmod: the hash function is computed modulo hmod = max (1,n-1)
1562C i: a supervariable
1563C ilast: the entry in a link list preceding i
1564C inext: the entry in a link list following i
1565C j: a supervariable
1566C jlast: the entry in a link list preceding j
1567C jnext: the entry in a link list, or path, following j
1568C k: the pivot order of an element or variable
1569C knt1: loop counter used during element construction
1570C knt2: loop counter used during element construction
1571C knt3: loop counter used during compression
1572C lenj: len (j)
1573C ln: length of a supervariable list
1574C maxint_n large integer to test risk of overflow on wflg
1575C maxmem: amount of memory needed for no compressions
1576C me: current supervariable being eliminated, and the
1577C current element created by eliminating that
1578C supervariable
1579C mem: memory in use assuming no compressions have occurred
1580C mindeg: current minimum degree
1581C nel: number of pivots selected so far
1582C newmem: amount of new memory needed for current pivot element
1583C nleft: n - nel, the number of nonpivotal rows/columns remaining
1584C nvi: the number of variables in a supervariable i (= nv (i))
1585C nvj: the number of variables in a supervariable j (= nv (j))
1586C nvpiv: number of pivots in current element
1587C slenme: number of variables in variable list of pivotal variable
1588C we: w (e)
1589C wflg: used for flagging the w array. See description of iw.
1590C wnvi: wflg - nv (i)
1591C x: either a supervariable or an element
1592C nprinc : number of principal variables = number of varialbles
1593C of the compressed graph.
1594C (if the graph is not compressed then nprinc = n)
1595C-----------------------------------------------------------------------
1596C LOCAL POINTERS:
1597C-----------------------------------------------------------------------
1598 INTEGER(8) :: P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
1599 & PN, PSRC
1600C Any parameter (pe (...) or pfree) or local variable
1601C starting with "p" (for Pointer) is an index into iw,
1602C and all indices into iw use variables starting with
1603C "p." The only exception to this rule is the iwlen
1604C input argument.
1605C p: pointer into lots of things
1606C p1: pe (i) for some variable i (start of element list)
1607C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
1608C p3: index of first supervariable in clean list
1609C pdst: destination pointer, for compression
1610C pend: end of memory to compress
1611C pj: pointer into an element or variable
1612C pme: pointer into the current element (pme1...pme2)
1613C pme1: the current element, me, is stored in iw (pme1...pme2)
1614C pme2: the end of the current element
1615C pn: pointer into a "clean" variable, also used to compress
1616C psrc: source pointer, for compression
1617C-----------------------------------------------------------------------
1618C FUNCTIONS CALLED:
1619C-----------------------------------------------------------------------
1620 INTRINSIC max, min, mod
1621C=======================================================================
1622C INITIALIZATIONS
1623C=======================================================================
1624 wflg = 2
1625 maxint_n=huge(wflg)-n
1626 mindeg = 1
1627 ncmpa = 0
1628 nel = 0
1629 hmod = int(max(1, n-1),kind=8)
1630 dmax = 0
1631 mem = pfree - 1
1632 maxmem = mem
1633 nprinc = 0
1634 DO i = 1, n
1635 last(i) = 0
1636 head(i) = 0
1637 nv(i) = 1
1638 w(i) = 1
1639 elen(i) = 0
1640 ENDDO
1641 DO i=1, n
1642 IF (len(i).GE.0) THEN
1643 degree(i) = len(i)
1644 nprinc = nprinc + 1
1645 ELSE
1646C i is a secondary variable belonging
1647C to supervariable j=-len (i)
1648 j = -len(i)
1649C used only to skip secondary variables in loop 20
1650 degree(i) = - 1
1651 IF ( pe(i) .NE. 0_8 ) THEN
1652C adjacency list of secondary variable was
1653C provided by the user,
1654C the space will be compressed if necessary
1655 len(i) = len(j)
1656 ELSE
1657 len(i) = 0
1658 ENDIF
1659 pe(i) = int(-j,8)
1660 nv(j) = nv(j) + nv(i)
1661 nv(i) = 0
1662 elen(i) = 0
1663 ENDIF
1664 ENDDO
1665C ----------------------------------------------------------------
1666C initialize degree lists and eliminate rows with no off-diag. nz.
1667C ----------------------------------------------------------------
1668 DO 20 i = 1, n
1669 deg = degree(i)
1670C degree(i) < 0 corresponds to secondary variables
1671C that need be skipped.
1672 IF (deg .GT. 0) THEN
1673C ----------------------------------------------------------
1674C place i in the degree list corresponding to its degree
1675C ----------------------------------------------------------
1676 inext = head(deg)
1677 IF (inext .NE. 0) last(inext) = i
1678 next(i) = inext
1679 head(deg) = i
1680 ELSE IF ( deg.EQ. 0) THEN
1681C ----------------------------------------------------------
1682C we have a variable that can be eliminated at once because
1683C there is no off-diagonal non-zero in its row.
1684C ----------------------------------------------------------
1685C
1686C We have a graph of supervariable and thus need to update
1687C singleton that might already be supervariables with nv(i)
1688C When a supervariable is eliminated its
1689C principal variable must be set to the current step
1690C (NEL+1) which must be stored (negated) in ELEN
1691C ONLY THEN (current step) NEL should be incremented.
1692C This will be exploited when computing the global ordering
1693C of all (secondary and principal) variables at the end of the AMD routine.
1694 elen(i) = - (nel + 1)
1695 nel = nel + nv(i)
1696 pe (i) = 0_8
1697 w(i) = 0
1698 ENDIF
1699 20 CONTINUE
1700C=======================================================================
1701C WHILE (selecting pivots) DO
1702C=======================================================================
1703C
1704C Note that we do want to loop until NEL = N since
1705C we update NEL with the size of the eliminated supervariable
1706C
1707 30 IF (nel .LT. n) THEN
1708C=======================================================================
1709C GET PIVOT OF MINIMUM DEGREE
1710C=======================================================================
1711C -------------------------------------------------------------
1712C find next supervariable for elimination
1713C -------------------------------------------------------------
1714 DO 40 deg = mindeg, n
1715 me = head(deg)
1716 IF (me .GT. 0) GO TO 50
1717 40 CONTINUE
1718 50 mindeg = deg
1719C -------------------------------------------------------------
1720C remove chosen variable from link list
1721C -------------------------------------------------------------
1722 inext = next(me)
1723 IF (inext .NE. 0) last(inext) = 0
1724 head(deg) = inext
1725C -------------------------------------------------------------
1726C me represents the elimination of pivots nel+1 to nel+nv(me).
1727C place me itself as the first in this set. It will be moved
1728C to the nel+nv(me) position when the permutation vectors are
1729C computed.
1730C -------------------------------------------------------------
1731 elenme = elen(me)
1732 elen(me) = - (nel + 1)
1733 nvpiv = nv(me)
1734 nel = nel + nvpiv
1735C=======================================================================
1736C CONSTRUCT NEW ELEMENT
1737C=======================================================================
1738C -------------------------------------------------------------
1739C At this point, me is the pivotal supervariable. It will be
1740C converted into the current element. Scan list of the
1741C pivotal supervariable, me, setting tree pointers and
1742C constructing new list of supervariables for the new element,
1743C me. p is a pointer to the current position in the old list.
1744C -------------------------------------------------------------
1745C flag the variable "me" as being in Lme by negating nv (me)
1746 nv(me) = -nvpiv
1747 degme = 0
1748 IF (elenme .EQ. 0) THEN
1749C ----------------------------------------------------------
1750C construct the new element in place
1751C ----------------------------------------------------------
1752 pme1 = pe(me)
1753 pme2 = pme1 - 1
1754 DO 60 p = pme1, pme1 + int(len(me) - 1,8)
1755 i = iw(p)
1756 nvi = nv(i)
1757 IF (nvi .GT. 0) THEN
1758C ----------------------------------------------------
1759C i is a principal variable not yet placed in Lme.
1760C store i in new list
1761C ----------------------------------------------------
1762 degme = degme + nvi
1763C flag i as being in Lme by negating nv (i)
1764 nv(i) = -nvi
1765 pme2 = pme2 + 1_8
1766 iw(pme2) = i
1767C ----------------------------------------------------
1768C remove variable i from degree list.
1769C ----------------------------------------------------
1770 ilast = last(i)
1771 inext = next(i)
1772 IF (inext .NE. 0) last(inext) = ilast
1773 IF (ilast .NE. 0) THEN
1774 next(ilast) = inext
1775 ELSE
1776C i is at the head of the degree list
1777 head(degree(i)) = inext
1778 ENDIF
1779 ENDIF
1780 60 CONTINUE
1781C this element takes no new memory in iw:
1782 newmem = 0
1783 ELSE
1784C ----------------------------------------------------------
1785C construct the new element in empty space, iw (pfree ...)
1786C ----------------------------------------------------------
1787 p = pe (me)
1788 pme1 = pfree
1789 slenme = len(me) - elenme
1790 knt1_updated = 0
1791 DO 120 knt1 = 1, elenme + 1
1792 knt1_updated = knt1_updated +1
1793 IF (knt1 .GT. elenme) THEN
1794C search the supervariables in me.
1795 e = me
1796 pj = p
1797 ln = slenme
1798 ELSE
1799C search the elements in me.
1800 e = iw(p)
1801 p = p + 1
1802 pj = pe(e)
1803 ln = len(e)
1804 ENDIF
1805C -------------------------------------------------------
1806C search for different supervariables and add them to the
1807C new list, compressing when necessary. this loop is
1808C executed once for each element in the list and once for
1809C all the supervariables in the list.
1810C -------------------------------------------------------
1811 knt2_updated = 0
1812 DO 110 knt2 = 1, ln
1813 knt2_updated = knt2_updated+1
1814 i = iw(pj)
1815 pj = pj + 1
1816 nvi = nv(i)
1817 IF (nvi .GT. 0) THEN
1818C -------------------------------------------------
1819C compress iw, if necessary
1820C -------------------------------------------------
1821 IF (pfree .GT. iwlen) THEN
1822C prepare for compressing iw by adjusting
1823C pointers and lengths so that the lists being
1824C searched in the inner and outer loops contain
1825C only the remaining entries.
1826 pe(me) = p
1827 len(me) = len(me) - knt1_updated
1828C Reset KNT1_UPDATED in case of recompress
1829C at same iteration of the loop 120
1830 knt1_updated = 0
1831C Check if anything left in supervariable ME
1832 IF (len(me) .EQ. 0) pe(me) = 0_8
1833 pe(e) = pj
1834 len(e) = ln - knt2_updated
1835C Reset KNT2_UPDATED in case of recompress
1836C at same iteration of the loop 110
1837 knt2_updated = 0
1838C Check if anything left in element E
1839 IF (len(e) .EQ. 0) pe(e) = 0_8
1840 ncmpa = ncmpa + 1
1841C store first item in pe
1842C set first entry to -item
1843 DO 70 j = 1, n
1844 pn = pe(j)
1845 IF (pn .GT. 0_8) THEN
1846 pe(j) = int(iw(pn),8)
1847 iw(pn) = -j
1848 ENDIF
1849 70 CONTINUE
1850C psrc/pdst point to source/destination
1851 pdst = 1
1852 psrc = 1
1853 pend = pme1 - 1
1854C while loop:
1855 80 CONTINUE
1856 IF (psrc .LE. pend) THEN
1857C search for next negative entry
1858 j = -iw(psrc)
1859 psrc = psrc + 1
1860 IF (j .GT. 0) THEN
1861 iw(pdst) = int(pe(j))
1862 pe(j) = pdst
1863 pdst = pdst + 1_8
1864C copy from source to destination
1865 lenj = len(j)
1866 DO 90 knt3 = 0, lenj - 2
1867 iw(pdst + knt3) = iw(psrc + knt3)
1868 90 CONTINUE
1869 pdst = pdst + int(lenj - 1,8)
1870 psrc = psrc + int(lenj - 1,8)
1871 ENDIF
1872 GO TO 80
1873 ENDIF
1874C move the new partially-constructed element
1875 p1 = pdst
1876 DO 100 psrc = pme1, pfree - 1
1877 iw(pdst) = iw(psrc)
1878 pdst = pdst + 1
1879 100 CONTINUE
1880 pme1 = p1
1881 pfree = pdst
1882 pj = pe(e)
1883 p = pe(me)
1884 ENDIF
1885C -------------------------------------------------
1886C i is a principal variable not yet placed in Lme
1887C store i in new list
1888C -------------------------------------------------
1889 degme = degme + nvi
1890C flag i as being in Lme by negating nv (i)
1891 nv(i) = -nvi
1892 iw(pfree) = i
1893 pfree = pfree + 1
1894C -------------------------------------------------
1895C remove variable i from degree link list
1896C -------------------------------------------------
1897 ilast = last(i)
1898 inext = next(i)
1899 IF (inext .NE. 0) last(inext) = ilast
1900 IF (ilast .NE. 0) THEN
1901 next(ilast) = inext
1902 ELSE
1903C i is at the head of the degree list
1904 head(degree(i)) = inext
1905 ENDIF
1906 ENDIF
1907 110 CONTINUE
1908 IF (e .NE. me) THEN
1909C set tree pointer and flag to indicate element e is
1910C absorbed into new element me (the parent of e is me)
1911 pe(e) = int(-me,8)
1912 w(e) = 0
1913 ENDIF
1914 120 CONTINUE
1915 pme2 = pfree - 1
1916C this element takes newmem new memory in iw (possibly zero)
1917 newmem = pfree - pme1
1918 mem = mem + newmem
1919 maxmem = max(maxmem, mem)
1920 ENDIF
1921C -------------------------------------------------------------
1922C me has now been converted into an element in iw (pme1..pme2)
1923C -------------------------------------------------------------
1924C degme holds the external degree of new element
1925 degree(me) = degme
1926 pe(me) = pme1
1927 len(me) = int(pme2 - pme1 + 1)
1928C -------------------------------------------------------------
1929C make sure that wflg is not too large. With the current
1930C value of wflg, wflg+n must not cause integer overflow
1931C -------------------------------------------------------------
1932 IF (wflg .GT. maxint_n) THEN
1933 DO 130 x = 1, n
1934 IF (w(x) .NE. 0) w(x) = 1
1935 130 CONTINUE
1936 wflg = 2
1937 ENDIF
1938C=======================================================================
1939C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
1940C=======================================================================
1941C -------------------------------------------------------------
1942C Scan 1: compute the external degrees of previous elements
1943C with respect to the current element. That is:
1944C (w (e) - wflg) = |Le \ Lme|
1945C for each element e that appears in any supervariable in Lme.
1946C The notation Le refers to the pattern (list of
1947C supervariables) of a previous element e, where e is not yet
1948C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
1949C The notation Lme refers to the pattern of the current element
1950C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
1951C zero, then the element e will be absorbed in scan 2.
1952C -------------------------------------------------------------
1953 DO 150 pme = pme1, pme2
1954 i = iw(pme)
1955 eln = elen(i)
1956 IF (eln .GT. 0) THEN
1957C note that nv (i) has been negated to denote i in Lme:
1958 nvi = -nv(i)
1959 wnvi = wflg - nvi
1960 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
1961 e = iw(p)
1962 we = w(e)
1963 IF (we .GE. wflg) THEN
1964C unabsorbed element e has been seen in this loop
1965 we = we - nvi
1966 ELSE IF (we .NE. 0) THEN
1967C e is an unabsorbed element
1968C this is the first we have seen e in all of Scan 1
1969 we = degree(e) + wnvi
1970 ENDIF
1971 w(e) = we
1972 140 CONTINUE
1973 ENDIF
1974 150 CONTINUE
1975C=======================================================================
1976C DEGREE UPDATE AND ELEMENT ABSORPTION
1977C=======================================================================
1978C -------------------------------------------------------------
1979C Scan 2: for each i in Lme, sum up the degree of Lme (which
1980C is degme), plus the sum of the external degrees of each Le
1981C for the elements e appearing within i, plus the
1982C supervariables in i. Place i in hash list.
1983C -------------------------------------------------------------
1984 DO 180 pme = pme1, pme2
1985 i = iw(pme)
1986 p1 = pe(i)
1987 p2 = p1 + int(elen(i) - 1,8)
1988 pn = p1
1989 hash = 0_8
1990 deg = 0
1991C ----------------------------------------------------------
1992C scan the element list associated with supervariable i
1993C ----------------------------------------------------------
1994 DO 160 p = p1, p2
1995 e = iw(p)
1996C dext = | Le \ Lme |
1997 dext = w(e) - wflg
1998 IF (dext .GT. 0) THEN
1999 deg = deg + dext
2000 iw(pn) = e
2001 pn = pn + 1
2002 hash = hash + int(e,kind=8)
2003 ELSE IF (dext .EQ. 0) THEN
2004#if defined (NOAGG2)
2005 iw(pn) = e
2006 pn = pn + 1
2007 hash = hash + int(e,kind=8)
2008#else
2009C aggressive absorption: e is not adjacent to me, but
2010C the |Le \ Lme| is 0, so absorb it into me
2011 pe(e) = int(-me,8)
2012 w(e) = 0
2013#endif
2014 ENDIF
2015 160 CONTINUE
2016C count the number of elements in i (including me):
2017 elen(i) = int(pn - p1 + 1_8)
2018C ----------------------------------------------------------
2019C scan the supervariables in the list associated with i
2020C ----------------------------------------------------------
2021 p3 = pn
2022 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
2023 j = iw(p)
2024 nvj = nv(j)
2025 IF (nvj .GT. 0) THEN
2026C j is unabsorbed, and not in Lme.
2027C add to degree and add to new list
2028 deg = deg + nvj
2029 iw(pn) = j
2030 pn = pn + 1
2031 hash = hash + int(j,kind=8)
2032 ENDIF
2033 170 CONTINUE
2034C ----------------------------------------------------------
2035C update the degree and check for mass elimination
2036C ----------------------------------------------------------
2037#if defined (NOAGG2)
2038 IF (deg.EQ.0.AND.(elen(i).GT.1)) THEN
2039C When DEG is zero we need to
2040C absorb in ME all elements adjacent to I
2041 p1 = pe(i)
2042C exclude ME --> -2
2043 p2 = p1 + int(elen(i),8) - 2_8
2044 DO p =p1,p2
2045 e = iw(p)
2046 pe(e) = int(-me,8)
2047 w(e) = 0
2048 ENDDO
2049 ENDIF
2050C .... Ready for mass elimination
2051#endif
2052 IF (deg .EQ. 0) THEN
2053C -------------------------------------------------------
2054C mass elimination
2055C -------------------------------------------------------
2056C There is nothing left of this node except for an
2057C edge to the current pivot element. elen (i) is 1,
2058C and there are no variables adjacent to node i.
2059C Absorb i into the current pivot element, me.
2060 pe(i) = int(-me,8)
2061 nvi = -nv(i)
2062 degme = degme - nvi
2063 nvpiv = nvpiv + nvi
2064 nel = nel + nvi
2065 nv(i) = 0
2066 elen(i) = 0
2067 ELSE
2068C -------------------------------------------------------
2069C update the upper-bound degree of i
2070C -------------------------------------------------------
2071C the following degree does not yet include the size
2072C of the current element, which is added later:
2073 degree(i) = min(degree(i), deg)
2074C -------------------------------------------------------
2075C add me to the list for i
2076C -------------------------------------------------------
2077C move first supervariable to end of list
2078 iw(pn) = iw(p3)
2079C move first element to end of element part of list
2080 iw(p3) = iw(p1)
2081C add new element to front of list.
2082 iw(p1) = me
2083C store the new length of the list in len (i)
2084 len(i) = int(pn - p1 + 1_8)
2085C -------------------------------------------------------
2086C place in hash bucket. Save hash key of i in last (i).
2087C -------------------------------------------------------
2088 hash = mod(hash, hmod) + 1_8
2089 j = head(hash)
2090 IF (j .LE. 0) THEN
2091C the degree list is empty, hash head is -j
2092 next(i) = -j
2093 head(hash) = -i
2094 ELSE
2095C degree list is not empty
2096C use last (head (hash)) as hash head
2097 next(i) = last(j)
2098 last(j) = i
2099 ENDIF
2100 last(i) = int(hash,kind=kind(last))
2101 ENDIF
2102 180 CONTINUE
2103 degree(me) = degme
2104C -------------------------------------------------------------
2105C Clear the counter array, w (...), by incrementing wflg.
2106C -------------------------------------------------------------
2107 dmax = max(dmax, degme)
2108 wflg = wflg + dmax
2109C make sure that wflg+n does not cause integer overflow
2110 IF (wflg .GT. maxint_n) THEN
2111 DO 190 x = 1, n
2112 IF (w(x) .NE. 0) w(x) = 1
2113 190 CONTINUE
2114 wflg = 2
2115 ENDIF
2116C at this point, w (1..n) .lt. wflg holds
2117C=======================================================================
2118C SUPERVARIABLE DETECTION
2119C=======================================================================
2120 DO 250 pme = pme1, pme2
2121 i = iw(pme)
2122 IF (nv(i) .LT. 0) THEN
2123C i is a principal variable in Lme
2124C -------------------------------------------------------
2125C examine all hash buckets with 2 or more variables. We
2126C do this by examing all unique hash keys for super-
2127C variables in the pattern Lme of the current element, me
2128C -------------------------------------------------------
2129 hash = int(last(i),kind=8)
2130C let i = head of hash bucket, and empty the hash bucket
2131 j = head(hash)
2132 IF (j .EQ. 0) GO TO 250
2133 IF (j .LT. 0) THEN
2134C degree list is empty
2135 i = -j
2136 head(hash) = 0
2137 ELSE
2138C degree list is not empty, restore last () of head
2139 i = last(j)
2140 last(j) = 0
2141 ENDIF
2142 IF (i .EQ. 0) GO TO 250
2143C while loop:
2144 200 CONTINUE
2145 IF (next(i) .NE. 0) THEN
2146C ----------------------------------------------------
2147C this bucket has one or more variables following i.
2148C scan all of them to see if i can absorb any entries
2149C that follow i in hash bucket. Scatter i into w.
2150C ----------------------------------------------------
2151 ln = len(i)
2152 eln = elen(i)
2153C do not flag the first element in the list (me)
2154 DO 210 p = pe(i) + 1, pe(i) + int(ln - 1,8)
2155 w (iw(p)) = wflg
2156 210 CONTINUE
2157C ----------------------------------------------------
2158C scan every other entry j following i in bucket
2159C ----------------------------------------------------
2160 jlast = i
2161 j = next(i)
2162C while loop:
2163 220 CONTINUE
2164 IF (j .NE. 0) THEN
2165C -------------------------------------------------
2166C check if j and i have identical nonzero pattern
2167C -------------------------------------------------
2168C jump if i and j do not have same size data structure
2169 IF (len(j) .NE. ln) GO TO 240
2170C jump if i and j do not have same number adj elts
2171 IF (elen(j) .NE. eln) GO TO 240
2172C do not flag the first element in the list (me)
2173 DO 230 p = pe(j) + 1, pe(j) + int(ln - 1,8)
2174C jump if an entry (iw(p)) is in j but not in i
2175 IF (w(iw(p)) .NE. wflg) GO TO 240
2176 230 CONTINUE
2177C -------------------------------------------------
2178C found it! j can be absorbed into i
2179C -------------------------------------------------
2180 pe(j) = int(-i,8)
2181C both nv (i) and nv (j) are negated since they
2182C are in Lme, and the absolute values of each
2183C are the number of variables in i and j:
2184 nv(i) = nv(i) + nv(j)
2185 nv(j) = 0
2186 elen(j) = 0
2187C delete j from hash bucket
2188 j = next(j)
2189 next(jlast) = j
2190 GO TO 220
2191C -------------------------------------------------
2192 240 CONTINUE
2193C j cannot be absorbed into i
2194C -------------------------------------------------
2195 jlast = j
2196 j = next(j)
2197 GO TO 220
2198 ENDIF
2199C ----------------------------------------------------
2200C no more variables can be absorbed into i
2201C go to next i in bucket and clear flag array
2202C ----------------------------------------------------
2203 wflg = wflg + 1
2204 i = next(i)
2205 IF (i .NE. 0) GO TO 200
2206 ENDIF
2207 ENDIF
2208 250 CONTINUE
2209C=======================================================================
2210C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
2211C=======================================================================
2212 p = pme1
2213 nleft = n - nel
2214 DO 260 pme = pme1, pme2
2215 i = iw(pme)
2216 nvi = -nv(i)
2217 IF (nvi .GT. 0) THEN
2218C i is a principal variable in Lme
2219C restore nv (i) to signify that i is principal
2220 nv(i) = nvi
2221C -------------------------------------------------------
2222C compute the external degree (add size of current elem)
2223C -------------------------------------------------------
2224 deg = min(degree(i) + degme - nvi, nleft - nvi)
2225C -------------------------------------------------------
2226C place the supervariable at the head of the degree list
2227C -------------------------------------------------------
2228 inext = head (deg)
2229 IF (inext .NE. 0) last(inext) = i
2230 next(i) = inext
2231 last (i) = 0
2232 head(deg) = i
2233C -------------------------------------------------------
2234C save the new degree, and find the minimum degree
2235C -------------------------------------------------------
2236 mindeg = min(mindeg, deg)
2237 degree(i) = deg
2238C -------------------------------------------------------
2239C place the supervariable in the element pattern
2240C -------------------------------------------------------
2241 iw(p) = i
2242 p = p + 1
2243 ENDIF
2244 260 CONTINUE
2245C=======================================================================
2246C FINALIZE THE NEW ELEMENT
2247C=======================================================================
2248 nv(me) = nvpiv + degme
2249C nv (me) is now the degree of pivot (including diagonal part)
2250C save the length of the list for the new element me
2251 len(me) = int(p - pme1)
2252 IF (len(me) .EQ. 0) THEN
2253C there is nothing left of the current pivot element
2254 pe(me) = 0_8
2255 w(me) = 0
2256 ENDIF
2257 IF (newmem .NE. 0) THEN
2258C element was not constructed in place: deallocate part
2259C of it (final size is less than or equal to newmem,
2260C since newly nonprincipal variables have been removed).
2261 pfree = p
2262 mem = mem - newmem + int(len(me),8)
2263 ENDIF
2264C=======================================================================
2265C END WHILE (selecting pivots)
2266 GO TO 30
2267 ENDIF
2268C=======================================================================
2269C=======================================================================
2270C COMPUTE THE PERMUTATION VECTORS
2271C=======================================================================
2272C ----------------------------------------------------------------
2273C The time taken by the following code is O(n). At this
2274C point, elen (e) = -k has been done for all elements e,
2275C and elen (i) = 0 has been done for all nonprincipal
2276C variables i. At this point, there are no principal
2277C supervariables left, and all elements are absorbed.
2278C ----------------------------------------------------------------
2279C ----------------------------------------------------------------
2280C compute the ordering of unordered nonprincipal variables
2281C ----------------------------------------------------------------
2282 DO 290 i = 1, n
2283 IF (elen(i) .EQ. 0) THEN
2284C ----------------------------------------------------------
2285C i is an un-ordered row. Traverse the tree from i until
2286C reaching an element, e. The element, e, was the
2287C principal supervariable of i and all nodes in the path
2288C from i to when e was selected as pivot.
2289C ----------------------------------------------------------
2290 j = int(-pe(i))
2291C while (j is a variable) do:
2292 270 CONTINUE
2293 IF (elen(j) .GE. 0) THEN
2294 j = int(-pe(j))
2295 GO TO 270
2296 ENDIF
2297 e = j
2298C ----------------------------------------------------------
2299C get the current pivot ordering of e
2300C ----------------------------------------------------------
2301 k = -elen(e)
2302C ----------------------------------------------------------
2303C traverse the path again from i to e, and compress the
2304C path (all nodes point to e). Path compression allows
2305C this code to compute in O(n) time. Order the unordered
2306C nodes in the path, and place the element e at the end.
2307C ----------------------------------------------------------
2308 j = i
2309C while (j is a variable) do:
2310 280 CONTINUE
2311 IF (elen(j) .GE. 0) THEN
2312 jnext = int(-pe(j))
2313 pe(j) = int(-e,8)
2314 IF (elen(j) .EQ. 0) THEN
2315C j is an unordered row
2316 elen(j) = k
2317 k = k + 1
2318 ENDIF
2319 j = jnext
2320 GO TO 280
2321 ENDIF
2322C leave elen (e) negative, so we know it is an element
2323 elen(e) = -k
2324 ENDIF
2325 290 CONTINUE
2326C ----------------------------------------------------------------
2327C reset the inverse permutation (elen (1..n)) to be positive,
2328C and compute the permutation (last (1..n)).
2329C ----------------------------------------------------------------
2330 DO 300 i = 1, n
2331 k = abs(elen(i))
2332 last(k) = i
2333 elen(i) = k
2334 300 CONTINUE
2335C=======================================================================
2336C RETURN THE MEMORY USAGE IN IW
2337C=======================================================================
2338C If maxmem is less than or equal to iwlen, then no compressions
2339C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
2340C compressions did occur, and iwlen would have had to have been
2341C greater than or equal to maxmem for no compressions to occur.
2342C Return the value of maxmem in the pfree argument.
2343 pfree = maxmem
2344C===============================
2345C Save PE in PARENT array
2346 DO i=1,n
2347 parent(i) = int(pe(i))
2348 ENDDO
2349C===============================
2350 RETURN
2351 END SUBROUTINE mumps_amd_elt
2352C ----------------------------------------------------------------------
2353C Description of MUMPS_HAMD:
2354C MUMPS_HAMD is a modification of AMD reference code (MUMPS_ANA_H)
2355C designed to take into account a halo in the graph.
2356C The graph is composed is partitioned in two types of nodes
2357C the so called internal nodes and the so called halo nodes.
2358C Halo nodes cannot be selected the both the inital degrees
2359C and updated degrees of internal node should be taken
2360C into account.
2361C This routine also referred to as HALOAMD in MUMPS comments
2362C is used for both Schur functionality and in the coupling with
2363C partitioners such as SCOTCH.
2364C
2365C Restrictive integer 64 bit variant :
2366C it is assumed that IW array size can exceed 32-bit integer
2367C
2368C
2369 SUBROUTINE mumps_hamd(N, IWLEN, PE, PFREE, LEN, IW, NV, ELEN,
2370 & LAST, NCMPA, DEGREE, HEAD, NEXT, W, PARENT,
2371 & LISTVAR_SCHUR, SIZE_SCHUR)
2372C
2373C Parameters
2374C Input not modified
2375 INTEGER, intent(in) :: SIZE_SCHUR
2376 INTEGER, intent(in) :: LISTVAR_SCHUR(SIZE_SCHUR)
2377 INTEGER, INTENT(IN) :: N
2378 INTEGER(8), INTENT(IN) :: IWLEN
2379C Input undefined on output
2380 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
2381C
2382C Output only
2383 INTEGER, INTENT(OUT) :: NCMPA
2384 INTEGER, INTENT(OUT) :: NV(N), ELEN(N), LAST(N), PARENT(N)
2385C
2386C Input/output
2387 INTEGER(8), INTENT(INOUT) :: PFREE
2388 INTEGER(8), INTENT(INOUT) :: PE(N)
2389C
2390C Internal Workspace only
2391 INTEGER :: NEXT(N), DEGREE(N), HEAD(N), W(N)
2392C
2393C ---------------------
2394C Interface Description
2395C ---------------------
2396C HAMD (short for HALOAMD)
2397C The initial version (so called HALOAMD_V1, developped in September 1997)
2398C is designed to experiment the numerical (fill-in) impact
2399C of taking into account the halo. This code should be able
2400C to experiment no-halo, partial halo, complete halo.
2401C DATE: September 17th 1997
2402C
2403C HALOAMD is designed to process a gragh composed of two types
2404C of nodes, V0 and V1, extracted from a larger gragh.
2405C V0^V1 = {},
2406C
2407C We used Min. degree heuristic to order only
2408C nodes in V0, but the adjacency to nodes
2409C in V1 is taken into account during ordering.
2410C Nodes in V1 are odered at last.
2411C Adjacency between nodes of V1 need not be provided,
2412C however |len(i)| must always corresponds to the number of
2413C edges effectively provided in the adjacency list of i.
2414C On input :
2415C ********
2416C Nodes INODE in V1 are flagged with len(INODE) = -degree
2417C modif version HALO V3 (August 1998):
2418C if len(i) =0 and i \in V1 then
2419C len(i) must be set on input to -N-1
2420C ERROR return (negative values in ncmpa)
2421C ************
2422C negative value in ncmpa indicates an error detected
2423C by HALOAMD.
2424C
2425C The graph provided MUST follow the rule:
2426C if (i,j) is an edge in the gragh then
2427C j must be in the adjacency list of i AND
2428C i must be in the adjacency list of j.
2429C REMARKS:
2430C 1/ Providing edges between nodes of V1 should not
2431C affect the final ordering, only the amount of edges
2432C of the halo should effectively affect the solution.
2433C This code should work in the following cases:
2434C 1/ halo not provided
2435C 2/ halo partially provided
2436C 3/ complete halo
2437C 4/ complete halo+interconnection between nodes of V1.
2438C
2439C 1/ should run and provide identical results (w.r.t to current
2440C implementation of AMD in SCOTCH).
2441C 3/ and 4 should provide identical results.
2442C
2443C 2/ All modifications of the AMD initial code are indicated
2444C with begin HALO .. end HALO
2445C
2446C
2447C Ordering of nodes in V0 is based on
2448C Approximate Minimum Degree ordering algorithm,
2449C with aggressive absorption:
2450C Given a representation of the nonzero pattern of a symmetric matrix,
2451C A, (excluding the diagonal) perform an approximate minimum
2452C degree ordering to compute a pivot order
2453C such that fill-in in the Cholesky factors A = LL^T is kept low.
2454C
2455C ------------------------------
2456C Modification history:
2457C ---------------------
2458C Date: September, 1997 (V1)
2459C April, 1998 (V2)
2460C August, 1998 (V3)
2461C Octobre, 1998 (V4)
2462C December, 1998 (V5)
2463C January, 1999 (V6)
2464C HALOAMD_V6:
2465C ----------
2466C 1/ ERROR 2 detection followed by stop statement suppressed
2467C . 2/ pb 1 identified in V5 was not correctly solved
2468C
2469C HALOAMD_V5:
2470C ----------
2471C 1/ Pb with matrix psmigr 1, because upper bound
2472C degree DEG >N was considered as a node in V1
2473C
2474C HALOAMD_V4:
2475C ----------
2476C Only UnsymetrizedMultifrontal interface
2477C (ok for both scotch and UnsymetricMultifrontal) is
2478C included in this file
2479C
2480C HALOAMD_V3:
2481C ----------
2482C Problem in version 2 : variables of V1 with len(i) =0
2483C are not well processed.
2484C See modification of the
2485C input to characterize those variables.
2486C
2487C Problem detected by Jacko Koster while experimenting with
2488C version 2 of haloAMD in the context of multiple front method :
2489C "if for an interface variable i, row i in the matrix has only a
2490C nonzero entry on the diagonal, we first remove this entry and len(i)
2491C is set to zero on input to HALOAMD. However, this means that HALOAMD
2492C will treat variable i as an interior variable (in V0) instead as an
2493C interface variable (in V1). (It is indeed a bit strange to have such
2494C interface variables but we encountered some in our debugging
2495C experiments with some random partitionings.)
2496C
2497C Solution :
2498C IF on input i \in V1 and len(i) =0 (that is adjlist(i)={}) THEN
2499C len(i) must be set on input to -N-1.
2500C ENDIF
2501C therefore all variables i / len(i) < 0 an only those are in V1
2502C variable with len(i) = -N-1 are then processed differently at
2503C the beginning of the code
2504C
2505C HALOAMD_V2:
2506C ----------
2507C The end of the tree (including links to block of flagged indices
2508C is built) . The list of flagged indices is
2509C considered as a dense amalgamated node.
2510C
2511C Comments on the OUTPUT:
2512C ----------------------
2513C Let V= V0 U V1 the nodes of the initial graph (|V|=n).
2514C The assembly tree corresponds to the tree
2515C of the supernodes (or supervariables). Each node of the
2516C assembly tree is then composed of one principal variable
2517C and a list of secondary variables. The list of
2518C variable of a node (principal + secondary variables) then
2519C describes the structure of the diagonal bloc of the
2520C supernode.
2521C The elimination tree denotes the tree of all the variables(=node) and
2522C is therefore of order n.
2523C
2524C The arrays NV(N) and PE(N) give a description of the
2525C assembly tree.
2526C 1/ Description of array nv(N) (on OUPUT)
2527C nv(i)=0 i is a secondary variable
2528C N+1> nv(i) >0 i is a principal variable, nv(i) holds the
2529C the number of elements in column i of L (true degree of i)
2530C 2/ Description of array PE(N) (on OUPUT)
2531C pe(i) = -(father of variable/node i) in the elimination tree:
2532C If nv (i) .gt. 0, then i represents a node in the assembly tree,
2533C and the parent of i is -pe (i), or zero if i is a root.
2534C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
2535C subtree, the root of which is a node in the assembly tree.
2536C 3/ Example:
2537C Let If be a root node father of Is in the assembly tree.
2538C If is the principal
2539C variable of the node If and let If1, If2, If3 be the
2540C secondary variables of node If.
2541C Is is the principal
2542C variable of the node Is and let Is1, Is2 be the secondary variables
2543C of node Is.
2544C
2545C THEN:
2546C NV(If1)=NV(If2)=NV(If3) = 0 (secondary variables)
2547C NV(Is1)=NV(Is2) = 0 (secondary variables)
2548C NV(If) > 0 ( principal variable)
2549C NV(Is) > 0 ( principal variable)
2550C PE(If) = 0 (root node)
2551C PE(Is) = -If (If is the father of Is in the assembly tree)
2552C PE(If1)=PE(If2)=PE(If3)= -If ( If is the principal variable)
2553C PE(Is1)=PE(Is2)= -Is ( Is is the principal variable)
2554C-----------------------------------------------------------------------
2555C INPUT ARGUMENTS (unaltered):
2556C-----------------------------------------------------------------------
2557C n: The matrix order.
2558C
2559C Restriction: n .ge. 1
2560C iwlen: The length of iw (1..iwlen). On input, the matrix is
2561C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
2562C slightly larger than what is required to hold the matrix, at
2563C least iwlen .ge. pfree + n is recommended. Otherwise,
2564C excessive compressions will take place.
2565C *** We do not recommend running this algorithm with ***
2566C *** iwlen .lt. pfree + n. ***
2567C *** Better performance will be obtained if ***
2568C *** iwlen .ge. pfree + n ***
2569C *** or better yet ***
2570C *** iwlen .gt. 1.2 * pfree ***
2571C *** (where pfree is its value on input). ***
2572C The algorithm will not run at all if iwlen .lt. pfree-1.
2573C
2574C Restriction: iwlen .ge. pfree-1
2575C-----------------------------------------------------------------------
2576C INPUT/OUPUT ARGUMENTS:
2577C-----------------------------------------------------------------------
2578C pe: On input, pe (i) is the index in iw of the start of row i, or
2579C zero if row i has no off-diagonal non-zeros.
2580C
2581C During execution, it is used for both supervariables and
2582C elements:
2583C
2584C * Principal supervariable i: index into iw of the
2585C description of supervariable i. A supervariable
2586C represents one or more rows of the matrix
2587C with identical nonzero pattern.
2588C * Non-principal supervariable i: if i has been absorbed
2589C into another supervariable j, then pe (i) = -j.
2590C That is, j has the same pattern as i.
2591C Note that j might later be absorbed into another
2592C supervariable j2, in which case pe (i) is still -j,
2593C and pe (j) = -j2.
2594C * Unabsorbed element e: the index into iw of the description
2595C of element e, if e has not yet been absorbed by a
2596C subsequent element. Element e is created when
2597C the supervariable of the same name is selected as
2598C the pivot.
2599C * Absorbed element e: if element e is absorbed into element
2600C e2, then pe (e) = -e2. This occurs when the pattern of
2601C e (that is, Le) is found to be a subset of the pattern
2602C of e2 (that is, Le2). If element e is "null" (it has
2603C no nonzeros outside its pivot block), then pe (e) = 0.
2604C
2605C On output, pe holds the assembly tree/forest, which implicitly
2606C represents a pivot order with identical fill-in as the actual
2607C order (via a depth-first search of the tree).
2608C
2609C On output:
2610C If nv (i) .gt. 0, then i represents a node in the assembly tree,
2611C and the parent of i is -pe (i), or zero if i is a root.
2612C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
2613C subtree, the root of which is a node in the assembly tree.
2614C On output: (PE is copied on output into PARENT array)
2615C
2616C pfree: On input, the matrix is stored in iw (1..pfree-1) and
2617C the rest of the array iw is free.
2618C During execution, additional data is placed in iw, and pfree
2619C is modified so that components of iw from pfree are free.
2620C On output, pfree is set equal to the size of iw that
2621C would have been needed for no compressions to occur. If
2622C ncmpa is zero, then pfree (on output) is less than or equal to
2623C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
2624C Otherwise, pfree (on output) is greater than iwlen, and all the
2625C memory in iw was used.
2626C-----------------------------------------------------------------------
2627C INPUT/MODIFIED (undefined on output):
2628C-----------------------------------------------------------------------
2629C len: On input, len (i)
2630C positive or null (>=0) : i \in V0 and
2631C len(i) holds the number of entries in row i of the
2632C matrix, excluding the diagonal.
2633C negative (<0) : i \in V1, and
2634C -len(i) hold the number of entries in row i of the
2635C matrix, excluding the diagonal.
2636C len(i) = - | Adj(i) | if i \in V1
2637C or -N -1 if | Adj(i) | = 0 and i \in V1
2638C The contents of len (1..n)
2639C are undefined on output.
2640C iw: On input, iw (1..pfree-1) holds the description of each row i
2641C in the matrix. The matrix must be symmetric, and both upper
2642C and lower triangular parts must be present. The diagonal must
2643C not be present. Row i is held as follows:
2644C
2645C len (i): the length of the row i data structure
2646C iw (pe (i) ... pe (i) + len (i) - 1):
2647C the list of column indices for nonzeros
2648C in row i (simple supervariables), excluding
2649C the diagonal. All supervariables start with
2650C one row/column each (supervariable i is just
2651C row i).
2652C if len (i) is zero on input, then pe (i) is ignored
2653C on input.
2654C
2655C Note that the rows need not be in any particular order,
2656C and there may be empty space between the rows.
2657C
2658C During execution, the supervariable i experiences fill-in.
2659C This is represented by placing in i a list of the elements
2660C that cause fill-in in supervariable i:
2661C
2662C len (i): the length of supervariable i
2663C iw (pe (i) ... pe (i) + elen (i) - 1):
2664C the list of elements that contain i. This list
2665C is kept short by removing absorbed elements.
2666C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
2667C the list of supervariables in i. This list
2668C is kept short by removing nonprincipal
2669C variables, and any entry j that is also
2670C contained in at least one of the elements
2671C (j in Le) in the list for i (e in row i).
2672C
2673C When supervariable i is selected as pivot, we create an
2674C element e of the same name (e=i):
2675C
2676C len (e): the length of element e
2677C iw (pe (e) ... pe (e) + len (e) - 1):
2678C the list of supervariables in element e.
2679C
2680C An element represents the fill-in that occurs when supervariable
2681C i is selected as pivot (which represents the selection of row i
2682C and all non-principal variables whose principal variable is i).
2683C We use the term Le to denote the set of all supervariables
2684C in element e. Absorbed supervariables and elements are pruned
2685C from these lists when computationally convenient.
2686C
2687C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
2688C The contents of iw are undefined on output.
2689C-----------------------------------------------------------------------
2690C OUTPUT (need not be set on input):
2691C-----------------------------------------------------------------------
2692C nv: During execution, abs (nv (i)) is equal to the number of rows
2693C that are represented by the principal supervariable i. If i is
2694C a nonprincipal variable, then nv (i) = 0. Initially,
2695C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
2696C principal variable in the pattern Lme of the current pivot
2697C element me. On output, nv (e) holds the true degree of element
2698C e at the time it was created (including the diagonal part).
2699C begin HALO
2700C On output, nv(I) can be used to find node in set V1.
2701C nv(I) = N+1 characterizes nodes in V1.
2702C end HALO
2703C elen: See the description of iw above. At the start of execution,
2704C elen (i) is set to zero. During execution, elen (i) is the
2705C number of elements in the list for supervariable i. When e
2706C becomes an element, elen (e) = -nel is set, where nel is the
2707C current step of factorization. elen (i) = 0 is done when i
2708C becomes nonprincipal.
2709C
2710C For variables, elen (i) .ge. 0 holds until just before the
2711C permutation vectors are computed. For elements,
2712C elen (e) .lt. 0 holds.
2713C
2714C On output elen (1..n) holds the inverse permutation (the same
2715C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
2716C then row i is the kth pivot row. Row i of A appears as the
2717C (elen(i))-th row in the permuted matrix, PAP^T.
2718C last: In a degree list, last (i) is the supervariable preceding i,
2719C or zero if i is the head of the list. In a hash bucket,
2720C last (i) is the hash key for i. last (head (hash)) is also
2721C used as the head of a hash bucket if head (hash) contains a
2722C degree list (see head, below).
2723C
2724C On output, last (1..n) holds the permutation (the same as the
2725C 'PERM' argument in Sparspak). That is, if i = last (k), then
2726C row i is the kth pivot row. Row last (k) of A is the k-th row
2727C in the permuted matrix, PAP^T.
2728C ncmpa: The number of times iw was compressed. If this is
2729C excessive, then the execution took longer than what could have
2730C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
2731C larger than the value of pfree on input (or at least
2732C iwlen .ge. pfree + n). The fastest performance will be
2733C obtained when ncmpa is returned as zero. If iwlen is set to
2734C the value returned by pfree on *output*, then no compressions
2735C will occur.
2736C begin HALO
2737C on output ncmpa <0 --> error detected during HALO_AMD:
2738C error 1: ncmpa = -N , ordering was stopped.
2739C end HALO
2740C
2741C-----------------------------------------------------------------------
2742C LOCAL (not input or output - used only during execution):
2743C-----------------------------------------------------------------------
2744C degree: If i is a supervariable, then degree (i) holds the
2745C current approximation of the external degree of row i (an upper
2746C bound). The external degree is the number of nonzeros in row i,
2747C minus abs (nv (i)) (the diagonal part). The bound is equal to
2748C the external degree if elen (i) is less than or equal to two.
2749C We also use the term "external degree" for elements e to refer
2750C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
2751C which is the degree of the off-diagonal part of the element e
2752C (not including the diagonal part).
2753C begin HALO
2754C degree(I) = n+1 indicates that i belongs to V1
2755C end HALO
2756C
2757C head: head is used for degree lists. head (deg) is the first
2758C supervariable in a degree list (all supervariables i in a
2759C degree list deg have the same approximate degree, namely,
2760C deg = degree (i)). If the list deg is empty then
2761C head (deg) = 0.
2762C
2763C During supervariable detection head (hash) also serves as a
2764C pointer to a hash bucket.
2765C If head (hash) .gt. 0, there is a degree list of degree hash.
2766C The hash bucket head pointer is last (head (hash)).
2767C If head (hash) = 0, then the degree list and hash bucket are
2768C both empty.
2769C If head (hash) .lt. 0, then the degree list is empty, and
2770C -head (hash) is the head of the hash bucket.
2771C After supervariable detection is complete, all hash buckets
2772C are empty, and the (last (head (hash)) = 0) condition is
2773C restored for the non-empty degree lists.
2774C next: next (i) is the supervariable following i in a link list, or
2775C zero if i is the last in the list. Used for two kinds of
2776C lists: degree lists and hash buckets (a supervariable can be
2777C in only one kind of list at a time).
2778C w: The flag array w determines the status of elements and
2779C variables, and the external degree of elements.
2780C
2781C for elements:
2782C if w (e) = 0, then the element e is absorbed
2783C if w (e) .ge. wflg, then w (e) - wflg is the size of
2784C the set |Le \ Lme|, in terms of nonzeros (the
2785C sum of abs (nv (i)) for each principal variable i that
2786C is both in the pattern of element e and NOT in the
2787C pattern of the current pivot element, me).
2788C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
2789C not yet been seen in the scan of the element lists in
2790C the computation of |Le\Lme| in loop 150 below.
2791C
2792C for variables:
2793C during supervariable detection, if w (j) .ne. wflg then j is
2794C not in the pattern of variable i
2795C
2796C The w array is initialized by setting w (i) = 1 for all i,
2797C and by setting wflg = 2. It is reinitialized if wflg becomes
2798C too large (to ensure that wflg+n does not cause integer
2799C overflow).
2800C-----------------------------------------------------------------------
2801C LOCAL INTEGERS:
2802C-----------------------------------------------------------------------
2803 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
2804 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
2805 & LENJ, LN, ME, MINDEG, NEL,
2806 & NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X,
2807 & nbflag, nreal, lastd, nelme
2808 INTEGER KNT1_UPDATED, KNT2_UPDATED
2809 INTEGER(8) :: MAXMEM, MEM, NEWMEM
2810 INTEGER :: MAXINT_N
2811 INTEGER(8) :: HASH, HMOD
2812C deg: the degree of a variable or element
2813C degme: size, |Lme|, of the current element, me (= degree (me))
2814C dext: external degree, |Le \ Lme|, of some element e
2815C dmax: largest |Le| seen so far
2816C e: an element
2817C elenme: the length, elen (me), of element list of pivotal var.
2818C eln: the length, elen (...), of an element list
2819C hash: the computed value of the hash function
2820C hmod: the hash function is computed modulo hmod = max (1,n-1)
2821C i: a supervariable
2822C ilast: the entry in a link list preceding i
2823C inext: the entry in a link list following i
2824C j: a supervariable
2825C jlast: the entry in a link list preceding j
2826C jnext: the entry in a link list, or path, following j
2827C k: the pivot order of an element or variable
2828C knt1: loop counter used during element construction
2829C knt2: loop counter used during element construction
2830C knt3: loop counter used during compression
2831C lenj: len (j)
2832C ln: length of a supervariable list
2833C maxint_n: large integer to test risk of overflow on wflg
2834C maxmem: amount of memory needed for no compressions
2835C me: current supervariable being eliminated, and the
2836C current element created by eliminating that
2837C supervariable
2838C mem: memory in use assuming no compressions have occurred
2839C mindeg: current minimum degree
2840C nel: number of pivots selected so far
2841C newmem: amount of new memory needed for current pivot element
2842C nleft: n - nel, the number of nonpivotal rows/columns remaining
2843C nvi: the number of variables in a supervariable i (= nv (i))
2844C nvj: the number of variables in a supervariable j (= nv (j))
2845C nvpiv: number of pivots in current element
2846C slenme: number of variables in variable list of pivotal variable
2847C we: w (e)
2848C wflg: used for flagging the w array. See description of iw.
2849C wnvi: wflg - nv (i)
2850C x: either a supervariable or an element
2851C begin HALO
2852C nbflag: number of flagged entries in the initial gragh.
2853C nreal : number of entries on which ordering must be perfomed
2854C (nreel = N- nbflag)
2855C nelme number of pivots selected when reaching the root
2856C lastd index of the last row in the list of dense rows
2857C end HALO
2858C-----------------------------------------------------------------------
2859C LOCAL POINTERS:
2860C-----------------------------------------------------------------------
2861 INTEGER(8) :: P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
2862 & PN, PSRC
2863C Any parameter (pe (...) or pfree) or local variable
2864C starting with "p" (for Pointer) is an index into iw,
2865C and all indices into iw use variables starting with
2866C "p." The only exception to this rule is the iwlen
2867C input argument.
2868C p: pointer into lots of things
2869C p1: pe (i) for some variable i (start of element list)
2870C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
2871C p3: index of first supervariable in clean list
2872C pdst: destination pointer, for compression
2873C pend: end of memory to compress
2874C pj: pointer into an element or variable
2875C pme: pointer into the current element (pme1...pme2)
2876C pme1: the current element, me, is stored in iw (pme1...pme2)
2877C pme2: the end of the current element
2878C pn: pointer into a "clean" variable, also used to compress
2879C psrc: source pointer, for compression
2880C-----------------------------------------------------------------------
2881C FUNCTIONS CALLED:
2882C-----------------------------------------------------------------------
2883 INTRINSIC max, min, mod
2884C=======================================================================
2885C INITIALIZATIONS
2886C=======================================================================
2887 wflg = 2
2888 maxint_n=huge(wflg)-n
2889 mindeg = 1
2890 ncmpa = 0
2891 nel = 0
2892 hmod = int(max(1, n-1),kind=8)
2893 dmax = 0
2894 mem = pfree - 1
2895 maxmem = mem
2896C begin HALO
2897 nbflag = 0
2898 lastd = 0
2899C end HALO
2900 DO 10 i = 1, n
2901 last(i) = 0
2902 head(i) = 0
2903 nv(i) = 1
2904 w(i) = 1
2905 elen(i) = 0
2906 degree(i) = len(i)
2907 10 CONTINUE
2908C
2909C begin HALO-SCHUR
2910 nbflag = size_schur
2911C
2912 DO k=1,size_schur
2913C
2914 i = listvar_schur(k)
2915 degree(i) = n+1
2916 IF ((len(i) .EQ.0).OR.(len(i).EQ.-n-1)) THEN
2917C Both ways of characterizing i \in Schur with Adj(I) = 0
2918C Because of compress, we force skipping this
2919C entry which is anyway empty
2920 pe(i) = 0_8
2921 len(i) = 0
2922 ENDIF
2923C insert I at the end of degree list of n
2924C (safe: because max external degree is N-1)
2925 deg = n
2926 IF (lastd.EQ.0) THEN
2927C degree list is empty
2928 lastd = i
2929 head(deg) = i
2930 next(i) = 0
2931 last(i) = 0
2932 ELSE
2933 next(lastd) = i
2934 last(i) = lastd
2935 lastd = i
2936 next(i) = 0
2937 ENDIF
2938C
2939 ENDDO
2940C number of entries to be ordered.
2941 nreal = n - nbflag
2942C end HALO-SCHUR
2943C ----------------------------------------------------------------
2944C initialize degree lists and eliminate rows with no off-diag. nz.
2945C ----------------------------------------------------------------
2946 DO 20 i = 1, n
2947 deg = degree(i)
2948C begin HALO-SCHUR
2949 IF (deg.EQ.n+1) GOTO 20
2950C end HALO-SCHUR
2951C
2952 IF (deg .GT. 0) THEN
2953C ----------------------------------------------------------
2954C place i in the degree list corresponding to its degree
2955C ----------------------------------------------------------
2956 inext = head(deg)
2957 IF (inext .NE. 0) last(inext) = i
2958 next(i) = inext
2959 head(deg) = i
2960 ELSE
2961C ----------------------------------------------------------
2962C we have a variable that can be eliminated at once because
2963C there is no off-diagonal non-zero in its row.
2964C ----------------------------------------------------------
2965 nel = nel + nv(i)
2966 elen(i) = -nel
2967 pe(i) = 0_8
2968 w(i) = 0
2969 ENDIF
2970 20 CONTINUE
2971C=======================================================================
2972C WHILE (selecting pivots) DO
2973C=======================================================================
2974C begin HALO V5
2975 nleft = n-nel
2976C end HALO V5
2977C begin HALO
2978C AMD test: 30 IF (NEL .LT. N) THEN
2979 30 IF (nel .LT. nreal) THEN
2980C end HALO
2981C=======================================================================
2982C GET PIVOT OF MINIMUM DEGREE
2983C=======================================================================
2984C -------------------------------------------------------------
2985C find next supervariable for elimination
2986C -------------------------------------------------------------
2987 DO 40 deg = mindeg, n
2988 me = head(deg)
2989 IF (me .GT. 0) GO TO 50
2990 40 CONTINUE
2991 50 mindeg = deg
2992C begin HALO
2993 IF (me.LE.0) THEN
2994 write (*,*) ' ERROR 1 in HALO_AMD '
2995C return to calling program with error return
2996 ncmpa = -n
2997 GOTO 500
2998 ENDIF
2999C end HALO
3000C -------------------------------------------------------------
3001C remove chosen variable from link list
3002C -------------------------------------------------------------
3003 inext = next(me)
3004 IF (inext .NE. 0) last(inext) = 0
3005 head(deg) = inext
3006C -------------------------------------------------------------
3007C me represents the elimination of pivots nel+1 to nel+nv(me).
3008C place me itself as the first in this set. It will be moved
3009C to the nel+nv(me) position when the permutation vectors are
3010C computed.
3011C -------------------------------------------------------------
3012 elenme = elen(me)
3013 elen(me) = - (nel + 1)
3014 nvpiv = nv(me)
3015 nel = nel + nvpiv
3016C=======================================================================
3017C CONSTRUCT NEW ELEMENT
3018C=======================================================================
3019C -------------------------------------------------------------
3020C At this point, me is the pivotal supervariable. It will be
3021C converted into the current element. Scan list of the
3022C pivotal supervariable, me, setting tree pointers and
3023C constructing new list of supervariables for the new element,
3024C me. p is a pointer to the current position in the old list.
3025C -------------------------------------------------------------
3026C flag the variable "me" as being in Lme by negating nv (me)
3027 nv(me) = -nvpiv
3028 degme = 0
3029 IF (elenme .EQ. 0) THEN
3030C ----------------------------------------------------------
3031C construct the new element in place
3032C ----------------------------------------------------------
3033 pme1 = pe(me)
3034 pme2 = pme1 - 1
3035 DO 60 p = pme1, pme1 + len(me) - 1
3036 i = iw(p)
3037 nvi = nv(i)
3038 IF (nvi .GT. 0) THEN
3039C ----------------------------------------------------
3040C i is a principal variable not yet placed in Lme.
3041C store i in new list
3042C ----------------------------------------------------
3043 degme = degme + nvi
3044C flag i as being in Lme by negating nv (i)
3045 nv(i) = -nvi
3046 pme2 = pme2 + 1
3047 iw(pme2) = i
3048C begin HALO
3049 IF (degree(i).LE.n) THEN
3050C end HALO
3051C ----------------------------------------------------
3052C remove variable i from degree list. (only if i \in V0)
3053C ----------------------------------------------------
3054 ilast = last(i)
3055 inext = next(i)
3056 IF (inext .NE. 0) last(inext) = ilast
3057 IF (ilast .NE. 0) THEN
3058 next(ilast) = inext
3059 ELSE
3060C i is at the head of the degree list
3061 head(degree(i)) = inext
3062 ENDIF
3063C begin HALO
3064 ENDIF
3065C end HALO
3066 ENDIF
3067 60 CONTINUE
3068C this element takes no new memory in iw:
3069 newmem = 0
3070 ELSE
3071C ----------------------------------------------------------
3072C construct the new element in empty space, iw (pfree ...)
3073C ----------------------------------------------------------
3074 p = pe(me)
3075 pme1 = pfree
3076 slenme = len(me) - elenme
3077 knt1_updated = 0
3078 DO 120 knt1 = 1, elenme + 1
3079 knt1_updated = knt1_updated +1
3080 IF (knt1 .GT. elenme) THEN
3081C search the supervariables in me.
3082 e = me
3083 pj = p
3084 ln = slenme
3085 ELSE
3086C search the elements in me.
3087 e = iw(p)
3088 p = p + 1
3089 pj = pe(e)
3090 ln = len(e)
3091 ENDIF
3092C -------------------------------------------------------
3093C search for different supervariables and add them to the
3094C new list, compressing when necessary. this loop is
3095C executed once for each element in the list and once for
3096C all the supervariables in the list.
3097C -------------------------------------------------------
3098 knt2_updated = 0
3099 DO 110 knt2 = 1, ln
3100 knt2_updated = knt2_updated+1
3101 i = iw(pj)
3102 pj = pj + 1
3103 nvi = nv(i)
3104 IF (nvi .GT. 0) THEN
3105C -------------------------------------------------
3106C compress iw, if necessary
3107C -------------------------------------------------
3108 IF (pfree .GT. iwlen) THEN
3109C prepare for compressing iw by adjusting
3110C pointers and lengths so that the lists being
3111C searched in the inner and outer loops contain
3112C only the remaining entries.
3113 pe(me) = p
3114 len(me) = len(me) - knt1_updated
3115C Reset KNT1_UPDATED in case of recompress
3116C at same iteration of the loop 120
3117 knt1_updated = 0
3118C Check if anything left in supervariable ME
3119 IF (len(me) .EQ. 0) pe(me) = 0_8
3120 pe(e) = pj
3121 len(e) = ln - knt2_updated
3122C Reset KNT2_UPDATED in case of recompress
3123C at same iteration of the loop 110
3124 knt2_updated = 0
3125C Check if anything left in element E
3126 IF (len(e) .EQ. 0) pe(e) = 0
3127 ncmpa = ncmpa + 1
3128C store first item in pe
3129C set first entry to -item
3130 DO 70 j = 1, n
3131 pn = pe(j)
3132 IF (pn .GT. 0) THEN
3133 pe(j) = int(iw(pn),8)
3134 iw(pn) = -j
3135 ENDIF
3136 70 CONTINUE
3137C psrc/pdst point to source/destination
3138 pdst = 1
3139 psrc = 1
3140 pend = pme1 - 1
3141C while loop:
3142 80 CONTINUE
3143 IF (psrc .LE. pend) THEN
3144C search for next negative entry
3145 j = -iw(psrc)
3146 psrc = psrc + 1
3147 IF (j .GT. 0) THEN
3148 iw(pdst) = int(pe(j))
3149 pe(j) = pdst
3150 pdst = pdst + 1
3151C copy from source to destination
3152 lenj = len(j)
3153 DO 90 knt3 = 0, lenj - 2
3154 iw(pdst + knt3) = iw(psrc + knt3)
3155 90 CONTINUE
3156 pdst = pdst + lenj - 1
3157 psrc = psrc + lenj - 1
3158 ENDIF
3159 GO TO 80
3160 ENDIF
3161C move the new partially-constructed element
3162 p1 = pdst
3163 DO 100 psrc = pme1, pfree - 1
3164 iw(pdst) = iw(psrc)
3165 pdst = pdst + 1
3166 100 CONTINUE
3167 pme1 = p1
3168 pfree = pdst
3169 pj = pe(e)
3170 p = pe(me)
3171 ENDIF
3172C -------------------------------------------------
3173C i is a principal variable not yet placed in Lme
3174C store i in new list
3175C -------------------------------------------------
3176 degme = degme + nvi
3177C flag i as being in Lme by negating nv (i)
3178 nv(i) = -nvi
3179 iw(pfree) = i
3180 pfree = pfree + 1
3181C begin HALO
3182 IF (degree(i).LE.n) THEN
3183C end HALO
3184C -------------------------------------------------
3185C remove variable i from degree link list
3186C (only if i in V0)
3187C -------------------------------------------------
3188 ilast = last(i)
3189 inext = next(i)
3190 IF (inext .NE. 0) last(inext) = ilast
3191 IF (ilast .NE. 0) THEN
3192 next(ilast) = inext
3193 ELSE
3194C i is at the head of the degree list
3195 head(degree(i)) = inext
3196 ENDIF
3197C begin HALO
3198 ENDIF
3199C end HALO
3200 ENDIF
3201 110 CONTINUE
3202 IF (e .NE. me) THEN
3203C set tree pointer and flag to indicate element e is
3204C absorbed into new element me (the parent of e is me)
3205 pe(e) = int(-me,8)
3206 w(e) = 0
3207 ENDIF
3208 120 CONTINUE
3209 pme2 = pfree - 1
3210C this element takes newmem new memory in iw (possibly zero)
3211 newmem = pfree - pme1
3212 mem = mem + newmem
3213 maxmem = max(maxmem, mem)
3214 ENDIF
3215C -------------------------------------------------------------
3216C me has now been converted into an element in iw (pme1..pme2)
3217C -------------------------------------------------------------
3218C degme holds the external degree of new element
3219 degree(me) = degme
3220 pe(me) = pme1
3221 len(me) = int(pme2 - pme1 + 1_8)
3222C -------------------------------------------------------------
3223C make sure that wflg is not too large. With the current
3224C value of wflg, wflg+n must not cause integer overflow
3225C -------------------------------------------------------------
3226 IF (wflg .GT. maxint_n) THEN
3227 DO 130 x = 1, n
3228 IF (w(x) .NE. 0) w(x) = 1
3229 130 CONTINUE
3230 wflg = 2
3231 ENDIF
3232C=======================================================================
3233C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
3234C=======================================================================
3235C -------------------------------------------------------------
3236C Scan 1: compute the external degrees of previous elements
3237C with respect to the current element. That is:
3238C (w (e) - wflg) = |Le \ Lme|
3239C for each element e that appears in any supervariable in Lme.
3240C The notation Le refers to the pattern (list of
3241C supervariables) of a previous element e, where e is not yet
3242C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
3243C The notation Lme refers to the pattern of the current element
3244C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
3245C zero, then the element e will be absorbed in scan 2.
3246C -------------------------------------------------------------
3247 DO 150 pme = pme1, pme2
3248 i = iw(pme)
3249 eln = elen(i)
3250 IF (eln .GT. 0) THEN
3251C note that nv (i) has been negated to denote i in Lme:
3252 nvi = -nv(i)
3253 wnvi = wflg - nvi
3254 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
3255 e = iw(p)
3256 we = w(e)
3257 IF (we .GE. wflg) THEN
3258C unabsorbed element e has been seen in this loop
3259 we = we - nvi
3260 ELSE IF (we .NE. 0) THEN
3261C e is an unabsorbed element
3262C this is the first we have seen e in all of Scan 1
3263 we = degree(e) + wnvi
3264 ENDIF
3265 w(e) = we
3266 140 CONTINUE
3267 ENDIF
3268 150 CONTINUE
3269C=======================================================================
3270C DEGREE UPDATE AND ELEMENT ABSORPTION
3271C=======================================================================
3272C -------------------------------------------------------------
3273C Scan 2: for each i in Lme, sum up the degree of Lme (which
3274C is degme), plus the sum of the external degrees of each Le
3275C for the elements e appearing within i, plus the
3276C supervariables in i. Place i in hash list.
3277C -------------------------------------------------------------
3278 DO 180 pme = pme1, pme2
3279 i = iw(pme)
3280 p1 = pe(i)
3281 p2 = p1 + elen(i) - 1
3282 pn = p1
3283 hash = 0_8
3284 deg = 0
3285C ----------------------------------------------------------
3286C scan the element list associated with supervariable i
3287C ----------------------------------------------------------
3288 DO 160 p = p1, p2
3289 e = iw(p)
3290C dext = | Le \ Lme |
3291 dext = w(e) - wflg
3292 IF (dext .GT. 0) THEN
3293 deg = deg + dext
3294 iw (pn) = e
3295 pn = pn + 1
3296 hash = hash + int(e,kind=8)
3297 ELSE IF (dext .EQ. 0) THEN
3298#if defined (NOAGG3)
3299 iw(pn) = e
3300 pn = pn + 1
3301 hash = hash + e
3302#else
3303C aggressive absorption: e is not adjacent to me, but
3304C the |Le \ Lme| is 0, so absorb it into me
3305 pe(e) = int(-me,8)
3306 w(e) = 0
3307#endif
3308 ENDIF
3309 160 CONTINUE
3310C count the number of elements in i (including me):
3311 elen(i) = int(pn - p1 + 1_8)
3312C ----------------------------------------------------------
3313C scan the supervariables in the list associated with i
3314C ----------------------------------------------------------
3315 p3 = pn
3316 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
3317 j = iw(p)
3318 nvj = nv(j)
3319 IF (nvj .GT. 0) THEN
3320C j is unabsorbed, and not in Lme.
3321C add to degree and add to new list
3322 deg = deg + nvj
3323 iw(pn) = j
3324 pn = pn + 1
3325 hash = hash + int(j,kind=8)
3326 ENDIF
3327 170 CONTINUE
3328C begin HALO
3329 IF (degree(i).EQ.n+1) deg = n+1
3330C end HALO
3331C ----------------------------------------------------------
3332C update the degree and check for mass elimination
3333C ----------------------------------------------------------
3334#if defined (NOAGG3)
3335 IF (elen(i).EQ.1 .AND. p3.EQ.pn) THEN
3336#else
3337 IF (deg .EQ. 0) THEN
3338#endif
3339C -------------------------------------------------------
3340C mass elimination
3341C -------------------------------------------------------
3342C There is nothing left of this node except for an
3343C edge to the current pivot element. elen (i) is 1,
3344C and there are no variables adjacent to node i.
3345C Absorb i into the current pivot element, me.
3346 pe(i) = int(-me,8)
3347 nvi = -nv(i)
3348 degme = degme - nvi
3349 nvpiv = nvpiv + nvi
3350 nel = nel + nvi
3351 nv(i) = 0
3352 elen(i) = 0
3353 ELSE
3354C -------------------------------------------------------
3355C update the upper-bound degree of i
3356C -------------------------------------------------------
3357C the following degree does not yet include the size
3358C of the current element, which is added later:
3359C begin HALO V6
3360 IF (degree(i).NE.n+1) THEN
3361C I does not belong to halo
3362 deg = min(deg, nleft)
3363 degree(i) = min(degree(i), deg)
3364 ENDIF
3365C end HALO V6
3366C -------------------------------------------------------
3367C add me to the list for i
3368C -------------------------------------------------------
3369C move first supervariable to end of list
3370 iw(pn) = iw(p3)
3371C move first element to end of element part of list
3372 iw(p3) = iw(p1)
3373C add new element to front of list.
3374 iw(p1) = me
3375C store the new length of the list in len (i)
3376 len(i) = int(pn - p1 + 1)
3377C begin HALO
3378 IF (deg.LE.n) THEN
3379C end HALO
3380C -------------------------------------------------------
3381C place in hash bucket. Save hash key of i in last (i).
3382C -------------------------------------------------------
3383 hash = mod(hash, hmod) + 1_8
3384 j = head(hash)
3385 IF (j .LE. 0) THEN
3386C the degree list is empty, hash head is -j
3387 next(i) = -j
3388 head(hash) = -i
3389 ELSE
3390C degree list is not empty
3391C use last (head (hash)) as hash head
3392 next(i) = last(j)
3393 last(j) = i
3394 ENDIF
3395 last(i) = int(hash, kind=kind(last))
3396C begin HALO
3397 ENDIF
3398C end HALO
3399 ENDIF
3400 180 CONTINUE
3401 degree(me) = degme
3402C -------------------------------------------------------------
3403C Clear the counter array, w (...), by incrementing wflg.
3404C -------------------------------------------------------------
3405 dmax = max(dmax, degme)
3406 wflg = wflg + dmax
3407C make sure that wflg+n does not cause integer overflow
3408 IF (wflg .GT. maxint_n) THEN
3409 DO 190 x = 1, n
3410 IF (w(x) .NE. 0) w(x) = 1
3411 190 CONTINUE
3412 wflg = 2
3413 ENDIF
3414C at this point, w (1..n) .lt. wflg holds
3415C=======================================================================
3416C SUPERVARIABLE DETECTION
3417C=======================================================================
3418 DO 250 pme = pme1, pme2
3419 i = iw(pme)
3420C begin HALO
3421C old AMD IF (NV (I) .LT. 0) THEN
3422 IF ( (nv(i) .LT. 0) .AND. (degree(i) .LE. n) ) THEN
3423C end HALO
3424C i is a principal variable in Lme
3425C -------------------------------------------------------
3426C examine all hash buckets with 2 or more variables. We
3427C do this by examing all unique hash keys for super-
3428C variables in the pattern Lme of the current element, me
3429C -------------------------------------------------------
3430 hash = int(last(i),kind=8)
3431C let i = head of hash bucket, and empty the hash bucket
3432 j = head(hash)
3433 IF (j .EQ. 0) GO TO 250
3434 IF (j .LT. 0) THEN
3435C degree list is empty
3436 i = -j
3437 head(hash) = 0
3438 ELSE
3439C degree list is not empty, restore last () of head
3440 i = last(j)
3441 last(j) = 0
3442 ENDIF
3443 IF (i .EQ. 0) GO TO 250
3444C while loop:
3445 200 CONTINUE
3446 IF (next(i) .NE. 0) THEN
3447C ----------------------------------------------------
3448C this bucket has one or more variables following i.
3449C scan all of them to see if i can absorb any entries
3450C that follow i in hash bucket. Scatter i into w.
3451C ----------------------------------------------------
3452 ln = len(i)
3453 eln = elen(i)
3454C do not flag the first element in the list (me)
3455 DO 210 p = pe(i) + 1, pe(i) + ln - 1
3456 w(iw(p)) = wflg
3457 210 CONTINUE
3458C ----------------------------------------------------
3459C scan every other entry j following i in bucket
3460C ----------------------------------------------------
3461 jlast = i
3462 j = next(i)
3463C while loop:
3464 220 CONTINUE
3465 IF (j .NE. 0) THEN
3466C -------------------------------------------------
3467C check if j and i have identical nonzero pattern
3468C -------------------------------------------------
3469C jump if i and j do not have same size data structure
3470 IF (len(j) .NE. ln) GO TO 240
3471C jump if i and j do not have same number adj elts
3472 IF (elen(j) .NE. eln) GO TO 240
3473C do not flag the first element in the list (me)
3474 DO 230 p = pe(j) + 1, pe(j) + ln - 1
3475C jump if an entry (iw(p)) is in j but not in i
3476 IF (w(iw(p)) .NE. wflg) GO TO 240
3477 230 CONTINUE
3478C -------------------------------------------------
3479C found it! j can be absorbed into i
3480C -------------------------------------------------
3481 pe(j) = int(-i,8)
3482C both nv (i) and nv (j) are negated since they
3483C are in Lme, and the absolute values of each
3484C are the number of variables in i and j:
3485 nv(i) = nv(i) + nv(j)
3486 nv(j) = 0
3487 elen(j) = 0
3488C delete j from hash bucket
3489 j = next(j)
3490 next(jlast) = j
3491 GO TO 220
3492C -------------------------------------------------
3493 240 CONTINUE
3494C j cannot be absorbed into i
3495C -------------------------------------------------
3496 jlast = j
3497 j = next(j)
3498 GO TO 220
3499 ENDIF
3500C ----------------------------------------------------
3501C no more variables can be absorbed into i
3502C go to next i in bucket and clear flag array
3503C ----------------------------------------------------
3504 wflg = wflg + 1
3505 i = next(i)
3506 IF (i .NE. 0) GO TO 200
3507 ENDIF
3508 ENDIF
3509 250 CONTINUE
3510C=======================================================================
3511C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
3512C=======================================================================
3513 p = pme1
3514 nleft = n - nel
3515 DO 260 pme = pme1, pme2
3516 i = iw(pme)
3517 nvi = -nv(i)
3518 IF (nvi .GT. 0) THEN
3519C i is a principal variable in Lme
3520C restore nv (i) to signify that i is principal
3521 nv(i) = nvi
3522C begin HALO
3523 IF (degree(i).LE.n) THEN
3524C end HALO
3525C -------------------------------------------------------
3526C compute the external degree (add size of current elem)
3527C -------------------------------------------------------
3528 deg = min(degree(i) + degme - nvi, nleft - nvi)
3529C -------------------------------------------------------
3530C place the supervariable at the head of the degree list
3531C -------------------------------------------------------
3532 inext = head(deg)
3533 IF (inext .NE. 0) last(inext) = i
3534 next(i) = inext
3535 last(i) = 0
3536 head(deg) = i
3537C -------------------------------------------------------
3538C save the new degree, and find the minimum degree
3539C -------------------------------------------------------
3540 mindeg = min(mindeg, deg)
3541 degree(i) = deg
3542C begin HALO
3543 ENDIF
3544C end HALO
3545C -------------------------------------------------------
3546C place the supervariable in the element pattern
3547C -------------------------------------------------------
3548 iw (p) = i
3549 p = p + 1
3550 ENDIF
3551 260 CONTINUE
3552C=======================================================================
3553C FINALIZE THE NEW ELEMENT
3554C=======================================================================
3555 nv(me) = nvpiv + degme
3556C nv (me) is now the degree of pivot (including diagonal part)
3557C save the length of the list for the new element me
3558 len(me) = int(p - pme1)
3559 IF (len(me) .EQ. 0) THEN
3560C there is nothing left of the current pivot element
3561 pe(me) = 0_8
3562 w(me) = 0
3563 ENDIF
3564 IF (newmem .NE. 0) THEN
3565C element was not constructed in place: deallocate part
3566C of it (final size is less than or equal to newmem,
3567C since newly nonprincipal variables have been removed).
3568 pfree = p
3569 mem = mem - newmem + len(me)
3570 ENDIF
3571C=======================================================================
3572C END WHILE (selecting pivots)
3573 GO TO 30
3574 ENDIF
3575C=======================================================================
3576C begin HALO V2
3577 IF (nel.LT.n) THEN
3578C
3579C All possible pivots (not flagged have been eliminated).
3580C We amalgamate all flagged variables at the root and
3581C we finish the elimination tree.
3582C 1/ Go through all
3583C non absorbed elements (root of the subgraph)
3584C and absorb in ME
3585C 2/ perform mass elimination of all dense rows
3586 DO deg = mindeg, n
3587 me = head(deg)
3588 IF (me .GT. 0) GO TO 51
3589 ENDDO
3590 51 mindeg = deg
3591C
3592 IF (me.NE.listvar_schur(1)) THEN
3593 write(6,*) ' ERROR 2 in MUMPS_HAMD '
3594 write(6,*) ' wrong principal var for Schur !!'
3595 ncmpa = -n - 2
3596 CALL mumps_abort()
3597 ENDIF
3598C
3599 nelme = -(nel+1)
3600 DO x=1,n
3601 IF ((pe(x).GT.0) .AND. (elen(x).LT.0)) THEN
3602C X is an unabsorbed element
3603 pe(x) = int(-me,8)
3604C W(X) = 0 could be suppressed ?? check it
3605 ELSEIF (degree(x).EQ.n+1) THEN
3606C X is a dense row, absorb it in ME (mass elimination)
3607 nel = nel + nv(x)
3608 pe(x) = int(-me,8)
3609 elen(x) = 0
3610C Correct value of NV is (secondary variable)
3611 nv(x) = 0
3612 ENDIF
3613 ENDDO
3614C ME is the root node
3615 elen(me) = nelme
3616C Correct value of NV is (principal variable)
3617 nv(me) = n-nreal
3618 pe(me) = 0
3619C end HALO V2
3620C
3621C begin HALO
3622 IF (nel.NE.n) THEN
3623 write(*,*) ' ERROR 2 in MUMPS_HAMD NEL, N=', nel,n
3624 ncmpa = -n - 1
3625 ENDIF
3626 ENDIF
3627C end HALO
3628C=======================================================================
3629C COMPUTE THE PERMUTATION VECTORS
3630C=======================================================================
3631C ----------------------------------------------------------------
3632C The time taken by the following code is O(n). At this
3633C point, elen (e) = -k has been done for all elements e,
3634C and elen (i) = 0 has been done for all nonprincipal
3635C variables i. At this point, there are no principal
3636C supervariables left, and all elements are absorbed.
3637C ----------------------------------------------------------------
3638C ----------------------------------------------------------------
3639C compute the ordering of unordered nonprincipal variables
3640C ----------------------------------------------------------------
3641 DO 290 i = 1, n
3642 IF (elen(i) .EQ. 0) THEN
3643C ----------------------------------------------------------
3644C i is an un-ordered row. Traverse the tree from i until
3645C reaching an element, e. The element, e, was the
3646C principal supervariable of i and all nodes in the path
3647C from i to when e was selected as pivot.
3648C ----------------------------------------------------------
3649 j = int(-pe(i))
3650C while (j is a variable) do:
3651 270 CONTINUE
3652 IF (elen(j) .GE. 0) THEN
3653 j = int(-pe(j))
3654 GO TO 270
3655 ENDIF
3656 e = j
3657C ----------------------------------------------------------
3658C get the current pivot ordering of e
3659C ----------------------------------------------------------
3660 k = -elen(e)
3661C ----------------------------------------------------------
3662C traverse the path again from i to e, and compress the
3663C path (all nodes point to e). Path compression allows
3664C this code to compute in O(n) time. Order the unordered
3665C nodes in the path, and place the element e at the end.
3666C ----------------------------------------------------------
3667 j = i
3668C while (j is a variable) do:
3669 280 CONTINUE
3670 IF (elen(j) .GE. 0) THEN
3671 jnext = int(-pe(j))
3672 pe(j) = int(-e,8)
3673 IF (elen(j) .EQ. 0) THEN
3674C j is an unordered row
3675 elen(j) = k
3676 k = k + 1
3677 ENDIF
3678 j = jnext
3679 GO TO 280
3680 ENDIF
3681C leave elen (e) negative, so we know it is an element
3682 elen(e) = -k
3683 ENDIF
3684 290 CONTINUE
3685C ----------------------------------------------------------------
3686C reset the inverse permutation (elen (1..n)) to be positive,
3687C and compute the permutation (last (1..n)).
3688C ----------------------------------------------------------------
3689 DO 300 i = 1, n
3690 k = abs(elen(i))
3691 last(k) = i
3692 elen(i) = k
3693 300 CONTINUE
3694C=======================================================================
3695C RETURN THE MEMORY USAGE IN IW
3696C=======================================================================
3697C If maxmem is less than or equal to iwlen, then no compressions
3698C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
3699C compressions did occur, and iwlen would have had to have been
3700C greater than or equal to maxmem for no compressions to occur.
3701C Return the value of maxmem in the pfree argument.
3702 500 pfree = maxmem
3703C===============================
3704C Save IPE in PARENT array
3705 DO i=1,n
3706 parent(i) = int(pe(i))
3707 ENDDO
3708C===============================
3709 RETURN
3710 END SUBROUTINE mumps_hamd
3711C-----------------------------------------------------------------------
3712C-----------------------------------------------------------------------
3713C Description of MUMPS_HAMF4:
3714C MUMPS_HAMF4 is a modified version of halo AMD routine MUMPS_HAMD
3715C implementing an approximate minimum fill-in heuritic.
3716C Version provided to F. Pellegrini on Nov 2000 to be used in SCOTCH.
3717C Approximation of level4 of the minimum fill heuristic
3718C
3719C Restrictive integer 64 bit variant :
3720C it is assumed that IW array size can exceed 32-bit integer
3721C
3722 SUBROUTINE mumps_hamf4
3723 & (norig, n, compute_perm, nbbuck,
3724 & iwlen, pe, pfree, len, iw, nv, elen,
3725 & last, ncmpa, degree, wf, next, w, head
3726 & , parent
3727 & )
3728 IMPLICIT NONE
3729C
3730C Parameters
3731C Input not modified
3732C N : number of nodes in the complete graph including halo
3733C NORIG :
3734C if compressed graph (nv(1).ne-1) then
3735C NORIG is the sum(nv(i)) for i \in [1:N]
3736C else NORIG = N
3737 INTEGER, INTENT(IN) :: NORIG, N, NBBUCK
3738 LOGICAL, INTENT(IN) :: COMPUTE_PERM
3739 INTEGER(8), INTENT(IN) :: IWLEN
3740C Input undefined on output
3741 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
3742C NV also meaningful as input to encode compressed graphs
3743 INTEGER, INTENT(INOUT) :: NV(N)
3744C
3745C Output only
3746 INTEGER, INTENT(OUT) :: NCMPA
3747 INTEGER, INTENT(OUT) :: ELEN(N), LAST(N)
3748 INTEGER, INTENT(OUT) :: PARENT(N)
3749C
3750C Input/output
3751 INTEGER(8), INTENT(INOUT) :: PFREE
3752 INTEGER(8), INTENT(INOUT) :: PE(N)
3753C
3754C Internal Workspace only
3755C Min fill approximation one extra array of size NBBUCK+2
3756C is also needed
3757 INTEGER :: NEXT(N), DEGREE(N), W(N)
3758 INTEGER :: HEAD(0:NBBUCK+1), WF(N)
3759C
3760C Comments on the OUTPUT:
3761C ----------------------
3762C Let V= V0 U V1 the nodes of the initial graph (|V|=n).
3763C The assembly tree corresponds to the tree
3764C of the supernodes (or supervariables). Each node of the
3765C assembly tree is then composed of one principal variable
3766C and a list of secondary variables. The list of
3767C variable of a node (principal + secondary variables) then
3768C describes the structure of the diagonal bloc of the
3769C supernode.
3770C The elimination tree denotes the tree of all the variables(=node) and
3771C is therefore of order n.
3772C
3773C The arrays NV(N) and PE(N) give a description of the
3774C assembly tree.
3775C Note that on output
3776C INTEGER(8) PE array is copied on output into
3777C INTEGER PARENT array
3778C
3779C 1/ Description of array nv(N) (on OUTPUT)
3780C nv(i)=0 i is a secondary variable
3781C nv(i) >0 i is a principal variable, nv(i) holds the
3782C the number of elements in column i of L (true degree of i)
3783C With compressed graph (nv(1).ne.-1 on input),
3784C nv(i) can be greater than N since degree can be as large as NORIG
3785C
3786C 2/ Description of array PE(N) (on OUTPUT)
3787C Note that on
3788C pe(i) = -(father of variable/node i) in the elimination tree:
3789C If nv (i) .gt. 0, then i represents a node in the assembly tree,
3790C and the parent of i is -pe (i), or zero if i is a root.
3791C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
3792C subtree, the root of which is a node in the assembly tree.
3793C
3794C 3/ Example:
3795C Let If be a root node father of Is in the assembly tree.
3796C If is the principal
3797C variable of the node If and let If1, If2, If3 be the secondary variables
3798C of node If.
3799C Is is the principal
3800C variable of the node Is and let Is1, Is2 be the secondary variables
3801C of node Is.
3802C
3803C THEN:
3804C NV(If1)=NV(If2)=NV(If3) = 0 (secondary variables)
3805C NV(Is1)=NV(Is2) = 0 (secondary variables)
3806C NV(If) > 0 ( principal variable)
3807C NV(Is) > 0 ( principal variable)
3808C PE(If) = 0 (root node)
3809C PE(Is) = -If (If is the father of Is in the assembly tree)
3810C PE(If1)=PE(If2)=PE(If3)= -If ( If is the principal variable)
3811C PE(Is1)=PE(Is2)= -Is ( Is is the principal variable)
3812C
3813C
3814C
3815C HALOAMD_V1: (September 1997)
3816C **********
3817C Initial version designed to experiment the numerical (fill-in) impact
3818C of taking into account the halo. This code should be able
3819C to experiment no-halo, partial halo, complete halo.
3820C DATE: September 17th 1997
3821C
3822C HALOAMD is designed to process a gragh composed of two types
3823C of nodes, V0 and V1, extracted from a larger gragh.
3824C V0^V1 = {},
3825C
3826C We used Min. degree heuristic to order only
3827C nodes in V0, but the adjacency to nodes
3828C in V1 is taken into account during ordering.
3829C Nodes in V1 are odered at last.
3830C Adjacency between nodes of V1 need not be provided,
3831C however |len(i)| must always corresponds to the number of
3832C edges effectively provided in the adjacency list of i.
3833C On input :
3834c ********
3835C Nodes INODE in V1 are flagged with len(INODE) = -degree
3836C if len(i) =0 and i \in V1 then
3837C len(i) must be set on input to -NORIG-1
3838C ERROR return (negative values in ncmpa)
3839C ************
3840C negative value in ncmpa indicates an error detected
3841C by HALOAMD.
3842C
3843C The graph provided MUST follow the rule:
3844C if (i,j) is an edge in the gragh then
3845C j must be in the adjacency list of i AND
3846C i must be in the adjacency list of j.
3847C REMARKS
3848C -------
3849C
3850C 1/ Providing edges between nodes of V1 should not
3851C affect the final ordering, only the amount of edges
3852C of the halo should effectively affect the solution.
3853C This code should work in the following cases:
3854C 1/ halo not provided
3855C 2/ halo partially provided
3856C 3/ complete halo
3857C 4/ complete halo+interconnection between nodes of V1.
3858C
3859C 1/ should run and provide identical results (w.r.t to current
3860C implementation of AMD in SCOTCH).
3861C 3/ and 4 should provide identical results.
3862C
3863C 2/ All modifications of the AMD initial code are indicated
3864C with begin HALO .. end HALO
3865C
3866C
3867C Given a representation of the nonzero pattern of a symmetric matrix,
3868C A, (excluding the diagonal) perform an approximate minimum
3869C fill-in heuristic. Aggresive absorption is
3870C used to tighten the bound on the degree. This can result an
3871C significant improvement in the quality of the ordering for
3872C some matrices.
3873C-----------------------------------------------------------------------
3874C INPUT ARGUMENTS (unaltered):
3875C-----------------------------------------------------------------------
3876C n: The matrix order.
3877C Restriction: n .ge. 1
3878C compute_perm : indicates if permutations should be computed
3879C on output in last/elen
3880C iwlen: The length of iw (1..iwlen). On input, the matrix is
3881C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
3882C slightly larger than what is required to hold the matrix, at
3883C least iwlen .ge. pfree + n is recommended. Otherwise,
3884C excessive compressions will take place.
3885C *** We do not recommend running this algorithm with ***
3886C *** iwlen .lt. pfree + n. ***
3887C *** Better performance will be obtained if ***
3888C *** iwlen .ge. pfree + n ***
3889C *** or better yet ***
3890C *** iwlen .gt. 1.2 * pfree ***
3891C *** (where pfree is its value on input). ***
3892C The algorithm will not run at all if iwlen .lt. pfree-1.
3893C
3894C Restriction: iwlen .ge. pfree-1
3895C-----------------------------------------------------------------------
3896C INPUT/OUPUT ARGUMENTS:
3897C-----------------------------------------------------------------------
3898C pe: On input, pe (i) is the index in iw of the start of row i, or
3899C zero if row i has no off-diagonal non-zeros.
3900C
3901C During execution, it is used for both supervariables and
3902C elements:
3903C
3904C * Principal supervariable i: index into iw of the
3905C description of supervariable i. A supervariable
3906C represents one or more rows of the matrix
3907C with identical nonzero pattern.
3908C * Non-principal supervariable i: if i has been absorbed
3909C into another supervariable j, then pe (i) = -j.
3910C That is, j has the same pattern as i.
3911C Note that j might later be absorbed into another
3912C supervariable j2, in which case pe (i) is still -j,
3913C and pe (j) = -j2.
3914C * Unabsorbed element e: the index into iw of the description
3915C of element e, if e has not yet been absorbed by a
3916C subsequent element. Element e is created when
3917C the supervariable of the same name is selected as
3918C the pivot.
3919C * Absorbed element e: if element e is absorbed into element
3920C e2, then pe (e) = -e2. This occurs when the pattern of
3921C e (that is, Le) is found to be a subset of the pattern
3922C of e2 (that is, Le2). If element e is "null" (it has
3923C no nonzeros outside its pivot block), then pe (e) = 0.
3924C
3925C On output, pe holds the assembly tree/forest, which implicitly
3926C represents a pivot order with identical fill-in as the actual
3927C order (via a depth-first search of the tree).
3928C
3929C On output:
3930C If nv (i) .gt. 0, then i represents a node in the assembly tree,
3931C and the parent of i is -pe (i), or zero if i is a root.
3932C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
3933C subtree, the root of which is a node in the assembly tree.
3934C On output: (PE is copied on output into PARENT array)
3935C
3936C pfree: On input, the matrix is stored in iw (1..pfree-1) and
3937C the rest of the array iw is free.
3938C During execution, additional data is placed in iw, and pfree
3939C is modified so that components of iw from pfree are free.
3940C On output, pfree is set equal to the size of iw that
3941C would have been needed for no compressions to occur. If
3942C ncmpa is zero, then pfree (on output) is less than or equal to
3943C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
3944C Otherwise, pfree (on output) is greater than iwlen, and all the
3945C memory in iw was used.
3946C
3947C nv: On input, encoding of compressed graph:
3948C if NV(1) = -1 then graph is not compressed otherwise
3949C NV(I) holds the weight of node I.
3950C During execution, abs (nv (i)) is equal to the number of rows
3951C that are represented by the principal supervariable i. If i is
3952C a nonprincipal variable, then nv (i) = 0. Initially,
3953C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
3954C principal variable in the pattern Lme of the current pivot
3955C element me. On output, nv (e) holds the true degree of element
3956C e at the time it was created (including the diagonal part).
3957C begin HALO
3958C On output, nv(I) can be used to find node in set V1.
3959C Not true anymore : ( nv(I) = N+1 characterizes nodes in V1
3960C instead nodes in V1 are considered as a dense root node )
3961C end HALO
3962C-----------------------------------------------------------------------
3963C INPUT/MODIFIED (undefined on output):
3964C-----------------------------------------------------------------------
3965C len: On input, len (i)
3966C positive or null (>=0) : i \in V0 and
3967C len(i) holds the number of entries in row i of the
3968C matrix, excluding the diagonal.
3969C negative (<0) : i \in V1, and
3970C -len(i) hold the number of entries in row i of the
3971C matrix, excluding the diagonal.
3972C The contents of len (1..n)
3973C are undefined on output.
3974C iw: On input, iw (1..pfree-1) holds the description of each row i
3975C in the matrix. The matrix must be symmetric, and both upper
3976C and lower triangular parts must be present. The diagonal must
3977C not be present. Row i is held as follows:
3978C
3979C len (i): the length of the row i data structure
3980C iw (pe (i) ... pe (i) + len (i) - 1):
3981C the list of column indices for nonzeros
3982C in row i (simple supervariables), excluding
3983C the diagonal. All supervariables start with
3984C one row/column each (supervariable i is just
3985C row i).
3986C if len (i) is zero on input, then pe (i) is ignored
3987C on input.
3988C
3989C Note that the rows need not be in any particular order,
3990C and there may be empty space between the rows.
3991C
3992C During execution, the supervariable i experiences fill-in.
3993C This is represented by placing in i a list of the elements
3994C that cause fill-in in supervariable i:
3995C
3996C len (i): the length of supervariable i
3997C iw (pe (i) ... pe (i) + elen (i) - 1):
3998C the list of elements that contain i. This list
3999C is kept short by removing absorbed elements.
4000C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
4001C the list of supervariables in i. This list
4002C is kept short by removing nonprincipal
4003C variables, and any entry j that is also
4004C contained in at least one of the elements
4005C (j in Le) in the list for i (e in row i).
4006C
4007C When supervariable i is selected as pivot, we create an
4008C element e of the same name (e=i):
4009C
4010C len (e): the length of element e
4011C iw (pe (e) ... pe (e) + len (e) - 1):
4012C the list of supervariables in element e.
4013C
4014C An element represents the fill-in that occurs when supervariable
4015C i is selected as pivot (which represents the selection of row i
4016C and all non-principal variables whose principal variable is i).
4017C We use the term Le to denote the set of all supervariables
4018C in element e. Absorbed supervariables and elements are pruned
4019C from these lists when computationally convenient.
4020C
4021C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
4022C The contents of iw are undefined on output.
4023C
4024C-----------------------------------------------------------------------
4025C OUTPUT (need not be set on input):
4026C-----------------------------------------------------------------------
4027C elen: See the description of iw above. At the start of execution,
4028C elen (i) is set to zero. During execution, elen (i) is the
4029C number of elements in the list for supervariable i. When e
4030C becomes an element, elen (e) = -nel is set, where nel is the
4031C current step of factorization. elen (i) = 0 is done when i
4032C becomes nonprincipal.
4033C
4034C For variables, elen (i) .ge. 0 holds
4035C until just before the permutation vectors are computed.
4036C For elements, elen (e) .lt. 0 holds.
4037C
4038C On output elen (1..n) holds the inverse permutation (the same
4039C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
4040C then row i is the kth pivot row. Row i of A appears as the
4041C (elen(i))-th row in the permuted matrix, PAP^T.
4042C last: In a degree list, last (i) is the supervariable preceding i,
4043C or zero if i is the head of the list. In a hash bucket,
4044C last (i) is the hash key for i. last (head (hash)) is also
4045C used as the head of a hash bucket if head (hash) contains a
4046C degree list (see head, below).
4047C
4048C On output, last (1..n) holds the permutation (the same as the
4049C 'PERM' argument in Sparspak). That is, if i = last (k), then
4050C row i is the kth pivot row. Row last (k) of A is the k-th row
4051C in the permuted matrix, PAP^T.
4052C ncmpa: The number of times iw was compressed. If this is
4053C excessive, then the execution took longer than what could have
4054C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
4055C larger than the value of pfree on input (or at least
4056C iwlen .ge. pfree + n). The fastest performance will be
4057C obtained when ncmpa is returned as zero. If iwlen is set to
4058C the value returned by pfree on *output*, then no compressions
4059C will occur.
4060C begin HALO
4061C on output ncmpa <0 --> error detected during HALO_AMD:
4062C error 1: ncmpa = -N , ordering was stopped.
4063C end HALO
4064C
4065C-----------------------------------------------------------------------
4066C LOCAL (not input or output - used only during execution):
4067C-----------------------------------------------------------------------
4068C degree: If i is a supervariable, then degree (i) holds the
4069C current approximation of the external degree of row i (an upper
4070C bound). The external degree is the number of nonzeros in row i,
4071C minus abs (nv (i)) (the diagonal part). The bound is equal to
4072C the external degree if elen (i) is less than or equal to two.
4073C We also use the term "external degree" for elements e to refer
4074C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
4075C which is the degree of the off-diagonal part of the element e
4076C (not including the diagonal part).
4077C begin HALO
4078C while processing variables degree(I) = -NBBUCK-1 (=N2)
4079C indicates that i belongs to V1
4080C end HALO
4081C
4082C head: head is used for degree lists. head (deg) is the first
4083C supervariable in a degree list (all supervariables i in a
4084C degree list deg have the same approximate degree, namely,
4085C deg = degree (i)). If the list deg is empty then
4086C head (deg) = 0.
4087C
4088C During supervariable detection head (hash) also serves as a
4089C pointer to a hash bucket.
4090C If head (hash) .gt. 0, there is a degree list of degree hash.
4091C The hash bucket head pointer is last (head (hash)).
4092C If head (hash) = 0, then the degree list and hash bucket are
4093C both empty.
4094C If head (hash) .lt. 0, then the degree list is empty, and
4095C -head (hash) is the head of the hash bucket.
4096C After supervariable detection is complete, all hash buckets
4097C are empty, and the (last (head (hash)) = 0) condition is
4098C restored for the non-empty degree lists.
4099C next: next (i) is the supervariable following i in a link list, or
4100C zero if i is the last in the list. Used for two kinds of
4101C lists: degree lists and hash buckets (a supervariable can be
4102C in only one kind of list at a time).
4103C w: The flag array w determines the status of elements and
4104C variables, and the external degree of elements.
4105C
4106C for elements:
4107C if w (e) = 0, then the element e is absorbed
4108C if w (e) .ge. wflg, then w (e) - wflg is the size of
4109C the set |Le \ Lme|, in terms of nonzeros (the
4110C sum of abs (nv (i)) for each principal variable i that
4111C is both in the pattern of element e and NOT in the
4112C pattern of the current pivot element, me).
4113C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
4114C not yet been seen in the scan of the element lists in
4115C the computation of |Le\Lme| in loop 150 below.
4116C
4117C for variables:
4118C during supervariable detection, if w (j) .ne. wflg then j is
4119C not in the pattern of variable i
4120C
4121C The w array is initialized by setting w (i) = 1 for all i,
4122C and by setting wflg = 2. It is reinitialized if wflg becomes
4123C too large (to ensure that wflg+n does not cause integer
4124C overflow).
4125C
4126C wf : integer array used to store the already filled area of
4127C the variables adajcent to current pivot.
4128C wf is then used to update the score of variable i.
4129C
4130C-----------------------------------------------------------------------
4131C LOCAL INTEGERS:
4132C-----------------------------------------------------------------------
4133 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
4134 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
4135 & LENJ, LN, ME, MINDEG, NEL,
4136 & NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X,
4137 & nbflag, lastd, nelme, wf3, wf4, n2, pas
4138 INTEGER :: NLEFT_V1
4139 INTEGER KNT1_UPDATED, KNT2_UPDATED
4140 INTEGER(8) :: MAXMEM, MEM, NEWMEM
4141 INTEGER :: MAXINT_N
4142 INTEGER(8) :: HASH, HMOD
4143 DOUBLE PRECISION RMF, RMF1
4144 DOUBLE PRECISION dummy
4145 INTEGER idummy
4146C deg: the degree of a variable or element
4147C degme: size, |Lme|, of the current element, me (= degree (me))
4148C dext: external degree, |Le \ Lme|, of some element e
4149C dmax: largest |Le| seen so far
4150C e: an element
4151C elenme: the length, elen (me), of element list of pivotal var.
4152C eln: the length, elen (...), of an element list
4153C hash: the computed value of the hash function
4154C hmod: the hash function is computed modulo hmod = max (1,n-1)
4155C i: a supervariable
4156C ilast: the entry in a link list preceding i
4157C inext: the entry in a link list following i
4158C j: a supervariable
4159C jlast: the entry in a link list preceding j
4160C jnext: the entry in a link list, or path, following j
4161C k: the pivot order of an element or variable
4162C knt1: loop counter used during element construction
4163C knt2: loop counter used during element construction
4164C knt3: loop counter used during compression
4165C lenj: len (j)
4166C ln: length of a supervariable list
4167C maxint_n: large integer to test risk of overflow on wflg
4168C maxmem: amount of memory needed for no compressions
4169C me: current supervariable being eliminated, and the
4170C current element created by eliminating that
4171C supervariable
4172C mem: memory in use assuming no compressions have occurred
4173C mindeg: current minimum degree
4174C nel: number of pivots selected so far
4175C newmem: amount of new memory needed for current pivot element
4176C nleft: n - nel, the number of nonpivotal rows/columns remaining
4177C nvi: the number of variables in a supervariable i (= nv (i))
4178C nvj: the number of variables in a supervariable j (= nv (j))
4179C nvpiv: number of pivots in current element
4180C slenme: number of variables in variable list of pivotal variable
4181C we: w (e)
4182C wflg: used for flagging the w array. See description of iw.
4183C wnvi: wflg - nv (i)
4184C x: either a supervariable or an element
4185C wf3: off diagoanl block area
4186C wf4: diagonal block area
4187C mf : Minimum fill
4188C begin HALO
4189C nbflag: number of flagged entries in the initial gragh.
4190C nreal : number of entries on which ordering must be perfomed
4191C (nreel = N- nbflag)
4192C nelme number of pivots selected when reaching the root
4193C lastd index of the last row in the list of dense rows
4194C end HALO
4195C-----------------------------------------------------------------------
4196C LOCAL POINTERS:
4197C-----------------------------------------------------------------------
4198 INTEGER(8) :: P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
4199 & PN, PSRC
4200C Any parameter (pe (...) or pfree) or local variable
4201C starting with "p" (for Pointer) is an index into iw,
4202C and all indices into iw use variables starting with
4203C "p." The only exception to this rule is the iwlen
4204C input argument.
4205C p: pointer into lots of things
4206C p1: pe (i) for some variable i (start of element list)
4207C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
4208C p3: index of first supervariable in clean list
4209C pdst: destination pointer, for compression
4210C pend: end of memory to compress
4211C pj: pointer into an element or variable
4212C pme: pointer into the current element (pme1...pme2)
4213C pme1: the current element, me, is stored in iw (pme1...pme2)
4214C pme2: the end of the current element
4215C pn: pointer into a "clean" variable, also used to compress
4216C psrc: source pointer, for compression
4217C-----------------------------------------------------------------------
4218C FUNCTIONS CALLED:
4219C-----------------------------------------------------------------------
4220 INTRINSIC max, min, mod, huge
4221 INTEGER TOTEL
4222 LOGICAL COMPRESS
4223C=======================================================================
4224C INITIALIZATIONS
4225C=======================================================================
4226C HEAD (0:NBBUCK+1)
4227C
4228C idummy holds the largest integer - 1
4229C dummy = dble (idummy)
4230 idummy = huge(idummy) - 1
4231 dummy = dble(idummy)
4232C variable with degree equal to N2 are in halo
4233C bucket NBBUCK+1 used for HALO variables
4234 n2 = -nbbuck-1
4235C Distance betweeen elements of the N, ..., NBBUCK entries of HEAD
4236C
4237 pas = max((n/8), 1)
4238 wflg = 2
4239 maxint_n=huge(wflg)-n
4240 ncmpa = 0
4241 nel = 0
4242 hmod = int(max(1, nbbuck-1),kind=8)
4243 dmax = 0
4244 mem = pfree - 1
4245 maxmem = mem
4246 mindeg = 0
4247 nleft_v1 = 0
4248C
4249 nbflag = 0
4250 lastd = 0
4251 head(0:nbbuck+1) = 0
4252 DO 10 i = 1, n
4253 last(i) = 0
4254C NV(I) = 1
4255 w(i) = 1
4256 elen(i) = 0
4257 10 CONTINUE
4258 IF(nv(1) .LT. 0) THEN
4259 compress = .false.
4260 ELSE
4261 compress = .true.
4262 ENDIF
4263 IF(compress) THEN
4264 totel = 0
4265 DO i=1,n
4266 IF (len(i).LT.0) THEN
4267 degree(i) = n2
4268 nbflag = nbflag +1
4269 nleft_v1 = nleft_v1 + nv(i)
4270 IF (len(i).EQ.-norig-1) THEN
4271C variable in V1 with empty adj list
4272 len(i) = 0
4273C Because of compress, we force skipping this
4274C entry which is anyway empty
4275 pe(i) = 0_8
4276 ELSE
4277 len(i) = - len(i)
4278 ENDIF
4279C end HALO V3
4280 ELSE
4281 totel = totel + nv(i)
4282 degree(i) = 0
4283 DO p= pe(i) , pe(i)+int(len(i)-1,8)
4284 degree(i) = degree(i) + nv(iw(p))
4285 ENDDO
4286C DEGREE (I) = LEN (I)
4287 ENDIF
4288 ENDDO
4289 ELSE
4290 DO i=1,n
4291 nv(i) = 1
4292 IF (len(i).LT.0) THEN
4293 degree(i) = n2
4294 nbflag = nbflag +1
4295 nleft_v1 = nleft_v1 + nv(i)
4296 IF (len(i).EQ.-n-1) THEN
4297 len(i) = 0
4298C Because of compress, we force skipping this
4299C entry which is anyway empty
4300 pe(i) = 0_8
4301 ELSE
4302 len(i) = - len(i)
4303 ENDIF
4304C end HALO V3
4305 ELSE
4306 degree(i) = len(i)
4307 ENDIF
4308 ENDDO
4309 totel = n - nbflag
4310 ENDIF
4311C
4312C
4313C ----------------------------------------------------------------
4314C initialize degree lists and eliminate rows with no off-diag. nz.
4315C ----------------------------------------------------------------
4316 DO 20 i = 1, n
4317 deg = degree(i)
4318 IF (deg.EQ.n2) THEN
4319C DEG = N2 (flagged variables are stored
4320C in the degree list of NBBUCK + 1
4321C (safe: because max
4322C max value of degree is NBBUCK)
4323C
4324 deg = nbbuck + 1
4325 IF (lastd.EQ.0) THEN
4326C degree list is empty
4327 lastd = i
4328 head(deg) = i
4329 next(i) = 0
4330 last(i) = 0
4331 ELSE
4332 next(lastd) = i
4333 last(i) = lastd
4334 lastd = i
4335 next(i) = 0
4336 ENDIF
4337 GOTO 20
4338 ENDIF
4339C
4340C
4341 IF (deg .GT. 0) THEN
4342 wf(i) = deg
4343C version 1
4344 IF (deg.GT.norig) THEN
4345 deg = min(((deg-norig)/pas) + norig, nbbuck)
4346 ENDIF
4347C Note that if deg=0 then
4348C No fill-in will occur,
4349C but one variable is adjacent to I
4350C ----------------------------------------------------------
4351C place i in the degree list corresponding to its degree
4352C ----------------------------------------------------------
4353 inext = head(deg)
4354 IF (inext .NE. 0) last(inext) = i
4355 next(i) = inext
4356 head(deg) = i
4357 ELSE
4358C ----------------------------------------------------------
4359C we have a variable that can be eliminated at once because
4360C there is no off-diagonal non-zero in its row.
4361C ----------------------------------------------------------
4362 nel = nel + nv(i)
4363 elen(i) = -nel
4364 pe(i) = 0_8
4365 w (i) = 0
4366 ENDIF
4367C=======================================================================
4368C
4369 20 CONTINUE
4370C=======================================================================
4371C WHILE (selecting pivots) DO
4372C=======================================================================
4373 nleft = totel-nel + nleft_v1
4374C=======================================================================
4375C =====================================================================
4376 30 IF (nel .LT. totel) THEN
4377C =====================================================================
4378C GET PIVOT OF MINIMUM DEGREE
4379C=======================================================================
4380C -------------------------------------------------------------
4381C find next supervariable for elimination
4382C -------------------------------------------------------------
4383 DO 40 deg = mindeg, nbbuck
4384 me = head(deg)
4385 IF (me .GT. 0) GO TO 50
4386 40 CONTINUE
4387 50 mindeg = deg
4388 IF (me.LE.0) THEN
4389 ncmpa = -n
4390 CALL mumps_abort()
4391 ENDIF
4392 IF (deg.GT.norig) THEN
4393C -------------------------------
4394C Linear search to find variable
4395C with best score in the list
4396C -------------------------------
4397C While end of list list not reached
4398C NEXT(J) = 0
4399 j = next(me)
4400 k = wf(me)
4401 55 CONTINUE
4402 IF (j.GT.0) THEN
4403 IF (wf(j).LT.k) THEN
4404 me = j
4405 k = wf(me)
4406 ENDIF
4407 j= next(j)
4408 GOTO 55
4409 ENDIF
4410 ilast = last(me)
4411 inext = next(me)
4412 IF (inext .NE. 0) last(inext) = ilast
4413 IF (ilast .NE. 0) THEN
4414 next(ilast) = inext
4415 ELSE
4416C me is at the head of the degree list
4417 head(deg) = inext
4418 ENDIF
4419C
4420 ELSE
4421C -------------------------------------------------------------
4422C remove chosen variable from link list
4423C -------------------------------------------------------------
4424 inext = next(me)
4425 IF (inext .NE. 0) last(inext) = 0
4426 head(deg) = inext
4427 ENDIF
4428C -------------------------------------------------------------
4429C me represents the elimination of pivots nel+1 to nel+nv(me).
4430C place me itself as the first in this set. It will be moved
4431C to the nel+nv(me) position when the permutation vectors are
4432C computed.
4433C -------------------------------------------------------------
4434 elenme = elen(me)
4435 elen(me) = - (nel + 1)
4436 nvpiv = nv(me)
4437 nel = nel + nvpiv
4438C=======================================================================
4439C CONSTRUCT NEW ELEMENT
4440C=======================================================================
4441C -------------------------------------------------------------
4442C At this point, me is the pivotal supervariable. It will be
4443C converted into the current element. Scan list of the
4444C pivotal supervariable, me, setting tree pointers and
4445C constructing new list of supervariables for the new element,
4446C me. p is a pointer to the current position in the old list.
4447C -------------------------------------------------------------
4448C flag the variable "me" as being in Lme by negating nv (me)
4449 nv(me) = -nvpiv
4450 degme = 0
4451 IF (elenme .EQ. 0) THEN
4452C ----------------------------------------------------------
4453C construct the new element in place
4454C ----------------------------------------------------------
4455 pme1 = pe(me)
4456 pme2 = pme1 - 1
4457 DO 60 p = pme1, pme1 + len(me) - 1
4458 i = iw(p)
4459 nvi = nv(i)
4460 IF (nvi .GT. 0) THEN
4461C ----------------------------------------------------
4462C i is a principal variable not yet placed in Lme.
4463C store i in new list
4464C ----------------------------------------------------
4465 degme = degme + nvi
4466C flag i as being in Lme by negating nv (i)
4467 nv(i) = -nvi
4468 pme2 = pme2 + 1
4469 iw(pme2) = i
4470 IF (degree(i).NE.n2) THEN
4471C ----------------------------------------------------
4472C remove variable i from degree list. (only if i \in V0)
4473C ----------------------------------------------------
4474 ilast = last(i)
4475 inext = next(i)
4476 IF (inext .NE. 0) last(inext) = ilast
4477 IF (ilast .NE. 0) THEN
4478 next(ilast) = inext
4479 ELSE
4480C i is at the head of the degree list
4481 IF (wf(i).GT.norig) THEN
4482 deg = min(((wf(i)-norig)/pas) + norig, nbbuck)
4483 ELSE
4484 deg = wf(i)
4485 ENDIF
4486 head(deg) = inext
4487 ENDIF
4488 ENDIF
4489 ENDIF
4490 60 CONTINUE
4491C this element takes no new memory in iw:
4492 newmem = 0
4493 ELSE
4494C ----------------------------------------------------------
4495C construct the new element in empty space, iw (pfree ...)
4496C ----------------------------------------------------------
4497 p = pe(me)
4498 pme1 = pfree
4499 slenme = len(me) - elenme
4500 knt1_updated = 0
4501 DO 120 knt1 = 1, elenme + 1
4502 knt1_updated = knt1_updated +1
4503 IF (knt1 .GT. elenme) THEN
4504C search the supervariables in me.
4505 e = me
4506 pj = p
4507 ln = slenme
4508 ELSE
4509C search the elements in me.
4510 e = iw(p)
4511 p = p + 1
4512 pj = pe(e)
4513 ln = len (e)
4514 ENDIF
4515C -------------------------------------------------------
4516C search for different supervariables and add them to the
4517C new list, compressing when necessary. this loop is
4518C executed once for each element in the list and once for
4519C all the supervariables in the list.
4520C -------------------------------------------------------
4521 knt2_updated = 0
4522 DO 110 knt2 = 1, ln
4523 knt2_updated = knt2_updated+1
4524 i = iw(pj)
4525 pj = pj + 1
4526 nvi = nv(i)
4527 IF (nvi .GT. 0) THEN
4528C -------------------------------------------------
4529C compress iw, if necessary
4530C -------------------------------------------------
4531 IF (pfree .GT. iwlen) THEN
4532C prepare for compressing iw by adjusting
4533C pointers and lengths so that the lists being
4534C searched in the inner and outer loops contain
4535C only the remaining entries.
4536 pe(me) = p
4537 len(me) = len(me) - knt1_updated
4538C Reset KNT1_UPDATED in case of recompress
4539C at same iteration of the loop 120
4540 knt1_updated = 0
4541C Check if anything left in supervariable ME
4542 IF (len(me) .EQ. 0) pe(me) = 0_8
4543 pe(e) = pj
4544 len(e) = ln - knt2_updated
4545C Reset KNT2_UPDATED in case of recompress
4546C at same iteration of the loop 110
4547 knt2_updated = 0
4548C Check if anything left in element E
4549 IF (len(e) .EQ. 0) pe(e) = 0_8
4550 ncmpa = ncmpa + 1
4551C store first item in pe
4552C set first entry to -item
4553 DO 70 j = 1, n
4554 pn = pe(j)
4555 IF (pn .GT. 0) THEN
4556 pe(j) = int(iw(pn),8)
4557 iw(pn) = -j
4558 ENDIF
4559 70 CONTINUE
4560C psrc/pdst point to source/destination
4561 pdst = 1
4562 psrc = 1
4563 pend = pme1 - 1
4564C while loop:
4565 80 CONTINUE
4566 IF (psrc .LE. pend) THEN
4567C search for next negative entry
4568 j = -iw(psrc)
4569 psrc = psrc + 1
4570 IF (j .GT. 0) THEN
4571 iw(pdst) = int(pe(j))
4572 pe(j) = pdst
4573 pdst = pdst + 1_8
4574C copy from source to destination
4575 lenj = len(j)
4576 DO 90 knt3 = 0, lenj - 2
4577 iw(pdst + knt3) = iw(psrc + knt3)
4578 90 CONTINUE
4579 pdst = pdst + lenj - 1
4580 psrc = psrc + lenj - 1
4581 ENDIF
4582 GO TO 80
4583 ENDIF
4584C move the new partially-constructed element
4585 p1 = pdst
4586 DO 100 psrc = pme1, pfree - 1
4587 iw(pdst) = iw(psrc)
4588 pdst = pdst + 1
4589 100 CONTINUE
4590 pme1 = p1
4591 pfree = pdst
4592 pj = pe(e)
4593 p = pe(me)
4594 ENDIF
4595C -------------------------------------------------
4596C i is a principal variable not yet placed in Lme
4597C store i in new list
4598C -------------------------------------------------
4599 degme = degme + nvi
4600C flag i as being in Lme by negating nv (i)
4601 nv(i) = -nvi
4602 iw(pfree) = i
4603 pfree = pfree + 1
4604 IF (degree(i).NE.n2) THEN
4605C -------------------------------------------------
4606C remove variable i from degree link list
4607C (only if i in V0)
4608C -------------------------------------------------
4609 ilast = last(i)
4610 inext = next(i)
4611 IF (inext .NE. 0) last(inext) = ilast
4612 IF (ilast .NE. 0) THEN
4613 next(ilast) = inext
4614 ELSE
4615 IF (wf(i).GT.norig) THEN
4616 deg = min(((wf(i)-norig)/pas) + norig , nbbuck)
4617 ELSE
4618 deg = wf(i)
4619 ENDIF
4620C i is at the head of the degree list
4621 head(deg) = inext
4622 ENDIF
4623 ENDIF
4624 ENDIF
4625 110 CONTINUE
4626 IF (e .NE. me) THEN
4627C set tree pointer and flag to indicate element e is
4628C absorbed into new element me (the parent of e is me)
4629 pe(e) = int(-me,8)
4630 w(e) = 0
4631 ENDIF
4632 120 CONTINUE
4633 pme2 = pfree - 1
4634C this element takes newmem new memory in iw (possibly zero)
4635 newmem = pfree - pme1
4636 mem = mem + newmem
4637 maxmem = max(maxmem, mem)
4638 ENDIF
4639C -------------------------------------------------------------
4640C me has now been converted into an element in iw (pme1..pme2)
4641C -------------------------------------------------------------
4642C degme holds the external degree of new element
4643 degree(me) = degme
4644 pe(me) = pme1
4645 len(me) = int(pme2 - pme1 + 1_8)
4646C -------------------------------------------------------------
4647C make sure that wflg is not too large. With the current
4648C value of wflg, wflg+n must not cause integer overflow
4649C -------------------------------------------------------------
4650 IF (wflg .GT. maxint_n) THEN
4651 DO 130 x = 1, n
4652 IF (w(x) .NE. 0) w(x) = 1
4653 130 CONTINUE
4654 wflg = 2
4655 ENDIF
4656C=======================================================================
4657C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
4658C=======================================================================
4659C -------------------------------------------------------------
4660C Scan 1: compute the external degrees of previous elements
4661C with respect to the current element. That is:
4662C (w (e) - wflg) = |Le \ Lme|
4663C for each element e that appears in any supervariable in Lme.
4664C The notation Le refers to the pattern (list of
4665C supervariables) of a previous element e, where e is not yet
4666C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
4667C The notation Lme refers to the pattern of the current element
4668C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
4669C zero, then the element e will be absorbed in scan 2.
4670C -------------------------------------------------------------
4671 DO 150 pme = pme1, pme2
4672 i = iw(pme)
4673 eln = elen(i)
4674 IF (eln .GT. 0) THEN
4675C note that nv (i) has been negated to denote i in Lme:
4676 nvi = -nv(i)
4677 wnvi = wflg - nvi
4678 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
4679 e = iw(p)
4680 we = w(e)
4681 IF (we .GE. wflg) THEN
4682C unabsorbed element e has been seen in this loop
4683 we = we - nvi
4684 ELSE IF (we .NE. 0) THEN
4685C e is an unabsorbed element
4686C this is the first we have seen e in all of Scan 1
4687 we = degree(e) + wnvi
4688 wf(e) = 0
4689 ENDIF
4690 w(e) = we
4691 140 CONTINUE
4692 ENDIF
4693 150 CONTINUE
4694C=======================================================================
4695C DEGREE UPDATE AND ELEMENT ABSORPTION
4696C=======================================================================
4697C -------------------------------------------------------------
4698C Scan 2: for each i in Lme, sum up the degree of Lme (which
4699C is degme), plus the sum of the external degrees of each Le
4700C for the elements e appearing within i, plus the
4701C supervariables in i. Place i in hash list.
4702C -------------------------------------------------------------
4703 DO 180 pme = pme1, pme2
4704 i = iw(pme)
4705 p1 = pe(i)
4706 p2 = p1 + elen(i) - 1
4707 pn = p1
4708 hash = 0_8
4709 deg = 0
4710 wf3 = 0
4711 wf4 = 0
4712 nvi = -nv(i)
4713C ----------------------------------------------------------
4714C scan the element list associated with supervariable i
4715C ----------------------------------------------------------
4716 DO 160 p = p1, p2
4717 e = iw(p)
4718C dext = | Le \ Lme |
4719 dext = w(e) - wflg
4720 IF (dext .GT. 0) THEN
4721 IF ( wf(e) .EQ. 0 ) THEN
4722C First time we meet e : compute wf(e)
4723C which holds the surface associated to element e
4724C it will later be deducted from fill-in
4725C area of all variables adjacent to e
4726 wf(e) = dext * ( (2 * degree(e)) - dext - 1)
4727 ENDIF
4728 wf4 = wf4 + wf(e)
4729 deg = deg + dext
4730 iw(pn) = e
4731 pn = pn + 1
4732 hash = hash + int(e, kind=8)
4733 ELSE IF (dext .EQ. 0) THEN
4734#if defined (NOAGG4)
4735 iw(pn) = e
4736 pn = pn + 1
4737 hash = hash + int(e,kind=8)
4738#else
4739C aggressive absorption: e is not adjacent to me, but
4740C the |Le \ Lme| is 0, so absorb it into me
4741 pe(e) = int(-me,8)
4742 w(e) = 0
4743#endif
4744 ENDIF
4745 160 CONTINUE
4746C count the number of elements in i (including me):
4747 elen(i) = int(pn - p1 + 1_8)
4748C ----------------------------------------------------------
4749C scan the supervariables in the list associated with i
4750C ----------------------------------------------------------
4751 p3 = pn
4752 DO 170 p = p2 + 1_8, p1 + int(len(i) - 1,8)
4753 j = iw(p)
4754 nvj = nv(j)
4755 IF (nvj .GT. 0) THEN
4756C j is unabsorbed, and not in Lme.
4757C add to degree and add to new list
4758 deg = deg + nvj
4759 wf3 = wf3 + nvj
4760 iw(pn) = j
4761 pn = pn + 1
4762 hash = hash + int(j,kind=8)
4763 ENDIF
4764 170 CONTINUE
4765C
4766 IF (degree(i).EQ.n2) deg = n2
4767C ----------------------------------------------------------
4768C update the degree and check for mass elimination
4769C ----------------------------------------------------------
4770#if defined (NOAGG4)
4771 IF (elen(i).EQ.1 .AND. p3.EQ.pn) THEN
4772#else
4773 IF (deg .EQ. 0) THEN
4774#endif
4775C -------------------------------------------------------
4776C mass elimination
4777C -------------------------------------------------------
4778C There is nothing left of this node except for an
4779C edge to the current pivot element. elen (i) is 1,
4780C and there are no variables adjacent to node i.
4781C Absorb i into the current pivot element, me.
4782 pe (i) = int(-me,8)
4783 nvi = -nv(i)
4784 degme = degme - nvi
4785 nvpiv = nvpiv + nvi
4786 nel = nel + nvi
4787 nv(i) = 0
4788 elen(i) = 0
4789 ELSE
4790C -------------------------------------------------------
4791C update the upper-bound degree of i
4792C -------------------------------------------------------
4793C the following degree does not yet include the size
4794C of the current element, which is added later:
4795 IF (degree(i).NE.n2) THEN
4796C I does not belong to halo
4797 IF ( degree(i).LT.deg ) THEN
4798C Our appox degree is loose.
4799C we keep old value. Note that in
4800C this case we cannot substract WF(I)
4801C for min-fill score.
4802 wf4 = 0
4803 wf3 = 0
4804 ELSE
4805 degree(i) = deg
4806 ENDIF
4807 ENDIF
4808C
4809C compute WF(I) taking into account size of block 3.0
4810 wf(i) = wf4 + 2*nvi*wf3
4811C -------------------------------------------------------
4812C add me to the list for i
4813C -------------------------------------------------------
4814C move first supervariable to end of list
4815 iw(pn) = iw(p3)
4816C move first element to end of element part of list
4817 iw (p3) = iw(p1)
4818C add new element to front of list.
4819 iw(p1) = me
4820C store the new length of the list in len (i)
4821 len(i) = int(pn - p1 + 1)
4822 IF (deg.NE.n2) THEN
4823C -------------------------------------------------------
4824C place in hash bucket. Save hash key of i in last (i).
4825C -------------------------------------------------------
4826 hash = mod(hash, hmod) + 1_8
4827 j = head(hash)
4828 IF (j .LE. 0) THEN
4829C the degree list is empty, hash head is -j
4830 next(i) = -j
4831 head(hash) = -i
4832 ELSE
4833C degree list is not empty
4834C use last (head (hash)) as hash head
4835 next(i) = last(j)
4836 last(j) = i
4837 ENDIF
4838 last(i) = int(hash,kind=kind(last))
4839 ENDIF
4840 ENDIF
4841 180 CONTINUE
4842 degree(me) = degme
4843C -------------------------------------------------------------
4844C Clear the counter array, w (...), by incrementing wflg.
4845C -------------------------------------------------------------
4846 dmax = max(dmax, degme)
4847 wflg = wflg + dmax
4848C make sure that wflg+n does not cause integer overflow
4849 IF (wflg .GT. maxint_n) THEN
4850 DO 190 x = 1, n
4851 IF (w(x) .NE. 0) w(x) = 1
4852 190 CONTINUE
4853 wflg = 2
4854 ENDIF
4855C at this point, w (1..n) .lt. wflg holds
4856C=======================================================================
4857C SUPERVARIABLE DETECTION
4858C=======================================================================
4859 DO 250 pme = pme1, pme2
4860 i = iw(pme)
4861 IF ( (nv(i) .LT. 0) .AND. (degree(i).NE.n2) ) THEN
4862C i is a principal variable in Lme
4863C -------------------------------------------------------
4864C examine all hash buckets with 2 or more variables. We
4865C do this by examing all unique hash keys for super-
4866C variables in the pattern Lme of the current element, me
4867C -------------------------------------------------------
4868 hash = int(last(i),kind=8)
4869C let i = head of hash bucket, and empty the hash bucket
4870 j = head(hash)
4871 IF (j .EQ. 0) GO TO 250
4872 IF (j .LT. 0) THEN
4873C degree list is empty
4874 i = -j
4875 head(hash) = 0
4876 ELSE
4877C degree list is not empty, restore last () of head
4878 i = last(j)
4879 last(j) = 0
4880 ENDIF
4881 IF (i .EQ. 0) GO TO 250
4882C while loop:
4883 200 CONTINUE
4884 IF (next(i) .NE. 0) THEN
4885C ----------------------------------------------------
4886C this bucket has one or more variables following i.
4887C scan all of them to see if i can absorb any entries
4888C that follow i in hash bucket. Scatter i into w.
4889C ----------------------------------------------------
4890 ln = len(i)
4891 eln = elen(i)
4892C do not flag the first element in the list (me)
4893 DO 210 p = pe(i) + 1_8, pe(i) + int(ln - 1,8)
4894 w(iw(p)) = wflg
4895 210 CONTINUE
4896C ----------------------------------------------------
4897C scan every other entry j following i in bucket
4898C ----------------------------------------------------
4899 jlast = i
4900 j = next(i)
4901C while loop:
4902 220 CONTINUE
4903 IF (j .NE. 0) THEN
4904C -------------------------------------------------
4905C check if j and i have identical nonzero pattern
4906C -------------------------------------------------
4907C jump if i and j do not have same size data structure
4908 IF (len(j) .NE. ln) GO TO 240
4909C jump if i and j do not have same number adj elts
4910 IF (elen(j) .NE. eln) GO TO 240
4911C do not flag the first element in the list (me)
4912 DO 230 p = pe(j) + 1_8, pe(j) + int(ln - 1,8)
4913C jump if an entry (iw(p)) is in j but not in i
4914 IF (w(iw(p)) .NE. wflg) GO TO 240
4915 230 CONTINUE
4916C -------------------------------------------------
4917C found it! j can be absorbed into i
4918C -------------------------------------------------
4919 pe(j) = int(-i,8)
4920 wf(i) = max(wf(i),wf(j))
4921C both nv (i) and nv (j) are negated since they
4922C are in Lme, and the absolute values of each
4923C are the number of variables in i and j:
4924 nv(i) = nv(i) + nv(j)
4925 nv(j) = 0
4926 elen(j) = 0
4927C delete j from hash bucket
4928 j = next(j)
4929 next(jlast) = j
4930 GO TO 220
4931C -------------------------------------------------
4932 240 CONTINUE
4933C j cannot be absorbed into i
4934C -------------------------------------------------
4935 jlast = j
4936 j = next(j)
4937 GO TO 220
4938 ENDIF
4939C ----------------------------------------------------
4940C no more variables can be absorbed into i
4941C go to next i in bucket and clear flag array
4942C ----------------------------------------------------
4943 wflg = wflg + 1
4944 i = next(i)
4945 IF (i .NE. 0) GO TO 200
4946 ENDIF
4947 ENDIF
4948 250 CONTINUE
4949C=======================================================================
4950C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
4951C=======================================================================
4952 p = pme1
4953 nleft = totel - nel + nleft_v1
4954 DO 260 pme = pme1, pme2
4955 i = iw(pme)
4956 nvi = -nv(i)
4957 IF (nvi .GT. 0) THEN
4958C i is a principal variable in Lme
4959C restore nv (i) to signify that i is principal
4960 nv(i) = nvi
4961 IF (degree(i).NE.n2) THEN
4962C -------------------------------------------------------
4963C compute the external degree (add size of current elem)
4964C -------------------------------------------------------
4965C--------------------------
4966C--------------------------
4967 IF (degree(i) + degme .GT. nleft ) THEN
4968C
4969 deg = degree(i)
4970 rmf1 = dble(deg)*dble( (deg-1) + 2*degme )
4971 & - dble(wf(i))
4972 degree(i) = nleft - nvi
4973 deg = degree(i)
4974 rmf = dble(deg)*dble(deg-1)
4975 & - dble(degme-nvi)*dble(degme-nvi-1)
4976 rmf = min(rmf, rmf1)
4977 ELSE
4978 deg = degree(i)
4979 degree(i) = degree(i) + degme - nvi
4980C All previous cliques taken into account (AMF4)
4981 rmf = dble(deg)*dble( (deg-1) + 2*degme )
4982 & - dble(wf(i))
4983 ENDIF
4984C
4985 rmf = rmf / dble(nvi+1)
4986C
4987 IF (rmf.LT.dummy) THEN
4988 wf(i) = int( anint( rmf ))
4989 ELSEIF (rmf / dble(n) .LT. dummy) THEN
4990 wf(i) = int ( anint( rmf/dble(n) ))
4991 ELSE
4992 wf(i) = idummy
4993 ENDIF
4994 wf(i) = max(1,wf(i))
4995 deg = wf(i)
4996 IF (deg.GT.norig) THEN
4997 deg = min(((deg-norig)/pas) + norig, nbbuck)
4998 ENDIF
4999 inext = head(deg)
5000 IF (inext .NE. 0) last(inext) = i
5001 next(i) = inext
5002 last(i) = 0
5003 head(deg) = i
5004C -------------------------------------------------------
5005C save the new degree, and find the minimum degree
5006C -------------------------------------------------------
5007 mindeg = min(mindeg, deg)
5008C begin HALO
5009 ENDIF
5010C end HALO
5011C -------------------------------------------------------
5012C place the supervariable in the element pattern
5013C -------------------------------------------------------
5014 iw(p) = i
5015 p = p + 1
5016 ENDIF
5017 260 CONTINUE
5018C=======================================================================
5019C FINALIZE THE NEW ELEMENT
5020C=======================================================================
5021 nv(me) = nvpiv + degme
5022C fill_est = fill_est + nvpiv * (nvpiv + 2 * degme)
5023C nv (me) is now the degree of pivot (including diagonal part)
5024C save the length of the list for the new element me
5025 len(me) = int(p - pme1)
5026 IF (len(me) .EQ. 0) THEN
5027C there is nothing left of the current pivot element
5028 pe(me) = 0_8
5029 w(me) = 0
5030 ENDIF
5031 IF (newmem .NE. 0) THEN
5032C element was not constructed in place: deallocate part
5033C of it (final size is less than or equal to newmem,
5034C since newly nonprincipal variables have been removed).
5035 pfree = p
5036 mem = mem - newmem + int(len(me),8)
5037 ENDIF
5038C=======================================================================
5039C END WHILE (selecting pivots)
5040 GO TO 30
5041 ENDIF
5042C=======================================================================
5043C begin HALO V2
5044 IF (nel.LT.norig) THEN
5045C
5046C All possible pivots (not flagged have been eliminated).
5047C We amalgamate all flagged variables at the root and
5048C we finish the elimination tree.
5049C 1/ Go through all
5050C non absorbed elements (root of the subgraph)
5051C and absorb in ME
5052C 2/ perform mass elimination of all dense rows
5053 DO deg = mindeg, nbbuck+1
5054 me = head(deg)
5055 IF (me .GT. 0) GO TO 51
5056 ENDDO
5057 51 mindeg = deg
5058 nelme = -(nel+1)
5059 DO x=1,n
5060 IF ((pe(x).GT.0) .AND. (elen(x).LT.0)) THEN
5061C X is an unabsorbed element
5062 pe(x) = int(-me,8)
5063C W(X) = 0 could be suppressed ?? check it
5064 ELSEIF (degree(x).EQ.n2) THEN
5065C X is a dense row, absorb it in ME (mass elimination)
5066 nel = nel + nv(x)
5067 pe(x) = int(-me,8)
5068 elen(x) = 0
5069C Correct value of NV is (secondary variable)
5070 nv(x) = 0
5071 ENDIF
5072 ENDDO
5073C ME is the root node
5074 elen(me) = nelme
5075C Correct value of NV is (principal variable)
5076 nv(me) = nbflag
5077 pe(me) = 0_8
5078 IF (nel.NE.norig) THEN
5079 ncmpa = -norig - 1
5080 GOTO 500
5081 ENDIF
5082 ENDIF
5083C end HALO
5084C=======================================================================
5085C COMPUTE THE PERMUTATION VECTORS and update TREE
5086C=======================================================================
5087C ----------------------------------------------------------------
5088C The time taken by the following code is O(n). At this
5089C point, elen (e) = -k has been done for all elements e,
5090C and elen (i) = 0 has been done for all nonprincipal
5091C variables i. At this point, there are no principal
5092C supervariables left, and all elements are absorbed.
5093C ----------------------------------------------------------------
5094C ----------------------------------------------------------------
5095C compute the ordering of unordered nonprincipal variables
5096C ----------------------------------------------------------------
5097 DO 290 i = 1, n
5098 IF (elen(i) .EQ. 0) THEN
5099C ----------------------------------------------------------
5100C i is an un-ordered row. Traverse the tree from i until
5101C reaching an element, e. The element, e, was the
5102C principal supervariable of i and all nodes in the path
5103C from i to when e was selected as pivot.
5104C ----------------------------------------------------------
5105 j = int(-pe(i))
5106C while (j is a variable) do:
5107 270 CONTINUE
5108 IF (elen(j) .GE. 0) THEN
5109 j = int(-pe(j))
5110 GO TO 270
5111 ENDIF
5112 e = j
5113C ----------------------------------------------------------
5114C get the current pivot ordering of e
5115C ----------------------------------------------------------
5116 k = -elen(e)
5117C ----------------------------------------------------------
5118C traverse the path again from i to e, and compress the
5119C path (all nodes point to e). Path compression allows
5120C this code to compute in O(n) time. Order the unordered
5121C nodes in the path, and place the element e at the end.
5122C ----------------------------------------------------------
5123 j = i
5124C while (j is a variable) do:
5125 280 CONTINUE
5126 IF (elen(j) .GE. 0) THEN
5127 jnext = int(-pe(j))
5128 pe(j) = int(-e,8)
5129 IF (elen(j) .EQ. 0) THEN
5130C j is an unordered row
5131 elen(j) = k
5132 k = k + 1
5133 ENDIF
5134 j = jnext
5135 GO TO 280
5136 ENDIF
5137C leave elen (e) negative, so we know it is an element
5138 elen(e) = -k
5139 ENDIF
5140 290 CONTINUE
5141 IF (compute_perm) THEN
5142C ----------------------------------------------------------------
5143C reset the inverse permutation (elen (1..n)) to be positive,
5144C and compute the pivot order (last (1..n)).
5145C ----------------------------------------------------------------
5146C begin COMPRESS
5147 IF(compress) THEN
5148C N is the size of the compressed graph.
5149C If the graph was compressed on input then
5150C indices in ELEN are in [1,TOTEL]
5151C We build the inverse of ELEN in LAST (similar to
5152C the pivot order but has zeros in it) and then compress
5153C it. Since LAST is assumed to be of size N at the
5154C interface level, we need another array to store
5155C the inverse of ELEN for entries greater than N
5156C We use DEGREE.
5157 last(1:n) = 0
5158 head(1:totel-n)=0
5159 DO i = 1, n
5160 k = abs(elen(i))
5161 IF ( k <= n ) THEN
5162 last(k) = i
5163 ELSE
5164 head(k-n)=i
5165 ENDIF
5166 ENDDO
5167 i = 1
5168 DO k = 1, n
5169 IF(last(k) .NE. 0) THEN
5170 last(i) = last(k)
5171 elen(last(k)) = i
5172 i = i + 1
5173 ENDIF
5174 ENDDO
5175 DO k = n+1, totel
5176 IF (head(k-n) .NE. 0) THEN
5177 last(i)=head(k-n)
5178 elen(head(k-n)) = i
5179 i = i + 1
5180 ENDIF
5181 END DO
5182 ELSE
5183 DO 300 i = 1, n
5184 k = abs(elen(i))
5185 last(k) = i
5186 elen(i) = k
5187300 CONTINUE
5188 ENDIF
5189C end COMPRESS
5190 ENDIF
5191C=======================================================================
5192C RETURN THE MEMORY USAGE IN IW
5193C=======================================================================
5194C If maxmem is less than or equal to iwlen, then no compressions
5195C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
5196C compressions did occur, and iwlen would have had to have been
5197C greater than or equal to maxmem for no compressions to occur.
5198C Return the value of maxmem in the pfree argument.
5199 500 pfree = maxmem
5200C===============================
5201C Save IPE in PARENT array
5202 DO i=1,n
5203 parent(i) = int(pe(i))
5204 ENDDO
5205C===============================
5206 RETURN
5207 END SUBROUTINE mumps_hamf4
5208C
5209C-----------------------------------------------------------------------
5210C MUMPS_QAMD: modified version of reference AMD routine MUMPS_ANA_H
5211C designed to automatically detect and exploit dense or quasi dense
5212C rows in the reduced matrix at any step of the minimum degree.
5213C
5214C References:
5215C P.R. AMESTOY, Recent progress in parallel multifrontal solvers
5216C for unsymmetric sparse matrices,
5217C Proceedings of the 15th World Congress on Scientific Computation,
5218C Modelling and Applied Mathematics, IMACS, Berlin (1997).
5219C P.R. AMESTOY (1999), Methodes directes paralleles de
5220C resolution des systemes creux de grande taille.
5221C Rapport de these d'habilitation de l'INPT.
5222C
5223C Date 1997
5224C ---------
5225C
5226 SUBROUTINE mumps_qamd
5227 & (totel, compute_perm, iversion, thresh, ndense,
5228 & n, iwlen, pe, pfree, len, iw, nv,
5229 & elen, last, ncmpa, degree, head, next, w,
5230 & parent)
5231C Input not modified
5232 INTEGER, INTENT(IN) :: TOTEL, N
5233 LOGICAL, INTENT(IN) :: COMPUTE_PERM
5234 INTEGER, INTENT(IN) :: IVersion, THRESH
5235 INTEGER(8), INTENT(IN) :: IWLEN
5236 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
5237 INTEGER, INTENT(OUT) :: NCMPA
5238 INTEGER, INTENT(OUT) :: ELEN(N), PARENT(N)
5239 INTEGER, INTENT(OUT) :: LAST(N)
5240 INTEGER(8), INTENT(INOUT) :: PFREE
5241 INTEGER(8), INTENT(INOUT) :: PE(N)
5242C NV also meaningful as input to encode compressed graphs
5243 INTEGER, INTENT(INOUT) :: NV(N)
5244 INTEGER, INTENT(OUT) :: NEXT(N), DEGREE(N), HEAD(TOTEL), W(N)
5245 INTEGER, INTENT(OUT) :: NDENSE(N)
5246C The input integer parameter THRESH defines the quasi density:
5247C THRESH : input parameter (not modified)
5248C THRESH is used to compute THRESM
5249C <=0 or N Only exactly dense rows in the reduced matrix are selected.
5250C >1 and <=N THRESH correspond to the munimum density requirement.
5251C
5252C IVersion =
5253C 1 : No dense row detection during elimination
5254C Suppressing dense row selection after 1st
5255C and final restrart (Using initial degree of
5256C quasi dense
5257C rows when restarting and suppress
5258C dense row selection)
5259C else : All functionalities enabled
5260C Additionnal parameters/variables due to dense row manipulation:
5261C PARAMETERS:
5262C ----------
5263C
5264C Local variables:
5265C ---------------
5266 INTEGER THRESM, MINDEN, MAXDEN, NDME
5267 INTEGER NBD,NBED, NBDM, LASTD, NELME
5268C INTEGER DEG1
5269 LOGICAL IDENSE
5270 DOUBLE PRECISION RELDEN
5271C
5272C THRESM : Local Integer holding a
5273C potentially modified value of THRESH.
5274C When quasi dense rows are reintegrated in the
5275C graph to be processed then THRESM is modified.
5276C Note that if one sets THRESM to negative value then
5277C <0 Classical AMD algorithm (no dense row detection)
5278C RELDEN : holds average density to set THRESM automatically
5279C MINDEN: min degree of quasi-dense rows when restarting
5280C MAXDEN: max degree of quasi-dense rows when restarting
5281C NDME : number of dense row adjacent to me
5282C NELME number of pivots selected when reching the root
5283C LASTD index of the last row in the list of dense rows
5284C NBD is the total number of dense rows selected
5285C NBED is the total number of exactly dense rows detected.
5286C NBDM is the maximum number of dense rows selected
5287C IDENSE is used to indicate that the supervariable I is a dense or
5288C quasi-dense row.
5289C-----------------------------------------------------------------------
5290C Given a representation of the nonzero pattern of a symmetric matrix,
5291C A, (excluding the diagonal) perform an approximate minimum
5292C degree ordering to compute a pivot order
5293C such that fill-in in the Cholesky factors A = LL^T is kept low.
5294C Aggressive absorption might be used to
5295C tighten the bound on the degree. This can result a
5296C significant improvement in the quality of the ordering for
5297C some matrices.
5298C-----------------------------------------------------------------------
5299C INPUT ARGUMENTS (unaltered):
5300C-----------------------------------------------------------------------
5301C n : The matrix order.
5302C number of supervariables if compress/blocked format
5303C Restriction: n .ge. 1
5304C totel : Number of variables to eliminate
5305C In case of blocked format:
5306C each variable i is a supervariable of size nv(i)
5307C totel is computed as the sum(nv(i)) for i \in [1:n]
5308C the algorithm stops when totel variables are
5309C eliminated.
5310C compute_perm : indicates if permutations should be computed
5311C on output in last/elen
5312C iwlen: The length of iw (1..iwlen). On input, the matrix is
5313C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
5314C slightly larger than what is required to hold the matrix, at
5315C least iwlen .ge. pfree + n is recommended. Otherwise,
5316C excessive compressions will take place.
5317C *** We do not recommend running this algorithm with ***
5318C *** iwlen .lt. pfree + n. ***
5319C *** Better performance will be obtained if ***
5320C *** iwlen .ge. pfree + n ***
5321C *** or better yet ***
5322C *** iwlen .gt. 1.2 * pfree ***
5323C *** (where pfree is its value on input). ***
5324C The algorithm will not run at all if iwlen .lt. pfree-1.
5325C
5326C Restriction: iwlen .ge. pfree-1
5327C-----------------------------------------------------------------------
5328C INPUT/OUPUT ARGUMENTS:
5329C-----------------------------------------------------------------------
5330C pe: On input, pe (i) is the index in iw of the start of row i, or
5331C zero if row i has no off-diagonal non-zeros.
5332C
5333C During execution, it is used for both supervariables and
5334C elements:
5335C
5336C * Principal supervariable i: index into iw of the
5337C description of supervariable i. A supervariable
5338C represents one or more rows of the matrix
5339C with identical nonzero pattern.
5340C * Non-principal supervariable i: if i has been absorbed
5341C into another supervariable j, then pe (i) = -j.
5342C That is, j has the same pattern as i.
5343C Note that j might later be absorbed into another
5344C supervariable j2, in which case pe (i) is still -j,
5345C and pe (j) = -j2.
5346C * Unabsorbed element e: the index into iw of the description
5347C of element e, if e has not yet been absorbed by a
5348C subsequent element. Element e is created when
5349C the supervariable of the same name is selected as
5350C the pivot.
5351C * Absorbed element e: if element e is absorbed into element
5352C e2, then pe (e) = -e2. This occurs when the pattern of
5353C e (that is, Le) is found to be a subset of the pattern
5354C of e2 (that is, Le2). If element e is "null" (it has
5355C no nonzeros outside its pivot block), then pe (e) = 0.
5356C
5357C On output, pe holds the assembly tree/forest, which implicitly
5358C represents a pivot order with identical fill-in as the actual
5359C order (via a depth-first search of the tree).
5360C
5361C On output:
5362C If nv (i) .gt. 0, then i represents a node in the assembly tree,
5363C and the parent of i is -pe (i), or zero if i is a root.
5364C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
5365C subtree, the root of which is a node in the assembly tree.
5366C
5367C On output: (PE is copied on output into PARENT array)
5368C
5369C pfree: On input, the matrix is stored in iw (1..pfree-1) and
5370C the rest of the array iw is free.
5371C During execution, additional data is placed in iw, and pfree
5372C is modified so that components of iw from pfree are free.
5373C On output, pfree is set equal to the size of iw that
5374C would have been needed for no compressions to occur. If
5375C ncmpa is zero, then pfree (on output) is less than or equal to
5376C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
5377C Otherwise, pfree (on output) is greater than iwlen, and all the
5378C memory in iw was used.
5379C
5380C nv: On input, encoding of compressed graph:
5381C if nv(1) = -1 then graph is not compressed otherwise
5382C nv(I) holds the weight of node I.
5383C During execution, abs (nv (i)) is equal to the number of rows
5384C that are represented by the principal supervariable i. If i is
5385C a nonprincipal variable, then nv (i) = 0.
5386C nv (i) .lt. 0 signifies that i is a
5387C principal variable in the pattern Lme of the current pivot
5388C element me.
5389C On output, nv (e) holds the true degree of element
5390C e at the time it was created (including the diagonal part).
5391C begin HALO
5392C On output, nv(I) can be used to find node in set V1.
5393C Not true anymore : ( nv(I) = N+1 characterizes nodes in V1.
5394C instead nodes in V1 are considered as a dense root node )
5395C end HALO
5396C-----------------------------------------------------------------------
5397C INPUT/MODIFIED (undefined on output):
5398C-----------------------------------------------------------------------
5399C len: On input, len (i) holds the number of entries in row i of the
5400C matrix, excluding the diagonal. The contents of len (1..n)
5401C are undefined on output.
5402C iw: On input, iw (1..pfree-1) holds the description of each row i
5403C in the matrix. The matrix must be symmetric, and both upper
5404C and lower triangular parts must be present. The diagonal must
5405C not be present. Row i is held as follows:
5406C
5407C len (i): the length of the row i data structure
5408C iw (pe (i) ... pe (i) + len (i) - 1):
5409C the list of column indices for nonzeros
5410C in row i (simple supervariables), excluding
5411C the diagonal. All supervariables start with
5412C one row/column each (supervariable i is just
5413C row i).
5414C if len (i) is zero on input, then pe (i) is ignored
5415C on input.
5416C
5417C Note that the rows need not be in any particular order,
5418C and there may be empty space between the rows.
5419C
5420C During execution, the supervariable i experiences fill-in.
5421C This is represented by placing in i a list of the elements
5422C that cause fill-in in supervariable i:
5423C
5424C len (i): the length of supervariable i
5425C iw (pe (i) ... pe (i) + elen (i) - 1):
5426C the list of elements that contain i. This list
5427C is kept short by removing absorbed elements.
5428C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
5429C the list of supervariables in i. This list
5430C is kept short by removing nonprincipal
5431C variables, and any entry j that is also
5432C contained in at least one of the elements
5433C (j in Le) in the list for i (e in row i).
5434C
5435C When supervariable i is selected as pivot, we create an
5436C element e of the same name (e=i):
5437C
5438C len (e): the length of element e
5439C iw (pe (e) ... pe (e) + len (e) - 1):
5440C the list of supervariables in element e.
5441C
5442C An element represents the fill-in that occurs when supervariable
5443C i is selected as pivot (which represents the selection of row i
5444C and all non-principal variables whose principal variable is i).
5445C We use the term Le to denote the set of all supervariables
5446C in element e. Absorbed supervariables and elements are pruned
5447C from these lists when computationally convenient.
5448C
5449C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
5450C The contents of iw are undefined on output.
5451C-----------------------------------------------------------------------
5452C OUTPUT (need not be set on input):
5453C-----------------------------------------------------------------------
5454C elen: See the description of iw above. At the start of execution,
5455C elen (i) is set to zero. During execution, elen (i) is the
5456C number of elements in the list for supervariable i. When e
5457C becomes an element, elen (e) = -nel is set, where nel is the
5458C current step of factorization. elen (i) = 0 is done when i
5459C becomes nonprincipal.
5460C
5461C For variables, elen (i) .ge. 0 holds until just before the
5462C permutation vectors are computed. For elements,
5463C elen (e) .lt. 0 holds.
5464C
5465C On output elen (1..n) holds the inverse permutation (the same
5466C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
5467C then row i is the kth pivot row. Row i of A appears as the
5468C (elen(i))-th row in the permuted matrix, PAP^T.
5469C last: In a degree list, last (i) is the supervariable preceding i,
5470C or zero if i is the head of the list. In a hash bucket,
5471C last (i) is the hash key for i. last (head (hash)) is also
5472C used as the head of a hash bucket if head (hash) contains a
5473C degree list (see head, below).
5474C
5475C On output, last (1..n) holds the permutation (the same as the
5476C 'PERM' argument in Sparspak). That is, if i = last (k), then
5477C row i is the kth pivot row. Row last (k) of A is the k-th row
5478C in the permuted matrix, PAP^T.
5479C ncmpa: The number of times iw was compressed. If this is
5480C excessive, then the execution took longer than what could have
5481C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
5482C larger than the value of pfree on input (or at least
5483C iwlen .ge. pfree + n). The fastest performance will be
5484C obtained when ncmpa is returned as zero. If iwlen is set to
5485C the value returned by pfree on *output*, then no compressions
5486C will occur.
5487C-----------------------------------------------------------------------
5488C LOCAL (not input or output - used only during execution):
5489C-----------------------------------------------------------------------
5490C degree: If i is a supervariable, then degree (i) holds the
5491C current approximation of the external degree of row i (an upper
5492C bound). The external degree is the number of nonzeros in row i,
5493C minus abs (nv (i)) (the diagonal part). The bound is equal to
5494C the external degree if elen (i) is less than or equal to two.
5495C
5496C We also use the term "external degree" for elements e to refer
5497C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
5498C which is the degree of the off-diagonal part of the element e
5499C (not including the diagonal part).
5500Cdense
5501C degree (I) =N+1 if I is an exactly dense row in reduced matrix.
5502C =N+1+LAST_approximate_external_deg of I
5503C if I is a quasi dense row in reduced matrix.
5504C All dense or quasi dense rows are stored in the list pointed
5505C by head(n). Quasi-dense rows (degree(I)=n) are stored first,
5506C and are followed by exactly dense rows in the reduced matrix.
5507C LASTD holds the last row in this list of dense rows or is zero
5508C if the list is empty.
5509Cdense
5510C head: head is used for degree lists. head (deg) is the first
5511C supervariable in a degree list (all supervariables i in a
5512C degree list deg have the same approximate degree, namely,
5513C deg = degree (i)). If the list deg is empty then
5514C head (deg) = 0.
5515C
5516C During supervariable detection head (hash) also serves as a
5517C pointer to a hash bucket.
5518C If head (hash) .gt. 0, there is a degree list of degree hash.
5519C The hash bucket head pointer is last (head (hash)).
5520C If head (hash) = 0, then the degree list and hash bucket are
5521C both empty.
5522C If head (hash) .lt. 0, then the degree list is empty, and
5523C -head (hash) is the head of the hash bucket.
5524C After supervariable detection is complete, all hash buckets
5525C are empty, and the (last (head (hash)) = 0) condition is
5526C restored for the non-empty degree lists.
5527C next: next (i) is the supervariable following i in a link list, or
5528C zero if i is the last in the list. Used for two kinds of
5529C lists: degree lists and hash buckets (a supervariable can be
5530C in only one kind of list at a time).
5531C w: The flag array w determines the status of elements and
5532C variables, and the external degree of elements.
5533C
5534C for elements:
5535C if w (e) = 0, then the element e is absorbed
5536C if w (e) .ge. wflg, then w (e) - wflg is the size of
5537C the set |Le \ Lme|, in terms of nonzeros (the
5538C sum of abs (nv (i)) for each principal variable i that
5539C is both in the pattern of element e and NOT in the
5540C pattern of the current pivot element, me).
5541C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
5542C not yet been seen in the scan of the element lists in
5543C the computation of |Le\Lme| in loop 150 below.
5544C
5545C for variables:
5546C during supervariable detection, if w (j) .ne. wflg then j is
5547C not in the pattern of variable i
5548C
5549C The w array is initialized by setting w (i) = 1 for all i,
5550C and by setting wflg = 2. It is reinitialized if wflg becomes
5551C too large (to ensure that wflg+n does not cause integer
5552C overflow).
5553C-----------------------------------------------------------------------
5554C LOCAL INTEGERS:
5555C-----------------------------------------------------------------------
5556 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
5557 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
5558 & LENJ, LN, ME, MINDEG, NEL,
5559 & NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X
5560 INTEGER KNT1_UPDATED, KNT2_UPDATED
5561 INTEGER(8) MAXMEM, MEM, NEWMEM
5562 INTEGER :: MAXINT_N
5563 INTEGER(8):: HASH, HMOD
5564C deg: the degree of a variable or element
5565C degme: size, |Lme|, of the current element, me (= degree (me))
5566C dext: external degree, |Le \ Lme|, of some element e
5567C dmax: largest |Le| seen so far
5568C e: an element
5569C elenme: the length, elen (me), of element list of pivotal var.
5570C eln: the length, elen (...), of an element list
5571C hash: the computed value of the hash function
5572C hmod: the hash function is computed modulo hmod = max (1,n-1)
5573C i: a supervariable
5574C ilast: the entry in a link list preceding i
5575C inext: the entry in a link list following i
5576C j: a supervariable
5577C jlast: the entry in a link list preceding j
5578C jnext: the entry in a link list, or path, following j
5579C k: the pivot order of an element or variable
5580C knt1: loop counter used during element construction
5581C knt2: loop counter used during element construction
5582C knt3: loop counter used during compression
5583C lenj: len (j)
5584C ln: length of a supervariable list
5585C maxint_n: large integer to test risk of overflow on wflg
5586C maxmem: amount of memory needed for no compressions
5587C me: current supervariable being eliminated, and the
5588C current element created by eliminating that
5589C supervariable
5590C mem: memory in use assuming no compressions have occurred
5591C mindeg: current minimum degree
5592C nel: number of pivots selected so far
5593C newmem: amount of new memory needed for current pivot element
5594C nleft: n - nel, the number of nonpivotal rows/columns remaining
5595C nvi: the number of variables in a supervariable i (= nv (i))
5596C nvj: the number of variables in a supervariable j (= nv (j))
5597C nvpiv: number of pivots in current element
5598C slenme: number of variables in variable list of pivotal variable
5599C we: w (e)
5600C wflg: used for flagging the w array. See description of iw.
5601C wnvi: wflg - nv (i)
5602C x: either a supervariable or an element
5603C-----------------------------------------------------------------------
5604C LOCAL POINTERS:
5605C-----------------------------------------------------------------------
5606 INTEGER(8) P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
5607 & PN, PSRC, PLN, PELN
5608C Any parameter (pe (...) or pfree) or local variable
5609C starting with "p" (for Pointer) is an index into iw,
5610C and all indices into iw use variables starting with
5611C "p." The only exception to this rule is the iwlen
5612C input argument.
5613C p: pointer into lots of things
5614C p1: pe (i) for some variable i (start of element list)
5615C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
5616C p3: index of first supervariable in clean list
5617C pdst: destination pointer, for compression
5618C pend: end of memory to compress
5619C pj: pointer into an element or variable
5620C pme: pointer into the current element (pme1...pme2)
5621C pme1: the current element, me, is stored in iw (pme1...pme2)
5622C pme2: the end of the current element
5623C pn: pointer into a "clean" variable, also used to compress
5624C psrc: source pointer, for compression
5625 LOGICAL COMPRESS
5626C-----------------------------------------------------------------------
5627C FUNCTIONS CALLED:
5628C-----------------------------------------------------------------------
5629 INTRINSIC max, min, mod
5630C=======================================================================
5631C INITIALIZATIONS
5632C=======================================================================
5633C ------------------------------------------------------
5634C Experiments with automatic setting of parameter THRESH.
5635C ------------------------------------------------------
5636 IF (thresh.GT.0) THEN
5637 thresm = min(n,thresh)
5638 DO i=1,n
5639 thresm = max(thresm, len(i))
5640 ENDDO
5641 relden = dble(pfree-1)/dble(n)
5642C RELDEN holds the average density, THRESM the maximum density
5643 thresm = int(relden)*10 + (thresm-int(relden))/10 + 1
5644C ------------------------------------------------------
5645C end automatic setting of THRESM
5646C ------------------------------------------------------
5647 ELSE
5648C only exactly dense row will be selected
5649 thresm = totel
5650 ENDIF
5651 IF (thresm.GE.0) THEN
5652 IF ((thresm.GT.totel).OR.(thresm.LT.2)) THEN
5653C exactly dense rows only
5654 thresm = totel
5655 ENDIF
5656 ENDIF
5657 lastd = 0
5658 nbd = 0
5659 nbed = 0
5660 nbdm = 0
5661 wflg = 2
5662 maxint_n=huge(wflg)-n
5663 mindeg = 1
5664 ncmpa = 0
5665 nel = 0
5666 hmod = int(max(1, n-1),kind=8)
5667 dmax = 0
5668 mem = pfree - 1
5669 maxmem = mem
5670 DO i = 1, n
5671 ndense(i)= 0
5672 w(i) = 1
5673 elen(i) = 0
5674 last(i) = 0
5675 ENDDO
5676 DO i = 1, totel
5677 head(i) = 0
5678 ENDDO
5679 IF(nv(1) .LT. 0) THEN
5680 compress = .false.
5681 ELSE
5682 compress = .true.
5683 ENDIF
5684 IF (compress) THEN
5685 DO i=1,n
5686 degree(i) = 0
5687 DO p= pe(i) , pe(i)+int(len(i)-1,8)
5688 degree(i) = degree(i) + nv(iw(p))
5689 ENDDO
5690 ENDDO
5691 ELSE
5692 DO i=1,n
5693 nv(i) = 1
5694 degree(i) = len(i)
5695 ENDDO
5696 ENDIF
5697C ----------------------------------------------------------------
5698C initialize degree lists and eliminate rows with no off-diag. nz.
5699C ----------------------------------------------------------------
5700C NEXT = 0
5701 DO 20 i = 1, n
5702 deg = degree(i)
5703 IF (deg .GT. 0) THEN
5704C ----------------------------------------------------------
5705C place i in the degree list corresponding to its degree
5706C or in the dense row list if i is dense or quasi dense.
5707C ----------------------------------------------------------
5708C test for row density
5709 IF ( (thresm.GE.0) .AND.
5710 & (deg+nv(i).GE.thresm) ) THEN
5711C I will be inserted in the degree list of N
5712 nbd = nbd+nv(i)
5713 IF (deg+nv(i).NE.totel-nel) THEN
5714 degree(i) = degree(i)+totel+1
5715C insert I at the beginning of degree list of n
5716 deg = totel
5717 inext = head(deg)
5718 IF (inext .NE. 0) last(inext) = i
5719 next(i) = inext
5720 head(deg) = i
5721 last(i) = 0
5722 IF (lastd.EQ.0) lastd=i
5723 ELSE
5724 nbed = nbed+nv(i)
5725 degree(i) = totel+1
5726C insert I at the end of degree list of n
5727 deg = totel
5728 IF (lastd.EQ.0) THEN
5729C degree list is empty
5730 lastd = i
5731 head(deg) = i
5732 next(i) = 0
5733 last(i) = 0
5734 ELSE
5735 next(lastd) = i
5736 last(i) = lastd
5737 lastd = i
5738 next(i) = 0
5739 ENDIF
5740 ENDIF
5741 ELSE
5742C place i in the degree list corresponding to its degree
5743 inext = head(deg)
5744 IF (inext .NE. 0) last(inext) = i
5745 next(i) = inext
5746 head(deg) = i
5747 ENDIF
5748 ELSE
5749C ----------------------------------------------------------
5750C we have a variable that can be eliminated at once because
5751C there is no off-diagonal non-zero in its row.
5752C ----------------------------------------------------------
5753 nel = nel + nv(i)
5754C NEL = NEL + 1
5755 elen(i) = -nel
5756 pe(i) = 0_8
5757 w(i) = 0
5758 ENDIF
5759 20 CONTINUE
5760C We suppress dense row selection if none of them was found in A
5761C in the 1st pass
5762 IF (nbd.EQ.0) thresm = totel
5763C
5764C=======================================================================
5765C WHILE (selecting pivots) DO
5766C=======================================================================
5767 30 IF (nel .LT. totel) THEN
5768C=======================================================================
5769C GET PIVOT OF MINIMUM DEGREE
5770C=======================================================================
5771C -------------------------------------------------------------
5772C find next supervariable for elimination
5773C -------------------------------------------------------------
5774 DO 40 deg = mindeg, totel
5775 me = head(deg)
5776 IF (me .GT. 0) GO TO 50
5777 40 CONTINUE
5778 50 mindeg = deg
5779 IF (deg.LT.totel) THEN
5780C -------------------------------------------------------------
5781C remove chosen variable from link list
5782C -------------------------------------------------------------
5783 inext = next(me)
5784 IF (inext .NE. 0) last(inext) = 0
5785 head(deg) = inext
5786 ELSE
5787 nbdm = max(nbdm,nbd)
5788 IF (degree(me).GT.totel+1) THEN
5789 minden = nbd
5790 maxden = 0
5791 IF (wflg .GT. maxint_n) THEN
5792 DO 52 x = 1, n
5793 IF (w(x) .NE. 0) w(x) = 1
5794 52 CONTINUE
5795 wflg = 2
5796 ENDIF
5797 wflg = wflg + 1
5798 51 CONTINUE
5799C ---------------------------------------------------------
5800C remove chosen variable from link list
5801C ---------------------------------------------------------
5802 inext = next(me)
5803 IF (inext .NE. 0) THEN
5804 last(inext) = 0
5805 ELSE
5806 lastd = 0
5807 ENDIF
5808C ----------------------------------------------------------
5809c build adjacency list of ME in quotient gragh
5810C and calculate its external degree in ndense(me)
5811C ----------------------------------------------------------
5812 ndense(me) = 0
5813 w(me) = wflg
5814 p1 = pe(me)
5815 p2 = p1 + int(len(me) -1,8)
5816C PLN-1 holds the pointer in IW to the last elet/var in adj list
5817C of ME. LEN(ME) will then be set to PLN-P1
5818C PELN-1 hold the pointer in IW to the last elet in adj list
5819C of ME. ELEN(ME) will then be set to PELN-P1
5820C element adjacent to ME
5821 pln = p1
5822 peln = p1
5823 DO 55 p=p1,p2
5824 e= iw(p)
5825 IF (w(e).EQ.wflg) GOTO 55
5826 w(e) = wflg
5827 IF (pe(e).LT.0_8) THEN
5828C E is a nonprincipal variable or absorbed element
5829 x = e
5830 53 x = int(-pe(x))
5831 IF (w(x) .EQ.wflg) GOTO 55
5832 w(x) = wflg
5833 IF ( pe(x) .LT. 0_8 ) GOTO 53
5834 e = x
5835 ENDIF
5836C -------------------------------------------
5837C E is an unabsorbed element or a "dense" row
5838C (NOT already flagged)
5839C -------------------------------------------
5840 IF (elen(e).LT.0) then
5841C E is a new element in adj(ME)
5842 ndense(e) = ndense(e) - nv(me)
5843 iw(pln) = iw(peln)
5844 iw(peln) = e
5845 pln = pln+1_8
5846 peln = peln + 1_8
5847C update ndense of ME with all unflagged dense
5848C rows in E
5849 pme1 = pe(e)
5850 DO 54 pme = pme1, pme1+int(len(e)-1,8)
5851 x = iw(pme)
5852 IF ((elen(x).GE.0).AND.(w(x).NE.wflg)) THEN
5853C X is a dense row
5854 ndense(me) = ndense(me) + nv(x)
5855 w(x) = wflg
5856 ENDIF
5857 54 CONTINUE
5858 ELSE
5859C E is a dense row
5860 ndense(me) = ndense(me) + nv(e)
5861 iw(pln)=e
5862 pln = pln+1_8
5863 ENDIF
5864 55 CONTINUE
5865C ----------------------------------------------
5866C DEGREE(ME)-(N+1) holds last external degree computed
5867C when Me was detected as dense
5868C NDENSE(ME) is the exact external degree of ME
5869C ----------------------------------------------
5870 wflg = wflg + 1
5871 len(me) = int(pln-p1)
5872 elen(me) = int(peln-p1)
5873 ndme = ndense(me)+nv(me)
5874 minden = min(minden, ndme)
5875 maxden = max(maxden, ndme)
5876C If we want to select ME as exactly dense (NDME.EQ.NBD)
5877C of quasi dense NDME.GE.THRESMupdated then
5878C ndense(of elements adjacent to ME) sould be updated
5879 IF (ndense(me).EQ.0) ndense(me) =1
5880 IF (iversion.EQ.1) THEN
5881C ------------------------------------------------
5882C place ME in the degree list of DEGREE(ME)-(N+1)
5883C NDENSE is not used in this case (simulate of
5884C preprocessing )
5885C ------------------------------------------------
5886 deg = max(degree(me)-(totel+1), 1)
5887 ELSE
5888C -----------------------------------------
5889C place ME in the degree list of NDENSE(ME)
5890C -----------------------------------------
5891 deg = ndense(me)
5892 ENDIF
5893 degree(me) = deg
5894 mindeg = min(deg,mindeg)
5895 jnext = head(deg)
5896 IF (jnext.NE. 0) last(jnext) = me
5897 next(me) = jnext
5898 head(deg) = me
5899C ------------------------------
5900C process next quasi dense row
5901C ------------------------------
5902 me = inext
5903 IF (me.NE.0) THEN
5904 IF (degree(me).GT.(totel+1) ) GOTO 51
5905 ENDIF
5906 head(totel) = me
5907C ---------------------------------------
5908C update dense row selection strategy
5909C -------------------------------------
5910C
5911 IF (iversion .EQ.1 ) THEN
5912 thresm = totel
5913 ELSE
5914 thresm=max(thresm*2,minden+(maxden-minden)/2)
5915C THRESM = max(THRESM*2, MINDEN*2)
5916 thresm = min(thresm,nbd)
5917 IF (thresm.GE.nbd) thresm=totel
5918 ENDIF
5919 nbd = nbed
5920C
5921 GOTO 30
5922 ENDIF
5923C -------------------------------------------------------------
5924C -------------------------------------------------------------
5925 IF (degree(me).EQ.totel+1) THEN
5926C we have only exactly "dense" rows that we
5927C amalgamate at the root node
5928 IF (nbd.NE.nbed) THEN
5929 write(6,*) ' Internal ERROR quasi dense rows remains'
5930 CALL mumps_abort()
5931 ENDIF
5932C 1/ Go through all
5933C non absorbed elements (root of the subgraph)
5934C and absorb in ME
5935C 2/ perform mass elimination of all dense rows
5936C RMK: we could compute sum(NVPIV(d)) to check if = NBD
5937 nelme = -(nel+1)
5938 DO 59 x=1,n
5939 IF ((pe(x).GT.0_8) .AND. (elen(x).LT.0)) THEN
5940C X is an unabsorbed element
5941 pe(x) = int(-me,8)
5942C W(X) = 0 could be suppressed ?? check it
5943 ELSEIF (degree(x).EQ.totel+1) THEN
5944C X is a dense row, absorb it in ME (mass elimination)
5945 nel = nel + nv(x)
5946 pe(x) = int(-me,8)
5947 elen(x) = 0
5948 nv(x) = 0
5949 ENDIF
5950 59 CONTINUE
5951C ME is the root node
5952 elen(me) = nelme
5953 nv(me) = nbd
5954 pe(me) = 0_8
5955 IF (nel.NE.totel) THEN
5956 write(6,*) 'Internal ERROR 2 detected in QAMD'
5957 write(6,*) ' NEL not equal to N: N, NEL =',n,nel
5958 CALL mumps_abort()
5959 ENDIF
5960 GOTO 265
5961 ENDIF
5962 ENDIF
5963C -------------------------------------------------------------
5964C me represents the elimination of pivots nel+1 to nel+nv(me).
5965C place me itself as the first in this set. It will be moved
5966C to the nel+nv(me) position when the permutation vectors are
5967C computed.
5968C -------------------------------------------------------------
5969 elenme = elen(me)
5970 elen(me) = - (nel + 1)
5971 nvpiv = nv(me)
5972 nel = nel + nvpiv
5973 ndense(me) = 0
5974C=======================================================================
5975C CONSTRUCT NEW ELEMENT
5976C=======================================================================
5977C -------------------------------------------------------------
5978C At this point, me is the pivotal supervariable. It will be
5979C converted into the current element. Scan list of the
5980C pivotal supervariable, me, setting tree pointers and
5981C constructing new list of supervariables for the new element,
5982C me. p is a pointer to the current position in the old list.
5983C -------------------------------------------------------------
5984C flag the variable "me" as being in Lme by negating nv (me)
5985 nv(me) = -nvpiv
5986 degme = 0
5987 IF (elenme .EQ. 0) THEN
5988C ----------------------------------------------------------
5989C construct the new element in place
5990C ----------------------------------------------------------
5991 pme1 = pe(me)
5992 pme2 = pme1 - 1
5993 DO 60 p = pme1, pme1 + int(len(me) - 1,8)
5994 i = iw(p)
5995 nvi = nv(i)
5996 IF (nvi .GT. 0) THEN
5997C ----------------------------------------------------
5998C i is a principal variable not yet placed in Lme.
5999C store i in new list
6000C ----------------------------------------------------
6001 degme = degme + nvi
6002C flag i as being in Lme by negating nv (i)
6003 nv(i) = -nvi
6004 pme2 = pme2 + 1_8
6005 iw(pme2) = i
6006C ----------------------------------------------------
6007C remove variable i from degree list.
6008C ----------------------------------------------------
6009C only done for non "dense" rows
6010 IF (degree(i).LE.totel) THEN
6011 ilast = last(i)
6012 inext = next(i)
6013 IF (inext .NE. 0) last(inext) = ilast
6014 IF (ilast .NE. 0) THEN
6015 next(ilast) = inext
6016 ELSE
6017C i is at the head of the degree list
6018 head(degree(i)) = inext
6019 ENDIF
6020 ELSE
6021 ndense(me) = ndense(me) + nvi
6022 ENDIF
6023 ENDIF
6024 60 CONTINUE
6025C this element takes no new memory in iw:
6026 newmem = 0
6027 ELSE
6028C ----------------------------------------------------------
6029C construct the new element in empty space, iw (pfree ...)
6030C ----------------------------------------------------------
6031 p = pe(me)
6032 pme1 = pfree
6033 slenme = len(me) - elenme
6034 knt1_updated = 0
6035 DO 120 knt1 = 1, elenme + 1
6036 knt1_updated = knt1_updated +1
6037 IF (knt1 .GT. elenme) THEN
6038C search the supervariables in me.
6039 e = me
6040 pj = p
6041 ln = slenme
6042 ELSE
6043C search the elements in me.
6044 e = iw(p)
6045 p = p + 1
6046 pj = pe(e)
6047 ln = len(e)
6048 ENDIF
6049C -------------------------------------------------------
6050C search for different supervariables and add them to the
6051C new list, compressing when necessary. this loop is
6052C executed once for each element in the list and once for
6053C all the supervariables in the list.
6054C -------------------------------------------------------
6055 knt2_updated = 0
6056 DO 110 knt2 = 1, ln
6057 knt2_updated = knt2_updated+1
6058 i = iw(pj)
6059 pj = pj + 1
6060 nvi = nv(i)
6061 IF (nvi .GT. 0) THEN
6062C -------------------------------------------------
6063C compress iw, if necessary
6064C -------------------------------------------------
6065 IF (pfree .GT. iwlen) THEN
6066C prepare for compressing iw by adjusting
6067C pointers and lengths so that the lists being
6068C searched in the inner and outer loops contain
6069C only the remaining entries.
6070 pe(me) = p
6071 len(me) = len(me) - knt1_updated
6072C Reset KNT1_UPDATED in case of recompress
6073C at same iteration of the loop 120
6074 knt1_updated = 0
6075C Check if anything left in supervariable ME
6076 IF (len(me) .EQ. 0) pe(me) = 0_8
6077 pe(e) = pj
6078 len(e) = ln - knt2_updated
6079C Reset KNT2_UPDATED in case of recompress
6080C at same iteration of the loop 110
6081 knt2_updated = 0
6082C Check if anything left in element E
6083 IF (len(e) .EQ. 0) pe(e) = 0_8
6084 ncmpa = ncmpa + 1
6085C store first item in pe
6086C set first entry to -item
6087 DO 70 j = 1, n
6088 pn = pe(j)
6089 IF (pn .GT. 0) THEN
6090 pe(j) = int(iw(pn),8)
6091 iw(pn) = -j
6092 ENDIF
6093 70 CONTINUE
6094C psrc/pdst point to source/destination
6095 pdst = 1
6096 psrc = 1
6097 pend = pme1 - 1
6098C while loop:
6099 80 CONTINUE
6100 IF (psrc .LE. pend) THEN
6101C search for next negative entry
6102 j = -iw(psrc)
6103 psrc = psrc + 1
6104 IF (j .GT. 0) THEN
6105 iw(pdst) = int(pe(j))
6106 pe(j) = pdst
6107 pdst = pdst + 1_8
6108C copy from source to destination
6109 lenj = len(j)
6110 DO 90 knt3 = 0, lenj - 2
6111 iw(pdst + knt3) = iw(psrc + knt3)
6112 90 CONTINUE
6113 pdst = pdst + lenj - 1
6114 psrc = psrc + lenj - 1
6115 ENDIF
6116 GO TO 80
6117 ENDIF
6118C move the new partially-constructed element
6119 p1 = pdst
6120 DO 100 psrc = pme1, pfree - 1
6121 iw(pdst) = iw(psrc)
6122 pdst = pdst + 1
6123 100 CONTINUE
6124 pme1 = p1
6125 pfree = pdst
6126 pj = pe(e)
6127 p = pe(me)
6128 ENDIF
6129C -------------------------------------------------
6130C i is a principal variable not yet placed in Lme
6131C store i in new list
6132C -------------------------------------------------
6133 degme = degme + nvi
6134C flag i as being in Lme by negating nv (i)
6135 nv(i) = -nvi
6136 iw(pfree) = i
6137 pfree = pfree + 1
6138C -------------------------------------------------
6139C remove variable i from degree link list
6140C -------------------------------------------------
6141C only done for non "dense" rows
6142 IF (degree(i).LE.totel) THEN
6143 ilast = last(i)
6144 inext = next(i)
6145 IF (inext .NE. 0) last(inext) = ilast
6146 IF (ilast .NE. 0) THEN
6147 next(ilast) = inext
6148 ELSE
6149C i is at the head of the degree list
6150 head(degree(i)) = inext
6151 ENDIF
6152 ELSE
6153 ndense(me) = ndense(me) + nvi
6154 ENDIF
6155 ENDIF
6156 110 CONTINUE
6157 IF (e .NE. me) THEN
6158C set tree pointer and flag to indicate element e is
6159C absorbed into new element me (the parent of e is me)
6160 pe(e) = int(-me,8)
6161 w(e) = 0
6162 ENDIF
6163 120 CONTINUE
6164 pme2 = pfree - 1_8
6165C this element takes newmem new memory in iw (possibly zero)
6166 newmem = pfree - pme1
6167 mem = mem + newmem
6168 maxmem = max(maxmem, mem)
6169 ENDIF
6170C -------------------------------------------------------------
6171C me has now been converted into an element in iw (pme1..pme2)
6172C -------------------------------------------------------------
6173C degme holds the external degree of new element
6174 degree(me) = degme
6175 pe(me) = pme1
6176 len(me) = int(pme2 - pme1 + 1_8)
6177C -------------------------------------------------------------
6178C make sure that wflg is not too large. With the current
6179C value of wflg, wflg+n must not cause integer overflow
6180C -------------------------------------------------------------
6181 IF (wflg .GT. maxint_n) THEN
6182 DO 130 x = 1, n
6183 IF (w(x) .NE. 0) w(x) = 1
6184 130 CONTINUE
6185 wflg = 2
6186 ENDIF
6187C=======================================================================
6188C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
6189C=======================================================================
6190C -------------------------------------------------------------
6191C Scan 1: compute the external degrees of previous elements
6192C with respect to the current element. That is:
6193C (w (e) - wflg) = |Le \ Lme|
6194C for each element e that appears in any supervariable in Lme.
6195C The notation Le refers to the pattern (list of
6196C supervariables) of a previous element e, where e is not yet
6197C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
6198C The notation Lme refers to the pattern of the current element
6199C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
6200C zero, then the element e will be absorbed in scan 2.
6201C -------------------------------------------------------------
6202 DO 150 pme = pme1, pme2
6203 i = iw(pme)
6204 IF (degree(i).GT.totel) GOTO 150
6205 eln = elen(i)
6206 IF (eln .GT. 0) THEN
6207C note that nv (i) has been negated to denote i in Lme:
6208 nvi = -nv(i)
6209 wnvi = wflg - nvi
6210 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
6211 e = iw(p)
6212 we = w(e)
6213 IF (we .GE. wflg) THEN
6214C unabsorbed element e has been seen in this loop
6215 we = we - nvi
6216 ELSE IF (we .NE. 0) THEN
6217C e is an unabsorbed element
6218C this is the first we have seen e in all of Scan 1
6219 we = degree(e) + wnvi - ndense(e)
6220 ENDIF
6221 w(e) = we
6222 140 CONTINUE
6223 ENDIF
6224 150 CONTINUE
6225C=======================================================================
6226C DEGREE UPDATE AND ELEMENT ABSORPTION
6227C=======================================================================
6228C -------------------------------------------------------------
6229C Scan 2: for each i in Lme, sum up the degree of Lme (which
6230C is degme), plus the sum of the external degrees of each Le
6231C for the elements e appearing within i, plus the
6232C supervariables in i. Place i in hash list.
6233C -------------------------------------------------------------
6234 DO 180 pme = pme1, pme2
6235 i = iw (pme)
6236 IF (degree(i).GT.totel) GOTO 180
6237 p1 = pe(i)
6238 p2 = p1 + int(elen(i) - 1,8)
6239 pn = p1
6240 hash = 0_8
6241 deg = 0
6242C ----------------------------------------------------------
6243C scan the element list associated with supervariable i
6244C ----------------------------------------------------------
6245 DO 160 p = p1, p2
6246 e = iw (p)
6247C dext = | Le \ Lme |
6248 dext = w(e) - wflg
6249 IF (dext .GT. 0) THEN
6250 deg = deg + dext
6251 iw(pn) = e
6252 pn = pn + 1
6253 hash = hash + int(e,kind=8)
6254#if defined (NOAGG5)
6255C ------------------------------
6256C suppress aggressive absorption
6257C ------------------------------
6258 ELSE IF (dext .EQ. 0) THEN
6259 iw(pn) = e
6260 pn = pn + 1
6261 hash = hash + int(e,kind=8)
6262#else
6263C
6264C ------------------------------
6265C try aggressive absorption
6266C when possible
6267C
6268 ELSE IF ((dext .EQ. 0) .AND.
6269 & (ndense(me).EQ.nbd)) THEN
6270C aggressive absorption: e is not adjacent to me, but
6271C |Le(G') \ Lme(G')| is 0 and all dense rows
6272C are in me, so absorb it into me
6273 pe(e) = int(-me,8)
6274 w(e) = 0
6275 ELSE IF (dext.EQ.0) THEN
6276 iw(pn) = e
6277 pn = pn+1
6278 hash = hash + int(e,kind=8)
6279#endif
6280 ENDIF
6281 160 CONTINUE
6282C count the number of elements in i (including me):
6283 elen(i) = int(pn - p1 + 1)
6284C ----------------------------------------------------------
6285C scan the supervariables in the list associated with i
6286C ----------------------------------------------------------
6287 p3 = pn
6288 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
6289 j = iw(p)
6290 nvj = nv(j)
6291 IF (nvj .GT. 0) THEN
6292C j is unabsorbed, and not in Lme.
6293C add to degree and add to new list
6294C add degree only of non-dense rows.
6295 IF (degree(j).LE.totel) deg=deg+nvj
6296 iw(pn) = j
6297 pn = pn + 1
6298 hash = hash + int(j,kind=8)
6299 ENDIF
6300 170 CONTINUE
6301C ----------------------------------------------------------
6302C update the degree and check for mass elimination
6303C ----------------------------------------------------------
6304#if defined (NOAGG5)
6305 IF (deg.EQ.0.AND.(ndense(me).EQ.nbd).AND.(elen(i).GT.1)) THEN
6306C When mass elimination will be performed then
6307C absorb in ME all element adjacent to I
6308 p1 = pe(i)
6309C exclude ME --> -2
6310 p2 = p1 + int(elen(i),8) - 2_8
6311 DO p =p1,p2
6312 e = iw(p)
6313 pe(e) = int(-me,8)
6314 w(e) = 0
6315 ENDDO
6316 ENDIF
6317C .... Ready for mass elimination
6318#endif
6319 IF ((deg .EQ. 0).AND.(ndense(me).EQ.nbd)) THEN
6320C -------------------------------------------------------
6321C mass elimination
6322C -------------------------------------------------------
6323C There is nothing left of this node except for an
6324C edge to the current pivot element. elen (i) is 1,
6325C and there are no variables adjacent to node i.
6326C Absorb i into the current pivot element, me.
6327 pe(i) = int(-me,8)
6328 nvi = -nv(i)
6329 degme = degme - nvi
6330 nvpiv = nvpiv + nvi
6331 nel = nel + nvi
6332 nv(i) = 0
6333 elen(i) = 0
6334 ELSE
6335C -------------------------------------------------------
6336C update the upper-bound degree of i
6337C -------------------------------------------------------
6338C the following degree does not yet include the size
6339C of the current element, which is added later:
6340 degree(i) = min(deg+nbd-ndense(me),
6341 & degree(i))
6342C -------------------------------------------------------
6343C add me to the list for i
6344C -------------------------------------------------------
6345C move first supervariable to end of list
6346 iw(pn) = iw(p3)
6347C move first element to end of element part of list
6348 iw(p3) = iw(p1)
6349C add new element to front of list.
6350 iw(p1) = me
6351C store the new length of the list in len (i)
6352 len(i) = int(pn - p1 + 1)
6353C -------------------------------------------------------
6354C place in hash bucket. Save hash key of i in last (i).
6355C -------------------------------------------------------
6356 hash = mod(hash, hmod) + 1_8
6357 j = head(hash)
6358 IF (j .LE. 0) THEN
6359C the degree list is empty, hash head is -j
6360 next(i) = -j
6361 head(hash) = -i
6362 ELSE
6363C degree list is not empty
6364C use last (head (hash)) as hash head
6365 next(i) = last(j)
6366 last(j) = i
6367 ENDIF
6368 last(i) = int(hash,kind=kind(last))
6369 ENDIF
6370 180 CONTINUE
6371 degree(me) = degme
6372C -------------------------------------------------------------
6373C Clear the counter array, w (...), by incrementing wflg.
6374C -------------------------------------------------------------
6375 dmax = max(dmax, degme)
6376 wflg = wflg + dmax
6377C make sure that wflg+n does not cause integer overflow
6378 IF (wflg .GT. maxint_n) THEN
6379 DO 190 x = 1, n
6380 IF (w(x) .NE. 0) w(x) = 1
6381 190 CONTINUE
6382 wflg = 2
6383 ENDIF
6384C at this point, w (1..n) .lt. wflg holds
6385C=======================================================================
6386C SUPERVARIABLE DETECTION
6387C=======================================================================
6388 DO 250 pme = pme1, pme2
6389 i = iw(pme)
6390 IF ( (nv(i).LT.0) .AND. (degree(i).LE.totel) ) THEN
6391C only done for nondense rows
6392C i is a principal variable in Lme
6393C -------------------------------------------------------
6394C examine all hash buckets with 2 or more variables. We
6395C do this by examing all unique hash keys for super-
6396C variables in the pattern Lme of the current element, me
6397C -------------------------------------------------------
6398 hash = int(last(i),kind=8)
6399C let i = head of hash bucket, and empty the hash bucket
6400 j = head(hash)
6401 IF (j .EQ. 0) GO TO 250
6402 IF (j .LT. 0) THEN
6403C degree list is empty
6404 i = -j
6405 head(hash) = 0
6406 ELSE
6407C degree list is not empty, restore last () of head
6408 i = last (j)
6409 last(j) = 0
6410 ENDIF
6411 IF (i .EQ. 0) GO TO 250
6412C while loop:
6413 200 CONTINUE
6414 IF (next(i) .NE. 0) THEN
6415C ----------------------------------------------------
6416C this bucket has one or more variables following i.
6417C scan all of them to see if i can absorb any entries
6418C that follow i in hash bucket. Scatter i into w.
6419C ----------------------------------------------------
6420 ln = len(i)
6421 eln = elen(i)
6422C do not flag the first element in the list (me)
6423 DO 210 p = pe(i) + 1, pe(i) + int(ln - 1,8)
6424 w(iw(p)) = wflg
6425 210 CONTINUE
6426C ----------------------------------------------------
6427C scan every other entry j following i in bucket
6428C ----------------------------------------------------
6429 jlast = i
6430 j = next(i)
6431C while loop:
6432 220 CONTINUE
6433 IF (j .NE. 0) THEN
6434C -------------------------------------------------
6435C check if j and i have identical nonzero pattern
6436C -------------------------------------------------
6437C jump if i and j do not have same size data structure
6438 IF (len(j) .NE. ln) GO TO 240
6439C jump if i and j do not have same number adj elts
6440 IF (elen(j) .NE. eln) GO TO 240
6441C do not flag the first element in the list (me)
6442 DO 230 p = pe(j) + 1, pe(j) + int(ln - 1,8)
6443C jump if an entry (iw(p)) is in j but not in i
6444 IF (w(iw(p)) .NE. wflg) GO TO 240
6445 230 CONTINUE
6446C -------------------------------------------------
6447C found it! j can be absorbed into i
6448C -------------------------------------------------
6449 pe(j) = int(-i,8)
6450C both nv (i) and nv (j) are negated since they
6451C are in Lme, and the absolute values of each
6452C are the number of variables in i and j:
6453 nv(i) = nv(i) + nv(j)
6454 nv(j) = 0
6455 elen(j) = 0
6456C delete j from hash bucket
6457 j = next(j)
6458 next(jlast) = j
6459 GO TO 220
6460C -------------------------------------------------
6461 240 CONTINUE
6462C j cannot be absorbed into i
6463C -------------------------------------------------
6464 jlast = j
6465 j = next(j)
6466 GO TO 220
6467 ENDIF
6468C ----------------------------------------------------
6469C no more variables can be absorbed into i
6470C go to next i in bucket and clear flag array
6471C ----------------------------------------------------
6472 wflg = wflg + 1
6473 i = next(i)
6474 IF (i .NE. 0) GO TO 200
6475 ENDIF
6476 ENDIF
6477 250 CONTINUE
6478C=======================================================================
6479C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
6480C=======================================================================
6481 p = pme1
6482 nleft = totel - nel
6483 DO 260 pme = pme1, pme2
6484 i = iw(pme)
6485 nvi = -nv(i)
6486 IF (nvi .GT. 0) THEN
6487C i is a principal variable in Lme
6488C restore nv (i) to signify that i is principal
6489 nv(i) = nvi
6490 IF (degree(i).LE.totel) THEN
6491C -------------------------------------------------------
6492C compute the external degree (add size of current elem)
6493C -------------------------------------------------------
6494 deg = min(degree(i)+ degme - nvi, nleft - nvi)
6495 degree(i) = deg
6496 idense = .false.
6497C
6498 IF ( (iversion .NE. 1).AND. (thresm.GE.0)) THEN
6499C -------------------
6500C Dense row detection
6501C -------------------
6502C DEGME is exact external degree of pivot ME |Le\Ve|,
6503C DEG is is approx external degree of I
6504C Relaxed dense row selection based on:
6505C 1/ We want to avoid selecting dense rows that are
6506C almost completely represented by adj(ME)
6507C 1/ its density in reduced matrix and
6508 IF (deg+nvi .GE. thresm) THEN
6509 IF (thresm.EQ.totel) THEN
6510C We must be sure that I is exactly dense in reduced matrix
6511 IF ((elen(i).LE.2) .AND. ((deg+nvi).EQ.nleft) ) THEN
6512C DEG approximation is exact and I is dense
6513 degree(i) = totel+1
6514 idense = .true.
6515 ENDIF
6516 ELSE
6517C relaxed dense row detection
6518 idense = .true.
6519 IF ((elen(i).LE.2).AND.((deg+nvi).EQ.nleft) ) THEN
6520 degree(i) = totel+1
6521 ELSE
6522 degree(i) = totel+1+degree(i)
6523 ENDIF
6524 ENDIF
6525 ENDIF
6526 IF (idense) THEN
6527C update NDENSE of all elements in the list of element
6528C adjacent to I (including ME).
6529 p1 = pe(i)
6530 p2 = p1 + int(elen(i) - 1,8)
6531 IF (p2.GE.p1) THEN
6532 DO 264 pj=p1,p2
6533 e= iw(pj)
6534 ndense (e) = ndense(e) + nvi
6535 264 CONTINUE
6536 ENDIF
6537C insert I in the list of dense rows
6538 nbd = nbd+nvi
6539 deg = totel
6540 IF (degree(i).EQ.totel+1) THEN
6541c insert I at the end of the list
6542 nbed = nbed +nvi
6543 IF (lastd.EQ.0) THEN
6544C degree list is empty
6545 lastd = i
6546 head(deg) = i
6547 next(i) = 0
6548 last(i) = 0
6549 ELSE
6550 next(lastd) = i
6551 last(i) = lastd
6552 lastd = i
6553 next(i) = 0
6554 ENDIF
6555 ELSE
6556C insert I at the beginning of the list
6557 inext = head(deg)
6558 IF (inext .NE. 0) last(inext) = i
6559 next(i) = inext
6560 head (deg) = i
6561 last(i) = 0
6562 IF (lastd.EQ.0) lastd=i
6563 ENDIF
6564C end of IDENSE=true
6565 ENDIF
6566C end of THRESM>0
6567 ENDIF
6568C
6569 IF (.NOT.idense) THEN
6570C -------------------------------------------------------
6571C place the supervariable at the head of the degree list
6572C -------------------------------------------------------
6573 inext = head(deg)
6574 IF (inext .NE. 0) last(inext) = i
6575 next(i) = inext
6576 last(i) = 0
6577 head(deg) = i
6578 ENDIF
6579C -------------------------------------------------------
6580C save the new degree, and find the minimum degree
6581C -------------------------------------------------------
6582 mindeg = min(mindeg, deg)
6583 ENDIF
6584C -------------------------------------------------------
6585C place the supervariable in the element pattern
6586C -------------------------------------------------------
6587 iw(p) = i
6588 p = p + 1
6589 ENDIF
6590 260 CONTINUE
6591C=======================================================================
6592C FINALIZE THE NEW ELEMENT
6593C=======================================================================
6594 nv(me) = nvpiv + degme
6595C nv (me) is now the degree of pivot (including diagonal part)
6596C save the length of the list for the new element me
6597 len(me) = int(p - pme1)
6598 IF (len(me) .EQ. 0) THEN
6599C there is nothing left of the current pivot element
6600 pe(me) = 0_8
6601 w(me) = 0
6602 ENDIF
6603 IF (newmem .NE. 0) THEN
6604C element was not constructed in place: deallocate part
6605C of it (final size is less than or equal to newmem,
6606C since newly nonprincipal variables have been removed).
6607 pfree = p
6608 mem = mem - newmem + int(len(me),8)
6609 ENDIF
6610C=======================================================================
6611C END WHILE (selecting pivots)
6612 GO TO 30
6613 ENDIF
6614C=======================================================================
6615 265 CONTINUE
6616C=======================================================================
6617C COMPUTE THE PERMUTATION VECTORS and update TREE
6618C=======================================================================
6619C ----------------------------------------------------------------
6620C The time taken by the following code is O(n). At this
6621C point, elen (e) = -k has been done for all elements e,
6622C and elen (i) = 0 has been done for all nonprincipal
6623C variables i. At this point, there are no principal
6624C supervariables left, and all elements are absorbed.
6625C ----------------------------------------------------------------
6626C ----------------------------------------------------------------
6627C compute the ordering of unordered nonprincipal variables
6628C ----------------------------------------------------------------
6629 DO 290 i = 1, n
6630 IF (elen(i) .EQ. 0) THEN
6631C ----------------------------------------------------------
6632C i is an un-ordered row. Traverse the tree from i until
6633C reaching an element, e. The element, e, was the
6634C principal supervariable of i and all nodes in the path
6635C from i to when e was selected as pivot.
6636C ----------------------------------------------------------
6637 j = int(-pe(i))
6638C while (j is a variable) do:
6639 270 CONTINUE
6640 IF (elen(j) .GE. 0) THEN
6641 j = int(-pe(j))
6642 GO TO 270
6643 ENDIF
6644 e = j
6645C ----------------------------------------------------------
6646C get the current pivot ordering of e
6647C ----------------------------------------------------------
6648 k = -elen(e)
6649C ----------------------------------------------------------
6650C traverse the path again from i to e, and compress the
6651C path (all nodes point to e). Path compression allows
6652C this code to compute in O(n) time. Order the unordered
6653C nodes in the path, and place the element e at the end.
6654C ----------------------------------------------------------
6655 j = i
6656C while (j is a variable) do:
6657 280 CONTINUE
6658 IF (elen(j) .GE. 0) THEN
6659 jnext = int(-pe(j))
6660 pe(j) = int(-e,8)
6661 IF (elen(j) .EQ. 0) THEN
6662C j is an unordered row
6663 elen(j) = k
6664 k = k + 1
6665 ENDIF
6666 j = jnext
6667 GO TO 280
6668 ENDIF
6669C leave elen (e) negative, so we know it is an element
6670 elen(e) = -k
6671 ENDIF
6672 290 CONTINUE
6673 IF (compute_perm) THEN
6674C ----------------------------------------------------------------
6675C reset the inverse permutation (elen (1..n)) to be positive,
6676C and compute the permutation (last (1..n)).
6677C ----------------------------------------------------------------
6678 IF(compress) THEN
6679 last(1:n) = 0
6680 head(1:totel-n)=0
6681 DO i = 1, n
6682 k = abs(elen(i))
6683 IF ( k <= n ) THEN
6684 last(k) = i
6685 ELSE
6686 head(k-n)=i
6687 ENDIF
6688 ENDDO
6689 i = 1
6690 DO k = 1, n
6691 IF(last(k) .NE. 0) THEN
6692 last(i) = last(k)
6693 elen(last(k)) = i
6694 i = i + 1
6695 ENDIF
6696 ENDDO
6697 DO k = n+1, totel
6698 IF (head(k-n) .NE. 0) THEN
6699 last(i)=head(k-n)
6700 elen(head(k-n)) = i
6701 i = i + 1
6702 ENDIF
6703 END DO
6704 ELSE
6705 DO 300 i = 1, n
6706 k = abs(elen(i))
6707 last(k) = i
6708 elen(i) = k
6709 300 CONTINUE
6710 ENDIF
6711C=======================================================================
6712C END OF COMPUTING PERMUTATIONS
6713C=======================================================================
6714 ENDIF
6715C=======================================================================
6716C RETURN THE MEMORY USAGE IN IW
6717C=======================================================================
6718C If maxmem is less than or equal to iwlen, then no compressions
6719C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
6720C compressions did occur, and iwlen would have had to have been
6721C greater than or equal to maxmem for no compressions to occur.
6722C Return the value of maxmem in the pfree argument.
6723 pfree = maxmem
6724C===============================
6725C Save PE in PARENT array
6726 DO i=1,n
6727 parent(i) = int(pe(i))
6728 ENDDO
6729C===============================
6730 RETURN
6731 END SUBROUTINE mumps_qamd
6732C-----------------------------------------------------------------------
6733C MUMPS_CST_AMF: modified version of MUMPS_HAMF4 routine
6734C implementing constraint minimum fill-in based
6735C ordering.
6736C Written by Stephane Pralet iduring his post-doctorate at INPT-IRIT
6737C (Oct. 2004- Oct. 2005)
6738C
6739C Restrictive integer 64 bit variant :
6740C it is assumed that IW array size can exceed 32-bit integer
6741C
6742 SUBROUTINE mumps_cst_amf (N, NBBUCK,
6743 & IWLEN, PE, PFREE, LEN, IW, NV, ELEN,
6744 & LAST, NCMPA, DEGREE, WF, NEXT, W, HEAD,
6745 & CONSTRAINT,THESON, PARENT)
6746 IMPLICIT NONE
6747C
6748C Parameters
6749C Input not modified
6750 INTEGER, INTENT(IN) :: N, NBBUCK
6751 INTEGER(8), INTENT(IN) :: IWLEN
6752C Input undefined on output
6753 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
6754C NV meaningful as input to encode compressed graphs
6755 INTEGER, INTENT(INOUT) :: NV(N)
6756C
6757C Output only
6758 INTEGER, INTENT(OUT) :: NCMPA
6759 INTEGER, INTENT(OUT) :: ELEN(N), LAST(N), PARENT(N)
6760C
6761C Input/output
6762 INTEGER(8), INTENT(INOUT) :: PFREE
6763 INTEGER(8), INTENT(INOUT) :: PE(N)
6764C
6765C Internal Workspace only
6766C Min fill approximation one extra array of size NBBUCK+2
6767C is also needed
6768 INTEGER :: NEXT(N), DEGREE(N), W(N)
6769 INTEGER :: HEAD(0:NBBUCK+1), WF(N)
6770C
6771C Comments on the OUTPUT:
6772C ----------------------
6773C Let V= V0 U V1 the nodes of the initial graph (|V|=n).
6774C The assembly tree corresponds to the tree
6775C of the supernodes (or supervariables). Each node of the
6776C assembly tree is then composed of one principal variable
6777C and a list of secondary variables. The list of
6778C variable of a node (principal + secondary variables) then
6779C describes the structure of the diagonal bloc of the
6780C supernode.
6781C The elimination tree denotes the tree of all the variables(=node) and
6782C is therefore of order n.
6783C
6784C The arrays NV(N) and PE(N) give a description of the
6785C assembly tree.
6786C
6787C 1/ Description of array nv(N) (on OUPUT)
6788C nv(i)=0 i is a secondary variable
6789C N+1> nv(i) >0 i is a principal variable, nv(i) holds the
6790C the number of elements in column i of L (true degree of i)
6791C
6792C 2/ Description of array PE(N) (on OUPUT)
6793C pe(i) = -(father of variable/node i) in the elimination tree:
6794C If nv (i) .gt. 0, then i represents a node in the assembly tree,
6795C and the parent of i is -pe (i), or zero if i is a root.
6796C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
6797C subtree, the root of which is a node in the assembly tree.
6798C
6799C 3/ Example:
6800C Let If be a root node father of Is in the assembly tree.
6801C If is the principal
6802C variable of the node If and let If1, If2, If3 be the secondary variables
6803C of node If.
6804C Is is the principal
6805C variable of the node Is and let Is1, Is2 be the secondary variables
6806C of node Is.
6807C
6808C THEN:
6809C NV(If1)=NV(If2)=NV(If3) = 0 (secondary variables)
6810C NV(Is1)=NV(Is2) = 0 (secondary variables)
6811C NV(If) > 0 ( principal variable)
6812C NV(Is) > 0 ( principal variable)
6813C PE(If) = 0 (root node)
6814C PE(Is) = -If (If is the father of Is in the assembly tree)
6815C PE(If1)=PE(If2)=PE(If3)= -If ( If is the principal variable)
6816C PE(Is1)=PE(Is2)= -Is ( Is is the principal variable)
6817C
6818C
6819C
6820C HALOAMD_V1: (September 1997)
6821C **********
6822C Initial version designed to experiment the numerical (fill-in) impact
6823C of taking into account the halo. This code should be able
6824C to experiment no-halo, partial halo, complete halo.
6825C DATE: September 17th 1997
6826C
6827C HALOAMD is designed to process a gragh composed of two types
6828C of nodes, V0 and V1, extracted from a larger gragh.
6829C V0^V1 = {},
6830C
6831C We used Min. degree heuristic to order only
6832C nodes in V0, but the adjacency to nodes
6833C in V1 is taken into account during ordering.
6834C Nodes in V1 are odered at last.
6835C Adjacency between nodes of V1 need not be provided,
6836C however |len(i)| must always corresponds to the number of
6837C edges effectively provided in the adjacency list of i.
6838C On input :
6839c ********
6840C Nodes INODE in V1 are flagged with len(INODE) = -degree
6841C modif version HALO V3 (August 1998):
6842C if len(i) =0 and i \in V1 then
6843C len(i) must be set on input to -N-1
6844C ERROR return (negative values in ncmpa)
6845C ************
6846C negative value in ncmpa indicates an error detected
6847C by HALOAMD.
6848C
6849C The graph provided MUST follow the rule:
6850C if (i,j) is an edge in the gragh then
6851C j must be in the adjacency list of i AND
6852C i must be in the adjacency list of j.
6853C REMARKS
6854C -------
6855C
6856C 1/ Providing edges between nodes of V1 should not
6857C affect the final ordering, only the amount of edges
6858C of the halo should effectively affect the solution.
6859C This code should work in the following cases:
6860C 1/ halo not provided
6861C 2/ halo partially provided
6862C 3/ complete halo
6863C 4/ complete halo+interconnection between nodes of V1.
6864C
6865C 1/ should run and provide identical results (w.r.t to current
6866C implementation of AMD in SCOTCH).
6867C 3/ and 4 should provide identical results.
6868C
6869C 2/ All modifications of the AMD initial code are indicated
6870C with begin HALO .. end HALO
6871C
6872C
6873C Ordering of nodes in V0 is based on approximate minimum
6874C fill-in heuristic.
6875C
6876C-----------------------------------------------------------------------
6877C begin CONSTRAINT
6878C CONSTRAINT(I) >= 0 : I can be selected
6879C < 0 : I cannot be selected
6880C > 0 : I release CONSTRAINT(I)
6881C THESON(I) = 0 : I is a leaf in the supervariable representation
6882C THESON(I) > I : THESON(I) belongs to the same supervariable as I
6883C Parameters:
6884 INTEGER, INTENT(INOUT) :: CONSTRAINT(N)
6885 INTEGER, INTENT(out) :: THESON(N)
6886 INTEGER PREV,TOTO
6887C end CONSTRAINT
6888C-----------------------------------------------------------------------
6889C INPUT ARGUMENTS (unaltered):
6890C-----------------------------------------------------------------------
6891C n: The matrix order.
6892C
6893C Restriction: n .ge. 1
6894C iwlen: The length of iw (1..iwlen). On input, the matrix is
6895C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
6896C slightly larger than what is required to hold the matrix, at
6897C least iwlen .ge. pfree + n is recommended. Otherwise,
6898C excessive compressions will take place.
6899C *** We do not recommend running this algorithm with ***
6900C *** iwlen .lt. pfree + n. ***
6901C *** Better performance will be obtained if ***
6902C *** iwlen .ge. pfree + n ***
6903C *** or better yet ***
6904C *** iwlen .gt. 1.2 * pfree ***
6905C *** (where pfree is its value on input). ***
6906C The algorithm will not run at all if iwlen .lt. pfree-1.
6907C
6908C Restriction: iwlen .ge. pfree-1
6909C-----------------------------------------------------------------------
6910C INPUT/OUPUT ARGUMENTS:
6911C-----------------------------------------------------------------------
6912C pe: On input, pe (i) is the index in iw of the start of row i, or
6913C zero if row i has no off-diagonal non-zeros.
6914C
6915C During execution, it is used for both supervariables and
6916C elements:
6917C
6918C * Principal supervariable i: index into iw of the
6919C description of supervariable i. A supervariable
6920C represents one or more rows of the matrix
6921C with identical nonzero pattern.
6922C * Non-principal supervariable i: if i has been absorbed
6923C into another supervariable j, then pe (i) = -j.
6924C That is, j has the same pattern as i.
6925C Note that j might later be absorbed into another
6926C supervariable j2, in which case pe (i) is still -j,
6927C and pe (j) = -j2.
6928C * Unabsorbed element e: the index into iw of the description
6929C of element e, if e has not yet been absorbed by a
6930C subsequent element. Element e is created when
6931C the supervariable of the same name is selected as
6932C the pivot.
6933C * Absorbed element e: if element e is absorbed into element
6934C e2, then pe (e) = -e2. This occurs when the pattern of
6935C e (that is, Le) is found to be a subset of the pattern
6936C of e2 (that is, Le2). If element e is "null" (it has
6937C no nonzeros outside its pivot block), then pe (e) = 0.
6938C
6939C On output, pe holds the assembly tree/forest, which implicitly
6940C represents a pivot order with identical fill-in as the actual
6941C order (via a depth-first search of the tree).
6942C
6943C On output:
6944C If nv (i) .gt. 0, then i represents a node in the assembly tree,
6945C and the parent of i is -pe (i), or zero if i is a root.
6946C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
6947C subtree, the root of which is a node in the assembly tree.
6948C On output: (PE is copied on output into PARENT array)
6949C
6950C pfree: On input, the matrix is stored in iw (1..pfree-1) and
6951C the rest of the array iw is free.
6952C During execution, additional data is placed in iw, and pfree
6953C is modified so that components of iw from pfree are free.
6954C On output, pfree is set equal to the size of iw that
6955C would have been needed for no compressions to occur. If
6956C ncmpa is zero, then pfree (on output) is less than or equal to
6957C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
6958C Otherwise, pfree (on output) is greater than iwlen, and all the
6959C memory in iw was used.
6960C
6961C nv: On input, encoding of compressed graph:
6962C if NV(1) = -1 then graph is not compressed otherwise
6963C NV(I) holds the weight of node I.
6964C During execution, abs (nv (i)) is equal to the number of rows
6965C that are represented by the principal supervariable i. If i is
6966C a nonprincipal variable, then nv (i) = 0. Initially,
6967C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
6968C principal variable in the pattern Lme of the current pivot
6969C element me. On output, nv (e) holds the true degree of element
6970C e at the time it was created (including the diagonal part).
6971C begin HALO
6972C On output, nv(I) can be used to find node in set V1.
6973C Not true anymore : ( nv(I) = N+1 characterizes nodes in V1.
6974C instead nodes in V1 are considered as a dense root node )
6975C end HALO
6976C-----------------------------------------------------------------------
6977C INPUT/MODIFIED (undefined on output):
6978C-----------------------------------------------------------------------
6979C len: On input, len (i)
6980C positive or null (>=0) : i \in V0 and
6981C len(i) holds the number of entries in row i of the
6982C matrix, excluding the diagonal.
6983C negative (<0) : i \in V1, and
6984C -len(i) hold the number of entries in row i of the
6985C matrix, excluding the diagonal.
6986C len(i) = - | Adj(i) | if i \in V1
6987C or -N -1 if | Adj(i) | = 0 and i \in V1
6988C The contents of len (1..n)
6989C are undefined on output.
6990C iw: On input, iw (1..pfree-1) holds the description of each row i
6991C in the matrix. The matrix must be symmetric, and both upper
6992C and lower triangular parts must be present. The diagonal must
6993C not be present. Row i is held as follows:
6994C
6995C len (i): the length of the row i data structure
6996C iw (pe (i) ... pe (i) + len (i) - 1):
6997C the list of column indices for nonzeros
6998C in row i (simple supervariables), excluding
6999C the diagonal. All supervariables start with
7000C one row/column each (supervariable i is just
7001C row i).
7002C if len (i) is zero on input, then pe (i) is ignored
7003C on input.
7004C
7005C Note that the rows need not be in any particular order,
7006C and there may be empty space between the rows.
7007C
7008C During execution, the supervariable i experiences fill-in.
7009C This is represented by placing in i a list of the elements
7010C that cause fill-in in supervariable i:
7011C
7012C len (i): the length of supervariable i
7013C iw (pe (i) ... pe (i) + elen (i) - 1):
7014C the list of elements that contain i. This list
7015C is kept short by removing absorbed elements.
7016C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
7017C the list of supervariables in i. This list
7018C is kept short by removing nonprincipal
7019C variables, and any entry j that is also
7020C contained in at least one of the elements
7021C (j in Le) in the list for i (e in row i).
7022C
7023C When supervariable i is selected as pivot, we create an
7024C element e of the same name (e=i):
7025C
7026C len (e): the length of element e
7027C iw (pe (e) ... pe (e) + len (e) - 1):
7028C the list of supervariables in element e.
7029C
7030C An element represents the fill-in that occurs when supervariable
7031C i is selected as pivot (which represents the selection of row i
7032C and all non-principal variables whose principal variable is i).
7033C We use the term Le to denote the set of all supervariables
7034C in element e. Absorbed supervariables and elements are pruned
7035C from these lists when computationally convenient.
7036C
7037C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
7038C The contents of iw are undefined on output.
7039C-----------------------------------------------------------------------
7040C OUTPUT (need not be set on input):
7041C-----------------------------------------------------------------------
7042C elen: See the description of iw above. At the start of execution,
7043C elen (i) is set to zero. During execution, elen (i) is the
7044C number of elements in the list for supervariable i. When e
7045C becomes an element, elen (e) = -nel is set, where nel is the
7046C current step of factorization. elen (i) = 0 is done when i
7047C becomes nonprincipal.
7048C
7049C For variables, elen (i) .ge. 0 holds until just before the
7050C permutation vectors are computed. For elements,
7051C elen (e) .lt. 0 holds.
7052C
7053C On output elen (1..n) holds the inverse permutation (the same
7054C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
7055C then row i is the kth pivot row. Row i of A appears as the
7056C (elen(i))-th row in the permuted matrix, PAP^T.
7057C last: In a degree list, last (i) is the supervariable preceding i,
7058C or zero if i is the head of the list. In a hash bucket,
7059C last (i) is the hash key for i. last (head (hash)) is also
7060C used as the head of a hash bucket if head (hash) contains a
7061C degree list (see head, below).
7062C
7063C On output, last (1..n) holds the permutation (the same as the
7064C 'PERM' argument in Sparspak). That is, if i = last (k), then
7065C row i is the kth pivot row. Row last (k) of A is the k-th row
7066C in the permuted matrix, PAP^T.
7067C ncmpa: The number of times iw was compressed. If this is
7068C excessive, then the execution took longer than what could have
7069C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
7070C larger than the value of pfree on input (or at least
7071C iwlen .ge. pfree + n). The fastest performance will be
7072C obtained when ncmpa is returned as zero. If iwlen is set to
7073C the value returned by pfree on *output*, then no compressions
7074C will occur.
7075C begin HALO
7076C on output ncmpa <0 --> error detected during HALO_AMD:
7077C error 1: ncmpa = -N , ordering was stopped.
7078C end HALO
7079C
7080C-----------------------------------------------------------------------
7081C LOCAL (not input or output - used only during execution):
7082C-----------------------------------------------------------------------
7083C degree: If i is a supervariable, then degree (i) holds the
7084C current approximation of the external degree of row i (an upper
7085C bound). The external degree is the number of nonzeros in row i,
7086C minus abs (nv (i)) (the diagonal part). The bound is equal to
7087C the external degree if elen (i) is less than or equal to two.
7088C We also use the term "external degree" for elements e to refer
7089C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
7090C which is the degree of the off-diagonal part of the element e
7091C (not including the diagonal part).
7092C begin HALO
7093C degree(I) = n+1 indicates that i belongs to V1
7094C end HALO
7095C
7096C head: head is used for degree lists. head (deg) is the first
7097C supervariable in a degree list (all supervariables i in a
7098C degree list deg have the same approximate degree, namely,
7099C deg = degree (i)). If the list deg is empty then
7100C head (deg) = 0.
7101C
7102C During supervariable detection head (hash) also serves as a
7103C pointer to a hash bucket.
7104C If head (hash) .gt. 0, there is a degree list of degree hash.
7105C The hash bucket head pointer is last (head (hash)).
7106C If head (hash) = 0, then the degree list and hash bucket are
7107C both empty.
7108C If head (hash) .lt. 0, then the degree list is empty, and
7109C -head (hash) is the head of the hash bucket.
7110C After supervariable detection is complete, all hash buckets
7111C are empty, and the (last (head (hash)) = 0) condition is
7112C restored for the non-empty degree lists.
7113C next: next (i) is the supervariable following i in a link list, or
7114C zero if i is the last in the list. Used for two kinds of
7115C lists: degree lists and hash buckets (a supervariable can be
7116C in only one kind of list at a time).
7117C w: The flag array w determines the status of elements and
7118C variables, and the external degree of elements.
7119C
7120C for elements:
7121C if w (e) = 0, then the element e is absorbed
7122C if w (e) .ge. wflg, then w (e) - wflg is the size of
7123C the set |Le \ Lme|, in terms of nonzeros (the
7124C sum of abs (nv (i)) for each principal variable i that
7125C is both in the pattern of element e and NOT in the
7126C pattern of the current pivot element, me).
7127C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
7128C not yet been seen in the scan of the element lists in
7129C the computation of |Le\Lme| in loop 150 below.
7130C
7131C for variables:
7132C during supervariable detection, if w (j) .ne. wflg then j is
7133C not in the pattern of variable i
7134C
7135C The w array is initialized by setting w (i) = 1 for all i,
7136C and by setting wflg = 2. It is reinitialized if wflg becomes
7137C too large (to ensure that wflg+n does not cause integer
7138C overflow).
7139C
7140C wf : integer array used to store the already filled area of
7141C the variables adajcent to current pivot.
7142C wf is then used to update the score of variable i.
7143C
7144C-----------------------------------------------------------------------
7145C LOCAL INTEGERS:
7146C-----------------------------------------------------------------------
7147 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
7148 & ILAST, INEXT, J, JLAST, JNEXT, K, KNT1, KNT2, KNT3,
7149 & LENJ, LN, ME, MINDEG, NEL,
7150 & NLEFT, NVI, NVJ, NVPIV, SLENME, WE, WFLG, WNVI, X,
7151 & NBFLAG, NREAL, LASTD, NELME, WF3, WF4, N2, PAS
7152 INTEGER KNT1_UPDATED, KNT2_UPDATED
7153 INTEGER(8) :: MAXMEM, MEM, NEWMEM
7154 INTEGER :: MAXINT_N
7155 INTEGER(8):: HASH, HMOD
7156 DOUBLE PRECISION :: RMF, RMF1
7157 DOUBLE PRECISION :: dummy
7158 INTEGER :: idummy
7159C deg: the degree of a variable or element
7160C degme: size, |Lme|, of the current element, me (= degree (me))
7161C dext: external degree, |Le \ Lme|, of some element e
7162C dmax: largest |Le| seen so far
7163C e: an element
7164C elenme: the length, elen (me), of element list of pivotal var.
7165C eln: the length, elen (...), of an element list
7166C hash: the computed value of the hash function
7167C hmod: the hash function is computed modulo hmod = max (1,n-1)
7168C i: a supervariable
7169C ilast: the entry in a link list preceding i
7170C inext: the entry in a link list following i
7171C j: a supervariable
7172C jlast: the entry in a link list preceding j
7173C jnext: the entry in a link list, or path, following j
7174C k: the pivot order of an element or variable
7175C knt1: loop counter used during element construction
7176C knt2: loop counter used during element construction
7177C knt3: loop counter used during compression
7178C lenj: len (j)
7179C ln: length of a supervariable list
7180C maxint_n: large integer to test risk of overflow on wflg
7181C maxmem: amount of memory needed for no compressions
7182C me: current supervariable being eliminated, and the
7183C current element created by eliminating that
7184C supervariable
7185C mem: memory in use assuming no compressions have occurred
7186C mindeg: current minimum degree
7187C nel: number of pivots selected so far
7188C newmem: amount of new memory needed for current pivot element
7189C nleft: n - nel, the number of nonpivotal rows/columns remaining
7190C nvi: the number of variables in a supervariable i (= nv (i))
7191C nvj: the number of variables in a supervariable j (= nv (j))
7192C nvpiv: number of pivots in current element
7193C slenme: number of variables in variable list of pivotal variable
7194C we: w (e)
7195C wflg: used for flagging the w array. See description of iw.
7196C wnvi: wflg - nv (i)
7197C x: either a supervariable or an element
7198C wf3: off diagonal block area
7199C wf4: diagonal block area
7200C mf : Minimum fill
7201C begin HALO
7202C nbflag: number of flagged entries in the initial gragh.
7203C nreal : number of entries on which ordering must be perfomed
7204C (nreel = N- nbflag)
7205C nelme number of pivots selected when reaching the root
7206C lastd index of the last row in the list of dense rows
7207C end HALO
7208C-----------------------------------------------------------------------
7209C LOCAL POINTERS:
7210C-----------------------------------------------------------------------
7211 INTEGER(8) P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
7212 & PN, PSRC
7213C Any parameter (pe (...) or pfree) or local variable
7214C starting with "p" (for Pointer) is an index into iw,
7215C and all indices into iw use variables starting with
7216C "p." The only exception to this rule is the iwlen
7217C input argument.
7218C p: pointer into lots of things
7219C p1: pe (i) for some variable i (start of element list)
7220C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
7221C p3: index of first supervariable in clean list
7222C pdst: destination pointer, for compression
7223C pend: end of memory to compress
7224C pj: pointer into an element or variable
7225C pme: pointer into the current element (pme1...pme2)
7226C pme1: the current element, me, is stored in iw (pme1...pme2)
7227C pme2: the end of the current element
7228C pn: pointer into a "clean" variable, also used to compress
7229C psrc: source pointer, for compression
7230C-----------------------------------------------------------------------
7231C FUNCTIONS CALLED:
7232C-----------------------------------------------------------------------
7233 INTRINSIC max, min, mod, huge
7234 INTEGER TOTEL
7235C=======================================================================
7236C INITIALIZATIONS
7237C=======================================================================
7238C HEAD (0:NBBUCK+1)
7239C begin HALO
7240C
7241C idummy holds the largest integer - 1
7242C dummy = dble (idummy)
7243 idummy = huge(idummy) - 1
7244 dummy = dble(idummy)
7245C variable with degree equal to N2 are in halo
7246C bucket NBBUCK+1 used for HALO variables
7247 n2 = -nbbuck-1
7248C end HALO
7249C Distance betweeen elements of the N, ..., NBBUCK entries of HEAD
7250C
7251C update done on 20 Feb 2002 (PAS>= 1)
7252 pas = max((n/8), 1)
7253 wflg = 2
7254 maxint_n=huge(wflg)-n
7255 ncmpa = 0
7256 nel = 0
7257 hmod = int(max(1, nbbuck-1),kind=8)
7258 dmax = 0
7259 mem = pfree - 1
7260 maxmem = mem
7261 mindeg = 0
7262C
7263 nbflag = 0
7264 lastd = 0
7265 head(0:nbbuck+1) = 0
7266 DO 10 i = 1, n
7267 theson(i) = 0
7268 last(i) = 0
7269C NV (I) = 1
7270 w(i) = 1
7271 elen(i) = 0
7272 10 CONTINUE
7273 totel = 0
7274 DO i=1,n
7275 IF (len(i).LT.0) THEN
7276 degree(i) = n2
7277 nbflag = nbflag +1
7278 IF (len(i).EQ.-n-1) THEN
7279C variable in V1 with empty adj list
7280 len(i) = 0
7281C Because of compress, we force skipping this
7282C entry which is anyway empty
7283 pe(i) = 0_8
7284 ELSE
7285 len(i) = - len(i)
7286 ENDIF
7287C end HALO V3
7288 ELSE
7289 totel = totel + nv(i)
7290 degree(i) = 0
7291 DO p= pe(i) , pe(i)+int(len(i)-1,8)
7292 degree(i) = degree(i) + nv(iw(p))
7293 ENDDO
7294 ENDIF
7295 ENDDO
7296C
7297C
7298C number of entries to be ordered.
7299 nreal = n - nbflag
7300C ----------------------------------------------------------------
7301C initialize degree lists and eliminate rows with no off-diag. nz.
7302C ----------------------------------------------------------------
7303 DO 20 i = 1, n
7304 deg = degree(i)
7305 IF (deg.EQ.n2) THEN
7306C DEG = N2 (flagged variables are stored
7307C in the degree list of NBBUCK + 1
7308C (safe: because max
7309C max value of degree is NBBUCK)
7310C
7311 deg = nbbuck + 1
7312 IF (lastd.EQ.0) THEN
7313C degree list is empty
7314 lastd = i
7315 head(deg) = i
7316 next(i) = 0
7317 last(i) = 0
7318 ELSE
7319 next(lastd) = i
7320 last(i) = lastd
7321 lastd = i
7322 next(i) = 0
7323 ENDIF
7324 GOTO 20
7325 ENDIF
7326C
7327C
7328 IF (deg .GT. 0) THEN
7329 wf(i) = deg
7330 IF (deg.GT.n) THEN
7331 deg = min(((deg-n)/pas) + n , nbbuck)
7332 ENDIF
7333C Note that if deg=0 then
7334C No fill-in will occur,
7335C but one variable is adjacent to I
7336C ----------------------------------------------------------
7337C place i in the degree list corresponding to its degree
7338C ----------------------------------------------------------
7339 inext = head(deg)
7340 IF (inext .NE. 0) last(inext) = i
7341 next(i) = inext
7342 head(deg) = i
7343 ELSE
7344C ----------------------------------------------------------
7345C we have a variable that can be eliminated at once because
7346C there is no off-diagonal non-zero in its row.
7347C ----------------------------------------------------------
7348 nel = nel + nv(i)
7349 elen(i) = -nel
7350 pe(i) = 0_8
7351 w(i) = 0
7352 ENDIF
7353C=======================================================================
7354C
7355 20 CONTINUE
7356C=======================================================================
7357C WHILE (selecting pivots) DO
7358C=======================================================================
7359 nleft = totel-nel
7360C=======================================================================
7361C =====================================================================
7362 30 IF (nel .LT. totel) THEN
7363C =====================================================================
7364C GET PIVOT OF MINIMUM DEGREE
7365C=======================================================================
7366C -------------------------------------------------------------
7367C find next supervariable for elimination
7368C -------------------------------------------------------------
7369 DO 40 deg = mindeg, nbbuck
7370 me = head(deg)
7371 IF (me .GT. 0) GO TO 50
7372 40 CONTINUE
7373 50 mindeg = deg
7374 IF (me.LE.0) THEN
7375 ncmpa = -n
7376 CALL mumps_abort()
7377 ENDIF
7378 IF (deg.GT.n) THEN
7379C -------------------------------
7380C Linear search to find variable
7381C with best score in the list
7382C -------------------------------
7383C While end of list list not reached
7384C NEXT(J) = 0
7385 j = next(me)
7386 k = wf(me)
7387C if ME is not available
7388 IF(constraint(me) .LT. 0) THEN
7389 k = -1
7390 ENDIF
7391 55 CONTINUE
7392 IF (j.GT.0) THEN
7393C j is available
7394 IF(constraint(j) .GE. 0) THEN
7395 IF (wf(j).LT.k .OR. k .LT. 0) THEN
7396 me = j
7397 k = wf(me)
7398 ENDIF
7399 ENDIF
7400 j= next(j)
7401 GOTO 55
7402 ENDIF
7403 ilast = last(me)
7404 inext = next(me)
7405 IF (inext .NE. 0) last(inext) = ilast
7406 IF (ilast .NE. 0) THEN
7407 next(ilast) = inext
7408 ELSE
7409C me is at the head of the degree list
7410 head(deg) = inext
7411 ENDIF
7412C
7413 ELSE
7414C select ME which verify the constraint
7415C if it is directly ok
7416 IF(constraint(me) .GE. 0) GOTO 59
7417 56 CONTINUE
7418C if ME has a successor exaine it
7419 IF(next(me) .NE. 0) THEN
7420 me = next(me)
7421 IF(constraint(me) .GE. 0) THEN
7422 GOTO 59
7423 ELSE
7424 GOTO 56
7425 ENDIF
7426 ELSE
7427C ME has no successor -> increase deg till finding a valid ME
7428C 57: increase deg till a non empty list is found
7429 57 deg = deg+1
7430 me = head(deg)
7431C no empty found
7432 IF(me .GT. 0) THEN
7433C good piv found
7434 IF(constraint(me) .GE. 0) THEN
7435 GOTO 59
7436 ELSE
7437C else loop on next
7438 GOTO 56
7439 ENDIF
7440 ELSE
7441C increase degree
7442 GOTO 57
7443 ENDIF
7444 ENDIF
7445 59 prev = last(me)
7446 inext = next(me)
7447 IF(prev .NE. 0) THEN
7448 next(prev) = inext
7449 ELSE
7450 head(deg) = inext
7451 ENDIF
7452C remove ME from the x2 linked lists
7453 IF (inext .NE. 0) last(inext) = prev
7454 ENDIF
7455C -------------------------------------------------------------
7456C remove chosen variable from link list
7457C -------------------------------------------------------------
7458 toto = me
7459 5910 IF(toto .NE. 0) THEN
7460 j = constraint(toto)
7461 IF(j .GT. 0) THEN
7462 constraint(j) = 0
7463 ENDIF
7464 toto = theson(toto)
7465 GOTO 5910
7466 ENDIF
7467C -------------------------------------------------------------
7468C me represents the elimination of pivots nel+1 to nel+nv(me).
7469C place me itself as the first in this set. It will be moved
7470C to the nel+nv(me) position when the permutation vectors are
7471C computed.
7472C -------------------------------------------------------------
7473 elenme = elen(me)
7474 elen(me) = - (nel + 1)
7475 nvpiv = nv(me)
7476 nel = nel + nvpiv
7477C=======================================================================
7478C CONSTRUCT NEW ELEMENT
7479C=======================================================================
7480C -------------------------------------------------------------
7481C At this point, me is the pivotal supervariable. It will be
7482C converted into the current element. Scan list of the
7483C pivotal supervariable, me, setting tree pointers and
7484C constructing new list of supervariables for the new element,
7485C me. p is a pointer to the current position in the old list.
7486C -------------------------------------------------------------
7487C flag the variable "me" as being in Lme by negating nv (me)
7488 nv(me) = -nvpiv
7489 degme = 0
7490 IF (elenme .EQ. 0) THEN
7491C ----------------------------------------------------------
7492C construct the new element in place
7493C ----------------------------------------------------------
7494 pme1 = pe(me)
7495 pme2 = pme1 - 1
7496 DO 60 p = pme1, pme1 + len(me) - 1
7497 i = iw(p)
7498 nvi = nv(i)
7499 IF (nvi .GT. 0) THEN
7500C ----------------------------------------------------
7501C i is a principal variable not yet placed in Lme.
7502C store i in new list
7503C ----------------------------------------------------
7504 degme = degme + nvi
7505C flag i as being in Lme by negating nv (i)
7506 nv(i) = -nvi
7507 pme2 = pme2 + 1
7508 iw(pme2) = i
7509 IF (degree(i).NE.n2) THEN
7510C ----------------------------------------------------
7511C remove variable i from degree list. (only if i \in V0)
7512C ----------------------------------------------------
7513 ilast = last(i)
7514 inext = next(i)
7515 IF (inext .NE. 0) last(inext) = ilast
7516 IF (ilast .NE. 0) THEN
7517 next(ilast) = inext
7518 ELSE
7519C i is at the head of the degree list
7520 IF (wf(i).GT.n) THEN
7521 deg = min(((wf(i)-n)/pas) + n , nbbuck)
7522 ELSE
7523 deg = wf(i)
7524 ENDIF
7525 head(deg) = inext
7526 ENDIF
7527 ENDIF
7528 ENDIF
7529 60 CONTINUE
7530C this element takes no new memory in iw:
7531 newmem = 0
7532 ELSE
7533C ----------------------------------------------------------
7534C construct the new element in empty space, iw (pfree ...)
7535C ----------------------------------------------------------
7536 p = pe(me)
7537 pme1 = pfree
7538 slenme = len(me) - elenme
7539 knt1_updated = 0
7540 DO 120 knt1 = 1, elenme + 1
7541 knt1_updated = knt1_updated +1
7542 IF (knt1 .GT. elenme) THEN
7543C search the supervariables in me.
7544 e = me
7545 pj = p
7546 ln = slenme
7547 ELSE
7548C search the elements in me.
7549 e = iw(p)
7550 p = p + 1
7551 pj = pe(e)
7552 ln = len(e)
7553 ENDIF
7554C -------------------------------------------------------
7555C search for different supervariables and add them to the
7556C new list, compressing when necessary. this loop is
7557C executed once for each element in the list and once for
7558C all the supervariables in the list.
7559C -------------------------------------------------------
7560 knt2_updated = 0
7561 DO 110 knt2 = 1, ln
7562 knt2_updated = knt2_updated+1
7563 i = iw(pj)
7564 pj = pj + 1
7565 nvi = nv(i)
7566 IF (nvi .GT. 0) THEN
7567C -------------------------------------------------
7568C compress iw, if necessary
7569C -------------------------------------------------
7570 IF (pfree .GT. iwlen) THEN
7571C prepare for compressing iw by adjusting
7572C pointers and lengths so that the lists being
7573C searched in the inner and outer loops contain
7574C only the remaining entries.
7575 pe(me) = p
7576 len(me) = len(me) - knt1_updated
7577C Reset KNT1_UPDATED in case of recompress
7578C at same iteration of the loop 120
7579 knt1_updated = 0
7580C Check if anything left in supervariable ME
7581 IF (len(me) .EQ. 0) pe(me) = 0_8
7582 pe(e) = pj
7583 len(e) = ln - knt2_updated
7584C Reset KNT2_UPDATED in case of recompress
7585C at same iteration of the loop 110
7586 knt2_updated = 0
7587C Check if anything left in element E
7588 IF (len(e) .EQ. 0) pe(e) = 0_8
7589 ncmpa = ncmpa + 1
7590C store first item in pe
7591C set first entry to -item
7592 DO 70 j = 1, n
7593 pn = pe(j)
7594 IF (pn .GT. 0) THEN
7595 pe(j) = int(iw(pn),8)
7596 iw(pn) = -j
7597 ENDIF
7598 70 CONTINUE
7599C psrc/pdst point to source/destination
7600 pdst = 1
7601 psrc = 1
7602 pend = pme1 - 1
7603C while loop:
7604 80 CONTINUE
7605 IF (psrc .LE. pend) THEN
7606C search for next negative entry
7607 j = -iw(psrc)
7608 psrc = psrc + 1
7609 IF (j .GT. 0) THEN
7610 iw(pdst) = int(pe(j))
7611 pe(j) = pdst
7612 pdst = pdst + 1_8
7613C copy from source to destination
7614 lenj = len(j)
7615 DO 90 knt3 = 0, lenj - 2
7616 iw(pdst + knt3) = iw(psrc + knt3)
7617 90 CONTINUE
7618 pdst = pdst + int(lenj - 1,8)
7619 psrc = psrc + int(lenj - 1,8)
7620 ENDIF
7621 GO TO 80
7622 ENDIF
7623C move the new partially-constructed element
7624 p1 = pdst
7625 DO 100 psrc = pme1, pfree - 1
7626 iw(pdst) = iw(psrc)
7627 pdst = pdst + 1
7628 100 CONTINUE
7629 pme1 = p1
7630 pfree = pdst
7631 pj = pe(e)
7632 p = pe(me)
7633 ENDIF
7634C -------------------------------------------------
7635C i is a principal variable not yet placed in Lme
7636C store i in new list
7637C -------------------------------------------------
7638 degme = degme + nvi
7639C flag i as being in Lme by negating nv (i)
7640 nv(i) = -nvi
7641 iw(pfree) = i
7642 pfree = pfree + 1
7643 IF (degree(i).NE.n2) THEN
7644C -------------------------------------------------
7645C remove variable i from degree link list
7646C (only if i in V0)
7647C -------------------------------------------------
7648 ilast = last(i)
7649 inext = next(i)
7650 IF (inext .NE. 0) last(inext) = ilast
7651 IF (ilast .NE. 0) THEN
7652 next(ilast) = inext
7653 ELSE
7654 IF (wf(i).GT.n) THEN
7655 deg = min(((wf(i)-n)/pas) + n , nbbuck)
7656 ELSE
7657 deg = wf(i)
7658 ENDIF
7659C i is at the head of the degree list
7660 head(deg) = inext
7661 ENDIF
7662 ENDIF
7663 ENDIF
7664 110 CONTINUE
7665 IF (e .NE. me) THEN
7666C set tree pointer and flag to indicate element e is
7667C absorbed into new element me (the parent of e is me)
7668 pe(e) = int(-me,8)
7669 w(e) = 0
7670 ENDIF
7671 120 CONTINUE
7672 pme2 = pfree - 1
7673C this element takes newmem new memory in iw (possibly zero)
7674 newmem = pfree - pme1
7675 mem = mem + newmem
7676 maxmem = max(maxmem, mem)
7677 ENDIF
7678C -------------------------------------------------------------
7679C me has now been converted into an element in iw (pme1..pme2)
7680C -------------------------------------------------------------
7681C degme holds the external degree of new element
7682 degree(me) = degme
7683 pe(me) = pme1
7684 len(me) = int(pme2 - pme1 + 1_8)
7685C -------------------------------------------------------------
7686C make sure that wflg is not too large. With the current
7687C value of wflg, wflg+n must not cause integer overflow
7688C -------------------------------------------------------------
7689 IF (wflg .GT. maxint_n) THEN
7690 DO 130 x = 1, n
7691 IF (w(x) .NE. 0) w(x) = 1
7692 130 CONTINUE
7693 wflg = 2
7694 ENDIF
7695C=======================================================================
7696C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
7697C=======================================================================
7698C -------------------------------------------------------------
7699C Scan 1: compute the external degrees of previous elements
7700C with respect to the current element. That is:
7701C (w (e) - wflg) = |Le \ Lme|
7702C for each element e that appears in any supervariable in Lme.
7703C The notation Le refers to the pattern (list of
7704C supervariables) of a previous element e, where e is not yet
7705C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
7706C The notation Lme refers to the pattern of the current element
7707C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
7708C zero, then the element e will be absorbed in scan 2.
7709C -------------------------------------------------------------
7710 DO 150 pme = pme1, pme2
7711 i = iw(pme)
7712 eln = elen(i)
7713 IF (eln .GT. 0) THEN
7714C note that nv (i) has been negated to denote i in Lme:
7715 nvi = -nv(i)
7716 wnvi = wflg - nvi
7717 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
7718 e = iw(p)
7719 we = w(e)
7720 IF (we .GE. wflg) THEN
7721C unabsorbed element e has been seen in this loop
7722 we = we - nvi
7723 ELSE IF (we .NE. 0) THEN
7724C e is an unabsorbed element
7725C this is the first we have seen e in all of Scan 1
7726 we = degree(e) + wnvi
7727 wf(e) = 0
7728 ENDIF
7729 w(e) = we
7730 140 CONTINUE
7731 ENDIF
7732 150 CONTINUE
7733C=======================================================================
7734C DEGREE UPDATE AND ELEMENT ABSORPTION
7735C=======================================================================
7736C -------------------------------------------------------------
7737C Scan 2: for each i in Lme, sum up the degree of Lme (which
7738C is degme), plus the sum of the external degrees of each Le
7739C for the elements e appearing within i, plus the
7740C supervariables in i. Place i in hash list.
7741C -------------------------------------------------------------
7742 DO 180 pme = pme1, pme2
7743 i = iw(pme)
7744 p1 = pe(i)
7745 p2 = p1 + int(elen(i) - 1,8)
7746 pn = p1
7747 hash = 0_8
7748 deg = 0
7749 wf3 = 0
7750 wf4 = 0
7751 nvi = -nv(i)
7752C ----------------------------------------------------------
7753C scan the element list associated with supervariable i
7754C ----------------------------------------------------------
7755 DO 160 p = p1, p2
7756 e = iw(p)
7757C dext = | Le \ Lme |
7758 dext = w(e) - wflg
7759 IF (dext .GT. 0) THEN
7760 IF ( wf(e) .EQ. 0 ) THEN
7761C First time we meet e : compute wf(e)
7762C which holds the surface associated to element e
7763C it will later be deducted from fill-in
7764C area of all variables adjacent to e
7765 wf(e) = dext * ( (2 * degree(e)) - dext - 1)
7766 ENDIF
7767 wf4 = wf4 + wf(e)
7768 deg = deg + dext
7769 iw(pn) = e
7770 pn = pn + 1
7771 hash = hash + int(e,kind=8)
7772 ELSE IF (dext .EQ. 0) THEN
7773#if defined (NOAGG4)
7774 iw(pn) = e
7775 pn = pn + 1
7776 hash = hash + int(e,kind=8)
7777#else
7778C aggressive absorption: e is not adjacent to me, but
7779C the |Le \ Lme| is 0, so absorb it into me
7780 pe(e) = int(-me,8)
7781 w(e) = 0
7782#endif
7783 ENDIF
7784 160 CONTINUE
7785C count the number of elements in i (including me):
7786 elen(i) = int(pn - p1 + 1_8)
7787C ----------------------------------------------------------
7788C scan the supervariables in the list associated with i
7789C ----------------------------------------------------------
7790 p3 = pn
7791 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
7792 j = iw(p)
7793 nvj = nv(j)
7794 IF (nvj .GT. 0) THEN
7795C j is unabsorbed, and not in Lme.
7796C add to degree and add to new list
7797 deg = deg + nvj
7798 wf3 = wf3 + nvj
7799 iw(pn) = j
7800 pn = pn + 1
7801 hash = hash + int(j,kind=8)
7802 ENDIF
7803 170 CONTINUE
7804C
7805 IF (degree(i).EQ.n2) deg = n2
7806C ----------------------------------------------------------
7807C update the degree and check for mass elimination
7808C ----------------------------------------------------------
7809#if defined (NOAGG4)
7810 IF (elen(i).EQ.1 .AND. p3.EQ.pn) THEN
7811#else
7812 IF (deg .EQ. 0) THEN
7813#endif
7814C -------------------------------------------------------
7815C mass elimination
7816C -------------------------------------------------------
7817C There is nothing left of this node except for an
7818C edge to the current pivot element. elen (i) is 1,
7819C and there are no variables adjacent to node i.
7820C Absorb i into the current pivot element, me.
7821 toto = i
7822 5911 IF(toto .NE. 0) THEN
7823 j = constraint(toto)
7824 IF(j .GT. 0) THEN
7825 constraint(j) = 0
7826 ENDIF
7827 toto = theson(toto)
7828 GOTO 5911
7829 ENDIF
7830 pe(i) = int(-me,8)
7831 nvi = -nv(i)
7832 degme = degme - nvi
7833 nvpiv = nvpiv + nvi
7834 nel = nel + nvi
7835 nv (i) = 0
7836 elen(i) = 0
7837 ELSE
7838C -------------------------------------------------------
7839C update the upper-bound degree of i
7840C -------------------------------------------------------
7841C the following degree does not yet include the size
7842C of the current element, which is added later:
7843C AMD DEGREE (I) = min (DEGREE (I), DEG)
7844 IF (degree(i).NE.n2) THEN
7845C I does not belong to halo
7846C dk = min (d(k-1)+degme, deg+degme)
7847 IF ( degree(i).LT.deg ) THEN
7848C Our appox degree is loose.
7849C we keep old value. Note that in
7850C this case we cannot substract WF(I)
7851C for min-fill score.
7852 wf4 = 0
7853 wf3 = 0
7854 ELSE
7855 degree(i) = deg
7856 ENDIF
7857 ENDIF
7858C
7859C compute WF(I) taking into account size of block 3.0
7860 wf(i) = wf4 + 2*nvi*wf3
7861C -------------------------------------------------------
7862C add me to the list for i
7863C -------------------------------------------------------
7864C move first supervariable to end of list
7865 iw(pn) = iw(p3)
7866C move first element to end of element part of list
7867 iw(p3) = iw(p1)
7868C add new element to front of list.
7869 iw(p1) = me
7870C store the new length of the list in len (i)
7871 len(i) = int(pn - p1 + 1_8)
7872 IF (deg.NE.n2) THEN
7873C -------------------------------------------------------
7874C place in hash bucket. Save hash key of i in last (i).
7875C -------------------------------------------------------
7876 hash = mod(hash, hmod) + 1_8
7877 j = head(hash)
7878 IF (j .LE. 0) THEN
7879C the degree list is empty, hash head is -j
7880 next(i) = -j
7881 head(hash) = -i
7882 ELSE
7883C degree list is not empty
7884C use last (head (hash)) as hash head
7885 next(i) = last(j)
7886 last(j) = i
7887 ENDIF
7888 last(i) = int(hash,kind=kind(last))
7889 ENDIF
7890 ENDIF
7891 180 CONTINUE
7892 degree(me) = degme
7893C -------------------------------------------------------------
7894C Clear the counter array, w (...), by incrementing wflg.
7895C -------------------------------------------------------------
7896 dmax = max(dmax, degme)
7897 wflg = wflg + dmax
7898C make sure that wflg+n does not cause integer overflow
7899 IF (wflg .GT. maxint_n) THEN
7900 DO 190 x = 1, n
7901 IF (w(x) .NE. 0) w(x) = 1
7902 190 CONTINUE
7903 wflg = 2
7904 ENDIF
7905C at this point, w (1..n) .lt. wflg holds
7906C=======================================================================
7907C SUPERVARIABLE DETECTION
7908C=======================================================================
7909 DO 250 pme = pme1, pme2
7910 i = iw(pme)
7911 IF ( (nv(i) .LT. 0) .AND. (degree(i).NE.n2) ) THEN
7912C i is a principal variable in Lme
7913C -------------------------------------------------------
7914C examine all hash buckets with 2 or more variables. We
7915C do this by examing all unique hash keys for super-
7916C variables in the pattern Lme of the current element, me
7917C -------------------------------------------------------
7918 hash = int(last(i),kind=8)
7919C let i = head of hash bucket, and empty the hash bucket
7920 j = head(hash)
7921 IF (j .EQ. 0) GO TO 250
7922 IF (j .LT. 0) THEN
7923C degree list is empty
7924 i = -j
7925 head(hash) = 0
7926 ELSE
7927C degree list is not empty, restore last () of head
7928 i = last(j)
7929 last(j) = 0
7930 ENDIF
7931 IF (i .EQ. 0) GO TO 250
7932C while loop:
7933 200 CONTINUE
7934 IF (next(i) .NE. 0) THEN
7935C ----------------------------------------------------
7936C this bucket has one or more variables following i.
7937C scan all of them to see if i can absorb any entries
7938C that follow i in hash bucket. Scatter i into w.
7939C ----------------------------------------------------
7940 ln = len(i)
7941 eln = elen(i)
7942C do not flag the first element in the list (me)
7943 DO 210 p = pe(i) + 1, pe(i) + int(ln - 1,8)
7944 w(iw(p)) = wflg
7945 210 CONTINUE
7946C ----------------------------------------------------
7947C scan every other entry j following i in bucket
7948C ----------------------------------------------------
7949 jlast = i
7950 j = next(i)
7951C while loop:
7952 220 CONTINUE
7953 IF (j .NE. 0) THEN
7954 IF(constraint(j) .LT. 0
7955 & .AND. constraint(i) .LT. 0) THEN
7956 GOTO 240
7957 ENDIF
7958 IF(constraint(i) .GE. 0) THEN
7959 IF(constraint(j) .LT. 0) THEN
7960 toto = i
7961 221 IF(toto .NE. 0) THEN
7962 IF(constraint(toto) .EQ. j) THEN
7963 GOTO 225
7964 ENDIF
7965 toto =theson(toto)
7966 GOTO 221
7967 ENDIF
7968 ELSE
7969 GOTO 225
7970 ENDIF
7971 ELSE
7972C if I is locked see if it is freed thanks to J
7973 IF(constraint(j) .GE. 0) THEN
7974 toto = j
7975 222 IF(toto .NE. 0) THEN
7976 IF(constraint(toto) .EQ. i) THEN
7977 GOTO 225
7978 ENDIF
7979 toto =theson(toto)
7980 GOTO 222
7981 ENDIF
7982 ENDIF
7983 ENDIF
7984 GOTO 240
7985 225 CONTINUE
7986C -------------------------------------------------
7987C check if j and i have identical nonzero pattern
7988C -------------------------------------------------
7989C jump if i and j do not have same size data structure
7990 IF (len(j) .NE. ln) GO TO 240
7991C jump if i and j do not have same number adj elts
7992 IF (elen(j) .NE. eln) GO TO 240
7993C do not flag the first element in the list (me)
7994 DO 230 p = pe(j) + 1_8, pe(j) + int(ln - 1,8)
7995C jump if an entry (iw(p)) is in j but not in i
7996 IF (w(iw(p)) .NE. wflg) GO TO 240
7997 230 CONTINUE
7998C -------------------------------------------------
7999C found it! j can be absorbed into i
8000C -------------------------------------------------
8001C update the supervariable composition
8002 toto = i
8003 231 IF(theson(toto) .NE. 0) THEN
8004 toto = theson(toto)
8005 GOTO 231
8006 ENDIF
8007 theson(toto) = j
8008 IF(constraint(i) .LT. 0) THEN
8009 constraint(i) = 0
8010 ENDIF
8011 pe(j) = int(-i,8)
8012 wf(i) = max(wf(i),wf(j))
8013C both nv (i) and nv (j) are negated since they
8014C are in Lme, and the absolute values of each
8015C are the number of variables in i and j:
8016 nv(i) = nv(i) + nv(j)
8017 nv(j) = 0
8018 elen(j) = 0
8019C delete j from hash bucket
8020 j = next(j)
8021 next(jlast) = j
8022 GO TO 220
8023C -------------------------------------------------
8024 240 CONTINUE
8025C j cannot be absorbed into i
8026C -------------------------------------------------
8027 jlast = j
8028 j = next(j)
8029 GO TO 220
8030 ENDIF
8031C ----------------------------------------------------
8032C no more variables can be absorbed into i
8033C go to next i in bucket and clear flag array
8034C ----------------------------------------------------
8035 wflg = wflg + 1
8036 i = next(i)
8037 IF (i .NE. 0) GO TO 200
8038 ENDIF
8039 ENDIF
8040 250 CONTINUE
8041C=======================================================================
8042C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
8043C=======================================================================
8044 p = pme1
8045 nleft = totel - nel
8046 DO 260 pme = pme1, pme2
8047 i = iw(pme)
8048 nvi = -nv(i)
8049 IF (nvi .GT. 0) THEN
8050C i is a principal variable in Lme
8051C restore nv (i) to signify that i is principal
8052 nv(i) = nvi
8053 IF (degree(i).NE.n2) THEN
8054C -------------------------------------------------------
8055C compute the external degree (add size of current elem)
8056C -------------------------------------------------------
8057 deg = min(degree(i) + degme - nvi, nleft - nvi)
8058 IF (degree(i) + degme .GT. nleft ) THEN
8059C
8060 deg = degree(i)
8061 rmf1 = dble(deg)*dble( (deg-1) + 2*degme )
8062 & - dble(wf(i))
8063 degree(i) = nleft - nvi
8064 deg = degree(i)
8065 rmf = dble(deg)*dble(deg-1)
8066 & - dble(degme-nvi)*dble(degme-nvi-1)
8067 rmf = min(rmf, rmf1)
8068 ELSE
8069 deg = degree(i)
8070 degree(i) = degree(i) + degme - nvi
8071 rmf = dble(deg)*dble( (deg-1) + 2*degme )
8072 & - dble(wf(i))
8073 ENDIF
8074 rmf = rmf / dble(nvi+1)
8075C
8076 IF (rmf.LT.dummy) THEN
8077 wf(i) = int( anint( rmf ))
8078 ELSEIF (rmf / dble(n) .LT. dummy) THEN
8079 wf(i) = int( anint( rmf/dble(n) ))
8080 ELSE
8081 wf(i) = idummy
8082 ENDIF
8083 wf(i) = max(1,wf(i))
8084C -------------------------------------------------------
8085C place the supervariable at the head of the degree list
8086C -------------------------------------------------------
8087 deg = wf(i)
8088 IF (deg.GT.n) THEN
8089 deg = min(((deg-n)/pas) + n , nbbuck)
8090 ENDIF
8091 inext = head(deg)
8092 IF (inext .NE. 0) last(inext) = i
8093 next(i) = inext
8094 last(i) = 0
8095 head(deg) = i
8096C -------------------------------------------------------
8097C save the new degree, and find the minimum degree
8098C -------------------------------------------------------
8099 mindeg = min(mindeg, deg)
8100 ENDIF
8101C -------------------------------------------------------
8102C place the supervariable in the element pattern
8103C -------------------------------------------------------
8104 iw(p) = i
8105 p = p + 1
8106 ENDIF
8107 260 CONTINUE
8108C=======================================================================
8109C FINALIZE THE NEW ELEMENT
8110C=======================================================================
8111 nv(me) = nvpiv + degme
8112C fill_est = fill_est + nvpiv * (nvpiv + 2 * degme)
8113C nv (me) is now the degree of pivot (including diagonal part)
8114C save the length of the list for the new element me
8115 len(me) = int(p - pme1)
8116 IF (len(me) .EQ. 0) THEN
8117C there is nothing left of the current pivot element
8118 pe(me) = 0_8
8119 w(me) = 0
8120 ENDIF
8121 IF (newmem .NE. 0) THEN
8122C element was not constructed in place: deallocate part
8123C of it (final size is less than or equal to newmem,
8124C since newly nonprincipal variables have been removed).
8125 pfree = p
8126 mem = mem - newmem + int(len(me),8)
8127 ENDIF
8128C=======================================================================
8129C END WHILE (selecting pivots)
8130 GO TO 30
8131 ENDIF
8132C=======================================================================
8133C begin HALO V2
8134 IF (nbflag.GT.0) THEN
8135C
8136C All possible pivots (not flagged have been eliminated).
8137C We amalgamate all flagged variables at the root and
8138C we finish the elimination tree.
8139C 1/ Go through all
8140C non absorbed elements (root of the subgraph)
8141C and absorb in ME
8142C 2/ perform mass elimination of all dense rows
8143 DO deg = mindeg, nbbuck+1
8144 me = head(deg)
8145 IF (me .GT. 0) GO TO 51
8146 ENDDO
8147 51 mindeg = deg
8148 nelme = -(nel+1)
8149 DO x=1,n
8150 IF ((pe(x).GT.0_8) .AND. (elen(x).LT.0)) THEN
8151C X is an unabsorbed element
8152 pe(x) = int(-me,8)
8153C W(X) = 0 could be suppressed ?? check it
8154 ELSEIF (degree(x).EQ.n2) THEN
8155C X is a dense row, absorb it in ME (mass elimination)
8156 nel = nel + nv(x)
8157 pe(x) = int(-me,8)
8158 elen(x) = 0
8159C Correct value of NV is (secondary variable)
8160 nv(x) = 0
8161 ENDIF
8162 ENDDO
8163C ME is the root node
8164 elen(me) = nelme
8165C Correct value of NV is (principal variable)
8166 nv(me) = n-nreal
8167 pe(me) = 0_8
8168C
8169 ENDIF
8170C end HALO
8171C=======================================================================
8172C COMPUTE THE PERMUTATION VECTORS
8173C=======================================================================
8174C ----------------------------------------------------------------
8175C The time taken by the following code is O(n). At this
8176C point, elen (e) = -k has been done for all elements e,
8177C and elen (i) = 0 has been done for all nonprincipal
8178C variables i. At this point, there are no principal
8179C supervariables left, and all elements are absorbed.
8180C ----------------------------------------------------------------
8181C ----------------------------------------------------------------
8182C compute the ordering of unordered nonprincipal variables
8183C ----------------------------------------------------------------
8184 DO 290 i = 1, n
8185 IF (elen(i) .EQ. 0) THEN
8186C ----------------------------------------------------------
8187C i is an un-ordered row. Traverse the tree from i until
8188C reaching an element, e. The element, e, was the
8189C principal supervariable of i and all nodes in the path
8190C from i to when e was selected as pivot.
8191C ----------------------------------------------------------
8192 j = int(-pe(i))
8193C while (j is a variable) do:
8194 270 CONTINUE
8195 IF (elen(j) .GE. 0) THEN
8196 j = int(-pe(j))
8197 GO TO 270
8198 ENDIF
8199 e = j
8200C ----------------------------------------------------------
8201C get the current pivot ordering of e
8202C ----------------------------------------------------------
8203 k = -elen(e)
8204C ----------------------------------------------------------
8205C traverse the path again from i to e, and compress the
8206C path (all nodes point to e). Path compression allows
8207C this code to compute in O(n) time. Order the unordered
8208C nodes in the path, and place the element e at the end.
8209C ----------------------------------------------------------
8210 j = i
8211C while (j is a variable) do:
8212 280 CONTINUE
8213 IF (elen(j) .GE. 0) THEN
8214 jnext = int(-pe(j))
8215 pe(j) = int(-e,8)
8216 IF (elen(j) .EQ. 0) THEN
8217C j is an unordered row
8218 elen(j) = k
8219 k = k + 1
8220 ENDIF
8221 j = jnext
8222 GO TO 280
8223 ENDIF
8224C leave elen (e) negative, so we know it is an element
8225 elen(e) = -k
8226 ENDIF
8227 290 CONTINUE
8228C ----------------------------------------------------------------
8229C reset the inverse permutation (elen (1..n)) to be positive,
8230C and compute the permutation (last (1..n)).
8231C ----------------------------------------------------------------
8232 IF(.true.) THEN
8233C N is the size of the compressed graph.
8234C If the graph was compressed on input then
8235C indices in ELEN are in [1,TOTEL]
8236C We build the inverse of ELEN in LAST (similar to
8237C the pivot order but has zeros in it) and then compress
8238C it. Since LAST is assumed to be of size N at the
8239C interface level, we need another array to store
8240C the inverse of ELEN for entries greater than N
8241C We use DEGREE.
8242 last(1:n) = 0
8243 degree(1:totel-n)=0
8244 DO i = 1, n
8245 k = abs(elen(i))
8246 IF ( k <= n ) THEN
8247 last(k) = i
8248 ELSE
8249 degree(k-n)=i
8250 ENDIF
8251 ENDDO
8252 i = 1
8253 DO k = 1, n
8254 IF(last(k) .NE. 0) THEN
8255 last(i) = last(k)
8256 elen(last(k)) = i
8257 i = i + 1
8258 ENDIF
8259 ENDDO
8260 DO k = n+1, totel
8261 IF (degree(k-n) .NE. 0) THEN
8262 last(i)=degree(k-n)
8263 elen(degree(k-n)) = i
8264 i = i + 1
8265 ENDIF
8266 END DO
8267 ELSE
8268 DO 300 i = 1, n
8269 k = abs(elen(i))
8270 last(k) = i
8271 elen(i) = k
8272300 CONTINUE
8273 ENDIF
8274C=======================================================================
8275C RETURN THE MEMORY USAGE IN IW
8276C=======================================================================
8277C If maxmem is less than or equal to iwlen, then no compressions
8278C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
8279C compressions did occur, and iwlen would have had to have been
8280C greater than or equal to maxmem for no compressions to occur.
8281C Return the value of maxmem in the pfree argument.
8282 pfree = maxmem
8283C===============================
8284C Save PE in PARENT array
8285 DO i=1,n
8286 parent(i) = int(pe(i))
8287 ENDDO
8288C===============================
8289 RETURN
8290 END SUBROUTINE mumps_cst_amf
8291C-----------------------------------------------------------------------
8292C MUMPS_SYMQAMD: modified version of MUMPS_QAMD code to
8293C designed to compute a symbolic factorization given
8294C an input ordering (provided in PERM array) and possibly
8295C a schur area.
8296C ---------
8297 SUBROUTINE mumps_symqamd
8298 & ( thresh, ndense,
8299 & n, totel, iwlen, pe, pfree, len, iw, nv,
8300 & elen, last, ncmpa, degree, head, next, w,
8301 & perm, listvar_schur, size_schur,
8302 & agg6, parent )
8303 IMPLICIT NONE
8304C Input not modified
8305 INTEGER, INTENT(IN) :: N, TOTEL, SIZE_SCHUR
8306 LOGICAL, INTENT(IN) :: AGG6
8307 INTEGER, INTENT(IN) :: THRESH
8308 INTEGER(8), INTENT(IN) :: IWLEN
8309 INTEGER, INTENT(IN) :: LISTVAR_SCHUR(max(1,SIZE_SCHUR))
8310C Input undefined on output
8311 INTEGER, INTENT(INOUT) :: LEN(N), IW(IWLEN)
8312C
8313C Output only
8314 INTEGER, INTENT(OUT) :: NCMPA
8315 INTEGER, INTENT(OUT) :: ELEN(N), LAST(TOTEL), PARENT(N)
8316C
8317C Input/output
8318 INTEGER, INTENT(INOUT) :: NV(N)
8319 INTEGER(8), INTENT(INOUT) :: PFREE
8320 INTEGER(8), INTENT(INOUT) :: PE(N)
8321 INTEGER, INTENT(INOUT) :: PERM(N)
8322C
8323C Internal Workspace only
8324 INTEGER, INTENT(OUT) :: NDENSE(N), DEGREE(N),
8325 & head(totel), next(n), w(n)
8326C
8327C =======================
8328C INTERFACE DOCUMENTATION
8329C SPECIFIC TO SYMQAMD.
8330C =======================
8331C (more details are sometimes
8332C available in the
8333C PREVIOUS DOCUMENTATION
8334C section)
8335C
8336C N (in): the size of the matrix
8337C number of supervariables if blocked format
8338C TOTEL (in) : Number of variables to eliminate
8339C
8340C IWLEN (in): the length of the workspace IW
8341C
8342C PFREE (inout): says that IW(1:PFREE-1) contains the graph on input, see
8343C below. (on output see meaning bellow)
8344C IW (inout):
8345C On input, IW(1:PFREE-1) contains the orginal graph
8346C On output it has been corrupted because IW(1:IWLEN) has been
8347C used as workspace.
8348C
8349C LEN(inout): On input,
8350C LEN (i) holds the number of entries in row i of the
8351C matrix, excluding the diagonal. The contents of LEN(1..N)
8352C are undefined on output.
8353C
8354C PE(inout): On input PE(i) contains the pointers in IW to (the column
8355C indices of) row i of the matrix.
8356C On output it contains the tree:
8357C - if I is a principal variable (NV(I) >0) then -pe(I) is the principal
8358C variable of the father, or 0 if I is a root node.
8359C - if I is a secondary variable (NV(I)=0) then -pe(I) is the principal
8360C variable of the node it belongs to.
8361C
8362C On output: (PE is copied on output into PARENT array)
8363C
8364C
8365C NV(inout):
8366C On input: encoding of a blocked matrix
8367C if NV(1).NE.-1 the NV(I) holds the weight of node I.
8368C During execution,
8369C abs (nv (i)) is equal to the number of rows
8370C that are represented by the principal supervariable i.
8371C If i is a nonprincipal variable, then nv (i) = 0.
8372C nv (i) .lt. 0 signifies that i is a
8373C principal variable in the pattern Lme of the current pivot
8374C element me.
8375C On output:
8376C - if i is a principal variable, NV(i) is the size of the front
8377C in the multifrontal terminology.
8378C - if i is a secondary variable, NV(i)=0
8379C
8380C PERM (inout) : MUST BE SET TO HOLD THE POSITION OF VARIABLE I IN THE
8381C PERMUTED ORDER.
8382C PERM(I) = J means that I is the Jth pivot.
8383C PERM IS NOT ALTERED IF SIZE_SCHUR = 0.
8384C IF SIZE_SCHUR > 0 and variable I is part of the Schur,
8385C then PERM(I) must be greater than N - SIZE_SCHUR.
8386C In that case, PERM(I) is altered: it is set to N+1 internally !
8387C
8388C SIZE_SCHUR (in) : > 0 means that the last SIZE_SCHUR variable
8389C in the order (such that PERM(I) > N-SIZE_SCHUR)
8390C are part of the schur decompositon
8391C and should remain ordered last and amalgamated
8392C at the root of the elimination tree.
8393C
8394C LISTVAR_SCHUR(1:SIZE_SCHUR) (in): should be set on entry to the list of
8395C variables (original indices) in the Schur complement
8396C
8397C THRESH (in): is used to set the local variable THRESM, corresponding
8398C to the internal restarting feature.
8399C <= 0 Recommended value. Automatic setting will be done.
8400C Note that this does not correspond to the historical
8401C documentation further below.
8402C = N Only exactly dense rows in the reduced matrix are selected.
8403C > 1 and <= N THRESH correspond to the minimum density requirement.
8404C
8405C At the moment if SIZE_SCHUR > 0 restarting functionality is disabled,
8406C which means that performance is not optimal. It should work again with
8407C a small modification but this has to be tested when it is re-enabled.
8408C
8409C ELEN (out) needs not be set on entry.
8410C It contains the inverse
8411C permutation on output. Not sure what it contains for the Schur
8412C variables.
8413C (it should be ok for the Schur too).
8414C
8415C LAST used internally as working space;
8416C On output, last (1..n) holds the permutation, i = last (k), then
8417C row i is the kth pivot row.
8418C Not used on output and
8419C Computation has been suppressed
8420C since in the context of blocked matrix format
8421C one cannot so easily compute last out of elen
8422C (see end of MUMPS_QAMD in case of COMRPESS,
8423C because elen(i) \in [1:TOTEL] and not \in [1:N])
8424C
8425C AGG6 (in): controls if aggressive absorption should be authorized.
8426C
8427C -------------------------------------------
8428C ARGUMENTS USED INTERNALLY AS WORKARRAYS
8429C Maybe some things are significant on output
8430C but not in the normal cases of usage.
8431C -------------------------------------------
8432C
8433C NDENSE, LAST, NEXT, HEAD, DEGREE, W
8434C
8435C ------
8436C OUTPUT
8437C ------
8438C
8439C NCMPA (out): number of compressions.
8440C
8441C
8442C ======================
8443C PREVIOUS DOCUMENTATION
8444C ======================
8445C
8446C NDENSE of an element is the number of dense rows in the element.
8447C-----------------------------------------------------------------------
8448C It is a modified version of MUMPS_QAMD
8449C designed to automatically detect and exploit dense or quasi dense
8450C rows in the reduced matrix at any step of the minimum degree.
8451C The input integer parameter THRESH defines the quasi density:
8452C THRESH : input parameter (not modified)
8453C THRESH is used to compute THRESM
8454C <=0 or N Only exactly dense rows in the reduced matrix are selected.
8455C >1 and <=N THRESH correspond to the munimum density requirement.
8456C Version 0: All dense and quasi dense rows are amalgamated at the
8457C root node.
8458C Version 1: Restart AMD with all quasi dense rows, and
8459C increase density requirement.
8460C-----------------------------------------------------------------------
8461C Additionnal parameters/variables due to dense row manipulation:
8462C
8463C Local variables:
8464C ---------------
8465 INTEGER THRESM, NDME, PERMeqN
8466 INTEGER NBD,NBED, NBDM, LASTD, NELME
8467 LOGICAL IDENSE
8468C THRESM : Local Integer holding a
8469C potentially modified value of THRESH.
8470C When quasi dense rows are reintegrated in the
8471C graph to be processed then THRESM is modified.
8472C Note that if one sets THRESM to negative value then
8473C <0 Classical AMD algorithm (no dense row detection)
8474C NDME : number of dense row adjacent to me
8475C NELME number of pivots selected when reching the root
8476C LASTD index of the last row in the list of dense rows
8477C NBD is the total number of dense rows selected
8478C NBED is the total number of exactly dense rows detected.
8479C NBDM is the maximum number of dense rows selected
8480C IDENSE is used to indicate that the supervariable I is a dense or
8481C quasi-dense row.
8482C-----------------------------------------------------------------------
8483C INPUT ARGUMENTS (unaltered):
8484C-----------------------------------------------------------------------
8485C n: The matrix order.
8486C
8487C Restriction: n .ge. 1
8488C iwlen: The length of iw (1..iwlen). On input, the matrix is
8489C stored in iw (1..pfree-1). However, iw (1..iwlen) should be
8490C slightly larger than what is required to hold the matrix, at
8491C least iwlen .ge. pfree + n is recommended. Otherwise,
8492C excessive compressions will take place.
8493C *** We do not recommend running this algorithm with ***
8494C *** iwlen .lt. pfree + n. ***
8495C *** Better performance will be obtained if ***
8496C *** iwlen .ge. pfree + n ***
8497C *** or better yet ***
8498C *** iwlen .gt. 1.2 * pfree ***
8499C *** (where pfree is its value on input). ***
8500C The algorithm will not run at all if iwlen .lt. pfree-1.
8501C
8502C Restriction: iwlen .ge. pfree-1
8503C-----------------------------------------------------------------------
8504C INPUT/OUPUT ARGUMENTS:
8505C-----------------------------------------------------------------------
8506C pe: On input, pe (i) is the index in iw of the start of row i, or
8507C zero if row i has no off-diagonal non-zeros.
8508C
8509C During execution, it is used for both supervariables and
8510C elements:
8511C
8512C * Principal supervariable i: index into iw of the
8513C description of supervariable i. A supervariable
8514C represents one or more rows of the matrix
8515C with identical nonzero pattern.
8516C * Non-principal supervariable i: if i has been absorbed
8517C into another supervariable j, then pe (i) = -j.
8518C That is, j has the same pattern as i.
8519C Note that j might later be absorbed into another
8520C supervariable j2, in which case pe (i) is still -j,
8521C and pe (j) = -j2.
8522C * Unabsorbed element e: the index into iw of the description
8523C of element e, if e has not yet been absorbed by a
8524C subsequent element. Element e is created when
8525C the supervariable of the same name is selected as
8526C the pivot.
8527C * Absorbed element e: if element e is absorbed into element
8528C e2, then pe (e) = -e2. This occurs when the pattern of
8529C e (that is, Le) is found to be a subset of the pattern
8530C of e2 (that is, Le2). If element e is "null" (it has
8531C no nonzeros outside its pivot block), then pe (e) = 0.
8532C
8533C On output, pe holds the assembly tree/forest, which implicitly
8534C represents a pivot order with identical fill-in as the actual
8535C order (via a depth-first search of the tree).
8536C
8537C On output:
8538C If nv (i) .gt. 0, then i represents a node in the assembly tree,
8539C and the parent of i is -pe (i), or zero if i is a root.
8540C If nv (i) = 0, then (i,-pe (i)) represents an edge in a
8541C subtree, the root of which is a node in the assembly tree.
8542C pfree: On input, the matrix is stored in iw (1..pfree-1) and
8543C the rest of the array iw is free.
8544C During execution, additional data is placed in iw, and pfree
8545C is modified so that components of iw from pfree are free.
8546C On output, pfree is set equal to the size of iw that
8547C would have been needed for no compressions to occur. If
8548C ncmpa is zero, then pfree (on output) is less than or equal to
8549C iwlen, and the space iw (pfree+1 ... iwlen) was not used.
8550C Otherwise, pfree (on output) is greater than iwlen, and all the
8551C memory in iw was used.
8552C-----------------------------------------------------------------------
8553C INPUT/MODIFIED (undefined on output):
8554C-----------------------------------------------------------------------
8555C len: On input, len (i) holds the number of entries in row i of the
8556C matrix, excluding the diagonal. The contents of len (1..n)
8557C are undefined on output.
8558C iw: On input, iw (1..pfree-1) holds the description of each row i
8559C in the matrix. The matrix must be symmetric, and both upper
8560C and lower triangular parts must be present. The diagonal must
8561C not be present. Row i is held as follows:
8562C
8563C len (i): the length of the row i data structure
8564C iw (pe (i) ... pe (i) + len (i) - 1):
8565C the list of column indices for nonzeros
8566C in row i (simple supervariables), excluding
8567C the diagonal. All supervariables start with
8568C one row/column each (supervariable i is just
8569C row i).
8570C if len (i) is zero on input, then pe (i) is ignored
8571C on input.
8572C
8573C Note that the rows need not be in any particular order,
8574C and there may be empty space between the rows.
8575C
8576C During execution, the supervariable i experiences fill-in.
8577C This is represented by placing in i a list of the elements
8578C that cause fill-in in supervariable i:
8579C
8580C len (i): the length of supervariable i
8581C iw (pe (i) ... pe (i) + elen (i) - 1):
8582C the list of elements that contain i. This list
8583C is kept short by removing absorbed elements.
8584C iw (pe (i) + elen (i) ... pe (i) + len (i) - 1):
8585C the list of supervariables in i. This list
8586C is kept short by removing nonprincipal
8587C variables, and any entry j that is also
8588C contained in at least one of the elements
8589C (j in Le) in the list for i (e in row i).
8590C
8591C When supervariable i is selected as pivot, we create an
8592C element e of the same name (e=i):
8593C
8594C len (e): the length of element e
8595C iw (pe (e) ... pe (e) + len (e) - 1):
8596C the list of supervariables in element e.
8597C
8598C An element represents the fill-in that occurs when supervariable
8599C i is selected as pivot (which represents the selection of row i
8600C and all non-principal variables whose principal variable is i).
8601C We use the term Le to denote the set of all supervariables
8602C in element e. Absorbed supervariables and elements are pruned
8603C from these lists when computationally convenient.
8604C
8605C CAUTION: THE INPUT MATRIX IS OVERWRITTEN DURING COMPUTATION.
8606C The contents of iw are undefined on output.
8607C-----------------------------------------------------------------------
8608C OUTPUT (need not be set on input):
8609C-----------------------------------------------------------------------
8610C nv: During execution, abs (nv (i)) is equal to the number of rows
8611C that are represented by the principal supervariable i. If i is
8612C a nonprincipal variable, then nv (i) = 0. Initially,
8613C nv (i) = 1 for all i. nv (i) .lt. 0 signifies that i is a
8614C principal variable in the pattern Lme of the current pivot
8615C element me. On output, nv (e) holds the true degree of element
8616C e at the time it was created (including the diagonal part).
8617C elen: See the description of iw above. At the start of execution,
8618C elen (i) is set to zero. During execution, elen (i) is the
8619C number of elements in the list for supervariable i. When e
8620C becomes an element, elen (e) = -nel is set, where nel is the
8621C current step of factorization. elen (i) = 0 is done when i
8622C becomes nonprincipal.
8623C
8624C For variables, elen (i) .ge. 0 holds until just before the
8625C permutation vectors are computed. For elements,
8626C elen (e) .lt. 0 holds.
8627C
8628C On output elen (1..n) holds the inverse permutation (the same
8629C as the 'INVP' argument in Sparspak). That is, if k = elen (i),
8630C then row i is the kth pivot row. Row i of A appears as the
8631C (elen(i))-th row in the permuted matrix, PAP^T.
8632C last: In a degree list, last (i) is the supervariable preceding i,
8633C or zero if i is the head of the list. In a hash bucket,
8634C last (i) is the hash key for i. last (head (hash)) is also
8635C used as the head of a hash bucket if head (hash) contains a
8636C degree list (see head, below).
8637C
8638C On output, last (1..n) holds the permutation (the same as the
8639C 'PERM' argument in Sparspak). That is, if i = last (k), then
8640C row i is the kth pivot row. Row last (k) of A is the k-th row
8641C in the permuted matrix, PAP^T.
8642C ncmpa: The number of times iw was compressed. If this is
8643C excessive, then the execution took longer than what could have
8644C been. To reduce ncmpa, try increasing iwlen to be 10% or 20%
8645C larger than the value of pfree on input (or at least
8646C iwlen .ge. pfree + n). The fastest performance will be
8647C obtained when ncmpa is returned as zero. If iwlen is set to
8648C the value returned by pfree on *output*, then no compressions
8649C will occur.
8650C-----------------------------------------------------------------------
8651C LOCAL (not input or output - used only during execution):
8652C-----------------------------------------------------------------------
8653C degree: If i is a supervariable, then degree (i) holds the
8654C current approximation of the external degree of row i (an upper
8655C bound). The external degree is the number of nonzeros in row i,
8656C minus abs (nv (i)) (the diagonal part). The bound is equal to
8657C the external degree if elen (i) is less than or equal to two.
8658C
8659C We also use the term "external degree" for elements e to refer
8660C to |Le \ Lme|. If e is an element, then degree (e) holds |Le|,
8661C which is the degree of the off-diagonal part of the element e
8662C (not including the diagonal part).
8663C degree (I) =N+1 if I is an exactly dense row in reduced matrix.
8664C =N+1+LAST_approximate_external_deg of I
8665C if I is a quasi dense row in reduced matrix.
8666C All dense or quasi dense rows are stored in the list pointed
8667C by head(n). Quasi-dense rows (degree(I)=n) are stored first,
8668C and are followed by exactly dense rows in the reduced matrix.
8669C LASTD holds the last row in this list of dense rows or is zero
8670C if the list is empty.
8671C head: head is used for degree lists. head (deg) is the first
8672C supervariable in a degree list (all supervariables i in a
8673C degree list deg have the same approximate degree, namely,
8674C deg = degree (i)). If the list deg is empty then
8675C head (deg) = 0.
8676C
8677C During supervariable detection head (hash) also serves as a
8678C pointer to a hash bucket.
8679C If head (hash) .gt. 0, there is a degree list of degree hash.
8680C The hash bucket head pointer is last (head (hash)).
8681C If head (hash) = 0, then the degree list and hash bucket are
8682C both empty.
8683C If head (hash) .lt. 0, then the degree list is empty, and
8684C -head (hash) is the head of the hash bucket.
8685C After supervariable detection is complete, all hash buckets
8686C are empty, and the (last (head (hash)) = 0) condition is
8687C restored for the non-empty degree lists.
8688C next: next (i) is the supervariable following i in a link list, or
8689C zero if i is the last in the list. Used for two kinds of
8690C lists: degree lists and hash buckets (a supervariable can be
8691C in only one kind of list at a time).
8692C w: The flag array w determines the status of elements and
8693C variables, and the external degree of elements.
8694C
8695C for elements:
8696C if w (e) = 0, then the element e is absorbed
8697C if w (e) .ge. wflg, then w (e) - wflg is the size of
8698C the set |Le \ Lme|, in terms of nonzeros (the
8699C sum of abs (nv (i)) for each principal variable i that
8700C is both in the pattern of element e and NOT in the
8701C pattern of the current pivot element, me).
8702C if wflg .gt. w (e) .gt. 0, then e is not absorbed and has
8703C not yet been seen in the scan of the element lists in
8704C the computation of |Le\Lme| in loop 150 below.
8705C
8706C for variables:
8707C during supervariable detection, if w (j) .ne. wflg then j is
8708C not in the pattern of variable i
8709C
8710C The w array is initialized by setting w (i) = 1 for all i,
8711C and by setting wflg = 2. It is reinitialized if wflg becomes
8712C too large (to ensure that wflg+n does not cause integer
8713C overflow).
8714C-----------------------------------------------------------------------
8715C LOCAL INTEGERS:
8716C-----------------------------------------------------------------------
8717C THRESM is used to
8718C accelerate symolic factorization
8719C THRESM is dynamically updated to
8720C allow more quasi-dense row selection
8721C ThresPrev holds last starting value
8722C at the beginning of one iteration
8723C ThresMin holds minimum value of THRESH
8724 INTEGER :: FDEG, ThresMin, ThresPrev, IBEGSchur, NbSchur,
8725 & ThresMinINIT
8726 INTEGER :: DEGMAX,THD, THDperm, THD_AGG
8727 DOUBLE PRECISION :: RELDEN
8728 LOGICAL :: AGG6_loc, DenseRows
8729 LOGICAL :: SchurON
8730 INTEGER :: DEG, DEGME, DEXT, DMAX, E, ELENME, ELN, I,
8731 & ilast, inext, j, jlast, jnext, k, knt1, knt2, knt3,
8732 & lenj, ln, me, mindeg, nel,
8733 & nleft, nvi, nvj, nvpiv, slenme, we, wflg, wnvi, x
8734 INTEGER KNT1_UPDATED, KNT2_UPDATED
8735 INTEGER :: SIZE_SCHUR_LOC
8736 INTEGER(8) MAXMEM, MEM, NEWMEM
8737 INTEGER :: MAXINT_N
8738 INTEGER(8) :: HASH, HMOD
8739 LOGICAL :: COMPRESS
8740C deg: the degree of a variable or element
8741C degme: size, |Lme|, of the current element, me (= degree (me))
8742C dext: external degree, |Le \ Lme|, of some element e
8743C dmax: largest |Le| seen so far
8744C e: an element
8745C elenme: the length, elen (me), of element list of pivotal var.
8746C eln: the length, elen (...), of an element list
8747C hash: the computed value of the hash function
8748C hmod: the hash function is computed modulo hmod = max (1,n-1)
8749C i: a supervariable
8750C ilast: the entry in a link list preceding i
8751C inext: the entry in a link list following i
8752C j: a supervariable
8753C jlast: the entry in a link list preceding j
8754C jnext: the entry in a link list, or path, following j
8755C k: the pivot order of an element or variable
8756C knt1: loop counter used during element construction
8757C knt2: loop counter used during element construction
8758C knt3: loop counter used during compression
8759C lenj: len (j)
8760C ln: length of a supervariable list
8761C maxint_n: large integer to test risk of overflow on wflg
8762C maxmem: amount of memory needed for no compressions
8763C me: current supervariable being eliminated, and the
8764C current element created by eliminating that
8765C supervariable
8766C mem: memory in use assuming no compressions have occurred
8767C mindeg: current minimum degree
8768C nel: number of pivots selected so far
8769C newmem: amount of new memory needed for current pivot element
8770C nleft: n - nel, the number of nonpivotal rows/columns remaining
8771C nvi: the number of variables in a supervariable i (= nv (i))
8772C nvj: the number of variables in a supervariable j (= nv (j))
8773C nvpiv: number of pivots in current element
8774C slenme: number of variables in variable list of pivotal variable
8775C we: w (e)
8776C wflg: used for flagging the w array. See description of iw.
8777C wnvi: wflg - nv (i)
8778C x: either a supervariable or an element
8779C-----------------------------------------------------------------------
8780C LOCAL POINTERS:
8781C-----------------------------------------------------------------------
8782 INTEGER(8) P, P1, P2, P3, PDST, PEND, PJ, PME, PME1, PME2,
8783 & PN, PSRC, PLN, PELN
8784C Any parameter (pe (...) or pfree) or local variable
8785C starting with "p" (for Pointer) is an index into iw,
8786C and all indices into iw use variables starting with
8787C "p." The only exception to this rule is the iwlen
8788C input argument.
8789C p: pointer into lots of things
8790C p1: pe (i) for some variable i (start of element list)
8791C p2: pe (i) + elen (i) - 1 for some var. i (end of el. list)
8792C p3: index of first supervariable in clean list
8793C pdst: destination pointer, for compression
8794C pend: end of memory to compress
8795C pj: pointer into an element or variable
8796C pme: pointer into the current element (pme1...pme2)
8797C pme1: the current element, me, is stored in iw (pme1...pme2)
8798C pme2: the end of the current element
8799C pn: pointer into a "clean" variable, also used to compress
8800C psrc: source pointer, for compression
8801C-----------------------------------------------------------------------
8802C FUNCTIONS CALLED:
8803C-----------------------------------------------------------------------
8804 INTRINSIC max, min, mod, maxval
8805C=======================================================================
8806C INITIALIZATIONS
8807C=======================================================================
8808 IF (n.EQ.1) THEN
8809 elen(1) = 1
8810 last(1) = 1
8811 pe(1) = 0_8
8812 IF (nv(1).LT.0) nv(1) = 1
8813 ncmpa = 0
8814 parent(1) = 0
8815 RETURN
8816 ENDIF
8817 agg6_loc = agg6
8818 denserows = .false.
8819C
8820C We can now assume that N>1
8821C
8822CSymbolic Intialize degrees with the order given by PERM
8823C
8824 size_schur_loc = size_schur
8825 size_schur_loc = min(n,size_schur_loc)
8826 size_schur_loc = max(0,size_schur_loc)
8827 schuron = (size_schur_loc > 0)
8828 ibegschur = n-size_schur_loc+1
8829 thresm = thresh ! local value of THRESH
8830 IF (thresm.GT.n) thresm = n
8831 IF (thresm.LT.0) thresm = 0
8832C Variables in the schur are considered as exactly dense
8833C (Schur variables are ordered last, we check it here)
8834 IF ( schuron ) THEN
8835 DO i= 1, n
8836 IF ( perm(i) .GE. ibegschur) THEN
8837 perm(i) = n + 1
8838C Because of compress, we force skipping this
8839C entry which is anyway empty
8840 IF (len(i) .EQ.0) THEN
8841 pe(i) = 0_8
8842 ENDIF
8843 ENDIF
8844 ENDDO
8845 ENDIF
8846C
8847 IF (schuron) THEN
8848C
8849C Only restriction is n>= THRESM > 0
8850C
8851C only exactly dense row will be selected
8852C It should also work ok combined to
8853C quasi dense row selection.
8854C (To be Tested it seperately)
8855 thresm = n
8856 thresmin = n
8857 thresprev = n
8858 ELSE
8859 thresm = max(int(31*n/32),thresm)
8860 thresm = max(thresm,1)
8861C
8862 degmax= maxval(len)
8863 relden=dble(pfree-1)/dble(n)
8864 thd = int(relden)*10 + (degmax-int(relden))/10 + 1
8865 IF (thd.LT.degmax) THEN
8866 denserows = .true.
8867 thdperm = n
8868 DO i = 1,n
8869 IF (len(i) .GT. thd) THEN
8870 thdperm = min(thdperm,perm(i))
8871 ENDIF
8872 ENDDO
8873 thresm = min(thresm, thdperm)
8874 ENDIF
8875C Compute ThresMin and initialise ThresPrev
8876 thresmin = max( 3*thresm / 4, 1)
8877 thresprev = thresm
8878C
8879 ENDIF ! test on SchurON
8880C
8881 thresmininit = thresmin/4
8882 thd_agg = max(128, min(totel/2048, 1024))
8883 IF (thresm.GT.0) THEN
8884 IF ((thresm.GT.n).OR.(thresm.LT.2)) THEN
8885C exactly dense rows only
8886 thresm = n
8887 ENDIF
8888 ENDIF
8889 lastd = 0
8890 nbd = 0
8891 nbed = 0
8892 nbdm = 0
8893 wflg = 2
8894 maxint_n=huge(wflg)-totel
8895 mindeg = 1
8896 ncmpa = 0
8897 nel = 0
8898 hmod = int(max(1, n-1),kind=8)
8899 dmax = 0
8900 mem = pfree - 1
8901 maxmem = mem
8902 DO i = 1, n
8903 ndense(i)= 0
8904 w(i) = 1
8905 elen(i) = 0
8906C NV (I) = 1
8907C DEGREE (I) = LEN (I)
8908 ENDDO
8909 DO i=1, n
8910 last(i) = 0
8911 head(i) = 0
8912 ENDDO
8913C initialize degree
8914 IF(nv(1) .LT. 0) THEN
8915 compress = .false.
8916 ELSE
8917 compress = .true.
8918 ENDIF
8919 IF (compress) THEN
8920 DO i=1,n
8921 degree(i) = 0
8922 DO p= pe(i) , pe(i)+int(len(i)-1,8)
8923 degree(i) = degree(i) + nv(iw(p))
8924 ENDDO
8925 ENDDO
8926 ELSE
8927 DO i=1,n
8928 nv(i) = 1
8929 degree(i) = len(i)
8930 ENDDO
8931 ENDIF
8932C ----------------------------------------------------------------
8933C initialize degree lists and eliminate rows with no off-diag. nz.
8934C ----------------------------------------------------------------
8935 DO 20 i = 1, n
8936 deg = degree(i)
8937 IF (perm(i).EQ.n) THEN
8938C save that I is last in the order
8939 permeqn = i
8940 perm(i) = n-1
8941 ENDIF
8942 fdeg = perm(i)
8943 IF ( (deg .GT. 0).OR.(perm(i).EQ.n+1) ) THEN
8944C ----------------------------------------------------------
8945C place i in the degree list corresponding to its degree
8946C or in the dense row list if i is dense or quasi dense.
8947C ----------------------------------------------------------
8948C test for row density
8949 IF ( (thresm.GT.0) .AND.
8950 & (fdeg .GT.thresm) ) THEN
8951C I will be inserted in the degree list of N
8952 nbd = nbd+nv(i)
8953 IF (fdeg.NE.n+1) THEN
8954C
8955 degree(i) = degree(i)+totel+2
8956C insert I at the beginning of degree list of n
8957 deg = n
8958 inext = head(deg)
8959 IF (inext .NE. 0) last(inext) = i
8960 next(i) = inext
8961 head(deg) = i
8962 last(i) = 0
8963 IF (lastd.EQ.0) lastd=i
8964 ELSE
8965C Only Schur variables are concerned here
8966C Property: LISTVAR_SCHUR (1) will
8967C be first in the list of schur variables
8968 nbed = nbed+nv(i)
8969 degree(i) = totel+1
8970C insert I at the end of degree list of n
8971 deg = n
8972 IF (lastd.EQ.0) THEN
8973C degree list is empty
8974 lastd = i
8975 head(deg) = i
8976 next(i) = 0
8977 last(i) = 0
8978 ELSE
8979 next(lastd) = i
8980 last(i) = lastd
8981 lastd = i
8982 next(i) = 0
8983 ENDIF
8984 ENDIF
8985 ELSE
8986C place i in the degree list corresponding to its degree
8987 inext = head(fdeg)
8988 IF (inext .NE. 0) last(inext) = i
8989 next(i) = inext
8990 head(fdeg) = i
8991 ENDIF
8992 ELSE
8993C ----------------------------------------------------------
8994C we have a variable that can be eliminated at once because
8995C there is no off-diagonal non-zero in its row.
8996C ----------------------------------------------------------
8997 nel = nel + nv(i)
8998 elen(i) = -nel
8999 pe(i) = 0_8
9000 w(i) = 0
9001 ENDIF
9002 20 CONTINUE
9003C We suppress dense row selection if none of them was found in A
9004C in the 1st pass
9005 IF ((nbd.EQ.0).AND.(thresm.GT.0)) thresm = n
9006C
9007C=======================================================================
9008C WHILE (selecting pivots) DO
9009C=======================================================================
9010 30 IF (nel .LT. totel) THEN
9011C=======================================================================
9012C GET PIVOT OF MINIMUM DEGREE
9013C=======================================================================
9014C -------------------------------------------------------------
9015C find next supervariable for elimination
9016C -------------------------------------------------------------
9017 DO 40 deg = mindeg, n
9018 me = head(deg)
9019 IF (me .GT. 0) GO TO 50
9020 40 CONTINUE
9021 50 mindeg = deg
9022C -------------------------------------------------------------
9023C We want to respect the ordering provided by the user
9024C Therefefore if (DEG > THRESM .and. NBD.ge.0) then
9025C A quasi-dense variable might have a perm value
9026C smaller than ME.
9027C We thus in this case force restarting.
9028C -------------------------------------------------------------
9029 IF ( (deg.NE.n) .AND.
9030 & (deg.GT.thresm+1) .AND. (nbd.GT.0) ) THEN
9031 mindeg = n
9032 GOTO 30
9033 ENDIF
9034 IF (degree(me).LE.totel) THEN
9035C -------------------------------------------------------------
9036C remove chosen variable from link list
9037C -------------------------------------------------------------
9038 inext = next(me)
9039 IF (inext .NE. 0) last(inext) = 0
9040 head(deg) = inext
9041 ELSE
9042C
9043C Because of restarting forced even if
9044C variable (not yet quasi dense) but of
9045C value of perm larger than thresm still
9046C to be eliminated we have to reset MINDEB to 1
9047 mindeg = 1
9048 nbdm = max(nbdm,nbd)
9049 IF (degree(me).GT.totel+1) THEN
9050 IF (wflg .GT. maxint_n) THEN
9051 DO 52 x = 1, n
9052 IF (w(x) .NE. 0) w(x) = 1
9053 52 CONTINUE
9054 wflg = 2
9055 ENDIF
9056 wflg = wflg + 1
9057 51 CONTINUE
9058C ---------------------------------------------------------
9059C remove chosen variable from link list
9060C ---------------------------------------------------------
9061 inext = next(me)
9062 IF (inext .NE. 0) THEN
9063 last(inext) = 0
9064 ELSE
9065 lastd = 0
9066 ENDIF
9067C ----------------------------------------------------------
9068c build adjacency list of ME in quotient gragh
9069C and calculate its external degree in ndense(me)
9070C ----------------------------------------------------------
9071 ndense(me) = 0
9072 w(me) = wflg
9073 p1 = pe(me)
9074 p2 = p1 + int(len(me) -1,8)
9075C PLN-1 holds the pointer in IW to the last elet/var in adj list
9076C of ME. LEN(ME) will then be set to PLN-P1
9077C PELN-1 hold the pointer in IW to the last elet in in adj list
9078C of ME. ELEN(ME) will then be set to PELN-P1
9079C element adjacent to ME
9080 pln = p1
9081 peln = p1
9082 DO 55 p=p1,p2
9083 e= iw(p)
9084 IF (w(e).EQ.wflg) GOTO 55
9085 w(e) = wflg
9086 IF (pe(e).LT.0_8) THEN
9087C E is a nonprincipal variable or absorbed element
9088 x = e
9089 53 x = int(-pe(x))
9090 IF (w(x) .EQ.wflg) GOTO 55
9091 w(x) = wflg
9092 IF ( pe(x) .LT. 0_8 ) GOTO 53
9093 e = x
9094 ENDIF
9095C -------------------------------------------
9096C E is an unabsorbed element or a "dense" row
9097C (NOT already flagged)
9098C -------------------------------------------
9099 IF (elen(e).LT.0) THEN
9100C E is a new element in adj(ME)
9101 ndense(e) = ndense(e) - nv(me)
9102 iw(pln) = iw(peln)
9103 iw(peln) = e
9104 pln = pln+1_8
9105 peln = peln + 1_8
9106C update ndense of ME with all unflagged dense
9107C rows in E
9108 pme1 = pe(e)
9109 DO 54 pme = pme1, pme1+int(len(e)-1,8)
9110 x = iw(pme)
9111 IF ((elen(x).GE.0).AND.(w(x).NE.wflg)) THEN
9112C X is a dense row
9113 ndense(me) = ndense(me) + nv(x)
9114 w(x) = wflg
9115 ENDIF
9116 54 CONTINUE
9117 ELSE
9118C E is a dense row
9119 ndense(me) = ndense(me) + nv(e)
9120 iw(pln)=e
9121 pln = pln+1_8
9122 ENDIF
9123 55 CONTINUE
9124C ----------------------------------------------
9125C DEGREE(ME)-(TOTEL+2) holds last external degree computed
9126C when Me was detected as dense
9127C NDENSE(ME) is the exact external degree of ME
9128C ----------------------------------------------
9129 wflg = wflg + 1
9130 len(me) = int(pln-p1)
9131 elen(me) = int(peln-p1)
9132 ndme = ndense(me)+nv(me)
9133 IF (ndense(me).EQ.0) ndense(me) =1
9134C ---------------------------------------------------------
9135C place ME in the degree list of NDENSE(ME), update DEGREE
9136C ---------------------------------------------------------
9137 degree(me) = ndense(me)
9138 deg = perm(me)
9139 mindeg = min(deg,mindeg)
9140 jnext = head(deg)
9141 IF (jnext.NE. 0) last(jnext) = me
9142 next(me) = jnext
9143 head(deg) = me
9144C ------------------------------
9145C process next quasi dense row
9146C ------------------------------
9147 me = inext
9148 IF (me.NE.0) THEN
9149 IF (degree(me).GT.(totel+1) ) GOTO 51
9150 ENDIF
9151 head(n) = me
9152C ---------------------------------------
9153C update dense row selection strategy
9154C -------------------------------------
9155 IF (thresm.LT.n) THEN
9156 thresmin = max(thresm+thresmin,thresprev+thresmin/2+1)
9157 thresmin = min(thresmin, n)
9158 thresprev = thresprev+(n-thresprev)/2+thresmininit
9159 thresm = max(
9160 & thresm + int(sqrt(dble(thresmin)))+ thresmininit ,
9161 & thresprev)
9162 thresm = min(thresm,n)
9163 thresmin = min(thresm, thresmin)
9164 thresprev = thresm
9165 ENDIF
9166 nbd = nbed
9167C get back to Min degree elimination loop
9168C
9169 GOTO 30
9170 ENDIF
9171C -------------------------------------------------------------
9172C -------------------------------------------------------------
9173 IF (degree(me).EQ.totel+1) THEN
9174C we have only exactly "dense" rows that we
9175C amalgamate at the root node
9176 IF (nbd.NE.nbed) THEN
9177 write(6,*) ' ERROR in MUMPS_SYMQAMD quasi dense rows remains'
9178 CALL mumps_abort()
9179 ENDIF
9180 nbschur = 0 ! Only for checking
9181 nelme = -(nel+1)
9182 DO 59 x=1,n
9183 IF ((pe(x).GT.0) .AND. (elen(x).LT.0)) THEN
9184 pe(x) = int(-listvar_schur(1),8)
9185 ELSE IF ((pe(x).GT.0) .AND. (elen(x).LT.0)) THEN
9186C X is an unabsorbed element
9187C -- Force sons to be linked to first node in Schur
9188 pe(x) = int(-listvar_schur(1),8)
9189C W(X) = 0 could be suppressed ?? check it
9190 ELSEIF (degree(x).EQ.totel+1) THEN
9191C X is a dense row, absorb it in ME (mass elimination)
9192 nel = nel + nv(x)
9193 pe(x) = int(-me,8)
9194 elen(x) = 0
9195 nv(x) = 0
9196 nbschur = nbschur+ 1
9197 ENDIF
9198 59 CONTINUE
9199 IF (nbschur.NE.size_schur_loc) then
9200 write(6,*) ' Internal error 2 in QAMD :',
9201 & ' Schur size expected:',size_schur_loc, 'Real:', nbschur
9202 CALL mumps_abort()
9203 ENDIF
9204C ME is the root node
9205 elen(me) = nelme
9206 nv(me) = nbd
9207 pe(me) = 0_8
9208 IF (nel.NE.n) THEN
9209 write(6,*) 'Internal ERROR 2 detected in QAMD'
9210 write(6,*) ' NEL not equal to N: N, NEL =',n,nel
9211 CALL mumps_abort()
9212 ENDIF
9213 IF (me.NE. listvar_schur(1)) THEN
9214C -- Set all node in Schur list to point to LISTVAR_SCHUR(1)
9215 DO i=1, size_schur_loc
9216 pe(listvar_schur(i)) = int(-listvar_schur(1),8)
9217 ENDDO
9218 pe(listvar_schur(1)) = 0_8
9219 nv( listvar_schur(1))= nv(me)
9220 nv(me) = 0
9221 elen( listvar_schur(1)) = elen(me)
9222 elen(me) = 0
9223 ENDIF
9224 GOTO 265
9225 ENDIF
9226 ENDIF
9227C -------------------------------------------------------------
9228C me represents the elimination of pivots nel+1 to nel+nv(me).
9229C place me itself as the first in this set. It will be moved
9230C to the nel+nv(me) position when the permutation vectors are
9231C computed.
9232C -------------------------------------------------------------
9233 elenme = elen(me)
9234 elen(me) = - (nel + 1)
9235 nvpiv = nv(me)
9236 nel = nel + nvpiv
9237 ndense(me) = 0
9238C=======================================================================
9239C CONSTRUCT NEW ELEMENT
9240C=======================================================================
9241C -------------------------------------------------------------
9242C At this point, me is the pivotal supervariable. It will be
9243C converted into the current element. Scan list of the
9244C pivotal supervariable, me, setting tree pointers and
9245C constructing new list of supervariables for the new element,
9246C me. p is a pointer to the current position in the old list.
9247C -------------------------------------------------------------
9248C flag the variable "me" as being in Lme by negating nv (me)
9249 nv(me) = -nvpiv
9250 degme = 0
9251 IF (elenme .EQ. 0) THEN
9252C ----------------------------------------------------------
9253C construct the new element in place
9254C ----------------------------------------------------------
9255 pme1 = pe(me)
9256 pme2 = pme1 - 1
9257 DO 60 p = pme1, pme1 + int(len(me) - 1,8)
9258 i = iw(p)
9259 nvi = nv(i)
9260 IF (nvi .GT. 0) THEN
9261C ----------------------------------------------------
9262C i is a principal variable not yet placed in Lme.
9263C store i in new list
9264C ----------------------------------------------------
9265 degme = degme + nvi
9266C flag i as being in Lme by negating nv (i)
9267 nv(i) = -nvi
9268 pme2 = pme2 + 1
9269 iw(pme2) = i
9270C ----------------------------------------------------
9271C remove variable i from degree list.
9272C ----------------------------------------------------
9273C only done for non "dense" rows
9274 IF (degree(i).LE.totel) THEN
9275 ilast = last(i)
9276 inext = next(i)
9277 IF (inext .NE. 0) last(inext) = ilast
9278 IF (ilast .NE. 0) THEN
9279 next(ilast) = inext
9280 ELSE
9281C i is at the head of the degree list
9282 head(perm(i)) = inext
9283 ENDIF
9284 ELSE
9285 ndense(me) = ndense(me) + nvi
9286 ENDIF
9287 ENDIF
9288 60 CONTINUE
9289C this element takes no new memory in iw:
9290 newmem = 0
9291 ELSE
9292C ----------------------------------------------------------
9293C construct the new element in empty space, iw (pfree ...)
9294C ----------------------------------------------------------
9295 p = pe(me)
9296 pme1 = pfree
9297 slenme = len (me) - elenme
9298 knt1_updated = 0
9299 DO 120 knt1 = 1, elenme + 1
9300 knt1_updated = knt1_updated +1
9301 IF (knt1 .GT. elenme) THEN
9302C search the supervariables in me.
9303 e = me
9304 pj = p
9305 ln = slenme
9306 ELSE
9307C search the elements in me.
9308 e = iw(p)
9309 p = p + 1
9310 pj = pe(e)
9311 ln = len(e)
9312 ENDIF
9313C -------------------------------------------------------
9314C search for different supervariables and add them to the
9315C new list, compressing when necessary. this loop is
9316C executed once for each element in the list and once for
9317C all the supervariables in the list.
9318C -------------------------------------------------------
9319 knt2_updated = 0
9320 DO 110 knt2 = 1, ln
9321 knt2_updated = knt2_updated+1
9322 i = iw(pj)
9323 pj = pj + 1
9324 nvi = nv(i)
9325 IF (nvi .GT. 0) THEN
9326C -------------------------------------------------
9327C compress iw, if necessary
9328C -------------------------------------------------
9329 IF (pfree .GT. iwlen) THEN
9330C prepare for compressing iw by adjusting
9331C pointers and lengths so that the lists being
9332C searched in the inner and outer loops contain
9333C only the remaining entries.
9334 pe(me) = p
9335 len(me) = len(me) - knt1_updated
9336C Reset KNT1_UPDATED in case of recompress
9337C at same iteration of the loop 120
9338 knt1_updated = 0
9339C Check if anything left in supervariable ME
9340 IF (len(me) .EQ. 0) pe(me) = 0
9341 pe(e) = pj
9342 len(e) = ln - knt2_updated
9343C Reset KNT2_UPDATED in case of recompress
9344C at same iteration of the loop 110
9345 knt2_updated = 0
9346C Check if anything left in element E
9347 IF (len(e) .EQ. 0) pe(e) = 0
9348 ncmpa = ncmpa + 1
9349C store first item in pe
9350C set first entry to -item
9351 DO 70 j = 1, n
9352 pn = pe(j)
9353 IF (pn .GT. 0) THEN
9354 pe(j) = int(iw(pn),8)
9355 iw(pn) = -j
9356 ENDIF
9357 70 CONTINUE
9358C psrc/pdst point to source/destination
9359 pdst = 1
9360 psrc = 1
9361 pend = pme1 - 1
9362C while loop:
9363 80 CONTINUE
9364 IF (psrc .LE. pend) THEN
9365C search for next negative entry
9366 j = -iw(psrc)
9367 psrc = psrc + 1
9368 IF (j .GT. 0) THEN
9369 iw(pdst) = int(pe(j))
9370 pe(j) = pdst
9371 pdst = pdst + 1
9372C copy from source to destination
9373 lenj = len(j)
9374 DO 90 knt3 = 0, lenj - 2
9375 iw(pdst + knt3) = iw(psrc + knt3)
9376 90 CONTINUE
9377 pdst = pdst + lenj - 1
9378 psrc = psrc + lenj - 1
9379 ENDIF
9380 GO TO 80
9381 ENDIF
9382C move the new partially-constructed element
9383 p1 = pdst
9384 DO 100 psrc = pme1, pfree - 1
9385 iw(pdst) = iw(psrc)
9386 pdst = pdst + 1
9387 100 CONTINUE
9388 pme1 = p1
9389 pfree = pdst
9390 pj = pe(e)
9391 p = pe(me)
9392 ENDIF
9393C -------------------------------------------------
9394C i is a principal variable not yet placed in Lme
9395C store i in new list
9396C -------------------------------------------------
9397 degme = degme + nvi
9398C flag i as being in Lme by negating nv (i)
9399 nv(i) = -nvi
9400 iw(pfree) = i
9401 pfree = pfree + 1
9402C -------------------------------------------------
9403C remove variable i from degree link list
9404C -------------------------------------------------
9405C only done for non "dense" rows
9406 IF (degree(i).LE.totel) THEN
9407 ilast = last(i)
9408 inext = next(i)
9409 IF (inext .NE. 0) last(inext) = ilast
9410 IF (ilast .NE. 0) THEN
9411 next(ilast) = inext
9412 ELSE
9413C i is at the head of the degree list
9414 head(perm(i)) = inext
9415 ENDIF
9416 ELSE
9417 ndense(me) = ndense(me) + nvi
9418 ENDIF
9419 ENDIF
9420 110 CONTINUE
9421 IF (e .NE. me) THEN
9422C set tree pointer and flag to indicate element e is
9423C absorbed into new element me (the parent of e is me)
9424 pe(e) = int(-me,8)
9425 w(e) = 0
9426 ENDIF
9427 120 CONTINUE
9428 pme2 = pfree - 1
9429C this element takes newmem new memory in iw (possibly zero)
9430 newmem = pfree - pme1
9431 mem = mem + newmem
9432 maxmem = max (maxmem, mem)
9433 ENDIF
9434C -------------------------------------------------------------
9435C me has now been converted into an element in iw (pme1..pme2)
9436C -------------------------------------------------------------
9437C degme holds the external degree of new element
9438 degree(me) = degme
9439 pe(me) = pme1
9440 len(me) = int(pme2 - pme1 + 1_8)
9441C -------------------------------------------------------------
9442C make sure that wflg is not too large. With the current
9443C value of wflg, wflg+n must not cause integer overflow
9444C -------------------------------------------------------------
9445 IF (wflg .GT. maxint_n) THEN
9446 DO 130 x = 1, n
9447 IF (w(x) .NE. 0) w(x) = 1
9448 130 CONTINUE
9449 wflg = 2
9450 ENDIF
9451C=======================================================================
9452C COMPUTE (w (e) - wflg) = |Le\Lme| FOR ALL ELEMENTS
9453Cdense
9454C COMPUTE (w(e) - wflg) = |Le(G')\Lme(G')| FOR ALL ELEMENTS
9455C where G' is the subgraph of G excluding ''dense" rows)
9456Cdense
9457C=======================================================================
9458C -------------------------------------------------------------
9459C Scan 1: compute the external degrees of previous elements
9460C with respect to the current element. That is:
9461C (w (e) - wflg) = |Le \ Lme|
9462C for each element e that appears in any supervariable in Lme.
9463C The notation Le refers to the pattern (list of
9464C supervariables) of a previous element e, where e is not yet
9465C absorbed, stored in iw (pe (e) + 1 ... pe (e) + iw (pe (e))).
9466C The notation Lme refers to the pattern of the current element
9467C (stored in iw (pme1..pme2)). If (w (e) - wflg) becomes
9468C zero, then the element e will be absorbed in scan 2.
9469C aggressive absorption is possible only if NDENSE(ME) = NBD
9470C which is true when only exactly dense rows have been selected.
9471C -------------------------------------------------------------
9472 DO 150 pme = pme1, pme2
9473 i = iw(pme)
9474 IF (degree(i).GT.totel) GOTO 150
9475 eln = elen(i)
9476 IF (eln .GT. 0) THEN
9477C note that nv (i) has been negated to denote i in Lme:
9478 nvi = -nv(i)
9479 wnvi = wflg - nvi
9480 DO 140 p = pe(i), pe(i) + int(eln - 1,8)
9481 e = iw(p)
9482 we = w(e)
9483 IF (we .GE. wflg) THEN
9484C unabsorbed element e has been seen in this loop
9485 we = we - nvi
9486 ELSE IF (we .NE. 0) THEN
9487C e is an unabsorbed element
9488C this is the first we have seen e in all of Scan 1
9489 we = degree(e) + wnvi - ndense(e)
9490Cn dense
9491 ENDIF
9492 w(e) = we
9493 140 CONTINUE
9494 ENDIF
9495 150 CONTINUE
9496C=======================================================================
9497C DEGREE UPDATE AND ELEMENT ABSORPTION
9498C=======================================================================
9499C -------------------------------------------------------------
9500C Scan 2: for each i in Lme, sum up the degree of Lme (which
9501C is degme), plus the sum of the external degrees of each Le
9502C for the elements e appearing within i, plus the
9503C supervariables in i. Place i in hash list.
9504C -------------------------------------------------------------
9505 agg6_loc = (agg6 .OR. (degree(me) .LT. thd_agg))
9506 DO 180 pme = pme1, pme2
9507 i = iw(pme)
9508 IF (degree(i).GT.totel) GOTO 180
9509 p1 = pe(i)
9510 p2 = p1 + int(elen (i) - 1,8)
9511 pn = p1
9512 hash = 0_8
9513 deg = 0
9514C ----------------------------------------------------------
9515C scan the element list associated with supervariable i
9516C ----------------------------------------------------------
9517 DO 160 p = p1, p2
9518 e = iw(p)
9519C dext = | Le \ Lme |
9520 dext = w(e) - wflg
9521 IF (dext .GT. 0) THEN
9522 deg = deg + dext
9523 iw(pn) = e
9524 pn = pn + 1_8
9525 hash = hash + int(e,kind=8)
9526C ------------------------------
9527C suppress aggressive absorption
9528C ------------------------------
9529 ELSE IF (.NOT. agg6_loc .AND. dext .EQ. 0) THEN
9530 iw (pn) = e
9531 pn = pn + 1_8
9532 hash = hash + int(e,kind=8)
9533C
9534C ------------------------------
9535C try aggressive absorption
9536C when possible
9537 ELSE IF (agg6_loc .AND. (dext .EQ. 0) .AND.
9538 & ((ndense(me).EQ.nbd).OR.(ndense(e).EQ.0))) THEN
9539C aggressive absorption: e is not adjacent to me, but
9540C |Le(G') \ Lme(G')| is 0 and all dense rows
9541C are in me, so absorb it into me
9542 pe(e) = int(-me,8)
9543 w(e) = 0
9544 ELSE IF (agg6_loc .AND. dext.EQ.0) THEN
9545 iw(pn) = e
9546 pn = pn+1
9547 hash = hash + int(e,kind=8)
9548 ENDIF
9549 160 CONTINUE
9550C count the number of elements in i (including me):
9551 elen(i) = int(pn - p1 + 1)
9552C ----------------------------------------------------------
9553C scan the supervariables in the list associated with i
9554C ----------------------------------------------------------
9555 p3 = pn
9556 DO 170 p = p2 + 1, p1 + int(len(i) - 1,8)
9557 j = iw(p)
9558 nvj = nv(j)
9559 IF (nvj .GT. 0) THEN
9560C j is unabsorbed, and not in Lme.
9561C add to degree and add to new list
9562C add degree only of non-dense rows.
9563 IF (degree(j).LE.totel) deg=deg+nvj
9564 iw(pn) = j
9565 pn = pn + 1
9566 hash = hash + int(j,kind=8)
9567 ENDIF
9568 170 CONTINUE
9569C ----------------------------------------------------------
9570C update the degree and check for mass elimination
9571C ----------------------------------------------------------
9572 IF (((elen(i).EQ.1).AND.(p3.EQ.pn))
9573 & .OR.
9574 & (agg6_loc.AND.(deg .EQ. 0).AND.(ndense(me).EQ.nbd))
9575 & )
9576 & THEN
9577C -------------------------------------------------------
9578C mass elimination
9579C -------------------------------------------------------
9580C There is nothing left of this node except for an
9581C edge to the current pivot element. elen (i) is 1,
9582C and there are no variables adjacent to node i.
9583C Absorb i into the current pivot element, me.
9584 pe(i) = int(-me,8)
9585 nvi = -nv(i)
9586 degme = degme - nvi
9587 nvpiv = nvpiv + nvi
9588 nel = nel + nvi
9589 nv(i) = 0
9590 elen(i) = 0
9591 ELSE
9592C -------------------------------------------------------
9593C update the upper-bound degree of i
9594C -------------------------------------------------------
9595C the following degree does not yet include the size
9596C of the current element, which is added later:
9597 degree(i) = min(deg+nbd-ndense(me),
9598 & degree(i))
9599C -------------------------------------------------------
9600C add me to the list for i
9601C -------------------------------------------------------
9602C move first supervariable to end of list
9603 iw(pn) = iw(p3)
9604C move first element to end of element part of list
9605 iw(p3) = iw(p1)
9606C add new element to front of list.
9607 iw(p1) = me
9608C store the new length of the list in len (i)
9609 len(i) = int(pn - p1 + 1)
9610C -------------------------------------------------------
9611C place in hash bucket. Save hash key of i in last (i).
9612C -------------------------------------------------------
9613 hash = mod(hash, hmod) + 1_8
9614 j = head(hash)
9615 IF (j .LE. 0) THEN
9616C the degree list is empty, hash head is -j
9617 next(i) = -j
9618 head(hash) = -i
9619 ELSE
9620C degree list is not empty
9621C use last (head (hash)) as hash head
9622 next(i) = last(j)
9623 last(j) = i
9624 ENDIF
9625 last(i) = int(hash,kind=kind(last))
9626 ENDIF
9627 180 CONTINUE
9628 degree(me) = degme
9629C -------------------------------------------------------------
9630C Clear the counter array, w (...), by incrementing wflg.
9631C -------------------------------------------------------------
9632 dmax = max(dmax, degme)
9633 wflg = wflg + dmax
9634C make sure that wflg+n does not cause integer overflow
9635 IF (wflg .GT. maxint_n) THEN
9636 DO 190 x = 1, n
9637 IF (w(x) .NE. 0) w(x) = 1
9638 190 CONTINUE
9639 wflg = 2
9640 ENDIF
9641C at this point, w (1..n) .lt. wflg holds
9642C=======================================================================
9643C SUPERVARIABLE DETECTION
9644C=======================================================================
9645 DO 250 pme = pme1, pme2
9646 i = iw(pme)
9647 IF ( (nv(i).LT.0) .AND. (degree(i).LE.totel) ) THEN
9648C only done for nondense rows
9649C i is a principal variable in Lme
9650C -------------------------------------------------------
9651C examine all hash buckets with 2 or more variables. We
9652C do this by examing all unique hash keys for super-
9653C variables in the pattern Lme of the current element, me
9654C -------------------------------------------------------
9655 hash = int(last(i),kind=8)
9656C let i = head of hash bucket, and empty the hash bucket
9657 j = head(hash)
9658 IF (j .EQ. 0) GO TO 250
9659 IF (j .LT. 0) THEN
9660C degree list is empty
9661 i = -j
9662 head(hash) = 0
9663 ELSE
9664C degree list is not empty, restore last () of head
9665 i = last(j)
9666 last(j) = 0
9667 ENDIF
9668 IF (i .EQ. 0) GO TO 250
9669C while loop:
9670 200 CONTINUE
9671 IF (next(i) .NE. 0) THEN
9672 x = i
9673C ----------------------------------------------------
9674C this bucket has one or more variables following i.
9675C scan all of them to see if i can absorb any entries
9676C that follow i in hash bucket. Scatter i into w.
9677C ----------------------------------------------------
9678 ln = len(i)
9679 eln = elen(i)
9680C do not flag the first element in the list (me)
9681 DO 210 p = pe(i) + 1, pe(i) + int(ln - 1,8)
9682 w(iw(p)) = wflg
9683 210 CONTINUE
9684C ----------------------------------------------------
9685C scan every other entry j following i in bucket
9686C ----------------------------------------------------
9687 jlast = i
9688 j = next(i)
9689C while loop:
9690 220 CONTINUE
9691 IF (j .NE. 0) THEN
9692C -------------------------------------------------
9693C check if j and i have identical nonzero pattern
9694C -------------------------------------------------
9695C jump if i and j do not have same size data structure
9696 IF (len(j) .NE. ln) GO TO 240
9697C jump if i and j do not have same number adj elts
9698 IF (elen(j) .NE. eln) GO TO 240
9699C do not flag the first element in the list (me)
9700 DO 230 p = pe(j) + 1, pe(j) + int(ln - 1,8)
9701C jump if an entry (iw(p)) is in j but not in i
9702 IF (w(iw(p)) .NE. wflg) GO TO 240
9703 230 CONTINUE
9704C -------------------------------------------------
9705C found it! j can be absorbed into i
9706C -------------------------------------------------
9707 IF (perm(j).GT.perm(x)) THEN
9708 ! J is absorbed by X
9709 pe(j) = int(-x,8)
9710 nv(x) = nv(x) + nv(j)
9711 nv(j) = 0
9712 elen(j) = 0
9713 ELSE
9714 ! X is absorbed by J
9715 pe(x) = int(-j,8)
9716 nv(j) = nv(x) + nv(j)
9717 nv(x) = 0
9718 elen(x) = 0
9719 x = j
9720 ENDIF
9721C both nv (i) and nv (j) are negated since they
9722C are in Lme, and the absolute values of each
9723C are the number of variables in i and j:
9724C delete j from hash bucket
9725 j = next(j)
9726 next(jlast) = j
9727 GO TO 220
9728C -------------------------------------------------
9729 240 CONTINUE
9730C j cannot be absorbed into i
9731C -------------------------------------------------
9732 jlast = j
9733 j = next(j)
9734 GO TO 220
9735 ENDIF
9736C ----------------------------------------------------
9737C no more variables can be absorbed into i
9738C go to next i in bucket and clear flag array
9739C ----------------------------------------------------
9740 wflg = wflg + 1
9741 i = next(i)
9742 IF (i .NE. 0) GO TO 200
9743 ENDIF
9744 ENDIF
9745 250 CONTINUE
9746C=======================================================================
9747C RESTORE DEGREE LISTS AND REMOVE NONPRINCIPAL SUPERVAR. FROM ELEMENT
9748C=======================================================================
9749C ------------------------------
9750C Update thresm for having more
9751C quasi dense rows to select
9752C ------------------------------
9753 IF ( .NOT.denserows.AND.(thresm .GT. 0).AND.(thresm.LT.n) )
9754 & THEN
9755 thresm = max(thresmin, thresm-nvpiv)
9756 ENDIF
9757 p = pme1
9758 nleft = totel - nel
9759 DO 260 pme = pme1, pme2
9760 i = iw(pme)
9761 nvi = -nv(i)
9762 IF (nvi .GT. 0) THEN
9763C i is a principal variable in Lme
9764C restore nv (i) to signify that i is principal
9765 nv(i) = nvi
9766 IF (degree(i).LE.totel) THEN
9767C -------------------------------------------------------
9768C compute the external degree (add size of current elem)
9769C -------------------------------------------------------
9770 deg = min(degree(i)+ degme - nvi, nleft - nvi)
9771 degree(i) = deg
9772 idense = .false.
9773C
9774C -------------------
9775C Dense row detection
9776C -------------------
9777 IF (thresm.GT.0) THEN
9778 IF (perm(i) .GT. thresm) THEN
9779C relaxed dense row detection
9780 idense = .true.
9781C
9782 degree(i) = degree(i)+totel+2
9783 ENDIF
9784 IF (idense) THEN
9785C update NDENSE of all elements in the list of element
9786C adjacent to I (including ME).
9787 p1 = pe(i)
9788 p2 = p1 + int(elen(i) - 1,8)
9789 IF (p2.GE.p1) THEN
9790 DO 264 pj=p1,p2
9791 e= iw(pj)
9792 ndense(e) = ndense(e) + nvi
9793 264 CONTINUE
9794 ENDIF
9795C insert I in the list of dense rows
9796 nbd = nbd+nvi
9797 fdeg = n
9798 deg = n
9799C insert I at the beginning of the list
9800 inext = head(deg)
9801 IF (inext .NE. 0) last(inext) = i
9802 next(i) = inext
9803 head(deg) = i
9804 last(i) = 0
9805 IF (lastd.EQ.0) lastd=i
9806C end of IDENSE=true
9807 ENDIF
9808C end of THRESM>0
9809 ENDIF
9810C
9811 IF (.NOT.idense) THEN
9812 fdeg = perm(i)
9813C -------------------------------------------------------
9814C place the supervariable at the head of the degree list
9815C -------------------------------------------------------
9816 inext = head(fdeg)
9817 IF (inext .NE. 0) last(inext) = i
9818 next(i) = inext
9819 last(i) = 0
9820 head(fdeg) = i
9821 ENDIF
9822C -------------------------------------------------------
9823C save the new degree, and find the minimum degree
9824C -------------------------------------------------------
9825 mindeg = min(mindeg, fdeg)
9826 ENDIF
9827C -------------------------------------------------------
9828C place the supervariable in the element pattern
9829C -------------------------------------------------------
9830 iw(p) = i
9831 p = p + 1
9832 ENDIF
9833 260 CONTINUE
9834C=======================================================================
9835C FINALIZE THE NEW ELEMENT
9836C=======================================================================
9837 nv(me) = nvpiv + degme
9838C nv (me) is now the degree of pivot (including diagonal part)
9839C save the length of the list for the new element me
9840 len(me) = int(p - pme1)
9841 IF (len(me) .EQ. 0) THEN
9842C there is nothing left of the current pivot element
9843 pe(me) = 0_8
9844 w(me) = 0
9845 ENDIF
9846 IF (newmem .NE. 0) THEN
9847C element was not constructed in place: deallocate part
9848C of it (final size is less than or equal to newmem,
9849C since newly nonprincipal variables have been removed).
9850 pfree = p
9851 mem = mem - newmem + int(len(me),8)
9852 ENDIF
9853C=======================================================================
9854C END WHILE (selecting pivots)
9855 GO TO 30
9856 ENDIF
9857C=======================================================================
9858 265 CONTINUE
9859C=======================================================================
9860C COMPUTE THE PERMUTATION VECTORS
9861C=======================================================================
9862C ----------------------------------------------------------------
9863C The time taken by the following code is O(n). At this
9864C point, elen (e) = -k has been done for all elements e,
9865C and elen (i) = 0 has been done for all nonprincipal
9866C variables i. At this point, there are no principal
9867C supervariables left, and all elements are absorbed.
9868C ----------------------------------------------------------------
9869C ----------------------------------------------------------------
9870C compute the ordering of unordered nonprincipal variables
9871C ----------------------------------------------------------------
9872 DO 290 i = 1, n
9873 IF (elen(i) .EQ. 0) THEN
9874C ----------------------------------------------------------
9875C i is an un-ordered row. Traverse the tree from i until
9876C reaching an element, e. The element, e, was the
9877C principal supervariable of i and all nodes in the path
9878C from i to when e was selected as pivot.
9879C ----------------------------------------------------------
9880 j = int(-pe(i))
9881C while (j is a variable) do:
9882 270 CONTINUE
9883 IF (elen(j) .GE. 0) THEN
9884 j = int(-pe(j))
9885 GO TO 270
9886 ENDIF
9887 e = j
9888C ----------------------------------------------------------
9889C get the current pivot ordering of e
9890C ----------------------------------------------------------
9891 k = -elen(e)
9892C ----------------------------------------------------------
9893C traverse the path again from i to e, and compress the
9894C path (all nodes point to e). Path compression allows
9895C this code to compute in O(n) time. Order the unordered
9896C nodes in the path, and place the element e at the end.
9897C ----------------------------------------------------------
9898 j = i
9899C while (j is a variable) do:
9900 280 CONTINUE
9901 IF (elen(j) .GE. 0) THEN
9902 jnext = int(-pe(j))
9903 pe(j) = int(-e,8)
9904 IF (elen(j) .EQ. 0) THEN
9905C j is an unordered row
9906 elen(j) = k
9907 k = k + 1
9908 ENDIF
9909 j = jnext
9910 GO TO 280
9911 ENDIF
9912C leave elen (e) negative, so we know it is an element
9913 elen(e) = -k
9914 ENDIF
9915 290 CONTINUE
9916C ----------------------------------------------------------------
9917C reset the inverse permutation (elen (1..n)) to be positive,
9918C and compute the permutation (last (1..n)).
9919C ----------------------------------------------------------------
9920 DO 300 i = 1, n
9921 k = abs(elen(i))
9922C LAST (K) = I
9923C LAST (K) = I
9924 elen(i) = k
9925 300 CONTINUE
9926 IF (.NOT.schuron) THEN
9927C -----------------------------
9928C restore PERM(I)=N for PERMeqN
9929C -----------------------------
9930 perm(permeqn) = n
9931 ENDIF
9932C=======================================================================
9933C RETURN THE MEMORY USAGE IN IW
9934C=======================================================================
9935C If maxmem is less than or equal to iwlen, then no compressions
9936C occurred, and iw (maxmem+1 ... iwlen) was unused. Otherwise
9937C compressions did occur, and iwlen would have had to have been
9938C greater than or equal to maxmem for no compressions to occur.
9939C Return the value of maxmem in the pfree argument.
9940 pfree = maxmem
9941C===============================
9942C Save PE in PARENT array
9943 DO i=1,n
9944 parent(i) = int(pe(i))
9945 ENDDO
9946C===============================
9947 RETURN
9948 END SUBROUTINE mumps_symqamd
#define mumps_abort
Definition VE_Metis.h:25
subroutine mumps_qamd(totel, compute_perm, iversion, thresh, ndense, n, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, head, next, w, parent)
subroutine mumps_ana_h(totel, compute_perm, n, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, head, next, w, parent)
subroutine mumps_symqamd(thresh, ndense, n, totel, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, head, next, w, perm, listvar_schur, size_schur, agg6, parent)
subroutine mumps_cst_amf(n, nbbuck, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, wf, next, w, head, constraint, theson, parent)
subroutine mumps_hamd(n, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, head, next, w, parent, listvar_schur, size_schur)
subroutine mumps_amd_elt(n, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, head, next, w, parent)
subroutine mumps_hamf4(norig, n, compute_perm, nbbuck, iwlen, pe, pfree, len, iw, nv, elen, last, ncmpa, degree, wf, next, w, head, parent)
#define min(a, b)
Definition macros.h:20
#define max(a, b)
Definition macros.h:21