Actual source code: bvops.c
slepc-main 2024-12-17
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: SlepcMatCheckSeq(Q);
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;
119: PetscAssertPointer(q,5);
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: SlepcMatCheckSeq(Q);
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);
240: PetscCall(PetscLogEventBegin(BV_MultInPlace,V,Q,0,0));
241: PetscUseTypeMethod(V,multinplace,Q,s,e);
242: PetscCall(PetscLogEventEnd(BV_MultInPlace,V,Q,0,0));
243: PetscCall(PetscObjectStateIncrease((PetscObject)V));
244: PetscFunctionReturn(PETSC_SUCCESS);
245: }
247: /*@
248: BVMultInPlaceHermitianTranspose - Update a set of vectors as V(:,s:e-1) = V*Q'(:,s:e-1).
250: Logically Collective
252: Input Parameters:
253: + Q - a sequential dense matrix
254: . s - first column of V to be overwritten
255: - e - first column of V not to be overwritten
257: Input/Output Parameter:
258: . V - basis vectors
260: Notes:
261: This is a variant of BVMultInPlace() where the conjugate transpose
262: of Q is used.
264: Level: intermediate
266: .seealso: BVMultInPlace()
267: @*/
268: PetscErrorCode BVMultInPlaceHermitianTranspose(BV V,Mat Q,PetscInt s,PetscInt e)
269: {
270: PetscInt m,n;
272: PetscFunctionBegin;
278: BVCheckSizes(V,1);
280: SlepcMatCheckSeq(Q);
282: 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);
283: 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);
284: PetscCall(MatGetSize(Q,&m,&n));
285: 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);
286: 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: PetscCall(PetscLogEventBegin(BV_MultInPlace,V,Q,0,0));
289: PetscUseTypeMethod(V,multinplacetrans,Q,s,e);
290: PetscCall(PetscLogEventEnd(BV_MultInPlace,V,Q,0,0));
291: PetscCall(PetscObjectStateIncrease((PetscObject)V));
292: PetscFunctionReturn(PETSC_SUCCESS);
293: }
295: /*@
296: BVScale - Multiply the BV entries by a scalar value.
298: Logically Collective
300: Input Parameters:
301: + bv - basis vectors
302: - alpha - scaling factor
304: Note:
305: All active columns (except the leading ones) are scaled.
307: Level: intermediate
309: .seealso: BVScaleColumn(), BVSetActiveColumns()
310: @*/
311: PetscErrorCode BVScale(BV bv,PetscScalar alpha)
312: {
313: PetscFunctionBegin;
317: BVCheckSizes(bv,1);
318: if (alpha == (PetscScalar)1.0) PetscFunctionReturn(PETSC_SUCCESS);
320: PetscCall(PetscLogEventBegin(BV_Scale,bv,0,0,0));
321: PetscUseTypeMethod(bv,scale,-1,alpha);
322: PetscCall(PetscLogEventEnd(BV_Scale,bv,0,0,0));
323: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
324: PetscFunctionReturn(PETSC_SUCCESS);
325: }
327: /*@
328: BVScaleColumn - Scale one column of a BV.
330: Logically Collective
332: Input Parameters:
333: + bv - basis vectors
334: . j - column number to be scaled
335: - alpha - scaling factor
337: Level: intermediate
339: .seealso: BVScale(), BVSetActiveColumns()
340: @*/
341: PetscErrorCode BVScaleColumn(BV bv,PetscInt j,PetscScalar alpha)
342: {
343: PetscFunctionBegin;
348: BVCheckSizes(bv,1);
350: 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);
351: if (alpha == (PetscScalar)1.0) PetscFunctionReturn(PETSC_SUCCESS);
353: PetscCall(PetscLogEventBegin(BV_Scale,bv,0,0,0));
354: PetscUseTypeMethod(bv,scale,j,alpha);
355: PetscCall(PetscLogEventEnd(BV_Scale,bv,0,0,0));
356: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
357: PetscFunctionReturn(PETSC_SUCCESS);
358: }
360: static inline PetscErrorCode BVSetRandomColumn_Private(BV bv,PetscInt k)
361: {
362: PetscInt i,low,high;
363: PetscScalar *px,t;
364: Vec x;
366: PetscFunctionBegin;
367: PetscCall(BVGetColumn(bv,k,&x));
368: if (bv->rrandom) { /* generate the same vector irrespective of number of processes */
369: PetscCall(VecGetOwnershipRange(x,&low,&high));
370: PetscCall(VecGetArray(x,&px));
371: for (i=0;i<bv->N;i++) {
372: PetscCall(PetscRandomGetValue(bv->rand,&t));
373: if (i>=low && i<high) px[i-low] = t;
374: }
375: PetscCall(VecRestoreArray(x,&px));
376: } else PetscCall(VecSetRandom(x,bv->rand));
377: PetscCall(BVRestoreColumn(bv,k,&x));
378: PetscFunctionReturn(PETSC_SUCCESS);
379: }
381: static inline PetscErrorCode BVSetRandomNormalColumn_Private(BV bv,PetscInt k,Vec w1,Vec w2)
382: {
383: PetscInt i,low,high;
384: PetscScalar *px,s,t;
385: Vec x;
387: PetscFunctionBegin;
388: PetscCall(BVGetColumn(bv,k,&x));
389: if (bv->rrandom) { /* generate the same vector irrespective of number of processes */
390: PetscCall(VecGetOwnershipRange(x,&low,&high));
391: PetscCall(VecGetArray(x,&px));
392: for (i=0;i<bv->N;i++) {
393: PetscCall(PetscRandomGetValue(bv->rand,&s));
394: PetscCall(PetscRandomGetValue(bv->rand,&t));
395: if (i>=low && i<high) {
396: #if defined(PETSC_USE_COMPLEX)
397: 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)));
398: #else
399: px[i-low] = PetscSqrtReal(-2.0*PetscLogReal(s))*PetscCosReal(2.0*PETSC_PI*t);
400: #endif
401: }
402: }
403: PetscCall(VecRestoreArray(x,&px));
404: } else PetscCall(VecSetRandomNormal(x,bv->rand,w1,w2));
405: PetscCall(BVRestoreColumn(bv,k,&x));
406: PetscFunctionReturn(PETSC_SUCCESS);
407: }
409: static inline PetscErrorCode BVSetRandomSignColumn_Private(BV bv,PetscInt k)
410: {
411: PetscInt i,low,high;
412: PetscScalar *px,t;
413: Vec x;
415: PetscFunctionBegin;
416: PetscCall(BVGetColumn(bv,k,&x));
417: PetscCall(VecGetOwnershipRange(x,&low,&high));
418: if (bv->rrandom) { /* generate the same vector irrespective of number of processes */
419: PetscCall(VecGetArray(x,&px));
420: for (i=0;i<bv->N;i++) {
421: PetscCall(PetscRandomGetValue(bv->rand,&t));
422: if (i>=low && i<high) px[i-low] = (PetscRealPart(t)<0.5)? -1.0: 1.0;
423: }
424: PetscCall(VecRestoreArray(x,&px));
425: } else {
426: PetscCall(VecSetRandom(x,bv->rand));
427: PetscCall(VecGetArray(x,&px));
428: for (i=low;i<high;i++) {
429: px[i-low] = (PetscRealPart(px[i-low])<0.5)? -1.0: 1.0;
430: }
431: PetscCall(VecRestoreArray(x,&px));
432: }
433: PetscCall(BVRestoreColumn(bv,k,&x));
434: PetscFunctionReturn(PETSC_SUCCESS);
435: }
437: /*@
438: BVSetRandom - Set the columns of a BV to random numbers.
440: Logically Collective
442: Input Parameters:
443: . bv - basis vectors
445: Note:
446: All active columns (except the leading ones) are modified.
448: Level: advanced
450: .seealso: BVSetRandomContext(), BVSetRandomColumn(), BVSetRandomNormal(), BVSetRandomSign(), BVSetRandomCond(), BVSetActiveColumns()
451: @*/
452: PetscErrorCode BVSetRandom(BV bv)
453: {
454: PetscInt k;
456: PetscFunctionBegin;
459: BVCheckSizes(bv,1);
461: PetscCall(BVGetRandomContext(bv,&bv->rand));
462: PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
463: for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomColumn_Private(bv,k));
464: PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
465: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
466: PetscFunctionReturn(PETSC_SUCCESS);
467: }
469: /*@
470: BVSetRandomColumn - Set one column of a BV to random numbers.
472: Logically Collective
474: Input Parameters:
475: + bv - basis vectors
476: - j - column number to be set
478: Level: advanced
480: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomNormal(), BVSetRandomCond()
481: @*/
482: PetscErrorCode BVSetRandomColumn(BV bv,PetscInt j)
483: {
484: PetscFunctionBegin;
488: BVCheckSizes(bv,1);
489: 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);
491: PetscCall(BVGetRandomContext(bv,&bv->rand));
492: PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
493: PetscCall(BVSetRandomColumn_Private(bv,j));
494: PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
495: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
496: PetscFunctionReturn(PETSC_SUCCESS);
497: }
499: /*@
500: BVSetRandomNormal - Set the columns of a BV to random numbers with a normal
501: distribution.
503: Logically Collective
505: Input Parameter:
506: . bv - basis vectors
508: Notes:
509: All active columns (except the leading ones) are modified.
511: Other functions such as BVSetRandom(), BVSetRandomColumn(), and BVSetRandomCond()
512: produce random numbers with a uniform distribution. This function returns values
513: that fit a normal distribution (Gaussian).
515: Developer Notes:
516: The current implementation obtains each of the columns by applying the Box-Muller
517: transform on two random vectors with uniformly distributed entries.
519: Level: advanced
521: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetRandomCond(), BVSetActiveColumns()
522: @*/
523: PetscErrorCode BVSetRandomNormal(BV bv)
524: {
525: PetscInt k;
526: Vec w1=NULL,w2=NULL;
528: PetscFunctionBegin;
531: BVCheckSizes(bv,1);
533: PetscCall(BVGetRandomContext(bv,&bv->rand));
534: if (!bv->rrandom) {
535: PetscCall(BVCreateVec(bv,&w1));
536: PetscCall(BVCreateVec(bv,&w2));
537: }
538: PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
539: for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomNormalColumn_Private(bv,k,w1,w2));
540: PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
541: if (!bv->rrandom) {
542: PetscCall(VecDestroy(&w1));
543: PetscCall(VecDestroy(&w2));
544: }
545: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
546: PetscFunctionReturn(PETSC_SUCCESS);
547: }
549: /*@
550: BVSetRandomSign - Set the entries of a BV to values 1 or -1 with equal
551: probability.
553: Logically Collective
555: Input Parameter:
556: . bv - basis vectors
558: Notes:
559: All active columns (except the leading ones) are modified.
561: This function is used, e.g., in contour integral methods when estimating
562: the number of eigenvalues enclosed by the contour via an unbiased
563: estimator of tr(f(A)) [Bai et al., JCAM 1996].
565: Developer Notes:
566: The current implementation obtains random numbers and then replaces them
567: with -1 or 1 depending on the value being less than 0.5 or not.
569: Level: advanced
571: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetActiveColumns()
572: @*/
573: PetscErrorCode BVSetRandomSign(BV bv)
574: {
575: PetscScalar low,high;
576: PetscInt k;
578: PetscFunctionBegin;
581: BVCheckSizes(bv,1);
583: PetscCall(BVGetRandomContext(bv,&bv->rand));
584: PetscCall(PetscRandomGetInterval(bv->rand,&low,&high));
585: 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]");
586: PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
587: for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomSignColumn_Private(bv,k));
588: PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
589: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
590: PetscFunctionReturn(PETSC_SUCCESS);
591: }
593: /*@
594: BVSetRandomCond - Set the columns of a BV to random numbers, in a way that
595: the generated matrix has a given condition number.
597: Logically Collective
599: Input Parameters:
600: + bv - basis vectors
601: - condn - condition number
603: Note:
604: All active columns (except the leading ones) are modified.
606: Level: advanced
608: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetRandomColumn(), BVSetRandomNormal(), BVSetActiveColumns()
609: @*/
610: PetscErrorCode BVSetRandomCond(BV bv,PetscReal condn)
611: {
612: PetscInt k,i;
613: PetscScalar *eig,*d;
614: DS ds;
615: Mat A,X,Xt,M,G;
617: PetscFunctionBegin;
620: BVCheckSizes(bv,1);
622: PetscCall(BVGetRandomContext(bv,&bv->rand));
623: PetscCall(PetscLogEventBegin(BV_SetRandom,bv,0,0,0));
624: /* B = rand(n,k) */
625: for (k=bv->l;k<bv->k;k++) PetscCall(BVSetRandomColumn_Private(bv,k));
626: PetscCall(DSCreate(PetscObjectComm((PetscObject)bv),&ds));
627: PetscCall(DSSetType(ds,DSHEP));
628: PetscCall(DSAllocate(ds,bv->m));
629: PetscCall(DSSetDimensions(ds,bv->k,bv->l,bv->k));
630: /* [V,S] = eig(B'*B) */
631: PetscCall(DSGetMat(ds,DS_MAT_A,&A));
632: PetscCall(BVDot(bv,bv,A));
633: PetscCall(DSRestoreMat(ds,DS_MAT_A,&A));
634: PetscCall(PetscMalloc1(bv->m,&eig));
635: PetscCall(DSSolve(ds,eig,NULL));
636: PetscCall(DSSynchronize(ds,eig,NULL));
637: PetscCall(DSVectors(ds,DS_MAT_X,NULL,NULL));
638: /* M = diag(linspace(1/condn,1,n)./sqrt(diag(S)))' */
639: PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,bv->k,bv->k,NULL,&M));
640: PetscCall(MatZeroEntries(M));
641: PetscCall(MatDenseGetArray(M,&d));
642: 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]);
643: PetscCall(MatDenseRestoreArray(M,&d));
644: /* G = X*M*X' */
645: PetscCall(DSGetMat(ds,DS_MAT_X,&X));
646: PetscCall(MatTranspose(X,MAT_INITIAL_MATRIX,&Xt));
647: PetscCall(MatProductCreate(Xt,M,NULL,&G));
648: PetscCall(MatProductSetType(G,MATPRODUCT_PtAP));
649: PetscCall(MatProductSetFromOptions(G));
650: PetscCall(MatProductSymbolic(G));
651: PetscCall(MatProductNumeric(G));
652: PetscCall(MatProductClear(G));
653: PetscCall(DSRestoreMat(ds,DS_MAT_X,&X));
654: PetscCall(MatDestroy(&Xt));
655: PetscCall(MatDestroy(&M));
656: /* B = B*G */
657: PetscCall(BVMultInPlace(bv,G,bv->l,bv->k));
658: PetscCall(MatDestroy(&G));
659: PetscCall(PetscFree(eig));
660: PetscCall(DSDestroy(&ds));
661: PetscCall(PetscLogEventEnd(BV_SetRandom,bv,0,0,0));
662: PetscCall(PetscObjectStateIncrease((PetscObject)bv));
663: PetscFunctionReturn(PETSC_SUCCESS);
664: }
666: /*@
667: BVMatMult - Computes the matrix-vector product for each column, Y=A*V.
669: Neighbor-wise Collective
671: Input Parameters:
672: + V - basis vectors context
673: - A - the matrix
675: Output Parameter:
676: . Y - the result
678: Notes:
679: Both V and Y must be distributed in the same manner. Only active columns
680: (excluding the leading ones) are processed.
681: In the result Y, columns are overwritten starting from the leading ones.
682: The number of active columns in V and Y should match, although they need
683: not be the same columns.
685: It is possible to choose whether the computation is done column by column
686: or as a Mat-Mat product, see BVSetMatMultMethod().
688: Level: beginner
690: .seealso: BVCopy(), BVSetActiveColumns(), BVMatMultColumn(), BVMatMultTranspose(), BVMatMultHermitianTranspose(), BVSetMatMultMethod()
691: @*/
692: PetscErrorCode BVMatMult(BV V,Mat A,BV Y)
693: {
694: PetscInt M,N,m,n;
696: PetscFunctionBegin;
699: BVCheckSizes(V,1);
700: BVCheckOp(V,1,matmult);
705: BVCheckSizes(Y,3);
706: PetscCheckSameComm(V,1,A,2);
707: PetscCheckSameTypeAndComm(V,1,Y,3);
709: PetscCall(MatGetSize(A,&M,&N));
710: PetscCall(MatGetLocalSize(A,&m,&n));
711: PetscCheck(M==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,M,Y->N);
712: PetscCheck(m==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,m,Y->n);
713: PetscCheck(N==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,N,V->N);
714: PetscCheck(n==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,n,V->n);
715: 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);
717: PetscCall(PetscLogEventBegin(BV_MatMult,V,A,Y,0));
718: PetscUseTypeMethod(V,matmult,A,Y);
719: PetscCall(PetscLogEventEnd(BV_MatMult,V,A,Y,0));
720: PetscCall(PetscObjectStateIncrease((PetscObject)Y));
721: PetscFunctionReturn(PETSC_SUCCESS);
722: }
724: /*@
725: BVMatMultTranspose - Computes the matrix-vector product with the transpose
726: of a matrix for each column, Y=A^T*V.
728: Neighbor-wise Collective
730: Input Parameters:
731: + V - basis vectors context
732: - A - the matrix
734: Output Parameter:
735: . Y - the result
737: Notes:
738: Both V and Y must be distributed in the same manner. Only active columns
739: (excluding the leading ones) are processed.
740: In the result Y, columns are overwritten starting from the leading ones.
741: The number of active columns in V and Y should match, although they need
742: not be the same columns.
744: Currently implemented via MatCreateTranspose().
746: Level: beginner
748: .seealso: BVMatMult(), BVMatMultHermitianTranspose()
749: @*/
750: PetscErrorCode BVMatMultTranspose(BV V,Mat A,BV Y)
751: {
752: PetscInt M,N,m,n;
753: Mat AT;
755: PetscFunctionBegin;
758: BVCheckSizes(V,1);
763: BVCheckSizes(Y,3);
764: PetscCheckSameComm(V,1,A,2);
765: PetscCheckSameTypeAndComm(V,1,Y,3);
767: PetscCall(MatGetSize(A,&M,&N));
768: PetscCall(MatGetLocalSize(A,&m,&n));
769: PetscCheck(M==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,M,V->N);
770: PetscCheck(m==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,m,V->n);
771: PetscCheck(N==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,N,Y->N);
772: PetscCheck(n==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,n,Y->n);
773: 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);
775: PetscCall(MatCreateTranspose(A,&AT));
776: PetscCall(BVMatMult(V,AT,Y));
777: PetscCall(MatDestroy(&AT));
778: PetscFunctionReturn(PETSC_SUCCESS);
779: }
781: /*@
782: BVMatMultHermitianTranspose - Computes the matrix-vector product with the
783: conjugate transpose of a matrix for each column, Y=A^H*V.
785: Neighbor-wise Collective
787: Input Parameters:
788: + V - basis vectors context
789: - A - the matrix
791: Output Parameter:
792: . Y - the result
794: Note:
795: Both V and Y must be distributed in the same manner. Only active columns
796: (excluding the leading ones) are processed.
797: In the result Y, columns are overwritten starting from the leading ones.
798: The number of active columns in V and Y should match, although they need
799: not be the same columns.
801: Currently implemented via MatCreateHermitianTranspose().
803: Level: beginner
805: .seealso: BVMatMult(), BVMatMultTranspose()
806: @*/
807: PetscErrorCode BVMatMultHermitianTranspose(BV V,Mat A,BV Y)
808: {
809: PetscInt j,M,N,m,n;
810: Vec v,y;
812: PetscFunctionBegin;
815: BVCheckSizes(V,1);
820: BVCheckSizes(Y,3);
821: PetscCheckSameComm(V,1,A,2);
822: PetscCheckSameTypeAndComm(V,1,Y,3);
824: PetscCall(MatGetSize(A,&M,&N));
825: PetscCall(MatGetLocalSize(A,&m,&n));
826: PetscCheck(M==V->N,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,M,V->N);
827: PetscCheck(m==V->n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local row dimension A %" PetscInt_FMT ", V %" PetscInt_FMT,m,V->n);
828: PetscCheck(N==Y->N,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,N,Y->N);
829: PetscCheck(n==Y->n,PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local column dimension A %" PetscInt_FMT ", Y %" PetscInt_FMT,n,Y->n);
830: 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);
832: /* TODO: recover this code if PETSc ever gets MATPRODUCT_AhB done
833: PetscCall(MatCreateHermitianTranspose(A,&AH));
834: PetscCall(BVMatMult(V,AH,Y));
835: PetscCall(MatDestroy(&AH));
836: */
837: for (j=0;j<V->k-V->l;j++) {
838: PetscCall(BVGetColumn(V,V->l+j,&v));
839: PetscCall(BVGetColumn(Y,Y->l+j,&y));
840: PetscCall(MatMultHermitianTranspose(A,v,y));
841: PetscCall(BVRestoreColumn(V,V->l+j,&v));
842: PetscCall(BVRestoreColumn(Y,Y->l+j,&y));
843: }
844: PetscFunctionReturn(PETSC_SUCCESS);
845: }
847: /*@
848: BVMatMultColumn - Computes the matrix-vector product for a specified
849: column, storing the result in the next column v_{j+1}=A*v_j.
851: Neighbor-wise Collective
853: Input Parameters:
854: + V - basis vectors context
855: . A - the matrix
856: - j - the column
858: Level: beginner
860: .seealso: BVMatMult(), BVMatMultTransposeColumn(), BVMatMultHermitianTransposeColumn()
861: @*/
862: PetscErrorCode BVMatMultColumn(BV V,Mat A,PetscInt j)
863: {
864: Vec vj,vj1;
866: PetscFunctionBegin;
869: BVCheckSizes(V,1);
871: PetscCheckSameComm(V,1,A,2);
873: PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
874: 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);
876: PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
877: PetscCall(BVGetColumn(V,j,&vj));
878: PetscCall(BVGetColumn(V,j+1,&vj1));
879: PetscCall(MatMult(A,vj,vj1));
880: PetscCall(BVRestoreColumn(V,j,&vj));
881: PetscCall(BVRestoreColumn(V,j+1,&vj1));
882: PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
883: PetscCall(PetscObjectStateIncrease((PetscObject)V));
884: PetscFunctionReturn(PETSC_SUCCESS);
885: }
887: /*@
888: BVMatMultTransposeColumn - Computes the transpose matrix-vector product for a
889: specified column, storing the result in the next column v_{j+1}=A^T*v_j.
891: Neighbor-wise Collective
893: Input Parameters:
894: + V - basis vectors context
895: . A - the matrix
896: - j - the column
898: Level: beginner
900: .seealso: BVMatMult(), BVMatMultColumn(), BVMatMultHermitianTransposeColumn()
901: @*/
902: PetscErrorCode BVMatMultTransposeColumn(BV V,Mat A,PetscInt j)
903: {
904: Vec vj,vj1;
906: PetscFunctionBegin;
909: BVCheckSizes(V,1);
911: PetscCheckSameComm(V,1,A,2);
913: PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
914: 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);
916: PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
917: PetscCall(BVGetColumn(V,j,&vj));
918: PetscCall(BVGetColumn(V,j+1,&vj1));
919: PetscCall(MatMultTranspose(A,vj,vj1));
920: PetscCall(BVRestoreColumn(V,j,&vj));
921: PetscCall(BVRestoreColumn(V,j+1,&vj1));
922: PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
923: PetscCall(PetscObjectStateIncrease((PetscObject)V));
924: PetscFunctionReturn(PETSC_SUCCESS);
925: }
927: /*@
928: BVMatMultHermitianTransposeColumn - Computes the conjugate-transpose matrix-vector
929: product for a specified column, storing the result in the next column v_{j+1}=A^H*v_j.
931: Neighbor-wise Collective
933: Input Parameters:
934: + V - basis vectors context
935: . A - the matrix
936: - j - the column
938: Level: beginner
940: .seealso: BVMatMult(), BVMatMultColumn(), BVMatMultTransposeColumn()
941: @*/
942: PetscErrorCode BVMatMultHermitianTransposeColumn(BV V,Mat A,PetscInt j)
943: {
944: Vec vj,vj1;
946: PetscFunctionBegin;
949: BVCheckSizes(V,1);
951: PetscCheckSameComm(V,1,A,2);
953: PetscCheck(j>=0,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
954: 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);
956: PetscCall(PetscLogEventBegin(BV_MatMultVec,V,A,0,0));
957: PetscCall(BVGetColumn(V,j,&vj));
958: PetscCall(BVGetColumn(V,j+1,&vj1));
959: PetscCall(MatMultHermitianTranspose(A,vj,vj1));
960: PetscCall(BVRestoreColumn(V,j,&vj));
961: PetscCall(BVRestoreColumn(V,j+1,&vj1));
962: PetscCall(PetscLogEventEnd(BV_MatMultVec,V,A,0,0));
963: PetscCall(PetscObjectStateIncrease((PetscObject)V));
964: PetscFunctionReturn(PETSC_SUCCESS);
965: }