Actual source code: bvglobal.c

slepc-3.13.1 2020-04-12
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>      /*I "slepcbv.h" I*/

 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(), 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(), 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:   Compute Y^H*A*X: right part column by column (with MatMult) and bottom
848:   part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
849: */
850: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
851: {
853:   PetscInt       i,j,lx,ly,kx,ky,ulim;
854:   Vec            z,f;

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

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

907:   lx = X->l; kx = X->k;
908:   ly = Y->l; ky = Y->k;
909:   BVDuplicate(X,&W);
910:   X->l = 0; X->k = kx;
911:   W->l = 0; W->k = kx;
912:   BVMatMult(X,A,W);

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

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

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

963:   lx = X->l; kx = X->k;
964:   ly = Y->l; ky = Y->k;

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

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

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

1025:   lx = X->l; kx = X->k;
1026:   ly = Y->l; ky = Y->k;

1028:   /* top-right part, Y0'*X1 */
1029:   if (ly>0 && lx<kx) {
1030:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1031:     X->l = lx; X->k = kx;
1032:     Y->l = 0;  Y->k = ly;
1033:     BVDot(X,Y,H);
1034:     MatDenseGetArray(H,&harray);
1035:     for (j=lx;j<kx;j++) {
1036:       PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
1037:     }
1038:     MatDenseRestoreArray(H,&harray);
1039:     MatDestroy(&H);
1040:   }

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

1060: /*@
1061:    BVMatProject - Computes the projection of a matrix onto a subspace.

1063:    Collective on X

1065:    Input Parameters:
1066: +  X - basis vectors
1067: .  A - (optional) matrix to be projected
1068: .  Y - left basis vectors, can be equal to X
1069: -  M - Mat object where the result must be placed

1071:    Output Parameter:
1072: .  M - the resulting matrix

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

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

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

1086:    On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1087:    where ky (resp. kx) is the number of active columns of Y (resp. X).
1088:    Another difference with respect to BVDot() is that all entries of M are
1089:    computed except the leading ly,lx part, where ly (resp. lx) is the
1090:    number of leading columns of Y (resp. X). Hence, the leading columns of
1091:    X and Y participate in the computation, as opposed to BVDot().
1092:    The leading part of M is assumed to be already available from previous
1093:    computations.

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

1099:    Level: intermediate

1101: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1102: @*/
1103: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
1104: {
1106:   PetscBool      match,set,flg,symm=PETSC_FALSE;
1107:   PetscInt       m,n;
1108:   PetscScalar    *marray;
1109:   Mat            Xmatrix,Ymatrix;
1110:   PetscObjectId  idx,idy;

1118:   BVCheckSizes(X,1);
1119:   if (A) {
1122:   }
1124:   BVCheckSizes(Y,3);
1127:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1128:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");

1130:   MatGetSize(M,&m,&n);
1131:   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);
1132:   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);
1133:   if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);

1135:   PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1136:   /* temporarily set standard inner product */
1137:   Xmatrix = X->matrix;
1138:   Ymatrix = Y->matrix;
1139:   X->matrix = Y->matrix = NULL;

1141:   PetscObjectGetId((PetscObject)X,&idx);
1142:   PetscObjectGetId((PetscObject)Y,&idy);
1143:   if (A && idx==idy) { /* check symmetry of M=X'AX */
1144:     MatIsHermitianKnown(A,&set,&flg);
1145:     symm = set? flg: PETSC_FALSE;
1146:   }

1148:   MatDenseGetArray(M,&marray);

1150:   if (A) {
1151:     if (X->vmm==BV_MATMULT_VECS) {
1152:       /* perform computation column by column */
1153:       BVMatProject_Vec(X,A,Y,marray,m,symm);
1154:     } else {
1155:       /* use BVMatMult, then BVDot */
1156:       MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1157:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1158:         BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1159:       } else {
1160:         BVMatProject_MatMult(X,A,Y,marray,m);
1161:       }
1162:     }
1163:   } else {
1164:     /* use BVDot on subblocks */
1165:     BVMatProject_Dot(X,Y,marray,m);
1166:   }

1168:   MatDenseRestoreArray(M,&marray);
1169:   PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1170:   /* restore non-standard inner product */
1171:   X->matrix = Xmatrix;
1172:   Y->matrix = Ymatrix;
1173:   return(0);
1174: }