Actual source code: bvglobal.c

slepc-3.7.0 2016-05-16
Report Typos and Errors
  1: /*
  2:    BV operations involving global communication.

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain

  8:    This file is part of SLEPc.

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

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

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

 24: #include <slepc/private/bvimpl.h>      /*I "slepcbv.h" I*/

 28: /*
 29:   BVDot for the particular case of non-standard inner product with
 30:   matrix B, which is assumed to be symmetric (or complex Hermitian)
 31: */
 32: PETSC_STATIC_INLINE PetscErrorCode BVDot_Private(BV X,BV Y,Mat M)
 33: {
 35:   PetscObjectId  idx,idy;
 36:   PetscInt       i,j,jend,m;
 37:   PetscScalar    *marray;
 38:   PetscBool      symm=PETSC_FALSE;
 39:   Vec            z;

 42:   MatGetSize(M,&m,NULL);
 43:   MatDenseGetArray(M,&marray);
 44:   PetscObjectGetId((PetscObject)X,&idx);
 45:   PetscObjectGetId((PetscObject)Y,&idy);
 46:   if (idx==idy) symm=PETSC_TRUE;  /* M=X'BX is symmetric */
 47:   jend = X->k;
 48:   for (j=X->l;j<jend;j++) {
 49:     if (symm) Y->k = j+1;
 50:     BVGetColumn(X,j,&z);
 51:     (*Y->ops->dotvec)(Y,z,marray+j*m+Y->l);
 52:     BVRestoreColumn(X,j,&z);
 53:     if (symm) {
 54:       for (i=X->l;i<j;i++)
 55:         marray[j+i*m] = PetscConj(marray[i+j*m]);
 56:     }
 57:   }
 58:   MatDenseRestoreArray(M,&marray);
 59:   return(0);
 60: }

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

 67:    Collective on BV

 69:    Input Parameters:
 70: +  X, Y - basis vectors
 71: -  M    - Mat object where the result must be placed

 73:    Output Parameter:
 74: .  M    - the resulting matrix

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

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

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

 90:    X and Y need not be different objects.

 92:    Level: intermediate

 94: .seealso: BVDotVec(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
 95: @*/
 96: PetscErrorCode BVDot(BV X,BV Y,Mat M)
 97: {
 99:   PetscBool      match;
100:   PetscInt       m,n;
101:   Mat            B;

108:   BVCheckSizes(X,1);
110:   BVCheckSizes(Y,2);
113:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
114:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");

116:   MatGetSize(M,&m,&n);
117:   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);
118:   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);
119:   if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
120:   if (X->matrix!=Y->matrix) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
121:   if (X->l==X->k || Y->l==Y->k) return(0);

123:   PetscLogEventBegin(BV_Dot,X,Y,0,0);
124:   if (X->matrix) { /* non-standard inner product */
125:     if (X->vmm==BV_MATMULT_VECS) {
126:       /* perform computation column by column */
127:       BVDot_Private(X,Y,M);
128:     } else {
129:       /* compute BX first */
130:       BV_IPMatMultBV(X);
131:       B = X->matrix;
132:       X->matrix = NULL;
133:       (*X->ops->dot)(X->cached,Y,M);
134:       X->matrix = B;
135:     }
136:   } else {
137:     (*X->ops->dot)(X,Y,M);
138:   }
139:   PetscLogEventEnd(BV_Dot,X,Y,0,0);
140:   return(0);
141: }

145: /*@
146:    BVDotVec - Computes multiple dot products of a vector against all the
147:    column vectors of a BV.

149:    Collective on BV and Vec

151:    Input Parameters:
152: +  X - basis vectors
153: -  y - a vector

155:    Output Parameter:
156: .  m - an array where the result must be placed

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

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

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

170:    Level: intermediate

172: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
173: @*/
174: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar *m)
175: {
177:   PetscInt       n;

183:   BVCheckSizes(X,1);

187:   VecGetLocalSize(y,&n);
188:   if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

190:   PetscLogEventBegin(BV_DotVec,X,y,0,0);
191:   (*X->ops->dotvec)(X,y,m);
192:   PetscLogEventEnd(BV_DotVec,X,y,0,0);
193:   return(0);
194: }

