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 : #include <slepc/private/dsimpl.h> /*I "slepcds.h" I*/
11 : #include <slepcblaslapack.h>
12 :
13 : typedef struct {
14 : PetscInt m; /* number of columns */
15 : PetscInt p; /* number of rows of B */
16 : PetscInt tm; /* number of rows of X after truncating */
17 : PetscInt tp; /* number of rows of V after truncating */
18 : } DS_GSVD;
19 :
20 64 : static PetscErrorCode DSAllocate_GSVD(DS ds,PetscInt ld)
21 : {
22 64 : PetscFunctionBegin;
23 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_A));
24 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_B));
25 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_X));
26 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_U));
27 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_V));
28 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_T));
29 64 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_D));
30 64 : PetscCall(PetscFree(ds->perm));
31 64 : PetscCall(PetscMalloc1(ld,&ds->perm));
32 64 : PetscFunctionReturn(PETSC_SUCCESS);
33 : }
34 :
35 : /*
36 : In compact form, A is either in form (a) or (b):
37 :
38 : (a) (b)
39 : lower bidiagonal with upper arrow (n=m+1) square upper bidiagonal with upper arrow (n=m)
40 : 0 l k m-1
41 : ----------------------------------------- 0 l k m-1
42 : |* . | -----------------------------------------
43 : | * . | |* . |
44 : | * . | | * . |
45 : | * . | | * . |
46 : l |. . . . o o | l |. . . o o |
47 : | o o | | o o |
48 : | o o | | o o |
49 : | o o | | o o |
50 : | o o | | o o |
51 : | o o | | o o |
52 : k |. . . . . . . . . . o | k |. . . . . . . . . o x |
53 : | x x | | x x |
54 : | x x | | x x |
55 : | x x | | x x |
56 : | x x | | x x |
57 : | x x | | x x |
58 : | x x | | x x |
59 : | x x | | x x |
60 : | x x | | x x |
61 : | x x| | x x|
62 : n-1 | x| n-1 | x|
63 : ----------------------------------------- -----------------------------------------
64 :
65 : and B is square bidiagonal with upper arrow (p=m)
66 :
67 : 0 l k m-1
68 : -----------------------------------------
69 : |* . |
70 : | * . |
71 : | * . |
72 : | * . |
73 : l |. . . . o o |
74 : | o o |
75 : | o o |
76 : | o o |
77 : | o o |
78 : | o o |
79 : k |. . . . . . . . . . o x |
80 : | x x |
81 : | x x |
82 : | x x |
83 : | x x |
84 : | x x |
85 : | x x |
86 : | x x |
87 : | x x|
88 : p-1 | x|
89 : ----------------------------------------
90 : */
91 30 : static PetscErrorCode DSView_GSVD(DS ds,PetscViewer viewer)
92 : {
93 30 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
94 30 : PetscViewerFormat format;
95 30 : PetscInt i,j,r,k=ds->k,n=ds->n,m=ctx->m,p=ctx->p,rowsa,rowsb,colsa,colsb;
96 30 : PetscReal *T,*S,value;
97 :
98 30 : PetscFunctionBegin;
99 30 : PetscCall(PetscViewerGetFormat(viewer,&format));
100 30 : if (format == PETSC_VIEWER_ASCII_INFO) PetscFunctionReturn(PETSC_SUCCESS);
101 30 : if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
102 17 : PetscCall(PetscViewerASCIIPrintf(viewer,"number of columns: %" PetscInt_FMT "\n",m));
103 17 : PetscCall(PetscViewerASCIIPrintf(viewer,"number of rows of B: %" PetscInt_FMT "\n",p));
104 17 : PetscFunctionReturn(PETSC_SUCCESS);
105 : }
106 13 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
107 13 : if (ds->compact) {
108 1 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
109 1 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&S));
110 1 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
111 1 : rowsa = n;
112 1 : colsa = ds->extrarow? m+1: m;
113 1 : rowsb = p;
114 1 : colsb = ds->extrarow? m+1: m;
115 1 : if (format == PETSC_VIEWER_ASCII_MATLAB) {
116 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",rowsa,colsa));
117 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = zeros(%" PetscInt_FMT ",3);\n",2*ds->n));
118 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = [\n"));
119 0 : for (i=0;i<PetscMin(rowsa,colsa);i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,i+1,(double)T[i]));
120 0 : for (i=0;i<k;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,k+1,(double)T[i+ds->ld]));
121 0 : if (n>m) { /* A lower bidiagonal */
122 0 : for (i=k;i<rowsa-1;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+2,i+1,(double)T[i+ds->ld]));
123 : } else { /* A (square) upper bidiagonal */
124 0 : for (i=k;i<colsa-1;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,i+2,(double)T[i+ds->ld]));
125 : }
126 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(zzz);\n",DSMatName[DS_MAT_T]));
127 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",rowsb,colsb));
128 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = zeros(%" PetscInt_FMT ",3);\n",2*ds->n));
129 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = [\n"));
130 0 : for (i=0;i<rowsb;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,i+1,(double)S[i]));
131 0 : for (i=0;i<colsb-1;i++) {
132 0 : r = PetscMax(i+2,ds->k+1);
133 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,r,(double)T[i+2*ds->ld]));
134 : }
135 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(zzz);\n",DSMatName[DS_MAT_D]));
136 : } else {
137 1 : PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix %s =\n",DSMatName[DS_MAT_T]));
138 11 : for (i=0;i<rowsa;i++) {
139 110 : for (j=0;j<colsa;j++) {
140 100 : if (i==j) value = T[i];
141 90 : else if (i<ds->k && j==ds->k) value = T[i+ds->ld];
142 90 : else if (n>m && i==j+1 && i>ds->k) value = T[j+ds->ld];
143 90 : else if (n<=m && i+1==j && i>=ds->k) value = T[i+ds->ld];
144 : else value = 0.0;
145 100 : PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
146 : }
147 10 : PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
148 : }
149 1 : PetscCall(PetscViewerASCIIPrintf(viewer,"Matrix %s =\n",DSMatName[DS_MAT_D]));
150 11 : for (i=0;i<rowsb;i++) {
151 110 : for (j=0;j<colsb;j++) {
152 100 : if (i==j) value = S[i];
153 90 : else if (i<ds->k && j==ds->k) value = T[PetscMin(i,j)+2*ds->ld];
154 90 : else if (i+1==j && i>=ds->k) value = T[i+2*ds->ld];
155 : else value = 0.0;
156 100 : PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
157 : }
158 10 : PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
159 : }
160 : }
161 1 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
162 1 : PetscCall(PetscViewerFlush(viewer));
163 1 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
164 1 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&S));
165 : } else {
166 12 : PetscCall(DSViewMat(ds,viewer,DS_MAT_A));
167 12 : PetscCall(DSViewMat(ds,viewer,DS_MAT_B));
168 : }
169 13 : if (ds->state>DS_STATE_INTERMEDIATE) {
170 0 : PetscCall(DSViewMat(ds,viewer,DS_MAT_X));
171 0 : PetscCall(DSViewMat(ds,viewer,DS_MAT_U));
172 0 : PetscCall(DSViewMat(ds,viewer,DS_MAT_V));
173 : }
174 13 : PetscFunctionReturn(PETSC_SUCCESS);
175 : }
176 :
177 17 : static PetscErrorCode DSVectors_GSVD(DS ds,DSMatType mat,PetscInt *j,PetscReal *rnorm)
178 : {
179 17 : PetscFunctionBegin;
180 17 : switch (mat) {
181 0 : case DS_MAT_U:
182 : case DS_MAT_V:
183 0 : if (rnorm) *rnorm = 0.0;
184 : break;
185 : case DS_MAT_X:
186 : break;
187 0 : default:
188 0 : SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid mat parameter");
189 : }
190 17 : PetscFunctionReturn(PETSC_SUCCESS);
191 : }
192 :
193 556 : static PetscErrorCode DSSort_GSVD(DS ds,PetscScalar *wr,PetscScalar *wi,PetscScalar *rr,PetscScalar *ri,PetscInt *k)
194 : {
195 556 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
196 556 : PetscInt t,l,ld=ds->ld,i,*perm,*perm2;
197 556 : PetscReal *T=NULL,*D=NULL,*eig;
198 556 : PetscScalar *A=NULL,*B=NULL;
199 556 : PetscBool compact=ds->compact;
200 :
201 556 : PetscFunctionBegin;
202 556 : if (!ds->sc) PetscFunctionReturn(PETSC_SUCCESS);
203 556 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
204 556 : l = ds->l;
205 556 : t = ds->t;
206 556 : perm = ds->perm;
207 556 : PetscCall(PetscMalloc2(t,&eig,t,&perm2));
208 556 : if (compact) {
209 537 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
210 537 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
211 5429 : for (i=0;i<t;i++) eig[i] = (D[i]==0)?PETSC_INFINITY:T[i]/D[i];
212 : } else {
213 19 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
214 19 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_B],&B));
215 230 : for (i=0;i<t;i++) eig[i] = (B[i+i*ld]==0)?PETSC_INFINITY:PetscRealPart(A[i+i*ld])/PetscRealPart(B[i*(1+ld)]);
216 : }
217 556 : PetscCall(DSSortEigenvaluesReal_Private(ds,eig,perm));
218 556 : PetscCall(PetscArraycpy(perm2,perm,t));
219 5460 : for (i=l;i<t;i++) wr[i] = eig[perm[i]];
220 556 : if (compact) {
221 537 : PetscCall(PetscArraycpy(eig,T,t));
222 5230 : for (i=l;i<t;i++) T[i] = eig[perm[i]];
223 537 : PetscCall(PetscArraycpy(eig,D,t));
224 5230 : for (i=l;i<t;i++) D[i] = eig[perm[i]];
225 537 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
226 537 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
227 : } else {
228 230 : for (i=l;i<t;i++) eig[i] = PetscRealPart(A[i*(1+ld)]);
229 230 : for (i=l;i<t;i++) A[i*(1+ld)] = eig[perm[i]];
230 230 : for (i=l;i<t;i++) eig[i] = PetscRealPart(B[i*(1+ld)]);
231 230 : for (i=l;i<t;i++) B[i*(1+ld)] = eig[perm[i]];
232 19 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
233 19 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_B],&B));
234 : }
235 556 : PetscCall(DSPermuteColumns_Private(ds,l,t,ds->n,DS_MAT_U,perm2));
236 556 : PetscCall(PetscArraycpy(perm2,perm,t));
237 556 : PetscCall(DSPermuteColumns_Private(ds,l,t,ctx->m,DS_MAT_X,perm2));
238 556 : PetscCall(DSPermuteColumns_Private(ds,l,t,ctx->p,DS_MAT_V,perm));
239 556 : PetscCall(PetscFree2(eig,perm2));
240 556 : PetscFunctionReturn(PETSC_SUCCESS);
241 : }
242 :
243 534 : static PetscErrorCode DSUpdateExtraRow_GSVD(DS ds)
244 : {
245 534 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
246 534 : PetscInt i;
247 534 : PetscBLASInt n=0,m=0,ld=0;
248 534 : const PetscScalar *U,*V;
249 534 : PetscReal *T,*e,*f,alpha,beta,betah;
250 :
251 534 : PetscFunctionBegin;
252 534 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
253 534 : PetscCheck(ds->compact,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-compact storage");
254 534 : PetscCall(PetscBLASIntCast(ds->n,&n));
255 534 : PetscCall(PetscBLASIntCast(ctx->m,&m));
256 534 : PetscCall(PetscBLASIntCast(ds->ld,&ld));
257 534 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
258 534 : e = T+ld;
259 534 : f = T+2*ld;
260 534 : PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_U],&U));
261 534 : PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_V],&V));
262 534 : if (n<=m) { /* upper variant, A is square upper bidiagonal */
263 222 : beta = e[m-1]; /* in compact, we assume all entries are zero except the last one */
264 222 : betah = f[m-1];
265 2191 : for (i=0;i<m;i++) {
266 1969 : e[i] = PetscRealPart(beta*U[m-1+i*ld]);
267 1969 : f[i] = PetscRealPart(betah*V[m-1+i*ld]);
268 : }
269 : } else { /* lower variant, A is (m+1)xm lower bidiagonal */
270 312 : alpha = T[m];
271 312 : betah = f[m-1];
272 3205 : for (i=0;i<m;i++) {
273 2893 : e[i] = PetscRealPart(alpha*U[m+i*ld]);
274 2893 : f[i] = PetscRealPart(betah*V[m-1+i*ld]);
275 : }
276 312 : T[m] = PetscRealPart(alpha*U[m+m*ld]);
277 : }
278 534 : ds->k = m;
279 534 : PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_U],&U));
280 534 : PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_V],&V));
281 534 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
282 534 : PetscFunctionReturn(PETSC_SUCCESS);
283 : }
284 :
285 525 : static PetscErrorCode DSTruncate_GSVD(DS ds,PetscInt n,PetscBool trim)
286 : {
287 525 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
288 525 : PetscScalar *U;
289 525 : PetscReal *T;
290 525 : PetscInt i,m=ctx->m,ld=ds->ld;
291 525 : PetscBool lower=(ds->n>ctx->m)?PETSC_TRUE:PETSC_FALSE;
292 :
293 525 : PetscFunctionBegin;
294 525 : PetscCheck(ds->compact,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-compact storage");
295 525 : if (trim) {
296 46 : ds->l = 0;
297 46 : ds->k = 0;
298 46 : ds->n = lower? n+1: n;
299 46 : ctx->m = n;
300 46 : ctx->p = n;
301 46 : ds->t = ds->n; /* truncated length equal to the new dimension */
302 46 : ctx->tm = ctx->m; /* must also keep the previous dimension of X */
303 46 : ctx->tp = ctx->p; /* must also keep the previous dimension of V */
304 : } else {
305 479 : if (lower) {
306 : /* move value of diagonal element of arrow (alpha) */
307 274 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
308 274 : T[n] = T[m];
309 274 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
310 : /* copy last column of U so that it updates the next initial vector of U1 */
311 274 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
312 3074 : for (i=0;i<=m;i++) U[i+n*ld] = U[i+m*ld];
313 274 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
314 : }
315 479 : ds->k = (ds->extrarow)? n: 0;
316 479 : ds->t = ds->n; /* truncated length equal to previous dimension */
317 479 : ctx->tm = ctx->m; /* must also keep the previous dimension of X */
318 479 : ctx->tp = ctx->p; /* must also keep the previous dimension of V */
319 479 : ds->n = lower? n+1: n;
320 479 : ctx->m = n;
321 479 : ctx->p = n;
322 : }
323 525 : PetscFunctionReturn(PETSC_SUCCESS);
324 : }
325 :
326 549 : static PetscErrorCode DSSwitchFormat_GSVD(DS ds)
327 : {
328 549 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
329 549 : PetscReal *T,*D;
330 549 : PetscScalar *A,*B;
331 549 : PetscInt i,n=ds->n,k=ds->k,ld=ds->ld,m=ctx->m;
332 :
333 549 : PetscFunctionBegin;
334 549 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
335 : /* switch from compact (arrow) to dense storage */
336 : /* bidiagonal associated to B is stored in D and T+2*ld */
337 549 : PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_A],&A));
338 549 : PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_B],&B));
339 549 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
340 549 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
341 549 : PetscCall(PetscArrayzero(A,ld*ld));
342 549 : PetscCall(PetscArrayzero(B,ld*ld));
343 2573 : for (i=0;i<k;i++) {
344 2024 : A[i+i*ld] = T[i];
345 2024 : A[i+k*ld] = T[i+ld];
346 2024 : B[i+i*ld] = D[i];
347 2024 : B[i+k*ld] = T[i+2*ld];
348 : }
349 : /* B is upper bidiagonal */
350 549 : B[k+k*ld] = D[k];
351 2965 : for (i=k+1;i<m;i++) {
352 2416 : B[i+i*ld] = D[i];
353 2416 : B[i-1+i*ld] = T[i-1+2*ld];
354 : }
355 : /* A can be upper (square) or lower bidiagonal */
356 3507 : for (i=k;i<m;i++) A[i+i*ld] = T[i];
357 2316 : if (n>m) for (i=k;i<m;i++) A[i+1+i*ld] = T[i+ld];
358 1191 : else for (i=k+1;i<m;i++) A[i-1+i*ld] = T[i-1+ld];
359 549 : PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_A],&A));
360 549 : PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_B],&B));
361 549 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
362 549 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
363 549 : PetscFunctionReturn(PETSC_SUCCESS);
364 : }
365 :
366 : /*
367 : Compact format is used when [A;B] has orthonormal columns.
368 : In this case R=I and the GSVD of (A,B) is the CS decomposition
369 : */
370 556 : static PetscErrorCode DSSolve_GSVD(DS ds,PetscScalar *wr,PetscScalar *wi)
371 : {
372 556 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
373 556 : PetscInt i,j;
374 556 : PetscBLASInt n1,m1,info,lc = 0,n = 0,m = 0,p = 0,p1,l,k,q,ld,off,lwork,r;
375 556 : PetscScalar *A,*B,*X,*U,*V,sone=1.0,smone=-1.0;
376 556 : PetscReal *alpha,*beta,*T,*D;
377 : #if !defined(SLEPC_MISSING_LAPACK_GGSVD3)
378 556 : PetscScalar a,dummy;
379 556 : PetscReal rdummy;
380 556 : PetscBLASInt idummy;
381 : #endif
382 :
383 556 : PetscFunctionBegin;
384 556 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
385 556 : PetscCall(PetscBLASIntCast(ds->n,&m));
386 556 : PetscCall(PetscBLASIntCast(ctx->m,&n));
387 556 : PetscCall(PetscBLASIntCast(ctx->p,&p));
388 556 : PetscCall(PetscBLASIntCast(ds->l,&lc));
389 556 : PetscCheck(ds->compact || lc==0,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"DSGSVD with non-compact format does not support locking");
390 : /* In compact storage B is always nxn and A can be either nxn or (n+1)xn */
391 556 : PetscCheck(!ds->compact || (p==n && (m==p || m==p+1)),PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Dimensions not supported in compact format");
392 556 : PetscCall(PetscBLASIntCast(ds->ld,&ld));
393 556 : n1 = n-lc; /* n1 = size of leading block, excl. locked + size of trailing block */
394 556 : m1 = m-lc;
395 556 : p1 = p-lc;
396 556 : off = lc+lc*ld;
397 556 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
398 556 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_B],&B));
399 556 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_X],&X));
400 556 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
401 556 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_V],&V));
402 556 : PetscCall(PetscArrayzero(X,ld*ld));
403 755 : for (i=0;i<lc;i++) X[i+i*ld] = 1.0;
404 556 : PetscCall(PetscArrayzero(U,ld*ld));
405 755 : for (i=0;i<lc;i++) U[i+i*ld] = 1.0;
406 556 : PetscCall(PetscArrayzero(V,ld*ld));
407 755 : for (i=0;i<lc;i++) V[i+i*ld] = 1.0;
408 556 : if (ds->compact) PetscCall(DSSwitchFormat_GSVD(ds));
409 :
410 : #if !defined(SLEPC_MISSING_LAPACK_GGSVD3)
411 : /* workspace query and memory allocation */
412 556 : lwork = -1;
413 : #if !defined (PETSC_USE_COMPLEX)
414 : PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,&dummy,&ld,&dummy,&ld,&rdummy,&rdummy,&dummy,&ld,&dummy,&ld,&dummy,&ld,&a,&lwork,&idummy,&info));
415 : PetscCall(PetscBLASIntCast((PetscInt)a,&lwork));
416 : #else
417 556 : PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,&dummy,&ld,&dummy,&ld,&rdummy,&rdummy,&dummy,&ld,&dummy,&ld,&dummy,&ld,&a,&lwork,&rdummy,&idummy,&info));
418 556 : PetscCall(PetscBLASIntCast((PetscInt)PetscRealPart(a),&lwork));
419 : #endif
420 :
421 : #if !defined (PETSC_USE_COMPLEX)
422 : PetscCall(DSAllocateWork_Private(ds,lwork,2*ds->ld,ds->ld));
423 : alpha = ds->rwork;
424 : beta = ds->rwork+ds->ld;
425 : PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,&lwork,ds->iwork,&info));
426 : #else
427 556 : PetscCall(DSAllocateWork_Private(ds,lwork,4*ds->ld,ds->ld));
428 556 : alpha = ds->rwork+2*ds->ld;
429 556 : beta = ds->rwork+3*ds->ld;
430 556 : PetscCallBLAS("LAPACKggsvd3",LAPACKggsvd3_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,&lwork,ds->rwork,ds->iwork,&info));
431 : #endif
432 556 : SlepcCheckLapackInfo("ggsvd3",info);
433 :
434 : #else /* defined(SLEPC_MISSING_LAPACK_GGSVD3) */
435 :
436 : lwork = PetscMax(PetscMax(3*n,m),p)+n;
437 : #if !defined (PETSC_USE_COMPLEX)
438 : PetscCall(DSAllocateWork_Private(ds,lwork,2*ds->ld,ds->ld));
439 : alpha = ds->rwork;
440 : beta = ds->rwork+ds->ld;
441 : PetscCallBLAS("LAPACKggsvd",LAPACKggsvd_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,ds->iwork,&info));
442 : #else
443 : PetscCall(DSAllocateWork_Private(ds,lwork,4*ds->ld,ds->ld));
444 : alpha = ds->rwork+2*ds->ld;
445 : beta = ds->rwork+3*ds->ld;
446 : PetscCallBLAS("LAPACKggsvd",LAPACKggsvd_("U","V","Q",&m1,&n1,&p1,&k,&l,A+off,&ld,B+off,&ld,alpha,beta,U+off,&ld,V+off,&ld,X+off,&ld,ds->work,ds->rwork,ds->iwork,&info));
447 : #endif
448 : SlepcCheckLapackInfo("ggsvd",info);
449 :
450 : #endif
451 :
452 556 : PetscCheck(k+l>=n1,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"The rank deficient case not supported yet");
453 556 : if (ds->compact) {
454 537 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
455 537 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
456 : /* R is the identity matrix (except the sign) */
457 5230 : for (i=lc;i<n;i++) {
458 4693 : if (PetscRealPart(A[i+i*ld])<0.0) { /* scale column i */
459 28603 : for (j=lc;j<n;j++) X[j+i*ld] = -X[j+i*ld];
460 : }
461 : }
462 537 : PetscCall(PetscArrayzero(T+ld,m-1));
463 537 : PetscCall(PetscArrayzero(T+2*ld,n-1));
464 5230 : for (i=lc;i<n;i++) {
465 4693 : T[i] = alpha[i-lc];
466 4693 : D[i] = beta[i-lc];
467 4693 : if (D[i]==0.0) wr[i] = PETSC_INFINITY;
468 4693 : else wr[i] = T[i]/D[i];
469 : }
470 537 : ds->t = n;
471 537 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
472 537 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
473 : } else {
474 : /* X = X*inv(R) */
475 19 : q = PetscMin(m,n);
476 19 : PetscCallBLAS("BLAStrsm",BLAStrsm_("R","U","N","N",&n,&q,&sone,A,&ld,X,&ld));
477 19 : if (m<n) {
478 4 : r = n-m;
479 4 : PetscCallBLAS("BLASgemm",BLASgemm_("N","N",&n,&r,&m,&sone,X,&ld,A,&ld,&smone,X+m*ld,&ld));
480 4 : PetscCallBLAS("BLAStrsm",BLAStrsm_("R","U","N","N",&n,&r,&sone,B+m*ld,&ld,X+m*ld,&ld));
481 : }
482 19 : if (k>0) {
483 13 : for (i=k;i<PetscMin(m,k+l);i++) {
484 11 : PetscCall(PetscArraycpy(X+(i-k)*ld,X+i*ld,ld));
485 11 : PetscCall(PetscArraycpy(U+(i-k)*ld,U+i*ld,ld));
486 : }
487 : }
488 : /* singular values */
489 19 : PetscCall(PetscArrayzero(A,ld*ld));
490 19 : PetscCall(PetscArrayzero(B,ld*ld));
491 230 : for (j=k;j<PetscMin(m,k+l);j++) {
492 211 : A[(j-k)*(1+ld)] = alpha[j];
493 211 : B[(j-k)*(1+ld)] = beta[j];
494 211 : wr[j-k] = alpha[j]/beta[j];
495 : }
496 19 : ds->t = PetscMin(m,k+l)-k; /* set number of computed values */
497 : }
498 556 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
499 556 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_B],&B));
500 556 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_X],&X));
501 556 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
502 556 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_V],&V));
503 556 : PetscFunctionReturn(PETSC_SUCCESS);
504 : }
505 :
506 24 : static PetscErrorCode DSCond_GSVD(DS ds,PetscReal *cond)
507 : {
508 24 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
509 24 : PetscBLASInt lwork,lrwork=0,info,m,n,p,ld;
510 24 : PetscScalar *A,*work;
511 24 : const PetscScalar *M;
512 24 : PetscReal *sigma,conda,condb;
513 : #if defined(PETSC_USE_COMPLEX)
514 24 : PetscReal *rwork;
515 : #endif
516 :
517 24 : PetscFunctionBegin;
518 24 : PetscCall(PetscBLASIntCast(ds->n,&m));
519 24 : PetscCall(PetscBLASIntCast(ctx->m,&n));
520 24 : PetscCall(PetscBLASIntCast(ctx->p,&p));
521 24 : PetscCall(PetscBLASIntCast(ds->ld,&ld));
522 24 : lwork = 5*n;
523 : #if defined(PETSC_USE_COMPLEX)
524 24 : lrwork = 5*n;
525 : #endif
526 24 : PetscCall(DSAllocateWork_Private(ds,ld*n+lwork,n+lrwork,0));
527 24 : A = ds->work;
528 24 : work = ds->work+ld*n;
529 24 : sigma = ds->rwork;
530 : #if defined(PETSC_USE_COMPLEX)
531 24 : rwork = ds->rwork+n;
532 : #endif
533 24 : if (ds->compact) PetscCall(DSSwitchFormat_GSVD(ds));
534 :
535 24 : PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_A],&M));
536 24 : PetscCall(PetscArraycpy(A,M,ld*n));
537 24 : PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_A],&M));
538 : #if defined(PETSC_USE_COMPLEX)
539 24 : PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&m,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,rwork,&info));
540 : #else
541 : PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&m,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,&info));
542 : #endif
543 24 : SlepcCheckLapackInfo("gesvd",info);
544 24 : conda = sigma[0]/sigma[PetscMin(m,n)-1];
545 :
546 24 : PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_B],&M));
547 24 : PetscCall(PetscArraycpy(A,M,ld*n));
548 24 : PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_B],&M));
549 : #if defined(PETSC_USE_COMPLEX)
550 24 : PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&p,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,rwork,&info));
551 : #else
552 : PetscCallBLAS("LAPACKgesvd",LAPACKgesvd_("N","N",&p,&n,A,&ld,sigma,NULL,&ld,NULL,&ld,work,&lwork,&info));
553 : #endif
554 24 : SlepcCheckLapackInfo("gesvd",info);
555 24 : condb = sigma[0]/sigma[PetscMin(p,n)-1];
556 :
557 24 : *cond = PetscMax(conda,condb);
558 24 : PetscFunctionReturn(PETSC_SUCCESS);
559 : }
560 :
561 : #if !defined(PETSC_HAVE_MPIUNI)
562 31 : static PetscErrorCode DSSynchronize_GSVD(DS ds,PetscScalar eigr[],PetscScalar eigi[])
563 : {
564 31 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
565 31 : PetscInt ld=ds->ld,l=ds->l,k=0,kr=0;
566 31 : PetscMPIInt m,rank,off=0,size,n,ldn,ld3;
567 31 : PetscScalar *A,*U,*V,*X;
568 31 : PetscReal *T;
569 :
570 31 : PetscFunctionBegin;
571 31 : PetscCall(PetscMPIIntCast(ctx->m,&m));
572 31 : if (ds->compact) kr = 3*ld;
573 5 : else k = 2*(m-l)*ld;
574 31 : if (ds->state>DS_STATE_RAW) k += 3*(m-l)*ld;
575 31 : if (eigr) k += m-l;
576 31 : PetscCall(DSAllocateWork_Private(ds,k+kr,0,0));
577 31 : PetscCall(PetscMPIIntCast(k*sizeof(PetscScalar)+kr*sizeof(PetscReal),&size));
578 31 : PetscCall(PetscMPIIntCast(m-l,&n));
579 31 : PetscCall(PetscMPIIntCast(ld*(m-l),&ldn));
580 31 : PetscCall(PetscMPIIntCast(3*ld,&ld3));
581 31 : if (ds->compact) PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
582 5 : else PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
583 31 : if (ds->state>DS_STATE_RAW) {
584 31 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
585 31 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_V],&V));
586 31 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_X],&X));
587 : }
588 31 : PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ds),&rank));
589 31 : if (!rank) {
590 15 : if (ds->compact) PetscCallMPI(MPI_Pack(T,ld3,MPIU_REAL,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
591 2 : else PetscCallMPI(MPI_Pack(A+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
592 15 : if (ds->state>DS_STATE_RAW) {
593 15 : PetscCallMPI(MPI_Pack(U+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
594 15 : PetscCallMPI(MPI_Pack(V+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
595 15 : PetscCallMPI(MPI_Pack(X+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
596 : }
597 15 : if (eigr) PetscCallMPI(MPI_Pack(eigr+l,n,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
598 : }
599 62 : PetscCallMPI(MPI_Bcast(ds->work,size,MPI_BYTE,0,PetscObjectComm((PetscObject)ds)));
600 31 : if (rank) {
601 16 : if (ds->compact) PetscCallMPI(MPI_Unpack(ds->work,size,&off,T,ld3,MPIU_REAL,PetscObjectComm((PetscObject)ds)));
602 3 : else PetscCallMPI(MPI_Unpack(ds->work,size,&off,A+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
603 16 : if (ds->state>DS_STATE_RAW) {
604 16 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,U+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
605 16 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,V+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
606 16 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,X+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
607 : }
608 16 : if (eigr) PetscCallMPI(MPI_Unpack(ds->work,size,&off,eigr+l,n,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
609 : }
610 31 : if (ds->compact) PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
611 5 : else PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
612 31 : if (ds->state>DS_STATE_RAW) {
613 31 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
614 31 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_V],&V));
615 31 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_X],&X));
616 : }
617 31 : PetscFunctionReturn(PETSC_SUCCESS);
618 : }
619 : #endif
620 :
621 1664 : static PetscErrorCode DSMatGetSize_GSVD(DS ds,DSMatType t,PetscInt *rows,PetscInt *cols)
622 : {
623 1664 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
624 :
625 1664 : PetscFunctionBegin;
626 1664 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the other dimensions with DSGSVDSetDimensions()");
627 1664 : switch (t) {
628 19 : case DS_MAT_A:
629 19 : *rows = ds->n;
630 19 : *cols = ds->extrarow? ctx->m+1: ctx->m;
631 19 : break;
632 19 : case DS_MAT_B:
633 19 : *rows = ctx->p;
634 19 : *cols = ds->extrarow? ctx->m+1: ctx->m;
635 19 : break;
636 0 : case DS_MAT_T:
637 0 : *rows = ds->n;
638 0 : *cols = PetscDefined(USE_COMPLEX)? 2: 3;
639 0 : break;
640 0 : case DS_MAT_D:
641 0 : *rows = ctx->p;
642 0 : *cols = 1;
643 0 : break;
644 542 : case DS_MAT_U:
645 542 : *rows = ds->state==DS_STATE_TRUNCATED? ds->t: ds->n;
646 542 : *cols = ds->n;
647 542 : break;
648 542 : case DS_MAT_V:
649 542 : *rows = ds->state==DS_STATE_TRUNCATED? ctx->tp: ctx->p;
650 542 : *cols = ctx->p;
651 542 : break;
652 542 : case DS_MAT_X:
653 542 : *rows = ds->state==DS_STATE_TRUNCATED? ctx->tm: ctx->m;
654 542 : *cols = ctx->m;
655 542 : break;
656 0 : default:
657 0 : SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid t parameter");
658 : }
659 1664 : PetscFunctionReturn(PETSC_SUCCESS);
660 : }
661 :
662 556 : static PetscErrorCode DSGSVDSetDimensions_GSVD(DS ds,PetscInt m,PetscInt p)
663 : {
664 556 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
665 :
666 556 : PetscFunctionBegin;
667 556 : DSCheckAlloc(ds,1);
668 556 : if (m == PETSC_DETERMINE) {
669 0 : ctx->m = ds->ld;
670 556 : } else if (m != PETSC_CURRENT) {
671 556 : PetscCheck(m>0 && m<=ds->ld,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of m. Must be between 1 and ld");
672 556 : ctx->m = m;
673 : }
674 556 : if (p == PETSC_DETERMINE) {
675 3 : ctx->p = ds->n;
676 553 : } else if (p != PETSC_CURRENT) {
677 553 : PetscCheck(p>0 && p<=ds->ld,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of p. Must be between 1 and ld");
678 553 : ctx->p = p;
679 : }
680 556 : PetscFunctionReturn(PETSC_SUCCESS);
681 : }
682 :
683 : /*@
684 : DSGSVDSetDimensions - Sets the number of columns and rows for a DSGSVD.
685 :
686 : Logically Collective
687 :
688 : Input Parameters:
689 : + ds - the direct solver context
690 : . m - the number of columns
691 : - p - the number of rows for the second matrix (B)
692 :
693 : Notes:
694 : This call is complementary to DSSetDimensions(), to provide two dimensions
695 : that are specific to this DS type. The number of rows for the first matrix (A)
696 : is set by DSSetDimensions().
697 :
698 : Use PETSC_CURRENT to leave any of the values unchanged. Use PETSC_DETERMINE
699 : to set m to the leading dimension and p to the number of columns of B.
700 :
701 : Level: intermediate
702 :
703 : .seealso: DSGSVDGetDimensions(), DSSetDimensions()
704 : @*/
705 556 : PetscErrorCode DSGSVDSetDimensions(DS ds,PetscInt m,PetscInt p)
706 : {
707 556 : PetscFunctionBegin;
708 556 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
709 1668 : PetscValidLogicalCollectiveInt(ds,m,2);
710 1668 : PetscValidLogicalCollectiveInt(ds,p,3);
711 556 : PetscTryMethod(ds,"DSGSVDSetDimensions_C",(DS,PetscInt,PetscInt),(ds,m,p));
712 556 : PetscFunctionReturn(PETSC_SUCCESS);
713 : }
714 :
715 12 : static PetscErrorCode DSGSVDGetDimensions_GSVD(DS ds,PetscInt *m,PetscInt *p)
716 : {
717 12 : DS_GSVD *ctx = (DS_GSVD*)ds->data;
718 :
719 12 : PetscFunctionBegin;
720 12 : if (m) *m = ctx->m;
721 12 : if (p) *p = ctx->p;
722 12 : PetscFunctionReturn(PETSC_SUCCESS);
723 : }
724 :
725 : /*@
726 : DSGSVDGetDimensions - Returns the number of columns and rows for a DSGSVD.
727 :
728 : Not Collective
729 :
730 : Input Parameter:
731 : . ds - the direct solver context
732 :
733 : Output Parameters:
734 : + m - the number of columns
735 : - p - the number of rows for the second matrix (B)
736 :
737 : Level: intermediate
738 :
739 : .seealso: DSGSVDSetDimensions()
740 : @*/
741 12 : PetscErrorCode DSGSVDGetDimensions(DS ds,PetscInt *m,PetscInt *p)
742 : {
743 12 : PetscFunctionBegin;
744 12 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
745 12 : PetscUseMethod(ds,"DSGSVDGetDimensions_C",(DS,PetscInt*,PetscInt*),(ds,m,p));
746 12 : PetscFunctionReturn(PETSC_SUCCESS);
747 : }
748 :
749 64 : static PetscErrorCode DSDestroy_GSVD(DS ds)
750 : {
751 64 : PetscFunctionBegin;
752 64 : PetscCall(PetscFree(ds->data));
753 64 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDSetDimensions_C",NULL));
754 64 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDGetDimensions_C",NULL));
755 64 : PetscFunctionReturn(PETSC_SUCCESS);
756 : }
757 :
758 : /*MC
759 : DSGSVD - Dense Generalized Singular Value Decomposition.
760 :
761 : Level: beginner
762 :
763 : Notes:
764 : The problem is expressed as A*X = U*C, B*X = V*S, where A and B are
765 : matrices with the same number of columns, m, U and V are orthogonal
766 : (unitary), and X is an mxm invertible matrix. The DS object does not
767 : expose matrices C and S, instead the singular values sigma, which are
768 : the ratios c_i/s_i, are returned in the arguments of DSSolve().
769 : Note that the number of columns of the returned X, U, V may be smaller
770 : in the case that some c_i or s_i are zero.
771 :
772 : The number of rows of A (and U) is the value n passed with DSSetDimensions().
773 : The number of columns m and the number of rows of B (and V) must be
774 : set via DSGSVDSetDimensions().
775 :
776 : Internally, LAPACK's representation is used, U'*A*Q = C*[0 R], V'*B*Q = S*[0 R],
777 : where X = Q*inv(R) is computed at the end of DSSolve().
778 :
779 : If the compact storage format is selected, then a simplified problem is
780 : solved, where A and B are bidiagonal (possibly with an arrow), and [A;B]
781 : is assumed to have orthonormal columns. We consider two cases: (1) A and B
782 : are square mxm upper bidiagonal, and (2) A is lower bidiagonal with m+1
783 : rows and B is square upper bidiagonal. In these cases, R=I so it
784 : corresponds to the CS decomposition. The first matrix is stored in two
785 : diagonals of DS_MAT_T, while the second matrix is stored in DS_MAT_D
786 : and the remaining diagonal of DS_MAT_T.
787 :
788 : Allowed arguments of DSVectors() are DS_MAT_U, DS_MAT_V and DS_MAT_X.
789 :
790 : Used DS matrices:
791 : + DS_MAT_A - first problem matrix
792 : . DS_MAT_B - second problem matrix
793 : . DS_MAT_T - first upper bidiagonal matrix (if compact storage is selected)
794 : . DS_MAT_D - second upper bidiagonal matrix (if compact storage is selected)
795 : . DS_MAT_U - (upper) left generalized singular vectors
796 : . DS_MAT_V - (lower) left generalized singular vectors
797 : - DS_MAT_X - right generalized singular vectors
798 :
799 : Implemented methods:
800 : . 0 - Lapack (_ggsvd3 if available, or _ggsvd)
801 :
802 : .seealso: DSCreate(), DSSetType(), DSType, DSGSVDSetDimensions()
803 : M*/
804 64 : SLEPC_EXTERN PetscErrorCode DSCreate_GSVD(DS ds)
805 : {
806 64 : DS_GSVD *ctx;
807 :
808 64 : PetscFunctionBegin;
809 64 : PetscCall(PetscNew(&ctx));
810 64 : ds->data = (void*)ctx;
811 :
812 64 : ds->ops->allocate = DSAllocate_GSVD;
813 64 : ds->ops->view = DSView_GSVD;
814 64 : ds->ops->vectors = DSVectors_GSVD;
815 64 : ds->ops->sort = DSSort_GSVD;
816 64 : ds->ops->solve[0] = DSSolve_GSVD;
817 : #if !defined(PETSC_HAVE_MPIUNI)
818 64 : ds->ops->synchronize = DSSynchronize_GSVD;
819 : #endif
820 64 : ds->ops->truncate = DSTruncate_GSVD;
821 64 : ds->ops->update = DSUpdateExtraRow_GSVD;
822 64 : ds->ops->cond = DSCond_GSVD;
823 64 : ds->ops->matgetsize = DSMatGetSize_GSVD;
824 64 : ds->ops->destroy = DSDestroy_GSVD;
825 64 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDSetDimensions_C",DSGSVDSetDimensions_GSVD));
826 64 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSGSVDGetDimensions_C",DSGSVDGetDimensions_GSVD));
827 64 : PetscFunctionReturn(PETSC_SUCCESS);
828 : }
|