diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..d3daa1c5fd94e6453951c7bdd71c2c6acb14e180 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,110 @@ +FROM continuumio/anaconda:latest +MAINTAINER Pierre-Elouan Rethore <pe@retho.re> + +RUN apt-get update \ + && apt-get install -y \ + build-essential \ + gcc \ + gfortran \ + wget \ + binutils \ + gcc \ + libgtk2.0-0 \ + libgtk2.0-dev \ + psmisc + + + +RUN mkdir /install +WORKDIR /install + +#ENV REQUIREMENTS requirements1.txt +#ARG REQUIREMENTS + +# Install python library requirements to run the notebooks +COPY requirements2.txt /install +RUN pip install --upgrade pip \ + && pip install -r /install/requirements2.txt + +## Install PyOptSparse & IpOpt +RUN apt-get update \ + && apt-get install -y \ + mercurial \ + meld +RUN apt-get update \ + && apt-get install -y \ + swig + +ENV POSDIR /install/pyoptsparse +ENV IPV 3.11.7 +ENV IPOPT_DIR $POSDIR/pyoptsparse/pyIPOPT/Ipopt + + +RUN hg clone https://bitbucket.org/mdolab/pyoptsparse $POSDIR + +# Install Ipopt +COPY install_ipopt2.sh /install +COPY ma27ad.f /install +RUN /install/install_ipopt2.sh +ENV LD_LIBRARY_PATH $LD_LIBRARY_PATH:$IPOPT_DIR/lib + +# Install SNOPT +COPY snopt/* $POSDIR/pyoptsparse/pySNOPT/source/ + +## Install PyOptSparse +#COPY install_pyoptsparse.sh /install +WORKDIR $POSDIR +RUN python setup.py install + +#RUN mkdir /notebooks +#WORKDIR /notebooks + +#COPY mycert.pem /install/ +#COPY mykey.key /install/ +#COPY jupyter_notebook_config.py /install/ + +# Add Tini. Tini operates as a process subreaper for jupyter. This prevents +# kernel crashes. +#ENV TINI_VERSION v0.6.0 +#ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /usr/bin/tini +#RUN chmod +x /usr/bin/tini + + +# Install the Colonel + +RUN mkdir /deb +WORKDIR /deb +COPY *.deb /deb/ +RUN dpkg -i *.deb + +RUN apt-get clean \ + && apt-get autoremove -y + +RUN mkdir /install +WORKDIR /install +COPY fuga/*.pas /install/ +COPY fuga/*.lpr /install/ +COPY fuga/*.lpi /install/ + + +## Build +#RUN lazbuild ColonelLazarus.lpr + +#RUN curl -sL https://deb.nodesource.com/setup_8.x | bash - +#RUN apt-get update -y && apt-get install -y nodejs + + +#RUN jupyter labextension install @jupyter-widgets/jupyterlab-manager \ +# && jupyter labextension install jupyterlab_bokeh + +#ENTRYPOINT ["/usr/bin/tini", "--"] + + +#EXPOSE 8898 + +CMD bash + + # CMD jupyter notebook \ + # --notebook-dir=/notebooks \ + # --config=/install/jupyter_notebook_config.py \ + # --allow-root diff --git a/docker/fpc-src_3.0.4-2_amd64.deb b/docker/fpc-src_3.0.4-2_amd64.deb new file mode 100644 index 0000000000000000000000000000000000000000..0c121d0fa64ace642134c8559cce2c341eb9e6a8 Binary files /dev/null and b/docker/fpc-src_3.0.4-2_amd64.deb differ diff --git a/docker/fpc_3.0.4-2_amd64.deb b/docker/fpc_3.0.4-2_amd64.deb new file mode 100644 index 0000000000000000000000000000000000000000..986469225241e34ee0228b4d60c5d6eef6cbe4c1 Binary files /dev/null and b/docker/fpc_3.0.4-2_amd64.deb differ diff --git a/docker/install_ipopt2.sh b/docker/install_ipopt2.sh new file mode 100755 index 0000000000000000000000000000000000000000..6ae360eb659aa76acde920f229863cc4ef6eb027 --- /dev/null +++ b/docker/install_ipopt2.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +curl https://www.coin-or.org/download/source/Ipopt/Ipopt-$IPV.tgz > /install/Ipopt-$IPV.tgz +cd /install +tar xvf Ipopt-$IPV.tgz +mv Ipopt-$IPV $IPOPT_DIR +cp /install/ma27ad.f $IPOPT_DIR/ThirdParty/HSLold/ +cd $IPOPT_DIR/ThirdParty/Blas +sh ./get.Blas +cd $IPOPT_DIR/ThirdParty/Lapack +sh ./get.Lapack +cd $IPOPT_DIR +./configure --disable-linear-solver-loader +make install diff --git a/docker/ma27ad.f b/docker/ma27ad.f new file mode 100644 index 0000000000000000000000000000000000000000..d5ea17a9f3757eea3052dc806463b884ffc230aa --- /dev/null +++ b/docker/ma27ad.f @@ -0,0 +1,3496 @@ +* COPYRIGHT (c) 1982 AEA Technology +*######DATE 20 September 2001 +C September 2001: threadsafe version of MA27 +C 19/3/03. Array ICNTL in MA27GD made assumed size. +C 17/9/09. Bug corrected in MA27HD. Also some tidying of code in +C MA27HD and change of most comments to lower case. +C 16/6/10. Statement function in MA27OD replaced by in-line code. + + SUBROUTINE MA27ID(ICNTL,CNTL) + INTEGER ICNTL(30) + DOUBLE PRECISION CNTL(5) + + INTEGER IFRLVL + PARAMETER ( IFRLVL=5 ) + +C Stream number for error messages + ICNTL(1) = 6 +C Stream number for diagnostic messages + ICNTL(2) = 6 +C Control the level of diagnostic printing. +C 0 no printing +C 1 printing of scalar parameters and first parts of arrays. +C 2 printing of scalar parameters and whole of arrays. + ICNTL(3) = 0 +C The largest integer such that all integers I in the range +C -ICNTL(4).LE.I.LE.ICNTL(4) can be handled by the shortest integer +C type in use. + ICNTL(4) = 2139062143 +C Minimum number of eliminations in a step that is automatically +C accepted. if two adjacent steps can be combined and each has less +C eliminations then they are combined. + ICNTL(5) = 1 +C Control whether direct or indirect access is used by MA27C/CD. +C Indirect access is employed in forward and back substitution +C respectively if the size of a block is less than +C ICNTL(IFRLVL+MIN(10,NPIV)) and ICNTL(IFRLVL+10+MIN(10,NPIV)) +C respectively, where NPIV is the number of pivots in the block. + ICNTL(IFRLVL+1) = 32639 + ICNTL(IFRLVL+2) = 32639 + ICNTL(IFRLVL+3) = 32639 + ICNTL(IFRLVL+4) = 32639 + ICNTL(IFRLVL+5) = 14 + ICNTL(IFRLVL+6) = 9 + ICNTL(IFRLVL+7) = 8 + ICNTL(IFRLVL+8) = 8 + ICNTL(IFRLVL+9) = 9 + ICNTL(IFRLVL+10) = 10 + ICNTL(IFRLVL+11) = 32639 + ICNTL(IFRLVL+12) = 32639 + ICNTL(IFRLVL+13) = 32639 + ICNTL(IFRLVL+14) = 32689 + ICNTL(IFRLVL+15) = 24 + ICNTL(IFRLVL+16) = 11 + ICNTL(IFRLVL+17) = 9 + ICNTL(IFRLVL+18) = 8 + ICNTL(IFRLVL+19) = 9 + ICNTL(IFRLVL+20) = 10 +C Not used + ICNTL(26) = 0 + ICNTL(27) = 0 + ICNTL(28) = 0 + ICNTL(29) = 0 + ICNTL(30) = 0 + +C Control threshold pivoting. + CNTL(1) = 0.1D0 +C If a column of the reduced matrix has relative density greater than +C CNTL(2), it is forced into the root. All such columns are taken to +C have sparsity pattern equal to their merged patterns, so the fill +C and operation counts may be overestimated. + CNTL(2) = 1.0D0 +C An entry with absolute value less than CNTL(3) is never accepted as +C a 1x1 pivot or as the off-diagonal of a 2x2 pivot. + CNTL(3) = 0.0D0 +C Not used + CNTL(4) = 0.0 + CNTL(5) = 0.0 + + RETURN + END + + SUBROUTINE MA27AD(N,NZ,IRN,ICN,IW,LIW,IKEEP,IW1,NSTEPS,IFLAG, + + ICNTL,CNTL,INFO,OPS) +C THIS SUBROUTINE COMPUTES A MINIMUM DEGREE ORDERING OR ACCEPTS A GIVEN +C ORDERING. IT COMPUTES ASSOCIATED ASSEMBLY AND ELIMINATION +C INFORMATION FOR MA27B/BD. +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C NZ MUST BE SET TO THE NUMBER OF NON-ZEROS INPUT. IT IS NOT +C ALTERED. +C IRN(I),I=1,2,...,NZ MUST BE SET TO THE ROW NUMBERS OF THE +C NON-ZEROS. IT IS NOT ALTERED UNLESS IT IS EQUIVALENCED +C TO IW (SEE DESCRIPTION OF IW). +C ICN(I),I=1,2,...,NZ MUST BE SET TO THE COLUMN NUMBERS OF THE +C NON-ZEROS. IT IS NOT ALTERED UNLESS IT IS EQUIVALENCED +C TO IW (SEE DESCRIPTION OF IW). +C IW NEED NOT BE SET ON INPUT. IT IS USED FOR WORKSPACE. +C IRN(1) MAY BE EQUIVALENCED TO IW(1) AND ICN(1) MAY BE +C EQUIVALENCED TO IW(K), WHERE K.GT.NZ. +C LIW MUST BE SET TO THE LENGTH OF IW. IT MUST BE AT LEAST 2*NZ+3*N +C FOR THE IFLAG=0 ENTRY AND AT LEAST NZ+3*N FOR THE IFLAG=1 +C ENTRY. IT IS NOT ALTERED. +C IKEEP NEED NOT BE SET UNLESS AN ORDERING IS GIVEN, IN WHICH CASE +C IKEEP(I,1) MUST BE SET TO THE POSITION OF VARIABLE I IN THE +C ORDER. ON OUTPUT IKEEP CONTAINS INFORMATION NEEDED BY MA27B/BD. +C IKEEP(I,1) HOLDS THE POSITION OF VARIABLE I IN THE PIVOT ORDER. +C IKEEP(I,2), IKEEP(I,3) HOLD THE NUMBER OF ELIMINATIONS, ASSEMBLIES +C AT MAJOR STEP I, I=1,2,...,NSTEPS. NOTE THAT WHEN AN ORDER IS +C GIVEN IT MAY BE REPLACED BY ANOTHER ORDER THAT GIVES IDENTICAL +C NUMERICAL RESULTS. +C IW1 IS USED FOR WORKSPACE. +C NSTEPS NEED NOT BE SET. ON OUTPUT IT CONTAINS THE NUMBER OF MAJOR +C STEPS NEEDED FOR A DEFINITE MATRIX AND MUST BE PASSED UNCHANGED +C TO MA27B/BD. +C IFLAG MUST SET TO ZERO IF THE USER WANTS THE PIVOT ORDER CHOSEN +C AUTOMATICALLY AND TO ONE IF HE WANTS TO SPECIFY IT IN IKEEP. +C ICNTL is an INTEGER array of length 30 containing user options +C with integer values (defaults set in MA27I/ID) +C ICNTL(1) (LP) MUST BE SET TO THE STREAM NUMBER FOR ERROR MESSAGES. +C ERROR MESSAGES ARE SUPPRESSED IF ICNTL(1) IS NOT POSITIVE. +C IT IS NOT ALTERED. +C ICNTL(2) (MP) MUST BE SET TO THE STREAM NUMBER FOR DIAGNOSTIC +C MESSAGES. DIAGNOSTIC MESSAGES ARE SUPPRESSED IF ICNTL(2) IS NOT +C POSITIVE. IT IS NOT ALTERED. +C ICNTL(3) (LDIAG) CONTROLS THE LEVEL OF DIAGNOSTIC PRINTING. +C 0 NO PRINTING +C 1 PRINTING OF SCALAR PARAMETERS AND FIRST PARTS OF ARRAYS. +C 2 PRINTING OF SCALAR PARAMETERS AND WHOLE OF ARRAYS. +C ICNTL(4) (IOVFLO) IS THE LARGEST INTEGER SUCH THAT ALL INTEGERS +C I IN THE RANGE -IOVFLO.LE.I.LE.IOVFLO CAN BE HANDLED BY THE +C SHORTEST INTEGER TYPE IN USE. +C ICNT(5) (NEMIN) MUST BE SET TO THE MINIMUM NUMBER OF ELIMINATIONS +C IN A STEP THAT IS AUTOMATICALLY ACCEPTED. IF TWO ADJACENT STEPS +C CAN BE COMBINED AND EACH HAS LESS ELIMINATIONS THEN THEY ARE +C COMBINED. +C ICNTL(IFRLVL+I) I=1,20, (IFRLVL) MUST BE SET TO CONTROL WHETHER +C DIRECT OR INDIRECT ACCESS IS USED BY MA27C/CD. INDIRECT ACCESS +C IS EMPLOYED IN FORWARD AND BACK SUBSTITUTION RESPECTIVELY IF THE +C SIZE OF A BLOCK IS LESS THAN ICNTL(IFRLVL+(MIN(10,NPIV)) AND +C ICNTL(IFRLVL+10+MIN(10,NPIV)) RESPECTIVELY, WHERE NPIV IS THE +C NUMBER OF PIVOTS IN THE BLOCK. +C ICNTL(I) I=26,30 are not used. +C CNTL is an DOUBLE PRECISION array of length 5 containing user options +C with real values (defaults set in MA27I/ID) +C CNTL(1) (U) IS USED TO CONTROL THRESHOLD PIVOTING. IT IS NOT +C ALTERED. +C CNTL(2) (FRATIO) has default value 1.0. If a column of the +C reduced matrix has relative density greater than CNTL(2), it +C is forced into the root. All such columns are taken to have +C sparsity pattern equal to their merged patterns, so the fill +C and operation counts may be overestimated. +C CNTL(3) (PIVTOL) has default value 0.0. An entry with absolute +C value less than CNTL(3) is never accepted as a 1x1 pivot or +C as the off-diagonal of a 2x2 pivot. +C CNTL(I) I=4,5 are not used. +C INFO is an INTEGER array of length 20 which is used to return +C information to the user. +C INFO(1) (IFLAG) is an error return code, zero for success, greater +C than zero for a warning and less than zero for errors, see +C INFO(2). +C INFO(2) (IERROR) HOLDS ADDITIONAL INFORMATION IN THE EVENT OF ERRORS. +C IF INFO(1)=-3 INFO(2) HOLDS A LENGTH THAT MAY SUFFICE FOR IW. +C IF INFO(1)=-4 INFO(2) HOLDS A LENGTH THAT MAY SUFFICE FOR A. +C IF INFO(1)=-5 INFO(2) IS SET TO THE PIVOT STEP AT WHICH SINGULARITY +C WAS DETECTED. +C IF INFO(1)=-6 INFO(2) IS SET TO THE PIVOT STEP AT WHICH A CHANGE OF +C PIVOT SIGN WAS FOUND. +C IF INFO(1)= 1 INFO(2) HOLDS THE NUMBER OF FAULTY ENTRIES. +C IF INFO(1)= 2 INFO(2) IS SET TO THE NUMBER OF SIGNS CHANGES IN +C THE PIVOTS. +C IF INFO(1)=3 INFO(2) IS SET TO THE RANK OF THE MATRIX. +C INFO(3) and INFO(4) (NRLTOT and NIRTOT) REAL AND INTEGER STRORAGE +C RESPECTIVELY REQUIRED FOR THE FACTORIZATION IF NO COMPRESSES ARE +C ALLOWED. +C INFO(5) and INFO(6) (NRLNEC and NIRNEC) REAL AND INTEGER STORAGE +C RESPECTIVELY REQUIRED FOR THE FACTORIZATION IF COMPRESSES ARE +C ALLOWED AND THE MATRIX IS DEFINITE. +C INFO(7) and INFO(8) (NRLADU and NIRADU) REAL AND INTEGER STORAGE +C RESPECTIVELY FOR THE MATRIX FACTORS AS CALCULATED BY MA27A/AD +C FOR THE DEFINITE CASE. +C INFO(9) and INFO(10) (NRLBDU and NIRBDU) REAL AND INTEGER STORAGE +C RESPECTIVELY FOR THE MATRIX FACTORS AS FOUND BY MA27B/BD. +C INFO(11) (NCMPA) ACCUMULATES THE NUMBER OF TIMES THE ARRAY IW IS +C COMPRESSED BY MA27A/AD. +C INFO(12) and INFO(13) (NCMPBR and NCMPBI) ACCUMULATE THE NUMBER +C OF COMPRESSES OF THE REALS AND INTEGERS PERFORMED BY MA27B/BD. +C INFO(14) (NTWO) IS USED BY MA27B/BD TO RECORD THE NUMBER OF 2*2 +C PIVOTS USED. +C INFO(15) (NEIG) IS USED BY ME27B/BD TO RECORD THE NUMBER OF +C NEGATIVE EIGENVALUES OF A. +C INFO(16) to INFO(20) are not used. +C OPS ACCUMULATES THE NO. OF MULTIPLY/ADD PAIRS NEEDED TO CREATE THE +C TRIANGULAR FACTORIZATION, IN THE DEFINITE CASE. +C +C .. Scalar Arguments .. + INTEGER IFLAG,LIW,N,NSTEPS,NZ +C .. +C .. Array Arguments .. + DOUBLE PRECISION CNTL(5),OPS + INTEGER ICNTL(30),INFO(20) + INTEGER ICN(*),IKEEP(N,3),IRN(*),IW(LIW),IW1(N,2) +C .. +C .. Local Scalars .. + INTEGER I,IWFR,K,L1,L2,LLIW +C .. +C .. External Subroutines .. + EXTERNAL MA27GD,MA27HD,MA27JD,MA27KD,MA27LD,MA27MD,MA27UD +C .. +C .. Intrinsic Functions .. + INTRINSIC MIN +C .. +C .. Executable Statements .. + DO 5 I = 1,15 + INFO(I) = 0 + 5 CONTINUE + + IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0) GO TO 40 +C PRINT INPUT VARIABLES. + WRITE (ICNTL(2),FMT=10) N,NZ,LIW,IFLAG + + 10 FORMAT(/,/,' ENTERING MA27AD WITH N NZ LIW IFLAG', + + /,21X,I7,I7,I9,I7) + + NSTEPS = 0 + K = MIN(8,NZ) + IF (ICNTL(3).GT.1) K = NZ + IF (K.GT.0) WRITE (ICNTL(2),FMT=20) (IRN(I),ICN(I),I=1,K) + + 20 FORMAT (' MATRIX NON-ZEROS',/,4 (I9,I6),/, + + (I9,I6,I9,I6,I9,I6,I9,I6)) + + K = MIN(10,N) + IF (ICNTL(3).GT.1) K = N + IF (IFLAG.EQ.1 .AND. K.GT.0) THEN + WRITE (ICNTL(2),FMT=30) (IKEEP(I,1),I=1,K) + END IF + + 30 FORMAT (' IKEEP(.,1)=',10I6,/, (12X,10I6)) + + 40 IF (N.LT.1 .OR. N.GT.ICNTL(4)) GO TO 70 + IF (NZ.LT.0) GO TO 100 + LLIW = LIW - 2*N + L1 = LLIW + 1 + L2 = L1 + N + IF (IFLAG.EQ.1) GO TO 50 + IF (LIW.LT.2*NZ+3*N+1) GO TO 130 +C SORT + CALL MA27GD(N,NZ,IRN,ICN,IW,LLIW,IW1,IW1(1,2),IW(L1),IWFR, + + ICNTL,INFO) +C ANALYZE USING MINIMUM DEGREE ORDERING + CALL MA27HD(N,IW1,IW,LLIW,IWFR,IW(L1),IW(L2),IKEEP(1,2), + + IKEEP(1,3),IKEEP,ICNTL(4),INFO(11),CNTL(2)) + GO TO 60 +C SORT USING GIVEN ORDER + 50 IF (LIW.LT.NZ+3*N+1) GO TO 120 + CALL MA27JD(N,NZ,IRN,ICN,IKEEP,IW,LLIW,IW1,IW1(1,2),IW(L1),IWFR, + + ICNTL,INFO) +C ANALYZE USING GIVEN ORDER + CALL MA27KD(N,IW1,IW,LLIW,IWFR,IKEEP,IKEEP(1,2),IW(L1),IW(L2), + + INFO(11)) +C PERFORM DEPTH-FIRST SEARCH OF ASSEMBLY TREE + 60 CALL MA27LD(N,IW1,IW(L1),IKEEP,IKEEP(1,2),IKEEP(1,3),IW(L2), + + NSTEPS,ICNTL(5)) +C EVALUATE STORAGE AND OPERATION COUNT REQUIRED BY MA27B/BD IN THE +C DEFINITE CASE. +C SET IW(1) SO THAT ARRAYS IW AND IRN CAN BE TESTED FOR EQUIVALENCE +C IN MA27M/MD. + IF(NZ.GE.1) IW(1) = IRN(1) + 1 + CALL MA27MD(N,NZ,IRN,ICN,IKEEP,IKEEP(1,3),IKEEP(1,2),IW(L2), + + NSTEPS,IW1,IW1(1,2),IW,INFO,OPS) + GO TO 160 + + 70 INFO(1) = -1 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + + 80 FORMAT (' **** ERROR RETURN FROM MA27AD **** INFO(1)=',I3) + + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=90) N + + 90 FORMAT (' VALUE OF N OUT OF RANGE ... =',I10) + + GO TO 160 + + 100 INFO(1) = -2 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=110) NZ + + 110 FORMAT (' VALUE OF NZ OUT OF RANGE .. =',I10) + + GO TO 160 + + 120 INFO(2) = NZ + 3*N + 1 + GO TO 140 + + 130 INFO(2) = 2*NZ + 3*N + 1 + 140 INFO(1) = -3 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=150) LIW,INFO(2) + + 150 FORMAT (' LIW TOO SMALL, MUST BE INCREASED FROM',I10, + + ' TO AT LEAST',I10) + + 160 IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0 .OR. INFO(1).LT.0) GO TO 200 +C PRINT PARAMETER VALUES ON EXIT. + WRITE (ICNTL(2),FMT=170) NSTEPS,INFO(1),OPS,INFO(2),INFO(3), + + INFO(4),INFO(5),INFO(6),INFO(7),INFO(8),INFO(11) + + 170 FORMAT (/,' LEAVING MA27AD WITH NSTEPS INFO(1) OPS IERROR', + + ' NRLTOT NIRTOT', + + /,20X,2I7,F7.0,3I7, + + /,20X,' NRLNEC NIRNEC NRLADU NIRADU NCMPA', + + /,20X,6I7) + + K = MIN(9,N) + IF (ICNTL(3).GT.1) K = N + IF (K.GT.0) WRITE (ICNTL(2),FMT=30) (IKEEP(I,1),I=1,K) + K = MIN(K,NSTEPS) + IF (K.GT.0) WRITE (ICNTL(2),FMT=180) (IKEEP(I,2),I=1,K) + + 180 FORMAT (' IKEEP(.,2)=',10I6,/, (12X,10I6)) + + IF (K.GT.0) WRITE (ICNTL(2),FMT=190) (IKEEP(I,3),I=1,K) + + 190 FORMAT (' IKEEP(.,3)=',10I6,/, (12X,10I6)) + + 200 CONTINUE + + RETURN + END + + SUBROUTINE MA27BD(N,NZ,IRN,ICN,A,LA,IW,LIW,IKEEP,NSTEPS,MAXFRT, + + IW1,ICNTL,CNTL,INFO) +C THIS SUBROUTINE COMPUTES THE FACTORISATION OF THE MATRIX INPUT IN +C A,IRN,ICN USING INFORMATION (IN IKEEP) FROM MA27A/AD. +C N MUST BE SET TO THE ORDER OF THE MATRIX. IT IS NOT ALTERED. +C NZ MUST BE SET TO THE NUMBER OF NON-ZEROS INPUT. IT IS NOT +C ALTERED. +C IRN,ICN,A. ENTRY K (K=1,NZ) OF IRN,ICN MUST BE SET TO THE ROW +C AND COLUMN INDEX RESPECTIVELY OF THE NON-ZERO IN A. +C IRN AND ICN ARE UNALTERED BY MA27B/BD. +C ON EXIT, ENTRIES 1 TO NRLBDU OF A HOLD REAL INFORMATION +C ON THE FACTORS AND SHOULD BE PASSED UNCHANGED TO MA27C/CD. +C LA LENGTH OF ARRAY A. AN INDICATION OF A SUITABLE VALUE, +C SUFFICIENT FOR FACTORIZATION OF A DEFINITE MATRIX, WILL +C HAVE BEEN PROVIDED IN NRLNEC AND NRLTOT BY MA27A/AD. +C IT IS NOT ALTERED BY MA27B/BD. +C IW NEED NOT BE SET ON ENTRY. USED AS A WORK ARRAY BY MA27B/BD. +C ON EXIT, ENTRIES 1 TO NIRBDU HOLD INTEGER INFORMATION ON THE +C FACTORS AND SHOULD BE PASSED UNCHANGED TO MA27C/CD. +C LIW LENGTH OF ARRAY IW. AN INDICATION OF A SUITABLE VALUE WILL +C HAVE BEEN PROVIDED IN NIRNEC AND NIRTOT BY MA27A/AD. +C IT IS NOT ALTERED BY MA27B/BD. +C IKEEP MUST BE UNCHANGED SINCE THE CALL TO MA27A/AD. +C IT IS NOT ALTERED BY MA27B/BD. +C NSTEPS MUST BE UNCHANGED SINCE THE CALL TO MA27A/AD. +C IT IS NOT ALTERED BY MA27B/BD. +C MAXFRT NEED NOT BE SET AND MUST BE PASSED UNCHANGED TO MA27C/CD. +C IT IS THE MAXIMUM SIZE OF THE FRONTAL MATRIX GENERATED DURING +C THE DECOMPOSITION. +C IW1 USED AS WORKSPACE BY MA27B/BD. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C CNTL is a DOUBLE PRECISION array of length 5, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER LA,LIW,MAXFRT,N,NSTEPS,NZ +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA),CNTL(5) + INTEGER ICN(*),IKEEP(N,3),IRN(*),IW(LIW),IW1(N) + INTEGER ICNTL(30),INFO(20) +C .. +C .. Local Scalars .. + INTEGER I,IAPOS,IBLK,IPOS,IROWS,J1,J2,JJ,K,KBLK,KZ,LEN,NCOLS, + + NROWS,NZ1 +C .. +C .. External Subroutines .. + EXTERNAL MA27ND,MA27OD +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MIN +C .. +C .. Executable Statements .. + INFO(1) = 0 + + IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0) GO TO 60 +C PRINT INPUT PARAMETERS. + WRITE (ICNTL(2),FMT=10) N,NZ,LA,LIW,NSTEPS,CNTL(1) + + 10 FORMAT (/,/, + + ' ENTERING MA27BD WITH N NZ LA LIW', + + ' NSTEPS U',/,21X,I7,I7,I9,I9,I7,1PD10.2) + + KZ = MIN(6,NZ) + IF (ICNTL(3).GT.1) KZ = NZ + IF (NZ.GT.0) WRITE (ICNTL(2),FMT=20) (A(K),IRN(K),ICN(K),K=1,KZ) + + 20 FORMAT (' MATRIX NON-ZEROS',/,1X,2 (1P,D16.3,2I6),/, + + (1X,1P,D16.3,2I6,1P,D16.3,2I6)) + + K = MIN(9,N) + IF (ICNTL(3).GT.1) K = N + IF (K.GT.0) WRITE (ICNTL(2),FMT=30) (IKEEP(I,1),I=1,K) + + 30 FORMAT (' IKEEP(.,1)=',10I6,/, (12X,10I6)) + + K = MIN(K,NSTEPS) + IF (K.GT.0) WRITE (ICNTL(2),FMT=40) (IKEEP(I,2),I=1,K) + + 40 FORMAT (' IKEEP(.,2)=',10I6,/, (12X,10I6)) + + IF (K.GT.0) WRITE (ICNTL(2),FMT=50) (IKEEP(I,3),I=1,K) + + 50 FORMAT (' IKEEP(.,3)=',10I6,/, (12X,10I6)) + + 60 IF (N.LT.1 .OR. N.GT.ICNTL(4)) GO TO 70 + IF (NZ.LT.0) GO TO 100 + IF (LIW.LT.NZ) GO TO 120 + IF (LA.LT.NZ+N) GO TO 150 + IF (NSTEPS.LT.1 .OR. NSTEPS.GT.N) GO TO 175 +C SORT + CALL MA27ND(N,NZ,NZ1,A,LA,IRN,ICN,IW,LIW,IKEEP,IW1,ICNTL,INFO) + IF (INFO(1).EQ.-3) GO TO 130 + IF (INFO(1).EQ.-4) GO TO 160 +C FACTORIZE + CALL MA27OD(N,NZ1,A,LA,IW,LIW,IKEEP,IKEEP(1,3),NSTEPS,MAXFRT, + + IKEEP(1,2),IW1,ICNTL,CNTL,INFO) + IF (INFO(1).EQ.-3) GO TO 130 + IF (INFO(1).EQ.-4) GO TO 160 + IF (INFO(1).EQ.-5) GO TO 180 + IF (INFO(1).EQ.-6) GO TO 200 +C **** WARNING MESSAGE **** + IF (INFO(1).EQ.3 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=65) INFO(1),INFO(2) + END IF + + 65 FORMAT (' *** WARNING MESSAGE FROM SUBROUTINE MA27BD', + + ' *** INFO(1) =',I2, + + /,5X,'MATRIX IS SINGULAR. RANK=',I5) + + GO TO 220 +C **** ERROR RETURNS **** + 70 INFO(1) = -1 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + + 80 FORMAT (' **** ERROR RETURN FROM MA27BD **** INFO(1)=',I3) + + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=90) N + + 90 FORMAT (' VALUE OF N OUT OF RANGE ... =',I10) + + GO TO 220 + + 100 INFO(1) = -2 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=110) NZ + + 110 FORMAT (' VALUE OF NZ OUT OF RANGE .. =',I10) + + GO TO 220 + + 120 INFO(1) = -3 + INFO(2) = NZ + 130 IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=140) LIW,INFO(2) + + 140 FORMAT (' LIW TOO SMALL, MUST BE INCREASED FROM',I10,' TO', + + ' AT LEAST',I10) + + GO TO 220 + + 150 INFO(1) = -4 + INFO(2) = NZ + N + 160 IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=170) LA,INFO(2) + + 170 FORMAT (' LA TOO SMALL, MUST BE INCREASED FROM ',I10,' TO', + + ' AT LEAST',I10) + + GO TO 220 + + 175 INFO(1) = -7 + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) THEN + WRITE (ICNTL(1),FMT='(A)') ' NSTEPS is out of range' + END IF + GO TO 220 + + 180 IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=190) INFO(2) + + 190 FORMAT (' ZERO PIVOT AT STAGE',I10, + + ' WHEN INPUT MATRIX DECLARED DEFINITE') + + GO TO 220 + + 200 IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=80) INFO(1) + IF (ICNTL(1).GT.0) WRITE (ICNTL(1),FMT=210) + + 210 FORMAT (' CHANGE IN SIGN OF PIVOT ENCOUNTERED', + + ' WHEN FACTORING ALLEGEDLY DEFINITE MATRIX') + + 220 IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0 .OR. INFO(1).LT.0) GO TO 310 +C PRINT OUTPUT PARAMETERS. + WRITE (ICNTL(2),FMT=230) MAXFRT,INFO(1),INFO(9),INFO(10),INFO(12), + + INFO(13),INFO(14),INFO(2) + + 230 FORMAT (/,' LEAVING MA27BD WITH', + + /,10X,' MAXFRT INFO(1) NRLBDU NIRBDU NCMPBR', + + ' NCMPBI NTWO IERROR', + + /,11X,8I7) + + IF (INFO(1).LT.0) GO TO 310 +C PRINT OUT MATRIX FACTORS FROM MA27B/BD. + KBLK = ABS(IW(1)+0) + IF (KBLK.EQ.0) GO TO 310 + IF (ICNTL(3).EQ.1) KBLK = 1 + IPOS = 2 + IAPOS = 1 + DO 300 IBLK = 1,KBLK + NCOLS = IW(IPOS) + NROWS = IW(IPOS+1) + J1 = IPOS + 2 + IF (NCOLS.GT.0) GO TO 240 + NCOLS = -NCOLS + NROWS = 1 + J1 = J1 - 1 + 240 WRITE (ICNTL(2),FMT=250) IBLK,NROWS,NCOLS + + 250 FORMAT (' BLOCK PIVOT =',I8,' NROWS =',I8,' NCOLS =',I8) + + J2 = J1 + NCOLS - 1 + IPOS = J2 + 1 + WRITE (ICNTL(2),FMT=260) (IW(JJ),JJ=J1,J2) + + 260 FORMAT (' COLUMN INDICES =',10I6,/, (17X,10I6)) + + WRITE (ICNTL(2),FMT=270) + + 270 FORMAT (' REAL ENTRIES .. EACH ROW STARTS ON A NEW LINE') + + LEN = NCOLS + DO 290 IROWS = 1,NROWS + J1 = IAPOS + J2 = IAPOS + LEN - 1 + WRITE (ICNTL(2),FMT=280) (A(JJ),JJ=J1,J2) + + 280 FORMAT (1P,5D13.3) + + LEN = LEN - 1 + IAPOS = J2 + 1 + 290 CONTINUE + 300 CONTINUE + 310 RETURN + END + + SUBROUTINE MA27CD(N,A,LA,IW,LIW,W,MAXFRT,RHS,IW1,NSTEPS, + + ICNTL,INFO) +C THIS SUBROUTINE USES THE FACTORISATION OF THE MATRIX IN A,IW TO +C SOLVE A SYSTEM OF EQUATIONS. +C N MUST BE SET TO THE ORDER OF THE MATRIX. IT IS NOT ALTERED. +C A,IW HOLD INFORMATION ON THE FACTORS AND MUST BE UNCHANGED SINCE +C THE CALL TO MA27B/BD. THEY ARE NOT ALTERED BY MA27C/CDD. +C LA,LIW MUST BE SET TO THE LENGTHS OF A,IW RESPECTIVELY. THEY +C ARE NOT ALTERED. +C W USED AS A WORK ARRAY. +C MAXFRT IS THE LENGTH OF W AND MUST BE PASSED UNCHANGED FROM THE +C CALL TO MA27B/BD. IT IS NOT ALTERED. +C RHS MUST BE SET TO THE RIGHT HAND SIDE FOR THE EQUATIONS BEING +C SOLVED. ON EXIT, THIS ARRAY WILL HOLD THE SOLUTION. +C IW1 USED AS A WORK ARRAY. +C NSTEPS IS THE LENGTH OF IW1 WHICH MUST BE AT LEAST THE ABSOLUTE +C VALUE OF IW(1). IT IS NOT ALTERED. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER LA,LIW,MAXFRT,N,NSTEPS +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA),RHS(N),W(MAXFRT) + INTEGER IW(LIW),IW1(NSTEPS),ICNTL(30),INFO(20) +C .. +C .. Local Scalars .. + INTEGER I,IAPOS,IBLK,IPOS,IROWS,J1,J2,JJ,K,KBLK,LATOP,LEN,NBLK, + + NCOLS,NROWS +C .. +C .. External Subroutines .. + EXTERNAL MA27QD,MA27RD +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MIN +C .. +C .. Executable Statements .. + INFO(1) = 0 + + IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0) GO TO 110 +C PRINT INPUT PARAMETERS. + WRITE (ICNTL(2),FMT=10) N,LA,LIW,MAXFRT,NSTEPS + + 10 FORMAT (/,/,' ENTERING MA27CD WITH N LA LIW MAXFRT', + + ' NSTEPS',/,21X,5I7) +C PRINT OUT MATRIX FACTORS FROM MA27B/BD. + KBLK = ABS(IW(1)+0) + IF (KBLK.EQ.0) GO TO 90 + IF (ICNTL(3).EQ.1) KBLK = 1 + IPOS = 2 + IAPOS = 1 + DO 80 IBLK = 1,KBLK + NCOLS = IW(IPOS) + NROWS = IW(IPOS+1) + J1 = IPOS + 2 + IF (NCOLS.GT.0) GO TO 20 + NCOLS = -NCOLS + NROWS = 1 + J1 = J1 - 1 + 20 WRITE (ICNTL(2),FMT=30) IBLK,NROWS,NCOLS + + 30 FORMAT (' BLOCK PIVOT =',I8,' NROWS =',I8,' NCOLS =',I8) + + J2 = J1 + NCOLS - 1 + IPOS = J2 + 1 + WRITE (ICNTL(2),FMT=40) (IW(JJ),JJ=J1,J2) + + 40 FORMAT (' COLUMN INDICES =',10I6,/, (17X,10I6)) + + WRITE (ICNTL(2),FMT=50) + + 50 FORMAT (' REAL ENTRIES .. EACH ROW STARTS ON A NEW LINE') + + LEN = NCOLS + DO 70 IROWS = 1,NROWS + J1 = IAPOS + J2 = IAPOS + LEN - 1 + WRITE (ICNTL(2),FMT=60) (A(JJ),JJ=J1,J2) + + 60 FORMAT (1P,5D13.3) + + LEN = LEN - 1 + IAPOS = J2 + 1 + 70 CONTINUE + 80 CONTINUE + 90 K = MIN(10,N) + IF (ICNTL(3).GT.1) K = N + IF (N.GT.0) WRITE (ICNTL(2),FMT=100) (RHS(I),I=1,K) + + 100 FORMAT (' RHS',1P,5D13.3,/, (4X,1P,5D13.3)) + + 110 IF (IW(1).LT.0) GO TO 130 + NBLK = IW(1) + IF (NBLK.GT.0) GO TO 140 +C WE HAVE A ZERO MATRIX + DO 120 I = 1,N + RHS(I) = 0.0D0 + 120 CONTINUE + GO TO 150 + + 130 NBLK = -IW(1) +C FORWARD SUBSTITUTION + 140 CALL MA27QD(N,A,LA,IW(2),LIW-1,W,MAXFRT,RHS,IW1,NBLK,LATOP,ICNTL) +C BACK SUBSTITUTION. + CALL MA27RD(N,A,LA,IW(2),LIW-1,W,MAXFRT,RHS,IW1,NBLK,LATOP,ICNTL) + 150 IF (ICNTL(3).LE.0 .OR. ICNTL(2).LE.0) GO TO 170 +C PRINT OUTPUT PARAMETERS. + WRITE (ICNTL(2),FMT=160) + + 160 FORMAT (/,/,' LEAVING MA27CD WITH') + + IF (N.GT.0) WRITE (ICNTL(2),FMT=100) (RHS(I),I=1,K) + 170 CONTINUE + + RETURN + END + SUBROUTINE MA27GD(N,NZ,IRN,ICN,IW,LW,IPE,IQ,FLAG,IWFR, + + ICNTL,INFO) +C +C SORT PRIOR TO CALLING ANALYSIS ROUTINE MA27H/HD. +C +C GIVEN THE POSITIONS OF THE OFF-DIAGONAL NON-ZEROS OF A SYMMETRIC +C MATRIX, CONSTRUCT THE SPARSITY PATTERN OF THE OFF-DIAGONAL +C PART OF THE WHOLE MATRIX (UPPER AND LOWER TRIANGULAR PARTS). +C EITHER ONE OF A PAIR (I,J),(J,I) MAY BE USED TO REPRESENT +C THE PAIR. DIAGONAL ELEMENTS AND DUPLICATES ARE IGNORED. +C +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C NZ MUST BE SET TO THE NUMBER OF NON-ZEROS INPUT. IT IS NOT +C ALTERED. +C IRN(I),I=1,2,...,NZ MUST BE SET TO THE ROW NUMBERS OF THE +C NON-ZEROS ON INPUT. IT IS NOT ALTERED UNLESS IT IS EQUIVALENCED +C TO IW (SEE DESCRIPTION OF IW). +C ICN(I),I=1,2,...,NZ MUST BE SET TO THE COLUMN NUMBERS OF THE +C NON-ZEROS ON INPUT. IT IS NOT ALTERED UNLESS IT IS EQUIVALENCED +C TO IW (SEE DESCRIPTION OF IW). +C IW NEED NOT BE SET ON INPUT. ON OUTPUT IT CONTAINS LISTS OF +C COLUMN INDICES, EACH LIST BEING HEADED BY ITS LENGTH. +C IRN(1) MAY BE EQUIVALENCED TO IW(1) AND ICN(1) MAY BE +C EQUIVALENCED TO IW(K), WHERE K.GT.NZ. +C LW MUST BE SET TO THE LENGTH OF IW. IT MUST BE AT LEAST 2*NZ+N. +C IT IS NOT ALTERED. +C IPE NEED NOT BE SET ON INPUT. ON OUTPUT IPE(I) POINTS TO THE START OF +C THE ENTRY IN IW FOR ROW I, OR IS ZERO IF THERE IS NO ENTRY. +C IQ NEED NOT BE SET. ON OUTPUT IQ(I),I=1,N CONTAINS THE NUMBER OF +C OFF-DIAGONAL N0N-ZEROS IN ROW I INCLUDING DUPLICATES. +C FLAG IS USED FOR WORKSPACE TO HOLD FLAGS TO PERMIT DUPLICATE ENTRIES +C TO BE IDENTIFIED QUICKLY. +C IWFR NEED NOT BE SET ON INPUT. ON OUTPUT IT POINTS TO THE FIRST +C UNUSED LOCATION IN IW. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER IWFR,LW,N,NZ +C .. +C .. Array Arguments .. + INTEGER FLAG(N),ICN(*),IPE(N),IQ(N),IRN(*),IW(LW) + INTEGER ICNTL(*),INFO(20) +C .. +C .. Local Scalars .. + INTEGER I,ID,J,JN,K,K1,K2,L,LAST,LR,N1,NDUP +C .. +C .. Executable Statements .. +C +C INITIALIZE INFO(2) AND COUNT IN IPE THE +C NUMBERS OF NON-ZEROS IN THE ROWS AND MOVE ROW AND COLUMN +C NUMBERS INTO IW. + INFO(2) = 0 + DO 10 I = 1,N + IPE(I) = 0 + 10 CONTINUE + LR = NZ + IF (NZ.EQ.0) GO TO 120 + DO 110 K = 1,NZ + I = IRN(K) + J = ICN(K) + IF (I.LT.J) THEN + IF (I.GE.1 .AND. J.LE.N) GO TO 90 + ELSE IF (I.GT.J) THEN + IF (J.GE.1 .AND. I.LE.N) GO TO 90 + ELSE + IF (I.GE.1 .AND. I.LE.N) GO TO 80 + END IF + INFO(2) = INFO(2) + 1 + INFO(1) = 1 + IF (INFO(2).LE.1 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=60) INFO(1) + END IF + + 60 FORMAT (' *** WARNING MESSAGE FROM SUBROUTINE MA27AD', + + ' *** INFO(1) =',I2) + + IF (INFO(2).LE.10 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=70) K,I,J + END IF + + 70 FORMAT (I6,'TH NON-ZERO (IN ROW',I6,' AND COLUMN',I6, + + ') IGNORED') + + 80 I = 0 + J = 0 + GO TO 100 + + 90 IPE(I) = IPE(I) + 1 + IPE(J) = IPE(J) + 1 + 100 IW(K) = J + LR = LR + 1 + IW(LR) = I + 110 CONTINUE +C +C ACCUMULATE ROW COUNTS TO GET POINTERS TO ROW STARTS IN BOTH IPE AND IQ +C AND INITIALIZE FLAG + 120 IQ(1) = 1 + N1 = N - 1 + IF (N1.LE.0) GO TO 140 + DO 130 I = 1,N1 + FLAG(I) = 0 + IF (IPE(I).EQ.0) IPE(I) = -1 + IQ(I+1) = IPE(I) + IQ(I) + 1 + IPE(I) = IQ(I) + 130 CONTINUE + 140 LAST = IPE(N) + IQ(N) + FLAG(N) = 0 + IF (LR.GE.LAST) GO TO 160 + K1 = LR + 1 + DO 150 K = K1,LAST + IW(K) = 0 + 150 CONTINUE + 160 IPE(N) = IQ(N) + IWFR = LAST + 1 + IF (NZ.EQ.0) GO TO 230 +C +C RUN THROUGH PUTTING THE MATRIX ELEMENTS IN THE RIGHT PLACE +C BUT WITH SIGNS INVERTED. IQ IS USED FOR HOLDING RUNNING POINTERS +C AND IS LEFT HOLDING POINTERS TO ROW ENDS. + DO 220 K = 1,NZ + J = IW(K) + IF (J.LE.0) GO TO 220 + L = K + IW(K) = 0 + DO 210 ID = 1,NZ + IF (L.GT.NZ) GO TO 170 + L = L + NZ + GO TO 180 + + 170 L = L - NZ + 180 I = IW(L) + IW(L) = 0 + IF (I.LT.J) GO TO 190 + L = IQ(J) + 1 + IQ(J) = L + JN = IW(L) + IW(L) = -I + GO TO 200 + + 190 L = IQ(I) + 1 + IQ(I) = L + JN = IW(L) + IW(L) = -J + 200 J = JN + IF (J.LE.0) GO TO 220 + 210 CONTINUE + 220 CONTINUE +C +C RUN THROUGH RESTORING SIGNS, REMOVING DUPLICATES AND SETTING THE +C MATE OF EACH NON-ZERO. +C NDUP COUNTS THE NUMBER OF DUPLICATE ELEMENTS. + 230 NDUP = 0 + DO 280 I = 1,N + K1 = IPE(I) + 1 + K2 = IQ(I) + IF (K1.LE.K2) GO TO 240 +C ROW IS EMPTY. SET POINTER TO ZERO. + IPE(I) = 0 + IQ(I) = 0 + GO TO 280 +C ON ENTRY TO THIS LOOP FLAG(J).LT.I FOR J=1,2,...,N. DURING THE LOOP +C FLAG(J) IS SET TO I IF A NON-ZERO IN COLUMN J IS FOUND. THIS +C PERMITS DUPLICATES TO BE RECOGNIZED QUICKLY. + 240 DO 260 K = K1,K2 + J = -IW(K) + IF (J.LE.0) GO TO 270 + L = IQ(J) + 1 + IQ(J) = L + IW(L) = I + IW(K) = J + IF (FLAG(J).NE.I) GO TO 250 + NDUP = NDUP + 1 + IW(L) = 0 + IW(K) = 0 + 250 FLAG(J) = I + 260 CONTINUE + 270 IQ(I) = IQ(I) - IPE(I) + IF (NDUP.EQ.0) IW(K1-1) = IQ(I) + 280 CONTINUE + IF (NDUP.EQ.0) GO TO 310 +C +C COMPRESS IW TO REMOVE DUMMY ENTRIES CAUSED BY DUPLICATES. + IWFR = 1 + DO 300 I = 1,N + K1 = IPE(I) + 1 + IF (K1.EQ.1) GO TO 300 + K2 = IQ(I) + IPE(I) + L = IWFR + IPE(I) = IWFR + IWFR = IWFR + 1 + DO 290 K = K1,K2 + IF (IW(K).EQ.0) GO TO 290 + IW(IWFR) = IW(K) + IWFR = IWFR + 1 + 290 CONTINUE + IW(L) = IWFR - L - 1 + 300 CONTINUE + 310 RETURN + + END + + SUBROUTINE MA27HD(N,IPE,IW,LW,IWFR,NV,NXT,LST,IPD,FLAG,IOVFLO, + + NCMPA,FRATIO) +C Bug was found in the then identical subroutine MA57HD which was then +C corrected. +C Changes made in September 2009 because of bug in compress control +C found by Nick. +C +C ANALYSIS SUBROUTINE +C +C GIVEN REPRESENTATION OF THE WHOLE MATRIX (EXCLUDING DIAGONAL) +C PERFORM MINIMUM DEGREE ORDERING, CONSTRUCTING TREE POINTERS. +C IT WORKS WITH SUPERVARIABLES WHICH ARE COLLECTIONS OF ONE OR MORE +C VARIABLES, STARTING WITH SUPERVARIABLE I CONTAINING VARIABLE I FOR +C I = 1,2,...,N. ALL VARIABLES IN A SUPERVARIABLE ARE ELIMINATED +C TOGETHER. EACH SUPERVARIABLE HAS AS NUMERICAL NAME THAT OF ONE +C OF ITS VARIABLES (ITS PRINCIPAL VARIABLE). +C +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C IPE(I) MUST BE SET TO POINT TO THE POSITION IN IW OF THE +C START OF ROW I OR HAVE THE VALUE ZERO IF ROW I HAS NO OFF- +C DIAGONAL NON-ZEROS. DURING EXECUTION IT IS USED AS FOLLOWS. IF +C SUPERVARIABLE I IS ABSORBED INTO SUPERVARIABLE J THEN IPE(I)=-J. +C IF SUPERVARIABLE I IS ELIMINATED THEN IPE(I) EITHER POINTS TO THE +C LIST OF SUPERVARIABLES FOR CREATED ELEMENT I OR IS ZERO IF +C THE CREATED ELEMENT IS NULL. IF ELEMENT I +C IS ABSORBED INTO ELEMENT J THEN IPE(I)=-J. +C IW MUST BE SET ON ENTRY TO HOLD LISTS OF VARIABLES BY +C ROWS, EACH LIST BEING HEADED BY ITS LENGTH. +C DURING EXECUTION THESE LISTS ARE REVISED AND HOLD +C LISTS OF ELEMENTS AND SUPERVARIABLES. THE ELEMENTS +C ALWAYS HEAD THE LISTS. WHEN A SUPERVARIABLE +C IS ELIMINATED ITS LIST IS REPLACED BY A LIST OF SUPERVARIABLES +C IN THE NEW ELEMENT. +C LW MUST BE SET TO THE LENGTH OF IW. IT IS NOT ALTERED. +C IWFR MUST BE SET TO THE POSITION IN IW OF THE FIRST FREE VARIABLE. +C IT IS REVISED DURING EXECUTION AND CONTINUES TO HAVE THIS MEANING. +C NV(JS) NEED NOT BE SET. DURING EXECUTION IT IS ZERO IF +C JS IS NOT A PRINCIPAL VARIABLE AND IF IT IS IT HOLDS +C THE NUMBER OF VARIABLES IN SUPERVARIABLE JS. FOR ELIMINATED +C VARIABLES IT IS SET TO THE DEGREE AT THE TIME OF ELIMINATION. +C NXT(JS) NEED NOT BE SET. DURING EXECUTION IT IS THE NEXT +C SUPERVARIABLE HAVING THE SAME DEGREE AS JS, OR ZERO +C IF IT IS LAST IN ITS LIST. +C LST(JS) NEED NOT BE SET. DURING EXECUTION IT IS THE +C LAST SUPERVARIABLE HAVING THE SAME DEGREE AS JS OR +C -(ITS DEGREE) IF IT IS FIRST IN ITS LIST. +C IPD(ID) NEED NOT BE SET. DURING EXECUTION IT +C IS THE FIRST SUPERVARIABLE WITH DEGREE ID OR ZERO +C IF THERE ARE NONE. +C FLAG IS USED AS WORKSPACE FOR ELEMENT AND SUPERVARIABLE FLAGS. +C WHILE THE CODE IS FINDING THE DEGREE OF SUPERVARIABLE IS +C FLAG HAS THE FOLLOWING VALUES. +C A) FOR THE CURRENT PIVOT/NEW ELEMENT ME +C FLAG(ME)=-1 +C B) FOR VARIABLES JS +C FLAG(JS)=-1 IF JS IS NOT A PRINCIPAL VARIABLE +C FLAG(JS)=0 IF JS IS A SUPERVARIABLE IN THE NEW ELEMENT +C FLAG(JS)=NFLG IF JS IS A SUPERVARIABLE NOT IN THE NEW +C ELEMENT THAT HAS BEEN COUNTED IN THE DEGREE +C CALCULATION +C FLAG(JS).GT.NFLG IF JS IS A SUPERVARIABLE NOT IN THE NEW +C ELEMENT THAT HAS NOT BEEN COUNTED IN THE DEGREE +C CALCULATION +C C) FOR ELEMENTS IE +C FLAG(IE)=-1 IF ELEMENT IE HAS BEEN MERGED INTO ANOTHER +C FLAG(IE)=-NFLG IF ELEMENT IE HAS BEEN USED IN THE DEGREE +C CALCULATION FOR IS. +C FLAG(IE).LT.-NFLG IF ELEMENT IE HAS NOT BEEN USED IN THE +C DEGREE CALCULATION FOR IS +C IOVFLO see ICNTL(4) in MA27A/AD. +C NCMPA see INFO(11) in MA27A/AD. +C FRATIO see CNTL(2) in MA27A/AD. +C +C .. Scalar Arguments .. + DOUBLE PRECISION FRATIO + INTEGER IWFR,LW,N,IOVFLO,NCMPA +C .. +C .. Array Arguments .. + INTEGER FLAG(N),IPD(N),IPE(N),IW(LW),LST(N),NV(N),NXT(N) +C .. +C .. Local Scalars .. + INTEGER I,ID,IDL,IDN,IE,IP,IS,JP,JP1,JP2,JS,K,K1,K2,KE,KP,KP0,KP1, + + KP2,KS,L,LEN,LIMIT,LN,LS,LWFR,MD,ME,ML,MS,NEL,NFLG,NP, + + NP0,NS,NVPIV,NVROOT,ROOT +C LIMIT Limit on number of variables for putting node in root. +C NVROOT Number of variables in the root node +C ROOT Index of the root node (N+1 if none chosen yet). +C .. +C .. External Subroutines .. + EXTERNAL MA27UD +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MIN +C .. +C If a column of the reduced matrix has relative density greater than +C CNTL(2), it is forced into the root. All such columns are taken to +C have sparsity pattern equal to their merged patterns, so the fill +C and operation counts may be overestimated. +C +C IS,JS,KS,LS,MS,NS are used to refer to supervariables. +C IE,JE,KE are used to refer to elements. +C IP,JP,KP,K,NP are used to point to lists of elements +C or supervariables. +C ID is used for the degree of a supervariable. +C MD is used for the current minimum degree. +C IDN is used for the no. of variables in a newly created element +C NEL is used to hold the no. of variables that have been +C eliminated. +C ME=MS is the name of the supervariable eliminated and +C of the element created in the main loop. +C NFLG is used for the current flag value in array FLAG. It starts +C with the value IOVFLO and is reduced by 1 each time it is used +C until it has the value 2 when it is reset to the value IOVFLO. +C +C .. Executable Statements .. +C Initializations + DO 10 I = 1,N + IPD(I) = 0 + NV(I) = 1 + FLAG(I) = IOVFLO + 10 CONTINUE + MD = 1 + NCMPA = 0 + NFLG = IOVFLO + NEL = 0 + ROOT = N+1 + NVROOT = 0 +C +C Link together variables having same degree + DO 30 IS = 1,N + K = IPE(IS) + IF (K.GT.0) THEN + ID = IW(K) + 1 + NS = IPD(ID) + IF (NS.GT.0) LST(NS) = IS + NXT(IS) = NS + IPD(ID) = IS + LST(IS) = -ID + ELSE +C We have a variable that can be eliminated at once because there is +C no off-diagonal nonzero in its row. + NEL = NEL + 1 + FLAG(IS) = -1 + NXT(IS) = 0 + LST(IS) = 0 + ENDIF + 30 CONTINUE + +C +C Start of main loop +C + DO 340 ML = 1,N +C Leave loop if all variables have been eliminated. + IF (NEL+NVROOT+1.GE.N) GO TO 350 +C +C Find next supervariable for elimination. + DO 40 ID = MD,N + MS = IPD(ID) + IF (MS.GT.0) GO TO 50 + 40 CONTINUE + 50 MD = ID +C Nvpiv holds the number of variables in the pivot. + NVPIV = NV(MS) +C +C Remove chosen variable from linked list + NS = NXT(MS) + NXT(MS) = 0 + LST(MS) = 0 + IF (NS.GT.0) LST(NS) = -ID + IPD(ID) = NS + ME = MS + NEL = NEL + NVPIV +C IDN holds the degree of the new element. + IDN = 0 +C +C Run through the list of the pivotal supervariable, setting tree +C pointers and constructing new list of supervariables. +C KP is a pointer to the current position in the old list. + KP = IPE(ME) + FLAG(MS) = -1 +C IP points to the start of the new list. + IP = IWFR +C LEN holds the length of the list associated with the pivot. + LEN = IW(KP) + DO 140 KP1 = 1,LEN + KP = KP + 1 + KE = IW(KP) +C Jump if KE is an element that has not been merged into another. + IF (FLAG(KE).LE.-2) GO TO 60 +C Jump if KE is an element that has been merged into another or is +C a supervariable that has been eliminated. + IF (FLAG(KE).LE.0) THEN + IF (IPE(KE).NE.-ROOT) GO TO 140 +C KE has been merged into the root + KE = ROOT + IF (FLAG(KE).LE.0) GO TO 140 + END IF +C We have a supervariable. Prepare to search rest of list. + JP = KP - 1 + LN = LEN - KP1 + 1 + IE = MS + GO TO 70 +C Search variable list of element KE, using JP as a pointer to it. + 60 IE = KE + JP = IPE(IE) + LN = IW(JP) +C +C Search for different supervariables and add them to the new list, +C compressing when necessary. This loop is executed once for +C each element in the list and once for all the supervariables +C in the list. + 70 DO 130 JP1 = 1,LN + JP = JP + 1 + IS = IW(JP) +C Jump if IS is not a principal variable or has already been counted. + IF (FLAG(IS).LE.0) THEN + IF (IPE(IS).EQ.-ROOT) THEN +C IS has been merged into the root + IS = ROOT + IW(JP) = ROOT + IF (FLAG(IS).LE.0) GO TO 130 + ELSE + GO TO 130 + END IF + END IF + FLAG(IS) = 0 + +C To fix Nick bug need to add one here to store (eventually) length +C of new row + IF (IWFR .GE. LW-1) THEN +C Logic was previously as below +CCC IF (IWFR.LT.LW) GO TO 100 +C Prepare for compressing IW by adjusting pointers and +C lengths so that the lists being searched in the inner and outer +C loops contain only the remaining entries. + IPE(MS) = KP + IW(KP) = LEN - KP1 + IPE(IE) = JP + IW(JP) = LN - JP1 +C Compress IW + CALL MA27UD(N,IPE,IW,IP-1,LWFR,NCMPA) +C Copy new list forward + JP2 = IWFR - 1 + IWFR = LWFR + IF (IP.GT.JP2) GO TO 90 + DO 80 JP = IP,JP2 + IW(IWFR) = IW(JP) + IWFR = IWFR + 1 + 80 CONTINUE +C Adjust pointers for the new list and the lists being searched. + 90 IP = LWFR + JP = IPE(IE) + KP = IPE(ME) + ENDIF + +C Store IS in new list. + IW(IWFR) = IS + IDN = IDN + NV(IS) + IWFR = IWFR + 1 +C Remove IS from degree linked list + LS = LST(IS) + LST(IS) = 0 + NS = NXT(IS) + NXT(IS) = 0 + IF (NS.GT.0) LST(NS) = LS + IF (LS.LT.0) THEN + LS = -LS + IPD(LS) = NS + ELSE IF (LS.GT.0) THEN + NXT(LS) = NS + END IF + 130 CONTINUE +C Jump if we have just been searching the variables at the end of +C the list of the pivot. + IF (IE.EQ.MS) GO TO 150 +C Set tree pointer and flag to indicate element IE is absorbed into +C new element ME. + IPE(IE) = -ME + FLAG(IE) = -1 + 140 CONTINUE + +C Store the degree of the pivot. + 150 NV(MS) = IDN + NVPIV + +C Jump if new element is null. + IF (IWFR.EQ.IP) THEN + IPE(ME) = 0 + GO TO 340 + ENDIF + + K1 = IP + K2 = IWFR - 1 +C +C Run through new list of supervariables revising each associated list, +C recalculating degrees and removing duplicates. + LIMIT = NINT(FRATIO*(N-NEL)) + DO 310 K = K1,K2 + IS = IW(K) + IF (IS.EQ.ROOT) GO TO 310 + IF (NFLG.GT.2) GO TO 170 +C Reset FLAG values to +/-IOVFLO. + DO 160 I = 1,N + IF (FLAG(I).GT.0) FLAG(I) = IOVFLO + IF (FLAG(I).LE.-2) FLAG(I) = -IOVFLO + 160 CONTINUE + NFLG = IOVFLO +C Reduce NFLG by one to cater for this supervariable. + 170 NFLG = NFLG - 1 +C Begin with the degree of the new element. Its variables must always +C be counted during the degree calculation and they are already +C flagged with the value 0. + ID = IDN +C Run through the list associated with supervariable IS + KP1 = IPE(IS) + 1 +C NP points to the next entry in the revised list. + NP = KP1 + KP2 = IW(KP1-1) + KP1 - 1 + DO 220 KP = KP1,KP2 + KE = IW(KP) +C Test whether KE is an element, a redundant entry or a supervariable. + IF (FLAG(KE).EQ.-1) THEN + IF (IPE(KE).NE.-ROOT) GO TO 220 +C KE has been merged into the root + KE = ROOT + IW(KP) = ROOT + IF (FLAG(KE).EQ.-1) GO TO 220 + END IF + IF (FLAG(KE).GE.0) GO TO 230 +C Search list of element KE, revising the degree when new variables +C found. + JP1 = IPE(KE) + 1 + JP2 = IW(JP1-1) + JP1 - 1 + IDL = ID + DO 190 JP = JP1,JP2 + JS = IW(JP) +C Jump if JS has already been counted. + IF (FLAG(JS).LE.NFLG) GO TO 190 + ID = ID + NV(JS) + FLAG(JS) = NFLG + 190 CONTINUE +C Jump if one or more new supervariables were found. + IF (ID.GT.IDL) GO TO 210 +C Check whether every variable of element KE is in new element ME. + DO 200 JP = JP1,JP2 + JS = IW(JP) + IF (FLAG(JS).NE.0) GO TO 210 + 200 CONTINUE +C Set tree pointer and FLAG to indicate that element KE is absorbed +C into new element ME. + IPE(KE) = -ME + FLAG(KE) = -1 + GO TO 220 +C Store element KE in the revised list for supervariable IS and flag it. + 210 IW(NP) = KE + FLAG(KE) = -NFLG + NP = NP + 1 + 220 CONTINUE + NP0 = NP + GO TO 250 +C Treat the rest of the list associated with supervariable IS. It +C consists entirely of supervariables. + 230 KP0 = KP + NP0 = NP + DO 240 KP = KP0,KP2 + KS = IW(KP) + IF (FLAG(KS).LE.NFLG) THEN + IF (IPE(KS).EQ.-ROOT) THEN + KS = ROOT + IW(KP) = ROOT + IF (FLAG(KS).LE.NFLG) GO TO 240 + ELSE + GO TO 240 + END IF + END IF +C Add to degree, flag supervariable KS and add it to new list. + ID = ID + NV(KS) + FLAG(KS) = NFLG + IW(NP) = KS + NP = NP + 1 + 240 CONTINUE +C Move first supervariable to end of list, move first element to end +C of element part of list and add new element to front of list. + 250 IF (ID.GE.LIMIT) GO TO 295 + IW(NP) = IW(NP0) + IW(NP0) = IW(KP1) + IW(KP1) = ME +C Store the new length of the list. + IW(KP1-1) = NP - KP1 + 1 +C +C Check whether row is is identical to another by looking in linked +C list of supervariables with degree ID at those whose lists have +C first entry ME. Note that those containing ME come first so the +C search can be terminated when a list not starting with ME is +C found. + JS = IPD(ID) + DO 280 L = 1,N + IF (JS.LE.0) GO TO 300 + KP1 = IPE(JS) + 1 + IF (IW(KP1).NE.ME) GO TO 300 +C JS has same degree and is active. Check if identical to IS. + KP2 = KP1 - 1 + IW(KP1-1) + DO 260 KP = KP1,KP2 + IE = IW(KP) +C Jump if IE is a supervariable or an element not in the list of IS. + IF (ABS(FLAG(IE)+0).GT.NFLG) GO TO 270 + 260 CONTINUE + GO TO 290 + + 270 JS = NXT(JS) + 280 CONTINUE +C Supervariable amalgamation. Row IS is identical to row JS. +C Regard all variables in the two supervariables as being in IS. Set +C tree pointer, FLAG and NV entries. + 290 IPE(JS) = -IS + NV(IS) = NV(IS) + NV(JS) + NV(JS) = 0 + FLAG(JS) = -1 +C Replace JS by IS in linked list. + NS = NXT(JS) + LS = LST(JS) + IF (NS.GT.0) LST(NS) = IS + IF (LS.GT.0) NXT(LS) = IS + LST(IS) = LS + NXT(IS) = NS + LST(JS) = 0 + NXT(JS) = 0 + IF (IPD(ID).EQ.JS) IPD(ID) = IS + GO TO 310 +C Treat IS as full. Merge it into the root node. + 295 IF (NVROOT.EQ.0) THEN + ROOT = IS + IPE(IS) = 0 + ELSE + IW(K) = ROOT + IPE(IS) = -ROOT + NV(ROOT) = NV(ROOT) + NV(IS) + NV(IS) = 0 + FLAG(IS) = -1 + END IF + NVROOT = NV(ROOT) + GO TO 310 +C Insert IS into linked list of supervariables of same degree. + 300 NS = IPD(ID) + IF (NS.GT.0) LST(NS) = IS + NXT(IS) = NS + IPD(ID) = IS + LST(IS) = -ID + MD = MIN(MD,ID) + 310 CONTINUE + +C +C Reset flags for supervariables in newly created element and +C remove those absorbed into others. + DO 320 K = K1,K2 + IS = IW(K) + IF (NV(IS).EQ.0) GO TO 320 + FLAG(IS) = NFLG + IW(IP) = IS + IP = IP + 1 + 320 CONTINUE + + FLAG(ME) = -NFLG +C Move first entry to end to make room for length. + IW(IP) = IW(K1) + IW(K1) = IP - K1 +C Set pointer for new element and reset IWFR. + IPE(ME) = K1 + IWFR = IP + 1 + +C End of main loop + 340 CONTINUE +C + +C Absorb any remaining variables into the root + 350 DO 360 IS = 1,N + IF(NXT(IS).NE.0 .OR. LST(IS).NE.0) THEN + IF (NVROOT.EQ.0) THEN + ROOT = IS + IPE(IS) = 0 + ELSE + IPE(IS) = -ROOT + END IF + NVROOT = NVROOT + NV(IS) + NV(IS) = 0 + END IF + 360 CONTINUE +C Link any remaining elements to the root + DO 370 IE = 1,N + IF (IPE(IE).GT.0) IPE(IE) = -ROOT + 370 CONTINUE + IF(NVROOT.GT.0)NV(ROOT)=NVROOT + END + SUBROUTINE MA27UD(N,IPE,IW,LW,IWFR,NCMPA) +C COMPRESS LISTS HELD BY MA27H/HD AND MA27K/KD IN IW AND ADJUST POINTERS +C IN IPE TO CORRESPOND. +C N IS THE MATRIX ORDER. IT IS NOT ALTERED. +C IPE(I) POINTS TO THE POSITION IN IW OF THE START OF LIST I OR IS +C ZERO IF THERE IS NO LIST I. ON EXIT IT POINTS TO THE NEW POSITION. +C IW HOLDS THE LISTS, EACH HEADED BY ITS LENGTH. ON OUTPUT THE SAME +C LISTS ARE HELD, BUT THEY ARE NOW COMPRESSED TOGETHER. +C LW HOLDS THE LENGTH OF IW. IT IS NOT ALTERED. +C IWFR NEED NOT BE SET ON ENTRY. ON EXIT IT POINTS TO THE FIRST FREE +C LOCATION IN IW. +C ON RETURN IT IS SET TO THE FIRST FREE LOCATION IN IW. +C NCMPA see INFO(11) in MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER IWFR,LW,N,NCMPA +C .. +C .. Array Arguments .. + INTEGER IPE(N),IW(LW) +C .. +C .. Local Scalars .. + INTEGER I,IR,K,K1,K2,LWFR +C .. +C .. Executable Statements .. + NCMPA = NCMPA + 1 +C PREPARE FOR COMPRESSING BY STORING THE LENGTHS OF THE +C LISTS IN IPE AND SETTING THE FIRST ENTRY OF EACH LIST TO +C -(LIST NUMBER). + DO 10 I = 1,N + K1 = IPE(I) + IF (K1.LE.0) GO TO 10 + IPE(I) = IW(K1) + IW(K1) = -I + 10 CONTINUE +C +C COMPRESS +C IWFR POINTS JUST BEYOND THE END OF THE COMPRESSED FILE. +C LWFR POINTS JUST BEYOND THE END OF THE UNCOMPRESSED FILE. + IWFR = 1 + LWFR = IWFR + DO 60 IR = 1,N + IF (LWFR.GT.LW) GO TO 70 +C SEARCH FOR THE NEXT NEGATIVE ENTRY. + DO 20 K = LWFR,LW + IF (IW(K).LT.0) GO TO 30 + 20 CONTINUE + GO TO 70 +C PICK UP ENTRY NUMBER, STORE LENGTH IN NEW POSITION, SET NEW POINTER +C AND PREPARE TO COPY LIST. + 30 I = -IW(K) + IW(IWFR) = IPE(I) + IPE(I) = IWFR + K1 = K + 1 + K2 = K + IW(IWFR) + IWFR = IWFR + 1 + IF (K1.GT.K2) GO TO 50 +C COPY LIST TO NEW POSITION. + DO 40 K = K1,K2 + IW(IWFR) = IW(K) + IWFR = IWFR + 1 + 40 CONTINUE + 50 LWFR = K2 + 1 + 60 CONTINUE + 70 RETURN + + END + SUBROUTINE MA27JD(N,NZ,IRN,ICN,PERM,IW,LW,IPE,IQ,FLAG,IWFR, + + ICNTL,INFO) +C +C SORT PRIOR TO CALLING ANALYSIS ROUTINE MA27K/KD. +C +C GIVEN THE POSITIONS OF THE OFF-DIAGONAL NON-ZEROS OF A SYMMETRIC +C MATRIX AND A PERMUTATION, CONSTRUCT THE SPARSITY PATTERN +C OF THE STRICTLY UPPER TRIANGULAR PART OF THE PERMUTED MATRIX. +C EITHER ONE OF A PAIR (I,J),(J,I) MAY BE USED TO REPRESENT +C THE PAIR. DIAGONAL ELEMENTS ARE IGNORED. NO CHECK IS MADE +C FOR DUPLICATE ELEMENTS UNLESS ANY ROW HAS MORE THAN ICNTL(4) +C NON-ZEROS, IN WHICH CASE DUPLICATES ARE REMOVED. +C +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C NZ MUST BE SET TO THE NUMBER OF NON-ZEROS INPUT. IT IS NOT +C ALTERED. +C IRN(I),I=1,2,...,NZ MUST BE SET TO THE ROW INDICES OF THE +C NON-ZEROS ON INPUT. IT IS NOT ALTERED UNLESS EQUIVALENCED WITH IW. +C IRN(1) MAY BE EQUIVALENCED WITH IW(1). +C ICN(I),I=1,2,...,NZ MUST BE SET TO THE COLUMN INDICES OF THE +C NON-ZEROS ON INPUT. IT IS NOT ALTERED UNLESS EQUIVALENCED +C WITH IW.ICN(1) MAY BE EQUIVELENCED WITH IW(K),K.GT.NZ. +C PERM(I) MUST BE SET TO HOLD THE POSITION OF VARIABLE I IN THE +C PERMUTED ORDER. IT IS NOT ALTERED. +C IW NEED NOT BE SET ON INPUT. ON OUTPUT IT CONTAINS LISTS OF +C COLUMN NUMBERS, EACH LIST BEING HEADED BY ITS LENGTH. +C LW MUST BE SET TO THE LENGTH OF IW. IT MUST BE AT LEAST +C MAX(NZ,N+(NO. OF OFF-DIAGONAL NON-ZEROS)). IT IS NOT ALTERED. +C IPE NEED NOT BE SET ON INPUT. ON OUTPUT IPE(I) POINTS TO THE START OF +C THE ENTRY IN IW FOR ROW I, OR IS ZERO IF THERE IS NO ENTRY. +C IQ NEED NOT BE SET. ON OUTPUT IQ(I) CONTAINS THE NUMBER OF +C OFF-DIAGONAL NON-ZEROS IN ROW I, INCLUDING DUPLICATES. +C FLAG IS USED FOR WORKSPACE TO HOLD FLAGS TO PERMIT DUPLICATE +C ENTRIES TO BE IDENTIFIED QUICKLY. +C IWFR NEED NOT BE SET ON INPUT. ON OUTPUT IT POINTS TO THE FIRST +C UNUSED LOCATION IN IW. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER IWFR,LW,N,NZ +C .. +C .. Array Arguments .. + INTEGER FLAG(N),ICN(*),IPE(N),IQ(N),IRN(*),IW(LW),PERM(N) + INTEGER ICNTL(30),INFO(20) +C .. +C .. Local Scalars .. + INTEGER I,ID,IN,J,JDUMMY,K,K1,K2,L,LBIG,LEN +C .. +C .. Intrinsic Functions .. + INTRINSIC MAX +C .. +C .. Executable Statements .. +C +C INITIALIZE INFO(1), INFO(2) AND IQ + INFO(1) = 0 + INFO(2) = 0 + DO 10 I = 1,N + IQ(I) = 0 + 10 CONTINUE +C +C COUNT THE NUMBERS OF NON-ZEROS IN THE ROWS, PRINT WARNINGS ABOUT +C OUT-OF-RANGE INDICES AND TRANSFER GENUINE ROW NUMBERS +C (NEGATED) INTO IW. + IF (NZ.EQ.0) GO TO 110 + DO 100 K = 1,NZ + I = IRN(K) + J = ICN(K) + IW(K) = -I + IF(I.LT.J) THEN + IF (I.GE.1 .AND. J.LE.N) GO TO 80 + ELSE IF(I.GT.J) THEN + IF (J.GE.1 .AND. I.LE.N) GO TO 80 + ELSE + IW(K) = 0 + IF (I.GE.1 .AND. I.LE.N) GO TO 100 + END IF + INFO(2) = INFO(2) + 1 + INFO(1) = 1 + IW(K) = 0 + IF (INFO(2).LE.1 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=60) INFO(1) + END IF + + 60 FORMAT (' *** WARNING MESSAGE FROM SUBROUTINE MA27AD', + + ' *** INFO(1) =',I2) + + IF (INFO(2).LE.10 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=70) K,I,J + END IF + + 70 FORMAT (I6,'TH NON-ZERO (IN ROW',I6,' AND COLUMN',I6, + + ') IGNORED') + + GO TO 100 + + 80 IF (PERM(J).GT.PERM(I)) GO TO 90 + IQ(J) = IQ(J) + 1 + GO TO 100 + + 90 IQ(I) = IQ(I) + 1 + 100 CONTINUE +C +C ACCUMULATE ROW COUNTS TO GET POINTERS TO ROW ENDS +C IN IPE. + 110 IWFR = 1 + LBIG = 0 + DO 120 I = 1,N + L = IQ(I) + LBIG = MAX(L,LBIG) + IWFR = IWFR + L + IPE(I) = IWFR - 1 + 120 CONTINUE +C +C PERFORM IN-PLACE SORT + IF (NZ.EQ.0) GO TO 250 + DO 160 K = 1,NZ + I = -IW(K) + IF (I.LE.0) GO TO 160 + L = K + IW(K) = 0 + DO 150 ID = 1,NZ + J = ICN(L) + IF (PERM(I).LT.PERM(J)) GO TO 130 + L = IPE(J) + IPE(J) = L - 1 + IN = IW(L) + IW(L) = I + GO TO 140 + + 130 L = IPE(I) + IPE(I) = L - 1 + IN = IW(L) + IW(L) = J + 140 I = -IN + IF (I.LE.0) GO TO 160 + 150 CONTINUE + 160 CONTINUE +C +C MAKE ROOM IN IW FOR ROW LENGTHS AND INITIALIZE FLAG. + K = IWFR - 1 + L = K + N + IWFR = L + 1 + DO 190 I = 1,N + FLAG(I) = 0 + J = N + 1 - I + LEN = IQ(J) + IF (LEN.LE.0) GO TO 180 + DO 170 JDUMMY = 1,LEN + IW(L) = IW(K) + K = K - 1 + L = L - 1 + 170 CONTINUE + 180 IPE(J) = L + L = L - 1 + 190 CONTINUE + IF (LBIG.GE.ICNTL(4)) GO TO 210 +C +C PLACE ROW LENGTHS IN IW + DO 200 I = 1,N + K = IPE(I) + IW(K) = IQ(I) + IF (IQ(I).EQ.0) IPE(I) = 0 + 200 CONTINUE + GO TO 250 +C +C +C REMOVE DUPLICATE ENTRIES + 210 IWFR = 1 + DO 240 I = 1,N + K1 = IPE(I) + 1 + K2 = IPE(I) + IQ(I) + IF (K1.LE.K2) GO TO 220 + IPE(I) = 0 + GO TO 240 + + 220 IPE(I) = IWFR + IWFR = IWFR + 1 + DO 230 K = K1,K2 + J = IW(K) + IF (FLAG(J).EQ.I) GO TO 230 + IW(IWFR) = J + IWFR = IWFR + 1 + FLAG(J) = I + 230 CONTINUE + K = IPE(I) + IW(K) = IWFR - K - 1 + 240 CONTINUE + 250 RETURN + + END + SUBROUTINE MA27KD(N,IPE,IW,LW,IWFR,IPS,IPV,NV,FLAG,NCMPA) +C +C USING A GIVEN PIVOTAL SEQUENCE AND A REPRESENTATION OF THE MATRIX THAT +C INCLUDES ONLY NON-ZEROS OF THE STRICTLY UPPER-TRIANGULAR PART +C OF THE PERMUTED MATRIX, CONSTRUCT TREE POINTERS. +C +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C IPE(I) MUST BE SET TO POINT TO THE POSITION IN IW OF THE +C START OF ROW I OR HAVE THE VALUE ZERO IF ROW I HAS NO OFF- +C DIAGONAL NON-ZEROS. DURING EXECUTION IT IS USED AS FOLLOWS. +C IF VARIABLE I IS ELIMINATED THEN IPE(I) POINTS TO THE LIST +C OF VARIABLES FOR CREATED ELEMENT I. IF ELEMENT I IS +C ABSORBED INTO NEWLY CREATED ELEMENT J THEN IPE(I)=-J. +C IW MUST BE SET ON ENTRY TO HOLD LISTS OF VARIABLES BY +C ROWS, EACH LIST BEING HEADED BY ITS LENGTH. WHEN A VARIABLE +C IS ELIMINATED ITS LIST IS REPLACED BY A LIST OF VARIABLES +C IN THE NEW ELEMENT. +C LW MUST BE SET TO THE LENGTH OF IW. IT IS NOT ALTERED. +C IWFR MUST BE SET TO THE POSITION IN IW OF THE FIRST FREE VARIABLE. +C IT IS REVISED DURING EXECUTION, CONTINUING TO HAVE THIS MEANING. +C IPS(I) MUST BE SET TO THE POSITION OF VARIABLE I IN THE REQUIRED +C ORDERING. IT IS NOT ALTERED. +C IPV NEED NOT BE SET. IPV(K) IS SET TO HOLD THE K TH VARIABLE +C IN PIVOT ORDER. +C NV NEED NOT BE SET. IF VARIABLE J HAS NOT BEEN ELIMINATED THEN +C THE LAST ELEMENT WHOSE LEADING VARIABLE (VARIABLE EARLIEST +C IN THE PIVOT SEQUENCE) IS J IS ELEMENT NV(J). IF ELEMENT J +C EXISTS THEN THE LAST ELEMENT HAVING THE SAME LEADING +C VARIABLE IS NV(J). IN BOTH CASES NV(J)=0 IF THERE IS NO SUCH +C ELEMENT. IF ELEMENT J HAS BEEN MERGED INTO A LATER ELEMENT +C THEN NV(J) IS THE DEGREE AT THE TIME OF ELIMINATION. +C FLAG IS USED AS WORKSPACE FOR VARIABLE FLAGS. +C FLAG(JS)=ME IF JS HAS BEEN INCLUDED IN THE LIST FOR ME. +C NCMPA see INFO(11) in MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER IWFR,LW,N,NCMPA +C .. +C .. Array Arguments .. + INTEGER FLAG(N),IPE(N),IPS(N),IPV(N),IW(LW),NV(N) +C .. +C .. Local Scalars .. + INTEGER I,IE,IP,J,JE,JP,JP1,JP2,JS,KDUMMY,LN,LWFR,ME,MINJS,ML,MS +C .. +C .. External Subroutines .. + EXTERNAL MA27UD +C .. +C .. Intrinsic Functions .. + INTRINSIC MIN +C .. +C .. Executable Statements .. +C +C INITIALIZATIONS + DO 10 I = 1,N + FLAG(I) = 0 + NV(I) = 0 + J = IPS(I) + IPV(J) = I + 10 CONTINUE + NCMPA = 0 +C +C START OF MAIN LOOP +C + DO 100 ML = 1,N +C ME=MS IS THE NAME OF THE VARIABLE ELIMINATED AND +C OF THE ELEMENT CREATED IN THE MAIN LOOP. + MS = IPV(ML) + ME = MS + FLAG(MS) = ME +C +C MERGE ROW MS WITH ALL THE ELEMENTS HAVING MS AS LEADING VARIABLE. +C IP POINTS TO THE START OF THE NEW LIST. + IP = IWFR +C MINJS IS SET TO THE POSITION IN THE ORDER OF THE LEADING VARIABLE +C IN THE NEW LIST. + MINJS = N + IE = ME + DO 70 KDUMMY = 1,N +C SEARCH VARIABLE LIST OF ELEMENT IE. +C JP POINTS TO THE CURRENT POSITION IN THE LIST BEING SEARCHED. + JP = IPE(IE) +C LN IS THE LENGTH OF THE LIST BEING SEARCHED. + LN = 0 + IF (JP.LE.0) GO TO 60 + LN = IW(JP) +C +C SEARCH FOR DIFFERENT VARIABLES AND ADD THEM TO LIST, +C COMPRESSING WHEN NECESSARY + DO 50 JP1 = 1,LN + JP = JP + 1 +C PLACE NEXT VARIABLE IN JS. + JS = IW(JP) +C JUMP IF VARIABLE HAS ALREADY BEEN INCLUDED. + IF (FLAG(JS).EQ.ME) GO TO 50 + FLAG(JS) = ME + IF (IWFR.LT.LW) GO TO 40 +C PREPARE FOR COMPRESSING IW BY ADJUSTING POINTER TO AND LENGTH OF +C THE LIST FOR IE TO REFER TO THE REMAINING ENTRIES. + IPE(IE) = JP + IW(JP) = LN - JP1 +C COMPRESS IW. + CALL MA27UD(N,IPE,IW,IP-1,LWFR,NCMPA) +C COPY NEW LIST FORWARD + JP2 = IWFR - 1 + IWFR = LWFR + IF (IP.GT.JP2) GO TO 30 + DO 20 JP = IP,JP2 + IW(IWFR) = IW(JP) + IWFR = IWFR + 1 + 20 CONTINUE + 30 IP = LWFR + JP = IPE(IE) +C ADD VARIABLE JS TO NEW LIST. + 40 IW(IWFR) = JS + MINJS = MIN(MINJS,IPS(JS)+0) + IWFR = IWFR + 1 + 50 CONTINUE +C RECORD ABSORPTION OF ELEMENT IE INTO NEW ELEMENT. + 60 IPE(IE) = -ME +C PICK UP NEXT ELEMENT WITH LEADING VARIABLE MS. + JE = NV(IE) +C STORE DEGREE OF IE. + NV(IE) = LN + 1 + IE = JE +C LEAVE LOOP IF THERE ARE NO MORE ELEMENTS. + IF (IE.EQ.0) GO TO 80 + 70 CONTINUE + 80 IF (IWFR.GT.IP) GO TO 90 +C DEAL WITH NULL NEW ELEMENT. + IPE(ME) = 0 + NV(ME) = 1 + GO TO 100 +C LINK NEW ELEMENT WITH OTHERS HAVING SAME LEADING VARIABLE. + 90 MINJS = IPV(MINJS) + NV(ME) = NV(MINJS) + NV(MINJS) = ME +C MOVE FIRST ENTRY IN NEW LIST TO END TO ALLOW ROOM FOR LENGTH AT +C FRONT. SET POINTER TO FRONT. + IW(IWFR) = IW(IP) + IW(IP) = IWFR - IP + IPE(ME) = IP + IWFR = IWFR + 1 + 100 CONTINUE + RETURN + + END + SUBROUTINE MA27LD(N,IPE,NV,IPS,NE,NA,ND,NSTEPS,NEMIN) +C +C TREE SEARCH +C +C GIVEN SON TO FATHER TREE POINTERS, PERFORM DEPTH-FIRST +C SEARCH TO FIND PIVOT ORDER AND NUMBER OF ELIMINATIONS +C AND ASSEMBLIES AT EACH STAGE. +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C IPE(I) MUST BE SET EQUAL TO -(FATHER OF NODE I) OR ZERO IF +C NODE IS A ROOT. IT IS ALTERED TO POINT TO ITS NEXT +C YOUNGER BROTHER IF IT HAS ONE, BUT OTHERWISE IS NOT +C CHANGED. +C NV(I) MUST BE SET TO ZERO IF NO VARIABLES ARE ELIMINATED AT NODE +C I AND TO THE DEGREE OTHERWISE. ONLY LEAF NODES CAN HAVE +C ZERO VALUES OF NV(I). NV IS NOT ALTERED. +C IPS(I) NEED NOT BE SET. IT IS USED TEMPORARILY TO HOLD +C -(ELDEST SON OF NODE I) IF IT HAS ONE AND 0 OTHERWISE. IT IS +C EVENTUALLY SET TO HOLD THE POSITION OF NODE I IN THE ORDER. +C NE(IS) NEED NOT BE SET. IT IS SET TO THE NUMBER OF VARIABLES +C ELIMINATED AT STAGE IS OF THE ELIMINATION. +C NA(IS) NEED NOT BE SET. IT IS SET TO THE NUMBER OF ELEMENTS +C ASSEMBLED AT STAGE IS OF THE ELIMINATION. +C ND(IS) NEED NOT BE SET. IT IS SET TO THE DEGREE AT STAGE IS OF +C THE ELIMINATION. +C NSTEPS NEED NOT BE SET. IT IS SET TO THE NUMBER OF ELIMINATION +C STEPS. +C NEMIN see ICNTL(5) in MA27A/AD. +C +C .. Scalar Arguments .. + INTEGER N,NSTEPS,NEMIN +C .. +C .. Array Arguments .. + INTEGER IPE(N),IPS(N),NA(N),ND(N),NE(N),NV(N) +C .. +C .. Local Scalars .. + INTEGER I,IB,IF,IL,IS,ISON,K,L,NR +C .. +C .. Executable Statements .. +C INITIALIZE IPS AND NE. + DO 10 I = 1,N + IPS(I) = 0 + NE(I) = 0 + 10 CONTINUE +C +C SET IPS(I) TO -(ELDEST SON OF NODE I) AND IPE(I) TO NEXT YOUNGER +C BROTHER OF NODE I IF IT HAS ONE. +C FIRST PASS IS FOR NODES WITHOUT ELIMINATIONS. + DO 20 I = 1,N + IF (NV(I).GT.0) GO TO 20 + IF = -IPE(I) + IS = -IPS(IF) + IF (IS.GT.0) IPE(I) = IS + IPS(IF) = -I + 20 CONTINUE +C NR IS DECREMENTED FOR EACH ROOT NODE. THESE ARE STORED IN +C NE(I),I=NR,N. + NR = N + 1 +C SECOND PASS TO ADD NODES WITH ELIMINATIONS. + DO 50 I = 1,N + IF (NV(I).LE.0) GO TO 50 +C NODE IF IS THE FATHER OF NODE I. + IF = -IPE(I) + IF (IF.EQ.0) GO TO 40 + IS = -IPS(IF) +C JUMP IF NODE IF HAS NO SONS YET. + IF (IS.LE.0) GO TO 30 +C SET POINTER TO NEXT BROTHER + IPE(I) = IS +C NODE I IS ELDEST SON OF NODE IF. + 30 IPS(IF) = -I + GO TO 50 +C WE HAVE A ROOT + 40 NR = NR - 1 + NE(NR) = I + 50 CONTINUE +C +C DEPTH-FIRST SEARCH. +C IL HOLDS THE CURRENT TREE LEVEL. ROOTS ARE AT LEVEL N, THEIR SONS +C ARE AT LEVEL N-1, ETC. +C IS HOLDS THE CURRENT ELIMINATION STAGE. WE ACCUMULATE THE NUMBER +C OF ELIMINATIONS AT STAGE IS DIRECTLY IN NE(IS). THE NUMBER OF +C ASSEMBLIES IS ACCUMULATED TEMPORARILY IN NA(IL), FOR TREE +C LEVEL IL, AND IS TRANSFERED TO NA(IS) WHEN WE REACH THE +C APPROPRIATE STAGE IS. + IS = 1 +C I IS THE CURRENT NODE. + I = 0 + DO 160 K = 1,N + IF (I.GT.0) GO TO 60 +C PICK UP NEXT ROOT. + I = NE(NR) + NE(NR) = 0 + NR = NR + 1 + IL = N + NA(N) = 0 +C GO TO SON FOR AS LONG AS POSSIBLE, CLEARING FATHER-SON POINTERS +C IN IPS AS EACH IS USED AND SETTING NA(IL)=0 FOR ALL LEVELS +C REACHED. + 60 DO 70 L = 1,N + IF (IPS(I).GE.0) GO TO 80 + ISON = -IPS(I) + IPS(I) = 0 + I = ISON + IL = IL - 1 + NA(IL) = 0 + 70 CONTINUE +C RECORD POSITION OF NODE I IN THE ORDER. + 80 IPS(I) = K + NE(IS) = NE(IS) + 1 +C JUMP IF NODE HAS NO ELIMINATIONS. + IF (NV(I).LE.0) GO TO 120 + IF (IL.LT.N) NA(IL+1) = NA(IL+1) + 1 + NA(IS) = NA(IL) + ND(IS) = NV(I) +C CHECK FOR STATIC CONDENSATION + IF (NA(IS).NE.1) GO TO 90 + IF (ND(IS-1)-NE(IS-1).EQ.ND(IS)) GO TO 100 +C CHECK FOR SMALL NUMBERS OF ELIMINATIONS IN BOTH LAST TWO STEPS. + 90 IF (NE(IS).GE.NEMIN) GO TO 110 + IF (NA(IS).EQ.0) GO TO 110 + IF (NE(IS-1).GE.NEMIN) GO TO 110 +C COMBINE THE LAST TWO STEPS + 100 NA(IS-1) = NA(IS-1) + NA(IS) - 1 + ND(IS-1) = ND(IS) + NE(IS-1) + NE(IS-1) = NE(IS) + NE(IS-1) + NE(IS) = 0 + GO TO 120 + + 110 IS = IS + 1 + 120 IB = IPE(I) + IF (IB.GE.0) THEN +C NODE I HAS A BROTHER OR IS A ROOT + IF (IB.GT.0) NA(IL) = 0 + I = IB + ELSE +C GO TO FATHER OF NODE I + I = -IB + IL = IL + 1 + END IF + 160 CONTINUE + NSTEPS = IS - 1 + RETURN + + END + SUBROUTINE MA27MD(N,NZ,IRN,ICN,PERM,NA,NE,ND,NSTEPS,LSTKI,LSTKR, + + IW,INFO,OPS) +C +C STORAGE AND OPERATION COUNT EVALUATION. +C +C EVALUATE NUMBER OF OPERATIONS AND SPACE REQUIRED BY FACTORIZATION +C USING MA27B/BD. THE VALUES GIVEN ARE EXACT ONLY IF NO NUMERICAL +C PIVOTING IS PERFORMED AND THEN ONLY IF IRN(1) WAS NOT +C EQUIVALENCED TO IW(1) BY THE USER BEFORE CALLING MA27A/AD. IF +C THE EQUIVALENCE HAS BEEN MADE ONLY AN UPPER BOUND FOR NIRNEC +C AND NRLNEC CAN BE CALCULATED ALTHOUGH THE OTHER COUNTS WILL +C STILL BE EXACT. +C +C N MUST BE SET TO THE MATRIX ORDER. IT IS NOT ALTERED. +C NZ MUST BE SET TO THE NUMBER OF NON-ZEROS INPUT. IT IS NOT ALTERED. +C IRN,ICN. UNLESS IRN(1) HAS BEEN EQUIVALENCED TO IW(1) +C IRN,ICN MUST BE SET TO THE ROW AND COLUMN INDICES OF THE +C NON-ZEROS ON INPUT. THEY ARE NOT ALTERED BY MA27M/MD. +C PERM MUST BE SET TO THE POSITION IN THE PIVOT ORDER OF EACH ROW. +C IT IS NOT ALTERED. +C NA,NE,ND MUST BE SET TO HOLD, FOR EACH TREE NODE, THE NUMBER OF STACK +C ELEMENTS ASSEMBLED, THE NUMBER OF ELIMINATIONS AND THE SIZE OF +C THE ASSEMBLED FRONT MATRIX RESPECTIVELY. THEY ARE NOT ALTERED. +C NSTEPS MUST BE SET TO HOLD THE NUMBER OF TREE NODES. IT IS NOT +C ALTERED. +C LSTKI IS USED AS A WORK ARRAY BY MA27M/MD. +C LSTKR. IF IRN(1) IS EQUIVALENCED TO IW(1) THEN LSTKR(I) +C MUST HOLD THE TOTAL NUMBER OF OFF-DIAGONAL ENTRIES (INCLUDING +C DUPLICATES) IN ROW I (I=1,..,N) OF THE ORIGINAL MATRIX. IT +C IS USED AS WORKSPACE BY MA27M/MD. +C IW IS A WORKSPACE ARRAY USED BY OTHER SUBROUTINES AND PASSED TO THIS +C SUBROUTINE ONLY SO THAT A TEST FOR EQUIVALENCE WITH IRN CAN BE +C MADE. +C +C COUNTS FOR OPERATIONS AND STORAGE ARE ACCUMULATED IN VARIABLES +C OPS,NRLTOT,NIRTOT,NRLNEC,NIRNEC,NRLADU,NRLNEC,NIRNEC. +C OPS NUMBER OF MULTIPLICATIONS AND ADDITIONS DURING FACTORIZATION. +C NRLADU,NIRADU REAL AND INTEGER STORAGE RESPECTIVELY FOR THE +C MATRIX FACTORS. +C NRLTOT,NIRTOT REAL AND INTEGER STRORAGE RESPECTIVELY REQUIRED +C FOR THE FACTORIZATION IF NO COMPRESSES ARE ALLOWED. +C NRLNEC,NIRNEC REAL AND INTEGER STORAGE RESPECTIVELY REQUIRED FOR +C THE FACTORIZATION IF COMPRESSES ARE ALLOWED. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C OPS ACCUMULATES THE NO. OF MULTIPLY/ADD PAIRS NEEDED TO CREATE THE +C TRIANGULAR FACTORIZATION, IN THE DEFINITE CASE. +C +C .. Scalar Arguments .. + DOUBLE PRECISION OPS + INTEGER N,NSTEPS,NZ +C .. +C .. Array Arguments .. + INTEGER ICN(*),IRN(*),IW(*),LSTKI(N),LSTKR(N),NA(NSTEPS), + + ND(NSTEPS),NE(NSTEPS),PERM(N),INFO(20) +C .. +C .. Local Scalars .. + INTEGER I,INEW,IOLD,IORG,IROW,ISTKI,ISTKR,ITOP,ITREE,JOLD,JORG,K, + + LSTK,NASSR,NELIM,NFR,NSTK,NUMORG,NZ1,NZ2 + DOUBLE PRECISION DELIM + INTEGER NRLADU,NIRADU,NIRTOT,NRLTOT,NIRNEC,NRLNEC +C .. +C .. Intrinsic Functions .. + INTRINSIC MAX,MIN +C .. +C .. Executable Statements .. +C + IF (NZ.EQ.0) GO TO 20 +C JUMP IF IW AND IRN HAVE NOT BEEN EQUIVALENCED. + IF (IRN(1).NE.IW(1)) GO TO 20 +C RESET IRN(1). + IRN(1) = IW(1) - 1 +C THE TOTAL NUMBER OF OFF-DIAGONAL ENTRIES IS ACCUMULATED IN NZ2. +C LSTKI IS SET TO HOLD THE TOTAL NUMBER OF ENTRIES (INCUDING +C THE DIAGONAL) IN EACH ROW IN PERMUTED ORDER. + NZ2 = 0 + DO 10 IOLD = 1,N + INEW = PERM(IOLD) + LSTKI(INEW) = LSTKR(IOLD) + 1 + NZ2 = NZ2 + LSTKR(IOLD) + 10 CONTINUE +C NZ1 IS THE NUMBER OF ENTRIES IN ONE TRIANGLE INCLUDING THE DIAGONAL. +C NZ2 IS THE TOTAL NUMBER OF ENTRIES INCLUDING THE DIAGONAL. + NZ1 = NZ2/2 + N + NZ2 = NZ2 + N + GO TO 60 +C COUNT (IN LSTKI) NON-ZEROS IN ORIGINAL MATRIX BY PERMUTED ROW (UPPER +C TRIANGLE ONLY). INITIALIZE COUNTS. + 20 DO 30 I = 1,N + LSTKI(I) = 1 + 30 CONTINUE +C ACCUMULATE NUMBER OF NON-ZEROS WITH INDICES IN RANGE IN NZ1 +C DUPLICATES ON THE DIAGONAL ARE IGNORED BUT NZ1 INCLUDES ANY +C DIAGONALS NOT PRESENT ON INPUT. +C ACCUMULATE ROW COUNTS IN LSTKI. + NZ1 = N + IF (NZ.EQ.0) GO TO 50 + DO 40 I = 1,NZ + IOLD = IRN(I) + JOLD = ICN(I) +C JUMP IF INDEX IS OUT OF RANGE. + IF (IOLD.LT.1 .OR. IOLD.GT.N) GO TO 40 + IF (JOLD.LT.1 .OR. JOLD.GT.N) GO TO 40 + IF (IOLD.EQ.JOLD) GO TO 40 + NZ1 = NZ1 + 1 + IROW = MIN(PERM(IOLD)+0,PERM(JOLD)+0) + LSTKI(IROW) = LSTKI(IROW) + 1 + 40 CONTINUE + 50 NZ2 = NZ1 +C ISTKR,ISTKI CURRENT NUMBER OF STACK ENTRIES IN +C REAL AND INTEGER STORAGE RESPECTIVELY. +C OPS,NRLADU,NIRADU,NIRTOT,NRLTOT,NIRNEC,NRLNEC,NZ2 ARE DEFINED ABOVE. +C NZ2 CURRENT NUMBER OF ORIGINAL MATRIX ENTRIES NOT YET PROCESSED. +C NUMORG CURRENT TOTAL NUMBER OF ROWS ELIMINATED. +C ITOP CURRENT NUMBER OF ELEMENTS ON THE STACK. + 60 ISTKI = 0 + ISTKR = 0 + OPS = 0.0D0 + NRLADU = 0 +C ONE LOCATION IS NEEDED TO RECORD THE NUMBER OF BLOCKS +C ACTUALLY USED. + NIRADU = 1 + NIRTOT = NZ1 + NRLTOT = NZ1 + NIRNEC = NZ2 + NRLNEC = NZ2 + NUMORG = 0 + ITOP = 0 +C +C EACH PASS THROUGH THIS LOOP PROCESSES A NODE OF THE TREE. + DO 100 ITREE = 1,NSTEPS + NELIM = NE(ITREE) + DELIM = NELIM + NFR = ND(ITREE) + NSTK = NA(ITREE) +C ADJUST STORAGE COUNTS ON ASSEMBLY OF CURRENT FRONTAL MATRIX. + NASSR = NFR* (NFR+1)/2 + IF (NSTK.NE.0) NASSR = NASSR - LSTKR(ITOP) + 1 + NRLTOT = MAX(NRLTOT,NRLADU+NASSR+ISTKR+NZ1) + NIRTOT = MAX(NIRTOT,NIRADU+NFR+2+ISTKI+NZ1) + NRLNEC = MAX(NRLNEC,NRLADU+NASSR+ISTKR+NZ2) + NIRNEC = MAX(NIRNEC,NIRADU+NFR+2+ISTKI+NZ2) +C DECREASE NZ2 BY THE NUMBER OF ENTRIES IN ROWS BEING ELIMINATED AT +C THIS STAGE. + DO 70 IORG = 1,NELIM + JORG = NUMORG + IORG + NZ2 = NZ2 - LSTKI(JORG) + 70 CONTINUE + NUMORG = NUMORG + NELIM +C JUMP IF THERE ARE NO STACK ASSEMBLIES AT THIS NODE. + IF (NSTK.LE.0) GO TO 90 +C REMOVE ELEMENTS FROM THE STACK. THERE ARE ITOP ELEMENTS ON THE +C STACK WITH THE APPROPRIATE ENTRIES IN LSTKR,LSTKI GIVING +C THE REAL AND INTEGER STORAGE RESPECTIVELY FOR EACH STACK +C ELEMENT. + DO 80 K = 1,NSTK + LSTK = LSTKR(ITOP) + ISTKR = ISTKR - LSTK + LSTK = LSTKI(ITOP) + ISTKI = ISTKI - LSTK + ITOP = ITOP - 1 + 80 CONTINUE +C ACCUMULATE NON-ZEROS IN FACTORS AND NUMBER OF OPERATIONS. + 90 NRLADU = NRLADU + (NELIM* (2*NFR-NELIM+1))/2 + NIRADU = NIRADU + 2 + NFR + IF (NELIM.EQ.1) NIRADU = NIRADU - 1 + OPS = OPS + ((NFR*DELIM*(NFR+1)-(2*NFR+1)*DELIM*(DELIM+1)/2+ + + DELIM* (DELIM+1)* (2*DELIM+1)/6)/2) + IF (ITREE.EQ.NSTEPS) GO TO 100 +C JUMP IF ALL OF FRONTAL MATRIX HAS BEEN ELIMINATED. + IF (NFR.EQ.NELIM) GO TO 100 +C STACK REMAINDER OF ELEMENT. + ITOP = ITOP + 1 + LSTKR(ITOP) = (NFR-NELIM)* (NFR-NELIM+1)/2 + LSTKI(ITOP) = NFR - NELIM + 1 + ISTKI = ISTKI + LSTKI(ITOP) + ISTKR = ISTKR + LSTKR(ITOP) +C WE DO NOT NEED TO ADJUST THE COUNTS FOR THE REAL STORAGE BECAUSE +C THE REMAINDER OF THE FRONTAL MATRIX IS SIMPLY MOVED IN THE +C STORAGE FROM FACTORS TO STACK AND NO EXTRA STORAGE IS REQUIRED. + NIRTOT = MAX(NIRTOT,NIRADU+ISTKI+NZ1) + NIRNEC = MAX(NIRNEC,NIRADU+ISTKI+NZ2) + 100 CONTINUE +C +C ADJUST THE STORAGE COUNTS TO ALLOW FOR THE USE OF THE REAL AND +C INTEGER STORAGE FOR PURPOSES OTHER THAN PURELY THE +C FACTORIZATION ITSELF. +C THE SECOND TWO TERMS ARE THE MINUMUM AMOUNT REQUIRED BY MA27N/ND. + NRLNEC = MAX(NRLNEC,N+MAX(NZ,NZ1)) + NRLTOT = MAX(NRLTOT,N+MAX(NZ,NZ1)) + NRLNEC = MIN(NRLNEC,NRLTOT) + NIRNEC = MAX(NZ,NIRNEC) + NIRTOT = MAX(NZ,NIRTOT) + NIRNEC = MIN(NIRNEC,NIRTOT) + + INFO(3) = NRLTOT + INFO(4) = NIRTOT + INFO(5) = NRLNEC + INFO(6) = NIRNEC + INFO(7) = NRLADU + INFO(8) = NIRADU + RETURN + + END + SUBROUTINE MA27ND(N,NZ,NZ1,A,LA,IRN,ICN,IW,LIW,PERM,IW2,ICNTL, + + INFO) +C +C SORT PRIOR TO FACTORIZATION USING MA27O/OD. +C +C THIS SUBROUTINE REORDERS THE USER'S INPUT SO THAT THE UPPER TRIANGLE +C OF THE PERMUTED MATRIX, INCLUDING THE DIAGONAL, IS +C HELD ORDERED BY ROWS AT THE END OF THE STORAGE FOR A AND IW. +C IT IGNORES ENTRIES WITH ONE OR BOTH INDICES OUT OF RANGE AND +C ACCUMULATES DIAGONAL ENTRIES. +C IT ADDS EXPLICIT ZEROS ON THE DIAGONAL WHERE NECESSARY. +C N - MUST BE SET TO THE ORDER OF THE MATRIX. +C IT IS NOT ALTERED BY MA27N/ND. +C NZ - ON ENTRY NZ MUST BE SET TO THE NUMBER +C OF NON-ZEROS INPUT. NOT ALTERED BY MA27N/ND. +C NZ1 - ON EXIT NZ1 WILL BE EQUAL TO THE NUMBER OF ENTRIES IN THE +C SORTED MATRIX. +C A - ON ENTRY A(I) MUST +C HOLD THE VALUE OF THE ORIGINAL MATRIX ELEMENT IN POSITION +C (IRN(I),ICN(I)),I=1,NZ. ON EXIT A(LA-NZ1+I),I=1,NZ1 HOLDS +C THE UPPER TRIANGLE OF THE PERMUTED MATRIX BY ROWS WITH +C THE DIAGONAL ENTRY FIRST ALTHOUGH THERE IS NO FURTHER +C ORDERING WITHIN THE ROWS THEMSELVES. +C LA - LENGTH OF ARRAY A. MUST BE AT LEAST N+MAX(NZ,NZ1). +C IT IS NOT ALTERED BY MA27N/ND. +C IRN - IRN(I) MUST BE SET TO +C HOLD THE ROW INDEX OF ENTRY A(I),I=1,NZ. IRN WILL BE +C UNALTERED BY MA27N/ND, UNLESS IT IS EQUIVALENCED WITH IW. +C ICN - ICN(I) MUST BE SET TO +C HOLD THE COLUMN INDEX OF ENTRY A(I),I=1,NZ. ICN WILL BE +C UNALTERED BY MA27N/ND, UNLESS IT IS EQUIVALENCED WITH IW. +C IW - USED AS WORKSPACE AND ON +C EXIT, ENTRIES IW(LIW-NZ1+I),I=1,NZ1 HOLD THE COLUMN INDICES +C (THE ORIGINAL UNPERMUTED INDICES) OF THE CORRESPONDING ENTRY +C OF A WITH THE FIRST ENTRY FOR EACH ROW FLAGGED NEGATIVE. +C IRN(1) MAY BE EQUIVALENCED WITH IW(1) AND ICN(1) MAY BE +C EQUIVALENCED WITH IW(K) WHERE K.GT.NZ. +C LIW - LENGTH OF ARRAY IW. MUST BE AT LEAST AS +C GREAT AS THE MAXIMUM OF NZ AND NZ1. +C NOT ALTERED BY MA27N/ND. +C PERM - PERM(I) HOLDS THE +C POSITION IN THE TENTATIVE PIVOT ORDER OF ROW I IN THE +C ORIGINAL MATRIX,I=1,N. NOT ALTERED BY MA27N/ND. +C IW2 - USED AS WORKSPACE. +C SEE COMMENTS IN CODE IMMEDIATELY PRIOR TO +C EACH USE. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C INFO(1) - ON EXIT FROM MA27N/ND, A ZERO VALUE OF +C INFO(1) INDICATES THAT NO ERROR HAS BEEN DETECTED. +C POSSIBLE NON-ZERO VALUES ARE .. +C +1 WARNING. INDICES OUT OF RANGE. THESE ARE IGNORED, +C THEIR NUMBER IS RECORDED IN INFO(2) OF MA27E/ED AND +C MESSAGES IDENTIFYING THE FIRST TEN ARE OUTPUT ON UNIT +C ICNTL(2). +C -3 INTEGER ARRAY IW IS TOO SMALL. +C -4 DOUBLE PRECISION ARRAY A IS TOO SMALL. +C +C .. Parameters .. + DOUBLE PRECISION ZERO + PARAMETER (ZERO=0.0D0) +C .. +C .. Scalar Arguments .. + INTEGER LA,LIW,N,NZ,NZ1 +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA) + INTEGER ICN(*),IRN(*),IW(LIW),IW2(N),PERM(N),ICNTL(30),INFO(20) +C .. +C .. Local Scalars .. + DOUBLE PRECISION ANEXT,ANOW + INTEGER I,IA,ICH,II,IIW,INEW,IOLD,IPOS,J1,J2,JJ,JNEW,JOLD,JPOS,K +C .. +C .. Intrinsic Functions .. + INTRINSIC MIN +C .. +C .. Executable Statements .. + INFO(1) = 0 +C INITIALIZE WORK ARRAY (IW2) IN PREPARATION FOR +C COUNTING NUMBERS OF NON-ZEROS IN THE ROWS AND INITIALIZE +C LAST N ENTRIES IN A WHICH WILL HOLD THE DIAGONAL ENTRIES + IA = LA + DO 10 IOLD = 1,N + IW2(IOLD) = 1 + A(IA) = ZERO + IA = IA - 1 + 10 CONTINUE +C SCAN INPUT COPYING ROW INDICES FROM IRN TO THE FIRST NZ POSITIONS +C IN IW. THE NEGATIVE OF THE INDEX IS HELD TO FLAG ENTRIES FOR +C THE IN-PLACE SORT. ENTRIES IN IW CORRESPONDING TO DIAGONALS AND +C ENTRIES WITH OUT-OF-RANGE INDICES ARE SET TO ZERO. +C FOR DIAGONAL ENTRIES, REALS ARE ACCUMULATED IN THE LAST N +C LOCATIONS OF A. +C THE NUMBER OF ENTRIES IN EACH ROW OF THE PERMUTED MATRIX IS +C ACCUMULATED IN IW2. +C INDICES OUT OF RANGE ARE IGNORED AFTER BEING COUNTED AND +C AFTER APPROPRIATE MESSAGES HAVE BEEN PRINTED. + INFO(2) = 0 +C NZ1 IS THE NUMBER OF NON-ZEROS HELD AFTER INDICES OUT OF RANGE HAVE +C BEEN IGNORED AND DIAGONAL ENTRIES ACCUMULATED. + NZ1 = N + IF (NZ.EQ.0) GO TO 80 + DO 70 K = 1,NZ + IOLD = IRN(K) + IF (IOLD.GT.N .OR. IOLD.LE.0) GO TO 30 + JOLD = ICN(K) + IF (JOLD.GT.N .OR. JOLD.LE.0) GO TO 30 + INEW = PERM(IOLD) + JNEW = PERM(JOLD) + IF (INEW.NE.JNEW) GO TO 20 + IA = LA - N + IOLD + A(IA) = A(IA) + A(K) + GO TO 60 + + 20 INEW = MIN(INEW,JNEW) +C INCREMENT NUMBER OF ENTRIES IN ROW INEW. + IW2(INEW) = IW2(INEW) + 1 + IW(K) = -IOLD + NZ1 = NZ1 + 1 + GO TO 70 +C ENTRY OUT OF RANGE. IT WILL BE IGNORED AND A FLAG SET. + 30 INFO(1) = 1 + INFO(2) = INFO(2) + 1 + IF (INFO(2).LE.1 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=40) INFO(1) + ENDIF + + 40 FORMAT (' *** WARNING MESSAGE FROM SUBROUTINE MA27BD', + + ' *** INFO(1) =',I2) + + IF (INFO(2).LE.10 .AND. ICNTL(2).GT.0) THEN + WRITE (ICNTL(2),FMT=50) K,IRN(K),ICN(K) + END IF + + 50 FORMAT (I6,'TH NON-ZERO (IN ROW',I6,' AND COLUMN',I6, + + ') IGNORED') + + 60 IW(K) = 0 + 70 CONTINUE +C CALCULATE POINTERS (IN IW2) TO THE POSITION IMMEDIATELY AFTER THE END +C OF EACH ROW. + 80 IF (NZ.LT.NZ1 .AND. NZ1.NE.N) GO TO 100 +C ROOM IS INCLUDED FOR THE DIAGONALS. + K = 1 + DO 90 I = 1,N + K = K + IW2(I) + IW2(I) = K + 90 CONTINUE + GO TO 120 +C ROOM IS NOT INCLUDED FOR THE DIAGONALS. + 100 K = 1 + DO 110 I = 1,N + K = K + IW2(I) - 1 + IW2(I) = K + 110 CONTINUE +C FAIL IF INSUFFICIENT SPACE IN ARRAYS A OR IW. + 120 IF (NZ1.GT.LIW) GO TO 210 + IF (NZ1+N.GT.LA) GO TO 220 +C NOW RUN THROUGH NON-ZEROS IN ORDER PLACING THEM IN THEIR NEW +C POSITION AND DECREMENTING APPROPRIATE IW2 ENTRY. IF WE ARE +C ABOUT TO OVERWRITE AN ENTRY NOT YET MOVED, WE MUST DEAL WITH +C THIS AT THIS TIME. + IF (NZ1.EQ.N) GO TO 180 + DO 140 K = 1,NZ + IOLD = -IW(K) + IF (IOLD.LE.0) GO TO 140 + JOLD = ICN(K) + ANOW = A(K) + IW(K) = 0 + DO 130 ICH = 1,NZ + INEW = PERM(IOLD) + JNEW = PERM(JOLD) + INEW = MIN(INEW,JNEW) + IF (INEW.EQ.PERM(JOLD)) JOLD = IOLD + JPOS = IW2(INEW) - 1 + IOLD = -IW(JPOS) + ANEXT = A(JPOS) + A(JPOS) = ANOW + IW(JPOS) = JOLD + IW2(INEW) = JPOS + IF (IOLD.EQ.0) GO TO 140 + ANOW = ANEXT + JOLD = ICN(JPOS) + 130 CONTINUE + 140 CONTINUE + IF (NZ.GE.NZ1) GO TO 180 +C MOVE UP ENTRIES TO ALLOW FOR DIAGONALS. + IPOS = NZ1 + JPOS = NZ1 - N + DO 170 II = 1,N + I = N - II + 1 + J1 = IW2(I) + J2 = JPOS + IF (J1.GT.JPOS) GO TO 160 + DO 150 JJ = J1,J2 + IW(IPOS) = IW(JPOS) + A(IPOS) = A(JPOS) + IPOS = IPOS - 1 + JPOS = JPOS - 1 + 150 CONTINUE + 160 IW2(I) = IPOS + 1 + IPOS = IPOS - 1 + 170 CONTINUE +C RUN THROUGH ROWS INSERTING DIAGONAL ENTRIES AND FLAGGING BEGINNING +C OF EACH ROW BY NEGATING FIRST COLUMN INDEX. + 180 DO 190 IOLD = 1,N + INEW = PERM(IOLD) + JPOS = IW2(INEW) - 1 + IA = LA - N + IOLD + A(JPOS) = A(IA) + IW(JPOS) = -IOLD + 190 CONTINUE +C MOVE SORTED MATRIX TO THE END OF THE ARRAYS. + IPOS = NZ1 + IA = LA + IIW = LIW + DO 200 I = 1,NZ1 + A(IA) = A(IPOS) + IW(IIW) = IW(IPOS) + IPOS = IPOS - 1 + IA = IA - 1 + IIW = IIW - 1 + 200 CONTINUE + GO TO 230 +C **** ERROR RETURN **** + 210 INFO(1) = -3 + INFO(2) = NZ1 + GO TO 230 + + 220 INFO(1) = -4 + INFO(2) = NZ1 + N +C + 230 RETURN + + END + SUBROUTINE MA27OD(N,NZ,A,LA,IW,LIW,PERM,NSTK,NSTEPS,MAXFRT,NELIM, + + IW2,ICNTL,CNTL,INFO) +C +C FACTORIZATION SUBROUTINE +C +C THIS SUBROUTINE OPERATES ON THE INPUT MATRIX ORDERED BY MA27N/ND AND +C PRODUCES THE FACTORS OF U AND D ('A'=UTRANSPOSE*D*U) FOR USE IN +C SUBSEQUENT SOLUTIONS. GAUSSIAN ELIMINATION IS USED WITH PIVOTS +C CHOSEN FROM THE DIAGONAL. TO ENSURE STABILITY, BLOCK PIVOTS OF +C ORDER 2 WILL BE USED IF THE DIAGONAL ENTRY IS NOT LARGE ENOUGH. +C +C N - MUST BE SET TO THE ORDER OF THE MATRIX. IT IS NOT ALTERED. +C NZ - MUST BE SET TO THE NUMBER OF NON-ZEROS IN UPPER TRIANGLE OF +C PERMUTED MATRIX. NOT ALTERED BY MA27O/OD. +C A - MUST BE SET ON INPUT TO MATRIX HELD BY ROWS REORDERED BY +C PERMUTATION FROM MA27A/AD IN A(LA-NZ+I),I=1,NZ. ON +C EXIT FROM MA27O/OD, THE FACTORS OF U AND D ARE HELD IN +C POSITIONS 1 TO POSFAC-1. +C LA - LENGTH OF ARRAY A. A VALUE FOR LA +C SUFFICIENT FOR DEFINITE SYSTEMS +C WILL HAVE BEEN PROVIDED BY MA27A/AD. NOT ALTERED BY MA27O/OD. +C IW - MUST BE SET SO THAT,ON INPUT, IW(LIW-NZ+I),I=1,NZ +C HOLDS THE COLUMN INDEX OF THE ENTRY IN A(LA-NZ+I). ON EXIT, +C IW HOLDS INTEGER INDEXING INFORMATION ON THE FACTORS. +C THE ABSOLUTE VALUE OF THE FIRST ENTRY IN IW WILL BE SET TO +C THE NUMBER OF BLOCK PIVOTS ACTUALLY USED. THIS MAY BE +C DIFFERENT FROM NSTEPS SINCE NUMERICAL CONSIDERATIONS +C MAY PREVENT US CHOOSING A PIVOT AT EACH STAGE. IF THIS ENTRY +C IN IW IS NEGATIVE, THEN AT LEAST ONE TWO BY TWO +C PIVOT HAS BEEN USED DURING THE DECOMPOSITION. +C INTEGER INFORMATION ON EACH BLOCK PIVOT ROW FOLLOWS. FOR +C EACH BLOCK PIVOT ROW THE COLUMN INDICES ARE PRECEDED BY A +C COUNT OF THE NUMBER OF ROWS AND COLUMNS IN THE BLOCK PIVOT +C WHERE, IF ONLY ONE ROW IS PRESENT, ONLY THE NUMBER OF +C COLUMNS TOGETHER WITH A NEGATIVE FLAG IS HELD. THE FIRST +C COLUMN INDEX FOR A TWO BY TWO PIVOT IS FLAGGED NEGATIVE. +C LIW - LENGTH OF ARRAY IW. A VALUE FOR LIW SUFFICIENT FOR +C DEFINITE SYSTEMS +C WILL HAVE BEEN PROVIDED BY MA27A/AD. NOT ALTERED BY MA27O/OD +C PERM - PERM(I) MUST BE SET TO POSITION OF ROW/COLUMN I IN THE +C TENTATIVE PIVOT ORDER GENERATED BY MA27A/AD. +C IT IS NOT ALTERED BY MA27O/OD. +C NSTK - MUST BE LEFT UNCHANGED SINCE OUTPUT FROM MA27A/AD. NSTK(I) +C GIVES THE NUMBER OF GENERATED STACK ELEMENTS ASSEMBLED AT +C STAGE I. IT IS NOT ALTERED BY MA27O/OD. +C NSTEPS - LENGTH OF ARRAYS NSTK AND NELIM. VALUE IS GIVEN ON OUTPUT +C FROM MA27A/AD (WILL NEVER EXCEED N). IT IS NOT ALTERED BY +C MA27O/OD. +C MAXFRT - NEED NOT BE SET ON INPUT. ON OUTPUT +C MAXFRT WILL BE SET TO THE MAXIMUM FRONT SIZE ENCOUNTERED +C DURING THE DECOMPOSITION. +C NELIM - MUST BE UNCHANGED SINCE OUTPUT FROM MA27A/AD. NELIM(I) +C GIVES THE NUMBER OF ORIGINAL ROWS ASSEMBLED AT STAGE I. +C IT IS NOT ALTERED BY MA27O/OD. +C IW2 - INTEGER ARRAY OF LENGTH N. USED AS WORKSPACE BY MA27O/OD. +C ALTHOUGH WE COULD HAVE USED A SHORT WORD INTEGER IN THE IBM +C VERSION, WE HAVE NOT DONE SO BECAUSE THERE IS A SPARE +C FULL INTEGER ARRAY (USED IN THE SORT BEFORE MA27O/OD) +C AVAILABLE WHEN MA27O/OD IS CALLED FROM MA27B/BD. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C CNTL is a DOUBLE PRECISION array of length 5, see MA27A/AD. +C INFO is an INTEGER array of length 20, see MA27A/AD. +C INFO(1) - INTEGER VARIABLE. DIAGNOSTIC FLAG. A ZERO VALUE ON EXIT +C INDICATES SUCCESS. POSSIBLE NEGATIVE VALUES ARE ... +C -3 INSUFFICIENT STORAGE FOR IW. +C -4 INSUFFICIENT STORAGE FOR A. +C -5 ZERO PIVOT FOUND IN FACTORIZATION OF DEFINITE MATRIX. +C +C .. Parameters .. + DOUBLE PRECISION ZERO,HALF,ONE + PARAMETER (ZERO=0.0D0,HALF=0.5D0,ONE=1.0D0) +C .. +C .. Scalar Arguments .. + INTEGER LA,LIW,MAXFRT,N,NSTEPS,NZ +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA),CNTL(5) + INTEGER IW(LIW),IW2(N),NELIM(NSTEPS),NSTK(NSTEPS),PERM(N) + INTEGER ICNTL(30),INFO(20) +C .. +C .. Local Scalars .. + DOUBLE PRECISION AMAX,AMULT,AMULT1,AMULT2,DETPIV,RMAX,SWOP, + + THRESH,TMAX,UU + INTEGER AINPUT,APOS,APOS1,APOS2,APOS3,ASTK,ASTK2,AZERO,I,IASS, + + IBEG,IDUMMY,IELL,IEND,IEXCH,IFR,IINPUT,IOLDPS,IORG,IPIV, + + IPMNP,IPOS,IROW,ISNPIV,ISTK,ISTK2,ISWOP,IWPOS,IX,IY,J,J1, + + J2,JCOL,JDUMMY,JFIRST,JJ,JJ1,JJJ,JLAST,JMAX,JMXMIP,JNEW, + + JNEXT,JPIV,JPOS,K,K1,K2,KDUMMY,KK,KMAX,KROW,LAELL,LAPOS2, + + LIELL,LNASS,LNPIV,LT,LTOPST,NASS,NBLK,NEWEL,NFRONT,NPIV, + + NPIVP1,NTOTPV,NUMASS,NUMORG,NUMSTK,PIVSIZ,POSFAC,POSPV1, + + POSPV2 + INTEGER IDIAG +C IDIAG IS A TEMPORARY FOR THE DISPLACEMENT FROM THE START OF THE +C ASSEMBLED MATRIX (OF ORDER IX) OF THE DIAGONAL ENTRY IN ITS ROW IY. + INTEGER NTWO,NEIG,NCMPBI,NCMPBR,NRLBDU,NIRBDU +C .. +C .. External Subroutines .. + EXTERNAL MA27PD +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MAX,MIN +C .. +C .. Executable Statements .. +C INITIALIZATION. +C NBLK IS THE NUMBER OF BLOCK PIVOTS USED. + NBLK = 0 + NTWO = 0 + NEIG = 0 + NCMPBI = 0 + NCMPBR = 0 + MAXFRT = 0 + NRLBDU = 0 + NIRBDU = 0 +C A PRIVATE VARIABLE UU IS SET TO CNTL(1), SO THAT CNTL(1) WILL REMAIN +C UNALTERED. + UU = MIN(CNTL(1),HALF) + UU = MAX(UU,-HALF) + DO 10 I = 1,N + IW2(I) = 0 + 10 CONTINUE +C IWPOS IS POINTER TO FIRST FREE POSITION FOR FACTORS IN IW. +C POSFAC IS POINTER FOR FACTORS IN A. AT EACH PASS THROUGH THE +C MAJOR LOOP POSFAC INITIALLY POINTS TO THE FIRST FREE LOCATION +C IN A AND THEN IS SET TO THE POSITION OF THE CURRENT PIVOT IN A. +C ISTK IS POINTER TO TOP OF STACK IN IW. +C ISTK2 IS POINTER TO BOTTOM OF STACK IN IW (NEEDED BY COMPRESS). +C ASTK IS POINTER TO TOP OF STACK IN A. +C ASTK2 IS POINTER TO BOTTOM OF STACK IN A (NEEDED BY COMPRESS). +C IINPUT IS POINTER TO CURRENT POSITION IN ORIGINAL ROWS IN IW. +C AINPUT IS POINTER TO CURRENT POSITION IN ORIGINAL ROWS IN A. +C AZERO IS POINTER TO LAST POSITION ZEROED IN A. +C NTOTPV IS THE TOTAL NUMBER OF PIVOTS SELECTED. THIS IS USED +C TO DETERMINE WHETHER THE MATRIX IS SINGULAR. + IWPOS = 2 + POSFAC = 1 + ISTK = LIW - NZ + 1 + ISTK2 = ISTK - 1 + ASTK = LA - NZ + 1 + ASTK2 = ASTK - 1 + IINPUT = ISTK + AINPUT = ASTK + AZERO = 0 + NTOTPV = 0 +C NUMASS IS THE ACCUMULATED NUMBER OF ROWS ASSEMBLED SO FAR. + NUMASS = 0 +C +C EACH PASS THROUGH THIS MAIN LOOP PERFORMS ALL THE OPERATIONS +C ASSOCIATED WITH ONE SET OF ASSEMBLY/ELIMINATIONS. + DO 760 IASS = 1,NSTEPS +C NASS WILL BE SET TO THE NUMBER OF FULLY ASSEMBLED VARIABLES IN +C CURRENT NEWLY CREATED ELEMENT. + NASS = NELIM(IASS) +C NEWEL IS A POINTER INTO IW TO CONTROL OUTPUT OF INTEGER INFORMATION +C FOR NEWLY CREATED ELEMENT. + NEWEL = IWPOS + 1 +C SYMBOLICALLY ASSEMBLE INCOMING ROWS AND GENERATED STACK ELEMENTS +C ORDERING THE RESULTANT ELEMENT ACCORDING TO PERMUTATION PERM. WE +C ASSEMBLE THE STACK ELEMENTS FIRST BECAUSE THESE WILL ALREADY BE +C ORDERED. +C SET HEADER POINTER FOR MERGE OF INDEX LISTS. + JFIRST = N + 1 +C INITIALIZE NUMBER OF VARIABLES IN CURRENT FRONT. + NFRONT = 0 + NUMSTK = NSTK(IASS) + LTOPST = 1 + LNASS = 0 +C JUMP IF NO STACK ELEMENTS ARE BEING ASSEMBLED AT THIS STAGE. + IF (NUMSTK.EQ.0) GO TO 80 + J2 = ISTK - 1 + LNASS = NASS + LTOPST = ((IW(ISTK)+1)*IW(ISTK))/2 + DO 70 IELL = 1,NUMSTK +C ASSEMBLE ELEMENT IELL PLACING +C THE INDICES INTO A LINKED LIST IN IW2 ORDERED +C ACCORDING TO PERM. + JNEXT = JFIRST + JLAST = N + 1 + J1 = J2 + 2 + J2 = J1 - 1 + IW(J1-1) +C RUN THROUGH INDEX LIST OF STACK ELEMENT IELL. + DO 60 JJ = J1,J2 + J = IW(JJ) +C JUMP IF ALREADY ASSEMBLED + IF (IW2(J).GT.0) GO TO 60 + JNEW = PERM(J) +C IF VARIABLE WAS PREVIOUSLY FULLY SUMMED BUT WAS NOT PIVOTED ON +C EARLIER BECAUSE OF NUMERICAL TEST, INCREMENT NUMBER OF FULLY +C SUMMED ROWS/COLUMNS IN FRONT. + IF (JNEW.LE.NUMASS) NASS = NASS + 1 +C FIND POSITION IN LINKED LIST FOR NEW VARIABLE. NOTE THAT WE START +C FROM WHERE WE LEFT OFF AFTER ASSEMBLY OF PREVIOUS VARIABLE. + DO 20 IDUMMY = 1,N + IF (JNEXT.EQ.N+1) GO TO 30 + IF (PERM(JNEXT).GT.JNEW) GO TO 30 + JLAST = JNEXT + JNEXT = IW2(JLAST) + 20 CONTINUE + 30 IF (JLAST.NE.N+1) GO TO 40 + JFIRST = J + GO TO 50 + + 40 IW2(JLAST) = J + 50 IW2(J) = JNEXT + JLAST = J +C INCREMENT NUMBER OF VARIABLES IN THE FRONT. + NFRONT = NFRONT + 1 + 60 CONTINUE + 70 CONTINUE + LNASS = NASS - LNASS +C NOW INCORPORATE ORIGINAL ROWS. NOTE THAT THE COLUMNS IN THESE ROWS +C NEED NOT BE IN ORDER. WE ALSO PERFORM +C A SWOP SO THAT THE DIAGONAL ENTRY IS THE FIRST IN ITS +C ROW. THIS ALLOWS US TO AVOID STORING THE INVERSE OF ARRAY PERM. + 80 NUMORG = NELIM(IASS) + J1 = IINPUT + DO 150 IORG = 1,NUMORG + J = -IW(J1) + DO 140 IDUMMY = 1,LIW + JNEW = PERM(J) +C JUMP IF VARIABLE ALREADY INCLUDED. + IF (IW2(J).GT.0) GO TO 130 +C HERE WE MUST ALWAYS START OUR SEARCH AT THE BEGINNING. + JLAST = N + 1 + JNEXT = JFIRST + DO 90 JDUMMY = 1,N + IF (JNEXT.EQ.N+1) GO TO 100 + IF (PERM(JNEXT).GT.JNEW) GO TO 100 + JLAST = JNEXT + JNEXT = IW2(JLAST) + 90 CONTINUE + 100 IF (JLAST.NE.N+1) GO TO 110 + JFIRST = J + GO TO 120 + + 110 IW2(JLAST) = J + 120 IW2(J) = JNEXT +C INCREMENT NUMBER OF VARIABLES IN FRONT. + NFRONT = NFRONT + 1 + 130 J1 = J1 + 1 + IF (J1.GT.LIW) GO TO 150 + J = IW(J1) + IF (J.LT.0) GO TO 150 + 140 CONTINUE + 150 CONTINUE +C NOW RUN THROUGH LINKED LIST IW2 PUTTING INDICES OF VARIABLES IN NEW +C ELEMENT INTO IW AND SETTING IW2 ENTRY TO POINT TO THE RELATIVE +C POSITION OF THE VARIABLE IN THE NEW ELEMENT. + IF (NEWEL+NFRONT.LT.ISTK) GO TO 160 +C COMPRESS IW. + CALL MA27PD(A,IW,ISTK,ISTK2,IINPUT,2,NCMPBR,NCMPBI) + IF (NEWEL+NFRONT.LT.ISTK) GO TO 160 + INFO(2) = LIW + 1 + NEWEL + NFRONT - ISTK + GO TO 770 + + 160 J = JFIRST + DO 170 IFR = 1,NFRONT + NEWEL = NEWEL + 1 + IW(NEWEL) = J + JNEXT = IW2(J) + IW2(J) = NEWEL - (IWPOS+1) + J = JNEXT + 170 CONTINUE +C +C ASSEMBLE REALS INTO FRONTAL MATRIX. + MAXFRT = MAX(MAXFRT,NFRONT) + IW(IWPOS) = NFRONT +C FIRST ZERO OUT FRONTAL MATRIX AS APPROPRIATE FIRST CHECKING TO SEE +C IF THERE IS SUFFICIENT SPACE. + LAELL = ((NFRONT+1)*NFRONT)/2 + APOS2 = POSFAC + LAELL - 1 + IF (NUMSTK.NE.0) LNASS = LNASS* (2*NFRONT-LNASS+1)/2 + IF (POSFAC+LNASS-1.GE.ASTK) GO TO 180 + IF (APOS2.LT.ASTK+LTOPST-1) GO TO 190 +C COMPRESS A. + 180 CALL MA27PD(A,IW,ASTK,ASTK2,AINPUT,1,NCMPBR,NCMPBI) + IF (POSFAC+LNASS-1.GE.ASTK) GO TO 780 + IF (APOS2.GE.ASTK+LTOPST-1) GO TO 780 + 190 IF (APOS2.LE.AZERO) GO TO 220 + APOS = AZERO + 1 + LAPOS2 = MIN(APOS2,ASTK-1) + IF (LAPOS2.LT.APOS) GO TO 210 + DO 200 K = APOS,LAPOS2 + A(K) = ZERO + 200 CONTINUE + 210 AZERO = APOS2 +C JUMP IF THERE ARE NO STACK ELEMENTS TO ASSEMBLE. + 220 IF (NUMSTK.EQ.0) GO TO 260 +C PLACE REALS CORRESPONDING TO STACK ELEMENTS IN CORRECT POSITIONS IN A. + DO 250 IELL = 1,NUMSTK + J1 = ISTK + 1 + J2 = ISTK + IW(ISTK) + DO 240 JJ = J1,J2 + IROW = IW(JJ) + IROW = IW2(IROW) + IX = NFRONT + IY = IROW + IDIAG = ((IY-1)* (2*IX-IY+2))/2 + APOS = POSFAC + IDIAG + DO 230 JJJ = JJ,J2 + J = IW(JJJ) + APOS2 = APOS + IW2(J) - IROW + A(APOS2) = A(APOS2) + A(ASTK) + A(ASTK) = ZERO + ASTK = ASTK + 1 + 230 CONTINUE + 240 CONTINUE +C INCREMENT STACK POINTER. + ISTK = J2 + 1 + 250 CONTINUE +C INCORPORATE REALS FROM ORIGINAL ROWS. + 260 DO 280 IORG = 1,NUMORG + J = -IW(IINPUT) +C WE CAN DO THIS BECAUSE THE DIAGONAL IS NOW THE FIRST ENTRY. + IROW = IW2(J) + IX = NFRONT + IY = IROW + IDIAG = ((IY-1)* (2*IX-IY+2))/2 + APOS = POSFAC + IDIAG +C THE FOLLOWING LOOP GOES FROM 1 TO NZ BECAUSE THERE MAY BE DUPLICATES. + DO 270 IDUMMY = 1,NZ + APOS2 = APOS + IW2(J) - IROW + A(APOS2) = A(APOS2) + A(AINPUT) + AINPUT = AINPUT + 1 + IINPUT = IINPUT + 1 + IF (IINPUT.GT.LIW) GO TO 280 + J = IW(IINPUT) + IF (J.LT.0) GO TO 280 + 270 CONTINUE + 280 CONTINUE +C RESET IW2 AND NUMASS. + NUMASS = NUMASS + NUMORG + J1 = IWPOS + 2 + J2 = IWPOS + NFRONT + 1 + DO 290 K = J1,J2 + J = IW(K) + IW2(J) = 0 + 290 CONTINUE +C PERFORM PIVOTING ON ASSEMBLED ELEMENT. +C NPIV IS THE NUMBER OF PIVOTS SO FAR SELECTED. +C LNPIV IS THE NUMBER OF PIVOTS SELECTED AFTER THE LAST PASS THROUGH +C THE THE FOLLOWING LOOP. + LNPIV = -1 + NPIV = 0 + DO 650 KDUMMY = 1,NASS + IF (NPIV.EQ.NASS) GO TO 660 + IF (NPIV.EQ.LNPIV) GO TO 660 + LNPIV = NPIV + NPIVP1 = NPIV + 1 +C JPIV IS USED AS A FLAG TO INDICATE WHEN 2 BY 2 PIVOTING HAS OCCURRED +C SO THAT IPIV IS INCREMENTED CORRECTLY. + JPIV = 1 +C NASS IS MAXIMUM POSSIBLE NUMBER OF PIVOTS. +C WE EITHER TAKE THE DIAGONAL ENTRY OR THE 2 BY 2 PIVOT WITH THE +C LARGEST OFF-DIAGONAL AT EACH STAGE. +C EACH PASS THROUGH THIS LOOP TRIES TO CHOOSE ONE PIVOT. + DO 640 IPIV = NPIVP1,NASS + JPIV = JPIV - 1 +C JUMP IF WE HAVE JUST PROCESSED A 2 BY 2 PIVOT. + IF (JPIV.EQ.1) GO TO 640 + IX = NFRONT-NPIV + IY = IPIV-NPIV + IDIAG = ((IY-1)* (2*IX-IY+2))/2 + APOS = POSFAC + IDIAG +C IF THE USER HAS INDICATED THAT THE MATRIX IS DEFINITE, WE +C DO NOT NEED TO TEST FOR STABILITY BUT WE DO CHECK TO SEE IF THE +C PIVOT IS NON-ZERO OR HAS CHANGED SIGN. +C IF IT IS ZERO, WE EXIT WITH AN ERROR. IF IT HAS CHANGED SIGN +C AND U WAS SET NEGATIVE, THEN WE AGAIN EXIT IMMEDIATELY. IF THE +C PIVOT CHANGES SIGN AND U WAS ZERO, WE CONTINUE WITH THE +C FACTORIZATION BUT PRINT A WARNING MESSAGE ON UNIT ICNTL(2). +C ISNPIV HOLDS A FLAG FOR THE SIGN OF THE PIVOTS TO DATE SO THAT +C A SIGN CHANGE WHEN DECOMPOSING AN ALLEGEDLY DEFINITE MATRIX CAN +C BE DETECTED. + IF (UU.GT.ZERO) GO TO 320 + IF (ABS(A(APOS)).LE.CNTL(3)) GO TO 790 +C JUMP IF THIS IS NOT THE FIRST PIVOT TO BE SELECTED. + IF (NTOTPV.GT.0) GO TO 300 +C SET ISNPIV. + IF (A(APOS).GT.ZERO) ISNPIV = 1 + IF (A(APOS).LT.ZERO) ISNPIV = -1 + 300 IF (A(APOS).GT.ZERO .AND. ISNPIV.EQ.1) GO TO 560 + IF (A(APOS).LT.ZERO .AND. ISNPIV.EQ.-1) GO TO 560 + IF (INFO(1).NE.2) INFO(2) = 0 + INFO(2) = INFO(2) + 1 + INFO(1) = 2 + I = NTOTPV + 1 + IF (ICNTL(2).GT.0 .AND. INFO(2).LE.10) THEN + WRITE (ICNTL(2),FMT=310) INFO(1),I + END IF + + 310 FORMAT (' *** WARNING MESSAGE FROM SUBROUTINE MA27BD', + + ' *** INFO(1) =',I2,/,' PIVOT',I6, + + ' HAS DIFFERENT SIGN FROM THE PREVIOUS ONE') + + ISNPIV = -ISNPIV + IF (UU.EQ.ZERO) GO TO 560 + GO TO 800 + + 320 AMAX = ZERO + TMAX = AMAX +C FIND LARGEST ENTRY TO RIGHT OF DIAGONAL IN ROW OF PROSPECTIVE PIVOT +C IN THE FULLY-SUMMED PART. ALSO RECORD COLUMN OF THIS LARGEST +C ENTRY. + J1 = APOS + 1 + J2 = APOS + NASS - IPIV + IF (J2.LT.J1) GO TO 340 + DO 330 JJ = J1,J2 + IF (ABS(A(JJ)).LE.AMAX) GO TO 330 + JMAX = IPIV + JJ - J1 + 1 + AMAX = ABS(A(JJ)) + 330 CONTINUE +C DO SAME AS ABOVE FOR NON-FULLY-SUMMED PART ONLY HERE WE DO NOT NEED +C TO RECORD COLUMN SO LOOP IS SIMPLER. + 340 J1 = J2 + 1 + J2 = APOS + NFRONT - IPIV + IF (J2.LT.J1) GO TO 360 + DO 350 JJ = J1,J2 + TMAX = MAX(ABS(A(JJ)),TMAX) + 350 CONTINUE +C NOW CALCULATE LARGEST ENTRY IN OTHER PART OF ROW. + 360 RMAX = MAX(TMAX,AMAX) + APOS1 = APOS + KK = NFRONT - IPIV + LT = IPIV - (NPIV+1) + IF (LT.EQ.0) GO TO 380 + DO 370 K = 1,LT + KK = KK + 1 + APOS1 = APOS1 - KK + RMAX = MAX(RMAX,ABS(A(APOS1))) + 370 CONTINUE +C JUMP IF STABILITY TEST SATISFIED. + 380 IF (ABS(A(APOS)).GT.MAX(CNTL(3),UU*RMAX)) GO TO 450 +C CHECK BLOCK PIVOT OF ORDER 2 FOR STABILITY. + IF (ABS(AMAX).LE.CNTL(3)) GO TO 640 + IX = NFRONT-NPIV + IY = JMAX-NPIV + IDIAG = ((IY-1)* (2*IX-IY+2))/2 + APOS2 = POSFAC + IDIAG + DETPIV = A(APOS)*A(APOS2) - AMAX*AMAX + THRESH = ABS(DETPIV) +C SET THRESH TO U TIMES THE RECIPROCAL OF THE MAX-NORM OF THE INVERSE +C OF THE PROSPECTIVE BLOCK. + THRESH = THRESH/ (UU*MAX(ABS(A(APOS))+AMAX, + + ABS(A(APOS2))+AMAX)) +C CHECK 2 BY 2 PIVOT FOR STABILITY. +C FIRST CHECK AGAINST ROW IPIV. + IF (THRESH.LE.RMAX) GO TO 640 +C FIND LARGEST ENTRY IN ROW JMAX. +C FIND MAXIMUM TO THE RIGHT OF THE DIAGONAL. + RMAX = ZERO + J1 = APOS2 + 1 + J2 = APOS2 + NFRONT - JMAX + IF (J2.LT.J1) GO TO 400 + DO 390 JJ = J1,J2 + RMAX = MAX(RMAX,ABS(A(JJ))) + 390 CONTINUE +C NOW CHECK TO THE LEFT OF THE DIAGONAL. +C WE USE TWO LOOPS TO AVOID TESTING FOR ROW IPIV INSIDE THE LOOP. + 400 KK = NFRONT - JMAX + 1 + APOS3 = APOS2 + JMXMIP = JMAX - IPIV - 1 + IF (JMXMIP.EQ.0) GO TO 420 + DO 410 K = 1,JMXMIP + APOS2 = APOS2 - KK + KK = KK + 1 + RMAX = MAX(RMAX,ABS(A(APOS2))) + 410 CONTINUE + 420 IPMNP = IPIV - NPIV - 1 + IF (IPMNP.EQ.0) GO TO 440 + APOS2 = APOS2 - KK + KK = KK + 1 + DO 430 K = 1,IPMNP + APOS2 = APOS2 - KK + KK = KK + 1 + RMAX = MAX(RMAX,ABS(A(APOS2))) + 430 CONTINUE + 440 IF (THRESH.LE.RMAX) GO TO 640 + PIVSIZ = 2 + GO TO 460 + + 450 PIVSIZ = 1 + 460 IROW = IPIV - NPIV +C +C PIVOT HAS BEEN CHOSEN. IF BLOCK PIVOT OF ORDER 2, PIVSIZ IS EQUAL TO +C TWO OTHERWISE PIVSIZ EQUALS ONE.. +C THE FOLLOWING LOOP MOVES THE PIVOT BLOCK TO THE TOP LEFT HAND CORNER +C OF THE FRONTAL MATRIX. + DO 550 KROW = 1,PIVSIZ +C WE JUMP IF SWOP IS NOT NECESSARY. + IF (IROW.EQ.1) GO TO 530 + J1 = POSFAC + IROW + J2 = POSFAC + NFRONT - (NPIV+1) + IF (J2.LT.J1) GO TO 480 + APOS2 = APOS + 1 +C SWOP PORTION OF ROWS WHOSE COLUMN INDICES ARE GREATER THAN LATER ROW. + DO 470 JJ = J1,J2 + SWOP = A(APOS2) + A(APOS2) = A(JJ) + A(JJ) = SWOP + APOS2 = APOS2 + 1 + 470 CONTINUE + 480 J1 = POSFAC + 1 + J2 = POSFAC + IROW - 2 + APOS2 = APOS + KK = NFRONT - (IROW+NPIV) + IF (J2.LT.J1) GO TO 500 +C SWOP PORTION OF ROWS/COLUMNS WHOSE INDICES LIE BETWEEN THE TWO ROWS. + DO 490 JJJ = J1,J2 + JJ = J2 - JJJ + J1 + KK = KK + 1 + APOS2 = APOS2 - KK + SWOP = A(APOS2) + A(APOS2) = A(JJ) + A(JJ) = SWOP + 490 CONTINUE + 500 IF (NPIV.EQ.0) GO TO 520 + APOS1 = POSFAC + KK = KK + 1 + APOS2 = APOS2 - KK +C SWOP PORTION OF COLUMNS WHOSE INDICES ARE LESS THAN EARLIER ROW. + DO 510 JJ = 1,NPIV + KK = KK + 1 + APOS1 = APOS1 - KK + APOS2 = APOS2 - KK + SWOP = A(APOS2) + A(APOS2) = A(APOS1) + A(APOS1) = SWOP + 510 CONTINUE +C SWOP DIAGONALS AND INTEGER INDEXING INFORMATION + 520 SWOP = A(APOS) + A(APOS) = A(POSFAC) + A(POSFAC) = SWOP + IPOS = IWPOS + NPIV + 2 + IEXCH = IWPOS + IROW + NPIV + 1 + ISWOP = IW(IPOS) + IW(IPOS) = IW(IEXCH) + IW(IEXCH) = ISWOP + 530 IF (PIVSIZ.EQ.1) GO TO 550 +C SET VARIABLES FOR THE SWOP OF SECOND ROW OF BLOCK PIVOT. + IF (KROW.EQ.2) GO TO 540 + IROW = JMAX - (NPIV+1) + JPOS = POSFAC + POSFAC = POSFAC + NFRONT - NPIV + NPIV = NPIV + 1 + APOS = APOS3 + GO TO 550 +C RESET VARIABLES PREVIOUSLY SET FOR SECOND PASS. + 540 NPIV = NPIV - 1 + POSFAC = JPOS + 550 CONTINUE +C + IF (PIVSIZ.EQ.2) GO TO 600 +C PERFORM THE ELIMINATION USING ENTRY (IPIV,IPIV) AS PIVOT. +C WE STORE U AND DINVERSE. + 560 A(POSFAC) = ONE/A(POSFAC) + IF (A(POSFAC).LT.ZERO) NEIG = NEIG + 1 + J1 = POSFAC + 1 + J2 = POSFAC + NFRONT - (NPIV+1) + IF (J2.LT.J1) GO TO 590 + IBEG = J2 + 1 + DO 580 JJ = J1,J2 + AMULT = -A(JJ)*A(POSFAC) + IEND = IBEG + NFRONT - (NPIV+JJ-J1+2) +C THE FOLLOWING SPECIAL COMMENT FORCES VECTORIZATION ON THE CRAY-1. +CDIR$ IVDEP + DO 570 IROW = IBEG,IEND + JCOL = JJ + IROW - IBEG + A(IROW) = A(IROW) + AMULT*A(JCOL) + 570 CONTINUE + IBEG = IEND + 1 + A(JJ) = AMULT + 580 CONTINUE + 590 NPIV = NPIV + 1 + NTOTPV = NTOTPV + 1 + JPIV = 1 + POSFAC = POSFAC + NFRONT - NPIV + 1 + GO TO 640 +C PERFORM ELIMINATION USING BLOCK PIVOT OF ORDER TWO. +C REPLACE BLOCK PIVOT BY ITS INVERSE. +C SET FLAG TO INDICATE USE OF 2 BY 2 PIVOT IN IW. + 600 IPOS = IWPOS + NPIV + 2 + NTWO = NTWO + 1 + IW(IPOS) = -IW(IPOS) + POSPV1 = POSFAC + POSPV2 = POSFAC + NFRONT - NPIV + SWOP = A(POSPV2) + IF (DETPIV.LT.ZERO) NEIG = NEIG + 1 + IF (DETPIV.GT.ZERO .AND. SWOP.LT.ZERO) NEIG = NEIG + 2 + A(POSPV2) = A(POSPV1)/DETPIV + A(POSPV1) = SWOP/DETPIV + A(POSPV1+1) = -A(POSPV1+1)/DETPIV + J1 = POSPV1 + 2 + J2 = POSPV1 + NFRONT - (NPIV+1) + IF (J2.LT.J1) GO TO 630 + JJ1 = POSPV2 + IBEG = POSPV2 + NFRONT - (NPIV+1) + DO 620 JJ = J1,J2 + JJ1 = JJ1 + 1 + AMULT1 = - (A(POSPV1)*A(JJ)+A(POSPV1+1)*A(JJ1)) + AMULT2 = - (A(POSPV1+1)*A(JJ)+A(POSPV2)*A(JJ1)) + IEND = IBEG + NFRONT - (NPIV+JJ-J1+3) +C THE FOLLOWING SPECIAL COMMENT FORCES VECTORIZATION ON THE CRAY-1. +CDIR$ IVDEP + DO 610 IROW = IBEG,IEND + K1 = JJ + IROW - IBEG + K2 = JJ1 + IROW - IBEG + A(IROW) = A(IROW) + AMULT1*A(K1) + AMULT2*A(K2) + 610 CONTINUE + IBEG = IEND + 1 + A(JJ) = AMULT1 + A(JJ1) = AMULT2 + 620 CONTINUE + 630 NPIV = NPIV + 2 + NTOTPV = NTOTPV + 2 + JPIV = 2 + POSFAC = POSPV2 + NFRONT - NPIV + 1 + 640 CONTINUE + 650 CONTINUE +C END OF MAIN ELIMINATION LOOP. +C + 660 IF (NPIV.NE.0) NBLK = NBLK + 1 + IOLDPS = IWPOS + IWPOS = IWPOS + NFRONT + 2 + IF (NPIV.EQ.0) GO TO 690 + IF (NPIV.GT.1) GO TO 680 + IW(IOLDPS) = -IW(IOLDPS) + DO 670 K = 1,NFRONT + J1 = IOLDPS + K + IW(J1) = IW(J1+1) + 670 CONTINUE + IWPOS = IWPOS - 1 + GO TO 690 + + 680 IW(IOLDPS+1) = NPIV +C COPY REMAINDER OF ELEMENT TO TOP OF STACK + 690 LIELL = NFRONT - NPIV + IF (LIELL.EQ.0 .OR. IASS.EQ.NSTEPS) GO TO 750 + IF (IWPOS+LIELL.LT.ISTK) GO TO 700 + CALL MA27PD(A,IW,ISTK,ISTK2,IINPUT,2,NCMPBR,NCMPBI) + 700 ISTK = ISTK - LIELL - 1 + IW(ISTK) = LIELL + J1 = ISTK + KK = IWPOS - LIELL - 1 +C THE FOLLOWING SPECIAL COMMENT FORCES VECTORIZATION ON THE CRAY-1. +CDIR$ IVDEP + DO 710 K = 1,LIELL + J1 = J1 + 1 + KK = KK + 1 + IW(J1) = IW(KK) + 710 CONTINUE +C WE COPY IN REVERSE DIRECTION TO AVOID OVERWRITE PROBLEMS. + LAELL = ((LIELL+1)*LIELL)/2 + KK = POSFAC + LAELL + IF (KK.NE.ASTK) GO TO 720 + ASTK = ASTK - LAELL + GO TO 740 +C THE MOVE AND ZEROING OF ARRAY A IS PERFORMED WITH TWO LOOPS SO +C THAT THE CRAY-1 WILL VECTORIZE THEM SAFELY. + 720 KMAX = KK - 1 +C THE FOLLOWING SPECIAL COMMENT FORCES VECTORIZATION ON THE CRAY-1. +CDIR$ IVDEP + DO 730 K = 1,LAELL + KK = KK - 1 + ASTK = ASTK - 1 + A(ASTK) = A(KK) + 730 CONTINUE + KMAX = MIN(KMAX,ASTK-1) + DO 735 K = KK,KMAX + A(K) = ZERO + 735 CONTINUE + 740 AZERO = MIN(AZERO,ASTK-1) + 750 IF (NPIV.EQ.0) IWPOS = IOLDPS + 760 CONTINUE +C +C END OF LOOP ON TREE NODES. +C + IW(1) = NBLK + IF (NTWO.GT.0) IW(1) = -NBLK + NRLBDU = POSFAC - 1 + NIRBDU = IWPOS - 1 + IF (NTOTPV.EQ.N) GO TO 810 + INFO(1) = 3 + INFO(2) = NTOTPV + GO TO 810 +C **** ERROR RETURNS **** + 770 INFO(1) = -3 + GO TO 810 + + 780 INFO(1) = -4 + INFO(2) = LA + MAX(POSFAC+LNASS,APOS2-LTOPST+2) - ASTK + GO TO 810 + + 790 INFO(1) = -5 + INFO(2) = NTOTPV + 1 + GO TO 810 + + 800 INFO(1) = -6 + INFO(2) = NTOTPV + 1 + 810 CONTINUE + INFO(9) = NRLBDU + INFO(10) = NIRBDU + INFO(12) = NCMPBR + INFO(13) = NCMPBI + INFO(14) = NTWO + INFO(15) = NEIG + + RETURN + END + SUBROUTINE MA27PD(A,IW,J1,J2,ITOP,IREAL,NCMPBR,NCMPBI) +C THIS SUBROUTINE PERFORMS A VERY SIMPLE COMPRESS (BLOCK MOVE). +C ENTRIES J1 TO J2 (INCL.) IN A OR IW AS APPROPRIATE ARE MOVED TO +C OCCUPY THE POSITIONS IMMEDIATELY PRIOR TO POSITION ITOP. +C A/IW HOLD THE ARRAY BEING COMPRESSED. +C J1/J2 DEFINE THE ENTRIES BEING MOVED. +C ITOP DEFINES THE POSITION IMMEDIATELY AFTER THE POSITIONS TO WHICH +C J1 TO J2 ARE MOVED. +C IREAL MUST BE SET BY THE USER TO 2 IF THE MOVE IS ON ARRAY IW, +C ANY OTHER VALUE WILL PERFORM THE MOVE ON A. +C NCMPBR and NCMPBI, see INFO(12) and INFO(13) in MA27A/AD (ACCUMULATE +C THE NUMBER OF COMPRESSES OF THE REALS AND INTEGERS PERFORMED BY +C MA27B/BD. +C +C .. Scalar Arguments .. + INTEGER IREAL,ITOP,J1,J2,NCMPBR,NCMPBI +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(*) + INTEGER IW(*) +C .. +C .. Local Scalars .. + INTEGER IPOS,JJ,JJJ +C .. +C .. Executable Statements .. + IPOS = ITOP - 1 + IF (J2.EQ.IPOS) GO TO 50 + IF (IREAL.EQ.2) GO TO 20 + NCMPBR = NCMPBR + 1 + IF (J1.GT.J2) GO TO 40 + DO 10 JJJ = J1,J2 + JJ = J2 - JJJ + J1 + A(IPOS) = A(JJ) + IPOS = IPOS - 1 + 10 CONTINUE + GO TO 40 + + 20 NCMPBI = NCMPBI + 1 + IF (J1.GT.J2) GO TO 40 + DO 30 JJJ = J1,J2 + JJ = J2 - JJJ + J1 + IW(IPOS) = IW(JJ) + IPOS = IPOS - 1 + 30 CONTINUE + 40 J2 = ITOP - 1 + J1 = IPOS + 1 + 50 RETURN + + END + SUBROUTINE MA27QD(N,A,LA,IW,LIW,W,MAXFNT,RHS,IW2,NBLK,LATOP,ICNTL) +C THIS SUBROUTINE PERFORMS FORWARD ELIMINATION +C USING THE FACTOR U TRANSPOSE STORED IN A/IA AFTER MA27B/BD. +C +C N - MUST BE SET TO THE ORDER OF THE MATRIX. NOT ALTERED +C BY MA27Q/QD. +C A - MUST BE SET TO HOLD THE REAL VALUES +C CORRESPONDING TO THE FACTORS OF DINVERSE AND U. THIS MUST BE +C UNCHANGED SINCE THE PRECEDING CALL TO MA27B/BD. NOT ALTERED +C BY MA27Q/QD. +C LA - LENGTH OF ARRAY A. NOT ALTERED BY MA27Q/QD. +C IW - HOLDS THE INTEGER INDEXING +C INFORMATION FOR THE MATRIX FACTORS IN A. THIS MUST BE +C UNCHANGED SINCE THE PRECEDING CALL TO MA27B/BD. NOT ALTERED +C BY MA27Q/QD. +C LIW - LENGTH OF ARRAY IW. NOT ALTERED BY MA27Q/QD. +C W - USED +C AS WORKSPACE BY MA27Q/QD TO HOLD THE COMPONENTS OF THE RIGHT +C HAND SIDES CORRESPONDING TO CURRENT BLOCK PIVOTAL ROWS. +C MAXFNT - MUST BE SET TO THE LARGEST NUMBER OF +C VARIABLES IN ANY BLOCK PIVOT ROW. THIS VALUE WILL HAVE +C BEEN OUTPUT BY MA27B/BD. NOT ALTERED BY MA27Q/QD. +C RHS - ON INPUT, +C MUST BE SET TO HOLD THE RIGHT HAND SIDES FOR THE EQUATIONS +C WHICH THE USER DESIRES TO SOLVE. ON OUTPUT, RHS WILL HOLD +C THE MODIFIED VECTORS CORRESPONDING TO PERFORMING FORWARD +C ELIMINATION ON THE RIGHT HAND SIDES. +C IW2 - NEED NOT BE SET ON ENTRY. ON EXIT IW2(I) (I = 1,NBLK) +C WILL HOLD POINTERS TO THE +C BEGINNING OF EACH BLOCK PIVOT IN ARRAY IW. +C NBLK - NUMBER OF BLOCK PIVOT ROWS. NOT ALTERED BY MA27Q/QD. +C LATOP - NEED NOT BE SET ON ENTRY. ON EXIT, IT IS THE POSITION IN +C A OF THE LAST ENTRY IN THE FACTORS. IT MUST BE PASSED +C UNCHANGED TO MA27R/RD. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C ICNTL(IFRLVL+I) I=1,20 IS USED TO CONTROL WHETHER DIRECT OR INDIRECT +C ACCESS IS USED BY MA27C/CD. INDIRECT ACCESS IS EMPLOYED +C IN FORWARD AND BACK SUBSTITUTION RESPECTIVELY IF THE SIZE OF +C A BLOCK IS LESS THAN ICNTL(IFRLVL+MIN(10,NPIV)) AND +C ICNTL(IFRLVL+10+MIN(10,NPIV)) RESPECTIVELY, WHERE NPIV IS THE +C NUMBER OF PIVOTS IN THE BLOCK. +C + INTEGER IFRLVL + PARAMETER ( IFRLVL=5 ) +C .. Scalar Arguments .. + INTEGER LA,LATOP,LIW,MAXFNT,N,NBLK +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA),RHS(N),W(MAXFNT) + INTEGER IW(LIW),IW2(NBLK),ICNTL(30) +C .. +C .. Local Scalars .. + DOUBLE PRECISION W1,W2 + INTEGER APOS,IBLK,IFR,ILVL,IPIV,IPOS,IRHS,IROW,IST,J,J1,J2,J3,JJ, + + JPIV,K,K1,K2,K3,LIELL,NPIV +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MIN +C .. +C .. Executable Statements .. +C APOS. RUNNING POINTER TO CURRENT PIVOT POSITION IN ARRAY A. +C IPOS. RUNNING POINTER TO BEGINNING OF BLOCK PIVOT ROW IN IW. + APOS = 1 + IPOS = 1 + J2 = 0 + IBLK = 0 + NPIV = 0 + DO 140 IROW = 1,N + IF (NPIV.GT.0) GO TO 90 + IBLK = IBLK + 1 + IF (IBLK.GT.NBLK) GO TO 150 + IPOS = J2 + 1 +C SET UP POINTER IN PREPARATION FOR BACK SUBSTITUTION. + IW2(IBLK) = IPOS +C ABS(LIELL) IS NUMBER OF VARIABLES (COLUMNS) IN BLOCK PIVOT ROW. + LIELL = -IW(IPOS) +C NPIV IS NUMBER OF PIVOTS (ROWS) IN BLOCK PIVOT. + NPIV = 1 + IF (LIELL.GT.0) GO TO 10 + LIELL = -LIELL + IPOS = IPOS + 1 + NPIV = IW(IPOS) + 10 J1 = IPOS + 1 + J2 = IPOS + LIELL + ILVL = MIN(NPIV,10) + IF (LIELL.LT.ICNTL(IFRLVL+ILVL)) GO TO 90 +C +C PERFORM OPERATIONS USING DIRECT ADDRESSING. +C +C LOAD APPROPRIATE COMPONENTS OF RIGHT HAND SIDES INTO ARRAY W. + IFR = 0 + DO 20 JJ = J1,J2 + J = ABS(IW(JJ)+0) + IFR = IFR + 1 + W(IFR) = RHS(J) + 20 CONTINUE +C JPIV IS USED AS A FLAG SO THAT IPIV IS INCREMENTED CORRECTLY AFTER +C THE USE OF A 2 BY 2 PIVOT. + JPIV = 1 + J3 = J1 +C PERFORM OPERATIONS. + DO 70 IPIV = 1,NPIV + JPIV = JPIV - 1 + IF (JPIV.EQ.1) GO TO 70 +C JUMP IF WE HAVE A 2 BY 2 PIVOT. + IF (IW(J3).LT.0) GO TO 40 +C PERFORM FORWARD SUBSTITUTION USING 1 BY 1 PIVOT. + JPIV = 1 + J3 = J3 + 1 + APOS = APOS + 1 + IST = IPIV + 1 + IF (LIELL.LT.IST) GO TO 70 + W1 = W(IPIV) + K = APOS + DO 30 J = IST,LIELL + W(J) = W(J) + A(K)*W1 + K = K + 1 + 30 CONTINUE + APOS = APOS + LIELL - IST + 1 + GO TO 70 +C PERFORM OPERATIONS WITH 2 BY 2 PIVOT. + 40 JPIV = 2 + J3 = J3 + 2 + APOS = APOS + 2 + IST = IPIV + 2 + IF (LIELL.LT.IST) GO TO 60 + W1 = W(IPIV) + W2 = W(IPIV+1) + K1 = APOS + K2 = APOS + LIELL - IPIV + DO 50 J = IST,LIELL + W(J) = W(J) + W1*A(K1) + W2*A(K2) + K1 = K1 + 1 + K2 = K2 + 1 + 50 CONTINUE + 60 APOS = APOS + 2* (LIELL-IST+1) + 1 + 70 CONTINUE +C RELOAD W BACK INTO RHS. + IFR = 0 + DO 80 JJ = J1,J2 + J = ABS(IW(JJ)+0) + IFR = IFR + 1 + RHS(J) = W(IFR) + 80 CONTINUE + NPIV = 0 + GO TO 140 +C +C PERFORM OPERATIONS USING INDIRECT ADDRESSING. +C +C JUMP IF WE HAVE A 2 BY 2 PIVOT. + 90 IF (IW(J1).LT.0) GO TO 110 +C PERFORM FORWARD SUBSTITUTION USING 1 BY 1 PIVOT. + NPIV = NPIV - 1 + APOS = APOS + 1 + J1 = J1 + 1 + IF (J1.GT.J2) GO TO 140 + IRHS = IW(J1-1) + W1 = RHS(IRHS) + K = APOS + DO 100 J = J1,J2 + IRHS = ABS(IW(J)+0) + RHS(IRHS) = RHS(IRHS) + A(K)*W1 + K = K + 1 + 100 CONTINUE + APOS = APOS + J2 - J1 + 1 + GO TO 140 +C PERFORM OPERATIONS WITH 2 BY 2 PIVOT + 110 NPIV = NPIV - 2 + J1 = J1 + 2 + APOS = APOS + 2 + IF (J1.GT.J2) GO TO 130 + IRHS = -IW(J1-2) + W1 = RHS(IRHS) + IRHS = IW(J1-1) + W2 = RHS(IRHS) + K1 = APOS + K3 = APOS + J2 - J1 + 2 + DO 120 J = J1,J2 + IRHS = ABS(IW(J)+0) + RHS(IRHS) = RHS(IRHS) + W1*A(K1) + W2*A(K3) + K1 = K1 + 1 + K3 = K3 + 1 + 120 CONTINUE + 130 APOS = APOS + 2* (J2-J1+1) + 1 + 140 CONTINUE + 150 LATOP = APOS - 1 + RETURN + + END + SUBROUTINE MA27RD(N,A,LA,IW,LIW,W,MAXFNT,RHS,IW2,NBLK,LATOP,ICNTL) +C THIS SUBROUTINE PERFORMS BACKWARD ELIMINATION OPERATIONS +C USING THE FACTORS DINVERSE AND U +C STORED IN A/IW AFTER MA27B/BD. +C +C N - MUST BE SET TO THE ORDER OF THE MATRIX. NOT ALTERED +C BY MA27R/RD. +C A - MUST BE SET TO HOLD THE REAL VALUES CORRESPONDING +C TO THE FACTORS OF DINVERSE AND U. THIS MUST BE +C UNCHANGED SINCE THE PRECEDING CALL TO MA27B/BD. NOT ALTERED +C BY MA27R/RD. +C LA - LENGTH OF ARRAY A. NOT ALTERED BY MA27R/RD. +C IW - HOLDS THE INTEGER INDEXING +C INFORMATION FOR THE MATRIX FACTORS IN A. THIS MUST BE +C UNCHANGED SINCE THE PRECEDING CALL TO MA27B/BD. NOT ALTERED +C BY MA27R/RD. +C LIW - LENGTH OF ARRAY IW. NOT ALTERED BY MA27R/RD. +C W - USED +C AS WORKSPACE BY MA27R/RD TO HOLD THE COMPONENTS OF THE RIGHT +C HAND SIDES CORRESPONDING TO CURRENT BLOCK PIVOTAL ROWS. +C MAXFNT - INTEGER VARIABLE. MUST BE SET TO THE LARGEST NUMBER OF +C VARIABLES IN ANY BLOCK PIVOT ROW. THIS VALUE WAS GIVEN +C ON OUTPUT FROM MA27B/BD. NOT ALTERED BY MA27R/RD. +C RHS - ON INPUT, +C MUST BE SET TO HOLD THE RIGHT HAND SIDE MODIFIED BY THE +C FORWARD SUBSTITUTION OPERATIONS. ON OUTPUT, RHS WILL HOLD +C THE SOLUTION VECTOR. +C IW2 - ON ENTRY IW2(I) (I = 1,NBLK) +C MUST HOLD POINTERS TO THE +C BEGINNING OF EACH BLOCK PIVOT IN ARRAY IW, AS SET BY +C MA27Q/QD. +C NBLK - NUMBER OF BLOCK PIVOT ROWS. NOT ALTERED BY MA27R/RD. +C LATOP - IT IS THE POSITION IN +C A OF THE LAST ENTRY IN THE FACTORS. IT MUST BE UNCHANGED +C SINCE THE CALL TO MA27Q/QD. IT IS NOT ALTERED BY MA27R/RD. +C ICNTL is an INTEGER array of length 30, see MA27A/AD. +C ICNTL(IFRLVL+I) I=1,20 IS USED TO CONTROL WHETHER DIRECT OR INDIRECT +C ACCESS IS USED BY MA27C/CD. INDIRECT ACCESS IS EMPLOYED +C IN FORWARD AND BACK SUBSTITUTION RESPECTIVELY IF THE SIZE OF +C A BLOCK IS LESS THAN ICNTL(IFRLVL+MIN(10,NPIV)) AND +C ICNTL(IFRLVL+10+MIN(10,NPIV)) RESPECTIVELY, WHERE NPIV IS THE +C NUMBER OF PIVOTS IN THE BLOCK. +C + INTEGER IFRLVL + PARAMETER ( IFRLVL=5 ) +C +C .. Scalar Arguments .. + INTEGER LA,LATOP,LIW,MAXFNT,N,NBLK +C .. +C .. Array Arguments .. + DOUBLE PRECISION A(LA),RHS(N),W(MAXFNT) + INTEGER IW(LIW),IW2(NBLK),ICNTL(30) +C .. +C .. Local Scalars .. + DOUBLE PRECISION W1,W2 + INTEGER APOS,APOS2,I1RHS,I2RHS,IBLK,IFR,IIPIV,IIRHS,ILVL,IPIV, + + IPOS,IRHS,IST,J,J1,J2,JJ,JJ1,JJ2,JPIV,JPOS,K,LIELL,LOOP, + + NPIV +C .. +C .. Intrinsic Functions .. + INTRINSIC ABS,MIN +C .. +C .. Executable Statements .. +C APOS. RUNNING POINTER TO CURRENT PIVOT POSITION IN ARRAY A. +C IPOS. RUNNING POINTER TO BEGINNING OF CURRENT BLOCK PIVOT ROW. + APOS = LATOP + 1 + NPIV = 0 + IBLK = NBLK + 1 +C RUN THROUGH BLOCK PIVOT ROWS IN THE REVERSE ORDER. + DO 180 LOOP = 1,N + IF (NPIV.GT.0) GO TO 110 + IBLK = IBLK - 1 + IF (IBLK.LT.1) GO TO 190 + IPOS = IW2(IBLK) +C ABS(LIELL) IS NUMBER OF VARIABLES (COLUMNS) IN BLOCK PIVOT ROW. + LIELL = -IW(IPOS) +C NPIV IS NUMBER OF PIVOTS (ROWS) IN BLOCK PIVOT. + NPIV = 1 + IF (LIELL.GT.0) GO TO 10 + LIELL = -LIELL + IPOS = IPOS + 1 + NPIV = IW(IPOS) + 10 JPOS = IPOS + NPIV + J2 = IPOS + LIELL + ILVL = MIN(10,NPIV) + 10 + IF (LIELL.LT.ICNTL(IFRLVL+ILVL)) GO TO 110 +C +C PERFORM OPERATIONS USING DIRECT ADDRESSING. +C + J1 = IPOS + 1 +C LOAD APPROPRIATE COMPONENTS OF RHS INTO W. + IFR = 0 + DO 20 JJ = J1,J2 + J = ABS(IW(JJ)+0) + IFR = IFR + 1 + W(IFR) = RHS(J) + 20 CONTINUE +C JPIV IS USED AS A FLAG SO THAT IPIV IS INCREMENTED CORRECTLY AFTER +C THE USE OF A 2 BY 2 PIVOT. + JPIV = 1 +C PERFORM ELIMINATIONS. + DO 90 IIPIV = 1,NPIV + JPIV = JPIV - 1 + IF (JPIV.EQ.1) GO TO 90 + IPIV = NPIV - IIPIV + 1 + IF (IPIV.EQ.1) GO TO 30 +C JUMP IF WE HAVE A 2 BY 2 PIVOT. + IF (IW(JPOS-1).LT.0) GO TO 60 +C PERFORM BACK-SUBSTITUTION USING 1 BY 1 PIVOT. + 30 JPIV = 1 + APOS = APOS - (LIELL+1-IPIV) + IST = IPIV + 1 + W1 = W(IPIV)*A(APOS) + IF (LIELL.LT.IST) GO TO 50 + JJ1 = APOS + 1 + DO 40 J = IST,LIELL + W1 = W1 + A(JJ1)*W(J) + JJ1 = JJ1 + 1 + 40 CONTINUE + 50 W(IPIV) = W1 + JPOS = JPOS - 1 + GO TO 90 +C PERFORM BACK-SUBSTITUTION OPERATIONS WITH 2 BY 2 PIVOT + 60 JPIV = 2 + APOS2 = APOS - (LIELL+1-IPIV) + APOS = APOS2 - (LIELL+2-IPIV) + IST = IPIV + 1 + W1 = W(IPIV-1)*A(APOS) + W(IPIV)*A(APOS+1) + W2 = W(IPIV-1)*A(APOS+1) + W(IPIV)*A(APOS2) + IF (LIELL.LT.IST) GO TO 80 + JJ1 = APOS + 2 + JJ2 = APOS2 + 1 + DO 70 J = IST,LIELL + W1 = W1 + W(J)*A(JJ1) + W2 = W2 + W(J)*A(JJ2) + JJ1 = JJ1 + 1 + JJ2 = JJ2 + 1 + 70 CONTINUE + 80 W(IPIV-1) = W1 + W(IPIV) = W2 + JPOS = JPOS - 2 + 90 CONTINUE +C RELOAD WORKING VECTOR INTO SOLUTION VECTOR. + IFR = 0 + DO 100 JJ = J1,J2 + J = ABS(IW(JJ)+0) + IFR = IFR + 1 + RHS(J) = W(IFR) + 100 CONTINUE + NPIV = 0 + GO TO 180 +C +C PERFORM OPERATIONS USING INDIRECT ADDRESSING. +C + 110 IF (NPIV.EQ.1) GO TO 120 +C JUMP IF WE HAVE A 2 BY 2 PIVOT. + IF (IW(JPOS-1).LT.0) GO TO 150 +C PERFORM BACK-SUBSTITUTION USING 1 BY 1 PIVOT. + 120 NPIV = NPIV - 1 + APOS = APOS - (J2-JPOS+1) + IIRHS = IW(JPOS) + W1 = RHS(IIRHS)*A(APOS) + J1 = JPOS + 1 + IF (J1.GT.J2) GO TO 140 + K = APOS + 1 + DO 130 J = J1,J2 + IRHS = ABS(IW(J)+0) + W1 = W1 + A(K)*RHS(IRHS) + K = K + 1 + 130 CONTINUE + 140 RHS(IIRHS) = W1 + JPOS = JPOS - 1 + GO TO 180 +C PERFORM OPERATIONS WITH 2 BY 2 PIVOT + 150 NPIV = NPIV - 2 + APOS2 = APOS - (J2-JPOS+1) + APOS = APOS2 - (J2-JPOS+2) + I1RHS = -IW(JPOS-1) + I2RHS = IW(JPOS) + W1 = RHS(I1RHS)*A(APOS) + RHS(I2RHS)*A(APOS+1) + W2 = RHS(I1RHS)*A(APOS+1) + RHS(I2RHS)*A(APOS2) + J1 = JPOS + 1 + IF (J1.GT.J2) GO TO 170 + JJ1 = APOS + 2 + JJ2 = APOS2 + 1 + DO 160 J = J1,J2 + IRHS = ABS(IW(J)+0) + W1 = W1 + RHS(IRHS)*A(JJ1) + W2 = W2 + RHS(IRHS)*A(JJ2) + JJ1 = JJ1 + 1 + JJ2 = JJ2 + 1 + 160 CONTINUE + 170 RHS(I1RHS) = W1 + RHS(I2RHS) = W2 + JPOS = JPOS - 2 + 180 CONTINUE + 190 RETURN + + END diff --git a/docker/requirements2.txt b/docker/requirements2.txt new file mode 100644 index 0000000000000000000000000000000000000000..2aec83576f2d0d46825646b9a59926e3c874ff6a --- /dev/null +++ b/docker/requirements2.txt @@ -0,0 +1,4 @@ +-e git+https://github.com/FUSED-Wind/windIO.git#egg=windio +-e git+https://github.com/OpenMDAO/OpenMDAO.git#egg=openmdao +bokeh==0.12.14 +ipywidgets