198: /*@
199:    BVDotVecBegin - Starts a split phase dot product computation.

201:    Input Parameters:
202: +  X - basis vectors
203: .  y - a vector
204: -  m - an array where the result will go (can be NULL)

206:    Note:
207:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

209:    Level: advanced

211: .seealso: BVDotVecEnd(), BVDotVec()
212: @*/
213: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)
214: {
215:   PetscErrorCode      ierr;
216:   PetscInt            i,n,nv;
217:   PetscSplitReduction *sr;
218:   MPI_Comm            comm;

224:   BVCheckSizes(X,1);

228:   VecGetLocalSize(y,&n);
229:   if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);

231:   if (X->ops->dotvec_begin) {
232:     (*X->ops->dotvec_begin)(X,y,m);
233:   } else {
234:     nv = X->k-X->l;
235:     PetscObjectGetComm((PetscObject)X,&comm);
236:     PetscSplitReductionGet(comm,&sr);
237:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
238:     for (i=0;i<nv;i++) {
239:       if (sr->numopsbegin+i >= sr->maxops) {
240:         PetscSplitReductionExtend(sr);
241:       }
242:       sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
243:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
244:     }
245:     PetscLogEventBegin(BV_DotVec,X,y,0,0);
246:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
247:     sr->numopsbegin += nv;
248:     PetscLogEventEnd(BV_DotVec,X,y,0,0);
249:   }
250:   return(0);
251: }

255: /*@
256:    BVDotVecEnd - Ends a split phase dot product computation.

258:    Input Parameters:
259: +  X - basis vectors
260: .  y - a vector
261: -  m - an array where the result will go

263:    Note:
264:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

266:    Level: advanced

268: .seealso: BVDotVecBegin(), BVDotVec()
269: @*/
270: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)
271: {
272:   PetscErrorCode      ierr;
273:   PetscInt            i,nv;
274:   PetscSplitReduction *sr;
275:   MPI_Comm            comm;

280:   BVCheckSizes(X,1);

282:   if (X->ops->dotvec_end) {
283:     (*X->ops->dotvec_end)(X,y,m);
284:   } else {
285:     nv = X->k-X->l;
286:     PetscObjectGetComm((PetscObject)X,&comm);
287:     PetscSplitReductionGet(comm,&sr);
288:     PetscSplitReductionEnd(sr);

290:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
291:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
292:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
293:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

295:     /* Finished getting all the results so reset to no outstanding requests */
296:     if (sr->numopsend == sr->numopsbegin) {
297:       sr->state       = STATE_BEGIN;
298:       sr->numopsend   = 0;
299:       sr->numopsbegin = 0;
300:     }
301:   }
302:   return(0);
303: }

307: /*@
308:    BVDotColumn - Computes multiple dot products of a column against all the
309:    previous columns of a BV.

311:    Collective on BV

313:    Input Parameters:
314: +  X - basis vectors
315: -  j - the column index

317:    Output Parameter:
318: .  m - an array where the result must be placed

320:    Notes:
321:    This operation is equivalent to BVDotVec() but it uses column j of X
322:    rather than taking a Vec as an argument. The number of active columns of
323:    X is set to j before the computation, and restored afterwards.
324:    If X has leading columns specified, then these columns do not participate
325:    in the computation. Therefore, the length of array m must be equal to j
326:    minus the number of leading columns.

328:    Level: advanced

330: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
331: @*/
332: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *m)
333: {
335:   PetscInt       ksave;
336:   Vec            y;

342:   BVCheckSizes(X,1);

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

347:   PetscLogEventBegin(BV_DotVec,X,0,0,0);
348:   ksave = X->k;
349:   X->k = j;
350:   BVGetColumn(X,j,&y);
351:   (*X->ops->dotvec)(X,y,m);
352:   BVRestoreColumn(X,j,&y);
353:   X->k = ksave;
354:   PetscLogEventEnd(BV_DotVec,X,0,0,0);
355:   return(0);
356: }

