1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-2020, 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 involving global communication
12: */
14: #include <slepc/private/bvimpl.h> 16: /*
17: BVDot for the particular case of non-standard inner product with
18: matrix B, which is assumed to be symmetric (or complex Hermitian)
19: */
20: PETSC_STATIC_INLINE PetscErrorCode BVDot_Private(BV X,BV Y,Mat M) 21: {
23: PetscObjectId idx,idy;
24: PetscInt i,j,jend,m;
25: PetscScalar *marray;
26: PetscBool symm=PETSC_FALSE;
27: Mat B;
28: Vec z;
31: BVCheckOp(Y,1,dotvec);
32: MatGetSize(M,&m,NULL);
33: MatDenseGetArray(M,&marray);
34: PetscObjectGetId((PetscObject)X,&idx);
35: PetscObjectGetId((PetscObject)Y,&idy);
36: B = Y->matrix;
37: Y->matrix = NULL;
38: if (idx==idy) symm=PETSC_TRUE; /* M=X'BX is symmetric */
39: jend = X->k;
40: for (j=X->l;j<jend;j++) {
41: if (symm) Y->k = j+1;
42: BVGetColumn(X->cached,j,&z);
43: (*Y->ops->dotvec)(Y,z,marray+j*m+Y->l);
44: BVRestoreColumn(X->cached,j,&z);
45: if (symm) {
46: for (i=X->l;i<j;i++)
47: marray[j+i*m] = PetscConj(marray[i+j*m]);
48: }
49: }
50: MatDenseRestoreArray(M,&marray);
51: Y->matrix = B;
52: return(0);
53: }
55: /*@
56: BVDot - Computes the 'block-dot' product of two basis vectors objects.
58: Collective on X
60: Input Parameters:
61: + X, Y - basis vectors
62: - M - Mat object where the result must be placed
64: Output Parameter:
65: . M - the resulting matrix
67: Notes:
68: This is the generalization of VecDot() for a collection of vectors, M = Y^H*X.
69: The result is a matrix M whose entry m_ij is equal to y_i^H x_j (where y_i^H
70: denotes the conjugate transpose of y_i).
72: If a non-standard inner product has been specified with BVSetMatrix(),
73: then the result is M = Y^H*B*X. In this case, both X and Y must have
74: the same associated matrix.
76: On entry, M must be a sequential dense Mat with dimensions m,n at least, where
77: m is the number of active columns of Y and n is the number of active columns of X.
78: Only rows (resp. columns) of M starting from ly (resp. lx) are computed,
79: where ly (resp. lx) is the number of leading columns of Y (resp. X).
81: X and Y need not be different objects.
83: Level: intermediate
85: .seealso: BVDotVec(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
86: @*/
87: PetscErrorCode BVDot(BV X,BV Y,Mat M) 88: {
90: PetscBool match;
91: PetscInt m,n;
98: BVCheckSizes(X,1);
100: BVCheckSizes(Y,2);
103: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
104: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
106: MatGetSize(M,&m,&n);
107: 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);
108: 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);
109: if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
110: if (X->matrix!=Y->matrix) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
111: if (X->l==X->k || Y->l==Y->k) return(0);
113: PetscLogEventBegin(BV_Dot,X,Y,0,0);
114: if (X->matrix) { /* non-standard inner product */
115: /* compute BX first */
116: BV_IPMatMultBV(X);
117: if (X->vmm==BV_MATMULT_VECS) {
118: /* perform computation column by column */
119: BVDot_Private(X,Y,M);
120: } else {
121: (*X->ops->dot)(X->cached,Y,M);
122: }
123: } else {
124: (*X->ops->dot)(X,Y,M);
125: }
126: PetscLogEventEnd(BV_Dot,X,Y,0,0);
127: return(0);
128: }
130: /*@
131: BVDotVec - Computes multiple dot products of a vector against all the
132: column vectors of a BV.
134: Collective on X
136: Input Parameters:
137: + X - basis vectors
138: - y - a vector
140: Output Parameter:
141: . m - an array where the result must be placed
143: Notes:
144: This is analogue to VecMDot(), but using BV to represent a collection
145: of vectors. The result is m = X^H*y, so m_i is equal to x_j^H y. Note
146: that here X is transposed as opposed to BVDot().
148: If a non-standard inner product has been specified with BVSetMatrix(),
149: then the result is m = X^H*B*y.
151: The length of array m must be equal to the number of active columns of X
152: minus the number of leading columns, i.e. the first entry of m is the
153: product of the first non-leading column with y.
155: Level: intermediate
157: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
158: @*/
159: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar m[])160: {
162: PetscInt n;
168: BVCheckSizes(X,1);
169: BVCheckOp(X,1,dotvec);
173: VecGetLocalSize(y,&n);
174: if (X->n!=n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
176: PetscLogEventBegin(BV_DotVec,X,y,0,0);
177: (*X->ops->dotvec)(X,y,m);
178: PetscLogEventEnd(BV_DotVec,X,y,0,0);
179: return(0);
180: }
182: /*@
183: BVDotVecBegin - Starts a split phase dot product computation.
185: Input Parameters:
186: + X - basis vectors
187: . y - a vector
188: - m - an array where the result will go (can be NULL)
190: Note:
191: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
193: Level: advanced
195: .seealso: BVDotVecEnd(), BVDotVec()
196: @*/
197: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)198: {
199: PetscErrorCode ierr;
200: PetscInt i,n,nv;
201: PetscSplitReduction *sr;
202: MPI_Comm comm;
208: BVCheckSizes(X,1);
212: VecGetLocalSize(y,&n);
213: if (X->n!=n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
215: if (X->ops->dotvec_begin) {
216: (*X->ops->dotvec_begin)(X,y,m);
217: } else {
218: BVCheckOp(X,1,dotvec_local);
219: nv = X->k-X->l;
220: PetscObjectGetComm((PetscObject)X,&comm);
221: PetscSplitReductionGet(comm,&sr);
222: if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
223: for (i=0;i<nv;i++) {
224: if (sr->numopsbegin+i >= sr->maxops) {
225: PetscSplitReductionExtend(sr);
226: }
227: sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
228: sr->invecs[sr->numopsbegin+i] = (void*)X;
229: }
230: PetscLogEventBegin(BV_DotVec,X,y,0,0);
231: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
232: sr->numopsbegin += nv;
233: PetscLogEventEnd(BV_DotVec,X,y,0,0);
234: }
235: return(0);
236: }
238: /*@
239: BVDotVecEnd - Ends a split phase dot product computation.
241: Input Parameters:
242: + X - basis vectors
243: . y - a vector
244: - m - an array where the result will go
246: Note:
247: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
249: Level: advanced
251: .seealso: BVDotVecBegin(), BVDotVec()
252: @*/
253: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)254: {
255: PetscErrorCode ierr;
256: PetscInt i,nv;
257: PetscSplitReduction *sr;
258: MPI_Comm comm;
263: BVCheckSizes(X,1);
265: if (X->ops->dotvec_end) {
266: (*X->ops->dotvec_end)(X,y,m);
267: } else {
268: nv = X->k-X->l;
269: PetscObjectGetComm((PetscObject)X,&comm);
270: PetscSplitReductionGet(comm,&sr);
271: PetscSplitReductionEnd(sr);
273: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
274: if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
275: if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_SUM) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
276: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
278: /* Finished getting all the results so reset to no outstanding requests */
279: if (sr->numopsend == sr->numopsbegin) {
280: sr->state = STATE_BEGIN;
281: sr->numopsend = 0;
282: sr->numopsbegin = 0;
283: }
284: }
285: return(0);
286: }
288: /*@
289: BVDotColumn - Computes multiple dot products of a column against all the
290: previous columns of a BV.
292: Collective on X
294: Input Parameters:
295: + X - basis vectors
296: - j - the column index
298: Output Parameter:
299: . q - an array where the result must be placed
301: Notes:
302: This operation is equivalent to BVDotVec() but it uses column j of X
303: rather than taking a Vec as an argument. The number of active columns of
304: X is set to j before the computation, and restored afterwards.
305: If X has leading columns specified, then these columns do not participate
306: in the computation. Therefore, the length of array q must be equal to j
307: minus the number of leading columns.
309: Developer Notes:
310: If q is NULL, then the result is written in position nc+l of the internal
311: buffer vector, see BVGetBufferVec().
313: Level: advanced
315: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
316: @*/
317: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *q)318: {
320: PetscInt ksave;
321: Vec y;
327: BVCheckSizes(X,1);
328: BVCheckOp(X,1,dotvec);
330: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
331: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
333: PetscLogEventBegin(BV_DotVec,X,0,0,0);
334: ksave = X->k;
335: X->k = j;
336: if (!q && !X->buffer) { BVGetBufferVec(X,&X->buffer); }
337: BVGetColumn(X,j,&y);
338: (*X->ops->dotvec)(X,y,q);
339: BVRestoreColumn(X,j,&y);
340: X->k = ksave;
341: PetscLogEventEnd(BV_DotVec,X,0,0,0);
342: return(0);
343: }
345: /*@
346: BVDotColumnBegin - Starts a split phase dot product computation.
348: Input Parameters:
349: + X - basis vectors
350: - j - the column index
351: - m - an array where the result will go (can be NULL)
353: Note:
354: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
356: Level: advanced
358: .seealso: BVDotColumnEnd(), BVDotColumn()
359: @*/
360: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)361: {
362: PetscErrorCode ierr;
363: PetscInt i,nv,ksave;
364: PetscSplitReduction *sr;
365: MPI_Comm comm;
366: Vec y;
372: BVCheckSizes(X,1);
374: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
375: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
376: ksave = X->k;
377: X->k = j;
378: BVGetColumn(X,j,&y);
380: if (X->ops->dotvec_begin) {
381: (*X->ops->dotvec_begin)(X,y,m);
382: } else {
383: BVCheckOp(X,1,dotvec_local);
384: nv = X->k-X->l;
385: PetscObjectGetComm((PetscObject)X,&comm);
386: PetscSplitReductionGet(comm,&sr);
387: if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
388: for (i=0;i<nv;i++) {
389: if (sr->numopsbegin+i >= sr->maxops) {
390: PetscSplitReductionExtend(sr);
391: }
392: sr->reducetype[sr->numopsbegin+i] = PETSC_SR_REDUCE_SUM;
393: sr->invecs[sr->numopsbegin+i] = (void*)X;
394: }
395: PetscLogEventBegin(BV_DotVec,X,0,0,0);
396: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
397: sr->numopsbegin += nv;
398: PetscLogEventEnd(BV_DotVec,X,0,0,0);
399: }
400: BVRestoreColumn(X,j,&y);
401: X->k = ksave;
402: return(0);
403: }
405: /*@
406: BVDotColumnEnd - Ends a split phase dot product computation.
408: Input Parameters:
409: + X - basis vectors
410: . j - the column index
411: - m - an array where the result will go
413: Notes:
414: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
416: Level: advanced
418: .seealso: BVDotColumnBegin(), BVDotColumn()
419: @*/
420: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)421: {
422: PetscErrorCode ierr;
423: PetscInt i,nv,ksave;
424: PetscSplitReduction *sr;
425: MPI_Comm comm;
426: Vec y;
432: BVCheckSizes(X,1);
434: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
435: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
436: ksave = X->k;
437: X->k = j;
439: if (X->ops->dotvec_end) {
440: BVGetColumn(X,j,&y);
441: (*X->ops->dotvec_end)(X,y,m);
442: BVRestoreColumn(X,j,&y);
443: } else {
444: nv = X->k-X->l;
445: PetscObjectGetComm((PetscObject)X,&comm);
446: PetscSplitReductionGet(comm,&sr);
447: PetscSplitReductionEnd(sr);
449: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
450: if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
451: if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_SUM) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
452: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
454: /* Finished getting all the results so reset to no outstanding requests */
455: if (sr->numopsend == sr->numopsbegin) {
456: sr->state = STATE_BEGIN;
457: sr->numopsend = 0;
458: sr->numopsbegin = 0;
459: }
460: }
461: X->k = ksave;
462: return(0);
463: }
465: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)466: {
468: PetscScalar p;
471: BV_IPMatMult(bv,z);
472: VecDot(bv->Bx,z,&p);
473: BV_SafeSqrt(bv,p,val);
474: return(0);
475: }
477: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)478: {
480: PetscScalar p;
483: BV_IPMatMult(bv,z);
484: VecDotBegin(bv->Bx,z,&p);
485: return(0);
486: }
488: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)489: {
491: PetscScalar p;
494: VecDotEnd(bv->Bx,z,&p);
495: BV_SafeSqrt(bv,p,val);
496: return(0);
497: }
499: /*@
500: BVNorm - Computes the matrix norm of the BV.
502: Collective on bv
504: Input Parameters:
505: + bv - basis vectors
506: - type - the norm type
508: Output Parameter:
509: . val - the norm
511: Notes:
512: All active columns (except the leading ones) are considered as a matrix.
513: The allowed norms are NORM_1, NORM_FROBENIUS, and NORM_INFINITY.
515: This operation fails if a non-standard inner product has been
516: specified with BVSetMatrix().
518: Level: intermediate
520: .seealso: BVNormVec(), BVNormColumn(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
521: @*/
522: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)523: {
531: BVCheckSizes(bv,1);
533: if (type==NORM_2 || type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
534: if (bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");
536: PetscLogEventBegin(BV_Norm,bv,0,0,0);
537: (*bv->ops->norm)(bv,-1,type,val);
538: PetscLogEventEnd(BV_Norm,bv,0,0,0);
539: return(0);
540: }
542: /*@
543: BVNormVec - Computes the norm of a given vector.
545: Collective on bv
547: Input Parameters:
548: + bv - basis vectors
549: . v - the vector
550: - type - the norm type
552: Output Parameter:
553: . val - the norm
555: Notes:
556: This is the analogue of BVNormColumn() but for a vector that is not in the BV.
557: If a non-standard inner product has been specified with BVSetMatrix(),
558: then the returned value is sqrt(v'*B*v), where B is the inner product
559: matrix (argument 'type' is ignored). Otherwise, VecNorm() is called.
561: Level: developer
563: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
564: @*/
565: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)566: {
568: PetscInt n;
576: BVCheckSizes(bv,1);
580: if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
582: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
583: if (bv->matrix) { /* non-standard inner product */
584: VecGetLocalSize(v,&n);
585: if (bv->n!=n) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
586: BVNorm_Private(bv,v,type,val);
587: } else {
588: VecNorm(v,type,val);
589: }
590: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
591: return(0);
592: }
594: /*@
595: BVNormVecBegin - Starts a split phase norm computation.
597: Input Parameters:
598: + bv - basis vectors
599: . v - the vector
600: . type - the norm type
601: - val - the norm
603: Note:
604: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
606: Level: advanced
608: .seealso: BVNormVecEnd(), BVNormVec()
609: @*/
610: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)611: {
613: PetscInt n;
621: BVCheckSizes(bv,1);
625: if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
627: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
628: if (bv->matrix) { /* non-standard inner product */
629: VecGetLocalSize(v,&n);
630: if (bv->n!=n) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
631: BVNorm_Begin_Private(bv,v,type,val);
632: } else {
633: VecNormBegin(v,type,val);
634: }
635: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
636: return(0);
637: }
639: /*@
640: BVNormVecEnd - Ends a split phase norm computation.
642: Input Parameters:
643: + bv - basis vectors
644: . v - the vector
645: . type - the norm type
646: - val - the norm
648: Note:
649: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
651: Level: advanced
653: .seealso: BVNormVecBegin(), BVNormVec()
654: @*/
655: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)656: {
664: BVCheckSizes(bv,1);
666: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
668: if (bv->matrix) { /* non-standard inner product */
669: BVNorm_End_Private(bv,v,type,val);
670: } else {
671: VecNormEnd(v,type,val);
672: }
673: return(0);
674: }
676: /*@
677: BVNormColumn - Computes the vector norm of a selected column.
679: Collective on bv
681: Input Parameters:
682: + bv - basis vectors
683: . j - column number to be used
684: - type - the norm type
686: Output Parameter:
687: . val - the norm
689: Notes:
690: The norm of V[j] is computed (NORM_1, NORM_2, or NORM_INFINITY).
691: If a non-standard inner product has been specified with BVSetMatrix(),
692: then the returned value is sqrt(V[j]'*B*V[j]),
693: where B is the inner product matrix (argument 'type' is ignored).
695: Level: intermediate
697: .seealso: BVNorm(), BVNormVec(), BVNormalize(), BVSetActiveColumns(), BVSetMatrix()
698: @*/
699: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)700: {
702: Vec z;
710: BVCheckSizes(bv,1);
712: 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);
713: if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
715: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
716: if (bv->matrix) { /* non-standard inner product */
717: BVGetColumn(bv,j,&z);
718: BVNorm_Private(bv,z,type,val);
719: BVRestoreColumn(bv,j,&z);
720: } else {
721: (*bv->ops->norm)(bv,j,type,val);
722: }
723: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
724: return(0);
725: }
727: /*@
728: BVNormColumnBegin - Starts a split phase norm computation.
730: Input Parameters:
731: + bv - basis vectors
732: . j - column number to be used
733: . type - the norm type
734: - val - the norm
736: Note:
737: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
739: Level: advanced
741: .seealso: BVNormColumnEnd(), BVNormColumn()
742: @*/
743: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)744: {
745: PetscErrorCode ierr;
746: PetscSplitReduction *sr;
747: PetscReal lresult;
748: MPI_Comm comm;
749: Vec z;
757: BVCheckSizes(bv,1);
759: 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);
760: if (type==NORM_1_AND_2 && !bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
762: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
763: BVGetColumn(bv,j,&z);
764: if (bv->matrix) { /* non-standard inner product */
765: BVNorm_Begin_Private(bv,z,type,val);
766: } else if (bv->ops->norm_begin) {
767: (*bv->ops->norm_begin)(bv,j,type,val);
768: } else {
769: BVCheckOp(bv,1,norm_local);
770: PetscObjectGetComm((PetscObject)z,&comm);
771: PetscSplitReductionGet(comm,&sr);
772: if (sr->state != STATE_BEGIN) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
773: if (sr->numopsbegin >= sr->maxops) {
774: PetscSplitReductionExtend(sr);
775: }
776: sr->invecs[sr->numopsbegin] = (void*)bv;
777: (*bv->ops->norm_local)(bv,j,type,&lresult);
778: if (type == NORM_2) lresult = lresult*lresult;
779: if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_MAX;
780: else sr->reducetype[sr->numopsbegin] = PETSC_SR_REDUCE_SUM;
781: sr->lvalues[sr->numopsbegin++] = lresult;
782: }
783: BVRestoreColumn(bv,j,&z);
784: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
785: return(0);
786: }
788: /*@
789: BVNormColumnEnd - Ends a split phase norm computation.
791: Input Parameters:
792: + bv - basis vectors
793: . j - column number to be used
794: . type - the norm type
795: - val - the norm
797: Note:
798: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
800: Level: advanced
802: .seealso: BVNormColumnBegin(), BVNormColumn()
803: @*/
804: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)805: {
806: PetscErrorCode ierr;
807: PetscSplitReduction *sr;
808: MPI_Comm comm;
809: Vec z;
817: BVCheckSizes(bv,1);
819: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
821: BVGetColumn(bv,j,&z);
822: if (bv->matrix) { /* non-standard inner product */
823: BVNorm_End_Private(bv,z,type,val);
824: } else if (bv->ops->norm_end) {
825: (*bv->ops->norm_end)(bv,j,type,val);
826: } else {
827: PetscObjectGetComm((PetscObject)z,&comm);
828: PetscSplitReductionGet(comm,&sr);
829: PetscSplitReductionEnd(sr);
831: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
832: if ((void*)bv != sr->invecs[sr->numopsend]) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
833: if (sr->reducetype[sr->numopsend] != PETSC_SR_REDUCE_MAX && type == NORM_MAX) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
834: *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
835: if (type == NORM_2) *val = PetscSqrtReal(*val);
836: if (sr->numopsend == sr->numopsbegin) {
837: sr->state = STATE_BEGIN;
838: sr->numopsend = 0;
839: sr->numopsbegin = 0;
840: }
841: }
842: BVRestoreColumn(bv,j,&z);
843: return(0);
844: }
846: /*@
847: BVNormalize - Normalize all columns (starting from the leading ones).
849: Collective on bv
851: Input Parameters:
852: + bv - basis vectors
853: - eigi - (optional) imaginary parts of eigenvalues
855: Notes:
856: On output, all columns will have unit norm. The normalization is done with
857: respect to the 2-norm, or to the B-norm if a non-standard inner product has
858: been specified with BVSetMatrix(), see BVNormColumn().
860: If the optional argument eigi is passed (taken into account only in real
861: scalars) it is interpreted as the imaginary parts of the eigenvalues and
862: the BV is supposed to contain the corresponding eigenvectors. Suppose the
863: first three values are eigi = { 0, alpha, -alpha }, then the first column
864: is normalized as usual, but the second and third ones are normalized assuming
865: that they contain the real and imaginary parts of a complex conjugate pair of
866: eigenvectors.
868: If eigi is passed, the inner-product matrix is ignored.
870: If there are leading columns, they are not modified (are assumed to be already
871: normalized).
873: Level: intermediate
875: .seealso: BVNormColumn()
876: @*/
877: PetscErrorCode BVNormalize(BV bv,PetscScalar *eigi)878: {
880: PetscReal norm;
881: PetscInt i;
882: Vec v;
883: #if !defined(PETSC_USE_COMPLEX)
884: Vec v1;
885: #endif
890: BVCheckSizes(bv,1);
892: PetscLogEventBegin(BV_Normalize,bv,0,0,0);
893: if (bv->matrix && !eigi) {
894: for (i=bv->l;i<bv->k;i++) {
895: BVNormColumn(bv,i,NORM_2,&norm);
896: BVScaleColumn(bv,i,1.0/norm);
897: }
898: } else if (bv->ops->normalize) {
899: (*bv->ops->normalize)(bv,eigi);
900: } else {
901: for (i=bv->l;i<bv->k;i++) {
902: #if !defined(PETSC_USE_COMPLEX)
903: if (eigi && eigi[i] != 0.0) {
904: BVGetColumn(bv,i,&v);
905: BVGetColumn(bv,i+1,&v1);
906: VecNormalizeComplex(v,v1,PETSC_TRUE,NULL);
907: BVRestoreColumn(bv,i,&v);
908: BVRestoreColumn(bv,i+1,&v1);
909: i++;
910: } else
911: #endif
912: {
913: BVGetColumn(bv,i,&v);
914: VecNormalize(v,NULL);
915: BVRestoreColumn(bv,i,&v);
916: }
917: }
918: }
919: PetscLogEventEnd(BV_Normalize,bv,0,0,0);
920: PetscObjectStateIncrease((PetscObject)bv);
921: return(0);
922: }
924: /*
925: Compute Y^H*A*X: right part column by column (with MatMult) and bottom
926: part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
927: */
928: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)929: {
931: PetscInt i,j,lx,ly,kx,ky,ulim;
932: Vec z,f;
935: lx = X->l; kx = X->k;
936: ly = Y->l; ky = Y->k;
937: BVCreateVec(X,&f);
938: BVCheckOp(Y,3,dotvec);
939: for (j=lx;j<kx;j++) {
940: BVGetColumn(X,j,&z);
941: MatMult(A,z,f);
942: BVRestoreColumn(X,j,&z);
943: ulim = PetscMin(ly+(j-lx)+1,ky);
944: Y->l = 0; Y->k = ulim;
945: (*Y->ops->dotvec)(Y,f,marray+j*ldm);
946: if (symm) {
947: for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
948: }
949: }
950: if (!symm) {
951: BVCheckOp(X,1,dotvec);
952: BV_AllocateCoeffs(Y);
953: for (j=ly;j<ky;j++) {
954: BVGetColumn(Y,j,&z);
955: MatMultHermitianTranspose(A,z,f);
956: BVRestoreColumn(Y,j,&z);
957: ulim = PetscMin(lx+(j-ly),kx);
958: X->l = 0; X->k = ulim;
959: (*X->ops->dotvec)(X,f,Y->h);
960: for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
961: }
962: }
963: VecDestroy(&f);
964: X->l = lx; X->k = kx;
965: Y->l = ly; Y->k = ky;
966: return(0);
967: }
969: /*
970: Compute Y^H*A*X= [ -- | Y0'*W1 ]
971: [ Y1'*W0 | Y1'*W1 ]
972: Allocates auxiliary BV to store the result of A*X, then one BVDot973: call for top-right part and another one for bottom part;
974: result placed in marray[*,ldm]
975: */
976: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)977: {
979: PetscInt j,lx,ly,kx,ky;
980: PetscScalar *harray;
981: Mat H;
982: BV W;
985: lx = X->l; kx = X->k;
986: ly = Y->l; ky = Y->k;
987: BVDuplicate(X,&W);
988: X->l = 0; X->k = kx;
989: W->l = 0; W->k = kx;
990: BVMatMult(X,A,W);
992: /* top-right part, Y0'*AX1 */
993: if (ly>0 && lx<kx) {
994: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
995: W->l = lx; W->k = kx;
996: Y->l = 0; Y->k = ly;
997: BVDot(W,Y,H);
998: MatDenseGetArray(H,&harray);
999: for (j=lx;j<kx;j++) {
1000: PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
1001: }
1002: MatDenseRestoreArray(H,&harray);
1003: MatDestroy(&H);
1004: }
1006: /* bottom part, Y1'*AX */
1007: if (kx>0 && ly<ky) {
1008: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1009: W->l = 0; W->k = kx;
1010: Y->l = ly; Y->k = ky;
1011: BVDot(W,Y,H);
1012: MatDenseGetArray(H,&harray);
1013: for (j=0;j<kx;j++) {
1014: PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
1015: }
1016: MatDenseRestoreArray(H,&harray);
1017: MatDestroy(&H);
1018: }
1019: BVDestroy(&W);
1020: X->l = lx; X->k = kx;
1021: Y->l = ly; Y->k = ky;
1022: return(0);
1023: }
1025: /*
1026: Compute Y^H*A*X= [ -- | Y0'*W1 ]
1027: [ Y1'*W0 | Y1'*W1 ]
1028: First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
1029: Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
1030: bottom-left part; result placed in marray[*,ldm]
1031: */
1032: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)1033: {
1035: PetscInt i,j,lx,ly,kx,ky;
1036: PetscScalar *harray;
1037: Mat H;
1038: BV W;
1041: lx = X->l; kx = X->k;
1042: ly = Y->l; ky = Y->k;
1044: /* right part, Y'*AX1 */
1045: BVDuplicateResize(X,kx-lx,&W);
1046: if (ky>0 && lx<kx) {
1047: BVMatMult(X,A,W);
1048: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
1049: Y->l = 0; Y->k = ky;
1050: BVDot(W,Y,H);
1051: MatDenseGetArray(H,&harray);
1052: for (j=lx;j<kx;j++) {
1053: PetscArraycpy(marray+j*ldm,harray+(j-lx)*ky,ky);
1054: }
1055: MatDenseRestoreArray(H,&harray);
1056: MatDestroy(&H);
1057: }
1059: /* bottom-left part, Y1'*AX0 */
1060: if (lx>0 && ly<ky) {
1061: if (symm) {
1062: /* do not compute, just copy symmetric elements */
1063: for (i=ly;i<ky;i++) {
1064: for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
1065: }
1066: } else {
1067: BVResize(W,ky-ly,PETSC_FALSE);
1068: Y->l = ly; Y->k = ky;
1069: BVMatMultHermitianTranspose(Y,A,W);
1070: MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
1071: X->l = 0; X->k = lx;
1072: BVDot(W,X,H);
1073: MatDenseGetArray(H,&harray);
1074: for (i=0;i<ky-ly;i++) {
1075: for (j=0;j<lx;j++) {
1076: marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
1077: }
1078: }
1079: MatDenseRestoreArray(H,&harray);
1080: MatDestroy(&H);
1081: }
1082: }
1083: BVDestroy(&W);
1084: X->l = lx; X->k = kx;
1085: Y->l = ly; Y->k = ky;
1086: return(0);
1087: }
1089: /*
1090: Compute Y^H*X = [ -- | Y0'*X1 ] (X contains A*X):
1091: [ Y1'*X0 | Y1'*X1 ]
1092: one BVDot call for top-right part and another one for bottom part;
1093: result placed in marray[*,ldm]
1094: */
1095: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)1096: {
1098: PetscInt j,lx,ly,kx,ky;
1099: PetscScalar *harray;
1100: Mat H;
1103: lx = X->l; kx = X->k;
1104: ly = Y->l; ky = Y->k;
1106: /* top-right part, Y0'*X1 */
1107: if (ly>0 && lx<kx) {
1108: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1109: X->l = lx; X->k = kx;
1110: Y->l = 0; Y->k = ly;
1111: BVDot(X,Y,H);
1112: MatDenseGetArray(H,&harray);
1113: for (j=lx;j<kx;j++) {
1114: PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
1115: }
1116: MatDenseRestoreArray(H,&harray);
1117: MatDestroy(&H);
1118: }
1120: /* bottom part, Y1'*X */
1121: if (kx>0 && ly<ky) {
1122: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1123: X->l = 0; X->k = kx;
1124: Y->l = ly; Y->k = ky;
1125: BVDot(X,Y,H);
1126: MatDenseGetArray(H,&harray);
1127: for (j=0;j<kx;j++) {
1128: PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
1129: }
1130: MatDenseRestoreArray(H,&harray);
1131: MatDestroy(&H);
1132: }
1133: X->l = lx; X->k = kx;
1134: Y->l = ly; Y->k = ky;
1135: return(0);
1136: }
1138: /*@
1139: BVMatProject - Computes the projection of a matrix onto a subspace.
1141: Collective on X
1143: Input Parameters:
1144: + X - basis vectors
1145: . A - (optional) matrix to be projected
1146: . Y - left basis vectors, can be equal to X
1147: - M - Mat object where the result must be placed
1149: Output Parameter:
1150: . M - the resulting matrix
1152: Notes:
1153: If A=NULL, then it is assumed that X already contains A*X.
1155: This operation is similar to BVDot(), with important differences.
1156: The goal is to compute the matrix resulting from the orthogonal projection
1157: of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
1158: oblique projection onto X along Y, M = Y^H*A*X.
1160: A difference with respect to BVDot() is that the standard inner product
1161: is always used, regardless of a non-standard inner product being specified
1162: with BVSetMatrix().
1164: On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1165: where ky (resp. kx) is the number of active columns of Y (resp. X).
1166: Another difference with respect to BVDot() is that all entries of M are
1167: computed except the leading ly,lx part, where ly (resp. lx) is the
1168: number of leading columns of Y (resp. X). Hence, the leading columns of
1169: X and Y participate in the computation, as opposed to BVDot().
1170: The leading part of M is assumed to be already available from previous
1171: computations.
1173: In the orthogonal projection case, Y=X, some computation can be saved if
1174: A is real symmetric (or complex Hermitian). In order to exploit this
1175: property, the symmetry flag of A must be set with MatSetOption().
1177: Level: intermediate
1179: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1180: @*/
1181: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)1182: {
1184: PetscBool match,set,flg,symm=PETSC_FALSE;
1185: PetscInt m,n;
1186: PetscScalar *marray;
1187: Mat Xmatrix,Ymatrix;
1188: PetscObjectId idx,idy;
1196: BVCheckSizes(X,1);
1197: if (A) {
1200: }
1202: BVCheckSizes(Y,3);
1205: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1206: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");
1208: MatGetSize(M,&m,&n);
1209: 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);
1210: 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);
1211: if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
1213: PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1214: /* temporarily set standard inner product */
1215: Xmatrix = X->matrix;
1216: Ymatrix = Y->matrix;
1217: X->matrix = Y->matrix = NULL;
1219: PetscObjectGetId((PetscObject)X,&idx);
1220: PetscObjectGetId((PetscObject)Y,&idy);
1221: if (A && idx==idy) { /* check symmetry of M=X'AX */
1222: MatIsHermitianKnown(A,&set,&flg);
1223: symm = set? flg: PETSC_FALSE;
1224: }
1226: MatDenseGetArray(M,&marray);
1228: if (A) {
1229: if (X->vmm==BV_MATMULT_VECS) {
1230: /* perform computation column by column */
1231: BVMatProject_Vec(X,A,Y,marray,m,symm);
1232: } else {
1233: /* use BVMatMult, then BVDot */
1234: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1235: if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1236: BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1237: } else {
1238: BVMatProject_MatMult(X,A,Y,marray,m);
1239: }
1240: }
1241: } else {
1242: /* use BVDot on subblocks */
1243: BVMatProject_Dot(X,Y,marray,m);
1244: }
1246: MatDenseRestoreArray(M,&marray);
1247: PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1248: /* restore non-standard inner product */
1249: X->matrix = Xmatrix;
1250: Y->matrix = Ymatrix;
1251: return(0);
1252: }