File: bandred.f

package info (click to toggle)
scilab 4.0-12
  • links: PTS
  • area: non-free
  • in suites: etch, etch-m68k
  • size: 100,640 kB
  • ctags: 57,333
  • sloc: ansic: 377,889; fortran: 242,862; xml: 179,819; tcl: 42,062; sh: 10,593; ml: 9,441; makefile: 4,377; cpp: 1,354; java: 621; csh: 260; yacc: 247; perl: 130; lex: 126; asm: 72; lisp: 30
file content (2347 lines) | stat: -rw-r--r-- 95,671 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
c     algorithm 582, collected algorithms from acm.
c     algorithm appeared in acm-trans. math. software, vol.8, no. 2,
c     jun., 1982, p. 190.
c     ==============================================================
      subroutine   gpskca   (n, degree, rstart, connec, optpro, wrklen, 
     1                       permut, work, bandwd, profil, error, space)
      integer   n, rstart(n), wrklen, bandwd, profil, error, space
      integer   degree(n),connec(1),permut(n),work(wrklen),optpro
c     ------------------------------------------------------------------
c input parameters:
c     n      -- the dimension of the matrix
c     degree,rstart,connec -- 
c           describe the structure of the sparsematrix. degree(i) 
c           specifies the number of non-zero  off-diagonal entries in the
c           i-th  row of the sparse matrix.  the column indices of these
c           entries are given in consecutive locations in connec, starting at
c           location  rstart(i).in other words, the indices of the non-zero
c           off-diagonal elements of the  i-th  row are found
c                   in:
c                       connec (rstart(i)),
c                       connec (rstart(i) + 1),
c                                . . .
c                       connec (rstart(i) + degree(i) - 1)
c
c                   dimensions:
c                       rstart is dimension  n  (or longer).
c                       degree is dimension  n  (or longer).
c                       connec is dimension roughly the number of non-
c                              zero entries in the matrix.
c
c     optpro -- 1 if reducing the profile of the matrix
c                      is more important than reducing the bandwidth
c               0 if bandwidth reduction is most important
c
c     wrklen -- if not enough space is given in work the error flag
c                   will be set and further computation stopped.
c
c input and output parameter:
c     permut -- on input, an alternative reordering for the
c                   rows and columns of the matrix.  permut(i) gives
c                   the position in which row and column  i  should
c                   be placed to reduce the bandwidth or the profile.
c                   if the user has no alternative to the natural
c                   ordering implicit in  degree,  rstart  and  connec,
c                   he should initialize  permut  to be the identity
c                   permutation  permut(i) = i .
c
c                   on output,  permut  will contain the permutation
c                   for reordering the rows and columns which reduces
c                   the bandwidth and/or profile.  the result will be
c                   the reordering found by 'gpskca' or the reordering
c                   given by the user in 'permut', whichever does the
c                   job better.
c
c
c output parameters:
c     work   -- a temporary storage vector, of 6n+3  locations.
c               the 1st  n  locations of original row and column indices 
c               locations  n+1, ... , 2n  new positions 
c                   found by gpskca.  
c     bandwd -- the bandwidth of the reordered matrix
c     profil -- the profile of the reordered matrix
c     error  -- will be equal to zero if a new numbering could be
c                   found in the space provided.  otherwise,  error
c                   will be set to a positive error code (see table
c                   given below).  if the reordering algorithm has been
c                   stopped by lack of workspace, the space parameter
c                   will be set to the number of additional locations
c                   required to complete at least the next phase of
c                   the algorithm.
c     space  -- will indicate either how much space the reordering
c                   actually required or how much space will be
c                   required to complete the next phase of the
c                   reordering algorithm.  the possible outcomes are ..
c                      error = 0          space is the minimal value for
c                                         wrklen  required to reorder
c                                         this matrix again.
c                      error <> 0         space is the minimum number
c                      due to lack of     of extra workspace required
c                      workspace          to continue the reordering
c                                         algorithm on this matrix.
c                      error <> 0         space = -1
c                      due to error
c                      in data structures
c     ==================================================================
c     e r r o r    c o d e s
c         error codes have the form  0xy  or  1xy.
c         errors of the form  1xy  result from inadequate workspace.
c         errors of the form  0xy  are internal program checks
c         the last digit (y) is mainly useful for debugging the
c         the reordering algorithm.  the middle digit  (x)  indicates
c         how much of the algorithm has been performed.
c         the table below gives the correspondence between the
c         values of  x   and the structure of the algorithm.
c             x = 0     initial processing
c             x = 1     computing pseudo-diameter  (algorithm i)
c             x = 2     transition between algorithm i and ii
c             x = 3     combining level structures (algorithm ii)
c             x = 4     transition between algorithm ii and iii
c             x = 5     bandwidth numbering (algorithm iiia)
c             x = 6     profile numbering (algorithm iiib)
c             x = 7     final bandwidth/profile computation
      integer     i, inc1, inc2, avail, nxtnum, lowdg, stnode, nleft,
     1            tree1, tree2, depth, empty, stotal, reqd, cspace,
     2            lvllst, lvlptr, active, rvnode, width1, width2, mxdg
      logical     revrs1, oneis1
c
c     << number any degree zero nodes >>
c
c     while << some nodes yet unnumbered >> do
c         << find a pseudo-diameter of the matrix graph >>
c         << convert form of level trees >>
c         << combine level trees into one level structure >>
c         << convert form of level structure >>
c         if optpro=1 then
c             << renumber by king algorithm >>
c         else
c             << renumber by reverse cuthill-mckee algorithm >>
c     ==================================================================
c     ... initialize counters, then number any nodes of degree  0.
c         the list of nodes, by new number, will be built in place at
c         the front of the work area.
      nxtnum = 1
      error = 0
      space = 2*n
c
      mxdg = 0
      do 300 i = 1, n
          if  (degree(i))  6000, 100, 200
  100         work(nxtnum) = i
              nxtnum = nxtnum + 1
              go to 300
  200         if  (degree(i) .gt. mxdg)  mxdg = degree(i)
  300 continue
c     ... while  nxtnum <= n  do ...
 1000 if  ( nxtnum .gt. n )  go to 2000
c         ... find an unnumbered node of minimal degree
          lowdg = mxdg + 1
          stnode = 0
          do 400 i = 1, n
              if ( (degree(i) .le. 0) .or. (degree(i) .ge. lowdg) )
     1           go to 400
                  lowdg = degree(i)
                  stnode = i
  400     continue
c
          if ( stnode .eq. 0 )  go to 6100
c set up pointers for three lists in work area, then look
c for pseudo-diameter, beginning with stnode.
          avail = (wrklen - nxtnum + 1) / 3
          nleft = n - nxtnum + 1
          space = max0 (space, nxtnum + 3*n - 1)
          if ( avail .lt. n )  go to 5200
c
          call gpskcb (n, degree, rstart, connec, avail, nleft,
     1                 stnode, rvnode, work(nxtnum), tree1, tree2,
     2                 active, depth, width1, width2,
     3                 error, space)
          if ( error .ne. 0 )  go to 5000
          space = max0 (space, nxtnum + 3*(active+depth+1) - 1)
c dynamic space check for most of remainder of algorithm
          reqd = max0 (nxtnum + 2*n + 3*depth - 1, 3*n + 2*depth + 1)
          space = max0 (space, reqd)
          if  ( wrklen .lt. reqd )  go to 5300
c output from gpskcb is a pair of level trees, in the form of lists of 
c nodes by level.  convert this to two lists of  of level number by node.
c at the same time pack storage so that one of the level tree vectors is
c at the back end of the work area.
          lvlptr = nxtnum + avail - depth
          call gpskce (n, avail, active, depth, wrklen, work(nxtnum),
     1                 work(lvlptr), work(1), nxtnum, tree1,
     2                 tree2, width1, width2, oneis1, error, space)
          if ( error .ne. 0 ) go to 5000
          if (( tree1 .ne. wrklen - n + 1 ) .or. (tree2 .ne. nxtnum))
     1      go to 6200
c combine the two level trees into a more general level structure.
          avail = wrklen - nxtnum + 1 - 2*n - 3*depth
          stotal = n + nxtnum
          empty = stotal + depth
          inc1 = tree1 - depth
          inc2 = inc1 - depth
c
          call gpskcg (n, degree, rstart, connec, active, width1,
     1                 width2, work(tree1), work(tree2), work(empty),
     2                 avail, depth, work(inc1), work(inc2),
     3                 work(stotal), oneis1, revrs1, error, cspace)
c
          if ( error .ne. 0 )  go to 5000
          space = max0 (space, nxtnum + cspace - 1)
c combined level structure is represented by gpskcg as a vector of level 
c numbers. for renumbering phase, convert this also to the inverse permutation.
          lvlptr = tree1 - (depth + 1)
          lvllst = lvlptr - active
          if ( stotal + depth .gt. lvlptr )  go to 6300
c
          call gpskci (n, active, depth, work(tree1), work(lvllst),
     1                 work(lvlptr), work(stotal), error, space)
          if  (error .ne. 0)  go to 5000
c now renumber all members of this component using either a reverse
c cuthill-mckee or a king strategy,
c as profile or bandwidth reduction is more important.
          if ( optpro.eq.1 )  go to 500
              call gpskcj (n, degree, rstart, connec, active,
     1                     work(nxtnum), stnode, rvnode, revrs1, depth,
     2                     work(lvllst), work(lvlptr), work(tree1),
     3                     error, space)
              if ( error .ne. 0 )  go to 5000
              nxtnum = nxtnum + active
              go to 600
c
  500         call gpskck (n, degree, rstart, connec, lvllst-1, nxtnum,
     1                     work, active, depth, work(lvllst),
     2                     work(lvlptr), work(tree1), error, space)
              if ( error .ne. 0 )  go to 5000
c         =========================================================
c         ... end of while loop ... repeat if graph is disconnected
c         =========================================================
  600     go to 1000
c check whether initial numbering or final numbering provides better results
 2000 if  (wrklen .lt. 2*n)  go to 5400
c
      if  (optpro.eq.1)  go to 2100
          call gpskcl (n, degree, rstart, connec, work(1), work(n+1),
     1                 permut, bandwd, profil, error, space)
          go to 2200
c
 2100     call gpskcm (n, degree, rstart, connec, work(1), work(n+1),
     1                 permut, bandwd, profil, error, space)
c
 2200 return
c     . . .  e r r o r   d i a g n o s t i c s
c error detected by lower level routine.  make sure that signs
c of degree are properly set
 5000 do 5100 i = 1, n
          if  (degree(i) .lt. 0)  degree(i) = -degree(i)
 5100 continue
c
      bandwd = -1
      profil = -1
      return
c storage allocation errors detected in this routine
 5200 error = 101
      space = -1
      go to 5000
 5300 error = 102
      space = -1
      go to 5000
 5400 error =  10
      space = 2*n - wrklen
      go to 5000