360: /*@
361:    BVDotColumnBegin - Starts a split phase dot product computation.

363:    Input Parameters:
364: +  X - basis vectors
365: -  j - the column index
366: -  m - an array where the result will go (can be NULL)

368:    Note:
369:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

371:    Level: advanced

373: .seealso: BVDotColumnEnd(), BVDotColumn()
374: @*/
375: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)
376: {
377:   PetscErrorCode      ierr;
378:   PetscInt            i,nv,ksave;
379:   PetscSplitReduction *sr;
380:   MPI_Comm            comm;
381:   Vec                 y;

387:   BVCheckSizes(X,1);

389:   if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
390:   if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
391:   ksave = X->k;
392:   X->k = j;
393:   BVGetColumn(X,j,&y);

395:   if (X->ops->dotvec_begin) {
396:     (*X->ops->dotvec_begin)(X,y,m);
397:   } else {
398:     nv = X->k-X->l;
399:     PetscObjectGetComm((PetscObject)X,&comm);
400:     PetscSplitReductionGet(comm,&sr);
401:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
402:     for (i=0;i<nv;i++) {
403:       if (sr->numopsbegin+i >= sr->maxops) {
404:         PetscSplitReductionExtend(sr);
405:       }
406:       sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
407:       sr->invecs[sr->numopsbegin+i]     = (void*)X;
408:     }
409:     PetscLogEventBegin(BV_DotVec,X,0,0,0);
410:     (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
411:     sr->numopsbegin += nv;
412:     PetscLogEventEnd(BV_DotVec,X,0,0,0);
413:   }
414:   BVRestoreColumn(X,j,&y);
415:   X->k = ksave;
416:   return(0);
417: }

421: /*@
422:    BVDotColumnEnd - Ends a split phase dot product computation.

424:    Input Parameters:
425: +  X - basis vectors
426: .  j - the column index
427: -  m - an array where the result will go

429:    Notes:
430:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

432:    Level: advanced

434: .seealso: BVDotColumnBegin(), BVDotColumn()
435: @*/
436: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)
437: {
438:   PetscErrorCode      ierr;
439:   PetscInt            i,nv,ksave;
440:   PetscSplitReduction *sr;
441:   MPI_Comm            comm;
442:   Vec                 y;

448:   BVCheckSizes(X,1);

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

455:   if (X->ops->dotvec_end) {
456:     BVGetColumn(X,j,&y);
457:     (*X->ops->dotvec_end)(X,y,m);
458:     BVRestoreColumn(X,j,&y);
459:   } else {
460:     nv = X->k-X->l;
461:     PetscObjectGetComm((PetscObject)X,&comm);
462:     PetscSplitReductionGet(comm,&sr);
463:     PetscSplitReductionEnd(sr);

465:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
466:     if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
467:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
468:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

470:     /* Finished getting all the results so reset to no outstanding requests */
471:     if (sr->numopsend == sr->numopsbegin) {
472:       sr->state       = STATE_BEGIN;
473:       sr->numopsend   = 0;
474:       sr->numopsbegin = 0;
475:     }
476:   }
477:   X->k = ksave;
478:   return(0);
479: }

483: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)
484: {
486:   PetscScalar    p;

489:   BV_IPMatMult(bv,z);
490:   VecDot(bv->Bx,z,&p);
491:   BV_SafeSqrt(bv,p,val);
492:   return(0);
493: }

497: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)
498: {
500:   PetscScalar    p;

503:   BV_IPMatMult(bv,z);
504:   VecDotBegin(bv->Bx,z,&p);
505:   return(0);
506: }

510: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)
511: {
513:   PetscScalar    p;

516:   VecDotEnd(bv->Bx,z,&p);
517:   BV_SafeSqrt(bv,p,val);
518:   return(0);
519: }

523: /*@
524:    BVNorm - Computes the matrix norm of the BV.

526:    Collective on BV

528:    Input Parameters:
529: +  bv   - basis vectors
530: -  type - the norm type

532:    Output Parameter:
533: .  val  - the norm

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

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

542:    Level: intermediate

544: .seealso: BVNormVec(), BVNormColumn(), BVSetActiveColumns(), BVSetMatrix()
545: @*/
546: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)
547: {

555:   BVCheckSizes(bv,1);

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

560:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
561:   (*bv->ops->norm)(bv,-1,type,val);
562:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
563:   return(0);
564: }

