1: /*
2: BV operations involving global communication.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2016, Universitat Politecnica de Valencia, Spain
8: This file is part of SLEPc.
10: SLEPc is free software: you can redistribute it and/or modify it under the
11: terms of version 3 of the GNU Lesser General Public License as published by
12: the Free Software Foundation.
14: SLEPc is distributed in the hope that it will be useful, but WITHOUT ANY
15: WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16: FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
17: more details.
19: You should have received a copy of the GNU Lesser General Public License
20: along with SLEPc. If not, see <http://www.gnu.org/licenses/>.
21: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
22: */
24: #include <slepc/private/bvimpl.h> /*I "slepcbv.h" I*/
28: /*
29: BVDot for the particular case of non-standard inner product with
30: matrix B, which is assumed to be symmetric (or complex Hermitian)
31: */
32: PETSC_STATIC_INLINE PetscErrorCode BVDot_Private(BV X,BV Y,Mat M) 33: {
35: PetscObjectId idx,idy;
36: PetscInt i,j,jend,m;
37: PetscScalar *marray;
38: PetscBool symm=PETSC_FALSE;
39: Vec z;
42: MatGetSize(M,&m,NULL);
43: MatDenseGetArray(M,&marray);
44: PetscObjectGetId((PetscObject)X,&idx);
45: PetscObjectGetId((PetscObject)Y,&idy);
46: if (idx==idy) symm=PETSC_TRUE; /* M=X'BX is symmetric */
47: jend = X->k;
48: for (j=X->l;j<jend;j++) {
49: if (symm) Y->k = j+1;
50: BVGetColumn(X,j,&z);
51: (*Y->ops->dotvec)(Y,z,marray+j*m+Y->l);
52: BVRestoreColumn(X,j,&z);
53: if (symm) {
54: for (i=X->l;i<j;i++)
55: marray[j+i*m] = PetscConj(marray[i+j*m]);
56: }
57: }
58: MatDenseRestoreArray(M,&marray);
59: return(0);
60: }
64: /*@
65: BVDot - Computes the 'block-dot' product of two basis vectors objects.
67: Collective on BV 69: Input Parameters:
70: + X, Y - basis vectors
71: - M - Mat object where the result must be placed
73: Output Parameter:
74: . M - the resulting matrix
76: Notes:
77: This is the generalization of VecDot() for a collection of vectors, M = Y^H*X.
78: The result is a matrix M whose entry m_ij is equal to y_i^H x_j (where y_i^H
79: denotes the conjugate transpose of y_i).
81: If a non-standard inner product has been specified with BVSetMatrix(),
82: then the result is M = Y^H*B*X. In this case, both X and Y must have
83: the same associated matrix.
85: On entry, M must be a sequential dense Mat with dimensions m,n at least, where
86: m is the number of active columns of Y and n is the number of active columns of X.
87: Only rows (resp. columns) of M starting from ly (resp. lx) are computed,
88: where ly (resp. lx) is the number of leading columns of Y (resp. X).
90: X and Y need not be different objects.
92: Level: intermediate
94: .seealso: BVDotVec(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
95: @*/
96: PetscErrorCode BVDot(BV X,BV Y,Mat M) 97: {
99: PetscBool match;
100: PetscInt m,n;
101: Mat B;
108: BVCheckSizes(X,1);
110: BVCheckSizes(Y,2);
113: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
114: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
116: MatGetSize(M,&m,&n);
117: if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D rows, should have at least %D",m,Y->k);
118: if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Mat argument has %D columns, should have at least %D",n,X->k);
119: if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
120: if (X->matrix!=Y->matrix) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
121: if (X->l==X->k || Y->l==Y->k) return(0);
123: PetscLogEventBegin(BV_Dot,X,Y,0,0);
124: if (X->matrix) { /* non-standard inner product */
125: if (X->vmm==BV_MATMULT_VECS) {
126: /* perform computation column by column */
127: BVDot_Private(X,Y,M);
128: } else {
129: /* compute BX first */
130: BV_IPMatMultBV(X);
131: B = X->matrix;
132: X->matrix = NULL;
133: (*X->ops->dot)(X->cached,Y,M);
134: X->matrix = B;
135: }
136: } else {
137: (*X->ops->dot)(X,Y,M);
138: }
139: PetscLogEventEnd(BV_Dot,X,Y,0,0);
140: return(0);
141: }
145: /*@
146: BVDotVec - Computes multiple dot products of a vector against all the
147: column vectors of a BV.
149: Collective on BV and Vec
151: Input Parameters:
152: + X - basis vectors
153: - y - a vector
155: Output Parameter:
156: . m - an array where the result must be placed
158: Notes:
159: This is analogue to VecMDot(), but using BV to represent a collection
160: of vectors. The result is m = X^H*y, so m_i is equal to x_j^H y. Note
161: that here X is transposed as opposed to BVDot().
163: If a non-standard inner product has been specified with BVSetMatrix(),
164: then the result is m = X^H*B*y.
166: The length of array m must be equal to the number of active columns of X
167: minus the number of leading columns, i.e. the first entry of m is the
168: product of the first non-leading column with y.
170: Level: intermediate
172: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
173: @*/
174: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar *m)175: {
177: PetscInt n;
183: BVCheckSizes(X,1);
187: VecGetLocalSize(y,&n);
188: if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
190: PetscLogEventBegin(BV_DotVec,X,y,0,0);
191: (*X->ops->dotvec)(X,y,m);
192: PetscLogEventEnd(BV_DotVec,X,y,0,0);
193: return(0);
194: }
198: /*@
199: BVDotVecBegin - Starts a split phase dot product computation.
201: Input Parameters:
202: + X - basis vectors
203: . y - a vector
204: - m - an array where the result will go (can be NULL)
206: Note:
207: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
209: Level: advanced
211: .seealso: BVDotVecEnd(), BVDotVec()
212: @*/
213: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)214: {
215: PetscErrorCode ierr;
216: PetscInt i,n,nv;
217: PetscSplitReduction *sr;
218: MPI_Comm comm;
224: BVCheckSizes(X,1);
228: VecGetLocalSize(y,&n);
229: if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
231: if (X->ops->dotvec_begin) {
232: (*X->ops->dotvec_begin)(X,y,m);
233: } else {
234: nv = X->k-X->l;
235: PetscObjectGetComm((PetscObject)X,&comm);
236: PetscSplitReductionGet(comm,&sr);
237: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
238: for (i=0;i<nv;i++) {
239: if (sr->numopsbegin+i >= sr->maxops) {
240: PetscSplitReductionExtend(sr);
241: }
242: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
243: sr->invecs[sr->numopsbegin+i] = (void*)X;
244: }
245: PetscLogEventBegin(BV_DotVec,X,y,0,0);
246: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
247: sr->numopsbegin += nv;
248: PetscLogEventEnd(BV_DotVec,X,y,0,0);
249: }
250: return(0);
251: }
255: /*@
256: BVDotVecEnd - Ends a split phase dot product computation.
258: Input Parameters:
259: + X - basis vectors
260: . y - a vector
261: - m - an array where the result will go
263: Note:
264: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
266: Level: advanced
268: .seealso: BVDotVecBegin(), BVDotVec()
269: @*/
270: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)271: {
272: PetscErrorCode ierr;
273: PetscInt i,nv;
274: PetscSplitReduction *sr;
275: MPI_Comm comm;
280: BVCheckSizes(X,1);
282: if (X->ops->dotvec_end) {
283: (*X->ops->dotvec_end)(X,y,m);
284: } else {
285: nv = X->k-X->l;
286: PetscObjectGetComm((PetscObject)X,&comm);
287: PetscSplitReductionGet(comm,&sr);
288: PetscSplitReductionEnd(sr);
290: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
291: if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
292: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
293: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
295: /* Finished getting all the results so reset to no outstanding requests */
296: if (sr->numopsend == sr->numopsbegin) {
297: sr->state = STATE_BEGIN;
298: sr->numopsend = 0;
299: sr->numopsbegin = 0;
300: }
301: }
302: return(0);
303: }
307: /*@
308: BVDotColumn - Computes multiple dot products of a column against all the
309: previous columns of a BV.
311: Collective on BV313: Input Parameters:
314: + X - basis vectors
315: - j - the column index
317: Output Parameter:
318: . m - an array where the result must be placed
320: Notes:
321: This operation is equivalent to BVDotVec() but it uses column j of X
322: rather than taking a Vec as an argument. The number of active columns of
323: X is set to j before the computation, and restored afterwards.
324: If X has leading columns specified, then these columns do not participate
325: in the computation. Therefore, the length of array m must be equal to j
326: minus the number of leading columns.
328: Level: advanced
330: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
331: @*/
332: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *m)333: {
335: PetscInt ksave;
336: Vec y;
342: BVCheckSizes(X,1);
344: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
345: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
347: PetscLogEventBegin(BV_DotVec,X,0,0,0);
348: ksave = X->k;
349: X->k = j;
350: BVGetColumn(X,j,&y);
351: (*X->ops->dotvec)(X,y,m);
352: BVRestoreColumn(X,j,&y);
353: X->k = ksave;
354: PetscLogEventEnd(BV_DotVec,X,0,0,0);
355: return(0);
356: }
360: /*@
361: BVDotColumnBegin - Starts a split phase dot product computation.
363: Input Parameters:
364: + X - basis vectors
365: - j - the column index
366: - m - an array where the result will go (can be NULL)
368: Note:
369: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
371: Level: advanced
373: .seealso: BVDotColumnEnd(), BVDotColumn()
374: @*/
375: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)376: {
377: PetscErrorCode ierr;
378: PetscInt i,nv,ksave;
379: PetscSplitReduction *sr;
380: MPI_Comm comm;
381: Vec y;
387: BVCheckSizes(X,1);
389: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
390: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
391: ksave = X->k;
392: X->k = j;
393: BVGetColumn(X,j,&y);
395: if (X->ops->dotvec_begin) {
396: (*X->ops->dotvec_begin)(X,y,m);
397: } else {
398: nv = X->k-X->l;
399: PetscObjectGetComm((PetscObject)X,&comm);
400: PetscSplitReductionGet(comm,&sr);
401: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
402: for (i=0;i<nv;i++) {
403: if (sr->numopsbegin+i >= sr->maxops) {
404: PetscSplitReductionExtend(sr);
405: }
406: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
407: sr->invecs[sr->numopsbegin+i] = (void*)X;
408: }
409: PetscLogEventBegin(BV_DotVec,X,0,0,0);
410: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
411: sr->numopsbegin += nv;
412: PetscLogEventEnd(BV_DotVec,X,0,0,0);
413: }
414: BVRestoreColumn(X,j,&y);
415: X->k = ksave;
416: return(0);
417: }
421: /*@
422: BVDotColumnEnd - Ends a split phase dot product computation.
424: Input Parameters:
425: + X - basis vectors
426: . j - the column index
427: - m - an array where the result will go
429: Notes:
430: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
432: Level: advanced
434: .seealso: BVDotColumnBegin(), BVDotColumn()
435: @*/
436: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)437: {
438: PetscErrorCode ierr;
439: PetscInt i,nv,ksave;
440: PetscSplitReduction *sr;
441: MPI_Comm comm;
442: Vec y;
448: BVCheckSizes(X,1);
450: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
451: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
452: ksave = X->k;
453: X->k = j;
455: if (X->ops->dotvec_end) {
456: BVGetColumn(X,j,&y);
457: (*X->ops->dotvec_end)(X,y,m);
458: BVRestoreColumn(X,j,&y);
459: } else {
460: nv = X->k-X->l;
461: PetscObjectGetComm((PetscObject)X,&comm);
462: PetscSplitReductionGet(comm,&sr);
463: PetscSplitReductionEnd(sr);
465: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
466: if ((void*)X != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVxxxEnd() in a different order or with a different BV than BVxxxBegin()");
467: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
468: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
470: /* Finished getting all the results so reset to no outstanding requests */
471: if (sr->numopsend == sr->numopsbegin) {
472: sr->state = STATE_BEGIN;
473: sr->numopsend = 0;
474: sr->numopsbegin = 0;
475: }
476: }
477: X->k = ksave;
478: return(0);
479: }
483: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)484: {
486: PetscScalar p;
489: BV_IPMatMult(bv,z);
490: VecDot(bv->Bx,z,&p);
491: BV_SafeSqrt(bv,p,val);
492: return(0);
493: }
497: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)498: {
500: PetscScalar p;
503: BV_IPMatMult(bv,z);
504: VecDotBegin(bv->Bx,z,&p);
505: return(0);
506: }
510: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)511: {
513: PetscScalar p;
516: VecDotEnd(bv->Bx,z,&p);
517: BV_SafeSqrt(bv,p,val);
518: return(0);
519: }
523: /*@
524: BVNorm - Computes the matrix norm of the BV.
526: Collective on BV528: Input Parameters:
529: + bv - basis vectors
530: - type - the norm type
532: Output Parameter:
533: . val - the norm
535: Notes:
536: All active columns (except the leading ones) are considered as a matrix.
537: The allowed norms are NORM_1, NORM_FROBENIUS, and NORM_INFINITY.
539: This operation fails if a non-standard inner product has been
540: specified with BVSetMatrix().
542: Level: intermediate
544: .seealso: BVNormVec(), BVNormColumn(), BVSetActiveColumns(), BVSetMatrix()
545: @*/
546: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)547: {
555: BVCheckSizes(bv,1);
557: if (type==NORM_2 || type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
558: if (bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");
560: PetscLogEventBegin(BV_Norm,bv,0,0,0);
561: (*bv->ops->norm)(bv,-1,type,val);
562: PetscLogEventEnd(BV_Norm,bv,0,0,0);
563: return(0);
564: }
568: /*@
569: BVNormVec - Computes the norm of a given vector.
571: Collective on BV573: Input Parameters:
574: + bv - basis vectors
575: . v - the vector
576: - type - the norm type
578: Output Parameter:
579: . val - the norm
581: Notes:
582: This is the analogue of BVNormColumn() but for a vector that is not in the BV.
583: If a non-standard inner product has been specified with BVSetMatrix(),
584: then the returned value is sqrt(v'*B*v), where B is the inner product
585: matrix (argument 'type' is ignored). Otherwise, VecNorm() is called.
587: Level: developer
589: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
590: @*/
591: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)592: {
594: PetscInt n;
602: BVCheckSizes(bv,1);
606: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
608: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
609: if (bv->matrix) { /* non-standard inner product */
610: VecGetLocalSize(v,&n);
611: if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
612: BVNorm_Private(bv,v,type,val);
613: } else {
614: VecNorm(v,type,val);
615: }
616: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
617: return(0);
618: }
622: /*@
623: BVNormVecBegin - Starts a split phase norm computation.
625: Input Parameters:
626: + bv - basis vectors
627: . v - the vector
628: . type - the norm type
629: - val - the norm
631: Note:
632: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
634: Level: advanced
636: .seealso: BVNormVecEnd(), BVNormVec()
637: @*/
638: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)639: {
641: PetscInt n;
649: BVCheckSizes(bv,1);
653: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
655: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
656: if (bv->matrix) { /* non-standard inner product */
657: VecGetLocalSize(v,&n);
658: if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
659: BVNorm_Begin_Private(bv,v,type,val);
660: } else {
661: VecNormBegin(v,type,val);
662: }
663: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
664: return(0);
665: }
669: /*@
670: BVNormVecEnd - Ends a split phase norm computation.
672: Input Parameters:
673: + bv - basis vectors
674: . v - the vector
675: . type - the norm type
676: - val - the norm
678: Note:
679: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
681: Level: advanced
683: .seealso: BVNormVecBegin(), BVNormVec()
684: @*/
685: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)686: {
694: BVCheckSizes(bv,1);
696: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
698: if (bv->matrix) { /* non-standard inner product */
699: BVNorm_End_Private(bv,v,type,val);
700: } else {
701: VecNormEnd(v,type,val);
702: }
703: return(0);
704: }
708: /*@
709: BVNormColumn - Computes the vector norm of a selected column.
711: Collective on BV713: Input Parameters:
714: + bv - basis vectors
715: . j - column number to be used
716: - type - the norm type
718: Output Parameter:
719: . val - the norm
721: Notes:
722: The norm of V[j] is computed (NORM_1, NORM_2, or NORM_INFINITY).
723: If a non-standard inner product has been specified with BVSetMatrix(),
724: then the returned value is sqrt(V[j]'*B*V[j]),
725: where B is the inner product matrix (argument 'type' is ignored).
727: Level: intermediate
729: .seealso: BVNorm(), BVNormVec(), BVSetActiveColumns(), BVSetMatrix()
730: @*/
731: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)732: {
734: Vec z;
742: BVCheckSizes(bv,1);
744: if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
745: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
747: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
748: if (bv->matrix) { /* non-standard inner product */
749: BVGetColumn(bv,j,&z);
750: BVNorm_Private(bv,z,type,val);
751: BVRestoreColumn(bv,j,&z);
752: } else {
753: (*bv->ops->norm)(bv,j,type,val);
754: }
755: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
756: return(0);
757: }
761: /*@
762: BVNormColumnBegin - Starts a split phase norm computation.
764: Input Parameters:
765: + bv - basis vectors
766: . j - column number to be used
767: . type - the norm type
768: - val - the norm
770: Note:
771: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
773: Level: advanced
775: .seealso: BVNormColumnEnd(), BVNormColumn()
776: @*/
777: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)778: {
779: PetscErrorCode ierr;
780: PetscSplitReduction *sr;
781: PetscReal lresult;
782: MPI_Comm comm;
783: Vec z;
791: BVCheckSizes(bv,1);
793: if (j<0 || j>=bv->m) SETERRQ2(PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Argument j has wrong value %D, the number of columns is %D",j,bv->m);
794: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
796: PetscLogEventBegin(BV_NormVec,bv,0,0,0);
797: BVGetColumn(bv,j,&z);
798: if (bv->matrix) { /* non-standard inner product */
799: BVNorm_Begin_Private(bv,z,type,val);
800: } else if (bv->ops->norm_begin) {
801: (*bv->ops->norm_begin)(bv,j,type,val);
802: } else {
803: PetscObjectGetComm((PetscObject)z,&comm);
804: PetscSplitReductionGet(comm,&sr);
805: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
806: if (sr->numopsbegin >= sr->maxops) {
807: PetscSplitReductionExtend(sr);
808: }
809: sr->invecs[sr->numopsbegin] = (void*)bv;
810: (*bv->ops->norm_local)(bv,j,type,&lresult);
811: if (type == NORM_2) lresult = lresult*lresult;
812: if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = REDUCE_MAX;
813: else sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
814: sr->lvalues[sr->numopsbegin++] = lresult;
815: }
816: BVRestoreColumn(bv,j,&z);
817: PetscLogEventEnd(BV_NormVec,bv,0,0,0);
818: return(0);
819: }
823: /*@
824: BVNormColumnEnd - Ends a split phase norm computation.
826: Input Parameters:
827: + bv - basis vectors
828: . j - column number to be used
829: . type - the norm type
830: - val - the norm
832: Note:
833: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
835: Level: advanced
837: .seealso: BVNormColumnBegin(), BVNormColumn()
838: @*/
839: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)840: {
841: PetscErrorCode ierr;
842: PetscSplitReduction *sr;
843: MPI_Comm comm;
844: Vec z;
852: BVCheckSizes(bv,1);
854: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
856: BVGetColumn(bv,j,&z);
857: if (bv->matrix) { /* non-standard inner product */
858: BVNorm_End_Private(bv,z,type,val);
859: } else if (bv->ops->norm_end) {
860: (*bv->ops->norm_end)(bv,j,type,val);
861: } else {
862: PetscObjectGetComm((PetscObject)z,&comm);
863: PetscSplitReductionGet(comm,&sr);
864: PetscSplitReductionEnd(sr);
866: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
867: if ((void*)bv != sr->invecs[sr->numopsend]) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() in a different order or with a different vector than VecxxxBegin()");
868: if (sr->reducetype[sr->numopsend] != REDUCE_MAX && type == NORM_MAX) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called BVNormEnd(,NORM_MAX,) on a reduction started with VecDotBegin() or NORM_1 or NORM_2");
869: *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
870: if (type == NORM_2) *val = PetscSqrtReal(*val);
871: if (sr->numopsend == sr->numopsbegin) {
872: sr->state = STATE_BEGIN;
873: sr->numopsend = 0;
874: sr->numopsbegin = 0;
875: }
876: }
877: BVRestoreColumn(bv,j,&z);
878: return(0);
879: }
883: /*
884: Compute Y^H*A*X: right part column by column (with MatMult) and bottom
885: part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
886: */
887: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)888: {
890: PetscInt i,j,lx,ly,kx,ky,ulim;
891: Vec z,f;
894: lx = X->l; kx = X->k;
895: ly = Y->l; ky = Y->k;
896: BVCreateVec(X,&f);
897: for (j=lx;j<kx;j++) {
898: BVGetColumn(X,j,&z);
899: MatMult(A,z,f);
900: BVRestoreColumn(X,j,&z);
901: ulim = PetscMin(ly+(j-lx)+1,ky);
902: Y->l = 0; Y->k = ulim;
903: (*Y->ops->dotvec)(Y,f,marray+j*ldm);
904: if (symm) {
905: for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
906: }
907: }
908: if (!symm) {
909: BV_AllocateCoeffs(Y);
910: for (j=ly;j<ky;j++) {
911: BVGetColumn(Y,j,&z);
912: MatMultHermitianTranspose(A,z,f);
913: BVRestoreColumn(Y,j,&z);
914: ulim = PetscMin(lx+(j-ly),kx);
915: X->l = 0; X->k = ulim;
916: (*X->ops->dotvec)(X,f,Y->h);
917: for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
918: }
919: }
920: VecDestroy(&f);
921: X->l = lx; X->k = kx;
922: Y->l = ly; Y->k = ky;
923: return(0);
924: }
928: /*
929: Compute Y^H*A*X= [ -- | Y0'*W1 ]
930: [ Y1'*W0 | Y1'*W1 ]
931: Allocates auxiliary BV to store the result of A*X, then one BVDot932: call for top-right part and another one for bottom part;
933: result placed in marray[*,ldm]
934: */
935: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)936: {
938: PetscInt j,lx,ly,kx,ky;
939: PetscScalar *harray;
940: Mat H;
941: BV W;
944: lx = X->l; kx = X->k;
945: ly = Y->l; ky = Y->k;
946: BVDuplicate(X,&W);
947: X->l = 0; X->k = kx;
948: BVMatMult(X,A,W);
950: /* top-right part, Y0'*AX1 */
951: if (ly>0 && lx<kx) {
952: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
953: W->l = lx; W->k = kx;
954: Y->l = 0; Y->k = ly;
955: BVDot(W,Y,H);
956: MatDenseGetArray(H,&harray);
957: for (j=lx;j<kx;j++) {
958: PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
959: }
960: MatDenseRestoreArray(H,&harray);
961: MatDestroy(&H);
962: }
964: /* bottom part, Y1'*AX */
965: if (kx>0 && ly<ky) {
966: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
967: W->l = 0; W->k = kx;
968: Y->l = ly; Y->k = ky;
969: BVDot(W,Y,H);
970: MatDenseGetArray(H,&harray);
971: for (j=0;j<kx;j++) {
972: PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
973: }
974: MatDenseRestoreArray(H,&harray);
975: MatDestroy(&H);
976: }
977: BVDestroy(&W);
978: X->l = lx; X->k = kx;
979: Y->l = ly; Y->k = ky;
980: return(0);
981: }
985: /*
986: Compute Y^H*A*X= [ -- | Y0'*W1 ]
987: [ Y1'*W0 | Y1'*W1 ]
988: First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
989: Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
990: bottom-left part; result placed in marray[*,ldm]
991: */
992: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)993: {
995: PetscInt i,j,lx,ly,kx,ky;
996: PetscScalar *harray;
997: Mat H;
998: BV W;
1001: lx = X->l; kx = X->k;
1002: ly = Y->l; ky = Y->k;
1004: /* right part, Y'*AX1 */
1005: BVDuplicateResize(X,kx-lx,&W);
1006: if (ky>0 && lx<kx) {
1007: BVMatMult(X,A,W);
1008: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
1009: Y->l = 0; Y->k = ky;
1010: BVDot(W,Y,H);
1011: MatDenseGetArray(H,&harray);
1012: for (j=lx;j<kx;j++) {
1013: PetscMemcpy(marray+j*ldm,harray+(j-lx)*ky,ky*sizeof(PetscScalar));
1014: }
1015: MatDenseRestoreArray(H,&harray);
1016: MatDestroy(&H);
1017: }
1019: /* bottom-left part, Y1'*AX0 */
1020: if (lx>0 && ly<ky) {
1021: if (symm) {
1022: /* do not compute, just copy symmetric elements */
1023: for (i=ly;i<ky;i++) {
1024: for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
1025: }
1026: } else {
1027: BVResize(W,ky-ly,PETSC_FALSE);
1028: Y->l = ly; Y->k = ky;
1029: BVMatMultHermitianTranspose(Y,A,W);
1030: MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
1031: X->l = 0; X->k = lx;
1032: BVDot(W,X,H);
1033: MatDenseGetArray(H,&harray);
1034: for (i=0;i<ky-ly;i++) {
1035: for (j=0;j<lx;j++) {
1036: marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
1037: }
1038: }
1039: MatDenseRestoreArray(H,&harray);
1040: MatDestroy(&H);
1041: }
1042: }
1043: BVDestroy(&W);
1044: X->l = lx; X->k = kx;
1045: Y->l = ly; Y->k = ky;
1046: return(0);
1047: }
1051: /*
1052: Compute Y^H*X = [ -- | Y0'*X1 ] (X contains A*X):
1053: [ Y1'*X0 | Y1'*X1 ]
1054: one BVDot call for top-right part and another one for bottom part;
1055: result placed in marray[*,ldm]
1056: */
1057: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)1058: {
1060: PetscInt j,lx,ly,kx,ky;
1061: PetscScalar *harray;
1062: Mat H;
1065: lx = X->l; kx = X->k;
1066: ly = Y->l; ky = Y->k;
1068: /* top-right part, Y0'*X1 */
1069: if (ly>0 && lx<kx) {
1070: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1071: X->l = lx; X->k = kx;
1072: Y->l = 0; Y->k = ly;
1073: BVDot(X,Y,H);
1074: MatDenseGetArray(H,&harray);
1075: for (j=lx;j<kx;j++) {
1076: PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
1077: }
1078: MatDenseRestoreArray(H,&harray);
1079: MatDestroy(&H);
1080: }
1082: /* bottom part, Y1'*X */
1083: if (kx>0 && ly<ky) {
1084: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1085: X->l = 0; X->k = kx;
1086: Y->l = ly; Y->k = ky;
1087: BVDot(X,Y,H);
1088: MatDenseGetArray(H,&harray);
1089: for (j=0;j<kx;j++) {
1090: PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
1091: }
1092: MatDenseRestoreArray(H,&harray);
1093: MatDestroy(&H);
1094: }
1095: X->l = lx; X->k = kx;
1096: Y->l = ly; Y->k = ky;
1097: return(0);
1098: }
1102: /*@
1103: BVMatProject - Computes the projection of a matrix onto a subspace.
1105: Collective on BV1107: Input Parameters:
1108: + X - basis vectors
1109: . A - (optional) matrix to be projected
1110: . Y - left basis vectors, can be equal to X
1111: - M - Mat object where the result must be placed
1113: Output Parameter:
1114: . M - the resulting matrix
1116: Notes:
1117: If A=NULL, then it is assumed that X already contains A*X.
1119: This operation is similar to BVDot(), with important differences.
1120: The goal is to compute the matrix resulting from the orthogonal projection
1121: of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
1122: oblique projection onto X along Y, M = Y^H*A*X.
1124: A difference with respect to BVDot() is that the standard inner product
1125: is always used, regardless of a non-standard inner product being specified
1126: with BVSetMatrix().
1128: On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1129: where ky (resp. kx) is the number of active columns of Y (resp. X).
1130: Another difference with respect to BVDot() is that all entries of M are
1131: computed except the leading ly,lx part, where ly (resp. lx) is the
1132: number of leading columns of Y (resp. X). Hence, the leading columns of
1133: X and Y participate in the computation, as opposed to BVDot().
1134: The leading part of M is assumed to be already available from previous
1135: computations.
1137: In the orthogonal projection case, Y=X, some computation can be saved if
1138: A is real symmetric (or complex Hermitian). In order to exploit this
1139: property, the symmetry flag of A must be set with MatSetOption().
1141: Level: intermediate
1143: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1144: @*/
1145: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)1146: {
1148: PetscBool match,set,flg,symm=PETSC_FALSE;
1149: PetscInt m,n;
1150: PetscScalar *marray;
1151: Mat Xmatrix,Ymatrix;
1152: PetscObjectId idx,idy;
1160: BVCheckSizes(X,1);
1161: if (A) {
1164: }
1166: BVCheckSizes(Y,3);
1169: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1170: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");
1172: MatGetSize(M,&m,&n);
1173: if (m<Y->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D rows, should have at least %D",m,Y->k);
1174: if (n<X->k) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_SIZ,"Matrix M has %D columns, should have at least %D",n,X->k);
1175: if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
1177: PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1178: /* temporarily set standard inner product */
1179: Xmatrix = X->matrix;
1180: Ymatrix = Y->matrix;
1181: X->matrix = Y->matrix = NULL;
1183: PetscObjectGetId((PetscObject)X,&idx);
1184: PetscObjectGetId((PetscObject)Y,&idy);
1185: if (!A && idx==idy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot set X=Y if A=NULL");
1187: MatDenseGetArray(M,&marray);
1189: if (A && idx==idy) { /* check symmetry of M=X'AX */
1190: MatIsHermitianKnown(A,&set,&flg);
1191: symm = set? flg: PETSC_FALSE;
1192: }
1194: if (A) {
1195: if (X->vmm==BV_MATMULT_VECS) {
1196: /* perform computation column by column */
1197: BVMatProject_Vec(X,A,Y,marray,m,symm);
1198: } else {
1199: /* use BVMatMult, then BVDot */
1200: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1201: if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1202: BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1203: } else {
1204: BVMatProject_MatMult(X,A,Y,marray,m);
1205: }
1206: }
1207: } else {
1208: /* use BVDot on subblocks */
1209: BVMatProject_Dot(X,Y,marray,m);
1210: }
1212: MatDenseRestoreArray(M,&marray);
1213: PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1214: /* restore non-standard inner product */
1215: X->matrix = Xmatrix;
1216: Y->matrix = Ymatrix;
1217: return(0);
1218: }