source: trunk/SOURCES/reduc.f @ 23

Last change on this file since 23 was 4, checked in by dumas, 10 years ago

initial import GRISLI trunk

File size: 90.1 KB
Line 
1C
2C     ALGORITHM APPEARED IN ACM-TRANS. MATH. SOFTWARE, VOL.8, NO. 2,
3C     JUN., 1982, P. 190.
4C     ==============================================================
5C
6C     GIBBS-POOLE-STOCKMEYER AND GIBBS-KING ALGORITHMS ...
7C
8C     1.  SUBROUTINES  GPSKCA, GPSKCB, ..., GPSKCQ  WHICH IMPLEMENT
9C         GIBBS-POOLE-STOCKMEYER AND GIBBS-KING ALGORITHMS ...
10C
11C     2.  SAMPLE DRIVER PROGRAM
12C
13C     3.  SAMPLE TEST PROBLEMS
14C
15C     4.  OUTPUT PRODUCED BY SAMPLE DRIVER ON SAMPLE TEST PROBLEMS
16C
17C     ALL OF THE ABOVE ARE IN 80 COLUMN FORMAT.  THE FIRST TWO
18C     SECTIONS HAVE SEQUENCE NUMBERS IN COLUMNS 73 TO 80.  THE
19C     THIRD SECTION HAS DATA IN ALL 80 COLUMNS.  THE LAST SECTION
20C     HAS CARRIAGE CONTROL CHARACTERS IN COLUMN 1 AND DATA IN ALL
21C     80 COLUMNS.
22C
23C     THESE FOUR SECTIONS OF THE FILE ARE SEPARATED BY SINGLE CARDS
24C     OF THE FORM  'C === SEPARATOR ===' IN COLUMNS 1 TO 19
25C
26C     ==============================================================
27C
28C     THE SAMPLE TEST PROBLEMS INCLUDED WITH THIS CODE PROVIDE A
29C     MINIMAL CHECKOUT OF THE FUNCTIONING OF THE CODE.  THE TEST
30C     PROBLEMS HAVE NUMERICAL VALUES WITH THE INTEGER PART BEING
31C     THE ROW INDEX, THE FRACTIONAL PART THE COLUMN INDEX, OF THE
32C     MATRIX AFTER GPS(K) REORDERING.  THE TEST OUTPUT INCLUDES A
33C     LISTING OF THE REORDERED MATRIX, IN WHICH THE NUMERIC VALUES
34C     SHOULD APPEAR IN CORRECT POSITIONS, INTERMINGLED WITH ZEROES
35C     WHICH REPRESENT FILL IN THE SPARSE MATRIX FACTORIZATION.
36C
37C     ==============================================================
38C
39C === SEPARATOR ===  BEGINNING OF GPS AND GK ALGORITHMS
40      SUBROUTINE   GPSKCA   (N, DEGREE, RSTART, CONNEC, OPTPRO, WRKLEN, GPSKCA 1
41     1                       PERMUT, WORK, BANDWD, PROFIL, ERROR, SPACE)
42C
43C     ==================================================================
44C     ==================================================================
45C     =                                                                =
46C     = B A N D W I D T H    OR    P R O F I L E    R E D U C T I O N  =
47C     =        FOR A SPARSE AND (STRUCTURALLY) SYMMETRIC MATRIX,       =
48C     =                         USING EITHER                           =
49C     =                                                                =
50C     =   THE GIBBS-POOLE-STOCKMEYER ALGORITHM (BANDWIDTH REDUCTION)   =
51C     =                               OR                               =
52C     =          THE GIBBS-KING ALGORITHM (PROFILE REDUCTION)          =
53C     =                                                                =
54C     ==================================================================
55C     ==================================================================
56C     =     THIS CODE SUPERSEDES TOMS ALGORITHMS 508 AND 509 IN THE    =
57C     =     COLLECTED ALGORITHMS OF THE ACM (CALGO).                   =
58C     ==================================================================
59C     ==================================================================
60C
61C     -------------------
62C     P A R A M E T E R S
63C     -------------------
64C
65      INTEGER     N, RSTART(N), WRKLEN, BANDWD, PROFIL, ERROR, SPACE
66C
67CIBM  INTEGER *2  DEGREE(N), CONNEC(1), PERMUT(N), WORK(WRKLEN)
68      INTEGER     DEGREE(N), CONNEC(1), PERMUT(N), WORK(WRKLEN)
69C
70      LOGICAL     OPTPRO
71C
72C     ------------------------------------------------------------------
73C
74C     INPUT PARAMETERS:
75C     ----- ----------
76C
77C         N      -- THE DIMENSION OF THE MATRIX
78C
79C         DEGREE,
80C         RSTART,
81C         CONNEC -- DESCRIBE THE STRUCTURE OF THE SPARSE MATRIX.
82C                   DEGREE(I) SPECIFIES THE NUMBER OF NON-ZERO
83C                   OFF-DIAGONAL ENTRIES IN THE  I-TH  ROW OF THE
84C                   SPARSE MATRIX.  THE COLUMN INDICES OF THESE
85C                   ENTRIES ARE GIVEN IN CONSECUTIVE LOCATIONS IN
86C                   CONNEC, STARTING AT LOCATION  RSTART(I).
87C                   IN OTHER WORDS, THE INDICES OF THE NON-ZERO
88C                   OFF-DIAGONAL ELEMENTS OF THE  I-TH  ROW ARE FOUND
89C                   IN:
90C                       CONNEC (RSTART(I)),
91C                       CONNEC (RSTART(I) + 1),
92C                                . . .
93C                       CONNEC (RSTART(I) + DEGREE(I) - 1)
94C
95C                   DIMENSIONS:
96C                       RSTART IS DIMENSION  N  (OR LONGER).
97C                       DEGREE IS DIMENSION  N  (OR LONGER).
98C                       CONNEC IS DIMENSION ROUGHLY THE NUMBER OF NON-
99C                              ZERO ENTRIES IN THE MATRIX.
100C
101C         OPTPRO -- .TRUE. IF REDUCING THE PROFILE OF THE MATRIX
102C                          IS MORE IMPORTANT THAN REDUCING THE
103C                          BANDWIDTH
104C                   .FALSE. IF BANDWIDTH REDUCTION IS MOST IMPORTANT
105C
106C         WRKLEN -- THE  ACTUAL  LENGTH OF THE VECTOR  WORK  AS SUPPLIED
107C                   BY THE USER.  SEE THE DISCUSSION OF THE WORKSPACE
108C                   'WORK'  BELOW FOR TYPICAL STORAGE REQUIREMENTS.
109C                   THE VALUE OF  WRKLEN  WILL BE USED TO ENSURE THAT
110C                   THE ROUTINE WILL NOT USE MORE STORAGE THAN IS
111C                   AVAILABLE.  IF NOT ENOUGH SPACE IS GIVEN IN  WORK
112C                   TO PERMIT A SOLUTION TO BE FOUND, THE  ERROR  FLAG
113C                   WILL BE SET AND FURTHER COMPUTATION STOPPED.
114C
115C
116C     INPUT AND OUTPUT PARAMETER:
117C     ----- --- ------ ---------
118C
119C         PERMUT -- ON INPUT, AN ALTERNATIVE REORDERING FOR THE
120C                   ROWS AND COLUMNS OF THE MATRIX.  PERMUT(I) GIVES
121C                   THE POSITION IN WHICH ROW AND COLUMN  I  SHOULD
122C                   BE PLACED TO REDUCE THE BANDWIDTH OR THE PROFILE.
123C                   IF THE USER HAS NO ALTERNATIVE TO THE NATURAL
124C                   ORDERING IMPLICIT IN  DEGREE,  RSTART  AND  CONNEC,
125C                   HE SHOULD INITIALIZE  PERMUT  TO BE THE IDENTITY
126C                   PERMUTATION  PERMUT(I) = I .
127C
128C                   ON OUTPUT,  PERMUT  WILL CONTAIN THE PERMUTATION
129C                   FOR REORDERING THE ROWS AND COLUMNS WHICH REDUCES
130C                   THE BANDWIDTH AND/OR PROFILE.  THE RESULT WILL BE
131C                   THE REORDERING FOUND BY 'GPSKCA' OR THE REORDERING
132C                   GIVEN BY THE USER IN 'PERMUT', WHICHEVER DOES THE
133C                   JOB BETTER.
134C
135C
136C     OUTPUT PARAMETERS:
137C     ------ ----------
138C
139C         WORK   -- A TEMPORARY STORAGE VECTOR, OF LENGTH SOMEWHAT
140C                   GREATER THAN  3N.  THE SPACE BEYOND  3N  REQUIRED
141C                   IS PROBLEM-DEPENDENT.  ANY PROBLEM CAN BE SOLVED
142C                   IN  6N+3  LOCATIONS.
143C                   MOST PROBLEMS CAN BE REORDERED WITH  4N  LOCATIONS
144C                   IN 'WORK'.  IF SPACE IS NOT A CONSTRAINT, PROVIDE
145C                   6N+3  LOCATIONS IN 'WORK'.  OTHERWISE, PROVIDE AS
146C                   MUCH MORE THAN  3N  AS IS CONVENIENT AND CHECK THE
147C                   ERROR FLAG AND SPACE REQUIRED PARAMETERS (SEE BELOW)
148C
149C                   ON OUTPUT, THE 1ST  N  LOCATIONS OF WORK WILL BE
150C                   A LISTING OF THE ORIGINAL ROW AND COLUMN INDICES AS
151C                   THEY APPEAR IN THE COMPUTED REORDERING.
152C                   LOCATIONS  N+1, ... , 2N  OF  WORK  WILL CONTAIN
153C                   THE NEW POSITIONS FOR THE EQUATIONS IN THE ORDER
154C                   FOUND BY GPSKCA.  THUS, THE TWO VECTORS ARE INVERSE
155C                   PERMUTATIONS OF EACH OTHER.  IF THE ORDERING
156C                   FOUND BY THIS ALGORITHM IS BETTER THAN THE USER-
157C                   SUPPLIED ORDER, THE SECOND PERMUTATION VECTOR IS
158C                   IDENTICAL TO THE RESULT RETURNED IN  'PERMUT'.
159C
160C         BANDWD -- THE BANDWIDTH OF THE MATRIX WHEN ROWS AND COLUMNS
161C                   ARE REORDERED IN THE ORDERING RETURNED IN  PERMUT.
162C
163C         PROFIL -- THE PROFILE OF THE MATRIX WHEN ROWS AND COLUMNS ARE
164C                   REORDERED IN THE ORDERING RETURNED IN  PERMUT.
165C
166C         ERROR  -- WILL BE EQUAL TO ZERO IF A NEW NUMBERING COULD BE
167C                   FOUND IN THE SPACE PROVIDED.  OTHERWISE,  ERROR
168C                   WILL BE SET TO A POSITIVE ERROR CODE (SEE TABLE
169C                   GIVEN BELOW).  IF THE REORDERING ALGORITHM HAS BEEN
170C                   STOPPED BY LACK OF WORKSPACE, THE SPACE PARAMETER
171C                   WILL BE SET TO THE NUMBER OF ADDITIONAL LOCATIONS
172C                   REQUIRED TO COMPLETE AT LEAST THE NEXT PHASE OF
173C                   THE ALGORITHM.
174C
175C                   WHENEVER A NON-ZERO VALUE FOR  ERROR  IS GIVEN
176C                   PERMUT  WILL RETAIN THE VALUES PROVIDED BY THE USER
177C                   AND THE SCALARS  BANDWD  AND  PROFIL  WILL BE SET TO
178C                   OUTRAGEOUS VALUES.  IT IS THE USER'S RESPONSIBILITY
179C                   TO CHECK THE STATUS OF  ERROR.
180C
181C         SPACE  -- WILL INDICATE EITHER HOW MUCH SPACE THE REORDERING
182C                   ACTUALLY REQUIRED OR HOW MUCH SPACE WILL BE
183C                   REQUIRED TO COMPLETE THE NEXT PHASE OF THE
184C                   REORDERING ALGORITHM.  THE POSSIBLE OUTCOMES ARE ..
185C
186C                      ERROR = 0          SPACE IS THE MINIMAL VALUE FOR
187C                                         WRKLEN  REQUIRED TO REORDER
188C                                         THIS MATRIX AGAIN.
189C
190C                      ERROR <> 0         SPACE IS THE MINIMUM NUMBER
191C                      DUE TO LACK OF     OF EXTRA WORKSPACE REQUIRED
192C                      WORKSPACE          TO CONTINUE THE REORDERING
193C                                         ALGORITHM ON THIS MATRIX.
194C
195C                      ERROR <> 0         SPACE = -1
196C                      DUE TO ERROR
197C                      IN DATA STRUCTURES
198C
199C
200C     ==================================================================
201C
202C     ----------------------
203C     E R R O R    C O D E S
204C     ----------------------
205C
206C         ERROR CODES HAVE THE FORM  0XY  OR  1XY.
207C
208C         ERRORS OF THE FORM  1XY  RESULT FROM INADEQUATE WORKSPACE.
209C
210C         ERRORS OF THE FORM  0XY  ARE INTERNAL PROGRAM CHECKS, WHICH
211C         MOST LIKELY OCCUR BECAUSE THE CONNECTIVITY STRUCTURE OF THE
212C         MATRIX IS REPRESENTED INCORRECTLY (E.G., THE DEGREE OF
213C         A NODE IS NOT CORRECT  OR  NODE I IS CONNECTED TO NODE J,
214C         BUT NOT CONVERSELY).
215C
216C         THE LAST DIGIT (Y) IS MAINLY USEFUL FOR DEBUGGING THE
217C         THE REORDERING ALGORITHM.  THE MIDDLE DIGIT  (X)  INDICATES
218C         HOW MUCH OF THE ALGORITHM HAS BEEN PERFORMED.
219C         THE TABLE BELOW GIVES THE CORRESPONDENCE BETWEEN THE
220C         VALUES OF  X   AND THE STRUCTURE OF THE ALGORITHM.
221C             X = 0     INITIAL PROCESSING
222C             X = 1     COMPUTING PSEUDO-DIAMETER  (ALGORITHM I)
223C             X = 2     TRANSITION BETWEEN ALGORITHM I AND II
224C             X = 3     COMBINING LEVEL STRUCTURES (ALGORITHM II)
225C             X = 4     TRANSITION BETWEEN ALGORITHM II AND III
226C             X = 5     BANDWIDTH NUMBERING (ALGORITHM IIIA)
227C             X = 6     PROFILE NUMBERING (ALGORITHM IIIB)
228C             X = 7     FINAL BANDWIDTH/PROFILE COMPUTATION
229C
230C     ==================================================================
231C
232C     ---------------------    ---------------
233C     A L T E R N A T I V E    V E R S I O N S
234C     ---------------------    ---------------
235C
236C     SHORT INTEGER VERSION
237C
238C         ON MACHINES WITH TWO OR MORE PRECISIONS FOR INTEGERS,
239C         ALL OF THE INPUT ARRAYS EXCEPT 'RSTART' CAN BE CONVERTED
240C         TO THE SHORTER PRECISION AS LONG AS THAT SHORTER PRECISION
241C         ALLOWS NUMBERS AS LARGE AS 'N'.  A VERSION OF THIS CODE
242C         SUITABLE FOR USE ON IBM COMPUTERS (INTEGER * 2) IS EMBEDDED
243C         AS COMMENTS IN THIS CODE.  ALL SUCH COMMENTS HAVE THE
244C         CHARACTERS 'CIBM' IN THE FIRST FOUR COLUMNS, AND PRECEDE THE
245C         EQUIVALENT STANDARD CODE WHICH THEY WOULD REPLACE.
246C
247C     CONNECTIVITY COMPATIBILITY VERSION
248C
249C         THE ORIGINAL (1976) TOMS CODE  'REDUCE'  USED A LESS STORAGE
250C         EFFICIENT FORMAT FOR THE CONNECTIVITY TABLE  'CONNEC'.
251C         THE 1976 CODE USED A RECTANGULAR MATRIX OF DIMENSIONS
252C         N  BY  MAXDGR,  WHERE  MAXDGR  IS AT LEAST AS LARGE AS
253C         THE MAXIMUM DEGREE OF ANY NODE IN THE GRAPH OF THE MATRIX.
254C         THE FORMAT USED IN THE CURRENT CODE IS OFTEN SUBSTANTIALLY
255C         MORE EFFICIENT.  HOWEVER, FOR USERS FOR WHOM CONVERSION WILL
256C         BE DIFFICULT OR IMPOSSIBLE, TWO ALTERNATIVES ARE ..
257C             1.  SIMPLY NOTE THAT CHANGING THE ORDER OF SUBSCRIPTS
258C                 IN A RECTANGULAR CONNECTION TABLE WILL ENABLE YOU
259C                 TO USE THE NEW VERSION.  THIS SUBROUTINE WILL ACCEPT A
260C                 RECTANGULAR CONNECTION TABLE OF DIMENSIONS
261C                     MAXDGR BY N,
262C                 PROVIDED THAT  RSTART(I)  IS SET TO  (I-1)*MAXDGR + 1.
263C             2.  THE AUTHOR WILL MAKE AVAILABLE A VARIANT VERSION
264C                 'GPSKRA', WHICH EXPECTS THE ADJACENCY MATRIX OR
265C                 CONNECTIVITY TABLE IN THE SAME FORM AS DID  'REDUCE'.
266C                 THIS VERSION CAN BE OBTAINED BY WRITING TO ..
267C                     JOHN GREGG LEWIS
268C                     BOEING COMPUTER SERVICES COMPANY
269C                     MAIL STOP 9C-01
270C                     P.O. BOX 24346
271C                     SEATTLE, WA 98124
272C                 PLEASE INCLUDE A DESCRIPTION OF THE COMPUTING
273C                 ENVIRONMENT ON WHICH YOU WILL BE USING THE CODE.
274C
275C     ==================================================================
276C
277      INTEGER     I, INC1, INC2, AVAIL, NXTNUM, LOWDG, STNODE, NLEFT,
278     1            TREE1, TREE2, DEPTH, EMPTY, STOTAL, REQD, CSPACE,
279     2            LVLLST, LVLPTR, ACTIVE, RVNODE, WIDTH1, WIDTH2, MXDG
280C
281      LOGICAL     REVRS1, ONEIS1
282C
283C     ==================================================================
284C
285C     << NUMBER ANY DEGREE ZERO NODES >>
286C
287C     WHILE << SOME NODES YET UNNUMBERED >> DO
288C         << FIND A PSEUDO-DIAMETER OF THE MATRIX GRAPH >>
289C         << CONVERT FORM OF LEVEL TREES >>
290C         << COMBINE LEVEL TREES INTO ONE LEVEL STRUCTURE >>
291C         << CONVERT FORM OF LEVEL STRUCTURE >>
292C         IF OPTPRO THEN
293C             << RENUMBER BY KING ALGORITHM >>
294C         ELSE
295C             << RENUMBER BY REVERSE CUTHILL-MCKEE ALGORITHM >>
296C
297C     ==================================================================
298C
299C     ... INITIALIZE COUNTERS, THEN NUMBER ANY NODES OF DEGREE  0.
300C         THE LIST OF NODES, BY NEW NUMBER, WILL BE BUILT IN PLACE AT
301C         THE FRONT OF THE WORK AREA.
302C
303        write(6,*)' dans gpskca'       
304        write(6,*)'N=',n
305        write(6,*)'wrklen=',wrklen
306
307      NXTNUM = 1
308      ERROR = 0
309      SPACE = 2*N
310C
311      MXDG = 0
312      DO 300 I = 1, N
313          IF  (DEGREE(I))  6000, 100, 200
314  100         WORK(NXTNUM) = I
315              NXTNUM = NXTNUM + 1
316              GO TO 300
317  200         IF  (DEGREE(I) .GT. MXDG)  MXDG = DEGREE(I)
318  300 CONTINUE
319C
320C
321C     ==============================
322C     ... WHILE  NXTNUM <= N  DO ...
323C     ==============================
324C
325 1000 IF  ( NXTNUM .GT. N )  GO TO 2000
326C
327C         ... FIND AN UNNUMBERED NODE OF MINIMAL DEGREE
328C
329          LOWDG = MXDG + 1
330          STNODE = 0
331          DO 400 I = 1, N
332              IF ( (DEGREE(I) .LE. 0) .OR. (DEGREE(I) .GE. LOWDG) )
333     1           GO TO 400
334                  LOWDG = DEGREE(I)
335                  STNODE = I
336  400     CONTINUE
337C
338          IF ( STNODE .EQ. 0 )  GO TO 6100
339C
340C         ... SET UP POINTERS FOR THREE LISTS IN WORK AREA, THEN LOOK
341C             FOR PSEUDO-DIAMETER, BEGINNING WITH STNODE.
342C
343          AVAIL = (WRKLEN - NXTNUM + 1) / 3
344          NLEFT = N - NXTNUM + 1
345          SPACE = MAX0 (SPACE, NXTNUM + 3*N - 1)
346          IF ( AVAIL .LT. N )  GO TO 5200
347C
348          CALL GPSKCB (N, DEGREE, RSTART, CONNEC, AVAIL, NLEFT,
349     1                 STNODE, RVNODE, WORK(NXTNUM), TREE1, TREE2,
350     2                 ACTIVE, DEPTH, WIDTH1, WIDTH2,
351     3                 ERROR, SPACE)
352          IF ( ERROR .NE. 0 )  GO TO 5000
353          SPACE = MAX0 (SPACE, NXTNUM + 3*(ACTIVE+DEPTH+1) - 1)
354C
355C         ... DYNAMIC SPACE CHECK FOR MOST OF REMAINDER OF ALGORITHM
356C
357          REQD = MAX0 (NXTNUM + 2*N + 3*DEPTH - 1, 3*N + 2*DEPTH + 1)
358          SPACE = MAX0 (SPACE, REQD)
359          IF  ( WRKLEN .LT. REQD )  GO TO 5300
360C
361C
362C         ... OUTPUT FROM GPSKCB IS A PAIR OF LEVEL TREES, IN THE FORM
363C             OF LISTS OF NODES BY LEVEL.  CONVERT THIS TO TWO LISTS OF
364C             OF LEVEL NUMBER BY NODE.  AT THE SAME TIME PACK
365C             STORAGE SO THAT ONE OF THE LEVEL TREE VECTORS IS AT THE
366C             BACK END OF THE WORK AREA.
367C
368          LVLPTR = NXTNUM + AVAIL - DEPTH
369          CALL GPSKCE (N, AVAIL, ACTIVE, DEPTH, WRKLEN, WORK(NXTNUM),
370     1                 WORK(LVLPTR), WORK(1), NXTNUM, TREE1,
371     2                 TREE2, WIDTH1, WIDTH2, ONEIS1, ERROR, SPACE)
372          IF ( ERROR .NE. 0 ) GO TO 5000
373          IF (( TREE1 .NE. WRKLEN - N + 1 ) .OR. (TREE2 .NE. NXTNUM))
374     1      GO TO 6200
375C
376C         ... COMBINE THE TWO LEVEL TREES INTO A MORE GENERAL
377C             LEVEL STRUCTURE.
378C
379          AVAIL = WRKLEN - NXTNUM + 1 - 2*N - 3*DEPTH
380          STOTAL = N + NXTNUM
381          EMPTY = STOTAL + DEPTH
382          INC1 = TREE1 - DEPTH
383          INC2 = INC1 - DEPTH
384C
385          CALL GPSKCG (N, DEGREE, RSTART, CONNEC, ACTIVE, WIDTH1,
386     1                 WIDTH2, WORK(TREE1), WORK(TREE2), WORK(EMPTY),
387     2                 AVAIL, DEPTH, WORK(INC1), WORK(INC2),
388     3                 WORK(STOTAL), ONEIS1, REVRS1, ERROR, CSPACE)
389C
390          IF ( ERROR .NE. 0 )  GO TO 5000
391          SPACE = MAX0 (SPACE, NXTNUM + CSPACE - 1)
392C
393C         ... COMBINED LEVEL STRUCTURE IS REPRESENTED BY GPSKCG AS
394C             A VECTOR OF LEVEL NUMBERS.  FOR RENUMBERING PHASE,
395C             CONVERT THIS ALSO TO THE INVERSE PERMUTATION.
396C
397          LVLPTR = TREE1 - (DEPTH + 1)
398          LVLLST = LVLPTR - ACTIVE
399          IF ( STOTAL + DEPTH .GT. LVLPTR )  GO TO 6300
400C
401          CALL GPSKCI (N, ACTIVE, DEPTH, WORK(TREE1), WORK(LVLLST),
402     1                 WORK(LVLPTR), WORK(STOTAL), ERROR, SPACE)
403          IF  (ERROR .NE. 0)  GO TO 5000
404C
405C         ... NOW RENUMBER ALL MEMBERS OF THIS COMPONENT USING
406C             EITHER A REVERSE CUTHILL-MCKEE OR A KING STRATEGY,
407C             AS PROFILE OR BANDWIDTH REDUCTION IS MORE IMPORTANT.
408C
409          IF ( OPTPRO )  GO TO 500
410              CALL GPSKCJ (N, DEGREE, RSTART, CONNEC, ACTIVE,
411     1                     WORK(NXTNUM), STNODE, RVNODE, REVRS1, DEPTH,
412     2                     WORK(LVLLST), WORK(LVLPTR), WORK(TREE1),
413     3                     ERROR, SPACE)
414              IF ( ERROR .NE. 0 )  GO TO 5000
415              NXTNUM = NXTNUM + ACTIVE
416              GO TO 600
417C
418  500         CALL GPSKCK (N, DEGREE, RSTART, CONNEC, LVLLST-1, NXTNUM,
419     1                     WORK, ACTIVE, DEPTH, WORK(LVLLST),
420     2                     WORK(LVLPTR), WORK(TREE1), ERROR, SPACE)
421              IF ( ERROR .NE. 0 )  GO TO 5000
422C
423C         =========================================================
424C         ... END OF WHILE LOOP ... REPEAT IF GRAPH IS DISCONNECTED
425C         =========================================================
426C
427  600     GO TO 1000
428C
429C     ... CHECK WHETHER INITIAL NUMBERING OR FINAL NUMBERING
430C         PROVIDES BETTER RESULTS
431C
432 2000 IF  (WRKLEN .LT. 2*N)  GO TO 5400
433C
434      IF  (OPTPRO)  GO TO 2100
435          CALL GPSKCL (N, DEGREE, RSTART, CONNEC, WORK(1), WORK(N+1),
436     1                 PERMUT, BANDWD, PROFIL, ERROR, SPACE)
437          GO TO 2200
438C
439 2100     CALL GPSKCM (N, DEGREE, RSTART, CONNEC, WORK(1), WORK(N+1),
440     1                 PERMUT, BANDWD, PROFIL, ERROR, SPACE)
441C
442 2200 RETURN
443C
444C
445C     . . .  E R R O R   D I A G N O S T I C S
446C            ---------------------------------
447C
448C     ... ERROR DETECTED BY LOWER LEVEL ROUTINE.  MAKE SURE THAT SIGNS
449C         OF DEGREE ARE PROPERLY SET
450C
451 5000 DO 5100 I = 1, N
452          IF  (DEGREE(I) .LT. 0)  DEGREE(I) = -DEGREE(I)
453 5100 CONTINUE
454C
455      BANDWD = -1
456      PROFIL = -1
457      RETURN
458C
459C     ... STORAGE ALLOCATION ERRORS DETECTED IN THIS ROUTINE
460C
461 5200 ERROR = 101
462      SPACE = -1
463      GO TO 5000
464C
465 5300 ERROR = 102
466      SPACE = -1
467      GO TO 5000
468C
469 5400 ERROR =  10
470      SPACE = 2*N - WRKLEN
471      GO TO 5000
472C
473C     ... DATA STRUCTURE ERRORS DETECTED IN THIS ROUTINE
474C
475 6000 ERROR = 1
476      GO TO 6900
477C
478 6100 ERROR = 2
479      GO TO 6900
480C
481 6200 ERROR = 3
482      GO TO 6900
483C
484 6300 ERROR = 4
485C
486 6900 SPACE = -1
487      GO TO 5000
488      END
489
490      SUBROUTINE  GPSKCB  (N, DEGREE, RSTART, CONNEC, AVAIL, NLEFT,     GPSKC446
491     1                     STNODE, RVNODE, WORK, FORWD, BESTBK, NNODES,
492     2                     DEPTH, FWIDTH, BWIDTH, ERROR, SPACE)
493C
494C     ==================================================================
495C
496C     FIND A PSEUDO-DIAMETER OF THE MATRIX GRAPH ...
497C
498C         << BUILD A LEVEL TREE FROM STNODE >>
499C         REPEAT
500C             << BUILD A LEVEL TREE FROM EACH NODE 'BKNODE' IN THE
501C                DEEPEST LEVEL OF  STNODE'S TREE >>
502C             << REPLACE 'STNODE' WITH 'BKNODE' IF A DEEPER AND
503C                NARROWER TREE WAS FOUND. >>
504C         UNTIL
505C             << NO FURTHER IMPROVEMENT MADE >>
506C
507C     ... HEURISTIC ABOVE DIFFERS FROM THE ALGORITHM PUBLISHED IN
508C         SIAM J. NUMERICAL ANALYSIS, BUT MATCHES THE CODE
509C         DISTRIBUTED BY TOMS.
510C
511C
512C     PARAMETERS :
513C
514C         N, DEGREE, RSTART & CONNEC  DESCRIBE THE MATRIX STRUCTURE
515C
516C         WORK   -- WORKING SPACE, OF LENGTH  3*AVAIL, USED TO STORE
517C         THREE LEVEL TREES.
518C
519C         STNODE IS INITIALLY THE NUMBER OF A NODE TO BE USED TO
520C             START THE PROCESS, TO BE THE ROOT OF THE FIRST TREE.
521C             ON OUTPUT, STNODE IS THE END OF THE PSEUDO-DIAMETER WHOSE
522C             LEVEL TREE IS NARROWEST.
523C
524C         RVNODE WILL BE THE OTHER END OF THE PSEUDO-DIAMETER.
525C
526C         NNODES WILL BE THE NUMBER OF NODES IN THIS CONNECTED
527C             COMPONNENT OF THE MATRIX GRAPH, I.E., THE LENGTH OF
528C             THE LEVEL TREES.
529C
530C         DEPTH  -- THE DEPTH OF THE LEVEL TREES BEING RETURNED,
531C                   I.E., THE LENGTH OF THE PSEUDO-DIAMETER.
532C
533C     ==================================================================
534C
535C     STRUCTURE OF WORKSPACE ...
536C
537C     ---------------------------------------------------------------
538C     : NUMBERED :  TLIST1  PTR1  :  TLIST2  PTR2  :  TLIST3  PTR3  :
539C     ---------------------------------------------------------------
540C
541C     TLISTI IS A LIST OF NODES OF LENGTH  'ACTIVE'
542C     PTRI   IS A LIST OF POINTERS INTO TLISTI, OF LENGTH  'DEPTH+1'
543C
544C     ==================================================================
545C
546      INTEGER     N, RSTART(N), AVAIL, NLEFT,
547     1            STNODE, RVNODE, FORWD, BESTBK, NNODES, DEPTH, FWIDTH,
548     4            BWIDTH, ERROR, SPACE
549C
550CIBM  INTEGER *2  DEGREE(N), CONNEC(1), WORK(AVAIL,3)
551      INTEGER     DEGREE(N), CONNEC(1), WORK(AVAIL,3)
552C
553C     ----------------
554C
555      INTEGER     BACKWD, MXDPTH, WIDTH, FDEPTH, LSTLVL,
556     1            NLAST, T, I, BKNODE, LSTLVI
557C
558      LOGICAL     IMPROV
559C
560C
561C     ... BUILD INITIAL LEVEL TREE FROM 'STNODE'.  FIND OUT HOW MANY
562C         NODES LIE IN THE CURRENT CONNECTED COMPONENT.
563C
564      FORWD = 1
565      BACKWD = 2
566      BESTBK = 3
567C
568      CALL GPSKCC (N, DEGREE, RSTART, CONNEC, STNODE, AVAIL, NLEFT,
569     1              WORK(1,FORWD), NNODES, DEPTH, WIDTH, ERROR,
570     2              SPACE)
571      IF ( ERROR .NE. 0 )  GO TO 5000
572C
573      MXDPTH = AVAIL - NNODES - 1
574C
575C     ==========================================
576C     REPEAT UNTIL NO DEEPER TREES ARE FOUND ...
577C     ==========================================
578C
579 1000     FWIDTH = WIDTH
580          FDEPTH = DEPTH
581          LSTLVL = AVAIL - DEPTH + 1
582          NLAST = WORK (LSTLVL-1, FORWD) - WORK (LSTLVL, FORWD)
583          LSTLVL = WORK (LSTLVL, FORWD)
584          BWIDTH = N+1
585C
586C         ... SORT THE DEEPEST LEVEL OF 'FORWD' TREE INTO INCREASING
587C             ORDER OF NODE DEGREE.
588C
589          CALL GPSKCQ (NLAST, WORK(LSTLVL,FORWD), N, DEGREE, ERROR)
590          IF  (ERROR .NE. 0)  GO TO 6000
591C
592C         ... BUILD LEVEL TREE FROM NODES IN 'LSTLVL' UNTIL A DEEPER
593C             AND NARROWER TREE IS FOUND OR THE LIST IS EXHAUSTED.
594C
595          IMPROV = .FALSE.
596          DO 1200 I = 1, NLAST
597              LSTLVI = LSTLVL + I - 1
598              BKNODE = WORK (LSTLVI, FORWD)
599              CALL GPSKCD (N, DEGREE, RSTART, CONNEC, BKNODE, AVAIL,
600     1                     NNODES, MXDPTH, WORK(1,BACKWD), DEPTH, WIDTH,
601     2                     BWIDTH, ERROR, SPACE)
602              IF ( ERROR .NE. 0 )  GO TO 5000
603C
604              IF ( DEPTH .LE. FDEPTH )  GO TO 1100
605C
606C                 ... NEW DEEPER TREE ... MAKE IT NEW 'FORWD' TREE
607C                     AND BREAK OUT OF 'DO' LOOP.
608C
609                  IMPROV = .TRUE.
610                  T = FORWD
611                  FORWD = BACKWD
612                  BACKWD = T
613                  STNODE = BKNODE
614                  GO TO 1300
615C
616C                 ... ELSE CHECK FOR NARROWER TREE.
617C
618 1100             IF ( WIDTH .GE. BWIDTH )  GO TO 1200
619                      T = BESTBK
620                      BESTBK = BACKWD
621                      BACKWD = T
622                      BWIDTH = WIDTH
623                      RVNODE = BKNODE
624 1200     CONTINUE
625C
626C         ... END OF REPEAT LOOP
627C         ----------------------
628C
629 1300     IF ( IMPROV )  GO TO 1000
630C
631      DEPTH = FDEPTH
632      RETURN
633C
634C     ... IN CASE OF ERROR, SIMPLY RETURN ERROR FLAG TO USER.
635C
636 5000 RETURN
637C
638 6000 ERROR = 11
639      SPACE = -1
640      RETURN
641C
642      END
643      SUBROUTINE   GPSKCC   (N, DEGREE, RSTART, CONNEC, STNODE, AVAIL,  GPSKC599
644     1                       NLEFT, LIST, ACTIVE, DEPTH, WIDTH, ERROR,
645     2                       SPACE)
646C
647C     ==================================================================
648C     BUILD THE LEVEL TREE ROOTED AT 'STNODE' IN THE SPACE PROVIDED IN
649C     LIST.  CHECK FOR OVERRUN OF SPACE ALLOCATION.
650C     ==================================================================
651C
652      INTEGER     N, RSTART(N), STNODE, AVAIL, NLEFT,
653     1            ACTIVE, DEPTH, WIDTH, ERROR, SPACE
654C
655CIBM  INTEGER *2  DEGREE(N), connec(1), LIST(AVAIL)
656      INTEGER     DEGREE(N), CONNEC(1), LIST(AVAIL)
657C
658C     ... PARAMETERS:
659C
660C         INPUT ...
661C
662C             N, DEGREE, RSTART, CONNEC -- DESCRIBE THE MATRIX STRUCTURE
663C
664C             STNODE -- THE ROOT OF THE LEVEL TREE.
665C
666C             AVAIL  -- THE LENGTH OF THE WORKING SPACE AVAILABLE
667C
668C             NLEFT  -- THE NUMBER OF NODES YET TO BE NUMBERED
669C
670C             LIST   -- THE WORKING SPACE.
671C
672C         OUTPUT ...
673C
674C             ACTIVE -- THE NUMBER OF NODES IN THE COMPONENT
675C
676C             DEPTH  -- THE DEPTH OF THE LEVEL TREE ROOTED AT  STNODE.
677C
678C             WIDTH  -- THE WIDTH OF THE LEVEL TREE ROOTED AT  STNODE.
679C
680C             ERROR  -- ZERO UNLESS STORAGE WAS INSUFFICIENT.
681C
682C     ------------------------------------------------------------------
683C
684      INTEGER         LSTART, NLEVEL, FRONT, J, NEWNOD, PTR, CDGREE,
685     1                LFRONT, LISTJ
686C
687C     ... BUILD THE LEVEL TREE USING  LIST  AS A QUEUE AND LEAVING
688C         THE NODES IN PLACE.  THIS GENERATES THE NODES ORDERED BY LEVEL
689C         PUT POINTERS TO THE BEGINNING OF EACH LEVEL, BUILDING FROM
690C         THE BACK OF THE WORK AREA.
691C
692      ACTIVE = 1
693      DEPTH = 0
694      WIDTH = 0
695      ERROR = 0
696      LSTART = 1
697      FRONT = 1
698      LIST (ACTIVE) = STNODE
699      DEGREE (STNODE) = -DEGREE (STNODE)
700      LIST (AVAIL)  = 1
701      NLEVEL = AVAIL
702C
703C     ... REPEAT UNTIL QUEUE BECOMES EMPTY OR WE RUN OUT OF SPACE.
704C     ------------------------------------------------------------
705C
706 1000     IF ( FRONT .LT. LSTART ) GO TO 1100
707C
708C         ... FIRST NODE OF LEVEL.  UPDATE POINTERS.
709C
710              LSTART = ACTIVE + 1
711              WIDTH = MAX0 (WIDTH, LSTART - LIST(NLEVEL))
712              NLEVEL = NLEVEL - 1
713              DEPTH = DEPTH + 1
714              IF ( NLEVEL .LE. ACTIVE )  GO TO 5000
715                  LIST (NLEVEL) = LSTART
716C
717C         ... FIND ALL NEIGHBORS OF CURRENT NODE, ADD THEM TO QUEUE.
718C
719 1100     LFRONT = LIST (FRONT)
720          PTR = RSTART (LFRONT)
721          CDGREE = -DEGREE (LFRONT)
722          IF (CDGREE .LE. 0)  GO TO 6000
723          DO 1200 J = 1, CDGREE
724              NEWNOD = CONNEC (PTR)
725              PTR = PTR + 1
726C
727C             ... ADD TO QUEUE ONLY NODES NOT ALREADY IN QUEUE
728C
729              IF ( DEGREE(NEWNOD) .LE. 0 )  GO TO 1200
730                  DEGREE (NEWNOD) = -DEGREE (NEWNOD)
731                  ACTIVE = ACTIVE + 1
732                  IF ( NLEVEL .LE. ACTIVE )  GO TO 5000
733                  IF ( ACTIVE .GT. NLEFT  )  GO TO 6000
734                      LIST (ACTIVE) = NEWNOD
735 1200     CONTINUE
736          FRONT = FRONT + 1
737C
738C         ... IS QUEUE EMPTY?
739C         -------------------
740C
741          IF ( FRONT .LE. ACTIVE )  GO TO 1000
742C
743C     ... YES, THE TREE IS BUILT.  UNDO OUR MARKINGS.
744C
745      DO 1300 J = 1, ACTIVE
746          LISTJ = LIST(J)
747          DEGREE (LISTJ) = -DEGREE (LISTJ)
748 1300 CONTINUE
749C
750      RETURN
751C
752C     ... INSUFFICIENT STORAGE ...
753C
754 5000 SPACE = 3 * ( (NLEFT+1-ACTIVE)*DEPTH / NLEFT + (NLEFT+1-ACTIVE) )
755      ERROR = 110
756      RETURN
757C
758 6000 ERROR = 12
759      SPACE = -1
760      RETURN
761C
762      END
763      SUBROUTINE   GPSKCD   (N, DEGREE, RSTART, CONNEC, STNODE, AVAIL,  GPSKC719
764     1                       ACTIVE, MXDPTH, LIST, DEPTH, WIDTH, MAXWID,
765     2                       ERROR, SPACE)
766C
767C     ==================================================================
768C     BUILD THE LEVEL TREE ROOTED AT 'STNODE' IN THE SPACE PROVIDED IN
769C     LIST.  OVERFLOW CHECK NEEDED ONLY ON DEPTH OF TREE.
770C
771C     BUILD THE LEVEL TREE TO COMPLETION ONLY IF THE WIDTH OF ALL
772C     LEVELS IS SMALLER THAN 'MAXWID'.  IF A WIDER LEVEL IS FOUND
773C     TERMINATE THE CONSTRUCTION.
774C     ==================================================================
775C
776      INTEGER     N, RSTART(N), STNODE, AVAIL, ACTIVE, MXDPTH,
777     1            DEPTH, WIDTH, MAXWID, ERROR, SPACE
778C
779CIBM  INTEGER *2  DEGREE(N), CONNEC(1), LIST(AVAIL)
780      INTEGER     DEGREE(N), CONNEC(1), LIST(AVAIL)
781C
782C     ... PARAMETERS:
783C
784C         INPUT ...
785C
786C             N, DEGREE, RSTART, CONNEC -- DESCRIBE THE MATRIX STRUCTURE
787C
788C             STNODE -- THE ROOT OF THE LEVEL TREE.
789C
790C             AVAIL  -- THE LENGTH OF THE WORKING SPACE AVAILABLE
791C
792C             NLEFT  -- THE NUMBER OF NODES YET TO BE NUMBERED
793C
794C             ACTIVE -- THE NUMBER OF NODES IN THE COMPONENT
795C
796C             MXDPTH -- MAXIMUM DEPTH OF LEVEL TREE POSSIBLE IN
797C                       ALLOTTED WORKING SPACE
798C
799C             LIST   -- THE WORKING SPACE.
800C
801C         OUTPUT ...
802C
803C             DEPTH  -- THE DEPTH OF THE LEVEL TREE ROOTED AT  STNODE.
804C
805C             WIDTH  -- THE WIDTH OF THE LEVEL TREE ROOTED AT  STNODE.
806C
807C             MAXWID -- LIMIT ON WIDTH OF THE TREE.  TREE WILL NOT BE
808C                       USED IF WIDTH OF ANY LEVEL IS AS GREAT AS
809C                       MAXWID, SO CONSTRUCTION OF TREE NEED NOT
810C                       CONTINUE IF ANY LEVEL THAT WIDE IS FOUND.
811C             ERROR  -- ZERO UNLESS STORAGE WAS INSUFFICIENT.
812C
813C     ------------------------------------------------------------------
814C
815      INTEGER     LSTART, NLEVEL, FRONT, J, NEWNOD, PTR, BACK,
816     1            SPTR, FPTR, LFRONT, LISTJ
817C
818C     ... BUILD THE LEVEL TREE USING  LIST  AS A QUEUE AND LEAVING
819C         THE NODES IN PLACE.  THIS GENERATES THE NODES ORDERED BY LEVEL
820C         PUT POINTERS TO THE BEGINNING OF EACH LEVEL, BUILDING FROM
821C         THE BACK OF THE WORK AREA.
822C
823      BACK = 1
824      DEPTH = 0
825      WIDTH = 0
826      ERROR = 0
827      LSTART = 1
828      FRONT = 1
829      LIST (BACK) = STNODE
830      DEGREE (STNODE) = -DEGREE (STNODE)
831      LIST (AVAIL)  = 1
832      NLEVEL = AVAIL
833C
834C     ... REPEAT UNTIL QUEUE BECOMES EMPTY OR WE RUN OUT OF SPACE.
835C     ------------------------------------------------------------
836C
837 1000     IF ( FRONT .LT. LSTART ) GO TO 1100
838C
839C         ... FIRST NODE OF LEVEL.  UPDATE POINTERS.
840C
841              LSTART = BACK + 1
842              WIDTH = MAX0 (WIDTH, LSTART - LIST(NLEVEL))
843              IF  ( WIDTH .GE. MAXWID )  GO TO 2000
844              NLEVEL = NLEVEL - 1
845              DEPTH = DEPTH + 1
846              IF ( DEPTH .GT. MXDPTH )  GO TO 5000
847                  LIST (NLEVEL) = LSTART
848C
849C         ... FIND ALL NEIGHBORS OF CURRENT NODE, ADD THEM TO QUEUE.
850C
851 1100     LFRONT = LIST (FRONT)
852          SPTR = RSTART (LFRONT)
853          FPTR = SPTR - DEGREE (LFRONT) - 1
854          DO 1200 PTR = SPTR, FPTR
855              NEWNOD = CONNEC (PTR)
856C
857C             ... ADD TO QUEUE ONLY NODES NOT ALREADY IN QUEUE
858C
859              IF ( DEGREE(NEWNOD) .LE. 0 )  GO TO 1200
860                  DEGREE (NEWNOD) = -DEGREE (NEWNOD)
861                  BACK = BACK + 1
862                  LIST (BACK) = NEWNOD
863 1200     CONTINUE
864          FRONT = FRONT + 1
865C
866C         ... IS QUEUE EMPTY?
867C         -------------------
868C
869          IF ( FRONT .LE. BACK )  GO TO 1000
870C
871C     ... YES, THE TREE IS BUILT.  UNDO OUR MARKINGS.
872C
873      IF (BACK .NE. ACTIVE)  GO TO 6000
874C
875 1300 DO 1400 J = 1, BACK
876          LISTJ = LIST(J)
877          DEGREE (LISTJ) = -DEGREE (LISTJ)
878 1400 CONTINUE
879C
880      RETURN
881C
882C     ... ABORT GENERATION OF TREE BECAUSE IT IS ALREADY TOO WIDE
883C
884 2000 WIDTH = N + 1
885      DEPTH = 0
886      GO TO 1300
887C
888C     ... INSUFFICIENT STORAGE ...
889C
890 5000 SPACE = 3 * ( (ACTIVE+1-BACK)*DEPTH / ACTIVE + (ACTIVE+1-BACK) )
891      ERROR = 111
892      RETURN
893C
894 6000 ERROR = 13
895      SPACE = -1
896      RETURN
897C
898      END
899      SUBROUTINE   GPSKCE   (N, AVAIL, ACTIVE, DEPTH, WRKLEN,           GPSKC855
900     1                       LVLLST, LVLPTR, WORK, NXTNUM, TREE1, TREE2,
901     2                       WIDTH1, WIDTH2, ONEIS1, ERROR, SPACE)
902C
903C     ==================================================================
904C
905C     TRANSITION BETWEEN ALGORITHM I AND ALGORITHM II OF
906C     THE GIBBS-POOLE-STOCKMEYER PAPER.
907C
908C     IN THIS IMPLEMENTATION ALGORITHM I REPRESENTS LEVEL TREES AS
909C     LISTS OF NODES ORDERED BY LEVEL.  ALGORITHM II APPEARS TO REQUIRE
910C     LEVEL NUMBERS INDEXED BY NODE -- VECTORS FOR EFFICIENCY.
911C     THIS SUBROUTINE CHANGES THE LEVEL TREE REPRESENTATION TO THAT
912C     REQUIRED BY ALGORITHM II.  NOTE THAT THE FIRST ALGORITHM CAN BE
913C     CARRIED OUT WITH THE LEVEL NUMBER VECTOR FORMAT, PROBABLY REQURING
914C     MORE COMPUTATION TIME, BUT PERHAPS LESS STORAGE.
915C
916C     INPUT:  TWO LEVEL TREES, AS LEVEL LISTS AND LEVEL POINTERS,
917C             FOUND IN TWO OF THE THREE COLUMNS OF THE ARRAYS 'LVLLST'
918C             AND 'LVLPTR'
919C
920C     OUTPUT: TWO LEVEL TREES, AS VECTORS OF LEVEL NUMBERS,
921C             ONE PACKED TO THE FRONT, ONE TO THE REAR OF THE WORKING
922C             AREA 'WORK'.  NOTE THAT 'WORK', 'LVLLST' AND 'LVLPTR'
923C             SHARE COMMON LOCATIONS.
924C
925C     ================================================================
926C
927C     ... STRUCTURE OF WORKSPACE
928C
929C         INPUT .. (OUTPUT FROM GPSKCB)
930C
931C     --------------------------------------------------------------
932C     : NUMBERED : TLIST1  PTR1  :  TLIST2  PTR2  :  TLIST3  PTR3  :
933C     --------------------------------------------------------------
934C
935C         OUTPUT .. (GOES TO COMBIN)
936C
937C     --------------------------------------------------------------
938C     : NUMBERED :  TREE2  :           ...               :  TREE1  :
939C     --------------------------------------------------------------
940C
941C     ==================================================================
942C
943      INTEGER     N, AVAIL, ACTIVE, DEPTH, WRKLEN, NXTNUM,
944     1            WIDTH1, WIDTH2, TREE1, TREE2, ERROR, SPACE
945C
946CIBM  INTEGER *2  LVLLST(AVAIL,3), LVLPTR(AVAIL,3), WORK(WRKLEN)
947      INTEGER     LVLLST(AVAIL,3), LVLPTR(AVAIL,3), WORK(WRKLEN)
948C
949      LOGICAL     ONEIS1
950C
951C     ------------------------------------------------------------------
952C
953      INTEGER     I, BTREE, FTREE, FWIDTH, BWIDTH
954C
955C
956C     ... CHECK THAT WE HAVE ENOUGH ROOM TO DO THE NECESSARY UNPACKING
957C
958      IF (3*AVAIL .GT. WRKLEN)  GO TO 6000
959      IF (AVAIL .LT. N)  GO TO 5100
960C
961C     ... INPUT HAS THREE POSSIBLE CASES:
962C             LVLLST(*,1) IS EMPTY
963C             LVLLST(*,2) IS EMPTY
964C             LVLLST(*,3) IS EMPTY
965C
966      FTREE = TREE1
967      BTREE = TREE2
968      FWIDTH = WIDTH1
969      BWIDTH = WIDTH2
970C
971      TREE1 = WRKLEN - N + 1
972      TREE2 = NXTNUM
973C
974      IF ( (FTREE .EQ. 1) .OR. (BTREE .EQ. 1) )  GO TO 300
975C
976C         ... CASE 1:  1ST SLOT IS EMPTY.  UNPACK 3 INTO 1, 2 INTO 3
977C
978          IF (FTREE .NE. 2)  GO TO 100
979              ONEIS1 = .TRUE.
980              WIDTH2 = BWIDTH
981              WIDTH1 = FWIDTH
982              GO TO 200
983C
984  100         ONEIS1 = .FALSE.
985              WIDTH1 = BWIDTH
986              WIDTH2 = FWIDTH
987C
988  200     CALL GPSKCF (N, ACTIVE, DEPTH, LVLLST(1,3), LVLPTR(1,3),
989     1                    WORK(TREE2), ONEIS1)
990C
991          CALL GPSKCF (N, ACTIVE, DEPTH, LVLLST(1,2), LVLPTR(1,2),
992     1                    WORK(TREE1), .NOT. ONEIS1)
993C
994          GO TO 1000
995C
996C
997  300 IF ( (FTREE .EQ. 2) .OR. (BTREE .EQ. 2) )  GO TO 600
998C
999C         ... CASE 2:  2ND SLOT IS EMPTY.  TO ENABLE COMPLETE
1000C              REPACKING, MOVE 3 INTO 2, THEN FALL INTO NEXT CASE
1001C
1002          DO 400 I = 1, ACTIVE
1003              LVLLST(I,2) = LVLLST(I,3)
1004  400     CONTINUE
1005C
1006          DO 500 I = 1, DEPTH
1007              LVLPTR(I,2) = LVLPTR(I,3)
1008  500     CONTINUE
1009C
1010C         ... CASE 3:  SLOT 3 IS EMPTY.  MOVE 1 INTO 3, THEN 2 INTO 1.
1011C
1012  600     IF (FTREE .EQ. 1) GO TO 700
1013              ONEIS1 = .FALSE.
1014              WIDTH1 = BWIDTH
1015              WIDTH2 = FWIDTH
1016              GO TO 800
1017C
1018  700         ONEIS1 = .TRUE.
1019              WIDTH1 = FWIDTH
1020              WIDTH2 = BWIDTH
1021C
1022  800     CALL GPSKCF (N, ACTIVE, DEPTH, LVLLST(1,1), LVLPTR(1,1),
1023     1                    WORK(TREE1), .NOT. ONEIS1)
1024C
1025          CALL GPSKCF (N, ACTIVE, DEPTH, LVLLST(1,2), LVLPTR(1,2),
1026     1                    WORK(TREE2), ONEIS1)
1027 1000 RETURN
1028C
1029C     ------------------------------------------------------------------
1030C
1031 5100 SPACE = 3 * (N - AVAIL)
1032      ERROR = 120
1033      RETURN
1034C
1035 6000 ERROR = 20
1036      SPACE = -1
1037      RETURN
1038C
1039      END
1040      SUBROUTINE  GPSKCF  (N, ACTIVE, DEPTH, LVLLST, LVLPTR, LVLNUM,    GPSKC996
1041     1                     REVERS)
1042C
1043C     ==================================================================
1044C
1045C     CONVERT LEVEL STRUCTURE REPRESENTATION FROM A LIST OF NODES
1046C     GROUPED BY LEVEL TO A VECTOR GIVING LEVEL NUMBER FOR EACH NODE.
1047C
1048C     LVLLST, LVLPTR -- LIST OF LISTS
1049C
1050C     LVLNUM -- OUTPUT VECTOR OF LEVEL NUMBERS
1051C
1052C     REVERS -- IF .TRUE., NUMBER LEVEL STRUCTURE FROM BACK END
1053C               INSTEAD OF FROM FRONT
1054C
1055C     ==================================================================
1056C
1057      INTEGER     N, ACTIVE, DEPTH
1058C
1059CIBM  INTEGER *2  LVLLST(ACTIVE), LVLPTR(DEPTH), LVLNUM(N)
1060      INTEGER     LVLLST(ACTIVE), LVLPTR(DEPTH), LVLNUM(N)
1061      LOGICAL     REVERS
1062C
1063C     ------------------------------------------------------------------
1064C
1065      INTEGER     I, LEVEL, LSTART, LEND, XLEVEL, PLSTRT, LVLLSI
1066C
1067      IF  (ACTIVE .EQ. N)  GO TO 200
1068C
1069C         ... IF NOT ALL NODES OF GRAPH ARE ACTIVE, MASK OUT THE
1070C             NODES WHICH ARE NOT ACTIVE
1071C
1072          DO 100 I = 1, N
1073              LVLNUM(I) = 0
1074  100     CONTINUE
1075C
1076  200 DO 400 LEVEL = 1, DEPTH
1077          XLEVEL = LEVEL
1078          PLSTRT = DEPTH - LEVEL + 1
1079          IF (REVERS) XLEVEL = PLSTRT
1080          LSTART = LVLPTR (PLSTRT)
1081          LEND = LVLPTR (PLSTRT - 1) - 1
1082C
1083          DO 300 I = LSTART, LEND
1084              LVLLSI = LVLLST(I)
1085              LVLNUM (LVLLSI) = XLEVEL
1086  300     CONTINUE
1087  400 CONTINUE
1088C
1089      RETURN
1090      END
1091      SUBROUTINE   GPSKCG   (N, DEGREE, RSTART, CONNEC, ACTIVE, WIDTH1, GPSK1047
1092     1                       WIDTH2, TREE1, TREE2, WORK, WRKLEN, DEPTH,
1093     2                       INC1, INC2, TOTAL, ONEIS1, REVRS1, ERROR,
1094     3                       SPACE)
1095C
1096C     ==================================================================
1097C
1098C     COMBINE THE TWO ROOTED LEVEL TREES INTO A SINGLE LEVEL STRUCTURE
1099C     WHICH MAY HAVE SMALLER WIDTH THAN EITHER OF THE TREES.  THE NEW
1100C     STRUCTURE IS NOT NECESSARILY A ROOTED STRUCTURE.
1101C
1102C     PARAMETERS:
1103C
1104C         N, DEGREE, RSTART, CONNEC -- GIVE THE DIMENSION AND STRUCTURE
1105C                                      OF THE SPARSE SYMMETRIC MATRIX
1106C
1107C         ACTIVE -- THE NUMBER OF NODES IN THIS CONNECTED COMPONENT OF
1108C                   THE MATRIX GRAPH
1109C
1110C         TREE1  -- ON INPUT, ONE OF THE INPUT LEVEL TREES.  ON
1111C                   OUTPUT, THE COMBINED LEVEL STRUCTURE
1112C
1113C         TREE2  -- THE SECOND INPUT LEVEL TREE
1114C
1115C         WIDTH1 -- THE MAXIMUM WIDTH OF A LEVEL IN TREE1
1116C
1117C         WIDTH2 -- THE MAXIMUM WIDTH OF A LEVEL IN TREE2
1118C
1119C         WORK   -- A WORKING AREA OF LENGTH 'WRKLEN'
1120C
1121C         INC1,  -- VECTORS OF LENGTH 'DEPTH'
1122C         INC2,
1123C         TOTAL
1124C
1125C         ONEIS1 -- INDICATES WHETHER TREE1 OR TREE2 REPRESENTS THE
1126C                   FORWARD TREE OR THE BACKWARDS TREE OF PHASE 1.
1127C                   USED TO MIMIC ARBITRARY TIE-BREAKING PROCEDURE OF
1128C                   ORIGINAL GIBBS-POOLE-STOCKMEYER CODE.
1129C
1130C         REVRS1 -- OUTPUT PARAMETER INDICATING WHETHER A BACKWARDS
1131C                   ORDERING WAS USED FOR THE LARGEST COMPONENT OF
1132C                   THE REDUCED GRAPH
1133C
1134C         ERROR  -- NON-ZERO ONLY IF FAILURE OF SPACE ALLOCATION OR
1135C                   DATA STRUCTURE ERROR FOUND
1136C
1137C         SPACE -- MINIMUM SPACE REQUIRED TO RERUN OR COMPLETE PHASE.
1138C
1139C     ------------------------------------------------------------------
1140C
1141      INTEGER     N, RSTART(N), ACTIVE, WIDTH1, WIDTH2, WRKLEN, DEPTH,
1142     2            ERROR, SPACE
1143C
1144CIBM  INTEGER *2  DEGREE(N), CONNEC(1), TREE1(N), TREE2(N),
1145      INTEGER     DEGREE(N), CONNEC(1), TREE1(N), TREE2(N),
1146     1            WORK(WRKLEN), INC1(DEPTH), INC2(DEPTH), TOTAL(DEPTH)
1147C
1148      LOGICAL     ONEIS1, REVRS1
1149C
1150C     ==================================================================
1151C
1152C     << REMOVE ALL NODES OF PSEUDO-DIAMETERS >>
1153C     << FIND CONNECTED COMPONENTS OF REDUCED GRAPH >>
1154C     << COMBINE LEVEL TREES, COMPONENT BY COMPONENT >>
1155C
1156C     ==================================================================
1157C
1158C     STRUCTURE OF WORKSPACE ...
1159C
1160C     ------------------------------------------------------------------
1161C     : NUMBERED : TREE2 : TOTAL : NODES : START : SIZE : INC1 : INC2 :
1162C     ------------------------------------------------------------------
1163C
1164C     --------
1165C      TREE1 :
1166C     --------
1167C
1168C         NUMBERED  IS THE SET OF  NUMBERED NODES (PROBABLY EMPTY)
1169C
1170C         TREE1 AND TREE1 ARE LEVEL TREES (LENGTH N)
1171C         TOTAL, INC1 AND INC2  ARE VECTORS OF NODE COUNTS PER LEVEL
1172C             (LENGTH 'DEPTH')
1173C         NODES IS THE SET OF NODES IN THE REDUCED GRAPH (THE NODES
1174C             NOT ON ANY SHORTEST PATH FROM ONE END OF THE
1175C             PSEUDODIAMETER TO THE OTHER)
1176C         START, SIZE ARE POINTERS INTO 'NODES', ONE OF EACH FOR
1177C         EACH CONNECTED COMPONENT OF THE REDUCED GRAPH.
1178C         THE SIZES OF NODES, START AND SIZE ARE NOT KNOWN APRIORI.
1179C
1180C     ==================================================================
1181      INTEGER     I, SIZE, AVAIL, CSTOP, START, COMPON, TREE1I, PCSTRT,
1182     1            CSTART, MXINC1, MXINC2, COMPNS, MXCOMP, OFFDIA,
1183     2            CSIZE, PCSIZE, WORKI, TWORKI
1184C
1185C     ------------------------------------------------------------------
1186C
1187C     ... FIND ALL SHORTEST PATHS FROM START TO FINISH.  REMOVE NODES ON
1188C         THESE PATHS AND IN OTHER CONNECTED COMPONENTS OF FULL GRAPH
1189C         FROM FURTHER CONSIDERATION.  SIGN OF ENTRIES IN TREE1 IS USED
1190C         AS A MASK.
1191C
1192      OFFDIA = ACTIVE
1193C
1194      DO 100 I = 1, DEPTH
1195          TOTAL(I) = 0
1196  100 CONTINUE
1197C
1198      DO 200 I = 1, N
1199          TREE1I = TREE1 (I)
1200          IF ((TREE1(I) .NE. TREE2(I)) .OR. (TREE1(I) .EQ. 0)) GO TO 200
1201              TOTAL (TREE1I) = TOTAL (TREE1I) + 1
1202              TREE1(I) = - TREE1(I)
1203              OFFDIA = OFFDIA - 1
1204  200 CONTINUE
1205C
1206      IF ( OFFDIA .EQ. 0 )  GO TO 1100
1207      IF ( OFFDIA .LT. 0 )  GO TO 6000
1208C
1209C     ... FIND CONNECTED COMPONENTS OF GRAPH INDUCED BY THE NODES NOT
1210C         REMOVED.  'MXCOMP' IS THE LARGEST NUMBER OF COMPONENTS
1211C         REPRESENTABLE IN THE WORKING SPACE AVAILABLE.
1212C
1213      AVAIL = WRKLEN - OFFDIA
1214      MXCOMP = AVAIL/2
1215      START = OFFDIA + 1
1216      SIZE = START + MXCOMP
1217C
1218      IF  (MXCOMP .LE. 0)  GO TO 5100
1219C
1220      CALL GPSKCH (N, DEGREE, RSTART, CONNEC, TREE1, OFFDIA, WORK,
1221     1             MXCOMP, WORK(START), WORK(SIZE), COMPNS, ERROR,
1222     2             SPACE)
1223      IF ( ERROR .NE. 0 )  GO TO 5000
1224C
1225C     ... RECORD SPACE ACTUALLY USED  (NOT INCLUDING  NUMBERED )
1226C
1227      SPACE = 2*N + 3*(DEPTH) + 2*COMPNS + OFFDIA
1228C
1229C     ... SORT THE COMPONENT START POINTERS INTO INCREASING ORDER
1230C         OF SIZE OF COMPONENT
1231C
1232      IF (COMPNS .GT. 1)
1233     1    CALL GPSKCN (COMPNS, WORK(SIZE), WORK(START), ERROR)
1234          IF  (ERROR .NE. 0)  GO TO 6200
1235C
1236C     ... FOR EACH COMPONENT IN TURN, CHOOSE TO USE THE ORDERING OF THE
1237C         'FORWARD' TREE1 OR OF THE 'BACKWARD' TREE2 TO NUMBER THE NODES
1238C         IN THIS COMPONENT.  THE NUMBERING IS CHOSEN TO MINIMIZE THE
1239C         MAXIMUM INCREMENT TO ANY LEVEL.
1240C
1241      DO 1000 COMPON = 1, COMPNS
1242          PCSTRT = START + COMPON - 1
1243          CSTART = WORK (PCSTRT)
1244          PCSIZE = SIZE + COMPON - 1
1245          CSIZE = WORK (PCSIZE)
1246          CSTOP  = CSTART + CSIZE - 1
1247          IF ( ( CSIZE .LT. 0 ) .OR. ( CSIZE .GT. OFFDIA ) )  GO TO 6100
1248C
1249          DO 300 I = 1, DEPTH
1250              INC1(I) = 0
1251              INC2(I) = 0
1252  300     CONTINUE
1253C
1254          MXINC1 = 0
1255          MXINC2 = 0
1256C
1257          DO 400 I = CSTART, CSTOP
1258              WORKI = WORK(I)
1259              TWORKI = -TREE1 (WORKI)
1260              INC1 (TWORKI) = INC1 (TWORKI) + 1
1261              TWORKI =  TREE2 (WORKI)
1262              INC2 (TWORKI) = INC2 (TWORKI) + 1
1263  400     CONTINUE
1264C
1265C         ... BAROQUE TESTS BELOW DUPLICATE THE GIBBS-POOLE-STOCKMEYER-
1266C             CRANE PROGRAM, *** NOT *** THE PUBLISHED ALGORITHM.
1267C
1268          DO 500 I = 1, DEPTH
1269              IF ((INC1(I) .EQ. 0) .AND. (INC2(I) .EQ. 0))  GO TO 500
1270                  IF  (MXINC1  .LT.  TOTAL(I) + INC1(I))
1271     1                 MXINC1 = TOTAL(I) + INC1(I)
1272                  IF  (MXINC2  .LT.  TOTAL(I) + INC2(I))
1273     1                 MXINC2 = TOTAL(I) + INC2(I)
1274  500     CONTINUE
1275C
1276C         ... USE ORDERING OF NARROWER TREE UNLESS IT INCREASES
1277C             WIDTH MORE THAN WIDER TREE.  IN CASE OF TIE, USE TREE 2!
1278C
1279          IF ( (MXINC1 .GT. MXINC2)  .OR.
1280     1         ( (MXINC1 .EQ. MXINC2) .AND. ( (WIDTH1 .GT. WIDTH2) .OR.
1281     2                                        ( (WIDTH1 .EQ. WIDTH2)
1282     3                                         .AND. ONEIS1) ) ) )
1283     4      GO TO 700
1284C
1285              IF ( COMPON .EQ. 1 )  REVRS1 = .NOT. ONEIS1
1286C
1287              DO 600 I = 1, DEPTH
1288                  TOTAL(I) = TOTAL(I) + INC1(I)
1289  600         CONTINUE
1290              GO TO 1000
1291C
1292  700         IF ( COMPON .EQ. 1 )  REVRS1 = ONEIS1
1293              DO 800 I = CSTART, CSTOP
1294                  WORKI = WORK(I)
1295                  TREE1 (WORKI) = - TREE2 (WORKI)
1296  800         CONTINUE
1297C
1298              DO 900 I = 1, DEPTH
1299                  TOTAL(I) = TOTAL(I) + INC2(I)
1300  900         CONTINUE
1301C
1302 1000 CONTINUE
1303      GO TO 2000
1304C
1305C     ... DEFAULT WHEN THE REDUCED GRAPH IS EMPTY
1306C
1307 1100 REVRS1 = .TRUE.
1308      SPACE = 2*N
1309C
1310 2000 RETURN
1311C
1312C     ------------------------------------------------------------------
1313C
1314C     ERROR FOUND ...
1315C
1316 5000 SPACE = -1
1317      GO TO 2000
1318C
1319 5100 SPACE = 2 - AVAIL
1320      ERROR = 131
1321      GO TO 2000
1322C
1323 6000 ERROR = 30
1324      GO TO 5000
1325C
1326 6100 ERROR = 31
1327      GO TO 5000
1328C
1329 6200 ERROR = 32
1330      GO TO 5000
1331C
1332      END
1333      SUBROUTINE   GPSKCH   (N, DEGREE, RSTART, CONNEC, STATUS, NREDUC, GPSK1289
1334     1                       WORK, MXCOMP, START, SIZE, COMPNS, ERROR,
1335     2                       SPACE)
1336C
1337C     ==================================================================
1338C
1339C     FIND THE CONNECTED COMPONENTS OF THE GRAPH INDUCED BY THE SET
1340C     OF NODES WITH POSITIVE 'STATUS'.  WE SHALL BUILD THE LIST OF
1341C     CONNECTED COMPONENTS IN 'WORK', WITH A LIST OF POINTERS
1342C     TO THE BEGINNING NODES OF COMPONENTS LOCATED IN 'START'
1343C
1344C
1345      INTEGER     N, RSTART(N), NREDUC, MXCOMP, COMPNS, ERROR, SPACE
1346C
1347CIBM  INTEGER *2  DEGREE(N), CONNEC(1), STATUS(N), WORK(NREDUC),
1348      INTEGER     DEGREE(N), CONNEC(1), STATUS(N), WORK(NREDUC),
1349     1            START(MXCOMP), SIZE(MXCOMP)
1350C
1351C
1352C     PARAMETERS ...
1353C
1354C         N      -- DIMENSION OF THE ORIGINAL MATRIX
1355C         DEGREE, RSTART, CONNEC -- THE STRUCTURE OF THE ORIGINAL MATRIX
1356C
1357C         STATUS -- DERIVED FROM A LEVEL TREE. POSITIVE ENTRIES INDICATE
1358C                   ACTIVE NODES.  NODES WITH STATUS <= 0 ARE IGNORED.
1359C
1360C         NREDUC -- THE NUMBER OF ACTIVE NODES
1361C
1362C         WORK   -- WORK SPACE, USED AS A QUEUE TO BUILD CONNECTED
1363C                   COMPONENTS IN PLACE.
1364C
1365C         MXCOMP -- MAXIMUM NUMBER OF COMPONENTS ALLOWED BY CURRENT
1366C                   SPACE ALLOCATION.  MUST NOT BE VIOLATED.
1367C
1368C         START  -- POINTER TO BEGINNING OF  I-TH  CONNECTED COMPONENT
1369C
1370C         SIZE   -- SIZE OF EACH COMPONENT
1371C
1372C         COMPNS -- NUMBER OF COMPONENTS ACTUALLY FOUND
1373C
1374C         ERROR  -- SHOULD BE ZERO ON RETURN UNLESS WE HAVE TOO LITTLE
1375C                   SPACE OR WE ENCOUNTER AN ERROR IN THE DATA STRUCTURE
1376C
1377C         SPACE  -- MAXIMUM AMOUNT OF WORKSPACE USED / NEEDED
1378C
1379C     ==================================================================
1380C
1381      INTEGER     I, J, FREE, JPTR, NODE, JNODE, FRONT, CDGREE, ROOT
1382C
1383C     ------------------------------------------------------------------
1384C
1385C
1386C     REPEAT
1387C         << FIND AN UNASSIGNED NODE AND START A NEW COMPONENT >>
1388C         REPEAT
1389C             << ADD ALL NEW NEIGHBORS OF FRONT NODE TO QUEUE, >>
1390C             << REMOVE FRONT NODE.                            >>
1391C         UNTIL <<QUEUE EMPTY>>
1392C     UNTIL << ALL NODES ASSIGNED >>
1393C
1394      FREE   = 1
1395      COMPNS = 0
1396      ROOT   = 1
1397C
1398C     ... START OF OUTER REPEAT LOOP
1399C
1400C         ... FIND AN UNASSIGNED NODE
1401C
1402  100     DO 200 I = ROOT, N
1403              IF (STATUS(I) .LE. 0) GO TO 200
1404                  NODE = I
1405                  GO TO 300
1406  200     CONTINUE
1407          GO TO 6100
1408C
1409C         ... START NEW COMPONENT
1410C
1411  300     COMPNS = COMPNS + 1
1412          ROOT   = NODE + 1
1413          IF (COMPNS .GT. MXCOMP)  GO TO 5000
1414          START (COMPNS) = FREE
1415          WORK (FREE) = NODE
1416          STATUS (NODE) = -STATUS (NODE)
1417          FRONT = FREE
1418          FREE = FREE + 1
1419C
1420C             ... INNER REPEAT UNTIL QUEUE BECOMES EMPTY
1421C
1422  400         NODE = WORK (FRONT)
1423              FRONT = FRONT + 1
1424C
1425              JPTR = RSTART (NODE)
1426              CDGREE = DEGREE (NODE)
1427              DO 500 J = 1, CDGREE
1428                  JNODE = CONNEC (JPTR)
1429                  JPTR = JPTR + 1
1430                  IF (STATUS(JNODE) .LT. 0) GO TO 500
1431                  IF (STATUS(JNODE) .EQ. 0) GO TO 6000
1432                      STATUS (JNODE) = -STATUS (JNODE)
1433                      WORK (FREE) = JNODE
1434                      FREE = FREE + 1
1435  500         CONTINUE
1436C
1437              IF (FRONT .LT. FREE) GO TO 400
1438C
1439C         ... END OF INNER REPEAT.  COMPUTE SIZE OF COMPONENT AND
1440C             SEE IF THERE ARE MORE NODES TO BE ASSIGNED
1441C
1442          SIZE (COMPNS) = FREE - START (COMPNS)
1443          IF (FREE .LE. NREDUC)  GO TO 100
1444C
1445      IF (FREE .NE. NREDUC+1)  GO TO 6200
1446      RETURN
1447C
1448C     ------------------------------------------------------------------
1449C
1450 5000 SPACE = NREDUC - FREE + 1
1451      ERROR = 130
1452      RETURN
1453C
1454 6000 ERROR = 33
1455      SPACE = -1
1456      RETURN
1457C
1458 6100 ERROR = 34
1459      SPACE = -1
1460      RETURN
1461C
1462 6200 ERROR = 35
1463      SPACE = -1
1464      RETURN
1465      END
1466      SUBROUTINE   GPSKCI   (N, ACTIVE, DEPTH, LSTRUC, LVLLST, LVLPTR,  GPSK1422
1467     1                       LTOTAL, ERROR, SPACE)
1468C
1469C     ==================================================================
1470C
1471C     TRANSITIONAL SUBROUTINE, ALGORITHM II TO IIIA OR IIIB.
1472C
1473C     CONVERT LEVEL STRUCTURE GIVEN AS VECTOR OF LEVEL NUMBERS FOR NODES
1474C     TO STRUCTURE AS LIST OF NODES BY LEVEL
1475C
1476C     N, ACTIVE, DEPTH -- PROBLEM SIZES
1477C     LSTRUC -- INPUT LEVEL STRUCTURE
1478C     LVLLST, LVLPTR -- OUTPUT LEVEL STRUCTURE
1479C     LTOTAL -- NUMBER OF NODES AT EACH LEVEL (PRECOMPUTED)
1480C
1481      INTEGER     N, ACTIVE, DEPTH, ERROR, SPACE
1482C
1483CIBM  INTEGER *2  LSTRUC(N), LVLLST(ACTIVE), LVLPTR(1), LTOTAL(DEPTH)
1484      INTEGER     LSTRUC(N), LVLLST(ACTIVE), LVLPTR(1), LTOTAL(DEPTH)
1485C
1486C     ===============================================================
1487C
1488C     STRUCTURE OF WORKSPACE ..
1489C
1490C         INPUT (FROM COMBIN) ..
1491C
1492C     ------------------------------------------------------------------
1493C     :  NUMBERED  :  ..(N)..  :  TOTAL  :         ...        :  TREE  :
1494C     ------------------------------------------------------------------
1495C
1496C         OUTPUT (TO GPSKCJ OR GPSKCK) ..
1497C
1498C     ------------------------------------------------------------------
1499C     :  NUMBERED  :       ...             :  TLIST  :  TPTR  :  TREE  :
1500C     ------------------------------------------------------------------
1501C
1502C     HERE, NUMBERED IS THE SET OF NODES IN NUMBERED COMPONENTS
1503C         TOTAL IS A VECTOR OF LENGTH 'DEPTH' GIVING THE NUMBER
1504C         OF NODES IN EACH LEVEL OF THE 'TREE'.
1505C         TLIST, TPTR ARE LISTS OF NODES OF THE TREE, ARRANGED
1506C         BY LEVEL.  TLIST IS OF LENGTH 'ACTIVE', TPTR 'DEPTH+1'.
1507C
1508C     =================================================================
1509C
1510      INTEGER     I, ACOUNT, START, LEVEL, PLEVEL
1511C
1512C     ... ESTABLISH STARTING AND ENDING POINTERS FOR EACH LEVEL
1513C
1514      START = 1
1515      DO 100 I = 1, DEPTH
1516          LVLPTR(I) = START
1517          START = START + LTOTAL(I)
1518          LTOTAL(I) = START
1519  100 CONTINUE
1520      LVLPTR(DEPTH+1) = START
1521C
1522      ACOUNT = 0
1523      DO 300 I = 1, N
1524          IF (LSTRUC(I)) 200, 300, 6000
1525  200         LEVEL = -LSTRUC(I)
1526              LSTRUC(I) = LEVEL
1527              PLEVEL = LVLPTR (LEVEL)
1528              LVLLST (PLEVEL) = I
1529              LVLPTR (LEVEL) = LVLPTR (LEVEL) + 1
1530              ACOUNT = ACOUNT + 1
1531              IF (LVLPTR (LEVEL) .GT. LTOTAL (LEVEL))  GO TO 6100
1532  300 CONTINUE
1533C
1534C     ... RESET STARTING POINTERS
1535C
1536      LVLPTR(1) = 1
1537      DO 400 I = 1, DEPTH
1538          LVLPTR(I+1) = LTOTAL(I)
1539  400 CONTINUE
1540C
1541      RETURN
1542C
1543C     ------------------------------------------------------------------
1544C
1545 6000 ERROR = 40
1546      GO TO 6200
1547C
1548 6100 ERROR = 41
1549C
1550 6200 SPACE = -1
1551      RETURN
1552C
1553      END
1554      SUBROUTINE   GPSKCJ   (N, DEGREE, RSTART, CONNEC,                 GPSK1510
1555     1                       NCOMPN, INVNUM, SNODE1, SNODE2, REVRS1,
1556     2                       DEPTH, LVLLST, LVLPTR, LVLNUM, ERROR,
1557     3                       SPACE)
1558C
1559C     ==================================================================
1560C
1561C     NUMBER THE NODES IN A GENERALIZED LEVEL STRUCTURE ACCORDING
1562C     TO A GENERALIZATION OF THE CUTHILL MCKEE STRATEGY.
1563C
1564C     N      -- DIMENSION OF ORIGINAL PROBLEM
1565C     DEGREE, RSTART, CONNEC -- GIVE STRUCTURE OF SPARSE AND
1566C                               SYMMETRIC MATRIX
1567C
1568C     NCOMPN -- NUMBER OF NODES IN THIS COMPONENT OF MATRIX GRAPH
1569C
1570C     INVNUM -- WILL BECOME A LIST OF THE ORIGINAL NODES IN THE ORDER
1571C               WHICH REDUCES THE BANDWIDTH OF THE MATRIX.
1572C
1573C     NXTNUM -- THE NEXT INDEX TO BE ASSIGNED (1 FOR FIRST COMPONENT)
1574C
1575C     REVRS1 -- IF .TRUE., FIRST COMPONENT OF REDUCED GRAPH WAS NUMBERED
1576C               BACKWARDS.
1577C
1578C     LVLLST -- LIST OF NODES IN LEVEL TREE ORDERED BY LEVEL.
1579C
1580C     LVLPTR -- POSITION OF INITIAL NODE IN EACH LEVEL OF LVLLST.
1581C
1582C     LVLNUM -- LEVEL NUMBER OF EACH NODE IN COMPONENT
1583C
1584C
1585      INTEGER     N, RSTART(N), NCOMPN, SNODE1, SNODE2, DEPTH,
1586     1            ERROR, SPACE
1587C
1588CIBM  INTEGER *2  DEGREE(N), CONNEC(1), INVNUM(NCOMPN),
1589      INTEGER     DEGREE(N), CONNEC(1), INVNUM(NCOMPN),
1590     1            LVLLST(NCOMPN), LVLPTR(DEPTH), LVLNUM(N)
1591C
1592      LOGICAL     REVRS1
1593C
1594C
1595C     ==================================================================
1596C
1597C     NUMBERING REQUIRES TWO QUEUES, WHICH CAN BE BUILD IN PLACE
1598C     IN INVNUM.
1599C
1600C
1601C     ==================================================================
1602C     A L G O R I T H M    S T R U C T U R E
1603C     ==================================================================
1604C
1605C     << SET QUEUE1 TO BE THE SET CONTAINING ONLY THE START NODE. >>
1606C
1607C     FOR LEVEL = 1 TO DEPTH DO
1608C
1609C         BEGIN
1610C         LOOP
1611C
1612C             REPEAT
1613C                 BEGIN
1614C                 << CNODE <- FRONT OF QUEUE1                        >>
1615C                 << ADD UNNUMBERED NEIGHBORS OF CNODE TO THE BACK   >>
1616C                 << OF QUEUE1 OR QUEUE2 (USE QUEUE1 IF NEIGHBOR     >>
1617C                 << AT SAME LEVEL, QUEUE2 IF AT NEXT LEVEL).  SORT  >>
1618C                 << THE NEWLY QUEUED NODES INTO INCREASING ORDER OF >>
1619C                 << DEGREE.  NUMBER CNODE, DELETE IT FROM QUEUE1.   >>
1620C                 END
1621C             UNTIL
1622C                 << QUEUE1 IS EMPTY >>
1623C
1624C         EXIT IF << ALL NODES AT THIS LEVEL NUMBERED >>
1625C
1626C             BEGIN
1627C             << FIND THE UNNUMBERED NODE OF MINIMAL DEGREE AT THIS >>
1628C             << LEVEL, RESTART QUEUE1 WITH THIS NODE.              >>
1629C             END
1630C
1631C         END << LOOP LOOP >>
1632C
1633C         << PROMOTE QUEUE2 TO BE INITIAL QUEUE1 FOR NEXT ITERATION >>
1634C         << OF  FOR  LOOP.                                         >>
1635C
1636C         END <<FOR LOOP>>
1637C
1638C     ==================================================================
1639C
1640C     STRUCTURE OF WORKSPACE ..
1641C
1642C     --------------------------------------------------------------
1643C     : NUMBERED :  QUEUE1  :  QUEUE2  : ... : TLIST : TPTR : TREE :
1644C     --------------------------------------------------------------
1645C
1646C     ON COMPLETION, WE HAVE ONLY A NEW, LONGER NUMBERED SET.
1647C
1648C     ==================================================================
1649      INTEGER     I, BQ1, BQ2, FQ1, INC, CPTR, CNODE,
1650     1            INODE, LEVEL, NLEFT, LSTART, LWIDTH, QUEUE1,
1651     2            QUEUE2, CDGREE, XLEVEL, STNODE, ILEVEL, SQ1, SQ2,
1652     3            NSORT, LOWDG, BPTR, LVLLSC, LVLLSB, INVNMI
1653C
1654      LOGICAL     FORWRD, RLEVEL
1655C
1656C     ------------------------------------------------------------------
1657C
1658C     ... GIBBS-POOLE-STOCKMEYER HEURISTIC CHOICE OF ORDER
1659C
1660      IF  (DEGREE(SNODE1) .GT. DEGREE(SNODE2))  GO TO 10
1661          FORWRD = REVRS1
1662          STNODE = SNODE1
1663          GO TO 20
1664C
1665   10     FORWRD = .NOT. REVRS1
1666          STNODE = SNODE2
1667C
1668C     ... SET UP INITIAL QUEUES AT FRONT OF 'INVNUM' FOR FORWRD ORDER,
1669C         AT BACK FOR REVERSED ORDER.
1670C
1671   20 IF (FORWRD) GO TO 100
1672          INC = -1
1673          QUEUE1 = NCOMPN
1674          GO TO 200
1675C
1676  100     INC = +1
1677          QUEUE1 = 1
1678C
1679  200 INVNUM (QUEUE1) = STNODE
1680      RLEVEL = (LVLNUM(STNODE) .EQ. DEPTH)
1681      LVLNUM (STNODE) = 0
1682      FQ1 = QUEUE1
1683      BQ1 = QUEUE1 + INC
1684C
1685C     -------------------------------
1686C     NUMBER NODES LEVEL BY LEVEL ...
1687C     -------------------------------
1688C
1689      DO 3000 XLEVEL = 1, DEPTH
1690          LEVEL = XLEVEL
1691          IF  (RLEVEL)  LEVEL = DEPTH - XLEVEL + 1
1692C
1693          LSTART = LVLPTR (LEVEL)
1694          LWIDTH = LVLPTR (LEVEL+1) - LSTART
1695          NLEFT = LWIDTH
1696          QUEUE2 = QUEUE1 + INC*LWIDTH
1697          BQ2 = QUEUE2
1698C
1699C         ==============================================================
1700C         ... 'LOOP' CONSTRUCT BEGINS AT STATEMENT 1000
1701C                 THE INNER 'REPEAT' WILL BE DONE AS MANY TIMES AS
1702C                 IS NECESSARY TO NUMBER ALL THE NODES AT THIS LEVEL.
1703C         ==============================================================
1704C
1705 1000     CONTINUE
1706C
1707C             ==========================================================
1708C             ... REPEAT ... UNTIL QUEUE1 BECOMES EMPTY
1709C                 TAKE NODE FROM FRONT OF QUEUE1, FIND EACH OF ITS
1710C                 NEIGHBORS WHICH HAVE NOT YET BEEN NUMBERED, AND
1711C                 ADD THE NEIGHBORS TO QUEUE1 OR QUEUE2 ACCORDING TO
1712C                 THEIR LEVELS.
1713C             ==========================================================
1714C
1715 1100             CNODE = INVNUM (FQ1)
1716                  FQ1 = FQ1 + INC
1717                  SQ1 = BQ1
1718                  SQ2 = BQ2
1719                  NLEFT = NLEFT - 1
1720C
1721                  CPTR = RSTART (CNODE)
1722                  CDGREE = DEGREE (CNODE)
1723                  DO 1300 I = 1, CDGREE
1724                      INODE = CONNEC (CPTR)
1725                      CPTR = CPTR + 1
1726                      ILEVEL = LVLNUM (INODE)
1727                      IF (ILEVEL .EQ. 0)  GO TO 1300
1728                          LVLNUM (INODE) = 0
1729                          IF ( ILEVEL .EQ. LEVEL ) GO TO 1200
1730C
1731                              IF  (IABS(LEVEL-ILEVEL) .NE. 1) GO TO 6400
1732                                  INVNUM (BQ2) = INODE
1733                                  BQ2 = BQ2 + INC
1734                                  GO TO 1300
1735C
1736 1200                             INVNUM (BQ1) = INODE
1737                                  BQ1 = BQ1 + INC
1738 1300             CONTINUE
1739C
1740C                 ==================================================
1741C                 ... SORT THE NODES JUST ADDED TO QUEUE1 AND QUEUE2
1742C                     SEPARATELY INTO INCREASING ORDER OF DEGREE.
1743C                 ==================================================
1744C
1745                  IF  (IABS (BQ1 - SQ1) .LE. 1)  GO TO 1500
1746                      NSORT = IABS (BQ1 - SQ1)
1747                      IF  (FORWRD)  GO TO 1400
1748                          CALL GPSKCP (NSORT, INVNUM(BQ1+1), N, DEGREE,
1749     1                                 ERROR)
1750                          IF  (ERROR .NE. 0)  GO TO 6600
1751                          GO TO 1500
1752C
1753 1400                     CALL GPSKCQ (NSORT, INVNUM(SQ1), N, DEGREE,
1754     1                                 ERROR)
1755                          IF  (ERROR .NE. 0)  GO TO 6600
1756C
1757 1500             IF  (IABS (BQ2 - SQ2) .LE. 1)  GO TO 1700
1758                      NSORT = IABS (BQ2 - SQ2)
1759                      IF  (FORWRD)  GO TO 1600
1760                          CALL GPSKCP (NSORT, INVNUM(BQ2+1), N, DEGREE,
1761     1                                 ERROR)
1762                          IF  (ERROR .NE. 0)  GO TO 6600
1763                          GO TO 1700
1764C
1765 1600                     CALL GPSKCQ (NSORT, INVNUM(SQ2), N, DEGREE,
1766     1                                 ERROR)
1767                          IF  (ERROR .NE. 0)  GO TO 6600
1768C
1769C                     ... END OF REPEAT LOOP
1770C
1771 1700             IF  (FQ1 .NE. BQ1)  GO TO 1100
1772C
1773C         ==============================================================
1774C         ... QUEUE1 IS NOW EMPTY ...
1775C             IF THERE ARE ANY UNNUMBERED NODES LEFT AT THIS LEVEL,
1776C             FIND THE ONE OF MINIMAL DEGREE AND RETURN TO THE
1777C             REPEAT LOOP ABOVE.
1778C         ==============================================================
1779C
1780 2000     IF  ((BQ1 .EQ. QUEUE2) .AND. (NLEFT .EQ. 0))  GO TO 2900
1781C
1782              IF ((NLEFT .LE. 0) .OR. (NLEFT .NE. INC * (QUEUE2 - BQ1)))
1783     1             GO TO 6200
1784C
1785              LOWDG = N + 1
1786              BPTR  = N + 1
1787              CPTR  = LSTART - 1
1788              DO 2800 I = 1, NLEFT
1789 2600             CPTR   = CPTR + 1
1790                  LVLLSC = LVLLST (CPTR)
1791                  IF (LVLNUM (LVLLSC) .EQ. LEVEL)  GO TO 2700
1792                      IF (LVLNUM (LVLLSC) .NE. 0)  GO TO 6300
1793                      GO TO 2600
1794C
1795 2700             IF  (DEGREE(LVLLSC) .GE. LOWDG)  GO TO 2800
1796                      LOWDG = DEGREE (LVLLSC)
1797                      BPTR  = CPTR
1798C
1799 2800         CONTINUE
1800C
1801C             ... MINIMAL DEGREE UNNUMBERED NODE FOUND ...
1802C
1803              IF  (BPTR .GT. N)  GO TO 6500
1804              LVLLSB = LVLLST (BPTR)
1805              INVNUM (BQ1) = LVLLSB
1806              LVLNUM (LVLLSB) = 0
1807              BQ1 = BQ1 + INC
1808              GO TO 1000
1809C
1810C             =============================================
1811C             ... ADVANCE QUEUE POINTERS TO MAKE QUEUE2 THE
1812C                 NEW QUEUE1 FOR THE NEXT ITERATION.
1813C             =============================================
1814C
1815 2900     QUEUE1 = QUEUE2
1816          FQ1 = QUEUE1
1817          BQ1 = BQ2
1818          IF  ((BQ1 .EQ. FQ1) .AND. (XLEVEL .LT. DEPTH))  GO TO 6100
1819C
1820 3000 CONTINUE
1821C
1822C     ... CHANGE SIGN OF DEGREE TO MARK THESE NODES AS 'NUMBERED'
1823C
1824      DO 3100 I = 1, NCOMPN
1825          INVNMI = INVNUM(I)
1826          DEGREE (INVNMI) = -DEGREE (INVNMI)
1827 3100 CONTINUE
1828C
1829      RETURN
1830C
1831C     ------------------------------------------------------------------
1832C
1833 6000 SPACE = -1
1834      RETURN
1835C
1836 6100 ERROR = 51
1837      GO TO 6000
1838C
1839 6200 ERROR = 52
1840      GO TO 6000
1841C
1842 6300 ERROR = 53
1843      GO TO 6000
1844C
1845 6400 ERROR = 54
1846      GO TO 6000
1847C
1848 6500 ERROR = 55
1849      GO TO 6000
1850C
1851 6600 ERROR = 56
1852      GO TO 6000
1853C
1854      END
1855      SUBROUTINE  GPSKCK  (N, DEGREE, RSTART, CONNEC, WRKLEN, NXTNUM,   GPSK1811
1856     1                     WORK, NCOMPN, DEPTH, LVLLST, LVLPTR, LVLNUM,
1857     2                     ERROR, SPACE)
1858C
1859      INTEGER     N, RSTART(N), WRKLEN, NXTNUM, NCOMPN, DEPTH, ERROR,
1860     1            SPACE
1861C
1862CIBM  INTEGER *2  DEGREE(N), CONNEC(1), WORK(WRKLEN), LVLLST(N),
1863      INTEGER     DEGREE(N), CONNEC(1), WORK(WRKLEN), LVLLST(N),
1864     1            LVLPTR(DEPTH), LVLNUM(N)
1865C
1866C     ==================================================================
1867C
1868C     NUMBER NODES IN A GENERALIZED LEVEL STRUCTURE ACCORDING TO
1869C     A GENERALIZATION OF THE KING ALGORITHM, WHICH REDUCES
1870C     THE PROFILE OF THE SPARSE SYMMETRIC MATRIX.
1871C
1872C     ---------------------
1873C
1874C     CODE USES A PRIORITY QUEUE TO CHOOSE THE NEXT NODE TO BE NUMBERED
1875C     THE PRIORITY QUEUE IS REPRESENTED BY A SIMPLE LINEAR-LINKED LIST
1876C     TO SAVE SPACE.  THIS WILL REQUIRE MORE SEARCHING THAN A FULLY
1877C     LINKED REPRESENTATION, BUT THE DATA MANIPULATION IS SIMPLER.
1878C
1879C     -------------------
1880C
1881C     << ESTABLISH PRIORITY QUEUE 'ACTIVE' FOR LEVEL 1 NODES >>
1882C
1883C     FOR I = 1 TO DEPTH DO
1884C         << SET QUEUE 'QUEUED' TO BE EMPTY, LIST 'NEXT' TO BE >>
1885C         << SET OF NODES AT NEXT LEVEL.                       >>
1886C
1887C         FOR J = 1 TO 'NODES AT THIS LEVEL' DO
1888C             << FIND FIRST NODE IN ACTIVE WITH MINIMAL CONNECTIONS >>
1889C             << TO 'NEXT'.  NUMBER THIS NODE AND REMOVE HIM FROM   >>
1890C             << 'ACTIVE'.  FOR EACH NODE IN 'NEXT' WHICH CONNECTED >>
1891C             << TO THIS NODE, MOVE IT TO 'QUEUED' AND REMOVE IT    >>
1892C             << FROM 'NEXT'.                                       >>
1893C
1894C         << SET NEW QUEUE 'ACTIVE' TO BE 'QUEUED' FOLLOWED BY ANY >>
1895C         << NODES STILL IN 'NEXT'.                                >>
1896C
1897C     ==================================================================
1898C
1899C     DATA STRUCTURE ASSUMPTIONS:
1900C     THE FIRST 'NXTNUM-1' ELEMENTS OF  WORK  ARE ALREADY IN USE.
1901C     THE LEVEL STRUCTURE 'LVLLST' IS CONTIGUOUS WITH  WORK, THAT IS,
1902C     IT RESIDES IN ELEMENTS  WRKLEN+1, ...  OF  WORK.  'LVLPTR' AND
1903C     'LVLNUM' ARE ALSO EMBEDDED IN WORK, BEHIND 'LVLLST'.  THE
1904C     THREE VECTORS ARE PASSED SEPARATELY TO CLARIFY THE INDEXING,
1905C     BUT THE QUEUES DEVELOPED WILL BE ALLOWED TO OVERRUN 'LVLLST'
1906C     AS NEEDED.
1907C
1908C     ... BUILD THE FIRST 'ACTIVE' QUEUE STARTING W1 LOCATIONS FROM
1909C         THE FRONT OF THE CURRENT WORKING AREA  (W1 IS THE WIDTH OF THE
1910C         FIRST LEVEL).  BUILD THE FIRST 'QUEUED' QUEUE STARTING FROM
1911C         THE BACK OF WORK SPACE.  THE LIST 'NEXT' WILL BE REALIZED
1912C         IMPLICITLY IN 'LVLNUM' AS:
1913C                  LVLNUM(I) > 0   <== LEVEL NUMBER OF NODE.  'NEXT' IS
1914C                                      SET WITH LVLNUM(I) = LEVEL+1
1915C                  LVLNUM(I) = 0   <== I-TH NODE IS IN 'QUEUED' OR IS
1916C                                      NOT IN THIS COMPONENT OF GRAPH,
1917C                                      OR HAS JUST BEEN NUMBERED.
1918C                  LVLNUM(I) < 0   <== I-TH NODE IS IN 'ACTIVE' AND IS
1919C                                      CONNECTED TO -LVLNUM(I) NODES IN
1920C                                      'NEXT'.
1921C
1922C     ==================================================================
1923C
1924C     STRUCTURE OF WORKSPACE ..
1925C
1926C     --------------------------------------------------------------
1927C     : NUMBERED : DONE : ACTIVE : ALEVEL : ... : QUEUED : LVLLST :
1928C     --------------------------------------------------------------
1929C
1930C     -------------------
1931C       LVLPTR : LVLNUM :
1932C     -------------------
1933C
1934C     IN THE ABOVE,
1935C         NUMBERED IS THE SET OF NODES ALREADY NUMBERED FROM
1936C         PREVIOUS COMPONENTS AND EARLIER LEVELS OF THIS COMPONENT.
1937C         DONE, ACTIVE, ALEVEL  ARE VECTORS OF LENGTH THE WIDTH OF
1938C         THE CURRENT LEVEL.  ACTIVE IS A SET OF INDICES INTO
1939C         ALEVEL.  AS THE NODES IN ALEVEL ARE NUMBERED, THEY
1940C         ARE PLACED INTO 'DONE'.
1941C         QUEUED IS A QUEUE OF NODES IN THE 'NEXT' LEVEL, WHICH
1942C         GROWS FROM THE START OF THE 'NEXT' LEVEL IN LVLLST
1943C         FORWARDS TOWARD 'ALEVEL'.  QUEUED IS OF LENGTH NO MORE
1944C         THAN THE WIDTH OF THE NEXT LEVEL.
1945C         LVLLST IS THE LIST OF UNNUMBERED NODES IN THE TREE,
1946C         ARRANGED BY LEVEL.
1947C
1948C     ==================================================================
1949      INTEGER     I, J, K, PTR, JPTR, KPTR, LPTR, MPTR, PPTR, RPTR,
1950     1            MPPTR, JNODE, KNODE, CNODE, LEVEL, LOWDG, UNUSED,
1951     2            MXQUE, NNEXT, ASTART, MINDG, LSTART, LWIDTH, ACTIVE,
1952     2            QUEUEB, QUEUED, QCOUNT, NCONNC, NACTIV, CDGREE,
1953     3            LDGREE, NFINAL, JDGREE, STRTIC, ADDED, TWRKLN,
1954     4            LVLLSL, CONNEJ, CONNER, ASTPTR, ACTPTR, ACTIVI,
1955     5            ASTRTI, QUEUEI, ACPPTR
1956C
1957C     ------------------------------------------------------------------
1958C
1959      TWRKLN = WRKLEN + NCOMPN + N + DEPTH + 1
1960      UNUSED = TWRKLN
1961C
1962      ASTART = LVLPTR(1)
1963      LWIDTH = LVLPTR(2) - ASTART
1964      ASTART = WRKLEN  + 1
1965      ACTIVE = NXTNUM + LWIDTH + 1
1966      NACTIV = LWIDTH
1967      NFINAL = NXTNUM + NCOMPN
1968C
1969      NNEXT = LVLPTR(3) - LVLPTR(2)
1970      QUEUED = WRKLEN
1971      QUEUEB = QUEUED
1972      MXQUE = ACTIVE + LWIDTH
1973C
1974C     ... BUILD FIRST PRIORITY QUEUE 'ACTIVE'
1975C
1976      LOWDG = - (N + 1)
1977      LPTR = LVLPTR(1)
1978      DO 200 I = 1, LWIDTH
1979          NCONNC = 0
1980          LVLLSL= LVLLST (LPTR)
1981          JPTR = RSTART (LVLLSL)
1982          LDGREE = DEGREE(LVLLSL)
1983          DO 100 J = 1, LDGREE
1984              CONNEJ = CONNEC (JPTR)
1985              IF ( LVLNUM (CONNEJ) .EQ. 2 )  NCONNC = NCONNC - 1
1986              JPTR = JPTR + 1
1987  100     CONTINUE
1988C
1989          ACTIVI = ACTIVE + I - 1
1990          WORK (ACTIVI) = I
1991          LVLNUM (LVLLSL) = NCONNC
1992          LOWDG = MAX0 (LOWDG, NCONNC)
1993          LPTR = LPTR + 1
1994  200 CONTINUE
1995      WORK (ACTIVE-1) = 0
1996C
1997C     -----------------------------------
1998C     NOW NUMBER NODES LEVEL BY LEVEL ...
1999C     -----------------------------------
2000C
2001      DO 2000 LEVEL = 1, DEPTH
2002C
2003C         ... NUMBER ALL NODES IN THIS LEVEL
2004C
2005          DO 1100 I = 1, LWIDTH
2006              PPTR = -1
2007              PTR = WORK (ACTIVE-1)
2008              IF (NNEXT .EQ. 0)  GO TO 1000
2009C
2010C                 ... IF NODES REMAIN IN NEXT, FIND THE EARLIEST NODE
2011C                     IN ACTIVE OF MINIMAL DEGREE.
2012C
2013                  MINDG = -(N+1)
2014                  DO 400 J = 1, NACTIV
2015                      ASTPTR = ASTART + PTR
2016                      CNODE = WORK (ASTPTR)
2017                      IF ( LVLNUM (CNODE) .EQ. LOWDG )  GO TO 500
2018                      IF ( LVLNUM (CNODE) .LE. MINDG )  GO TO 300
2019                          MPPTR = PPTR
2020                          MPTR = PTR
2021                          MINDG = LVLNUM (CNODE)
2022  300                 PPTR = PTR
2023                      ACTPTR = ACTIVE + PTR
2024                      PTR = WORK (ACTPTR)
2025  400             CONTINUE
2026C
2027C                     ... ESTABLISH  PTR  AS FIRST MIN DEGREE NODE
2028C                         PPTR AS PREDECESSOR IN LIST.
2029C
2030                  PTR = MPTR
2031                  PPTR = MPPTR
2032C
2033  500             ASTPTR = ASTART + PTR
2034                  CNODE = WORK (ASTPTR)
2035                  LOWDG = LVLNUM (CNODE)
2036                  LVLNUM (CNODE) = 0
2037                  JPTR = RSTART (CNODE)
2038C
2039C                 ... UPDATE CONNECTION COUNTS FOR ALL NODES WHICH
2040C                     CONNECT TO  CNODE'S  NEIGHBORS IN  NEXT.
2041C
2042                  CDGREE = DEGREE(CNODE)
2043                  STRTIC = QUEUEB
2044C
2045                  DO 700 J = 1, CDGREE
2046                      JNODE = CONNEC (JPTR)
2047                      JPTR = JPTR + 1
2048                      IF (LVLNUM (JNODE) .NE. LEVEL+1 )  GO TO 700
2049                          IF (QUEUEB .LT. MXQUE)  GO TO 5000
2050                          WORK (QUEUEB) = JNODE
2051                          QUEUEB = QUEUEB - 1
2052                          NNEXT = NNEXT - 1
2053                          LVLNUM (JNODE) = 0
2054                          IF  (NACTIV .EQ. 1)  GO TO 700
2055                            KPTR = RSTART (JNODE)
2056                            JDGREE = DEGREE (JNODE)
2057                            DO 600 K = 1, JDGREE
2058                                KNODE = CONNEC (KPTR)
2059                                KPTR = KPTR + 1
2060                                IF (LVLNUM (KNODE) .GE. 0)  GO TO 600
2061                                    LVLNUM (KNODE) = LVLNUM (KNODE) + 1
2062                                    IF  (LOWDG .LT. LVLNUM(KNODE))
2063     1                                   LOWDG = LVLNUM(KNODE)
2064  600                       CONTINUE
2065  700             CONTINUE
2066C
2067C                 ... TO MIMIC THE ALGORITHM AS IMPLEMENTED BY GIBBS,
2068C                     SORT THE NODES JUST ADDED TO THE QUEUE INTO
2069C                     INCREASING ORDER OF ORIGINAL INDEX. (BUT, BECAUSE
2070C                     THE QUEUE IS STORED BACKWARDS IN MEMORY, THE SORT
2071C                     ROUTINE IS CALLED FOR DECREASING INDEX.)
2072C
2073C                     TREAT  0, 1 OR 2  NODES ADDED AS SPECIAL CASES
2074C
2075                  ADDED = STRTIC - QUEUEB
2076                  IF  (ADDED - 2)  1000, 800, 900
2077C
2078  800                 IF (WORK(STRTIC-1) .GT. WORK(STRTIC))  GO TO 1000
2079                          JNODE = WORK(STRTIC)
2080                          WORK(STRTIC) = WORK(STRTIC-1)
2081                          WORK(STRTIC-1) = JNODE
2082                          GO TO 1000
2083C
2084  900                 CALL GPSKCO (ADDED, WORK(QUEUEB+1), ERROR)
2085                      IF  (ERROR .NE. 0)  GO TO 5500
2086C
2087C
2088C                 ... NUMBER THIS NODE AND DELETE IT FROM 'ACTIVE'.
2089C                     MARK IT UNAVAILABLE BY CHANGING SIGN OF DEGREE
2090C
2091 1000         NACTIV = NACTIV - 1
2092              ASTPTR = ASTART + PTR
2093              CNODE = WORK (ASTPTR)
2094              WORK (NXTNUM) = CNODE
2095              DEGREE (CNODE) = -DEGREE (CNODE)
2096              NXTNUM = NXTNUM + 1
2097C
2098C             ... DELETE LINK TO THIS NODE FROM LIST
2099C
2100              ACPPTR = ACTIVE + PPTR
2101              ACTPTR = ACTIVE + PTR
2102              WORK (ACPPTR) = WORK (ACTPTR)
2103 1100     CONTINUE
2104C
2105C         ... NOW MOVE THE QUEUE 'QUEUED' FORWARD, AT THE SAME
2106C             TIME COMPUTING CONNECTION COUNTS FOR ITS ELEMENTS.
2107C             THEN DO THE SAME FOR THE REMAINING NODES IN 'NEXT'.
2108C
2109          UNUSED = MIN0 (UNUSED, QUEUEB - MXQUE)
2110          IF ( NXTNUM .NE. ACTIVE-1 )  GO TO 5100
2111          IF ( LEVEL .EQ. DEPTH ) GO TO 2000
2112              LSTART = LVLPTR (LEVEL+1)
2113              LWIDTH = LVLPTR (LEVEL+2) - LSTART
2114              ACTIVE = NXTNUM + LWIDTH + 1
2115              ASTART = ACTIVE + LWIDTH
2116              NACTIV = LWIDTH
2117              MXQUE = ASTART + LWIDTH
2118              IF ( MXQUE .GT. QUEUEB + 1 )  GO TO 5000
2119              UNUSED = MIN0 (UNUSED, QUEUEB - MXQUE + 1)
2120C
2121              QCOUNT = QUEUED - QUEUEB
2122              LOWDG = -N-1
2123              WORK (ACTIVE-1) = 0
2124C
2125              PTR = LSTART
2126              DO 1600 I = 1, LWIDTH
2127C
2128C                 ... CHOOSE NEXT NODE FROM EITHER 'QUEUED' OR 'NEXT'
2129C
2130                  IF (I .GT. QCOUNT )  GO TO 1200
2131                      QUEUEI = QUEUED + 1 - I
2132                      CNODE = WORK (QUEUEI)
2133                      GO TO 1300
2134C
2135 1200                 CNODE = LVLLST (PTR)
2136                      PTR = PTR + 1
2137                      IF ( PTR .GT. LVLPTR(LEVEL+2) )  GO TO 5200
2138                          IF (LVLNUM (CNODE) .GT. 0)  GO TO 1300
2139                              GO TO 1200
2140C
2141 1300             IF ( LEVEL+1 .EQ. DEPTH ) GO TO 1500
2142C
2143                      RPTR = RSTART (CNODE)
2144                      NCONNC = 0
2145                      JDGREE = DEGREE (CNODE)
2146                      DO 1400 J = 1, JDGREE
2147                          CONNER = CONNEC (RPTR)
2148                          IF ( LVLNUM (CONNER) .EQ. LEVEL+2 )
2149     1                        NCONNC = NCONNC - 1
2150                          RPTR = RPTR + 1
2151 1400                 CONTINUE
2152                      LVLNUM (CNODE) = NCONNC
2153                      LOWDG = MAX0 (LOWDG, NCONNC)
2154C
2155C             ... ADD CNODE TO NEW 'ACTIVE' QUEUE
2156C
2157 1500             ACTIVI = ACTIVE + (I - 1)
2158                  ASTRTI = ASTART + (I - 1)
2159                  WORK (ACTIVI) = I
2160                  WORK (ASTRTI) = CNODE
2161 1600         CONTINUE
2162C
2163              IF (DEPTH .EQ. LEVEL+1 ) GO TO 1700
2164                  NNEXT = LVLPTR (LEVEL+3) - LVLPTR (LEVEL+2)
2165                  QUEUED = LSTART - 1 + LWIDTH + WRKLEN
2166                  QUEUEB = QUEUED
2167                  GO TO 2000
2168C
2169 1700             NNEXT = 0
2170C
2171 2000 CONTINUE
2172C
2173      IF  (NXTNUM .NE. NFINAL)  GO TO 5300
2174      SPACE = MAX0 (SPACE, TWRKLN - UNUSED)
2175      RETURN
2176C
2177C
2178C     ------------------------------------------------------------------
2179C
2180 5000 SPACE = NACTIV + NNEXT
2181      ERROR = 160
2182      RETURN
2183C
2184 5100 ERROR = 61
2185      GO TO 5400
2186C
2187 5200 ERROR = 62
2188      GO TO 5400
2189C
2190 5300 ERROR = 63
2191C
2192 5400 RETURN
2193C
2194 5500 ERROR = 64
2195      GO TO 5400
2196C
2197      END
2198      SUBROUTINE   GPSKCL   (N, DEGREE, RSTART, CONNEC, INVNUM, NEWNUM, GPSK2154
2199     1                       OLDNUM, BANDWD, PROFIL, ERROR, SPACE)
2200C
2201C
2202      INTEGER     N, RSTART(N), BANDWD, PROFIL, ERROR, SPACE
2203C
2204CIBM  INTEGER *2  DEGREE(N), CONNEC(1), INVNUM(N), NEWNUM(N), OLDNUM(N)
2205      INTEGER     DEGREE(N), CONNEC(1), INVNUM(N), NEWNUM(N),
2206     1            OLDNUM(N)
2207C
2208C     ==================================================================
2209C
2210C
2211C     COMPUTE THE BANDWIDTH AND PROFILE FOR THE RENUMBERING GIVEN
2212C     BY 'INVNUM' AND ALSO FOR THE RENUMBERING GIVEN BY 'OLDNUM'.
2213C     'NEWNUM' WILL BE A PERMUTATION VECTOR COPY OF THE NODE
2214C     LIST 'INVNUM'.
2215C
2216C     ==================================================================
2217C
2218      INTEGER     I, J, JPTR, IDGREE, OLDBND, OLDPRO, NEWBND, NEWPRO,
2219     1            OLDRWD, NEWRWD, OLDORG, NEWORG, JNODE, INVNMI
2220C
2221C     ------------------------------------------------------------------
2222C
2223C     ... CREATE NEWNUM AS A PERMUTATION VECTOR
2224C
2225      DO 100 I = 1, N
2226          INVNMI = INVNUM (I)
2227          NEWNUM (INVNMI) = I
2228  100 CONTINUE
2229C
2230C     ... COMPUTE PROFILE AND BANDWIDTH FOR BOTH THE OLD AND THE NEW
2231C         ORDERINGS.
2232C
2233      OLDBND = 0
2234      OLDPRO = 0
2235      NEWBND = 0
2236      NEWPRO = 0
2237C
2238      DO 300 I = 1, N
2239          IF (DEGREE(I) .EQ. 0)  GO TO 300
2240          IF (DEGREE(I) .GT. 0)  GO TO 6000
2241              IDGREE = -DEGREE(I)
2242              DEGREE(I) = IDGREE
2243              NEWORG = NEWNUM(I)
2244              OLDORG = OLDNUM(I)
2245              NEWRWD = 0
2246              OLDRWD = 0
2247              JPTR = RSTART (I)
2248C
2249C             ... FIND NEIGHBOR WHICH IS NUMBERED FARTHEST AHEAD OF THE
2250C                 CURRENT NODE.
2251C
2252              DO 200 J = 1, IDGREE
2253                  JNODE = CONNEC(JPTR)
2254                  JPTR = JPTR + 1
2255                  NEWRWD = MAX0 (NEWRWD, NEWORG - NEWNUM(JNODE))
2256                  OLDRWD = MAX0 (OLDRWD, OLDORG - OLDNUM(JNODE))
2257  200         CONTINUE
2258C
2259              NEWPRO = NEWPRO + NEWRWD
2260              NEWBND = MAX0 (NEWBND, NEWRWD)
2261              OLDPRO = OLDPRO + OLDRWD
2262              OLDBND = MAX0 (OLDBND, OLDRWD)
2263  300 CONTINUE
2264C
2265C     ... IF NEW ORDERING HAS BETTER BANDWIDTH THAN OLD ORDERING,
2266C         REPLACE OLD ORDERING BY NEW ORDERING
2267C
2268      IF  (NEWBND .GT. OLDBND)  GO TO 500
2269          BANDWD = NEWBND
2270          PROFIL = NEWPRO
2271          DO 400 I = 1, N
2272              OLDNUM(I) = NEWNUM(I)
2273  400     CONTINUE
2274          GO TO 600
2275C
2276C     ... RETAIN OLD ORDERING
2277C
2278  500     BANDWD = OLDBND
2279          PROFIL = OLDPRO
2280C
2281  600 RETURN
2282C
2283C     ------------------------------------------------------------------
2284C
2285 6000 SPACE = -1
2286      ERROR = 70
2287      RETURN
2288C
2289      END
2290      SUBROUTINE   GPSKCM   (N, DEGREE, RSTART, CONNEC, INVNUM, NEWNUM, GPSK2245
2291     1                       OLDNUM, BANDWD, PROFIL, ERROR, SPACE)
2292C
2293C
2294      INTEGER     N, RSTART(N), BANDWD, PROFIL, ERROR, SPACE
2295C
2296CIBM  INTEGER *2  DEGREE(N), CONNEC(1), INVNUM(N), NEWNUM(N), OLDNUM(N)
2297      INTEGER     DEGREE(N), CONNEC(1), INVNUM(N), NEWNUM(N),
2298     1            OLDNUM(N)
2299C
2300C     ==================================================================
2301C
2302C
2303C     COMPUTE THE BANDWIDTH AND PROFILE FOR THE RENUMBERING GIVEN
2304C     BY 'INVNUM', BY THE REVERSE OF NUMBERING 'INVNUM', AND ALSO
2305C     BY THE RENUMBERING GIVEN IN 'OLDNUM'.
2306C     'NEWNUM' WILL BE A PERMUTATION VECTOR COPY OF THE NODE
2307C     LIST 'INVNUM'.
2308C
2309C     ==================================================================
2310C
2311      INTEGER     I, J, JPTR, IDGREE, OLDBND, OLDPRO, NEWBND, NEWPRO,
2312     1            OLDRWD, NEWRWD, OLDORG, NEWORG, JNODE, NRVBND, NRVPRO,
2313     2            NRVORG, NRVRWD, INVNMI, NMIP1
2314C
2315C     ------------------------------------------------------------------
2316C
2317C     ... CREATE NEWNUM AS A PERMUTATION VECTOR
2318C
2319      DO 100 I = 1, N
2320          INVNMI = INVNUM (I)
2321          NEWNUM (INVNMI) = I
2322  100 CONTINUE
2323C
2324C     ... COMPUTE PROFILE AND BANDWIDTH FOR BOTH THE OLD AND THE NEW
2325C         ORDERINGS.
2326C
2327      OLDBND = 0
2328      OLDPRO = 0
2329      NEWBND = 0
2330      NEWPRO = 0
2331      NRVBND = 0
2332      NRVPRO = 0
2333C
2334      DO 300 I = 1, N
2335          IF (DEGREE(I) .EQ. 0)  GO TO 300
2336          IF (DEGREE(I) .GT. 0)  GO TO 6000
2337              IDGREE = -DEGREE(I)
2338              DEGREE(I) = IDGREE
2339              NEWRWD = 0
2340              OLDRWD = 0
2341              NRVRWD = 0
2342              NEWORG = NEWNUM(I)
2343              OLDORG = OLDNUM(I)
2344              NRVORG = N - NEWNUM(I) + 1
2345              JPTR = RSTART (I)
2346C
2347C             ... FIND NEIGHBOR WHICH IS NUMBERED FARTHEST AHEAD OF THE
2348C                 CURRENT NODE.
2349C
2350              DO 200 J = 1, IDGREE
2351                  JNODE = CONNEC(JPTR)
2352                  JPTR = JPTR + 1
2353                  NEWRWD = MAX0 (NEWRWD, NEWORG - NEWNUM(JNODE))
2354                  OLDRWD = MAX0 (OLDRWD, OLDORG - OLDNUM(JNODE))
2355                  NRVRWD = MAX0 (NRVRWD, NRVORG - N + NEWNUM(JNODE) - 1)
2356  200         CONTINUE
2357C
2358              NEWPRO = NEWPRO + NEWRWD
2359              NEWBND = MAX0 (NEWBND, NEWRWD)
2360              NRVPRO = NRVPRO + NRVRWD
2361              NRVBND = MAX0 (NRVBND, NRVRWD)
2362              OLDPRO = OLDPRO + OLDRWD
2363              OLDBND = MAX0 (OLDBND, OLDRWD)
2364  300 CONTINUE
2365C
2366C     ... IF NEW ORDERING HAS BETTER BANDWIDTH THAN OLD ORDERING,
2367C         REPLACE OLD ORDERING BY NEW ORDERING
2368C
2369      IF  ((NEWPRO .GT. OLDPRO)  .OR. (NEWPRO .GT. NRVPRO)) GO TO 500
2370          BANDWD = NEWBND
2371          PROFIL = NEWPRO
2372          DO 400 I = 1, N
2373              OLDNUM(I) = NEWNUM(I)
2374  400     CONTINUE
2375          GO TO 800
2376C
2377C     ... CHECK NEW REVERSED ORDERING FOR BEST PROFILE
2378C
2379  500 IF  (NRVPRO .GT. OLDPRO)  GO TO 700
2380          BANDWD = NRVBND
2381          PROFIL = NRVPRO
2382          DO 600 I = 1, N
2383              OLDNUM(I) = N - NEWNUM(I) + 1
2384              IF  (I .GT. N/2)  GO TO 600
2385                  J = INVNUM(I)
2386                  NMIP1 = (N + 1) - I
2387                  INVNUM(I) = INVNUM (NMIP1)
2388                  INVNUM (NMIP1) = J
2389  600     CONTINUE
2390          GO TO 800
2391C
2392C
2393C     ... RETAIN OLD ORDERING
2394C
2395  700     BANDWD = OLDBND
2396          PROFIL = OLDPRO
2397C
2398  800 RETURN
2399C
2400C     ------------------------------------------------------------------
2401C
2402 6000 ERROR = 71
2403      SPACE = -1
2404      RETURN
2405C
2406      END
2407      SUBROUTINE   GPSKCN   (N, KEY, DATA, ERROR)                       GPSK2361
2408C
2409C     ==================================================================
2410C
2411C     I N S E R T I O N    S O R T
2412C
2413C     INPUT:
2414C         N    -- NUMBER OF ELEMENTS TO BE SORTED
2415C         KEY  -- AN ARRAY OF LENGTH  N  CONTAINING THE VALUES
2416C                 WHICH ARE TO BE SORTED
2417C         DATA -- A SECOND ARRAY OF LENGTH  N  CONTAINING DATA
2418C                 ASSOCIATED WITH THE INDIVIDUAL KEYS.
2419C
2420C     OUTPUT:
2421C         KEY  -- WILL BE ARRANGED SO THAT VALUES ARE IN DECREASING
2422C                 ORDER
2423C         DATA -- REARRANGED TO CORRESPOND TO REARRANGED KEYS
2424C         ERROR -- WILL BE ZERO UNLESS THE PROGRAM IS MALFUNCTIONING,
2425C                  IN WHICH CASE IT WILL BE EQUAL TO 1.
2426C
2427C
2428C     ==================================================================
2429C
2430      INTEGER     N, ERROR
2431C
2432CIBM  INTEGER *2  KEY(N), DATA(N)
2433      INTEGER     KEY(N), DATA(N)
2434C
2435C     ------------------------------------------------------------------
2436C
2437      INTEGER     I, J, D, K, IP1, JM1
2438C
2439C     ------------------------------------------------------------------
2440C
2441      IF (N .EQ. 1)  RETURN
2442      IF  (N .LE. 0)  GO TO 6000
2443C
2444      ERROR = 0
2445C
2446C     ... INSERTION SORT ... FOR I := N-1 STEP -1 TO 1 DO ...
2447C
2448 2400 I = N - 1
2449      IP1 = N
2450C
2451 2500     IF ( KEY (I) .GE. KEY (IP1) )  GO TO 2800
2452C
2453C             ... OUT OF ORDER ... MOVE UP TO CORRECT PLACE
2454C
2455              K = KEY (I)
2456              D = DATA (I)
2457              J = IP1
2458              JM1 = I
2459C
2460C             ... REPEAT ... UNTIL 'CORRECT PLACE FOR K FOUND'
2461C
2462 2600             KEY (JM1) = KEY (J)
2463                  DATA (JM1) = DATA (J)
2464                  JM1 = J
2465                  J = J + 1
2466                  IF  (J .GT. N)  GO TO 2700
2467                  IF (KEY (J) .GT. K)  GO TO 2600
2468C
2469 2700         KEY (JM1) = K
2470              DATA (JM1) = D
2471C
2472 2800     IP1 = I
2473          I = I - 1
2474          IF ( I .GT. 0 )  GO TO 2500
2475C
2476 3000 RETURN
2477C
2478 6000 ERROR = 1
2479      GO TO 3000
2480C
2481      END
2482      SUBROUTINE   GPSKCO   (N, KEY, ERROR)                             GPSK2436
2483C
2484C     ==================================================================
2485C
2486C     I N S E R T I O N    S O R T
2487C
2488C     INPUT:
2489C         N    -- NUMBER OF ELEMENTS TO BE SORTED
2490C         KEY  -- AN ARRAY OF LENGTH  N  CONTAINING THE VALUES
2491C                 WHICH ARE TO BE SORTED
2492C
2493C     OUTPUT:
2494C         KEY  -- WILL BE ARRANGED SO THAT VALUES ARE IN DECREASING
2495C                 ORDER
2496C
2497C     ==================================================================
2498C
2499      INTEGER     N, ERROR
2500C
2501CIBM  INTEGER *2  KEY(N)
2502      INTEGER     KEY(N)
2503C
2504C     ------------------------------------------------------------------
2505C
2506      INTEGER     I, J, K, IP1, JM1
2507C
2508C     ------------------------------------------------------------------
2509C
2510      IF (N .EQ. 1)  RETURN
2511      IF  (N .LE. 0)  GO TO 6000
2512C
2513      ERROR = 0
2514C
2515C     ... INSERTION SORT ... FOR I := N-1 STEP -1 TO 1 DO ...
2516C
2517 2400 I = N - 1
2518      IP1 = N
2519C
2520 2500     IF ( KEY (I) .GE. KEY (IP1) )  GO TO 2800
2521C
2522C             ... OUT OF ORDER ... MOVE UP TO CORRECT PLACE
2523C
2524              K = KEY (I)
2525              J = IP1
2526              JM1 = I
2527C
2528C             ... REPEAT ... UNTIL 'CORRECT PLACE FOR K FOUND'
2529C
2530 2600             KEY (JM1) = KEY (J)
2531                  JM1 = J
2532                  J = J + 1
2533                  IF  (J .GT. N)  GO TO 2700
2534                  IF (KEY (J) .GT. K)  GO TO 2600
2535C
2536 2700         KEY (JM1) = K
2537C
2538 2800     IP1 = I
2539          I = I - 1
2540          IF ( I .GT. 0 )  GO TO 2500
2541C
2542 3000 RETURN
2543C
2544 6000 ERROR = 1
2545      GO TO 3000
2546C
2547      END
2548      SUBROUTINE  GPSKCP  (N, INDEX, NVEC, DEGREE, ERROR)               GPSK2502
2549C
2550C     ==================================================================
2551C
2552C     I N S E R T I O N      S O R T
2553C
2554C     INPUT:
2555C         N    -- NUMBER OF ELEMENTS TO BE SORTED
2556C         INDEX  -- AN ARRAY OF LENGTH  N  CONTAINING THE INDICES
2557C                 WHOSE DEGREES ARE TO BE SORTED
2558C         DEGREE -- AN  NVEC  VECTOR, GIVING THE DEGREES OF NODES
2559C                   WHICH ARE TO BE SORTED.
2560C
2561C     OUTPUT:
2562C         INDEX  -- WILL BE ARRANGED SO THAT VALUES ARE IN DECREASING
2563C                 ORDER
2564C         ERROR -- WILL BE ZERO UNLESS THE PROGRAM IS MALFUNCTIONING,
2565C                  IN WHICH CASE IT WILL BE EQUAL TO 1.
2566C
2567C     ==================================================================
2568C
2569      INTEGER     N, NVEC, ERROR
2570C
2571CIBM  INTEGER *2  INDEX(N), DEGREE(NVEC)
2572      INTEGER     INDEX(N), DEGREE(NVEC)
2573C
2574C     ------------------------------------------------------------------
2575C
2576      INTEGER     I, J, V, IP1, JM1, INDEXI, INDXI1, INDEXJ
2577C
2578C     ------------------------------------------------------------------
2579C
2580      IF (N .EQ. 1)  RETURN
2581      IF  (N .LE. 0)  GO TO 6000
2582C
2583      ERROR = 0
2584C
2585C     ------------------------------------------------------------------
2586C     INSERTION SORT THE ENTIRE FILE
2587C     ------------------------------------------------------------------
2588C
2589C
2590C     ... INSERTION SORT ... FOR I := N-1 STEP -1 TO 1 DO ...
2591C
2592 2400 I = N - 1
2593      IP1 = N
2594C
2595 2500     INDEXI = INDEX (I)
2596          INDXI1 = INDEX (IP1)
2597          IF ( DEGREE(INDEXI) .GE. DEGREE(INDXI1) )  GO TO 2800
2598C
2599C             ... OUT OF ORDER ... MOVE UP TO CORRECT PLACE
2600C
2601              V = DEGREE (INDEXI)
2602              J = IP1
2603              JM1 = I
2604              INDEXJ = INDEX (J)
2605C
2606C             ... REPEAT ... UNTIL 'CORRECT PLACE FOR V FOUND'
2607C
2608 2600             INDEX (JM1) = INDEXJ
2609                  JM1 = J
2610                  J = J + 1
2611                  IF (J .GT. N)  GO TO 2700
2612                  INDEXJ = INDEX (J)
2613                  IF (DEGREE(INDEXJ) .GT. V)  GO TO 2600
2614C
2615 2700         INDEX (JM1) = INDEXI
2616C
2617 2800     IP1 = I
2618          I = I - 1
2619          IF ( I .GT. 0 )  GO TO 2500
2620C
2621 3000 RETURN
2622C
2623 6000 ERROR = 1
2624      GO TO 3000
2625C
2626      END
2627      SUBROUTINE  GPSKCQ (N, INDEX, NVEC, DEGREE, ERROR)                GPSK2581
2628C
2629C     ==================================================================
2630C
2631C     I N S E R T I O N      S O R T
2632C
2633C     INPUT:
2634C         N    -- NUMBER OF ELEMENTS TO BE SORTED
2635C         INDEX  -- AN ARRAY OF LENGTH  N  CONTAINING THE INDICES
2636C                 WHOSE DEGREES ARE TO BE SORTED
2637C         DEGREE -- AN  NVEC  VECTOR, GIVING THE DEGREES OF NODES
2638C                   WHICH ARE TO BE SORTED.
2639C
2640C     OUTPUT:
2641C         INDEX  -- WILL BE ARRANGED SO THAT VALUES ARE IN INCREASING
2642C                   ORDER
2643C         ERROR -- WILL BE ZERO UNLESS THE PROGRAM IS MALFUNCTIONING,
2644C                  IN WHICH CASE IT WILL BE EQUAL TO 1.
2645C
2646C     ==================================================================
2647C
2648      INTEGER     N, NVEC, ERROR
2649C
2650CIBM  INTEGER *2  INDEX(N), DEGREE(NVEC)
2651      INTEGER     INDEX(N), DEGREE(NVEC)
2652C
2653C     ------------------------------------------------------------------
2654C
2655      INTEGER     I, J, V, INDEXI, INDXI1, INDEXJ, IP1, JM1
2656C
2657C     ------------------------------------------------------------------
2658C
2659      IF (N .EQ. 1)  RETURN
2660      IF  (N .LE. 0)  GO TO 6000
2661C
2662      ERROR = 0
2663C
2664C     ------------------------------------------------------------------
2665C     INSERTION SORT THE ENTIRE FILE
2666C     ------------------------------------------------------------------
2667C
2668C
2669C     ... INSERTION SORT ... FOR I := N-1 STEP -1 TO 1 DO ...
2670C
2671 2400 I = N - 1
2672      IP1 = N
2673C
2674 2500     INDEXI = INDEX (I)
2675          INDXI1 = INDEX (IP1)
2676          IF ( DEGREE(INDEXI) .LE. DEGREE(INDXI1) )  GO TO 2800
2677C
2678C             ... OUT OF ORDER ... MOVE UP TO CORRECT PLACE
2679C
2680              V = DEGREE (INDEXI)
2681              J = IP1
2682              JM1 = I
2683              INDEXJ = INDEX (J)
2684C
2685C             ... REPEAT ... UNTIL 'CORRECT PLACE FOR V FOUND'
2686C
2687 2600             INDEX (JM1) = INDEXJ
2688                  JM1 = J
2689                  J = J + 1
2690                  IF (J .GT. N)  GO TO 2700
2691                  INDEXJ = INDEX (J)
2692                  IF (DEGREE(INDEXJ) .LT. V)  GO TO 2600
2693C
2694 2700         INDEX (JM1) = INDEXI
2695C
2696 2800     IP1 = I
2697          I = I - 1
2698          IF ( I .GT. 0 )  GO TO 2500
2699C
2700 3000 RETURN
2701C
2702 6000 ERROR = 1
2703      GO TO 3000
2704C
2705      END
2706
Note: See TracBrowser for help on using the repository browser.