c data structure errors detected in this routine
 6000 error = 1
      go to 6900
 6100 error = 2
      go to 6900
 6200 error = 3
      go to 6900
 6300 error = 4
 6900 space = -1
      go to 5000
      end
c *****************************************************************************
      subroutine  gpskcb  (n, degree, rstart, connec, avail, nleft,     
     1                     stnode, rvnode, work, forwd, bestbk, nnodes,
     2                     depth, fwidth, bwidth, error, space)
c find a pseudo-diameter of the matrix graph ...
c         << build a level tree from stnode >>
c         repeat
c             << build a level tree from each node 'bknode' in the
c                deepest level of  stnode's tree >>
c             << replace 'stnode' with 'bknode' if a deeper and
c                narrower tree was found. >>
c         until
c             << no further improvement made >>
c
c     ... heuristic above differs from the algorithm published in
c         siam j. numerical analysis, but matches the code
c         distributed by toms.
c parameters :
c     n, degree, rstart & connec  describe the matrix structure
c     work   -- working space, of length  3*avail, used to store
c               three level trees.
c     stnode is initially the number of a node to be used to start the
c            process, to be the root of the first tree. on output, stnode is
c            the end of the pseudo-diameter whose level tree is narrowest.
c     rvnode will be the other end of the pseudo-diameter.
c     nnodes will be the number of nodes in this connected componnent
c            of the matrix graph, i.e., the length of the level trees.
c     depth  -- the depth of the level trees being returned,
c                   i.e., the length of the pseudo-diameter.
c     ==================================================================
c     structure of workspace ...
c     ---------------------------------------------------------------
c     : numbered :  tlist1  ptr1  :  tlist2  ptr2  :  tlist3  ptr3  :
c     ---------------------------------------------------------------
c     tlisti is a list of nodes of length  'active'
c     ptri   is a list of pointers into tlisti, of length  'depth+1'
      integer n,rstart(n),avail,nleft,stnode,rvnode,forwd,bestbk,
     1 nnodes,depth,fwidth,bwidth,error,space
      integer degree(n), connec(1), work(avail,3),backwd
      integer mxdpth,width,fdepth,lstlvl,nlast,t,i,bknode,lstlvi
      logical improv
c build initial level tree from 'stnode'.  find out how many
c nodes lie in the current connected component.
      forwd = 1
      backwd = 2
      bestbk = 3
c
      call gpskcc (n, degree, rstart, connec, stnode, avail, nleft,
     1              work(1,forwd), nnodes, depth, width, error,
     2              space)
      if ( error .ne. 0 )  go to 5000
c
      mxdpth = avail - nnodes - 1
c repeat until no deeper trees are found ...
 1000     fwidth = width
          fdepth = depth
          lstlvl = avail - depth + 1
          nlast = work (lstlvl-1, forwd) - work (lstlvl, forwd)
          lstlvl = work (lstlvl, forwd)
          bwidth = n+1
c sort the deepest level of 'forwd' tree into increasing order of node degree.
          call gpskcq (nlast, work(lstlvl,forwd), n, degree, error)
          if  (error .ne. 0)  go to 6000
c build level tree from nodes in 'lstlvl' until a deeper
c and narrower tree is found or the list is exhausted.
          improv = .false.
          do 1200 i = 1, nlast
              lstlvi = lstlvl + i - 1
              bknode = work (lstlvi, forwd)
              call gpskcd (n, degree, rstart, connec, bknode, avail,
     1                     nnodes, mxdpth, work(1,backwd), depth, width,
     2                     bwidth, error, space)
              if ( error .ne. 0 )  go to 5000
c
              if ( depth .le. fdepth )  go to 1100
c new deeper tree ... make it new 'forwd' tree and break out of 'do' loop.

                  improv = .true.
                  t = forwd
                  forwd = backwd
                  backwd = t
                  stnode = bknode
                  go to 1300
c else check for narrower tree.
 1100             if ( width .ge. bwidth )  go to 1200
                      t = bestbk
                      bestbk = backwd
                      backwd = t
                      bwidth = width
                      rvnode = bknode
 1200     continue
c end of repeat loop
 1300     if ( improv )  go to 1000
c
      depth = fdepth
      return
c in case of error, simply return error flag to user.
 5000 return
c
 6000 error = 11
      space = -1
      return
c
      end
c***************************************************************************
      subroutine gpskcc(n,degree,rstart,connec,stnode,avail,  
     1 nleft, list, active, depth, width, error,space)
c     build the level tree rooted at 'stnode' in the space provided in
c     list.  check for overrun of space allocation.
      integer     n, rstart(n), stnode, avail, nleft,
     1            active, depth, width, error, space
      integer     degree(n), connec(1), list(avail)
c input ...
c     n, degree, rstart, connec -- describe the matrix structure
c     stnode -- the root of the level tree.
c     avail  -- the length of the working space available
c     nleft  -- the number of nodes yet to be numbered
c     list   -- the working space.
c output ...
c     active -- the number of nodes in the component
c     depth  -- the depth of the level tree rooted at  stnode.
c     width  -- the width of the level tree rooted at  stnode.
c     error  -- zero unless storage was insufficient.
      integer lstart,nlevel,front,j,newnod,ptr,cdgree,lfront,listj
c build the level tree using  list  as a queue and leaving the nodes in place.
c this generates the nodes ordered by level  put pointers to the beginning
c of each level, building from the back of the work area.
      active = 1
      depth = 0
      width = 0
      error = 0
      lstart = 1
      front = 1
      list (active) = stnode
      degree (stnode) = -degree (stnode)
      list (avail)  = 1
      nlevel = avail
c     ... repeat until queue becomes empty or we run out of space.
 1000     if ( front .lt. lstart ) go to 1100
c         ... first node of level.  update pointers.
              lstart = active + 1
              width = max0 (width, lstart - list(nlevel))
              nlevel = nlevel - 1
              depth = depth + 1
              if ( nlevel .le. active )  go to 5000
                  list (nlevel) = lstart
c         ... find all neighbors of current node, add them to queue.
 1100     lfront = list (front)
          ptr = rstart (lfront)
          cdgree = -degree (lfront)
          if (cdgree .le. 0)  go to 6000
          do 1200 j = 1, cdgree
              newnod = connec (ptr)
              ptr = ptr + 1
c             ... add to queue only nodes not already in queue
              if ( degree(newnod) .le. 0 )  go to 1200
                  degree (newnod) = -degree (newnod)
                  active = active + 1
                  if ( nlevel .le. active )  go to 5000
                  if ( active .gt. nleft  )  go to 6000
                      list (active) = newnod
 1200     continue
          front = front + 1
c         ... is queue empty?
          if ( front .le. active )  go to 1000
c     ... yes, the tree is built.  undo our markings.
      do 1300 j = 1, active
          listj = list(j)
          degree (listj) = -degree (listj)
 1300 continue
c
      return
c     ... insufficient storage ...
 5000 space = 3 * ( (nleft+1-active)*depth / nleft + (nleft+1-active) )
      error = 110
      return
c
 6000 error = 12
      space = -1
      return
c
      end
c**************************************************************************
      subroutine   gpskcd(n,degree,rstart,connec,stnode,avail,  
     1 active, mxdpth, list, depth, width, maxwid,error, space)
c     build the level tree rooted at 'stnode' in the space provided in
c     list.  overflow check needed only on depth of tree.
c
c     build the level tree to completion only if the width of all
c     levels is smaller than 'maxwid'.  if a wider level is found
c     terminate the construction.
      integer     n, rstart(n), stnode, avail, active, mxdpth,
     1            depth, width, maxwid, error, space
      integer     degree(n), connec(1), list(avail)
c         input ...
c             n, degree, rstart, connec -- describe the matrix structure
c             stnode -- the root of the level tree.
c             avail  -- the length of the working space available
c             nleft  -- the number of nodes yet to be numbered
c             active -- the number of nodes in the component
c             mxdpth -- maximum depth of level tree possible in
c                       allotted working space
c             list   -- the working space.
c         output ...
c             depth  -- the depth of the level tree rooted at  stnode.
c             width  -- the width of the level tree rooted at  stnode.
c             maxwid -- limit on width of the tree.  tree will not be
c                       used if width of any level is as great as
c                       maxwid, so construction of tree need not
c                       continue if any level that wide is found.
c             error  -- zero unless storage was insufficient.
      integer     lstart, nlevel, front, j, newnod, ptr, back,
     1            sptr, fptr, lfront, listj
c
c     ... build the level tree using  list  as a queue and leaving
c         the nodes in place.  this generates the nodes ordered by level
c         put pointers to the beginning of each level, building from
c         the back of the work area.
c
      back = 1
      depth = 0
      width = 0
      error = 0
      lstart = 1
      front = 1
      list (back) = stnode
      degree (stnode) = -degree (stnode)
      list (avail)  = 1
      nlevel = avail
c     ... repeat until queue becomes empty or we run out of space.
c     ------------------------------------------------------------
 1000     if ( front .lt. lstart ) go to 1100
c         ... first node of level.  update pointers.
              lstart = back + 1
              width = max0 (width, lstart - list(nlevel))
              if  ( width .ge. maxwid )  go to 2000
              nlevel = nlevel - 1
              depth = depth + 1
              if ( depth .gt. mxdpth )  go to 5000
                  list (nlevel) = lstart
c         ... find all neighbors of current node, add them to queue.
 1100     lfront = list (front)
          sptr = rstart (lfront)
          fptr = sptr - degree (lfront) - 1
          do 1200 ptr = sptr, fptr
              newnod = connec (ptr)
c             ... add to queue only nodes not already in queue
              if ( degree(newnod) .le. 0 )  go to 1200
                  degree (newnod) = -degree (newnod)
                  back = back + 1
                  list (back) = newnod
 1200     continue
          front = front + 1
c ... is queue empty?
          if ( front .le. back )  go to 1000
c     ... yes, the tree is built.  undo our markings.
      if (back .ne. active)  go to 6000
c
 1300 do 1400 j = 1, back
          listj = list(j)
          degree (listj) = -degree (listj)
 1400 continue
      return
c     ... abort generation of tree because it is already too wide
 2000 width = n + 1
      depth = 0
      go to 1300
c     ... insufficient storage ...
 5000 space = 3 * ( (active+1-back)*depth / active + (active+1-back) )
      error = 111
      return
 6000 error = 13
      space = -1
      return
      end
c*************************************************************************
      subroutine gpskce(n,avail,active,depth,wrklen,lvllst,lvlptr,           
     1 work,nxtnum,tree1,tree2,width1,width2,oneis1,error,space)
