Date: 2017-05-17T08:25:16+00:00

Actual source code: bvglobal.c
slepc-3.7.4 2017-05-17
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:     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: }