Line data Source code
1 : /*
2 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3 : SLEPc - Scalable Library for Eigenvalue Problem Computations
4 : Copyright (c) 2002-, Universitat Politecnica de Valencia, Spain
5 :
6 : This file is part of SLEPc.
7 : SLEPc is distributed under a 2-clause BSD license (see LICENSE).
8 : - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9 : */
10 : /*
11 : BV orthogonalization routines
12 : */
13 :
14 : #include <slepc/private/bvimpl.h> /*I "slepcbv.h" I*/
15 :
16 : /*
17 : BV_NormVecOrColumn - Compute the 2-norm of the working vector, irrespective of
18 : whether it is in a column or not
19 : */
20 51493 : static inline PetscErrorCode BV_NormVecOrColumn(BV bv,PetscInt j,Vec v,PetscReal *nrm)
21 : {
22 51493 : PetscFunctionBegin;
23 51493 : if (v) PetscCall(BVNormVec(bv,v,NORM_2,nrm));
24 51448 : else PetscCall(BVNormColumn(bv,j,NORM_2,nrm));
25 51493 : PetscFunctionReturn(PETSC_SUCCESS);
26 : }
27 :
28 : /*
29 : BVDotColumnInc - Same as BVDotColumn() but also including column j, which
30 : is multiplied by itself
31 : */
32 303339 : static inline PetscErrorCode BVDotColumnInc(BV X,PetscInt j,PetscScalar *q)
33 : {
34 303339 : PetscInt ksave;
35 303339 : Vec y;
36 :
37 303339 : PetscFunctionBegin;
38 303339 : PetscCall(PetscLogEventBegin(BV_DotVec,X,0,0,0));
39 303339 : ksave = X->k;
40 303339 : X->k = j+1;
41 303339 : PetscCall(BVGetColumn(X,j,&y));
42 303339 : PetscUseTypeMethod(X,dotvec,y,q);
43 303339 : PetscCall(BVRestoreColumn(X,j,&y));
44 303339 : X->k = ksave;
45 303339 : PetscCall(PetscLogEventEnd(BV_DotVec,X,0,0,0));
46 303339 : PetscFunctionReturn(PETSC_SUCCESS);
47 : }
48 :
49 : /*
50 : BVOrthogonalizeMGS1 - Compute one step of Modified Gram-Schmidt
51 : */
52 19514 : static PetscErrorCode BVOrthogonalizeMGS1(BV bv,PetscInt j,Vec v,PetscBool *which,PetscScalar *h,PetscScalar *c,PetscReal *onrm,PetscReal *nrm)
53 : {
54 19514 : PetscInt i;
55 19514 : PetscScalar dot;
56 19514 : PetscBool indef=bv->indef;
57 19514 : Vec vi,z,w=v;
58 19514 : const PetscScalar *omega;
59 :
60 19514 : PetscFunctionBegin;
61 19514 : if (!v) PetscCall(BVGetColumn(bv,j,&w));
62 19514 : if (onrm) PetscCall(BVNormVec(bv,w,NORM_2,onrm));
63 19514 : z = w;
64 19514 : if (indef) PetscCall(VecGetArrayRead(bv->omega,&omega));
65 210162 : for (i=-bv->nc;i<j;i++) {
66 190648 : if (which && i>=0 && !which[i]) continue;
67 85593 : PetscCall(BVGetColumn(bv,i,&vi));
68 : /* h_i = (v, v_i) */
69 85593 : if (bv->matrix) {
70 160 : PetscCall(BV_IPMatMult(bv,w));
71 160 : z = bv->Bx;
72 : }
73 85593 : PetscCall(VecDot(z,vi,&dot));
74 : /* v <- v - h_i v_i */
75 85593 : PetscCall(BV_SetValue(bv,i,0,c,dot));
76 85593 : if (indef) dot /= PetscRealPart(omega[bv->nc+i]);
77 85593 : PetscCall(VecAXPY(w,-dot,vi));
78 190648 : PetscCall(BVRestoreColumn(bv,i,&vi));
79 : }
80 19514 : if (nrm) PetscCall(BVNormVec(bv,w,NORM_2,nrm));
81 19514 : if (!v) PetscCall(BVRestoreColumn(bv,j,&w));
82 19514 : PetscCall(BV_AddCoefficients(bv,j,h,c));
83 19514 : if (indef) PetscCall(VecRestoreArrayRead(bv->omega,&omega));
84 19514 : PetscFunctionReturn(PETSC_SUCCESS);
85 : }
86 :
87 : /*
88 : BVOrthogonalizeCGS1 - Compute |v'| (estimated), |v| and one step of CGS with
89 : only one global synchronization
90 : */
91 393688 : static PetscErrorCode BVOrthogonalizeCGS1(BV bv,PetscInt j,Vec v,PetscBool *which,PetscScalar *h,PetscScalar *c,PetscReal *onorm,PetscReal *norm)
92 : {
93 393688 : PetscReal sum,beta;
94 :
95 393688 : PetscFunctionBegin;
96 : /* h = W^* v ; alpha = (v, v) */
97 393688 : bv->k = j;
98 393688 : if (onorm || norm) {
99 353091 : if (!v) {
100 303339 : PetscCall(BVDotColumnInc(bv,j,c));
101 303339 : PetscCall(BV_SquareRoot(bv,j,c,&beta));
102 : } else {
103 49752 : PetscCall(BVDotVec(bv,v,c));
104 49752 : PetscCall(BVNormVec(bv,v,NORM_2,&beta));
105 : }
106 : } else {
107 40597 : if (!v) PetscCall(BVDotColumn(bv,j,c));
108 0 : else PetscCall(BVDotVec(bv,v,c));
109 : }
110 :
111 : /* q = v - V h */
112 393688 : if (PetscUnlikely(bv->indef)) PetscCall(BV_ApplySignature(bv,j,c,PETSC_TRUE));
113 393688 : if (!v) PetscCall(BVMultColumn(bv,-1.0,1.0,j,c));
114 49752 : else PetscCall(BVMultVec(bv,-1.0,1.0,v,c));
115 393688 : if (PetscUnlikely(bv->indef)) PetscCall(BV_ApplySignature(bv,j,c,PETSC_FALSE));
116 :
117 : /* compute |v| */
118 393688 : if (onorm) *onorm = beta;
119 :
120 393688 : if (norm) {
121 353091 : if (PetscUnlikely(bv->indef)) PetscCall(BV_NormVecOrColumn(bv,j,v,norm));
122 : else {
123 : /* estimate |v'| from |v| */
124 305483 : PetscCall(BV_SquareSum(bv,j,c,&sum));
125 305483 : *norm = beta*beta-sum;
126 305483 : if (PetscUnlikely(*norm <= 0.0)) PetscCall(BV_NormVecOrColumn(bv,j,v,norm));
127 301632 : else *norm = PetscSqrtReal(*norm);
128 : }
129 : }
130 393688 : PetscCall(BV_AddCoefficients(bv,j,h,c));
131 393688 : PetscFunctionReturn(PETSC_SUCCESS);
132 : }
133 :
134 : #define BVOrthogonalizeGS1(a,b,c,d,e,f,g,h) (bv->ops->gramschmidt?(*bv->ops->gramschmidt):(mgs?BVOrthogonalizeMGS1:BVOrthogonalizeCGS1))(a,b,c,d,e,f,g,h)
135 :
136 : /*
137 : BVOrthogonalizeGS - Orthogonalize with (classical or modified) Gram-Schmidt
138 :
139 : j - the index of the column to orthogonalize (cannot use both j and v)
140 : v - the vector to orthogonalize (cannot use both j and v)
141 : which - logical array indicating selected columns (only used in MGS)
142 : norm - (optional) norm of the vector after being orthogonalized
143 : lindep - (optional) flag indicating possible linear dependence
144 : */
145 277039 : static PetscErrorCode BVOrthogonalizeGS(BV bv,PetscInt j,Vec v,PetscBool *which,PetscReal *norm,PetscBool *lindep)
146 : {
147 277039 : PetscScalar *h,*c,*omega;
148 277039 : PetscReal onrm,nrm;
149 277039 : PetscInt k,l;
150 277039 : PetscBool mgs,dolindep,signature;
151 :
152 277039 : PetscFunctionBegin;
153 277039 : if (v) {
154 46058 : k = bv->k;
155 46058 : h = bv->h;
156 46058 : c = bv->c;
157 : } else {
158 : k = j;
159 : h = NULL;
160 : c = NULL;
161 : }
162 :
163 277039 : mgs = (bv->orthog_type==BV_ORTHOG_MGS)? PETSC_TRUE: PETSC_FALSE;
164 :
165 : /* if indefinite inner product, skip the computation of lindep */
166 277039 : if (bv->indef && lindep) *lindep = PETSC_FALSE;
167 277039 : dolindep = (!bv->indef && lindep)? PETSC_TRUE: PETSC_FALSE;
168 :
169 : /* if indefinite and we are orthogonalizing a column, the norm must always be computed */
170 277039 : signature = (bv->indef && !v)? PETSC_TRUE: PETSC_FALSE;
171 :
172 277039 : PetscCall(BV_CleanCoefficients(bv,k,h));
173 :
174 277039 : switch (bv->orthog_ref) {
175 :
176 231917 : case BV_ORTHOG_REFINE_IFNEEDED:
177 444063 : PetscCall(BVOrthogonalizeGS1(bv,k,v,which,h,c,&onrm,&nrm));
178 : /* repeat if ||q|| < eta ||h|| */
179 : l = 1;
180 347151 : while (l<3 && nrm && PetscAbsReal(nrm) < bv->orthog_eta*PetscAbsReal(onrm)) {
181 117957 : l++;
182 117957 : if (mgs||bv->indef) onrm = nrm;
183 461406 : PetscCall(BVOrthogonalizeGS1(bv,k,v,which,h,c,(mgs||bv->indef)?NULL:&onrm,&nrm));
184 : }
185 : /* linear dependence check: criterion not satisfied in the last iteration */
186 381286 : if (dolindep) *lindep = PetscNot(nrm && PetscAbsReal(nrm) >= bv->orthog_eta*PetscAbsReal(onrm));
187 : break;
188 :
189 78 : case BV_ORTHOG_REFINE_NEVER:
190 124 : PetscCall(BVOrthogonalizeGS1(bv,k,v,which,h,c,NULL,NULL));
191 : /* compute ||v|| */
192 78 : if (norm || dolindep || signature) PetscCall(BV_NormVecOrColumn(bv,k,v,&nrm));
193 : /* linear dependence check: just test for exactly zero norm */
194 78 : if (dolindep) *lindep = PetscNot(nrm);
195 : break;
196 :
197 45044 : case BV_ORTHOG_REFINE_ALWAYS:
198 85595 : PetscCall(BVOrthogonalizeGS1(bv,k,v,which,h,c,NULL,NULL));
199 130312 : PetscCall(BVOrthogonalizeGS1(bv,k,v,which,h,c,dolindep?&onrm:NULL,(norm||dolindep||signature)?&nrm:NULL));
200 : /* linear dependence check: criterion not satisfied in the second iteration */
201 45375 : if (dolindep) *lindep = PetscNot(nrm && PetscAbsReal(nrm) >= bv->orthog_eta*PetscAbsReal(onrm));
202 : break;
203 : }
204 277039 : if (signature) {
205 49959 : PetscCall(VecGetArray(bv->omega,&omega));
206 49959 : omega[bv->nc+k] = (nrm<0.0)? -1.0: 1.0;
207 49959 : PetscCall(VecRestoreArray(bv->omega,&omega));
208 : }
209 277039 : if (norm) {
210 262862 : *norm = nrm;
211 262862 : if (!v) { /* store norm value next to the orthogonalization coefficients */
212 230925 : if (dolindep && *lindep) PetscCall(BV_SetValue(bv,k,k,h,0.0));
213 230339 : else PetscCall(BV_SetValue(bv,k,k,h,nrm));
214 : }
215 : }
216 277039 : PetscFunctionReturn(PETSC_SUCCESS);
217 : }
218 :
219 : /*@
220 : BVOrthogonalizeVec - Orthogonalize a given vector with respect to all
221 : active columns.
222 :
223 : Collective
224 :
225 : Input Parameters:
226 : + bv - the basis vectors context
227 : - v - the vector
228 :
229 : Output Parameters:
230 : + H - (optional) coefficients computed during orthogonalization
231 : . norm - (optional) norm of the vector after being orthogonalized
232 : - lindep - (optional) flag indicating that refinement did not improve the quality
233 : of orthogonalization
234 :
235 : Notes:
236 : This function is equivalent to BVOrthogonalizeColumn() but orthogonalizes
237 : a vector as an argument rather than taking one of the BV columns. The
238 : vector is orthogonalized against all active columns (k) and the constraints.
239 : If H is given, it must have enough space to store k-l coefficients, where l
240 : is the number of leading columns.
241 :
242 : In the case of an indefinite inner product, the lindep parameter is not
243 : computed (set to false).
244 :
245 : Level: advanced
246 :
247 : .seealso: BVOrthogonalizeColumn(), BVSetOrthogonalization(), BVSetActiveColumns(), BVGetNumConstraints()
248 : @*/
249 46058 : PetscErrorCode BVOrthogonalizeVec(BV bv,Vec v,PetscScalar *H,PetscReal *norm,PetscBool *lindep)
250 : {
251 46058 : PetscInt ksave,lsave;
252 :
253 46058 : PetscFunctionBegin;
254 46058 : PetscValidHeaderSpecific(bv,BV_CLASSID,1);
255 46058 : PetscValidHeaderSpecific(v,VEC_CLASSID,2);
256 46058 : PetscValidType(bv,1);
257 46058 : BVCheckSizes(bv,1);
258 46058 : PetscValidType(v,2);
259 46058 : PetscCheckSameComm(bv,1,v,2);
260 :
261 46058 : PetscCall(PetscLogEventBegin(BV_OrthogonalizeVec,bv,0,0,0));
262 46058 : ksave = bv->k;
263 46058 : lsave = bv->l;
264 46058 : bv->l = -bv->nc; /* must also orthogonalize against constraints and leading columns */
265 46058 : PetscCall(BV_AllocateCoeffs(bv));
266 46058 : PetscCall(BV_AllocateSignature(bv));
267 46058 : PetscCall(BVOrthogonalizeGS(bv,0,v,NULL,norm,lindep));
268 46058 : bv->k = ksave;
269 46058 : bv->l = lsave;
270 46058 : if (H) PetscCall(BV_StoreCoefficients(bv,bv->k,bv->h,H));
271 46058 : PetscCall(PetscLogEventEnd(BV_OrthogonalizeVec,bv,0,0,0));
272 46058 : PetscFunctionReturn(PETSC_SUCCESS);
273 : }
274 :
275 : /*@
276 : BVOrthogonalizeColumn - Orthogonalize one of the column vectors with respect to
277 : the previous ones.
278 :
279 : Collective
280 :
281 : Input Parameters:
282 : + bv - the basis vectors context
283 : - j - index of column to be orthogonalized
284 :
285 : Output Parameters:
286 : + H - (optional) coefficients computed during orthogonalization
287 : . norm - (optional) norm of the vector after being orthogonalized
288 : - lindep - (optional) flag indicating that refinement did not improve the quality
289 : of orthogonalization
290 :
291 : Notes:
292 : This function applies an orthogonal projector to project vector V[j] onto
293 : the orthogonal complement of the span of the columns V[0..j-1],
294 : where V[.] are the vectors of BV. The columns V[0..j-1] are assumed to be
295 : mutually orthonormal.
296 :
297 : Leading columns V[0..l-1] also participate in the orthogonalization, as well
298 : as the constraints. If H is given, it must have enough space to store
299 : j-l+1 coefficients (the last coefficient will contain the value norm, unless
300 : the norm argument is NULL).
301 :
302 : If a non-standard inner product has been specified with BVSetMatrix(),
303 : then the vector is B-orthogonalized, using the non-standard inner product
304 : defined by matrix B. The output vector satisfies V[j]'*B*V[0..j-1] = 0.
305 :
306 : This routine does not normalize the resulting vector, see BVOrthonormalizeColumn().
307 :
308 : In the case of an indefinite inner product, the lindep parameter is not
309 : computed (set to false).
310 :
311 : Level: advanced
312 :
313 : .seealso: BVSetOrthogonalization(), BVSetMatrix(), BVSetActiveColumns(), BVOrthogonalize(), BVOrthogonalizeVec(), BVGetNumConstraints(), BVOrthonormalizeColumn()
314 : @*/
315 105998 : PetscErrorCode BVOrthogonalizeColumn(BV bv,PetscInt j,PetscScalar *H,PetscReal *norm,PetscBool *lindep)
316 : {
317 105998 : PetscInt ksave,lsave;
318 :
319 105998 : PetscFunctionBegin;
320 105998 : PetscValidHeaderSpecific(bv,BV_CLASSID,1);
321 317994 : PetscValidLogicalCollectiveInt(bv,j,2);
322 105998 : PetscValidType(bv,1);
323 105998 : BVCheckSizes(bv,1);
324 105998 : PetscCheck(j>=0,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
325 105998 : PetscCheck(j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,bv->m);
326 :
327 105998 : PetscCall(PetscLogEventBegin(BV_OrthogonalizeVec,bv,0,0,0));
328 105998 : ksave = bv->k;
329 105998 : lsave = bv->l;
330 105998 : bv->l = -bv->nc; /* must also orthogonalize against constraints and leading columns */
331 105998 : if (!bv->buffer) PetscCall(BVGetBufferVec(bv,&bv->buffer));
332 105998 : PetscCall(BV_AllocateSignature(bv));
333 105998 : PetscCall(BVOrthogonalizeGS(bv,j,NULL,NULL,norm,lindep));
334 105998 : bv->k = ksave;
335 105998 : bv->l = lsave;
336 105998 : if (H) PetscCall(BV_StoreCoefficients(bv,j,NULL,H));
337 105998 : PetscCall(PetscLogEventEnd(BV_OrthogonalizeVec,bv,0,0,0));
338 105998 : PetscCall(PetscObjectStateIncrease((PetscObject)bv));
339 105998 : PetscFunctionReturn(PETSC_SUCCESS);
340 : }
341 :
342 : /*@
343 : BVOrthonormalizeColumn - Orthonormalize one of the column vectors with respect to
344 : the previous ones.
345 :
346 : Collective
347 :
348 : Input Parameters:
349 : + bv - the basis vectors context
350 : . j - index of column to be orthonormalized
351 : - replace - whether it is allowed to set the vector randomly
352 :
353 : Output Parameters:
354 : + norm - (optional) norm of the vector after orthogonalization and before normalization
355 : - lindep - (optional) flag indicating that linear dependence was determined during
356 : orthogonalization
357 :
358 : Notes:
359 : This is equivalent to a call to BVOrthogonalizeColumn() followed by a
360 : call to BVScaleColumn() with the reciprocal of the norm.
361 :
362 : This function first orthogonalizes vector V[j] with respect to V[0..j-1],
363 : where V[.] are the vectors of BV. A byproduct of this computation is norm,
364 : the norm of the vector after orthogonalization. Secondly, it scales the
365 : vector with 1/norm, so that the resulting vector has unit norm.
366 :
367 : If after orthogonalization the vector V[j] is exactly zero, it cannot be normalized
368 : because norm=0. In that case, it could be left as zero or replaced by a random
369 : vector that is then orthonormalized. The latter is achieved by setting the
370 : argument replace to TRUE. The vector will be replaced by a random vector also
371 : if lindep was set to TRUE, even if the norm is not exactly zero.
372 :
373 : If the vector has been replaced by a random vector, the output arguments norm and
374 : lindep will be set according to the orthogonalization of this new vector.
375 :
376 : Level: advanced
377 :
378 : .seealso: BVOrthogonalizeColumn(), BVScaleColumn()
379 : @*/
380 116232 : PetscErrorCode BVOrthonormalizeColumn(BV bv,PetscInt j,PetscBool replace,PetscReal *norm,PetscBool *lindep)
381 : {
382 116232 : PetscScalar alpha;
383 116232 : PetscReal nrm;
384 116232 : PetscInt ksave,lsave;
385 116232 : PetscBool lndep;
386 :
387 116232 : PetscFunctionBegin;
388 116232 : PetscValidHeaderSpecific(bv,BV_CLASSID,1);
389 348696 : PetscValidLogicalCollectiveInt(bv,j,2);
390 116232 : PetscValidType(bv,1);
391 116232 : BVCheckSizes(bv,1);
392 116232 : PetscCheck(j>=0,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
393 116232 : PetscCheck(j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,bv->m);
394 :
395 : /* orthogonalize */
396 116232 : PetscCall(PetscLogEventBegin(BV_OrthogonalizeVec,bv,0,0,0));
397 116232 : ksave = bv->k;
398 116232 : lsave = bv->l;
399 116232 : bv->l = -bv->nc; /* must also orthogonalize against constraints and leading columns */
400 116232 : if (!bv->buffer) PetscCall(BVGetBufferVec(bv,&bv->buffer));
401 116232 : PetscCall(BV_AllocateSignature(bv));
402 116232 : PetscCall(BVOrthogonalizeGS(bv,j,NULL,NULL,&nrm,&lndep));
403 116232 : if (replace && (nrm==0.0 || lndep)) {
404 1 : PetscCall(PetscInfo(bv,"Vector was linearly dependent, generating a new random vector\n"));
405 1 : PetscCall(BVSetRandomColumn(bv,j));
406 1 : PetscCall(BVOrthogonalizeGS(bv,j,NULL,NULL,&nrm,&lndep));
407 1 : if (nrm==0.0 || lndep) { /* yet another attempt */
408 0 : PetscCall(BVSetRandomColumn(bv,j));
409 0 : PetscCall(BVOrthogonalizeGS(bv,j,NULL,NULL,&nrm,&lndep));
410 : }
411 : }
412 116232 : bv->k = ksave;
413 116232 : bv->l = lsave;
414 116232 : PetscCall(PetscLogEventEnd(BV_OrthogonalizeVec,bv,0,0,0));
415 :
416 : /* scale */
417 116232 : if (nrm!=1.0 && nrm!=0.0) {
418 115537 : alpha = 1.0/nrm;
419 115537 : PetscCall(PetscLogEventBegin(BV_Scale,bv,0,0,0));
420 115537 : PetscUseTypeMethod(bv,scale,j,alpha);
421 115537 : PetscCall(PetscLogEventEnd(BV_Scale,bv,0,0,0));
422 : }
423 116232 : if (norm) *norm = nrm;
424 116232 : if (lindep) *lindep = lndep;
425 116232 : PetscCall(PetscObjectStateIncrease((PetscObject)bv));
426 116232 : PetscFunctionReturn(PETSC_SUCCESS);
427 : }
428 :
429 : /*@
430 : BVOrthogonalizeSomeColumn - Orthogonalize one of the column vectors with
431 : respect to some of the previous ones.
432 :
433 : Collective
434 :
435 : Input Parameters:
436 : + bv - the basis vectors context
437 : . j - index of column to be orthogonalized
438 : - which - logical array indicating selected columns
439 :
440 : Output Parameters:
441 : + H - (optional) coefficients computed during orthogonalization
442 : . norm - (optional) norm of the vector after being orthogonalized
443 : - lindep - (optional) flag indicating that refinement did not improve the quality
444 : of orthogonalization
445 :
446 : Notes:
447 : This function is similar to BVOrthogonalizeColumn(), but V[j] is
448 : orthogonalized only against columns V[i] having which[i]=PETSC_TRUE.
449 : The length of array which must be j at least.
450 :
451 : The use of this operation is restricted to MGS orthogonalization type.
452 :
453 : In the case of an indefinite inner product, the lindep parameter is not
454 : computed (set to false).
455 :
456 : Level: advanced
457 :
458 : .seealso: BVOrthogonalizeColumn(), BVSetOrthogonalization()
459 : @*/
460 8750 : PetscErrorCode BVOrthogonalizeSomeColumn(BV bv,PetscInt j,PetscBool *which,PetscScalar *H,PetscReal *norm,PetscBool *lindep)
461 : {
462 8750 : PetscInt ksave,lsave;
463 :
464 8750 : PetscFunctionBegin;
465 8750 : PetscValidHeaderSpecific(bv,BV_CLASSID,1);
466 26250 : PetscValidLogicalCollectiveInt(bv,j,2);
467 8750 : PetscAssertPointer(which,3);
468 8750 : PetscValidType(bv,1);
469 8750 : BVCheckSizes(bv,1);
470 8750 : PetscCheck(j>=0,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j must be non-negative");
471 8750 : PetscCheck(j<bv->m,PetscObjectComm((PetscObject)bv),PETSC_ERR_ARG_OUTOFRANGE,"Index j=%" PetscInt_FMT " but BV only has %" PetscInt_FMT " columns",j,bv->m);
472 8750 : PetscCheck(bv->orthog_type==BV_ORTHOG_MGS,PetscObjectComm((PetscObject)bv),PETSC_ERR_SUP,"Operation only available for MGS orthogonalization");
473 :
474 8750 : PetscCall(PetscLogEventBegin(BV_OrthogonalizeVec,bv,0,0,0));
475 8750 : ksave = bv->k;
476 8750 : lsave = bv->l;
477 8750 : bv->l = -bv->nc; /* must also orthogonalize against constraints and leading columns */
478 8750 : if (!bv->buffer) PetscCall(BVGetBufferVec(bv,&bv->buffer));
479 8750 : PetscCall(BV_AllocateSignature(bv));
480 8750 : PetscCall(BVOrthogonalizeGS(bv,j,NULL,which,norm,lindep));
481 8750 : bv->k = ksave;
482 8750 : bv->l = lsave;
483 8750 : if (H) PetscCall(BV_StoreCoefficients(bv,j,NULL,H));
484 8750 : PetscCall(PetscLogEventEnd(BV_OrthogonalizeVec,bv,0,0,0));
485 8750 : PetscCall(PetscObjectStateIncrease((PetscObject)bv));
486 8750 : PetscFunctionReturn(PETSC_SUCCESS);
487 : }
488 :
489 : /*
490 : Block Gram-Schmidt: V2 = V2 - V1*R12, where R12 = V1'*V2
491 : */
492 124 : static PetscErrorCode BVOrthogonalize_BlockGS(BV V,Mat R)
493 : {
494 124 : BV V1;
495 :
496 124 : PetscFunctionBegin;
497 124 : PetscCall(BVGetSplit(V,&V1,NULL));
498 124 : PetscCall(BVDot(V,V1,R));
499 124 : PetscCall(BVMult(V,-1.0,1.0,V1,R));
500 124 : PetscCall(BVRestoreSplit(V,&V1,NULL));
501 124 : PetscFunctionReturn(PETSC_SUCCESS);
502 : }
503 :
504 : /*
505 : Orthogonalize a set of vectors with Gram-Schmidt, column by column.
506 : */
507 5717 : static PetscErrorCode BVOrthogonalize_GS(BV V,Mat R)
508 : {
509 5717 : PetscScalar *r=NULL;
510 5717 : PetscReal norm;
511 5717 : PetscInt j,ldr,lsave;
512 5717 : Vec v,w;
513 :
514 5717 : PetscFunctionBegin;
515 5717 : if (R) {
516 391 : PetscCall(MatDenseGetLDA(R,&ldr));
517 391 : PetscCall(MatDenseGetArray(R,&r));
518 : }
519 5717 : if (V->matrix) {
520 2115 : PetscCall(BVGetCachedBV(V,&V->cached));
521 2115 : PetscCall(BVSetActiveColumns(V->cached,V->l,V->k));
522 : }
523 39580 : for (j=V->l;j<V->k;j++) {
524 33863 : if (V->matrix && V->orthog_type==BV_ORTHOG_MGS) { /* fill cached BV */
525 0 : PetscCall(BVGetColumn(V->cached,j,&v));
526 0 : PetscCall(BVGetColumn(V,j,&w));
527 0 : PetscCall(MatMult(V->matrix,w,v));
528 0 : PetscCall(BVRestoreColumn(V,j,&w));
529 0 : PetscCall(BVRestoreColumn(V->cached,j,&v));
530 : }
531 33863 : if (R) {
532 3787 : PetscCall(BVOrthogonalizeColumn(V,j,NULL,&norm,NULL));
533 3787 : lsave = V->l;
534 3787 : V->l = -V->nc;
535 3787 : PetscCall(BV_StoreCoefficients(V,j,NULL,r+j*ldr));
536 3787 : V->l = lsave;
537 3787 : r[j+j*ldr] = norm;
538 30076 : } else PetscCall(BVOrthogonalizeColumn(V,j,NULL,&norm,NULL));
539 33863 : PetscCheck(norm,PetscObjectComm((PetscObject)V),PETSC_ERR_CONV_FAILED,"Breakdown in BVOrthogonalize due to a linearly dependent column");
540 33863 : if (V->matrix && V->orthog_type==BV_ORTHOG_CGS) { /* fill cached BV */
541 11463 : PetscCall(BVGetColumn(V->cached,j,&v));
542 11463 : PetscCall(VecCopy(V->Bx,v));
543 11463 : PetscCall(BVRestoreColumn(V->cached,j,&v));
544 : }
545 33863 : PetscCall(BVScaleColumn(V,j,1.0/norm));
546 : }
547 5717 : if (R) PetscCall(MatDenseRestoreArray(R,&r));
548 5717 : PetscFunctionReturn(PETSC_SUCCESS);
549 : }
550 :
551 : /*
552 : BV_GetBufferMat - Create auxiliary seqdense matrix that wraps the bv->buffer.
553 : */
554 468 : static inline PetscErrorCode BV_GetBufferMat(BV bv)
555 : {
556 468 : PetscInt ld;
557 468 : PetscScalar *array;
558 :
559 468 : PetscFunctionBegin;
560 468 : if (!bv->Abuffer) {
561 161 : if (!bv->buffer) PetscCall(BVGetBufferVec(bv,&bv->buffer));
562 161 : ld = bv->m+bv->nc;
563 161 : PetscCall(VecGetArray(bv->buffer,&array));
564 161 : PetscCall(MatCreateSeqDense(PETSC_COMM_SELF,ld,bv->m,array,&bv->Abuffer));
565 161 : PetscCall(VecRestoreArray(bv->buffer,&array));
566 : }
567 468 : PetscFunctionReturn(PETSC_SUCCESS);
568 : }
569 :
570 : /*
571 : BV_StoreCoeffsBlock_Default - Copy the contents of the BV buffer to a dense Mat
572 : provided by the caller. Only columns l:k-1 are copied, restricting to the upper
573 : triangular part if tri=PETSC_TRUE.
574 : */
575 151 : static inline PetscErrorCode BV_StoreCoeffsBlock_Default(BV bv,Mat R,PetscBool tri)
576 : {
577 151 : const PetscScalar *bb;
578 151 : PetscScalar *rr;
579 151 : PetscInt j,ldr,ldb;
580 :
581 151 : PetscFunctionBegin;
582 151 : PetscCall(MatDenseGetLDA(R,&ldr));
583 151 : PetscCall(MatDenseGetArray(R,&rr));
584 151 : ldb = bv->m+bv->nc;
585 151 : PetscCall(VecGetArrayRead(bv->buffer,&bb));
586 1391 : for (j=bv->l;j<bv->k;j++) PetscCall(PetscArraycpy(rr+j*ldr,bb+j*ldb,(tri?(j+1):bv->k)+bv->nc));
587 151 : PetscCall(VecRestoreArrayRead(bv->buffer,&bb));
588 151 : PetscCall(MatDenseRestoreArray(R,&rr));
589 151 : PetscFunctionReturn(PETSC_SUCCESS);
590 : }
591 :
592 : /*
593 : Orthogonalize a set of vectors with Cholesky: R=chol(V'*V), Q=V*inv(R)
594 : */
595 105 : static PetscErrorCode BVOrthogonalize_Chol(BV V,Mat Rin)
596 : {
597 105 : Mat R,S;
598 :
599 105 : PetscFunctionBegin;
600 105 : PetscCall(BV_GetBufferMat(V));
601 105 : R = V->Abuffer;
602 105 : if (Rin) S = Rin; /* use Rin as a workspace for S */
603 73 : else S = R;
604 105 : if (V->l) PetscCall(BVOrthogonalize_BlockGS(V,R));
605 105 : PetscCall(BVDot(V,V,R));
606 105 : PetscCall(BVMatCholInv_LAPACK_Private(V,R,S));
607 105 : PetscCall(BVMultInPlace(V,S,V->l,V->k));
608 105 : if (Rin) PetscCall(BV_StoreCoeffsBlock_Default(V,Rin,PETSC_TRUE));
609 105 : PetscFunctionReturn(PETSC_SUCCESS);
610 : }
611 :
612 : /*
613 : Orthogonalize a set of vectors with the Tall-Skinny QR method
614 : */
615 185 : static PetscErrorCode BVOrthogonalize_TSQR(BV V,Mat Rin)
616 : {
617 185 : PetscScalar *pv,*r=NULL;
618 185 : PetscInt ldr;
619 185 : Mat R;
620 :
621 185 : PetscFunctionBegin;
622 185 : PetscCall(BV_GetBufferMat(V));
623 185 : R = V->Abuffer;
624 185 : if (V->l) PetscCall(BVOrthogonalize_BlockGS(V,R));
625 185 : PetscCall(MatDenseGetLDA(R,&ldr));
626 185 : PetscCall(MatDenseGetArray(R,&r));
627 185 : PetscCall(BVGetArray(V,&pv));
628 185 : PetscCall(BVOrthogonalize_LAPACK_TSQR(V,V->n,V->k-V->l,pv+(V->nc+V->l)*V->ld,V->ld,r+V->l*ldr+V->l,ldr));
629 185 : PetscCall(BVRestoreArray(V,&pv));
630 185 : PetscCall(MatDenseRestoreArray(R,&r));
631 185 : if (Rin) PetscCall(BV_StoreCoeffsBlock_Default(V,Rin,PETSC_TRUE));
632 185 : PetscFunctionReturn(PETSC_SUCCESS);
633 : }
634 :
635 : /*
636 : Orthogonalize a set of vectors with TSQR, but computing R only, then doing Q=V*inv(R)
637 : */
638 73 : static PetscErrorCode BVOrthogonalize_TSQRCHOL(BV V,Mat Rin)
639 : {
640 73 : PetscScalar *pv,*r=NULL;
641 73 : PetscInt ldr;
642 73 : Mat R,S;
643 :
644 73 : PetscFunctionBegin;
645 73 : PetscCall(BV_GetBufferMat(V));
646 73 : R = V->Abuffer;
647 73 : if (Rin) S = Rin; /* use Rin as a workspace for S */
648 57 : else S = R;
649 73 : if (V->l) PetscCall(BVOrthogonalize_BlockGS(V,R));
650 73 : PetscCall(MatDenseGetLDA(R,&ldr));
651 73 : PetscCall(MatDenseGetArray(R,&r));
652 73 : PetscCall(BVGetArray(V,&pv));
653 73 : PetscCall(BVOrthogonalize_LAPACK_TSQR_OnlyR(V,V->n,V->k-V->l,pv+(V->nc+V->l)*V->ld,V->ld,r+V->l*ldr+V->l,ldr));
654 73 : PetscCall(BVRestoreArray(V,&pv));
655 73 : PetscCall(MatDenseRestoreArray(R,&r));
656 73 : PetscCall(BVMatTriInv_LAPACK_Private(V,R,S));
657 73 : PetscCall(BVMultInPlace(V,S,V->l,V->k));
658 73 : if (Rin) PetscCall(BV_StoreCoeffsBlock_Default(V,Rin,PETSC_TRUE));
659 73 : PetscFunctionReturn(PETSC_SUCCESS);
660 : }
661 :
662 : /*
663 : Orthogonalize a set of vectors with SVQB
664 : */
665 105 : static PetscErrorCode BVOrthogonalize_SVQB(BV V,Mat Rin)
666 : {
667 105 : Mat R,S;
668 :
669 105 : PetscFunctionBegin;
670 105 : PetscCall(BV_GetBufferMat(V));
671 105 : R = V->Abuffer;
672 105 : if (Rin) S = Rin; /* use Rin as a workspace for S */
673 73 : else S = R;
674 105 : if (V->l) PetscCall(BVOrthogonalize_BlockGS(V,R));
675 105 : PetscCall(BVDot(V,V,R));
676 105 : PetscCall(BVMatSVQB_LAPACK_Private(V,R,S));
677 105 : PetscCall(BVMultInPlace(V,S,V->l,V->k));
678 105 : if (Rin) PetscCall(BV_StoreCoeffsBlock_Default(V,Rin,PETSC_FALSE));
679 105 : PetscFunctionReturn(PETSC_SUCCESS);
680 : }
681 :
682 : /*@
683 : BVOrthogonalize - Orthogonalize all columns (starting from the leading ones),
684 : that is, compute the QR decomposition.
685 :
686 : Collective
687 :
688 : Input Parameters:
689 : + V - basis vectors to be orthogonalized (or B-orthogonalized), modified on output
690 : - R - a sequential dense matrix (or NULL), on output the triangular factor of
691 : the QR decomposition
692 :
693 : Notes:
694 : On input, matrix R must be a square sequential dense Mat, with at least as many
695 : rows and columns as the number of active columns of V. The output satisfies
696 : V0 = V*R (where V0 represent the input V) and V'*V = I (or V'*B*V = I if an
697 : inner product matrix B has been specified with BVSetMatrix()).
698 :
699 : If V has leading columns, then they are not modified (are assumed to be already
700 : orthonormal) and the leading columns of R are not referenced. Let the
701 : decomposition be
702 : .vb
703 : [ V01 V02 ] = [ V1 V2 ] [ R11 R12 ]
704 : [ 0 R22 ]
705 : .ve
706 : then V1 is left unchanged (equal to V01) as well as R11 (it should satisfy
707 : V01 = V1*R11).
708 :
709 : Can pass NULL if R is not required.
710 :
711 : The method to be used for block orthogonalization can be set with
712 : BVSetOrthogonalization(). If set to GS, the computation is done column by
713 : column with successive calls to BVOrthogonalizeColumn(). Note that in the
714 : SVQB method the R factor is not upper triangular.
715 :
716 : If V is rank-deficient or very ill-conditioned, that is, one or more columns are
717 : (almost) linearly dependent with respect to the rest, then the algorithm may
718 : break down or result in larger numerical error. Linearly dependent columns are
719 : essentially replaced by random directions, and the corresponding diagonal entry
720 : in R is set to (nearly) zero.
721 :
722 : Level: intermediate
723 :
724 : .seealso: BVOrthogonalizeColumn(), BVOrthogonalizeVec(), BVSetMatrix(), BVSetActiveColumns(), BVSetOrthogonalization(), BVOrthogBlockType
725 : @*/
726 6185 : PetscErrorCode BVOrthogonalize(BV V,Mat R)
727 : {
728 6185 : PetscInt m,n;
729 :
730 6185 : PetscFunctionBegin;
731 6185 : PetscValidHeaderSpecific(V,BV_CLASSID,1);
732 6185 : PetscValidType(V,1);
733 6185 : BVCheckSizes(V,1);
734 6185 : if (R) {
735 542 : PetscValidHeaderSpecific(R,MAT_CLASSID,2);
736 542 : PetscValidType(R,2);
737 542 : PetscCheckTypeName(R,MATSEQDENSE);
738 542 : PetscCall(MatGetSize(R,&m,&n));
739 542 : PetscCheck(m==n,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat argument is not square, it has %" PetscInt_FMT " rows and %" PetscInt_FMT " columns",m,n);
740 542 : PetscCheck(n>=V->k,PetscObjectComm((PetscObject)V),PETSC_ERR_ARG_SIZ,"Mat size %" PetscInt_FMT " is smaller than the number of BV active columns %" PetscInt_FMT,n,V->k);
741 : }
742 6185 : PetscCheck(!V->nc,PetscObjectComm((PetscObject)V),PETSC_ERR_SUP,"Not implemented for BV with constraints, use BVOrthogonalizeColumn() instead");
743 :
744 6185 : PetscCall(PetscLogEventBegin(BV_Orthogonalize,V,R,0,0));
745 6185 : switch (V->orthog_block) {
746 5717 : case BV_ORTHOG_BLOCK_GS: /* proceed column by column with Gram-Schmidt */
747 5717 : PetscCall(BVOrthogonalize_GS(V,R));
748 : break;
749 105 : case BV_ORTHOG_BLOCK_CHOL:
750 105 : PetscCall(BVOrthogonalize_Chol(V,R));
751 : break;
752 185 : case BV_ORTHOG_BLOCK_TSQR:
753 185 : PetscCheck(!V->matrix,PetscObjectComm((PetscObject)V),PETSC_ERR_SUP,"Orthogonalization method not available for non-standard inner product");
754 185 : PetscCall(BVOrthogonalize_TSQR(V,R));
755 : break;
756 73 : case BV_ORTHOG_BLOCK_TSQRCHOL:
757 73 : PetscCheck(!V->matrix,PetscObjectComm((PetscObject)V),PETSC_ERR_SUP,"Orthogonalization method not available for non-standard inner product");
758 73 : PetscCall(BVOrthogonalize_TSQRCHOL(V,R));
759 : break;
760 105 : case BV_ORTHOG_BLOCK_SVQB:
761 105 : PetscCall(BVOrthogonalize_SVQB(V,R));
762 : break;
763 : }
764 6185 : PetscCall(PetscLogEventEnd(BV_Orthogonalize,V,R,0,0));
765 6185 : PetscCall(PetscObjectStateIncrease((PetscObject)V));
766 6185 : PetscFunctionReturn(PETSC_SUCCESS);
767 : }
|