568: /*@
569:    BVNormVec - Computes the norm of a given vector.

571:    Collective on BV

573:    Input Parameters:
574: +  bv   - basis vectors
575: .  v    - the vector
576: -  type - the norm type

578:    Output Parameter:
579: .  val  - the norm

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

587:    Level: developer

589: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
590: @*/
591: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)
592: {
594:   PetscInt       n;

602:   BVCheckSizes(bv,1);

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

608:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
609:   if (bv->matrix) { /* non-standard inner product */
610:     VecGetLocalSize(v,&n);
611:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
612:     BVNorm_Private(bv,v,type,val);
613:   } else {
614:     VecNorm(v,type,val);
615:   }
616:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
617:   return(0);
618: }

622: /*@
623:    BVNormVecBegin - Starts a split phase norm computation.

625:    Input Parameters:
626: +  bv   - basis vectors
627: .  v    - the vector
628: .  type - the norm type
629: -  val  - the norm

631:    Note:
632:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

634:    Level: advanced

636: .seealso: BVNormVecEnd(), BVNormVec()
637: @*/
638: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)
639: {
641:   PetscInt       n;

649:   BVCheckSizes(bv,1);

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

655:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
656:   if (bv->matrix) { /* non-standard inner product */
657:     VecGetLocalSize(v,&n);
658:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
659:     BVNorm_Begin_Private(bv,v,type,val);
660:   } else {
661:     VecNormBegin(v,type,val);
662:   }
663:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
664:   return(0);
665: }

669: /*@
670:    BVNormVecEnd - Ends a split phase norm computation.

672:    Input Parameters:
673: +  bv   - basis vectors
674: .  v    - the vector
675: .  type - the norm type
676: -  val  - the norm

678:    Note:
679:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

681:    Level: advanced

683: .seealso: BVNormVecBegin(), BVNormVec()
684: @*/
685: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)
686: {

694:   BVCheckSizes(bv,1);

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

698:   if (bv->matrix) { /* non-standard inner product */
699:     BVNorm_End_Private(bv,v,type,val);
700:   } else {
701:     VecNormEnd(v,type,val);
702:   }
703:   return(0);
704: }

708: /*@
709:    BVNormColumn - Computes the vector norm of a selected column.

711:    Collective on BV

713:    Input Parameters:
714: +  bv   - basis vectors
715: .  j    - column number to be used
716: -  type - the norm type

718:    Output Parameter:
719: .  val  - the norm

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

727:    Level: intermediate

729: .seealso: BVNorm(), BVNormVec(), BVSetActiveColumns(), BVSetMatrix()
730: @*/
731: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)
732: {
734:   Vec            z;

742:   BVCheckSizes(bv,1);

744:   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);
745:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

747:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
748:   if (bv->matrix) { /* non-standard inner product */
749:     BVGetColumn(bv,j,&z);
750:     BVNorm_Private(bv,z,type,val);
751:     BVRestoreColumn(bv,j,&z);
752:   } else {
753:     (*bv->ops->norm)(bv,j,type,val);
754:   }
755:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
756:   return(0);
757: }

761: /*@
762:    BVNormColumnBegin - Starts a split phase norm computation.

764:    Input Parameters:
765: +  bv   - basis vectors
766: .  j    - column number to be used
767: .  type - the norm type
768: -  val  - the norm

770:    Note:
771:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

773:    Level: advanced

775: .seealso: BVNormColumnEnd(), BVNormColumn()
776: @*/
777: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)
778: {
779:   PetscErrorCode      ierr;
780:   PetscSplitReduction *sr;
781:   PetscReal           lresult;
782:   MPI_Comm            comm;
783:   Vec                 z;

791:   BVCheckSizes(bv,1);

793:   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);
794:   if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");

