Date: 2024-12-02T08:58:09+00:00

Actual source code: dsgsvd.c
slepc-3.22.2 2024-12-02
Report Typos and Errors

      1: /*
      2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: #include <slepc/private/dsimpl.h>
     11: #include <slepcblaslapack.h>

     13: typedef struct {
     14:   PetscInt m;              /* number of columns */
     15:   PetscInt p;              /* number of rows of B */
     16:   PetscInt tm;             /* number of rows of X after truncating */
     17:   PetscInt tp;             /* number of rows of V after truncating */
     18: } DS_GSVD;

     20: static PetscErrorCode DSAllocate_GSVD(DS ds,PetscInt ld)
     21: {
     22:   PetscFunctionBegin;
     23:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_A));
     24:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_B));
     25:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_X));
     26:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_U));
     27:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_V));
     28:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_T));
     29:   PetscCall(DSAllocateMat_Private(ds,DS_MAT_D));
     30:   PetscCall(PetscFree(ds->perm));
     31:   PetscCall(PetscMalloc1(ld,&ds->perm));
     32:   PetscFunctionReturn(PETSC_SUCCESS);
     33: }

     35: /*
     36:   In compact form, A is either in form (a) or (b):

     38:                      (a)                                            (b)
     39:     lower bidiagonal with upper arrow (n=m+1)         square upper bidiagonal with upper arrow (n=m)
     40:      0       l           k                 m-1
     41:     -----------------------------------------         0     l           k                   m-1
     42:     |*                   .                  |        -----------------------------------------
     43:     |  *                 .                  |        |*                 .                    |
     44:     |    *               .                  |        |  *               .                    |
     45:     |      *             .                  |        |    *             .                    |
     46:   l |. . . . o           o                  |      l |. . . o           o                    |
     47:     |          o         o                  |        |        o         o                    |
     48:     |            o       o                  |        |          o       o                    |
     49:     |              o     o                  |        |            o     o                    |
     50:     |                o   o                  |        |              o   o                    |
     51:     |                  o o                  |        |                o o                    |
     52:   k |. . . . . . . . . . o                  |      k |. . . . . . . . . o x                  |
     53:     |                    x x                |        |                    x x                |
     54:     |                      x x              |        |                      x x              |
     55:     |                        x x            |        |                        x x            |
     56:     |                          x x          |        |                          x x          |
     57:     |                            x x        |        |                            x x        |
     58:     |                              x x      |        |                              x x      |
     59:     |                                x x    |        |                                x x    |
     60:     |                                  x x  |        |                                  x x  |
     61:     |                                    x x|        |                                    x x|
     62: n-1 |                                      x|    n-1 |                                      x|
     63:     -----------------------------------------        -----------------------------------------

     65:   and B is square bidiagonal with upper arrow (p=m)

     67:      0       l           k                 m-1
     68:     -----------------------------------------
     69:     |*                   .                  |
     70:     |  *                 .                  |
     71:     |    *               .                  |
     72:     |      *             .                  |
     73:   l |. . . . o           o                  |
     74:     |          o         o                  |
     75:     |            o       o                  |
     76:     |              o     o                  |
     77:     |                o   o                  |
     78:     |                  o o                  |
     79:   k |. . . . . . . . . . o x                |
     80:     |                      x x              |
     81:     |                        x x            |
     82:     |                          x x          |
     83:     |                            x x        |
     84:     |                              x x      |
     85:     |                                x x    |
     86:     |                                  x x  |
     87:     |                                    x x|
     88: p-1 |                                      x|
     89:      ----------------------------------------
     90: */
     91: static PetscErrorCode DSView_GSVD(DS ds,PetscViewer viewer)
     92: {
     93:   DS_GSVD           *ctx = (DS_GSVD*)ds->data;
     94:   PetscViewerFormat format;
     95:   PetscInt          i,j,r,k=ds->k,n=ds->n,m=ctx->m,p=ctx->p,rowsa,rowsb,colsa,colsb;
     96:   PetscReal         *T,*S,value;

     98:   PetscFunctionBegin;
     99:   PetscCall(PetscViewerGetFormat(viewer,&format));
    100:   if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
    101:   if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
    102:     PetscCall(PetscViewerASCIIPrintf(viewer,"number of columns: %" PetscInt_FMT "\n",m));
    103:     PetscCall(PetscViewerASCIIPrintf(viewer,"number of rows of B: %" PetscInt_FMT "\n",p));
    104:     PetscFunctionReturn(PETSC_SUCCESS);
    105:   }
    106:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    107:   if (ds->compact) {
    108:     PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    109:     PetscCall(DSGetArrayReal(ds,DS_MAT_D,&S));
    110:     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
    111:     rowsa = n;
    112:     colsa = ds->extrarow? m+1: m;
    113:     rowsb = p;
    114:     colsb = ds->extrarow? m+1: m;
    115:     if (format == PETSC_VIEWER_ASCII_MATLAB) {
    116:       PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",rowsa,colsa));
    117:       PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = zeros(%" PetscInt_FMT ",3);\n",2*ds->n));
    118:       PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = [\n"));
    119:       for (i=0;i<PetscMin(rowsa,colsa);i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+1,i+1,(double)T[i]));
    120:       for (i=0;i<k;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+1,k+1,(double)T[i+ds->ld]));
    121:       if (n>m) { /* A lower bidiagonal */
    122:         for (i=k;i<rowsa-1;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+2,i+1,(double)T[i+ds->ld]));
    123:       } else { /* A (square) upper bidiagonal */
    124:         for (i=k;i<colsa-1;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+1,i+2,(double)T[i+ds->ld]));
    125:       }
    126:       PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(zzz);\n",DSMatName[DS_MAT_T]));
    127:       PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",rowsb,colsb));
    128:       PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = zeros(%" PetscInt_FMT ",3);\n",2*ds->n));
    129:       PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = [\n"));
    130:       for (i=0;i<rowsb;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+1,i+1,(double)S[i]));
    131:       for (i=0;i<colsb-1;i++) {
    132:         r = PetscMax(i+2,ds->k+1);
    133:         PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT "  %18.16e\n",i+1,r,(double)T[i+2*ds->ld]));
    134:       }
    135:       PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(zzz);\n",DSMatName[DS_MAT_D]));
    136:     } else {
    137:       PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix %s =\n",DSMatName[DS_MAT_T]));
    138:       for (i=0;i<rowsa;i++) {
    139:         for (j=0;j<colsa;j++) {
    140:           if (i==j) value = T[i];
    141:           else if (i<ds->k && j==ds->k) value = T[i+ds->ld];
    142:           else if (n>m && i==j+1 && i>ds->k) value = T[j+ds->ld];
    143:           else if (n<=m && i+1==j && i>=ds->k) value = T[i+ds->ld];
    144:           else value = 0.0;
    145:           PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
    146:         }
    147:         PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
    148:       }
    149:       PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix %s =\n",DSMatName[DS_MAT_D]));
    150:       for (i=0;i<rowsb;i++) {
    151:         for (j=0;j<colsb;j++) {
    152:           if (i==j) value = S[i];
    153:           else if (i<ds->k && j==ds->k) value = T[PetscMin(i,j)+2*ds->ld];
    154:           else if (i+1==j && i>=ds->k) value = T[i+2*ds->ld];
    155:           else value = 0.0;
    156:           PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
    157:         }
    158:         PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
    159:       }
    160:     }
    161:     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
    162:     PetscCall(PetscViewerFlush(viewer));
    163:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    164:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&S));
    165:   } else {
    166:     PetscCall(DSViewMat(ds,viewer,DS_MAT_A));
    167:     PetscCall(DSViewMat(ds,viewer,DS_MAT_B));
    168:   }
    169:   if (ds->state>DS_STATE_INTERMEDIATE) {
    170:     PetscCall(DSViewMat(ds,viewer,DS_MAT_X));
    171:     PetscCall(DSViewMat(ds,viewer,DS_MAT_U));
    172:     PetscCall(DSViewMat(ds,viewer,DS_MAT_V));
    173:   }
    174:   PetscFunctionReturn(PETSC_SUCCESS);
    175: }

    177: static PetscErrorCode DSVectors_GSVD(DS ds,DSMatType mat,PetscInt *j,PetscReal *rnorm)
    178: {
    179:   PetscFunctionBegin;
    180:   switch (mat) {
    181:     case DS_MAT_U:
    182:     case DS_MAT_V:
    183:       if (rnorm) *rnorm = 0.0;
    184:       break;
    185:     case DS_MAT_X:
    186:       break;
    187:     default:
    188:       SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid mat parameter");
    189:   }
    190:   PetscFunctionReturn(PETSC_SUCCESS);
    191: }

    193: static PetscErrorCode DSSort_GSVD(DS ds,PetscScalar *wr,PetscScalar *wi,PetscScalar *rr,PetscScalar *ri,PetscInt *k)
    194: {
    195:   DS_GSVD        *ctx = (DS_GSVD*)ds->data;
    196:   PetscInt       t,l,ld=ds->ld,i,*perm,*perm2;
    197:   PetscReal      *T=NULL,*D=NULL,*eig;
    198:   PetscScalar    *A=NULL,*B=NULL;
    199:   PetscBool      compact=ds->compact;

    201:   PetscFunctionBegin;
    202:   if (!ds->sc) PetscFunctionReturn(PETSC_SUCCESS);
    203:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    204:   l = ds->l;
    205:   t = ds->t;
    206:   perm = ds->perm;
    207:   PetscCall(PetscMalloc2(t,&eig,t,&perm2));
    208:   if (compact) {
    209:     PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    210:     PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
    211:     for (i=0;i<t;i++) eig[i] = (D[i]==0)?PETSC_INFINITY:T[i]/D[i];
    212:   } else {
    213:     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
    214:     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_B],&B));
    215:     for (i=0;i<t;i++) eig[i] = (B[i+i*ld]==0)?PETSC_INFINITY:PetscRealPart(A[i+i*ld])/PetscRealPart(B[i*(1+ld)]);
    216:   }
    217:   PetscCall(DSSortEigenvaluesReal_Private(ds,eig,perm));
    218:   PetscCall(PetscArraycpy(perm2,perm,t));
    219:   for (i=l;i<t;i++) wr[i] = eig[perm[i]];
    220:   if (compact) {
    221:     PetscCall(PetscArraycpy(eig,T,t));
    222:     for (i=l;i<t;i++) T[i] = eig[perm[i]];
    223:     PetscCall(PetscArraycpy(eig,D,t));
    224:     for (i=l;i<t;i++) D[i] = eig[perm[i]];
    225:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    226:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
    227:   } else {
    228:     for (i=l;i<t;i++) eig[i] = PetscRealPart(A[i*(1+ld)]);
    229:     for (i=l;i<t;i++) A[i*(1+ld)] = eig[perm[i]];
    230:     for (i=l;i<t;i++) eig[i] = PetscRealPart(B[i*(1+ld)]);
    231:     for (i=l;i<t;i++) B[i*(1+ld)] = eig[perm[i]];
    232:     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
    233:     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_B],&B));
    234:   }
    235:   PetscCall(DSPermuteColumns_Private(ds,l,t,ds->n,DS_MAT_U,perm2));
    236:   PetscCall(PetscArraycpy(perm2,perm,t));
    237:   PetscCall(DSPermuteColumns_Private(ds,l,t,ctx->m,DS_MAT_X,perm2));
    238:   PetscCall(DSPermuteColumns_Private(ds,l,t,ctx->p,DS_MAT_V,perm));
    239:   PetscCall(PetscFree2(eig,perm2));
    240:   PetscFunctionReturn(PETSC_SUCCESS);
    241: }

    243: static PetscErrorCode DSUpdateExtraRow_GSVD(DS ds)
    244: {
    245:   DS_GSVD           *ctx = (DS_GSVD*)ds->data;
    246:   PetscInt          i;
    247:   PetscBLASInt      n=0,m=0,ld=0;
    248:   const PetscScalar *U,*V;
    249:   PetscReal         *T,*e,*f,alpha,beta,betah;

    251:   PetscFunctionBegin;
    252:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    253:   PetscCheck(ds->compact,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-compact storage");
    254:   PetscCall(PetscBLASIntCast(ds->n,&n));
    255:   PetscCall(PetscBLASIntCast(ctx->m,&m));
    256:   PetscCall(PetscBLASIntCast(ds->ld,&ld));
    257:   PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    258:   e = T+ld;
    259:   f = T+2*ld;
    260:   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_U],&U));
    261:   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_V],&V));
    262:   if (n<=m) {   /* upper variant, A is square upper bidiagonal */
    263:     beta  = e[m-1];   /* in compact, we assume all entries are zero except the last one */
    264:     betah = f[m-1];
    265:     for (i=0;i<m;i++) {
    266:       e[i] = PetscRealPart(beta*U[m-1+i*ld]);
    267:       f[i] = PetscRealPart(betah*V[m-1+i*ld]);
    268:     }
    269:   } else {   /* lower variant, A is (m+1)xm lower bidiagonal */
    270:     alpha = T[m];
    271:     betah = f[m-1];
    272:     for (i=0;i<m;i++) {
    273:       e[i] = PetscRealPart(alpha*U[m+i*ld]);
    274:       f[i] = PetscRealPart(betah*V[m-1+i*ld]);
    275:     }
    276:     T[m] = PetscRealPart(alpha*U[m+m*ld]);
    277:   }
    278:   ds->k = m;
    279:   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_U],&U));
    280:   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_V],&V));
    281:   PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    282:   PetscFunctionReturn(PETSC_SUCCESS);
    283: }

    285: static PetscErrorCode DSTruncate_GSVD(DS ds,PetscInt n,PetscBool trim)
    286: {
    287:   DS_GSVD     *ctx = (DS_GSVD*)ds->data;
    288:   PetscScalar *U;
    289:   PetscReal   *T;
    290:   PetscInt    i,m=ctx->m,ld=ds->ld;
    291:   PetscBool   lower=(ds->n>ctx->m)?PETSC_TRUE:PETSC_FALSE;

    293:   PetscFunctionBegin;
    294:   PetscCheck(ds->compact,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-compact storage");
    295:   if (trim) {
    296:     ds->l   = 0;
    297:     ds->k   = 0;
    298:     ds->n   = lower? n+1: n;
    299:     ctx->m  = n;
    300:     ctx->p  = n;
    301:     ds->t   = ds->n;   /* truncated length equal to the new dimension */
    302:     ctx->tm = ctx->m;  /* must also keep the previous dimension of X */
    303:     ctx->tp = ctx->p;  /* must also keep the previous dimension of V */
    304:   } else {
    305:     if (lower) {
    306:       /* move value of diagonal element of arrow (alpha) */
    307:       PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    308:       T[n] = T[m];
    309:       PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    310:       /* copy last column of U so that it updates the next initial vector of U1 */
    311:       PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
    312:       for (i=0;i<=m;i++) U[i+n*ld] = U[i+m*ld];
    313:       PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
    314:     }
    315:     ds->k   = (ds->extrarow)? n: 0;
    316:     ds->t   = ds->n;   /* truncated length equal to previous dimension */
    317:     ctx->tm = ctx->m;  /* must also keep the previous dimension of X */
    318:     ctx->tp = ctx->p;  /* must also keep the previous dimension of V */
    319:     ds->n   = lower? n+1: n;
    320:     ctx->m  = n;
    321:     ctx->p  = n;
    322:   }
    323:   PetscFunctionReturn(PETSC_SUCCESS);
    324: }

    326: static PetscErrorCode DSSwitchFormat_GSVD(DS ds)
    327: {
    328:   DS_GSVD        *ctx = (DS_GSVD*)ds->data;
    329:   PetscReal      *T,*D;
    330:   PetscScalar    *A,*B;
    331:   PetscInt       i,n=ds->n,k=ds->k,ld=ds->ld,m=ctx->m;

    333:   PetscFunctionBegin;
    334:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    335:   /* switch from compact (arrow) to dense storage */
    336:   /* bidiagonal associated to B is stored in D and T+2*ld */
    337:   PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_A],&A));
    338:   PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_B],&B));
    339:   PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    340:   PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
    341:   PetscCall(PetscArrayzero(A,ld*ld));
    342:   PetscCall(PetscArrayzero(B,ld*ld));
    343:   for (i=0;i<k;i++) {
    344:     A[i+i*ld] = T[i];
    345:     A[i+k*ld] = T[i+ld];
    346:     B[i+i*ld] = D[i];
    347:     B[i+k*ld] = T[i+2*ld];
    348:   }
    349:   /* B is upper bidiagonal */
    350:   B[k+k*ld] = D[k];
    351:   for (i=k+1;i<m;i++) {
    352:     B[i+i*ld]   = D[i];
    353:     B[i-1+i*ld] = T[i-1+2*ld];
    354:   }
    355:   /* A can be upper (square) or lower bidiagonal */
    356:   for (i=k;i<m;i++) A[i+i*ld] = T[i];
    357:   if (n>m) for (i=k;i<m;i++) A[i+1+i*ld] = T[i+ld];
    358:   else for (i=k+1;i<m;i++) A[i-1+i*ld] = T[i-1+ld];
    359:   PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_A],&A));
    360:   PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_B],&B));
    361:   PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    362:   PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
    363:   PetscFunctionReturn(PETSC_SUCCESS);
    364: }

    366: /*
    367:   Compact format is used when [A;B] has orthonormal columns.
    368:   In this case R=I and the GSVD of (A,B) is the CS decomposition
    369: */
    370: static PetscErrorCode DSSolve_GSVD(DS ds,PetscScalar *wr,PetscScalar *wi)
    371: {
    372:   DS_GSVD        *ctx = (DS_GSVD*)ds->data;
    373:   PetscInt       i,j;
    374:   PetscBLASInt   n1,m1,info,lc = 0,n = 0,m = 0,p = 0,p1,l,k,q,ld,off,lwork,r;
    375:   PetscScalar    *A,*B,*X,*U,*V,sone=1.0,smone=-1.0;
    376:   PetscReal      *alpha,*beta,*T,*D;
    377: #if !defined(SLEPC_MISSING_LAPACK_GGSVD3)
    378:   PetscScalar    a,dummy;
    379:   PetscReal      rdummy;
    380:   PetscBLASInt   idummy;
    381: #endif

    383:   PetscFunctionBegin;
    384:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    385:   PetscCall(PetscBLASIntCast(ds->n,&m));
    386:   PetscCall(PetscBLASIntCast(ctx->m,&n));
    387:   PetscCall(PetscBLASIntCast(ctx->p,&p));
    388:   PetscCall(PetscBLASIntCast(ds->l,&lc));
    389:   PetscCheck(ds->compact || lc==0,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"DSGSVD with non-compact format does not support locking");
    390:   /* In compact storage B is always nxn and A can be either nxn or (n+1)xn */
    391:   PetscCheck(!ds->compact || (p==n && (m==p || m==p+1)),PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Dimensions not supported in compact format");
    392:   PetscCall(PetscBLASIntCast(ds->ld,&ld));
    393:   n1 = n-lc;     /* n1 = size of leading block, excl. locked + size of trailing block */
    394:   m1 = m-lc;
    395:   p1 = p-lc;
    396:   off = lc+lc*ld;
    397:   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
    398:   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_B],&B));
    399:   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_X],&X));
    400:   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
    401:   PetscCall(MatDenseGetArray(ds->omat[DS_MAT_V],&V));
    402:   PetscCall(PetscArrayzero(X,ld*ld));
    403:   for (i=0;i<lc;i++) X[i+i*ld] = 1.0;
    404:   PetscCall(PetscArrayzero(U,ld*ld));
    405:   for (i=0;i<lc;i++) U[i+i*ld] = 1.0;
    406:   PetscCall(PetscArrayzero(V,ld*ld));
    407:   for (i=0;i<lc;i++) V[i+i*ld] = 1.0;
    408:   if (ds->compact) PetscCall(DSSwitchFormat_GSVD(ds));

    410: #if !defined(SLEPC_MISSING_LAPACK_GGSVD3)
    411:   /* workspace query and memory allocation */
    412:   lwork = -1;
    413: #if !defined (PETSC_USE_COMPLEX)
    414:   PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,&dummy,&ld,&dummy,&ld,&rdummy,&rdummy,&dummy,&ld,&dummy,&ld,&dummy,&ld,&a,&lwork,&idummy,&info));
    415:   PetscCall(PetscBLASIntCast((PetscInt)a,&lwork));
    416: #else
    417:   PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,&dummy,&ld,&dummy,&ld,&rdummy,&rdummy,&dummy,&ld,&dummy,&ld,&dummy,&ld,&a,&lwork,&rdummy,&idummy,&info));
    418:   PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(a),&lwork));
    419: #endif

    421: #if !defined (PETSC_USE_COMPLEX)
    422:   PetscCall(DSAllocateWork_Private(ds,lwork,2*ds->ld,ds->ld));
    423:   alpha = ds->rwork;
    424:   beta  = ds->rwork+ds->ld;
    425:   PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,&lwork,ds->iwork,&info));
    426: #else
    427:   PetscCall(DSAllocateWork_Private(ds,lwork,4*ds->ld,ds->ld));
    428:   alpha = ds->rwork+2*ds->ld;
    429:   beta  = ds->rwork+3*ds->ld;
    430:   PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,&lwork,ds->rwork,ds->iwork,&info));
    431: #endif
    432:   SlepcCheckLapackInfo("ggsvd3",info);

    434: #else  /* defined(SLEPC_MISSING_LAPACK_GGSVD3) */

    436:   lwork = PetscMax(PetscMax(3*n,m),p)+n;
    437: #if !defined (PETSC_USE_COMPLEX)
    438:   PetscCall(DSAllocateWork_Private(ds,lwork,2*ds->ld,ds->ld));
    439:   alpha = ds->rwork;
    440:   beta  = ds->rwork+ds->ld;
    441:   PetscCallBLAS("LAPACKggsvd",LAPACKggsvd_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,ds->iwork,&info));
    442: #else
    443:   PetscCall(DSAllocateWork_Private(ds,lwork,4*ds->ld,ds->ld));
    444:   alpha = ds->rwork+2*ds->ld;
    445:   beta  = ds->rwork+3*ds->ld;
    446:   PetscCallBLAS("LAPACKggsvd",LAPACKggsvd_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,ds->rwork,ds->iwork,&info));
    447: #endif
    448:   SlepcCheckLapackInfo("ggsvd",info);

    450: #endif

    452:   PetscCheck(k+l>=n1,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"The rank deficient case not supported yet");
    453:   if (ds->compact) {
    454:     PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    455:     PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
    456:     /* R is the identity matrix (except the sign) */
    457:     for (i=lc;i<n;i++) {
    458:       if (PetscRealPart(A[i+i*ld])<0.0) { /* scale column i */
    459:         for (j=lc;j<n;j++) X[j+i*ld] = -X[j+i*ld];
    460:       }
    461:     }
    462:     PetscCall(PetscArrayzero(T+ld,m-1));
    463:     PetscCall(PetscArrayzero(T+2*ld,n-1));
    464:     for (i=lc;i<n;i++) {
    465:       T[i] = alpha[i-lc];
    466:       D[i] = beta[i-lc];
    467:       if (D[i]==0.0) wr[i] = PETSC_INFINITY;
    468:       else wr[i] = T[i]/D[i];
    469:     }
    470:     ds->t = n;
    471:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
    472:     PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    473:   } else {
    474:     /* X = X*inv(R) */
    475:     q = PetscMin(m,n);
    476:     PetscCallBLAS("BLAStrsm",BLAStrsm_("R","U","N","N",&n,&q,&sone,A,&ld,X,&ld));
    477:     if (m<n) {
    478:       r = n-m;
    479:       PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&r,&m,&sone,X,&ld,A,&ld,&smone,X+m*ld,&ld));
    480:       PetscCallBLAS("BLAStrsm",BLAStrsm_("R","U","N","N",&n,&r,&sone,B+m*ld,&ld,X+m*ld,&ld));
    481:     }
    482:     if (k>0) {
    483:       for (i=k;i<PetscMin(m,k+l);i++) {
    484:         PetscCall(PetscArraycpy(X+(i-k)*ld,X+i*ld,ld));
    485:         PetscCall(PetscArraycpy(U+(i-k)*ld,U+i*ld,ld));
    486:       }
    487:     }
    488:     /* singular values */
    489:     PetscCall(PetscArrayzero(A,ld*ld));
    490:     PetscCall(PetscArrayzero(B,ld*ld));
    491:     for (j=k;j<PetscMin(m,k+l);j++) {
    492:       A[(j-k)*(1+ld)] = alpha[j];
    493:       B[(j-k)*(1+ld)] = beta[j];
    494:       wr[j-k] = alpha[j]/beta[j];
    495:     }
    496:     ds->t = PetscMin(m,k+l)-k; /* set number of computed values */
    497:   }
    498:   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
    499:   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_B],&B));
    500:   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_X],&X));
    501:   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
    502:   PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_V],&V));
    503:   PetscFunctionReturn(PETSC_SUCCESS);
    504: }

    506: static PetscErrorCode DSCond_GSVD(DS ds,PetscReal *cond)
    507: {
    508:   DS_GSVD           *ctx = (DS_GSVD*)ds->data;
    509:   PetscBLASInt      lwork,lrwork=0,info,m,n,p,ld;
    510:   PetscScalar       *A,*work;
    511:   const PetscScalar *M;
    512:   PetscReal         *sigma,conda,condb;
    513: #if defined(PETSC_USE_COMPLEX)
    514:   PetscReal         *rwork;
    515: #endif

    517:   PetscFunctionBegin;
    518:   PetscCall(PetscBLASIntCast(ds->n,&m));
    519:   PetscCall(PetscBLASIntCast(ctx->m,&n));
    520:   PetscCall(PetscBLASIntCast(ctx->p,&p));
    521:   PetscCall(PetscBLASIntCast(ds->ld,&ld));
    522:   lwork = 5*n;
    523: #if defined(PETSC_USE_COMPLEX)
    524:   lrwork = 5*n;
    525: #endif
    526:   PetscCall(DSAllocateWork_Private(ds,ld*n+lwork,n+lrwork,0));
    527:   A     = ds->work;
    528:   work  = ds->work+ld*n;
    529:   sigma = ds->rwork;
    530: #if defined(PETSC_USE_COMPLEX)
    531:   rwork = ds->rwork+n;
    532: #endif
    533:   if (ds->compact) PetscCall(DSSwitchFormat_GSVD(ds));

    535:   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_A],&M));
    536:   PetscCall(PetscArraycpy(A,M,ld*n));
    537:   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_A],&M));
    538: #if defined(PETSC_USE_COMPLEX)
    539:   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&m,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,rwork,&info));
    540: #else
    541:   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&m,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,&info));
    542: #endif
    543:   SlepcCheckLapackInfo("gesvd",info);
    544:   conda = sigma[0]/sigma[PetscMin(m,n)-1];

    546:   PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_B],&M));
    547:   PetscCall(PetscArraycpy(A,M,ld*n));
    548:   PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_B],&M));
    549: #if defined(PETSC_USE_COMPLEX)
    550:   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&p,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,rwork,&info));
    551: #else
    552:   PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&p,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,&info));
    553: #endif
    554:   SlepcCheckLapackInfo("gesvd",info);
    555:   condb = sigma[0]/sigma[PetscMin(p,n)-1];

    557:   *cond = PetscMax(conda,condb);
    558:   PetscFunctionReturn(PETSC_SUCCESS);
    559: }

    561: #if !defined(PETSC_HAVE_MPIUNI)
    562: static PetscErrorCode DSSynchronize_GSVD(DS ds,PetscScalar eigr[],PetscScalar eigi[])
    563: {
    564:   DS_GSVD        *ctx = (DS_GSVD*)ds->data;
    565:   PetscInt       ld=ds->ld,l=ds->l,k=0,kr=0;
    566:   PetscMPIInt    m,rank,off=0,size,n,ldn,ld3;
    567:   PetscScalar    *A,*U,*V,*X;
    568:   PetscReal      *T;

    570:   PetscFunctionBegin;
    571:   PetscCall(PetscMPIIntCast(ctx->m,&m));
    572:   if (ds->compact) kr = 3*ld;
    573:   else k = 2*(m-l)*ld;
    574:   if (ds->state>DS_STATE_RAW) k += 3*(m-l)*ld;
    575:   if (eigr) k += m-l;
    576:   PetscCall(DSAllocateWork_Private(ds,k+kr,0,0));
    577:   PetscCall(PetscMPIIntCast(k*sizeof(PetscScalar)+kr*sizeof(PetscReal),&size));
    578:   PetscCall(PetscMPIIntCast(m-l,&n));
    579:   PetscCall(PetscMPIIntCast(ld*(m-l),&ldn));
    580:   PetscCall(PetscMPIIntCast(3*ld,&ld3));
    581:   if (ds->compact) PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
    582:   else PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
    583:   if (ds->state>DS_STATE_RAW) {
    584:     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
    585:     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_V],&V));
    586:     PetscCall(MatDenseGetArray(ds->omat[DS_MAT_X],&X));
    587:   }
    588:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ds),&rank));
    589:   if (!rank) {
    590:     if (ds->compact) PetscCallMPI(MPI_Pack(T,ld3,MPIU_REAL,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    591:     else PetscCallMPI(MPI_Pack(A+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    592:     if (ds->state>DS_STATE_RAW) {
    593:       PetscCallMPI(MPI_Pack(U+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    594:       PetscCallMPI(MPI_Pack(V+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    595:       PetscCallMPI(MPI_Pack(X+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    596:     }
    597:     if (eigr) PetscCallMPI(MPI_Pack(eigr+l,n,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
    598:   }
    599:   PetscCallMPI(MPI_Bcast(ds->work,size,MPI_BYTE,0,PetscObjectComm((PetscObject)ds)));
    600:   if (rank) {
    601:     if (ds->compact) PetscCallMPI(MPI_Unpack(ds->work,size,&off,T,ld3,MPIU_REAL,PetscObjectComm((PetscObject)ds)));
    602:     else PetscCallMPI(MPI_Unpack(ds->work,size,&off,A+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
    603:     if (ds->state>DS_STATE_RAW) {
    604:       PetscCallMPI(MPI_Unpack(ds->work,size,&off,U+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
    605:       PetscCallMPI(MPI_Unpack(ds->work,size,&off,V+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
    606:       PetscCallMPI(MPI_Unpack(ds->work,size,&off,X+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
    607:     }
    608:     if (eigr) PetscCallMPI(MPI_Unpack(ds->work,size,&off,eigr+l,n,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
    609:   }
    610:   if (ds->compact) PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
    611:   else PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
    612:   if (ds->state>DS_STATE_RAW) {
    613:     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
    614:     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_V],&V));
    615:     PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_X],&X));
    616:   }
    617:   PetscFunctionReturn(PETSC_SUCCESS);
    618: }
    619: #endif

    621: static PetscErrorCode DSMatGetSize_GSVD(DS ds,DSMatType t,PetscInt *rows,PetscInt *cols)
    622: {
    623:   DS_GSVD *ctx = (DS_GSVD*)ds->data;

    625:   PetscFunctionBegin;
    626:   PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
    627:   switch (t) {
    628:     case DS_MAT_A:
    629:       *rows = ds->n;
    630:       *cols = ds->extrarow? ctx->m+1: ctx->m;
    631:       break;
    632:     case DS_MAT_B:
    633:       *rows = ctx->p;
    634:       *cols = ds->extrarow? ctx->m+1: ctx->m;
    635:       break;
    636:     case DS_MAT_T:
    637:       *rows = ds->n;
    638:       *cols = PetscDefined(USE_COMPLEX)? 2: 3;
    639:       break;
    640:     case DS_MAT_D:
    641:       *rows = ctx->p;
    642:       *cols = 1;
    643:       break;
    644:     case DS_MAT_U:
    645:       *rows = ds->state==DS_STATE_TRUNCATED? ds->t: ds->n;
    646:       *cols = ds->n;
    647:       break;
    648:     case DS_MAT_V:
    649:       *rows = ds->state==DS_STATE_TRUNCATED? ctx->tp: ctx->p;
    650:       *cols = ctx->p;
    651:       break;
    652:     case DS_MAT_X:
    653:       *rows = ds->state==DS_STATE_TRUNCATED? ctx->tm: ctx->m;
    654:       *cols = ctx->m;
    655:       break;
    656:     default:
    657:       SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid t parameter");
    658:   }
    659:   PetscFunctionReturn(PETSC_SUCCESS);
    660: }

    662: static PetscErrorCode DSGSVDSetDimensions_GSVD(DS ds,PetscInt m,PetscInt p)
    663: {
    664:   DS_GSVD *ctx = (DS_GSVD*)ds->data;

    666:   PetscFunctionBegin;
    667:   DSCheckAlloc(ds,1);
    668:   if (m == PETSC_DETERMINE) {
    669:     ctx->m = ds->ld;
    670:   } else if (m != PETSC_CURRENT) {
    671:     PetscCheck(m>0 && m<=ds->ld,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of m. Must be between 1 and ld");
    672:     ctx->m = m;
    673:   }
    674:   if (p == PETSC_DETERMINE) {
    675:     ctx->p = ds->n;
    676:   } else if (p != PETSC_CURRENT) {
    677:     PetscCheck(p>0 && p<=ds->ld,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of p. Must be between 1 and ld");
    678:     ctx->p = p;
    679:   }
    680:   PetscFunctionReturn(PETSC_SUCCESS);
    681: }

    683: /*@
    684:    DSGSVDSetDimensions - Sets the number of columns and rows for a DSGSVD.

    686:    Logically Collective

    688:    Input Parameters:
    689: +  ds - the direct solver context
    690: .  m  - the number of columns
    691: -  p  - the number of rows for the second matrix (B)

    693:    Notes:
    694:    This call is complementary to DSSetDimensions(), to provide two dimensions
    695:    that are specific to this DS type. The number of rows for the first matrix (A)
    696:    is set by DSSetDimensions().

    698:    Use PETSC_CURRENT to leave any of the values unchanged. Use PETSC_DETERMINE
    699:    to set m to the leading dimension and p to the number of columns of B.

    701:    Level: intermediate

    703: .seealso: DSGSVDGetDimensions(), DSSetDimensions()
    704: @*/
    705: PetscErrorCode DSGSVDSetDimensions(DS ds,PetscInt m,PetscInt p)
    706: {
    707:   PetscFunctionBegin;
    711:   PetscTryMethod(ds,"DSGSVDSetDimensions_C",(DS,PetscInt,PetscInt),(ds,m,p));
    712:   PetscFunctionReturn(PETSC_SUCCESS);
    713: }

    715: static PetscErrorCode DSGSVDGetDimensions_GSVD(DS ds,PetscInt *m,PetscInt *p)
    716: {
    717:   DS_GSVD *ctx = (DS_GSVD*)ds->data;

    719:   PetscFunctionBegin;
    720:   if (m) *m = ctx->m;
    721:   if (p) *p = ctx->p;
    722:   PetscFunctionReturn(PETSC_SUCCESS);
    723: }

    725: /*@
    726:    DSGSVDGetDimensions - Returns the number of columns and rows for a DSGSVD.

    728:    Not Collective

    730:    Input Parameter:
    731: .  ds - the direct solver context

    733:    Output Parameters:
    734: +  m - the number of columns
    735: -  p - the number of rows for the second matrix (B)

    737:    Level: intermediate

    739: .seealso: DSGSVDSetDimensions()
    740: @*/
    741: PetscErrorCode DSGSVDGetDimensions(DS ds,PetscInt *m,PetscInt *p)
    742: {
    743:   PetscFunctionBegin;
    745:   PetscUseMethod(ds,"DSGSVDGetDimensions_C",(DS,PetscInt*,PetscInt*),(ds,m,p));
    746:   PetscFunctionReturn(PETSC_SUCCESS);
    747: }

    749: static PetscErrorCode DSDestroy_GSVD(DS ds)
    750: {
    751:   PetscFunctionBegin;
    752:   PetscCall(PetscFree(ds->data));
    753:   PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDSetDimensions_C",NULL));
    754:   PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDGetDimensions_C",NULL));
    755:   PetscFunctionReturn(PETSC_SUCCESS);
    756: }

    758: /*MC
    759:    DSGSVD - Dense Generalized Singular Value Decomposition.

    761:    Level: beginner

    763:    Notes:
    764:    The problem is expressed as A*X = U*C, B*X = V*S, where A and B are
    765:    matrices with the same number of columns, m, U and V are orthogonal
    766:    (unitary), and X is an mxm invertible matrix. The DS object does not
    767:    expose matrices C and S, instead the singular values sigma, which are
    768:    the ratios c_i/s_i, are returned in the arguments of DSSolve().
    769:    Note that the number of columns of the returned X, U, V may be smaller
    770:    in the case that some c_i or s_i are zero.

    772:    The number of rows of A (and U) is the value n passed with DSSetDimensions().
    773:    The number of columns m and the number of rows of B (and V) must be
    774:    set via DSGSVDSetDimensions().

    776:    Internally, LAPACK's representation is used, U'*A*Q = C*[0 R], V'*B*Q = S*[0 R],
    777:    where X = Q*inv(R) is computed at the end of DSSolve().

    779:    If the compact storage format is selected, then a simplified problem is
    780:    solved, where A and B are bidiagonal (possibly with an arrow), and [A;B]
    781:    is assumed to have orthonormal columns. We consider two cases: (1) A and B
    782:    are square mxm upper bidiagonal, and (2) A is lower bidiagonal with m+1
    783:    rows and B is square upper bidiagonal. In these cases, R=I so it
    784:    corresponds to the CS decomposition. The first matrix is stored in two
    785:    diagonals of DS_MAT_T, while the second matrix is stored in DS_MAT_D
    786:    and the remaining diagonal of DS_MAT_T.

    788:    Allowed arguments of DSVectors() are DS_MAT_U, DS_MAT_V and DS_MAT_X.

    790:    Used DS matrices:
    791: +  DS_MAT_A - first problem matrix
    792: .  DS_MAT_B - second problem matrix
    793: .  DS_MAT_T - first upper bidiagonal matrix (if compact storage is selected)
    794: .  DS_MAT_D - second upper bidiagonal matrix (if compact storage is selected)
    795: .  DS_MAT_U - (upper) left generalized singular vectors
    796: .  DS_MAT_V - (lower) left generalized singular vectors
    797: -  DS_MAT_X - right generalized singular vectors

    799:    Implemented methods:
    800: .  0 - Lapack (_ggsvd3 if available, or _ggsvd)

    802: .seealso: DSCreate(), DSSetType(), DSType, DSGSVDSetDimensions()
    803: M*/
    804: SLEPC_EXTERN PetscErrorCode DSCreate_GSVD(DS ds)
    805: {
    806:   DS_GSVD        *ctx;

    808:   PetscFunctionBegin;
    809:   PetscCall(PetscNew(&ctx));
    810:   ds->data = (void*)ctx;

    812:   ds->ops->allocate      = DSAllocate_GSVD;
    813:   ds->ops->view          = DSView_GSVD;
    814:   ds->ops->vectors       = DSVectors_GSVD;
    815:   ds->ops->sort          = DSSort_GSVD;
    816:   ds->ops->solve[0]      = DSSolve_GSVD;
    817: #if !defined(PETSC_HAVE_MPIUNI)
    818:   ds->ops->synchronize   = DSSynchronize_GSVD;
    819: #endif
    820:   ds->ops->truncate      = DSTruncate_GSVD;
    821:   ds->ops->update        = DSUpdateExtraRow_GSVD;
    822:   ds->ops->cond          = DSCond_GSVD;
    823:   ds->ops->matgetsize    = DSMatGetSize_GSVD;
    824:   ds->ops->destroy       = DSDestroy_GSVD;
    825:   PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDSetDimensions_C",DSGSVDSetDimensions_GSVD));
    826:   PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDGetDimensions_C",DSGSVDGetDimensions_GSVD));
    827:   PetscFunctionReturn(PETSC_SUCCESS);
    828: }