c
c     transition between algorithm i and algorithm ii of
c     the gibbs-poole-stockmeyer paper.
c
c     in this implementation algorithm i represents level trees as
c     lists of nodes ordered by level.  algorithm ii appears to require
c     level numbers indexed by node -- vectors for efficiency.
c     this subroutine changes the level tree representation to that
c     required by algorithm ii.  note that the first algorithm can be
c     carried out with the level number vector format, probably requring
c     more computation time, but perhaps less storage.
c
c     input:  two level trees, as level lists and level pointers,
c             found in two of the three columns of the arrays 'lvllst'
c             and 'lvlptr'
c
c     output: two level trees, as vectors of level numbers,
c             one packed to the front, one to the rear of the working
c             area 'work'.  note that 'work', 'lvllst' and 'lvlptr'
c             share common locations.
c     ================================================================
c     ... structure of workspace
c         input .. (output from gpskcb)
c     --------------------------------------------------------------
c     : numbered : tlist1  ptr1  :  tlist2  ptr2  :  tlist3  ptr3  :
c     --------------------------------------------------------------
c         output .. (goes to combin)
c     --------------------------------------------------------------
c     : numbered :  tree2  :           ...               :  tree1  :
c     --------------------------------------------------------------
      integer     n, avail, active, depth, wrklen, nxtnum,
     1            width1, width2, tree1, tree2, error, space
      integer     lvllst(avail,3), lvlptr(avail,3), work(wrklen)
      logical     oneis1
      integer     i, btree, ftree, fwidth, bwidth
c     ... check that we have enough room to do the necessary unpacking
      if (3*avail .gt. wrklen)  go to 6000
      if (avail .lt. n)  go to 5100
c
c     ... input has three possible cases:
c             lvllst(*,1) is empty
c             lvllst(*,2) is empty
c             lvllst(*,3) is empty
      ftree = tree1
      btree = tree2
      fwidth = width1
      bwidth = width2
c
      tree1 = wrklen - n + 1
      tree2 = nxtnum
c
      if ( (ftree .eq. 1) .or. (btree .eq. 1) )  go to 300
c         ... case 1:  1st slot is empty.  unpack 3 into 1, 2 into 3
          if (ftree .ne. 2)  go to 100
              oneis1 = .true.
              width2 = bwidth
              width1 = fwidth
              go to 200
c
  100         oneis1 = .false.
              width1 = bwidth
              width2 = fwidth
c
  200     call gpskcf (n, active, depth, lvllst(1,3), lvlptr(1,3),
     1                    work(tree2), oneis1)
c
          call gpskcf (n, active, depth, lvllst(1,2), lvlptr(1,2),
     1                    work(tree1), .not. oneis1)
c
          go to 1000
c
c
  300 if ( (ftree .eq. 2) .or. (btree .eq. 2) )  go to 600
c         ... case 2:  2nd slot is empty.  to enable complete
c              repacking, move 3 into 2, then fall into next case
          do 400 i = 1, active
              lvllst(i,2) = lvllst(i,3)
  400     continue
c
          do 500 i = 0, depth
              lvlptr(i,2) = lvlptr(i,3)
  500     continue
c         ... case 3:  slot 3 is empty.  move 1 into 3, then 2 into 1.
  600     if (ftree .eq. 1) go to 700
              oneis1 = .false.
              width1 = bwidth
              width2 = fwidth
              go to 800
c
  700         oneis1 = .true.
              width1 = fwidth
              width2 = bwidth
c
  800     call gpskcf (n, active, depth, lvllst(1,1), lvlptr(1,1),
     1                    work(tree1), .not. oneis1)
c
          call gpskcf (n, active, depth, lvllst(1,2), lvlptr(1,2),
     1                    work(tree2), oneis1)
 1000 return
c
c     ------------------------------------------------------------------
c
 5100 space = 3 * (n - avail)
      error = 120
      return
c
 6000 error = 20
      space = -1
      return
c
      end
c**************************************************************************
      subroutine  gpskcf(n,active,depth,lvllst,lvlptr,lvlnum,revers)
c convert level structure representation from a list of nodes
c grouped by level to a vector giving level number for each node.
c     lvllst, lvlptr -- list of lists
c     lvlnum -- output vector of level numbers
c     revers -- if .true., number level structure from back end
c               instead of from front
      integer  n,active,depth,lvllst(active),lvlptr(depth),lvlnum(n)
      logical     revers
      integer     i, level, lstart, lend, xlevel, plstrt, lvllsi
      if  (active .eq. n)  go to 200
c if not all nodes of graph are active, mask out the nodes which are not active
          do 100 i = 1, n
              lvlnum(i) = 0
  100     continue
c
  200 do 400 level = 1, depth
          xlevel = level
          plstrt = depth - level + 1
          if (revers) xlevel = plstrt
          lstart = lvlptr (plstrt)
          lend = lvlptr (plstrt - 1) - 1
c
          do 300 i = lstart, lend
              lvllsi = lvllst(i)
              lvlnum (lvllsi) = xlevel
  300     continue
  400 continue
      return
      end
c***************************************************************************
      subroutine gpskcg(n,degree,rstart,connec,active,width1,width2, 
     1 tree1,tree2,work,wrklen,depth,inc1,inc2,total,oneis1,revrs1,
     2 error,space)
c     combine the two rooted level trees into a single level structure
c     which may have smaller width than either of the trees.  the new
c     structure is not necessarily a rooted structure.
c parameters:
c     n, degree, rstart, connec -- give the dimension and structure
c                                      of the sparse symmetric matrix
c     active -- the number of nodes in this connected component of
c                   the matrix graph
c     tree1  -- on input, one of the input level trees.  on
c                   output, the combined level structure
c     tree2  -- the second input level tree
c     width1 -- the maximum width of a level in tree1
c     width2 -- the maximum width of a level in tree2
c     work   -- a working area of length 'wrklen'
c     inc1,  -- vectors of length 'depth'
c     inc2,total,oneis1
c          -- indicates whether tree1 or tree2 represents the
c                   forward tree or the backwards tree of phase 1.
c                   used to mimic arbitrary tie-breaking procedure of
c                   original gibbs-poole-stockmeyer code.
c
c         revrs1 -- output parameter indicating whether a backwards
c                   ordering was used for the largest component of
c                   the reduced graph
c         error  -- non-zero only if failure of space allocation or
c                   data structure error found
c         space -- minimum space required to rerun or complete phase.
      integer n,rstart(n),active,width1,width2,wrklen,depth,error,space
      integer     degree(n), connec(1), tree1(n), tree2(n),
     1            work(wrklen), inc1(depth), inc2(depth), total(depth)
      logical     oneis1, revrs1
c     << remove all nodes of pseudo-diameters >>
c     << find connected components of reduced graph >>
c     << combine level trees, component by component >>
c     structure of workspace ...
c     ------------------------------------------------------------------
c     : numbered : tree2 : total : nodes : start : size : inc1 : inc2 :
c     ------------------------------------------------------------------
c     --------
c      tree1 :
c     --------
c         numbered  is the set of  numbered nodes (probably empty)
c         tree1 and tree1 are level trees (length n)
c         total, inc1 and inc2  are vectors of node counts per level
c             (length 'depth')
c         nodes is the set of nodes in the reduced graph (the nodes
c             not on any shortest path from one end of the
c             pseudodiameter to the other)
c         start, zsize are pointers into 'nodes', one of each for
c         each connected component of the reduced graph.
c         the sizes of nodes, start and size are not known apriori.
c
c     ==================================================================
      integer     i, zsize, avail, cstop, start, compon, tree1i, pcstrt,
     1            cstart, mxinc1, mxinc2, compns, mxcomp, offdia,
     2            csize, pcsize, worki, tworki
c find all shortest paths from start to finish.  remove nodes onthese 
c paths and in other connected components of full graph from further
c consideration.  sign of entries in tree1 is used as a mask.
      offdia = active
c
      do 100 i = 1, depth
          total(i) = 0
  100 continue
c
      do 200 i = 1, n
          tree1i = tree1 (i)
          if ((tree1(i).ne.tree2(i)) .or. (tree1(i).eq.0)) go to 200
              total (tree1i) = total (tree1i) + 1
              tree1(i) = - tree1(i)
              offdia = offdia - 1
  200 continue
c
      if ( offdia .eq. 0 )  go to 1100
      if ( offdia .lt. 0 )  go to 6000
c find connected components of graph induced by the nodes not removed. 
c 'mxcomp' is the largest number of components representable in
c the working space available.
      avail = wrklen - offdia
      mxcomp = avail/2
      start = offdia + 1
      zsize = start + mxcomp
c
      if  (mxcomp .le. 0)  go to 5100
c
      call gpskch (n, degree, rstart, connec, tree1, offdia, work,
     1             mxcomp, work(start), work(zsize), compns, error,
     2             space)
      if ( error .ne. 0 )  go to 5000
c record space actually used  (not including  numbered )
      space = 2*n + 3*(depth) + 2*compns + offdia
c sort the component start pointers into increasing order of size of component
      if (compns .gt. 1)
     1    call gpskcn (compns, work(zsize), work(start), error)
          if  (error .ne. 0)  go to 6200
c for each component in turn, choose to use the ordering of the 'forward' 
c tree1 or of the 'backward' tree2 to number the nodes in this component. 
c the numbering is chosen to minimize the maximum increment to any level.
      do 1000 compon = 1, compns
          pcstrt = start + compon - 1
          cstart = work (pcstrt)
          pcsize = zsize + compon - 1
          csize = work (pcsize)
          cstop  = cstart + csize - 1
          if ((csize .lt. 0) .or. (csize .gt. offdia))  go to 6100
c
          do 300 i = 1, depth
              inc1(i) = 0
              inc2(i) = 0
  300     continue
c
          mxinc1 = 0
          mxinc2 = 0
c
          do 400 i = cstart, cstop
              worki = work(i)
              tworki = -tree1 (worki)
              inc1 (tworki) = inc1 (tworki) + 1
              tworki =  tree2 (worki)
              inc2 (tworki) = inc2 (tworki) + 1
  400     continue
c         ... baroque tests below duplicate the gibbs-poole-stockmeyer-
c             crane program, *** not *** the published algorithm.
          do 500 i = 1, depth
              if ((inc1(i) .eq. 0) .and. (inc2(i) .eq. 0))  go to 500
                  if  (mxinc1  .lt.  total(i) + inc1(i))
     1                 mxinc1 = total(i) + inc1(i)
                  if  (mxinc2  .lt.  total(i) + inc2(i))
     1                 mxinc2 = total(i) + inc2(i)
  500     continue
c         ... use ordering of narrower tree unless it increases
c             width more than wider tree.  in case of tie, use tree 2!
          if ( (mxinc1 .gt. mxinc2)  .or.
     1         ( (mxinc1 .eq. mxinc2) .and. ( (width1 .gt. width2) .or.
     2                                        ( (width1 .eq. width2)
     3                                         .and. oneis1) ) ) )
     4      go to 700
c
              if ( compon .eq. 1 )  revrs1 = .not. oneis1
c
              do 600 i = 1, depth
                  total(i) = total(i) + inc1(i)
  600         continue
              go to 1000
c
  700         if ( compon .eq. 1 )  revrs1 = oneis1
              do 800 i = cstart, cstop
                  worki = work(i)
                  tree1 (worki) = - tree2 (worki)
  800         continue