796:   PetscLogEventBegin(BV_NormVec,bv,0,0,0);
797:   BVGetColumn(bv,j,&z);
798:   if (bv->matrix) { /* non-standard inner product */
799:     BVNorm_Begin_Private(bv,z,type,val);
800:   } else if (bv->ops->norm_begin) {
801:     (*bv->ops->norm_begin)(bv,j,type,val);
802:   } else {
803:     PetscObjectGetComm((PetscObject)z,&comm);
804:     PetscSplitReductionGet(comm,&sr);
805:     if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
806:     if (sr->numopsbegin >= sr->maxops) {
807:       PetscSplitReductionExtend(sr);
808:     }
809:     sr->invecs[sr->numopsbegin] = (void*)bv;
810:     (*bv->ops->norm_local)(bv,j,type,&lresult);
811:     if (type == NORM_2) lresult = lresult*lresult;
812:     else if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = REDUCE_MAX;
813:     else sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
814:     sr->lvalues[sr->numopsbegin++] = lresult;
815:   }
816:   BVRestoreColumn(bv,j,&z);
817:   PetscLogEventEnd(BV_NormVec,bv,0,0,0);
818:   return(0);
819: }

823: /*@
824:    BVNormColumnEnd - Ends a split phase norm computation.

826:    Input Parameters:
827: +  bv   - basis vectors
828: .  j    - column number to be used
829: .  type - the norm type
830: -  val  - the norm

832:    Note:
833:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

835:    Level: advanced

837: .seealso: BVNormColumnBegin(), BVNormColumn()
838: @*/
839: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)
840: {
841:   PetscErrorCode      ierr;
842:   PetscSplitReduction *sr;
843:   MPI_Comm            comm;
844:   Vec                 z;

852:   BVCheckSizes(bv,1);

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

856:   BVGetColumn(bv,j,&z);
857:   if (bv->matrix) { /* non-standard inner product */
858:     BVNorm_End_Private(bv,z,type,val);
859:   } else if (bv->ops->norm_end) {
860:     (*bv->ops->norm_end)(bv,j,type,val);
861:   } else {
862:     PetscObjectGetComm((PetscObject)z,&comm);
863:     PetscSplitReductionGet(comm,&sr);
864:     PetscSplitReductionEnd(sr);

866:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
867:     if ((void*)bv != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
868:     if (sr->reducetype[sr->numopsend] != REDUCE_MAX && type == NORM_MAX) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
869:     *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
870:     if (type == NORM_2) *val = PetscSqrtReal(*val);
871:     if (sr->numopsend == sr->numopsbegin) {
872:       sr->state       = STATE_BEGIN;
873:       sr->numopsend   = 0;
874:       sr->numopsbegin = 0;
875:     }
876:   }
877:   BVRestoreColumn(bv,j,&z);
878:   return(0);
879: }

883: /*
884:   Compute Y^H*A*X: right part column by column (with MatMult) and bottom
885:   part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
886: */
887: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
888: {
890:   PetscInt       i,j,lx,ly,kx,ky,ulim;
891:   Vec            z,f;

894:   lx = X->l; kx = X->k;
895:   ly = Y->l; ky = Y->k;
896:   BVCreateVec(X,&f);
897:   for (j=lx;j<kx;j++) {
898:     BVGetColumn(X,j,&z);
899:     MatMult(A,z,f);
900:     BVRestoreColumn(X,j,&z);
901:     ulim = PetscMin(ly+(j-lx)+1,ky);
902:     Y->l = 0; Y->k = ulim;
903:     (*Y->ops->dotvec)(Y,f,marray+j*ldm);
904:     if (symm) {
905:       for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
906:     }
907:   }
908:   if (!symm) {
909:     BV_AllocateCoeffs(Y);
910:     for (j=ly;j<ky;j++) {
911:       BVGetColumn(Y,j,&z);
912:       MatMultHermitianTranspose(A,z,f);
913:       BVRestoreColumn(Y,j,&z);
914:       ulim = PetscMin(lx+(j-ly),kx);
915:       X->l = 0; X->k = ulim;
916:       (*X->ops->dotvec)(X,f,Y->h);
917:       for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
918:     }
919:   }
920:   VecDestroy(&f);
921:   X->l = lx; X->k = kx;
922:   Y->l = ly; Y->k = ky;
923:   return(0);
924: }

928: /*
929:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
930:                    [ Y1'*W0 | Y1'*W1 ]
931:   Allocates auxiliary BV to store the result of A*X, then one BVDot
932:   call for top-right part and another one for bottom part;
933:   result placed in marray[*,ldm]
934: */
935: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)
936: {
938:   PetscInt       j,lx,ly,kx,ky;
939:   PetscScalar    *harray;
940:   Mat            H;
941:   BV             W;

944:   lx = X->l; kx = X->k;
945:   ly = Y->l; ky = Y->k;
946:   BVDuplicate(X,&W);
947:   X->l = 0; X->k = kx;
948:   BVMatMult(X,A,W);

950:   /* top-right part, Y0'*AX1 */
951:   if (ly>0 && lx<kx) {
952:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
953:     W->l = lx; W->k = kx;
954:     Y->l = 0;  Y->k = ly;
955:     BVDot(W,Y,H);
956:     MatDenseGetArray(H,&harray);
957:     for (j=lx;j<kx;j++) {
958:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
959:     }
960:     MatDenseRestoreArray(H,&harray);
961:     MatDestroy(&H);
962:   }

964:   /* bottom part, Y1'*AX */
965:   if (kx>0 && ly<ky) {
966:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
967:     W->l = 0;  W->k = kx;
968:     Y->l = ly; Y->k = ky;
969:     BVDot(W,Y,H);
970:     MatDenseGetArray(H,&harray);
971:     for (j=0;j<kx;j++) {
972:       PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
973:     }
974:     MatDenseRestoreArray(H,&harray);
975:     MatDestroy(&H);
976:   }
977:   BVDestroy(&W);
978:   X->l = lx; X->k = kx;
979:   Y->l = ly; Y->k = ky;
980:   return(0);
981: }

