1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-2019, Universitat Politecnica de Valencia, Spain
6: This file is part of SLEPc.
7: SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9: */
10: /*
11: BV operations, except those involving global communication
12: */
14: #include <slepc/private/bvimpl.h> /*I "slepcbv.h" I*/
15: #include <slepcds.h>
17: /*@
18: BVMult - Computes Y = beta*Y + alpha*X*Q.
20: Logically Collective on BV 22: Input Parameters:
23: + Y,X - basis vectors
24: . alpha,beta - scalars
25: - Q - (optional) sequential dense matrix
27: Output Parameter:
28: . Y - the modified basis vectors
30: Notes:
31: X and Y must be different objects. The case X=Y can be addressed with
32: BVMultInPlace().
34: If matrix Q is NULL, then an AXPY operation Y = beta*Y + alpha*X is done
35: (i.e. results as if Q = identity). If provided,
36: the matrix Q must be a sequential dense Mat, with all entries equal on
37: all processes (otherwise each process will compute a different update).
38: The dimensions of Q must be at least m,n where m is the number of active
39: columns of X and n is the number of active columns of Y.
41: The leading columns of Y are not modified. Also, if X has leading
42: columns specified, then these columns do not participate in the computation.
43: Hence, only rows (resp. columns) of Q starting from lx (resp. ly) are used,
44: where lx (resp. ly) is the number of leading columns of X (resp. Y).
46: Level: intermediate
48: .seealso: BVMultVec(), BVMultColumn(), BVMultInPlace(), BVSetActiveColumns()
49: @*/
50: PetscErrorCode BVMult(BV Y,PetscScalar alpha,PetscScalar beta,BV X,Mat Q) 51: {
53: PetscBool match;
54: PetscInt m,n;
63: BVCheckSizes(Y,1);
65: BVCheckSizes(X,4);
68: if (X==Y) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_WRONG,"X and Y arguments must be different");
69: if (Q) {
70: PetscObjectTypeCompare((PetscObject)Q,MATSEQDENSE,&match);
71: if (!match) SETERRQ(PetscObjectComm((PetscObject)Y),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
72: MatGetSize(Q,&m,&n);
73: if (m<X->k) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_SIZ,"Mat argument has %D rows, should have at least %D",m,X->k);
74: if (n<Y->k) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_SIZ,"Mat argument has %D columns, should have at least %D",n,Y->k);
75: }
76: if (X->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)Y),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension X %D, Y %D",X->n,Y->n);
78: PetscLogEventBegin(BV_Mult,X,Y,0,0);
79: (*Y->ops->mult)(Y,alpha,beta,X,Q);
80: PetscLogEventEnd(BV_Mult,X,Y,0,0);
81: PetscObjectStateIncrease((PetscObject)Y);
82: return(0);
83: }
85: /*@
86: BVMultVec - Computes y = beta*y + alpha*X*q.
88: Logically Collective on BV and Vec
90: Input Parameters:
91: + X - a basis vectors object
92: . alpha,beta - scalars
93: . y - a vector
94: - q - an array of scalars
96: Output Parameter:
97: . y - the modified vector
99: Notes:
100: This operation is the analogue of BVMult() but with a BV and a Vec,
101: instead of two BV. Note that arguments are listed in different order
102: with respect to BVMult().
104: If X has leading columns specified, then these columns do not participate
105: in the computation.
107: The length of array q must be equal to the number of active columns of X
108: minus the number of leading columns, i.e. the first entry of q multiplies
109: the first non-leading column.
111: Level: intermediate
113: .seealso: BVMult(), BVMultColumn(), BVMultInPlace(), BVSetActiveColumns()
114: @*/
115: PetscErrorCode BVMultVec(BV X,PetscScalar alpha,PetscScalar beta,Vec y,PetscScalar q[])116: {
118: PetscInt n,N;
127: BVCheckSizes(X,1);
131: VecGetSize(y,&N);
132: VecGetLocalSize(y,&n);
133: if (N!=X->N || n!=X->n) SETERRQ4(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_INCOMP,"Vec sizes (global %D, local %D) do not match BV sizes (global %D, local %D)",N,n,X->N,X->n);
135: PetscLogEventBegin(BV_MultVec,X,y,0,0);
136: (*X->ops->multvec)(X,alpha,beta,y,q);
137: PetscLogEventEnd(BV_MultVec,X,y,0,0);
138: return(0);
139: }
141: /*@
142: BVMultColumn - Computes y = beta*y + alpha*X*q, where y is the j-th column
143: of X.
145: Logically Collective on BV147: Input Parameters:
148: + X - a basis vectors object
149: . alpha,beta - scalars
150: . j - the column index
151: - q - an array of scalars
153: Notes:
154: This operation is equivalent to BVMultVec() but it uses column j of X
155: rather than taking a Vec as an argument. The number of active columns of
156: X is set to j before the computation, and restored afterwards.
157: If X has leading columns specified, then these columns do not participate
158: in the computation. Therefore, the length of array q must be equal to j
159: minus the number of leading columns.
161: Developer Notes:
162: If q is NULL, then the coefficients are taken from position nc+l of the
163: internal buffer vector, see BVGetBufferVec().
165: Level: advanced
167: .seealso: BVMult(), BVMultVec(), BVMultInPlace(), BVSetActiveColumns()
168: @*/
169: PetscErrorCode BVMultColumn(BV X,PetscScalar alpha,PetscScalar beta,PetscInt j,PetscScalar *q)170: {
172: PetscInt ksave;
173: Vec y;
181: BVCheckSizes(X,1);
183: if (j<0) SETERRQ(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
184: if (j>=X->m) SETERRQ2(PetscObjectComm((PetscObject)X),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%D but BV only has %D columns",j,X->m);
186: PetscLogEventBegin(BV_MultVec,X,0,0,0);
187: ksave = X->k;
188: X->k = j;
189: if (!q && !X->buffer) { BVGetBufferVec(X,&X->buffer); }
190: BVGetColumn(X,j,&y);
191: (*X->ops->multvec)(X,alpha,beta,y,q);
192: BVRestoreColumn(X,j,&y);
193: X->k = ksave;
194: PetscLogEventEnd(BV_MultVec,X,0,0,0);
195: PetscObjectStateIncrease((PetscObject)X);
196: return(0);
197: }
199: /*@
200: BVMultInPlace - Update a set of vectors as V(:,s:e-1) = V*Q(:,s:e-1).
202: Logically Collective on BV204: Input Parameters:
205: + Q - a sequential dense matrix
206: . s - first column of V to be overwritten
207: - e - first column of V not to be overwritten
209: Input/Output Parameter:
210: . V - basis vectors
212: Notes:
213: The matrix Q must be a sequential dense Mat, with all entries equal on
214: all processes (otherwise each process will compute a different update).
216: This function computes V(:,s:e-1) = V*Q(:,s:e-1), that is, given a set of
217: vectors V, columns from s to e-1 are overwritten with columns from s to
218: e-1 of the matrix-matrix product V*Q. Only columns s to e-1 of Q are
219: referenced.
221: Level: intermediate
223: .seealso: BVMult(), BVMultVec(), BVMultInPlaceTranspose(), BVSetActiveColumns()
224: @*/
225: PetscErrorCode BVMultInPlace(BV V,Mat Q,PetscInt s,PetscInt e)226: {
228: PetscBool match;
229: PetscInt m,n;
237: BVCheckSizes(V,1);
239: PetscObjectTypeCompare((PetscObject)Q,MATSEQDENSE,&match);
240: if (!match) SETERRQ(PetscObjectComm((PetscObject)V),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
242: if (s<V->l || s>V->m) SETERRQ3(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument s has wrong value %D, should be between %D and %D",s,V->l,V->m);
243: if (e<V->l || e>V->m) SETERRQ3(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument e has wrong value %D, should be between %D and %D",e,V->l,V->m);
244: MatGetSize(Q,&m,&n);
245: if (m<V->k) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument has %D rows, should have at least %D",m,V->k);
246: if (e>n) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument only has %D columns, the requested value of e is larger: %D",n,e);
247: if (s>=e) return(0);
249: PetscLogEventBegin(BV_MultInPlace,V,Q,0,0);
250: (*V->ops->multinplace)(V,Q,s,e);
251: PetscLogEventEnd(BV_MultInPlace,V,Q,0,0);
252: PetscObjectStateIncrease((PetscObject)V);
253: return(0);
254: }
256: /*@
257: BVMultInPlaceTranspose - Update a set of vectors as V(:,s:e-1) = V*Q'(:,s:e-1).
259: Logically Collective on BV261: Input Parameters:
262: + Q - a sequential dense matrix
263: . s - first column of V to be overwritten
264: - e - first column of V not to be overwritten
266: Input/Output Parameter:
267: . V - basis vectors
269: Notes:
270: This is a variant of BVMultInPlace() where the conjugate transpose
271: of Q is used.
273: Level: intermediate
275: .seealso: BVMultInPlace()
276: @*/
277: PetscErrorCode BVMultInPlaceTranspose(BV V,Mat Q,PetscInt s,PetscInt e)278: {
280: PetscBool match;
281: PetscInt m,n;
289: BVCheckSizes(V,1);
291: PetscObjectTypeCompare((PetscObject)Q,MATSEQDENSE,&match);
292: if (!match) SETERRQ(PetscObjectComm((PetscObject)V),PETSC_ERR_SUP,"Mat argument must be of type seqdense");
294: if (s<V->l || s>V->m) SETERRQ3(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument s has wrong value %D, should be between %D and %D",s,V->l,V->m);
295: if (e<V->l || e>V->m) SETERRQ3(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Argument e has wrong value %D, should be between %D and %D",e,V->l,V->m);
296: MatGetSize(Q,&m,&n);
297: if (n<V->k) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument has %D columns, should have at least %D",n,V->k);
298: if (e>m) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument only has %D rows, the requested value of e is larger: %D",m,e);
299: if (s>=e || !V->n) return(0);
301: PetscLogEventBegin(BV_MultInPlace,V,Q,0,0);
302: (*V->ops->multinplacetrans)(V,Q,s,e);
303: PetscLogEventEnd(BV_MultInPlace,V,Q,0,0);
304: PetscObjectStateIncrease((PetscObject)V);
305: return(0);
306: }
308: /*@
309: BVScale - Multiply the BV entries by a scalar value.
311: Logically Collective on BV313: Input Parameters:
314: + bv - basis vectors
315: - alpha - scaling factor
317: Note:
318: All active columns (except the leading ones) are scaled.
320: Level: intermediate
322: .seealso: BVScaleColumn(), BVSetActiveColumns()
323: @*/
324: PetscErrorCode BVScale(BV bv,PetscScalar alpha)325: {
332: BVCheckSizes(bv,1);
333: if (alpha == (PetscScalar)1.0) return(0);
335: PetscLogEventBegin(BV_Scale,bv,0,0,0);
336: if (bv->n) {
337: (*bv->ops->scale)(bv,-1,alpha);
338: }
339: PetscLogEventEnd(BV_Scale,bv,0,0,0);
340: PetscObjectStateIncrease((PetscObject)bv);
341: return(0);
342: }
344: /*@
345: BVScaleColumn - Scale one column of a BV.
347: Logically Collective on BV349: Input Parameters:
350: + bv - basis vectors
351: . j - column number to be scaled
352: - alpha - scaling factor
354: Level: intermediate
356: .seealso: BVScale(), BVSetActiveColumns()
357: @*/
358: PetscErrorCode BVScaleColumn(BV bv,PetscInt j,PetscScalar alpha)359: {
367: BVCheckSizes(bv,1);
369: 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);
370: if (alpha == (PetscScalar)1.0) return(0);
372: PetscLogEventBegin(BV_Scale,bv,0,0,0);
373: if (bv->n) {
374: (*bv->ops->scale)(bv,j,alpha);
375: }
376: PetscLogEventEnd(BV_Scale,bv,0,0,0);
377: PetscObjectStateIncrease((PetscObject)bv);
378: return(0);
379: }
381: PETSC_STATIC_INLINE PetscErrorCode BVSetRandomColumn_Private(BV bv,PetscInt k)382: {
384: PetscInt i,low,high;
385: PetscScalar *px,t;
386: Vec x;
389: BVGetColumn(bv,k,&x);
390: if (bv->rrandom) { /* generate the same vector irrespective of number of processes */
391: VecGetOwnershipRange(x,&low,&high);
392: VecGetArray(x,&px);
393: for (i=0;i<bv->N;i++) {
394: PetscRandomGetValue(bv->rand,&t);
395: if (i>=low && i<high) px[i-low] = t;
396: }
397: VecRestoreArray(x,&px);
398: } else {
399: VecSetRandom(x,bv->rand);
400: }
401: BVRestoreColumn(bv,k,&x);
402: return(0);
403: }
405: /*@
406: BVSetRandom - Set the columns of a BV to random numbers.
408: Logically Collective on BV410: Input Parameters:
411: . bv - basis vectors
413: Note:
414: All active columns (except the leading ones) are modified.
416: Level: advanced
418: .seealso: BVSetRandomContext(), BVSetRandomColumn(), BVSetRandomCond(), BVSetActiveColumns()
419: @*/
420: PetscErrorCode BVSetRandom(BV bv)421: {
423: PetscInt k;
428: BVCheckSizes(bv,1);
430: BVGetRandomContext(bv,&bv->rand);
431: PetscLogEventBegin(BV_SetRandom,bv,0,0,0);
432: for (k=bv->l;k<bv->k;k++) {
433: BVSetRandomColumn_Private(bv,k);
434: }
435: PetscLogEventEnd(BV_SetRandom,bv,0,0,0);
436: PetscObjectStateIncrease((PetscObject)bv);
437: return(0);
438: }
440: /*@
441: BVSetRandomColumn - Set one column of a BV to random numbers.
443: Logically Collective on BV445: Input Parameters:
446: + bv - basis vectors
447: - j - column number to be set
449: Level: advanced
451: .seealso: BVSetRandomContext(), BVSetRandom(), BVSetActiveColumns()
452: @*/
453: PetscErrorCode BVSetRandomColumn(BV bv,PetscInt j)454: {
461: BVCheckSizes(bv,1);
462: 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);
464: BVGetRandomContext(bv,&bv->rand);
465: PetscLogEventBegin(BV_SetRandom,bv,0,0,0);
466: BVSetRandomColumn_Private(bv,j);
467: PetscLogEventEnd(BV_SetRandom,bv,0,0,0);
468: PetscObjectStateIncrease((PetscObject)bv);
469: return(0);
470: }
472: /*@
473: BVSetRandomCond - Set the columns of a BV to random numbers, in a way that
474: the generated matrix has a given condition number.
476: Logically Collective on BV478: Input Parameters:
479: + bv - basis vectors
480: - condn - condition number
482: Note:
483: All active columns (except the leading ones) are modified.
485: Level: advanced
487: .seealso: BVSetRandomContext(), BVSetRandomColumn(), BVSetActiveColumns()
488: @*/
489: PetscErrorCode BVSetRandomCond(BV bv,PetscReal condn)490: {
492: PetscInt k,i;
493: PetscScalar *eig,*d;
494: DS ds;
495: Mat A,X,Y,Xt,M;
500: BVCheckSizes(bv,1);
502: BVGetRandomContext(bv,&bv->rand);
503: PetscLogEventBegin(BV_SetRandom,bv,0,0,0);
504: /* B = rand(n,k) */
505: for (k=bv->l;k<bv->k;k++) {
506: BVSetRandomColumn_Private(bv,k);
507: }
508: DSCreate(PetscObjectComm((PetscObject)bv),&ds);
509: DSSetType(ds,DSHEP);
510: DSAllocate(ds,bv->m);
511: DSSetDimensions(ds,bv->k,0,bv->l,bv->k);
512: /* [V,S] = eig(B'*B) */
513: DSGetMat(ds,DS_MAT_A,&A);
514: BVDot(bv,bv,A);
515: DSRestoreMat(ds,DS_MAT_A,&A);
516: PetscMalloc1(bv->m,&eig);
517: DSSolve(ds,eig,NULL);
518: DSSynchronize(ds,eig,NULL);
519: DSVectors(ds,DS_MAT_X,NULL,NULL);
520: /* M = diag(linspace(1/condn,1,n)./sqrt(diag(S)))' */
521: MatCreateSeqDense(PETSC_COMM_SELF,bv->k,bv->k,NULL,&M);
522: MatZeroEntries(M);
523: MatDenseGetArray(M,&d);
524: for (i=0;i<bv->k;i++) d[i+i*bv->m] = (1.0/condn+(1.0-1.0/condn)/(bv->k-1)*i)/PetscSqrtScalar(eig[i]);
525: MatDenseRestoreArray(M,&d);
526: /* M = X*M*X' */
527: MatCreateSeqDense(PETSC_COMM_SELF,bv->k,bv->k,NULL,&Y);
528: MatCreateSeqDense(PETSC_COMM_SELF,bv->k,bv->k,NULL,&Xt);
529: DSGetMat(ds,DS_MAT_X,&X);
530: MatMatMult(X,M,MAT_REUSE_MATRIX,PETSC_DEFAULT,&Y);
531: MatTranspose(X,MAT_REUSE_MATRIX,&Xt);
532: MatMatMult(Y,Xt,MAT_REUSE_MATRIX,PETSC_DEFAULT,&M);
533: MatDestroy(&X);
534: /* B = B*M */
535: BVMultInPlace(bv,M,bv->l,bv->k);
536: MatDestroy(&Y);
537: MatDestroy(&Xt);
538: MatDestroy(&M);
539: PetscFree(eig);
540: DSDestroy(&ds);
541: PetscLogEventEnd(BV_SetRandom,bv,0,0,0);
542: PetscObjectStateIncrease((PetscObject)bv);
543: return(0);
544: }
546: /*@
547: BVMatMult - Computes the matrix-vector product for each column, Y=A*V.
549: Neighbor-wise Collective on Mat and BV551: Input Parameters:
552: + V - basis vectors context
553: - A - the matrix
555: Output Parameter:
556: . Y - the result
558: Note:
559: Both V and Y must be distributed in the same manner. Only active columns
560: (excluding the leading ones) are processed.
561: In the result Y, columns are overwritten starting from the leading ones.
562: The number of active columns in V and Y should match, although they need
563: not be the same columns.
565: It is possible to choose whether the computation is done column by column
566: or as a Mat-Mat product, see BVSetMatMultMethod().
568: Level: beginner
570: .seealso: BVCopy(), BVSetActiveColumns(), BVMatMultColumn(), BVMatMultHermitianTranspose(), BVSetMatMultMethod()
571: @*/
572: PetscErrorCode BVMatMult(BV V,Mat A,BV Y)573: {
579: BVCheckSizes(V,1);
584: BVCheckSizes(Y,3);
587: if (V->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension V %D, Y %D",V->n,Y->n);
588: if (V->k-V->l!=Y->k-Y->l) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Y has %D active columns, should match %D active columns in V",Y->k-Y->l,V->k-V->l);
590: PetscLogEventBegin(BV_MatMult,V,A,Y,0);
591: (*V->ops->matmult)(V,A,Y);
592: PetscLogEventEnd(BV_MatMult,V,A,Y,0);
593: PetscObjectStateIncrease((PetscObject)Y);
594: return(0);
595: }
597: /*@
598: BVMatMultHermitianTranspose - Computes the matrix-vector product with the
599: conjugate transpose of a matrix for each column, Y=A^H*V.
601: Neighbor-wise Collective on Mat and BV603: Input Parameters:
604: + V - basis vectors context
605: - A - the matrix
607: Output Parameter:
608: . Y - the result
610: Note:
611: Both V and Y must be distributed in the same manner. Only active columns
612: (excluding the leading ones) are processed.
613: In the result Y, columns are overwritten starting from the leading ones.
615: As opposed to BVMatMult(), this operation is always done column by column,
616: with a sequence of calls to MatMultHermitianTranspose().
618: Level: beginner
620: .seealso: BVCopy(), BVSetActiveColumns(), BVMatMult(), BVMatMultColumn()
621: @*/
622: PetscErrorCode BVMatMultHermitianTranspose(BV V,Mat A,BV Y)623: {
625: PetscInt j;
626: Vec z,f;
631: BVCheckSizes(V,1);
636: BVCheckSizes(Y,3);
639: if (V->n!=Y->n) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_INCOMP,"Mismatching local dimension V %D, Y %D",V->n,Y->n);
640: if (V->k-V->l>Y->m-Y->l) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Y has %D non-leading columns, not enough to store %D columns",Y->m-Y->l,V->k-V->l);
642: PetscLogEventBegin(BV_MatMult,V,A,Y,0);
643: for (j=0;j<V->k-V->l;j++) {
644: BVGetColumn(V,V->l+j,&z);
645: BVGetColumn(Y,Y->l+j,&f);
646: MatMultHermitianTranspose(A,z,f);
647: BVRestoreColumn(V,V->l+j,&z);
648: BVRestoreColumn(Y,Y->l+j,&f);
649: }
650: PetscLogEventEnd(BV_MatMult,V,A,Y,0);
651: PetscObjectStateIncrease((PetscObject)Y);
652: return(0);
653: }
655: /*@
656: BVMatMultColumn - Computes the matrix-vector product for a specified
657: column, storing the result in the next column: v_{j+1}=A*v_j.
659: Neighbor-wise Collective on Mat and BV661: Input Parameters:
662: + V - basis vectors context
663: . A - the matrix
664: - j - the column
666: Output Parameter:
667: . Y - the result
669: Level: beginner
671: .seealso: BVMatMult()
672: @*/
673: PetscErrorCode BVMatMultColumn(BV V,Mat A,PetscInt j)674: {
676: Vec vj,vj1;
681: BVCheckSizes(V,1);
684: if (j<0) SETERRQ(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
685: if (j+1>=V->m) SETERRQ2(PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_OUTOFRANGE,"Result should go in index j+1=%D but BV only has %D columns",j+1,V->m);
687: PetscLogEventBegin(BV_MatMultVec,V,A,0,0);
688: BVGetColumn(V,j,&vj);
689: BVGetColumn(V,j+1,&vj1);
690: MatMult(A,vj,vj1);
691: BVRestoreColumn(V,j,&vj);
692: BVRestoreColumn(V,j+1,&vj1);
693: PetscLogEventEnd(BV_MatMultVec,V,A,0,0);
694: PetscObjectStateIncrease((PetscObject)V);
695: return(0);
696: }