Actual source code: bvglobal.c

slepc-3.22.2 2024-12-02
Report Typos and Errors
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain

  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    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: static inline PetscErrorCode BVDot_Private(BV X,BV Y,Mat M)
 21: {
 22:   PetscObjectId  idx,idy;
 23:   PetscInt       i,j,jend,m;
 24:   PetscScalar    *marray;
 25:   PetscBool      symm=PETSC_FALSE;
 26:   Mat            B;
 27:   Vec            z;

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

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

 57:    Collective

 59:    Input Parameters:
 60: +  X - first basis vectors
 61: -  Y - second basis vectors

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

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

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

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

 80:    X and Y need not be different objects.

 82:    Level: intermediate

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

 90:   PetscFunctionBegin;
 95:   BVCheckSizes(X,1);
 97:   BVCheckSizes(Y,2);
 99:   PetscCheckSameTypeAndComm(X,1,Y,2);
100:   SlepcMatCheckSeq(M);

102:   PetscCall(MatGetSize(M,&m,&n));
103:   PetscCheck(m>=Y->k,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " rows, should have at least %" PetscInt_FMT,m,Y->k);
104:   PetscCheck(n>=X->k,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " columns, should have at least %" PetscInt_FMT,n,X->k);
105:   PetscCheck(X->n==Y->n,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %" PetscInt_FMT ", Y %" PetscInt_FMT,X->n,Y->n);
106:   PetscCheck(X->matrix==Y->matrix,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
107:   if (X->l==X->k || Y->l==Y->k) PetscFunctionReturn(PETSC_SUCCESS);

109:   PetscCall(PetscLogEventBegin(BV_Dot,X,Y,0,0));
110:   if (X->matrix) { /* non-standard inner product */
111:     /* compute BX first */
112:     PetscCall(BV_IPMatMultBV(X));
113:     if (X->vmm==BV_MATMULT_VECS) {
114:       /* perform computation column by column */
115:       PetscCall(BVDot_Private(X,Y,M));
116:     } else PetscUseTypeMethod(X->cached,dot,Y,M);
117:   } else PetscUseTypeMethod(X,dot,Y,M);
118:   PetscCall(PetscLogEventEnd(BV_Dot,X,Y,0,0));
119:   PetscFunctionReturn(PETSC_SUCCESS);
120: }

122: /*@
123:    BVDotVec - Computes multiple dot products of a vector against all the
124:    column vectors of a BV.

126:    Collective

128:    Input Parameters:
129: +  X - basis vectors
130: -  y - a vector

132:    Output Parameter:
133: .  m - an array where the result must be placed

135:    Notes:
136:    This is analogue to VecMDot(), but using BV to represent a collection
137:    of vectors. The result is m = X^H*y, so m_i is equal to x_i^H y. Note
138:    that here X is transposed as opposed to BVDot().

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

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

147:    Level: intermediate

149: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
150: @*/
151: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar m[])
152: {
153:   PetscInt       n;

155:   PetscFunctionBegin;
159:   BVCheckSizes(X,1);
160:   BVCheckOp(X,1,dotvec);
162:   PetscCheckSameTypeAndComm(X,1,y,2);

164:   PetscCall(VecGetLocalSize(y,&n));
165:   PetscCheck(X->n==n,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %" PetscInt_FMT ", y %" PetscInt_FMT,X->n,n);

167:   PetscCall(PetscLogEventBegin(BV_DotVec,X,y,0,0));
168:   PetscUseTypeMethod(X,dotvec,y,m);
169:   PetscCall(PetscLogEventEnd(BV_DotVec,X,y,0,0));
170:   PetscFunctionReturn(PETSC_SUCCESS);
171: }

173: /*@
174:    BVDotVecBegin - Starts a split phase dot product computation.

176:    Input Parameters:
177: +  X - basis vectors
178: .  y - a vector
179: -  m - an array where the result will go (can be NULL)

181:    Note:
182:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

184:    Level: advanced

186: .seealso: BVDotVecEnd(), BVDotVec()
187: @*/
188: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)
189: {
190:   PetscInt            i,n,nv;
191:   PetscSplitReduction *sr;
192:   MPI_Comm            comm;

194:   PetscFunctionBegin;
198:   BVCheckSizes(X,1);
200:   PetscCheckSameTypeAndComm(X,1,y,2);

202:   PetscCall(VecGetLocalSize(y,&n));
203:   PetscCheck(X->n==n,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %" PetscInt_FMT ", y %" PetscInt_FMT,X->n,n);

205:   if (X->ops->dotvec_begin) PetscUseTypeMethod(X,dotvec_begin,y,m);
206:   else {
207:     BVCheckOp(X,1,dotvec_local);
208:     nv = X->k-X->l;
209:     PetscCall(PetscObjectGetComm((PetscObject)X,&comm));
210:     PetscCall(PetscSplitReductionGet(comm,&sr));
211:     PetscCheck(sr->state==STATE_BEGIN,PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
212:     for (i=0;i<nv;i++) {
213:       if (sr->numopsbegin+i >= sr->maxops) PetscCall(PetscSplitReductionExtend(sr));
214:       sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
215:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
216:     }
217:     PetscCall(PetscLogEventBegin(BV_DotVec,X,y,0,0));
218:     PetscUseTypeMethod(X,dotvec_local,y,sr->lvalues+sr->numopsbegin);
219:     sr->numopsbegin += nv;
220:     PetscCall(PetscLogEventEnd(BV_DotVec,X,y,0,0));
221:   }
222:   PetscFunctionReturn(PETSC_SUCCESS);
223: }

225: /*@
226:    BVDotVecEnd - Ends a split phase dot product computation.

228:    Input Parameters:
229: +  X - basis vectors
230: .  y - a vector
231: -  m - an array where the result will go

233:    Note:
234:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

236:    Level: advanced

238: .seealso: BVDotVecBegin(), BVDotVec()
239: @*/
240: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)
241: {
242:   PetscInt            i,nv;
243:   PetscSplitReduction *sr;
244:   MPI_Comm            comm;

246:   PetscFunctionBegin;
249:   BVCheckSizes(X,1);

251:   if (X->ops->dotvec_end) PetscUseTypeMethod(X,dotvec_end,y,m);
252:   else {
253:     nv = X->k-X->l;
254:     PetscCall(PetscObjectGetComm((PetscObject)X,&comm));
255:     PetscCall(PetscSplitReductionGet(comm,&sr));
256:     PetscCall(PetscSplitReductionEnd(sr));

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

263:     /* Finished getting all the results so reset to no outstanding requests */
264:     if (sr->numopsend == sr->numopsbegin) {
265:       sr->state       = STATE_BEGIN;
266:       sr->numopsend   = 0;
267:       sr->numopsbegin = 0;
268:     }
269:   }
270:   PetscFunctionReturn(PETSC_SUCCESS);
271: }

273: /*@
274:    BVDotColumn - Computes multiple dot products of a column against all the
275:    previous columns of a BV.

277:    Collective

279:    Input Parameters:
280: +  X - basis vectors
281: -  j - the column index

283:    Output Parameter:
284: .  q - an array where the result must be placed

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

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

298:    Level: advanced

300: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
301: @*/
302: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *q)
303: {
304:   PetscInt       ksave;
305:   Vec            y;

307:   PetscFunctionBegin;
311:   BVCheckSizes(X,1);
312:   BVCheckOp(X,1,dotvec);

314:   PetscCheck(j>=0,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
315:   PetscCheck(j<X->m,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,X->m);

317:   PetscCall(PetscLogEventBegin(BV_DotVec,X,0,0,0));
318:   ksave = X->k;
319:   X->k = j;
320:   if (!q && !X->buffer) PetscCall(BVGetBufferVec(X,&X->buffer));
321:   PetscCall(BVGetColumn(X,j,&y));
322:   PetscUseTypeMethod(X,dotvec,y,q);
323:   PetscCall(BVRestoreColumn(X,j,&y));
324:   X->k = ksave;
325:   PetscCall(PetscLogEventEnd(BV_DotVec,X,0,0,0));
326:   PetscFunctionReturn(PETSC_SUCCESS);
327: }

329: /*@
330:    BVDotColumnBegin - Starts a split phase dot product computation.

332:    Input Parameters:
333: +  X - basis vectors
334: .  j - the column index
335: -  m - an array where the result will go (can be NULL)

337:    Note:
338:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

340:    Level: advanced

342: .seealso: BVDotColumnEnd(), BVDotColumn()
343: @*/
344: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)
345: {
346:   PetscInt            i,nv,ksave;
347:   PetscSplitReduction *sr;
348:   MPI_Comm            comm;
349:   Vec                 y;

351:   PetscFunctionBegin;
355:   BVCheckSizes(X,1);

357:   PetscCheck(j>=0,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
358:   PetscCheck(j<X->m,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,X->m);
359:   ksave = X->k;
360:   X->k = j;
361:   PetscCall(BVGetColumn(X,j,&y));

363:   if (X->ops->dotvec_begin) PetscUseTypeMethod(X,dotvec_begin,y,m);
364:   else {
365:     BVCheckOp(X,1,dotvec_local);
366:     nv = X->k-X->l;
367:     PetscCall(PetscObjectGetComm((PetscObject)X,&comm));
368:     PetscCall(PetscSplitReductionGet(comm,&sr));
369:     PetscCheck(sr->state==STATE_BEGIN,PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
370:     for (i=0;i<nv;i++) {
371:       if (sr->numopsbegin+i >= sr->maxops) PetscCall(PetscSplitReductionExtend(sr));
372:       sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
373:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
374:     }
375:     PetscCall(PetscLogEventBegin(BV_DotVec,X,0,0,0));
376:     PetscUseTypeMethod(X,dotvec_local,y,sr->lvalues+sr->numopsbegin);
377:     sr->numopsbegin += nv;
378:     PetscCall(PetscLogEventEnd(BV_DotVec,X,0,0,0));
379:   }
380:   PetscCall(BVRestoreColumn(X,j,&y));
381:   X->k = ksave;
382:   PetscFunctionReturn(PETSC_SUCCESS);
383: }

385: /*@
386:    BVDotColumnEnd - Ends a split phase dot product computation.

388:    Input Parameters:
389: +  X - basis vectors
390: .  j - the column index
391: -  m - an array where the result will go

393:    Notes:
394:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

396:    Level: advanced

398: .seealso: BVDotColumnBegin(), BVDotColumn()
399: @*/
400: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)
401: {
402:   PetscInt            i,nv,ksave;
403:   PetscSplitReduction *sr;
404:   MPI_Comm            comm;
405:   Vec                 y;

407:   PetscFunctionBegin;
411:   BVCheckSizes(X,1);

413:   PetscCheck(j>=0,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
414:   PetscCheck(j<X->m,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,X->m);
415:   ksave = X->k;
416:   X->k = j;

418:   if (X->ops->dotvec_end) {
419:     PetscCall(BVGetColumn(X,j,&y));
420:     PetscUseTypeMethod(X,dotvec_end,y,m);
421:     PetscCall(BVRestoreColumn(X,j,&y));
422:   } else {
423:     nv = X->k-X->l;
424:     PetscCall(PetscObjectGetComm((PetscObject)X,&comm));
425:     PetscCall(PetscSplitReductionGet(comm,&sr));
426:     PetscCall(PetscSplitReductionEnd(sr));

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

433:     /* Finished getting all the results so reset to no outstanding requests */
434:     if (sr->numopsend == sr->numopsbegin) {
435:       sr->state       = STATE_BEGIN;
436:       sr->numopsend   = 0;
437:       sr->numopsbegin = 0;
438:     }
439:   }
440:   X->k = ksave;
441:   PetscFunctionReturn(PETSC_SUCCESS);
442: }

444: static inline PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)
445: {
446:   PetscScalar    p;

448:   PetscFunctionBegin;
449:   PetscCall(BV_IPMatMult(bv,z));
450:   PetscCall(VecDot(bv->Bx,z,&p));
451:   PetscCall(BV_SafeSqrt(bv,p,val));
452:   PetscFunctionReturn(PETSC_SUCCESS);
453: }

455: static inline PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)
456: {
457:   PetscScalar    p;

459:   PetscFunctionBegin;
460:   PetscCall(BV_IPMatMult(bv,z));
461:   PetscCall(VecDotBegin(bv->Bx,z,&p));
462:   PetscFunctionReturn(PETSC_SUCCESS);
463: }

465: static inline PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)
466: {
467:   PetscScalar    p;

469:   PetscFunctionBegin;
470:   PetscCall(VecDotEnd(bv->Bx,z,&p));
471:   PetscCall(BV_SafeSqrt(bv,p,val));
472:   PetscFunctionReturn(PETSC_SUCCESS);
473: }

