Rev 76639 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed
c -- formerly called from R's svd(x, ..., LINPACK = TRUE) --c Also called from loessf.f.c Minimally modernized in 2018-09, so is fixed-form F90, not F77cc dsvdc is a subroutine to reduce a double precision nxp matrix xc by orthogonal transformations u and v to diagonal form. thec diagonal elements s(i) are the singular values of x. thec columns of u are the corresponding left singular vectors,c and the columns of v the right singular vectors.cc on entrycc x double precision(ldx,p), where ldx.ge.n.c x contains the matrix whose singular valuec decomposition is to be computed. x isc destroyed by dsvdc.cc ldx integer.c ldx is the leading dimension of the array x.cc n integer.c n is the number of rows of the matrix x.cc p integer.c p is the number of columns of the matrix x.cc ldu integer.c ldu is the leading dimension of the array u.c (see below).cc ldv integer.c ldv is the leading dimension of the array v.c (see below).cc work double precision(n).c work is a scratch array.cc job integer.c job controls the computation of the singularc vectors. it has the decimal expansion abc with the following meaningcc a.eq.0 do not compute the left singularc vectors.c a.eq.1 return the n left singular vectorsc in u.c a.ge.2 return the first min(n,p) singularc vectors in u.c b.eq.0 do not compute the right singularc vectors.c b.eq.1 return the right singular vectorsc in v.cc on returncc s double precision(mm), where mm=min(n+1,p).c the first min(n,p) entries of s contain thec singular values of x arranged in descendingc order of magnitude.cc e double precision(p),c e ordinarily contains zeros. however see thec discussion of info for exceptions.cc u double precision(ldu,k), where ldu.ge.n. ifc joba.eq.1 then k.eq.n, if joba.ge.2c then k.eq.min(n,p).c u contains the matrix of left singular vectors.c u is not referenced if joba.eq.0. if n.le.pc or if joba.eq.2, then u may be identified with xc in the subroutine call.cc v double precision(ldv,p), where ldv.ge.p.c v contains the matrix of right singular vectors.c v is not referenced if job.eq.0. if p.le.n,c then v may be identified with x in thec subroutine call.cc info integer.c the singular values (and their correspondingc singular vectors) s(info+1),s(info+2),...,s(m)c are correct (here m=min(n,p)). thus ifc info.eq.0, all the singular values and theirc vectors are correct. in any event, the matrixc b = trans(u)*x*v is the bidiagonal matrixc with the elements of s on its diagonal and thec elements of e on its super-diagonal (trans(u)c is the transpose of u). thus the singularc values of x and b are the same.cc linpack. this version dated 08/14/78 .c correction made to shift 2/84.c g.w. stewart, university of maryland, argonne national lab.cc Modified 2000-12-28 to use a relative convergence test,c as this was infinite-looping on ix86.cc dsvdc uses the following functions and subprograms.cc external drotc blas daxpy,ddot,dscal,dswap,dnrm2,drotgc fortran dabs,dmax1,max0,min0,mod,dsqrtcsubroutine dsvdc(x,ldx,n,p,s,e,u,ldu,v,ldv,work,job,info)integer ldx,n,p,ldu,ldv,job,infodouble precision x(ldx,p),s(min(n+1,p)),e(p),+ u(ldu,n),v(ldv,p),work(n)cc internal variablescinteger i,iter,j,jobu,k,kase,kk,l,ll,lls,lm1,lp1,ls,lu,m,maxit,* mm,mm1,mp1,nct,nctp1,ncu,nrt,nrtp1double precision ddot,tdouble precision b,c,cs,el,emm1,f,g,dnrm2,scale,shift,sl,sm,sn,* smm1,t1,test,ztest,acclogical wantu,wantvcc unnecessary initializations of l and ls to keep g77 -Wall happycl = 0ls = 0ccc set the maximum number of iterations.cmaxit = 30cc determine what is to be computed.cwantu = .false.wantv = .false.jobu = mod(job,100)/10ncu = nif (jobu .gt. 1) ncu = min0(n,p)if (jobu .ne. 0) wantu = .true.if (mod(job,10) .ne. 0) wantv = .true.cc reduce x to bidiagonal form, storing the diagonal elementsc in s and the super-diagonal elements in e.cinfo = 0nct = min0(n-1,p)nrt = max0(0,min0(p-2,n))lu = max0(nct,nrt)if (lu .lt. 1) go to 170do 160 l = 1, lulp1 = l + 1if (l .gt. nct) go to 20cc compute the transformation for the l-th column andc place the l-th diagonal in s(l).cs(l) = dnrm2(n-l+1,x(l,l),1)if (s(l) .eq. 0.0d0) go to 10if (x(l,l) .ne. 0.0d0) s(l) = dsign(s(l),x(l,l))call dscal(n-l+1,1.0d0/s(l),x(l,l),1)x(l,l) = 1.0d0 + x(l,l)10 continues(l) = -s(l)20 continueif (p .lt. lp1) go to 50do 40 j = lp1, pif (l .gt. nct) go to 30if (s(l) .eq. 0.0d0) go to 30cc apply the transformation.ct = -ddot(n-l+1,x(l,l),1,x(l,j),1)/x(l,l)call daxpy(n-l+1,t,x(l,l),1,x(l,j),1)30 continuecc place the l-th row of x into e for thec subsequent calculation of the row transformation.ce(j) = x(l,j)40 continue50 continueif (.not.wantu .or. l .gt. nct) go to 70cc place the transformation in u for subsequent backc multiplication.cdo 60 i = l, nu(i,l) = x(i,l)60 continue70 continueif (l .gt. nrt) go to 150cc compute the l-th row transformation and place thec l-th super-diagonal in e(l).ce(l) = dnrm2(p-l,e(lp1),1)if (e(l) .eq. 0.0d0) go to 80if (e(lp1) .ne. 0.0d0) e(l) = dsign(e(l),e(lp1))call dscal(p-l,1.0d0/e(l),e(lp1),1)e(lp1) = 1.0d0 + e(lp1)80 continuee(l) = -e(l)if (lp1 .gt. n .or. e(l) .eq. 0.0d0) go to 120cc apply the transformation.cdo 90 i = lp1, nwork(i) = 0.0d090 continuedo 100 j = lp1, pcall daxpy(n-l,e(j),x(lp1,j),1,work(lp1),1)100 continuedo 110 j = lp1, pcall daxpy(n-l,-e(j)/e(lp1),work(lp1),1,x(lp1,j),1)110 continue120 continueif (.not.wantv) go to 140cc place the transformation in v for subsequentc back multiplication.cdo 130 i = lp1, pv(i,l) = e(i)130 continue140 continue150 continue160 continue170 continuecc set up the final bidiagonal matrix or order m.cm = min0(p,n+1)nctp1 = nct + 1nrtp1 = nrt + 1if (nct .lt. p) s(nctp1) = x(nctp1,nctp1)if (n .lt. m) s(m) = 0.0d0if (nrtp1 .lt. m) e(nrtp1) = x(nrtp1,m)e(m) = 0.0d0cc if required, generate u.cif (.not.wantu) go to 300if (ncu .lt. nctp1) go to 200do 190 j = nctp1, ncudo 180 i = 1, nu(i,j) = 0.0d0180 continueu(j,j) = 1.0d0190 continue200 continueif (nct .lt. 1) go to 290do 280 ll = 1, nctl = nct - ll + 1if (s(l) .eq. 0.0d0) go to 250lp1 = l + 1if (ncu .lt. lp1) go to 220do 210 j = lp1, ncut = -ddot(n-l+1,u(l,l),1,u(l,j),1)/u(l,l)call daxpy(n-l+1,t,u(l,l),1,u(l,j),1)210 continue220 continuecall dscal(n-l+1,-1.0d0,u(l,l),1)u(l,l) = 1.0d0 + u(l,l)lm1 = l - 1if (lm1 .lt. 1) go to 240do 230 i = 1, lm1u(i,l) = 0.0d0230 continue240 continuego to 270250 continuedo 260 i = 1, nu(i,l) = 0.0d0260 continueu(l,l) = 1.0d0270 continue280 continue290 continue300 continuecc if it is required, generate v.cif (.not.wantv) go to 350do 340 ll = 1, pl = p - ll + 1lp1 = l + 1if (l .gt. nrt) go to 320if (e(l) .eq. 0.0d0) go to 320do 310 j = lp1, pt = -ddot(p-l,v(lp1,l),1,v(lp1,j),1)/v(lp1,l)call daxpy(p-l,t,v(lp1,l),1,v(lp1,j),1)310 continue320 continuedo 330 i = 1, pv(i,l) = 0.0d0330 continuev(l,l) = 1.0d0340 continue350 continuecc main iteration loop for the singular values.cmm = miter = 0360 continuecc quit if all the singular values have been found.cc ...exitif (m .eq. 0) go to 620cc if too many iterations have been performed, setc flag and return.cif (iter .lt. maxit) go to 370info = mc ......exitgo to 620370 continuecc this section of the program inspects forc negligible elements in the s and e arrays. onc completion the variables kase and l are set as follows.cc kase = 1 if s(m) and e(l-1) are negligible and l.lt.mc kase = 2 if s(l) is negligible and l.lt.mc kase = 3 if e(l-1) is negligible, l.lt.m, andc s(l), ..., s(m) are not negligible (qr step).c kase = 4 if e(m-1) is negligible (convergence).cdo 390 ll = 1, ml = m - llc ...exitif (l .eq. 0) go to 400test = dabs(s(l)) + dabs(s(l+1))ztest = test + dabs(e(l))acc = dabs(test - ztest)/(1.0d-100 + test)if (acc .gt. 1.d-15) goto 380c if (ztest .ne. test) go to 380e(l) = 0.0d0c ......exitgo to 400380 continue390 continue400 continueif (l .ne. m - 1) go to 410kase = 4go to 480410 continuelp1 = l + 1mp1 = m + 1do 430 lls = lp1, mp1ls = m - lls + lp1c ...exitif (ls .eq. l) go to 440test = 0.0d0if (ls .ne. m) test = test + dabs(e(ls))if (ls .ne. l + 1) test = test + dabs(e(ls-1))ztest = test + dabs(s(ls))c 1.0d-100 is to guard against a zero matrix, hence zero testacc = dabs(test - ztest)/(1.0d-100 + test)if (acc .gt. 1.d-15) goto 420c if (ztest .ne. test) go to 420s(ls) = 0.0d0c ......exitgo to 440420 continue430 continue440 continueif (ls .ne. l) go to 450kase = 3go to 470450 continueif (ls .ne. m) go to 460kase = 1go to 470460 continuekase = 2l = ls470 continue480 continuel = l + 1cc perform the task indicated by kase.cc go to (490,520,540,570), kaseselect case(kase)case(1)goto 490case(2)goto 520case(3)goto 540case(4)goto 570end selectcc deflate negligible s(m).c490 continuemm1 = m - 1f = e(m-1)e(m-1) = 0.0d0do 510 kk = l, mm1k = mm1 - kk + lt1 = s(k)call drotg(t1,f,cs,sn)s(k) = t1if (k .eq. l) go to 500f = -sn*e(k-1)e(k-1) = cs*e(k-1)500 continueif (wantv) call drot(p,v(1,k),1,v(1,m),1,cs,sn)510 continuego to 610cc split at negligible s(l).c520 continuef = e(l-1)e(l-1) = 0.0d0do 530 k = l, mt1 = s(k)call drotg(t1,f,cs,sn)s(k) = t1f = -sn*e(k)e(k) = cs*e(k)if (wantu) call drot(n,u(1,k),1,u(1,l-1),1,cs,sn)530 continuego to 610cc perform one qr step.c540 continuecc calculate the shift.cscale = dmax1(dabs(s(m)),dabs(s(m-1)),dabs(e(m-1)),* dabs(s(l)),dabs(e(l)))sm = s(m)/scalesmm1 = s(m-1)/scaleemm1 = e(m-1)/scalesl = s(l)/scaleel = e(l)/scaleb = ((smm1 + sm)*(smm1 - sm) + emm1**2)/2.0d0c = (sm*emm1)**2shift = 0.0d0if (b .eq. 0.0d0 .and. c .eq. 0.0d0) go to 550shift = dsqrt(b**2+c)if (b .lt. 0.0d0) shift = -shiftshift = c/(b + shift)550 continuef = (sl + sm)*(sl - sm) + shiftg = sl*elcc chase zeros.cmm1 = m - 1do 560 k = l, mm1call drotg(f,g,cs,sn)if (k .ne. l) e(k-1) = ff = cs*s(k) + sn*e(k)e(k) = cs*e(k) - sn*s(k)g = sn*s(k+1)s(k+1) = cs*s(k+1)if (wantv) call drot(p,v(1,k),1,v(1,k+1),1,cs,sn)call drotg(f,g,cs,sn)s(k) = ff = cs*e(k) + sn*s(k+1)s(k+1) = -sn*e(k) + cs*s(k+1)g = sn*e(k+1)e(k+1) = cs*e(k+1)if (wantu .and. k .lt. n)* call drot(n,u(1,k),1,u(1,k+1),1,cs,sn)560 continuee(m-1) = fiter = iter + 1go to 610cc convergence.c570 continuecc make the singular value positive.cif (s(l) .ge. 0.0d0) go to 580s(l) = -s(l)if (wantv) call dscal(p,-1.0d0,v(1,l),1)580 continuecc order the singular value.c590 if (l .eq. mm) go to 600c ...exitif (s(l) .ge. s(l+1)) go to 600t = s(l)s(l) = s(l+1)s(l+1) = tif (wantv .and. l .lt. p)* call dswap(p,v(1,l),1,v(1,l+1),1)if (wantu .and. l .lt. n)* call dswap(n,u(1,l),1,u(1,l+1),1)l = l + 1go to 590600 continueiter = 0m = m - 1610 continuego to 360620 continuereturnend