c
              do 900 i = 1, depth
                  total(i) = total(i) + inc2(i)
  900         continue
c
 1000 continue
      go to 2000
c     ... default when the reduced graph is empty
 1100 revrs1 = .true.
      space = 2*n
 2000 return
c     error found ...
 5000 space = -1
      go to 2000
 5100 space = 2 - avail
      error = 131
      go to 2000
 6000 error = 30
      go to 5000
 6100 error = 31
      go to 5000
 6200 error = 32
      go to 5000
      end
c**************************************************************************
      subroutine gpskch(n,degree,rstart,connec,status,nreduc,
     1 work, mxcomp, start, zsize, compns, error, space)
c     find the connected components of the graph induced by the set
c     of nodes with positive 'status'.  we shall build the list of
c     connected components in 'work', with a list of pointers
c     to the beginning nodes of components located in 'start'
      integer     n, rstart(n), nreduc, mxcomp, compns, error, space
      integer     degree(n), connec(1), status(n), work(nreduc),
     1            start(mxcomp), zsize(mxcomp)
c     parameters ...
c         n      -- dimension of the original matrix
c         degree, rstart, connec -- the structure of the original matrix
c         status -- derived from a level tree. positive entries indicate
c                   active nodes.  nodes with status <= 0 are ignored.
c         nreduc -- the number of active nodes
c         work   -- work space, used as a queue to build connected
c                   components in place.
c         mxcomp -- maximum number of components allowed by current
c                   space allocation.  must not be violated.
c         start  -- pointer to beginning of  i-th  connected component
c         zsize   -- size of each component
c         compns -- number of components actually found
c         error  -- should be zero on return unless we have too little
c                   space or we encounter an error in the data structure
c         space  -- maximum amount of workspace used / needed
      integer     i, j, free, jptr, node, jnode, front, cdgree, root
c     repeat
c         << find an unassigned node and start a new component >>
c         repeat
c             << add all new neighbors of front node to queue, >>
c             << remove front node.                            >>
c         until <<queue empty>>
c     until << all nodes assigned >>
      free   = 1
      compns = 0
      root   = 1
c ... start of outer repeat loop
c         ... find an unassigned node
  100     do 200 i = root, n
              if (status(i) .le. 0) go to 200
                  node = i
                  go to 300
  200     continue
          go to 6100
c         ... start new component
  300     compns = compns + 1
          root   = node + 1
          if (compns .gt. mxcomp)  go to 5000
          start (compns) = free
          work (free) = node
          status (node) = -status (node)
          front = free
          free = free + 1
c             ... inner repeat until queue becomes empty
  400         node = work (front)
              front = front + 1
c
              jptr = rstart (node)
              cdgree = degree (node)
              do 500 j = 1, cdgree
                  jnode = connec (jptr)
                  jptr = jptr + 1
                  if (status(jnode) .lt. 0) go to 500
                  if (status(jnode) .eq. 0) go to 6000
                      status (jnode) = -status (jnode)
                      work (free) = jnode
                      free = free + 1
  500         continue
c
              if (front .lt. free) go to 400
c ... end of inner repeat.  compute size of component and
c             see if there are more nodes to be assigned
          zsize (compns) = free - start (compns)
          if (free .le. nreduc)  go to 100
c
      if (free .ne. nreduc+1)  go to 6200
      return
 5000 space = nreduc - free + 1
      error = 130
      return
 6000 error = 33
      space = -1
      return
 6100 error = 34
      space = -1
      return
 6200 error = 35
      space = -1
      return
      end
c**************************************************************************
      subroutine gpskci(n,active,depth,lstruc,lvllst,lvlptr, 
     1 ltotal, error, space)
c transitional subroutine, algorithm ii to iiia or iiib.
c convert level structure given as vector of level numbers for nodes
c to structure as list of nodes by level
c     n, active, depth -- problem sizes
c     lstruc -- input level structure
c     lvllst, lvlptr -- output level structure
c     ltotal -- number of nodes at each level (precomputed)
      integer     n, active, depth, error, space
      integer     lstruc(n), lvllst(active), lvlptr(1), ltotal(depth)
c     structure of workspace ..
c         input (from combin) ..
c     ------------------------------------------------------------------
c     :  numbered  :  ..(n)..  :  total  :         ...        :  tree  :
c     ------------------------------------------------------------------
c
c         output (to gpskcj or gpskck) ..
c
c     ------------------------------------------------------------------
c     :  numbered  :       ...             :  tlist  :  tptr  :  tree  :
c     ------------------------------------------------------------------
c
c     here, numbered is the set of nodes in numbered components
c         total is a vector of length 'depth' giving the number
c         of nodes in each level of the 'tree'.
c         tlist, tptr are lists of nodes of the tree, arranged
c         by level.  tlist is of length 'active', tptr 'depth+1'.
      integer     i, acount, start, level, plevel
c     ... establish starting and ending pointers for each level
      start = 1
      do 100 i = 1, depth
          lvlptr(i) = start
          start = start + ltotal(i)
          ltotal(i) = start
  100 continue
      lvlptr(depth+1) = start
c
      acount = 0
      do 300 i = 1, n
          if (lstruc(i)) 200, 300, 6000
  200         level = -lstruc(i)
              lstruc(i) = level
              plevel = lvlptr (level)
              lvllst (plevel) = i
              lvlptr (level) = lvlptr (level) + 1
              acount = acount + 1
              if (lvlptr (level) .gt. ltotal (level))  go to 6100
  300 continue
c     ... reset starting pointers
      lvlptr(1) = 1
      do 400 i = 1, depth
          lvlptr(i+1) = ltotal(i)
  400 continue
      return
 6000 error = 40
      go to 6200
 6100 error = 41
 6200 space = -1
      return
      end
c************************************************************************
      subroutine gpskcj(n,degree,rstart,connec,ncompn,invnum,snode1,
     1 snode2, revrs1,depth, lvllst, lvlptr, lvlnum, error,space)
c     number the nodes in a generalized level structure according
c     to a generalization of the cuthill mckee strategy.
c
c     n      -- dimension of original problem
c     degree, rstart, connec -- give structure of sparse and
c                               symmetric matrix
c     ncompn -- number of nodes in this component of matrix graph
c     invnum -- will become a list of the original nodes in the order
c               which reduces the bandwidth of the matrix.
c     nxtnum -- the next index to be assigned (1 for first component)
c     revrs1 -- if .true., first component of reduced graph was numbered
c               backwards.
c     lvllst -- list of nodes in level tree ordered by level.
c     lvlptr -- position of initial node in each level of lvllst.
c     lvlnum -- level number of each node in component
      integer     n, rstart(n), ncompn, snode1, snode2, depth,
     1            error, space
      integer     degree(n), connec(1), invnum(ncompn),
     1            lvllst(ncompn), lvlptr(depth), lvlnum(n)
      logical     revrs1
c numbering requires two queues, which can be build in place in invnum.
c     ==================================================================
c     a l g o r i t h m    s t r u c t u r e
c     ==================================================================
c     << set queue1 to be the set containing only the start node. >>
c
c     for level = 1 to depth do
c         begin
c         loop
c             repeat
c                 begin
c                 << cnode <- front of queue1                        >>
c                 << add unnumbered neighbors of cnode to the back   >>
c                 << of queue1 or queue2 (use queue1 if neighbor     >>
c                 << at same level, queue2 if at next level).  sort  >>
c                 << the newly queued nodes into increasing order of >>
c                 << degree.  number cnode, delete it from queue1.   >>
c                 end
c             until
c                 << queue1 is empty >>
c         exit if << all nodes at this level numbered >>
c             begin
c             << find the unnumbered node of minimal degree at this >>
c             << level, restart queue1 with this node.              >>
c             end
c         end << loop loop >>
c         << promote queue2 to be initial queue1 for next iteration >>
c         << of  for  loop.                                         >>
c         end <<for loop>>
c     ==================================================================
c     structure of workspace ..
c     --------------------------------------------------------------
c     : numbered :  queue1  :  queue2  : ... : tlist : tptr : tree :
c     --------------------------------------------------------------
c     on completion, we have only a new, longer numbered set.
      integer     i, bq1, bq2, fq1, inc, cptr, cnode,
     1            inode, level, nleft, lstart, lwidth, queue1,
     2            queue2, cdgree, xlevel, stnode, ilevel, sq1, sq2,
     3            nsort, lowdg, bptr, lvllsc, lvllsb, invnmi
c
      logical     forwrd, rlevel
c ... gibbs-poole-stockmeyer heuristic choice of order
      if  (degree(snode1) .gt. degree(snode2))  go to 10
          forwrd = revrs1
          stnode = snode1
          go to 20
c
   10     forwrd = .not. revrs1
          stnode = snode2
c ... set up initial queues at front of 'invnum' for forwrd order,
c         at back for reversed order.
   20 if (forwrd) go to 100
          inc = -1
          queue1 = ncompn
          go to 200
c
  100     inc = +1
          queue1 = 1
c
  200 invnum (queue1) = stnode
      rlevel = (lvlnum(stnode) .eq. depth)
      lvlnum (stnode) = 0
      fq1 = queue1
      bq1 = queue1 + inc
c number nodes level by level ...
      do 3000 xlevel = 1, depth
          level = xlevel
          if  (rlevel)  level = depth - xlevel + 1
c
          lstart = lvlptr (level)
          lwidth = lvlptr (level+1) - lstart
          nleft = lwidth
          queue2 = queue1 + inc*lwidth
          bq2 = queue2
c ... 'loop' construct begins at statement 1000
c                 the inner 'repeat' will be done as many times as
c                 is necessary to number all the nodes at this level.
 1000     continue
c ... repeat ... until queue1 becomes empty
c take node from front of queue1, find each of its neighbors which have
c not yet been numbered, and add the neighbors to queue1 or queue2 
c according to their levels.
c
 1100             cnode = invnum (fq1)
                  fq1 = fq1 + inc
                  sq1 = bq1
                  sq2 = bq2
                  nleft = nleft - 1
c
                  cptr = rstart (cnode)
                  cdgree = degree (cnode)
                  do 1300 i = 1, cdgree
                      inode = connec (cptr)
                      cptr = cptr + 1
                      ilevel = lvlnum (inode)
                      if (ilevel .eq. 0)  go to 1300
                          lvlnum (inode) = 0
                          if ( ilevel .eq. level ) go to 1200
c
                              if  (iabs(level-ilevel) .ne. 1) go to 6400
                                  invnum (bq2) = inode
                                  bq2 = bq2 + inc
                                  go to 1300
c
 1200                             invnum (bq1) = inode
                                  bq1 = bq1 + inc
 1300             continue
c ... sort the nodes just added to queue1 and queue2
c separately into increasing order of degree.
                  if  (iabs (bq1 - sq1) .le. 1)  go to 1500
                      nsort = iabs (bq1 - sq1)
                      if  (forwrd)  go to 1400
                          call gpskcp (nsort, invnum(bq1+1), n, degree,
     1                                 error)
                          if  (error .ne. 0)  go to 6600
                          go to 1500
