LCOV - code coverage report
Current view: top level - svd/tutorials - ex53.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 441 451 97.8 %
Date: 2024-11-21 00:34:55 Functions: 21 21 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       3             :    SLEPc - Scalable Library for Eigenvalue Problem Computations
       4             :    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
       5             : 
       6             :    This file is part of SLEPc.
       7             :    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
       8             :    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
       9             : */
      10             : 
      11             : static char help[] = "Partial hyperbolic singular value decomposition (HSVD) of matrix generated by plane rotations.\n"
      12             :   "The command line options are:\n"
      13             :   "  -p <p>, number of rows in upper part of matrix A.\n"
      14             :   "  -q <q>, number of rows in lower part of matrix A.\n"
      15             :   "  -n <n>, number of columns of matrix A.\n"
      16             :   "  -k <k>, condition number.\n"
      17             :   "  -d <d>, density.\n"
      18             :   "  -prog, show progress of matrix generation\n";
      19             : 
      20             : #include <slepcsvd.h>
      21             : #include <slepcblaslapack.h>
      22             : 
      23             : /* The problem matrix is the (p+q)-by-n matrix
      24             : 
      25             :      A =  |     Q1 * D1 * U |
      26             :           | 1/2*Q2 * D2 * U |
      27             : 
      28             :  with p>=n, where Q1 (p-by-p), Q2 (q-by-q) and U (n-by-n) are orthonormal
      29             :  matrices, D1 is a diagonal p-by-n matrix with elements
      30             :      D1(i,i) = sqrt(5/4)*d(i), if i<=q
      31             :              = d(i),           if i>q
      32             :  D2 is a diagonal q-by-n matrix with elements D2(i,i)= d(i),
      33             :  and d is an n-element vector with elements distributed exponentially
      34             :  from 1/k to 1.
      35             : 
      36             :  The signature matrix is Omega = diag(I_p,-I_q)
      37             : 
      38             :  The hyperbolic singular values of A are equal to the elements of vector d.
      39             : 
      40             :  A is generated by random plane rotations applied to the diagonal matrices
      41             :  D1 and D2
      42             : 
      43             :  This test case is based on the paper:
      44             : 
      45             :  [1] A. Bojanczyk, N.J. Higham, and H. Patel, "Solving the Indefinite Least
      46             :      Squares Problem by Hyperbolic QR Factorization", SIAM J. Matrix Anal.
      47             :      Appl. 24(4):914-931 2003
      48             : */
      49             : 
      50             : /* Timing */
      51             : #ifdef TIMING
      52             :   static PetscReal tt_rotr,tt_rotc,tt_assmr=0.0,tt_assmc=0.0,tt_getr=0.0,tt_getc=0.0,tt_setvalr=0.0,tt_setvalc=0.0;
      53             :   #define time_now(t) t=MPI_Wtime();
      54             :   #define time_diff(tacum,t0,t,t1) {t=MPI_Wtime(); tacum += t-t0; t1=t;}
      55             : #else
      56             :   #define time_diff(tacum,t0,t,t1)
      57             :   #define time_now(t)
      58             : #endif
      59             : 
      60             : struct _p_XMat {
      61             :   MPI_Comm    comm;
      62             :   PetscInt    M,N;         /* global number of rows and columns */
      63             :   PetscInt    Istart,Iend; /* Index of 1st row and last local rows */
      64             :   PetscInt    *nzr;        /* number of non-zeros in each row */
      65             :   PetscInt    **rcol;      /* row columns */
      66             :   PetscInt    *ranges;     /* proc row ranges */
      67             :   PetscScalar **rval;      /* row values */
      68             : };
      69             : 
      70             : typedef struct _p_XMat *XMat;
      71             : 
      72             : /* Iterator over non-zero rows of 2 columns */
      73             : struct _p_ColsNzIter {
      74             :   XMat      A;
      75             :   PetscInt  j1,j2;    /* Columns considered */
      76             :   PetscInt  iloc;     /* current local row */
      77             : };
      78             : 
      79             : typedef struct _p_ColsNzIter *ColsNzIter;
      80             : 
      81          12 : static PetscErrorCode XMatCreate(MPI_Comm comm,XMat *A,PetscInt Istart,PetscInt Iend,PetscInt M,PetscInt N)
      82             : {
      83          12 :   PetscInt    i;
      84          12 :   PetscMPIInt np;
      85             : 
      86          12 :   PetscFunctionBeginUser;
      87          12 :   PetscCall(PetscNew(A));
      88          12 :   (*A)->M = M;
      89          12 :   (*A)->N = N;
      90          12 :   (*A)->Istart = Istart;
      91          12 :   (*A)->Iend = Iend;
      92          12 :   (*A)->comm = comm;
      93          12 :   PetscCallMPI(MPI_Comm_size(comm,&np));
      94          12 :   PetscCall(PetscMalloc4(Iend-Istart,&(*A)->nzr,Iend-Istart,&(*A)->rcol,Iend-Istart,&(*A)->rval,np+1,&(*A)->ranges));
      95        1532 :   for (i=0; i<Iend-Istart; i++) {
      96        1520 :     (*A)->nzr[i] = 0;
      97        1520 :     (*A)->rcol[i] = NULL;
      98        1520 :     (*A)->rval[i] = NULL;
      99             :   }
     100          24 :   PetscCallMPI(MPI_Allgather(&Istart,1,MPIU_INT,(*A)->ranges,1,MPIU_INT,comm));
     101          12 :   (*A)->ranges[np]=M;
     102          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     103             : }
     104             : 
     105          12 : static PetscErrorCode XMatDestroy(XMat *A)
     106             : {
     107          12 :   PetscInt m,i;
     108             : 
     109          12 :   PetscFunctionBeginUser;
     110          12 :   m = (*A)->Iend-(*A)->Istart;
     111        1532 :   for (i=0; i<m; i++) {
     112        1520 :     if ((*A)->nzr[i]>0) {
     113        1520 :       PetscCall(PetscFree2((*A)->rcol[i],(*A)->rval[i]));
     114             :     }
     115             :   }
     116          12 :   PetscCall(PetscFree4((*A)->nzr,(*A)->rcol,(*A)->rval,(*A)->ranges));
     117          12 :   PetscCall(PetscFree(*A));
     118          12 :   *A = NULL;
     119          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     120             : }
     121             : 
     122        1264 : static PetscErrorCode XMatGetSize(XMat A,PetscInt *M,PetscInt *N)
     123             : {
     124        1264 :   PetscFunctionBeginUser;
     125        1264 :   *M = A->M;
     126        1264 :   *N = A->N;
     127        1264 :   PetscFunctionReturn(PETSC_SUCCESS);
     128             : }
     129             : 
     130        1776 : static PetscErrorCode XMatGetOwnershipRange(XMat A,PetscInt *Istart,PetscInt *Iend)
     131             : {
     132        1776 :   PetscFunctionBeginUser;
     133        1776 :   *Istart = A->Istart;
     134        1776 :   *Iend = A->Iend;
     135        1776 :   PetscFunctionReturn(PETSC_SUCCESS);
     136             : }
     137             : 
     138         160 : static PetscErrorCode XMatGetOwnershipRanges(XMat A,PetscInt **ranges)
     139             : {
     140         160 :   PetscFunctionBeginUser;
     141         160 :   *ranges = A->ranges;
     142         160 :   PetscFunctionReturn(PETSC_SUCCESS);
     143             : }
     144             : 
     145        2368 : static PetscErrorCode XMatGetRow(XMat A,PetscInt i,PetscInt *nc,PetscInt **vj,PetscScalar **va)
     146             : {
     147        2368 :   PetscInt iloc=i-A->Istart;
     148             : 
     149        2368 :   PetscFunctionBeginUser;
     150        2368 :   *nc = A->nzr[iloc];
     151        2368 :   *vj = A->rcol[iloc];
     152        2368 :   *va = A->rval[iloc];
     153        2368 :   PetscFunctionReturn(PETSC_SUCCESS);
     154             : }
     155             : 
     156        2368 : static PetscErrorCode XMatRestoreRow(XMat A,PetscInt i,PetscInt *nc,PetscInt **vj,PetscScalar **va)
     157             : {
     158        2368 :   PetscFunctionBeginUser;
     159        2368 :   *nc = 0;
     160        2368 :   *vj = NULL;
     161        2368 :   *va = NULL;
     162        2368 :   PetscFunctionReturn(PETSC_SUCCESS);
     163             : }
     164             : 
     165       12160 : static PetscErrorCode XMatChangeRow(XMat A,PetscInt i,PetscInt nc,PetscInt vj[],PetscScalar va[])
     166             : {
     167       12160 :   PetscInt iloc = i-A->Istart;
     168             : 
     169       12160 :   PetscFunctionBeginUser;
     170       12160 :   if (A->nzr[iloc]>0) {
     171       12088 :     PetscCall(PetscFree2(A->rcol[iloc],A->rval[iloc]));
     172             :   }
     173       12160 :   A->nzr[iloc] = nc;
     174       12160 :   A->rcol[iloc] = vj;
     175       12160 :   A->rval[iloc] = va;
     176       12160 :   PetscFunctionReturn(PETSC_SUCCESS);
     177             : }
     178             : 
     179             : /* Given a row with non-zero elements in columns indicated by rcol, get the
     180             :    position where the non-zero element of column j is, or where it should be inserted.
     181             :    Returns true if there is a non-zero element for the column, false otherwise */
     182      226400 : static PetscBool getcolpos(const PetscInt rcol[],PetscInt nz,PetscInt j,PetscInt *k)
     183             : {
     184      226400 :   PetscInt ka,kb;
     185      226400 :   if (nz==0) {
     186       23952 :     *k = 0;
     187       23952 :     return PETSC_FALSE;
     188             :   }
     189      202448 :   if (j<=rcol[0]) {
     190       67504 :     *k = 0;
     191       67504 :     return (rcol[0]==j)? PETSC_TRUE: PETSC_FALSE;
     192             :   }
     193      134944 :   if (rcol[nz-1]<=j) {
     194       45680 :     *k = nz-(rcol[nz-1]==j);
     195       45680 :     return (rcol[nz-1]==j)? PETSC_TRUE: PETSC_FALSE;
     196             :   }
     197             :   /* Bisection: rcol[ka] < j < rcol[kb] */
     198       89264 :   ka = 0; kb = nz-1;
     199      277048 :   while (ka+1<kb) {
     200      195048 :     *k = (ka+kb)/2;
     201      195048 :     if (rcol[*k]<=j) {
     202       98032 :       if (rcol[*k]==j) return PETSC_TRUE;
     203             :       else ka = *k;
     204             :     } else kb = *k;
     205             :   }
     206       82000 :   *k = kb;
     207       82000 :   return PETSC_FALSE;
     208             : }
     209             : 
     210             : /* Only local elements can be set */
     211        1440 : static PetscErrorCode XMatSetValue(XMat A,PetscInt i,PetscInt j,PetscScalar x,InsertMode dummy)
     212             : {
     213        1440 :   PetscInt    nz,iloc,k,kx,*col1,*col2;
     214        1440 :   PetscScalar *val1,*val2;
     215             : 
     216        1440 :   PetscFunctionBeginUser;
     217        1440 :   PetscCheck(i>=A->Istart && i<A->Iend && j>=0 && j<A->N,A->comm,PETSC_ERR_ARG_OUTOFRANGE,"Incorrect index of row/column");
     218        1440 :   iloc = i-A->Istart;
     219        1440 :   nz = A->nzr[iloc];
     220        1440 :   col1 = A->rcol[iloc];
     221        1440 :   val1 = A->rval[iloc];
     222        1440 :   if (!getcolpos(col1,nz,j,&k)) {
     223        1440 :     A->nzr[iloc]++;
     224             :     /* Replace row */
     225        1440 :     PetscCall(PetscMalloc2(nz+1,&col2,nz+1,&val2));
     226        1440 :     A->rcol[iloc] = col2;
     227        1440 :     A->rval[iloc] = val2;
     228        1440 :     for (kx=0; kx<k; kx++) {
     229           0 :       col2[kx] = col1[kx];
     230           0 :       val2[kx] = val1[kx];
     231             :     }
     232        1440 :     for (; kx<nz; kx++) {
     233           0 :       col2[kx+1] = col1[kx];
     234           0 :       val2[kx+1] = val1[kx];
     235             :     }
     236        1440 :     if (nz>0) {
     237           0 :       PetscCall(PetscFree2(col1,val1));
     238             :     }
     239        1440 :     col1 = col2;
     240        1440 :     val1 = val2;
     241             :   }
     242        1440 :   col1[k] = j;
     243        1440 :   val1[k] = x;
     244        1440 :   PetscFunctionReturn(PETSC_SUCCESS);
     245             : }
     246             : 
     247             : /* Convert to PETSc Mat */
     248          12 : static PetscErrorCode XMatConvert(XMat XA,Mat A)
     249             : {
     250          12 :   PetscInt    i,iloc;
     251             : 
     252          12 :   PetscFunctionBeginUser;
     253        1532 :   for (i=XA->Istart; i<XA->Iend; i++) {
     254        1520 :     iloc = i-XA->Istart;
     255        1520 :     PetscCall(MatSetValues(A,1,&i,XA->nzr[iloc],XA->rcol[iloc],XA->rval[iloc],INSERT_VALUES));
     256             :   }
     257          12 :   PetscCall(MatAssemblyBegin(A,MAT_FINAL_ASSEMBLY));
     258          12 :   PetscCall(MatAssemblyEnd(A,MAT_FINAL_ASSEMBLY));
     259          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     260             : }
     261             : 
     262             : /* gets the number of nonzeros in the matrix on this MPI rank */
     263          12 : static PetscErrorCode XMatGetNumberNonzeros(XMat A,PetscInt *nz)
     264             : {
     265          12 :   PetscInt i;
     266             : 
     267          12 :   PetscFunctionBeginUser;
     268          12 :   *nz = 0;
     269        1532 :   for (i=0; i<A->Iend-A->Istart; i++) *nz += A->nzr[i];
     270          12 :   PetscFunctionReturn(PETSC_SUCCESS);
     271             : }
     272             : 
     273         888 : static PetscErrorCode XMatCreateColsNzIter(XMat A,PetscInt j1,PetscInt j2,ColsNzIter *iter)
     274             : {
     275         888 :   PetscFunctionBeginUser;
     276         888 :   PetscCall(PetscNew(iter));
     277         888 :   (*iter)->A = A;
     278         888 :   (*iter)->j1 = j1;
     279         888 :   (*iter)->j2 = j2;
     280         888 :   (*iter)->iloc = 0;
     281         888 :   PetscFunctionReturn(PETSC_SUCCESS);
     282             : }
     283             : 
     284         888 : static PetscErrorCode ColitDestroy(ColsNzIter *iter)
     285             : {
     286         888 :   PetscFunctionBeginUser;
     287         888 :   PetscCall(PetscFree(*iter));
     288         888 :   PetscFunctionReturn(PETSC_SUCCESS);
     289             : }
     290             : 
     291       11560 : static PetscErrorCode ColitNextRow(ColsNzIter iter,PetscInt *i,PetscScalar **paij1,PetscScalar **paij2)
     292             : {
     293       11560 :   PetscInt    iloc = iter->iloc,*rcol,nz,k,k1,k2,kx,jx,*rcol2;
     294       11560 :   PetscScalar *rval,*rval2;
     295       11560 :   PetscBool   found1, found2;
     296       11560 :   XMat        A=iter->A;
     297             : 
     298       11560 :   PetscFunctionBeginUser;
     299       11560 :   *i = -1;
     300       11560 :   *paij1 = *paij2 = NULL;
     301       11560 :   if (iloc>=0) {
     302       11488 :     rcol =  A->rcol[iloc];
     303       11488 :     nz = A->nzr[iloc];
     304      213472 :     while (PETSC_TRUE) {
     305      112480 :       found1 = getcolpos(rcol,nz,iter->j1,&k1);
     306      112480 :       found2 = getcolpos(PetscSafePointerPlusOffset(rcol,k1+found1),nz-k1-found1,iter->j2,&k2);
     307      112480 :       if (found1 || found2) break;
     308      101808 :       iloc++;
     309      101808 :       if (iloc>=A->Iend-A->Istart) {
     310             :         iloc = -1;
     311             :         break;
     312             :       }
     313      100992 :       rcol = A->rcol[iloc];
     314      100992 :       nz = A->nzr[iloc];
     315             :     }
     316       11488 :     if (iloc>=0) {
     317       10672 :       k2 += k1 + 1;
     318       10672 :       rval = A->rval[iloc];
     319       10672 :       *i = A->Istart+iloc;
     320       10672 :       if (!found1 || !found2) {
     321             :         /* Copy row to a new one */
     322        9808 :         rcol2 = rcol;
     323        9808 :         rval2 = rval;
     324        9808 :         PetscCall(PetscMalloc2(nz+1,&rcol,nz+1,&rval));
     325        9808 :         if (found1) {
     326        5472 :           kx = k2;
     327        5472 :           jx = iter->j2;
     328             :         } else {
     329        4336 :           kx = k1;
     330        4336 :           jx = iter->j1;
     331             :         }
     332       63976 :         for (k=0; k<kx; k++) {
     333       54168 :           rcol[k] = rcol2[k];
     334       54168 :           rval[k] = rval2[k];
     335             :         }
     336        9808 :         rcol[kx] = jx;
     337        9808 :         rval[kx] = 0.0;
     338       72784 :         for (k=kx+1; k<nz+1; k++) {
     339       62976 :           rcol[k] = rcol2[k-1];
     340       62976 :           rval[k] = rval2[k-1];
     341             :         }
     342        9808 :         PetscCall(XMatChangeRow(A,*i,nz+1,rcol,rval));
     343             :       }
     344       10672 :       *paij1 = &rval[k1];
     345       10672 :       *paij2 = &rval[k2];
     346       10672 :       iloc++;
     347       10672 :       if (iloc>=A->Iend-A->Istart) iloc = -1;
     348             :     }
     349       11488 :     iter->iloc = iloc;
     350             :   }
     351       11560 :   PetscFunctionReturn(PETSC_SUCCESS);
     352             : }
     353             : 
     354         160 : static PetscErrorCode SendrecvRow(XMat A,PetscInt nc1,const PetscInt vj1[],const PetscScalar va1[],PetscInt i2,PetscInt *nc2,PetscInt vj2[],PetscScalar va2[])
     355             : {
     356         160 :   PetscInt    *ranges,N=A->N;
     357         160 :   PetscMPIInt rank,naux,len1,len2;
     358         160 :   MPI_Status  st;
     359             : 
     360         160 :   PetscFunctionBeginUser;
     361         160 :   PetscCall(XMatGetOwnershipRanges(A,&ranges));
     362         160 :   PetscAssertAbort(i2>=0 && i2<A->M,A->comm,PETSC_ERR_ARG_OUTOFRANGE,"Incorrect index of row");
     363             :   /* Find owner of row i2 */
     364         160 :   rank=0;
     365         240 :   while (ranges[rank+1]<=i2) rank++;
     366             :   /* Send row i1, receive row i2 */
     367         160 :   PetscCall(PetscMPIIntCast(nc1,&len1));
     368         160 :   PetscCall(PetscMPIIntCast(N,&len2));
     369         160 :   PetscCallMPI(MPI_Sendrecv(vj1,len1,MPIU_INT,rank,0,vj2,len2,MPIU_INT,rank,0,A->comm,&st));
     370         160 :   PetscCallMPI(MPI_Sendrecv(va1,len1,MPIU_SCALAR,rank,0,va2,len2,MPIU_SCALAR,rank,0,A->comm,MPI_STATUS_IGNORE));
     371         160 :   PetscCallMPI(MPI_Get_count(&st,MPIU_INT,&naux));
     372         160 :   *nc2 = (PetscInt)naux;
     373         160 :   PetscFunctionReturn(PETSC_SUCCESS);
     374             : }
     375             : 
     376        1264 : static PetscErrorCode PadRows(PetscInt nc1,const PetscInt vj1[],const PetscScalar va1[],PetscInt nc2,const PetscInt vj2[],const PetscScalar va2[],PetscInt *nc,PetscInt **vjj1,PetscScalar **vaa1,PetscInt **vjj2,PetscScalar **vaa2,PetscInt *iwork,PetscScalar *swork)
     377             : {
     378        1264 :   PetscInt    k1,k2,k,n1=nc1+nc2,*vjjaux=iwork;
     379        1264 :   PetscScalar *vaa1aux=swork,*vaa2aux=swork+n1;
     380             : 
     381        1264 :   PetscFunctionBeginUser;
     382        1264 :   *nc=0;
     383       10560 :   for (k1=k2=k=0; k1<nc1 && k2<nc2; ) {
     384        9296 :     if (vj1[k1]<vj2[k2]) {
     385             :       /* Take next element from first row */
     386        4324 :       vaa1aux[k] = va1[k1];
     387        4324 :       vaa2aux[k] = 0.0;
     388        4324 :       vjjaux[k++] = vj1[k1++];
     389        4972 :     } else if (vj1[k1]>vj2[k2]) {
     390             :       /* Take next element from second row */
     391        4312 :       vaa1aux[k] = 0.0;
     392        4312 :       vaa2aux[k] = va2[k2];
     393        4312 :       vjjaux[k++] = vj2[k2++];
     394             :     } else {
     395             :       /* Take next element from both rows */
     396         660 :       vaa1aux[k] = va1[k1];
     397         660 :       vaa2aux[k] = va2[k2++];
     398         660 :       vjjaux[k++] = vj1[k1++];
     399             :     }
     400             :   }
     401             : 
     402             :   /* We reached the end of one of the rows. Continue with the other one */
     403        2556 :   while (k1<nc1) {
     404             :       /* Take next element from first row */
     405        1292 :       vaa1aux[k] = va1[k1];
     406        1292 :       vaa2aux[k] = 0.0;
     407        1292 :       vjjaux[k++] = vj1[k1++];
     408             :   }
     409        2580 :   while (k2<nc2) {
     410             :       /* Take next element from second row */
     411        1316 :       vaa1aux[k] = 0.0;
     412        1316 :       vaa2aux[k] = va2[k2];
     413        1316 :       vjjaux[k++] = vj2[k2++];
     414             :   }
     415        1264 :   *nc=k;
     416             : 
     417             :   /* Copy rows (each row must be allocated separately)*/
     418        1264 :   PetscCall(PetscMalloc2(k,vjj1,k,vaa1));
     419        1264 :   PetscCall(PetscMalloc2(k,vjj2,k,vaa2));
     420        1264 :   PetscCall(PetscArraycpy(*vjj1,vjjaux,k));
     421        1264 :   PetscCall(PetscArraycpy(*vjj2,vjjaux,k));
     422        1264 :   PetscCall(PetscArraycpy(*vaa1,vaa1aux,k));
     423        1264 :   PetscCall(PetscArraycpy(*vaa2,vaa2aux,k));
     424        1264 :   PetscFunctionReturn(PETSC_SUCCESS);
     425             : }
     426             : 
     427         160 : static inline void MyAxpby(PetscInt n,PetscScalar a,PetscScalar x[],PetscScalar b,const PetscScalar y[])
     428             : {
     429         160 :   PetscInt i;
     430             : 
     431        1280 :   for (i=0; i<n; i++) x[i] = a*x[i]+b*y[i];
     432             : }
     433             : 
     434             : /* Apply plane rotation on rows i1, i2 of A */
     435        1776 : static PetscErrorCode RotateRows(XMat A,PetscInt i1,PetscInt i2,PetscReal c,PetscReal s,PetscInt *nzloc,PetscInt *iwork,PetscScalar *swork)
     436             : {
     437        1776 :   PetscInt     M,N,Istart,Iend,nc,nc1,nc2,*vj1=NULL,*vj2=NULL,*vjj1=NULL,*vjj2=NULL,*iworkx=iwork;
     438        1776 :   PetscBLASInt nc_,one=1;
     439        1776 :   PetscScalar  *va1=NULL,*va2=NULL,*vaa1=NULL,*vaa2=NULL,*sworkx=swork;
     440        1776 :   PetscBool    i1mine, i2mine;
     441             : #ifdef TIMING
     442             :   PetscReal    t,t0;
     443             : #endif
     444             : 
     445        1776 :   PetscFunctionBeginUser;
     446        1776 :   PetscCall(XMatGetOwnershipRange(A,&Istart,&Iend));
     447        1776 :   i1mine = (Istart<=i1 && i1<Iend)? PETSC_TRUE: PETSC_FALSE;
     448        1776 :   i2mine = (Istart<=i2 && i2<Iend)? PETSC_TRUE: PETSC_FALSE;
     449             : 
     450        1776 :   if (i1mine || i2mine) {
     451        1264 :     PetscCall(XMatGetSize(A,&M,&N));
     452             : 
     453             :     /* Get local row(s) (at least 1, possibly 2) */
     454        1264 :     time_now(t0);
     455        1264 :     if (i1mine) PetscCall(XMatGetRow(A,i1,&nc1,&vj1,&va1));
     456        1264 :     if (i2mine) PetscCall(XMatGetRow(A,i2,&nc2,&vj2,&va2));
     457        1264 :     time_diff(tt_getr,t0,t,t0);
     458             :     /* Get remote row (at most 1, possibly none) */
     459        1264 :     if (!i2mine) {
     460          80 :       vj2 = iworkx;
     461          80 :       iworkx += N;
     462          80 :       va2 = sworkx;
     463          80 :       sworkx += N;
     464          80 :       PetscCall(SendrecvRow(A,nc1,vj1,va1,i2,&nc2,vj2,va2));
     465        1184 :     } else if (!i1mine) {
     466          80 :       vj1 = iworkx;
     467          80 :       iworkx += N;
     468          80 :       va1 = sworkx;
     469          80 :       sworkx += N;
     470          80 :       PetscCall(SendrecvRow(A,nc2,vj2,va2,i1,&nc1,vj1,va1));
     471             :     }
     472             : 
     473        1264 :     PetscCall(PadRows(nc1,vj1,va1,nc2,vj2,va2,&nc,&vjj1,&vaa1,&vjj2,&vaa2,iworkx,sworkx));
     474        1264 :     if (i1mine) {
     475        1184 :       *nzloc += nc-nc1;
     476        1184 :       PetscCall(XMatRestoreRow(A,i1,&nc1,&vj1,&va1));
     477             :     }
     478        1264 :     if (i2mine) {
     479        1184 :       *nzloc += nc-nc2;
     480        1184 :       PetscCall(XMatRestoreRow(A,i2,&nc2,&vj2,&va2));
     481             :     }
     482             : 
     483             :     /* Compute rotation and update matrix */
     484        1264 :     if (nc) {
     485        1256 :       PetscCall(PetscBLASIntCast(nc,&nc_));
     486        1256 :       if (i1mine && i2mine) PetscCallBLAS("BLASrot",BLASMIXEDrot_(&nc_,vaa1,&one,vaa2,&one,&c,&s));
     487         160 :       else if (i1mine) {
     488          80 :         MyAxpby(nc,c,vaa1,s,vaa2);
     489          80 :         PetscCall(PetscFree2(vjj2,vaa2));
     490             :       } else {
     491          80 :         MyAxpby(nc,c,vaa2,-s,vaa1);
     492          80 :         PetscCall(PetscFree2(vjj1,vaa1));
     493             :       }
     494        1256 :       time_now(t0);
     495        1256 :       if (i1mine) PetscCall(XMatChangeRow(A,i1,nc,vjj1,vaa1));
     496        1256 :       if (i2mine) PetscCall(XMatChangeRow(A,i2,nc,vjj2,vaa2));
     497        1776 :       time_diff(tt_setvalr,t0,t,t0);
     498             :     }
     499             :   }
     500        1776 :   PetscFunctionReturn(PETSC_SUCCESS);
     501             : }
     502             : 
     503             : /* Apply plane rotation on columns j1, j2 of A */
     504         888 : static PetscErrorCode RotateCols(XMat A,PetscInt j1,PetscInt j2,PetscReal c,PetscReal s,PetscInt *nzloc)
     505             : {
     506         888 :   PetscInt    i;
     507         888 :   PetscScalar aux1,aux2,*paij1,*paij2;
     508         888 :   ColsNzIter  iter;
     509             : 
     510         888 :   PetscFunctionBeginUser;
     511         888 :   PetscCall(XMatCreateColsNzIter(A,j1,j2,&iter));
     512       22232 :   while (PETSC_TRUE) {
     513       11560 :     PetscCall(ColitNextRow(iter,&i,&paij1,&paij2));
     514       11560 :     if (i<0) break;
     515       10672 :     if (*paij1**paij2==0.0) (*nzloc)++;
     516       10672 :     aux1 = *paij1*c+*paij2*s;
     517       10672 :     aux2 = -*paij1*s+*paij2*c;
     518       10672 :     *paij1 = aux1;
     519       10672 :     *paij2 = aux2;
     520             :   }
     521         888 :   PetscCall(ColitDestroy(&iter));
     522         888 :   PetscFunctionReturn(PETSC_SUCCESS);
     523             : }
     524             : 
     525             : /* Generate a pair of indices i1, i2, where 0 <= i1 < i2 < n */
     526        2664 : static PetscErrorCode GetIndexPair(PetscRandom rand,PetscInt n,PetscInt *i1,PetscInt *i2)
     527             : {
     528        2664 :   PetscInt  aux;
     529        2664 :   PetscReal x;
     530             : 
     531        2664 :   PetscFunctionBeginUser;
     532        2664 :   PetscCall(PetscRandomGetValueReal(rand,&x));
     533        2664 :   *i1 = (PetscInt)(x*n);
     534        2664 :   PetscCall(PetscRandomGetValueReal(rand,&x));
     535        2664 :   *i2 = (PetscInt)(x*(n-1));
     536        2664 :   if (*i2>=*i1) (*i2)++;
     537        2664 :   if (*i1>*i2) {
     538        1332 :     aux = *i1;
     539        1332 :     *i1 = *i2;
     540        1332 :     *i2 = aux;
     541             :   }
     542        2664 :   PetscFunctionReturn(PETSC_SUCCESS);
     543             : }
     544             : 
     545          12 : int main(int argc,char **argv)
     546             : {
     547          12 :   Mat         A,Omega;         /* operator matrix, signature matrix */
     548          12 :   XMat        XA;
     549          12 :   SVD         svd;             /* singular value problem solver context */
     550          12 :   Vec         u,v,vomega,*U,*V;
     551          12 :   MatType     Atype;
     552          12 :   PetscReal   tol,lev1=0.0,lev2=0.0,k=1e3,dens=0.1,log0,loginc,sq,x,angle,c,s;
     553          12 :   PetscScalar *swork;
     554          12 :   PetscInt    P=110,Q=80,N=100,i,j,Istart,Iend,nconv,nsv,i1,i2,nroth,nrotv,*iwork,nnzwanted,nz,nzloc;
     555          12 :   PetscBool   flg,flgp,flgq,flgn,terse,skiporth=PETSC_FALSE,progress=PETSC_FALSE;
     556          12 :   PetscRandom rand;
     557          12 :   MatInfo     Ainfo;
     558             : #ifdef TIMING
     559             :   PetscReal   t,t0;
     560             : #endif
     561             : 
     562          12 :   PetscFunctionBeginUser;
     563          12 :   PetscCall(SlepcInitialize(&argc,&argv,NULL,help));
     564             : 
     565          12 :   PetscCall(PetscOptionsGetInt(NULL,NULL,"-p",&P,&flgp));
     566          12 :   PetscCall(PetscOptionsGetInt(NULL,NULL,"-q",&Q,&flgq));
     567          12 :   PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&N,&flgn));
     568          12 :   PetscCall(PetscOptionsGetReal(NULL,NULL,"-k",&k,&flg));
     569          12 :   PetscCall(PetscOptionsGetReal(NULL,NULL,"-d",&dens,&flg));
     570          12 :   PetscCall(PetscOptionsGetBool(NULL,NULL,"-prog",&progress,&flg));
     571          12 :   if (!flgp && flgn) P=N;
     572          12 :   if (!flgq && flgn) Q=N;
     573          12 :   PetscCheck(P>=N,PETSC_COMM_WORLD,PETSC_ERR_USER_INPUT,"Parameter p must be >= n");
     574          12 :   PetscCheck(k>=1.0,PETSC_COMM_WORLD,PETSC_ERR_USER_INPUT,"Parameter k must be >= 1.0");
     575          12 :   PetscCheck(dens<=1.0,PETSC_COMM_WORLD,PETSC_ERR_USER_INPUT,"Parameter d must be <= 1.0");
     576             : 
     577             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     578             :         Build matrix that defines the hyperbolic singular value problem
     579             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     580             : 
     581          12 :   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\nHyperbolic singular value problem.\n\n"));
     582          12 :   PetscCall(PetscPrintf(PETSC_COMM_WORLD,"\n Matrix dimensions: (%" PetscInt_FMT "+%" PetscInt_FMT ")x%" PetscInt_FMT,P,Q,N));
     583          12 :   PetscCall(PetscPrintf(PETSC_COMM_WORLD,", using signature Omega=blkdiag(I_%" PetscInt_FMT ",-I_%" PetscInt_FMT ")\n\n",P,Q));
     584             : 
     585          12 :   PetscCall(MatCreate(PETSC_COMM_WORLD,&A));
     586          12 :   PetscCall(MatSetSizes(A,PETSC_DECIDE,PETSC_DECIDE,P+Q,N));
     587          12 :   PetscCall(MatSetFromOptions(A));
     588          12 :   PetscCall(MatSetOption(A,MAT_IGNORE_OFF_PROC_ENTRIES,PETSC_TRUE));
     589             : 
     590             :   /* Set diagonals */
     591          12 :   PetscCall(MatGetOwnershipRange(A,&Istart,&Iend));
     592             : 
     593          12 :   PetscCall(XMatCreate(MPI_COMM_WORLD,&XA,Istart,Iend,P+Q,N));
     594          12 :   log0 = PetscLogReal(1/k);
     595          12 :   loginc = -log0/(N-1);
     596          12 :   sq = PetscSqrtReal(5.0/4.0);
     597        1532 :   for (i=Istart;i<Iend;i++) {
     598        1520 :     if (i<P && i<N) {
     599         800 :       if (i<Q) x = sq*PetscExpReal(log0+i*loginc);
     600         160 :       else     x = PetscExpReal(log0+i*loginc);
     601         800 :       PetscCall(XMatSetValue(XA,i,i,x,INSERT_VALUES));
     602         720 :     } else if (i>=P && i-P<N) {
     603         640 :       j = i-P;
     604        1520 :       PetscCall(XMatSetValue(XA,i,j,PetscExpReal(log0+j*loginc),INSERT_VALUES));
     605             :     }
     606             :   }
     607             : 
     608             :   /* Apply plane rotations */
     609          12 :   nnzwanted = dens*(P+Q)*N;
     610          12 :   PetscCall(XMatGetNumberNonzeros(XA,&nzloc));
     611          24 :   PetscCallMPI(MPI_Allreduce(&nzloc,&nz,1,MPIU_INT,MPI_SUM,MPI_COMM_WORLD));
     612          12 :   PetscCall(PetscRandomCreate(PETSC_COMM_SELF,&rand));
     613          12 :   PetscCall(PetscRandomSetFromOptions(rand));
     614          12 :   nroth = nrotv = 0;
     615          12 :   PetscCall(PetscMalloc2(2*N,&iwork,3*N,&swork));
     616             :   time_now(t0);
     617         900 :   while (nz<0.95*nnzwanted) {
     618             :     /* Plane rotation on 2 of the top P rows*/
     619         888 :     PetscCall(PetscRandomGetValueReal(rand,&angle));
     620         888 :     c=PetscCosReal(angle);
     621         888 :     s=PetscSinReal(angle);
     622         888 :     PetscCall(GetIndexPair(rand,P,&i1,&i2));
     623         888 :     PetscCall(RotateRows(XA,i1,i2,c,s,&nzloc,iwork,swork));
     624         888 :     time_diff(tt_rotr,t0,t,t0);
     625         888 :     nroth++;
     626             :     /* Plane rotation on 2 of the bottom Q rows*/
     627         888 :     if (Q>1) {
     628         888 :       PetscCall(PetscRandomGetValueReal(rand,&angle));
     629         888 :       c=PetscCosReal(angle);
     630         888 :       s=PetscSinReal(angle);
     631         888 :       PetscCall(GetIndexPair(rand,Q,&i1,&i2));
     632         888 :       PetscCall(RotateRows(XA,P+i1,P+i2,c,s,&nzloc,iwork,swork));
     633         888 :       time_diff(tt_rotr,t0,t,t0);
     634         888 :       nroth++;
     635             :     }
     636             :     /* Plane rotation on 2 columns */
     637         888 :     PetscCall(PetscRandomGetValueReal(rand,&angle));
     638         888 :     c=PetscCosReal(angle);
     639         888 :     s=PetscSinReal(angle);
     640         888 :     PetscCall(GetIndexPair(rand,N,&i1,&i2));
     641         888 :     PetscCall(RotateCols(XA,i1,i2,c,s,&nzloc));
     642         888 :     time_diff(tt_rotc,t0,t,t0);
     643         888 :     nrotv++;
     644             :     /* Update total number of non-zeros */
     645        1776 :     PetscCallMPI(MPI_Allreduce(&nzloc,&nz,1,MPIU_INT,MPI_SUM,MPI_COMM_WORLD));
     646        1788 :     if (progress) PetscCall(PetscFPrintf(MPI_COMM_WORLD,stderr,"\rProgress: %.2f%%",(double)nz/nnzwanted*100));
     647             :   }
     648          12 :   if (progress) PetscCall(PetscFPrintf(MPI_COMM_WORLD,stderr,"\r"));
     649             : 
     650          12 :   PetscCall(PetscFree2(iwork,swork));
     651          12 :   PetscCall(PetscRandomDestroy(&rand));
     652             : 
     653          12 :   PetscCall(XMatConvert(XA,A));
     654          12 :   PetscCall(XMatDestroy(&XA));
     655          12 :   PetscCall(MatGetInfo(A,MAT_GLOBAL_SUM,&Ainfo));
     656          12 :   PetscCall(PetscPrintf(MPI_COMM_WORLD," Matrix created. %" PetscInt_FMT " rotations applied. nnz=%.0f. Density: %.4g\n\n",nroth+nrotv,Ainfo.nz_used,(double)Ainfo.nz_used/(1.0*(P+Q)*N)));
     657             : 
     658             : #ifdef TIMING
     659             :   PetscCall(PetscPrintf(MPI_COMM_WORLD,"#T rot-rows: %6.3f  get-rows: %6.3f  setval-rows: %6.3f  assm-rows: %.3f\n",tt_rotr,tt_getr,tt_setvalr,tt_assmr));
     660             :   PetscCall(PetscPrintf(MPI_COMM_WORLD,"#T rot cols: %6.3f  get-cols: %6.3f  setval-cols: %6.3f  assm-cols: %.3f\n",tt_rotc,tt_getc,tt_setvalc,tt_assmc));
     661             : #endif
     662             : 
     663             :   /* scale by 0.5 the lower Q rows of A */
     664          12 :   PetscCall(MatCreateVecs(A,NULL,&vomega));
     665          12 :   PetscCall(VecSet(vomega,1.0));
     666         652 :   for (i=PetscMax(P,Istart);i<Iend;i++) {
     667         640 :     PetscCall(VecSetValue(vomega,i,0.5,INSERT_VALUES));
     668             :   }
     669          12 :   PetscCall(VecAssemblyBegin(vomega));
     670          12 :   PetscCall(VecAssemblyEnd(vomega));
     671          12 :   PetscCall(MatDiagonalScale(A,vomega,NULL));
     672             : 
     673             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     674             :                           Create the signature
     675             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     676             : 
     677          12 :   PetscCall(VecSet(vomega,1.0));
     678          12 :   PetscCall(VecGetOwnershipRange(vomega,&Istart,&Iend));
     679        1532 :   for (i=Istart;i<Iend;i++) {
     680        1520 :     if (i>=P) PetscCall(VecSetValue(vomega,i,-1.0,INSERT_VALUES));
     681             :   }
     682          12 :   PetscCall(VecAssemblyBegin(vomega));
     683          12 :   PetscCall(VecAssemblyEnd(vomega));
     684             : 
     685          12 :   PetscCall(MatGetType(A,&Atype));
     686          12 :   PetscCall(MatCreate(PETSC_COMM_WORLD,&Omega));
     687          12 :   PetscCall(MatSetSizes(Omega,PETSC_DECIDE,PETSC_DECIDE,P+Q,P+Q));
     688          12 :   PetscCall(MatSetType(Omega,Atype));
     689          12 :   PetscCall(MatDiagonalSet(Omega,vomega,INSERT_VALUES));
     690             : 
     691             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     692             :           Create the singular value solver and set various options
     693             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     694             : 
     695          12 :   PetscCall(SVDCreate(PETSC_COMM_WORLD,&svd));
     696             : 
     697          12 :   PetscCall(SVDSetOperators(svd,A,NULL));
     698          12 :   PetscCall(SVDSetSignature(svd,vomega));
     699          12 :   PetscCall(SVDSetProblemType(svd,SVD_HYPERBOLIC));
     700             : 
     701          12 :   PetscCall(SVDSetFromOptions(svd));
     702             : 
     703             :   /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     704             :                  Solve the problem, display solution
     705             :      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     706             : 
     707          12 :   PetscCall(MatCreateVecs(A,&v,&u));
     708          12 :   PetscCall(SVDSolve(svd));
     709             : 
     710             :   /* show detailed info unless -terse option is given by user */
     711          12 :   PetscCall(PetscOptionsHasName(NULL,NULL,"-terse",&terse));
     712          12 :   if (terse) PetscCall(SVDErrorView(svd,SVD_ERROR_NORM,NULL));
     713             :   else {
     714           0 :     PetscCall(PetscViewerPushFormat(PETSC_VIEWER_STDOUT_WORLD,PETSC_VIEWER_ASCII_INFO_DETAIL));
     715           0 :     PetscCall(SVDConvergedReasonView(svd,PETSC_VIEWER_STDOUT_WORLD));
     716           0 :     PetscCall(SVDErrorView(svd,SVD_ERROR_NORM,PETSC_VIEWER_STDOUT_WORLD));
     717           0 :     PetscCall(PetscViewerPopFormat(PETSC_VIEWER_STDOUT_WORLD));
     718             :   }
     719             : 
     720             :   /* check orthogonality */
     721          12 :   PetscCall(PetscOptionsGetBool(NULL,NULL,"-skiporth",&skiporth,NULL));
     722          12 :   PetscCall(SVDGetConverged(svd,&nconv));
     723          12 :   PetscCall(SVDGetDimensions(svd,&nsv,NULL,NULL));
     724          12 :   nconv = PetscMin(nconv,nsv);
     725          12 :   if (nconv>0 && !skiporth) {
     726          12 :     PetscCall(SVDGetTolerances(svd,&tol,NULL));
     727          12 :     PetscCall(VecDuplicateVecs(u,nconv,&U));
     728          12 :     PetscCall(VecDuplicateVecs(v,nconv,&V));
     729          72 :     for (i=0;i<nconv;i++) PetscCall(SVDGetSingularTriplet(svd,i,NULL,U[i],V[i]));
     730          12 :     PetscCall(VecCheckOrthonormality(U,nconv,NULL,nconv,Omega,NULL,&lev1));
     731          12 :     PetscCall(VecCheckOrthonormality(V,nconv,NULL,nconv,NULL,NULL,&lev2));
     732          12 :     if (lev1+lev2<20*tol) PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Level of orthogonality below the tolerance\n"));
     733           0 :     else PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Level of orthogonality: %g (U) %g (V)\n",(double)lev1,(double)lev2));
     734          12 :     PetscCall(VecDestroyVecs(nconv,&U));
     735          12 :     PetscCall(VecDestroyVecs(nconv,&V));
     736             :   }
     737          12 :   PetscCall(VecDestroy(&u));
     738          12 :   PetscCall(VecDestroy(&v));
     739             : 
     740             :   /* free work space */
     741          12 :   PetscCall(SVDDestroy(&svd));
     742          12 :   PetscCall(MatDestroy(&Omega));
     743          12 :   PetscCall(MatDestroy(&A));
     744          12 :   PetscCall(VecDestroy(&vomega));
     745          12 :   PetscCall(SlepcFinalize());
     746             :   return 0;
     747             : }
     748             : 
     749             : /*TEST
     750             : 
     751             :    testset:
     752             :       args: -svd_nsv 5 -d .15 -terse
     753             :       output_file: output/ex53_1.out
     754             :       nsize: {{1 2}}
     755             :       test:
     756             :          args: -svd_type trlanczos -ds_parallel {{redundant synchronized}}
     757             :          suffix: 1_trlanczos
     758             :       test:
     759             :          args: -svd_type cross
     760             :          suffix: 1_cross
     761             :       test:
     762             :          args: -svd_type cyclic
     763             :          requires: !single
     764             :          suffix: 1_cyclic
     765             : 
     766             : TEST*/

Generated by: LCOV version 1.14