Actual source code: bvops.c
 
   slepc-3.19.2 2023-09-05
   
  1: /*
  2:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  3:    SLEPc - Scalable Library for Eigenvalue Problem Computations
  4:    Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
  6:    This file is part of SLEPc.
  7:    SLEPc is distributed under a 2-clause BSD license (see LICENSE).
  8:    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  9: */
 10: /*
 11:    BV operations, except those involving global communication
 12: */
 14: #include <slepc/private/bvimpl.h>
 15: #include <slepcds.h>
 17: /*@
 18:    BVMult - Computes Y = beta*Y + alpha*X*Q.
 20:    Logically Collective
 22:    Input Parameters:
 23: +  Y     - first basis vectors context (modified on output)
 24: .  alpha - first scalar
 25: .  beta  - second scalar
 26: .  X     - second basis vectors context
 27: -  Q     - (optional) sequential dense matrix
 29:    Notes:
 30:    X and Y must be different objects. The case X=Y can be addressed with
 31:    BVMultInPlace().
 33:    If matrix Q is NULL, then an AXPY operation Y = beta*Y + alpha*X is done
 34:    (i.e. results as if Q = identity). If provided,
 35:    the matrix Q must be a sequential dense Mat, with all entries equal on
 36:    all processes (otherwise each process will compute a different update).
 37:    The dimensions of Q must be at least m,n where m is the number of active
 38:    columns of X and n is the number of active columns of Y.
 40:    The leading columns of Y are not modified. Also, if X has leading
 41:    columns specified, then these columns do not participate in the computation.
 42:    Hence, only rows (resp. columns) of Q starting from lx (resp. ly) are used,
 43:    where lx (resp. ly) is the number of leading columns of X (resp. Y).
 45:    Level: intermediate
 47: .seealso: BVMultVec(), BVMultColumn(), BVMultInPlace(), BVSetActiveColumns()
 48: @*/
 49: PetscErrorCode BVMult(BV Y,PetscScalar alpha,PetscScalar beta,BV X,Mat Q)
 50: {
 51:   PetscInt       m,n;
 53:   PetscFunctionBegin;
 60:   BVCheckSizes(Y,1);
 61:   BVCheckOp(Y,1,mult);
 63:   BVCheckSizes(X,4);
 65:   PetscCheckSameTypeAndComm(Y,1,X,4);
 66:   PetscCheck(X!=Y,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_WRONG,"X and Y arguments must be different");
 67:   if (Q) {
 68:     PetscCheckTypeNames(Q,MATSEQDENSE,MATSEQDENSECUDA);
 69:     PetscCall(MatGetSize(Q,&m,&n));
 70:     PetscCheck(m>=X->k,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " rows, should have at least %" PetscInt_FMT,m,X->k);
 71:     PetscCheck(n>=Y->k,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " columns, should have at least %" PetscInt_FMT,n,Y->k);
 72:   }
 73:   PetscCheck(X->n==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %" PetscInt_FMT ", Y %" PetscInt_FMT,X->n,Y->n);
 75:   PetscCall(PetscLogEventBegin(BV_Mult,X,Y,0,0));
 76:   PetscUseTypeMethod(Y,mult,alpha,beta,X,Q);
 77:   PetscCall(PetscLogEventEnd(BV_Mult,X,Y,0,0));
 78:   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
 79:   PetscFunctionReturn(PETSC_SUCCESS);
 80: }
 82: /*@
 83:    BVMultVec - Computes y = beta*y + alpha*X*q.
 85:    Logically Collective
 87:    Input Parameters:
 88: +  X     - a basis vectors object
 89: .  alpha - first scalar
 90: .  beta  - second scalar
 91: .  y     - a vector (modified on output)
 92: -  q     - an array of scalars
 94:    Notes:
 95:    This operation is the analogue of BVMult() but with a BV and a Vec,
 96:    instead of two BV. Note that arguments are listed in different order
 97:    with respect to BVMult().
 99:    If X has leading columns specified, then these columns do not participate
100:    in the computation.
102:    The length of array q must be equal to the number of active columns of X
103:    minus the number of leading columns, i.e. the first entry of q multiplies
104:    the first non-leading column.
106:    Level: intermediate
108: .seealso: BVMult(), BVMultColumn(), BVMultInPlace(), BVSetActiveColumns()
109: @*/
110: PetscErrorCode BVMultVec(BV X,PetscScalar alpha,PetscScalar beta,Vec y,PetscScalar q[])
111: {
112:   PetscInt       n,N;
114:   PetscFunctionBegin;
121:   BVCheckSizes(X,1);
122:   BVCheckOp(X,1,multvec);
124:   PetscCheckSameComm(X,1,y,4);
126:   PetscCall(VecGetSize(y,&N));
127:   PetscCall(VecGetLocalSize(y,&n));
128:   PetscCheck(N==X->N && n==X->n,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Vec sizes (global %" PetscInt_FMT ", local %" PetscInt_FMT ") do not match BV sizes (global %" PetscInt_FMT ", local %" PetscInt_FMT ")",N,n,X->N,X->n);
130:   PetscCall(PetscLogEventBegin(BV_MultVec,X,y,0,0));
131:   PetscUseTypeMethod(X,multvec,alpha,beta,y,q);
132:   PetscCall(PetscLogEventEnd(BV_MultVec,X,y,0,0));
133:   PetscFunctionReturn(PETSC_SUCCESS);
134: }
136: /*@
137:    BVMultColumn - Computes y = beta*y + alpha*X*q, where y is the j-th column
138:    of X.
140:    Logically Collective
142:    Input Parameters:
143: +  X     - a basis vectors object
144: .  alpha - first scalar
145: .  beta  - second scalar
146: .  j     - the column index
147: -  q     - an array of scalars
149:    Notes:
150:    This operation is equivalent to BVMultVec() but it uses column j of X
151:    rather than taking a Vec as an argument. The number of active columns of
152:    X is set to j before the computation, and restored afterwards.
153:    If X has leading columns specified, then these columns do not participate
154:    in the computation. Therefore, the length of array q must be equal to j
155:    minus the number of leading columns.
157:    Developer Notes:
158:    If q is NULL, then the coefficients are taken from position nc+l of the
159:    internal buffer vector, see BVGetBufferVec().
161:    Level: advanced
163: .seealso: BVMult(), BVMultVec(), BVMultInPlace(), BVSetActiveColumns()
164: @*/
165: PetscErrorCode BVMultColumn(BV X,PetscScalar alpha,PetscScalar beta,PetscInt j,PetscScalar *q)
166: {
167:   PetscInt       ksave;
168:   Vec            y;
170:   PetscFunctionBegin;
176:   BVCheckSizes(X,1);
178:   PetscCheck(j>=0,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
179:   PetscCheck(j<X->m,PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,X->m);
181:   PetscCall(PetscLogEventBegin(BV_MultVec,X,0,0,0));
182:   ksave = X->k;
183:   X->k = j;
184:   if (!q && !X->buffer) PetscCall(BVGetBufferVec(X,&X->buffer));
185:   PetscCall(BVGetColumn(X,j,&y));
186:   PetscUseTypeMethod(X,multvec,alpha,beta,y,q);
187:   PetscCall(BVRestoreColumn(X,j,&y));
188:   X->k = ksave;
189:   PetscCall(PetscLogEventEnd(BV_MultVec,X,0,0,0));
190:   PetscCall(PetscObjectStateIncrease((PetscObject)X));
191:   PetscFunctionReturn(PETSC_SUCCESS);
192: }
194: /*@
195:    BVMultInPlace - Update a set of vectors as V(:,s:e-1) = V*Q(:,s:e-1).
197:    Logically Collective
199:    Input Parameters:
200: +  Q - a sequential dense matrix
201: .  s - first column of V to be overwritten
202: -  e - first column of V not to be overwritten
204:    Input/Output Parameter:
205: .  V - basis vectors
207:    Notes:
208:    The matrix Q must be a sequential dense Mat, with all entries equal on
209:    all processes (otherwise each process will compute a different update).
211:    This function computes V(:,s:e-1) = V*Q(:,s:e-1), that is, given a set of
212:    vectors V, columns from s to e-1 are overwritten with columns from s to
213:    e-1 of the matrix-matrix product V*Q. Only columns s to e-1 of Q are
214:    referenced.
216:    Level: intermediate
218: .seealso: BVMult(), BVMultVec(), BVMultInPlaceHermitianTranspose(), BVSetActiveColumns()
219: @*/
220: PetscErrorCode BVMultInPlace(BV V,Mat Q,PetscInt s,PetscInt e)
221: {
222:   PetscInt       m,n;
224:   PetscFunctionBegin;
230:   BVCheckSizes(V,1);
232:   PetscCheckTypeNames(Q,MATSEQDENSE,MATSEQDENSECUDA);
234:   PetscCheck(s>=V->l && s<=V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument s has wrong value %" PetscInt_FMT ", should be between %" PetscInt_FMT " and %" PetscInt_FMT,s,V->l,V->m);
235:   PetscCheck(e>=V->l && e<=V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument e has wrong value %" PetscInt_FMT ", should be between %" PetscInt_FMT " and %" PetscInt_FMT,e,V->l,V->m);
236:   PetscCall(MatGetSize(Q,&m,&n));
237:   PetscCheck(m>=V->k,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " rows, should have at least %" PetscInt_FMT,m,V->k);
238:   PetscCheck(e<=n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument only has %" PetscInt_FMT " columns, the requested value of e is larger: %" PetscInt_FMT,n,e);
239:   if (s>=e) PetscFunctionReturn(PETSC_SUCCESS);
241:   PetscCall(PetscLogEventBegin(BV_MultInPlace,V,Q,0,0));
242:   PetscUseTypeMethod(V,multinplace,Q,s,e);
243:   PetscCall(PetscLogEventEnd(BV_MultInPlace,V,Q,0,0));
244:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
245:   PetscFunctionReturn(PETSC_SUCCESS);
246: }
248: /*@
249:    BVMultInPlaceHermitianTranspose - Update a set of vectors as V(:,s:e-1) = V*Q'(:,s:e-1).
251:    Logically Collective
253:    Input Parameters:
254: +  Q - a sequential dense matrix
255: .  s - first column of V to be overwritten
256: -  e - first column of V not to be overwritten
258:    Input/Output Parameter:
259: .  V - basis vectors
261:    Notes:
262:    This is a variant of BVMultInPlace() where the conjugate transpose
263:    of Q is used.
265:    Level: intermediate
267: .seealso: BVMultInPlace()
268: @*/
269: PetscErrorCode BVMultInPlaceHermitianTranspose(BV V,Mat Q,PetscInt s,PetscInt e)
270: {
271:   PetscInt       m,n;
273:   PetscFunctionBegin;
279:   BVCheckSizes(V,1);
281:   PetscCheckTypeNames(Q,MATSEQDENSE,MATSEQDENSECUDA);
283:   PetscCheck(s>=V->l && s<=V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument s has wrong value %" PetscInt_FMT ", should be between %" PetscInt_FMT " and %" PetscInt_FMT,s,V->l,V->m);
284:   PetscCheck(e>=V->l && e<=V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument e has wrong value %" PetscInt_FMT ", should be between %" PetscInt_FMT " and %" PetscInt_FMT,e,V->l,V->m);
285:   PetscCall(MatGetSize(Q,&m,&n));
286:   PetscCheck(n>=V->k,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument has %" PetscInt_FMT " columns, should have at least %" PetscInt_FMT,n,V->k);
287:   PetscCheck(e<=m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument only has %" PetscInt_FMT " rows, the requested value of e is larger: %" PetscInt_FMT,m,e);
288:   if (s>=e || !V->n) PetscFunctionReturn(PETSC_SUCCESS);
290:   PetscCall(PetscLogEventBegin(BV_MultInPlace,V,Q,0,0));
291:   PetscUseTypeMethod(V,multinplacetrans,Q,s,e);
292:   PetscCall(PetscLogEventEnd(BV_MultInPlace,V,Q,0,0));
293:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
294:   PetscFunctionReturn(PETSC_SUCCESS);
295: }
297: /*@
298:    BVScale - Multiply the BV entries by a scalar value.
300:    Logically Collective
302:    Input Parameters:
303: +  bv    - basis vectors
304: -  alpha - scaling factor
306:    Note:
307:    All active columns (except the leading ones) are scaled.
309:    Level: intermediate
311: .seealso: BVScaleColumn(), BVSetActiveColumns()
312: @*/
313: PetscErrorCode BVScale(BV bv,PetscScalar alpha)
314: {
315:   PetscFunctionBegin;
319:   BVCheckSizes(bv,1);
320:   if (alpha == (PetscScalar)1.0) PetscFunctionReturn(PETSC_SUCCESS);
322:   PetscCall(PetscLogEventBegin(BV_Scale,bv,0,0,0));
323:   if (bv->n) PetscUseTypeMethod(bv,scale,-1,alpha);
324:   PetscCall(PetscLogEventEnd(BV_Scale,bv,0,0,0));
325:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
326:   PetscFunctionReturn(PETSC_SUCCESS);
327: }
329: /*@
330:    BVScaleColumn - Scale one column of a BV.
332:    Logically Collective
334:    Input Parameters:
335: +  bv    - basis vectors
336: .  j     - column number to be scaled
337: -  alpha - scaling factor
339:    Level: intermediate
341: .seealso: BVScale(), BVSetActiveColumns()
342: @*/
343: PetscErrorCode BVScaleColumn(BV bv,PetscInt j,PetscScalar alpha)
344: {
345:   PetscFunctionBegin;
350:   BVCheckSizes(bv,1);
352:   PetscCheck(j>=0 && j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %" PetscInt_FMT ", the number of columns is %" PetscInt_FMT,j,bv->m);
353:   if (alpha == (PetscScalar)1.0) PetscFunctionReturn(PETSC_SUCCESS);
355:   PetscCall(PetscLogEventBegin(BV_Scale,bv,0,0,0));
356:   if (bv->n) PetscUseTypeMethod(bv,scale,j,alpha);
357:   PetscCall(PetscLogEventEnd(BV_Scale,bv,0,0,0));
358:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
359:   PetscFunctionReturn(PETSC_SUCCESS);
360: }
362: static inline PetscErrorCode BVSetRandomColumn_Private(BV bv,PetscInt k)
363: {
364:   PetscInt       i,low,high;
365:   PetscScalar    *px,t;
366:   Vec            x;
368:   PetscFunctionBegin;
369:   PetscCall(BVGetColumn(bv,k,&x));
370:   if (bv->rrandom) {  /* generate the same vector irrespective of number of processes */
371:     PetscCall(VecGetOwnershipRange(x,&low,&high));
372:     PetscCall(VecGetArray(x,&px));
373:     for (i=0;i<bv->N;i++) {
374:       PetscCall(PetscRandomGetValue(bv->rand,&t));
375:       if (i>=low && i<high) px[i-low] = t;
376:     }
377:     PetscCall(VecRestoreArray(x,&px));
378:   } else PetscCall(VecSetRandom(x,bv->rand));
379:   PetscCall(BVRestoreColumn(bv,k,&x));
380:   PetscFunctionReturn(PETSC_SUCCESS);
381: }
383: static inline PetscErrorCode BVSetRandomNormalColumn_Private(BV bv,PetscInt k,Vec w1,Vec w2)
384: {
385:   PetscInt       i,low,high;
386:   PetscScalar    *px,s,t;
387:   Vec            x;
389:   PetscFunctionBegin;
390:   PetscCall(BVGetColumn(bv,k,&x));
391:   if (bv->rrandom) {  /* generate the same vector irrespective of number of processes */
392:     PetscCall(VecGetOwnershipRange(x,&low,&high));
393:     PetscCall(VecGetArray(x,&px));
394:     for (i=0;i<bv->N;i++) {
395:       PetscCall(PetscRandomGetValue(bv->rand,&s));
396:       PetscCall(PetscRandomGetValue(bv->rand,&t));
397:       if (i>=low && i<high) {
398: #if defined(PETSC_USE_COMPLEX)
399:         px[i-low] = PetscCMPLX(PetscSqrtReal(-2.0*PetscLogReal(PetscRealPart(s)))*PetscCosReal(2.0*PETSC_PI*PetscRealPart(t)),PetscSqrtReal(-2.0*PetscLogReal(PetscImaginaryPart(s)))*PetscCosReal(2.0*PETSC_PI*PetscImaginaryPart(t)));
400: #else
401:         px[i-low] = PetscSqrtReal(-2.0*PetscLogReal(s))*PetscCosReal(2.0*PETSC_PI*t);
402: #endif
403:       }
404:     }
405:     PetscCall(VecRestoreArray(x,&px));
406:   } else PetscCall(VecSetRandomNormal(x,bv->rand,w1,w2));
407:   PetscCall(BVRestoreColumn(bv,k,&x));
408:   PetscFunctionReturn(PETSC_SUCCESS);
409: }
411: static inline PetscErrorCode BVSetRandomSignColumn_Private(BV bv,PetscInt k)
412: {
413:   PetscInt       i,low,high;
414:   PetscScalar    *px,t;
415:   Vec            x;
417:   PetscFunctionBegin;
418:   PetscCall(BVGetColumn(bv,k,&x));
419:   PetscCall(VecGetOwnershipRange(x,&low,&high));
420:   if (bv->rrandom) {  /* generate the same vector irrespective of number of processes */
421:     PetscCall(VecGetArray(x,&px));
422:     for (i=0;i<bv->N;i++) {
423:       PetscCall(PetscRandomGetValue(bv->rand,&t));
424:       if (i>=low && i<high) px[i-low] = (PetscRealPart(t)<0.5)? -1.0: 1.0;
425:     }
426:     PetscCall(VecRestoreArray(x,&px));
427:   } else {
428:     PetscCall(VecSetRandom(x,bv->rand));
429:     PetscCall(VecGetArray(x,&px));
430:     for (i=low;i<high;i++) {
431:       px[i-low] = (PetscRealPart(px[i-low])<0.5)? -1.0: 1.0;
432:     }
433:     PetscCall(VecRestoreArray(x,&px));
434:   }
435:   PetscCall(BVRestoreColumn(bv,k,&x));
436:   PetscFunctionReturn(PETSC_SUCCESS);
437: }
439: /*@
440:    BVSetRandom - Set the columns of a BV to random numbers.
442:    Logically Collective
444:    Input Parameters:
445: .  bv - basis vectors
447:    Note:
448:    All active columns (except the leading ones) are modified.
450:    Level: advanced
452: .seealso: BVSetRandomContext(), BVSetRandomColumn(), BVSetRandomNormal(), BVSetRandomSign(), BVSetRandomCond(), BVSetActiveColumns()
453: @*/
454: PetscErrorCode BVSetRandom(BV bv)
455: {
456:   PetscInt       k;
458:   PetscFunctionBegin;
461:   BVCheckSizes(bv,1);
463:   PetscCall(BVGetRandomContext(bv,&bv->rand));
464:   PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
465:   for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomColumn_Private(bv,k));
466:   PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
467:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
468:   PetscFunctionReturn(PETSC_SUCCESS);
469: }
471: /*@
472:    BVSetRandomColumn - Set one column of a BV to random numbers.
474:    Logically Collective
476:    Input Parameters:
477: +  bv - basis vectors
478: -  j  - column number to be set
480:    Level: advanced
482: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomNormal(), BVSetRandomCond()
483: @*/
484: PetscErrorCode BVSetRandomColumn(BV bv,PetscInt j)
485: {
486:   PetscFunctionBegin;
490:   BVCheckSizes(bv,1);
491:   PetscCheck(j>=0 && j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %" PetscInt_FMT ", the number of columns is %" PetscInt_FMT,j,bv->m);
493:   PetscCall(BVGetRandomContext(bv,&bv->rand));
494:   PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
495:   PetscCall(BVSetRandomColumn_Private(bv,j));
496:   PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
497:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
498:   PetscFunctionReturn(PETSC_SUCCESS);
499: }
501: /*@
502:    BVSetRandomNormal - Set the columns of a BV to random numbers with a normal
503:    distribution.
505:    Logically Collective
507:    Input Parameter:
508: .  bv - basis vectors
510:    Notes:
511:    All active columns (except the leading ones) are modified.
513:    Other functions such as BVSetRandom(), BVSetRandomColumn(), and BVSetRandomCond()
514:    produce random numbers with a uniform distribution. This function returns values
515:    that fit a normal distribution (Gaussian).
517:    Developer Notes:
518:    The current implementation obtains each of the columns by applying the Box-Muller
519:    transform on two random vectors with uniformly distributed entries.
521:    Level: advanced
523: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetRandomCond(), BVSetActiveColumns()
524: @*/
525: PetscErrorCode BVSetRandomNormal(BV bv)
526: {
527:   PetscInt       k;
528:   Vec            w1=NULL,w2=NULL;
530:   PetscFunctionBegin;
533:   BVCheckSizes(bv,1);
535:   PetscCall(BVGetRandomContext(bv,&bv->rand));
536:   if (!bv->rrandom) {
537:     PetscCall(BVCreateVec(bv,&w1));
538:     PetscCall(BVCreateVec(bv,&w2));
539:   }
540:   PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
541:   for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomNormalColumn_Private(bv,k,w1,w2));
542:   PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
543:   if (!bv->rrandom) {
544:     PetscCall(VecDestroy(&w1));
545:     PetscCall(VecDestroy(&w2));
546:   }
547:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
548:   PetscFunctionReturn(PETSC_SUCCESS);
549: }
551: /*@
552:    BVSetRandomSign - Set the entries of a BV to values 1 or -1 with equal
553:    probability.
555:    Logically Collective
557:    Input Parameter:
558: .  bv - basis vectors
560:    Notes:
561:    All active columns (except the leading ones) are modified.
563:    This function is used, e.g., in contour integral methods when estimating
564:    the number of eigenvalues enclosed by the contour via an unbiased
565:    estimator of tr(f(A)) [Bai et al., JCAM 1996].
567:    Developer Notes:
568:    The current implementation obtains random numbers and then replaces them
569:    with -1 or 1 depending on the value being less than 0.5 or not.
571:    Level: advanced
573: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetActiveColumns()
574: @*/
575: PetscErrorCode BVSetRandomSign(BV bv)
576: {
577:   PetscScalar    low,high;
578:   PetscInt       k;
580:   PetscFunctionBegin;
583:   BVCheckSizes(bv,1);
585:   PetscCall(BVGetRandomContext(bv,&bv->rand));
586:   PetscCall(PetscRandomGetInterval(bv->rand,&low,&high));
587:   PetscCheck(PetscRealPart(low)==0.0 && PetscRealPart(high)==1.0,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"The PetscRandom object in the BV must have interval [0,1]");
588:   PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
589:   for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomSignColumn_Private(bv,k));
590:   PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
591:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
592:   PetscFunctionReturn(PETSC_SUCCESS);
593: }
595: /*@
596:    BVSetRandomCond - Set the columns of a BV to random numbers, in a way that
597:    the generated matrix has a given condition number.
599:    Logically Collective
601:    Input Parameters:
602: +  bv    - basis vectors
603: -  condn - condition number
605:    Note:
606:    All active columns (except the leading ones) are modified.
608:    Level: advanced
610: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetRandomNormal(), BVSetActiveColumns()
611: @*/
612: PetscErrorCode BVSetRandomCond(BV bv,PetscReal condn)
613: {
614:   PetscInt       k,i;
615:   PetscScalar    *eig,*d;
616:   DS             ds;
617:   Mat            A,X,Xt,M,G;
619:   PetscFunctionBegin;
622:   BVCheckSizes(bv,1);
624:   PetscCall(BVGetRandomContext(bv,&bv->rand));
625:   PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
626:   /* B = rand(n,k) */
627:   for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomColumn_Private(bv,k));
628:   PetscCall(DSCreate(PetscObjectComm((PetscObject)bv),&ds));
629:   PetscCall(DSSetType(ds,DSHEP));
630:   PetscCall(DSAllocate(ds,bv->m));
631:   PetscCall(DSSetDimensions(ds,bv->k,bv->l,bv->k));
632:   /* [V,S] = eig(B'*B) */
633:   PetscCall(DSGetMat(ds,DS_MAT_A,&A));
634:   PetscCall(BVDot(bv,bv,A));
635:   PetscCall(DSRestoreMat(ds,DS_MAT_A,&A));
636:   PetscCall(PetscMalloc1(bv->m,&eig));
637:   PetscCall(DSSolve(ds,eig,NULL));
638:   PetscCall(DSSynchronize(ds,eig,NULL));
639:   PetscCall(DSVectors(ds,DS_MAT_X,NULL,NULL));
640:   /* M = diag(linspace(1/condn,1,n)./sqrt(diag(S)))' */
641:   PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,bv->k,bv->k,NULL,&M));
642:   PetscCall(MatZeroEntries(M));
643:   PetscCall(MatDenseGetArray(M,&d));
644:   for (i=0;i<bv->k;i++) d[i+i*bv->m] = (1.0/condn+(1.0-1.0/condn)/(bv->k-1)*i)/PetscSqrtScalar(eig[i]);
645:   PetscCall(MatDenseRestoreArray(M,&d));
646:   /* G = X*M*X' */
647:   PetscCall(DSGetMat(ds,DS_MAT_X,&X));
648:   PetscCall(MatTranspose(X,MAT_INITIAL_MATRIX,&Xt));
649:   PetscCall(MatProductCreate(Xt,M,NULL,&G));
650:   PetscCall(MatProductSetType(G,MATPRODUCT_PtAP));
651:   PetscCall(MatProductSetFromOptions(G));
652:   PetscCall(MatProductSymbolic(G));
653:   PetscCall(MatProductNumeric(G));
654:   PetscCall(MatProductClear(G));
655:   PetscCall(DSRestoreMat(ds,DS_MAT_X,&X));
656:   PetscCall(MatDestroy(&Xt));
657:   PetscCall(MatDestroy(&M));
658:   /* B = B*G */
659:   PetscCall(BVMultInPlace(bv,G,bv->l,bv->k));
660:   PetscCall(MatDestroy(&G));
661:   PetscCall(PetscFree(eig));
662:   PetscCall(DSDestroy(&ds));
663:   PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
664:   PetscCall(PetscObjectStateIncrease((PetscObject)bv));
665:   PetscFunctionReturn(PETSC_SUCCESS);
666: }
668: /*@
669:    BVMatMult - Computes the matrix-vector product for each column, Y=A*V.
671:    Neighbor-wise Collective
673:    Input Parameters:
674: +  V - basis vectors context
675: -  A - the matrix
677:    Output Parameter:
678: .  Y - the result
680:    Notes:
681:    Both V and Y must be distributed in the same manner. Only active columns
682:    (excluding the leading ones) are processed.
683:    In the result Y, columns are overwritten starting from the leading ones.
684:    The number of active columns in V and Y should match, although they need
685:    not be the same columns.
687:    It is possible to choose whether the computation is done column by column
688:    or as a Mat-Mat product, see BVSetMatMultMethod().
690:    Level: beginner
692: .seealso: BVCopy(), BVSetActiveColumns(), BVMatMultColumn(), BVMatMultTranspose(), BVMatMultHermitianTranspose(), BVSetMatMultMethod()
693: @*/
694: PetscErrorCode BVMatMult(BV V,Mat A,BV Y)
695: {
696:   PetscInt       M,N,m,n;
698:   PetscFunctionBegin;
701:   BVCheckSizes(V,1);
702:   BVCheckOp(V,1,matmult);
707:   BVCheckSizes(Y,3);
708:   PetscCheckSameComm(V,1,A,2);
709:   PetscCheckSameTypeAndComm(V,1,Y,3);
711:   PetscCall(MatGetSize(A,&M,&N));
712:   PetscCall(MatGetLocalSize(A,&m,&n));
713:   PetscCheck(M==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,M,Y->N);
714:   PetscCheck(m==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,m,Y->n);
715:   PetscCheck(N==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,N,V->N);
716:   PetscCheck(n==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,n,V->n);
717:   PetscCheck(V->k-V->l==Y->k-Y->l,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Y has %" PetscInt_FMT " active columns, should match %" PetscInt_FMT " active columns in V",Y->k-Y->l,V->k-V->l);
719:   PetscCall(PetscLogEventBegin(BV_MatMult,V,A,Y,0));
720:   PetscUseTypeMethod(V,matmult,A,Y);
721:   PetscCall(PetscLogEventEnd(BV_MatMult,V,A,Y,0));
722:   PetscCall(PetscObjectStateIncrease((PetscObject)Y));
723:   PetscFunctionReturn(PETSC_SUCCESS);
724: }
726: /*@
727:    BVMatMultTranspose - Computes the matrix-vector product with the transpose
728:    of a matrix for each column, Y=A^T*V.
730:    Neighbor-wise Collective
732:    Input Parameters:
733: +  V - basis vectors context
734: -  A - the matrix
736:    Output Parameter:
737: .  Y - the result
739:    Notes:
740:    Both V and Y must be distributed in the same manner. Only active columns
741:    (excluding the leading ones) are processed.
742:    In the result Y, columns are overwritten starting from the leading ones.
743:    The number of active columns in V and Y should match, although they need
744:    not be the same columns.
746:    Currently implemented via MatCreateTranspose().
748:    Level: beginner
750: .seealso: BVMatMult(), BVMatMultHermitianTranspose()
751: @*/
752: PetscErrorCode BVMatMultTranspose(BV V,Mat A,BV Y)
753: {
754:   PetscInt       M,N,m,n;
755:   Mat            AT;
757:   PetscFunctionBegin;
760:   BVCheckSizes(V,1);
765:   BVCheckSizes(Y,3);
766:   PetscCheckSameComm(V,1,A,2);
767:   PetscCheckSameTypeAndComm(V,1,Y,3);
769:   PetscCall(MatGetSize(A,&M,&N));
770:   PetscCall(MatGetLocalSize(A,&m,&n));
771:   PetscCheck(M==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,M,V->N);
772:   PetscCheck(m==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,m,V->n);
773:   PetscCheck(N==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,N,Y->N);
774:   PetscCheck(n==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,n,Y->n);
775:   PetscCheck(V->k-V->l==Y->k-Y->l,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Y has %" PetscInt_FMT " active columns, should match %" PetscInt_FMT " active columns in V",Y->k-Y->l,V->k-V->l);
777:   PetscCall(MatCreateTranspose(A,&AT));
778:   PetscCall(BVMatMult(V,AT,Y));
779:   PetscCall(MatDestroy(&AT));
780:   PetscFunctionReturn(PETSC_SUCCESS);
781: }
783: /*@
784:    BVMatMultHermitianTranspose - Computes the matrix-vector product with the
785:    conjugate transpose of a matrix for each column, Y=A^H*V.
787:    Neighbor-wise Collective
789:    Input Parameters:
790: +  V - basis vectors context
791: -  A - the matrix
793:    Output Parameter:
794: .  Y - the result
796:    Note:
797:    Both V and Y must be distributed in the same manner. Only active columns
798:    (excluding the leading ones) are processed.
799:    In the result Y, columns are overwritten starting from the leading ones.
800:    The number of active columns in V and Y should match, although they need
801:    not be the same columns.
803:    Currently implemented via MatCreateHermitianTranspose().
805:    Level: beginner
807: .seealso: BVMatMult(), BVMatMultTranspose()
808: @*/
809: PetscErrorCode BVMatMultHermitianTranspose(BV V,Mat A,BV Y)
810: {
811:   PetscInt       j,M,N,m,n;
812:   Vec            v,y;
814:   PetscFunctionBegin;
817:   BVCheckSizes(V,1);
822:   BVCheckSizes(Y,3);
823:   PetscCheckSameComm(V,1,A,2);
824:   PetscCheckSameTypeAndComm(V,1,Y,3);
826:   PetscCall(MatGetSize(A,&M,&N));
827:   PetscCall(MatGetLocalSize(A,&m,&n));
828:   PetscCheck(M==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,M,V->N);
829:   PetscCheck(m==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,m,V->n);
830:   PetscCheck(N==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,N,Y->N);
831:   PetscCheck(n==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,n,Y->n);
832:   PetscCheck(V->k-V->l==Y->k-Y->l,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Y has %" PetscInt_FMT " active columns, should match %" PetscInt_FMT " active columns in V",Y->k-Y->l,V->k-V->l);
834:   /* TODO: recover this code if PETSc ever gets MATPRODUCT_AhB done
835:   PetscCall(MatCreateHermitianTranspose(A,&AH));
836:   PetscCall(BVMatMult(V,AH,Y));
837:   PetscCall(MatDestroy(&AH));
838:   */
839:   for (j=0;j<V->k-V->l;j++) {
840:     PetscCall(BVGetColumn(V,V->l+j,&v));
841:     PetscCall(BVGetColumn(Y,Y->l+j,&y));
842:     PetscCall(MatMultHermitianTranspose(A,v,y));
843:     PetscCall(BVRestoreColumn(V,V->l+j,&v));
844:     PetscCall(BVRestoreColumn(Y,Y->l+j,&y));
845:   }
846:   PetscFunctionReturn(PETSC_SUCCESS);
847: }
849: /*@
850:    BVMatMultColumn - Computes the matrix-vector product for a specified
851:    column, storing the result in the next column v_{j+1}=A*v_j.
853:    Neighbor-wise Collective
855:    Input Parameters:
856: +  V - basis vectors context
857: .  A - the matrix
858: -  j - the column
860:    Level: beginner
862: .seealso: BVMatMult(), BVMatMultTransposeColumn(), BVMatMultHermitianTransposeColumn()
863: @*/
864: PetscErrorCode BVMatMultColumn(BV V,Mat A,PetscInt j)
865: {
866:   Vec            vj,vj1;
868:   PetscFunctionBegin;
871:   BVCheckSizes(V,1);
873:   PetscCheckSameComm(V,1,A,2);
875:   PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
876:   PetscCheck(j+1<V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Result should go in index j+1=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j+1,V->m);
878:   PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
879:   PetscCall(BVGetColumn(V,j,&vj));
880:   PetscCall(BVGetColumn(V,j+1,&vj1));
881:   PetscCall(MatMult(A,vj,vj1));
882:   PetscCall(BVRestoreColumn(V,j,&vj));
883:   PetscCall(BVRestoreColumn(V,j+1,&vj1));
884:   PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
885:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
886:   PetscFunctionReturn(PETSC_SUCCESS);
887: }
889: /*@
890:    BVMatMultTransposeColumn - Computes the transpose matrix-vector product for a
891:    specified column, storing the result in the next column v_{j+1}=A^T*v_j.
893:    Neighbor-wise Collective
895:    Input Parameters:
896: +  V - basis vectors context
897: .  A - the matrix
898: -  j - the column
900:    Level: beginner
902: .seealso: BVMatMult(), BVMatMultColumn(), BVMatMultHermitianTransposeColumn()
903: @*/
904: PetscErrorCode BVMatMultTransposeColumn(BV V,Mat A,PetscInt j)
905: {
906:   Vec            vj,vj1;
908:   PetscFunctionBegin;
911:   BVCheckSizes(V,1);
913:   PetscCheckSameComm(V,1,A,2);
915:   PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
916:   PetscCheck(j+1<V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Result should go in index j+1=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j+1,V->m);
918:   PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
919:   PetscCall(BVGetColumn(V,j,&vj));
920:   PetscCall(BVGetColumn(V,j+1,&vj1));
921:   PetscCall(MatMultTranspose(A,vj,vj1));
922:   PetscCall(BVRestoreColumn(V,j,&vj));
923:   PetscCall(BVRestoreColumn(V,j+1,&vj1));
924:   PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
925:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
926:   PetscFunctionReturn(PETSC_SUCCESS);
927: }
929: /*@
930:    BVMatMultHermitianTransposeColumn - Computes the conjugate-transpose matrix-vector
931:    product for a specified column, storing the result in the next column v_{j+1}=A^H*v_j.
933:    Neighbor-wise Collective
935:    Input Parameters:
936: +  V - basis vectors context
937: .  A - the matrix
938: -  j - the column
940:    Level: beginner
942: .seealso: BVMatMult(), BVMatMultColumn(), BVMatMultTransposeColumn()
943: @*/
944: PetscErrorCode BVMatMultHermitianTransposeColumn(BV V,Mat A,PetscInt j)
945: {
946:   Vec            vj,vj1;
948:   PetscFunctionBegin;
951:   BVCheckSizes(V,1);
953:   PetscCheckSameComm(V,1,A,2);
955:   PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
956:   PetscCheck(j+1<V->m,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Result should go in index j+1=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j+1,V->m);
958:   PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
959:   PetscCall(BVGetColumn(V,j,&vj));
960:   PetscCall(BVGetColumn(V,j+1,&vj1));
961:   PetscCall(MatMultHermitianTranspose(A,vj,vj1));
962:   PetscCall(BVRestoreColumn(V,j,&vj));
963:   PetscCall(BVRestoreColumn(V,j+1,&vj1));
964:   PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
965:   PetscCall(PetscObjectStateIncrease((PetscObject)V));
966:   PetscFunctionReturn(PETSC_SUCCESS);
967: }