c
 1400                     call gpskcq (nsort, invnum(sq1), n, degree,
     1                                 error)
                          if  (error .ne. 0)  go to 6600
c
 1500             if  (iabs (bq2 - sq2) .le. 1)  go to 1700
                      nsort = iabs (bq2 - sq2)
                      if  (forwrd)  go to 1600
                          call gpskcp (nsort, invnum(bq2+1), n, degree,
     1                                 error)
                          if  (error .ne. 0)  go to 6600
                          go to 1700
c
 1600                     call gpskcq (nsort, invnum(sq2), n, degree,
     1                                 error)
                          if  (error .ne. 0)  go to 6600
c
c                     ... end of repeat loop
c
 1700             if  (fq1 .ne. bq1)  go to 1100
c ... queue1 is now empty ...
c if there are any unnumbered nodes left at this level,find the one of 
c minimal degree and return to the repeat loop above.
 2000     if  ((bq1 .eq. queue2) .and. (nleft .eq. 0))  go to 2900
c
              if ((nleft .le. 0) .or. (nleft .ne. inc * (queue2 - bq1)))
     1             go to 6200
c
              lowdg = n + 1
              bptr  = n + 1
              cptr  = lstart - 1
              do 2800 i = 1, nleft
 2600             cptr   = cptr + 1
                  lvllsc = lvllst (cptr)
                  if (lvlnum (lvllsc) .eq. level)  go to 2700
                      if (lvlnum (lvllsc) .ne. 0)  go to 6300
                      go to 2600
c
 2700             if  (degree(lvllsc) .ge. lowdg)  go to 2800
                      lowdg = degree (lvllsc)
                      bptr  = cptr
c
 2800         continue
c             ... minimal degree unnumbered node found ...
              if  (bptr .gt. n)  go to 6500
              lvllsb = lvllst (bptr)
              invnum (bq1) = lvllsb
              lvlnum (lvllsb) = 0
              bq1 = bq1 + inc
              go to 1000
c  ... advance queue pointers to make queue2 the
c                 new queue1 for the next iteration.
 2900     queue1 = queue2
          fq1 = queue1
          bq1 = bq2
          if  ((bq1 .eq. fq1) .and. (xlevel .lt. depth))  go to 6100
c
 3000 continue
c     ... change sign of degree to mark these nodes as 'numbered'
      do 3100 i = 1, ncompn
          invnmi = invnum(i)
          degree (invnmi) = -degree (invnmi)
 3100 continue
      return
 6000 space = -1
      return
 6100 error = 51
      go to 6000
 6200 error = 52
      go to 6000
 6300 error = 53
      go to 6000
 6400 error = 54
      go to 6000
 6500 error = 55
      go to 6000
 6600 error = 56
      go to 6000
      end
c************************************************************************
      subroutine gpskck(n,degree,rstart,connec,wrklen,nxtnum,
     1 work, ncompn, depth, lvllst, lvlptr, lvlnum, error, space)
c
      integer     n,rstart(n),wrklen,nxtnum,ncompn,depth,error,space
      integer     degree(n), connec(1), work(wrklen), lvllst(n),
     1            lvlptr(depth), lvlnum(n)
c     number nodes in a generalized level structure according to
c     a generalization of the king algorithm, which reduces
c     the profile of the sparse symmetric matrix.
c     ---------------------
c     code uses a priority queue to choose the next node to be numbered
c     the priority queue is represented by a simple linear-linked list
c     to save space.  this will require more searching than a fully
c     linked representation, but the data manipulation is simpler.
c     -------------------
c     << establish priority queue 'active' for level 1 nodes >>
c
c     for i = 1 to depth do
c         << set queue 'queued' to be empty, list 'next' to be >>
c         << set of nodes at next level.                       >>
c
c         for j = 1 to 'nodes at this level' do
c             << find first node in active with minimal connections >>
c             << to 'next'.  number this node and remove him from   >>
c             << 'active'.  for each node in 'next' which connected >>
c             << to this node, move it to 'queued' and remove it    >>
c             << from 'next'.                                       >>
c
c         << set new queue 'active' to be 'queued' followed by any >>
c         << nodes still in 'next'.                                >>
c
c     ==================================================================
c
c     data structure assumptions:
c     the first 'nxtnum-1' elements of  work  are already in use.
c     the level structure 'lvllst' is contiguous with  work, that is,
c     it resides in elements  wrklen+1, ...  of  work.  'lvlptr' and
c     'lvlnum' are also embedded in work, behind 'lvllst'.  the
c     three vectors are passed separately to clarify the indexing,
c     but the queues developed will be allowed to overrun 'lvllst'
c     as needed.
c
c     ... build the first 'active' queue starting w1 locations from
c         the front of the current working area  (w1 is the width of the
c         first level).  build the first 'queued' queue starting from
c         the back of work space.  the list 'next' will be realized
c         implicitly in 'lvlnum' as:
c                  lvlnum(i) > 0   <== level number of node.  'next' is
c                                      set with lvlnum(i) = level+1
c                  lvlnum(i) = 0   <== i-th node is in 'queued' or is
c                                      not in this component of graph,
c                                      or has just been numbered.
c                  lvlnum(i) < 0   <== i-th node is in 'active' and is
c                                      connected to -lvlnum(i) nodes in
c                                      'next'.
c     ==================================================================
c     structure of workspace ..
c     --------------------------------------------------------------
c     : numbered : done : active : alevel : ... : queued : lvllst :
c     --------------------------------------------------------------
c     -------------------
c       lvlptr : lvlnum :
c     -------------------
c     in the above,
c         numbered is the set of nodes already numbered from
c         previous components and earlier levels of this component.
c         done, active, alevel  are vectors of length the width of
c         the current level.  active is a set of indices into
c         alevel.  as the nodes in alevel are numbered, they
c         are placed into 'done'.
c         queued is a queue of nodes in the 'next' level, which
c         grows from the start of the 'next' level in lvllst
c         forwards toward 'alevel'.  queued is of length no more
c         than the width of the next level.
c         lvllst is the list of unnumbered nodes in the tree,
c         arranged by level.
c
c     ==================================================================
      integer     i, j, k, ptr, jptr, kptr, lptr, mptr, pptr, rptr,
     1            mpptr, jnode, knode, cnode, level, lowdg, unused,
     2            mxque, nnext, astart, mindg, lstart, lwidth, active,
     2            queueb, queued, qcount, nconnc, nactiv, cdgree,
     3            ldgree, nfinal, jdgree, strtic, added, twrkln,
     4            lvllsl, connej, conner, astptr, actptr, activi,
     5            astrti, queuei, acpptr
c
      twrkln = wrklen + ncompn + n + depth + 1
      unused = twrkln
c
      astart = lvlptr(1)
      lwidth = lvlptr(2) - astart
      astart = wrklen  + 1
      active = nxtnum + lwidth + 1
      nactiv = lwidth
      nfinal = nxtnum + ncompn 
c
      nnext = lvlptr(3) - lvlptr(2)
      queued = wrklen
      queueb = queued
      mxque = active + lwidth
c     ... build first priority queue 'active'
      lowdg = - (n + 1)
      lptr = lvlptr(1)
      do 200 i = 1, lwidth
          nconnc = 0
          lvllsl= lvllst (lptr)
          jptr = rstart (lvllsl)
          ldgree = degree(lvllsl)
          do 100 j = 1, ldgree
              connej = connec (jptr)
              if ( lvlnum (connej) .eq. 2 )  nconnc = nconnc - 1
              jptr = jptr + 1
  100     continue
c
          activi = active + i - 1
          work (activi) = i
          lvlnum (lvllsl) = nconnc
          lowdg = max0 (lowdg, nconnc)
          lptr = lptr + 1
  200 continue
      work (active-1) = 0
c     now number nodes level by level ...
      do 2000 level = 1, depth
c         ... number all nodes in this level
          do 1100 i = 1, lwidth
              pptr = -1
              ptr = work (active-1)
              if (nnext .eq. 0)  go to 1000
c if nodes remain in next, find the earliest node in active of minimal degree.
                  mindg = -(n+1)
                  do 400 j = 1, nactiv
                      astptr = astart + ptr
                      cnode = work (astptr)
                      if ( lvlnum (cnode) .eq. lowdg )  go to 500
                      if ( lvlnum (cnode) .le. mindg )  go to 300
                          mpptr = pptr
                          mptr = ptr
                          mindg = lvlnum (cnode)
  300                 pptr = ptr
                      actptr = active + ptr
                      ptr = work (actptr)
  400             continue
c establish  ptr  as first min degree node pptr as predecessor in list.
                  ptr = mptr
                  pptr = mpptr
c
  500             astptr = astart + ptr
                  cnode = work (astptr)
                  lowdg = lvlnum (cnode)
                  lvlnum (cnode) = 0
                  jptr = rstart (cnode)
c update connection counts for all nodes which
c connect to  cnode's  neighbors in  next.
                  cdgree = degree(cnode)
                  strtic = queueb
c
                  do 700 j = 1, cdgree
                      jnode = connec (jptr)
                      jptr = jptr + 1
                      if (lvlnum (jnode) .ne. level+1 )  go to 700
                          if (queueb .lt. mxque)  go to 5000
                          work (queueb) = jnode
                          queueb = queueb - 1
                          nnext = nnext - 1
                          lvlnum (jnode) = 0
                          if  (nactiv .eq. 1)  go to 700
                            kptr = rstart (jnode)
                            jdgree = degree (jnode)
                            do 600 k = 1, jdgree
                                knode = connec (kptr)
                                kptr = kptr + 1
                                if (lvlnum (knode) .ge. 0)  go to 600
                                    lvlnum (knode) = lvlnum (knode) + 1
                                    if  (lowdg .lt. lvlnum(knode))
     1                                   lowdg = lvlnum(knode)
  600                       continue
  700             continue
c to mimic the algorithm as implemented by gibbs, sort the nodes just
c added to the queue into increasing order of original index. (but, because
c the queue is stored backwards in memory, the sort routine is called
c for decreasing index.)
c
c treat  0, 1 or 2  nodes added as special cases
                  added = strtic - queueb
                  if  (added - 2)  1000, 800, 900
c
  800                 if (work(strtic-1) .gt. work(strtic))  go to 1000
                          jnode = work(strtic)
                          work(strtic) = work(strtic-1)
                          work(strtic-1) = jnode
                          go to 1000
c
  900                 call gpskco (added, work(queueb+1), error)
                      if  (error .ne. 0)  go to 5500
c number this node and delete it from 'active'.
c mark it unavailable by changing sign of degree
 1000         nactiv = nactiv - 1
              astptr = astart + ptr
              cnode = work (astptr)
              work (nxtnum) = cnode
              degree (cnode) = -degree (cnode)
              nxtnum = nxtnum + 1
c             ... delete link to this node from list
              acpptr = active + pptr
              actptr = active + ptr
              work (acpptr) = work (actptr)
 1100     continue
