Actual source code: bvglobal.c

slepc-3.6.1 2015-09-03
Report Typos and Errors
  1: /*
  2:    BV operations involving global communication.

  4:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  5:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  6:    Copyright (c) 2002-2015, 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;

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

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

122:   PetscLogEventBegin(BV_Dot,X,Y,0,0);
123:   if (X->matrix) { /* non-standard inner product: cast into dotvec ops */
124:     BVDot_Private(X,Y,M);
125:   } else {
126:     (*X->ops->dot)(X,Y,M);
127:   }
128:   PetscLogEventEnd(BV_Dot,X,Y,0,0);
129:   return(0);
130: }

134: /*@
135:    BVDotVec - Computes multiple dot products of a vector against all the
136:    column vectors of a BV.

138:    Collective on BV and Vec

140:    Input Parameters:
141: +  X - basis vectors
142: -  y - a vector

144:    Output Parameter:
145: .  m - an array where the result must be placed

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

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

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

159:    Level: intermediate

161: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
162: @*/
163: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar *m)
164: {
166:   PetscInt       n;

172:   BVCheckSizes(X,1);

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

179:   PetscLogEventBegin(BV_Dot,X,y,0,0);
180:   (*X->ops->dotvec)(X,y,m);
181:   PetscLogEventEnd(BV_Dot,X,y,0,0);
182:   return(0);
183: }

187: /*@
188:    BVDotVecBegin - Starts a split phase dot product computation.

190:    Input Parameters:
191: +  X - basis vectors
192: .  y - a vector
193: -  m - an array where the result will go (can be NULL)

195:    Note:
196:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

198:    Level: advanced

200: .seealso: BVDotVecEnd(), BVDotVec()
201: @*/
202: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)
203: {
204:   PetscErrorCode      ierr;
205:   PetscInt            i,n,nv;
206:   PetscSplitReduction *sr;
207:   MPI_Comm            comm;

213:   BVCheckSizes(X,1);

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

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

244: /*@
245:    BVDotVecEnd - Ends a split phase dot product computation.

247:    Input Parameters:
248: +  X - basis vectors
249: .  y - a vector
250: -  m - an array where the result will go

252:    Note:
253:    Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().

255:    Level: advanced

257: .seealso: BVDotVecBegin(), BVDotVec()
258: @*/
259: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)
260: {
261:   PetscErrorCode      ierr;
262:   PetscInt            i,nv;
263:   PetscSplitReduction *sr;
264:   MPI_Comm            comm;

269:   BVCheckSizes(X,1);

271:   if (X->ops->dotvec_end) {
272:     (*X->ops->dotvec_end)(X,y,m);
273:   } else {
274:     nv = X->k-X->l;
275:     PetscObjectGetComm((PetscObject)X,&comm);
276:     PetscSplitReductionGet(comm,&sr);
277:     PetscSplitReductionEnd(sr);

279:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
280:     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()");
281:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
282:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

284:     /* Finished getting all the results so reset to no outstanding requests */
285:     if (sr->numopsend == sr->numopsbegin) {
286:       sr->state       = STATE_BEGIN;
287:       sr->numopsend   = 0;
288:       sr->numopsbegin = 0;
289:     }
290:   }
291:   return(0);
292: }

296: /*@
297:    BVDotColumn - Computes multiple dot products of a column against all the
298:    previous columns of a BV.

300:    Collective on BV

302:    Input Parameters:
303: +  X - basis vectors
304: -  j - the column index

306:    Output Parameter:
307: .  m - an array where the result must be placed

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

317:    Level: advanced

319: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
320: @*/
321: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *m)
322: {
324:   PetscInt       ksave;
325:   Vec            y;

331:   BVCheckSizes(X,1);

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

336:   PetscLogEventBegin(BV_Dot,X,0,0,0);
337:   ksave = X->k;
338:   X->k = j;
339:   BVGetColumn(X,j,&y);
340:   (*X->ops->dotvec)(X,y,m);
341:   BVRestoreColumn(X,j,&y);
342:   X->k = ksave;
343:   PetscLogEventEnd(BV_Dot,X,0,0,0);
344:   return(0);
345: }

