LCOV - code coverage report
Current view: top level - svd/impls/trlanczos - trlanczos.c (source / functions) Hit Total Coverage
Test: SLEPc Lines: 1385 1491 92.9 %
Date: 2024-12-04 00:39:21 Functions: 57 59 96.6 %
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             :    SLEPc singular value solver: "trlanczos"
      12             : 
      13             :    Method: Thick-restart Lanczos
      14             : 
      15             :    Algorithm:
      16             : 
      17             :        Golub-Kahan-Lanczos bidiagonalization with thick-restart.
      18             : 
      19             :    References:
      20             : 
      21             :        [1] G.H. Golub and W. Kahan, "Calculating the singular values
      22             :            and pseudo-inverse of a matrix", SIAM J. Numer. Anal. Ser.
      23             :            B 2:205-224, 1965.
      24             : 
      25             :        [2] V. Hernandez, J.E. Roman, and A. Tomas, "A robust and
      26             :            efficient parallel SVD solver based on restarted Lanczos
      27             :            bidiagonalization", Elec. Trans. Numer. Anal. 31:68-85,
      28             :            2008.
      29             : */
      30             : 
      31             : #include <slepc/private/svdimpl.h>          /*I "slepcsvd.h" I*/
      32             : #include <slepc/private/bvimpl.h>
      33             : 
      34             : static PetscBool  cited = PETSC_FALSE,citedg = PETSC_FALSE;
      35             : static const char citation[] =
      36             :   "@Article{slepc-svd,\n"
      37             :   "   author = \"V. Hern{\\'a}ndez and J. E. Rom{\\'a}n and A. Tom{\\'a}s\",\n"
      38             :   "   title = \"A robust and efficient parallel {SVD} solver based on restarted {Lanczos} bidiagonalization\",\n"
      39             :   "   journal = \"Electron. Trans. Numer. Anal.\",\n"
      40             :   "   volume = \"31\",\n"
      41             :   "   pages = \"68--85\",\n"
      42             :   "   year = \"2008\"\n"
      43             :   "}\n";
      44             : static const char citationg[] =
      45             :   "@Article{slepc-gsvd,\n"
      46             :   "   author = \"F. Alvarruiz and C. Campos and J. E. Roman\",\n"
      47             :   "   title = \"Thick-restarted {Lanczos} bidiagonalization methods for the {GSVD}\",\n"
      48             :   "   journal = \"J. Comput. Appl. Math.\",\n"
      49             :   "   volume = \"440\",\n"
      50             :   "   pages = \"115506\",\n"
      51             :   "   year = \"2024\"\n"
      52             :   "}\n";
      53             : 
      54             : typedef struct {
      55             :   /* user parameters */
      56             :   PetscBool           oneside;   /* one-sided variant */
      57             :   PetscReal           keep;      /* restart parameter */
      58             :   PetscBool           lock;      /* locking/non-locking variant */
      59             :   KSP                 ksp;       /* solver for least-squares problem in GSVD */
      60             :   SVDTRLanczosGBidiag bidiag;    /* bidiagonalization variant for GSVD */
      61             :   PetscReal           scalef;    /* scale factor for matrix B */
      62             :   PetscReal           scaleth;   /* scale threshold for automatic scaling */
      63             :   PetscBool           explicitmatrix;
      64             :   /* auxiliary variables */
      65             :   Mat                 Z;         /* aux matrix for GSVD, Z=[A;B] */
      66             : } SVD_TRLANCZOS;
      67             : 
      68             : /* Context for shell matrix [A; B] */
      69             : typedef struct {
      70             :   Mat       A,B,AT,BT;
      71             :   Vec       y1,y2,y;
      72             :   PetscInt  m;
      73             :   PetscReal scalef;
      74             : } MatZData;
      75             : 
      76          55 : static PetscErrorCode MatZCreateContext(SVD svd,MatZData **zdata)
      77             : {
      78          55 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
      79             : 
      80          55 :   PetscFunctionBegin;
      81          55 :   PetscCall(PetscNew(zdata));
      82          55 :   (*zdata)->A = svd->A;
      83          55 :   (*zdata)->B = svd->B;
      84          55 :   (*zdata)->AT = svd->AT;
      85          55 :   (*zdata)->BT = svd->BT;
      86          55 :   (*zdata)->scalef = lanczos->scalef;
      87          55 :   PetscCall(MatCreateVecsEmpty(svd->A,NULL,&(*zdata)->y1));
      88          55 :   PetscCall(MatCreateVecsEmpty(svd->B,NULL,&(*zdata)->y2));
      89          55 :   PetscCall(VecGetLocalSize((*zdata)->y1,&(*zdata)->m));
      90          55 :   PetscCall(BVCreateVec(svd->U,&(*zdata)->y));
      91          55 :   PetscFunctionReturn(PETSC_SUCCESS);
      92             : }
      93             : 
      94             : /* Update scale factor for B in Z=[A;B]
      95             :    If matrices are swapped, the scale factor is inverted.*/
      96          81 : static PetscErrorCode MatZUpdateScale(SVD svd)
      97             : {
      98          81 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
      99          81 :   MatZData       *zdata;
     100          81 :   Mat            mats[2],normal;
     101          81 :   MatType        Atype;
     102          81 :   PetscBool      sametype;
     103          81 :   PetscReal      scalef = svd->swapped? 1.0/lanczos->scalef : lanczos->scalef;
     104             : 
     105          81 :   PetscFunctionBegin;
     106          81 :   if (lanczos->explicitmatrix) {
     107             :     /* Destroy the matrix Z and create it again */
     108          16 :     PetscCall(MatDestroy(&lanczos->Z));
     109          16 :     mats[0] = svd->A;
     110          16 :     if (scalef == 1.0) {
     111           8 :       mats[1] = svd->B;
     112             :     } else {
     113           8 :       PetscCall(MatDuplicate(svd->B,MAT_COPY_VALUES,&mats[1]));
     114           8 :       PetscCall(MatScale(mats[1],scalef));
     115             :     }
     116          16 :     PetscCall(MatCreateNest(PetscObjectComm((PetscObject)svd),2,NULL,1,NULL,mats,&lanczos->Z));
     117          16 :     PetscCall(MatGetType(svd->A,&Atype));
     118          16 :     PetscCall(PetscObjectTypeCompare((PetscObject)svd->B,Atype,&sametype));
     119          16 :     if (!sametype) Atype = MATAIJ;
     120          16 :     PetscCall(MatConvert(lanczos->Z,Atype,MAT_INPLACE_MATRIX,&lanczos->Z));
     121          16 :     if (scalef != 1.0) PetscCall(MatDestroy(&mats[1]));
     122             :   } else {
     123          65 :     PetscCall(MatShellGetContext(lanczos->Z,&zdata));
     124          65 :     zdata->scalef = scalef;
     125             :   }
     126             : 
     127             :   /* create normal equations matrix, to build the preconditioner in LSQR */
     128          81 :   PetscCall(MatCreateNormalHermitian(lanczos->Z,&normal));
     129             : 
     130          81 :   if (!lanczos->ksp) PetscCall(SVDTRLanczosGetKSP(svd,&lanczos->ksp));
     131          81 :   PetscCall(SVD_KSPSetOperators(lanczos->ksp,lanczos->Z,normal));
     132          81 :   PetscCall(KSPSetUp(lanczos->ksp));
     133          81 :   PetscCall(MatDestroy(&normal));
     134          81 :   PetscFunctionReturn(PETSC_SUCCESS);
     135             : }
     136             : 
     137          55 : static PetscErrorCode MatDestroy_Z(Mat Z)
     138             : {
     139          55 :   MatZData       *zdata;
     140             : 
     141          55 :   PetscFunctionBegin;
     142          55 :   PetscCall(MatShellGetContext(Z,&zdata));
     143          55 :   PetscCall(VecDestroy(&zdata->y1));
     144          55 :   PetscCall(VecDestroy(&zdata->y2));
     145          55 :   PetscCall(VecDestroy(&zdata->y));
     146          55 :   PetscCall(PetscFree(zdata));
     147          55 :   PetscFunctionReturn(PETSC_SUCCESS);
     148             : }
     149             : 
     150      132472 : static PetscErrorCode MatMult_Z(Mat Z,Vec x,Vec y)
     151             : {
     152      132472 :   MatZData       *zdata;
     153      132472 :   PetscScalar    *y_elems;
     154             : 
     155      132472 :   PetscFunctionBegin;
     156      132472 :   PetscCall(MatShellGetContext(Z,&zdata));
     157      132472 :   PetscCall(VecGetArray(y,&y_elems));
     158      132472 :   PetscCall(VecPlaceArray(zdata->y1,y_elems));
     159      132472 :   PetscCall(VecPlaceArray(zdata->y2,y_elems+zdata->m));
     160             : 
     161      132472 :   PetscCall(MatMult(zdata->A,x,zdata->y1));
     162      132472 :   PetscCall(MatMult(zdata->B,x,zdata->y2));
     163      132472 :   PetscCall(VecScale(zdata->y2,zdata->scalef));
     164             : 
     165      132472 :   PetscCall(VecResetArray(zdata->y1));
     166      132472 :   PetscCall(VecResetArray(zdata->y2));
     167      132472 :   PetscCall(VecRestoreArray(y,&y_elems));
     168      132472 :   PetscFunctionReturn(PETSC_SUCCESS);
     169             : }
     170             : 
     171      132686 : static PetscErrorCode MatMultTranspose_Z(Mat Z,Vec y,Vec x)
     172             : {
     173      132686 :   MatZData          *zdata;
     174      132686 :   const PetscScalar *y_elems;
     175             : 
     176      132686 :   PetscFunctionBegin;
     177      132686 :   PetscCall(MatShellGetContext(Z,&zdata));
     178      132686 :   PetscCall(VecGetArrayRead(y,&y_elems));
     179      132686 :   PetscCall(VecPlaceArray(zdata->y1,y_elems));
     180      132686 :   PetscCall(VecPlaceArray(zdata->y2,y_elems+zdata->m));
     181             : 
     182      132686 :   PetscCall(MatMult(zdata->BT,zdata->y2,x));
     183      132686 :   PetscCall(VecScale(x,zdata->scalef));
     184      132686 :   PetscCall(MatMultAdd(zdata->AT,zdata->y1,x,x));
     185             : 
     186      132686 :   PetscCall(VecResetArray(zdata->y1));
     187      132686 :   PetscCall(VecResetArray(zdata->y2));
     188      132686 :   PetscCall(VecRestoreArrayRead(y,&y_elems));
     189      132686 :   PetscFunctionReturn(PETSC_SUCCESS);
     190             : }
     191             : 
     192         163 : static PetscErrorCode MatCreateVecs_Z(Mat Z,Vec *right,Vec *left)
     193             : {
     194         163 :   MatZData       *zdata;
     195             : 
     196         163 :   PetscFunctionBegin;
     197         163 :   PetscCall(MatShellGetContext(Z,&zdata));
     198         163 :   if (right) PetscCall(MatCreateVecs(zdata->A,right,NULL));
     199         163 :   if (left) PetscCall(VecDuplicate(zdata->y,left));
     200         163 :   PetscFunctionReturn(PETSC_SUCCESS);
     201             : }
     202             : 
     203         114 : static PetscErrorCode SVDSetUp_TRLanczos(SVD svd)
     204             : {
     205         114 :   PetscInt       M,N,P,m,n,p;
     206         114 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
     207         114 :   MatZData       *zdata;
     208         114 :   Mat            aux;
     209             : 
     210         114 :   PetscFunctionBegin;
     211         114 :   PetscCall(MatGetSize(svd->A,&M,&N));
     212         114 :   PetscCall(SVDSetDimensions_Default(svd));
     213         114 :   PetscCheck(svd->ncv<=svd->nsv+svd->mpd,PetscObjectComm((PetscObject)svd),PETSC_ERR_USER_INPUT,"The value of ncv must not be larger than nsv+mpd");
     214         114 :   PetscCheck(lanczos->lock || svd->mpd>=svd->ncv,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Should not use mpd parameter in non-locking variant");
     215         203 :   if (svd->max_it==PETSC_DETERMINE) svd->max_it = PetscMax(N/svd->ncv,100)*((svd->stop==SVD_STOP_THRESHOLD)?10:1);
     216         114 :   if (!lanczos->keep) lanczos->keep = 0.5;
     217         114 :   svd->leftbasis = PETSC_TRUE;
     218         114 :   PetscCall(SVDAllocateSolution(svd,1));
     219         114 :   if (svd->isgeneralized) {
     220          67 :     PetscCall(MatGetSize(svd->B,&P,NULL));
     221          67 :     if (lanczos->bidiag == SVD_TRLANCZOS_GBIDIAG_LOWER && ((svd->which==SVD_LARGEST && P<=N) || (svd->which==SVD_SMALLEST && M>N && P<=N))) {
     222           6 :       SlepcSwap(svd->A,svd->B,aux);
     223           6 :       SlepcSwap(svd->AT,svd->BT,aux);
     224           6 :       svd->swapped = PETSC_TRUE;
     225          61 :     } else svd->swapped = PETSC_FALSE;
     226             : 
     227          67 :     PetscCall(SVDSetWorkVecs(svd,1,1));
     228             : 
     229          67 :     if (svd->conv==SVD_CONV_ABS) {  /* Residual norms are multiplied by matrix norms */
     230           0 :       if (!svd->nrma) PetscCall(MatNorm(svd->A,NORM_INFINITY,&svd->nrma));
     231           0 :       if (!svd->nrmb) PetscCall(MatNorm(svd->B,NORM_INFINITY,&svd->nrmb));
     232             :     }
     233             : 
     234             :     /* Create the matrix Z=[A;B] */
     235          67 :     PetscCall(MatGetLocalSize(svd->A,&m,&n));
     236          67 :     PetscCall(MatGetLocalSize(svd->B,&p,NULL));
     237          67 :     if (!lanczos->explicitmatrix) {
     238          55 :       PetscCall(MatDestroy(&lanczos->Z));
     239          55 :       PetscCall(MatZCreateContext(svd,&zdata));
     240          55 :       PetscCall(MatCreateShell(PetscObjectComm((PetscObject)svd),m+p,n,PETSC_DECIDE,PETSC_DECIDE,zdata,&lanczos->Z));
     241          55 :       PetscCall(MatShellSetOperation(lanczos->Z,MATOP_MULT,(void(*)(void))MatMult_Z));
     242             : #if defined(PETSC_USE_COMPLEX)
     243             :       PetscCall(MatShellSetOperation(lanczos->Z,MATOP_MULT_HERMITIAN_TRANSPOSE,(void(*)(void))MatMultTranspose_Z));
     244             : #else
     245          55 :       PetscCall(MatShellSetOperation(lanczos->Z,MATOP_MULT_TRANSPOSE,(void(*)(void))MatMultTranspose_Z));
     246             : #endif
     247          55 :       PetscCall(MatShellSetOperation(lanczos->Z,MATOP_CREATE_VECS,(void(*)(void))MatCreateVecs_Z));
     248          55 :       PetscCall(MatShellSetOperation(lanczos->Z,MATOP_DESTROY,(void(*)(void))MatDestroy_Z));
     249             :     }
     250             :     /* Explicit matrix is created here, when updating the scale */
     251          67 :     PetscCall(MatZUpdateScale(svd));
     252             : 
     253          47 :   } else if (svd->ishyperbolic) {
     254          15 :     PetscCall(BV_SetMatrixDiagonal(svd->swapped?svd->V:svd->U,svd->omega,svd->OP));
     255          15 :     PetscCall(SVDSetWorkVecs(svd,1,0));
     256             :   }
     257         114 :   PetscCall(DSSetCompact(svd->ds,PETSC_TRUE));
     258         114 :   PetscCall(DSSetExtraRow(svd->ds,PETSC_TRUE));
     259         114 :   PetscCall(DSAllocate(svd->ds,svd->ncv+1));
     260         114 :   PetscFunctionReturn(PETSC_SUCCESS);
     261             : }
     262             : 
     263          20 : static PetscErrorCode SVDOneSideTRLanczosMGS(SVD svd,PetscReal *alpha,PetscReal *beta,BV V,BV U,PetscInt nconv,PetscInt l,PetscInt n,PetscScalar* work)
     264             : {
     265          20 :   PetscReal      a,b;
     266          20 :   PetscInt       i,k=nconv+l;
     267          20 :   Vec            ui,ui1,vi;
     268             : 
     269          20 :   PetscFunctionBegin;
     270          20 :   PetscCall(BVGetColumn(V,k,&vi));
     271          20 :   PetscCall(BVGetColumn(U,k,&ui));
     272          20 :   PetscCall(MatMult(svd->A,vi,ui));
     273          20 :   PetscCall(BVRestoreColumn(V,k,&vi));
     274          20 :   PetscCall(BVRestoreColumn(U,k,&ui));
     275          20 :   if (l>0) {
     276          18 :     PetscCall(BVSetActiveColumns(U,nconv,n));
     277         102 :     for (i=0;i<l;i++) work[i]=beta[i+nconv];
     278          18 :     PetscCall(BVMultColumn(U,-1.0,1.0,k,work));
     279             :   }
     280          20 :   PetscCall(BVNormColumn(U,k,NORM_2,&a));
     281          20 :   PetscCall(BVScaleColumn(U,k,1.0/a));
     282          20 :   alpha[k] = a;
     283             : 
     284         104 :   for (i=k+1;i<n;i++) {
     285          84 :     PetscCall(BVGetColumn(V,i,&vi));
     286          84 :     PetscCall(BVGetColumn(U,i-1,&ui1));
     287          84 :     PetscCall(MatMult(svd->AT,ui1,vi));
     288          84 :     PetscCall(BVRestoreColumn(V,i,&vi));
     289          84 :     PetscCall(BVRestoreColumn(U,i-1,&ui1));
     290          84 :     PetscCall(BVOrthonormalizeColumn(V,i,PETSC_FALSE,&b,NULL));
     291          84 :     beta[i-1] = b;
     292             : 
     293          84 :     PetscCall(BVGetColumn(V,i,&vi));
     294          84 :     PetscCall(BVGetColumn(U,i,&ui));
     295          84 :     PetscCall(MatMult(svd->A,vi,ui));
     296          84 :     PetscCall(BVRestoreColumn(V,i,&vi));
     297          84 :     PetscCall(BVGetColumn(U,i-1,&ui1));
     298          84 :     PetscCall(VecAXPY(ui,-b,ui1));
     299          84 :     PetscCall(BVRestoreColumn(U,i-1,&ui1));
     300          84 :     PetscCall(BVRestoreColumn(U,i,&ui));
     301          84 :     PetscCall(BVNormColumn(U,i,NORM_2,&a));
     302          84 :     PetscCall(BVScaleColumn(U,i,1.0/a));
     303          84 :     alpha[i] = a;
     304             :   }
     305             : 
     306          20 :   PetscCall(BVGetColumn(V,n,&vi));
     307          20 :   PetscCall(BVGetColumn(U,n-1,&ui1));
     308          20 :   PetscCall(MatMult(svd->AT,ui1,vi));
     309          20 :   PetscCall(BVRestoreColumn(V,n,&vi));
     310          20 :   PetscCall(BVRestoreColumn(U,n-1,&ui1));
     311          20 :   PetscCall(BVOrthogonalizeColumn(V,n,NULL,&b,NULL));
     312          20 :   beta[n-1] = b;
     313          20 :   PetscFunctionReturn(PETSC_SUCCESS);
     314             : }
     315             : 
     316             : /*
     317             :   Custom CGS orthogonalization, preprocess after first orthogonalization
     318             : */
     319         208 : static PetscErrorCode SVDOrthogonalizeCGS(BV V,PetscInt i,PetscScalar* h,PetscReal a,BVOrthogRefineType refine,PetscReal eta,PetscReal *norm)
     320             : {
     321         208 :   PetscReal      sum,onorm;
     322         208 :   PetscScalar    dot;
     323         208 :   PetscInt       j;
     324             : 
     325         208 :   PetscFunctionBegin;
     326         208 :   switch (refine) {
     327           0 :   case BV_ORTHOG_REFINE_NEVER:
     328           0 :     PetscCall(BVNormColumn(V,i,NORM_2,norm));
     329             :     break;
     330         104 :   case BV_ORTHOG_REFINE_ALWAYS:
     331         104 :     PetscCall(BVSetActiveColumns(V,0,i));
     332         104 :     PetscCall(BVDotColumn(V,i,h));
     333         104 :     PetscCall(BVMultColumn(V,-1.0,1.0,i,h));
     334         104 :     PetscCall(BVNormColumn(V,i,NORM_2,norm));
     335             :     break;
     336         104 :   case BV_ORTHOG_REFINE_IFNEEDED:
     337         104 :     dot = h[i];
     338         104 :     onorm = PetscSqrtReal(PetscRealPart(dot)) / a;
     339         104 :     sum = 0.0;
     340         898 :     for (j=0;j<i;j++) {
     341         794 :       sum += PetscRealPart(h[j] * PetscConj(h[j]));
     342             :     }
     343         104 :     *norm = PetscRealPart(dot)/(a*a) - sum;
     344         104 :     if (*norm>0.0) *norm = PetscSqrtReal(*norm);
     345           0 :     else PetscCall(BVNormColumn(V,i,NORM_2,norm));
     346         104 :     if (*norm < eta*onorm) {
     347         104 :       PetscCall(BVSetActiveColumns(V,0,i));
     348         104 :       PetscCall(BVDotColumn(V,i,h));
     349         104 :       PetscCall(BVMultColumn(V,-1.0,1.0,i,h));
     350         104 :       PetscCall(BVNormColumn(V,i,NORM_2,norm));
     351             :     }
     352             :     break;
     353             :   }
     354         208 :   PetscFunctionReturn(PETSC_SUCCESS);
     355             : }
     356             : 
     357          40 : static PetscErrorCode SVDOneSideTRLanczosCGS(SVD svd,PetscReal *alpha,PetscReal *beta,BV V,BV U,PetscInt nconv,PetscInt l,PetscInt n,PetscScalar* work)
     358             : {
     359          40 :   PetscReal          a,b,eta;
     360          40 :   PetscInt           i,j,k=nconv+l;
     361          40 :   Vec                ui,ui1,vi;
     362          40 :   BVOrthogRefineType refine;
     363             : 
     364          40 :   PetscFunctionBegin;
     365          40 :   PetscCall(BVGetColumn(V,k,&vi));
     366          40 :   PetscCall(BVGetColumn(U,k,&ui));
     367          40 :   PetscCall(MatMult(svd->A,vi,ui));
     368          40 :   PetscCall(BVRestoreColumn(V,k,&vi));
     369          40 :   PetscCall(BVRestoreColumn(U,k,&ui));
     370          40 :   if (l>0) {
     371          36 :     PetscCall(BVSetActiveColumns(U,nconv,n));
     372         204 :     for (i=0;i<l;i++) work[i]=beta[i+nconv];
     373          36 :     PetscCall(BVMultColumn(U,-1.0,1.0,k,work));
     374             :   }
     375          40 :   PetscCall(BVGetOrthogonalization(V,NULL,&refine,&eta,NULL));
     376             : 
     377         208 :   for (i=k+1;i<n;i++) {
     378         168 :     PetscCall(BVGetColumn(V,i,&vi));
     379         168 :     PetscCall(BVGetColumn(U,i-1,&ui1));
     380         168 :     PetscCall(MatMult(svd->AT,ui1,vi));
     381         168 :     PetscCall(BVRestoreColumn(V,i,&vi));
     382         168 :     PetscCall(BVRestoreColumn(U,i-1,&ui1));
     383         168 :     PetscCall(BVNormColumnBegin(U,i-1,NORM_2,&a));
     384         168 :     if (refine == BV_ORTHOG_REFINE_IFNEEDED) {
     385          84 :       PetscCall(BVSetActiveColumns(V,0,i+1));
     386          84 :       PetscCall(BVGetColumn(V,i,&vi));
     387          84 :       PetscCall(BVDotVecBegin(V,vi,work));
     388             :     } else {
     389          84 :       PetscCall(BVSetActiveColumns(V,0,i));
     390          84 :       PetscCall(BVDotColumnBegin(V,i,work));
     391             :     }
     392         168 :     PetscCall(BVNormColumnEnd(U,i-1,NORM_2,&a));
     393         168 :     if (refine == BV_ORTHOG_REFINE_IFNEEDED) {
     394          84 :       PetscCall(BVDotVecEnd(V,vi,work));
     395          84 :       PetscCall(BVRestoreColumn(V,i,&vi));
     396          84 :       PetscCall(BVSetActiveColumns(V,0,i));
     397          84 :     } else PetscCall(BVDotColumnEnd(V,i,work));
     398             : 
     399         168 :     PetscCall(BVScaleColumn(U,i-1,1.0/a));
     400        1356 :     for (j=0;j<i;j++) work[j] = work[j] / a;
     401         168 :     PetscCall(BVMultColumn(V,-1.0,1.0/a,i,work));
     402         168 :     PetscCall(SVDOrthogonalizeCGS(V,i,work,a,refine,eta,&b));
     403         168 :     PetscCall(BVScaleColumn(V,i,1.0/b));
     404         168 :     PetscCheck(PetscAbsReal(b)>10*PETSC_MACHINE_EPSILON,PetscObjectComm((PetscObject)svd),PETSC_ERR_PLIB,"Recurrence generated a zero vector; use a two-sided variant");
     405             : 
     406         168 :     PetscCall(BVGetColumn(V,i,&vi));
     407         168 :     PetscCall(BVGetColumn(U,i,&ui));
     408         168 :     PetscCall(BVGetColumn(U,i-1,&ui1));
     409         168 :     PetscCall(MatMult(svd->A,vi,ui));
     410         168 :     PetscCall(VecAXPY(ui,-b,ui1));
     411         168 :     PetscCall(BVRestoreColumn(V,i,&vi));
     412         168 :     PetscCall(BVRestoreColumn(U,i,&ui));
     413         168 :     PetscCall(BVRestoreColumn(U,i-1,&ui1));
     414             : 
     415         168 :     alpha[i-1] = a;
     416         168 :     beta[i-1] = b;
     417             :   }
     418             : 
     419          40 :   PetscCall(BVGetColumn(V,n,&vi));
     420          40 :   PetscCall(BVGetColumn(U,n-1,&ui1));
     421          40 :   PetscCall(MatMult(svd->AT,ui1,vi));
     422          40 :   PetscCall(BVRestoreColumn(V,n,&vi));
     423          40 :   PetscCall(BVRestoreColumn(U,n-1,&ui1));
     424             : 
     425          40 :   PetscCall(BVNormColumnBegin(svd->U,n-1,NORM_2,&a));
     426          40 :   if (refine == BV_ORTHOG_REFINE_IFNEEDED) {
     427          20 :     PetscCall(BVSetActiveColumns(V,0,n+1));
     428          20 :     PetscCall(BVGetColumn(V,n,&vi));
     429          20 :     PetscCall(BVDotVecBegin(V,vi,work));
     430             :   } else {
     431          20 :     PetscCall(BVSetActiveColumns(V,0,n));
     432          20 :     PetscCall(BVDotColumnBegin(V,n,work));
     433             :   }
     434          40 :   PetscCall(BVNormColumnEnd(svd->U,n-1,NORM_2,&a));
     435          40 :   if (refine == BV_ORTHOG_REFINE_IFNEEDED) {
     436          20 :     PetscCall(BVDotVecEnd(V,vi,work));
     437          20 :     PetscCall(BVRestoreColumn(V,n,&vi));
     438          20 :   } else PetscCall(BVDotColumnEnd(V,n,work));
     439             : 
     440          40 :   PetscCall(BVScaleColumn(U,n-1,1.0/a));
     441         440 :   for (j=0;j<n;j++) work[j] = work[j] / a;
     442          40 :   PetscCall(BVMultColumn(V,-1.0,1.0/a,n,work));
     443          40 :   PetscCall(SVDOrthogonalizeCGS(V,n,work,a,refine,eta,&b));
     444          40 :   PetscCall(BVSetActiveColumns(V,nconv,n));
     445          40 :   alpha[n-1] = a;
     446          40 :   beta[n-1] = b;
     447          40 :   PetscFunctionReturn(PETSC_SUCCESS);
     448             : }
     449             : 
     450          32 : static PetscErrorCode SVDSolve_TRLanczos(SVD svd)
     451             : {
     452          32 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
     453          32 :   PetscReal      *alpha,*beta;
     454          32 :   PetscScalar    *swork=NULL,*w,*aux;
     455          32 :   PetscInt       i,k,l,nv,ld;
     456          32 :   Mat            U,V;
     457          32 :   PetscBool      breakdown=PETSC_FALSE;
     458          32 :   BVOrthogType   orthog;
     459             : 
     460          32 :   PetscFunctionBegin;
     461          32 :   PetscCall(PetscCitationsRegister(citation,&cited));
     462             :   /* allocate working space */
     463          32 :   PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     464          32 :   PetscCall(BVGetOrthogonalization(svd->V,&orthog,NULL,NULL,NULL));
     465          32 :   PetscCall(PetscMalloc1(ld,&w));
     466          32 :   if (lanczos->oneside) PetscCall(PetscMalloc1(svd->ncv+1,&swork));
     467             : 
     468             :   /* normalize start vector */
     469          32 :   if (!svd->nini) {
     470          23 :     PetscCall(BVSetRandomColumn(svd->V,0));
     471          23 :     PetscCall(BVOrthonormalizeColumn(svd->V,0,PETSC_TRUE,NULL,NULL));
     472             :   }
     473             : 
     474             :   l = 0;
     475         564 :   while (svd->reason == SVD_CONVERGED_ITERATING) {
     476         532 :     svd->its++;
     477             : 
     478             :     /* inner loop */
     479         532 :     nv = PetscMin(svd->nconv+svd->mpd,svd->ncv);
     480         532 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
     481         532 :     beta = alpha + ld;
     482         532 :     if (lanczos->oneside) {
     483          60 :       if (orthog == BV_ORTHOG_MGS) PetscCall(SVDOneSideTRLanczosMGS(svd,alpha,beta,svd->V,svd->U,svd->nconv,l,nv,swork));
     484          40 :       else PetscCall(SVDOneSideTRLanczosCGS(svd,alpha,beta,svd->V,svd->U,svd->nconv,l,nv,swork));
     485         472 :     } else PetscCall(SVDTwoSideLanczos(svd,alpha,beta,svd->V,svd->U,svd->nconv+l,&nv,&breakdown));
     486         532 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
     487         532 :     PetscCall(BVScaleColumn(svd->V,nv,1.0/beta[nv-1]));
     488         532 :     PetscCall(BVSetActiveColumns(svd->V,svd->nconv,nv));
     489         532 :     PetscCall(BVSetActiveColumns(svd->U,svd->nconv,nv));
     490             : 
     491             :     /* solve projected problem */
     492         532 :     PetscCall(DSSetDimensions(svd->ds,nv,svd->nconv,svd->nconv+l));
     493         532 :     PetscCall(DSSVDSetDimensions(svd->ds,nv));
     494         532 :     PetscCall(DSSetState(svd->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     495         532 :     PetscCall(DSSolve(svd->ds,w,NULL));
     496         532 :     PetscCall(DSSort(svd->ds,w,NULL,NULL,NULL,NULL));
     497         532 :     PetscCall(DSUpdateExtraRow(svd->ds));
     498         532 :     PetscCall(DSSynchronize(svd->ds,w,NULL));
     499        5844 :     for (i=svd->nconv;i<nv;i++) svd->sigma[i] = PetscRealPart(w[i]);
     500             : 
     501             :     /* check convergence */
     502         532 :     PetscCall(SVDKrylovConvergence(svd,PETSC_FALSE,svd->nconv,nv-svd->nconv,1.0,&k));
     503         532 :     SVDSetCtxThreshold(svd,svd->sigma,k);
     504         532 :     PetscCall((*svd->stopping)(svd,svd->its,svd->max_it,k,svd->nsv,&svd->reason,svd->stoppingctx));
     505             : 
     506             :     /* update l */
     507         532 :     if (svd->reason != SVD_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     508         500 :     else l = PetscMax(1,(PetscInt)((nv-k)*lanczos->keep));
     509         532 :     if (!lanczos->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged triplets */
     510         532 :     if (l) PetscCall(PetscInfo(svd,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     511             : 
     512         532 :     if (svd->reason == SVD_CONVERGED_ITERATING) {
     513         500 :       if (PetscUnlikely(breakdown || k==nv)) {
     514             :         /* Start a new bidiagonalization */
     515           0 :         PetscCall(PetscInfo(svd,"Breakdown in bidiagonalization (it=%" PetscInt_FMT ")\n",svd->its));
     516           0 :         if (k<svd->nsv) {
     517           0 :           PetscCall(BVSetRandomColumn(svd->V,k));
     518           0 :           PetscCall(BVOrthonormalizeColumn(svd->V,k,PETSC_FALSE,NULL,&breakdown));
     519           0 :           if (breakdown) {
     520           0 :             svd->reason = SVD_DIVERGED_BREAKDOWN;
     521           0 :             PetscCall(PetscInfo(svd,"Unable to generate more start vectors\n"));
     522             :           }
     523             :         }
     524         500 :       } else PetscCall(DSTruncate(svd->ds,k+l,PETSC_FALSE));
     525             :     }
     526             : 
     527             :     /* compute converged singular vectors and restart vectors */
     528         532 :     PetscCall(DSGetMat(svd->ds,DS_MAT_V,&V));
     529         532 :     PetscCall(BVMultInPlace(svd->V,V,svd->nconv,k+l));
     530         532 :     PetscCall(DSRestoreMat(svd->ds,DS_MAT_V,&V));
     531         532 :     PetscCall(DSGetMat(svd->ds,DS_MAT_U,&U));
     532         532 :     PetscCall(BVMultInPlace(svd->U,U,svd->nconv,k+l));
     533         532 :     PetscCall(DSRestoreMat(svd->ds,DS_MAT_U,&U));
     534             : 
     535         532 :     if (svd->reason == SVD_CONVERGED_ITERATING && !breakdown) {
     536         500 :       PetscCall(BVCopyColumn(svd->V,nv,k+l));  /* copy the last vector to be the next initial vector */
     537         500 :       if (svd->stop==SVD_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
     538           0 :         svd->ncv = svd->mpd+k;
     539           0 :         PetscCall(SVDReallocateSolution(svd,svd->ncv+1));
     540           0 :         for (i=nv;i<svd->ncv;i++) svd->perm[i] = i;
     541           0 :         PetscCall(DSReallocate(svd->ds,svd->ncv+1));
     542           0 :         aux = w;
     543           0 :         PetscCall(PetscMalloc1(svd->ncv+1,&w));
     544           0 :         PetscCall(PetscArraycpy(w,aux,ld));
     545           0 :         PetscCall(PetscFree(aux));
     546           0 :         PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     547           0 :         if (lanczos->oneside) {
     548           0 :           PetscCall(PetscFree(swork));
     549           0 :           PetscCall(PetscMalloc1(svd->ncv+1,&swork));
     550             :         }
     551             :       }
     552             :     }
     553             : 
     554         532 :     svd->nconv = k;
     555         564 :     PetscCall(SVDMonitor(svd,svd->its,svd->nconv,svd->sigma,svd->errest,nv));
     556             :   }
     557             : 
     558             :   /* orthonormalize U columns in one side method */
     559          32 :   if (lanczos->oneside) {
     560          33 :     for (i=0;i<svd->nconv;i++) PetscCall(BVOrthonormalizeColumn(svd->U,i,PETSC_FALSE,NULL,NULL));
     561             :   }
     562             : 
     563             :   /* free working space */
     564          32 :   PetscCall(PetscFree(w));
     565          32 :   if (swork) PetscCall(PetscFree(swork));
     566          32 :   PetscCall(DSTruncate(svd->ds,svd->nconv,PETSC_TRUE));
     567          32 :   PetscFunctionReturn(PETSC_SUCCESS);
     568             : }
     569             : 
     570         486 : static PetscErrorCode SVDLanczosHSVD(SVD svd,PetscReal *alpha,PetscReal *beta,PetscReal *omega,Mat A,Mat AT,BV V,BV U,PetscInt k,PetscInt *n,PetscBool *breakdown)
     571             : {
     572         486 :   PetscInt       i;
     573         486 :   Vec            u,v,ou=svd->workl[0];
     574         486 :   PetscBool      lindep=PETSC_FALSE;
     575         486 :   PetscReal      norm;
     576             : 
     577         486 :   PetscFunctionBegin;
     578        5760 :   for (i=k;i<*n;i++) {
     579        5274 :     PetscCall(BVGetColumn(V,i,&v));
     580        5274 :     PetscCall(BVGetColumn(U,i,&u));
     581        5274 :     PetscCall(MatMult(A,v,u));
     582        5274 :     PetscCall(BVRestoreColumn(V,i,&v));
     583        5274 :     PetscCall(BVRestoreColumn(U,i,&u));
     584        5274 :     PetscCall(BVOrthonormalizeColumn(U,i,PETSC_FALSE,alpha+i,&lindep));
     585        5274 :     omega[i] = PetscSign(alpha[i]);
     586        5274 :     if (PetscUnlikely(lindep)) {
     587           0 :       *n = i;
     588           0 :       break;
     589             :     }
     590             : 
     591        5274 :     PetscCall(BVGetColumn(V,i+1,&v));
     592        5274 :     PetscCall(BVGetColumn(U,i,&u));
     593        5274 :     PetscCall(VecPointwiseMult(ou,svd->omega,u));
     594        5274 :     PetscCall(MatMult(AT,ou,v));
     595        5274 :     PetscCall(BVRestoreColumn(V,i+1,&v));
     596        5274 :     PetscCall(BVRestoreColumn(U,i,&u));
     597        5274 :     PetscCall(BVOrthonormalizeColumn(V,i+1,PETSC_FALSE,&norm,&lindep));
     598        5274 :     beta[i] = omega[i]*norm;
     599        5274 :     if (PetscUnlikely(lindep)) {
     600           0 :       *n = i+1;
     601           0 :       break;
     602             :     }
     603             :   }
     604             : 
     605         486 :   if (breakdown) *breakdown = lindep;
     606         486 :   PetscFunctionReturn(PETSC_SUCCESS);
     607             : }
     608             : 
     609          15 : static PetscErrorCode SVDSolve_TRLanczos_HSVD(SVD svd)
     610             : {
     611          15 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
     612          15 :   PetscReal      *alpha,*beta,*omega;
     613          15 :   PetscScalar    *w,*aux;
     614          15 :   PetscInt       i,k,l,nv,ld,nini;
     615          15 :   Mat            UU,VV,D,A,AT;
     616          15 :   BV             U,V;
     617          15 :   PetscBool      breakdown=PETSC_FALSE;
     618          15 :   BVOrthogType   orthog;
     619          15 :   Vec            vomega;
     620             : 
     621          15 :   PetscFunctionBegin;
     622             :   /* undo the effect of swapping in this function */
     623          15 :   if (svd->swapped) {
     624           4 :     A = svd->AT;
     625           4 :     AT = svd->A;
     626           4 :     U = svd->V;
     627           4 :     V = svd->U;
     628           4 :     nini = svd->ninil;
     629             :   } else {
     630          11 :     A = svd->A;
     631          11 :     AT = svd->AT;
     632          11 :     U = svd->U;
     633          11 :     V = svd->V;
     634          11 :     nini = svd->nini;
     635             :   }
     636             :   /* allocate working space */
     637          15 :   PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     638          15 :   PetscCall(BVGetOrthogonalization(V,&orthog,NULL,NULL,NULL));
     639          15 :   PetscCall(PetscMalloc1(ld,&w));
     640          15 :   PetscCheck(!lanczos->oneside,PetscObjectComm((PetscObject)svd),PETSC_ERR_SUP,"Oneside orthogonalization not supported for HSVD");
     641             : 
     642             :   /* normalize start vector */
     643          15 :   if (!nini) {
     644          15 :     PetscCall(BVSetRandomColumn(V,0));
     645          15 :     PetscCall(BVOrthonormalizeColumn(V,0,PETSC_TRUE,NULL,NULL));
     646             :   }
     647             : 
     648             :   l = 0;
     649         501 :   while (svd->reason == SVD_CONVERGED_ITERATING) {
     650         486 :     svd->its++;
     651             : 
     652             :     /* inner loop */
     653         486 :     nv = PetscMin(svd->nconv+svd->mpd,svd->ncv);
     654         486 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
     655         486 :     beta = alpha + ld;
     656         486 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_D,&omega));
     657         486 :     PetscCall(SVDLanczosHSVD(svd,alpha,beta,omega,A,AT,V,U,svd->nconv+l,&nv,&breakdown));
     658         486 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
     659         486 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_D,&omega));
     660         486 :     PetscCall(BVSetActiveColumns(V,svd->nconv,nv));
     661         486 :     PetscCall(BVSetActiveColumns(U,svd->nconv,nv));
     662             : 
     663             :     /* solve projected problem */
     664         486 :     PetscCall(DSSetDimensions(svd->ds,nv,svd->nconv,svd->nconv+l));
     665         486 :     PetscCall(DSHSVDSetDimensions(svd->ds,nv));
     666         486 :     PetscCall(DSSetState(svd->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     667         486 :     PetscCall(DSSolve(svd->ds,w,NULL));
     668         486 :     PetscCall(DSSort(svd->ds,w,NULL,NULL,NULL,NULL));
     669         486 :     PetscCall(DSUpdateExtraRow(svd->ds));
     670         486 :     PetscCall(DSSynchronize(svd->ds,w,NULL));
     671         486 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_D,&omega));
     672       10516 :     for (i=svd->nconv;i<nv;i++) {
     673       10030 :       svd->sigma[i] = PetscRealPart(w[i]);
     674       10030 :       svd->sign[i] = omega[i];
     675             :     }
     676         486 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_D,&omega));
     677             : 
     678             :     /* check convergence */
     679         486 :     PetscCall(SVDKrylovConvergence(svd,PETSC_FALSE,svd->nconv,nv-svd->nconv,1.0,&k));
     680         486 :     SVDSetCtxThreshold(svd,svd->sigma,k);
     681         486 :     PetscCall((*svd->stopping)(svd,svd->its,svd->max_it,k,svd->nsv,&svd->reason,svd->stoppingctx));
     682             : 
     683             :     /* update l */
     684         486 :     if (svd->reason != SVD_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     685         471 :     else l = PetscMax(1,(PetscInt)((nv-k)*lanczos->keep));
     686         486 :     if (!lanczos->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged triplets */
     687         486 :     if (l) PetscCall(PetscInfo(svd,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     688             : 
     689         486 :     if (svd->reason == SVD_CONVERGED_ITERATING) {
     690         471 :       if (PetscUnlikely(breakdown || k==nv)) {
     691             :         /* Start a new bidiagonalization */
     692           0 :         PetscCall(PetscInfo(svd,"Breakdown in bidiagonalization (it=%" PetscInt_FMT ")\n",svd->its));
     693           0 :         if (k<svd->nsv) {
     694           0 :           PetscCall(BVSetRandomColumn(V,k));
     695           0 :           PetscCall(BVOrthonormalizeColumn(V,k,PETSC_FALSE,NULL,&breakdown));
     696           0 :           if (breakdown) {
     697           0 :             svd->reason = SVD_DIVERGED_BREAKDOWN;
     698           0 :             PetscCall(PetscInfo(svd,"Unable to generate more start vectors\n"));
     699             :           }
     700             :         }
     701         471 :       } else PetscCall(DSTruncate(svd->ds,k+l,PETSC_FALSE));
     702             :     }
     703             : 
     704             :     /* compute converged singular vectors and restart vectors */
     705         486 :     PetscCall(DSGetMat(svd->ds,DS_MAT_V,&VV));
     706         486 :     PetscCall(BVMultInPlace(V,VV,svd->nconv,k+l));
     707         486 :     PetscCall(DSRestoreMat(svd->ds,DS_MAT_V,&VV));
     708         486 :     PetscCall(DSGetMat(svd->ds,DS_MAT_U,&UU));
     709         486 :     PetscCall(BVMultInPlace(U,UU,svd->nconv,k+l));
     710         486 :     PetscCall(DSRestoreMat(svd->ds,DS_MAT_U,&UU));
     711             : 
     712         486 :     if (svd->reason == SVD_CONVERGED_ITERATING && !breakdown) {
     713             :       /* copy the last vector of V to be the next initial vector
     714             :          and change signature matrix of U */
     715         471 :       PetscCall(BVCopyColumn(V,nv,k+l));
     716         471 :       PetscCall(BVSetActiveColumns(U,0,k+l));
     717         471 :       PetscCall(DSGetMatAndColumn(svd->ds,DS_MAT_D,0,&D,&vomega));
     718         471 :       PetscCall(BVSetSignature(U,vomega));
     719         471 :       PetscCall(DSRestoreMatAndColumn(svd->ds,DS_MAT_D,0,&D,&vomega));
     720             : 
     721         471 :       if (svd->stop==SVD_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
     722           2 :         svd->ncv = svd->mpd+k;
     723           2 :         PetscCall(SVDReallocateSolution(svd,svd->ncv+1));
     724          15 :         for (i=nv;i<svd->ncv;i++) svd->perm[i] = i;
     725           2 :         PetscCall(DSReallocate(svd->ds,svd->ncv+1));
     726           2 :         aux = w;
     727           2 :         PetscCall(PetscMalloc1(svd->ncv+1,&w));
     728           2 :         PetscCall(PetscArraycpy(w,aux,ld));
     729           2 :         PetscCall(PetscFree(aux));
     730           2 :         PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     731             :       }
     732             :     }
     733             : 
     734         486 :     svd->nconv = k;
     735         501 :     PetscCall(SVDMonitor(svd,svd->its,svd->nconv,svd->sigma,svd->errest,nv));
     736             :   }
     737             : 
     738             :   /* free working space */
     739          15 :   PetscCall(PetscFree(w));
     740          15 :   PetscCall(DSTruncate(svd->ds,svd->nconv,PETSC_TRUE));
     741          15 :   PetscFunctionReturn(PETSC_SUCCESS);
     742             : }
     743             : 
     744             : /* Given n computed generalized singular values in sigmain, backtransform them
     745             :    in sigmaout by undoing scaling and reciprocating if swapped=true. Also updates vectors V
     746             :    if given. If sigmaout=NULL then the result overwrites sigmain. */
     747         965 : static PetscErrorCode SVDLanczosBackTransform(SVD svd,PetscInt n,PetscReal *sigmain,PetscReal *sigmaout,BV V)
     748             : {
     749         965 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
     750         965 :   PetscInt      i;
     751         965 :   PetscReal     c,s,r,f,scalef;
     752             : 
     753         965 :   PetscFunctionBegin;
     754         965 :   scalef = svd->swapped? 1.0/lanczos->scalef: lanczos->scalef;
     755        9982 :   for (i=0;i<n;i++) {
     756        9017 :     if (V && scalef != 1.0) {
     757          92 :       s = 1.0/PetscSqrtReal(1.0+sigmain[i]*sigmain[i]);
     758          92 :       c = sigmain[i]*s;
     759          92 :       r = s/scalef;
     760          92 :       f = 1.0/PetscSqrtReal(c*c+r*r);
     761          92 :       PetscCall(BVScaleColumn(V,i,f));
     762             :     }
     763        9017 :     if (sigmaout) {
     764        8702 :       if (svd->swapped) sigmaout[i] = 1.0/(sigmain[i]*scalef);
     765        7718 :       else sigmaout[i] = sigmain[i]*scalef;
     766             :     } else {
     767         315 :       sigmain[i] *= scalef;
     768         315 :       if (svd->swapped) sigmain[i] = 1.0/sigmain[i];
     769             :     }
     770             :   }
     771         965 :   PetscFunctionReturn(PETSC_SUCCESS);
     772             : }
     773             : 
     774         223 : static PetscErrorCode SVDLanczosGSingle(SVD svd,PetscReal *alpha,PetscReal *beta,Mat Z,BV V,BV U,KSP ksp,PetscInt k,PetscInt *n,PetscBool *breakdown)
     775             : {
     776         223 :   SVD_TRLANCZOS     *lanczos = (SVD_TRLANCZOS*)svd->data;
     777         223 :   PetscInt          i,j,m;
     778         223 :   const PetscScalar *carr;
     779         223 :   PetscScalar       *arr;
     780         223 :   Vec               u,v,ut=svd->workl[0],x=svd->workr[0],v1,u1,u2;
     781         223 :   PetscBool         lindep=PETSC_FALSE;
     782             : 
     783         223 :   PetscFunctionBegin;
     784         223 :   PetscCall(MatCreateVecsEmpty(svd->A,NULL,&v1));
     785         223 :   PetscCall(BVGetColumn(V,k,&v));
     786         223 :   PetscCall(BVGetColumn(U,k,&u));
     787             : 
     788             :   /* Form ut=[u;0] */
     789         223 :   PetscCall(VecZeroEntries(ut));
     790         223 :   PetscCall(VecGetLocalSize(u,&m));
     791         223 :   PetscCall(VecGetArrayRead(u,&carr));
     792         223 :   PetscCall(VecGetArray(ut,&arr));
     793        9087 :   for (j=0; j<m; j++) arr[j] = carr[j];
     794         223 :   PetscCall(VecRestoreArrayRead(u,&carr));
     795         223 :   PetscCall(VecRestoreArray(ut,&arr));
     796             : 
     797             :   /* Solve least squares problem */
     798         223 :   PetscCall(KSPSolve(ksp,ut,x));
     799             : 
     800         223 :   PetscCall(MatMult(Z,x,v));
     801             : 
     802         223 :   PetscCall(BVRestoreColumn(U,k,&u));
     803         223 :   PetscCall(BVRestoreColumn(V,k,&v));
     804         223 :   PetscCall(BVOrthonormalizeColumn(V,k,PETSC_FALSE,alpha+k,&lindep));
     805         223 :   if (PetscUnlikely(lindep)) {
     806           0 :     *n = k;
     807           0 :     if (breakdown) *breakdown = lindep;
     808           0 :     PetscFunctionReturn(PETSC_SUCCESS);
     809             :   }
     810             : 
     811        1189 :   for (i=k+1; i<*n; i++) {
     812             : 
     813             :     /* Compute vector i of BV U */
     814         966 :     PetscCall(BVGetColumn(V,i-1,&v));
     815         966 :     PetscCall(VecGetArray(v,&arr));
     816         966 :     PetscCall(VecPlaceArray(v1,arr));
     817         966 :     PetscCall(VecRestoreArray(v,&arr));
     818         966 :     PetscCall(BVRestoreColumn(V,i-1,&v));
     819         966 :     PetscCall(BVInsertVec(U,i,v1));
     820         966 :     PetscCall(VecResetArray(v1));
     821         966 :     PetscCall(BVOrthonormalizeColumn(U,i,PETSC_FALSE,beta+i-1,&lindep));
     822         966 :     if (PetscUnlikely(lindep)) {
     823           0 :       *n = i;
     824           0 :       break;
     825             :     }
     826             : 
     827             :     /* Compute vector i of BV V */
     828             : 
     829         966 :     PetscCall(BVGetColumn(V,i,&v));
     830         966 :     PetscCall(BVGetColumn(U,i,&u));
     831             : 
     832             :     /* Form ut=[u;0] */
     833         966 :     PetscCall(VecGetArrayRead(u,&carr));
     834         966 :     PetscCall(VecGetArray(ut,&arr));
     835       34127 :     for (j=0; j<m; j++) arr[j] = carr[j];
     836         966 :     PetscCall(VecRestoreArrayRead(u,&carr));
     837         966 :     PetscCall(VecRestoreArray(ut,&arr));
     838             : 
     839             :     /* Solve least squares problem */
     840         966 :     PetscCall(KSPSolve(ksp,ut,x));
     841             : 
     842         966 :     PetscCall(MatMult(Z,x,v));
     843             : 
     844         966 :     PetscCall(BVRestoreColumn(U,i,&u));
     845         966 :     PetscCall(BVRestoreColumn(V,i,&v));
     846         966 :     if (!lanczos->oneside || i==k+1) PetscCall(BVOrthonormalizeColumn(V,i,PETSC_FALSE,alpha+i,&lindep));
     847             :     else {  /* cheap computation of V[i], if restart (i==k+1) do a full reorthogonalization */
     848         267 :       PetscCall(BVGetColumn(V,i,&u2));
     849         267 :       PetscCall(BVGetColumn(V,i-1,&u1));
     850         267 :       PetscCall(VecAXPY(u2,-beta[i-1],u1));
     851         267 :       PetscCall(BVRestoreColumn(V,i-1,&u1));
     852         267 :       PetscCall(VecNorm(u2,NORM_2,&alpha[i]));
     853         267 :       if (alpha[i]==0.0) lindep = PETSC_TRUE;
     854         267 :       else PetscCall(VecScale(u2,1.0/alpha[i]));
     855         267 :       PetscCall(BVRestoreColumn(V,i,&u2));
     856             :     }
     857         966 :     if (PetscUnlikely(lindep)) {
     858           0 :       *n = i;
     859           0 :       break;
     860             :     }
     861             :   }
     862             : 
     863             :   /* Compute vector n of BV U */
     864         223 :   if (!lindep) {
     865         223 :     PetscCall(BVGetColumn(V,*n-1,&v));
     866         223 :     PetscCall(VecGetArray(v,&arr));
     867         223 :     PetscCall(VecPlaceArray(v1,arr));
     868         223 :     PetscCall(VecRestoreArray(v,&arr));
     869         223 :     PetscCall(BVRestoreColumn(V,*n-1,&v));
     870         223 :     PetscCall(BVInsertVec(U,*n,v1));
     871         223 :     PetscCall(VecResetArray(v1));
     872         223 :     PetscCall(BVOrthonormalizeColumn(U,*n,PETSC_FALSE,beta+*n-1,&lindep));
     873             :   }
     874         223 :   if (breakdown) *breakdown = lindep;
     875         223 :   PetscCall(VecDestroy(&v1));
     876         223 :   PetscFunctionReturn(PETSC_SUCCESS);
     877             : }
     878             : 
     879             : /* solve generalized problem with single bidiagonalization of Q_A */
     880          11 : static PetscErrorCode SVDSolve_TRLanczosGSingle(SVD svd,BV U1,BV V)
     881             : {
     882          11 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
     883          11 :   PetscReal      *alpha,*beta,normr,scaleth,sigma0,*sigma,*aux2;
     884          11 :   PetscScalar    *w,*aux1;
     885          11 :   PetscInt       i,k,l,nv,ld;
     886          11 :   Mat            U,VV;
     887          11 :   PetscBool      breakdown=PETSC_FALSE;
     888             : 
     889          11 :   PetscFunctionBegin;
     890          11 :   PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     891          11 :   PetscCall(PetscMalloc2(ld,&w,ld,&sigma));
     892          11 :   normr = (svd->conv==SVD_CONV_ABS)? PetscMax(svd->nrma,svd->nrmb*lanczos->scalef): 1.0;
     893             :   /* Convert scale threshold th=c/s to the corresponding c */
     894          11 :   scaleth = (lanczos->scaleth!=0)? lanczos->scaleth/PetscSqrtReal(lanczos->scaleth*lanczos->scaleth+1): 0.0;
     895             : 
     896             :   /* normalize start vector */
     897          11 :   if (!svd->ninil) {
     898          10 :     PetscCall(BVSetRandomColumn(U1,0));
     899          10 :     PetscCall(BVOrthonormalizeColumn(U1,0,PETSC_TRUE,NULL,NULL));
     900             :   }
     901             : 
     902             :   l = 0;
     903         234 :   while (svd->reason == SVD_CONVERGED_ITERATING) {
     904         223 :     svd->its++;
     905             : 
     906             :     /* inner loop */
     907         223 :     nv = PetscMin(svd->nconv+svd->mpd,svd->ncv);
     908         223 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
     909         223 :     beta = alpha + ld;
     910         223 :     PetscCall(SVDLanczosGSingle(svd,alpha,beta,lanczos->Z,V,U1,lanczos->ksp,svd->nconv+l,&nv,&breakdown));
     911         223 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
     912         223 :     PetscCall(BVSetActiveColumns(V,svd->nconv,nv));
     913         223 :     PetscCall(BVSetActiveColumns(U1,svd->nconv,nv));
     914             : 
     915             :     /* solve projected problem */
     916         223 :     PetscCall(DSSetDimensions(svd->ds,nv,svd->nconv,svd->nconv+l));
     917         223 :     PetscCall(DSSVDSetDimensions(svd->ds,nv));
     918         223 :     PetscCall(DSSetState(svd->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
     919         223 :     PetscCall(DSSolve(svd->ds,w,NULL));
     920         223 :     PetscCall(DSSort(svd->ds,w,NULL,NULL,NULL,NULL));
     921         223 :     PetscCall(DSUpdateExtraRow(svd->ds));
     922         223 :     PetscCall(DSSynchronize(svd->ds,w,NULL));
     923        2194 :     for (i=svd->nconv;i<nv;i++) svd->sigma[i] = PetscRealPart(w[i]);
     924             : 
     925             :     /* check convergence */
     926         223 :     PetscCall(SVDKrylovConvergence(svd,PETSC_FALSE,svd->nconv,nv-svd->nconv,normr,&k));
     927         223 :     PetscCall(SVDLanczosBackTransform(svd,nv,svd->sigma,sigma,NULL));
     928         223 :     SVDSetCtxThreshold(svd,sigma,k);
     929         223 :     PetscCall((*svd->stopping)(svd,svd->its,svd->max_it,k,svd->nsv,&svd->reason,svd->stoppingctx));
     930             : 
     931         223 :     sigma0 = svd->which==SVD_LARGEST? svd->sigma[0] : 1.0/svd->sigma[0];
     932         223 :     if (scaleth!=0 && k==0 && sigma0>scaleth) {
     933             : 
     934             :       /* Scale and start from scratch */
     935           0 :       lanczos->scalef *= svd->sigma[0]/PetscSqrtReal(1-svd->sigma[0]*svd->sigma[0]);
     936           0 :       PetscCall(PetscInfo(svd,"Scaling by factor %g and starting from scratch\n",(double)lanczos->scalef));
     937           0 :       PetscCall(MatZUpdateScale(svd));
     938           0 :       if (svd->conv==SVD_CONV_ABS) normr = PetscMax(svd->nrma,svd->nrmb*lanczos->scalef);
     939             :       l = 0;
     940             : 
     941             :     } else {
     942             : 
     943             :       /* update l */
     944         223 :       if (svd->reason != SVD_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
     945         212 :       else l = PetscMax(1,(PetscInt)((nv-k)*lanczos->keep));
     946         223 :       if (!lanczos->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged triplets */
     947         223 :       if (l) PetscCall(PetscInfo(svd,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
     948             : 
     949         223 :       if (svd->reason == SVD_CONVERGED_ITERATING) {
     950         212 :         if (PetscUnlikely(breakdown || k==nv)) {
     951             :           /* Start a new bidiagonalization */
     952           0 :           PetscCall(PetscInfo(svd,"Breakdown in bidiagonalization (it=%" PetscInt_FMT ")\n",svd->its));
     953           0 :           if (k<svd->nsv) {
     954           0 :             PetscCall(BVSetRandomColumn(U1,k));
     955           0 :             PetscCall(BVOrthonormalizeColumn(U1,k,PETSC_FALSE,NULL,&breakdown));
     956           0 :             if (breakdown) {
     957           0 :               svd->reason = SVD_DIVERGED_BREAKDOWN;
     958           0 :               PetscCall(PetscInfo(svd,"Unable to generate more start vectors\n"));
     959             :             }
     960             :           }
     961         212 :         } else PetscCall(DSTruncate(svd->ds,k+l,PETSC_FALSE));
     962             :       }
     963             : 
     964             :       /* compute converged singular vectors and restart vectors */
     965         223 :       PetscCall(DSGetMat(svd->ds,DS_MAT_U,&U));
     966         223 :       PetscCall(BVMultInPlace(V,U,svd->nconv,k+l));
     967         223 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_U,&U));
     968         223 :       PetscCall(DSGetMat(svd->ds,DS_MAT_V,&VV));
     969         223 :       PetscCall(BVMultInPlace(U1,VV,svd->nconv,k+l));
     970         223 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_V,&VV));
     971             : 
     972         223 :       if (svd->reason == SVD_CONVERGED_ITERATING && !breakdown) {
     973         212 :         PetscCall(BVCopyColumn(U1,nv,k+l));  /* copy the last vector to be the next initial vector */
     974         212 :         if (svd->stop==SVD_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
     975           1 :           svd->ncv = svd->mpd+k;
     976           1 :           PetscCall(SVDReallocateSolution(svd,svd->ncv+1));
     977           1 :           PetscCall(BVResize(V,svd->ncv+1,PETSC_TRUE));
     978           1 :           PetscCall(BVResize(U1,svd->ncv+1,PETSC_TRUE));
     979           7 :           for (i=nv;i<svd->ncv;i++) svd->perm[i] = i;
     980           1 :           PetscCall(DSReallocate(svd->ds,svd->ncv+1));
     981           1 :           aux1 = w;
     982           1 :           aux2 = sigma;
     983           1 :           PetscCall(PetscMalloc2(svd->ncv+1,&w,svd->ncv+1,&sigma));
     984           1 :           PetscCall(PetscArraycpy(w,aux1,ld));
     985           1 :           PetscCall(PetscArraycpy(sigma,aux2,ld));
     986           1 :           PetscCall(PetscFree2(aux1,aux2));
     987           1 :           PetscCall(DSGetLeadingDimension(svd->ds,&ld));
     988             :         }
     989             :       }
     990             :     }
     991             : 
     992         223 :     svd->nconv = k;
     993         234 :     PetscCall(SVDMonitor(svd,svd->its,svd->nconv,sigma,svd->errest,nv));
     994             :   }
     995             : 
     996          11 :   PetscCall(PetscFree2(w,sigma));
     997          11 :   PetscFunctionReturn(PETSC_SUCCESS);
     998             : }
     999             : 
    1000             : /* Move generalized left singular vectors (0..nconv) from U1 and U2 to its final destination svd->U (single variant) */
    1001          11 : static inline PetscErrorCode SVDLeftSingularVectors_Single(SVD svd,BV U1,BV U2)
    1002             : {
    1003          11 :   PetscInt          i,k,m,p;
    1004          11 :   Vec               u,u1,u2;
    1005          11 :   PetscScalar       *ua,*u2a;
    1006          11 :   const PetscScalar *u1a;
    1007          11 :   PetscReal         s;
    1008             : 
    1009          11 :   PetscFunctionBegin;
    1010          11 :   PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1011          11 :   PetscCall(MatGetLocalSize(svd->B,&p,NULL));
    1012          63 :   for (i=0;i<svd->nconv;i++) {
    1013          52 :     PetscCall(BVGetColumn(U1,i,&u1));
    1014          52 :     PetscCall(BVGetColumn(U2,i,&u2));
    1015          52 :     PetscCall(BVGetColumn(svd->U,i,&u));
    1016          52 :     PetscCall(VecGetArrayRead(u1,&u1a));
    1017          52 :     PetscCall(VecGetArray(u,&ua));
    1018          52 :     PetscCall(VecGetArray(u2,&u2a));
    1019             :     /* Copy column from U1 to upper part of u */
    1020        2928 :     for (k=0;k<m;k++) ua[k] = u1a[k];
    1021             :     /* Copy column from lower part of U to U2. Orthogonalize column in U2 and copy back to U */
    1022        3116 :     for (k=0;k<p;k++) u2a[k] = ua[m+k];
    1023          52 :     PetscCall(VecRestoreArray(u2,&u2a));
    1024          52 :     PetscCall(BVRestoreColumn(U2,i,&u2));
    1025          52 :     PetscCall(BVOrthonormalizeColumn(U2,i,PETSC_FALSE,&s,NULL));
    1026          52 :     PetscCall(BVGetColumn(U2,i,&u2));
    1027          52 :     PetscCall(VecGetArray(u2,&u2a));
    1028        3116 :     for (k=0;k<p;k++) ua[m+k] = u2a[k];
    1029             :     /* Update singular value */
    1030          52 :     svd->sigma[i] /= s;
    1031          52 :     PetscCall(VecRestoreArrayRead(u1,&u1a));
    1032          52 :     PetscCall(VecRestoreArray(u,&ua));
    1033          52 :     PetscCall(VecRestoreArray(u2,&u2a));
    1034          52 :     PetscCall(BVRestoreColumn(U1,i,&u1));
    1035          52 :     PetscCall(BVRestoreColumn(U2,i,&u2));
    1036          52 :     PetscCall(BVRestoreColumn(svd->U,i,&u));
    1037             :   }
    1038          11 :   PetscFunctionReturn(PETSC_SUCCESS);
    1039             : }
    1040             : 
    1041         273 : static PetscErrorCode SVDLanczosGUpper(SVD svd,PetscReal *alpha,PetscReal *beta,PetscReal *alphah,PetscReal *betah,Mat Z,BV U1,BV U2,BV V,KSP ksp,PetscInt k,PetscInt *n,PetscBool *breakdown)
    1042             : {
    1043         273 :   SVD_TRLANCZOS     *lanczos = (SVD_TRLANCZOS*)svd->data;
    1044         273 :   PetscInt          i,j,m,p;
    1045         273 :   const PetscScalar *carr;
    1046         273 :   PetscScalar       *arr,*u2arr;
    1047         273 :   Vec               u,v,ut=svd->workl[0],x=svd->workr[0],v1,u1,u2;
    1048         273 :   PetscBool         lindep=PETSC_FALSE,lindep1=PETSC_FALSE,lindep2=PETSC_FALSE;
    1049             : 
    1050         273 :   PetscFunctionBegin;
    1051         273 :   PetscCall(MatCreateVecsEmpty(svd->A,NULL,&v1));
    1052         273 :   PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1053         273 :   PetscCall(MatGetLocalSize(svd->B,&p,NULL));
    1054             : 
    1055        1710 :   for (i=k; i<*n; i++) {
    1056             :     /* Compute vector i of BV U1 */
    1057        1437 :     PetscCall(BVGetColumn(V,i,&v));
    1058        1437 :     PetscCall(VecGetArrayRead(v,&carr));
    1059        1437 :     PetscCall(VecPlaceArray(v1,carr));
    1060        1437 :     PetscCall(BVInsertVec(U1,i,v1));
    1061        1437 :     PetscCall(VecResetArray(v1));
    1062        1437 :     if (!lanczos->oneside || i==k) PetscCall(BVOrthonormalizeColumn(U1,i,PETSC_FALSE,alpha+i,&lindep1));
    1063             :     else {  /* cheap computation of U1[i], if restart (i==k) do a full reorthogonalization */
    1064         484 :       PetscCall(BVGetColumn(U1,i,&u2));
    1065         484 :       if (i>0) {
    1066         484 :         PetscCall(BVGetColumn(U1,i-1,&u1));
    1067         484 :         PetscCall(VecAXPY(u2,-beta[i-1],u1));
    1068         484 :         PetscCall(BVRestoreColumn(U1,i-1,&u1));
    1069             :       }
    1070         484 :       PetscCall(VecNorm(u2,NORM_2,&alpha[i]));
    1071         484 :       if (alpha[i]==0.0) lindep = PETSC_TRUE;
    1072         484 :       else PetscCall(VecScale(u2,1.0/alpha[i]));
    1073         484 :       PetscCall(BVRestoreColumn(U1,i,&u2));
    1074             :     }
    1075             : 
    1076             :     /* Compute vector i of BV U2 */
    1077        1437 :     PetscCall(BVGetColumn(U2,i,&u2));
    1078        1437 :     PetscCall(VecGetArray(u2,&u2arr));
    1079        1437 :     if (i%2) {
    1080       37463 :       for (j=0; j<p; j++) u2arr[j] = -carr[m+j];
    1081             :     } else {
    1082       34652 :       for (j=0; j<p; j++) u2arr[j] = carr[m+j];
    1083             :     }
    1084        1437 :     PetscCall(VecRestoreArray(u2,&u2arr));
    1085        1437 :     PetscCall(VecRestoreArrayRead(v,&carr));
    1086        1437 :     PetscCall(BVRestoreColumn(V,i,&v));
    1087        1437 :     if (lanczos->oneside && i>k) {  /* cheap computation of U2[i], if restart (i==k) do a full reorthogonalization */
    1088         484 :       if (i>0) {
    1089         484 :         PetscCall(BVGetColumn(U2,i-1,&u1));
    1090         484 :         PetscCall(VecAXPY(u2,(i%2)?betah[i-1]:-betah[i-1],u1));
    1091         484 :         PetscCall(BVRestoreColumn(U2,i-1,&u1));
    1092             :       }
    1093         484 :       PetscCall(VecNorm(u2,NORM_2,&alphah[i]));
    1094         484 :       if (alphah[i]==0.0) lindep = PETSC_TRUE;
    1095         484 :       else PetscCall(VecScale(u2,1.0/alphah[i]));
    1096             :     }
    1097        1437 :     PetscCall(BVRestoreColumn(U2,i,&u2));
    1098        1437 :     if (!lanczos->oneside || i==k) PetscCall(BVOrthonormalizeColumn(U2,i,PETSC_FALSE,alphah+i,&lindep2));
    1099        1437 :     if (i%2) alphah[i] = -alphah[i];
    1100        1437 :     if (PetscUnlikely(lindep1 || lindep2)) {
    1101           0 :       lindep = PETSC_TRUE;
    1102           0 :       *n = i;
    1103           0 :       break;
    1104             :     }
    1105             : 
    1106             :     /* Compute vector i+1 of BV V */
    1107        1437 :     PetscCall(BVGetColumn(V,i+1,&v));
    1108             :     /* Form ut=[u;0] */
    1109        1437 :     PetscCall(BVGetColumn(U1,i,&u));
    1110        1437 :     PetscCall(VecZeroEntries(ut));
    1111        1437 :     PetscCall(VecGetArrayRead(u,&carr));
    1112        1437 :     PetscCall(VecGetArray(ut,&arr));
    1113       59819 :     for (j=0; j<m; j++) arr[j] = carr[j];
    1114        1437 :     PetscCall(VecRestoreArrayRead(u,&carr));
    1115        1437 :     PetscCall(VecRestoreArray(ut,&arr));
    1116             :     /* Solve least squares problem */
    1117        1437 :     PetscCall(KSPSolve(ksp,ut,x));
    1118        1437 :     PetscCall(MatMult(Z,x,v));
    1119        1437 :     PetscCall(BVRestoreColumn(U1,i,&u));
    1120        1437 :     PetscCall(BVRestoreColumn(V,i+1,&v));
    1121        1437 :     PetscCall(BVOrthonormalizeColumn(V,i+1,PETSC_FALSE,beta+i,&lindep));
    1122        1437 :     betah[i] = -alpha[i]*beta[i]/alphah[i];
    1123        1437 :     if (PetscUnlikely(lindep)) {
    1124           0 :       *n = i;
    1125           0 :       break;
    1126             :     }
    1127             :   }
    1128         273 :   if (breakdown) *breakdown = lindep;
    1129         273 :   PetscCall(VecDestroy(&v1));
    1130         273 :   PetscFunctionReturn(PETSC_SUCCESS);
    1131             : }
    1132             : 
    1133             : /* generate random initial vector in column k for joint upper-upper bidiagonalization */
    1134          22 : static inline PetscErrorCode SVDInitialVectorGUpper(SVD svd,BV V,BV U1,PetscInt k,PetscBool *breakdown)
    1135             : {
    1136          22 :   SVD_TRLANCZOS     *lanczos = (SVD_TRLANCZOS*)svd->data;
    1137          22 :   Vec               u,v,ut=svd->workl[0],x=svd->workr[0];
    1138          22 :   PetscInt          m,j;
    1139          22 :   PetscScalar       *arr;
    1140          22 :   const PetscScalar *carr;
    1141             : 
    1142          22 :   PetscFunctionBegin;
    1143             :   /* Form ut=[u;0] where u is the k-th column of U1 */
    1144          22 :   PetscCall(VecZeroEntries(ut));
    1145          22 :   PetscCall(BVGetColumn(U1,k,&u));
    1146          22 :   PetscCall(VecGetLocalSize(u,&m));
    1147          22 :   PetscCall(VecGetArrayRead(u,&carr));
    1148          22 :   PetscCall(VecGetArray(ut,&arr));
    1149        1312 :   for (j=0; j<m; j++) arr[j] = carr[j];
    1150          22 :   PetscCall(VecRestoreArrayRead(u,&carr));
    1151          22 :   PetscCall(VecRestoreArray(ut,&arr));
    1152          22 :   PetscCall(BVRestoreColumn(U1,k,&u));
    1153             :   /* Solve least squares problem Z*x=ut for x. Then set v=Z*x */
    1154          22 :   PetscCall(KSPSolve(lanczos->ksp,ut,x));
    1155          22 :   PetscCall(BVGetColumn(V,k,&v));
    1156          22 :   PetscCall(MatMult(lanczos->Z,x,v));
    1157          22 :   PetscCall(BVRestoreColumn(V,k,&v));
    1158          22 :   if (breakdown) PetscCall(BVOrthonormalizeColumn(V,k,PETSC_FALSE,NULL,breakdown));
    1159          22 :   else PetscCall(BVOrthonormalizeColumn(V,k,PETSC_TRUE,NULL,NULL));
    1160          22 :   PetscFunctionReturn(PETSC_SUCCESS);
    1161             : }
    1162             : 
    1163             : /* solve generalized problem with joint upper-upper bidiagonalization */
    1164          17 : static PetscErrorCode SVDSolve_TRLanczosGUpper(SVD svd,BV U1,BV U2,BV V)
    1165             : {
    1166          17 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    1167          17 :   PetscReal      *alpha,*beta,*alphah,*betah,normr,sigma0,*sigma,*aux2;
    1168          17 :   PetscScalar    *w,*aux1;
    1169          17 :   PetscInt       i,k,l,nv,ld;
    1170          17 :   Mat            U,Vmat,X;
    1171          17 :   PetscBool      breakdown=PETSC_FALSE;
    1172             : 
    1173          17 :   PetscFunctionBegin;
    1174          17 :   PetscCall(DSGetLeadingDimension(svd->ds,&ld));
    1175          17 :   PetscCall(PetscMalloc2(ld,&w,ld,&sigma));
    1176          17 :   normr = (svd->conv==SVD_CONV_ABS)? PetscMax(svd->nrma,svd->nrmb*lanczos->scalef): 1.0;
    1177             : 
    1178             :   /* normalize start vector */
    1179          17 :   if (!svd->ninil) PetscCall(BVSetRandomColumn(U1,0));
    1180          17 :   PetscCall(SVDInitialVectorGUpper(svd,V,U1,0,NULL));
    1181             : 
    1182             :   l = 0;
    1183         290 :   while (svd->reason == SVD_CONVERGED_ITERATING) {
    1184         273 :     svd->its++;
    1185             : 
    1186             :     /* inner loop */
    1187         273 :     nv = PetscMin(svd->nconv+svd->mpd,svd->ncv);
    1188         273 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
    1189         273 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_D,&alphah));
    1190         273 :     beta = alpha + ld;
    1191         273 :     betah = alpha + 2*ld;
    1192         273 :     PetscCall(SVDLanczosGUpper(svd,alpha,beta,alphah,betah,lanczos->Z,U1,U2,V,lanczos->ksp,svd->nconv+l,&nv,&breakdown));
    1193         273 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
    1194         273 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_D,&alphah));
    1195         273 :     PetscCall(BVSetActiveColumns(V,svd->nconv,nv));
    1196         273 :     PetscCall(BVSetActiveColumns(U1,svd->nconv,nv));
    1197         273 :     PetscCall(BVSetActiveColumns(U2,svd->nconv,nv));
    1198             : 
    1199             :     /* solve projected problem */
    1200         273 :     PetscCall(DSSetDimensions(svd->ds,nv,svd->nconv,svd->nconv+l));
    1201         273 :     PetscCall(DSGSVDSetDimensions(svd->ds,nv,nv));
    1202         273 :     PetscCall(DSSetState(svd->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
    1203         273 :     PetscCall(DSSolve(svd->ds,w,NULL));
    1204         273 :     PetscCall(DSSort(svd->ds,w,NULL,NULL,NULL,NULL));
    1205         273 :     PetscCall(DSUpdateExtraRow(svd->ds));
    1206         273 :     PetscCall(DSSynchronize(svd->ds,w,NULL));
    1207        2612 :     for (i=svd->nconv;i<nv;i++) svd->sigma[i] = PetscRealPart(w[i]);
    1208             : 
    1209             :     /* check convergence */
    1210         273 :     PetscCall(SVDKrylovConvergence(svd,PETSC_FALSE,svd->nconv,nv-svd->nconv,normr,&k));
    1211         273 :     PetscCall(SVDLanczosBackTransform(svd,nv,svd->sigma,sigma,NULL));
    1212         273 :     SVDSetCtxThreshold(svd,sigma,k);
    1213         273 :     PetscCall((*svd->stopping)(svd,svd->its,svd->max_it,k,svd->nsv,&svd->reason,svd->stoppingctx));
    1214             : 
    1215         273 :     sigma0 = svd->which==SVD_LARGEST? svd->sigma[0] : 1.0/svd->sigma[0];
    1216         273 :     if (lanczos->scaleth!=0 && k==0 && sigma0>lanczos->scaleth) {
    1217             : 
    1218             :       /* Scale and start from scratch */
    1219           5 :       lanczos->scalef *= svd->sigma[0];
    1220           5 :       PetscCall(PetscInfo(svd,"Scaling by factor %g and starting from scratch\n",(double)lanczos->scalef));
    1221           5 :       PetscCall(MatZUpdateScale(svd));
    1222           5 :       if (svd->conv==SVD_CONV_ABS) normr = PetscMax(svd->nrma,svd->nrmb*lanczos->scalef);
    1223           5 :       l = 0;
    1224           5 :       if (!svd->ninil) PetscCall(BVSetRandomColumn(U1,0));
    1225           5 :       PetscCall(SVDInitialVectorGUpper(svd,V,U1,0,NULL));
    1226             : 
    1227             :     } else {
    1228             : 
    1229             :       /* update l */
    1230         268 :       if (svd->reason != SVD_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
    1231         251 :       else l = PetscMax(1,(PetscInt)((nv-k)*lanczos->keep));
    1232         268 :       if (!lanczos->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged triplets */
    1233         268 :       if (l) PetscCall(PetscInfo(svd,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
    1234             : 
    1235         268 :       if (svd->reason == SVD_CONVERGED_ITERATING) {
    1236         251 :         if (PetscUnlikely(breakdown || k==nv)) {
    1237             :           /* Start a new bidiagonalization */
    1238           0 :           PetscCall(PetscInfo(svd,"Breakdown in bidiagonalization (it=%" PetscInt_FMT ")\n",svd->its));
    1239           0 :           if (k<svd->nsv) {
    1240           0 :             PetscCall(BVSetRandomColumn(U1,k));
    1241           0 :             PetscCall(SVDInitialVectorGUpper(svd,V,U1,k,&breakdown));
    1242           0 :             if (breakdown) {
    1243           0 :               svd->reason = SVD_DIVERGED_BREAKDOWN;
    1244           0 :               PetscCall(PetscInfo(svd,"Unable to generate more start vectors\n"));
    1245             :             }
    1246             :           }
    1247         251 :         } else PetscCall(DSTruncate(svd->ds,k+l,PETSC_FALSE));
    1248             :       }
    1249             :       /* compute converged singular vectors and restart vectors */
    1250         268 :       PetscCall(DSGetMat(svd->ds,DS_MAT_X,&X));
    1251         268 :       PetscCall(BVMultInPlace(V,X,svd->nconv,k+l));
    1252         268 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_X,&X));
    1253         268 :       PetscCall(DSGetMat(svd->ds,DS_MAT_U,&U));
    1254         268 :       PetscCall(BVMultInPlace(U1,U,svd->nconv,k+l));
    1255         268 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_U,&U));
    1256         268 :       PetscCall(DSGetMat(svd->ds,DS_MAT_V,&Vmat));
    1257         268 :       PetscCall(BVMultInPlace(U2,Vmat,svd->nconv,k+l));
    1258         268 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_V,&Vmat));
    1259             : 
    1260         268 :       if (svd->reason == SVD_CONVERGED_ITERATING && !breakdown) {
    1261         251 :         PetscCall(BVCopyColumn(V,nv,k+l));  /* copy the last vector to be the next initial vector */
    1262         251 :         if (svd->stop==SVD_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
    1263           1 :           svd->ncv = svd->mpd+k;
    1264           1 :           PetscCall(SVDReallocateSolution(svd,svd->ncv+1));
    1265           1 :           PetscCall(BVResize(U1,svd->ncv+1,PETSC_TRUE));
    1266           1 :           PetscCall(BVResize(U2,svd->ncv+1,PETSC_TRUE));
    1267           7 :           for (i=nv;i<svd->ncv;i++) svd->perm[i] = i;
    1268           1 :           PetscCall(DSReallocate(svd->ds,svd->ncv+1));
    1269           1 :           aux1 = w;
    1270           1 :           aux2 = sigma;
    1271           1 :           PetscCall(PetscMalloc2(svd->ncv+1,&w,svd->ncv+1,&sigma));
    1272           1 :           PetscCall(PetscArraycpy(w,aux1,ld));
    1273           1 :           PetscCall(PetscArraycpy(sigma,aux2,ld));
    1274           1 :           PetscCall(PetscFree2(aux1,aux2));
    1275           1 :           PetscCall(DSGetLeadingDimension(svd->ds,&ld));
    1276             :         }
    1277             :       }
    1278             :     }
    1279             : 
    1280         273 :     svd->nconv = k;
    1281         290 :     PetscCall(SVDMonitor(svd,svd->its,svd->nconv,sigma,svd->errest,nv));
    1282             :   }
    1283             : 
    1284          17 :   PetscCall(PetscFree2(w,sigma));
    1285          17 :   PetscFunctionReturn(PETSC_SUCCESS);
    1286             : }
    1287             : 
    1288             : /* Move generalized left singular vectors (0..nconv) from U1 and U2 to its final destination svd->U (upper and lower variants) */
    1289          56 : static inline PetscErrorCode SVDLeftSingularVectors(SVD svd,BV U1,BV U2)
    1290             : {
    1291          56 :   PetscInt          i,k,m,p;
    1292          56 :   Vec               u,u1,u2;
    1293          56 :   PetscScalar       *ua;
    1294          56 :   const PetscScalar *u1a,*u2a;
    1295             : 
    1296          56 :   PetscFunctionBegin;
    1297          56 :   PetscCall(BVGetSizes(U1,&m,NULL,NULL));
    1298          56 :   PetscCall(BVGetSizes(U2,&p,NULL,NULL));
    1299         319 :   for (i=0;i<svd->nconv;i++) {
    1300         263 :     PetscCall(BVGetColumn(U1,i,&u1));
    1301         263 :     PetscCall(BVGetColumn(U2,i,&u2));
    1302         263 :     PetscCall(BVGetColumn(svd->U,i,&u));
    1303         263 :     PetscCall(VecGetArrayRead(u1,&u1a));
    1304         263 :     PetscCall(VecGetArrayRead(u2,&u2a));
    1305         263 :     PetscCall(VecGetArray(u,&ua));
    1306             :     /* Copy column from u1 to upper part of u */
    1307       16965 :     for (k=0;k<m;k++) ua[k] = u1a[k];
    1308             :     /* Copy column from u2 to lower part of u */
    1309       22217 :     for (k=0;k<p;k++) ua[m+k] = u2a[k];
    1310         263 :     PetscCall(VecRestoreArrayRead(u1,&u1a));
    1311         263 :     PetscCall(VecRestoreArrayRead(u2,&u2a));
    1312         263 :     PetscCall(VecRestoreArray(u,&ua));
    1313         263 :     PetscCall(BVRestoreColumn(U1,i,&u1));
    1314         263 :     PetscCall(BVRestoreColumn(U2,i,&u2));
    1315         263 :     PetscCall(BVRestoreColumn(svd->U,i,&u));
    1316             :   }
    1317          56 :   PetscFunctionReturn(PETSC_SUCCESS);
    1318             : }
    1319             : 
    1320         402 : static PetscErrorCode SVDLanczosGLower(SVD svd,PetscReal *alpha,PetscReal *beta,PetscReal *alphah,PetscReal *betah,Mat Z,BV U1,BV U2,BV V,KSP ksp,PetscInt k,PetscInt *n,PetscBool *breakdown)
    1321             : {
    1322         402 :   SVD_TRLANCZOS     *lanczos = (SVD_TRLANCZOS*)svd->data;
    1323         402 :   PetscInt          i,j,m,p;
    1324         402 :   const PetscScalar *carr;
    1325         402 :   PetscScalar       *arr,*u2arr;
    1326         402 :   Vec               u,v,ut=svd->workl[0],x=svd->workr[0],v1,u1,u2;
    1327         402 :   PetscBool         lindep=PETSC_FALSE;
    1328             : 
    1329         402 :   PetscFunctionBegin;
    1330         402 :   PetscCall(MatCreateVecsEmpty(svd->A,NULL,&v1));
    1331         402 :   PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1332         402 :   PetscCall(MatGetLocalSize(svd->B,&p,NULL));
    1333             : 
    1334        2738 :   for (i=k; i<*n; i++) {
    1335             :     /* Compute vector i of BV U2 */
    1336        2336 :     PetscCall(BVGetColumn(V,i,&v));
    1337        2336 :     PetscCall(VecGetArrayRead(v,&carr));
    1338        2336 :     PetscCall(BVGetColumn(U2,i,&u2));
    1339        2336 :     PetscCall(VecGetArray(u2,&u2arr));
    1340        2336 :     if (i%2) {
    1341       69124 :       for (j=0; j<p; j++) u2arr[j] = -carr[m+j];
    1342             :     } else {
    1343       62766 :       for (j=0; j<p; j++) u2arr[j] = carr[m+j];
    1344             :     }
    1345        2336 :     PetscCall(VecRestoreArray(u2,&u2arr));
    1346        2336 :     if (lanczos->oneside && i>k) {  /* cheap computation of U2[i], if restart (i==k) do a full reorthogonalization */
    1347         450 :       if (i>0) {
    1348         450 :         PetscCall(BVGetColumn(U2,i-1,&u1));
    1349         450 :         PetscCall(VecAXPY(u2,(i%2)?betah[i-1]:-betah[i-1],u1));
    1350         450 :         PetscCall(BVRestoreColumn(U2,i-1,&u1));
    1351             :       }
    1352         450 :       PetscCall(VecNorm(u2,NORM_2,&alphah[i]));
    1353         450 :       if (alphah[i]==0.0) lindep = PETSC_TRUE;
    1354         450 :       else PetscCall(VecScale(u2,1.0/alphah[i]));
    1355             :     }
    1356        2336 :     PetscCall(BVRestoreColumn(U2,i,&u2));
    1357        2336 :     if (!lanczos->oneside || i==k) PetscCall(BVOrthonormalizeColumn(U2,i,PETSC_FALSE,alphah+i,&lindep));
    1358        2336 :     if (i%2) alphah[i] = -alphah[i];
    1359        2336 :     if (PetscUnlikely(lindep)) {
    1360           0 :       PetscCall(BVRestoreColumn(V,i,&v));
    1361           0 :       *n = i;
    1362           0 :       break;
    1363             :     }
    1364             : 
    1365             :     /* Compute vector i+1 of BV U1 */
    1366        2336 :     PetscCall(VecPlaceArray(v1,carr));
    1367        2336 :     PetscCall(BVInsertVec(U1,i+1,v1));
    1368        2336 :     PetscCall(VecResetArray(v1));
    1369        2336 :     PetscCall(BVOrthonormalizeColumn(U1,i+1,PETSC_FALSE,beta+i,&lindep));
    1370        2336 :     PetscCall(VecRestoreArrayRead(v,&carr));
    1371        2336 :     PetscCall(BVRestoreColumn(V,i,&v));
    1372        2336 :     if (PetscUnlikely(lindep)) {
    1373           0 :       *n = i+1;
    1374           0 :       break;
    1375             :     }
    1376             : 
    1377             :     /* Compute vector i+1 of BV V */
    1378        2336 :     PetscCall(BVGetColumn(V,i+1,&v));
    1379             :     /* Form ut=[u;0] where u is column i+1 of BV U1 */
    1380        2336 :     PetscCall(BVGetColumn(U1,i+1,&u));
    1381        2336 :     PetscCall(VecZeroEntries(ut));
    1382        2336 :     PetscCall(VecGetArrayRead(u,&carr));
    1383        2336 :     PetscCall(VecGetArray(ut,&arr));
    1384      109344 :     for (j=0; j<m; j++) arr[j] = carr[j];
    1385        2336 :     PetscCall(VecRestoreArrayRead(u,&carr));
    1386        2336 :     PetscCall(VecRestoreArray(ut,&arr));
    1387             :     /* Solve least squares problem */
    1388        2336 :     PetscCall(KSPSolve(ksp,ut,x));
    1389        2336 :     PetscCall(MatMult(Z,x,v));
    1390        2336 :     PetscCall(BVRestoreColumn(U1,i+1,&u));
    1391        2336 :     PetscCall(BVRestoreColumn(V,i+1,&v));
    1392        2336 :     if (!lanczos->oneside || i==k) PetscCall(BVOrthonormalizeColumn(V,i+1,PETSC_FALSE,alpha+i+1,&lindep));
    1393             :     else {  /* cheap computation of V[i+1], if restart (i==k) do a full reorthogonalization */
    1394         450 :       PetscCall(BVGetColumn(V,i+1,&u2));
    1395         450 :       PetscCall(BVGetColumn(V,i,&u1));
    1396         450 :       PetscCall(VecAXPY(u2,-beta[i],u1));
    1397         450 :       PetscCall(BVRestoreColumn(V,i,&u1));
    1398         450 :       PetscCall(VecNorm(u2,NORM_2,&alpha[i+1]));
    1399         450 :       if (alpha[i+1]==0.0) lindep = PETSC_TRUE;
    1400         450 :       else PetscCall(VecScale(u2,1.0/alpha[i+1]));
    1401         450 :       PetscCall(BVRestoreColumn(V,i+1,&u2));
    1402             :     }
    1403        2336 :     betah[i] = -alpha[i+1]*beta[i]/alphah[i];
    1404        2336 :     if (PetscUnlikely(lindep)) {
    1405           0 :       *n = i+1;
    1406           0 :       break;
    1407             :     }
    1408             :   }
    1409         402 :   if (breakdown) *breakdown = lindep;
    1410         402 :   PetscCall(VecDestroy(&v1));
    1411         402 :   PetscFunctionReturn(PETSC_SUCCESS);
    1412             : }
    1413             : 
    1414             : /* generate random initial vector in column k for joint lower-upper bidiagonalization */
    1415          48 : static inline PetscErrorCode SVDInitialVectorGLower(SVD svd,BV V,BV U1,BV U2,PetscInt k,PetscBool *breakdown)
    1416             : {
    1417          48 :   SVD_TRLANCZOS     *lanczos = (SVD_TRLANCZOS*)svd->data;
    1418          48 :   const PetscScalar *carr;
    1419          48 :   PetscScalar       *arr;
    1420          48 :   PetscReal         *alpha;
    1421          48 :   PetscInt          j,m,p;
    1422          48 :   Vec               u,uh,v,ut=svd->workl[0],x=svd->workr[0];
    1423             : 
    1424          48 :   PetscFunctionBegin;
    1425          48 :   PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1426          48 :   PetscCall(MatGetLocalSize(svd->B,&p,NULL));
    1427             :   /* Form ut=[0;uh], where uh is the k-th column of U2 */
    1428          48 :   PetscCall(BVGetColumn(U2,k,&uh));
    1429          48 :   PetscCall(VecZeroEntries(ut));
    1430          48 :   PetscCall(VecGetArrayRead(uh,&carr));
    1431          48 :   PetscCall(VecGetArray(ut,&arr));
    1432        3699 :   for (j=0; j<p; j++) arr[m+j] = carr[j];
    1433          48 :   PetscCall(VecRestoreArrayRead(uh,&carr));
    1434          48 :   PetscCall(VecRestoreArray(ut,&arr));
    1435          48 :   PetscCall(BVRestoreColumn(U2,k,&uh));
    1436             :   /* Solve least squares problem Z*x=ut for x. Then set ut=Z*x */
    1437          48 :   PetscCall(KSPSolve(lanczos->ksp,ut,x));
    1438          48 :   PetscCall(MatMult(lanczos->Z,x,ut));
    1439             :   /* Form u, column k of BV U1, as the upper part of ut and orthonormalize */
    1440          48 :   PetscCall(MatCreateVecsEmpty(svd->A,NULL,&u));
    1441          48 :   PetscCall(VecGetArrayRead(ut,&carr));
    1442          48 :   PetscCall(VecPlaceArray(u,carr));
    1443          48 :   PetscCall(BVInsertVec(U1,k,u));
    1444          48 :   PetscCall(VecResetArray(u));
    1445          48 :   PetscCall(VecRestoreArrayRead(ut,&carr));
    1446          48 :   PetscCall(VecDestroy(&u));
    1447          48 :   if (breakdown) PetscCall(BVOrthonormalizeColumn(U1,k,PETSC_FALSE,NULL,breakdown));
    1448          48 :   else PetscCall(BVOrthonormalizeColumn(U1,k,PETSC_TRUE,NULL,NULL));
    1449             : 
    1450          48 :   if (!breakdown || !*breakdown) {
    1451          48 :     PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1452             :     /* Compute k-th vector of BV V */
    1453          48 :     PetscCall(BVGetColumn(V,k,&v));
    1454             :     /* Form ut=[u;0] where u is the 1st column of U1 */
    1455          48 :     PetscCall(BVGetColumn(U1,k,&u));
    1456          48 :     PetscCall(VecZeroEntries(ut));
    1457          48 :     PetscCall(VecGetArrayRead(u,&carr));
    1458          48 :     PetscCall(VecGetArray(ut,&arr));
    1459        2609 :     for (j=0; j<m; j++) arr[j] = carr[j];
    1460          48 :     PetscCall(VecRestoreArrayRead(u,&carr));
    1461          48 :     PetscCall(VecRestoreArray(ut,&arr));
    1462             :     /* Solve least squares problem */
    1463          48 :     PetscCall(KSPSolve(lanczos->ksp,ut,x));
    1464          48 :     PetscCall(MatMult(lanczos->Z,x,v));
    1465          48 :     PetscCall(BVRestoreColumn(U1,k,&u));
    1466          48 :     PetscCall(BVRestoreColumn(V,k,&v));
    1467          48 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
    1468          48 :     if (breakdown) PetscCall(BVOrthonormalizeColumn(V,k,PETSC_FALSE,alpha+k,breakdown));
    1469          48 :     else PetscCall(BVOrthonormalizeColumn(V,k,PETSC_TRUE,alpha+k,NULL));
    1470          48 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
    1471             :   }
    1472          48 :   PetscFunctionReturn(PETSC_SUCCESS);
    1473             : }
    1474             : 
    1475             : /* solve generalized problem with joint lower-upper bidiagonalization */
    1476          39 : static PetscErrorCode SVDSolve_TRLanczosGLower(SVD svd,BV U1,BV U2,BV V)
    1477             : {
    1478          39 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    1479          39 :   PetscReal      *alpha,*beta,*alphah,*betah,normr,scalef,*sigma,sigma0,*aux2;
    1480          39 :   PetscScalar    *w,*aux1;
    1481          39 :   PetscInt       i,k,l,nv,ld;
    1482          39 :   Mat            U,Vmat,X;
    1483          39 :   PetscBool      breakdown=PETSC_FALSE,inverted;
    1484             : 
    1485          39 :   PetscFunctionBegin;
    1486          39 :   PetscCall(DSGetLeadingDimension(svd->ds,&ld));
    1487          39 :   PetscCall(PetscMalloc2(ld,&w,ld,&sigma));
    1488          39 :   inverted = ((svd->which==SVD_LARGEST && svd->swapped) || (svd->which==SVD_SMALLEST && !svd->swapped))? PETSC_TRUE: PETSC_FALSE;
    1489          39 :   scalef = svd->swapped? 1.0/lanczos->scalef : lanczos->scalef;
    1490          39 :   normr = (svd->conv==SVD_CONV_ABS)? PetscMax(svd->nrma,svd->nrmb*scalef): 1.0;
    1491             : 
    1492             :   /* normalize start vector */
    1493          39 :   if (!svd->ninil) PetscCall(BVSetRandomColumn(U2,0));
    1494          39 :   PetscCall(SVDInitialVectorGLower(svd,V,U1,U2,0,NULL));
    1495             : 
    1496             :   l = 0;
    1497         441 :   while (svd->reason == SVD_CONVERGED_ITERATING) {
    1498         402 :     svd->its++;
    1499             : 
    1500             :     /* inner loop */
    1501         402 :     nv = PetscMin(svd->nconv+svd->mpd,svd->ncv);
    1502         402 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_T,&alpha));
    1503         402 :     PetscCall(DSGetArrayReal(svd->ds,DS_MAT_D,&alphah));
    1504         402 :     beta = alpha + ld;
    1505         402 :     betah = alpha + 2*ld;
    1506         402 :     PetscCall(SVDLanczosGLower(svd,alpha,beta,alphah,betah,lanczos->Z,U1,U2,V,lanczos->ksp,svd->nconv+l,&nv,&breakdown));
    1507         402 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_T,&alpha));
    1508         402 :     PetscCall(DSRestoreArrayReal(svd->ds,DS_MAT_D,&alphah));
    1509         402 :     PetscCall(BVSetActiveColumns(V,svd->nconv,nv));
    1510         402 :     PetscCall(BVSetActiveColumns(U1,svd->nconv,nv+1));
    1511         402 :     PetscCall(BVSetActiveColumns(U2,svd->nconv,nv));
    1512             : 
    1513             :     /* solve projected problem */
    1514         402 :     PetscCall(DSSetDimensions(svd->ds,nv+1,svd->nconv,svd->nconv+l));
    1515         402 :     PetscCall(DSGSVDSetDimensions(svd->ds,nv,nv));
    1516         402 :     PetscCall(DSSetState(svd->ds,l?DS_STATE_RAW:DS_STATE_INTERMEDIATE));
    1517         402 :     PetscCall(DSSolve(svd->ds,w,NULL));
    1518         402 :     PetscCall(DSSort(svd->ds,w,NULL,NULL,NULL,NULL));
    1519         402 :     PetscCall(DSUpdateExtraRow(svd->ds));
    1520         402 :     PetscCall(DSSynchronize(svd->ds,w,NULL));
    1521        4190 :     for (i=svd->nconv;i<nv;i++) svd->sigma[i] = PetscRealPart(w[i]);
    1522             : 
    1523             :     /* check convergence */
    1524         402 :     PetscCall(SVDKrylovConvergence(svd,PETSC_FALSE,svd->nconv,nv-svd->nconv,normr,&k));
    1525         402 :     PetscCall(SVDLanczosBackTransform(svd,nv,svd->sigma,sigma,NULL));
    1526         402 :     SVDSetCtxThreshold(svd,sigma,k);
    1527         402 :     PetscCall((*svd->stopping)(svd,svd->its,svd->max_it,k,svd->nsv,&svd->reason,svd->stoppingctx));
    1528             : 
    1529         402 :     sigma0 = inverted? 1.0/svd->sigma[0] : svd->sigma[0];
    1530         402 :     if (lanczos->scaleth!=0 && k==0 && sigma0>lanczos->scaleth) {
    1531             : 
    1532             :       /* Scale and start from scratch */
    1533           9 :       lanczos->scalef *= svd->swapped? 1.0/svd->sigma[0] : svd->sigma[0];
    1534           9 :       PetscCall(PetscInfo(svd,"Scaling by factor %g and starting from scratch\n",(double)lanczos->scalef));
    1535           9 :       PetscCall(MatZUpdateScale(svd));
    1536           9 :       scalef = svd->swapped? 1.0/lanczos->scalef : lanczos->scalef;
    1537           9 :       if (svd->conv==SVD_CONV_ABS) normr = PetscMax(svd->nrma,svd->nrmb*scalef);
    1538           9 :       l = 0;
    1539           9 :       if (!svd->ninil) PetscCall(BVSetRandomColumn(U2,0));
    1540           9 :       PetscCall(SVDInitialVectorGLower(svd,V,U1,U2,0,NULL));
    1541             : 
    1542             :     } else {
    1543             : 
    1544             :       /* update l */
    1545         393 :       if (svd->reason != SVD_CONVERGED_ITERATING || breakdown || k==nv) l = 0;
    1546         354 :       else l = PetscMax(1,(PetscInt)((nv-k)*lanczos->keep));
    1547         393 :       if (!lanczos->lock && l>0) { l += k; k = 0; } /* non-locking variant: reset no. of converged triplets */
    1548         393 :       if (l) PetscCall(PetscInfo(svd,"Preparing to restart keeping l=%" PetscInt_FMT " vectors\n",l));
    1549             : 
    1550         393 :       if (svd->reason == SVD_CONVERGED_ITERATING) {
    1551         354 :         if (PetscUnlikely(breakdown || k==nv)) {
    1552             :           /* Start a new bidiagonalization */
    1553           0 :           PetscCall(PetscInfo(svd,"Breakdown in bidiagonalization (it=%" PetscInt_FMT ")\n",svd->its));
    1554           0 :           if (k<svd->nsv) {
    1555           0 :             PetscCall(BVSetRandomColumn(U2,k));
    1556           0 :             PetscCall(SVDInitialVectorGLower(svd,V,U1,U2,k,&breakdown));
    1557           0 :             if (breakdown) {
    1558           0 :               svd->reason = SVD_DIVERGED_BREAKDOWN;
    1559           0 :               PetscCall(PetscInfo(svd,"Unable to generate more start vectors\n"));
    1560             :             }
    1561             :           }
    1562         354 :         } else PetscCall(DSTruncate(svd->ds,k+l,PETSC_FALSE));
    1563             :       }
    1564             : 
    1565             :       /* compute converged singular vectors and restart vectors */
    1566         393 :       PetscCall(DSGetMat(svd->ds,DS_MAT_X,&X));
    1567         393 :       PetscCall(BVMultInPlace(V,X,svd->nconv,k+l));
    1568         393 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_X,&X));
    1569         393 :       PetscCall(DSGetMat(svd->ds,DS_MAT_U,&U));
    1570         393 :       PetscCall(BVMultInPlace(U1,U,svd->nconv,k+l+1));
    1571         393 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_U,&U));
    1572         393 :       PetscCall(DSGetMat(svd->ds,DS_MAT_V,&Vmat));
    1573         393 :       PetscCall(BVMultInPlace(U2,Vmat,svd->nconv,k+l));
    1574         393 :       PetscCall(DSRestoreMat(svd->ds,DS_MAT_V,&Vmat));
    1575             : 
    1576         393 :       if (svd->reason == SVD_CONVERGED_ITERATING && !breakdown) {
    1577         354 :         PetscCall(BVCopyColumn(V,nv,k+l));  /* copy the last vector to be the next initial vector */
    1578         354 :         if (svd->stop==SVD_STOP_THRESHOLD && nv-k<5) {  /* reallocate */
    1579           1 :           svd->ncv = svd->mpd+k;
    1580           1 :           PetscCall(SVDReallocateSolution(svd,svd->ncv+1));
    1581           1 :           PetscCall(BVResize(U1,svd->ncv+1,PETSC_TRUE));
    1582           1 :           PetscCall(BVResize(U2,svd->ncv+1,PETSC_TRUE));
    1583           7 :           for (i=nv;i<svd->ncv;i++) svd->perm[i] = i;
    1584           1 :           PetscCall(DSReallocate(svd->ds,svd->ncv+1));
    1585           1 :           aux1 = w;
    1586           1 :           aux2 = sigma;
    1587           1 :           PetscCall(PetscMalloc2(svd->ncv+1,&w,svd->ncv+1,&sigma));
    1588           1 :           PetscCall(PetscArraycpy(w,aux1,ld));
    1589           1 :           PetscCall(PetscArraycpy(sigma,aux2,ld));
    1590           1 :           PetscCall(PetscFree2(aux1,aux2));
    1591           1 :           PetscCall(DSGetLeadingDimension(svd->ds,&ld));
    1592             :         }
    1593             :       }
    1594             :     }
    1595             : 
    1596         402 :     svd->nconv = k;
    1597         441 :     PetscCall(SVDMonitor(svd,svd->its,svd->nconv,sigma,svd->errest,nv));
    1598             :   }
    1599             : 
    1600          39 :   PetscCall(PetscFree2(w,sigma));
    1601          39 :   PetscFunctionReturn(PETSC_SUCCESS);
    1602             : }
    1603             : 
    1604          67 : static PetscErrorCode SVDSolve_TRLanczos_GSVD(SVD svd)
    1605             : {
    1606          67 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    1607          67 :   PetscInt       k,m,p;
    1608          67 :   PetscBool      convchg=PETSC_FALSE;
    1609          67 :   BV             U1,U2,UU;
    1610          67 :   BVType         type;
    1611          67 :   VecType        vtype;
    1612          67 :   Mat            U,V;
    1613          67 :   SlepcSC        sc;
    1614             : 
    1615          67 :   PetscFunctionBegin;
    1616          67 :   PetscCall(PetscCitationsRegister(citationg,&citedg));
    1617             : 
    1618          67 :   if (svd->swapped) {
    1619           6 :     PetscCall(DSGetSlepcSC(svd->ds,&sc));
    1620           6 :     if (svd->which==SVD_LARGEST) sc->comparison = SlepcCompareSmallestReal;
    1621           0 :     else                         sc->comparison = SlepcCompareLargestReal;
    1622             :   }
    1623          67 :   if (svd->converged==SVDConvergedNorm) {  /* override temporarily since computed residual is already relative to the norms */
    1624          67 :     svd->converged = SVDConvergedAbsolute;
    1625          67 :     convchg = PETSC_TRUE;
    1626             :   }
    1627          67 :   PetscCall(MatGetLocalSize(svd->A,&m,NULL));
    1628          67 :   PetscCall(MatGetLocalSize(svd->B,&p,NULL));
    1629             : 
    1630             :   /* Create BV for U1 */
    1631          67 :   PetscCall(BVCreate(PetscObjectComm((PetscObject)svd),&U1));
    1632          67 :   PetscCall(BVGetType(svd->U,&type));
    1633          67 :   PetscCall(BVSetType(U1,type));
    1634          67 :   PetscCall(BVGetSizes(svd->U,NULL,NULL,&k));
    1635          67 :   PetscCall(BVSetSizes(U1,m,PETSC_DECIDE,k));
    1636          67 :   PetscCall(BVGetVecType(svd->U,&vtype));
    1637          67 :   PetscCall(BVSetVecType(U1,vtype));
    1638             : 
    1639             :   /* Create BV for U2 */
    1640          67 :   PetscCall(BVCreate(PetscObjectComm((PetscObject)svd),&U2));
    1641          67 :   PetscCall(BVSetType(U2,type));
    1642          67 :   PetscCall(BVSetSizes(U2,p,PETSC_DECIDE,k));
    1643          67 :   PetscCall(BVSetVecType(U2,vtype));
    1644             : 
    1645             :   /* Copy initial vectors from svd->U to U1 and U2 */
    1646          67 :   if (svd->ninil) {
    1647           4 :     Vec u, uh, nest, aux[2];
    1648           4 :     PetscCall(BVGetColumn(U1,0,&u));
    1649           4 :     PetscCall(BVGetColumn(U2,0,&uh));
    1650           4 :     aux[0] = u;
    1651           4 :     aux[1] = uh;
    1652           4 :     PetscCall(VecCreateNest(PetscObjectComm((PetscObject)svd),2,NULL,aux,&nest));
    1653           4 :     PetscCall(BVCopyVec(svd->U,0,nest));
    1654           4 :     PetscCall(BVRestoreColumn(U1,0,&u));
    1655           4 :     PetscCall(BVRestoreColumn(U2,0,&uh));
    1656           4 :     PetscCall(VecDestroy(&nest));
    1657             :   }
    1658             : 
    1659          67 :   switch (lanczos->bidiag) {
    1660          11 :     case SVD_TRLANCZOS_GBIDIAG_SINGLE:
    1661          11 :       PetscCall(SVDSolve_TRLanczosGSingle(svd,U1,svd->U));
    1662          11 :       if (svd->stop==SVD_STOP_THRESHOLD) PetscCall(BVResize(U2,svd->ncv+1,PETSC_FALSE));
    1663             :       break;
    1664          17 :     case SVD_TRLANCZOS_GBIDIAG_UPPER:
    1665          17 :       PetscCall(SVDSolve_TRLanczosGUpper(svd,U1,U2,svd->U));
    1666             :       break;
    1667          39 :     case SVD_TRLANCZOS_GBIDIAG_LOWER:
    1668          39 :       PetscCall(SVDSolve_TRLanczosGLower(svd,U1,U2,svd->U));
    1669             :       break;
    1670             :   }
    1671             : 
    1672             :   /* Compute converged right singular vectors */
    1673          67 :   PetscCall(BVSetActiveColumns(svd->U,0,svd->nconv));
    1674          67 :   PetscCall(BVSetActiveColumns(svd->V,0,svd->nconv));
    1675          67 :   PetscCall(BVGetMat(svd->U,&U));
    1676          67 :   PetscCall(BVGetMat(svd->V,&V));
    1677          67 :   PetscCall(KSPMatSolve(lanczos->ksp,U,V));
    1678          67 :   PetscCall(BVRestoreMat(svd->U,&U));
    1679          67 :   PetscCall(BVRestoreMat(svd->V,&V));
    1680             : 
    1681             :   /* Finish computing left singular vectors and move them to its place */
    1682          67 :   if (svd->swapped) SlepcSwap(U1,U2,UU);
    1683          67 :   switch (lanczos->bidiag) {
    1684          11 :     case SVD_TRLANCZOS_GBIDIAG_SINGLE:
    1685          11 :       PetscCall(SVDLeftSingularVectors_Single(svd,U1,U2));
    1686             :       break;
    1687          56 :     case SVD_TRLANCZOS_GBIDIAG_UPPER:
    1688             :     case SVD_TRLANCZOS_GBIDIAG_LOWER:
    1689          56 :       PetscCall(SVDLeftSingularVectors(svd,U1,U2));
    1690             :       break;
    1691             :   }
    1692             : 
    1693             :   /* undo scaling and compute the reciprocals of sigma if matrices were swapped */
    1694          67 :   PetscCall(SVDLanczosBackTransform(svd,svd->nconv,svd->sigma,NULL,svd->V));
    1695             : 
    1696          67 :   PetscCall(BVDestroy(&U1));
    1697          67 :   PetscCall(BVDestroy(&U2));
    1698          67 :   PetscCall(DSTruncate(svd->ds,svd->nconv,PETSC_TRUE));
    1699          67 :   if (convchg) svd->converged = SVDConvergedNorm;
    1700          67 :   PetscFunctionReturn(PETSC_SUCCESS);
    1701             : }
    1702             : 
    1703         101 : static PetscErrorCode SVDSetFromOptions_TRLanczos(SVD svd,PetscOptionItems *PetscOptionsObject)
    1704             : {
    1705         101 :   SVD_TRLANCZOS       *lanczos = (SVD_TRLANCZOS*)svd->data;
    1706         101 :   PetscBool           flg,val,lock;
    1707         101 :   PetscReal           keep,scale;
    1708         101 :   SVDTRLanczosGBidiag bidiag;
    1709             : 
    1710         101 :   PetscFunctionBegin;
    1711         101 :   PetscOptionsHeadBegin(PetscOptionsObject,"SVD TRLanczos Options");
    1712             : 
    1713         101 :     PetscCall(PetscOptionsBool("-svd_trlanczos_oneside","Use one-side reorthogonalization","SVDTRLanczosSetOneSide",lanczos->oneside,&val,&flg));
    1714         101 :     if (flg) PetscCall(SVDTRLanczosSetOneSide(svd,val));
    1715             : 
    1716         101 :     PetscCall(PetscOptionsReal("-svd_trlanczos_restart","Proportion of vectors kept after restart","SVDTRLanczosSetRestart",0.5,&keep,&flg));
    1717         101 :     if (flg) PetscCall(SVDTRLanczosSetRestart(svd,keep));
    1718             : 
    1719         101 :     PetscCall(PetscOptionsBool("-svd_trlanczos_locking","Choose between locking and non-locking variants","SVDTRLanczosSetLocking",PETSC_TRUE,&lock,&flg));
    1720         101 :     if (flg) PetscCall(SVDTRLanczosSetLocking(svd,lock));
    1721             : 
    1722         101 :     PetscCall(PetscOptionsEnum("-svd_trlanczos_gbidiag","Bidiagonalization choice for Generalized Problem","SVDTRLanczosSetGBidiag",SVDTRLanczosGBidiags,(PetscEnum)lanczos->bidiag,(PetscEnum*)&bidiag,&flg));
    1723         101 :     if (flg) PetscCall(SVDTRLanczosSetGBidiag(svd,bidiag));
    1724             : 
    1725         101 :     PetscCall(PetscOptionsBool("-svd_trlanczos_explicitmatrix","Build explicit matrix for KSP solver","SVDTRLanczosSetExplicitMatrix",lanczos->explicitmatrix,&val,&flg));
    1726         101 :     if (flg) PetscCall(SVDTRLanczosSetExplicitMatrix(svd,val));
    1727             : 
    1728         101 :     PetscCall(SVDTRLanczosGetScale(svd,&scale));
    1729         101 :     PetscCall(PetscOptionsReal("-svd_trlanczos_scale","Scale parameter for matrix B","SVDTRLanczosSetScale",scale,&scale,&flg));
    1730         101 :     if (flg) PetscCall(SVDTRLanczosSetScale(svd,scale));
    1731             : 
    1732         101 :   PetscOptionsHeadEnd();
    1733             : 
    1734         101 :   if (svd->OPb) {
    1735          61 :     if (!lanczos->ksp) PetscCall(SVDTRLanczosGetKSP(svd,&lanczos->ksp));
    1736          61 :     PetscCall(KSPSetFromOptions(lanczos->ksp));
    1737             :   }
    1738         101 :   PetscFunctionReturn(PETSC_SUCCESS);
    1739             : }
    1740             : 
    1741          34 : static PetscErrorCode SVDTRLanczosSetOneSide_TRLanczos(SVD svd,PetscBool oneside)
    1742             : {
    1743          34 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    1744             : 
    1745          34 :   PetscFunctionBegin;
    1746          34 :   if (lanczos->oneside != oneside) {
    1747          21 :     lanczos->oneside = oneside;
    1748          21 :     svd->state = SVD_STATE_INITIAL;
    1749             :   }
    1750          34 :   PetscFunctionReturn(PETSC_SUCCESS);
    1751             : }
    1752             : 
    1753             : /*@
    1754             :    SVDTRLanczosSetOneSide - Indicate if the variant of the Lanczos method
    1755             :    to be used is one-sided or two-sided.
    1756             : 
    1757             :    Logically Collective
    1758             : 
    1759             :    Input Parameters:
    1760             : +  svd     - singular value solver
    1761             : -  oneside - boolean flag indicating if the method is one-sided or not
    1762             : 
    1763             :    Options Database Key:
    1764             : .  -svd_trlanczos_oneside <boolean> - Indicates the boolean flag
    1765             : 
    1766             :    Notes:
    1767             :    By default, a two-sided variant is selected, which is sometimes slightly
    1768             :    more robust. However, the one-sided variant is faster because it avoids
    1769             :    the orthogonalization associated to left singular vectors.
    1770             : 
    1771             :    One-sided orthogonalization is also available for the GSVD, in which case
    1772             :    two orthogonalizations out of three are avoided.
    1773             : 
    1774             :    Level: advanced
    1775             : 
    1776             : .seealso: SVDLanczosSetOneSide()
    1777             : @*/
    1778          34 : PetscErrorCode SVDTRLanczosSetOneSide(SVD svd,PetscBool oneside)
    1779             : {
    1780          34 :   PetscFunctionBegin;
    1781          34 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1782         102 :   PetscValidLogicalCollectiveBool(svd,oneside,2);
    1783          34 :   PetscTryMethod(svd,"SVDTRLanczosSetOneSide_C",(SVD,PetscBool),(svd,oneside));
    1784          34 :   PetscFunctionReturn(PETSC_SUCCESS);
    1785             : }
    1786             : 
    1787           7 : static PetscErrorCode SVDTRLanczosGetOneSide_TRLanczos(SVD svd,PetscBool *oneside)
    1788             : {
    1789           7 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    1790             : 
    1791           7 :   PetscFunctionBegin;
    1792           7 :   *oneside = lanczos->oneside;
    1793           7 :   PetscFunctionReturn(PETSC_SUCCESS);
    1794             : }
    1795             : 
    1796             : /*@
    1797             :    SVDTRLanczosGetOneSide - Gets if the variant of the Lanczos method
    1798             :    to be used is one-sided or two-sided.
    1799             : 
    1800             :    Not Collective
    1801             : 
    1802             :    Input Parameters:
    1803             : .  svd     - singular value solver
    1804             : 
    1805             :    Output Parameters:
    1806             : .  oneside - boolean flag indicating if the method is one-sided or not
    1807             : 
    1808             :    Level: advanced
    1809             : 
    1810             : .seealso: SVDTRLanczosSetOneSide()
    1811             : @*/
    1812           7 : PetscErrorCode SVDTRLanczosGetOneSide(SVD svd,PetscBool *oneside)
    1813             : {
    1814           7 :   PetscFunctionBegin;
    1815           7 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1816           7 :   PetscAssertPointer(oneside,2);
    1817           7 :   PetscUseMethod(svd,"SVDTRLanczosGetOneSide_C",(SVD,PetscBool*),(svd,oneside));
    1818           7 :   PetscFunctionReturn(PETSC_SUCCESS);
    1819             : }
    1820             : 
    1821          51 : static PetscErrorCode SVDTRLanczosSetGBidiag_TRLanczos(SVD svd,SVDTRLanczosGBidiag bidiag)
    1822             : {
    1823          51 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    1824             : 
    1825          51 :   PetscFunctionBegin;
    1826          51 :   switch (bidiag) {
    1827          51 :     case SVD_TRLANCZOS_GBIDIAG_SINGLE:
    1828             :     case SVD_TRLANCZOS_GBIDIAG_UPPER:
    1829             :     case SVD_TRLANCZOS_GBIDIAG_LOWER:
    1830          51 :       if (lanczos->bidiag != bidiag) {
    1831          34 :         lanczos->bidiag = bidiag;
    1832          34 :         svd->state = SVD_STATE_INITIAL;
    1833             :       }
    1834          51 :       break;
    1835           0 :     default:
    1836           0 :       SETERRQ(PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_OUTOFRANGE,"Invalid bidiagonalization choice");
    1837             :   }
    1838          51 :   PetscFunctionReturn(PETSC_SUCCESS);
    1839             : }
    1840             : 
    1841             : /*@
    1842             :    SVDTRLanczosSetGBidiag - Sets the bidiagonalization choice to use in
    1843             :    the GSVD TRLanczos solver.
    1844             : 
    1845             :    Logically Collective
    1846             : 
    1847             :    Input Parameters:
    1848             : +  svd - the singular value solver
    1849             : -  bidiag - the bidiagonalization choice
    1850             : 
    1851             :    Options Database Key:
    1852             : .  -svd_trlanczos_gbidiag - Sets the bidiagonalization choice (either 's' or 'juu'
    1853             :    or 'jlu')
    1854             : 
    1855             :    Level: advanced
    1856             : 
    1857             : .seealso: SVDTRLanczosGetGBidiag(), SVDTRLanczosGBidiag
    1858             : @*/
    1859          51 : PetscErrorCode SVDTRLanczosSetGBidiag(SVD svd,SVDTRLanczosGBidiag bidiag)
    1860             : {
    1861          51 :   PetscFunctionBegin;
    1862          51 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1863         153 :   PetscValidLogicalCollectiveEnum(svd,bidiag,2);
    1864          51 :   PetscTryMethod(svd,"SVDTRLanczosSetGBidiag_C",(SVD,SVDTRLanczosGBidiag),(svd,bidiag));
    1865          51 :   PetscFunctionReturn(PETSC_SUCCESS);
    1866             : }
    1867             : 
    1868           6 : static PetscErrorCode SVDTRLanczosGetGBidiag_TRLanczos(SVD svd,SVDTRLanczosGBidiag *bidiag)
    1869             : {
    1870           6 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    1871             : 
    1872           6 :   PetscFunctionBegin;
    1873           6 :   *bidiag = lanczos->bidiag;
    1874           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1875             : }
    1876             : 
    1877             : /*@
    1878             :    SVDTRLanczosGetGBidiag - Gets the bidiagonalization choice used in the GSVD
    1879             :    TRLanczos solver.
    1880             : 
    1881             :    Not Collective
    1882             : 
    1883             :    Input Parameter:
    1884             : .  svd - the singular value solver
    1885             : 
    1886             :    Output Parameter:
    1887             : .  bidiag - the bidiagonalization choice
    1888             : 
    1889             :    Level: advanced
    1890             : 
    1891             : .seealso: SVDTRLanczosSetGBidiag(), SVDTRLanczosGBidiag
    1892             : @*/
    1893           6 : PetscErrorCode SVDTRLanczosGetGBidiag(SVD svd,SVDTRLanczosGBidiag *bidiag)
    1894             : {
    1895           6 :   PetscFunctionBegin;
    1896           6 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1897           6 :   PetscAssertPointer(bidiag,2);
    1898           6 :   PetscUseMethod(svd,"SVDTRLanczosGetGBidiag_C",(SVD,SVDTRLanczosGBidiag*),(svd,bidiag));
    1899           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1900             : }
    1901             : 
    1902           6 : static PetscErrorCode SVDTRLanczosSetKSP_TRLanczos(SVD svd,KSP ksp)
    1903             : {
    1904           6 :   SVD_TRLANCZOS  *ctx = (SVD_TRLANCZOS*)svd->data;
    1905             : 
    1906           6 :   PetscFunctionBegin;
    1907           6 :   PetscCall(PetscObjectReference((PetscObject)ksp));
    1908           6 :   PetscCall(KSPDestroy(&ctx->ksp));
    1909           6 :   ctx->ksp   = ksp;
    1910           6 :   svd->state = SVD_STATE_INITIAL;
    1911           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1912             : }
    1913             : 
    1914             : /*@
    1915             :    SVDTRLanczosSetKSP - Associate a linear solver object (KSP) to the SVD solver.
    1916             : 
    1917             :    Collective
    1918             : 
    1919             :    Input Parameters:
    1920             : +  svd - SVD solver
    1921             : -  ksp - the linear solver object
    1922             : 
    1923             :    Note:
    1924             :    Only used for the GSVD problem.
    1925             : 
    1926             :    Level: advanced
    1927             : 
    1928             : .seealso: SVDTRLanczosGetKSP()
    1929             : @*/
    1930           6 : PetscErrorCode SVDTRLanczosSetKSP(SVD svd,KSP ksp)
    1931             : {
    1932           6 :   PetscFunctionBegin;
    1933           6 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1934           6 :   PetscValidHeaderSpecific(ksp,KSP_CLASSID,2);
    1935           6 :   PetscCheckSameComm(svd,1,ksp,2);
    1936           6 :   PetscTryMethod(svd,"SVDTRLanczosSetKSP_C",(SVD,KSP),(svd,ksp));
    1937           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    1938             : }
    1939             : 
    1940          55 : static PetscErrorCode SVDTRLanczosGetKSP_TRLanczos(SVD svd,KSP *ksp)
    1941             : {
    1942          55 :   SVD_TRLANCZOS  *ctx = (SVD_TRLANCZOS*)svd->data;
    1943          55 :   PC             pc;
    1944             : 
    1945          55 :   PetscFunctionBegin;
    1946          55 :   if (!ctx->ksp) {
    1947             :     /* Create linear solver */
    1948          55 :     PetscCall(KSPCreate(PetscObjectComm((PetscObject)svd),&ctx->ksp));
    1949          55 :     PetscCall(PetscObjectIncrementTabLevel((PetscObject)ctx->ksp,(PetscObject)svd,1));
    1950          55 :     PetscCall(KSPSetOptionsPrefix(ctx->ksp,((PetscObject)svd)->prefix));
    1951          55 :     PetscCall(KSPAppendOptionsPrefix(ctx->ksp,"svd_trlanczos_"));
    1952          55 :     PetscCall(PetscObjectSetOptions((PetscObject)ctx->ksp,((PetscObject)svd)->options));
    1953          55 :     PetscCall(KSPSetType(ctx->ksp,KSPLSQR));
    1954          55 :     PetscCall(KSPGetPC(ctx->ksp,&pc));
    1955          55 :     PetscCall(PCSetType(pc,PCNONE));
    1956          55 :     PetscCall(KSPSetErrorIfNotConverged(ctx->ksp,PETSC_TRUE));
    1957         110 :     PetscCall(KSPSetTolerances(ctx->ksp,SlepcDefaultTol(svd->tol)/10.0,PETSC_CURRENT,PETSC_CURRENT,PETSC_CURRENT));
    1958             :   }
    1959          55 :   *ksp = ctx->ksp;
    1960          55 :   PetscFunctionReturn(PETSC_SUCCESS);
    1961             : }
    1962             : 
    1963             : /*@
    1964             :    SVDTRLanczosGetKSP - Retrieve the linear solver object (KSP) associated with
    1965             :    the SVD solver.
    1966             : 
    1967             :    Collective
    1968             : 
    1969             :    Input Parameter:
    1970             : .  svd - SVD solver
    1971             : 
    1972             :    Output Parameter:
    1973             : .  ksp - the linear solver object
    1974             : 
    1975             :    Level: advanced
    1976             : 
    1977             : .seealso: SVDTRLanczosSetKSP()
    1978             : @*/
    1979          55 : PetscErrorCode SVDTRLanczosGetKSP(SVD svd,KSP *ksp)
    1980             : {
    1981          55 :   PetscFunctionBegin;
    1982          55 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    1983          55 :   PetscAssertPointer(ksp,2);
    1984          55 :   PetscUseMethod(svd,"SVDTRLanczosGetKSP_C",(SVD,KSP*),(svd,ksp));
    1985          55 :   PetscFunctionReturn(PETSC_SUCCESS);
    1986             : }
    1987             : 
    1988          14 : static PetscErrorCode SVDTRLanczosSetRestart_TRLanczos(SVD svd,PetscReal keep)
    1989             : {
    1990          14 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    1991             : 
    1992          14 :   PetscFunctionBegin;
    1993          14 :   if (keep==(PetscReal)PETSC_DEFAULT || keep==(PetscReal)PETSC_DECIDE) ctx->keep = 0.5;
    1994             :   else {
    1995          14 :     PetscCheck(keep>=0.1 && keep<=0.9,PetscObjectComm((PetscObject)svd),PETSC_ERR_ARG_OUTOFRANGE,"The keep argument %g must be in the range [0.1,0.9]",(double)keep);
    1996          14 :     ctx->keep = keep;
    1997             :   }
    1998          14 :   PetscFunctionReturn(PETSC_SUCCESS);
    1999             : }
    2000             : 
    2001             : /*@
    2002             :    SVDTRLanczosSetRestart - Sets the restart parameter for the thick-restart
    2003             :    Lanczos method, in particular the proportion of basis vectors that must be
    2004             :    kept after restart.
    2005             : 
    2006             :    Logically Collective
    2007             : 
    2008             :    Input Parameters:
    2009             : +  svd  - the singular value solver
    2010             : -  keep - the number of vectors to be kept at restart
    2011             : 
    2012             :    Options Database Key:
    2013             : .  -svd_trlanczos_restart - Sets the restart parameter
    2014             : 
    2015             :    Notes:
    2016             :    Allowed values are in the range [0.1,0.9]. The default is 0.5.
    2017             : 
    2018             :    Level: advanced
    2019             : 
    2020             : .seealso: SVDTRLanczosGetRestart()
    2021             : @*/
    2022          14 : PetscErrorCode SVDTRLanczosSetRestart(SVD svd,PetscReal keep)
    2023             : {
    2024          14 :   PetscFunctionBegin;
    2025          14 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2026          42 :   PetscValidLogicalCollectiveReal(svd,keep,2);
    2027          14 :   PetscTryMethod(svd,"SVDTRLanczosSetRestart_C",(SVD,PetscReal),(svd,keep));
    2028          14 :   PetscFunctionReturn(PETSC_SUCCESS);
    2029             : }
    2030             : 
    2031           6 : static PetscErrorCode SVDTRLanczosGetRestart_TRLanczos(SVD svd,PetscReal *keep)
    2032             : {
    2033           6 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    2034             : 
    2035           6 :   PetscFunctionBegin;
    2036           6 :   *keep = ctx->keep;
    2037           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    2038             : }
    2039             : 
    2040             : /*@
    2041             :    SVDTRLanczosGetRestart - Gets the restart parameter used in the thick-restart
    2042             :    Lanczos method.
    2043             : 
    2044             :    Not Collective
    2045             : 
    2046             :    Input Parameter:
    2047             : .  svd - the singular value solver
    2048             : 
    2049             :    Output Parameter:
    2050             : .  keep - the restart parameter
    2051             : 
    2052             :    Level: advanced
    2053             : 
    2054             : .seealso: SVDTRLanczosSetRestart()
    2055             : @*/
    2056           6 : PetscErrorCode SVDTRLanczosGetRestart(SVD svd,PetscReal *keep)
    2057             : {
    2058           6 :   PetscFunctionBegin;
    2059           6 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2060           6 :   PetscAssertPointer(keep,2);
    2061           6 :   PetscUseMethod(svd,"SVDTRLanczosGetRestart_C",(SVD,PetscReal*),(svd,keep));
    2062           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    2063             : }
    2064             : 
    2065          20 : static PetscErrorCode SVDTRLanczosSetLocking_TRLanczos(SVD svd,PetscBool lock)
    2066             : {
    2067          20 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    2068             : 
    2069          20 :   PetscFunctionBegin;
    2070          20 :   ctx->lock = lock;
    2071          20 :   PetscFunctionReturn(PETSC_SUCCESS);
    2072             : }
    2073             : 
    2074             : /*@
    2075             :    SVDTRLanczosSetLocking - Choose between locking and non-locking variants of
    2076             :    the thick-restart Lanczos method.
    2077             : 
    2078             :    Logically Collective
    2079             : 
    2080             :    Input Parameters:
    2081             : +  svd  - the singular value solver
    2082             : -  lock - true if the locking variant must be selected
    2083             : 
    2084             :    Options Database Key:
    2085             : .  -svd_trlanczos_locking - Sets the locking flag
    2086             : 
    2087             :    Notes:
    2088             :    The default is to lock converged singular triplets when the method restarts.
    2089             :    This behaviour can be changed so that all directions are kept in the
    2090             :    working subspace even if already converged to working accuracy (the
    2091             :    non-locking variant).
    2092             : 
    2093             :    Level: advanced
    2094             : 
    2095             : .seealso: SVDTRLanczosGetLocking()
    2096             : @*/
    2097          20 : PetscErrorCode SVDTRLanczosSetLocking(SVD svd,PetscBool lock)
    2098             : {
    2099          20 :   PetscFunctionBegin;
    2100          20 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2101          60 :   PetscValidLogicalCollectiveBool(svd,lock,2);
    2102          20 :   PetscTryMethod(svd,"SVDTRLanczosSetLocking_C",(SVD,PetscBool),(svd,lock));
    2103          20 :   PetscFunctionReturn(PETSC_SUCCESS);
    2104             : }
    2105             : 
    2106           6 : static PetscErrorCode SVDTRLanczosGetLocking_TRLanczos(SVD svd,PetscBool *lock)
    2107             : {
    2108           6 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    2109             : 
    2110           6 :   PetscFunctionBegin;
    2111           6 :   *lock = ctx->lock;
    2112           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    2113             : }
    2114             : 
    2115             : /*@
    2116             :    SVDTRLanczosGetLocking - Gets the locking flag used in the thick-restart
    2117             :    Lanczos method.
    2118             : 
    2119             :    Not Collective
    2120             : 
    2121             :    Input Parameter:
    2122             : .  svd - the singular value solver
    2123             : 
    2124             :    Output Parameter:
    2125             : .  lock - the locking flag
    2126             : 
    2127             :    Level: advanced
    2128             : 
    2129             : .seealso: SVDTRLanczosSetLocking()
    2130             : @*/
    2131           6 : PetscErrorCode SVDTRLanczosGetLocking(SVD svd,PetscBool *lock)
    2132             : {
    2133           6 :   PetscFunctionBegin;
    2134           6 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2135           6 :   PetscAssertPointer(lock,2);
    2136           6 :   PetscUseMethod(svd,"SVDTRLanczosGetLocking_C",(SVD,PetscBool*),(svd,lock));
    2137           6 :   PetscFunctionReturn(PETSC_SUCCESS);
    2138             : }
    2139             : 
    2140          19 : static PetscErrorCode SVDTRLanczosSetExplicitMatrix_TRLanczos(SVD svd,PetscBool explicitmat)
    2141             : {
    2142          19 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    2143             : 
    2144          19 :   PetscFunctionBegin;
    2145          19 :   if (lanczos->explicitmatrix != explicitmat) {
    2146          15 :     lanczos->explicitmatrix = explicitmat;
    2147          15 :     svd->state = SVD_STATE_INITIAL;
    2148             :   }
    2149          19 :   PetscFunctionReturn(PETSC_SUCCESS);
    2150             : }
    2151             : 
    2152             : /*@
    2153             :    SVDTRLanczosSetExplicitMatrix - Indicate if the matrix Z=[A;B] must
    2154             :    be built explicitly.
    2155             : 
    2156             :    Logically Collective
    2157             : 
    2158             :    Input Parameters:
    2159             : +  svd         - singular value solver
    2160             : -  explicitmat - Boolean flag indicating if Z=[A;B] is built explicitly
    2161             : 
    2162             :    Options Database Key:
    2163             : .  -svd_trlanczos_explicitmatrix <boolean> - Indicates the boolean flag
    2164             : 
    2165             :    Notes:
    2166             :    This option is relevant for the GSVD case only.
    2167             :    Z is the coefficient matrix of the KSP solver used internally.
    2168             : 
    2169             :    Level: advanced
    2170             : 
    2171             : .seealso: SVDTRLanczosGetExplicitMatrix()
    2172             : @*/
    2173          19 : PetscErrorCode SVDTRLanczosSetExplicitMatrix(SVD svd,PetscBool explicitmat)
    2174             : {
    2175          19 :   PetscFunctionBegin;
    2176          19 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2177          57 :   PetscValidLogicalCollectiveBool(svd,explicitmat,2);
    2178          19 :   PetscTryMethod(svd,"SVDTRLanczosSetExplicitMatrix_C",(SVD,PetscBool),(svd,explicitmat));
    2179          19 :   PetscFunctionReturn(PETSC_SUCCESS);
    2180             : }
    2181             : 
    2182           0 : static PetscErrorCode SVDTRLanczosGetExplicitMatrix_TRLanczos(SVD svd,PetscBool *explicitmat)
    2183             : {
    2184           0 :   SVD_TRLANCZOS *lanczos = (SVD_TRLANCZOS*)svd->data;
    2185             : 
    2186           0 :   PetscFunctionBegin;
    2187           0 :   *explicitmat = lanczos->explicitmatrix;
    2188           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    2189             : }
    2190             : 
    2191             : /*@
    2192             :    SVDTRLanczosGetExplicitMatrix - Returns the flag indicating if Z=[A;B] is built explicitly.
    2193             : 
    2194             :    Not Collective
    2195             : 
    2196             :    Input Parameter:
    2197             : .  svd  - singular value solver
    2198             : 
    2199             :    Output Parameter:
    2200             : .  explicitmat - the mode flag
    2201             : 
    2202             :    Level: advanced
    2203             : 
    2204             : .seealso: SVDTRLanczosSetExplicitMatrix()
    2205             : @*/
    2206           0 : PetscErrorCode SVDTRLanczosGetExplicitMatrix(SVD svd,PetscBool *explicitmat)
    2207             : {
    2208           0 :   PetscFunctionBegin;
    2209           0 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2210           0 :   PetscAssertPointer(explicitmat,2);
    2211           0 :   PetscUseMethod(svd,"SVDTRLanczosGetExplicitMatrix_C",(SVD,PetscBool*),(svd,explicitmat));
    2212           0 :   PetscFunctionReturn(PETSC_SUCCESS);
    2213             : }
    2214             : 
    2215          23 : static PetscErrorCode SVDTRLanczosSetScale_TRLanczos(SVD svd,PetscReal scale)
    2216             : {
    2217          23 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    2218             : 
    2219          23 :   PetscFunctionBegin;
    2220          23 :   if (scale<0) {
    2221          11 :     ctx->scalef  = 1.0;
    2222          11 :     ctx->scaleth = -scale;
    2223             :   } else {
    2224          12 :     ctx->scalef  = scale;
    2225          12 :     ctx->scaleth = 0.0;
    2226             :   }
    2227          23 :   PetscFunctionReturn(PETSC_SUCCESS);
    2228             : }
    2229             : 
    2230             : /*@
    2231             :    SVDTRLanczosSetScale - Sets the scale parameter for the GSVD.
    2232             : 
    2233             :    Logically Collective
    2234             : 
    2235             :    Input Parameters:
    2236             : +  svd   - singular value solver
    2237             : -  scale - scale parameter
    2238             : 
    2239             :    Options Database Key:
    2240             : .  -svd_trlanczos_scale <real> - scale factor/threshold
    2241             : 
    2242             :    Notes:
    2243             :    This parameter is relevant for the GSVD case only. If the parameter is
    2244             :    positive, it indicates the scale factor for B in matrix Z=[A;B]. If
    2245             :    negative, its absolute value is the threshold for automatic scaling.
    2246             :    In automatic scaling, whenever the largest approximate generalized singular
    2247             :    value (or the inverse of the smallest value, if SVD_SMALLEST is used)
    2248             :    exceeds the threshold, the computation is restarted with matrix B
    2249             :    scaled by that value.
    2250             : 
    2251             :    Level: advanced
    2252             : 
    2253             : .seealso: SVDTRLanczosGetScale()
    2254             : @*/
    2255          23 : PetscErrorCode SVDTRLanczosSetScale(SVD svd,PetscReal scale)
    2256             : {
    2257          23 :   PetscFunctionBegin;
    2258          23 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2259          69 :   PetscValidLogicalCollectiveReal(svd,scale,2);
    2260          23 :   PetscTryMethod(svd,"SVDTRLanczosSetScale_C",(SVD,PetscReal),(svd,scale));
    2261          23 :   PetscFunctionReturn(PETSC_SUCCESS);
    2262             : }
    2263             : 
    2264         107 : static PetscErrorCode SVDTRLanczosGetScale_TRLanczos(SVD svd,PetscReal *scale)
    2265             : {
    2266         107 :   SVD_TRLANCZOS *ctx = (SVD_TRLANCZOS*)svd->data;
    2267             : 
    2268         107 :   PetscFunctionBegin;
    2269         107 :   if (ctx->scaleth==0) *scale = ctx->scalef;
    2270           6 :   else                 *scale = -ctx->scaleth;
    2271         107 :   PetscFunctionReturn(PETSC_SUCCESS);
    2272             : }
    2273             : 
    2274             : /*@
    2275             :    SVDTRLanczosGetScale - Gets the scale parameter for the GSVD.
    2276             : 
    2277             :    Not Collective
    2278             : 
    2279             :    Input Parameter:
    2280             : .  svd - the singular value solver
    2281             : 
    2282             :    Output Parameter:
    2283             : .  scale - the scale parameter
    2284             : 
    2285             :    Notes:
    2286             :    This parameter is relevant for the GSVD case only. If the parameter is
    2287             :    positive, it indicates the scale factor for B in matrix Z=[A;B]. If
    2288             :    negative, its absolute value is the threshold for automatic scaling.
    2289             : 
    2290             :    Level: advanced
    2291             : 
    2292             : .seealso: SVDTRLanczosSetScale()
    2293             : @*/
    2294         107 : PetscErrorCode SVDTRLanczosGetScale(SVD svd,PetscReal *scale)
    2295             : {
    2296         107 :   PetscFunctionBegin;
    2297         107 :   PetscValidHeaderSpecific(svd,SVD_CLASSID,1);
    2298         107 :   PetscAssertPointer(scale,2);
    2299         107 :   PetscUseMethod(svd,"SVDTRLanczosGetScale_C",(SVD,PetscReal*),(svd,scale));
    2300         107 :   PetscFunctionReturn(PETSC_SUCCESS);
    2301             : }
    2302             : 
    2303         103 : static PetscErrorCode SVDReset_TRLanczos(SVD svd)
    2304             : {
    2305         103 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    2306             : 
    2307         103 :   PetscFunctionBegin;
    2308         103 :   if (svd->isgeneralized || (!svd->problem_type && svd->OPb)) {
    2309          61 :     PetscCall(KSPReset(lanczos->ksp));
    2310          61 :     PetscCall(MatDestroy(&lanczos->Z));
    2311             :   }
    2312         103 :   PetscFunctionReturn(PETSC_SUCCESS);
    2313             : }
    2314             : 
    2315         102 : static PetscErrorCode SVDDestroy_TRLanczos(SVD svd)
    2316             : {
    2317         102 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    2318             : 
    2319         102 :   PetscFunctionBegin;
    2320         102 :   if (svd->isgeneralized || (!svd->problem_type && svd->OPb)) PetscCall(KSPDestroy(&lanczos->ksp));
    2321         102 :   PetscCall(PetscFree(svd->data));
    2322         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetOneSide_C",NULL));
    2323         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetOneSide_C",NULL));
    2324         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetGBidiag_C",NULL));
    2325         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetGBidiag_C",NULL));
    2326         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetKSP_C",NULL));
    2327         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetKSP_C",NULL));
    2328         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetRestart_C",NULL));
    2329         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetRestart_C",NULL));
    2330         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetLocking_C",NULL));
    2331         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetLocking_C",NULL));
    2332         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetExplicitMatrix_C",NULL));
    2333         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetExplicitMatrix_C",NULL));
    2334         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetScale_C",NULL));
    2335         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetScale_C",NULL));
    2336         102 :   PetscFunctionReturn(PETSC_SUCCESS);
    2337             : }
    2338             : 
    2339           1 : static PetscErrorCode SVDView_TRLanczos(SVD svd,PetscViewer viewer)
    2340             : {
    2341           1 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    2342           1 :   PetscBool      isascii;
    2343             : 
    2344           1 :   PetscFunctionBegin;
    2345           1 :   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
    2346           1 :   if (isascii) {
    2347           1 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  %d%% of basis vectors kept after restart\n",(int)(100*lanczos->keep)));
    2348           1 :     PetscCall(PetscViewerASCIIPrintf(viewer,"  using the %slocking variant\n",lanczos->lock?"":"non-"));
    2349           1 :     if (svd->isgeneralized) {
    2350           0 :       const char *bidiag="";
    2351             : 
    2352           0 :       switch (lanczos->bidiag) {
    2353           0 :         case SVD_TRLANCZOS_GBIDIAG_SINGLE: bidiag = "single"; break;
    2354           0 :         case SVD_TRLANCZOS_GBIDIAG_UPPER:  bidiag = "joint upper-upper"; break;
    2355           0 :         case SVD_TRLANCZOS_GBIDIAG_LOWER:  bidiag = "joint lower-upper"; break;
    2356             :       }
    2357           0 :       PetscCall(PetscViewerASCIIPrintf(viewer,"  bidiagonalization choice: %s\n",bidiag));
    2358           0 :       PetscCall(PetscViewerASCIIPrintf(viewer,"  %s matrix\n",lanczos->explicitmatrix?"explicit":"implicit"));
    2359           0 :       if (lanczos->scaleth==0) PetscCall(PetscViewerASCIIPrintf(viewer,"  scale factor for matrix B: %g\n",(double)lanczos->scalef));
    2360           0 :       else PetscCall(PetscViewerASCIIPrintf(viewer,"  automatic scaling for matrix B with threshold: %g\n",(double)lanczos->scaleth));
    2361           0 :       if (!lanczos->ksp) PetscCall(SVDTRLanczosGetKSP(svd,&lanczos->ksp));
    2362           0 :       PetscCall(PetscViewerASCIIPushTab(viewer));
    2363           0 :       PetscCall(KSPView(lanczos->ksp,viewer));
    2364           0 :       PetscCall(PetscViewerASCIIPopTab(viewer));
    2365           2 :     } else PetscCall(PetscViewerASCIIPrintf(viewer,"  %s-sided reorthogonalization\n",lanczos->oneside? "one": "two"));
    2366             :   }
    2367           1 :   PetscFunctionReturn(PETSC_SUCCESS);
    2368             : }
    2369             : 
    2370         215 : static PetscErrorCode SVDSetDSType_TRLanczos(SVD svd)
    2371             : {
    2372         215 :   SVD_TRLANCZOS  *lanczos = (SVD_TRLANCZOS*)svd->data;
    2373         215 :   DSType         dstype;
    2374             : 
    2375         215 :   PetscFunctionBegin;
    2376         215 :   dstype = svd->ishyperbolic? DSHSVD: DSSVD;
    2377         215 :   if (svd->OPb && (lanczos->bidiag==SVD_TRLANCZOS_GBIDIAG_UPPER || lanczos->bidiag==SVD_TRLANCZOS_GBIDIAG_LOWER)) dstype = DSGSVD;
    2378         215 :   PetscCall(DSSetType(svd->ds,dstype));
    2379         215 :   PetscFunctionReturn(PETSC_SUCCESS);
    2380             : }
    2381             : 
    2382         102 : SLEPC_EXTERN PetscErrorCode SVDCreate_TRLanczos(SVD svd)
    2383             : {
    2384         102 :   SVD_TRLANCZOS  *ctx;
    2385             : 
    2386         102 :   PetscFunctionBegin;
    2387         102 :   PetscCall(PetscNew(&ctx));
    2388         102 :   svd->data = (void*)ctx;
    2389             : 
    2390         102 :   ctx->lock    = PETSC_TRUE;
    2391         102 :   ctx->bidiag  = SVD_TRLANCZOS_GBIDIAG_LOWER;
    2392         102 :   ctx->scalef  = 1.0;
    2393         102 :   ctx->scaleth = 0.0;
    2394             : 
    2395         102 :   svd->ops->setup          = SVDSetUp_TRLanczos;
    2396         102 :   svd->ops->solve          = SVDSolve_TRLanczos;
    2397         102 :   svd->ops->solveg         = SVDSolve_TRLanczos_GSVD;
    2398         102 :   svd->ops->solveh         = SVDSolve_TRLanczos_HSVD;
    2399         102 :   svd->ops->destroy        = SVDDestroy_TRLanczos;
    2400         102 :   svd->ops->reset          = SVDReset_TRLanczos;
    2401         102 :   svd->ops->setfromoptions = SVDSetFromOptions_TRLanczos;
    2402         102 :   svd->ops->view           = SVDView_TRLanczos;
    2403         102 :   svd->ops->setdstype      = SVDSetDSType_TRLanczos;
    2404         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetOneSide_C",SVDTRLanczosSetOneSide_TRLanczos));
    2405         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetOneSide_C",SVDTRLanczosGetOneSide_TRLanczos));
    2406         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetGBidiag_C",SVDTRLanczosSetGBidiag_TRLanczos));
    2407         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetGBidiag_C",SVDTRLanczosGetGBidiag_TRLanczos));
    2408         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetKSP_C",SVDTRLanczosSetKSP_TRLanczos));
    2409         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetKSP_C",SVDTRLanczosGetKSP_TRLanczos));
    2410         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetRestart_C",SVDTRLanczosSetRestart_TRLanczos));
    2411         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetRestart_C",SVDTRLanczosGetRestart_TRLanczos));
    2412         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetLocking_C",SVDTRLanczosSetLocking_TRLanczos));
    2413         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetLocking_C",SVDTRLanczosGetLocking_TRLanczos));
    2414         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetExplicitMatrix_C",SVDTRLanczosSetExplicitMatrix_TRLanczos));
    2415         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetExplicitMatrix_C",SVDTRLanczosGetExplicitMatrix_TRLanczos));
    2416         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosSetScale_C",SVDTRLanczosSetScale_TRLanczos));
    2417         102 :   PetscCall(PetscObjectComposeFunction((PetscObject)svd,"SVDTRLanczosGetScale_C",SVDTRLanczosGetScale_TRLanczos));
    2418         102 :   PetscFunctionReturn(PETSC_SUCCESS);
    2419             : }

Generated by: LCOV version 1.14