c ... now move the queue 'queued' forward, at the same
c             time computing connection counts for its elements.
c             then do the same for the remaining nodes in 'next'.
          unused = min0 (unused, queueb - mxque)
          if ( nxtnum .ne. active-1 )  go to 5100
          if ( level .eq. depth ) go to 2000
              lstart = lvlptr (level+1)
              lwidth = lvlptr (level+2) - lstart
              active = nxtnum + lwidth + 1
              astart = active + lwidth
              nactiv = lwidth
              mxque = astart + lwidth
              if ( mxque .gt. queueb + 1 )  go to 5000
              unused = min0 (unused, queueb - mxque + 1)
c
              qcount = queued - queueb
              lowdg = -n-1
              work (active-1) = 0
c
              ptr = lstart
              do 1600 i = 1, lwidth
c ... choose next node from either 'queued' or 'next'
                  if (i .gt. qcount )  go to 1200
                      queuei = queued + 1 - i
                      cnode = work (queuei)
                      go to 1300
c
 1200                 cnode = lvllst (ptr)
                      ptr = ptr + 1
                       if ( ptr .gt. lvlptr(level+2) )  go to 5200
                          if (lvlnum (cnode) .gt. 0)  go to 1300
                              go to 1200
c
1300             if ( level+1 .eq. depth ) go to 1500
c
                      rptr = rstart (cnode)
                      nconnc = 0
                      jdgree = degree (cnode)
                      do 1400 j = 1, jdgree
                          conner = connec (rptr)
                          if ( lvlnum (conner) .eq. level+2 )
     1                        nconnc = nconnc - 1
                          rptr = rptr + 1
 1400                 continue
                      lvlnum (cnode) = nconnc
                      lowdg = max0 (lowdg, nconnc)
c ... add cnode to new 'active' queue
 1500             activi = active + (i - 1)
                  astrti = astart + (i - 1)
                  work (activi) = i
                  work (astrti) = cnode
 1600         continue
c
              if (depth .eq. level+1 ) go to 1700
                  nnext = lvlptr (level+3) - lvlptr (level+2)
                  queued = lstart - 1 + lwidth + wrklen
                  queueb = queued
                  go to 2000
c
 1700             nnext = 0
c
 2000 continue
c
c      print *,nxtnum,nfinal
      if  (nxtnum .ne. nfinal)  go to 5300
      space = max0 (space, twrkln - unused)
      return
 5000 space = nactiv + nnext
      error = 160
      return
 5100 error = 61
      go to 5400
 5200 error = 62
      go to 5400
c !!!!!!!
 5300 error = 63
 5400 return
 5500 error = 64
      go to 5400
      end
c************************************************************************
      subroutine   gpskcl   (n, degree, rstart, connec, invnum, newnum, 
     1                       oldnum, bandwd, profil, error, space)
c
      integer     n, rstart(n), bandwd, profil, error, space
      integer     degree(n), connec(1), invnum(n), newnum(n), oldnum(n)
c compute the bandwidth and profile for the renumbering given
c by 'invnum' and also for the renumbering given by 'oldnum'.
c 'newnum' will be a permutation vector copy of the node list 'invnum'.
      integer     i, j, jptr, idgree, oldbnd, oldpro, newbnd, newpro,
     1            oldrwd, newrwd, oldorg, neworg, jnode, invnmi
c     ... create newnum as a permutation vector
      do 100 i = 1, n
          invnmi = invnum (i)
          newnum (invnmi) = i
  100 continue
c compute profile and bandwidth for both the old and the new orderings.
      oldbnd = 0
      oldpro = 0
      newbnd = 0
      newpro = 0
c
      do 300 i = 1, n
          if (degree(i) .eq. 0)  go to 300
          if (degree(i) .gt. 0)  go to 6000
              idgree = -degree(i)
              degree(i) = idgree
              neworg = newnum(i)
              oldorg = oldnum(i)
              newrwd = 0
              oldrwd = 0
              jptr = rstart (i)
c find neighbor which is numbered farthest ahead of the current node.
              do 200 j = 1, idgree
                  jnode = connec(jptr)
                  jptr = jptr + 1
                  newrwd = max0 (newrwd, neworg - newnum(jnode))
                  oldrwd = max0 (oldrwd, oldorg - oldnum(jnode))
  200         continue
c
              newpro = newpro + newrwd
              newbnd = max0 (newbnd, newrwd)
              oldpro = oldpro + oldrwd
              oldbnd = max0 (oldbnd, oldrwd)
  300 continue
c ... if new ordering has better bandwidth than old ordering,
c         replace old ordering by new ordering
      if  (newbnd .gt. oldbnd)  go to 500
          bandwd = newbnd
          profil = newpro
          do 400 i = 1, n
              oldnum(i) = newnum(i)
  400     continue
          go to 600
c ... retain old ordering
  500     bandwd = oldbnd
          profil = oldpro
c
  600 return
 6000 space = -1
      error = 70
      return
      end
c**************************************************************************
      subroutine   gpskcm   (n, degree, rstart, connec, invnum, newnum, 
     1                       oldnum, bandwd, profil, error, space)
      integer     n, rstart(n), bandwd, profil, error, space
      integer     degree(n), connec(n), invnum(n), newnum(n), oldnum(n)
c     compute the bandwidth and profile for the renumbering given
c     by 'invnum', by the reverse of numbering 'invnum', and also
c     by the renumbering given in 'oldnum'.
c     'newnum' will be a permutation vector copy of the node
c     list 'invnum'.
      integer     i, j, jptr, idgree, oldbnd, oldpro, newbnd, newpro,
     1            oldrwd, newrwd, oldorg, neworg, jnode, nrvbnd, nrvpro,
     2            nrvorg, nrvrwd, invnmi, nmip1
c     ... create newnum as a permutation vector
      do 100 i = 1, n
          invnmi = invnum (i)
          newnum (invnmi) = i
  100 continue
c compute profile and bandwidth for both the old and the new orderings.
      oldbnd = 0
      oldpro = 0
      newbnd = 0
      newpro = 0
      nrvbnd = 0
      nrvpro = 0
c
      do 300 i = 1, n
          if (degree(i) .eq. 0)  go to 300
          if (degree(i) .gt. 0)  go to 6000
              idgree = -degree(i)
              degree(i) = idgree
              newrwd = 0
              oldrwd = 0
              nrvrwd = 0
              neworg = newnum(i)
              oldorg = oldnum(i)
              nrvorg = n - newnum(i) + 1
              jptr = rstart (i)
c ... find neighbor which is numbered farthest ahead of the current node.
              do 200 j = 1, idgree
                  jnode = connec(jptr)
                  jptr = jptr + 1
                  newrwd = max0 (newrwd, neworg - newnum(jnode))
                  oldrwd = max0 (oldrwd, oldorg - oldnum(jnode))
                  nrvrwd = max0 (nrvrwd, nrvorg - n + newnum(jnode) - 1)
  200         continue
c
              newpro = newpro + newrwd
              newbnd = max0 (newbnd, newrwd)
              nrvpro = nrvpro + nrvrwd
              nrvbnd = max0 (nrvbnd, nrvrwd)
              oldpro = oldpro + oldrwd
              oldbnd = max0 (oldbnd, oldrwd)
  300 continue
c ... if new ordering has better bandwidth than old ordering,
c         replace old ordering by new ordering
      if  ((newpro .gt. oldpro)  .or. (newpro .gt. nrvpro)) go to 500
          bandwd = newbnd
          profil = newpro
          do 400 i = 1, n
              oldnum(i) = newnum(i)
  400     continue
          go to 800
c ... check new reversed ordering for best profile
  500 if  (nrvpro .gt. oldpro)  go to 700
          bandwd = nrvbnd
          profil = nrvpro
          do 600 i = 1, n
              oldnum(i) = n - newnum(i) + 1
              if  (i .gt. n/2)  go to 600
                  j = invnum(i)
                  nmip1 = (n + 1) - i
                  invnum(i) = invnum (nmip1)
                  invnum (nmip1) = j
  600     continue
          go to 800
c ... retain old ordering
  700     bandwd = oldbnd
          profil = oldpro
c
  800 return
 6000 error = 71
      space = -1
      return
      end
c***************************************************************************
      subroutine   gpskcn   (n, key, data, error)                       
c     i n s e r t i o n    s o r t
c     input:
c         n    -- number of elements to be sorted
c         key  -- an array of length  n  containing the values
c                 which are to be sorted
c         data -- a second array of length  n  containing data
c                 associated with the individual keys.
c     output:
c         key  -- will be arranged so that values are in decreasing
c                 order
c         data -- rearranged to correspond to rearranged keys
c         error -- will be zero unless the program is malfunctioning,
c                  in which case it will be equal to 1.
      integer     n,error,key(n),data(n)
      integer     i, j, d, k, ip1, jm1
c
      if (n .eq. 1)  return
      if  (n .le. 0)  go to 6000
c
      error = 0
c     ... insertion sort ... for i := n-1 step -1 to 1 do ...
 2400 i = n - 1
      ip1 = n
c
 2500     if ( key (i) .ge. key (ip1) )  go to 2800
c             ... out of order ... move up to correct place
              k = key (i)
              d = data (i)
              j = ip1
              jm1 = i
c             ... repeat ... until 'correct place for k found'
 2600             key (jm1) = key (j)
                  data (jm1) = data (j)
                  jm1 = j
                  j = j + 1
                  if  (j .gt. n)  go to 2700
                  if (key (j) .gt. k)  go to 2600
c
 2700         key (jm1) = k
              data (jm1) = d
c
 2800     ip1 = i
          i = i - 1
          if ( i .gt. 0 )  go to 2500
c
 3000 return
c
 6000 error = 1
      go to 3000
c
      end
c**************************************************************************
      subroutine   gpskco   (n, key, error)                             
c     i n s e r t i o n    s o r t
c     input:
c         n    -- number of elements to be sorted
c         key  -- an array of length  n  containing the values
c                 which are to be sorted
c     output:
c         key  -- will be arranged so that values are in decreasing
c                 order
      integer     n, error,key(n)
      integer     i, j, k, ip1, jm1
      if (n .eq. 1)  return
      if  (n .le. 0)  go to 6000
c
      error = 0
c
c     ... insertion sort ... for i := n-1 step -1 to 1 do ...
c
 2400 i = n - 1
      ip1 = n
c
 2500     if ( key (i) .ge. key (ip1) )  go to 2800
c ... out of order ... move up to correct place
              k = key (i)
              j = ip1
              jm1 = i
c ... repeat ... until 'correct place for k found'
 2600             key (jm1) = key (j)
                  jm1 = j
                  j = j + 1
                  if  (j .gt. n)  go to 2700
                  if (key (j) .gt. k)  go to 2600
c
 2700         key (jm1) = k
c
 2800     ip1 = i
          i = i - 1
          if ( i .gt. 0 )  go to 2500
 3000 return
 6000 error = 1
      go to 3000