349: /*@
350:    BVDotColumnBegin - Starts a split phase dot product computation.

352:    Input Parameters:
353: +  X - basis vectors
354: -  j - the column index
355: -  m - an array where the result will go (can be NULL)

357:    Note:
358:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

360:    Level: advanced

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

376:   BVCheckSizes(X,1);

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

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

410: /*@
411:    BVDotColumnEnd - Ends a split phase dot product computation.

413:    Input Parameters:
414: +  X - basis vectors
415: -  j - the column index
416: -  m - an array where the result will go

418:    Note:
419:    Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().

421:    Level: advanced

423: .seealso: BVDotColumnBegin(), BVDotColumn()
424: @*/
425: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)
426: {
427:   PetscErrorCode      ierr;
428:   PetscInt            i,nv,ksave;
429:   PetscSplitReduction *sr;
430:   MPI_Comm            comm;
431:   Vec                 y;

437:   BVCheckSizes(X,1);

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

444:   if (X->ops->dotvec_end) {
445:     BVGetColumn(X,j,&y);
446:     (*X->ops->dotvec_end)(X,y,m);
447:     BVRestoreColumn(X,j,&y);
448:   } else {
449:     nv = X->k-X->l;
450:     PetscObjectGetComm((PetscObject)X,&comm);
451:     PetscSplitReductionGet(comm,&sr);
452:     PetscSplitReductionEnd(sr);

454:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
455:     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()");
456:     if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
457:     for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];

459:     /* Finished getting all the results so reset to no outstanding requests */
460:     if (sr->numopsend == sr->numopsbegin) {
461:       sr->state       = STATE_BEGIN;
462:       sr->numopsend   = 0;
463:       sr->numopsbegin = 0;
464:     }
465:   }
466:   X->k = ksave;
467:   return(0);
468: }

472: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)
473: {
475:   PetscScalar    p;

478:   BV_IPMatMult(bv,z);
479:   VecDot(bv->Bx,z,&p);
480:   if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
481:     PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
482:   if (bv->indef) {
483:     if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
484:     if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
485:     else *val = PetscSqrtScalar(PetscRealPart(p));
486:   } else { 
487:     if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
488:     *val = PetscSqrtScalar(PetscRealPart(p));
489:   }
490:   return(0);
491: }

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

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

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

514:   VecDotEnd(bv->Bx,z,&p);
515:   if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
516:     PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
517:   if (bv->indef) {
518:     if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
519:     if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
520:     else *val = PetscSqrtScalar(PetscRealPart(p));
521:   } else { 
522:     if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
523:     *val = PetscSqrtScalar(PetscRealPart(p));
524:   }
525:   return(0);
526: }

530: /*@
531:    BVNorm - Computes the matrix norm of the BV.

533:    Collective on BV

535:    Input Parameters:
536: +  bv   - basis vectors
537: -  type - the norm type

539:    Output Parameter:
540: .  val  - the norm

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

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

549:    Level: intermediate

551: .seealso: BVNormVec(), BVNormColumn(), BVSetActiveColumns(), BVSetMatrix()
552: @*/
553: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)
554: {

562:   BVCheckSizes(bv,1);

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

567:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
568:   (*bv->ops->norm)(bv,-1,type,val);
569:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
570:   return(0);
571: }

575: /*@
576:    BVNormVec - Computes the norm of a given vector.

578:    Collective on BV

580:    Input Parameters:
581: +  bv   - basis vectors
582: .  v    - the vector
583: -  type - the norm type

585:    Output Parameter:
586: .  val  - the norm

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

594:    Level: developer

596: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
597: @*/
598: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)
599: {
601:   PetscInt       n;

609:   BVCheckSizes(bv,1);

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

615:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
616:   if (bv->matrix) { /* non-standard inner product */
617:     VecGetLocalSize(v,&n);
618:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
619:     BVNorm_Private(bv,v,type,val);
620:   } else {
621:     VecNorm(v,type,val);
622:   }
623:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
624:   return(0);
625: }

629: /*@
630:    BVNormVecBegin - Starts a split phase norm computation.

632:    Input Parameters:
633: +  bv   - basis vectors
634: .  v    - the vector
635: .  type - the norm type
636: -  val  - the norm

638:    Note:
639:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

641:    Level: advanced

643: .seealso: BVNormVecEnd(), BVNormVec()
644: @*/
645: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)
646: {
648:   PetscInt       n;

656:   BVCheckSizes(bv,1);

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

662:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
663:   if (bv->matrix) { /* non-standard inner product */
664:     VecGetLocalSize(v,&n);
665:     if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
666:     BVNorm_Begin_Private(bv,v,type,val);
667:   } else {
668:     VecNormBegin(v,type,val);
669:   }
670:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
671:   return(0);
672: }