985: /*
986:   Compute Y^H*A*X= [   --   | Y0'*W1 ]
987:                    [ Y1'*W0 | Y1'*W1 ]
988:   First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
989:   Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
990:   bottom-left part; result placed in marray[*,ldm]
991: */
992: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)
993: {
995:   PetscInt       i,j,lx,ly,kx,ky;
996:   PetscScalar    *harray;
997:   Mat            H;
998:   BV             W;

1001:   lx = X->l; kx = X->k;
1002:   ly = Y->l; ky = Y->k;

1004:   /* right part, Y'*AX1 */
1005:   BVDuplicateResize(X,kx-lx,&W);
1006:   if (ky>0 && lx<kx) {
1007:     BVMatMult(X,A,W);
1008:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
1009:     Y->l = 0; Y->k = ky;
1010:     BVDot(W,Y,H);
1011:     MatDenseGetArray(H,&harray);
1012:     for (j=lx;j<kx;j++) {
1013:       PetscMemcpy(marray+j*ldm,harray+(j-lx)*ky,ky*sizeof(PetscScalar));
1014:     }
1015:     MatDenseRestoreArray(H,&harray);
1016:     MatDestroy(&H);
1017:   }

1019:   /* bottom-left part, Y1'*AX0 */
1020:   if (lx>0 && ly<ky) {
1021:     if (symm) {
1022:       /* do not compute, just copy symmetric elements */
1023:       for (i=ly;i<ky;i++) {
1024:         for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
1025:       }
1026:     } else {
1027:       BVResize(W,ky-ly,PETSC_FALSE);
1028:       Y->l = ly; Y->k = ky;
1029:       BVMatMultHermitianTranspose(Y,A,W);
1030:       MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
1031:       X->l = 0; X->k = lx;
1032:       BVDot(W,X,H);
1033:       MatDenseGetArray(H,&harray);
1034:       for (i=0;i<ky-ly;i++) {
1035:         for (j=0;j<lx;j++) {
1036:           marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
1037:         }
1038:       }
1039:       MatDenseRestoreArray(H,&harray);
1040:       MatDestroy(&H);
1041:     }
1042:   }
1043:   BVDestroy(&W);
1044:   X->l = lx; X->k = kx;
1045:   Y->l = ly; Y->k = ky;
1046:   return(0);
1047: }