c
      end
c**************************************************************************
      subroutine  gpskcp  (n, index, nvec, degree, error)               
c     i n s e r t i o n      s o r t
c     input:
c         n    -- number of elements to be sorted
c         index  -- an array of length  n  containing the indices
c                 whose degrees are to be sorted
c         degree -- an  nvec  vector, giving the degrees of nodes
c                   which are to be sorted.
c     output:
c         index  -- will be arranged so that values are in decreasing
c                 order
c         error -- will be zero unless the program is malfunctioning,
c                  in which case it will be equal to 1.
      integer     n, nvec, error,index(n), degree(nvec)
      integer     i, j, v, ip1, jm1, indexi, indxi1, indexj
      if (n .eq. 1)  return
      if  (n .le. 0)  go to 6000
c
      error = 0
c     insertion sort the entire file
c     ... insertion sort ... for i := n-1 step -1 to 1 do ...
c
 2400 i = n - 1
      ip1 = n
c
 2500     indexi = index (i)
          indxi1 = index (ip1)
          if ( degree(indexi) .ge. degree(indxi1) )  go to 2800
c ... out of order ... move up to correct place
              v = degree (indexi)
              j = ip1
              jm1 = i
              indexj = index (j)
c ... repeat ... until 'correct place for v found'
 2600             index (jm1) = indexj
                  jm1 = j
                  j = j + 1
                  if (j .gt. n)  go to 2700
                  indexj = index (j)
                  if (degree(indexj) .gt. v)  go to 2600
c
 2700         index (jm1) = indexi
c
 2800     ip1 = i
          i = i - 1
          if ( i .gt. 0 )  go to 2500
c
 3000 return
 6000 error = 1
      go to 3000
      end
c************************************************************************
      subroutine  gpskcq (n, index, nvec, degree, error)                
c     i n s e r t i o n      s o r t
c     input:
c         n    -- number of elements to be sorted
c         index  -- an array of length  n  containing the indices
c                 whose degrees are to be sorted
c         degree -- an  nvec  vector, giving the degrees of nodes
c                   which are to be sorted.
c     output:
c         index  -- will be arranged so that values are in increasing
c                   order
c         error -- will be zero unless the program is malfunctioning,
c                  in which case it will be equal to 1.
      integer     n, nvec, error,index(n), degree(nvec)
      integer     i, j, v, indexi, indxi1, indexj, ip1, jm1
      if (n .eq. 1)  return
      if  (n .le. 0)  go to 6000
c
      error = 0
c     insertion sort the entire file
c     ... insertion sort ... for i := n-1 step -1 to 1 do ...
c
 2400 i = n - 1
      ip1 = n
c
 2500     indexi = index (i)
          indxi1 = index (ip1)
          if ( degree(indexi) .le. degree(indxi1) )  go to 2800
c ... out of order ... move up to correct place
              v = degree (indexi)
              j = ip1
              jm1 = i
              indexj = index (j)
c             ... repeat ... until 'correct place for v found'
 2600             index (jm1) = indexj
                  jm1 = j
                  j = j + 1
                  if (j .gt. n)  go to 2700
                  indexj = index (j)
                  if (degree(indexj) .lt. v)  go to 2600
 2700         index (jm1) = indexi
 2800     ip1 = i
          i = i - 1
          if ( i .gt. 0 )  go to 2500
 3000 return
 6000 error = 1
      go to 3000
      end
c *************************main main main**************************************
c         gpstrf ..                                                     
c a subroutine which generates the full structure of the graph of a sparse     
c matrix, given the graph of the lower 
c triangle stored by columns  (or upper triangle stored by rows).
c         gpsrpk ..                                                     
c             a subroutine which repacks the connectivity or graph      
c             structure to the original lower triangular form           
c         gpslpk ..                                                     
c             a subroutine which takes the original data and the output 
c             reordering from the gibbs-poole-stockmeyer algorithm, and 
c             produces the required input for the linpack positive      
c             definite band linear equation solvers.  a simple printer  
c             listing of the output data structures is provided.        
c         gpsenv ..                                                     
c             a subroutine which takes the original data, and the output
c             reordering from the gibbs-king algorithm, and produces    
c             a reasonable data structure for a hypothetical envelope   
c             (variable bandwidth) linear equation solver (e.g., the    
c             envelope solver in sparspak).  a simple routine for       
c             printing the output data structures is provided.          
c                                                                       
c     the code assumes symmetric matrices with the lower triangle stored    
c     by columns.
      subroutine bandred(n,nz,liwork,iwork,lrwork,rwork,optpro,error,
     1 iperm,mrepi,iband)
      integer n,nz,error,optpro,iperm(n),mrepi(n),iband(n) 
      integer cstart,connec,invcol,degree,bandwd,         
     1 profil,permut,gpswrk,ireqd,space,gpserr,mxreqd,gpswln
      integer liwork,lrwork,iwork(liwork)
      double precision  rwork(lrwork)
      error=0
      do 1,i=1,n
         iband(i)=1
         mrepi(i)=i
         iperm(i)=i
 1    continue
   10 continue
      if  (error.ne.0)  go to 3000                                           
      cstart = 1                                                        
      permut = cstart + (n + 1)                                         
      connec = permut + n                                               
c     ... build full adjacency (connectivity) structure required for    
c         the reordering routines.  integer workspace is partitioned as 
c             column starts         (   n+1  )  (lower triangle)        
c             permutation from gps  (    n   )                          
c             adjacency structure   (2*nz - n)  (nz = nonzeroes in lower
c                                                triangle and diagonal) 
c             node degrees          (    n   )  (full structure)        
c             gps workspace         ( 6*n + 3)                          
c                                                                       
c         the 2*nz locations consisting of the adjacency structure      
c         and the vector of degrees are remapped into two vectors       
c         of length  nz  by subroutine  gpsrpk, and used in that        
c         form by the routines which reformat the real data.            
      degree = connec + (2*nz - n)                                      
      gpswrk = degree + n                                               
      ireqd = gpswrk + 6*n + 3                                          
      if  (liwork .lt. ireqd)  go to 3100                               
      gpswln = liwork - gpswrk + 1                                      
      call gpstrf(n,iwork(cstart),iwork(connec),iwork(gpswrk),     
     1              iwork(degree), iwork(permut), error)
      if  (error.ne.0)  go to 3000 
      call gpskca (n, iwork(degree), iwork(cstart), iwork(connec),      
     1             optpro, gpswln, iwork(permut), iwork(gpswrk),        
     2             bandwd, profil, gpserr, space)                       
c     
      do 21 i=1,n
         iperm(i)=iwork(permut+i-1)
         mrepi(i)=iwork(gpswrk+i-1)
 21   continue
c !!!!!
      if  (gpserr .ne. 0)  go to 3000                                    
      invcol = connec + nz                                              
      call gpsrpk (n, nz,iwork(cstart),iwork(connec),iwork(invcol),  
     1              error)                                       
      if  (error.ne.0)  go to 3000                                           
c                                                                       
      if  (optpro.eq.1)  go to 100                                           
      mxreqd = (bandwd + 1)  *  n                                       
      if  (mxreqd .gt. lrwork)  go to 4000                              
c                                                                       
        call gpslpk (n,nz,lrwork,bandwd,iwork(cstart),            
     1     iwork(connec),iwork(permut),iwork(invcol),rwork, error)
        iband(1)=bandwd
          go to 200                                                     
  100   call gpsenv (n, nz, profil, lrwork, iwork(connec),           
     1       iwork(cstart), iwork(invcol), iwork(permut),    
     2                  iwork(gpswrk), rwork, error)            
c
        do 22 i=1,n
         iband(i)=iwork(i)
 22   continue
  200 if  (error.ne.0)  go to 3000 
  300 return
 3000 continue
      error=64000
c call erro('program terminated by error')
      go to 300                                                         
 3100 call erro('insufficient workspace for integers')
c     write (6, 63100) ireqd                                       
      go to 300                                                         
 4000 call erro('reordering completed')
      call erro('real workspace insufficient for factorization')
      go to 300                                                         
63100 format (36h0insufficient workspace for integers    /              
     1        17h0require at least , i8)                                
      end                                                               
c************************************************************************
      subroutine gpstrf(n,cstart,connec,cstrt2,degree,permut,error)
c     transform connectivity data from form as lower triangle by columns
c         (upper triangle by rows) to complete connectivity structure.
c
c     this subroutine will check the data to ensure that only the
c     lower triangle is present.  repeated elements are allowed,
c     but no attempt will be made to detect them and reduce storage.
      integer     n,degree(1), connec(1), permut(n)
      integer     cstart(1), cstrt2(1),error
c         ... (actual dimension for cstart and cstrt2 is  n+1.  actual
c              dimension for connec is  2*nz - n)
      integer     i, j, k, kstart, nk, kstop, rk, rj, istart,
     1            jstart, jk
c     ... determine strict lower triangle degree of each node
      do 100 j = 1, n
          degree(j) = cstart(j+1) - cstart(j)
  100 continue
c     ... determine degree in full adjacency structure
      do 400 j = 1, n
          kstart = cstart(j)
          kstop  = cstart(j+1) - 1
          if  (kstart .gt. kstop)  go to 400
          do 300 k = kstart, kstop
              i = connec(k)
              if  (i - j) 3100, 300,  200
c                         i<j   i=j   i>j
c             ... in lower triangle
  200             if  (i .gt. n)  go to 3000
                      degree(i) = degree(i) + 1
  300     continue
  400 continue
c     ... compute row starts in full adjacency structure
      cstrt2(1) = 1
      if  (n .le. 1)  go to 1000
c
      do 500 i = 2, n
          cstrt2(i) = cstrt2(i-1) + degree(i-1)
  500 continue
c     ... expand lower adjacency structure into space for full adjacency
c         structure.  real workspace is left alone.
c         loops run backward, from last column to first, and last row
c         to first within column, to ensure that no overwriting occurs
c         and that the lower triangle is contiguous as the first group
c         of entries within a column of the full structure.
      do 700 rj = 1, n
          j = n - rj + 1
          jstart = cstrt2 (j)
          kstart = cstart (j)
          nk     = cstart(j+1) - kstart
          if  (nk .le. 0)  go to 700
c
          do 600 rk = 1, nk
              k = kstart + (nk - rk)
              i = connec(k)
              jk = jstart + (nk - rk)
              connec(jk) = i
c             ... build upper triangle
              if  (i .eq. j)  go to 600
              istart = cstrt2(i)
              connec (istart) = j
              cstrt2 (i) = istart + 1
  600     continue
          cstrt2 (j) = jstart + nk
  700 continue
c     ... reset row start pointers for full connectivity structure
c         and initialize permutation vector for gps
      do 800 j = 1, n
          cstart (j) = cstrt2 (j) - degree (j)
          permut (j) = j
  800 continue
      cstart(n+1) = cstart(n) + degree(n)
 1000 return
 3000 call erro('row index out of range')