676: /*@
677:    BVNormVecEnd - Ends a split phase norm computation.

679:    Input Parameters:
680: +  bv   - basis vectors
681: .  v    - the vector
682: .  type - the norm type
683: -  val  - the norm

685:    Note:
686:    Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().

688:    Level: advanced

690: .seealso: BVNormVecBegin(), BVNormVec()
691: @*/
692: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)
693: {

701:   BVCheckSizes(bv,1);

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

705:   if (bv->matrix) { /* non-standard inner product */
706:     BVNorm_End_Private(bv,v,type,val);
707:   } else {
708:     VecNormEnd(v,type,val);
709:   }
710:   return(0);
711: }

715: /*@
716:    BVNormColumn - Computes the vector norm of a selected column.

718:    Collective on BV

720:    Input Parameters:
721: +  bv   - basis vectors
722: .  j    - column number to be used
723: -  type - the norm type

725:    Output Parameter:
726: .  val  - the norm

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

734:    Level: intermediate

736: .seealso: BVNorm(), BVNormVec(), BVSetActiveColumns(), BVSetMatrix()
737: @*/
738: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)
739: {
741:   Vec            z;

749:   BVCheckSizes(bv,1);

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

754:   PetscLogEventBegin(BV_Norm,bv,0,0,0);
755:   if (bv->matrix) { /* non-standard inner product */
756:     BVGetColumn(bv,j,&z);
757:     BVNorm_Private(bv,z,type,val);
758:     BVRestoreColumn(bv,j,&z);
759:   } else {
760:     (*bv->ops->norm)(bv,j,type,val);
761:   }
762:   PetscLogEventEnd(BV_Norm,bv,0,0,0);
763:   return(0);
764: }

768: /*@
769:    BVNormColumnBegin - Starts a split phase norm computation.

771:    Input Parameters:
772: +  bv   - basis vectors
773: .  j    - column number to be used
774: .  type - the norm type
775: -  val  - the norm

777:    Note:
778:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

780:    Level: advanced

782: .seealso: BVNormColumnEnd(), BVNormColumn()
783: @*/
784: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)
785: {
786:   PetscErrorCode      ierr;
787:   PetscSplitReduction *sr;
788:   PetscReal           lresult;
789:   MPI_Comm            comm;
790:   Vec                 z;

798:   BVCheckSizes(bv,1);

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

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

830: /*@
831:    BVNormColumnEnd - Ends a split phase norm computation.

833:    Input Parameters:
834: +  bv   - basis vectors
835: .  j    - column number to be used
836: .  type - the norm type
837: -  val  - the norm

839:    Note:
840:    Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().

842:    Level: advanced

844: .seealso: BVNormColumnBegin(), BVNormColumn()
845: @*/
846: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)
847: {
848:   PetscErrorCode      ierr;
849:   PetscSplitReduction *sr;
850:   MPI_Comm            comm;
851:   Vec                 z;

859:   BVCheckSizes(bv,1);

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

863:   BVGetColumn(bv,j,&z);
864:   if (bv->matrix) { /* non-standard inner product */
865:     BVNorm_End_Private(bv,z,type,val);
866:   } else if (bv->ops->norm_end) {
867:     (*bv->ops->norm_end)(bv,j,type,val);
868:   } else {
869:     PetscObjectGetComm((PetscObject)z,&comm);
870:     PetscSplitReductionGet(comm,&sr);
871:     PetscSplitReductionEnd(sr);

873:     if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
874:     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()");
875:     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");
876:     *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
877:     if (type == NORM_2) *val = PetscSqrtReal(*val);
878:     if (sr->numopsend == sr->numopsbegin) {
879:       sr->state       = STATE_BEGIN;
880:       sr->numopsend   = 0;
881:       sr->numopsbegin = 0;
882:     }
883:   }
884:   BVRestoreColumn(bv,j,&z);
885:   return(0);
886: }

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

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

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

951:   lx = X->l; kx = X->k;
952:   ly = Y->l; ky = Y->k;
953:   BVDuplicate(X,&W);
954:   X->l = 0; X->k = kx;
955:   BVMatMult(X,A,W);

