1c $Id: unary.f,v 1.1 2008-04-11 06:01:06 geuzaine Exp $
2c----------------------------------------------------------------------c
3c                          S P A R S K I T                             c
4c----------------------------------------------------------------------c
5c                     UNARY SUBROUTINES MODULE                         c
6c----------------------------------------------------------------------c
7c contents:                                                            c
8c----------                                                            c
9c submat : extracts a submatrix from a sparse matrix.                  c
10c filter : filters elements from a matrix according to their magnitude.c
11c filterm: same as above, but for the MSR format                       c
12c csort  : sorts the elements in increasing order of columns           c
13c clncsr : clean up the CSR format matrix, remove duplicate entry, etc c
14c transp : in-place transposition routine (see also csrcsc in formats) c
15c copmat : copy of a matrix into another matrix (both stored csr)      c
16c msrcop : copies a matrix in MSR format into a matrix in MSR format   c
17c getelm : returns a(i,j) for any (i,j) from a CSR-stored matrix.      c
18c getdia : extracts a specified diagonal from a matrix.                c
19c getl   : extracts lower triangular part                              c
20c getu   : extracts upper triangular part                              c
21c levels : gets the level scheduling structure for lower triangular    c
22c          matrices.                                                   c
23c amask  : extracts     C = A mask M                                   c
24c rperm  : permutes the rows of a matrix (B = P A)                     c
25c cperm  : permutes the columns of a matrix (B = A Q)                  c
26c dperm  : permutes both the rows and columns of a matrix (B = P A Q ) c
27c dperm1 : general extractiob routine (extracts arbitrary rows)        c
28c dperm2 : general submatrix permutation/extraction routine            c
29c dmperm : symmetric permutation of row and column (B=PAP') in MSR fmt c
30c dvperm : permutes a real vector (in-place)                           c
31c ivperm : permutes an integer vector (in-place)                       c
32c retmx  : returns the max absolute value in each row of the matrix    c
33c diapos : returns the positions of the diagonal elements in A.        c
34c extbdg : extracts the main diagonal blocks of a matrix.              c
35c getbwd : returns the bandwidth information on a matrix.              c
36c blkfnd : finds the block-size of a matrix.                           c
37c blkchk : checks whether a given integer is the block size of A.      c
38c infdia : obtains information on the diagonals of A.                  c
39c amubdg : gets number of nonzeros in each row of A*B (as well as NNZ) c
40c aplbdg : gets number of nonzeros in each row of A+B (as well as NNZ) c
41c rnrms  : computes the norms of the rows of A                         c
42c cnrms  : computes the norms of the columns of A                      c
43c roscal : scales the rows of a matrix by their norms.                 c
44c coscal : scales the columns of a matrix by their norms.              c
45c addblk : Adds a matrix B into a block of A.                          c
46c get1up : Collects the first elements of each row of the upper        c
47c          triangular portion of the matrix.                           c
48c xtrows : extracts given rows from a matrix in CSR format.            c
49c csrkvstr:  Finds block row partitioning of matrix in CSR format      c
50c csrkvstc:  Finds block column partitioning of matrix in CSR format   c
51c kvstmerge: Merges block partitionings, for conformal row/col pattern c
52c----------------------------------------------------------------------c
53      subroutine submat (n,job,i1,i2,j1,j2,a,ja,ia,nr,nc,ao,jao,iao)
54      integer n,job,i1,i2,j1,j2,nr,nc,ia(*),ja(*),jao(*),iao(*)
55      real*8 a(*),ao(*)
56c-----------------------------------------------------------------------
57c extracts the submatrix A(i1:i2,j1:j2) and puts the result in
58c matrix ao,iao,jao
59c---- In place: ao,jao,iao may be the same as a,ja,ia.
60c--------------
61c on input
62c---------
63c n	= row dimension of the matrix
64c i1,i2 = two integers with i2 .ge. i1 indicating the range of rows to be
65c          extracted.
66c j1,j2 = two integers with j2 .ge. j1 indicating the range of columns
67c         to be extracted.
68c         * There is no checking whether the input values for i1, i2, j1,
69c           j2 are between 1 and n.
70c a,
71c ja,
72c ia    = matrix in compressed sparse row format.
73c
74c job	= job indicator: if job .ne. 1 then the real values in a are NOT
75c         extracted, only the column indices (i.e. data structure) are.
76c         otherwise values as well as column indices are extracted...
77c
78c on output
79c--------------
80c nr	= number of rows of submatrix
81c nc	= number of columns of submatrix
82c	  * if either of nr or nc is nonpositive the code will quit.
83c
84c ao,
85c jao,iao = extracted matrix in general sparse format with jao containing
86c	the column indices,and iao being the pointer to the beginning
87c	of the row,in arrays a,ja.
88c----------------------------------------------------------------------c
89c           Y. Saad, Sep. 21 1989                                      c
90c----------------------------------------------------------------------c
91      nr = i2-i1+1
92      nc = j2-j1+1
93c
94      if ( nr .le. 0 .or. nc .le. 0) return
95c
96      klen = 0
97c
98c     simple procedure. proceeds row-wise...
99c
100      do 100 i = 1,nr
101         ii = i1+i-1
102         k1 = ia(ii)
103         k2 = ia(ii+1)-1
104         iao(i) = klen+1
105c-----------------------------------------------------------------------
106         do 60 k=k1,k2
107            j = ja(k)
108            if (j .ge. j1 .and. j .le. j2) then
109               klen = klen+1
110               if (job .eq. 1) ao(klen) = a(k)
111               jao(klen) = j - j1+1
112            endif
113 60      continue
114 100  continue
115      iao(nr+1) = klen+1
116      return
117c------------end-of submat----------------------------------------------
118c-----------------------------------------------------------------------
119      end
120c-----------------------------------------------------------------------
121      subroutine filter(n,job,drptol,a,ja,ia,b,jb,ib,len,ierr)
122      real*8 a(*),b(*),drptol
123      integer ja(*),jb(*),ia(*),ib(*),n,job,len,ierr
124c-----------------------------------------------------------------------
125c     This module removes any elements whose absolute value
126c     is small from an input matrix A and puts the resulting
127c     matrix in B.  The input parameter job selects a definition
128c     of small.
129c-----------------------------------------------------------------------
130c on entry:
131c---------
132c  n	 = integer. row dimension of matrix
133c  job   = integer. used to determine strategy chosen by caller to
134c         drop elements from matrix A.
135c          job = 1
136c              Elements whose absolute value is less than the
137c              drop tolerance are removed.
138c          job = 2
139c              Elements whose absolute value is less than the
140c              product of the drop tolerance and the Euclidean
141c              norm of the row are removed.
142c          job = 3
143c              Elements whose absolute value is less that the
144c              product of the drop tolerance and the largest
145c              element in the row are removed.
146c
147c drptol = real. drop tolerance used for dropping strategy.
148c a
149c ja
150c ia     = input matrix in compressed sparse format
151c len	 = integer. the amount of space available in arrays b and jb.
152c
153c on return:
154c----------
155c b
156c jb
157c ib    = resulting matrix in compressed sparse format.
158c
159c ierr	= integer. containing error message.
160c         ierr .eq. 0 indicates normal return
161c         ierr .gt. 0 indicates that there is'nt enough
162c         space is a and ja to store the resulting matrix.
163c         ierr then contains the row number where filter stopped.
164c note:
165c------ This module is in place. (b,jb,ib can ne the same as
166c       a, ja, ia in which case the result will be overwritten).
167c----------------------------------------------------------------------c
168c           contributed by David Day,  Sep 19, 1989.                   c
169c----------------------------------------------------------------------c
170c local variables
171      real*8 norm,loctol
172      integer index,row,k,k1,k2
173c
174      index = 1
175      do 10 row= 1,n
176         k1 = ia(row)
177         k2 = ia(row+1) - 1
178         ib(row) = index
179	 goto (100,200,300) job
180 100     norm = 1.0d0
181         goto 400
182 200     norm = 0.0d0
183         do 22 k = k1,k2
184            norm = norm + a(k) * a(k)
185 22      continue
186         norm = sqrt(norm)
187         goto 400
188 300     norm = 0.0d0
189         do 23 k = k1,k2
190            if( abs(a(k))  .gt. norm) then
191               norm = abs(a(k))
192            endif
193 23      continue
194 400     loctol = drptol * norm
195	 do 30 k = k1,k2
196	    if( abs(a(k)) .gt. loctol)then
197               if (index .gt. len) then
198               ierr = row
199               return
200            endif
201            b(index) =  a(k)
202            jb(index) = ja(k)
203            index = index + 1
204         endif
205 30   continue
206 10   continue
207      ib(n+1) = index
208      return
209c--------------------end-of-filter -------------------------------------
210c-----------------------------------------------------------------------
211      end
212c-----------------------------------------------------------------------
213      subroutine filterm (n,job,drop,a,ja,b,jb,len,ierr)
214      real*8 a(*),b(*),drop
215      integer ja(*),jb(*),n,job,len,ierr
216c-----------------------------------------------------------------------
217c     This subroutine removes any elements whose absolute value
218c     is small from an input matrix A. Same as filter but
219c     uses the MSR format.
220c-----------------------------------------------------------------------
221c on entry:
222c---------
223c  n	 = integer. row dimension of matrix
224c  job   = integer. used to determine strategy chosen by caller to
225c         drop elements from matrix A.
226c          job = 1
227c              Elements whose absolute value is less than the
228c              drop tolerance are removed.
229c          job = 2
230c              Elements whose absolute value is less than the
231c              product of the drop tolerance and the Euclidean
232c              norm of the row are removed.
233c          job = 3
234c              Elements whose absolute value is less that the
235c              product of the drop tolerance and the largest
236c              element in the row are removed.
237c
238c drop = real. drop tolerance used for dropping strategy.
239c a
240c ja     = input matrix in Modifief Sparse Row format
241c len	 = integer. the amount of space in arrays b and jb.
242c
243c on return:
244c----------
245c
246c b, jb = resulting matrix in Modifief Sparse Row format
247c
248c ierr	= integer. containing error message.
249c         ierr .eq. 0 indicates normal return
250c         ierr .gt. 0 indicates that there is'nt enough
251c         space is a and ja to store the resulting matrix.
252c         ierr then contains the row number where filter stopped.
253c note:
254c------ This module is in place. (b,jb can ne the same as
255c       a, ja in which case the result will be overwritten).
256c----------------------------------------------------------------------c
257c           contributed by David Day,  Sep 19, 1989.                   c
258c----------------------------------------------------------------------c
259c local variables
260c
261      real*8 norm,loctol
262      integer index,row,k,k1,k2
263c
264      index = n+2
265      do 10 row= 1,n
266         k1 = ja(row)
267         k2 = ja(row+1) - 1
268         jb(row) = index
269	 goto (100,200,300) job
270 100     norm = 1.0d0
271         goto 400
272 200     norm = a(row)**2
273         do 22 k = k1,k2
274            norm = norm + a(k) * a(k)
275 22      continue
276         norm = sqrt(norm)
277         goto 400
278 300     norm = abs(a(row))
279         do 23 k = k1,k2
280            norm = max(abs(a(k)),norm)
281 23      continue
282 400     loctol = drop * norm
283	 do 30 k = k1,k2
284	    if( abs(a(k)) .gt. loctol)then
285               if (index .gt. len) then
286                  ierr = row
287                  return
288               endif
289               b(index) =  a(k)
290               jb(index) = ja(k)
291               index = index + 1
292            endif
293 30      continue
294 10   continue
295      jb(n+1) = index
296      return
297c--------------------end-of-filterm-------------------------------------
298c-----------------------------------------------------------------------
299      end
300c-----------------------------------------------------------------------
301      subroutine csort (n,a,ja,ia,iwork,values)
302      logical values
303      integer n, ja(*), ia(n+1), iwork(*)
304      real*8 a(*)
305c-----------------------------------------------------------------------
306c This routine sorts the elements of  a matrix (stored in Compressed
307c Sparse Row Format) in increasing order of their column indices within
308c each row. It uses a form of bucket sort with a cost of O(nnz) where
309c nnz = number of nonzero elements.
310c requires an integer work array of length 2*nnz.
311c-----------------------------------------------------------------------
312c on entry:
313c---------
314c n     = the row dimension of the matrix
315c a     = the matrix A in compressed sparse row format.
316c ja    = the array of column indices of the elements in array a.
317c ia    = the array of pointers to the rows.
318c iwork = integer work array of length max ( n+1, 2*nnz )
319c         where nnz = 2* (ia(n+1)-ia(1))  ) .
320c values= logical indicating whether or not the real values a(*) must
321c         also be permuted. if (.not. values) then the array a is not
322c         touched by csort and can be a dummy array.
323c
324c on return:
325c----------
326c the matrix stored in the structure a, ja, ia is permuted in such a
327c way that the column indices are in increasing order within each row.
328c iwork(1:nnz) contains the permutation used  to rearrange the elements.
329c-----------------------------------------------------------------------
330c Y. Saad - Feb. 1, 1991.
331c-----------------------------------------------------------------------
332c local variables
333      integer i, k, j, ifirst, nnz, next
334c
335c count the number of elements in each column
336c
337      do 1 i=1,n+1
338         iwork(i) = 0
339 1    continue
340      do 3 i=1, n
341         do 2 k=ia(i), ia(i+1)-1
342            j = ja(k)+1
343            iwork(j) = iwork(j)+1
344 2       continue
345 3    continue
346c
347c compute pointers from lengths.
348c
349      iwork(1) = 1
350      do 4 i=1,n
351         iwork(i+1) = iwork(i) + iwork(i+1)
352 4    continue
353c
354c get the positions of the nonzero elements in order of columns.
355c
356      ifirst = ia(1)
357      nnz = ia(n+1)-ifirst
358      do 5 i=1,n
359         do 51 k=ia(i),ia(i+1)-1
360            j = ja(k)
361            next = iwork(j)
362            iwork(nnz+next) = k
363            iwork(j) = next+1
364 51      continue
365 5    continue
366c
367c convert to coordinate format
368c
369      do 6 i=1, n
370         do 61 k=ia(i), ia(i+1)-1
371            iwork(k) = i
372 61      continue
373 6    continue
374c
375c loop to find permutation: for each element find the correct
376c position in (sorted) arrays a, ja. Record this in iwork.
377c
378      do 7 k=1, nnz
379         ko = iwork(nnz+k)
380         irow = iwork(ko)
381         next = ia(irow)
382c
383c the current element should go in next position in row. iwork
384c records this position.
385c
386         iwork(ko) = next
387         ia(irow)  = next+1
388 7       continue
389c
390c perform an in-place permutation of the  arrays.
391c
392         call ivperm (nnz, ja(ifirst), iwork)
393         if (values) call dvperm (nnz, a(ifirst), iwork)
394c
395c reshift the pointers of the original matrix back.
396c
397      do 8 i=n,1,-1
398         ia(i+1) = ia(i)
399 8    continue
400      ia(1) = ifirst
401c
402      return
403c---------------end-of-csort--------------------------------------------
404c-----------------------------------------------------------------------
405      end
406c-----------------------------------------------------------------------
407      subroutine clncsr(job,value2,nrow,a,ja,ia,indu,iwk)
408c     .. Scalar Arguments ..
409      integer job, nrow, value2
410c     ..
411c     .. Array Arguments ..
412      integer ia(nrow+1),indu(nrow),iwk(nrow+1),ja(*)
413      real*8  a(*)
414c     ..
415c
416c     This routine performs two tasks to clean up a CSR matrix
417c     -- remove duplicate/zero entries,
418c     -- perform a partial ordering, new order lower triangular part,
419c        main diagonal, upper triangular part.
420c
421c     On entry:
422c
423c     job   = options
424c         0 -- nothing is done
425c         1 -- eliminate duplicate entries, zero entries.
426c         2 -- eliminate duplicate entries and perform partial ordering.
427c         3 -- eliminate duplicate entries, sort the entries in the
428c              increasing order of clumn indices.
429c
430c     value2  -- 0 the matrix is pattern only (a is not touched)
431c                1 matrix has values too.
432c     nrow    -- row dimension of the matrix
433c     a,ja,ia -- input matrix in CSR format
434c
435c     On return:
436c     a,ja,ia -- cleaned matrix
437c     indu    -- pointers to the beginning of the upper triangular
438c                portion if job > 1
439c
440c     Work space:
441c     iwk     -- integer work space of size nrow+1
442c
443c     .. Local Scalars ..
444      integer i,j,k,ko,ipos,kfirst,klast
445      real*8  tmp
446c     ..
447c
448      if (job.le.0) return
449c
450c     .. eliminate duplicate entries --
451c     array INDU is used as marker for existing indices, it is also the
452c     location of the entry.
453c     IWK is used to stored the old IA array.
454c     matrix is copied to squeeze out the space taken by the duplicated
455c     entries.
456c
457      do 90 i = 1, nrow
458         indu(i) = 0
459         iwk(i) = ia(i)
460 90   continue
461      iwk(nrow+1) = ia(nrow+1)
462      k = 1
463      do 120 i = 1, nrow
464         ia(i) = k
465         ipos = iwk(i)
466         klast = iwk(i+1)
467 100     if (ipos.lt.klast) then
468            j = ja(ipos)
469            if (indu(j).eq.0) then
470c     .. new entry ..
471               if (value2.ne.0) then
472                  if (a(ipos) .ne. 0.0D0) then
473                     indu(j) = k
474                     ja(k) = ja(ipos)
475                     a(k) = a(ipos)
476                     k = k + 1
477                  endif
478               else
479                  indu(j) = k
480                  ja(k) = ja(ipos)
481                  k = k + 1
482               endif
483            else if (value2.ne.0) then
484c     .. duplicate entry ..
485               a(indu(j)) = a(indu(j)) + a(ipos)
486            endif
487            ipos = ipos + 1
488            go to 100
489         endif
490c     .. remove marks before working on the next row ..
491         do 110 ipos = ia(i), k - 1
492            indu(ja(ipos)) = 0
493 110     continue
494 120  continue
495      ia(nrow+1) = k
496      if (job.le.1) return
497c
498c     .. partial ordering ..
499c     split the matrix into strict upper/lower triangular
500c     parts, INDU points to the the beginning of the upper part.
501c
502      do 140 i = 1, nrow
503         klast = ia(i+1) - 1
504         kfirst = ia(i)
505 130     if (klast.gt.kfirst) then
506            if (ja(klast).lt.i .and. ja(kfirst).ge.i) then
507c     .. swap klast with kfirst ..
508               j = ja(klast)
509               ja(klast) = ja(kfirst)
510               ja(kfirst) = j
511               if (value2.ne.0) then
512                  tmp = a(klast)
513                  a(klast) = a(kfirst)
514                  a(kfirst) = tmp
515               endif
516            endif
517            if (ja(klast).ge.i)
518     &         klast = klast - 1
519            if (ja(kfirst).lt.i)
520     &         kfirst = kfirst + 1
521            go to 130
522         endif
523c
524         if (ja(klast).lt.i) then
525            indu(i) = klast + 1
526         else
527            indu(i) = klast
528         endif
529 140  continue
530      if (job.le.2) return
531c
532c     .. order the entries according to column indices
533c     burble-sort is used
534c
535      do 190 i = 1, nrow
536         do 160 ipos = ia(i), indu(i)-1
537            do 150 j = indu(i)-1, ipos+1, -1
538               k = j - 1
539               if (ja(k).gt.ja(j)) then
540                  ko = ja(k)
541                  ja(k) = ja(j)
542                  ja(j) = ko
543                  if (value2.ne.0) then
544                     tmp = a(k)
545                     a(k) = a(j)
546                     a(j) = tmp
547                  endif
548               endif
549 150        continue
550 160     continue
551         do 180 ipos = indu(i), ia(i+1)-1
552            do 170 j = ia(i+1)-1, ipos+1, -1
553               k = j - 1
554               if (ja(k).gt.ja(j)) then
555                  ko = ja(k)
556                  ja(k) = ja(j)
557                  ja(j) = ko
558                  if (value2.ne.0) then
559                     tmp = a(k)
560                     a(k) = a(j)
561                     a(j) = tmp
562                  endif
563               endif
564 170        continue
565 180     continue
566 190  continue
567      return
568c---- end of clncsr ----------------------------------------------------
569c-----------------------------------------------------------------------
570      end
571c-----------------------------------------------------------------------
572      subroutine copmat (nrow,a,ja,ia,ao,jao,iao,ipos,job)
573      real*8 a(*),ao(*)
574      integer nrow, ia(*),ja(*),jao(*),iao(*), ipos, job
575c----------------------------------------------------------------------
576c copies the matrix a, ja, ia, into the matrix ao, jao, iao.
577c----------------------------------------------------------------------
578c on entry:
579c---------
580c nrow	= row dimension of the matrix
581c a,
582c ja,
583c ia    = input matrix in compressed sparse row format.
584c ipos  = integer. indicates the position in the array ao, jao
585c         where the first element should be copied. Thus
586c         iao(1) = ipos on return.
587c job   = job indicator. if (job .ne. 1) the values are not copies
588c         (i.e., pattern only is copied in the form of arrays ja, ia).
589c
590c on return:
591c----------
592c ao,
593c jao,
594c iao   = output matrix containing the same data as a, ja, ia.
595c-----------------------------------------------------------------------
596c           Y. Saad, March 1990.
597c-----------------------------------------------------------------------
598c local variables
599      integer kst, i, k
600c
601      kst    = ipos -ia(1)
602      do 100 i = 1, nrow+1
603         iao(i) = ia(i) + kst
604 100  continue
605c
606      do 200 k=ia(1), ia(nrow+1)-1
607         jao(kst+k)= ja(k)
608 200  continue
609c
610      if (job .ne. 1) return
611      do 201 k=ia(1), ia(nrow+1)-1
612         ao(kst+k) = a(k)
613 201  continue
614c
615      return
616c--------end-of-copmat -------------------------------------------------
617c-----------------------------------------------------------------------
618      end
619c-----------------------------------------------------------------------
620      subroutine msrcop (nrow,a,ja,ao,jao,job)
621      real*8 a(*),ao(*)
622      integer nrow, ja(*),jao(*), job
623c----------------------------------------------------------------------
624c copies the MSR matrix a, ja, into the MSR matrix ao, jao
625c----------------------------------------------------------------------
626c on entry:
627c---------
628c nrow	= row dimension of the matrix
629c a,ja  = input matrix in Modified compressed sparse row format.
630c job   = job indicator. Values are not copied if job .ne. 1
631c
632c on return:
633c----------
634c ao, jao   = output matrix containing the same data as a, ja.
635c-----------------------------------------------------------------------
636c           Y. Saad,
637c-----------------------------------------------------------------------
638c local variables
639      integer i, k
640c
641      do 100 i = 1, nrow+1
642         jao(i) = ja(i)
643 100  continue
644c
645      do 200 k=ja(1), ja(nrow+1)-1
646         jao(k)= ja(k)
647 200  continue
648c
649      if (job .ne. 1) return
650      do 201 k=ja(1), ja(nrow+1)-1
651         ao(k) = a(k)
652 201  continue
653      do 202 k=1,nrow
654         ao(k) = a(k)
655 202  continue
656c
657      return
658c--------end-of-msrcop -------------------------------------------------
659c-----------------------------------------------------------------------
660      end
661c-----------------------------------------------------------------------
662      double precision function getelm (i,j,a,ja,ia,iadd,sorted)
663c-----------------------------------------------------------------------
664c     purpose:
665c     --------
666c     this function returns the element a(i,j) of a matrix a,
667c     for any pair (i,j).  the matrix is assumed to be stored
668c     in compressed sparse row (csr) format. getelm performs a
669c     binary search in the case where it is known that the elements
670c     are sorted so that the column indices are in increasing order.
671c     also returns (in iadd) the address of the element a(i,j) in
672c     arrays a and ja when the search is successsful (zero if not).
673c-----
674c     first contributed by noel nachtigal (mit).
675c     recoded jan. 20, 1991, by y. saad [in particular
676c     added handling of the non-sorted case + the iadd output]
677c-----------------------------------------------------------------------
678c     parameters:
679c     -----------
680c on entry:
681c----------
682c     i      = the row index of the element sought (input).
683c     j      = the column index of the element sought (input).
684c     a      = the matrix a in compressed sparse row format (input).
685c     ja     = the array of column indices (input).
686c     ia     = the array of pointers to the rows' data (input).
687c     sorted = logical indicating whether the matrix is knonw to
688c              have its column indices sorted in increasing order
689c              (sorted=.true.) or not (sorted=.false.).
690c              (input).
691c on return:
692c-----------
693c     getelm = value of a(i,j).
694c     iadd   = address of element a(i,j) in arrays a, ja if found,
695c              zero if not found. (output)
696c
697c     note: the inputs i and j are not checked for validity.
698c-----------------------------------------------------------------------
699c     noel m. nachtigal october 28, 1990 -- youcef saad jan 20, 1991.
700c-----------------------------------------------------------------------
701      integer i, ia(*), iadd, j, ja(*)
702      double precision a(*)
703      logical sorted
704c
705c     local variables.
706c
707      integer ibeg, iend, imid, k
708c
709c     initialization
710c
711      iadd = 0
712      getelm = 0.0
713      ibeg = ia(i)
714      iend = ia(i+1)-1
715c
716c     case where matrix is not necessarily sorted
717c
718      if (.not. sorted) then
719c
720c scan the row - exit as soon as a(i,j) is found
721c
722         do 5  k=ibeg, iend
723            if (ja(k) .eq.  j) then
724               iadd = k
725               goto 20
726            endif
727 5       continue
728c
729c     end unsorted case. begin sorted case
730c
731      else
732c
733c     begin binary search.   compute the middle index.
734c
735 10      imid = ( ibeg + iend ) / 2
736c
737c     test if  found
738c
739         if (ja(imid).eq.j) then
740            iadd = imid
741            goto 20
742         endif
743         if (ibeg .ge. iend) goto 20
744c
745c     else     update the interval bounds.
746c
747         if (ja(imid).gt.j) then
748            iend = imid -1
749         else
750            ibeg = imid +1
751         endif
752         goto 10
753c
754c     end both cases
755c
756      endif
757c
758 20   if (iadd .ne. 0) getelm = a(iadd)
759c
760      return
761c--------end-of-getelm--------------------------------------------------
762c-----------------------------------------------------------------------
763      end
764c-----------------------------------------------------------------------
765      subroutine getdia (nrow,ncol,job,a,ja,ia,len,diag,idiag,ioff)
766      real*8 diag(*),a(*)
767      integer nrow, ncol, job, len, ioff, ia(*), ja(*), idiag(*)
768c-----------------------------------------------------------------------
769c this subroutine extracts a given diagonal from a matrix stored in csr
770c format. the output matrix may be transformed with the diagonal removed
771c from it if desired (as indicated by job.)
772c-----------------------------------------------------------------------
773c our definition of a diagonal of matrix is a vector of length nrow
774c (always) which contains the elements in rows 1 to nrow of
775c the matrix that are contained in the diagonal offset by ioff
776c with respect to the main diagonal. if the diagonal element
777c falls outside the matrix then it is defined as a zero entry.
778c thus the proper definition of diag(*) with offset ioff is
779c
780c     diag(i) = a(i,ioff+i) i=1,2,...,nrow
781c     with elements falling outside the matrix being defined as zero.
782c
783c-----------------------------------------------------------------------
784c
785c on entry:
786c----------
787c
788c nrow	= integer. the row dimension of the matrix a.
789c ncol	= integer. the column dimension of the matrix a.
790c job   = integer. job indicator.  if job = 0 then
791c         the matrix a, ja, ia, is not altered on return.
792c         if job.ne.0  then getdia will remove the entries
793c         collected in diag from the original matrix.
794c         this is done in place.
795c
796c a,ja,
797c    ia = matrix stored in compressed sparse row a,ja,ia,format
798c ioff  = integer,containing the offset of the wanted diagonal
799c	  the diagonal extracted is the one corresponding to the
800c	  entries a(i,j) with j-i = ioff.
801c	  thus ioff = 0 means the main diagonal
802c
803c on return:
804c-----------
805c len   = number of nonzero elements found in diag.
806c         (len .le. min(nrow,ncol-ioff)-max(1,1-ioff) + 1 )
807c
808c diag  = real*8 array of length nrow containing the wanted diagonal.
809c	  diag contains the diagonal (a(i,j),j-i = ioff ) as defined
810c         above.
811c
812c idiag = integer array of  length len, containing the poisitions
813c         in the original arrays a and ja of the diagonal elements
814c         collected in diag. a zero entry in idiag(i) means that
815c         there was no entry found in row i belonging to the diagonal.
816c
817c a, ja,
818c    ia = if job .ne. 0 the matrix is unchanged. otherwise the nonzero
819c         diagonal entries collected in diag are removed from the
820c         matrix and therefore the arrays a, ja, ia will change.
821c	  (the matrix a, ja, ia will contain len fewer elements)
822c
823c----------------------------------------------------------------------c
824c     Y. Saad, sep. 21 1989 - modified and retested Feb 17, 1996.      c
825c----------------------------------------------------------------------c
826c     local variables
827      integer istart, max, iend, i, kold, k, kdiag, ko
828c
829      istart = max(0,-ioff)
830      iend = min(nrow,ncol-ioff)
831      len = 0
832      do 1 i=1,nrow
833         idiag(i) = 0
834	 diag(i) = 0.0d0
835 1    continue
836c
837c     extract  diagonal elements
838c
839      do 6 i=istart+1, iend
840         do 51 k= ia(i),ia(i+1) -1
841            if (ja(k)-i .eq. ioff) then
842               diag(i)= a(k)
843               idiag(i) = k
844               len = len+1
845               goto 6
846            endif
847 51      continue
848 6    continue
849      if (job .eq. 0 .or. len .eq.0) return
850c
851c     remove diagonal elements and rewind structure
852c
853      ko = 0
854      do  7 i=1, nrow
855         kold = ko
856         kdiag = idiag(i)
857         do 71 k= ia(i), ia(i+1)-1
858            if (k .ne. kdiag) then
859               ko = ko+1
860               a(ko) = a(k)
861               ja(ko) = ja(k)
862            endif
863 71      continue
864         ia(i) = kold+1
865 7    continue
866c
867c     redefine ia(nrow+1)
868c
869      ia(nrow+1) = ko+1
870      return
871c------------end-of-getdia----------------------------------------------
872c-----------------------------------------------------------------------
873      end
874c-----------------------------------------------------------------------
875      subroutine transp (nrow,ncol,a,ja,ia,iwk,ierr)
876      integer nrow, ncol, ia(*), ja(*), iwk(*), ierr
877      real*8 a(*)
878c------------------------------------------------------------------------
879c In-place transposition routine.
880c------------------------------------------------------------------------
881c this subroutine transposes a matrix stored in compressed sparse row
882c format. the transposition is done in place in that the arrays a,ja,ia
883c of the transpose are overwritten onto the original arrays.
884c------------------------------------------------------------------------
885c on entry:
886c---------
887c nrow	= integer. The row dimension of A.
888c ncol	= integer. The column dimension of A.
889c a	= real array of size nnz (number of nonzero elements in A).
890c         containing the nonzero elements
891c ja	= integer array of length nnz containing the column positions
892c 	  of the corresponding elements in a.
893c ia	= integer of size n+1, where n = max(nrow,ncol). On entry
894c         ia(k) contains the position in a,ja of  the beginning of
895c         the k-th row.
896c
897c iwk	= integer work array of same length as ja.
898c
899c on return:
900c----------
901c
902c ncol	= actual row dimension of the transpose of the input matrix.
903c         Note that this may be .le. the input value for ncol, in
904c         case some of the last columns of the input matrix are zero
905c         columns. In the case where the actual number of rows found
906c         in transp(A) exceeds the input value of ncol, transp will
907c         return without completing the transposition. see ierr.
908c a,
909c ja,
910c ia	= contains the transposed matrix in compressed sparse
911c         row format. The row dimension of a, ja, ia is now ncol.
912c
913c ierr	= integer. error message. If the number of rows for the
914c         transposed matrix exceeds the input value of ncol,
915c         then ierr is  set to that number and transp quits.
916c         Otherwise ierr is set to 0 (normal return).
917c
918c Note:
919c----- 1) If you do not need the transposition to be done in place
920c         it is preferrable to use the conversion routine csrcsc
921c         (see conversion routines in formats).
922c      2) the entries of the output matrix are not sorted (the column
923c         indices in each are not in increasing order) use csrcsc
924c         if you want them sorted.
925c----------------------------------------------------------------------c
926c           Y. Saad, Sep. 21 1989                                      c
927c  modified Oct. 11, 1989.                                             c
928c----------------------------------------------------------------------c
929c local variables
930      real*8 t, t1
931      ierr = 0
932      nnz = ia(nrow+1)-1
933c
934c     determine column dimension
935c
936      jcol = 0
937      do 1 k=1, nnz
938         jcol = max(jcol,ja(k))
939 1    continue
940      if (jcol .gt. ncol) then
941         ierr = jcol
942         return
943      endif
944c
945c     convert to coordinate format. use iwk for row indices.
946c
947      ncol = jcol
948c
949      do 3 i=1,nrow
950         do 2 k=ia(i),ia(i+1)-1
951            iwk(k) = i
952 2       continue
953 3    continue
954c     find pointer array for transpose.
955      do 35 i=1,ncol+1
956         ia(i) = 0
957 35   continue
958      do 4 k=1,nnz
959         i = ja(k)
960         ia(i+1) = ia(i+1)+1
961 4    continue
962      ia(1) = 1
963c------------------------------------------------------------------------
964      do 44 i=1,ncol
965         ia(i+1) = ia(i) + ia(i+1)
966 44   continue
967c
968c     loop for a cycle in chasing process.
969c
970      init = 1
971      k = 0
972 5    t = a(init)
973      i = ja(init)
974      j = iwk(init)
975      iwk(init) = -1
976c------------------------------------------------------------------------
977 6    k = k+1
978c     current row number is i.  determine  where to go.
979      l = ia(i)
980c     save the chased element.
981      t1 = a(l)
982      inext = ja(l)
983c     then occupy its location.
984      a(l)  = t
985      ja(l) = j
986c     update pointer information for next element to be put in row i.
987      ia(i) = l+1
988c     determine  next element to be chased
989      if (iwk(l) .lt. 0) goto 65
990      t = t1
991      i = inext
992      j = iwk(l)
993      iwk(l) = -1
994      if (k .lt. nnz) goto 6
995      goto 70
996 65   init = init+1
997      if (init .gt. nnz) goto 70
998      if (iwk(init) .lt. 0) goto 65
999c     restart chasing --
1000      goto 5
1001 70   continue
1002      do 80 i=ncol,1,-1
1003         ia(i+1) = ia(i)
1004 80   continue
1005      ia(1) = 1
1006c
1007      return
1008c------------------end-of-transp ----------------------------------------
1009c------------------------------------------------------------------------
1010      end
1011c------------------------------------------------------------------------
1012      subroutine getl (n,a,ja,ia,ao,jao,iao)
1013      integer n, ia(*), ja(*), iao(*), jao(*)
1014      real*8 a(*), ao(*)
1015c------------------------------------------------------------------------
1016c this subroutine extracts the lower triangular part of a matrix
1017c and writes the result ao, jao, iao. The routine is in place in
1018c that ao, jao, iao can be the same as a, ja, ia if desired.
1019c-----------
1020c on input:
1021c
1022c n     = dimension of the matrix a.
1023c a, ja,
1024c    ia = matrix stored in compressed sparse row format.
1025c On return:
1026c ao, jao,
1027c    iao = lower triangular matrix (lower part of a)
1028c	stored in a, ja, ia, format
1029c note: the diagonal element is the last element in each row.
1030c i.e. in  a(ia(i+1)-1 )
1031c ao, jao, iao may be the same as a, ja, ia on entry -- in which case
1032c getl will overwrite the result on a, ja, ia.
1033c
1034c------------------------------------------------------------------------
1035c local variables
1036      real*8 t
1037      integer ko, kold, kdiag, k, i
1038c
1039c inititialize ko (pointer for output matrix)
1040c
1041      ko = 0
1042      do  7 i=1, n
1043         kold = ko
1044         kdiag = 0
1045         do 71 k = ia(i), ia(i+1) -1
1046            if (ja(k)  .gt. i) goto 71
1047            ko = ko+1
1048            ao(ko) = a(k)
1049            jao(ko) = ja(k)
1050            if (ja(k)  .eq. i) kdiag = ko
1051 71      continue
1052         if (kdiag .eq. 0 .or. kdiag .eq. ko) goto 72
1053c
1054c     exchange
1055c
1056         t = ao(kdiag)
1057         ao(kdiag) = ao(ko)
1058         ao(ko) = t
1059c
1060         k = jao(kdiag)
1061         jao(kdiag) = jao(ko)
1062         jao(ko) = k
1063 72      iao(i) = kold+1
1064 7    continue
1065c     redefine iao(n+1)
1066      iao(n+1) = ko+1
1067      return
1068c----------end-of-getl -------------------------------------------------
1069c-----------------------------------------------------------------------
1070      end
1071c-----------------------------------------------------------------------
1072      subroutine getu (n,a,ja,ia,ao,jao,iao)
1073      integer n, ia(*), ja(*), iao(*), jao(*)
1074      real*8 a(*), ao(*)
1075c------------------------------------------------------------------------
1076c this subroutine extracts the upper triangular part of a matrix
1077c and writes the result ao, jao, iao. The routine is in place in
1078c that ao, jao, iao can be the same as a, ja, ia if desired.
1079c-----------
1080c on input:
1081c
1082c n     = dimension of the matrix a.
1083c a, ja,
1084c    ia = matrix stored in a, ja, ia, format
1085c On return:
1086c ao, jao,
1087c    iao = upper triangular matrix (upper part of a)
1088c	stored in compressed sparse row format
1089c note: the diagonal element is the last element in each row.
1090c i.e. in  a(ia(i+1)-1 )
1091c ao, jao, iao may be the same as a, ja, ia on entry -- in which case
1092c getu will overwrite the result on a, ja, ia.
1093c
1094c------------------------------------------------------------------------
1095c local variables
1096      real*8 t
1097      integer ko, k, i, kdiag, kfirst
1098      ko = 0
1099      do  7 i=1, n
1100         kfirst = ko+1
1101         kdiag = 0
1102         do 71 k = ia(i), ia(i+1) -1
1103            if (ja(k)  .lt. i) goto 71
1104            ko = ko+1
1105            ao(ko) = a(k)
1106            jao(ko) = ja(k)
1107            if (ja(k)  .eq. i) kdiag = ko
1108 71      continue
1109         if (kdiag .eq. 0 .or. kdiag .eq. kfirst) goto 72
1110c     exchange
1111         t = ao(kdiag)
1112         ao(kdiag) = ao(kfirst)
1113         ao(kfirst) = t
1114c
1115         k = jao(kdiag)
1116         jao(kdiag) = jao(kfirst)
1117         jao(kfirst) = k
1118 72      iao(i) = kfirst
1119 7    continue
1120c     redefine iao(n+1)
1121      iao(n+1) = ko+1
1122      return
1123c----------end-of-getu -------------------------------------------------
1124c-----------------------------------------------------------------------
1125      end
1126c-----------------------------------------------------------------------
1127      subroutine levels (n, jal, ial, nlev, lev, ilev, levnum)
1128      integer jal(*),ial(*), levnum(*), ilev(*), lev(*)
1129c-----------------------------------------------------------------------
1130c levels gets the level structure of a lower triangular matrix
1131c for level scheduling in the parallel solution of triangular systems
1132c strict lower matrices (e.g. unit) as well matrices with their main
1133c diagonal are accepted.
1134c-----------------------------------------------------------------------
1135c on entry:
1136c----------
1137c n        = integer. The row dimension of the matrix
1138c jal, ial =
1139c
1140c on return:
1141c-----------
1142c nlev     = integer. number of levels found
1143c lev      = integer array of length n containing the level
1144c            scheduling permutation.
1145c ilev     = integer array. pointer to beginning of levels in lev.
1146c            the numbers lev(i) to lev(i+1)-1 contain the row numbers
1147c            that belong to level number i, in the level scheduling
1148c            ordering. The equations of the same level can be solved
1149c            in parallel, once those of all the previous levels have
1150c            been solved.
1151c work arrays:
1152c-------------
1153c levnum   = integer array of length n (containing the level numbers
1154c            of each unknown on return)
1155c-----------------------------------------------------------------------
1156      do 10 i = 1, n
1157         levnum(i) = 0
1158 10   continue
1159c
1160c     compute level of each node --
1161c
1162      nlev = 0
1163      do 20 i = 1, n
1164         levi = 0
1165         do 15 j = ial(i), ial(i+1) - 1
1166            levi = max (levi, levnum(jal(j)))
1167 15      continue
1168         levi = levi+1
1169         levnum(i) = levi
1170         nlev = max(nlev,levi)
1171 20   continue
1172c-------------set data structure  --------------------------------------
1173      do 21 j=1, nlev+1
1174         ilev(j) = 0
1175 21   continue
1176c------count  number   of elements in each level -----------------------
1177      do 22 j=1, n
1178         i = levnum(j)+1
1179         ilev(i) = ilev(i)+1
1180 22   continue
1181c---- set up pointer for  each  level ----------------------------------
1182      ilev(1) = 1
1183      do 23 j=1, nlev
1184         ilev(j+1) = ilev(j)+ilev(j+1)
1185 23   continue
1186
1187c-----determine elements of each level --------------------------------
1188      do 30 j=1,n
1189         i = levnum(j)
1190         lev(ilev(i)) = j
1191         ilev(i) = ilev(i)+1
1192 30   continue
1193c     reset pointers backwards
1194      do 35 j=nlev, 1, -1
1195         ilev(j+1) = ilev(j)
1196 35   continue
1197      ilev(1) = 1
1198      return
1199c----------end-of-levels------------------------------------------------
1200C-----------------------------------------------------------------------
1201      end
1202c-----------------------------------------------------------------------
1203      subroutine amask (nrow,ncol,a,ja,ia,jmask,imask,
1204     *                  c,jc,ic,iw,nzmax,ierr)
1205c---------------------------------------------------------------------
1206      real*8 a(*),c(*)
1207      integer ia(nrow+1),ja(*),jc(*),ic(nrow+1),jmask(*),imask(nrow+1)
1208      logical iw(ncol)
1209c-----------------------------------------------------------------------
1210c This subroutine builds a sparse matrix from an input matrix by
1211c extracting only elements in positions defined by the mask jmask, imask
1212c-----------------------------------------------------------------------
1213c On entry:
1214c---------
1215c nrow  = integer. row dimension of input matrix
1216c ncol	= integer. Column dimension of input matrix.
1217c
1218c a,
1219c ja,
1220c ia	= matrix in Compressed Sparse Row format
1221c
1222c jmask,
1223c imask = matrix defining mask (pattern only) stored in compressed
1224c         sparse row format.
1225c
1226c nzmax = length of arrays c and jc. see ierr.
1227c
1228c On return:
1229c-----------
1230c
1231c a, ja, ia and jmask, imask are unchanged.
1232c
1233c c
1234c jc,
1235c ic	= the output matrix in Compressed Sparse Row format.
1236c
1237c ierr  = integer. serving as error message.c
1238c         ierr = 1  means normal return
1239c         ierr .gt. 1 means that amask stopped when processing
1240c         row number ierr, because there was not enough space in
1241c         c, jc according to the value of nzmax.
1242c
1243c work arrays:
1244c-------------
1245c iw	= logical work array of length ncol.
1246c
1247c note:
1248c------ the  algorithm is in place: c, jc, ic can be the same as
1249c a, ja, ia in which cas the code will overwrite the matrix c
1250c on a, ja, ia
1251c
1252c-----------------------------------------------------------------------
1253      ierr = 0
1254      len = 0
1255      do 1 j=1, ncol
1256         iw(j) = .false.
1257 1    continue
1258c     unpack the mask for row ii in iw
1259      do 100 ii=1, nrow
1260c     save pointer in order to be able to do things in place
1261         do 2 k=imask(ii), imask(ii+1)-1
1262            iw(jmask(k)) = .true.
1263 2       continue
1264c     add umasked elemnts of row ii
1265         k1 = ia(ii)
1266         k2 = ia(ii+1)-1
1267         ic(ii) = len+1
1268         do 200 k=k1,k2
1269            j = ja(k)
1270            if (iw(j)) then
1271               len = len+1
1272               if (len .gt. nzmax) then
1273                  ierr = ii
1274                  return
1275               endif
1276               jc(len) = j
1277               c(len) = a(k)
1278            endif
1279 200     continue
1280c
1281         do 3 k=imask(ii), imask(ii+1)-1
1282            iw(jmask(k)) = .false.
1283 3       continue
1284 100  continue
1285      ic(nrow+1)=len+1
1286c
1287      return
1288c-----end-of-amask -----------------------------------------------------
1289c-----------------------------------------------------------------------
1290      end
1291c-----------------------------------------------------------------------
1292      subroutine rperm (nrow,a,ja,ia,ao,jao,iao,perm,job)
1293      integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(nrow),job
1294      real*8 a(*),ao(*)
1295c-----------------------------------------------------------------------
1296c this subroutine permutes the rows of a matrix in CSR format.
1297c rperm  computes B = P A  where P is a permutation matrix.
1298c the permutation P is defined through the array perm: for each j,
1299c perm(j) represents the destination row number of row number j.
1300c Youcef Saad -- recoded Jan 28, 1991.
1301c-----------------------------------------------------------------------
1302c on entry:
1303c----------
1304c n 	= dimension of the matrix
1305c a, ja, ia = input matrix in csr format
1306c perm 	= integer array of length nrow containing the permutation arrays
1307c	  for the rows: perm(i) is the destination of row i in the
1308c         permuted matrix.
1309c         ---> a(i,j) in the original matrix becomes a(perm(i),j)
1310c         in the output  matrix.
1311c
1312c job	= integer indicating the work to be done:
1313c 		job = 1	permute a, ja, ia into ao, jao, iao
1314c                       (including the copying of real values ao and
1315c                       the array iao).
1316c 		job .ne. 1 :  ignore real values.
1317c                     (in which case arrays a and ao are not needed nor
1318c                      used).
1319c
1320c------------
1321c on return:
1322c------------
1323c ao, jao, iao = input matrix in a, ja, ia format
1324c note :
1325c        if (job.ne.1)  then the arrays a and ao are not used.
1326c----------------------------------------------------------------------c
1327c           Y. Saad, May  2, 1990                                      c
1328c----------------------------------------------------------------------c
1329      logical values
1330      values = (job .eq. 1)
1331c
1332c     determine pointers for output matix.
1333c
1334      do 50 j=1,nrow
1335         i = perm(j)
1336         iao(i+1) = ia(j+1) - ia(j)
1337 50   continue
1338c
1339c get pointers from lengths
1340c
1341      iao(1) = 1
1342      do 51 j=1,nrow
1343         iao(j+1)=iao(j+1)+iao(j)
1344 51   continue
1345c
1346c copying
1347c
1348      do 100 ii=1,nrow
1349c
1350c old row = ii  -- new row = iperm(ii) -- ko = new pointer
1351c
1352         ko = iao(perm(ii))
1353         do 60 k=ia(ii), ia(ii+1)-1
1354            jao(ko) = ja(k)
1355            if (values) ao(ko) = a(k)
1356            ko = ko+1
1357 60      continue
1358 100  continue
1359c
1360      return
1361c---------end-of-rperm -------------------------------------------------
1362c-----------------------------------------------------------------------
1363      end
1364c-----------------------------------------------------------------------
1365      subroutine cperm (nrow,a,ja,ia,ao,jao,iao,perm,job)
1366      integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(*), job
1367      real*8 a(*), ao(*)
1368c-----------------------------------------------------------------------
1369c this subroutine permutes the columns of a matrix a, ja, ia.
1370c the result is written in the output matrix  ao, jao, iao.
1371c cperm computes B = A P, where  P is a permutation matrix
1372c that maps column j into column perm(j), i.e., on return
1373c      a(i,j) becomes a(i,perm(j)) in new matrix
1374c Y. Saad, May 2, 1990 / modified Jan. 28, 1991.
1375c-----------------------------------------------------------------------
1376c on entry:
1377c----------
1378c nrow 	= row dimension of the matrix
1379c
1380c a, ja, ia = input matrix in csr format.
1381c
1382c perm	= integer array of length ncol (number of columns of A
1383c         containing the permutation array  the columns:
1384c         a(i,j) in the original matrix becomes a(i,perm(j))
1385c         in the output matrix.
1386c
1387c job	= integer indicating the work to be done:
1388c 		job = 1	permute a, ja, ia into ao, jao, iao
1389c                       (including the copying of real values ao and
1390c                       the array iao).
1391c 		job .ne. 1 :  ignore real values ao and ignore iao.
1392c
1393c------------
1394c on return:
1395c------------
1396c ao, jao, iao = input matrix in a, ja, ia format (array ao not needed)
1397c
1398c Notes:
1399c-------
1400c 1. if job=1 then ao, iao are not used.
1401c 2. This routine is in place: ja, jao can be the same.
1402c 3. If the matrix is initially sorted (by increasing column number)
1403c    then ao,jao,iao  may not be on return.
1404c
1405c----------------------------------------------------------------------c
1406c local parameters:
1407      integer k, i, nnz
1408c
1409      nnz = ia(nrow+1)-1
1410      do 100 k=1,nnz
1411         jao(k) = perm(ja(k))
1412 100  continue
1413c
1414c     done with ja array. return if no need to touch values.
1415c
1416      if (job .ne. 1) return
1417c
1418c else get new pointers -- and copy values too.
1419c
1420      do 1 i=1, nrow+1
1421         iao(i) = ia(i)
1422 1    continue
1423c
1424      do 2 k=1, nnz
1425         ao(k) = a(k)
1426 2    continue
1427c
1428      return
1429c---------end-of-cperm--------------------------------------------------
1430c-----------------------------------------------------------------------
1431      end
1432c-----------------------------------------------------------------------
1433      subroutine dperm (nrow,a,ja,ia,ao,jao,iao,perm,qperm,job)
1434      integer nrow,ja(*),ia(nrow+1),jao(*),iao(nrow+1),perm(nrow),
1435     +        qperm(*),job
1436      real*8 a(*),ao(*)
1437c-----------------------------------------------------------------------
1438c This routine permutes the rows and columns of a matrix stored in CSR
1439c format. i.e., it computes P A Q, where P, Q are permutation matrices.
1440c P maps row i into row perm(i) and Q maps column j into column qperm(j):
1441c      a(i,j)    becomes   a(perm(i),qperm(j)) in new matrix
1442c In the particular case where Q is the transpose of P (symmetric
1443c permutation of A) then qperm is not needed.
1444c note that qperm should be of length ncol (number of columns) but this
1445c is not checked.
1446c-----------------------------------------------------------------------
1447c Y. Saad, Sep. 21 1989 / recoded Jan. 28 1991.
1448c-----------------------------------------------------------------------
1449c on entry:
1450c----------
1451c n 	= dimension of the matrix
1452c a, ja,
1453c    ia = input matrix in a, ja, ia format
1454c perm 	= integer array of length n containing the permutation arrays
1455c	  for the rows: perm(i) is the destination of row i in the
1456c         permuted matrix -- also the destination of column i in case
1457c         permutation is symmetric (job .le. 2)
1458c
1459c qperm	= same thing for the columns. This should be provided only
1460c         if job=3 or job=4, i.e., only in the case of a nonsymmetric
1461c	  permutation of rows and columns. Otherwise qperm is a dummy
1462c
1463c job	= integer indicating the work to be done:
1464c * job = 1,2 permutation is symmetric  Ao :== P * A * transp(P)
1465c 		job = 1	permute a, ja, ia into ao, jao, iao
1466c 		job = 2 permute matrix ignoring real values.
1467c * job = 3,4 permutation is non-symmetric  Ao :== P * A * Q
1468c 		job = 3	permute a, ja, ia into ao, jao, iao
1469c 		job = 4 permute matrix ignoring real values.
1470c
1471c on return:
1472c-----------
1473c ao, jao, iao = input matrix in a, ja, ia format
1474c
1475c in case job .eq. 2 or job .eq. 4, a and ao are never referred to
1476c and can be dummy arguments.
1477c Notes:
1478c-------
1479c  1) algorithm is in place
1480c  2) column indices may not be sorted on return even  though they may be
1481c     on entry.
1482c----------------------------------------------------------------------c
1483c local variables
1484      integer locjob, mod
1485c
1486c     locjob indicates whether or not real values must be copied.
1487c
1488      locjob = mod(job,2)
1489c
1490c permute rows first
1491c
1492      call rperm (nrow,a,ja,ia,ao,jao,iao,perm,locjob)
1493c
1494c then permute columns
1495c
1496      locjob = 0
1497c
1498      if (job .le. 2) then
1499         call cperm (nrow,ao,jao,iao,ao,jao,iao,perm,locjob)
1500      else
1501         call cperm (nrow,ao,jao,iao,ao,jao,iao,qperm,locjob)
1502      endif
1503c
1504      return
1505c-------end-of-dperm----------------------------------------------------
1506c-----------------------------------------------------------------------
1507      end
1508c-----------------------------------------------------------------------
1509      subroutine dperm1 (i1,i2,a,ja,ia,b,jb,ib,perm,ipos,job)
1510      integer i1,i2,job,ja(*),ia(*),jb(*),ib(*),perm(*)
1511      real*8 a(*),b(*)
1512c-----------------------------------------------------------------------
1513c     general submatrix extraction routine.
1514c-----------------------------------------------------------------------
1515c     extracts rows perm(i1), perm(i1+1), ..., perm(i2) (in this order)
1516c     from a matrix (doing nothing in the column indices.) The resulting
1517c     submatrix is constructed in b, jb, ib. A pointer ipos to the
1518c     beginning of arrays b,jb,is also allowed (i.e., nonzero elements
1519c     are accumulated starting in position ipos of b, jb).
1520c-----------------------------------------------------------------------
1521c Y. Saad,Sep. 21 1989 / recoded Jan. 28 1991 / modified for PSPARSLIB
1522c Sept. 1997..
1523c-----------------------------------------------------------------------
1524c on entry:
1525c----------
1526c n 	= dimension of the matrix
1527c a,ja,
1528c   ia  = input matrix in CSR format
1529c perm 	= integer array of length n containing the indices of the rows
1530c         to be extracted.
1531c
1532c job   = job indicator. if (job .ne.1) values are not copied (i.e.,
1533c         only pattern is copied).
1534c
1535c on return:
1536c-----------
1537c b,ja,
1538c ib   = matrix in csr format. b(ipos:ipos+nnz-1),jb(ipos:ipos+nnz-1)
1539c     contain the value and column indices respectively of the nnz
1540c     nonzero elements of the permuted matrix. thus ib(1)=ipos.
1541c
1542c Notes:
1543c-------
1544c  algorithm is NOT in place
1545c-----------------------------------------------------------------------
1546c local variables
1547c
1548      integer ko,irow,k
1549      logical values
1550c-----------------------------------------------------------------------
1551      values = (job .eq. 1)
1552      ko = ipos
1553      ib(1) = ko
1554      do 900 i=i1,i2
1555         irow = perm(i)
1556         do 800 k=ia(irow),ia(irow+1)-1
1557            if (values) b(ko) = a(k)
1558            jb(ko) = ja(k)
1559            ko=ko+1
1560 800     continue
1561         ib(i-i1+2) = ko
1562 900  continue
1563      return
1564c--------end-of-dperm1--------------------------------------------------
1565c-----------------------------------------------------------------------
1566      end
1567c-----------------------------------------------------------------------
1568      subroutine dperm2 (i1,i2,a,ja,ia,b,jb,ib,cperm,rperm,istart,
1569     *        ipos,job)
1570      integer i1,i2,job,istart,ja(*),ia(*),jb(*),ib(*),cperm(*),rperm(*)
1571      real*8 a(*),b(*)
1572c-----------------------------------------------------------------------
1573c     general submatrix permutation/ extraction routine.
1574c-----------------------------------------------------------------------
1575c     extracts rows rperm(i1), rperm(i1+1), ..., rperm(i2) and does an
1576c     associated column permutation (using array cperm). The resulting
1577c     submatrix is constructed in b, jb, ib. For added flexibility, the
1578c     extracted elements are put in sequence starting from row 'istart'
1579c     of B. In addition a pointer ipos to the beginning of arrays b,jb,
1580c     is also allowed (i.e., nonzero elements are accumulated starting in
1581c     position ipos of b, jb). In most applications istart and ipos are
1582c     equal to one. However, the generality adds substantial flexiblity.
1583c     EXPLE: (1) to permute msr to msr (excluding diagonals)
1584c     call dperm2 (1,n,a,ja,ja,b,jb,jb,rperm,rperm,1,n+2)
1585c            (2) To extract rows 1 to 10: define rperm and cperm to be
1586c     identity permutations (rperm(i)=i, i=1,n) and then
1587c            call dperm2 (1,10,a,ja,ia,b,jb,ib,rperm,rperm,1,1)
1588c            (3) to achieve a symmetric permutation as defined by perm:
1589c            call dperm2 (1,10,a,ja,ia,b,jb,ib,perm,perm,1,1)
1590c            (4) to get a symmetric permutation of A and append the
1591c            resulting data structure to A's data structure (useful!)
1592c            call dperm2 (1,10,a,ja,ia,a,ja,ia(n+1),perm,perm,1,ia(n+1))
1593c-----------------------------------------------------------------------
1594c Y. Saad,Sep. 21 1989 / recoded Jan. 28 1991.
1595c-----------------------------------------------------------------------
1596c on entry:
1597c----------
1598c n 	= dimension of the matrix
1599c i1,i2 = extract rows rperm(i1) to rperm(i2) of A, with i1<i2.
1600c
1601c a,ja,
1602c   ia  = input matrix in CSR format
1603c cperm = integer array of length n containing the permutation arrays
1604c	  for the columns: cperm(i) is the destination of column j,
1605c         i.e., any column index ja(k) is transformed into cperm(ja(k))
1606c
1607c rperm	=  permutation array for the rows. rperm(i) = origin (in A) of
1608c          row i in B. This is the reverse permutation relative to the
1609c          ones used in routines cperm, dperm,....
1610c          rows rperm(i1), rperm(i1)+1, ... rperm(i2) are
1611c          extracted from A and stacked into B, starting in row istart
1612c          of B.
1613c istart= starting row for B where extracted matrix is to be added.
1614c         this is also only a pointer of the be beginning address for
1615c         ib , on return.
1616c ipos  = beginning position in arrays b and jb where to start copying
1617c         elements. Thus, ib(istart) = ipos.
1618c
1619c job   = job indicator. if (job .ne.1) values are not copied (i.e.,
1620c         only pattern is copied).
1621c
1622c on return:
1623c-----------
1624c b,ja,
1625c ib   = matrix in csr format. positions 1,2,...,istart-1 of ib
1626c     are not touched. b(ipos:ipos+nnz-1),jb(ipos:ipos+nnz-1)
1627c     contain the value and column indices respectively of the nnz
1628c     nonzero elements of the permuted matrix. thus ib(istart)=ipos.
1629c
1630c Notes:
1631c-------
1632c  1) algorithm is NOT in place
1633c  2) column indices may not be sorted on return even  though they
1634c     may be on entry.
1635c-----------------------------------------------------------------------
1636c local variables
1637c
1638      integer ko,irow,k
1639      logical values
1640c-----------------------------------------------------------------------
1641      values = (job .eq. 1)
1642      ko = ipos
1643      ib(istart) = ko
1644      do 900 i=i1,i2
1645         irow = rperm(i)
1646         do 800 k=ia(irow),ia(irow+1)-1
1647            if (values) b(ko) = a(k)
1648            jb(ko) = cperm(ja(k))
1649            ko=ko+1
1650 800     continue
1651         ib(istart+i-i1+1) = ko
1652 900  continue
1653      return
1654c--------end-of-dperm2--------------------------------------------------
1655c-----------------------------------------------------------------------
1656      end
1657c-----------------------------------------------------------------------
1658      subroutine dmperm (nrow,a,ja,ao,jao,perm,job)
1659      integer nrow,ja(*),jao(*),perm(nrow),job
1660      real*8 a(*),ao(*)
1661c-----------------------------------------------------------------------
1662c This routine performs a symmetric permutation of the rows and
1663c columns of a matrix stored in MSR format. i.e., it computes
1664c B = P A transp(P), where P, is  a permutation matrix.
1665c P maps row i into row perm(i) and column j into column perm(j):
1666c      a(i,j)    becomes   a(perm(i),perm(j)) in new matrix
1667c (i.e.  ao(perm(i),perm(j)) = a(i,j) )
1668c calls dperm.
1669c-----------------------------------------------------------------------
1670c Y. Saad, Nov 15, 1991.
1671c-----------------------------------------------------------------------
1672c on entry:
1673c----------
1674c n 	= dimension of the matrix
1675c a, ja = input matrix in MSR format.
1676c perm 	= integer array of length n containing the permutation arrays
1677c	  for the rows: perm(i) is the destination of row i in the
1678c         permuted matrix -- also the destination of column i in case
1679c         permutation is symmetric (job .le. 2)
1680c
1681c job	= integer indicating the work to be done:
1682c 		job = 1	permute a, ja, ia into ao, jao, iao
1683c 		job = 2 permute matrix ignoring real values.
1684c
1685c on return:
1686c-----------
1687c ao, jao = output matrix in MSR.
1688c
1689c in case job .eq. 2 a and ao are never referred to and can be dummy
1690c arguments.
1691c
1692c Notes:
1693c-------
1694c  1) algorithm is NOT in place
1695c  2) column indices may not be sorted on return even  though they may be
1696c     on entry.
1697c----------------------------------------------------------------------c
1698c     local variables
1699c
1700      integer n1, n2
1701      n1 = nrow+1
1702      n2 = n1+1
1703c
1704      call dperm (nrow,a,ja,ja,ao(n2),jao(n2),jao,perm,perm,job)
1705c
1706      jao(1) = n2
1707      do 101 j=1, nrow
1708         ao(perm(j)) = a(j)
1709         jao(j+1) = jao(j+1)+n1
1710 101  continue
1711c
1712c done
1713c
1714      return
1715c-----------------------------------------------------------------------
1716c--------end-of-dmperm--------------------------------------------------
1717      end
1718c-----------------------------------------------------------------------
1719      subroutine dvperm (n, x, perm)
1720      integer n, perm(n)
1721      real*8 x(n)
1722c-----------------------------------------------------------------------
1723c this subroutine performs an in-place permutation of a real vector x
1724c according to the permutation array perm(*), i.e., on return,
1725c the vector x satisfies,
1726c
1727c	x(perm(j)) :== x(j), j=1,2,.., n
1728c
1729c-----------------------------------------------------------------------
1730c on entry:
1731c---------
1732c n 	= length of vector x.
1733c perm 	= integer array of length n containing the permutation  array.
1734c x	= input vector
1735c
1736c on return:
1737c----------
1738c x	= vector x permuted according to x(perm(*)) :=  x(*)
1739c
1740c----------------------------------------------------------------------c
1741c           Y. Saad, Sep. 21 1989                                      c
1742c----------------------------------------------------------------------c
1743c local variables
1744      real*8 tmp, tmp1
1745c
1746      init      = 1
1747      tmp	= x(init)
1748      ii        = perm(init)
1749      perm(init)= -perm(init)
1750      k         = 0
1751c
1752c loop
1753c
1754 6    k = k+1
1755c
1756c save the chased element --
1757c
1758      tmp1	  = x(ii)
1759      x(ii)     = tmp
1760      next	  = perm(ii)
1761      if (next .lt. 0 ) goto 65
1762c
1763c test for end
1764c
1765      if (k .gt. n) goto 101
1766      tmp       = tmp1
1767      perm(ii)  = - perm(ii)
1768      ii        = next
1769c
1770c end loop
1771c
1772      goto 6
1773c
1774c reinitilaize cycle --
1775c
1776 65   init      = init+1
1777      if (init .gt. n) goto 101
1778      if (perm(init) .lt. 0) goto 65
1779      tmp	= x(init)
1780      ii	= perm(init)
1781      perm(init)=-perm(init)
1782      goto 6
1783c
1784 101  continue
1785      do 200 j=1, n
1786         perm(j) = -perm(j)
1787 200  continue
1788c
1789      return
1790c-------------------end-of-dvperm---------------------------------------
1791c-----------------------------------------------------------------------
1792      end
1793c-----------------------------------------------------------------------
1794      subroutine ivperm (n, ix, perm)
1795      integer n, perm(n), ix(n)
1796c-----------------------------------------------------------------------
1797c this subroutine performs an in-place permutation of an integer vector
1798c ix according to the permutation array perm(*), i.e., on return,
1799c the vector x satisfies,
1800c
1801c	ix(perm(j)) :== ix(j), j=1,2,.., n
1802c
1803c-----------------------------------------------------------------------
1804c on entry:
1805c---------
1806c n 	= length of vector x.
1807c perm 	= integer array of length n containing the permutation  array.
1808c ix	= input vector
1809c
1810c on return:
1811c----------
1812c ix	= vector x permuted according to ix(perm(*)) :=  ix(*)
1813c
1814c----------------------------------------------------------------------c
1815c           Y. Saad, Sep. 21 1989                                      c
1816c----------------------------------------------------------------------c
1817c local variables
1818      integer tmp, tmp1
1819c
1820      init      = 1
1821      tmp	= ix(init)
1822      ii        = perm(init)
1823      perm(init)= -perm(init)
1824      k         = 0
1825c
1826c loop
1827c
1828 6    k = k+1
1829c
1830c save the chased element --
1831c
1832      tmp1	  = ix(ii)
1833      ix(ii)     = tmp
1834      next	  = perm(ii)
1835      if (next .lt. 0 ) goto 65
1836c
1837c test for end
1838c
1839      if (k .gt. n) goto 101
1840      tmp       = tmp1
1841      perm(ii)  = - perm(ii)
1842      ii        = next
1843c
1844c end loop
1845c
1846      goto 6
1847c
1848c reinitilaize cycle --
1849c
1850 65   init      = init+1
1851      if (init .gt. n) goto 101
1852      if (perm(init) .lt. 0) goto 65
1853      tmp	= ix(init)
1854      ii	= perm(init)
1855      perm(init)=-perm(init)
1856      goto 6
1857c
1858 101  continue
1859      do 200 j=1, n
1860         perm(j) = -perm(j)
1861 200  continue
1862c
1863      return
1864c-------------------end-of-ivperm---------------------------------------
1865c-----------------------------------------------------------------------
1866      end
1867c-----------------------------------------------------------------------
1868      subroutine retmx (n,a,ja,ia,dd)
1869      real*8 a(*),dd(*)
1870      integer n,ia(*),ja(*)
1871c-----------------------------------------------------------------------
1872c returns in dd(*) the max absolute value of elements in row *.
1873c used for scaling purposes. superseded by rnrms  .
1874c
1875c on entry:
1876c n	= dimension of A
1877c a,ja,ia
1878c	= matrix stored in compressed sparse row format
1879c dd	= real*8 array of length n. On output,entry dd(i) contains
1880c	  the element of row i that has the largest absolute value.
1881c	  Moreover the sign of dd is modified such that it is the
1882c	  same as that of the diagonal element in row i.
1883c----------------------------------------------------------------------c
1884c           Y. Saad, Sep. 21 1989                                      c
1885c----------------------------------------------------------------------c
1886c local variables
1887      integer k2, i, k1, k
1888      real*8 t, t1, t2
1889c
1890c initialize
1891c
1892      k2 = 1
1893      do 11 i=1,n
1894         k1 = k2
1895         k2 = ia(i+1) - 1
1896         t = 0.0d0
1897         do 101  k=k1,k2
1898            t1 = abs(a(k))
1899            if (t1 .gt. t) t = t1
1900            if (ja(k) .eq. i) then
1901               if (a(k) .ge. 0.0) then
1902                  t2 = a(k)
1903               else
1904                  t2 = - a(k)
1905               endif
1906            endif
1907 101     continue
1908         dd(i) =  t2*t
1909c     we do not invert diag
1910 11   continue
1911      return
1912c---------end of retmx -------------------------------------------------
1913c-----------------------------------------------------------------------
1914      end
1915c-----------------------------------------------------------------------
1916      subroutine diapos  (n,ja,ia,idiag)
1917      integer ia(n+1), ja(*), idiag(n)
1918c-----------------------------------------------------------------------
1919c this subroutine returns the positions of the diagonal elements of a
1920c sparse matrix a, ja, ia, in the array idiag.
1921c-----------------------------------------------------------------------
1922c on entry:
1923c----------
1924c
1925c n	= integer. row dimension of the matrix a.
1926c a,ja,
1927c    ia = matrix stored compressed sparse row format. a array skipped.
1928c
1929c on return:
1930c-----------
1931c idiag  = integer array of length n. The i-th entry of idiag
1932c          points to the diagonal element a(i,i) in the arrays
1933c          a, ja. (i.e., a(idiag(i)) = element A(i,i) of matrix A)
1934c          if no diagonal element is found the entry is set to 0.
1935c----------------------------------------------------------------------c
1936c           Y. Saad, March, 1990
1937c----------------------------------------------------------------------c
1938      do 1 i=1, n
1939         idiag(i) = 0
1940 1    continue
1941c
1942c     sweep through data structure.
1943c
1944      do  6 i=1,n
1945         do 51 k= ia(i),ia(i+1) -1
1946            if (ja(k) .eq. i) idiag(i) = k
1947 51      continue
1948 6    continue
1949c----------- -end-of-diapos---------------------------------------------
1950c-----------------------------------------------------------------------
1951      return
1952      end
1953c-----------------------------------------------------------------------
1954      subroutine dscaldg (n,a,ja,ia,diag,job)
1955      real*8 a(*), diag(*),t
1956      integer ia(*),ja(*)
1957c-----------------------------------------------------------------------
1958c scales rows by diag where diag is either given (job=0)
1959c or to be computed:
1960c  job = 1 ,scale row i by  by  +/- max |a(i,j) | and put inverse of
1961c       scaling factor in diag(i),where +/- is the sign of a(i,i).
1962c  job = 2 scale by 2-norm of each row..
1963c if diag(i) = 0,then diag(i) is replaced by one
1964c (no scaling)..
1965c----------------------------------------------------------------------c
1966c           Y. Saad, Sep. 21 1989                                      c
1967c----------------------------------------------------------------------c
1968      goto (12,11,10) job+1
1969 10   do 110 j=1,n
1970         k1= ia(j)
1971         k2 = ia(j+1)-1
1972         t = 0.0d0
1973         do 111 k = k1,k2
1974 111        t = t+a(k)*a(k)
1975 110        diag(j) = sqrt(t)
1976            goto 12
1977 11   continue
1978      call retmx (n,a,ja,ia,diag)
1979c------
1980 12   do 1 j=1,n
1981         if (diag(j) .ne. 0.0d0) then
1982            diag(j) = 1.0d0/diag(j)
1983         else
1984            diag(j) = 1.0d0
1985         endif
1986 1    continue
1987      do 2 i=1,n
1988         t = diag(i)
1989         do 21 k=ia(i),ia(i+1) -1
1990            a(k) = a(k)*t
1991 21      continue
1992 2    continue
1993      return
1994c--------end of dscaldg -----------------------------------------------
1995c-----------------------------------------------------------------------
1996      end
1997c-----------------------------------------------------------------------
1998      subroutine extbdg (n,a,ja,ia,bdiag,nblk,ao,jao,iao)
1999      implicit real*8 (a-h,o-z)
2000      real*8 bdiag(*),a(*),ao(*)
2001      integer ia(*),ja(*),jao(*),iao(*)
2002c-----------------------------------------------------------------------
2003c this subroutine extracts the main diagonal blocks of a
2004c matrix stored in compressed sparse row format and puts the result
2005c into the array bdiag and the remainder in ao,jao,iao.
2006c-----------------------------------------------------------------------
2007c on entry:
2008c----------
2009c n	= integer. The row dimension of the matrix a.
2010c a,
2011c ja,
2012c ia    = matrix stored in csr format
2013c nblk  = dimension of each diagonal block. The diagonal blocks are
2014c         stored in compressed format rowwise,i.e.,we store in
2015c	  succession the i nonzeros of the i-th row after those of
2016c	  row number i-1..
2017c
2018c on return:
2019c----------
2020c bdiag = real*8 array of size (n x nblk) containing the diagonal
2021c	  blocks of A on return
2022c ao,
2023c jao,
2024C iao   = remainder of the matrix stored in csr format.
2025c----------------------------------------------------------------------c
2026c           Y. Saad, Sep. 21 1989                                      c
2027c----------------------------------------------------------------------c
2028      m = 1 + (n-1)/nblk
2029c this version is sequential -- there is a more parallel version
2030c that goes through the structure twice ....
2031      ltr =  ((nblk-1)*nblk)/2
2032      l = m * ltr
2033      do 1 i=1,l
2034         bdiag(i) = 0.0d0
2035 1    continue
2036      ko = 0
2037      kb = 1
2038      iao(1) = 1
2039c-------------------------
2040      do 11 jj = 1,m
2041         j1 = (jj-1)*nblk+1
2042         j2 =  min0 (n,j1+nblk-1)
2043         do 12 j=j1,j2
2044            do 13 i=ia(j),ia(j+1) -1
2045               k = ja(i)
2046               if (k .lt. j1) then
2047                  ko = ko+1
2048                  ao(ko) = a(i)
2049                  jao(ko) = k
2050               else if (k .lt. j) then
2051c     kb = (jj-1)*ltr+((j-j1)*(j-j1-1))/2+k-j1+1
2052c     bdiag(kb) = a(i)
2053                  bdiag(kb+k-j1) = a(i)
2054               endif
2055 13         continue
2056            kb = kb + j-j1
2057            iao(j+1) = ko+1
2058 12      continue
2059 11   continue
2060      return
2061c---------end-of-extbdg-------------------------------------------------
2062c-----------------------------------------------------------------------
2063      end
2064c-----------------------------------------------------------------------
2065      subroutine getbwd(n,a,ja,ia,ml,mu)
2066c-----------------------------------------------------------------------
2067c gets the bandwidth of lower part and upper part of A.
2068c does not assume that A is sorted.
2069c-----------------------------------------------------------------------
2070c on entry:
2071c----------
2072c n	= integer = the row dimension of the matrix
2073c a, ja,
2074c    ia = matrix in compressed sparse row format.
2075c
2076c on return:
2077c-----------
2078c ml	= integer. The bandwidth of the strict lower part of A
2079c mu	= integer. The bandwidth of the strict upper part of A
2080c
2081c Notes:
2082c ===== ml and mu are allowed to be negative or return. This may be
2083c       useful since it will tell us whether a band is confined
2084c       in the strict  upper/lower triangular part.
2085c       indeed the definitions of ml and mu are
2086c
2087c       ml = max ( (i-j)  s.t. a(i,j) .ne. 0  )
2088c       mu = max ( (j-i)  s.t. a(i,j) .ne. 0  )
2089c----------------------------------------------------------------------c
2090c Y. Saad, Sep. 21 1989                                                c
2091c----------------------------------------------------------------------c
2092      real*8 a(*)
2093      integer ja(*),ia(n+1),ml,mu,ldist,i,k
2094      ml = - n
2095      mu = - n
2096      do 3 i=1,n
2097         do 31 k=ia(i),ia(i+1)-1
2098            ldist = i-ja(k)
2099            ml = max(ml,ldist)
2100            mu = max(mu,-ldist)
2101 31      continue
2102 3    continue
2103      return
2104c---------------end-of-getbwd ------------------------------------------
2105c-----------------------------------------------------------------------
2106      end
2107c-----------------------------------------------------------------------
2108      subroutine blkfnd (nrow,ja,ia,nblk)
2109c-----------------------------------------------------------------------
2110c This routine attemptps to determine whether or not  the input
2111c matrix has a block structure and finds the blocks size
2112c if it does. A block matrix is one which is
2113c comprised of small square dense blocks. If there are zero
2114c elements within the square blocks and the original data structure
2115c takes these zeros into account then blkchk may fail to find the
2116c correct block size.
2117c-----------------------------------------------------------------------
2118c on entry
2119c---------
2120c nrow	= integer equal to the row dimension of the matrix.
2121c ja    = integer array containing the column indices of the entries
2122c         nonzero entries of the matrix stored by row.
2123c ia    = integer array of length nrow + 1 containing the pointers
2124c         beginning of each row in array ja.
2125c
2126c nblk  = integer containing the assumed value of nblk if job = 0
2127c
2128c on return
2129c----------
2130c nblk  = integer containing the value found for nblk when job = 1.
2131c         if imsg .ne. 0 this value is meaningless however.
2132c
2133c----------------------------------------------------------------------c
2134c           Y. Saad, Sep. 21 1989                                      c
2135c----------------------------------------------------------------------c
2136      integer ia(nrow+1),ja(*)
2137c-----------------------------------------------------------------------
2138c first part of code will find candidate block sizes.
2139c criterion used here is a simple one: scan rows and  determine groups
2140c of rows that have the same length and such that the first column
2141c number and the last column number are identical.
2142c-----------------------------------------------------------------------
2143      minlen = ia(2)-ia(1)
2144      irow   = 1
2145      do 1 i=2,nrow
2146         len = ia(i+1)-ia(i)
2147         if (len .lt. minlen) then
2148            minlen = len
2149            irow = i
2150         endif
2151 1    continue
2152c
2153c     ---- candidates are all dividers of minlen
2154c
2155      nblk = 1
2156      if (minlen .le. 1) return
2157c
2158      do 99 iblk = minlen, 1, -1
2159         if (mod(minlen,iblk) .ne. 0) goto 99
2160         len = ia(2) - ia(1)
2161         len0 = len
2162         jfirst = ja(1)
2163         jlast = ja(ia(2)-1)
2164         do 10 jrow = irow+1,irow+nblk-1
2165            i1 = ia(jrow)
2166            i2 = ia(jrow+1)-1
2167            len = i2+1-i1
2168            jf = ja(i1)
2169            jl = ja(i2)
2170            if (len .ne. len0 .or. jf .ne. jfirst .or.
2171     *           jl .ne. jlast) goto 99
2172 10      continue
2173c
2174c     check for this candidate ----
2175c
2176         call blkchk (nrow,ja,ia,iblk,imsg)
2177         if (imsg .eq. 0) then
2178c
2179c     block size found
2180c
2181            nblk = iblk
2182            return
2183         endif
2184 99   continue
2185c--------end-of-blkfnd -------------------------------------------------
2186c-----------------------------------------------------------------------
2187      end
2188c-----------------------------------------------------------------------
2189      subroutine blkchk (nrow,ja,ia,nblk,imsg)
2190c-----------------------------------------------------------------------
2191c This routine checks whether the input matrix is a block
2192c matrix with block size of nblk. A block matrix is one which is
2193c comprised of small square dense blocks. If there are zero
2194c elements within the square blocks and the data structure
2195c takes them into account then blkchk may fail to find the
2196c correct block size.
2197c-----------------------------------------------------------------------
2198c on entry
2199c---------
2200c nrow	= integer equal to the row dimension of the matrix.
2201c ja    = integer array containing the column indices of the entries
2202c         nonzero entries of the matrix stored by row.
2203c ia    = integer array of length nrow + 1 containing the pointers
2204c         beginning of each row in array ja.
2205c
2206c nblk  = integer containing the value of nblk to be checked.
2207c
2208c on return
2209c----------
2210c
2211c imsg  = integer containing a message  with the following meaning.
2212c          imsg = 0 means that the output value of nblk is a correct
2213c                   block size. nblk .lt. 0 means nblk not correct
2214c                   block size.
2215c          imsg = -1 : nblk does not divide nrow
2216c          imsg = -2 : a starting element in a row is at wrong position
2217c             (j .ne. mult*nblk +1 )
2218c          imsg = -3 : nblk does divide a row length -
2219c          imsg = -4 : an element is isolated outside a block or
2220c             two rows in same group have different lengths
2221c----------------------------------------------------------------------c
2222c           Y. Saad, Sep. 21 1989                                      c
2223c----------------------------------------------------------------------c
2224      integer ia(nrow+1),ja(*)
2225c----------------------------------------------------------------------
2226c first part of code will find candidate block sizes.
2227c this is not guaranteed to work . so a check is done at the end
2228c the criterion used here is a simple one:
2229c scan rows and determine groups of rows that have the same length
2230c and such that the first column number and the last column number
2231c are identical.
2232c----------------------------------------------------------------------
2233      imsg = 0
2234      if (nblk .le. 1) return
2235      nr = nrow/nblk
2236      if (nr*nblk .ne. nrow) goto 101
2237c--   main loop ---------------------------------------------------------
2238      irow = 1
2239      do 20 ii=1, nr
2240c     i1= starting position for group of nblk rows in original matrix
2241         i1 = ia(irow)
2242         j2 = i1
2243c     lena = length of each row in that group  in the original matrix
2244         lena = ia(irow+1)-i1
2245c     len = length of each block-row in that group in the output matrix
2246         len = lena/nblk
2247         if (len* nblk .ne. lena) goto 103
2248c
2249c     for each row
2250c
2251         do 6 i = 1, nblk
2252            irow = irow + 1
2253            if (ia(irow)-ia(irow-1) .ne. lena ) goto 104
2254c
2255c     for each block
2256c
2257            do 7 k=0, len-1
2258               jstart = ja(i1+nblk*k)-1
2259               if ( (jstart/nblk)*nblk .ne. jstart) goto 102
2260c
2261c     for each column
2262c
2263               do 5 j=1, nblk
2264                  if (jstart+j .ne. ja(j2) )  goto 104
2265                  j2 = j2+1
2266 5             continue
2267 7          continue
2268 6       continue
2269 20   continue
2270c     went through all loops successfully:
2271      return
2272 101  imsg = -1
2273      return
2274 102  imsg = -2
2275      return
2276 103  imsg = -3
2277      return
2278 104  imsg = -4
2279c----------------end of chkblk -----------------------------------------
2280c-----------------------------------------------------------------------
2281      return
2282      end
2283c-----------------------------------------------------------------------
2284      subroutine infdia (n,ja,ia,ind,idiag)
2285      integer ia(*), ind(*), ja(*)
2286c-----------------------------------------------------------------------
2287c     obtains information on the diagonals of A.
2288c-----------------------------------------------------------------------
2289c this subroutine finds the lengths of each of the 2*n-1 diagonals of A
2290c it also outputs the number of nonzero diagonals found.
2291c-----------------------------------------------------------------------
2292c on entry:
2293c----------
2294c n	= dimension of the matrix a.
2295c
2296c a,    ..... not needed here.
2297c ja,
2298c ia    = matrix stored in csr format
2299c
2300c on return:
2301c-----------
2302c
2303c idiag = integer. number of nonzero diagonals found.
2304c
2305c ind   = integer array of length at least 2*n-1. The k-th entry in
2306c         ind contains the number of nonzero elements in the diagonal
2307c         number k, the numbering beeing from the lowermost diagonal
2308c         (bottom-left). In other words ind(k) = length of diagonal
2309c         whose offset wrt the main diagonal is = - n + k.
2310c----------------------------------------------------------------------c
2311c           Y. Saad, Sep. 21 1989                                      c
2312c----------------------------------------------------------------------c
2313      n2= n+n-1
2314      do 1 i=1,n2
2315         ind(i) = 0
2316 1    continue
2317      do 3 i=1, n
2318         do 2 k=ia(i),ia(i+1)-1
2319            j = ja(k)
2320            ind(n+j-i) = ind(n+j-i) +1
2321 2       continue
2322 3    continue
2323c     count the nonzero ones.
2324      idiag = 0
2325      do 41 k=1, n2
2326         if (ind(k) .ne. 0) idiag = idiag+1
2327 41   continue
2328      return
2329c done
2330c------end-of-infdia ---------------------------------------------------
2331c-----------------------------------------------------------------------
2332      end
2333c-----------------------------------------------------------------------
2334      subroutine amubdg (nrow,ncol,ncolb,ja,ia,jb,ib,ndegr,nnz,iw)
2335      integer ja(*),jb(*),ia(nrow+1),ib(ncol+1),ndegr(nrow),iw(ncolb)
2336c-----------------------------------------------------------------------
2337c gets the number of nonzero elements in each row of A*B and the total
2338c number of nonzero elements in A*B.
2339c-----------------------------------------------------------------------
2340c on entry:
2341c --------
2342c
2343c nrow  = integer.  row dimension of matrix A
2344c ncol  = integer.  column dimension of matrix A = row dimension of
2345c                   matrix B.
2346c ncolb = integer. the colum dimension of the matrix B.
2347c
2348c ja, ia= row structure of input matrix A: ja = column indices of
2349c         the nonzero elements of A stored by rows.
2350c         ia = pointer to beginning of each row  in ja.
2351c
2352c jb, ib= row structure of input matrix B: jb = column indices of
2353c         the nonzero elements of A stored by rows.
2354c         ib = pointer to beginning of each row  in jb.
2355c
2356c on return:
2357c ---------
2358c ndegr	= integer array of length nrow containing the degrees (i.e.,
2359c         the number of nonzeros in  each row of the matrix A * B
2360c
2361c nnz   = total number of nonzero elements found in A * B
2362c
2363c work arrays:
2364c-------------
2365c iw	= integer work array of length ncolb.
2366c-----------------------------------------------------------------------
2367      do 1 k=1, ncolb
2368         iw(k) = 0
2369 1    continue
2370
2371      do 2 k=1, nrow
2372         ndegr(k) = 0
2373 2    continue
2374c
2375c     method used: Transp(A) * A = sum [over i=1, nrow]  a(i)^T a(i)
2376c     where a(i) = i-th row of  A. We must be careful not to add  the
2377c     elements already accounted for.
2378c
2379c
2380      do 7 ii=1,nrow
2381c
2382c     for each row of A
2383c
2384         ldg = 0
2385c
2386c    end-of-linked list
2387c
2388         last = -1
2389         do 6 j = ia(ii),ia(ii+1)-1
2390c
2391c     row number to be added:
2392c
2393            jr = ja(j)
2394            do 5 k=ib(jr),ib(jr+1)-1
2395               jc = jb(k)
2396               if (iw(jc) .eq. 0) then
2397c
2398c     add one element to the linked list
2399c
2400                  ldg = ldg + 1
2401                  iw(jc) = last
2402                  last = jc
2403               endif
2404 5          continue
2405 6       continue
2406         ndegr(ii) = ldg
2407c
2408c     reset iw to zero
2409c
2410         do 61 k=1,ldg
2411            j = iw(last)
2412            iw(last) = 0
2413            last = j
2414 61      continue
2415c-----------------------------------------------------------------------
2416 7    continue
2417c
2418      nnz = 0
2419      do 8 ii=1, nrow
2420         nnz = nnz+ndegr(ii)
2421 8    continue
2422c
2423      return
2424c---------------end-of-amubdg ------------------------------------------
2425c-----------------------------------------------------------------------
2426      end
2427c-----------------------------------------------------------------------
2428      subroutine aplbdg (nrow,ncol,ja,ia,jb,ib,ndegr,nnz,iw)
2429      integer ja(*),jb(*),ia(nrow+1),ib(nrow+1),iw(ncol),ndegr(nrow)
2430c-----------------------------------------------------------------------
2431c gets the number of nonzero elements in each row of A+B and the total
2432c number of nonzero elements in A+B.
2433c-----------------------------------------------------------------------
2434c on entry:
2435c ---------
2436c nrow	= integer. The row dimension of A and B
2437c ncol  = integer. The column dimension of A and B.
2438c
2439c a,
2440c ja,
2441c ia   = Matrix A in compressed sparse row format.
2442c
2443c b,
2444c jb,
2445c ib	=  Matrix B in compressed sparse row format.
2446c
2447c on return:
2448c----------
2449c ndegr	= integer array of length nrow containing the degrees (i.e.,
2450c         the number of nonzeros in  each row of the matrix A + B.
2451c
2452c nnz   = total number of nonzero elements found in A * B
2453c
2454c work arrays:
2455c------------
2456c iw	= integer work array of length equal to ncol.
2457c
2458c-----------------------------------------------------------------------
2459      do 1 k=1, ncol
2460         iw(k) = 0
2461 1    continue
2462c
2463      do 2 k=1, nrow
2464         ndegr(k) = 0
2465 2    continue
2466c
2467      do 7 ii=1,nrow
2468         ldg = 0
2469c
2470c    end-of-linked list
2471c
2472         last = -1
2473c
2474c     row of A
2475c
2476         do 5 j = ia(ii),ia(ii+1)-1
2477            jr = ja(j)
2478c
2479c     add element to the linked list
2480c
2481            ldg = ldg + 1
2482            iw(jr) = last
2483            last = jr
2484 5       continue
2485c
2486c     row of B
2487c
2488         do 6 j=ib(ii),ib(ii+1)-1
2489            jc = jb(j)
2490            if (iw(jc) .eq. 0) then
2491c
2492c     add one element to the linked list
2493c
2494               ldg = ldg + 1
2495               iw(jc) = last
2496               last = jc
2497            endif
2498 6       continue
2499c     done with row ii.
2500         ndegr(ii) = ldg
2501c
2502c     reset iw to zero
2503c
2504         do 61 k=1,ldg
2505            j = iw(last)
2506            iw(last) = 0
2507            last = j
2508 61      continue
2509c-----------------------------------------------------------------------
2510 7    continue
2511c
2512      nnz = 0
2513      do 8 ii=1, nrow
2514         nnz = nnz+ndegr(ii)
2515 8    continue
2516      return
2517c----------------end-of-aplbdg -----------------------------------------
2518c-----------------------------------------------------------------------
2519      end
2520c-----------------------------------------------------------------------
2521      subroutine rnrms   (nrow, nrm, a, ja, ia, diag)
2522      real*8 a(*), diag(nrow), scal
2523      integer ja(*), ia(nrow+1)
2524c-----------------------------------------------------------------------
2525c gets the norms of each row of A. (choice of three norms)
2526c-----------------------------------------------------------------------
2527c on entry:
2528c ---------
2529c nrow	= integer. The row dimension of A
2530c
2531c nrm   = integer. norm indicator. nrm = 1, means 1-norm, nrm =2
2532c                  means the 2-nrm, nrm = 0 means max norm
2533c
2534c a,
2535c ja,
2536c ia   = Matrix A in compressed sparse row format.
2537c
2538c on return:
2539c----------
2540c
2541c diag = real vector of length nrow containing the norms
2542c
2543c-----------------------------------------------------------------
2544      do 1 ii=1,nrow
2545c
2546c     compute the norm if each element.
2547c
2548         scal = 0.0d0
2549         k1 = ia(ii)
2550         k2 = ia(ii+1)-1
2551         if (nrm .eq. 0) then
2552            do 2 k=k1, k2
2553               scal = max(scal,abs(a(k) ) )
2554 2          continue
2555         elseif (nrm .eq. 1) then
2556            do 3 k=k1, k2
2557               scal = scal + abs(a(k) )
2558 3          continue
2559         else
2560            do 4 k=k1, k2
2561               scal = scal+a(k)**2
2562 4          continue
2563         endif
2564         if (nrm .eq. 2) scal = sqrt(scal)
2565         diag(ii) = scal
2566 1    continue
2567      return
2568c-----------------------------------------------------------------------
2569c-------------end-of-rnrms----------------------------------------------
2570      end
2571c-----------------------------------------------------------------------
2572      subroutine cnrms   (nrow, nrm, a, ja, ia, diag)
2573      real*8 a(*), diag(nrow)
2574      integer ja(*), ia(nrow+1)
2575c-----------------------------------------------------------------------
2576c gets the norms of each column of A. (choice of three norms)
2577c-----------------------------------------------------------------------
2578c on entry:
2579c ---------
2580c nrow	= integer. The row dimension of A
2581c
2582c nrm   = integer. norm indicator. nrm = 1, means 1-norm, nrm =2
2583c                  means the 2-nrm, nrm = 0 means max norm
2584c
2585c a,
2586c ja,
2587c ia   = Matrix A in compressed sparse row format.
2588c
2589c on return:
2590c----------
2591c
2592c diag = real vector of length nrow containing the norms
2593c
2594c-----------------------------------------------------------------
2595      do 10 k=1, nrow
2596         diag(k) = 0.0d0
2597 10   continue
2598      do 1 ii=1,nrow
2599         k1 = ia(ii)
2600         k2 = ia(ii+1)-1
2601         do 2 k=k1, k2
2602            j = ja(k)
2603c     update the norm of each column
2604            if (nrm .eq. 0) then
2605               diag(j) = max(diag(j),abs(a(k) ) )
2606            elseif (nrm .eq. 1) then
2607               diag(j) = diag(j) + abs(a(k) )
2608            else
2609               diag(j) = diag(j)+a(k)**2
2610            endif
2611 2       continue
2612 1    continue
2613      if (nrm .ne. 2) return
2614      do 3 k=1, nrow
2615         diag(k) = sqrt(diag(k))
2616 3    continue
2617      return
2618c-----------------------------------------------------------------------
2619c------------end-of-cnrms-----------------------------------------------
2620      end
2621c-----------------------------------------------------------------------
2622      subroutine roscal(nrow,job,nrm,a,ja,ia,diag,b,jb,ib,ierr)
2623      real*8 a(*), b(*), diag(nrow)
2624      integer nrow,job,nrm,ja(*),jb(*),ia(nrow+1),ib(nrow+1),ierr
2625c-----------------------------------------------------------------------
2626c scales the rows of A such that their norms are one on return
2627c 3 choices of norms: 1-norm, 2-norm, max-norm.
2628c-----------------------------------------------------------------------
2629c on entry:
2630c ---------
2631c nrow	= integer. The row dimension of A
2632c
2633c job   = integer. job indicator. Job=0 means get array b only
2634c         job = 1 means get b, and the integer arrays ib, jb.
2635c
2636c nrm   = integer. norm indicator. nrm = 1, means 1-norm, nrm =2
2637c                  means the 2-nrm, nrm = 0 means max norm
2638c
2639c a,
2640c ja,
2641c ia   = Matrix A in compressed sparse row format.
2642c
2643c on return:
2644c----------
2645c
2646c diag = diagonal matrix stored as a vector containing the matrix
2647c        by which the rows have been scaled, i.e., on return
2648c        we have B = Diag*A.
2649c
2650c b,
2651c jb,
2652c ib	= resulting matrix B in compressed sparse row sparse format.
2653c
2654c ierr  = error message. ierr=0     : Normal return
2655c                        ierr=i > 0 : Row number i is a zero row.
2656c Notes:
2657c-------
2658c 1)        The column dimension of A is not needed.
2659c 2)        algorithm in place (B can take the place of A).
2660c-----------------------------------------------------------------
2661      call rnrms (nrow,nrm,a,ja,ia,diag)
2662      ierr = 0
2663      do 1 j=1, nrow
2664         if (diag(j) .eq. 0.0d0) then
2665            ierr = j
2666            return
2667         else
2668            diag(j) = 1.0d0/diag(j)
2669         endif
2670 1    continue
2671      call diamua(nrow,job,a,ja,ia,diag,b,jb,ib)
2672      return
2673c-------end-of-roscal---------------------------------------------------
2674c-----------------------------------------------------------------------
2675      end
2676c-----------------------------------------------------------------------
2677      subroutine coscal(nrow,job,nrm,a,ja,ia,diag,b,jb,ib,ierr)
2678c-----------------------------------------------------------------------
2679      real*8 a(*),b(*),diag(nrow)
2680      integer nrow,job,ja(*),jb(*),ia(nrow+1),ib(nrow+1),ierr
2681c-----------------------------------------------------------------------
2682c scales the columns of A such that their norms are one on return
2683c result matrix written on b, or overwritten on A.
2684c 3 choices of norms: 1-norm, 2-norm, max-norm. in place.
2685c-----------------------------------------------------------------------
2686c on entry:
2687c ---------
2688c nrow	= integer. The row dimension of A
2689c
2690c job   = integer. job indicator. Job=0 means get array b only
2691c         job = 1 means get b, and the integer arrays ib, jb.
2692c
2693c nrm   = integer. norm indicator. nrm = 1, means 1-norm, nrm =2
2694c                  means the 2-nrm, nrm = 0 means max norm
2695c
2696c a,
2697c ja,
2698c ia   = Matrix A in compressed sparse row format.
2699c
2700c on return:
2701c----------
2702c
2703c diag = diagonal matrix stored as a vector containing the matrix
2704c        by which the columns have been scaled, i.e., on return
2705c        we have B = A * Diag
2706c
2707c b,
2708c jb,
2709c ib	= resulting matrix B in compressed sparse row sparse format.
2710c
2711c ierr  = error message. ierr=0     : Normal return
2712c                        ierr=i > 0 : Column number i is a zero row.
2713c Notes:
2714c-------
2715c 1)     The column dimension of A is not needed.
2716c 2)     algorithm in place (B can take the place of A).
2717c-----------------------------------------------------------------
2718      call cnrms (nrow,nrm,a,ja,ia,diag)
2719      ierr = 0
2720      do 1 j=1, nrow
2721         if (diag(j) .eq. 0.0) then
2722            ierr = j
2723            return
2724         else
2725            diag(j) = 1.0d0/diag(j)
2726         endif
2727 1    continue
2728      call amudia (nrow,job,a,ja,ia,diag,b,jb,ib)
2729      return
2730c--------end-of-coscal--------------------------------------------------
2731c-----------------------------------------------------------------------
2732      end
2733c-----------------------------------------------------------------------
2734      subroutine addblk(nrowa, ncola, a, ja, ia, ipos, jpos, job,
2735     & nrowb, ncolb, b, jb, ib, nrowc, ncolc, c, jc, ic, nzmx, ierr)
2736c      implicit none
2737      integer nrowa, nrowb, nrowc, ncola, ncolb, ncolc, ipos, jpos
2738      integer nzmx, ierr, job
2739      integer ja(1:*), ia(1:*), jb(1:*), ib(1:*), jc(1:*), ic(1:*)
2740      real*8 a(1:*), b(1:*), c(1:*)
2741c-----------------------------------------------------------------------
2742c     This subroutine adds a matrix B into a submatrix of A whose
2743c     (1,1) element is located in the starting position (ipos, jpos).
2744c     The resulting matrix is allowed to be larger than A (and B),
2745c     and the resulting dimensions nrowc, ncolc will be redefined
2746c     accordingly upon return.
2747c     The input matrices are assumed to be sorted, i.e. in each row
2748c     the column indices appear in ascending order in the CSR format.
2749c-----------------------------------------------------------------------
2750c on entry:
2751c ---------
2752c nrowa    = number of rows in A.
2753c bcola    = number of columns in A.
2754c a,ja,ia  = Matrix A in compressed sparse row format with entries sorted
2755c nrowb    = number of rows in B.
2756c ncolb    = number of columns in B.
2757c b,jb,ib  = Matrix B in compressed sparse row format with entries sorted
2758c
2759c nzmax	   = integer. The  length of the arrays c and jc. addblk will
2760c            stop if the number of nonzero elements in the matrix C
2761c            exceeds nzmax. See ierr.
2762c
2763c on return:
2764c----------
2765c nrowc    = number of rows in C.
2766c ncolc    = number of columns in C.
2767c c,jc,ic  = resulting matrix C in compressed sparse row sparse format
2768c            with entries sorted ascendly in each row.
2769c
2770c ierr	   = integer. serving as error message.
2771c         ierr = 0 means normal return,
2772c         ierr .gt. 0 means that addblk stopped while computing the
2773c         i-th row  of C with i=ierr, because the number
2774c         of elements in C exceeds nzmax.
2775c
2776c Notes:
2777c-------
2778c     this will not work if any of the two input matrices is not sorted
2779c-----------------------------------------------------------------------
2780      logical values
2781      integer i,j1,j2,ka,kb,kc,kamax,kbmax
2782      values = (job .ne. 0)
2783      ierr = 0
2784      nrowc = max(nrowa, nrowb+ipos-1)
2785      ncolc = max(ncola, ncolb+jpos-1)
2786      kc = 1
2787      kbmax = 0
2788      ic(1) = kc
2789c
2790      do 10 i=1, nrowc
2791         if (i.le.nrowa) then
2792            ka = ia(i)
2793            kamax = ia(i+1)-1
2794         else
2795            ka = ia(nrowa+1)
2796         end if
2797         if ((i.ge.ipos).and.((i-ipos).le.nrowb)) then
2798            kb = ib(i-ipos+1)
2799            kbmax = ib(i-ipos+2)-1
2800         else
2801            kb = ib(nrowb+1)
2802         end if
2803c
2804c     a do-while type loop -- goes through all the elements in a row.
2805c
2806 20      continue
2807         if (ka .le. kamax) then
2808            j1 = ja(ka)
2809         else
2810            j1 = ncolc+1
2811         endif
2812         if (kb .le. kbmax) then
2813            j2 = jb(kb) + jpos - 1
2814         else
2815            j2 = ncolc+1
2816         endif
2817c
2818c     if there are more elements to be added.
2819c
2820         if ((ka .le. kamax .or. kb .le. kbmax) .and.
2821     &        (j1 .le. ncolc .or. j2 .le. ncolc)) then
2822c
2823c     three cases
2824c
2825            if (j1 .eq. j2) then
2826               if (values) c(kc) = a(ka)+b(kb)
2827               jc(kc) = j1
2828               ka = ka+1
2829               kb = kb+1
2830               kc = kc+1
2831            else if (j1 .lt. j2) then
2832               jc(kc) = j1
2833               if (values) c(kc) = a(ka)
2834               ka = ka+1
2835               kc = kc+1
2836            else if (j1 .gt. j2) then
2837               jc(kc) = j2
2838               if (values) c(kc) = b(kb)
2839               kb = kb+1
2840               kc = kc+1
2841            endif
2842            if (kc .gt. nzmx) goto 999
2843            goto 20
2844         end if
2845         ic(i+1) = kc
2846 10   continue
2847      return
2848 999  ierr = i
2849      return
2850c---------end-of-addblk-------------------------------------------------
2851      end
2852c-----------------------------------------------------------------------
2853      subroutine get1up (n,ja,ia,ju)
2854      integer  n, ja(*),ia(*),ju(*)
2855c----------------------------------------------------------------------
2856c obtains the first element of each row of the upper triangular part
2857c of a matrix. Assumes that the matrix is already sorted.
2858c-----------------------------------------------------------------------
2859c parameters
2860c input
2861c -----
2862c ja      = integer array containing the column indices of aij
2863c ia      = pointer array. ia(j) contains the position of the
2864c           beginning of row j in ja
2865c
2866c output
2867c ------
2868c ju      = integer array of length n. ju(i) is the address in ja
2869c           of the first element of the uper triangular part of
2870c           of A (including rthe diagonal. Thus if row i does have
2871c           a nonzero diagonal element then ju(i) will point to it.
2872c           This is a more general version of diapos.
2873c-----------------------------------------------------------------------
2874c local vAriables
2875      integer i, k
2876c
2877      do 5 i=1, n
2878         ju(i) = 0
2879         k = ia(i)
2880c
2881 1       continue
2882         if (ja(k) .ge. i) then
2883            ju(i) = k
2884            goto 5
2885         elseif (k .lt. ia(i+1) -1) then
2886            k=k+1
2887c
2888c go try next element in row
2889c
2890            goto 1
2891         endif
2892 5    continue
2893      return
2894c-----end-of-get1up-----------------------------------------------------
2895      end
2896
2897c----------------------------------------------------------------------
2898      subroutine xtrows (i1,i2,a,ja,ia,ao,jao,iao,iperm,job)
2899      integer i1,i2,ja(*),ia(*),jao(*),iao(*),iperm(*),job
2900      real*8 a(*),ao(*)
2901c-----------------------------------------------------------------------
2902c this subroutine extracts given rows from a matrix in CSR format.
2903c Specifically, rows number iperm(i1), iperm(i1+1), ...., iperm(i2)
2904c are extracted and put in the output matrix ao, jao, iao, in CSR
2905c format.  NOT in place.
2906c Youcef Saad -- coded Feb 15, 1992.
2907c-----------------------------------------------------------------------
2908c on entry:
2909c----------
2910c i1,i2   = two integers indicating the rows to be extracted.
2911c           xtrows will extract rows iperm(i1), iperm(i1+1),..,iperm(i2),
2912c           from original matrix and stack them in output matrix
2913c           ao, jao, iao in csr format
2914c
2915c a, ja, ia = input matrix in csr format
2916c
2917c iperm	= integer array of length nrow containing the reverse permutation
2918c         array for the rows. row number iperm(j) in permuted matrix PA
2919c         used to be row number j in unpermuted matrix.
2920c         ---> a(i,j) in the permuted matrix was a(iperm(i),j)
2921c         in the inout matrix.
2922c
2923c job	= integer indicating the work to be done:
2924c 		job .ne. 1 : get structure only of output matrix,,
2925c               i.e., ignore real values. (in which case arrays a
2926c               and ao are not used nor accessed).
2927c 		job = 1	get complete data structure of output matrix.
2928c               (i.e., including arrays ao and iao).
2929c------------
2930c on return:
2931c------------
2932c ao, jao, iao = input matrix in a, ja, ia format
2933c note :
2934c        if (job.ne.1)  then the arrays a and ao are not used.
2935c----------------------------------------------------------------------c
2936c           Y. Saad, revised May  2, 1990                              c
2937c----------------------------------------------------------------------c
2938      logical values
2939      values = (job .eq. 1)
2940c
2941c copying
2942c
2943      ko = 1
2944      iao(1) = ko
2945      do 100 j=i1,i2
2946c
2947c ii=iperm(j) is the index of old row to be copied.
2948c
2949         ii = iperm(j)
2950         do 60 k=ia(ii), ia(ii+1)-1
2951            jao(ko) = ja(k)
2952            if (values) ao(ko) = a(k)
2953            ko = ko+1
2954 60      continue
2955         iao(j-i1+2) = ko
2956 100  continue
2957c
2958      return
2959c---------end-of-xtrows-------------------------------------------------
2960c-----------------------------------------------------------------------
2961      end
2962c-----------------------------------------------------------------------
2963      subroutine csrkvstr(n, ia, ja, nr, kvstr)
2964c-----------------------------------------------------------------------
2965      integer n, ia(n+1), ja(*), nr, kvstr(*)
2966c-----------------------------------------------------------------------
2967c     Finds block row partitioning of matrix in CSR format.
2968c-----------------------------------------------------------------------
2969c     On entry:
2970c--------------
2971c     n       = number of matrix scalar rows
2972c     ia,ja   = input matrix sparsity structure in CSR format
2973c
2974c     On return:
2975c---------------
2976c     nr      = number of block rows
2977c     kvstr   = first row number for each block row
2978c
2979c     Notes:
2980c-----------
2981c     Assumes that the matrix is sorted by columns.
2982c     This routine does not need any workspace.
2983c
2984c-----------------------------------------------------------------------
2985c     local variables
2986      integer i, j, jdiff
2987c-----------------------------------------------------------------------
2988      nr = 1
2989      kvstr(1) = 1
2990c---------------------------------
2991      do i = 2, n
2992         jdiff = ia(i+1)-ia(i)
2993         if (jdiff .eq. ia(i)-ia(i-1)) then
2994            do j = ia(i), ia(i+1)-1
2995               if (ja(j) .ne. ja(j-jdiff)) then
2996                  nr = nr + 1
2997                  kvstr(nr) = i
2998                  goto 299
2999               endif
3000            enddo
3001 299        continue
3002         else
3003 300        nr = nr + 1
3004            kvstr(nr) = i
3005         endif
3006      enddo
3007      kvstr(nr+1) = n+1
3008c---------------------------------
3009      return
3010      end
3011c-----------------------------------------------------------------------
3012c------------------------end-of-csrkvstr--------------------------------
3013      subroutine csrkvstc(n, ia, ja, nc, kvstc, iwk)
3014c-----------------------------------------------------------------------
3015      integer n, ia(n+1), ja(*), nc, kvstc(*), iwk(*)
3016c-----------------------------------------------------------------------
3017c     Finds block column partitioning of matrix in CSR format.
3018c-----------------------------------------------------------------------
3019c     On entry:
3020c--------------
3021c     n       = number of matrix scalar rows
3022c     ia,ja   = input matrix sparsity structure in CSR format
3023c
3024c     On return:
3025c---------------
3026c     nc      = number of block columns
3027c     kvstc   = first column number for each block column
3028c
3029c     Work space:
3030c----------------
3031c     iwk(*) of size equal to the number of scalar columns plus one.
3032c        Assumed initialized to 0, and left initialized on return.
3033c
3034c     Notes:
3035c-----------
3036c     Assumes that the matrix is sorted by columns.
3037c
3038c-----------------------------------------------------------------------
3039c     local variables
3040      integer i, j, k, ncol
3041c
3042c-----------------------------------------------------------------------
3043
3044c-----use ncol to find maximum scalar column number
3045      ncol = 0
3046
3047c-----mark the beginning position of the blocks in iwk
3048      do i = 1, n
3049         if (ia(i) .lt. ia(i+1)) then
3050            j = ja(ia(i))
3051            iwk(j) = 1
3052            do k = ia(i)+1, ia(i+1)-1
3053               j = ja(k)
3054               if (ja(k-1).ne.j-1) then
3055                  iwk(j) = 1
3056                  iwk(ja(k-1)+1) = 1
3057               endif
3058            enddo
3059            iwk(j+1) = 1
3060            ncol = max0(ncol, j)
3061         endif
3062      enddo
3063c---------------------------------
3064      nc = 1
3065      kvstc(1) = 1
3066      do i = 2, ncol+1
3067         if (iwk(i).ne.0) then
3068            nc = nc + 1
3069            kvstc(nc) = i
3070            iwk(i) = 0
3071         endif
3072      enddo
3073      nc = nc - 1
3074c---------------------------------
3075      return
3076      end
3077c-----------------------------------------------------------------------
3078c------------------------end-of-csrkvstc--------------------------------
3079c-----------------------------------------------------------------------
3080      subroutine kvstmerge(nr, kvstr, nc, kvstc, n, kvst)
3081c-----------------------------------------------------------------------
3082      integer nr, kvstr(nr+1), nc, kvstc(nc+1), n, kvst(*)
3083c-----------------------------------------------------------------------
3084c     Merges block partitionings, for conformal row/col pattern.
3085c-----------------------------------------------------------------------
3086c     On entry:
3087c--------------
3088c     nr,nc   = matrix block row and block column dimension
3089c     kvstr   = first row number for each block row
3090c     kvstc   = first column number for each block column
3091c
3092c     On return:
3093c---------------
3094c     n       = conformal row/col matrix block dimension
3095c     kvst    = conformal row/col block partitioning
3096c
3097c     Notes:
3098c-----------
3099c     If matrix is not square, this routine returns without warning.
3100c
3101c-----------------------------------------------------------------------
3102c-----local variables
3103      integer i,j
3104c---------------------------------
3105
3106      if (kvstr(nr+1) .ne. kvstc(nc+1)) return
3107
3108      i = 1
3109      j = 1
3110      n = 1
3111  200 if (i .gt. nr+1) then
3112         kvst(n) = kvstc(j)
3113         j = j + 1
3114      elseif (j .gt. nc+1) then
3115         kvst(n) = kvstr(i)
3116         i = i + 1
3117      elseif (kvstc(j) .eq. kvstr(i)) then
3118         kvst(n) = kvstc(j)
3119         j = j + 1
3120         i = i + 1
3121      elseif (kvstc(j) .lt. kvstr(i)) then
3122         kvst(n) = kvstc(j)
3123         j = j + 1
3124      else
3125         kvst(n) = kvstr(i)
3126         i = i + 1
3127      endif
3128      n = n + 1
3129      if (i.le.nr+1 .or. j.le.nc+1) goto 200
3130      n = n - 2
3131c---------------------------------
3132      return
3133c------------------------end-of-kvstmerge-------------------------------
3134      end
3135