1051: /*
1052:   Compute Y^H*X = [   --   | Y0'*X1 ]     (X contains A*X):
1053:                   [ Y1'*X0 | Y1'*X1 ]
1054:   one BVDot call for top-right part and another one for bottom part;
1055:   result placed in marray[*,ldm]
1056: */
1057: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)
1058: {
1060:   PetscInt       j,lx,ly,kx,ky;
1061:   PetscScalar    *harray;
1062:   Mat            H;

1065:   lx = X->l; kx = X->k;
1066:   ly = Y->l; ky = Y->k;

1068:   /* top-right part, Y0'*X1 */
1069:   if (ly>0 && lx<kx) {
1070:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1071:     X->l = lx; X->k = kx;
1072:     Y->l = 0;  Y->k = ly;
1073:     BVDot(X,Y,H);
1074:     MatDenseGetArray(H,&harray);
1075:     for (j=lx;j<kx;j++) {
1076:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
1077:     }
1078:     MatDenseRestoreArray(H,&harray);
1079:     MatDestroy(&H);
1080:   }

1082:   /* bottom part, Y1'*X */
1083:   if (kx>0 && ly<ky) {
1084:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1085:     X->l = 0;  X->k = kx;
1086:     Y->l = ly; Y->k = ky;
1087:     BVDot(X,Y,H);
1088:     MatDenseGetArray(H,&harray);
1089:     for (j=0;j<kx;j++) {
1090:       PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
1091:     }
1092:     MatDenseRestoreArray(H,&harray);
1093:     MatDestroy(&H);
1094:   }
1095:   X->l = lx; X->k = kx;
1096:   Y->l = ly; Y->k = ky;
1097:   return(0);
1098: }

1102: /*@
1103:    BVMatProject - Computes the projection of a matrix onto a subspace.

1105:    Collective on BV

1107:    Input Parameters:
1108: +  X - basis vectors
1109: .  A - (optional) matrix to be projected
1110: .  Y - left basis vectors, can be equal to X
1111: -  M - Mat object where the result must be placed

1113:    Output Parameter:
1114: .  M - the resulting matrix

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

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

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

1128:    On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1129:    where ky (resp. kx) is the number of active columns of Y (resp. X).
1130:    Another difference with respect to BVDot() is that all entries of M are
1131:    computed except the leading ly,lx part, where ly (resp. lx) is the
1132:    number of leading columns of Y (resp. X). Hence, the leading columns of
1133:    X and Y participate in the computation, as opposed to BVDot().
1134:    The leading part of M is assumed to be already available from previous
1135:    computations.

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

1141:    Level: intermediate

1143: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1144: @*/
1145: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
1146: {
1148:   PetscBool      match,set,flg,symm=PETSC_FALSE;
1149:   PetscInt       m,n;
1150:   PetscScalar    *marray;
1151:   Mat            Xmatrix,Ymatrix;
1152:   PetscObjectId  idx,idy;

1160:   BVCheckSizes(X,1);
1161:   if (A) {
1164:   }
1166:   BVCheckSizes(Y,3);
1169:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1170:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");

1172:   MatGetSize(M,&m,&n);
1173:   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);
1174:   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);
1175:   if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);

1177:   PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1178:   /* temporarily set standard inner product */
1179:   Xmatrix = X->matrix;
1180:   Ymatrix = Y->matrix;
1181:   X->matrix = Y->matrix = NULL;

1183:   PetscObjectGetId((PetscObject)X,&idx);
1184:   PetscObjectGetId((PetscObject)Y,&idy);
1185:   if (!A && idx==idy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot set X=Y if A=NULL");

1187:   MatDenseGetArray(M,&marray);

1189:   if (A && idx==idy) { /* check symmetry of M=X'AX */
1190:     MatIsHermitianKnown(A,&set,&flg);
1191:     symm = set? flg: PETSC_FALSE;
1192:   }

1194:   if (A) { 
1195:     if (X->vmm==BV_MATMULT_VECS) {
1196:       /* perform computation column by column */
1197:       BVMatProject_Vec(X,A,Y,marray,m,symm);
1198:     } else {
1199:       /* use BVMatMult, then BVDot */
1200:       MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1201:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1202:         BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1203:       } else {
1204:         BVMatProject_MatMult(X,A,Y,marray,m);
1205:       }
1206:     }
1207:   } else {
1208:     /* use BVDot on subblocks */
1209:     BVMatProject_Dot(X,Y,marray,m);
1210:   }

1212:   MatDenseRestoreArray(M,&marray);
1213:   PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1214:   /* restore non-standard inner product */
1215:   X->matrix = Xmatrix;
1216:   Y->matrix = Ymatrix;
1217:   return(0);
1218: }