957:   /* top-right part, Y0'*AX1 */
958:   if (ly>0 && lx<kx) {
959:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
960:     W->l = lx; W->k = kx;
961:     Y->l = 0;  Y->k = ly;
962:     BVDot(W,Y,H);
963:     MatDenseGetArray(H,&harray);
964:     for (j=lx;j<kx;j++) {
965:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
966:     }
967:     MatDenseRestoreArray(H,&harray);
968:     MatDestroy(&H);
969:   }

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

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

1008:   lx = X->l; kx = X->k;
1009:   ly = Y->l; ky = Y->k;

1011:   /* right part, Y'*AX1 */
1012:   BVDuplicateResize(X,kx-lx,&W);
1013:   if (ky>0 && lx<kx) {
1014:     BVMatMult(X,A,W);
1015:     MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
1016:     Y->l = 0; Y->k = ky;
1017:     BVDot(W,Y,H);
1018:     MatDenseGetArray(H,&harray);
1019:     for (j=lx;j<kx;j++) {
1020:       PetscMemcpy(marray+j*ldm,harray+(j-lx)*ky,ky*sizeof(PetscScalar));
1021:     }
1022:     MatDenseRestoreArray(H,&harray);
1023:     MatDestroy(&H);
1024:   }

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

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

1072:   lx = X->l; kx = X->k;
1073:   ly = Y->l; ky = Y->k;

1075:   /* top-right part, Y0'*X1 */
1076:   if (ly>0 && lx<kx) {
1077:     MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1078:     X->l = lx; X->k = kx;
1079:     Y->l = 0;  Y->k = ly;
1080:     BVDot(X,Y,H);
1081:     MatDenseGetArray(H,&harray);
1082:     for (j=lx;j<kx;j++) {
1083:       PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
1084:     }
1085:     MatDenseRestoreArray(H,&harray);
1086:     MatDestroy(&H);
1087:   }

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

1109: /*@
1110:    BVMatProject - Computes the projection of a matrix onto a subspace.

1112:    Collective on BV

1114:    Input Parameters:
1115: +  X - basis vectors
1116: .  A - (optional) matrix to be projected
1117: .  Y - left basis vectors, can be equal to X
1118: -  M - Mat object where the result must be placed

1120:    Output Parameter:
1121: .  M - the resulting matrix

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

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

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

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

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

1148:    Level: intermediate

1150: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1151: @*/
1152: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)
1153: {
1155:   PetscBool      match,set,flg,symm=PETSC_FALSE;
1156:   PetscInt       m,n;
1157:   PetscScalar    *marray;
1158:   Mat            Xmatrix,Ymatrix;
1159:   PetscObjectId  idx,idy;

1167:   BVCheckSizes(X,1);
1168:   if (A) {
1171:   }
1173:   BVCheckSizes(Y,3);
1176:   PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1177:   if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");

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

1184:   PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1185:   /* temporarily set standard inner product */
1186:   Xmatrix = X->matrix;
1187:   Ymatrix = Y->matrix;
1188:   X->matrix = Y->matrix = NULL;

1190:   PetscObjectGetId((PetscObject)X,&idx);
1191:   PetscObjectGetId((PetscObject)Y,&idy);
1192:   if (!A && idx==idy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot set X=Y if A=NULL");

1194:   MatDenseGetArray(M,&marray);

1196:   if (A && idx==idy) { /* check symmetry of M=X'AX */
1197:     MatIsHermitianKnown(A,&set,&flg);
1198:     symm = set? flg: PETSC_FALSE;
1199:   }

1201:   if (A) { 
1202:     if (X->vmm==BV_MATMULT_VECS) {
1203:       /* perform computation column by column */
1204:       BVMatProject_Vec(X,A,Y,marray,m,symm);
1205:     } else {
1206:       /* use BVMatMult, then BVDot */
1207:       MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1208:       if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1209:         BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1210:       } else {
1211:         BVMatProject_MatMult(X,A,Y,marray,m);
1212:       }
1213:     }
1214:   } else {
1215:     /* use BVDot on subblocks */
1216:     BVMatProject_Dot(X,Y,marray,m);
1217:   }

1219:   MatDenseRestoreArray(M,&marray);
1220:   PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1221:   /* restore non-standard inner product */
1222:   X->matrix = Xmatrix;
1223:   Y->matrix = Ymatrix;
1224:   return(0);
1225: }