Date: 2021-02-01T14:41:46+00:00

Actual source code: bvglobal.c
slepc-3.14.2 2021-02-01
Report Typos and Errors

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

      6:    This file is part of SLEPc.
      7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
      8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      9: */
     10: /*
     11:    BV operations involving global communication
     12: */

     14: #include <slepc/private/bvimpl.h>

     16: /*
     17:   BVDot for the particular case of non-standard inner product with
     18:   matrix B, which is assumed to be symmetric (or complex Hermitian)
     19: */
     20: PETSC_STATIC_INLINE PetscErrorCode BVDot_Private(BV X,BV Y,Mat M)
     21: {
     23:   PetscObjectId  idx,idy;
     24:   PetscInt       i,j,jend,m;
     25:   PetscScalar    *marray;
     26:   PetscBool      symm=PETSC_FALSE;
     27:   Mat            B;
     28:   Vec            z;

     31:   BVCheckOp(Y,1,dotvec);
     32:   MatGetSize(M,&m,NULL);
     33:   MatDenseGetArray(M,&marray);
     34:   PetscObjectGetId((PetscObject)X,&idx);
     35:   PetscObjectGetId((PetscObject)Y,&idy);
     36:   B = Y->matrix;
     37:   Y->matrix = NULL;
     38:   if (idx==idy) symm=PETSC_TRUE;  /* M=X'BX is symmetric */
     39:   jend = X->k;
     40:   for (j=X->l;j<jend;j++) {
     41:     if (symm) Y->k = j+1;
     42:     BVGetColumn(X->cached,j,&z);
     43:     (*Y->ops->dotvec)(Y,z,marray+j*m+Y->l);
     44:     BVRestoreColumn(X->cached,j,&z);
     45:     if (symm) {
     46:       for (i=X->l;i<j;i++)
     47:         marray[j+i*m] = PetscConj(marray[i+j*m]);
     48:     }
     49:   }
     50:   MatDenseRestoreArray(M,&marray);
     51:   Y->matrix = B;
     52:   return(0);
     53: }

     55: /*@
     56:    BVDot - Computes the 'block-dot' product of two basis vectors objects.

     58:    Collective on X

     60:    Input Parameters:
     61: +  X, Y - basis vectors
     62: -  M    - Mat object where the result must be placed

     64:    Output Parameter:
     65: .  M    - the resulting matrix

     67:    Notes:
     68:    This is the generalization of VecDot() for a collection of vectors, M = Y^H*X.
     69:    The result is a matrix M whose entry m_ij is equal to y_i^H x_j (where y_i^H
     70:    denotes the conjugate transpose of y_i).

     72:    If a non-standard inner product has been specified with BVSetMatrix(),
     73:    then the result is M = Y^H*B*X. In this case, both X and Y must have
     74:    the same associated matrix.

     76:    On entry, M must be a sequential dense Mat with dimensions m,n at least, where
     77:    m is the number of active columns of Y and n is the number of active columns of X.
     78:    Only rows (resp. columns) of M starting from ly (resp. lx) are computed,
     79:    where ly (resp. lx) is the number of leading columns of Y (resp. X).

     81:    X and Y need not be different objects.

     83:    Level: intermediate

     85: .seealso: BVDotVec(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
     86: @*/
     87: PetscErrorCode BVDot(BV X,BV Y,Mat M)
     88: {
     90:   PetscBool      match;
     91:   PetscInt       m,n;

     98:   BVCheckSizes(X,1);
    100:   BVCheckSizes(Y,2);
    103:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
    104:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");

    106:   MatGetSize(M,&m,&n);
    107:   if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D rows, should have at least %D",m,Y->k);
    108:   if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D columns, should have at least %D",n,X->k);
    109:   if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
    110:   if (X->matrix!=Y->matrix) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
    111:   if (X->l==X->k || Y->l==Y->k) return(0);

    113:   PetscLogEventBegin(BV_Dot,X,Y,0,0);
    114:   if (X->matrix) { /* non-standard inner product */
    115:     /* compute BX first */
    116:     BV_IPMatMultBV(X);
    117:     if (X->vmm==BV_MATMULT_VECS) {
    118:       /* perform computation column by column */
    119:       BVDot_Private(X,Y,M);
    120:     } else {
    121:       (*X->ops->dot)(X->cached,Y,M);
    122:     }
    123:   } else {
    124:     (*X->ops->dot)(X,Y,M);
    125:   }
    126:   PetscLogEventEnd(BV_Dot,X,Y,0,0);
    127:   return(0);
    128: }

    130: /*@
    131:    BVDotVec - Computes multiple dot products of a vector against all the
    132:    column vectors of a BV.

    134:    Collective on X

    136:    Input Parameters:
    137: +  X - basis vectors
    138: -  y - a vector

    140:    Output Parameter:
    141: .  m - an array where the result must be placed

    143:    Notes:
    144:    This is analogue to VecMDot(), but using BV to represent a collection
    145:    of vectors. The result is m = X^H*y, so m_i is equal to x_j^H y. Note
    146:    that here X is transposed as opposed to BVDot().

    148:    If a non-standard inner product has been specified with BVSetMatrix(),
    149:    then the result is m = X^H*B*y.

    151:    The length of array m must be equal to the number of active columns of X
    152:    minus the number of leading columns, i.e. the first entry of m is the
    153:    product of the first non-leading column with y.

    155:    Level: intermediate

    157: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
    158: @*/
    159: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar m[])
    160: {
    162:   PetscInt       n;

    168:   BVCheckSizes(X,1);
    169:   BVCheckOp(X,1,dotvec);

    173:   VecGetLocalSize(y,&n);
    174:   if (X->n!=n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

    176:   PetscLogEventBegin(BV_DotVec,X,y,0,0);
    177:   (*X->ops->dotvec)(X,y,m);
    178:   PetscLogEventEnd(BV_DotVec,X,y,0,0);
    179:   return(0);
    180: }

    182: /*@
    183:    BVDotVecBegin - Starts a split phase dot product computation.

    185:    Input Parameters:
    186: +  X - basis vectors
    187: .  y - a vector
    188: -  m - an array where the result will go (can be NULL)

    190:    Note:
    191:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

    193:    Level: advanced

    195: .seealso: BVDotVecEnd(), BVDotVec()
    196: @*/
    197: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)
    198: {
    199:   PetscErrorCode      ierr;
    200:   PetscInt            i,n,nv;
    201:   PetscSplitReduction *sr;
    202:   MPI_Comm            comm;

    208:   BVCheckSizes(X,1);

    212:   VecGetLocalSize(y,&n);
    213:   if (X->n!=n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

    215:   if (X->ops->dotvec_begin) {
    216:     (*X->ops->dotvec_begin)(X,y,m);
    217:   } else {
    218:     BVCheckOp(X,1,dotvec_local);
    219:     nv = X->k-X->l;
    220:     PetscObjectGetComm((PetscObject)X,&comm);
    221:     PetscSplitReductionGet(comm,&sr);
    222:     if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    223:     for (i=0;i<nv;i++) {
    224:       if (sr->numopsbegin+i >= sr->maxops) {
    225:         PetscSplitReductionExtend(sr);
    226:       }
    227:       sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
    228:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
    229:     }
    230:     PetscLogEventBegin(BV_DotVec,X,y,0,0);
    231:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
    232:     sr->numopsbegin += nv;
    233:     PetscLogEventEnd(BV_DotVec,X,y,0,0);
    234:   }
    235:   return(0);
    236: }

    238: /*@
    239:    BVDotVecEnd - Ends a split phase dot product computation.

    241:    Input Parameters:
    242: +  X - basis vectors
    243: .  y - a vector
    244: -  m - an array where the result will go

    246:    Note:
    247:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

    249:    Level: advanced

    251: .seealso: BVDotVecBegin(), BVDotVec()
    252: @*/
    253: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)
    254: {
    255:   PetscErrorCode      ierr;
    256:   PetscInt            i,nv;
    257:   PetscSplitReduction *sr;
    258:   MPI_Comm            comm;

    263:   BVCheckSizes(X,1);

    265:   if (X->ops->dotvec_end) {
    266:     (*X->ops->dotvec_end)(X,y,m);
    267:   } else {
    268:     nv = X->k-X->l;
    269:     PetscObjectGetComm((PetscObject)X,&comm);
    270:     PetscSplitReductionGet(comm,&sr);
    271:     PetscSplitReductionEnd(sr);

    273:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
    274:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
    275:     if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_SUM) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
    276:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

    278:     /* Finished getting all the results so reset to no outstanding requests */
    279:     if (sr->numopsend == sr->numopsbegin) {
    280:       sr->state       = STATE_BEGIN;
    281:       sr->numopsend   = 0;
    282:       sr->numopsbegin = 0;
    283:     }
    284:   }
    285:   return(0);
    286: }

    288: /*@
    289:    BVDotColumn - Computes multiple dot products of a column against all the
    290:    previous columns of a BV.

    292:    Collective on X

    294:    Input Parameters:
    295: +  X - basis vectors
    296: -  j - the column index

    298:    Output Parameter:
    299: .  q - an array where the result must be placed

    301:    Notes:
    302:    This operation is equivalent to BVDotVec() but it uses column j of X
    303:    rather than taking a Vec as an argument. The number of active columns of
    304:    X is set to j before the computation, and restored afterwards.
    305:    If X has leading columns specified, then these columns do not participate
    306:    in the computation. Therefore, the length of array q must be equal to j
    307:    minus the number of leading columns.

    309:    Developer Notes:
    310:    If q is NULL, then the result is written in position nc+l of the internal
    311:    buffer vector, see BVGetBufferVec().

    313:    Level: advanced

    315: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
    316: @*/
    317: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *q)
    318: {
    320:   PetscInt       ksave;
    321:   Vec            y;

    327:   BVCheckSizes(X,1);
    328:   BVCheckOp(X,1,dotvec);

    330:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    331:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);

    333:   PetscLogEventBegin(BV_DotVec,X,0,0,0);
    334:   ksave = X->k;
    335:   X->k = j;
    336:   if (!q && !X->buffer) { BVGetBufferVec(X,&X->buffer); }
    337:   BVGetColumn(X,j,&y);
    338:   (*X->ops->dotvec)(X,y,q);
    339:   BVRestoreColumn(X,j,&y);
    340:   X->k = ksave;
    341:   PetscLogEventEnd(BV_DotVec,X,0,0,0);
    342:   return(0);
    343: }

    345: /*@
    346:    BVDotColumnBegin - Starts a split phase dot product computation.

    348:    Input Parameters:
    349: +  X - basis vectors
    350: -  j - the column index
    351: -  m - an array where the result will go (can be NULL)

    353:    Note:
    354:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

    356:    Level: advanced

    358: .seealso: BVDotColumnEnd(), BVDotColumn()
    359: @*/
    360: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)
    361: {
    362:   PetscErrorCode      ierr;
    363:   PetscInt            i,nv,ksave;
    364:   PetscSplitReduction *sr;
    365:   MPI_Comm            comm;
    366:   Vec                 y;

    372:   BVCheckSizes(X,1);

    374:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    375:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
    376:   ksave = X->k;
    377:   X->k = j;
    378:   BVGetColumn(X,j,&y);

    380:   if (X->ops->dotvec_begin) {
    381:     (*X->ops->dotvec_begin)(X,y,m);
    382:   } else {
    383:     BVCheckOp(X,1,dotvec_local);
    384:     nv = X->k-X->l;
    385:     PetscObjectGetComm((PetscObject)X,&comm);
    386:     PetscSplitReductionGet(comm,&sr);
    387:     if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    388:     for (i=0;i<nv;i++) {
    389:       if (sr->numopsbegin+i >= sr->maxops) {
    390:         PetscSplitReductionExtend(sr);
    391:       }
    392:       sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
    393:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
    394:     }
    395:     PetscLogEventBegin(BV_DotVec,X,0,0,0);
    396:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
    397:     sr->numopsbegin += nv;
    398:     PetscLogEventEnd(BV_DotVec,X,0,0,0);
    399:   }
    400:   BVRestoreColumn(X,j,&y);
    401:   X->k = ksave;
    402:   return(0);
    403: }

    405: /*@
    406:    BVDotColumnEnd - Ends a split phase dot product computation.

    408:    Input Parameters:
    409: +  X - basis vectors
    410: .  j - the column index
    411: -  m - an array where the result will go

    413:    Notes:
    414:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

    416:    Level: advanced

    418: .seealso: BVDotColumnBegin(), BVDotColumn()
    419: @*/
    420: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)
    421: {
    422:   PetscErrorCode      ierr;
    423:   PetscInt            i,nv,ksave;
    424:   PetscSplitReduction *sr;
    425:   MPI_Comm            comm;
    426:   Vec                 y;

    432:   BVCheckSizes(X,1);

    434:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
    435:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
    436:   ksave = X->k;
    437:   X->k = j;

    439:   if (X->ops->dotvec_end) {
    440:     BVGetColumn(X,j,&y);
    441:     (*X->ops->dotvec_end)(X,y,m);
    442:     BVRestoreColumn(X,j,&y);
    443:   } else {
    444:     nv = X->k-X->l;
    445:     PetscObjectGetComm((PetscObject)X,&comm);
    446:     PetscSplitReductionGet(comm,&sr);
    447:     PetscSplitReductionEnd(sr);

    449:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
    450:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
    451:     if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_SUM) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
    452:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

    454:     /* Finished getting all the results so reset to no outstanding requests */
    455:     if (sr->numopsend == sr->numopsbegin) {
    456:       sr->state       = STATE_BEGIN;
    457:       sr->numopsend   = 0;
    458:       sr->numopsbegin = 0;
    459:     }
    460:   }
    461:   X->k = ksave;
    462:   return(0);
    463: }

    465: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)
    466: {
    468:   PetscScalar    p;

    471:   BV_IPMatMult(bv,z);
    472:   VecDot(bv->Bx,z,&p);
    473:   BV_SafeSqrt(bv,p,val);
    474:   return(0);
    475: }

    477: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)
    478: {
    480:   PetscScalar    p;

    483:   BV_IPMatMult(bv,z);
    484:   VecDotBegin(bv->Bx,z,&p);
    485:   return(0);
    486: }

    488: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)
    489: {
    491:   PetscScalar    p;

    494:   VecDotEnd(bv->Bx,z,&p);
    495:   BV_SafeSqrt(bv,p,val);
    496:   return(0);
    497: }

    499: /*@
    500:    BVNorm - Computes the matrix norm of the BV.

    502:    Collective on bv

    504:    Input Parameters:
    505: +  bv   - basis vectors
    506: -  type - the norm type

    508:    Output Parameter:
    509: .  val  - the norm

    511:    Notes:
    512:    All active columns (except the leading ones) are considered as a matrix.
    513:    The allowed norms are NORM_1, NORM_FROBENIUS, and NORM_INFINITY.

    515:    This operation fails if a non-standard inner product has been
    516:    specified with BVSetMatrix().

    518:    Level: intermediate

    520: .seealso: BVNormVec(), BVNormColumn(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
    521: @*/
    522: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)
    523: {

    531:   BVCheckSizes(bv,1);

    533:   if (type==NORM_2 || type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
    534:   if (bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");

    536:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
    537:   (*bv->ops->norm)(bv,-1,type,val);
    538:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
    539:   return(0);
    540: }

    542: /*@
    543:    BVNormVec - Computes the norm of a given vector.

    545:    Collective on bv

    547:    Input Parameters:
    548: +  bv   - basis vectors
    549: .  v    - the vector
    550: -  type - the norm type

    552:    Output Parameter:
    553: .  val  - the norm

    555:    Notes:
    556:    This is the analogue of BVNormColumn() but for a vector that is not in the BV.
    557:    If a non-standard inner product has been specified with BVSetMatrix(),
    558:    then the returned value is sqrt(v'*B*v), where B is the inner product
    559:    matrix (argument 'type' is ignored). Otherwise, VecNorm() is called.

    561:    Level: developer

    563: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
    564: @*/
    565: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)
    566: {
    568:   PetscInt       n;

    576:   BVCheckSizes(bv,1);

    580:   if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    582:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
    583:   if (bv->matrix) { /* non-standard inner product */
    584:     VecGetLocalSize(v,&n);
    585:     if (bv->n!=n) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
    586:     BVNorm_Private(bv,v,type,val);
    587:   } else {
    588:     VecNorm(v,type,val);
    589:   }
    590:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
    591:   return(0);
    592: }

    594: /*@
    595:    BVNormVecBegin - Starts a split phase norm computation.

    597:    Input Parameters:
    598: +  bv   - basis vectors
    599: .  v    - the vector
    600: .  type - the norm type
    601: -  val  - the norm

    603:    Note:
    604:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

    606:    Level: advanced

    608: .seealso: BVNormVecEnd(), BVNormVec()
    609: @*/
    610: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)
    611: {
    613:   PetscInt       n;

    621:   BVCheckSizes(bv,1);

    625:   if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    627:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
    628:   if (bv->matrix) { /* non-standard inner product */
    629:     VecGetLocalSize(v,&n);
    630:     if (bv->n!=n) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
    631:     BVNorm_Begin_Private(bv,v,type,val);
    632:   } else {
    633:     VecNormBegin(v,type,val);
    634:   }
    635:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
    636:   return(0);
    637: }

    639: /*@
    640:    BVNormVecEnd - Ends a split phase norm computation.

    642:    Input Parameters:
    643: +  bv   - basis vectors
    644: .  v    - the vector
    645: .  type - the norm type
    646: -  val  - the norm

    648:    Note:
    649:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

    651:    Level: advanced

    653: .seealso: BVNormVecBegin(), BVNormVec()
    654: @*/
    655: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)
    656: {

    664:   BVCheckSizes(bv,1);

    666:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    668:   if (bv->matrix) { /* non-standard inner product */
    669:     BVNorm_End_Private(bv,v,type,val);
    670:   } else {
    671:     VecNormEnd(v,type,val);
    672:   }
    673:   return(0);
    674: }

    676: /*@
    677:    BVNormColumn - Computes the vector norm of a selected column.

    679:    Collective on bv

    681:    Input Parameters:
    682: +  bv   - basis vectors
    683: .  j    - column number to be used
    684: -  type - the norm type

    686:    Output Parameter:
    687: .  val  - the norm

    689:    Notes:
    690:    The norm of V[j] is computed (NORM_1, NORM_2, or NORM_INFINITY).
    691:    If a non-standard inner product has been specified with BVSetMatrix(),
    692:    then the returned value is sqrt(V[j]'*B*V[j]),
    693:    where B is the inner product matrix (argument 'type' is ignored).

    695:    Level: intermediate

    697: .seealso: BVNorm(), BVNormVec(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
    698: @*/
    699: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)
    700: {
    702:   Vec            z;

    710:   BVCheckSizes(bv,1);

    712:   if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
    713:   if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    715:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
    716:   if (bv->matrix) { /* non-standard inner product */
    717:     BVGetColumn(bv,j,&z);
    718:     BVNorm_Private(bv,z,type,val);
    719:     BVRestoreColumn(bv,j,&z);
    720:   } else {
    721:     (*bv->ops->norm)(bv,j,type,val);
    722:   }
    723:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
    724:   return(0);
    725: }

    727: /*@
    728:    BVNormColumnBegin - Starts a split phase norm computation.

    730:    Input Parameters:
    731: +  bv   - basis vectors
    732: .  j    - column number to be used
    733: .  type - the norm type
    734: -  val  - the norm

    736:    Note:
    737:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

    739:    Level: advanced

    741: .seealso: BVNormColumnEnd(), BVNormColumn()
    742: @*/
    743: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)
    744: {
    745:   PetscErrorCode      ierr;
    746:   PetscSplitReduction *sr;
    747:   PetscReal           lresult;
    748:   MPI_Comm            comm;
    749:   Vec                 z;

    757:   BVCheckSizes(bv,1);

    759:   if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
    760:   if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    762:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
    763:   BVGetColumn(bv,j,&z);
    764:   if (bv->matrix) { /* non-standard inner product */
    765:     BVNorm_Begin_Private(bv,z,type,val);
    766:   } else if (bv->ops->norm_begin) {
    767:     (*bv->ops->norm_begin)(bv,j,type,val);
    768:   } else {
    769:     BVCheckOp(bv,1,norm_local);
    770:     PetscObjectGetComm((PetscObject)z,&comm);
    771:     PetscSplitReductionGet(comm,&sr);
    772:     if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
    773:     if (sr->numopsbegin >= sr->maxops) {
    774:       PetscSplitReductionExtend(sr);
    775:     }
    776:     sr->invecs[sr->numopsbegin] = (void*)bv;
    777:     (*bv->ops->norm_local)(bv,j,type,&lresult);
    778:     if (type == NORM_2) lresult = lresult*lresult;
    779:     if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_MAX;
    780:     else sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_SUM;
    781:     sr->lvalues[sr->numopsbegin++] = lresult;
    782:   }
    783:   BVRestoreColumn(bv,j,&z);
    784:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
    785:   return(0);
    786: }

    788: /*@
    789:    BVNormColumnEnd - Ends a split phase norm computation.

    791:    Input Parameters:
    792: +  bv   - basis vectors
    793: .  j    - column number to be used
    794: .  type - the norm type
    795: -  val  - the norm

    797:    Note:
    798:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

    800:    Level: advanced

    802: .seealso: BVNormColumnBegin(), BVNormColumn()
    803: @*/
    804: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)
    805: {
    806:   PetscErrorCode      ierr;
    807:   PetscSplitReduction *sr;
    808:   MPI_Comm            comm;
    809:   Vec                 z;

    817:   BVCheckSizes(bv,1);

    819:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

    821:   BVGetColumn(bv,j,&z);
    822:   if (bv->matrix) { /* non-standard inner product */
    823:     BVNorm_End_Private(bv,z,type,val);
    824:   } else if (bv->ops->norm_end) {
    825:     (*bv->ops->norm_end)(bv,j,type,val);
    826:   } else {
    827:     PetscObjectGetComm((PetscObject)z,&comm);
    828:     PetscSplitReductionGet(comm,&sr);
    829:     PetscSplitReductionEnd(sr);

    831:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
    832:     if ((void*)bv != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
    833:     if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_MAX && type == NORM_MAX) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
    834:     *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
    835:     if (type == NORM_2) *val = PetscSqrtReal(*val);
    836:     if (sr->numopsend == sr->numopsbegin) {
    837:       sr->state       = STATE_BEGIN;
    838:       sr->numopsend   = 0;
    839:       sr->numopsbegin = 0;
    840:     }
    841:   }
    842:   BVRestoreColumn(bv,j,&z);
    843:   return(0);
    844: }

    846: /*@
    847:    BVNormalize - Normalize all columns (starting from the leading ones).

    849:    Collective on bv

    851:    Input Parameters:
    852: +  bv   - basis vectors
    853: -  eigi - (optional) imaginary parts of eigenvalues

    855:    Notes:
    856:    On output, all columns will have unit norm. The normalization is done with
    857:    respect to the 2-norm, or to the B-norm if a non-standard inner product has
    858:    been specified with BVSetMatrix(), see BVNormColumn().

    860:    If the optional argument eigi is passed (taken into account only in real
    861:    scalars) it is interpreted as the imaginary parts of the eigenvalues and
    862:    the BV is supposed to contain the corresponding eigenvectors. Suppose the
    863:    first three values are eigi = { 0, alpha, -alpha }, then the first column
    864:    is normalized as usual, but the second and third ones are normalized assuming
    865:    that they contain the real and imaginary parts of a complex conjugate pair of
    866:    eigenvectors.

    868:    If eigi is passed, the inner-product matrix is ignored.

    870:    If there are leading columns, they are not modified (are assumed to be already
    871:    normalized).

    873:    Level: intermediate

    875: .seealso: BVNormColumn()
    876: @*/
    877: PetscErrorCode BVNormalize(BV bv,PetscScalar *eigi)
    878: {
    880:   PetscReal      norm;
    881:   PetscInt       i;
    882:   Vec            v;
    883: #if !defined(PETSC_USE_COMPLEX)
    884:   Vec            v1;
    885: #endif

    890:   BVCheckSizes(bv,1);

    892:   PetscLogEventBegin(BV_Normalize,bv,0,0,0);
    893:   if (bv->matrix && !eigi) {
    894:     for (i=bv->l;i<bv->k;i++) {
    895:       BVNormColumn(bv,i,NORM_2,&norm);
    896:       BVScaleColumn(bv,i,1.0/norm);
    897:     }
    898:   } else if (bv->ops->normalize) {
    899:     (*bv->ops->normalize)(bv,eigi);
    900:   } else {
    901:     for (i=bv->l;i<bv->k;i++) {
    902: #if !defined(PETSC_USE_COMPLEX)
    903:       if (eigi && eigi[i] != 0.0) {
    904:         BVGetColumn(bv,i,&v);
    905:         BVGetColumn(bv,i+1,&v1);
    906:         VecNormalizeComplex(v,v1,PETSC_TRUE,NULL);
    907:         BVRestoreColumn(bv,i,&v);
    908:         BVRestoreColumn(bv,i+1,&v1);
    909:         i++;
    910:       } else
    911: #endif
    912:       {
    913:         BVGetColumn(bv,i,&v);
    914:         VecNormalize(v,NULL);
    915:         BVRestoreColumn(bv,i,&v);
    916:       }
    917:     }
    918:   }
    919:   PetscLogEventEnd(BV_Normalize,bv,0,0,0);
    920:   PetscObjectStateIncrease((PetscObject)bv);
    921:   return(0);
    922: }

    924: /*
    925:   Compute Y^H*A*X: right part column by column (with MatMult) and bottom
    926:   part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
    927: */
    928: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
    929: {
    931:   PetscInt       i,j,lx,ly,kx,ky,ulim;
    932:   Vec            z,f;

    935:   lx = X->l; kx = X->k;
    936:   ly = Y->l; ky = Y->k;
    937:   BVCreateVec(X,&f);
    938:   BVCheckOp(Y,3,dotvec);
    939:   for (j=lx;j<kx;j++) {
    940:     BVGetColumn(X,j,&z);
    941:     MatMult(A,z,f);
    942:     BVRestoreColumn(X,j,&z);
    943:     ulim = PetscMin(ly+(j-lx)+1,ky);
    944:     Y->l = 0; Y->k = ulim;
    945:     (*Y->ops->dotvec)(Y,f,marray+j*ldm);
    946:     if (symm) {
    947:       for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
    948:     }
    949:   }
    950:   if (!symm) {
    951:     BVCheckOp(X,1,dotvec);
    952:     BV_AllocateCoeffs(Y);
    953:     for (j=ly;j<ky;j++) {
    954:       BVGetColumn(Y,j,&z);
    955:       MatMultHermitianTranspose(A,z,f);
    956:       BVRestoreColumn(Y,j,&z);
    957:       ulim = PetscMin(lx+(j-ly),kx);
    958:       X->l = 0; X->k = ulim;
    959:       (*X->ops->dotvec)(X,f,Y->h);
    960:       for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
    961:     }
    962:   }
    963:   VecDestroy(&f);
    964:   X->l = lx; X->k = kx;
    965:   Y->l = ly; Y->k = ky;
    966:   return(0);
    967: }

    969: /*
    970:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
    971:                    [ Y1'*W0 | Y1'*W1 ]
    972:   Allocates auxiliary BV to store the result of A*X, then one BVDot
    973:   call for top-right part and another one for bottom part;
    974:   result placed in marray[*,ldm]
    975: */
    976: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)
    977: {
    979:   PetscInt       j,lx,ly,kx,ky;
    980:   PetscScalar    *harray;
    981:   Mat            H;
    982:   BV             W;

    985:   lx = X->l; kx = X->k;
    986:   ly = Y->l; ky = Y->k;
    987:   BVDuplicate(X,&W);
    988:   X->l = 0; X->k = kx;
    989:   W->l = 0; W->k = kx;
    990:   BVMatMult(X,A,W);

    992:   /* top-right part, Y0'*AX1 */
    993:   if (ly>0 && lx<kx) {
    994:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
    995:     W->l = lx; W->k = kx;
    996:     Y->l = 0;  Y->k = ly;
    997:     BVDot(W,Y,H);
    998:     MatDenseGetArray(H,&harray);
    999:     for (j=lx;j<kx;j++) {
    1000:       PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
    1001:     }
    1002:     MatDenseRestoreArray(H,&harray);
    1003:     MatDestroy(&H);
    1004:   }

    1006:   /* bottom part, Y1'*AX */
    1007:   if (kx>0 && ly<ky) {
    1008:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
    1009:     W->l = 0;  W->k = kx;
    1010:     Y->l = ly; Y->k = ky;
    1011:     BVDot(W,Y,H);
    1012:     MatDenseGetArray(H,&harray);
    1013:     for (j=0;j<kx;j++) {
    1014:       PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
    1015:     }
    1016:     MatDenseRestoreArray(H,&harray);
    1017:     MatDestroy(&H);
    1018:   }
    1019:   BVDestroy(&W);
    1020:   X->l = lx; X->k = kx;
    1021:   Y->l = ly; Y->k = ky;
    1022:   return(0);
    1023: }

    1025: /*
    1026:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
    1027:                    [ Y1'*W0 | Y1'*W1 ]
    1028:   First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
    1029:   Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
    1030:   bottom-left part; result placed in marray[*,ldm]
    1031: */
    1032: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
    1033: {
    1035:   PetscInt       i,j,lx,ly,kx,ky;
    1036:   PetscScalar    *harray;
    1037:   Mat            H;
    1038:   BV             W;

    1041:   lx = X->l; kx = X->k;
    1042:   ly = Y->l; ky = Y->k;

    1044:   /* right part, Y'*AX1 */
    1045:   BVDuplicateResize(X,kx-lx,&W);
    1046:   if (ky>0 && lx<kx) {
    1047:     BVMatMult(X,A,W);
    1048:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
    1049:     Y->l = 0; Y->k = ky;
    1050:     BVDot(W,Y,H);
    1051:     MatDenseGetArray(H,&harray);
    1052:     for (j=lx;j<kx;j++) {
    1053:       PetscArraycpy(marray+j*ldm,harray+(j-lx)*ky,ky);
    1054:     }
    1055:     MatDenseRestoreArray(H,&harray);
    1056:     MatDestroy(&H);
    1057:   }

    1059:   /* bottom-left part, Y1'*AX0 */
    1060:   if (lx>0 && ly<ky) {
    1061:     if (symm) {
    1062:       /* do not compute, just copy symmetric elements */
    1063:       for (i=ly;i<ky;i++) {
    1064:         for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
    1065:       }
    1066:     } else {
    1067:       BVResize(W,ky-ly,PETSC_FALSE);
    1068:       Y->l = ly; Y->k = ky;
    1069:       BVMatMultHermitianTranspose(Y,A,W);
    1070:       MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
    1071:       X->l = 0; X->k = lx;
    1072:       BVDot(W,X,H);
    1073:       MatDenseGetArray(H,&harray);
    1074:       for (i=0;i<ky-ly;i++) {
    1075:         for (j=0;j<lx;j++) {
    1076:           marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
    1077:         }
    1078:       }
    1079:       MatDenseRestoreArray(H,&harray);
    1080:       MatDestroy(&H);
    1081:     }
    1082:   }
    1083:   BVDestroy(&W);
    1084:   X->l = lx; X->k = kx;
    1085:   Y->l = ly; Y->k = ky;
    1086:   return(0);
    1087: }

    1089: /*
    1090:   Compute Y^H*X = [   --   | Y0'*X1 ]     (X contains A*X):
    1091:                   [ Y1'*X0 | Y1'*X1 ]
    1092:   one BVDot call for top-right part and another one for bottom part;
    1093:   result placed in marray[*,ldm]
    1094: */
    1095: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)
    1096: {
    1098:   PetscInt       j,lx,ly,kx,ky;
    1099:   PetscScalar    *harray;
    1100:   Mat            H;

    1103:   lx = X->l; kx = X->k;
    1104:   ly = Y->l; ky = Y->k;

    1106:   /* top-right part, Y0'*X1 */
    1107:   if (ly>0 && lx<kx) {
    1108:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
    1109:     X->l = lx; X->k = kx;
    1110:     Y->l = 0;  Y->k = ly;
    1111:     BVDot(X,Y,H);
    1112:     MatDenseGetArray(H,&harray);
    1113:     for (j=lx;j<kx;j++) {
    1114:       PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
    1115:     }
    1116:     MatDenseRestoreArray(H,&harray);
    1117:     MatDestroy(&H);
    1118:   }

    1120:   /* bottom part, Y1'*X */
    1121:   if (kx>0 && ly<ky) {
    1122:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
    1123:     X->l = 0;  X->k = kx;
    1124:     Y->l = ly; Y->k = ky;
    1125:     BVDot(X,Y,H);
    1126:     MatDenseGetArray(H,&harray);
    1127:     for (j=0;j<kx;j++) {
    1128:       PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
    1129:     }
    1130:     MatDenseRestoreArray(H,&harray);
    1131:     MatDestroy(&H);
    1132:   }
    1133:   X->l = lx; X->k = kx;
    1134:   Y->l = ly; Y->k = ky;
    1135:   return(0);
    1136: }

    1138: /*@
    1139:    BVMatProject - Computes the projection of a matrix onto a subspace.

    1141:    Collective on X

    1143:    Input Parameters:
    1144: +  X - basis vectors
    1145: .  A - (optional) matrix to be projected
    1146: .  Y - left basis vectors, can be equal to X
    1147: -  M - Mat object where the result must be placed

    1149:    Output Parameter:
    1150: .  M - the resulting matrix

    1152:    Notes:
    1153:    If A=NULL, then it is assumed that X already contains A*X.

    1155:    This operation is similar to BVDot(), with important differences.
    1156:    The goal is to compute the matrix resulting from the orthogonal projection
    1157:    of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
    1158:    oblique projection onto X along Y, M = Y^H*A*X.

    1160:    A difference with respect to BVDot() is that the standard inner product
    1161:    is always used, regardless of a non-standard inner product being specified
    1162:    with BVSetMatrix().

    1164:    On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
    1165:    where ky (resp. kx) is the number of active columns of Y (resp. X).
    1166:    Another difference with respect to BVDot() is that all entries of M are
    1167:    computed except the leading ly,lx part, where ly (resp. lx) is the
    1168:    number of leading columns of Y (resp. X). Hence, the leading columns of
    1169:    X and Y participate in the computation, as opposed to BVDot().
    1170:    The leading part of M is assumed to be already available from previous
    1171:    computations.

    1173:    In the orthogonal projection case, Y=X, some computation can be saved if
    1174:    A is real symmetric (or complex Hermitian). In order to exploit this
    1175:    property, the symmetry flag of A must be set with MatSetOption().

    1177:    Level: intermediate

    1179: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
    1180: @*/
    1181: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
    1182: {
    1184:   PetscBool      match,set,flg,symm=PETSC_FALSE;
    1185:   PetscInt       m,n;
    1186:   PetscScalar    *marray;
    1187:   Mat            Xmatrix,Ymatrix;
    1188:   PetscObjectId  idx,idy;

    1196:   BVCheckSizes(X,1);
    1197:   if (A) {
    1200:   }
    1202:   BVCheckSizes(Y,3);
    1205:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
    1206:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");

    1208:   MatGetSize(M,&m,&n);
    1209:   if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D rows, should have at least %D",m,Y->k);
    1210:   if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D columns, should have at least %D",n,X->k);
    1211:   if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);

    1213:   PetscLogEventBegin(BV_MatProject,X,A,Y,0);
    1214:   /* temporarily set standard inner product */
    1215:   Xmatrix = X->matrix;
    1216:   Ymatrix = Y->matrix;
    1217:   X->matrix = Y->matrix = NULL;

    1219:   PetscObjectGetId((PetscObject)X,&idx);
    1220:   PetscObjectGetId((PetscObject)Y,&idy);
    1221:   if (A && idx==idy) { /* check symmetry of M=X'AX */
    1222:     MatIsHermitianKnown(A,&set,&flg);
    1223:     symm = set? flg: PETSC_FALSE;
    1224:   }

    1226:   MatDenseGetArray(M,&marray);

    1228:   if (A) {
    1229:     if (X->vmm==BV_MATMULT_VECS) {
    1230:       /* perform computation column by column */
    1231:       BVMatProject_Vec(X,A,Y,marray,m,symm);
    1232:     } else {
    1233:       /* use BVMatMult, then BVDot */
    1234:       MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
    1235:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
    1236:         BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
    1237:       } else {
    1238:         BVMatProject_MatMult(X,A,Y,marray,m);
    1239:       }
    1240:     }
    1241:   } else {
    1242:     /* use BVDot on subblocks */
    1243:     BVMatProject_Dot(X,Y,marray,m);
    1244:   }

    1246:   MatDenseRestoreArray(M,&marray);
    1247:   PetscLogEventEnd(BV_MatProject,X,A,Y,0);
    1248:   /* restore non-standard inner product */
    1249:   X->matrix = Xmatrix;
    1250:   Y->matrix = Ymatrix;
    1251:   return(0);
    1252: }