Actual source code: lsqr.c
1: #define PETSCKSP_DLL
3: /* lourens.vanzanen@shell.com contributed the standard error estimates of the solution, Jul 25, 2006 */
4: /* Bas van't Hof contributed the preconditioned aspects Feb 10, 2010 */
6: #define SWAP(a,b,c) { c = a; a = b; b = c; }
8: #include private/kspimpl.h
9: #include ../src/ksp/ksp/impls/lsqr/lsqr.h
11: typedef struct {
12: PetscInt nwork_n,nwork_m;
13: Vec *vwork_m; /* work vectors of length m, where the system is size m x n */
14: Vec *vwork_n; /* work vectors of length n */
15: Vec se; /* Optional standard error vector */
16: PetscTruth se_flg; /* flag for -ksp_lsqr_set_standard_error */
17: PetscReal arnorm; /* Norm of the vector A.r */
18: PetscReal anorm; /* Frobenius norm of the matrix A */
19: PetscReal rhs_norm; /* Norm of the right hand side */
20: } KSP_LSQR;
26: static PetscErrorCode KSPSetUp_LSQR(KSP ksp)
27: {
29: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
30: PetscTruth nopreconditioner;
33: PetscTypeCompare((PetscObject)ksp->pc,PCNONE,&nopreconditioner);
34: if (ksp->pc_side == PC_SYMMETRIC){
35: SETERRQ(PETSC_ERR_SUP,"no symmetric preconditioning for KSPLSQR");
36: } else if (ksp->pc_side == PC_RIGHT){
37: SETERRQ(PETSC_ERR_SUP,"no right preconditioning for KSPLSQR");
38: }
39: /* nopreconditioner =PETSC_FALSE; */
41: lsqr->nwork_m = 2;
42: if (lsqr->vwork_m) {
43: VecDestroyVecs(lsqr->vwork_m,lsqr->nwork_m);
44: }
45: if (nopreconditioner) {
46: lsqr->nwork_n = 4;
47: } else {
48: lsqr->nwork_n = 5;
49: }
50: if (lsqr->vwork_n) {
51: VecDestroyVecs(lsqr->vwork_n,lsqr->nwork_n);
52: }
53: KSPGetVecs(ksp,lsqr->nwork_n,&lsqr->vwork_n,lsqr->nwork_m,&lsqr->vwork_m);
54: if (lsqr->se_flg && !lsqr->se){
55: /* lsqr->se is not set by user, get it from pmat */
56: Vec *se;
57: KSPGetVecs(ksp,1,&se,0,PETSC_NULL);
58: lsqr->se = *se;
59: PetscFree(se);
60: }
61: return(0);
62: }
66: static PetscErrorCode KSPSolve_LSQR(KSP ksp)
67: {
69: PetscInt i,size1,size2;
70: PetscScalar rho,rhobar,phi,phibar,theta,c,s,tmp,tau,alphac;
71: PetscReal beta,alpha,rnorm;
72: Vec X,B,V,V1,U,U1,TMP,W,W2,SE,Z = PETSC_NULL;
73: Mat Amat,Pmat;
74: MatStructure pflag;
75: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
76: PetscTruth diagonalscale,nopreconditioner;
77:
79: PCDiagonalScale(ksp->pc,&diagonalscale);
80: if (diagonalscale) SETERRQ1(PETSC_ERR_SUP,"Krylov method %s does not support diagonal scaling",((PetscObject)ksp)->type_name);
82: PCGetOperators(ksp->pc,&Amat,&Pmat,&pflag);
83: PetscTypeCompare((PetscObject)ksp->pc,PCNONE,&nopreconditioner);
85: /* nopreconditioner =PETSC_FALSE; */
86: /* Calculate norm of right hand side */
87: VecNorm(ksp->vec_rhs,NORM_2,&lsqr->rhs_norm);
89: /* Calculate norm of matrix*/
90: MatNorm( Amat, NORM_FROBENIUS, &lsqr->anorm);
92: /* vectors of length m, where system size is mxn */
93: B = ksp->vec_rhs;
94: U = lsqr->vwork_m[0];
95: U1 = lsqr->vwork_m[1];
97: /* vectors of length n */
98: X = ksp->vec_sol;
99: W = lsqr->vwork_n[0];
100: V = lsqr->vwork_n[1];
101: V1 = lsqr->vwork_n[2];
102: W2 = lsqr->vwork_n[3];
103: if (!nopreconditioner) {
104: Z = lsqr->vwork_n[4];
105: }
107: /* standard error vector */
108: SE = lsqr->se;
109: if (SE){
110: VecGetSize(SE,&size1);
111: VecGetSize(X ,&size2);
112: if (size1 != size2) SETERRQ2(PETSC_ERR_ARG_SIZ,"Standard error vector (size %d) does not match solution vector (size %d)",size1,size2);
113: VecSet(SE,0.0);
114: }
116: /* Compute initial residual, temporarily use work vector u */
117: if (!ksp->guess_zero) {
118: KSP_MatMult(ksp,Amat,X,U); /* u <- b - Ax */
119: VecAYPX(U,-1.0,B);
120: } else {
121: VecCopy(B,U); /* u <- b (x is 0) */
122: }
124: /* Test for nothing to do */
125: VecNorm(U,NORM_2,&rnorm);
126: PetscObjectTakeAccess(ksp);
127: ksp->its = 0;
128: ksp->rnorm = rnorm;
129: PetscObjectGrantAccess(ksp);
130: KSPLogResidualHistory(ksp,rnorm);
131: KSPMonitor(ksp,0,rnorm);
132: (*ksp->converged)(ksp,0,rnorm,&ksp->reason,ksp->cnvP);
133: if (ksp->reason) return(0);
135: VecCopy(B,U);
136: VecNorm(U,NORM_2,&beta);
137: VecScale(U,1.0/beta);
138: KSP_MatMultTranspose(ksp,Amat,U,V);
139: if (nopreconditioner) {
140: VecNorm(V,NORM_2,&alpha);
141: } else {
142: PCApply(ksp->pc,V,Z);
143: VecDot(V,Z,&alphac);
144: if (PetscRealPart(alphac) <= 0.0) {
145: ksp->reason = KSP_DIVERGED_BREAKDOWN;
146: return(0);
147: }
148: alpha = sqrt(PetscRealPart(alphac));
149: VecScale(Z,1.0/alpha);
150: }
151: VecScale(V,1.0/alpha);
153: if (nopreconditioner){
154: VecCopy(V,W);
155: } else {
156: VecCopy(Z,W);
157: }
158: VecSet(X,0.0);
160: lsqr->arnorm = alpha * beta;
161: phibar = beta;
162: rhobar = alpha;
163: tau = -beta;
164: i = 0;
165: do {
166: if (nopreconditioner) {
167: KSP_MatMult(ksp,Amat,V,U1);
168: } else {
169: KSP_MatMult(ksp,Amat,Z,U1);
170: }
171: VecAXPY(U1,-alpha,U);
172: VecNorm(U1,NORM_2,&beta);
173: if (beta == 0.0){
174: ksp->reason = KSP_DIVERGED_BREAKDOWN;
175: break;
176: }
177: VecScale(U1,1.0/beta);
179: KSP_MatMultTranspose(ksp,Amat,U1,V1);
180: VecAXPY(V1,-beta,V);
181: if (nopreconditioner) {
182: VecNorm(V1,NORM_2,&alpha);
183: } else {
184: PCApply(ksp->pc,V1,Z);
185: VecDot(V1,Z,&alphac);
186: if (PetscRealPart(alphac) <= 0.0) {
187: ksp->reason = KSP_DIVERGED_BREAKDOWN;
188: break;
189: }
190: alpha = sqrt(PetscRealPart(alphac));
191: VecScale(Z,1.0/alpha);
192: }
193: VecScale(V1,1.0/alpha);
194: rho = PetscSqrtScalar(rhobar*rhobar + beta*beta);
195: c = rhobar / rho;
196: s = beta / rho;
197: theta = s * alpha;
198: rhobar = - c * alpha;
199: phi = c * phibar;
200: phibar = s * phibar;
201: tau = s * phi;
203: VecAXPY(X,phi/rho,W); /* x <- x + (phi/rho) w */
205: if (SE) {
206: VecCopy(W,W2);
207: VecSquare(W2);
208: VecScale(W2,1.0/(rho*rho));
209: VecAXPY(SE, 1.0, W2); /* SE <- SE + (w^2/rho^2) */
210: }
211: if (nopreconditioner) {
212: VecAYPX(W,-theta/rho,V1); /* w <- v - (theta/rho) w */
213: } else {
214: VecAYPX(W,-theta/rho,Z); /* w <- z - (theta/rho) w */
215: }
217: lsqr->arnorm = alpha*PetscAbsScalar(tau);
218: rnorm = PetscRealPart(phibar);
220: PetscObjectTakeAccess(ksp);
221: ksp->its++;
222: ksp->rnorm = rnorm;
223: PetscObjectGrantAccess(ksp);
224: KSPLogResidualHistory(ksp,rnorm);
225: KSPMonitor(ksp,i+1,rnorm);
226: (*ksp->converged)(ksp,i+1,rnorm,&ksp->reason,ksp->cnvP);
227: if (ksp->reason) break;
228: SWAP(U1,U,TMP);
229: SWAP(V1,V,TMP);
231: i++;
232: } while (i<ksp->max_it);
233: if (i >= ksp->max_it && !ksp->reason) {
234: ksp->reason = KSP_DIVERGED_ITS;
235: }
237: /* Finish off the standard error estimates */
238: if (SE) {
239: tmp = 1.0;
240: MatGetSize(Amat,&size1,&size2);
241: if ( size1 > size2 ) tmp = size1 - size2;
242: tmp = rnorm / PetscSqrtScalar(tmp);
243: VecSqrt(SE);
244: VecScale(SE,tmp);
245: }
247: return(0);
248: }
253: PetscErrorCode KSPDestroy_LSQR(KSP ksp)
254: {
255: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
260: /* Free work vectors */
261: if (lsqr->vwork_n) {
262: VecDestroyVecs(lsqr->vwork_n,lsqr->nwork_n);
263: }
264: if (lsqr->vwork_m) {
265: VecDestroyVecs(lsqr->vwork_m,lsqr->nwork_m);
266: }
267: if (lsqr->se_flg && lsqr->se){
268: VecDestroy(lsqr->se);
269: }
270: PetscFree(ksp->data);
271: return(0);
272: }
276: PetscErrorCode KSPLSQRSetStandardErrorVec( KSP ksp, Vec se )
277: {
278: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
282: if (lsqr->se) {
283: VecDestroy(lsqr->se);
284: }
285: lsqr->se = se;
286: return(0);
287: }
291: PetscErrorCode KSPLSQRGetStandardErrorVec( KSP ksp,Vec *se )
292: {
293: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
296: *se = lsqr->se;
297: return(0);
298: }
302: PetscErrorCode KSPLSQRGetArnorm( KSP ksp,PetscReal *arnorm, PetscReal *rhs_norm , PetscReal *anorm)
303: {
304: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
307: *arnorm = lsqr->arnorm;
308: *anorm = lsqr->anorm;
309: *rhs_norm = lsqr->rhs_norm;
310: return(0);
311: }
315: PetscErrorCode KSPSetFromOptions_LSQR(KSP ksp)
316: {
318: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
321: PetscOptionsHead("KSP LSQR Options");
322: PetscOptionsName("-ksp_LSQR_set_standard_error","Set Standard Error Estimates of Solution","KSPLSQRSetStandardErrorVec",&lsqr->se_flg);
323: PetscOptionsTail();
324: return(0);
325: }
329: PetscErrorCode KSPView_LSQR(KSP ksp,PetscViewer viewer)
330: {
331: KSP_LSQR *lsqr = (KSP_LSQR*)ksp->data;
335: if (lsqr->se) {
336: PetscReal rnorm;
337: KSPLSQRGetStandardErrorVec(ksp,&lsqr->se);
338: VecNorm(lsqr->se,NORM_2,&rnorm);
339: PetscPrintf(PETSC_COMM_WORLD," Norm of Standard Error %A, Iterations %D\n",rnorm,ksp->its);
340: }
341: return(0);
342: }
344: /*MC
345: KSPLSQR - This implements LSQR
347: Options Database Keys:
348: . see KSPSolve()
350: Level: beginner
352: Notes: The original unpreconditioned algorithm can be found in Paige and Saunders, ACM Transactions on Mathematical Software, Vol 8, pp 43-71, 1982.
353: In exact arithmetic the LSQR method (with no preconditioning) is identical to the KSPCG algorithm applied to the normal equations.
354: The preconditioned varient was implemented by Bas van't Hof and is essentially a left preconditioning for the Normal Equations.
355: This varient, when applied with no preconditioning is identical to the original algorithm in exact arithematic; however, in practice, with no preconditioning
356: due to inexact arithematic, it can converge differently. Hence when no preconditioner is used (PCType PCNONE) it automatically reverts to the original algorithm.
358: With the PETSc built-in preconditioners, such as ICC, one should call KSPSetOperators(ksp,A,A'*A,...) since the preconditioner needs to work
359: for the normal equations A'*A.
361: Developer Notes: How is this related to the KSPCGNE implementation? One difference is that KSPCGNE applies the preconditioner transpose times the preconditioner,
362: so one does not need to pass A'*A as the third argument to KSPSetOperators().
364: .seealso: KSPCreate(), KSPSetType(), KSPType (for list of available types), KSP
366: M*/
370: PetscErrorCode KSPCreate_LSQR(KSP ksp)
371: {
372: KSP_LSQR *lsqr;
376: PetscNewLog(ksp,KSP_LSQR,&lsqr);
377: lsqr->se = PETSC_NULL;
378: lsqr->se_flg = PETSC_FALSE;
379: lsqr->arnorm = 0.0;
380: ksp->data = (void*)lsqr;
381: ksp->pc_side = PC_LEFT;
382: ksp->ops->setup = KSPSetUp_LSQR;
383: ksp->ops->solve = KSPSolve_LSQR;
384: ksp->ops->destroy = KSPDestroy_LSQR;
385: ksp->ops->buildsolution = KSPDefaultBuildSolution;
386: ksp->ops->buildresidual = KSPDefaultBuildResidual;
387: ksp->ops->setfromoptions = KSPSetFromOptions_LSQR;
388: ksp->ops->view = KSPView_LSQR;
389: return(0);
390: }
395: PetscErrorCode VecSquare(Vec v)
396: {
398: PetscScalar *x;
399: PetscInt i, n;
402: VecGetLocalSize(v, &n);
403: VecGetArray(v, &x);
404: for(i = 0; i < n; i++) {
405: x[i] *= x[i];
406: }
407: VecRestoreArray(v, &x);
408: return(0);
409: }