Actual source code: svdview.c

      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: /*
     11:    The SVD routines related to various viewers
     12: */

     14: #include <slepc/private/svdimpl.h>
     15: #include <petscdraw.h>

     17: /*@
     18:    SVDView - Prints the `SVD` data structure.

     20:    Collective

     22:    Input Parameters:
     23: +  svd - the singular value solver context
     24: -  viewer - optional visualization context

     26:    Options Database Key:
     27: .  -svd_view - calls `SVDView()` at end of `SVDSolve()`

     29:    Notes:
     30:    The available visualization contexts include
     31: +     `PETSC_VIEWER_STDOUT_SELF` - standard output (default)
     32: -     `PETSC_VIEWER_STDOUT_WORLD` - synchronized standard output where only the
     33:          first process opens the file; all other processes send their data to the
     34:          first one to print

     36:    The user can open an alternative visualization context with `PetscViewerASCIIOpen()`
     37:    to output to a specified file.

     39:    Level: beginner

     41: .seealso: [](ch:svd), `SVDCreate()`, `SVDViewFromOptions()`, `EPSView()`
     42: @*/
     43: PetscErrorCode SVDView(SVD svd,PetscViewer viewer)
     44: {
     45:   const char     *type=NULL;
     46:   PetscBool      isascii,isshell,isexternal;

     48:   PetscFunctionBegin;
     50:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)svd),&viewer));
     52:   PetscCheckSameComm(svd,1,viewer,2);

     54:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
     55:   if (isascii) {
     56:     PetscCall(PetscObjectPrintClassNamePrefixType((PetscObject)svd,viewer));
     57:     PetscCall(PetscViewerASCIIPushTab(viewer));
     58:     PetscTryTypeMethod(svd,view,viewer);
     59:     PetscCall(PetscViewerASCIIPopTab(viewer));
     60:     if (svd->problem_type) {
     61:       switch (svd->problem_type) {
     62:         case SVD_STANDARD:    type = "(standard) singular value problem"; break;
     63:         case SVD_GENERALIZED: type = "generalized singular value problem"; break;
     64:         case SVD_HYPERBOLIC:  type = "hyperbolic singular value problem"; break;
     65:       }
     66:     } else type = "not yet set";
     67:     PetscCall(PetscViewerASCIIPrintf(viewer,"  problem type: %s\n",type));
     68:     PetscCall(PetscViewerASCIIPrintf(viewer,"  transpose mode: %s\n",svd->impltrans?"implicit":"explicit"));
     69:     if (svd->which == SVD_LARGEST) PetscCall(PetscViewerASCIIPrintf(viewer,"  selected portion of the spectrum: largest\n"));
     70:     else PetscCall(PetscViewerASCIIPrintf(viewer,"  selected portion of the spectrum: smallest\n"));
     71:     if (svd->stop==SVD_STOP_THRESHOLD) PetscCall(PetscViewerASCIIPrintf(viewer,"  computing singular values %s the threshold: %g%s\n",svd->which==SVD_LARGEST?"above":"below",(double)svd->thres,svd->threlative?" (relative)":""));
     72:     if (svd->nsv) PetscCall(PetscViewerASCIIPrintf(viewer,"  number of singular values (nsv): %" PetscInt_FMT "\n",svd->nsv));
     73:     PetscCall(PetscViewerASCIIPrintf(viewer,"  number of column vectors (ncv): %" PetscInt_FMT "\n",svd->ncv));
     74:     PetscCall(PetscViewerASCIIPrintf(viewer,"  maximum dimension of projected problem (mpd): %" PetscInt_FMT "\n",svd->mpd));
     75:     PetscCall(PetscViewerASCIIPrintf(viewer,"  maximum number of iterations: %" PetscInt_FMT "\n",svd->max_it));
     76:     PetscCall(PetscViewerASCIIPrintf(viewer,"  tolerance: %g\n",(double)svd->tol));
     77:     PetscCall(PetscViewerASCIIPrintf(viewer,"  convergence test: "));
     78:     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
     79:     switch (svd->conv) {
     80:     case SVD_CONV_ABS:
     81:       PetscCall(PetscViewerASCIIPrintf(viewer,"absolute\n"));break;
     82:     case SVD_CONV_REL:
     83:       PetscCall(PetscViewerASCIIPrintf(viewer,"relative to the singular value\n"));break;
     84:     case SVD_CONV_NORM:
     85:       PetscCall(PetscViewerASCIIPrintf(viewer,"relative to the matrix norms\n"));
     86:       PetscCall(PetscViewerASCIIPrintf(viewer,"  computed matrix norms: norm(A)=%g",(double)svd->nrma));
     87:       if (svd->isgeneralized) PetscCall(PetscViewerASCIIPrintf(viewer,", norm(B)=%g",(double)svd->nrmb));
     88:       PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
     89:       break;
     90:     case SVD_CONV_MAXIT:
     91:       PetscCall(PetscViewerASCIIPrintf(viewer,"maximum number of iterations\n"));break;
     92:     case SVD_CONV_USER:
     93:       PetscCall(PetscViewerASCIIPrintf(viewer,"user-defined\n"));break;
     94:     }
     95:     PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
     96:     if (svd->nini) PetscCall(PetscViewerASCIIPrintf(viewer,"  dimension of user-provided initial space: %" PetscInt_FMT "\n",PetscAbs(svd->nini)));
     97:     if (svd->ninil) PetscCall(PetscViewerASCIIPrintf(viewer,"  dimension of user-provided initial left space: %" PetscInt_FMT "\n",PetscAbs(svd->ninil)));
     98:   } else PetscTryTypeMethod(svd,view,viewer);
     99:   PetscCall(PetscObjectTypeCompareAny((PetscObject)svd,&isshell,SVDCROSS,SVDCYCLIC,""));
    100:   PetscCall(PetscObjectTypeCompareAny((PetscObject)svd,&isexternal,SVDSCALAPACK,SVDKSVD,SVDELEMENTAL,SVDPRIMME,""));
    101:   if (!isshell && !isexternal) {
    102:     PetscCall(PetscViewerPushFormat(viewer,PETSC_VIEWER_ASCII_INFO));
    103:     if (!svd->V) PetscCall(SVDGetBV(svd,&svd->V,NULL));
    104:     PetscCall(BVView(svd->V,viewer));
    105:     if (!svd->ds) PetscCall(SVDGetDS(svd,&svd->ds));
    106:     PetscCall(DSView(svd->ds,viewer));
    107:     PetscCall(PetscViewerPopFormat(viewer));
    108:   }
    109:   PetscFunctionReturn(PETSC_SUCCESS);
    110: }

    112: /*@
    113:    SVDViewFromOptions - View (print) an `SVD` object based on values in the options database.

    115:    Collective

    117:    Input Parameters:
    118: +  svd  - the singular value solver context
    119: .  obj  - optional object that provides the options prefix used to query the options database
    120: -  name - command line option

    122:    Level: intermediate

    124: .seealso: [](ch:svd), `SVDView()`, `SVDCreate()`, `PetscObjectViewFromOptions()`
    125: @*/
    126: PetscErrorCode SVDViewFromOptions(SVD svd,PetscObject obj,const char name[])
    127: {
    128:   PetscFunctionBegin;
    130:   PetscCall(PetscObjectViewFromOptions((PetscObject)svd,obj,name));
    131:   PetscFunctionReturn(PETSC_SUCCESS);
    132: }

    134: /*@
    135:    SVDConvergedReasonView - Displays the reason an `SVD` solve converged or diverged.

    137:    Collective

    139:    Input Parameters:
    140: +  svd - the singular value solver context
    141: -  viewer - the viewer to display the reason

    143:    Options Database Key:
    144: .  -svd_converged_reason - print reason for convergence/divergence, and number of iterations

    146:    Notes:
    147:    Use `SVDConvergedReasonViewFromOptions()` to display the reason based on values
    148:    in the options database.

    150:    To change the format of the output call `PetscViewerPushFormat()` before this
    151:    call. Use `PETSC_VIEWER_DEFAULT` for the default, or `PETSC_VIEWER_FAILED` to only
    152:    display a reason if it fails. The latter can be set in the command line with
    153:    `-svd_converged_reason ::failed`.

    155:    Level: intermediate

    157: .seealso: [](ch:svd), `SVDSetTolerances()`, `SVDGetIterationNumber()`, `SVDConvergedReasonViewFromOptions()`
    158: @*/
    159: PetscErrorCode SVDConvergedReasonView(SVD svd,PetscViewer viewer)
    160: {
    161:   PetscBool         isAscii;
    162:   PetscViewerFormat format;

    164:   PetscFunctionBegin;
    165:   if (!viewer) viewer = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)svd));
    166:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isAscii));
    167:   if (isAscii) {
    168:     PetscCall(PetscViewerGetFormat(viewer,&format));
    169:     PetscCall(PetscViewerASCIIAddTab(viewer,((PetscObject)svd)->tablevel));
    170:     if (svd->reason > 0 && format != PETSC_VIEWER_FAILED) PetscCall(PetscViewerASCIIPrintf(viewer,"%s SVD solve converged (%" PetscInt_FMT " singular triplet%s) due to %s; iterations %" PetscInt_FMT "\n",((PetscObject)svd)->prefix?((PetscObject)svd)->prefix:"",svd->nconv,(svd->nconv>1)?"s":"",SVDConvergedReasons[svd->reason],svd->its));
    171:     else if (svd->reason <= 0) PetscCall(PetscViewerASCIIPrintf(viewer,"%s SVD solve did not converge due to %s; iterations %" PetscInt_FMT "\n",((PetscObject)svd)->prefix?((PetscObject)svd)->prefix:"",SVDConvergedReasons[svd->reason],svd->its));
    172:     PetscCall(PetscViewerASCIISubtractTab(viewer,((PetscObject)svd)->tablevel));
    173:   }
    174:   PetscFunctionReturn(PETSC_SUCCESS);
    175: }

    177: /*@
    178:    SVDConvergedReasonViewFromOptions - Processes command line options to determine if/how
    179:    the `SVD` converged reason is to be viewed.

    181:    Collective

    183:    Input Parameter:
    184: .  svd - the singular value solver context

    186:    Level: intermediate

    188: .seealso: [](ch:svd), `SVDConvergedReasonView()`
    189: @*/
    190: PetscErrorCode SVDConvergedReasonViewFromOptions(SVD svd)
    191: {
    192:   PetscViewer       viewer;
    193:   PetscBool         flg;
    194:   static PetscBool  incall = PETSC_FALSE;
    195:   PetscViewerFormat format;

    197:   PetscFunctionBegin;
    198:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
    199:   incall = PETSC_TRUE;
    200:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_converged_reason",&viewer,&format,&flg));
    201:   if (flg) {
    202:     PetscCall(PetscViewerPushFormat(viewer,format));
    203:     PetscCall(SVDConvergedReasonView(svd,viewer));
    204:     PetscCall(PetscViewerPopFormat(viewer));
    205:     PetscCall(PetscViewerDestroy(&viewer));
    206:   }
    207:   incall = PETSC_FALSE;
    208:   PetscFunctionReturn(PETSC_SUCCESS);
    209: }

    211: static PetscErrorCode SVDErrorView_ASCII(SVD svd,SVDErrorType etype,PetscViewer viewer)
    212: {
    213:   PetscReal      error,sigma;
    214:   PetscInt       i,j,numsv;
    215:   PetscBool      requestednsv=PETSC_TRUE; /* user has specified nsv */
    216:   const char     *svstring = svd->isgeneralized?"generalized singular values":"singular values";

    218:   PetscFunctionBegin;
    219:   if (svd->stop==SVD_STOP_THRESHOLD && svd->nsv==0) requestednsv = PETSC_FALSE;
    220:   numsv = requestednsv? svd->nsv: svd->nconv;
    221:   if (requestednsv && svd->nconv<numsv) {
    222:     PetscCall(PetscViewerASCIIPrintf(viewer," Problem: less than %" PetscInt_FMT " %s converged\n\n",numsv,svstring));
    223:     PetscFunctionReturn(PETSC_SUCCESS);
    224:   }
    225:   if (!requestednsv && !numsv) {
    226:     PetscCall(PetscViewerASCIIPrintf(viewer," No %s have been found\n\n",svstring));
    227:     PetscFunctionReturn(PETSC_SUCCESS);
    228:   }
    229:   for (i=0;i<numsv;i++) {
    230:     PetscCall(SVDComputeError(svd,i,etype,&error));
    231:     if (error>=5.0*svd->tol) {
    232:       PetscCall(PetscViewerASCIIPrintf(viewer," Problem: some of the first %" PetscInt_FMT " relative errors are higher than the tolerance\n\n",numsv));
    233:       PetscFunctionReturn(PETSC_SUCCESS);
    234:     }
    235:   }
    236:   if (!requestednsv) PetscCall(PetscViewerASCIIPrintf(viewer," Found %" PetscInt_FMT " %s, all of them computed up to the required tolerance:",numsv,svstring));
    237:   else PetscCall(PetscViewerASCIIPrintf(viewer," All requested %s computed up to the required tolerance:",svstring));
    238:   for (i=0;i<=(numsv-1)/8;i++) {
    239:     PetscCall(PetscViewerASCIIPrintf(viewer,"\n     "));
    240:     for (j=0;j<PetscMin(8,numsv-8*i);j++) {
    241:       PetscCall(SVDGetSingularTriplet(svd,8*i+j,&sigma,NULL,NULL));
    242:       PetscCall(PetscViewerASCIIPrintf(viewer,"%.5f",(double)sigma));
    243:       if (8*i+j+1<numsv) PetscCall(PetscViewerASCIIPrintf(viewer,", "));
    244:     }
    245:   }
    246:   PetscCall(PetscViewerASCIIPrintf(viewer,"\n\n"));
    247:   PetscFunctionReturn(PETSC_SUCCESS);
    248: }

    250: static PetscErrorCode SVDErrorView_DETAIL(SVD svd,SVDErrorType etype,PetscViewer viewer)
    251: {
    252:   PetscReal      error,sigma;
    253:   PetscInt       i;
    254:   char           ex[30],sep[]=" ---------------------- --------------------\n";

    256:   PetscFunctionBegin;
    257:   if (!svd->nconv) PetscFunctionReturn(PETSC_SUCCESS);
    258:   switch (etype) {
    259:     case SVD_ERROR_ABSOLUTE:
    260:       PetscCall(PetscSNPrintf(ex,sizeof(ex)," absolute error"));
    261:       break;
    262:     case SVD_ERROR_RELATIVE:
    263:       PetscCall(PetscSNPrintf(ex,sizeof(ex)," relative error"));
    264:       break;
    265:     case SVD_ERROR_NORM:
    266:       if (svd->isgeneralized) PetscCall(PetscSNPrintf(ex,sizeof(ex)," ||r||/||[A;B]||"));
    267:       else PetscCall(PetscSNPrintf(ex,sizeof(ex),"  ||r||/||A||"));
    268:       break;
    269:   }
    270:   PetscCall(PetscViewerASCIIPrintf(viewer,"%s          sigma           %s\n%s",sep,ex,sep));
    271:   for (i=0;i<svd->nconv;i++) {
    272:     PetscCall(SVDGetSingularTriplet(svd,i,&sigma,NULL,NULL));
    273:     PetscCall(SVDComputeError(svd,i,etype,&error));
    274:     PetscCall(PetscViewerASCIIPrintf(viewer,"       % 6f          %12g\n",(double)sigma,(double)error));
    275:   }
    276:   PetscCall(PetscViewerASCIIPrintf(viewer,"%s",sep));
    277:   PetscFunctionReturn(PETSC_SUCCESS);
    278: }

    280: static PetscErrorCode SVDErrorView_MATLAB(SVD svd,SVDErrorType etype,PetscViewer viewer)
    281: {
    282:   PetscReal      error;
    283:   PetscInt       i;
    284:   const char     *name;

    286:   PetscFunctionBegin;
    287:   PetscCall(PetscObjectGetName((PetscObject)svd,&name));
    288:   PetscCall(PetscViewerASCIIPrintf(viewer,"Error_%s = [\n",name));
    289:   for (i=0;i<svd->nconv;i++) {
    290:     PetscCall(SVDComputeError(svd,i,etype,&error));
    291:     PetscCall(PetscViewerASCIIPrintf(viewer,"%18.16e\n",(double)error));
    292:   }
    293:   PetscCall(PetscViewerASCIIPrintf(viewer,"];\n"));
    294:   PetscFunctionReturn(PETSC_SUCCESS);
    295: }

    297: /*@
    298:    SVDErrorView - Displays the errors associated with the computed solution
    299:    (as well as the singular values).

    301:    Collective

    303:    Input Parameters:
    304: +  svd    - the singular value solver context
    305: .  etype  - error type
    306: -  viewer - optional visualization context

    308:    Options Database Keys:
    309: +  -svd_error_absolute - print absolute errors of each singular triplet
    310: .  -svd_error_relative - print relative errors of each singular triplet
    311: -  -svd_error_norm     - print errors relative to the matrix norms of each singular triplet

    313:    Notes:
    314:    By default, this function checks the error of all singular triplets and prints
    315:    the singular values if all of them are below the requested tolerance.
    316:    If the viewer has format `PETSC_VIEWER_ASCII_INFO_DETAIL` then a table with
    317:    singular values and corresponding errors is printed.

    319:    All the command-line options listed above admit an optional argument
    320:    specifying the viewer type and options. For instance, use
    321:    `-svd_error_relative :myerr.m:ascii_matlab` to save the errors in a file
    322:    that can be executed in Matlab.

    324:    Level: intermediate

    326: .seealso: [](ch:svd), `SVDSolve()`, `SVDValuesView()`, `SVDVectorsView()`
    327: @*/
    328: PetscErrorCode SVDErrorView(SVD svd,SVDErrorType etype,PetscViewer viewer)
    329: {
    330:   PetscBool         isascii;
    331:   PetscViewerFormat format;

    333:   PetscFunctionBegin;
    335:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)svd),&viewer));
    337:   PetscCheckSameComm(svd,1,viewer,3);
    338:   SVDCheckSolved(svd,1);
    339:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    340:   if (!isascii) PetscFunctionReturn(PETSC_SUCCESS);

    342:   PetscCall(PetscViewerGetFormat(viewer,&format));
    343:   switch (format) {
    344:     case PETSC_VIEWER_DEFAULT:
    345:     case PETSC_VIEWER_ASCII_INFO:
    346:       PetscCall(SVDErrorView_ASCII(svd,etype,viewer));
    347:       break;
    348:     case PETSC_VIEWER_ASCII_INFO_DETAIL:
    349:       PetscCall(SVDErrorView_DETAIL(svd,etype,viewer));
    350:       break;
    351:     case PETSC_VIEWER_ASCII_MATLAB:
    352:       PetscCall(SVDErrorView_MATLAB(svd,etype,viewer));
    353:       break;
    354:     default:
    355:       PetscCall(PetscInfo(svd,"Unsupported viewer format %s\n",PetscViewerFormats[format]));
    356:   }
    357:   PetscFunctionReturn(PETSC_SUCCESS);
    358: }

    360: /*@
    361:    SVDErrorViewFromOptions - Processes command line options to determine if/how
    362:    the errors of the computed solution are to be viewed.

    364:    Collective

    366:    Input Parameter:
    367: .  svd - the singular value solver context

    369:    Level: developer

    371: .seealso: [](ch:svd), `SVDErrorView()`
    372: @*/
    373: PetscErrorCode SVDErrorViewFromOptions(SVD svd)
    374: {
    375:   PetscViewer       viewer;
    376:   PetscBool         flg;
    377:   static PetscBool  incall = PETSC_FALSE;
    378:   PetscViewerFormat format;

    380:   PetscFunctionBegin;
    381:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
    382:   incall = PETSC_TRUE;
    383:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_error_absolute",&viewer,&format,&flg));
    384:   if (flg) {
    385:     PetscCall(PetscViewerPushFormat(viewer,format));
    386:     PetscCall(SVDErrorView(svd,SVD_ERROR_ABSOLUTE,viewer));
    387:     PetscCall(PetscViewerPopFormat(viewer));
    388:     PetscCall(PetscViewerDestroy(&viewer));
    389:   }
    390:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_error_relative",&viewer,&format,&flg));
    391:   if (flg) {
    392:     PetscCall(PetscViewerPushFormat(viewer,format));
    393:     PetscCall(SVDErrorView(svd,SVD_ERROR_RELATIVE,viewer));
    394:     PetscCall(PetscViewerPopFormat(viewer));
    395:     PetscCall(PetscViewerDestroy(&viewer));
    396:   }
    397:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_error_norm",&viewer,&format,&flg));
    398:   if (flg) {
    399:     PetscCall(PetscViewerPushFormat(viewer,format));
    400:     PetscCall(SVDErrorView(svd,SVD_ERROR_NORM,viewer));
    401:     PetscCall(PetscViewerPopFormat(viewer));
    402:     PetscCall(PetscViewerDestroy(&viewer));
    403:   }
    404:   incall = PETSC_FALSE;
    405:   PetscFunctionReturn(PETSC_SUCCESS);
    406: }

    408: static PetscErrorCode SVDValuesView_DRAW(SVD svd,PetscViewer viewer)
    409: {
    410:   PetscDraw      draw;
    411:   PetscDrawSP    drawsp;
    412:   PetscReal      re,im=0.0;
    413:   PetscInt       i;

    415:   PetscFunctionBegin;
    416:   if (!svd->nconv) PetscFunctionReturn(PETSC_SUCCESS);
    417:   PetscCall(PetscViewerDrawGetDraw(viewer,0,&draw));
    418:   PetscCall(PetscDrawSetTitle(draw,"Computed singular values"));
    419:   PetscCall(PetscDrawSPCreate(draw,1,&drawsp));
    420:   for (i=0;i<svd->nconv;i++) {
    421:     re = svd->sigma[svd->perm[i]];
    422:     PetscCall(PetscDrawSPAddPoint(drawsp,&re,&im));
    423:   }
    424:   PetscCall(PetscDrawSPDraw(drawsp,PETSC_TRUE));
    425:   PetscCall(PetscDrawSPSave(drawsp));
    426:   PetscCall(PetscDrawSPDestroy(&drawsp));
    427:   PetscFunctionReturn(PETSC_SUCCESS);
    428: }

    430: static PetscErrorCode SVDValuesView_BINARY(SVD svd,PetscViewer viewer)
    431: {
    432:   PetscInt       i,k;
    433:   PetscReal      *sv;

    435:   PetscFunctionBegin;
    436:   PetscCall(PetscMalloc1(svd->nconv,&sv));
    437:   for (i=0;i<svd->nconv;i++) {
    438:     k = svd->perm[i];
    439:     sv[i] = svd->sigma[k];
    440:   }
    441:   PetscCall(PetscViewerBinaryWrite(viewer,sv,svd->nconv,PETSC_REAL));
    442:   PetscCall(PetscFree(sv));
    443:   PetscFunctionReturn(PETSC_SUCCESS);
    444: }

    446: #if defined(PETSC_HAVE_HDF5)
    447: static PetscErrorCode SVDValuesView_HDF5(SVD svd,PetscViewer viewer)
    448: {
    449:   PetscInt       i,k,n,N;
    450:   PetscMPIInt    rank;
    451:   Vec            v;
    452:   char           vname[30];
    453:   const char     *ename;

    455:   PetscFunctionBegin;
    456:   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)svd),&rank));
    457:   N = svd->nconv;
    458:   n = rank? 0: N;
    459:   /* create a vector containing the singular values */
    460:   PetscCall(VecCreateMPI(PetscObjectComm((PetscObject)svd),n,N,&v));
    461:   PetscCall(PetscObjectGetName((PetscObject)svd,&ename));
    462:   PetscCall(PetscSNPrintf(vname,sizeof(vname),"sigma_%s",ename));
    463:   PetscCall(PetscObjectSetName((PetscObject)v,vname));
    464:   if (!rank) {
    465:     for (i=0;i<svd->nconv;i++) {
    466:       k = svd->perm[i];
    467:       PetscCall(VecSetValue(v,i,svd->sigma[k],INSERT_VALUES));
    468:     }
    469:   }
    470:   PetscCall(VecAssemblyBegin(v));
    471:   PetscCall(VecAssemblyEnd(v));
    472:   PetscCall(VecView(v,viewer));
    473:   PetscCall(VecDestroy(&v));
    474:   PetscFunctionReturn(PETSC_SUCCESS);
    475: }
    476: #endif

    478: static PetscErrorCode SVDValuesView_ASCII(SVD svd,PetscViewer viewer)
    479: {
    480:   PetscInt       i;

    482:   PetscFunctionBegin;
    483:   PetscCall(PetscViewerASCIIPrintf(viewer,"Singular values = \n"));
    484:   for (i=0;i<svd->nconv;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"   %.5f\n",(double)svd->sigma[svd->perm[i]]));
    485:   PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
    486:   PetscFunctionReturn(PETSC_SUCCESS);
    487: }

    489: static PetscErrorCode SVDValuesView_MATLAB(SVD svd,PetscViewer viewer)
    490: {
    491:   PetscInt       i;
    492:   const char     *name;

    494:   PetscFunctionBegin;
    495:   PetscCall(PetscObjectGetName((PetscObject)svd,&name));
    496:   PetscCall(PetscViewerASCIIPrintf(viewer,"Sigma_%s = [\n",name));
    497:   for (i=0;i<svd->nconv;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%18.16e\n",(double)svd->sigma[svd->perm[i]]));
    498:   PetscCall(PetscViewerASCIIPrintf(viewer,"];\n"));
    499:   PetscFunctionReturn(PETSC_SUCCESS);
    500: }

    502: /*@
    503:    SVDValuesView - Displays the computed singular values in a viewer.

    505:    Collective

    507:    Input Parameters:
    508: +  svd    - the singular value solver context
    509: -  viewer - the viewer

    511:    Options Database Key:
    512: .  -svd_view_values - print computed singular values

    514:    Note:
    515:    The command-line option listed above admits an optional argument
    516:    specifying the viewer type and options. For instance, use
    517:    `-svd_view_values :evals.m:ascii_matlab` to save the values in a file
    518:    that can be executed in Matlab.
    519:    See `PetscObjectViewFromOptions()` for more details.

    521:    Level: intermediate

    523: .seealso: [](ch:svd), `SVDSolve()`, `SVDVectorsView()`, `SVDErrorView()`
    524: @*/
    525: PetscErrorCode SVDValuesView(SVD svd,PetscViewer viewer)
    526: {
    527:   PetscBool         isascii,isdraw,isbinary;
    528:   PetscViewerFormat format;
    529: #if defined(PETSC_HAVE_HDF5)
    530:   PetscBool         ishdf5;
    531: #endif

    533:   PetscFunctionBegin;
    535:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)svd),&viewer));
    537:   PetscCheckSameComm(svd,1,viewer,2);
    538:   SVDCheckSolved(svd,1);
    539:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERDRAW,&isdraw));
    540:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERBINARY,&isbinary));
    541: #if defined(PETSC_HAVE_HDF5)
    542:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERHDF5,&ishdf5));
    543: #endif
    544:   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    545:   if (isdraw) PetscCall(SVDValuesView_DRAW(svd,viewer));
    546:   else if (isbinary) PetscCall(SVDValuesView_BINARY(svd,viewer));
    547: #if defined(PETSC_HAVE_HDF5)
    548:   else if (ishdf5) PetscCall(SVDValuesView_HDF5(svd,viewer));
    549: #endif
    550:   else if (isascii) {
    551:     PetscCall(PetscViewerGetFormat(viewer,&format));
    552:     switch (format) {
    553:       case PETSC_VIEWER_DEFAULT:
    554:       case PETSC_VIEWER_ASCII_INFO:
    555:       case PETSC_VIEWER_ASCII_INFO_DETAIL:
    556:         PetscCall(SVDValuesView_ASCII(svd,viewer));
    557:         break;
    558:       case PETSC_VIEWER_ASCII_MATLAB:
    559:         PetscCall(SVDValuesView_MATLAB(svd,viewer));
    560:         break;
    561:       default:
    562:         PetscCall(PetscInfo(svd,"Unsupported viewer format %s\n",PetscViewerFormats[format]));
    563:     }
    564:   }
    565:   PetscFunctionReturn(PETSC_SUCCESS);
    566: }

    568: /*@
    569:    SVDValuesViewFromOptions - Processes command line options to determine if/how
    570:    the computed singular values are to be viewed.

    572:    Collective

    574:    Input Parameter:
    575: .  svd - the singular value solver context

    577:    Level: developer

    579: .seealso: [](ch:svd), `SVDValuesView()`
    580: @*/
    581: PetscErrorCode SVDValuesViewFromOptions(SVD svd)
    582: {
    583:   PetscViewer       viewer;
    584:   PetscBool         flg;
    585:   static PetscBool  incall = PETSC_FALSE;
    586:   PetscViewerFormat format;

    588:   PetscFunctionBegin;
    589:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
    590:   incall = PETSC_TRUE;
    591:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_view_values",&viewer,&format,&flg));
    592:   if (flg) {
    593:     PetscCall(PetscViewerPushFormat(viewer,format));
    594:     PetscCall(SVDValuesView(svd,viewer));
    595:     PetscCall(PetscViewerPopFormat(viewer));
    596:     PetscCall(PetscViewerDestroy(&viewer));
    597:   }
    598:   incall = PETSC_FALSE;
    599:   PetscFunctionReturn(PETSC_SUCCESS);
    600: }

    602: /*@
    603:    SVDVectorsView - Outputs computed singular vectors to a viewer.

    605:    Collective

    607:    Input Parameters:
    608: +  svd    - the singular value solver context
    609: -  viewer - the viewer

    611:    Options Database Key:
    612: .  -svd_view_vectors - output singular vectors

    614:    Notes:
    615:    Right and left singular vectors are interleaved, that is, the vectors are
    616:    output in the following order\: `V0, U0, V1, U1, V2, U2, ...`

    618:    The command-line option listed above admits an optional argument
    619:    specifying the viewer type and options. For instance, use
    620:    `-svd_view_vectors binary:svecs.bin` to save the vectors in a binary file.
    621:    See `PetscObjectViewFromOptions()` for more details.

    623:    Level: intermediate

    625: .seealso: [](ch:svd), `SVDSolve()`, `SVDValuesView()`, `SVDErrorView()`
    626: @*/
    627: PetscErrorCode SVDVectorsView(SVD svd,PetscViewer viewer)
    628: {
    629:   PetscInt       i,k;
    630:   Vec            x;
    631:   char           vname[30];
    632:   const char     *ename;

    634:   PetscFunctionBegin;
    636:   if (!viewer) PetscCall(PetscViewerASCIIGetStdout(PetscObjectComm((PetscObject)svd),&viewer));
    638:   PetscCheckSameComm(svd,1,viewer,2);
    639:   SVDCheckSolved(svd,1);
    640:   if (svd->nconv) {
    641:     PetscCall(PetscObjectGetName((PetscObject)svd,&ename));
    642:     PetscCall(SVDComputeVectors(svd));
    643:     for (i=0;i<svd->nconv;i++) {
    644:       k = svd->perm[i];
    645:       PetscCall(PetscSNPrintf(vname,sizeof(vname),"V%" PetscInt_FMT "_%s",i,ename));
    646:       PetscCall(BVGetColumn(svd->V,k,&x));
    647:       PetscCall(PetscObjectSetName((PetscObject)x,vname));
    648:       PetscCall(VecView(x,viewer));
    649:       PetscCall(BVRestoreColumn(svd->V,k,&x));
    650:       PetscCall(PetscSNPrintf(vname,sizeof(vname),"U%" PetscInt_FMT "_%s",i,ename));
    651:       PetscCall(BVGetColumn(svd->U,k,&x));
    652:       PetscCall(PetscObjectSetName((PetscObject)x,vname));
    653:       PetscCall(VecView(x,viewer));
    654:       PetscCall(BVRestoreColumn(svd->U,k,&x));
    655:     }
    656:   }
    657:   PetscFunctionReturn(PETSC_SUCCESS);
    658: }

    660: /*@
    661:    SVDVectorsViewFromOptions - Processes command line options to determine if/how
    662:    the computed singular vectors are to be viewed.

    664:    Collective

    666:    Input Parameter:
    667: .  svd - the singular value solver context

    669:    Level: developer

    671: .seealso: [](ch:svd), `SVDVectorsView()`
    672: @*/
    673: PetscErrorCode SVDVectorsViewFromOptions(SVD svd)
    674: {
    675:   PetscViewer       viewer;
    676:   PetscBool         flg = PETSC_FALSE;
    677:   static PetscBool  incall = PETSC_FALSE;
    678:   PetscViewerFormat format;

    680:   PetscFunctionBegin;
    681:   if (incall) PetscFunctionReturn(PETSC_SUCCESS);
    682:   incall = PETSC_TRUE;
    683:   PetscCall(PetscOptionsCreateViewer(PetscObjectComm((PetscObject)svd),((PetscObject)svd)->options,((PetscObject)svd)->prefix,"-svd_view_vectors",&viewer,&format,&flg));
    684:   if (flg) {
    685:     PetscCall(PetscViewerPushFormat(viewer,format));
    686:     PetscCall(SVDVectorsView(svd,viewer));
    687:     PetscCall(PetscViewerPopFormat(viewer));
    688:     PetscCall(PetscViewerDestroy(&viewer));
    689:   }
    690:   incall = PETSC_FALSE;
    691:   PetscFunctionReturn(PETSC_SUCCESS);
    692: }