s_tms2.cc
Upload User: hkdiguang
Upload Date: 2013-05-12
Package Size: 105k
Code Size: 16k
Development Platform:

Unix_Linux

  1. // File: s_tms2.cc -- Implements the tms1 class
  2. // Author: Suvrit Sra
  3. // Date: 15 Nov, 2003
  4. /*************************************************************************
  5.  THE ORIGINAL SVDPAKC COPYRIGHT
  6.                            (c) Copyright 1993
  7.                         University of Tennessee
  8.                           All Rights Reserved                          
  9.  *************************************************************************/
  10. #include <cmath>
  11. #include <cstdio>
  12. #include <cstdlib>
  13. #include <cerrno>
  14. #include <cstring>
  15. #include <unistd.h>
  16. #include <fcntl.h>
  17. #include "s_tms2.h"
  18. using namespace ssvd;
  19. /***********************************************************************
  20.  *                                                                     *
  21.  *                       tsvd2()                                       *
  22.  *     Sparse SVD Via Eigensystem of Equivalent 2-Cyclic Matrix        *
  23.  *                  (double precision)                                 *
  24.  *                                                                     *
  25.  ***********************************************************************
  26.    Description
  27.    -----------
  28.    tsvd2 implements a trace-minimization svd method for determining
  29.    the p-largest singular triplets of a large sparse matrix A.
  30.    tms2 computes the singular triplets of the matrix A via the 
  31.    equivalent symmetric eigenvalue problem.
  32.    
  33.    B = (alpha*alpha)*I - A'A, where A is m (=nrow) by n (=ncol),
  34.    so that sqrt(alpha*alpha-lambda) is a singular value of A.
  35.    alpha is chosen so that B is (symmetric) positive definite.  In
  36.    the calling program, alpha is determined as the matrix 1-norm of
  37.    A.  the user can set alpha to be any known upper bound for the
  38.    the largest singular value of the matrix A.
  39.    (A' = transpose of A)
  40.      
  41.    User supplied routines: opat, opb,timer,store
  42.  
  43.    opat(x,y)                takes an m-vector x and should return A'*x
  44.                             in y.
  45.    opb(nrow+ncol,x,y,shift) takes an (m+n)-vector x and should return
  46.                             D*x in y, where D=[B-shift*I], I is the 
  47.                             (m+n) order identity matrix.
  48.    user should replace calls to timer() with an appropriate call to
  49.    an instrinsic timing routine that returns delta user cpu time
  50.    (i.e., user cpu time elapsed from a previous call to timing routine)
  51.    tsvd2 utilizes ritz-shifting and chebyshev polynomials for acceleration of 
  52.    convergence.
  53.    External parameters
  54.    -------------------
  55.    Defined and documented in tmsg.h
  56.    Local parameters:
  57.    ----------------
  58.    (input) 
  59.    n               order of equivalent symmetric eigenvalue problem
  60.                    should be equal to min(nrow,ncol), where nrow is the
  61.                    number of rows of A and ncol is the number of columns of A.
  62.    p               number of desired singular triplets (largest) of A.
  63.    s               dimension of initial subspace (s should be great er
  64.                    than p; s=2*p is usually safe but since the comp lexity
  65.                    of the method is determined by s, the user should
  66.                    try to keep s as close to p as possible).
  67.    job             acceleration strategy switch:
  68.                    job = 0, no acceleration used,
  69.                        = 1, ritz-shifting used.
  70.                        = 2, chebyshev polynomials and ritz-shifting used.
  71.    maxi            maximum number of trace minimization steps allowed.
  72.    tol             user-supplied tolerance for residual of an
  73.                    equivalent eigenpair of B (singular triplet of A).
  74.    red             user-supplied tolerance for residual reduction to
  75.                    initiate ritz-shifting when job=1 or job=2.
  76.    lwork(s)        (logical 0,1) work array.
  77.    (output parameters):
  78.     -----------------
  79.    ierr            ierr=99, input parameter job invalid.
  80.    (error flag)
  81.    mem             number of bytes of memory needed
  82.    
  83.    maxd            maximum polynomial degree used (job = 2).
  84.    mxv(3)          matrix-vector multiplication counters:
  85.                    mxv[0] = number of A*x,
  86.                    mxv[1] = number of A'*x,
  87.                    mxv[2] = mxv[0] + mxv[1]
  88.    sig(s)          contains p-desired singular values.
  89.    y(nrow+ncol,s)  first p columns contain left and right singular
  90.                    vectors, i.e.,
  91.                    y(1:nrow+ncol,1:p)  = [u(1:r,1:p)' | v(1:c,1:p)']',
  92.                    where r = no. of rows of matrix A and
  93.                    c = no. of cols of matrix A.
  94.    titer(s)        titer(i) := number of trace min. steps
  95.                    need for i-th triplet of A.
  96.    itcgt(s)        itcgt(i) := number of cg steps needed for
  97.                    i-th triplet of A.
  98.    time(5)         timing breakdown array:
  99.                    time[0]  = gram-schmidt orthogonalization
  100.                    time[1]  = section-formation (spectral decomposition)
  101.                    time[2]  = convergence criteria
  102.                    time[3]  = conjugate gradient method
  103.                    time[4]  = total execution time (user-cpu)
  104.    res(s)          2-norms of residual vectors
  105.                    (A*y[i]-sig(i)*y[i]), i=1,2,...,p.
  106.    Functions used
  107.    --------------
  108.     BLAS       daxpy, ddot, dgemm3, dgemv, dgemv2, xerbla,
  109.                pmul, dtrsm, porth
  110.     USER       timer,opb,opat,acosh (if not in math library)
  111.     RNG        random
  112.     PRECISION  epslon
  113.     MATH       sqrt,fabs,acosh
  114.     EISPACK    tred2,tql2,pythag
  115.    Precision
  116.    ---------
  117.    All floating-point calculations use double precision;
  118.    variables are declared as long and double. */
  119. long s_tms2::tsvd2(FILE* fp, long n, long p, long s, long job,
  120.            double tol, double red, double *sig, long maxi,
  121.            long *mem, long *itcgt, long *titer,double *time,
  122.            double *res, long *mxv, double **work1, double **work2,
  123.            double **work3, double **work4, double **work5,
  124.           double **y, long **iwork, long *lwork,long *maxd)
  125. {
  126.   double  *workptr5,total,*tempptr5,meps;
  127.   double  tmp,tmpi,pparm1,pparm2,e,enew;
  128.   double  t1,sec1,sec2,sec21,sec22,sec23,sec3,sec4;
  129.   long  degree,ndegre,itmp,ierr,iptr,left,i,j,k,irand,iter;
  130.   long  shift,memsize,temp_left,polyac;
  131.   pparm1 = 0;
  132.   pparm2 = 0;
  133.   e = 0;
  134.   degree = 0;
  135.   ndegre = 0;
  136.   /* allocate memory for temporary arrays in subroutines cgt() and cgts() */
  137.   memsize = sizeof(double) * n * 6;
  138.   if(!(workptr5 = (double *) malloc(memsize))) {
  139.     perror("FIRST MALLOC FAILED IN TSVD2()n");
  140.     exit(errno);
  141.   }
  142.   *mem += memsize;
  143.   tempptr5 = workptr5;
  144.   z = tempptr5;
  145.   tempptr5 += n;
  146.   v2 = tempptr5;
  147.   tempptr5 +=n;
  148.   r = tempptr5;
  149.   tempptr5 += n;
  150.   r2 = tempptr5;
  151.   tempptr5 += n;
  152.   pp = tempptr5;
  153.   tempptr5 += n;
  154.   z2 = tempptr5;
  155.   /* allocate memory for temporary array in subroutine myopb */
  156.   memsize = sizeof(double) * (ncol+nrow);
  157.   if(!(zz = (double *) malloc(memsize))) {
  158.      perror("SECOND MALLOC FAILED IN TSVD2()n");
  159.      exit(errno);
  160.     }
  161.   *mem += memsize;
  162.   /*get machine epsilon (meps) */
  163.   meps = epslon(ONE);
  164.   shift = FALSE;
  165.   ierr = 0;
  166.   if(job && (job != 1) && (job != 2)) {
  167.      ierr = 99;
  168.      return(ierr);
  169.   }
  170.   if(job == 1) {
  171.     for(i=0; i<p; i++) {
  172.         lwork[i] = FALSE;
  173.         work5[2][i] = -ONE;
  174.         work5[3][i] = -ONE;
  175.     }
  176.   }
  177.   else {
  178.     if(job==2) {
  179.          degree = 0;
  180.          ndegre = 0;
  181.          pparm1 = 0.04;
  182.          pparm2 = 4.0;
  183.     }
  184.   }
  185.   /*initialize timers,counters and flags: */
  186.   sec1 = ZERO;
  187.   sec21 = ZERO;
  188.   sec22 = ZERO;
  189.   sec23 = ZERO;
  190.   sec3 = ZERO;
  191.   sec4 = ZERO;
  192.   mxv[0] = 0;
  193.   mxv[1] = 0;
  194.   polyac = FALSE;
  195.   /*initialize y(1:n,1:s) = random matrix
  196.      (carry s vectors in the tmin iterations, assuming s.ge.p) */
  197.   irand =SEED;
  198.   for(k=0; k<s; k++) {
  199.      sig[k] = ZERO;
  200.      work5[1][k] = ZERO;
  201.   }
  202.   for(k=0; k<s; k++) {
  203.       for (i=0; i<n; i++) y[k][i] = mrandom(&irand);
  204.   }
  205.   /*----------------------------------------------------------
  206.        pointer and counter for hybrid monitor:
  207.   
  208.               1 2 3 4 5 ... i ... p
  209.              -----------------------
  210.          sig:| | | | | |...| |...| | (ascending order)
  211.              -----------------------
  212.                             ^
  213.                             |
  214.                           iptr : points to first e-value of B
  215.                                  that has not converged
  216.   
  217.        left:=s-iptr+1 (ie how many y-vectors remain for tsvd2)
  218.   -------------------------------------------------------------- */
  219.   
  220.   /* initialize a few pointers and counters: */
  221.   total = ZERO;
  222.   iptr = 1;
  223.   left = s;
  224.   for(i=0; i<s; i++) {
  225.       titer[i] = 0;
  226.       itcgt[i] = 0;
  227.   }
  228.   /*--------------------------------------------------------------
  229.        main tmin iteration loop (nmax iterations)
  230.    --------------------------------------------------------------*/
  231.   for(iter=0; iter<maxi; iter++) {
  232.      if((job==2) && (!shift)) { 
  233.        if(ndegre) {
  234.          degree = ndegre;
  235.          *maxd = imax(*maxd,degree);
  236.          polyac = TRUE;
  237.        }
  238.        else polyac = FALSE;
  239.      }
  240. /* section formation */
  241.      t1 = timer();
  242.      for(j=0; j<s; j++) {
  243.         for(i=0; i<n; i++) work2[j][i] = y[j][i];
  244.      }
  245.      if(polyac) {
  246.        porth(s,0,n,work2,work1[0],work1[1],work4[0],work4[1],
  247.              work4[2],e,degree,alpha);
  248.        mxv[0] += degree*s;
  249.        mxv[1] += degree*s;
  250.      }
  251.      else {
  252.        orthg(s,0,n,work1,work2,&work4[0][0]);
  253.      }
  254.    t1 = timer() - t1;
  255.    sec1 = sec1 + t1;
  256.   
  257.      /* form work1(1:n,iptr:s) = b(1:n,1:n)*work2(1:n,iptr:s) */
  258.   
  259.      t1 = timer();
  260.   
  261.   if(polyac) {
  262.     for(j=0; j<left; j++) {
  263.        for(i=0; i<n; i++) work1[iptr+j-1][i] = work2[iptr+j-1][i];
  264.     }
  265.   }
  266.   else {
  267.      for(j=0; j<left; j++)
  268.         myopb(n,work2[iptr+j-1],work1[iptr+j-1],ZERO);
  269.   }
  270.  
  271. /* form work3(1:left,1:left) = work2(1:n,iptr:s)'*work1(1:n,iptr:s) */
  272.   dgemm3(TRANSP, NTRANSP, left, left, n, ONE, work2, 0,iptr-1,
  273.          work1, 0, iptr-1, ZERO, work3, 0, 0);
  274.      
  275.   if(job >= 1) {
  276.     for(j=0; j<left; j++)
  277.        work4[0][j] = dasum(left, &work3[0][j], s) - fabs(work3[j][j]);
  278.   }
  279.      t1 = timer() - t1;
  280.      sec21 = sec21 + t1;
  281.      /*    compute the eigenvalues and eigenvectors of work3:  */
  282.      
  283.      t1 = timer();
  284.      /*    eigenvectors overwrite array work3(:,:)
  285.          store current e-values in work5(:,2)  */
  286.   if(polyac) {
  287.     tred2(0,left,work3,work5[0],work4[1],work3);
  288.     ierr = tql2(0,left,work5[0],work4[1],work3);
  289.     if(ierr) printf("IERR FROM TQL2 = %ldn",ierr);
  290.   }
  291.   else {
  292.      
  293.      for(j=iptr-1; j<s; j++) work5[1][j] = sig[j];
  294.      
  295.      tred2(0,left, work3, &sig[iptr-1], &work4[1][0], work3);
  296.      ierr = tql2(0,left, &sig[iptr-1], &work4[1][0], work3);
  297.     if(ierr) printf("IERR FROM TQL2 = %ldn",ierr);
  298.   } 
  299.   t1 = timer() - t1;
  300.   sec22 = sec22 + t1;
  301.      
  302.      /* form y(1:n,iptr:s) = work2(1:n,iptr:s)*work3(1:left,1:left) */
  303.      t1 = timer();
  304.   dgemm3(NTRANSP, NTRANSP, n, left, left, ONE, work2, 0, iptr-1,
  305.            work3, 0, 0, ZERO, y, 0, iptr-1);
  306.      t1 = timer() - t1;
  307.      sec23 = sec23 + t1;
  308.      
  309.      /*    test for convergence here */
  310.      
  311.      t1 = timer();
  312.      for(j=iptr-1; j<s; j++) {
  313.         myopb(n, y[j], work2[j], ZERO);
  314.         if(polyac) {
  315.           work5[1][j]=sig[j];
  316.           sig[j] = ddot(n,y[j],1,work2[j],1)/ddot(n,y[j],1,y[j],1);
  317.         }
  318.         daxpy(n, -sig[j], y[j], 1, work2[j],1);
  319.         work4[2][j-iptr+1] = sqrt(ddot(n,work2[j],1,work2[j],1));
  320.         if(j < p) titer[j] += 1;
  321.      }
  322.      mxv[0] += s-iptr+1;
  323.      mxv[1] += s-iptr+1;
  324.      t1 = timer() - t1;
  325.      sec3 = sec3 + t1;
  326.     temp_left=left; 
  327.     /* array work4(:,3) stores the vector 2-norms of residual vectors */
  328.      for(k=0; k<temp_left; k++) {
  329.          if(fabs(work4[2][k]) <= tol) {
  330.             iptr = iptr + 1;
  331.             if(iptr > p)  {
  332.                           goto L10;
  333.                           }
  334.             left = s-iptr+1;
  335.          }
  336.      }
  337.      if((!shift) && (job>=1)) {
  338.      
  339.        /* work4(:,1) stores gershgorin radii  *
  340.         * iwork(:,1) is the clustering vector */ 
  341.        disk(left, &sig[iptr-1], work4[0], iwork[0], iwork[1]);
  342.        
  343.        for(k=iptr-1; k<s; k++) {
  344.           if(iwork[0][k-iptr+1] == 1)
  345.             isol(k, work4[2][k-iptr+1], red, lwork, work5[2],
  346.                  work5[3],s);
  347.           else
  348.              if(iwork[0][k-iptr+1] > 1)
  349.                clus(k,iwork[0][k-iptr+1],&work4[2][k-iptr+1],red,lwork,
  350.                     work5[2], work5[3], work4[1],s);
  351.        }
  352.      }             
  353.        
  354.      /* continue algorithm...  */
  355.        
  356.      /* shift start */
  357.      
  358.      if((iter>0) && (!shift) && (job>=1)) {
  359.         if(lwork[iptr-1]) {
  360.            shift = TRUE;
  361.            polyac = FALSE;
  362.            orthg(s, 0, n, work1, y, &work4[0][0]);
  363.         }
  364.      }
  365.      if(shift) {
  366.      
  367.      /* compute shifts in work5(:,1) here: */
  368.   
  369.       for(k=iptr-1; k<s; k++) {
  370.          if((k>iptr-1) && (k<=p-1)) {
  371.            work5[0][k] = ZERO;
  372.            for(j=iptr-2; j<k; j++) {
  373.               if((j!=-1) && (sig[j] <= (sig[k] - work4[2][k-iptr+1]))) 
  374.                 work5[0][k] = sig[j];
  375.               }
  376.  
  377.            if((work5[0][k] == sig[k-1]) && (work5[0][k-1]==sig[k-1]))
  378.              work5[0][k] = sig[k];
  379.            if(work5[0][k] == ZERO) 
  380.              work5[0][k] = work5[0][k-1];
  381.          }
  382.          else if(k>p-1) work5[0][k] = work5[0][p-1];
  383.               else if(k==iptr-1) work5[0][k] = sig[k];
  384.       }
  385.      }
  386.      t1 = timer();
  387. /* monitor polynomial degree (if job=2) */
  388.    if(job==2) {
  389.      enew = sig[s-1];
  390.      e = fabs(enew-alpha*alpha);
  391.      if((sig[iptr-1]>pparm1*sig[s-1]) && (enew<alpha*alpha) &&
  392.         (!shift)) {
  393.        tmp = acosh(sig[s-1]/sig[iptr-1]);
  394.        itmp = 2*imax(((int) (pparm2/tmp)),1);
  395.        if(degree) ndegre = imin(2*degree,itmp);
  396.        else ndegre = 2;
  397.      }
  398.    }
  399.      
  400.   if(polyac) {
  401.     for(j=iptr-1; j<s; j++) {
  402.        pmul(n,y[j],work2[j],work4[0],work4[1],work4[2],
  403.             e,degree,alpha);
  404.        }
  405.     orthg(left,0,n,work1,&work2[iptr-1],work4[0]);
  406.     for(j=iptr-1; j<s; j++) {
  407.        for(i=0; i<n; i++)
  408.           y[j][i]=work2[j][i];
  409.     }
  410.     dtrsm('R','U',TRANSP,'N',n,left,ONE,work1,&y[iptr-1]);
  411.     mxv[0] += degree*left;
  412.     mxv[1] += degree*left;
  413.  }
  414.  else {
  415.   
  416.      /* do cg iterations */
  417.      /*load y into work1 array for orthog. projector in subroutine cgt*/
  418.      for(j=0; j<left; j++) {
  419.         for(i=0; i<n; i++)
  420.             work1[j][i] = y[iptr+j-1][i];
  421.      }
  422.            
  423.     /* cg loop for independent systems (no shifting used)  */
  424.      if(!shift) 
  425.        for(i=0; i<left; i++)
  426.              cgt(n, left, y[iptr+i-1], work1, &itcgt[iptr+i-1],
  427.                  sig[iptr+i-1], sig[s-1], &iwork[0][i], meps);
  428.      else {
  429.      
  430.          /*shift with work5(:,1) in cg iterations */
  431.        for(i=0; i<left; i++) {
  432.                 cgts(n, left, y[iptr+i-1], work1, &itcgt[iptr+i-1],
  433.                      sig[iptr+i-1], work5[1][iptr+i-1], sig[s-1],
  434.                      work5[0][iptr+i-1], &iwork[0][i], meps);
  435.                 }
  436.      }
  437.      for(i=0; i<left; i++) {
  438.         mxv[0] += iwork[0][i];
  439.         mxv[1] += iwork[0][i];
  440.      }
  441.   }
  442.      t1 = timer() - t1;
  443.      sec4 += t1;
  444. }
  445. L10:     
  446.    /* compute final 2-norms of residual vectors w.r.t. B */
  447.    for(j=0; j<p; j++) {
  448.      myopb(n, y[j], work2[j], alpha*alpha);
  449.      tmp = ddot(n,y[j],1,work2[j],1)/ddot(n,y[j],1,y[j],1);
  450.      daxpy(n,-tmp,y[j],1,work2[j],1);
  451.      tmp = sqrt(fabs(tmp));
  452.      work4[2][j] = sqrt(ddot(n,work2[j],1,work2[j],1));
  453.      opa(y[j],&y[j][n]);
  454.      tmpi = 1.0/fabs(tmp);
  455.      dscal(nrow,tmpi,&y[j][n],1);
  456.      work4[2][j] = work4[2][j]*tmpi;
  457.      sig[j]=tmp;
  458.    }
  459.    mxv[0] += 2*p;
  460.    mxv[1] += p;
  461.    
  462.    sec2   = sec21 + sec22 + sec23;
  463.    total += sec1 + sec2 + sec3 + sec4;
  464.    
  465.    /* load output time and mxv arrays */
  466.    time[0]=sec1;
  467.    time[1]=sec2;
  468.    time[2]=sec3;
  469.    time[3]=sec4;
  470.    time[4]=total;
  471.    mxv[2]=mxv[0]+mxv[1];
  472.   
  473.   /* load residual vector */
  474.   for(i=0; i<p; i++)
  475.       res[i] = work4[2][i];
  476.   return(ierr);
  477. }