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> /*I "slepcbv.h" I*/
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(), 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(), 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: Compute Y^H*A*X: right part column by column (with MatMult) and bottom
848: part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
849: */
850: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)851: {
853: PetscInt i,j,lx,ly,kx,ky,ulim;
854: Vec z,f;
857: lx = X->l; kx = X->k;
858: ly = Y->l; ky = Y->k;
859: BVCreateVec(X,&f);
860: BVCheckOp(Y,3,dotvec);
861: for (j=lx;j<kx;j++) {
862: BVGetColumn(X,j,&z);
863: MatMult(A,z,f);
864: BVRestoreColumn(X,j,&z);
865: ulim = PetscMin(ly+(j-lx)+1,ky);
866: Y->l = 0; Y->k = ulim;
867: (*Y->ops->dotvec)(Y,f,marray+j*ldm);
868: if (symm) {
869: for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
870: }
871: }
872: if (!symm) {
873: BVCheckOp(X,1,dotvec);
874: BV_AllocateCoeffs(Y);
875: for (j=ly;j<ky;j++) {
876: BVGetColumn(Y,j,&z);
877: MatMultHermitianTranspose(A,z,f);
878: BVRestoreColumn(Y,j,&z);
879: ulim = PetscMin(lx+(j-ly),kx);
880: X->l = 0; X->k = ulim;
881: (*X->ops->dotvec)(X,f,Y->h);
882: for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
883: }
884: }
885: VecDestroy(&f);
886: X->l = lx; X->k = kx;
887: Y->l = ly; Y->k = ky;
888: return(0);
889: }
891: /*
892: Compute Y^H*A*X= [ -- | Y0'*W1 ]
893: [ Y1'*W0 | Y1'*W1 ]
894: Allocates auxiliary BV to store the result of A*X, then one BVDot895: call for top-right part and another one for bottom part;
896: result placed in marray[*,ldm]
897: */
898: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)899: {
901: PetscInt j,lx,ly,kx,ky;
902: PetscScalar *harray;
903: Mat H;
904: BV W;
907: lx = X->l; kx = X->k;
908: ly = Y->l; ky = Y->k;
909: BVDuplicate(X,&W);
910: X->l = 0; X->k = kx;
911: W->l = 0; W->k = kx;
912: BVMatMult(X,A,W);
914: /* top-right part, Y0'*AX1 */
915: if (ly>0 && lx<kx) {
916: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
917: W->l = lx; W->k = kx;
918: Y->l = 0; Y->k = ly;
919: BVDot(W,Y,H);
920: MatDenseGetArray(H,&harray);
921: for (j=lx;j<kx;j++) {
922: PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
923: }
924: MatDenseRestoreArray(H,&harray);
925: MatDestroy(&H);
926: }
928: /* bottom part, Y1'*AX */
929: if (kx>0 && ly<ky) {
930: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
931: W->l = 0; W->k = kx;
932: Y->l = ly; Y->k = ky;
933: BVDot(W,Y,H);
934: MatDenseGetArray(H,&harray);
935: for (j=0;j<kx;j++) {
936: PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
937: }
938: MatDenseRestoreArray(H,&harray);
939: MatDestroy(&H);
940: }
941: BVDestroy(&W);
942: X->l = lx; X->k = kx;
943: Y->l = ly; Y->k = ky;
944: return(0);
945: }
947: /*
948: Compute Y^H*A*X= [ -- | Y0'*W1 ]
949: [ Y1'*W0 | Y1'*W1 ]
950: First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
951: Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
952: bottom-left part; result placed in marray[*,ldm]
953: */
954: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)955: {
957: PetscInt i,j,lx,ly,kx,ky;
958: PetscScalar *harray;
959: Mat H;
960: BV W;
963: lx = X->l; kx = X->k;
964: ly = Y->l; ky = Y->k;
966: /* right part, Y'*AX1 */
967: BVDuplicateResize(X,kx-lx,&W);
968: if (ky>0 && lx<kx) {
969: BVMatMult(X,A,W);
970: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
971: Y->l = 0; Y->k = ky;
972: BVDot(W,Y,H);
973: MatDenseGetArray(H,&harray);
974: for (j=lx;j<kx;j++) {
975: PetscArraycpy(marray+j*ldm,harray+(j-lx)*ky,ky);
976: }
977: MatDenseRestoreArray(H,&harray);
978: MatDestroy(&H);
979: }
981: /* bottom-left part, Y1'*AX0 */
982: if (lx>0 && ly<ky) {
983: if (symm) {
984: /* do not compute, just copy symmetric elements */
985: for (i=ly;i<ky;i++) {
986: for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
987: }
988: } else {
989: BVResize(W,ky-ly,PETSC_FALSE);
990: Y->l = ly; Y->k = ky;
991: BVMatMultHermitianTranspose(Y,A,W);
992: MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
993: X->l = 0; X->k = lx;
994: BVDot(W,X,H);
995: MatDenseGetArray(H,&harray);
996: for (i=0;i<ky-ly;i++) {
997: for (j=0;j<lx;j++) {
998: marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
999: }
1000: }
1001: MatDenseRestoreArray(H,&harray);
1002: MatDestroy(&H);
1003: }
1004: }
1005: BVDestroy(&W);
1006: X->l = lx; X->k = kx;
1007: Y->l = ly; Y->k = ky;
1008: return(0);
1009: }
1011: /*
1012: Compute Y^H*X = [ -- | Y0'*X1 ] (X contains A*X):
1013: [ Y1'*X0 | Y1'*X1 ]
1014: one BVDot call for top-right part and another one for bottom part;
1015: result placed in marray[*,ldm]
1016: */
1017: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)1018: {
1020: PetscInt j,lx,ly,kx,ky;
1021: PetscScalar *harray;
1022: Mat H;
1025: lx = X->l; kx = X->k;
1026: ly = Y->l; ky = Y->k;
1028: /* top-right part, Y0'*X1 */
1029: if (ly>0 && lx<kx) {
1030: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1031: X->l = lx; X->k = kx;
1032: Y->l = 0; Y->k = ly;
1033: BVDot(X,Y,H);
1034: MatDenseGetArray(H,&harray);
1035: for (j=lx;j<kx;j++) {
1036: PetscArraycpy(marray+j*ldm,harray+j*ly,ly);
1037: }
1038: MatDenseRestoreArray(H,&harray);
1039: MatDestroy(&H);
1040: }
1042: /* bottom part, Y1'*X */
1043: if (kx>0 && ly<ky) {
1044: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1045: X->l = 0; X->k = kx;
1046: Y->l = ly; Y->k = ky;
1047: BVDot(X,Y,H);
1048: MatDenseGetArray(H,&harray);
1049: for (j=0;j<kx;j++) {
1050: PetscArraycpy(marray+j*ldm+ly,harray+j*ky+ly,ky-ly);
1051: }
1052: MatDenseRestoreArray(H,&harray);
1053: MatDestroy(&H);
1054: }
1055: X->l = lx; X->k = kx;
1056: Y->l = ly; Y->k = ky;
1057: return(0);
1058: }
1060: /*@
1061: BVMatProject - Computes the projection of a matrix onto a subspace.
1063: Collective on X
1065: Input Parameters:
1066: + X - basis vectors
1067: . A - (optional) matrix to be projected
1068: . Y - left basis vectors, can be equal to X
1069: - M - Mat object where the result must be placed
1071: Output Parameter:
1072: . M - the resulting matrix
1074: Notes:
1075: If A=NULL, then it is assumed that X already contains A*X.
1077: This operation is similar to BVDot(), with important differences.
1078: The goal is to compute the matrix resulting from the orthogonal projection
1079: of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
1080: oblique projection onto X along Y, M = Y^H*A*X.
1082: A difference with respect to BVDot() is that the standard inner product
1083: is always used, regardless of a non-standard inner product being specified
1084: with BVSetMatrix().
1086: On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1087: where ky (resp. kx) is the number of active columns of Y (resp. X).
1088: Another difference with respect to BVDot() is that all entries of M are
1089: computed except the leading ly,lx part, where ly (resp. lx) is the
1090: number of leading columns of Y (resp. X). Hence, the leading columns of
1091: X and Y participate in the computation, as opposed to BVDot().
1092: The leading part of M is assumed to be already available from previous
1093: computations.
1095: In the orthogonal projection case, Y=X, some computation can be saved if
1096: A is real symmetric (or complex Hermitian). In order to exploit this
1097: property, the symmetry flag of A must be set with MatSetOption().
1099: Level: intermediate
1101: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1102: @*/
1103: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)1104: {
1106: PetscBool match,set,flg,symm=PETSC_FALSE;
1107: PetscInt m,n;
1108: PetscScalar *marray;
1109: Mat Xmatrix,Ymatrix;
1110: PetscObjectId idx,idy;
1118: BVCheckSizes(X,1);
1119: if (A) {
1122: }
1124: BVCheckSizes(Y,3);
1127: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1128: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");
1130: MatGetSize(M,&m,&n);
1131: 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);
1132: 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);
1133: if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
1135: PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1136: /* temporarily set standard inner product */
1137: Xmatrix = X->matrix;
1138: Ymatrix = Y->matrix;
1139: X->matrix = Y->matrix = NULL;
1141: PetscObjectGetId((PetscObject)X,&idx);
1142: PetscObjectGetId((PetscObject)Y,&idy);
1143: if (A && idx==idy) { /* check symmetry of M=X'AX */
1144: MatIsHermitianKnown(A,&set,&flg);
1145: symm = set? flg: PETSC_FALSE;
1146: }
1148: MatDenseGetArray(M,&marray);
1150: if (A) {
1151: if (X->vmm==BV_MATMULT_VECS) {
1152: /* perform computation column by column */
1153: BVMatProject_Vec(X,A,Y,marray,m,symm);
1154: } else {
1155: /* use BVMatMult, then BVDot */
1156: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1157: if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1158: BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1159: } else {
1160: BVMatProject_MatMult(X,A,Y,marray,m);
1161: }
1162: }
1163: } else {
1164: /* use BVDot on subblocks */
1165: BVMatProject_Dot(X,Y,marray,m);
1166: }
1168: MatDenseRestoreArray(M,&marray);
1169: PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1170: /* restore non-standard inner product */
1171: X->matrix = Xmatrix;
1172: Y->matrix = Ymatrix;
1173: return(0);
1174: }