475: /*@
476:    BVNorm - Computes the matrix norm of the BV.

478:    Collective

480:    Input Parameters:
481: +  bv   - basis vectors
482: -  type - the norm type

484:    Output Parameter:
485: .  val  - the norm

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

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

494:    Level: intermediate

496: .seealso: BVNormVec(), BVNormColumn(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
497: @*/
498: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)
499: {
500:   PetscFunctionBegin;
503:   PetscAssertPointer(val,3);
505:   BVCheckSizes(bv,1);

507:   PetscCheck(type!=NORM_2 && type!=NORM_1_AND_2,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
508:   PetscCheck(!bv->matrix,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");

510:   PetscCall(PetscLogEventBegin(BV_Norm,bv,0,0,0));
511:   PetscUseTypeMethod(bv,norm,-1,type,val);
512:   PetscCall(PetscLogEventEnd(BV_Norm,bv,0,0,0));
513:   PetscFunctionReturn(PETSC_SUCCESS);
514: }

516: /*@
517:    BVNormVec - Computes the norm of a given vector.

519:    Collective

521:    Input Parameters:
522: +  bv   - basis vectors
523: .  v    - the vector
524: -  type - the norm type

526:    Output Parameter:
527: .  val  - the norm

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

535:    Level: developer

537: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
538: @*/
539: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)
540: {
541:   PetscInt       n;

543:   PetscFunctionBegin;
547:   PetscAssertPointer(val,4);
549:   BVCheckSizes(bv,1);
551:   PetscCheckSameComm(bv,1,v,2);

553:   PetscCheck(type!=NORM_1_AND_2 || bv->matrix,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

555:   PetscCall(PetscLogEventBegin(BV_NormVec,bv,0,0,0));
556:   if (bv->matrix) { /* non-standard inner product */
557:     PetscCall(VecGetLocalSize(v,&n));
558:     PetscCheck(bv->n==n,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %" PetscInt_FMT ", v %" PetscInt_FMT,bv->n,n);
559:     PetscCall(BVNorm_Private(bv,v,type,val));
560:   } else PetscCall(VecNorm(v,type,val));
561:   PetscCall(PetscLogEventEnd(BV_NormVec,bv,0,0,0));
562:   PetscFunctionReturn(PETSC_SUCCESS);
563: }

565: /*@
566:    BVNormVecBegin - Starts a split phase norm computation.

568:    Input Parameters:
569: +  bv   - basis vectors
570: .  v    - the vector
571: .  type - the norm type
572: -  val  - the norm

574:    Note:
575:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

577:    Level: advanced

579: .seealso: BVNormVecEnd(), BVNormVec()
580: @*/
581: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)
582: {
583:   PetscInt       n;

585:   PetscFunctionBegin;
589:   PetscAssertPointer(val,4);
591:   BVCheckSizes(bv,1);
593:   PetscCheckSameTypeAndComm(bv,1,v,2);

595:   PetscCheck(type!=NORM_1_AND_2 || bv->matrix,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

597:   PetscCall(PetscLogEventBegin(BV_NormVec,bv,0,0,0));
598:   if (bv->matrix) { /* non-standard inner product */
599:     PetscCall(VecGetLocalSize(v,&n));
600:     PetscCheck(bv->n==n,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %" PetscInt_FMT ", v %" PetscInt_FMT,bv->n,n);
601:     PetscCall(BVNorm_Begin_Private(bv,v,type,val));
602:   } else PetscCall(VecNormBegin(v,type,val));
603:   PetscCall(PetscLogEventEnd(BV_NormVec,bv,0,0,0));
604:   PetscFunctionReturn(PETSC_SUCCESS);
605: }

607: /*@
608:    BVNormVecEnd - Ends a split phase norm computation.

610:    Input Parameters:
611: +  bv   - basis vectors
612: .  v    - the vector
613: .  type - the norm type
614: -  val  - the norm

616:    Note:
617:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

619:    Level: advanced

621: .seealso: BVNormVecBegin(), BVNormVec()
622: @*/
623: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)
624: {
625:   PetscFunctionBegin;
628:   PetscAssertPointer(val,4);
630:   BVCheckSizes(bv,1);

632:   PetscCheck(type!=NORM_1_AND_2,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

634:   if (bv->matrix) PetscCall(BVNorm_End_Private(bv,v,type,val));  /* non-standard inner product */
635:   else PetscCall(VecNormEnd(v,type,val));
636:   PetscFunctionReturn(PETSC_SUCCESS);
637: }

639: /*@
640:    BVNormColumn - Computes the vector norm of a selected column.

642:    Collective

644:    Input Parameters:
645: +  bv   - basis vectors
646: .  j    - column number to be used
647: -  type - the norm type

649:    Output Parameter:
650: .  val  - the norm

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

658:    Level: intermediate

660: .seealso: BVNorm(), BVNormVec(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
661: @*/
662: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)
663: {
664:   Vec            z;

666:   PetscFunctionBegin;
670:   PetscAssertPointer(val,4);
672:   BVCheckSizes(bv,1);

674:   PetscCheck(j>=0 && j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %" PetscInt_FMT ", the number of columns is %" PetscInt_FMT,j,bv->m);
675:   PetscCheck(type!=NORM_1_AND_2 || bv->matrix,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

677:   PetscCall(PetscLogEventBegin(BV_NormVec,bv,0,0,0));
678:   if (bv->matrix) { /* non-standard inner product */
679:     PetscCall(BVGetColumn(bv,j,&z));
680:     PetscCall(BVNorm_Private(bv,z,type,val));
681:     PetscCall(BVRestoreColumn(bv,j,&z));
682:   } else PetscUseTypeMethod(bv,norm,j,type,val);
683:   PetscCall(PetscLogEventEnd(BV_NormVec,bv,0,0,0));
684:   PetscFunctionReturn(PETSC_SUCCESS);
685: }

687: /*@
688:    BVNormColumnBegin - Starts a split phase norm computation.

690:    Input Parameters:
691: +  bv   - basis vectors
692: .  j    - column number to be used
693: .  type - the norm type
694: -  val  - the norm

696:    Note:
697:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

699:    Level: advanced

701: .seealso: BVNormColumnEnd(), BVNormColumn()
702: @*/
703: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)
704: {
705:   PetscSplitReduction *sr;
706:   PetscReal           lresult;
707:   MPI_Comm            comm;
708:   Vec                 z;

710:   PetscFunctionBegin;
714:   PetscAssertPointer(val,4);
716:   BVCheckSizes(bv,1);

718:   PetscCheck(j>=0 && j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %" PetscInt_FMT ", the number of columns is %" PetscInt_FMT,j,bv->m);
719:   PetscCheck(type!=NORM_1_AND_2 || bv->matrix,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

721:   PetscCall(PetscLogEventBegin(BV_NormVec,bv,0,0,0));
722:   PetscCall(BVGetColumn(bv,j,&z));
723:   if (bv->matrix) PetscCall(BVNorm_Begin_Private(bv,z,type,val)); /* non-standard inner product */
724:   else if (bv->ops->norm_begin) PetscUseTypeMethod(bv,norm_begin,j,type,val);
725:   else {
726:     BVCheckOp(bv,1,norm_local);
727:     PetscCall(PetscObjectGetComm((PetscObject)z,&comm));
728:     PetscCall(PetscSplitReductionGet(comm,&sr));
729:     PetscCheck(sr->state==STATE_BEGIN,PetscObjectComm((PetscObject)bv),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
730:     if (sr->numopsbegin >= sr->maxops) PetscCall(PetscSplitReductionExtend(sr));
731:     sr->invecs[sr->numopsbegin] = (void*)bv;
732:     PetscUseTypeMethod(bv,norm_local,j,type,&lresult);
733:     if (type == NORM_2) lresult = lresult*lresult;
734:     if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_MAX;
735:     else sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_SUM;
736:     sr->lvalues[sr->numopsbegin++] = lresult;
737:   }
738:   PetscCall(BVRestoreColumn(bv,j,&z));
739:   PetscCall(PetscLogEventEnd(BV_NormVec,bv,0,0,0));
740:   PetscFunctionReturn(PETSC_SUCCESS);
741: }

743: /*@
744:    BVNormColumnEnd - Ends a split phase norm computation.

746:    Input Parameters:
747: +  bv   - basis vectors
748: .  j    - column number to be used
749: .  type - the norm type
750: -  val  - the norm

752:    Note:
753:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

755:    Level: advanced

757: .seealso: BVNormColumnBegin(), BVNormColumn()
758: @*/
759: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)
760: {
761:   PetscSplitReduction *sr;
762:   MPI_Comm            comm;
763:   Vec                 z;

765:   PetscFunctionBegin;
769:   PetscAssertPointer(val,4);
771:   BVCheckSizes(bv,1);

773:   PetscCheck(type!=NORM_1_AND_2,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

775:   PetscCall(BVGetColumn(bv,j,&z));
776:   if (bv->matrix) PetscCall(BVNorm_End_Private(bv,z,type,val)); /* non-standard inner product */
777:   else if (bv->ops->norm_end) PetscUseTypeMethod(bv,norm_end,j,type,val);
778:   else {
779:     PetscCall(PetscObjectGetComm((PetscObject)z,&comm));
780:     PetscCall(PetscSplitReductionGet(comm,&sr));
781:     PetscCall(PetscSplitReductionEnd(sr));

783:     PetscCheck(sr->numopsend<sr->numopsbegin,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
784:     PetscCheck((void*)bv==sr->invecs[sr->numopsend],PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
785:     PetscCheck(sr->reducetype[sr->numopsend]==PETSC_SR_REDUCE_MAX || type!=NORM_MAX,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
786:     *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
787:     if (type == NORM_2) *val = PetscSqrtReal(*val);
788:     if (sr->numopsend == sr->numopsbegin) {
789:       sr->state       = STATE_BEGIN;
790:       sr->numopsend   = 0;
791:       sr->numopsbegin = 0;
792:     }
793:   }
794:   PetscCall(BVRestoreColumn(bv,j,&z));
795:   PetscFunctionReturn(PETSC_SUCCESS);
796: }

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

801:    Collective

803:    Input Parameters:
804: +  bv   - basis vectors
805: -  eigi - (optional) imaginary parts of eigenvalues

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

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

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

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

825:    Level: intermediate

827: .seealso: BVNormColumn()
828: @*/
829: PetscErrorCode BVNormalize(BV bv,PetscScalar *eigi)
830: {
831:   PetscReal      norm;
832:   PetscInt       i;

834:   PetscFunctionBegin;
837:   BVCheckSizes(bv,1);

839:   PetscCall(PetscLogEventBegin(BV_Normalize,bv,0,0,0));
840:   if (bv->matrix && !eigi) {
841:     for (i=bv->l;i<bv->k;i++) {
842:       PetscCall(BVNormColumn(bv,i,NORM_2,&norm));
843:       PetscCall(BVScaleColumn(bv,i,1.0/norm));
844:     }
845:   } else PetscTryTypeMethod(bv,normalize,eigi);
846:   PetscCall(PetscLogEventEnd(BV_Normalize,bv,0,0,0));
847:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
848:   PetscFunctionReturn(PETSC_SUCCESS);
849: }

851: /*
852:   Compute Y^H*A*X: right part column by column (with MatMult) and bottom
853:   part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
854: */
855: static inline PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
856: {
857:   PetscInt       i,j,lx,ly,kx,ky,ulim;
858:   Vec            z,f;

860:   PetscFunctionBegin;
861:   lx = X->l; kx = X->k;
862:   ly = Y->l; ky = Y->k;
863:   PetscCall(BVCreateVec(X,&f));
864:   BVCheckOp(Y,3,dotvec);
865:   for (j=lx;j<kx;j++) {
866:     PetscCall(BVGetColumn(X,j,&z));
867:     PetscCall(MatMult(A,z,f));
868:     PetscCall(BVRestoreColumn(X,j,&z));
869:     ulim = PetscMin(ly+(j-lx)+1,ky);
870:     Y->l = 0; Y->k = ulim;
871:     PetscUseTypeMethod(Y,dotvec,f,marray+j*ldm);
872:     if (symm) {
873:       for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
874:     }
875:   }
876:   if (!symm) {
877:     BVCheckOp(X,1,dotvec);
878:     PetscCall(BV_AllocateCoeffs(Y));
879:     for (j=ly;j<ky;j++) {
880:       PetscCall(BVGetColumn(Y,j,&z));
881:       PetscCall(MatMultHermitianTranspose(A,z,f));
882:       PetscCall(BVRestoreColumn(Y,j,&z));
883:       ulim = PetscMin(lx+(j-ly),kx);
884:       X->l = 0; X->k = ulim;
885:       PetscUseTypeMethod(X,dotvec,f,Y->h);
886:       for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
887:     }
888:   }
889:   PetscCall(VecDestroy(&f));
890:   X->l = lx; X->k = kx;
891:   Y->l = ly; Y->k = ky;
892:   PetscFunctionReturn(PETSC_SUCCESS);
893: }

895: /*
896:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
897:                    [ Y1'*W0 | Y1'*W1 ]
898:   Allocates auxiliary BV to store the result of A*X, then one BVDot
899:   call for top-right part and another one for bottom part;
900:   result placed in marray[*,ldm]
901: */
902: static inline PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)
903: {
904:   PetscInt          j,lx,ly,kx,ky;
905:   const PetscScalar *harray;
906:   Mat               H;
907:   BV                W;

909:   PetscFunctionBegin;
910:   lx = X->l; kx = X->k;
911:   ly = Y->l; ky = Y->k;
912:   PetscCall(BVDuplicate(X,&W));
913:   X->l = 0; X->k = kx;
914:   W->l = 0; W->k = kx;
915:   PetscCall(BVMatMult(X,A,W));

917:   /* top-right part, Y0'*AX1 */
918:   if (ly>0 && lx<kx) {
919:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H));
920:     W->l = lx; W->k = kx;
921:     Y->l = 0;  Y->k = ly;
922:     PetscCall(BVDot(W,Y,H));
923:     PetscCall(MatDenseGetArrayRead(H,&harray));
924:     for (j=lx;j<kx;j++) PetscCall(PetscArraycpy(marray+j*ldm,harray+j*ly,ly));
925:     PetscCall(MatDenseRestoreArrayRead(H,&harray));
926:     PetscCall(MatDestroy(&H));
927:   }

929:   /* bottom part, Y1'*AX */
930:   if (kx>0 && ly<ky) {
931:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H));
932:     W->l = 0;  W->k = kx;
933:     Y->l = ly; Y->k = ky;
934:     PetscCall(BVDot(W,Y,H));
935:     PetscCall(MatDenseGetArrayRead(H,&harray));
936:     for (j=0;j<kx;j++) PetscCall(PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly));
937:     PetscCall(MatDenseRestoreArrayRead(H,&harray));
938:     PetscCall(MatDestroy(&H));
939:   }
940:   PetscCall(BVDestroy(&W));
941:   X->l = lx; X->k = kx;
942:   Y->l = ly; Y->k = ky;
943:   PetscFunctionReturn(PETSC_SUCCESS);
944: }

946: /*
947:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
948:                    [ Y1'*W0 | Y1'*W1 ]
949:   First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
950:   Second stage: resize BV to accommodate A'*Y1, then call BVDot for transpose of
951:   bottom-left part; result placed in marray[*,ldm]
952: */
953: static inline PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
954: {
955:   PetscInt          i,j,lx,ly,kx,ky;
956:   const PetscScalar *harray;
957:   Mat               H;
958:   BV                W;

960:   PetscFunctionBegin;
961:   lx = X->l; kx = X->k;
962:   ly = Y->l; ky = Y->k;

964:   /* right part, Y'*AX1 */
965:   PetscCall(BVDuplicateResize(X,kx-lx,&W));
966:   if (ky>0 && lx<kx) {
967:     PetscCall(BVMatMult(X,A,W));
968:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H));
969:     Y->l = 0; Y->k = ky;
970:     PetscCall(BVDot(W,Y,H));
971:     PetscCall(MatDenseGetArrayRead(H,&harray));
972:     for (j=lx;j<kx;j++) PetscCall(PetscArraycpy(marray+j*ldm,harray+(j-lx)*ky,ky));
973:     PetscCall(MatDenseRestoreArrayRead(H,&harray));
974:     PetscCall(MatDestroy(&H));
975:   }

977:   /* bottom-left part, Y1'*AX0 */
978:   if (lx>0 && ly<ky) {
979:     if (symm) {
980:       /* do not compute, just copy symmetric elements */
981:       for (i=ly;i<ky;i++) {
982:         for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
983:       }
984:     } else {
985:       PetscCall(BVResize(W,ky-ly,PETSC_FALSE));
986:       Y->l = ly; Y->k = ky;
987:       PetscCall(BVMatMultHermitianTranspose(Y,A,W));
988:       PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H));
989:       X->l = 0; X->k = lx;
990:       PetscCall(BVDot(W,X,H));
991:       PetscCall(MatDenseGetArrayRead(H,&harray));
992:       for (i=0;i<ky-ly;i++) {
993:         for (j=0;j<lx;j++) {
994:           marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
995:         }
996:       }
997:       PetscCall(MatDenseRestoreArrayRead(H,&harray));
998:       PetscCall(MatDestroy(&H));
999:     }
1000:   }
1001:   PetscCall(BVDestroy(&W));
1002:   X->l = lx; X->k = kx;
1003:   Y->l = ly; Y->k = ky;
1004:   PetscFunctionReturn(PETSC_SUCCESS);
1005: }

