Actual source code: contig.c
slepc-3.22.2 2024-12-02
1: /*
2: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3: SLEPc - Scalable Library for Eigenvalue Problem Computations
4: Copyright (c) 2002-, 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 implemented as an array of Vecs sharing a contiguous array for elements
12: */
14: #include <slepc/private/bvimpl.h>
16: typedef struct {
17: Vec *V;
18: PetscScalar *array;
19: PetscBool mpi;
20: } BV_CONTIGUOUS;
22: static PetscErrorCode BVMult_Contiguous(BV Y,PetscScalar alpha,PetscScalar beta,BV X,Mat Q)
23: {
24: BV_CONTIGUOUS *y = (BV_CONTIGUOUS*)Y->data,*x = (BV_CONTIGUOUS*)X->data;
25: const PetscScalar *q;
26: PetscInt ldq;
28: PetscFunctionBegin;
29: if (Q) {
30: PetscCall(MatDenseGetLDA(Q,&ldq));
31: PetscCall(MatDenseGetArrayRead(Q,&q));
32: PetscCall(BVMult_BLAS_Private(Y,Y->n,Y->k-Y->l,X->k-X->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,q+Y->l*ldq+X->l,ldq,beta,y->array+(Y->nc+Y->l)*Y->ld,Y->ld));
33: PetscCall(MatDenseRestoreArrayRead(Q,&q));
34: } else PetscCall(BVAXPY_BLAS_Private(Y,Y->n,Y->k-Y->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,beta,y->array+(Y->nc+Y->l)*Y->ld,Y->ld));
35: PetscFunctionReturn(PETSC_SUCCESS);
36: }
38: static PetscErrorCode BVMultVec_Contiguous(BV X,PetscScalar alpha,PetscScalar beta,Vec y,PetscScalar *q)
39: {
40: BV_CONTIGUOUS *x = (BV_CONTIGUOUS*)X->data;
41: PetscScalar *py,*qq=q;
43: PetscFunctionBegin;
44: PetscCall(VecGetArray(y,&py));
45: if (!q) PetscCall(VecGetArray(X->buffer,&qq));
46: PetscCall(BVMultVec_BLAS_Private(X,X->n,X->k-X->l,alpha,x->array+(X->nc+X->l)*X->ld,X->ld,qq,beta,py));
47: if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
48: PetscCall(VecRestoreArray(y,&py));
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
52: static PetscErrorCode BVMultInPlace_Contiguous(BV V,Mat Q,PetscInt s,PetscInt e)
53: {
54: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)V->data;
55: const PetscScalar *q;
56: PetscInt ldq;
58: PetscFunctionBegin;
59: if (s>=e || !V->n) PetscFunctionReturn(PETSC_SUCCESS);
60: PetscCall(MatDenseGetLDA(Q,&ldq));
61: PetscCall(MatDenseGetArrayRead(Q,&q));
62: PetscCall(BVMultInPlace_BLAS_Private(V,V->n,V->k-V->l,s-V->l,e-V->l,ctx->array+(V->nc+V->l)*V->ld,V->ld,q+V->l*ldq+V->l,ldq,PETSC_FALSE));
63: PetscCall(MatDenseRestoreArrayRead(Q,&q));
64: PetscFunctionReturn(PETSC_SUCCESS);
65: }
67: static PetscErrorCode BVMultInPlaceHermitianTranspose_Contiguous(BV V,Mat Q,PetscInt s,PetscInt e)
68: {
69: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)V->data;
70: const PetscScalar *q;
71: PetscInt ldq;
73: PetscFunctionBegin;
74: if (s>=e || !V->n) PetscFunctionReturn(PETSC_SUCCESS);
75: PetscCall(MatDenseGetLDA(Q,&ldq));
76: PetscCall(MatDenseGetArrayRead(Q,&q));
77: PetscCall(BVMultInPlace_BLAS_Private(V,V->n,V->k-V->l,s-V->l,e-V->l,ctx->array+(V->nc+V->l)*V->ld,V->ld,q+V->l*ldq+V->l,ldq,PETSC_TRUE));
78: PetscCall(MatDenseRestoreArrayRead(Q,&q));
79: PetscFunctionReturn(PETSC_SUCCESS);
80: }
82: static PetscErrorCode BVDot_Contiguous(BV X,BV Y,Mat M)
83: {
84: BV_CONTIGUOUS *x = (BV_CONTIGUOUS*)X->data,*y = (BV_CONTIGUOUS*)Y->data;
85: PetscScalar *m;
86: PetscInt ldm;
88: PetscFunctionBegin;
89: PetscCall(MatDenseGetLDA(M,&ldm));
90: PetscCall(MatDenseGetArray(M,&m));
91: PetscCall(BVDot_BLAS_Private(X,Y->k-Y->l,X->k-X->l,X->n,y->array+(Y->nc+Y->l)*Y->ld,Y->ld,x->array+(X->nc+X->l)*X->ld,X->ld,m+X->l*ldm+Y->l,ldm,x->mpi));
92: PetscCall(MatDenseRestoreArray(M,&m));
93: PetscFunctionReturn(PETSC_SUCCESS);
94: }
96: static PetscErrorCode BVDotVec_Contiguous(BV X,Vec y,PetscScalar *q)
97: {
98: BV_CONTIGUOUS *x = (BV_CONTIGUOUS*)X->data;
99: const PetscScalar *py;
100: PetscScalar *qq=q;
101: Vec z = y;
103: PetscFunctionBegin;
104: if (PetscUnlikely(X->matrix)) {
105: PetscCall(BV_IPMatMult(X,y));
106: z = X->Bx;
107: }
108: PetscCall(VecGetArrayRead(z,&py));
109: if (!q) PetscCall(VecGetArray(X->buffer,&qq));
110: PetscCall(BVDotVec_BLAS_Private(X,X->n,X->k-X->l,x->array+(X->nc+X->l)*X->ld,X->ld,py,qq,x->mpi));
111: if (!q) PetscCall(VecRestoreArray(X->buffer,&qq));
112: PetscCall(VecRestoreArrayRead(z,&py));
113: PetscFunctionReturn(PETSC_SUCCESS);
114: }
116: static PetscErrorCode BVDotVec_Local_Contiguous(BV X,Vec y,PetscScalar *m)
117: {
118: BV_CONTIGUOUS *x = (BV_CONTIGUOUS*)X->data;
119: PetscScalar *py;
120: Vec z = y;
122: PetscFunctionBegin;
123: if (PetscUnlikely(X->matrix)) {
124: PetscCall(BV_IPMatMult(X,y));
125: z = X->Bx;
126: }
127: PetscCall(VecGetArray(z,&py));
128: PetscCall(BVDotVec_BLAS_Private(X,X->n,X->k-X->l,x->array+(X->nc+X->l)*X->ld,X->ld,py,m,PETSC_FALSE));
129: PetscCall(VecRestoreArray(z,&py));
130: PetscFunctionReturn(PETSC_SUCCESS);
131: }
133: static PetscErrorCode BVScale_Contiguous(BV bv,PetscInt j,PetscScalar alpha)
134: {
135: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
137: PetscFunctionBegin;
138: if (!bv->n) PetscFunctionReturn(PETSC_SUCCESS);
139: if (PetscUnlikely(j<0)) PetscCall(BVScale_BLAS_Private(bv,(bv->k-bv->l)*bv->ld,ctx->array+(bv->nc+bv->l)*bv->ld,alpha));
140: else PetscCall(BVScale_BLAS_Private(bv,bv->n,ctx->array+(bv->nc+j)*bv->ld,alpha));
141: PetscFunctionReturn(PETSC_SUCCESS);
142: }
144: static PetscErrorCode BVNorm_Contiguous(BV bv,PetscInt j,NormType type,PetscReal *val)
145: {
146: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
148: PetscFunctionBegin;
149: if (PetscUnlikely(j<0)) PetscCall(BVNorm_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,type,val,ctx->mpi));
150: else PetscCall(BVNorm_LAPACK_Private(bv,bv->n,1,ctx->array+(bv->nc+j)*bv->ld,bv->ld,type,val,ctx->mpi));
151: PetscFunctionReturn(PETSC_SUCCESS);
152: }
154: static PetscErrorCode BVNorm_Local_Contiguous(BV bv,PetscInt j,NormType type,PetscReal *val)
155: {
156: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
158: PetscFunctionBegin;
159: if (PetscUnlikely(j<0)) PetscCall(BVNorm_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,type,val,PETSC_FALSE));
160: else PetscCall(BVNorm_LAPACK_Private(bv,bv->n,1,ctx->array+(bv->nc+j)*bv->ld,bv->ld,type,val,PETSC_FALSE));
161: PetscFunctionReturn(PETSC_SUCCESS);
162: }
164: static PetscErrorCode BVNormalize_Contiguous(BV bv,PetscScalar *eigi)
165: {
166: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
167: PetscScalar *wi=NULL;
169: PetscFunctionBegin;
170: if (eigi) wi = eigi+bv->l;
171: PetscCall(BVNormalize_LAPACK_Private(bv,bv->n,bv->k-bv->l,ctx->array+(bv->nc+bv->l)*bv->ld,bv->ld,wi,ctx->mpi));
172: PetscFunctionReturn(PETSC_SUCCESS);
173: }
175: static PetscErrorCode BVMatMult_Contiguous(BV V,Mat A,BV W)
176: {
177: BV_CONTIGUOUS *v = (BV_CONTIGUOUS*)V->data,*w = (BV_CONTIGUOUS*)W->data;
178: PetscInt j;
179: Mat Vmat,Wmat;
181: PetscFunctionBegin;
182: if (V->vmm) {
183: PetscCall(BVGetMat(V,&Vmat));
184: PetscCall(BVGetMat(W,&Wmat));
185: PetscCall(MatProductCreateWithMat(A,Vmat,NULL,Wmat));
186: PetscCall(MatProductSetType(Wmat,MATPRODUCT_AB));
187: PetscCall(MatProductSetFromOptions(Wmat));
188: PetscCall(MatProductSymbolic(Wmat));
189: PetscCall(MatProductNumeric(Wmat));
190: PetscCall(MatProductClear(Wmat));
191: PetscCall(BVRestoreMat(V,&Vmat));
192: PetscCall(BVRestoreMat(W,&Wmat));
193: } else {
194: for (j=0;j<V->k-V->l;j++) PetscCall(MatMult(A,v->V[V->nc+V->l+j],w->V[W->nc+W->l+j]));
195: }
196: PetscFunctionReturn(PETSC_SUCCESS);
197: }
199: static PetscErrorCode BVCopy_Contiguous(BV V,BV W)
200: {
201: BV_CONTIGUOUS *v = (BV_CONTIGUOUS*)V->data,*w = (BV_CONTIGUOUS*)W->data;
202: PetscInt j;
204: PetscFunctionBegin;
205: for (j=0;j<V->k-V->l;j++) PetscCall(PetscArraycpy(w->array+(W->nc+W->l+j)*W->ld,v->array+(V->nc+V->l+j)*V->ld,V->n));
206: PetscFunctionReturn(PETSC_SUCCESS);
207: }
209: static PetscErrorCode BVCopyColumn_Contiguous(BV V,PetscInt j,PetscInt i)
210: {
211: BV_CONTIGUOUS *v = (BV_CONTIGUOUS*)V->data;
213: PetscFunctionBegin;
214: PetscCall(PetscArraycpy(v->array+(V->nc+i)*V->ld,v->array+(V->nc+j)*V->ld,V->n));
215: PetscFunctionReturn(PETSC_SUCCESS);
216: }
218: static PetscErrorCode BVResize_Contiguous(BV bv,PetscInt m,PetscBool copy)
219: {
220: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
221: PetscInt j,bs;
222: PetscScalar *newarray;
223: Vec *newV;
224: char str[50];
226: PetscFunctionBegin;
227: PetscCall(PetscLayoutGetBlockSize(bv->map,&bs));
228: PetscCall(PetscCalloc1(m*bv->ld,&newarray));
229: PetscCall(PetscMalloc1(m,&newV));
230: for (j=0;j<m;j++) {
231: if (ctx->mpi) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)bv),bs,bv->n,PETSC_DECIDE,newarray+j*bv->ld,newV+j));
232: else PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)bv),bs,bv->n,newarray+j*bv->ld,newV+j));
233: }
234: if (((PetscObject)bv)->name) {
235: for (j=0;j<m;j++) {
236: PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
237: PetscCall(PetscObjectSetName((PetscObject)newV[j],str));
238: }
239: }
240: if (copy) PetscCall(PetscArraycpy(newarray,ctx->array,PetscMin(m,bv->m)*bv->ld));
241: PetscCall(VecDestroyVecs(bv->m,&ctx->V));
242: ctx->V = newV;
243: PetscCall(PetscFree(ctx->array));
244: ctx->array = newarray;
245: PetscFunctionReturn(PETSC_SUCCESS);
246: }
248: static PetscErrorCode BVGetColumn_Contiguous(BV bv,PetscInt j,Vec *v)
249: {
250: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
251: PetscInt l;
253: PetscFunctionBegin;
254: l = BVAvailableVec;
255: bv->cv[l] = ctx->V[bv->nc+j];
256: PetscFunctionReturn(PETSC_SUCCESS);
257: }
259: static PetscErrorCode BVRestoreColumn_Contiguous(BV bv,PetscInt j,Vec *v)
260: {
261: PetscInt l;
263: PetscFunctionBegin;
264: l = (j==bv->ci[0])? 0: 1;
265: bv->cv[l] = NULL;
266: PetscFunctionReturn(PETSC_SUCCESS);
267: }
269: static PetscErrorCode BVGetArray_Contiguous(BV bv,PetscScalar **a)
270: {
271: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
273: PetscFunctionBegin;
274: *a = ctx->array;
275: PetscFunctionReturn(PETSC_SUCCESS);
276: }
278: static PetscErrorCode BVGetArrayRead_Contiguous(BV bv,const PetscScalar **a)
279: {
280: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
282: PetscFunctionBegin;
283: *a = ctx->array;
284: PetscFunctionReturn(PETSC_SUCCESS);
285: }
287: static PetscErrorCode BVDestroy_Contiguous(BV bv)
288: {
289: BV_CONTIGUOUS *ctx = (BV_CONTIGUOUS*)bv->data;
291: PetscFunctionBegin;
292: if (!bv->issplit) {
293: PetscCall(VecDestroyVecs(bv->nc+bv->m,&ctx->V));
294: PetscCall(PetscFree(ctx->array));
295: }
296: PetscCall(PetscFree(bv->data));
297: PetscFunctionReturn(PETSC_SUCCESS);
298: }
300: static PetscErrorCode BVView_Contiguous(BV bv,PetscViewer viewer)
301: {
302: PetscInt j;
303: Vec v;
304: PetscViewerFormat format;
305: PetscBool isascii,ismatlab=PETSC_FALSE;
306: const char *bvname,*name;
308: PetscFunctionBegin;
309: PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
310: if (isascii) {
311: PetscCall(PetscViewerGetFormat(viewer,&format));
312: if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscFunctionReturn(PETSC_SUCCESS);
313: if (format == PETSC_VIEWER_ASCII_MATLAB) ismatlab = PETSC_TRUE;
314: }
315: if (ismatlab) {
316: PetscCall(PetscObjectGetName((PetscObject)bv,&bvname));
317: PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[];\n",bvname));
318: }
319: for (j=0;j<bv->m;j++) {
320: PetscCall(BVGetColumn(bv,j,&v));
321: PetscCall(VecView(v,viewer));
322: if (ismatlab) {
323: PetscCall(PetscObjectGetName((PetscObject)v,&name));
324: PetscCall(PetscViewerASCIIPrintf(viewer,"%s=[%s,%s];clear %s\n",bvname,bvname,name,name));
325: }
326: PetscCall(BVRestoreColumn(bv,j,&v));
327: }
328: PetscFunctionReturn(PETSC_SUCCESS);
329: }
331: SLEPC_EXTERN PetscErrorCode BVCreate_Contiguous(BV bv)
332: {
333: BV_CONTIGUOUS *ctx;
334: PetscInt j,nloc,bs,lsplit,lda;
335: PetscBool seq,isdense;
336: PetscScalar *aa;
337: char str[50];
338: PetscScalar *array;
339: BV parent;
340: Vec *Vpar;
341: MatType mtype;
343: PetscFunctionBegin;
344: PetscCall(PetscNew(&ctx));
345: bv->data = (void*)ctx;
347: PetscCall(PetscStrcmp(bv->vtype,VECMPI,&ctx->mpi));
348: if (!ctx->mpi) {
349: PetscCall(PetscStrcmp(bv->vtype,VECSEQ,&seq));
350: PetscCheck(seq,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Cannot create a contiguous BV from a non-standard vector type: %s",bv->vtype);
351: }
353: PetscCall(PetscLayoutGetLocalSize(bv->map,&nloc));
354: PetscCall(PetscLayoutGetBlockSize(bv->map,&bs));
355: PetscCall(BV_SetDefaultLD(bv,nloc));
357: if (PetscUnlikely(bv->issplit)) {
358: PetscCheck(bv->issplit>0,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"BVCONTIGUOUS does not support BVGetSplitRows()");
359: /* split BV: share memory and Vecs of the parent BV */
360: parent = bv->splitparent;
361: lsplit = parent->lsplit;
362: Vpar = ((BV_CONTIGUOUS*)parent->data)->V;
363: ctx->V = (bv->issplit==1)? Vpar: Vpar+lsplit;
364: array = ((BV_CONTIGUOUS*)parent->data)->array;
365: ctx->array = (bv->issplit==1)? array: array+lsplit*bv->ld;
366: } else {
367: /* regular BV: allocate memory and Vecs for the BV entries */
368: PetscCall(PetscCalloc1(bv->m*bv->ld,&ctx->array));
369: PetscCall(PetscMalloc1(bv->m,&ctx->V));
370: for (j=0;j<bv->m;j++) {
371: if (ctx->mpi) PetscCall(VecCreateMPIWithArray(PetscObjectComm((PetscObject)bv),bs,nloc,PETSC_DECIDE,ctx->array+j*bv->ld,ctx->V+j));
372: else PetscCall(VecCreateSeqWithArray(PetscObjectComm((PetscObject)bv),bs,nloc,ctx->array+j*bv->ld,ctx->V+j));
373: }
374: }
375: if (((PetscObject)bv)->name) {
376: for (j=0;j<bv->m;j++) {
377: PetscCall(PetscSNPrintf(str,sizeof(str),"%s_%" PetscInt_FMT,((PetscObject)bv)->name,j));
378: PetscCall(PetscObjectSetName((PetscObject)ctx->V[j],str));
379: }
380: }
382: if (PetscUnlikely(bv->Acreate)) {
383: PetscCall(MatGetType(bv->Acreate,&mtype));
384: PetscCall(PetscStrcmpAny(mtype,&isdense,MATSEQDENSE,MATMPIDENSE,""));
385: PetscCheck(isdense,PetscObjectComm((PetscObject)bv->Acreate),PETSC_ERR_SUP,"BVCONTIGUOUS requires a dense matrix in BVCreateFromMat()");
386: PetscCall(MatDenseGetArray(bv->Acreate,&aa));
387: PetscCall(MatDenseGetLDA(bv->Acreate,&lda));
388: for (j=0;j<bv->m;j++) PetscCall(PetscArraycpy(ctx->array+j*bv->ld,aa+j*lda,bv->n));
389: PetscCall(MatDenseRestoreArray(bv->Acreate,&aa));
390: PetscCall(MatDestroy(&bv->Acreate));
391: }
393: bv->ops->mult = BVMult_Contiguous;
394: bv->ops->multvec = BVMultVec_Contiguous;
395: bv->ops->multinplace = BVMultInPlace_Contiguous;
396: bv->ops->multinplacetrans = BVMultInPlaceHermitianTranspose_Contiguous;
397: bv->ops->dot = BVDot_Contiguous;
398: bv->ops->dotvec = BVDotVec_Contiguous;
399: bv->ops->dotvec_local = BVDotVec_Local_Contiguous;
400: bv->ops->scale = BVScale_Contiguous;
401: bv->ops->norm = BVNorm_Contiguous;
402: bv->ops->norm_local = BVNorm_Local_Contiguous;
403: bv->ops->normalize = BVNormalize_Contiguous;
404: bv->ops->matmult = BVMatMult_Contiguous;
405: bv->ops->copy = BVCopy_Contiguous;
406: bv->ops->copycolumn = BVCopyColumn_Contiguous;
407: bv->ops->resize = BVResize_Contiguous;
408: bv->ops->getcolumn = BVGetColumn_Contiguous;
409: bv->ops->restorecolumn = BVRestoreColumn_Contiguous;
410: bv->ops->getarray = BVGetArray_Contiguous;
411: bv->ops->getarrayread = BVGetArrayRead_Contiguous;
412: bv->ops->getmat = BVGetMat_Default;
413: bv->ops->restoremat = BVRestoreMat_Default;
414: bv->ops->destroy = BVDestroy_Contiguous;
415: bv->ops->view = BVView_Contiguous;
416: PetscFunctionReturn(PETSC_SUCCESS);
417: }