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 : #include <slepc/private/dsimpl.h> /*I "slepcds.h" I*/
12 : #include <slepcblaslapack.h>
13 :
14 : typedef struct {
15 : PetscInt m; /* number of columns */
16 : PetscInt t; /* number of rows of V after truncating */
17 : PetscBool reorth; /* reorthogonalize left vectors */
18 : } DS_HSVD;
19 :
20 17 : static PetscErrorCode DSAllocate_HSVD(DS ds,PetscInt ld)
21 : {
22 17 : PetscFunctionBegin;
23 17 : if (!ds->compact) PetscCall(DSAllocateMat_Private(ds,DS_MAT_A));
24 17 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_U));
25 17 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_V));
26 17 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_T));
27 17 : PetscCall(DSAllocateMat_Private(ds,DS_MAT_D));
28 17 : PetscCall(PetscFree(ds->perm));
29 17 : PetscCall(PetscMalloc1(ld,&ds->perm));
30 17 : PetscFunctionReturn(PETSC_SUCCESS);
31 : }
32 :
33 : /* 0 l k m-1
34 : -----------------------------------------
35 : |* . . |
36 : | * . . |
37 : | * . . |
38 : | * . . |
39 : | o o |
40 : | o o |
41 : | o o |
42 : | o o |
43 : | o o |
44 : | o o |
45 : | o x |
46 : | x x |
47 : | x x |
48 : | x x |
49 : | x x |
50 : | x x |
51 : | x x |
52 : | x x |
53 : | x x|
54 : n-1 | x|
55 : -----------------------------------------
56 : */
57 :
58 10 : static PetscErrorCode DSView_HSVD(DS ds,PetscViewer viewer)
59 : {
60 10 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
61 10 : PetscViewerFormat format;
62 10 : PetscInt i,j,r,c,m=ctx->m,rows,cols;
63 10 : PetscReal *T,*S,value;
64 10 : const char *methodname[] = {
65 : "Cross product A'*Omega*A"
66 : };
67 10 : const int nmeth=PETSC_STATIC_ARRAY_LENGTH(methodname);
68 :
69 10 : PetscFunctionBegin;
70 10 : PetscCall(PetscViewerGetFormat(viewer,&format));
71 10 : if (format == PETSC_VIEWER_ASCII_INFO || format == PETSC_VIEWER_ASCII_INFO_DETAIL) {
72 5 : if (format == PETSC_VIEWER_ASCII_INFO_DETAIL) PetscCall(PetscViewerASCIIPrintf(viewer,"number of columns: %" PetscInt_FMT "\n",m));
73 5 : if (ds->method<nmeth) PetscCall(PetscViewerASCIIPrintf(viewer,"solving the problem with: %s\n",methodname[ds->method]));
74 5 : if (ctx->reorth) PetscCall(PetscViewerASCIIPrintf(viewer,"reorthogonalizing left vectors\n"));
75 5 : PetscFunctionReturn(PETSC_SUCCESS);
76 : }
77 5 : PetscCheck(m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the number of columns with DSHSVDSetDimensions()");
78 5 : if (ds->compact) {
79 4 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
80 4 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&S));
81 4 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_FALSE));
82 4 : rows = ds->n;
83 4 : cols = ds->extrarow? m+1: m;
84 4 : if (format == PETSC_VIEWER_ASCII_MATLAB) {
85 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",rows,cols));
86 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = zeros(%" PetscInt_FMT ",3);\n",2*ds->n));
87 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"zzz = [\n"));
88 44 : for (i=0;i<PetscMin(ds->n,m);i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,i+1,(double)T[i]));
89 42 : for (i=0;i<cols-1;i++) {
90 38 : c = PetscMax(i+2,ds->k+1);
91 38 : r = i+1;
92 38 : value = i<ds->l? 0.0: T[i+ds->ld];
93 38 : PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",r,c,(double)value));
94 : }
95 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(zzz);\n",DSMatName[DS_MAT_T]));
96 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"%% Size = %" PetscInt_FMT " %" PetscInt_FMT "\n",ds->n,ds->n));
97 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"omega = zeros(%" PetscInt_FMT ",3);\n",3*ds->n));
98 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"omega = [\n"));
99 44 : for (i=0;i<ds->n;i++) PetscCall(PetscViewerASCIIPrintf(viewer,"%" PetscInt_FMT " %" PetscInt_FMT " %18.16e\n",i+1,i+1,(double)S[i]));
100 4 : PetscCall(PetscViewerASCIIPrintf(viewer,"];\n%s = spconvert(omega);\n",DSMatName[DS_MAT_D]));
101 : } else {
102 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"T\n"));
103 0 : for (i=0;i<rows;i++) {
104 0 : for (j=0;j<cols;j++) {
105 0 : if (i==j) value = T[i];
106 0 : else if (i<ds->l) value = 0.0;
107 0 : else if (i<ds->k && j==ds->k) value = T[PetscMin(i,j)+ds->ld];
108 0 : else if (i+1==j && i>=ds->k) value = T[i+ds->ld];
109 : else value = 0.0;
110 0 : PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
111 : }
112 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
113 : }
114 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"omega\n"));
115 0 : for (i=0;i<ds->n;i++) {
116 0 : for (j=0;j<ds->n;j++) {
117 0 : if (i==j) value = S[i];
118 : else value = 0.0;
119 0 : PetscCall(PetscViewerASCIIPrintf(viewer," %18.16e ",(double)value));
120 : }
121 0 : PetscCall(PetscViewerASCIIPrintf(viewer,"\n"));
122 : }
123 : }
124 4 : PetscCall(PetscViewerASCIIUseTabs(viewer,PETSC_TRUE));
125 4 : PetscCall(PetscViewerFlush(viewer));
126 4 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
127 4 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&S));
128 : } else {
129 1 : PetscCall(DSViewMat(ds,viewer,DS_MAT_A));
130 1 : PetscCall(DSViewMat(ds,viewer,DS_MAT_D));
131 : }
132 5 : if (ds->state>DS_STATE_INTERMEDIATE) {
133 0 : PetscCall(DSViewMat(ds,viewer,DS_MAT_U));
134 0 : PetscCall(DSViewMat(ds,viewer,DS_MAT_V));
135 : }
136 5 : PetscFunctionReturn(PETSC_SUCCESS);
137 : }
138 :
139 1 : static PetscErrorCode DSVectors_HSVD(DS ds,DSMatType mat,PetscInt *j,PetscReal *rnorm)
140 : {
141 1 : PetscFunctionBegin;
142 1 : switch (mat) {
143 1 : case DS_MAT_U:
144 : case DS_MAT_V:
145 1 : if (rnorm) *rnorm = 0.0;
146 1 : break;
147 0 : default:
148 0 : SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid mat parameter");
149 : }
150 1 : PetscFunctionReturn(PETSC_SUCCESS);
151 : }
152 :
153 85 : static PetscErrorCode DSSort_HSVD(DS ds,PetscScalar *wr,PetscScalar *wi,PetscScalar *rr,PetscScalar *ri,PetscInt *k)
154 : {
155 85 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
156 85 : PetscInt n,l,i,*perm,ld=ds->ld;
157 85 : PetscScalar *A;
158 85 : PetscReal *d,*s;
159 :
160 85 : PetscFunctionBegin;
161 85 : if (!ds->sc) PetscFunctionReturn(PETSC_SUCCESS);
162 85 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the number of columns with DSHSVDSetDimensions()");
163 85 : l = ds->l;
164 85 : n = PetscMin(ds->n,ctx->m);
165 85 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&d));
166 85 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&s));
167 85 : PetscCall(DSAllocateWork_Private(ds,0,ds->ld,0));
168 85 : perm = ds->perm;
169 85 : if (!rr) PetscCall(DSSortEigenvaluesReal_Private(ds,d,perm));
170 0 : else PetscCall(DSSortEigenvalues_Private(ds,rr,ri,perm,PETSC_FALSE));
171 85 : PetscCall(PetscArraycpy(ds->rwork,s,n));
172 1927 : for (i=l;i<n;i++) s[i] = ds->rwork[perm[i]];
173 1927 : for (i=l;i<n;i++) wr[i] = d[perm[i]];
174 85 : PetscCall(DSPermuteBoth_Private(ds,l,n,ds->n,ctx->m,DS_MAT_U,DS_MAT_V,perm));
175 1927 : for (i=l;i<n;i++) d[i] = PetscRealPart(wr[i]);
176 85 : if (!ds->compact) {
177 2 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
178 332 : for (i=l;i<n;i++) A[i+i*ld] = wr[i];
179 2 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
180 : }
181 85 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&d));
182 85 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&s));
183 85 : PetscFunctionReturn(PETSC_SUCCESS);
184 : }
185 :
186 81 : static PetscErrorCode DSUpdateExtraRow_HSVD(DS ds)
187 : {
188 81 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
189 81 : PetscInt i;
190 81 : PetscBLASInt n=0,m=0,ld,l;
191 81 : const PetscScalar *U;
192 81 : PetscReal *T,*e,*Omega,beta;
193 :
194 81 : PetscFunctionBegin;
195 81 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the number of columns with DSHSVDSetDimensions()");
196 81 : PetscCall(PetscBLASIntCast(ds->n,&n));
197 81 : PetscCall(PetscBLASIntCast(ctx->m,&m));
198 81 : PetscCall(PetscBLASIntCast(ds->ld,&ld));
199 81 : PetscCall(PetscBLASIntCast(ds->l,&l));
200 81 : PetscCall(MatDenseGetArrayRead(ds->omat[DS_MAT_U],&U));
201 81 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&Omega));
202 81 : PetscCheck(ds->compact,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-compact storage");
203 81 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
204 81 : e = T+ld;
205 81 : beta = PetscAbs(e[m-1]); /* in compact, we assume all entries are zero except the last one */
206 1863 : for (i=0;i<n;i++) e[i] = PetscRealPart(beta*U[n-1+i*ld]*Omega[i]);
207 81 : ds->k = m;
208 81 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
209 81 : PetscCall(MatDenseRestoreArrayRead(ds->omat[DS_MAT_U],&U));
210 81 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&Omega));
211 81 : PetscFunctionReturn(PETSC_SUCCESS);
212 : }
213 :
214 79 : static PetscErrorCode DSTruncate_HSVD(DS ds,PetscInt n,PetscBool trim)
215 : {
216 79 : PetscInt i,ld=ds->ld,l=ds->l;
217 79 : PetscScalar *A;
218 79 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
219 :
220 79 : PetscFunctionBegin;
221 79 : if (!ds->compact && ds->extrarow) PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
222 79 : if (trim) {
223 11 : if (!ds->compact && ds->extrarow) { /* clean extra column */
224 0 : for (i=l;i<ds->n;i++) A[i+ctx->m*ld] = 0.0;
225 : }
226 11 : ds->l = 0;
227 11 : ds->k = 0;
228 11 : ds->n = n;
229 11 : ctx->m = n;
230 11 : ds->t = ds->n; /* truncated length equal to the new dimension */
231 11 : ctx->t = ctx->m; /* must also keep the previous dimension of V */
232 : } else {
233 68 : if (!ds->compact && ds->extrarow && ds->k==ds->n) {
234 : /* copy entries of extra column to the new position, then clean last row */
235 0 : for (i=l;i<n;i++) A[i+n*ld] = A[i+ctx->m*ld];
236 0 : for (i=l;i<ds->n;i++) A[i+ctx->m*ld] = 0.0;
237 : }
238 68 : ds->k = (ds->extrarow)? n: 0;
239 68 : ds->t = ds->n; /* truncated length equal to previous dimension */
240 68 : ctx->t = ctx->m; /* must also keep the previous dimension of V */
241 68 : ds->n = n;
242 68 : ctx->m = n;
243 : }
244 79 : if (!ds->compact && ds->extrarow) PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
245 79 : PetscFunctionReturn(PETSC_SUCCESS);
246 : }
247 :
248 85 : static PetscErrorCode DSSolve_HSVD_CROSS(DS ds,PetscScalar *wr,PetscScalar *wi)
249 : {
250 85 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
251 85 : PetscInt i,j,k=ds->k,rwu=0,iwu=0,swu=0,nv;
252 85 : PetscBLASInt n1,n2,info,l=0,n=0,m=0,ld,off,one=1,*perm,*cmplx,incx=1,lwork;
253 85 : PetscScalar *A,*U,*V,scal,*R,sone=1.0,szero=0.0;
254 85 : PetscReal *d,*e,*dd,*ee,*Omega;
255 :
256 85 : PetscFunctionBegin;
257 85 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the number of columns with DSHSVDSetDimensions()");
258 85 : PetscCall(PetscBLASIntCast(ds->n,&n));
259 85 : PetscCall(PetscBLASIntCast(ctx->m,&m));
260 85 : PetscCheck(!ds->compact || n==m,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for non-square matrices in compact storage");
261 85 : PetscCheck(ds->compact || n>=m,PetscObjectComm((PetscObject)ds),PETSC_ERR_SUP,"Not implemented for the case of more columns than rows");
262 85 : PetscCall(PetscBLASIntCast(ds->l,&l));
263 85 : PetscCall(PetscBLASIntCast(ds->ld,&ld));
264 85 : PetscCall(PetscBLASIntCast(PetscMax(0,ds->k-ds->l+1),&n2));
265 85 : n1 = n-l; /* n1 = size of leading block, excl. locked + size of trailing block */
266 85 : off = l+l*ld;
267 85 : if (!ds->compact) PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
268 85 : PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_U],&U));
269 85 : PetscCall(MatDenseGetArrayWrite(ds->omat[DS_MAT_V],&V));
270 85 : PetscCall(DSGetArrayReal(ds,DS_MAT_T,&d));
271 85 : e = d+ld;
272 85 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&Omega));
273 85 : PetscCall(PetscArrayzero(U,ld*ld));
274 375 : for (i=0;i<l;i++) U[i+i*ld] = 1.0;
275 85 : PetscCall(PetscArrayzero(V,ld*ld));
276 2935 : for (i=0;i<n;i++) V[i+i*ld] = 1.0;
277 375 : for (i=0;i<l;i++) wr[i] = d[i];
278 85 : if (wi) for (i=0;i<l;i++) wi[i] = 0.0;
279 :
280 85 : if (ds->compact) {
281 : /* Form the arrow tridiagonal cross product T=A'*Omega*A, where A is the arrow
282 : bidiagonal matrix formed by d, e. T is stored in dd, ee */
283 83 : PetscCall(DSAllocateWork_Private(ds,(n+6)*ld,4*ld,2*ld));
284 83 : R = ds->work+swu;
285 83 : swu += n*ld;
286 83 : perm = ds->iwork+iwu;
287 83 : iwu += n;
288 83 : cmplx = ds->iwork+iwu;
289 83 : dd = ds->rwork+rwu;
290 83 : rwu += ld;
291 83 : ee = ds->rwork+rwu;
292 83 : rwu += ld;
293 373 : for (i=0;i<l;i++) {dd[i] = d[i]*d[i]*Omega[i]; ee[i] = 0.0;}
294 733 : for (i=l;i<=ds->k;i++) {
295 650 : dd[i] = Omega[i]*d[i]*d[i];
296 650 : ee[i] = Omega[i]*d[i]*e[i];
297 : }
298 650 : for (i=l;i<k;i++) dd[k] += Omega[i]*e[i]*e[i];
299 945 : for (i=k+1;i<n;i++) {
300 862 : dd[i] = Omega[i]*d[i]*d[i]+Omega[i-1]*e[i-1]*e[i-1];
301 862 : ee[i] = Omega[i]*d[i]*e[i];
302 : }
303 :
304 : /* Reduce T to tridiagonal form */
305 83 : PetscCall(DSArrowTridiag(n2,dd+l,ee+l,V+off,ld));
306 :
307 : /* Solve the tridiagonal eigenproblem corresponding to T */
308 83 : PetscCallBLAS("LAPACKsteqr",LAPACKsteqr_("V",&n1,dd+l,ee+l,V+off,&ld,ds->rwork+rwu,&info));
309 83 : SlepcCheckLapackInfo("steqr",info);
310 1595 : for (i=l;i<n;i++) wr[i] = PetscSqrtScalar(PetscAbs(dd[i]));
311 :
312 : /* Build left singular vectors: U=A*V*Sigma^-1 */
313 83 : PetscCall(PetscArrayzero(U+l*ld,n1*ld));
314 1512 : for (i=l;i<n-1;i++) {
315 1429 : scal = d[i];
316 1429 : PetscCallBLAS("BLASaxpy",BLASaxpy_(&n1,&scal,V+l*ld+i,&ld,U+l*ld+i,&ld));
317 1429 : j = (i<k)?k:i+1;
318 1429 : scal = e[i];
319 1429 : PetscCallBLAS("BLASaxpy",BLASaxpy_(&n1,&scal,V+l*ld+j,&ld,U+l*ld+i,&ld));
320 : }
321 83 : scal = d[n-1];
322 83 : PetscCallBLAS("BLASaxpy",BLASaxpy_(&n1,&scal,V+off+(n1-1),&ld,U+off+(n1-1),&ld));
323 : /* Multiply by Sigma^-1 */
324 1595 : for (i=l;i<n;i++) {scal = 1.0/wr[i]; PetscCallBLAS("BLASscal",BLASscal_(&n1,&scal,U+i*ld+l,&one));}
325 :
326 : } else { /* non-compact */
327 :
328 2 : PetscCall(DSAllocateWork_Private(ds,(n+6)*ld,PetscDefined(USE_COMPLEX)?4*ld:ld,2*ld));
329 2 : R = ds->work+swu;
330 2 : swu += n*ld;
331 2 : perm = ds->iwork+iwu;
332 2 : iwu += n;
333 2 : cmplx = ds->iwork+iwu;
334 2 : dd = ds->rwork+rwu;
335 332 : for (j=l;j<m;j++) {
336 331040 : for (i=0;i<n;i++) ds->work[i] = Omega[i]*A[i+j*ld];
337 330 : PetscCallBLAS("BLASgemv",BLASgemv_("C",&n,&m,&sone,A,&ld,ds->work,&incx,&szero,V+j*ld,&incx));
338 : }
339 :
340 : /* compute eigenvalues */
341 2 : lwork = (n+6)*ld;
342 : #if defined(PETSC_USE_COMPLEX)
343 2 : rwu += ld;
344 2 : PetscCallBLAS("LAPACKsyev",LAPACKsyev_("V","L",&m,V,&ld,dd,ds->work,&lwork,ds->rwork+rwu,&info));
345 : #else
346 : PetscCallBLAS("LAPACKsyev",LAPACKsyev_("V","L",&m,V,&ld,dd,ds->work,&lwork,&info));
347 : #endif
348 2 : SlepcCheckLapackInfo("syev",info);
349 332 : for (i=l;i<PetscMin(n,m);i++) d[i] = PetscSqrtReal(PetscAbsReal(dd[i]));
350 :
351 : /* Build left singular vectors: U=A*V*Sigma^-1 */
352 332 : for (j=l;j<PetscMin(n,m);j++) {
353 330 : scal = 1.0/d[j];
354 330 : PetscCallBLAS("BLASgemv",BLASgemv_("N",&n,&m,&scal,A,&ld,V+j*ld,&incx,&szero,U+j*ld,&incx));
355 : }
356 : }
357 :
358 85 : if (ctx->reorth) { /* Reinforce orthogonality */
359 2 : nv = n1;
360 22 : for (i=0;i<n;i++) cmplx[i] = 0;
361 2 : PetscCall(DSPseudoOrthog_HR(&nv,U+off,ld,Omega+l,R,ld,perm,cmplx,NULL,ds->work+swu));
362 : } else { /* Update Omega */
363 1909 : for (i=l;i<PetscMin(n,m);i++) Omega[i] = PetscSign(dd[i]);
364 : }
365 :
366 : /* Update projected problem */
367 85 : if (ds->compact) {
368 1595 : for (i=l;i<n;i++) d[i] = PetscRealPart(wr[i]);
369 83 : PetscCall(PetscArrayzero(e,n-1));
370 : } else {
371 332 : for (i=l;i<m;i++) PetscCall(PetscArrayzero(A+l+i*ld,n-l));
372 1050 : for (i=l;i<n;i++) A[i+i*ld] = d[i];
373 : }
374 1927 : for (i=l;i<PetscMin(n,m);i++) wr[i] = d[i];
375 85 : if (wi) for (i=l;i<PetscMin(n,m);i++) wi[i] = 0.0;
376 :
377 85 : if (ctx->reorth) { /* Update vectors V with R */
378 2 : scal = -1.0;
379 18 : for (i=0;i<nv;i++) {
380 16 : if (PetscRealPart(R[i+i*ld]) < 0.0) PetscCallBLAS("BLASscal",BLASscal_(&n1,&scal,V+(i+l)*ld+l,&one));
381 : }
382 : }
383 :
384 85 : if (!ds->compact) PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
385 85 : PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_U],&U));
386 85 : PetscCall(MatDenseRestoreArrayWrite(ds->omat[DS_MAT_V],&V));
387 85 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&d));
388 85 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&Omega));
389 85 : PetscFunctionReturn(PETSC_SUCCESS);
390 : }
391 :
392 : #if !defined(PETSC_HAVE_MPIUNI)
393 14 : static PetscErrorCode DSSynchronize_HSVD(DS ds,PetscScalar eigr[],PetscScalar eigi[])
394 : {
395 14 : PetscInt ld=ds->ld,l=ds->l,k=0,kr=0;
396 14 : PetscMPIInt n,rank,off=0,size,ldn,ld3,ld_;
397 14 : PetscScalar *A,*U,*V;
398 14 : PetscReal *T,*D;
399 :
400 14 : PetscFunctionBegin;
401 14 : if (ds->compact) kr = 3*ld;
402 0 : else k = (ds->n-l)*ld;
403 14 : kr += ld;
404 14 : if (ds->state>DS_STATE_RAW) k += 2*(ds->n-l)*ld;
405 14 : if (eigr) k += ds->n-l;
406 14 : PetscCall(DSAllocateWork_Private(ds,k+kr,0,0));
407 14 : PetscCall(PetscMPIIntCast(k*sizeof(PetscScalar)+kr*sizeof(PetscReal),&size));
408 14 : PetscCall(PetscMPIIntCast(ds->n-l,&n));
409 14 : PetscCall(PetscMPIIntCast(ld*(ds->n-l),&ldn));
410 14 : PetscCall(PetscMPIIntCast(3*ld,&ld3));
411 14 : PetscCall(PetscMPIIntCast(ld,&ld_));
412 14 : if (ds->compact) PetscCall(DSGetArrayReal(ds,DS_MAT_T,&T));
413 0 : else PetscCall(MatDenseGetArray(ds->omat[DS_MAT_A],&A));
414 14 : PetscCall(DSGetArrayReal(ds,DS_MAT_D,&D));
415 14 : if (ds->state>DS_STATE_RAW) {
416 14 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_U],&U));
417 14 : PetscCall(MatDenseGetArray(ds->omat[DS_MAT_V],&V));
418 : }
419 14 : PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)ds),&rank));
420 14 : if (!rank) {
421 7 : if (ds->compact) PetscCallMPI(MPI_Pack(T,ld3,MPIU_REAL,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
422 0 : else PetscCallMPI(MPI_Pack(A+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
423 7 : PetscCallMPI(MPI_Pack(D,ld_,MPIU_REAL,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
424 7 : if (ds->state>DS_STATE_RAW) {
425 7 : PetscCallMPI(MPI_Pack(U+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
426 7 : PetscCallMPI(MPI_Pack(V+l*ld,ldn,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
427 : }
428 7 : if (eigr) PetscCallMPI(MPI_Pack(eigr+l,n,MPIU_SCALAR,ds->work,size,&off,PetscObjectComm((PetscObject)ds)));
429 : }
430 28 : PetscCallMPI(MPI_Bcast(ds->work,size,MPI_BYTE,0,PetscObjectComm((PetscObject)ds)));
431 14 : if (rank) {
432 7 : if (ds->compact) PetscCallMPI(MPI_Unpack(ds->work,size,&off,T,ld3,MPIU_REAL,PetscObjectComm((PetscObject)ds)));
433 0 : else PetscCallMPI(MPI_Unpack(ds->work,size,&off,A+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
434 7 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,D,ld_,MPIU_REAL,PetscObjectComm((PetscObject)ds)));
435 7 : if (ds->state>DS_STATE_RAW) {
436 7 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,U+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
437 7 : PetscCallMPI(MPI_Unpack(ds->work,size,&off,V+l*ld,ldn,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
438 : }
439 7 : if (eigr) PetscCallMPI(MPI_Unpack(ds->work,size,&off,eigr+l,n,MPIU_SCALAR,PetscObjectComm((PetscObject)ds)));
440 : }
441 14 : if (ds->compact) PetscCall(DSRestoreArrayReal(ds,DS_MAT_T,&T));
442 0 : else PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_A],&A));
443 14 : PetscCall(DSRestoreArrayReal(ds,DS_MAT_D,&D));
444 14 : if (ds->state>DS_STATE_RAW) {
445 14 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_U],&U));
446 14 : PetscCall(MatDenseRestoreArray(ds->omat[DS_MAT_V],&V));
447 : }
448 14 : PetscFunctionReturn(PETSC_SUCCESS);
449 : }
450 : #endif
451 :
452 230 : static PetscErrorCode DSMatGetSize_HSVD(DS ds,DSMatType t,PetscInt *rows,PetscInt *cols)
453 : {
454 230 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
455 :
456 230 : PetscFunctionBegin;
457 230 : PetscCheck(ctx->m,PetscObjectComm((PetscObject)ds),PETSC_ERR_ORDER,"You should set the number of columns with DSHSVDSetDimensions()");
458 230 : switch (t) {
459 2 : case DS_MAT_A:
460 2 : *rows = ds->n;
461 2 : *cols = ds->extrarow? ctx->m+1: ctx->m;
462 2 : break;
463 0 : case DS_MAT_T:
464 0 : *rows = ds->n;
465 0 : *cols = PetscDefined(USE_COMPLEX)? 2: 3;
466 0 : break;
467 70 : case DS_MAT_D:
468 70 : *rows = ds->n;
469 70 : *cols = 1;
470 70 : break;
471 79 : case DS_MAT_U:
472 79 : *rows = ds->state==DS_STATE_TRUNCATED? ds->t: ds->n;
473 79 : *cols = ds->n;
474 79 : break;
475 79 : case DS_MAT_V:
476 79 : *rows = ds->state==DS_STATE_TRUNCATED? ctx->t: ctx->m;
477 79 : *cols = ctx->m;
478 79 : break;
479 0 : default:
480 0 : SETERRQ(PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Invalid t parameter");
481 : }
482 230 : PetscFunctionReturn(PETSC_SUCCESS);
483 : }
484 :
485 85 : static PetscErrorCode DSHSVDSetDimensions_HSVD(DS ds,PetscInt m)
486 : {
487 85 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
488 :
489 85 : PetscFunctionBegin;
490 85 : DSCheckAlloc(ds,1);
491 85 : if (m==PETSC_DECIDE || m==PETSC_DEFAULT) {
492 0 : ctx->m = ds->ld;
493 : } else {
494 85 : PetscCheck(m>0 && m<=ds->ld,PetscObjectComm((PetscObject)ds),PETSC_ERR_ARG_OUTOFRANGE,"Illegal value of m. Must be between 1 and ld");
495 85 : ctx->m = m;
496 : }
497 85 : PetscFunctionReturn(PETSC_SUCCESS);
498 : }
499 :
500 : /*@
501 : DSHSVDSetDimensions - Sets the number of columns for a DSHSVD.
502 :
503 : Logically Collective
504 :
505 : Input Parameters:
506 : + ds - the direct solver context
507 : - m - the number of columns
508 :
509 : Notes:
510 : This call is complementary to DSSetDimensions(), to provide a dimension
511 : that is specific to this DS type.
512 :
513 : Level: intermediate
514 :
515 : .seealso: DSHSVDGetDimensions(), DSSetDimensions()
516 : @*/
517 85 : PetscErrorCode DSHSVDSetDimensions(DS ds,PetscInt m)
518 : {
519 85 : PetscFunctionBegin;
520 85 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
521 255 : PetscValidLogicalCollectiveInt(ds,m,2);
522 85 : PetscTryMethod(ds,"DSHSVDSetDimensions_C",(DS,PetscInt),(ds,m));
523 85 : PetscFunctionReturn(PETSC_SUCCESS);
524 : }
525 :
526 1 : static PetscErrorCode DSHSVDGetDimensions_HSVD(DS ds,PetscInt *m)
527 : {
528 1 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
529 :
530 1 : PetscFunctionBegin;
531 1 : *m = ctx->m;
532 1 : PetscFunctionReturn(PETSC_SUCCESS);
533 : }
534 :
535 : /*@
536 : DSHSVDGetDimensions - Returns the number of columns for a DSHSVD.
537 :
538 : Not Collective
539 :
540 : Input Parameter:
541 : . ds - the direct solver context
542 :
543 : Output Parameters:
544 : . m - the number of columns
545 :
546 : Level: intermediate
547 :
548 : .seealso: DSHSVDSetDimensions()
549 : @*/
550 1 : PetscErrorCode DSHSVDGetDimensions(DS ds,PetscInt *m)
551 : {
552 1 : PetscFunctionBegin;
553 1 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
554 1 : PetscAssertPointer(m,2);
555 1 : PetscUseMethod(ds,"DSHSVDGetDimensions_C",(DS,PetscInt*),(ds,m));
556 1 : PetscFunctionReturn(PETSC_SUCCESS);
557 : }
558 :
559 4 : static PetscErrorCode DSHSVDSetReorthogonalize_HSVD(DS ds,PetscBool reorth)
560 : {
561 4 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
562 :
563 4 : PetscFunctionBegin;
564 4 : ctx->reorth = reorth;
565 4 : PetscFunctionReturn(PETSC_SUCCESS);
566 : }
567 :
568 : /*@
569 : DSHSVDSetReorthogonalize - Sets the reorthogonalization of the left vectors in a DSHSVD.
570 :
571 : Logically Collective
572 :
573 : Input Parameters:
574 : + ds - the direct solver context
575 : - reorth - the reorthogonalization flag
576 :
577 : Options Database Key:
578 : . -ds_hsvd_reorthog <bool> - sets the reorthogonalization flag
579 :
580 : Note:
581 : The computed left vectors (U) should be orthogonal with respect to the signature (D).
582 : But it may be necessary to enforce this with a final reorthogonalization step (omitted
583 : by default).
584 :
585 : Level: intermediate
586 :
587 : .seealso: DSHSVDGetReorthogonalize()
588 : @*/
589 4 : PetscErrorCode DSHSVDSetReorthogonalize(DS ds,PetscBool reorth)
590 : {
591 4 : PetscFunctionBegin;
592 4 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
593 12 : PetscValidLogicalCollectiveBool(ds,reorth,2);
594 4 : PetscTryMethod(ds,"DSHSVDSetReorthogonalize_C",(DS,PetscBool),(ds,reorth));
595 4 : PetscFunctionReturn(PETSC_SUCCESS);
596 : }
597 :
598 4 : static PetscErrorCode DSHSVDGetReorthogonalize_HSVD(DS ds,PetscBool *reorth)
599 : {
600 4 : DS_HSVD *ctx = (DS_HSVD*)ds->data;
601 :
602 4 : PetscFunctionBegin;
603 4 : *reorth = ctx->reorth;
604 4 : PetscFunctionReturn(PETSC_SUCCESS);
605 : }
606 :
607 : /*@
608 : DSHSVDGetReorthogonalize - Returns the reorthogonalization flag of a DSHSVD.
609 :
610 : Not Collective
611 :
612 : Input Parameter:
613 : . ds - the direct solver context
614 :
615 : Output Parameters:
616 : . reorth - the reorthogonalization flag
617 :
618 : Level: intermediate
619 :
620 : .seealso: DSHSVDSetReorthogonalize()
621 : @*/
622 4 : PetscErrorCode DSHSVDGetReorthogonalize(DS ds,PetscBool *reorth)
623 : {
624 4 : PetscFunctionBegin;
625 4 : PetscValidHeaderSpecific(ds,DS_CLASSID,1);
626 4 : PetscAssertPointer(reorth,2);
627 4 : PetscUseMethod(ds,"DSHSVDGetReorthogonalize_C",(DS,PetscBool*),(ds,reorth));
628 4 : PetscFunctionReturn(PETSC_SUCCESS);
629 : }
630 :
631 16 : static PetscErrorCode DSSetFromOptions_HSVD(DS ds,PetscOptionItems *PetscOptionsObject)
632 : {
633 16 : PetscBool flg,reorth;
634 :
635 16 : PetscFunctionBegin;
636 16 : PetscOptionsHeadBegin(PetscOptionsObject,"DS HSVD Options");
637 :
638 16 : PetscCall(PetscOptionsBool("-ds_hsvd_reorthog","Reorthogonalize U vectors","DSHSVDSetReorthogonalize",PETSC_FALSE,&reorth,&flg));
639 16 : if (flg) PetscCall(DSHSVDSetReorthogonalize(ds,reorth));
640 :
641 16 : PetscOptionsHeadEnd();
642 16 : PetscFunctionReturn(PETSC_SUCCESS);
643 : }
644 :
645 17 : static PetscErrorCode DSDestroy_HSVD(DS ds)
646 : {
647 17 : PetscFunctionBegin;
648 17 : PetscCall(PetscFree(ds->data));
649 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDSetDimensions_C",NULL));
650 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDGetDimensions_C",NULL));
651 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDSetReorthogonalize_C",NULL));
652 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDGetReorthogonalize_C",NULL));
653 17 : PetscFunctionReturn(PETSC_SUCCESS);
654 : }
655 :
656 4 : static PetscErrorCode DSSetCompact_HSVD(DS ds,PetscBool comp)
657 : {
658 4 : PetscFunctionBegin;
659 4 : if (!comp) PetscCall(DSAllocateMat_Private(ds,DS_MAT_A));
660 4 : PetscFunctionReturn(PETSC_SUCCESS);
661 : }
662 :
663 : /*MC
664 : DSHSVD - Dense Hyperbolic Singular Value Decomposition.
665 :
666 : Level: beginner
667 :
668 : Notes:
669 : The problem is expressed as A = U*Sigma*V', where A is rectangular in
670 : general, with n rows and m columns. U is orthogonal with respect to a
671 : signature matrix, stored in D. V is orthogonal. Sigma is a diagonal
672 : matrix whose diagonal elements are the arguments of DSSolve(). After
673 : solve, A is overwritten with Sigma, D is overwritten with the new signature.
674 :
675 : The matrices of left and right singular vectors, U and V, have size n and m,
676 : respectively. The number of columns m must be specified via DSHSVDSetDimensions().
677 :
678 : If the DS object is in the intermediate state, A is assumed to be in upper
679 : bidiagonal form (possibly with an arrow) and is stored in compact format
680 : on matrix T. The compact storage is implemented for the square case
681 : only, m=n. The extra row should be interpreted in this case as an extra column.
682 :
683 : Used DS matrices:
684 : + DS_MAT_A - problem matrix (used only if compact=false)
685 : . DS_MAT_T - upper bidiagonal matrix
686 : . DS_MAT_D - diagonal matrix (signature)
687 : . DS_MAT_U - left singular vectors
688 : - DS_MAT_V - right singular vectors
689 :
690 : Implemented methods:
691 : . 0 - Cross product A'*Omega*A
692 :
693 : .seealso: DSCreate(), DSSetType(), DSType, DSHSVDSetDimensions()
694 : M*/
695 17 : SLEPC_EXTERN PetscErrorCode DSCreate_HSVD(DS ds)
696 : {
697 17 : DS_HSVD *ctx;
698 :
699 17 : PetscFunctionBegin;
700 17 : PetscCall(PetscNew(&ctx));
701 17 : ds->data = (void*)ctx;
702 :
703 17 : ds->ops->allocate = DSAllocate_HSVD;
704 17 : ds->ops->setfromoptions = DSSetFromOptions_HSVD;
705 17 : ds->ops->view = DSView_HSVD;
706 17 : ds->ops->vectors = DSVectors_HSVD;
707 17 : ds->ops->solve[0] = DSSolve_HSVD_CROSS;
708 17 : ds->ops->sort = DSSort_HSVD;
709 17 : ds->ops->truncate = DSTruncate_HSVD;
710 17 : ds->ops->update = DSUpdateExtraRow_HSVD;
711 17 : ds->ops->destroy = DSDestroy_HSVD;
712 17 : ds->ops->matgetsize = DSMatGetSize_HSVD;
713 : #if !defined(PETSC_HAVE_MPIUNI)
714 17 : ds->ops->synchronize = DSSynchronize_HSVD;
715 : #endif
716 17 : ds->ops->setcompact = DSSetCompact_HSVD;
717 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDSetDimensions_C",DSHSVDSetDimensions_HSVD));
718 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDGetDimensions_C",DSHSVDGetDimensions_HSVD));
719 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDSetReorthogonalize_C",DSHSVDSetReorthogonalize_HSVD));
720 17 : PetscCall(PetscObjectComposeFunction((PetscObject)ds,"DSHSVDGetReorthogonalize_C",DSHSVDGetReorthogonalize_HSVD));
721 17 : PetscFunctionReturn(PETSC_SUCCESS);
722 : }
|