1007: /*
1008:   Compute Y^H*X = [   --   | Y0'*X1 ]     (X contains A*X):
1009:                   [ Y1'*X0 | Y1'*X1 ]
1010:   one BVDot call for top-right part and another one for bottom part;
1011:   result placed in marray[*,ldm]
1012: */
1013: static inline PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)
1014: {
1015:   PetscInt          j,lx,ly,kx,ky;
1016:   const PetscScalar *harray;
1017:   Mat               H;

1019:   PetscFunctionBegin;
1020:   lx = X->l; kx = X->k;
1021:   ly = Y->l; ky = Y->k;

1023:   /* top-right part, Y0'*X1 */
1024:   if (ly>0 && lx<kx) {
1025:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H));
1026:     X->l = lx; X->k = kx;
1027:     Y->l = 0;  Y->k = ly;
1028:     PetscCall(BVDot(X,Y,H));
1029:     PetscCall(MatDenseGetArrayRead(H,&harray));
1030:     for (j=lx;j<kx;j++) PetscCall(PetscArraycpy(marray+j*ldm,harray+j*ly,ly));
1031:     PetscCall(MatDenseRestoreArrayRead(H,&harray));
1032:     PetscCall(MatDestroy(&H));
1033:   }

1035:   /* bottom part, Y1'*X */
1036:   if (kx>0 && ly<ky) {
1037:     PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H));
1038:     X->l = 0;  X->k = kx;
1039:     Y->l = ly; Y->k = ky;
1040:     PetscCall(BVDot(X,Y,H));
1041:     PetscCall(MatDenseGetArrayRead(H,&harray));
1042:     for (j=0;j<kx;j++) PetscCall(PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly));
1043:     PetscCall(MatDenseRestoreArrayRead(H,&harray));
1044:     PetscCall(MatDestroy(&H));
1045:   }
1046:   X->l = lx; X->k = kx;
1047:   Y->l = ly; Y->k = ky;
1048:   PetscFunctionReturn(PETSC_SUCCESS);
1049: }

