Date: 2016-03-29T14:58:05+00:00

Actual source code: dvdupdatev.c
slepc-3.6.3 2016-03-29
Report Typos and Errors

      1: /*
      2:   SLEPc eigensolver: "davidson"

      4:   Step: test for restarting, updateV, restartV

      6:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      7:    SLEPc - Scalable Library for Eigenvalue Problem Computations
      8:    Copyright (c) 2002-2015, Universitat Politecnica de Valencia, Spain

     10:    This file is part of SLEPc.

     12:    SLEPc is free software: you can redistribute it and/or modify it under  the
     13:    terms of version 3 of the GNU Lesser General Public License as published by
     14:    the Free Software Foundation.

     16:    SLEPc  is  distributed in the hope that it will be useful, but WITHOUT  ANY
     17:    WARRANTY;  without even the implied warranty of MERCHANTABILITY or  FITNESS
     18:    FOR  A  PARTICULAR PURPOSE. See the GNU Lesser General Public  License  for
     19:    more details.

     21:    You  should have received a copy of the GNU Lesser General  Public  License
     22:    along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
     23:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     24: */

     26:  #include davidson.h
     27: #include <slepc/private/dsimpl.h>

     29: typedef struct {
     30:   PetscInt          min_size_V;        /* restart with this number of eigenvectors */
     31:   PetscInt          plusk;             /* at restart, save plusk vectors from last iteration */
     32:   PetscInt          mpd;               /* max size of the searching subspace */
     33:   void              *old_updateV_data; /* old updateV data */
     34:   isRestarting_type old_isRestarting;  /* old isRestarting */
     35:   Mat               oldU;              /* previous projected right igenvectors */
     36:   Mat               oldV;              /* previous projected left eigenvectors */
     37:   PetscInt          size_oldU;         /* size of oldU */
     38:   PetscBool         allResiduals;      /* if computing all the residuals */
     39: } dvdManagV_basic;

     43: static PetscErrorCode dvd_updateV_start(dvdDashboard *d)
     44: {
     45:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
     46:   PetscInt        i;

     49:   for (i=0;i<d->eps->ncv;i++) d->eigi[i] = 0.0;
     50:   d->nR = d->real_nR;
     51:   for (i=0;i<d->eps->ncv;i++) d->nR[i] = PETSC_MAX_REAL;
     52:   d->nX = d->real_nX;
     53:   for (i=0;i<d->eps->ncv;i++) d->errest[i] = PETSC_MAX_REAL;
     54:   data->size_oldU = 0;
     55:   d->nconv = 0;
     56:   d->npreconv = 0;
     57:   d->V_tra_s = d->V_tra_e = d->V_new_s = d->V_new_e = 0;
     58:   d->size_D = 0;
     59:   return(0);
     60: }

     64: static PetscErrorCode dvd_isrestarting_fullV(dvdDashboard *d,PetscBool *r)
     65: {
     66:   PetscErrorCode  ierr;
     67:   PetscInt        l,k;
     68:   PetscBool       restart;
     69:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

     72:   BVGetActiveColumns(d->eps->V,&l,&k);
     73:   restart = (k+2 > d->eps->ncv)? PETSC_TRUE: PETSC_FALSE;

     75:   /* Check old isRestarting function */
     76:   if (!restart && data->old_isRestarting) {
     77:     data->old_isRestarting(d,&restart);
     78:   }
     79:   *r = restart;
     80:   return(0);
     81: }

     85: static PetscErrorCode dvd_managementV_basic_d(dvdDashboard *d)
     86: {
     87:   PetscErrorCode  ierr;
     88:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

     91:   /* Restore changes in dvdDashboard */
     92:   d->updateV_data = data->old_updateV_data;

     94:   /* Free local data */
     95:   if (data->oldU) { MatDestroy(&data->oldU); }
     96:   if (data->oldV) { MatDestroy(&data->oldV); }
     97:   PetscFree(d->real_nR);
     98:   PetscFree(d->real_nX);
     99:   PetscFree(data);
    100:   return(0);
    101: }

    105: static PetscErrorCode dvd_updateV_conv_gen(dvdDashboard *d)
    106: {
    107:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    108:   PetscInt        npreconv,cMT,cMTX,lV,kV,nV;
    109:   PetscErrorCode  ierr;
    110:   Mat             Q;
    111: #if !defined(PETSC_USE_COMPLEX)
    112:   PetscInt        i;
    113: #endif

    116:   npreconv = d->npreconv;
    117:   /* Constrains the converged pairs to nev */
    118: #if !defined(PETSC_USE_COMPLEX)
    119:   /* Tries to maintain together conjugate eigenpairs */
    120:   for (i=0; (i + (d->eigi[i]!=0.0?1:0) < npreconv) && (d->nconv + i < d->nev); i+= (d->eigi[i]!=0.0?2:1));
    121:   npreconv = i;
    122: #else
    123:   npreconv = PetscMax(PetscMin(d->nev-d->nconv,npreconv),0);
    124: #endif
    125:   /* Quick exit */
    126:   if (npreconv == 0) return(0);

    128:   BVGetActiveColumns(d->eps->V,&lV,&kV);
    129:   nV  = kV - lV;
    130:   cMT = nV - npreconv;
    131:   /* Harmonics restarts wiht right eigenvectors, and other with the left ones.
    132:      If the problem is standard or hermitian, left and right vectors are the same */
    133:   if (!(d->W||DVD_IS(d->sEP,DVD_EP_STD)||DVD_IS(d->sEP,DVD_EP_HERMITIAN))) {
    134:     /* ps.Q <- [ps.Q(0:npreconv-1) ps.Z(npreconv:size_H-1)] */
    135:     DSGetMat(d->eps->ds,DS_MAT_Q,&Q);
    136:     DSCopyMat(d->eps->ds,DS_MAT_Z,0,npreconv,Q,0,npreconv,nV,cMT,PETSC_TRUE);
    137:     DSRestoreMat(d->eps->ds,DS_MAT_Q,&Q);
    138:   }
    139:   if (DVD_IS(d->sEP,DVD_EP_INDEFINITE)) {
    140:     DSPseudoOrthogonalize(d->eps->ds,DS_MAT_Q,nV,d->nBds,&cMTX,d->nBds);
    141:   } else {
    142:     DSOrthogonalize(d->eps->ds,DS_MAT_Q,nV,&cMTX);
    143:   }
    144:   cMT = cMTX - npreconv;

    146:   if (d->W) {
    147:     DSOrthogonalize(d->eps->ds,DS_MAT_Z,nV,&cMTX);
    148:     cMT = PetscMin(cMT,cMTX - npreconv);
    149:   }

    151:   /* Lock the converged pairs */
    152:   d->eigr+= npreconv;
    153: #if !defined(PETSC_USE_COMPLEX)
    154:   if (d->eigi) d->eigi+= npreconv;
    155: #endif
    156:   d->nconv+= npreconv;
    157:   d->errest+= npreconv;
    158:   /* Notify the changes in V and update the other subspaces */
    159:   d->V_tra_s = npreconv;          d->V_tra_e = nV;
    160:   d->V_new_s = cMT;               d->V_new_e = d->V_new_s;
    161:   /* Remove oldU */
    162:   data->size_oldU = 0;

    164:   d->npreconv-= npreconv;
    165:   return(0);
    166: }

    170: static PetscErrorCode dvd_updateV_restart_gen(dvdDashboard *d)
    171: {
    172:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    173:   PetscInt        lV,kV,nV,size_plusk,size_X,cMTX,cMTY;
    174:   Mat             Q;
    175:   PetscErrorCode  ierr;

    178:   /* Select size_X desired pairs from V */
    179:   BVGetActiveColumns(d->eps->V,&lV,&kV);
    180:   nV = kV - lV;
    181:   size_X = PetscMin(data->min_size_V,nV);

    183:   /* Add plusk eigenvectors from the previous iteration */
    184:   size_plusk = PetscMax(0,PetscMin(PetscMin(data->plusk,data->size_oldU),d->eps->ncv - size_X));

    186:   d->size_MT = nV;
    187:   /* ps.Q <- orth([pX(0:size_X-1) [oldU(0:size_plusk-1); 0] ]) */
    188:   /* Harmonics restarts wiht right eigenvectors, and other with the left ones.
    189:      If the problem is standard or hermitian, left and right vectors are the same */
    190:   if (!(d->W||DVD_IS(d->sEP,DVD_EP_STD)||DVD_IS(d->sEP,DVD_EP_HERMITIAN))) {
    191:     DSGetMat(d->eps->ds,DS_MAT_Q,&Q);
    192:     DSCopyMat(d->eps->ds,DS_MAT_Z,0,0,Q,0,0,nV,size_X,PETSC_TRUE);
    193:     DSRestoreMat(d->eps->ds,DS_MAT_Q,&Q);
    194:   }
    195:   if (size_plusk > 0 && DVD_IS(d->sEP,DVD_EP_INDEFINITE)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Unsupported plusk>0 in indefinite eigenvalue problems");
    196:   if (size_plusk > 0) {
    197:     DSCopyMat(d->eps->ds,DS_MAT_Q,0,size_X,data->oldU,0,0,nV,size_plusk,PETSC_FALSE);
    198:   }
    199:   if (DVD_IS(d->sEP,DVD_EP_INDEFINITE)) {
    200:     DSPseudoOrthogonalize(d->eps->ds,DS_MAT_Q,size_X,d->nBds,&cMTX,d->nBds);
    201:   } else {
    202:     DSOrthogonalize(d->eps->ds,DS_MAT_Q,size_X+size_plusk,&cMTX);
    203:   }

    205:   if (d->W && size_plusk > 0) {
    206:     /* ps.Z <- orth([ps.Z(0:size_X-1) [oldV(0:size_plusk-1); 0] ]) */
    207:     DSCopyMat(d->eps->ds,DS_MAT_Z,0,size_X,data->oldV,0,0,nV,size_plusk,PETSC_FALSE);
    208:     DSOrthogonalize(d->eps->ds,DS_MAT_Z,size_X+size_plusk,&cMTY);
    209:     cMTX = PetscMin(cMTX, cMTY);
    210:   }

    212:   /* Notify the changes in V and update the other subspaces */
    213:   d->V_tra_s = 0;                     d->V_tra_e = cMTX;
    214:   d->V_new_s = d->V_tra_e;            d->V_new_e = d->V_new_s;

    216:   /* Remove oldU */
    217:   data->size_oldU = 0;

    219:   /* Remove npreconv */
    220:   d->npreconv = 0;
    221:   return(0);
    222: }

    226: static PetscErrorCode dvd_updateV_testConv(dvdDashboard *d,PetscInt s,PetscInt pre,PetscInt e,PetscInt *nConv)
    227: {
    228:   PetscInt        i,j,b;
    229:   PetscReal       norm;
    230:   PetscErrorCode  ierr;
    231:   PetscBool       conv, c;
    232:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;

    235:   if (nConv) *nConv = s;
    236:   for (i=s,conv=PETSC_TRUE;(conv || data->allResiduals) && (i < e);i+=b) {
    237: #if !defined(PETSC_USE_COMPLEX)
    238:     b = d->eigi[i]!=0.0?2:1;
    239: #else
    240:     b = 1;
    241: #endif
    242:     if (i+b-1 >= pre) {
    243:       d->calcpairs_residual(d,i,i+b);
    244:     }
    245:     /* Test the Schur vector */
    246:     for (j=0,c=PETSC_TRUE;j<b && c;j++) {
    247:       norm = d->nR[i+j]/d->nX[i+j];
    248:       c = d->testConv(d,d->eigr[i+j],d->eigi[i+j],norm,&d->errest[i+j]);
    249:     }
    250:     if (conv && c) { if (nConv) *nConv = i+b; }
    251:     else conv = PETSC_FALSE;
    252:   }
    253:   pre = PetscMax(pre,i);

    255: #if !defined(PETSC_USE_COMPLEX)
    256:   /* Enforce converged conjugate complex eigenpairs */
    257:   if (nConv) {
    258:     for (j=0;j<*nConv;j++) if (d->eigi[j] != 0.0) j++;
    259:     if (j>*nConv) (*nConv)--;
    260:   }
    261: #endif
    262:   for (i=pre;i<e;i++) d->errest[i] = d->nR[i] = PETSC_MAX_REAL;
    263:   return(0);
    264: }

    268: static PetscErrorCode dvd_updateV_update_gen(dvdDashboard *d)
    269: {
    270:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    271:   PetscInt        size_D,s,lV,kV,nV;
    272:   PetscErrorCode  ierr;

    275:   /* Select the desired pairs */
    276:   BVGetActiveColumns(d->eps->V,&lV,&kV);
    277:   nV = kV - lV;
    278:   size_D = PetscMin(PetscMin(PetscMin(d->bs,nV),d->eps->ncv-nV),nV);
    279:   if (size_D == 0) {
    280:     d->initV(d);
    281:     d->calcPairs(d);
    282:   }

    284:   /* Fill V with D */
    285:   d->improveX(d,0,size_D,&size_D);

    287:   /* If D is empty, exit */
    288:   d->size_D = size_D;
    289:   if (size_D == 0) return(0);

    291:   /* Get the residual of all pairs */
    292: #if !defined(PETSC_USE_COMPLEX)
    293:   s = (d->eigi[0]!=0.0)? 2: 1;
    294: #else
    295:   s = 1;
    296: #endif
    297:   BVGetActiveColumns(d->eps->V,&lV,&kV);
    298:   nV = kV - lV;
    299:   dvd_updateV_testConv(d,s,s,data->allResiduals?nV:size_D,NULL);

    301:   /* Notify the changes in V */
    302:   d->V_tra_s = 0;                 d->V_tra_e = 0;
    303:   d->V_new_s = nV;                d->V_new_e = nV+size_D;

    305:   /* Save the projected eigenvectors */
    306:   if (data->plusk > 0) {
    307:     MatZeroEntries(data->oldU);
    308:     data->size_oldU = nV;
    309:     DSCopyMat(d->eps->ds,DS_MAT_Q,0,0,data->oldU,0,0,nV,nV,PETSC_TRUE);
    310:     if (d->W) {
    311:       MatZeroEntries(data->oldV);
    312:       DSCopyMat(d->eps->ds,DS_MAT_Z,0,0,data->oldV,0,0,nV,nV,PETSC_TRUE);
    313:     }
    314:   }
    315:   return(0);
    316: }

    320: static PetscErrorCode dvd_updateV_extrapol(dvdDashboard *d)
    321: {
    322:   dvdManagV_basic *data = (dvdManagV_basic*)d->updateV_data;
    323:   PetscInt        i;
    324:   PetscBool       restart;
    325:   PetscErrorCode  ierr;

    328:   /* TODO: restrict select pairs to each case */
    329:   d->calcpairs_selectPairs(d, data->min_size_V);

    331:   /* If the subspaces doesn't need restart, add new vector */
    332:   d->isRestarting(d,&restart);
    333:   if (!restart) {
    334:     d->size_D = 0;
    335:     dvd_updateV_update_gen(d);

    337:     /* If some vector were add, exit */
    338:     if (d->size_D > 0) return(0);
    339:   }

    341:   /* If some eigenpairs were converged, lock them  */
    342:   if (d->npreconv > 0) {
    343:     i = d->npreconv;
    344:     dvd_updateV_conv_gen(d);

    346:     /* If some eigenpair was locked, exit */
    347:     if (i > d->npreconv) return(0);
    348:   }

    350:   /* Else, a restarting is performed */
    351:   dvd_updateV_restart_gen(d);
    352:   return(0);
    353: }

    357: PetscErrorCode dvd_managementV_basic(dvdDashboard *d,dvdBlackboard *b,PetscInt bs,PetscInt mpd,PetscInt min_size_V,PetscInt plusk,PetscBool harm,PetscBool allResiduals)
    358: {
    359:   PetscErrorCode  ierr;
    360:   dvdManagV_basic *data;
    361: #if !defined(PETSC_USE_COMPLEX)
    362:   PetscBool       her_probl,std_probl;
    363: #endif

    366:   /* Setting configuration constrains */
    367: #if !defined(PETSC_USE_COMPLEX)
    368:   /* if the last converged eigenvalue is complex its conjugate pair is also
    369:      converged */
    370:   her_probl = DVD_IS(d->sEP,DVD_EP_HERMITIAN)? PETSC_TRUE: PETSC_FALSE;
    371:   std_probl = DVD_IS(d->sEP,DVD_EP_STD)? PETSC_TRUE: PETSC_FALSE;
    372:   b->max_size_X = PetscMax(b->max_size_X,bs+((her_probl && std_probl)?0:1));
    373: #else
    374:   b->max_size_X = PetscMax(b->max_size_X,bs);
    375: #endif

    377:   b->max_size_V = PetscMax(b->max_size_V,mpd);
    378:   min_size_V = PetscMin(min_size_V,mpd-bs);
    379:   b->size_V = PetscMax(b->size_V,b->max_size_V+b->max_size_P+b->max_nev);
    380:   b->max_size_oldX = plusk;

    382:   /* Setup the step */
    383:   if (b->state >= DVD_STATE_CONF) {
    384:     PetscNewLog(d->eps,&data);
    385:     data->mpd = b->max_size_V;
    386:     data->min_size_V = min_size_V;
    387:     d->bs = bs;
    388:     data->plusk = plusk;
    389:     data->allResiduals = allResiduals;

    391:     d->eigr = d->eps->eigr;
    392:     d->eigi = d->eps->eigi;
    393:     d->errest = d->eps->errest;
    394:     PetscMalloc1(d->eps->ncv,&d->real_nR);
    395:     PetscMalloc1(d->eps->ncv,&d->real_nX);
    396:     if (plusk > 0) { MatCreateSeqDense(PETSC_COMM_SELF,d->eps->ncv,d->eps->ncv,NULL,&data->oldU); }
    397:     else data->oldU = NULL;
    398:     if (harm && plusk>0) { MatCreateSeqDense(PETSC_COMM_SELF,d->eps->ncv,d->eps->ncv,NULL,&data->oldV); }
    399:     else data->oldV = NULL;

    401:     data->old_updateV_data = d->updateV_data;
    402:     d->updateV_data = data;
    403:     data->old_isRestarting = d->isRestarting;
    404:     d->isRestarting = dvd_isrestarting_fullV;
    405:     d->updateV = dvd_updateV_extrapol;
    406:     d->preTestConv = dvd_updateV_testConv;
    407:     EPSDavidsonFLAdd(&d->startList,dvd_updateV_start);
    408:     EPSDavidsonFLAdd(&d->destroyList,dvd_managementV_basic_d);
    409:   }
    410:   return(0);
    411: }