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

Generated by: LCOV version 1.14