1: /*
2: BV operations involving global communication.
4: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
5: SLEPc - Scalable Library for Eigenvalue Problem Computations
6: Copyright (c) 2002-2015, 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;
107: BVCheckSizes(X,1);
109: BVCheckSizes(Y,2);
112: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
113: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
115: MatGetSize(M,&m,&n);
116: 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);
117: 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);
118: if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
119: if (X->matrix!=Y->matrix) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"X and Y must have the same inner product matrix");
120: if (X->l==X->k || Y->l==Y->k) return(0);
122: PetscLogEventBegin(BV_Dot,X,Y,0,0);
123: if (X->matrix) { /* non-standard inner product: cast into dotvec ops */
124: BVDot_Private(X,Y,M);
125: } else {
126: (*X->ops->dot)(X,Y,M);
127: }
128: PetscLogEventEnd(BV_Dot,X,Y,0,0);
129: return(0);
130: }
134: /*@
135: BVDotVec - Computes multiple dot products of a vector against all the
136: column vectors of a BV.
138: Collective on BV and Vec
140: Input Parameters:
141: + X - basis vectors
142: - y - a vector
144: Output Parameter:
145: . m - an array where the result must be placed
147: Notes:
148: This is analogue to VecMDot(), but using BV to represent a collection
149: of vectors. The result is m = X^H*y, so m_i is equal to x_j^H y. Note
150: that here X is transposed as opposed to BVDot().
152: If a non-standard inner product has been specified with BVSetMatrix(),
153: then the result is m = X^H*B*y.
155: The length of array m must be equal to the number of active columns of X
156: minus the number of leading columns, i.e. the first entry of m is the
157: product of the first non-leading column with y.
159: Level: intermediate
161: .seealso: BVDot(), BVDotColumn(), BVSetActiveColumns(), BVSetMatrix()
162: @*/
163: PetscErrorCode BVDotVec(BV X,Vec y,PetscScalar *m)164: {
166: PetscInt n;
172: BVCheckSizes(X,1);
176: VecGetLocalSize(y,&n);
177: if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
179: PetscLogEventBegin(BV_Dot,X,y,0,0);
180: (*X->ops->dotvec)(X,y,m);
181: PetscLogEventEnd(BV_Dot,X,y,0,0);
182: return(0);
183: }
187: /*@
188: BVDotVecBegin - Starts a split phase dot product computation.
190: Input Parameters:
191: + X - basis vectors
192: . y - a vector
193: - m - an array where the result will go (can be NULL)
195: Note:
196: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
198: Level: advanced
200: .seealso: BVDotVecEnd(), BVDotVec()
201: @*/
202: PetscErrorCode BVDotVecBegin(BV X,Vec y,PetscScalar *m)203: {
204: PetscErrorCode ierr;
205: PetscInt i,n,nv;
206: PetscSplitReduction *sr;
207: MPI_Comm comm;
213: BVCheckSizes(X,1);
217: VecGetLocalSize(y,&n);
218: if (X->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, y %D",X->n,n);
220: if (X->ops->dotvec_begin) {
221: (*X->ops->dotvec_begin)(X,y,m);
222: } else {
223: nv = X->k-X->l;
224: PetscObjectGetComm((PetscObject)X,&comm);
225: PetscSplitReductionGet(comm,&sr);
226: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
227: for (i=0;i<nv;i++) {
228: if (sr->numopsbegin+i >= sr->maxops) {
229: PetscSplitReductionExtend(sr);
230: }
231: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
232: sr->invecs[sr->numopsbegin+i] = (void*)X;
233: }
234: PetscLogEventBegin(BV_Dot,X,y,0,0);
235: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
236: sr->numopsbegin += nv;
237: PetscLogEventEnd(BV_Dot,X,y,0,0);
238: }
239: return(0);
240: }
244: /*@
245: BVDotVecEnd - Ends a split phase dot product computation.
247: Input Parameters:
248: + X - basis vectors
249: . y - a vector
250: - m - an array where the result will go
252: Note:
253: Each call to BVDotVecBegin() should be paired with a call to BVDotVecEnd().
255: Level: advanced
257: .seealso: BVDotVecBegin(), BVDotVec()
258: @*/
259: PetscErrorCode BVDotVecEnd(BV X,Vec y,PetscScalar *m)260: {
261: PetscErrorCode ierr;
262: PetscInt i,nv;
263: PetscSplitReduction *sr;
264: MPI_Comm comm;
269: BVCheckSizes(X,1);
271: if (X->ops->dotvec_end) {
272: (*X->ops->dotvec_end)(X,y,m);
273: } else {
274: nv = X->k-X->l;
275: PetscObjectGetComm((PetscObject)X,&comm);
276: PetscSplitReductionGet(comm,&sr);
277: PetscSplitReductionEnd(sr);
279: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
280: 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()");
281: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
282: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
284: /* Finished getting all the results so reset to no outstanding requests */
285: if (sr->numopsend == sr->numopsbegin) {
286: sr->state = STATE_BEGIN;
287: sr->numopsend = 0;
288: sr->numopsbegin = 0;
289: }
290: }
291: return(0);
292: }
296: /*@
297: BVDotColumn - Computes multiple dot products of a column against all the
298: previous columns of a BV.
300: Collective on BV302: Input Parameters:
303: + X - basis vectors
304: - j - the column index
306: Output Parameter:
307: . m - an array where the result must be placed
309: Notes:
310: This operation is equivalent to BVDotVec() but it uses column j of X
311: rather than taking a Vec as an argument. The number of active columns of
312: X is set to j before the computation, and restored afterwards.
313: If X has leading columns specified, then these columns do not participate
314: in the computation. Therefore, the length of array m must be equal to j
315: minus the number of leading columns.
317: Level: advanced
319: .seealso: BVDot(), BVDotVec(), BVSetActiveColumns(), BVSetMatrix()
320: @*/
321: PetscErrorCode BVDotColumn(BV X,PetscInt j,PetscScalar *m)322: {
324: PetscInt ksave;
325: Vec y;
331: BVCheckSizes(X,1);
333: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
334: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
336: PetscLogEventBegin(BV_Dot,X,0,0,0);
337: ksave = X->k;
338: X->k = j;
339: BVGetColumn(X,j,&y);
340: (*X->ops->dotvec)(X,y,m);
341: BVRestoreColumn(X,j,&y);
342: X->k = ksave;
343: PetscLogEventEnd(BV_Dot,X,0,0,0);
344: return(0);
345: }
349: /*@
350: BVDotColumnBegin - Starts a split phase dot product computation.
352: Input Parameters:
353: + X - basis vectors
354: - j - the column index
355: - m - an array where the result will go (can be NULL)
357: Note:
358: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
360: Level: advanced
362: .seealso: BVDotColumnEnd(), BVDotColumn()
363: @*/
364: PetscErrorCode BVDotColumnBegin(BV X,PetscInt j,PetscScalar *m)365: {
366: PetscErrorCode ierr;
367: PetscInt i,nv,ksave;
368: PetscSplitReduction *sr;
369: MPI_Comm comm;
370: Vec y;
376: BVCheckSizes(X,1);
378: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
379: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
380: ksave = X->k;
381: X->k = j;
382: BVGetColumn(X,j,&y);
384: if (X->ops->dotvec_begin) {
385: (*X->ops->dotvec_begin)(X,y,m);
386: } else {
387: nv = X->k-X->l;
388: PetscObjectGetComm((PetscObject)X,&comm);
389: PetscSplitReductionGet(comm,&sr);
390: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
391: for (i=0;i<nv;i++) {
392: if (sr->numopsbegin+i >= sr->maxops) {
393: PetscSplitReductionExtend(sr);
394: }
395: sr->reducetype[sr->numopsbegin+i] = REDUCE_SUM;
396: sr->invecs[sr->numopsbegin+i] = (void*)X;
397: }
398: PetscLogEventBegin(BV_Dot,X,0,0,0);
399: (*X->ops->dotvec_local)(X,y,sr->lvalues+sr->numopsbegin);
400: sr->numopsbegin += nv;
401: PetscLogEventEnd(BV_Dot,X,0,0,0);
402: }
403: BVRestoreColumn(X,j,&y);
404: X->k = ksave;
405: return(0);
406: }
410: /*@
411: BVDotColumnEnd - Ends a split phase dot product computation.
413: Input Parameters:
414: + X - basis vectors
415: - j - the column index
416: - m - an array where the result will go
418: Note:
419: Each call to BVDotColumnBegin() should be paired with a call to BVDotColumnEnd().
421: Level: advanced
423: .seealso: BVDotColumnBegin(), BVDotColumn()
424: @*/
425: PetscErrorCode BVDotColumnEnd(BV X,PetscInt j,PetscScalar *m)426: {
427: PetscErrorCode ierr;
428: PetscInt i,nv,ksave;
429: PetscSplitReduction *sr;
430: MPI_Comm comm;
431: Vec y;
437: BVCheckSizes(X,1);
439: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
440: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
441: ksave = X->k;
442: X->k = j;
444: if (X->ops->dotvec_end) {
445: BVGetColumn(X,j,&y);
446: (*X->ops->dotvec_end)(X,y,m);
447: BVRestoreColumn(X,j,&y);
448: } else {
449: nv = X->k-X->l;
450: PetscObjectGetComm((PetscObject)X,&comm);
451: PetscSplitReductionGet(comm,&sr);
452: PetscSplitReductionEnd(sr);
454: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times than VecxxxBegin()");
455: 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()");
456: if (sr->reducetype[sr->numopsend] != REDUCE_SUM) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Wrong type of reduction");
457: for (i=0;i<nv;i++) m[i] = sr->gvalues[sr->numopsend++];
459: /* Finished getting all the results so reset to no outstanding requests */
460: if (sr->numopsend == sr->numopsbegin) {
461: sr->state = STATE_BEGIN;
462: sr->numopsend = 0;
463: sr->numopsbegin = 0;
464: }
465: }
466: X->k = ksave;
467: return(0);
468: }
472: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Private(BV bv,Vec z,NormType type,PetscReal *val)473: {
475: PetscScalar p;
478: BV_IPMatMult(bv,z);
479: VecDot(bv->Bx,z,&p);
480: if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
481: PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
482: if (bv->indef) {
483: if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
484: if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
485: else *val = PetscSqrtScalar(PetscRealPart(p));
486: } else {
487: if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
488: *val = PetscSqrtScalar(PetscRealPart(p));
489: }
490: return(0);
491: }
495: PETSC_STATIC_INLINE PetscErrorCode BVNorm_Begin_Private(BV bv,Vec z,NormType type,PetscReal *val)496: {
498: PetscScalar p;
501: BV_IPMatMult(bv,z);
502: VecDotBegin(bv->Bx,z,&p);
503: return(0);
504: }
508: PETSC_STATIC_INLINE PetscErrorCode BVNorm_End_Private(BV bv,Vec z,NormType type,PetscReal *val)509: {
511: PetscScalar p;
514: VecDotEnd(bv->Bx,z,&p);
515: if (PetscAbsScalar(p)<PETSC_MACHINE_EPSILON)
516: PetscInfo(bv,"Zero norm, either the vector is zero or a semi-inner product is being used\n");
517: if (bv->indef) {
518: if (PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
519: if (PetscRealPart(p)<0.0) *val = -PetscSqrtScalar(-PetscRealPart(p));
520: else *val = PetscSqrtScalar(PetscRealPart(p));
521: } else {
522: if (PetscRealPart(p)<0.0 || PetscAbsReal(PetscImaginaryPart(p))/PetscAbsScalar(p)>PETSC_MACHINE_EPSILON) SETERRQ(PetscObjectComm((PetscObject)bv),1,"BVNorm: The inner product is not well defined");
523: *val = PetscSqrtScalar(PetscRealPart(p));
524: }
525: return(0);
526: }
530: /*@
531: BVNorm - Computes the matrix norm of the BV.
533: Collective on BV535: Input Parameters:
536: + bv - basis vectors
537: - type - the norm type
539: Output Parameter:
540: . val - the norm
542: Notes:
543: All active columns (except the leading ones) are considered as a matrix.
544: The allowed norms are NORM_1, NORM_FROBENIUS, and NORM_INFINITY.
546: This operation fails if a non-standard inner product has been
547: specified with BVSetMatrix().
549: Level: intermediate
551: .seealso: BVNormVec(), BVNormColumn(), BVSetActiveColumns(), BVSetMatrix()
552: @*/
553: PetscErrorCode BVNorm(BV bv,NormType type,PetscReal *val)554: {
562: BVCheckSizes(bv,1);
564: if (type==NORM_2 || type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
565: if (bv->matrix) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Matrix norm not available for non-standard inner product");
567: PetscLogEventBegin(BV_Norm,bv,0,0,0);
568: (*bv->ops->norm)(bv,-1,type,val);
569: PetscLogEventEnd(BV_Norm,bv,0,0,0);
570: return(0);
571: }
575: /*@
576: BVNormVec - Computes the norm of a given vector.
578: Collective on BV580: Input Parameters:
581: + bv - basis vectors
582: . v - the vector
583: - type - the norm type
585: Output Parameter:
586: . val - the norm
588: Notes:
589: This is the analogue of BVNormColumn() but for a vector that is not in the BV.
590: If a non-standard inner product has been specified with BVSetMatrix(),
591: then the returned value is sqrt(v'*B*v), where B is the inner product
592: matrix (argument 'type' is ignored). Otherwise, VecNorm() is called.
594: Level: developer
596: .seealso: BVNorm(), BVNormColumn(), BVSetMatrix()
597: @*/
598: PetscErrorCode BVNormVec(BV bv,Vec v,NormType type,PetscReal *val)599: {
601: PetscInt n;
609: BVCheckSizes(bv,1);
613: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
615: PetscLogEventBegin(BV_Norm,bv,0,0,0);
616: if (bv->matrix) { /* non-standard inner product */
617: VecGetLocalSize(v,&n);
618: if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
619: BVNorm_Private(bv,v,type,val);
620: } else {
621: VecNorm(v,type,val);
622: }
623: PetscLogEventEnd(BV_Norm,bv,0,0,0);
624: return(0);
625: }
629: /*@
630: BVNormVecBegin - Starts a split phase norm computation.
632: Input Parameters:
633: + bv - basis vectors
634: . v - the vector
635: . type - the norm type
636: - val - the norm
638: Note:
639: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
641: Level: advanced
643: .seealso: BVNormVecEnd(), BVNormVec()
644: @*/
645: PetscErrorCode BVNormVecBegin(BV bv,Vec v,NormType type,PetscReal *val)646: {
648: PetscInt n;
656: BVCheckSizes(bv,1);
660: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
662: PetscLogEventBegin(BV_Norm,bv,0,0,0);
663: if (bv->matrix) { /* non-standard inner product */
664: VecGetLocalSize(v,&n);
665: if (bv->n!=n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension bv %D, v %D",bv->n,n);
666: BVNorm_Begin_Private(bv,v,type,val);
667: } else {
668: VecNormBegin(v,type,val);
669: }
670: PetscLogEventEnd(BV_Norm,bv,0,0,0);
671: return(0);
672: }
676: /*@
677: BVNormVecEnd - Ends a split phase norm computation.
679: Input Parameters:
680: + bv - basis vectors
681: . v - the vector
682: . type - the norm type
683: - val - the norm
685: Note:
686: Each call to BVNormVecBegin() should be paired with a call to BVNormVecEnd().
688: Level: advanced
690: .seealso: BVNormVecBegin(), BVNormVec()
691: @*/
692: PetscErrorCode BVNormVecEnd(BV bv,Vec v,NormType type,PetscReal *val)693: {
701: BVCheckSizes(bv,1);
703: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
705: if (bv->matrix) { /* non-standard inner product */
706: BVNorm_End_Private(bv,v,type,val);
707: } else {
708: VecNormEnd(v,type,val);
709: }
710: return(0);
711: }
715: /*@
716: BVNormColumn - Computes the vector norm of a selected column.
718: Collective on BV720: Input Parameters:
721: + bv - basis vectors
722: . j - column number to be used
723: - type - the norm type
725: Output Parameter:
726: . val - the norm
728: Notes:
729: The norm of V[j] is computed (NORM_1, NORM_2, or NORM_INFINITY).
730: If a non-standard inner product has been specified with BVSetMatrix(),
731: then the returned value is sqrt(V[j]'*B*V[j]),
732: where B is the inner product matrix (argument 'type' is ignored).
734: Level: intermediate
736: .seealso: BVNorm(), BVNormVec(), BVSetActiveColumns(), BVSetMatrix()
737: @*/
738: PetscErrorCode BVNormColumn(BV bv,PetscInt j,NormType type,PetscReal *val)739: {
741: Vec z;
749: BVCheckSizes(bv,1);
751: 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);
752: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
754: PetscLogEventBegin(BV_Norm,bv,0,0,0);
755: if (bv->matrix) { /* non-standard inner product */
756: BVGetColumn(bv,j,&z);
757: BVNorm_Private(bv,z,type,val);
758: BVRestoreColumn(bv,j,&z);
759: } else {
760: (*bv->ops->norm)(bv,j,type,val);
761: }
762: PetscLogEventEnd(BV_Norm,bv,0,0,0);
763: return(0);
764: }
768: /*@
769: BVNormColumnBegin - Starts a split phase norm computation.
771: Input Parameters:
772: + bv - basis vectors
773: . j - column number to be used
774: . type - the norm type
775: - val - the norm
777: Note:
778: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
780: Level: advanced
782: .seealso: BVNormColumnEnd(), BVNormColumn()
783: @*/
784: PetscErrorCode BVNormColumnBegin(BV bv,PetscInt j,NormType type,PetscReal *val)785: {
786: PetscErrorCode ierr;
787: PetscSplitReduction *sr;
788: PetscReal lresult;
789: MPI_Comm comm;
790: Vec z;
798: BVCheckSizes(bv,1);
800: 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);
801: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
803: PetscLogEventBegin(BV_Norm,bv,0,0,0);
804: BVGetColumn(bv,j,&z);
805: if (bv->matrix) { /* non-standard inner product */
806: BVNorm_Begin_Private(bv,z,type,val);
807: } else if (bv->ops->norm_begin) {
808: (*bv->ops->norm_begin)(bv,j,type,val);
809: } else {
810: PetscObjectGetComm((PetscObject)z,&comm);
811: PetscSplitReductionGet(comm,&sr);
812: if (sr->state != STATE_BEGIN) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ORDER,"Called before all VecxxxEnd() called");
813: if (sr->numopsbegin >= sr->maxops) {
814: PetscSplitReductionExtend(sr);
815: }
816: sr->invecs[sr->numopsbegin] = (void*)bv;
817: (*bv->ops->norm_local)(bv,j,type,&lresult);
818: if (type == NORM_2) lresult = lresult*lresult;
819: else if (type == NORM_MAX) sr->reducetype[sr->numopsbegin] = REDUCE_MAX;
820: else sr->reducetype[sr->numopsbegin] = REDUCE_SUM;
821: sr->lvalues[sr->numopsbegin++] = lresult;
822: }
823: BVRestoreColumn(bv,j,&z);
824: PetscLogEventEnd(BV_Norm,bv,0,0,0);
825: return(0);
826: }
830: /*@
831: BVNormColumnEnd - Ends a split phase norm computation.
833: Input Parameters:
834: + bv - basis vectors
835: . j - column number to be used
836: . type - the norm type
837: - val - the norm
839: Note:
840: Each call to BVNormColumnBegin() should be paired with a call to BVNormColumnEnd().
842: Level: advanced
844: .seealso: BVNormColumnBegin(), BVNormColumn()
845: @*/
846: PetscErrorCode BVNormColumnEnd(BV bv,PetscInt j,NormType type,PetscReal *val)847: {
848: PetscErrorCode ierr;
849: PetscSplitReduction *sr;
850: MPI_Comm comm;
851: Vec z;
859: BVCheckSizes(bv,1);
861: if (type==NORM_1_AND_2) SETERRQ(PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Requested norm not available");
863: BVGetColumn(bv,j,&z);
864: if (bv->matrix) { /* non-standard inner product */
865: BVNorm_End_Private(bv,z,type,val);
866: } else if (bv->ops->norm_end) {
867: (*bv->ops->norm_end)(bv,j,type,val);
868: } else {
869: PetscObjectGetComm((PetscObject)z,&comm);
870: PetscSplitReductionGet(comm,&sr);
871: PetscSplitReductionEnd(sr);
873: if (sr->numopsend >= sr->numopsbegin) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONGSTATE,"Called VecxxxEnd() more times then VecxxxBegin()");
874: 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()");
875: 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");
876: *val = PetscRealPart(sr->gvalues[sr->numopsend++]);
877: if (type == NORM_2) *val = PetscSqrtReal(*val);
878: if (sr->numopsend == sr->numopsbegin) {
879: sr->state = STATE_BEGIN;
880: sr->numopsend = 0;
881: sr->numopsbegin = 0;
882: }
883: }
884: BVRestoreColumn(bv,j,&z);
885: return(0);
886: }
890: /*
891: Compute Y^H*A*X: right part column by column (with MatMult) and bottom
892: part row by row (with MatMultHermitianTranspose); result placed in marray[*,ldm]
893: */
894: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Vec(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)895: {
897: PetscInt i,j,lx,ly,kx,ky,ulim;
898: Vec z,f;
901: lx = X->l; kx = X->k;
902: ly = Y->l; ky = Y->k;
903: BVCreateVec(X,&f);
904: for (j=lx;j<kx;j++) {
905: BVGetColumn(X,j,&z);
906: MatMult(A,z,f);
907: BVRestoreColumn(X,j,&z);
908: ulim = PetscMin(ly+(j-lx)+1,ky);
909: Y->l = 0; Y->k = ulim;
910: (*Y->ops->dotvec)(Y,f,marray+j*ldm);
911: if (symm) {
912: for (i=0;i<j;i++) marray[j+i*ldm] = PetscConj(marray[i+j*ldm]);
913: }
914: }
915: if (!symm) {
916: BV_AllocateCoeffs(Y);
917: for (j=ly;j<ky;j++) {
918: BVGetColumn(Y,j,&z);
919: MatMultHermitianTranspose(A,z,f);
920: BVRestoreColumn(Y,j,&z);
921: ulim = PetscMin(lx+(j-ly),kx);
922: X->l = 0; X->k = ulim;
923: (*X->ops->dotvec)(X,f,Y->h);
924: for (i=0;i<ulim;i++) marray[j+i*ldm] = PetscConj(Y->h[i]);
925: }
926: }
927: VecDestroy(&f);
928: X->l = lx; X->k = kx;
929: Y->l = ly; Y->k = ky;
930: return(0);
931: }
935: /*
936: Compute Y^H*A*X= [ -- | Y0'*W1 ]
937: [ Y1'*W0 | Y1'*W1 ]
938: Allocates auxiliary BV to store the result of A*X, then one BVDot939: call for top-right part and another one for bottom part;
940: result placed in marray[*,ldm]
941: */
942: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm)943: {
945: PetscInt j,lx,ly,kx,ky;
946: PetscScalar *harray;
947: Mat H;
948: BV W;
951: lx = X->l; kx = X->k;
952: ly = Y->l; ky = Y->k;
953: BVDuplicate(X,&W);
954: X->l = 0; X->k = kx;
955: BVMatMult(X,A,W);
957: /* top-right part, Y0'*AX1 */
958: if (ly>0 && lx<kx) {
959: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
960: W->l = lx; W->k = kx;
961: Y->l = 0; Y->k = ly;
962: BVDot(W,Y,H);
963: MatDenseGetArray(H,&harray);
964: for (j=lx;j<kx;j++) {
965: PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
966: }
967: MatDenseRestoreArray(H,&harray);
968: MatDestroy(&H);
969: }
971: /* bottom part, Y1'*AX */
972: if (kx>0 && ly<ky) {
973: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
974: W->l = 0; W->k = kx;
975: Y->l = ly; Y->k = ky;
976: BVDot(W,Y,H);
977: MatDenseGetArray(H,&harray);
978: for (j=0;j<kx;j++) {
979: PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
980: }
981: MatDenseRestoreArray(H,&harray);
982: MatDestroy(&H);
983: }
984: BVDestroy(&W);
985: X->l = lx; X->k = kx;
986: Y->l = ly; Y->k = ky;
987: return(0);
988: }
992: /*
993: Compute Y^H*A*X= [ -- | Y0'*W1 ]
994: [ Y1'*W0 | Y1'*W1 ]
995: First stage: allocate auxiliary BV to store A*X1, one BVDot for right part;
996: Second stage: resize BV to accomodate A'*Y1, then call BVDot for transpose of
997: bottom-left part; result placed in marray[*,ldm]
998: */
999: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_MatMult_2(BV X,Mat A,BV Y,PetscScalar *marray,PetscInt ldm,PetscBool symm)1000: {
1002: PetscInt i,j,lx,ly,kx,ky;
1003: PetscScalar *harray;
1004: Mat H;
1005: BV W;
1008: lx = X->l; kx = X->k;
1009: ly = Y->l; ky = Y->k;
1011: /* right part, Y'*AX1 */
1012: BVDuplicateResize(X,kx-lx,&W);
1013: if (ky>0 && lx<kx) {
1014: BVMatMult(X,A,W);
1015: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx-lx,NULL,&H);
1016: Y->l = 0; Y->k = ky;
1017: BVDot(W,Y,H);
1018: MatDenseGetArray(H,&harray);
1019: for (j=lx;j<kx;j++) {
1020: PetscMemcpy(marray+j*ldm,harray+(j-lx)*ky,ky*sizeof(PetscScalar));
1021: }
1022: MatDenseRestoreArray(H,&harray);
1023: MatDestroy(&H);
1024: }
1026: /* bottom-left part, Y1'*AX0 */
1027: if (lx>0 && ly<ky) {
1028: if (symm) {
1029: /* do not compute, just copy symmetric elements */
1030: for (i=ly;i<ky;i++) {
1031: for (j=0;j<lx;j++) marray[i+j*ldm] = PetscConj(marray[j+i*ldm]);
1032: }
1033: } else {
1034: BVResize(W,ky-ly,PETSC_FALSE);
1035: Y->l = ly; Y->k = ky;
1036: BVMatMultHermitianTranspose(Y,A,W);
1037: MatCreateSeqDense(PETSC_COMM_SELF,lx,ky-ly,NULL,&H);
1038: X->l = 0; X->k = lx;
1039: BVDot(W,X,H);
1040: MatDenseGetArray(H,&harray);
1041: for (i=0;i<ky-ly;i++) {
1042: for (j=0;j<lx;j++) {
1043: marray[i+j*ldm+ly] = PetscConj(harray[j+i*(ky-ly)]);
1044: }
1045: }
1046: MatDenseRestoreArray(H,&harray);
1047: MatDestroy(&H);
1048: }
1049: }
1050: BVDestroy(&W);
1051: X->l = lx; X->k = kx;
1052: Y->l = ly; Y->k = ky;
1053: return(0);
1054: }
1058: /*
1059: Compute Y^H*X = [ -- | Y0'*X1 ] (X contains A*X):
1060: [ Y1'*X0 | Y1'*X1 ]
1061: one BVDot call for top-right part and another one for bottom part;
1062: result placed in marray[*,ldm]
1063: */
1064: PETSC_STATIC_INLINE PetscErrorCode BVMatProject_Dot(BV X,BV Y,PetscScalar *marray,PetscInt ldm)1065: {
1067: PetscInt j,lx,ly,kx,ky;
1068: PetscScalar *harray;
1069: Mat H;
1072: lx = X->l; kx = X->k;
1073: ly = Y->l; ky = Y->k;
1075: /* top-right part, Y0'*X1 */
1076: if (ly>0 && lx<kx) {
1077: MatCreateSeqDense(PETSC_COMM_SELF,ly,kx,NULL,&H);
1078: X->l = lx; X->k = kx;
1079: Y->l = 0; Y->k = ly;
1080: BVDot(X,Y,H);
1081: MatDenseGetArray(H,&harray);
1082: for (j=lx;j<kx;j++) {
1083: PetscMemcpy(marray+j*ldm,harray+j*ly,ly*sizeof(PetscScalar));
1084: }
1085: MatDenseRestoreArray(H,&harray);
1086: MatDestroy(&H);
1087: }
1089: /* bottom part, Y1'*X */
1090: if (kx>0 && ly<ky) {
1091: MatCreateSeqDense(PETSC_COMM_SELF,ky,kx,NULL,&H);
1092: X->l = 0; X->k = kx;
1093: Y->l = ly; Y->k = ky;
1094: BVDot(X,Y,H);
1095: MatDenseGetArray(H,&harray);
1096: for (j=0;j<kx;j++) {
1097: PetscMemcpy(marray+j*ldm+ly,harray+j*ky+ly,(ky-ly)*sizeof(PetscScalar));
1098: }
1099: MatDenseRestoreArray(H,&harray);
1100: MatDestroy(&H);
1101: }
1102: X->l = lx; X->k = kx;
1103: Y->l = ly; Y->k = ky;
1104: return(0);
1105: }
1109: /*@
1110: BVMatProject - Computes the projection of a matrix onto a subspace.
1112: Collective on BV1114: Input Parameters:
1115: + X - basis vectors
1116: . A - (optional) matrix to be projected
1117: . Y - left basis vectors, can be equal to X
1118: - M - Mat object where the result must be placed
1120: Output Parameter:
1121: . M - the resulting matrix
1123: Notes:
1124: If A=NULL, then it is assumed that X already contains A*X.
1126: This operation is similar to BVDot(), with important differences.
1127: The goal is to compute the matrix resulting from the orthogonal projection
1128: of A onto the subspace spanned by the columns of X, M = X^H*A*X, or the
1129: oblique projection onto X along Y, M = Y^H*A*X.
1131: A difference with respect to BVDot() is that the standard inner product
1132: is always used, regardless of a non-standard inner product being specified
1133: with BVSetMatrix().
1135: On entry, M must be a sequential dense Mat with dimensions ky,kx at least,
1136: where ky (resp. kx) is the number of active columns of Y (resp. X).
1137: Another difference with respect to BVDot() is that all entries of M are
1138: computed except the leading ly,lx part, where ly (resp. lx) is the
1139: number of leading columns of Y (resp. X). Hence, the leading columns of
1140: X and Y participate in the computation, as opposed to BVDot().
1141: The leading part of M is assumed to be already available from previous
1142: computations.
1144: In the orthogonal projection case, Y=X, some computation can be saved if
1145: A is real symmetric (or complex Hermitian). In order to exploit this
1146: property, the symmetry flag of A must be set with MatSetOption().
1148: Level: intermediate
1150: .seealso: BVDot(), BVSetActiveColumns(), BVSetMatrix()
1151: @*/
1152: PetscErrorCode BVMatProject(BV X,Mat A,BV Y,Mat M)1153: {
1155: PetscBool match,set,flg,symm=PETSC_FALSE;
1156: PetscInt m,n;
1157: PetscScalar *marray;
1158: Mat Xmatrix,Ymatrix;
1159: PetscObjectId idx,idy;
1167: BVCheckSizes(X,1);
1168: if (A) {
1171: }
1173: BVCheckSizes(Y,3);
1176: PetscObjectTypeCompare((PetscObject)M,MATSEQDENSE,&match);
1177: if (!match) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_SUP,"Matrix M must be of type seqdense");
1179: MatGetSize(M,&m,&n);
1180: 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);
1181: 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);
1182: if (X->n!=Y->n) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
1184: PetscLogEventBegin(BV_MatProject,X,A,Y,0);
1185: /* temporarily set standard inner product */
1186: Xmatrix = X->matrix;
1187: Ymatrix = Y->matrix;
1188: X->matrix = Y->matrix = NULL;
1190: PetscObjectGetId((PetscObject)X,&idx);
1191: PetscObjectGetId((PetscObject)Y,&idy);
1192: if (!A && idx==idy) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Cannot set X=Y if A=NULL");
1194: MatDenseGetArray(M,&marray);
1196: if (A && idx==idy) { /* check symmetry of M=X'AX */
1197: MatIsHermitianKnown(A,&set,&flg);
1198: symm = set? flg: PETSC_FALSE;
1199: }
1201: if (A) {
1202: if (X->vmm==BV_MATMULT_VECS) {
1203: /* perform computation column by column */
1204: BVMatProject_Vec(X,A,Y,marray,m,symm);
1205: } else {
1206: /* use BVMatMult, then BVDot */
1207: MatHasOperation(A,MATOP_MULT_TRANSPOSE,&flg);
1208: if (symm || (flg && X->l>=X->k/2 && Y->l>=Y->k/2)) {
1209: BVMatProject_MatMult_2(X,A,Y,marray,m,symm);
1210: } else {
1211: BVMatProject_MatMult(X,A,Y,marray,m);
1212: }
1213: }
1214: } else {
1215: /* use BVDot on subblocks */
1216: BVMatProject_Dot(X,Y,marray,m);
1217: }
1219: MatDenseRestoreArray(M,&marray);
1220: PetscLogEventEnd(BV_MatProject,X,A,Y,0);
1221: /* restore non-standard inner product */
1222: X->matrix = Xmatrix;
1223: Y->matrix = Ymatrix;
1224: return(0);
1225: }