c write (6, 63000) i, j
      error = 999
      go to 1000
 3100 call erro('data out of proper triangle')
c write (6, 63100) i, j
      error = 999
      go to 1000
63000 format (23h0row index out of range /
     1        4h i =, i8 /  4h j =, i8)
63100 format (30h0data out of proper triangle      /
     1        32h0i  should be greater than  j        /
     2        4h i =, i8 /
     3        4h j =, i8)
c
      end
c************************************************************************
      subroutine  gpsrpk(n,nz,cstart,connec,invcol,error)
c     return connectivity information to original format
c     to match form of real data for nonzero values.
c     this repacking enables us to carry out the physical reordering
c     with only a single copy of the connectivity structure.
      integer  n,nz,invcol(nz),connec(1),cstart(2),error
c     ... actual dimensions of cstart and connec are n+1  and  2*nz - n
c         respectively.  on input, connec contains the connectivity
c         structure of both triangles of the matrix, including one
c         copy of the diagonal.  on output, the first  nz  locations
c         of connec have returned to their original values, giving
c         the lower triangle as a list of row indices grouped by
c         column.  in this package, the vector  invcol  is allowed
c         to overlap the last  nz-n  locations of connec, and contains
c         on output the column indices for the corresponding row
c         indices in connec.
      integer     i, istart, istop, iptr, j
c     ... repack to lower triangle form (eliminating upper triangle)
c         (row indices stored by columns)
      iptr = cstart(1)
      do 200 j = 1, n
          istart = cstart(j)
          istop  = cstart(j+1) - 1
          cstart(j) = iptr
          if  (istop .lt. istart)  go to 200
          do 100 i = istart, istop
              if  (connec(i) .lt. j)  go to 100
                  connec(iptr) = connec(i)
                  iptr = iptr + 1
  100     continue
  200 continue
      cstart(n+1) = iptr
c
      if  (iptr .ne. nz+1)  go to 3000
c store column indices in next nz locations in connec to enable us to
c quickly recover the column index in the repacking of the real data.
      do 400 j = 1, n
          istart = cstart(j)
          istop  = cstart(j+1) - 1
          if  (istop .lt. istart)  go to 400
          do 300 i = istart, istop
              invcol(i) = j
  300     continue
  400 continue
c
 1000 return
c
 3000 call erro('program check in subroutine gpsrpk')
      error = 999
      go to 1000
c
      end
c************************************************************************
      subroutine  gpslpk (n,nz,alen,bandwd,cstart,connec,permut, 
     1                     invcol, a, error)
c     reorder real data into form for input to linpack positive
c     definite symmetric band matrix factorizer and solver
      integer     n, nz, alen, bandwd,cstart(1)
      integer     connec(nz), permut(n), invcol(nz),error
      double precision        a(alen)
c     ... actual dimensions required above
c         cstart -- n+1
c         a      -- n * (bandwd + 1)
c
c         the vector  a  represents, in input, the packed nonzeroes
c         of the lower triangle of the matrix, stored by columns.
c         on output, it is the upper triangle of the matrix, stored
c         by columns in the linpack band format, with  lda = bandwd+1
      integer     i, j, k, kstart, kstop, newi, newj, gnewj, bandp1,
     1            nzp1, laband, xaddr, nxaddr, nextj, nexti
      double precision        x, nextx
c     ... zero out currently unused part of a
      bandp1 = (bandwd + 1)
      laband = bandp1 * n
      if  (laband .gt. alen)  go to 3100
c
      nzp1 = nz + 1
      if  (nzp1 .gt. laband)  go to 200
      do 100 k = nzp1, laband
          a(k) = 0.0
  100 continue
c move entries from packed data structure in front part  of vector  a  into
c their final locations.  if the final  location is occupied (a collision), 
c recursively, move that entry on to its final location, ...
  200 do 800 j = 1, n
          kstart = cstart (j)
          kstop  = cstart (j+1) - 1
          gnewj  = permut (j)
c move all entries in  j-th  column     statement 300 below is return 
c point for an indefinite loop of the form  repeat ... until no collisions
          if  (kstop .lt. kstart)  go to 800
          do 700 k = kstart, kstop
              i = connec(k)
              if  (i .eq. 0)  go to 700
c
              newj = gnewj
              xaddr = k
              x     = a(k)
              a(k)  = 0.0
c
  300         newi  = permut (i)
              connec (xaddr) = 0
              if  (iabs (newi - newj) .gt. bandwd)  go to 3000
c get address of permuted (i,j) - element
              if  (newj .lt. newi)  go to 400
                  nxaddr = bandp1 * newj  +  (newi - newj)
                  go to 500
c
  400             nxaddr = bandp1 * newi  +  (newj - newi)
c             ... check for collison
  500         if  (nxaddr .gt. nz)  go to 600
              nexti = connec (nxaddr)
              if  (nexti .eq. 0)  go to 600
c collision -- target of current nonzero is still occupied. pick up values in
c target location, store current x, and go back to 300 with the new value for x
                  nextx = a(nxaddr)
                  a (nxaddr) = x
                  x     = nextx
c get row and column indices for element with which we collided
                  i     = nexti
                  nextj = invcol(nxaddr)
                  newj  = permut (nextj)
                  xaddr = nxaddr
                  go to 300
c
  600         a (nxaddr) = a (nxaddr)  +  x
c
  700     continue
  800 continue
 1000 return
c     ... error handling for data structure destruction
 3000 continue
      call erro('program failure in subroutine gpslpk')
c write (6, 63000) i, j, newi, newj
      error = 999
      go to 1000
 3100 continue
      call erro('program failure in subroutine gpslpk')
c write (6, 63100) alen, laband
      error = 999
      go to 1000
63000 format (1h0 / 37h0program failure in subroutine gpslpk /
     1        17h0i, j, newi, newj, 4i10)
63100 format (1h0 / 37h0program failure in subroutine gpslpk /
     1        35h0length supplied for reals is only , i8 /
     2        20h0length required is , i8)
c
      end
c************************************************************************
      subroutine  gpsenv  (n, nz, profil, alen, connec, cstart, invcol, 
     1                     permut, xenv, a, error)
c     produce the lower triangle of the envelope matrix resulting
c     from reordering a sparse symmetric matrix with the permutation
c     given by gibbs-poole-stockmeyer-king.
c
c     the lower triangle of the the original matrix is stored by
c     columns, with row indices in 'connec', nonzero values in
c     'a'.  on output, the reordered matrix will be stored with the
c     diagonal entries in the first  n  locations of  a, and the
c     off-diagonal envelope for the lower triangle stored by rows
c     in the next  alen - n  locations of  a.  the vector  cstart
c     will be overwritten to contain the initial entry in the
c     envelope for each row of  a.
c
      integer     n, nz, profil, alen, cstart(1), xenv(1)
      integer     connec(nz), invcol(nz), permut(n),error
      double precision        a(alen)
      integer     i, j, k, newi, newj, lenv, nextj, nxaddr, xaddr,
     1            kstart, kstop, eptr, nzp1, gnewj, nexti
      double precision        x, nextx
c     ... determine envelope structure from permutation
      do 100 i = 1, n
          xenv(i) = 0
  100 continue
c
      do 400 i = 1, n
          newi = permut (i)
          kstart = cstart (i)
          kstop  =  cstart (i+1) - 1
          if  (kstop .lt.  kstart)  go to 400
          do 300 k = kstart, kstop
              j = connec(k)
              newj = permut (j)
              if  (newi .gt. newj)  go to 200
                  xenv(newj) = max0( xenv(newj), newj - newi )
                  go to 300
  200             xenv(newi) = max0( xenv(newi), newi - newj )
  300     continue
  400 continue
c
      lenv = 0
      do 310 i = 1, n
          lenv = lenv + xenv(i)
  310 continue
      if  (profil .ne. lenv)  go to 3100
      if  (profil + n  .gt.  alen)  go to 3000
      if  (xenv(1) .ne. 0)  go to 3200
c     ... reset xenv entries to point to last entry in row
      eptr = n
      do 500 i = 1, n
          eptr = eptr + xenv(i)
          xenv(i) = eptr
  500 continue
c     ... initialize envelope
      nzp1 = nz + 1
      lenv = lenv + n
      if  (nzp1 .gt. lenv)  go to 700
      do 600 i = nzp1, lenv
          a(i) = 0.0
  600 continue
c     ... move entries from packed data structure in front part
c         of vector  a  into their final locations.  if the final
c         location is occupied (a collision), recursively, move that
c         entry on to its final location, ...
  700 do 1500 j = 1, n
          kstart = cstart (j)
          kstop  = cstart (j+1) - 1
          gnewj  = permut (j)
c         ... move all entries in  j-th  column
c             statement 800 below is return point for an indefinite
c             loop of the form  repeat ... until no collisions
          if  (kstop .lt. kstart)  go to 1500
          do 1400 k = kstart, kstop
              i = connec(k)
              if  (i .eq. 0)  go to 1400
c
              newj = gnewj
              xaddr = k
              x     = a(k)
              a(k)  = 0.0
c
  800         newi  = permut (i)
              connec (xaddr) = 0
c             ... get address of permuted (i,j) - element
              if  (newj - newi)  900, 1000, 1100
c
  900             nxaddr = xenv(newi) -  (newi - newj - 1)
                  if  (nxaddr .le. xenv(newi-1))  go to 3200
                  go to 1200
c
 1100             nxaddr = xenv(newj) - (newj - newi - 1)
                  if  (nxaddr .le. xenv(newj-1))  go to 3200
c
                  go to 1200
 1000             nxaddr = newi
c             ... check for collison
 1200         if  (nxaddr .gt. nz)  go to 1300
              nexti = connec (nxaddr)
              if  (nexti .eq. 0)  go to 1300
c collision -- target of current nonzero is still occupied. pick up values in
c target location, store current x, and go back to 800 with the new value for x
                  nextx = a(nxaddr)
                  a (nxaddr) = x
                  x     = nextx
c  check row and column indices for element with which we collided
                  i     = nexti
                  nextj = invcol(nxaddr)
                  newj  = permut (nextj)
                  xaddr = nxaddr
                  go to 800
 1300         a (nxaddr) = a (nxaddr)  +  x
 1400     continue
 1500 continue
c     ... reset envelope pointers to beginnings of row
c         with offset of  zero  instead of  n
      do 1600 i = 1, n
          cstart(i+1) = xenv(i) - n + 1
 1600 continue
      cstart(1) = 1
 2000 return
 3000 call erro('length of vector for envelope too short')
c write (6, 63000)
63000 format (40h0length of vector for envelope too short)
      go to 4000
 3100 call erro('internal diagnostic -- program failure')
c write (6, 63100)
63100 format (39h0internal diagnostic -- program failure)
      go to 4000
 3200 call erro('program failure')
c write (6, 63200)
63200 format (34h0program failure, i, j, newi, newj, 4i9)
      go to 4000
 4000 error = 999
      go to 2000
      end