1051: /*@
1052:    BVMatProject - Computes the projection of a matrix onto a subspace.

1054:    Collective

1056:    Input Parameters:
1057: +  X - basis vectors
1058: .  A - (optional) matrix to be projected
1059: -  Y - left basis vectors, can be equal to X

1061:    Output Parameter:
1062: .  M - the resulting matrix

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

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

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

1076:    On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1077:    where ky (resp. kx) is the number of active columns of Y (resp. X).
1078:    Another difference with respect to BVDot() is that all entries of M are
1079:    computed except the leading ly,lx part, where ly (resp. lx) is the
1080:    number of leading columns of Y (resp. X). Hence, the leading columns of
1081:    X and Y participate in the computation, as opposed to BVDot().
1082:    The leading part of M is assumed to be already available from previous
1083:    computations.

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

1089:    Level: intermediate

1091: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1092: @*/
1093: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
1094: {
1095:   PetscBool      set,flg,symm=PETSC_FALSE;
1096:   PetscInt       m,n,ldm;
1097:   PetscScalar    *marray;
1098:   Mat            Xmatrix,Ymatrix;
1099:   PetscObjectId  idx,idy;

1101:   PetscFunctionBegin;
1107:   BVCheckSizes(X,1);
1108:   if (A) {
1110:     PetscCheckSameComm(X,1,A,2);
1111:   }
1113:   BVCheckSizes(Y,3);
1115:   PetscCheckSameTypeAndComm(X,1,Y,3);
1116:   SlepcMatCheckSeq(M);

1118:   PetscCall(MatGetSize(M,&m,&n));
1119:   PetscCall(MatDenseGetLDA(M,&ldm));
1120:   PetscCheck(m>=Y->k,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %" PetscInt_FMT " rows, should have at least %" PetscInt_FMT,m,Y->k);
1121:   PetscCheck(n>=X->k,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %" PetscInt_FMT " columns, should have at least %" PetscInt_FMT,n,X->k);
1122:   PetscCheck(X->n==Y->n,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %" PetscInt_FMT ", Y %" PetscInt_FMT,X->n,Y->n);

1124:   PetscCall(PetscLogEventBegin(BV_MatProject,X,A,Y,0));
1125:   /* temporarily set standard inner product */
1126:   Xmatrix = X->matrix;
1127:   Ymatrix = Y->matrix;
1128:   X->matrix = Y->matrix = NULL;

1130:   PetscCall(PetscObjectGetId((PetscObject)X,&idx));
1131:   PetscCall(PetscObjectGetId((PetscObject)Y,&idy));
1132:   if (A && idx==idy) { /* check symmetry of M=X'AX */
1133:     PetscCall(MatIsHermitianKnown(A,&set,&flg));
1134:     symm = set? flg: PETSC_FALSE;
1135:   }

1137:   PetscCall(MatDenseGetArray(M,&marray));

1139:   if (A) {
1140:     if (X->vmm==BV_MATMULT_VECS) {
1141:       /* perform computation column by column */
1142:       PetscCall(BVMatProject_Vec(X,A,Y,marray,ldm,symm));
1143:     } else {
1144:       /* use BVMatMult, then BVDot */
1145:       PetscCall(MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg));
1146:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) PetscCall(BVMatProject_MatMult_2(X,A,Y,marray,ldm,symm));
1147:       else PetscCall(BVMatProject_MatMult(X,A,Y,marray,ldm));
1148:     }
1149:   } else {
1150:     /* use BVDot on subblocks */
1151:     PetscCall(BVMatProject_Dot(X,Y,marray,ldm));
1152:   }

1154:   PetscCall(MatDenseRestoreArray(M,&marray));
1155:   PetscCall(PetscLogEventEnd(BV_MatProject,X,A,Y,0));
1156:   /* restore non-standard inner product */
1157:   X->matrix = Xmatrix;
1158:   Y->matrix = Ymatrix;
1159:   PetscFunctionReturn(PETSC_SUCCESS);
1160: }