xref: /petsc/src/snes/impls/qn/qn.c (revision aeb49b86d700c2d4a06d6f7a22069c109820b654)
1 #include <petsc/private/snesimpl.h> /*I "petscsnes.h" I*/
2 
3 #define H(i,j)  qn->dXdFmat[i*qn->m + j]
4 
5 const char *const SNESQNScaleTypes[] =        {"DEFAULT","NONE","SHANNO","LINESEARCH","JACOBIAN","SNESQNScaleType","SNES_QN_SCALING_",0};
6 const char *const SNESQNRestartTypes[] =      {"DEFAULT","NONE","POWELL","PERIODIC","SNESQNRestartType","SNES_QN_RESTART_",0};
7 const char *const SNESQNTypes[] =             {"LBFGS","BROYDEN","BADBROYDEN","SNESQNType","SNES_QN_",0};
8 
9 typedef struct {
10   Vec               *U;                   /* Stored past states (vary from method to method) */
11   Vec               *V;                   /* Stored past states (vary from method to method) */
12   PetscInt          m;                    /* The number of kept previous steps */
13   PetscReal         *lambda;              /* The line search history of the method */
14   PetscReal         *norm;                /* norms of the steps */
15   PetscScalar       *alpha, *beta;
16   PetscScalar       *dXtdF, *dFtdX, *YtdX;
17   PetscBool         singlereduction;      /* Aggregated reduction implementation */
18   PetscScalar       *dXdFmat;             /* A matrix of values for dX_i dot dF_j */
19   PetscViewer       monitor;
20   PetscReal         powell_gamma;         /* Powell angle restart condition */
21   PetscReal         powell_downhill;      /* Powell descent restart condition */
22   PetscReal         scaling;              /* scaling of H0 */
23   SNESQNType        type;                 /* the type of quasi-newton method used */
24   SNESQNScaleType   scale_type;           /* the type of scaling used */
25   SNESQNRestartType restart_type;         /* determine the frequency and type of restart conditions */
26 } SNES_QN;
27 
28 #undef __FUNCT__
29 #define __FUNCT__ "SNESQNApply_Broyden"
30 PetscErrorCode SNESQNApply_Broyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D)
31 {
32   PetscErrorCode     ierr;
33   SNES_QN            *qn = (SNES_QN*)snes->data;
34   Vec                W   = snes->work[3];
35   Vec                *U  = qn->U;
36   PetscInt           m = qn->m;
37   PetscInt           k,i,j,lits,l = m;
38   PetscReal          unorm,a,b;
39   PetscReal          *lambda=qn->lambda;
40   PetscScalar        gdot;
41   PetscReal          udot;
42 
43   PetscFunctionBegin;
44   if (it < m) l = it;
45   if (it > 0) {
46     k = (it-1)%l;
47     ierr = SNESLineSearchGetLambda(snes->linesearch,&lambda[k]);CHKERRQ(ierr);
48     ierr = VecCopy(Xold,U[k]);CHKERRQ(ierr);
49     ierr = VecAXPY(U[k],-1.0,X);CHKERRQ(ierr);
50     if (qn->monitor) {
51       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
52       ierr = PetscViewerASCIIPrintf(qn->monitor, "scaling vector %d of %d by lambda: %14.12e \n",k,l,lambda[k]);CHKERRQ(ierr);
53       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
54     }
55   }
56   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
57     ierr = KSPSolve(snes->ksp,D,W);CHKERRQ(ierr);
58     SNESCheckKSPSolve(snes);
59     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
60     snes->linear_its += lits;
61     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
62   } else {
63     ierr = VecCopy(D,Y);CHKERRQ(ierr);
64     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
65   }
66 
67   /* inward recursion starting at the first update and working forward */
68   for (i = 0; i < l-1; i++) {
69     j = (it+i-l)%l;
70     k = (it+i-l+1)%l;
71     ierr = VecNorm(U[j],NORM_2,&unorm);CHKERRQ(ierr);
72     ierr = VecDot(U[j],Y,&gdot);CHKERRQ(ierr);
73     unorm *= unorm;
74     udot = PetscRealPart(gdot);
75     a = (lambda[j]/lambda[k]);
76     b = -(1.-lambda[j]);
77     a *= udot/unorm;
78     b *= udot/unorm;
79     ierr = VecAXPBYPCZ(Y,a,b,1.,U[k],U[j]);CHKERRQ(ierr);
80 
81     if (qn->monitor) {
82       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
83       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d and %d, gdot: %14.12e\n",k,j,PetscRealPart(gdot));CHKERRQ(ierr);
84       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
85     }
86   }
87   if (l > 0) {
88     k = (it-1)%l;
89     ierr = VecDot(U[k],Y,&gdot);CHKERRQ(ierr);
90     ierr = VecNorm(U[k],NORM_2,&unorm);CHKERRQ(ierr);
91     unorm *= unorm;
92     udot = PetscRealPart(gdot);
93     a = unorm/(unorm-lambda[k]*udot);
94     b = -(1.-lambda[k])*udot/(unorm-lambda[k]*udot);
95     if (qn->monitor) {
96       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
97       ierr = PetscViewerASCIIPrintf(qn->monitor, "using vector %d: a: %14.12e b: %14.12e \n",k,a,b);CHKERRQ(ierr);
98       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
99     }
100     ierr = VecAXPBY(Y,b,a,U[k]);CHKERRQ(ierr);
101   }
102   l = m;
103   if (it+1<m)l=it+1;
104   k = it%l;
105   if (qn->monitor) {
106     ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
107     ierr = PetscViewerASCIIPrintf(qn->monitor, "setting vector %d of %d\n",k,l);CHKERRQ(ierr);
108     ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
109   }
110   PetscFunctionReturn(0);
111 }
112 
113 #undef __FUNCT__
114 #define __FUNCT__ "SNESQNApply_BadBroyden"
115 PetscErrorCode SNESQNApply_BadBroyden(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
116 {
117   PetscErrorCode ierr;
118   SNES_QN        *qn = (SNES_QN*)snes->data;
119   Vec            W   = snes->work[3];
120   Vec            *U  = qn->U;
121   Vec            *T  = qn->V;
122 
123   /* ksp thing for Jacobian scaling */
124   PetscInt           h,k,j,i,lits;
125   PetscInt           m = qn->m;
126   PetscScalar        gdot,udot;
127   PetscInt           l = m;
128 
129   PetscFunctionBegin;
130   if (it < m) l = it;
131   ierr = VecCopy(D,Y);CHKERRQ(ierr);
132   if (l > 0) {
133     k    = (it-1)%l;
134     ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->lambda[k]);CHKERRQ(ierr);
135     ierr = VecCopy(Dold,U[k]);CHKERRQ(ierr);
136     ierr = VecAXPY(U[k],-1.0,D);CHKERRQ(ierr);
137     ierr = VecCopy(Xold,T[k]);CHKERRQ(ierr);
138     ierr = VecAXPY(T[k],-1.0,X);CHKERRQ(ierr);
139   }
140 
141   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
142     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
143     SNESCheckKSPSolve(snes);
144     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
145     snes->linear_its += lits;
146     ierr              = VecCopy(W,Y);CHKERRQ(ierr);
147   } else {
148     ierr = VecScale(Y,qn->scaling);CHKERRQ(ierr);
149   }
150 
151   /* inward recursion starting at the first update and working forward */
152   if (l > 0) {
153     for (i = 0; i < l-1; i++) {
154       j    = (it+i-l)%l;
155       k    = (it+i-l+1)%l;
156       h    = (it-1)%l;
157       ierr = VecDotBegin(U[j],U[h],&gdot);CHKERRQ(ierr);
158       ierr = VecDotBegin(U[j],U[j],&udot);CHKERRQ(ierr);
159       ierr = VecDotEnd(U[j],U[h],&gdot);CHKERRQ(ierr);
160       ierr = VecDotEnd(U[j],U[j],&udot);CHKERRQ(ierr);
161       ierr = VecAXPY(Y,PetscRealPart(gdot)/PetscRealPart(udot),T[k]);CHKERRQ(ierr);
162       ierr = VecAXPY(Y,-(1.-qn->lambda[k])*PetscRealPart(gdot)/PetscRealPart(udot),T[j]);CHKERRQ(ierr);
163       if (qn->monitor) {
164         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
165         ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d gdot: %14.12e\n", it, k, PetscRealPart(gdot));CHKERRQ(ierr);
166         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
167       }
168     }
169   }
170   PetscFunctionReturn(0);
171 }
172 
173 #undef __FUNCT__
174 #define __FUNCT__ "SNESQNApply_LBFGS"
175 PetscErrorCode SNESQNApply_LBFGS(SNES snes,PetscInt it,Vec Y,Vec X,Vec Xold,Vec D,Vec Dold)
176 {
177   PetscErrorCode ierr;
178   SNES_QN        *qn    = (SNES_QN*)snes->data;
179   Vec            W      = snes->work[3];
180   Vec            *dX    = qn->U;
181   Vec            *dF    = qn->V;
182   PetscScalar    *alpha = qn->alpha;
183   PetscScalar    *beta  = qn->beta;
184   PetscScalar    *dXtdF = qn->dXtdF;
185   PetscScalar    *dFtdX = qn->dFtdX;
186   PetscScalar    *YtdX  = qn->YtdX;
187 
188   /* ksp thing for Jacobian scaling */
189   PetscInt           k,i,j,g,lits;
190   PetscInt           m = qn->m;
191   PetscScalar        t;
192   PetscInt           l = m;
193 
194   PetscFunctionBegin;
195   if (it < m) l = it;
196   ierr = VecCopy(D,Y);CHKERRQ(ierr);
197   if (it > 0) {
198     k    = (it - 1) % l;
199     ierr = VecCopy(D,dF[k]);CHKERRQ(ierr);
200     ierr = VecAXPY(dF[k], -1.0, Dold);CHKERRQ(ierr);
201     ierr = VecCopy(X, dX[k]);CHKERRQ(ierr);
202     ierr = VecAXPY(dX[k], -1.0, Xold);CHKERRQ(ierr);
203     if (qn->singlereduction) {
204       ierr = VecMDotBegin(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
205       ierr = VecMDotBegin(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
206       ierr = VecMDotBegin(Y,l,dX,YtdX);CHKERRQ(ierr);
207       ierr = VecMDotEnd(dF[k],l,dX,dXtdF);CHKERRQ(ierr);
208       ierr = VecMDotEnd(dX[k],l,dF,dFtdX);CHKERRQ(ierr);
209       ierr = VecMDotEnd(Y,l,dX,YtdX);CHKERRQ(ierr);
210       for (j = 0; j < l; j++) {
211         H(k, j) = dFtdX[j];
212         H(j, k) = dXtdF[j];
213       }
214       /* copy back over to make the computation of alpha and beta easier */
215       for (j = 0; j < l; j++) dXtdF[j] = H(j, j);
216     } else {
217       ierr = VecDot(dX[k], dF[k], &dXtdF[k]);CHKERRQ(ierr);
218     }
219     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
220       ierr = SNESLineSearchGetLambda(snes->linesearch,&qn->scaling);CHKERRQ(ierr);
221     }
222   }
223 
224   /* outward recursion starting at iteration k's update and working back */
225   for (i=0; i<l; i++) {
226     k = (it-i-1)%l;
227     if (qn->singlereduction) {
228       /* construct t = dX[k] dot Y as Y_0 dot dX[k] + sum(-alpha[j]dX[k]dF[j]) */
229       t = YtdX[k];
230       for (j=0; j<i; j++) {
231         g  = (it-j-1)%l;
232         t -= alpha[g]*H(k, g);
233       }
234       alpha[k] = t/H(k,k);
235     } else {
236       ierr     = VecDot(dX[k],Y,&t);CHKERRQ(ierr);
237       alpha[k] = t/dXtdF[k];
238     }
239     if (qn->monitor) {
240       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
241       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha:        %14.12e\n", it, k, PetscRealPart(alpha[k]));CHKERRQ(ierr);
242       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
243     }
244     ierr = VecAXPY(Y,-alpha[k],dF[k]);CHKERRQ(ierr);
245   }
246 
247   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
248     ierr = KSPSolve(snes->ksp,Y,W);CHKERRQ(ierr);
249     SNESCheckKSPSolve(snes);
250     ierr              = KSPGetIterationNumber(snes->ksp,&lits);CHKERRQ(ierr);
251     snes->linear_its += lits;
252     ierr              = VecCopy(W, Y);CHKERRQ(ierr);
253   } else {
254     ierr = VecScale(Y, qn->scaling);CHKERRQ(ierr);
255   }
256   if (qn->singlereduction) {
257     ierr = VecMDot(Y,l,dF,YtdX);CHKERRQ(ierr);
258   }
259   /* inward recursion starting at the first update and working forward */
260   for (i = 0; i < l; i++) {
261     k = (it + i - l) % l;
262     if (qn->singlereduction) {
263       t = YtdX[k];
264       for (j = 0; j < i; j++) {
265         g  = (it + j - l) % l;
266         t += (alpha[g] - beta[g])*H(g, k);
267       }
268       beta[k] = t / H(k, k);
269     } else {
270       ierr    = VecDot(dF[k], Y, &t);CHKERRQ(ierr);
271       beta[k] = t / dXtdF[k];
272     }
273     ierr = VecAXPY(Y, (alpha[k] - beta[k]), dX[k]);CHKERRQ(ierr);
274     if (qn->monitor) {
275       ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
276       ierr = PetscViewerASCIIPrintf(qn->monitor, "it: %d k: %d alpha - beta: %14.12e\n", it, k, PetscRealPart(alpha[k] - beta[k]));CHKERRQ(ierr);
277       ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
278     }
279   }
280   PetscFunctionReturn(0);
281 }
282 
283 #undef __FUNCT__
284 #define __FUNCT__ "SNESSolve_QN"
285 static PetscErrorCode SNESSolve_QN(SNES snes)
286 {
287   PetscErrorCode       ierr;
288   SNES_QN              *qn = (SNES_QN*) snes->data;
289   Vec                  X,Xold;
290   Vec                  F,W;
291   Vec                  Y,D,Dold;
292   PetscInt             i, i_r;
293   PetscReal            fnorm,xnorm,ynorm,gnorm;
294   SNESLineSearchReason lssucceed;
295   PetscBool            powell,periodic;
296   PetscScalar          DolddotD,DolddotDold;
297   SNESConvergedReason  reason;
298 
299   /* basically just a regular newton's method except for the application of the Jacobian */
300 
301   PetscFunctionBegin;
302 
303   if (snes->xl || snes->xu || snes->ops->computevariablebounds) {
304     SETERRQ1(PetscObjectComm((PetscObject)snes),PETSC_ERR_ARG_WRONGSTATE, "SNES solver %s does not support bounds", ((PetscObject)snes)->type_name);
305   }
306 
307   ierr = PetscCitationsRegister(SNESCitation,&SNEScite);CHKERRQ(ierr);
308   F    = snes->vec_func;                /* residual vector */
309   Y    = snes->vec_sol_update;          /* search direction generated by J^-1D*/
310   W    = snes->work[3];
311   X    = snes->vec_sol;                 /* solution vector */
312   Xold = snes->work[0];
313 
314   /* directions generated by the preconditioned problem with F_pre = F or x - M(x, b) */
315   D    = snes->work[1];
316   Dold = snes->work[2];
317 
318   snes->reason = SNES_CONVERGED_ITERATING;
319 
320   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
321   snes->iter = 0;
322   snes->norm = 0.;
323   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
324 
325   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_PRECONDITIONED) {
326     ierr = SNESApplyNPC(snes,X,NULL,F);CHKERRQ(ierr);
327     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
328     if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
329       snes->reason = SNES_DIVERGED_INNER;
330       PetscFunctionReturn(0);
331     }
332     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
333   } else {
334     if (!snes->vec_func_init_set) {
335       ierr = SNESComputeFunction(snes,X,F);CHKERRQ(ierr);
336     } else snes->vec_func_init_set = PETSC_FALSE;
337 
338     ierr = VecNorm(F,NORM_2,&fnorm);CHKERRQ(ierr);
339     SNESCheckFunctionNorm(snes,fnorm);
340   }
341   if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
342       ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr);
343       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
344       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
345         snes->reason = SNES_DIVERGED_INNER;
346         PetscFunctionReturn(0);
347       }
348   } else {
349     ierr = VecCopy(F,D);CHKERRQ(ierr);
350   }
351 
352   ierr       = PetscObjectSAWsTakeAccess((PetscObject)snes);CHKERRQ(ierr);
353   snes->norm = fnorm;
354   ierr       = PetscObjectSAWsGrantAccess((PetscObject)snes);CHKERRQ(ierr);
355   ierr       = SNESLogConvergenceHistory(snes,fnorm,0);CHKERRQ(ierr);
356   ierr       = SNESMonitor(snes,0,fnorm);CHKERRQ(ierr);
357 
358   /* test convergence */
359   ierr = (*snes->ops->converged)(snes,0,0.0,0.0,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
360   if (snes->reason) PetscFunctionReturn(0);
361 
362   if (snes->pc && snes->pcside == PC_RIGHT) {
363     ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
364     ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
365     ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
366     ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
367     if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
368       snes->reason = SNES_DIVERGED_INNER;
369       PetscFunctionReturn(0);
370     }
371     ierr = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
372     ierr = VecCopy(F,D);CHKERRQ(ierr);
373   }
374 
375   /* scale the initial update */
376   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
377     ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
378     ierr = KSPSetOperators(snes->ksp,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
379   }
380 
381   for (i = 0, i_r = 0; i < snes->max_its; i++, i_r++) {
382     if (qn->scale_type == SNES_QN_SCALE_SHANNO && i_r > 0) {
383       PetscScalar ff,xf;
384       ierr = VecCopy(Dold,Y);CHKERRQ(ierr);
385       ierr = VecCopy(Xold,W);CHKERRQ(ierr);
386       ierr = VecAXPY(Y,-1.0,D);CHKERRQ(ierr);
387       ierr = VecAXPY(W,-1.0,X);CHKERRQ(ierr);
388       ierr = VecDotBegin(Y,Y,&ff);CHKERRQ(ierr);
389       ierr = VecDotBegin(W,Y,&xf);CHKERRQ(ierr);
390       ierr = VecDotEnd(Y,Y,&ff);CHKERRQ(ierr);
391       ierr = VecDotEnd(W,Y,&xf);CHKERRQ(ierr);
392       qn->scaling = PetscRealPart(xf)/PetscRealPart(ff);
393     }
394     switch (qn->type) {
395     case SNES_QN_BADBROYDEN:
396       ierr = SNESQNApply_BadBroyden(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
397       break;
398     case SNES_QN_BROYDEN:
399       ierr = SNESQNApply_Broyden(snes,i_r,Y,X,Xold,D);CHKERRQ(ierr);
400       break;
401     case SNES_QN_LBFGS:
402       SNESQNApply_LBFGS(snes,i_r,Y,X,Xold,D,Dold);CHKERRQ(ierr);
403       break;
404     }
405     /* line search for lambda */
406     ynorm = 1; gnorm = fnorm;
407     ierr  = VecCopy(D, Dold);CHKERRQ(ierr);
408     ierr  = VecCopy(X, Xold);CHKERRQ(ierr);
409     ierr  = SNESLineSearchApply(snes->linesearch, X, F, &fnorm, Y);CHKERRQ(ierr);
410     if (snes->reason == SNES_DIVERGED_FUNCTION_COUNT) break;
411     ierr = SNESLineSearchGetReason(snes->linesearch, &lssucceed);CHKERRQ(ierr);
412     ierr = SNESLineSearchGetNorms(snes->linesearch, &xnorm, &fnorm, &ynorm);CHKERRQ(ierr);
413     if (lssucceed) {
414       if (++snes->numFailures >= snes->maxFailures) {
415         snes->reason = SNES_DIVERGED_LINE_SEARCH;
416         break;
417       }
418     }
419     if (qn->scale_type == SNES_QN_SCALE_LINESEARCH) {
420       ierr = SNESLineSearchGetLambda(snes->linesearch, &qn->scaling);CHKERRQ(ierr);
421     }
422 
423     /* convergence monitoring */
424     ierr = PetscInfo4(snes,"fnorm=%18.16e, gnorm=%18.16e, ynorm=%18.16e, lssucceed=%d\n",(double)fnorm,(double)gnorm,(double)ynorm,(int)lssucceed);CHKERRQ(ierr);
425 
426     if (snes->pc && snes->pcside == PC_RIGHT) {
427       ierr = PetscLogEventBegin(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
428       ierr = SNESSolve(snes->pc,snes->vec_rhs,X);CHKERRQ(ierr);
429       ierr = PetscLogEventEnd(SNES_NPCSolve,snes->pc,X,0,0);CHKERRQ(ierr);
430       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
431       if (reason < 0 && reason != SNES_DIVERGED_MAX_IT) {
432         snes->reason = SNES_DIVERGED_INNER;
433         PetscFunctionReturn(0);
434       }
435       ierr = SNESGetNPCFunction(snes,F,&fnorm);CHKERRQ(ierr);
436     }
437 
438     ierr = SNESSetIterationNumber(snes, i+1);CHKERRQ(ierr);
439     snes->norm = fnorm;
440 
441     ierr = SNESLogConvergenceHistory(snes,snes->norm,snes->iter);CHKERRQ(ierr);
442     ierr = SNESMonitor(snes,snes->iter,snes->norm);CHKERRQ(ierr);
443     /* set parameter for default relative tolerance convergence test */
444     ierr = (*snes->ops->converged)(snes,snes->iter,xnorm,ynorm,fnorm,&snes->reason,snes->cnvP);CHKERRQ(ierr);
445     if (snes->reason) PetscFunctionReturn(0);
446     if (snes->pc && snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_UNPRECONDITIONED) {
447       ierr = SNESApplyNPC(snes,X,F,D);CHKERRQ(ierr);
448       ierr = SNESGetConvergedReason(snes->pc,&reason);CHKERRQ(ierr);
449       if (reason < 0  && reason != SNES_DIVERGED_MAX_IT) {
450         snes->reason = SNES_DIVERGED_INNER;
451         PetscFunctionReturn(0);
452       }
453     } else {
454       ierr = VecCopy(F, D);CHKERRQ(ierr);
455     }
456     powell = PETSC_FALSE;
457     if (qn->restart_type == SNES_QN_RESTART_POWELL) {
458       /* check restart by Powell's Criterion: |F^T H_0 Fold| > 0.2 * |Fold^T H_0 Fold| */
459       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
460         ierr = MatMult(snes->jacobian_pre,Dold,W);CHKERRQ(ierr);
461       } else {
462         ierr = VecCopy(Dold,W);CHKERRQ(ierr);
463       }
464       ierr = VecDotBegin(W, Dold, &DolddotDold);CHKERRQ(ierr);
465       ierr = VecDotBegin(W, D, &DolddotD);CHKERRQ(ierr);
466       ierr = VecDotEnd(W, Dold, &DolddotDold);CHKERRQ(ierr);
467       ierr = VecDotEnd(W, D, &DolddotD);CHKERRQ(ierr);
468       if (PetscAbs(PetscRealPart(DolddotD)) > qn->powell_gamma*PetscAbs(PetscRealPart(DolddotDold))) powell = PETSC_TRUE;
469     }
470     periodic = PETSC_FALSE;
471     if (qn->restart_type == SNES_QN_RESTART_PERIODIC) {
472       if (i_r>qn->m-1) periodic = PETSC_TRUE;
473     }
474     /* restart if either powell or periodic restart is satisfied. */
475     if (powell || periodic) {
476       if (qn->monitor) {
477         ierr = PetscViewerASCIIAddTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
478         ierr = PetscViewerASCIIPrintf(qn->monitor, "restart! |%14.12e| > %4.2f*|%14.12e| or i_r = %d\n", PetscRealPart(DolddotD), qn->powell_gamma, PetscRealPart(DolddotDold), i_r);CHKERRQ(ierr);
479         ierr = PetscViewerASCIISubtractTab(qn->monitor,((PetscObject)snes)->tablevel+2);CHKERRQ(ierr);
480       }
481       i_r = -1;
482       /* general purpose update */
483       if (snes->ops->update) {
484         ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
485       }
486       if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
487         ierr = SNESComputeJacobian(snes,X,snes->jacobian,snes->jacobian_pre);CHKERRQ(ierr);
488       }
489     }
490     /* general purpose update */
491     if (snes->ops->update) {
492       ierr = (*snes->ops->update)(snes, snes->iter);CHKERRQ(ierr);
493     }
494   }
495   if (i == snes->max_its) {
496     ierr = PetscInfo1(snes, "Maximum number of iterations has been reached: %D\n", snes->max_its);CHKERRQ(ierr);
497     if (!snes->reason) snes->reason = SNES_DIVERGED_MAX_IT;
498   }
499   PetscFunctionReturn(0);
500 }
501 
502 #undef __FUNCT__
503 #define __FUNCT__ "SNESSetUp_QN"
504 static PetscErrorCode SNESSetUp_QN(SNES snes)
505 {
506   SNES_QN        *qn = (SNES_QN*)snes->data;
507   PetscErrorCode ierr;
508 
509   PetscFunctionBegin;
510   ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->U);CHKERRQ(ierr);
511   if (qn->type != SNES_QN_BROYDEN) ierr = VecDuplicateVecs(snes->vec_sol, qn->m, &qn->V);CHKERRQ(ierr);
512   ierr = PetscMalloc4(qn->m,&qn->alpha,qn->m,&qn->beta,qn->m,&qn->dXtdF,qn->m,&qn->lambda);CHKERRQ(ierr);
513 
514   if (qn->singlereduction) {
515     ierr = PetscMalloc3(qn->m*qn->m,&qn->dXdFmat,qn->m,&qn->dFtdX,qn->m,&qn->YtdX);CHKERRQ(ierr);
516   }
517   ierr = SNESSetWorkVecs(snes,4);CHKERRQ(ierr);
518   /* set method defaults */
519   if (qn->scale_type == SNES_QN_SCALE_DEFAULT) {
520     if (qn->type == SNES_QN_BADBROYDEN) {
521       qn->scale_type = SNES_QN_SCALE_NONE;
522     } else {
523       qn->scale_type = SNES_QN_SCALE_SHANNO;
524     }
525   }
526   if (qn->restart_type == SNES_QN_RESTART_DEFAULT) {
527     if (qn->type == SNES_QN_LBFGS) {
528       qn->restart_type = SNES_QN_RESTART_POWELL;
529     } else {
530       qn->restart_type = SNES_QN_RESTART_PERIODIC;
531     }
532   }
533 
534   if (qn->scale_type == SNES_QN_SCALE_JACOBIAN) {
535     ierr = SNESSetUpMatrices(snes);CHKERRQ(ierr);
536   }
537   if (snes->pcside == PC_LEFT && snes->functype == SNES_FUNCTION_DEFAULT) {snes->functype = SNES_FUNCTION_UNPRECONDITIONED;}
538   PetscFunctionReturn(0);
539 }
540 
541 #undef __FUNCT__
542 #define __FUNCT__ "SNESReset_QN"
543 static PetscErrorCode SNESReset_QN(SNES snes)
544 {
545   PetscErrorCode ierr;
546   SNES_QN        *qn;
547 
548   PetscFunctionBegin;
549   if (snes->data) {
550     qn = (SNES_QN*)snes->data;
551     if (qn->U) {
552       ierr = VecDestroyVecs(qn->m, &qn->U);CHKERRQ(ierr);
553     }
554     if (qn->V) {
555       ierr = VecDestroyVecs(qn->m, &qn->V);CHKERRQ(ierr);
556     }
557     if (qn->singlereduction) {
558       ierr = PetscFree3(qn->dXdFmat, qn->dFtdX, qn->YtdX);CHKERRQ(ierr);
559     }
560     ierr = PetscFree4(qn->alpha,qn->beta,qn->dXtdF,qn->lambda);CHKERRQ(ierr);
561   }
562   PetscFunctionReturn(0);
563 }
564 
565 #undef __FUNCT__
566 #define __FUNCT__ "SNESDestroy_QN"
567 static PetscErrorCode SNESDestroy_QN(SNES snes)
568 {
569   PetscErrorCode ierr;
570 
571   PetscFunctionBegin;
572   ierr = SNESReset_QN(snes);CHKERRQ(ierr);
573   ierr = PetscFree(snes->data);CHKERRQ(ierr);
574   ierr = PetscObjectComposeFunction((PetscObject)snes,"",NULL);CHKERRQ(ierr);
575   PetscFunctionReturn(0);
576 }
577 
578 #undef __FUNCT__
579 #define __FUNCT__ "SNESSetFromOptions_QN"
580 static PetscErrorCode SNESSetFromOptions_QN(PetscOptions *PetscOptionsObject,SNES snes)
581 {
582 
583   PetscErrorCode    ierr;
584   SNES_QN           *qn    = (SNES_QN*)snes->data;
585   PetscBool         monflg = PETSC_FALSE,flg;
586   SNESLineSearch    linesearch;
587   SNESQNRestartType rtype = qn->restart_type;
588   SNESQNScaleType   stype = qn->scale_type;
589   SNESQNType        qtype = qn->type;
590 
591   PetscFunctionBegin;
592   ierr = PetscOptionsHead(PetscOptionsObject,"SNES QN options");CHKERRQ(ierr);
593   ierr = PetscOptionsInt("-snes_qn_m","Number of past states saved for L-BFGS methods","SNESQN",qn->m,&qn->m,NULL);CHKERRQ(ierr);
594   ierr = PetscOptionsReal("-snes_qn_powell_gamma","Powell angle tolerance",          "SNESQN", qn->powell_gamma, &qn->powell_gamma, NULL);CHKERRQ(ierr);
595   ierr = PetscOptionsReal("-snes_qn_powell_downhill","Powell descent tolerance",        "SNESQN", qn->powell_downhill, &qn->powell_downhill, NULL);CHKERRQ(ierr);
596   ierr = PetscOptionsBool("-snes_qn_monitor",         "Monitor for the QN methods",      "SNESQN", monflg, &monflg, NULL);CHKERRQ(ierr);
597   ierr = PetscOptionsBool("-snes_qn_single_reduction", "Aggregate reductions",           "SNESQN", qn->singlereduction, &qn->singlereduction, NULL);CHKERRQ(ierr);
598   ierr = PetscOptionsEnum("-snes_qn_scale_type","Scaling type","SNESQNSetScaleType",SNESQNScaleTypes,(PetscEnum)stype,(PetscEnum*)&stype,&flg);CHKERRQ(ierr);
599   if (flg) ierr = SNESQNSetScaleType(snes,stype);CHKERRQ(ierr);
600 
601   ierr = PetscOptionsEnum("-snes_qn_restart_type","Restart type","SNESQNSetRestartType",SNESQNRestartTypes,(PetscEnum)rtype,(PetscEnum*)&rtype,&flg);CHKERRQ(ierr);
602   if (flg) ierr = SNESQNSetRestartType(snes,rtype);CHKERRQ(ierr);
603 
604   ierr = PetscOptionsEnum("-snes_qn_type","Quasi-Newton update type","",SNESQNTypes,(PetscEnum)qtype,(PetscEnum*)&qtype,&flg);CHKERRQ(ierr);
605   if (flg) {ierr = SNESQNSetType(snes,qtype);CHKERRQ(ierr);}
606   ierr = PetscOptionsTail();CHKERRQ(ierr);
607   if (!snes->linesearch) {
608     ierr = SNESGetLineSearch(snes, &linesearch);CHKERRQ(ierr);
609     if (qn->type == SNES_QN_LBFGS) {
610       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHCP);CHKERRQ(ierr);
611     } else if (qn->type == SNES_QN_BROYDEN) {
612       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHBASIC);CHKERRQ(ierr);
613     } else {
614       ierr = SNESLineSearchSetType(linesearch, SNESLINESEARCHL2);CHKERRQ(ierr);
615     }
616   }
617   if (monflg) {
618     qn->monitor = PETSC_VIEWER_STDOUT_(PetscObjectComm((PetscObject)snes));CHKERRQ(ierr);
619   }
620   PetscFunctionReturn(0);
621 }
622 
623 #undef __FUNCT__
624 #define __FUNCT__ "SNESView_QN"
625 static PetscErrorCode SNESView_QN(SNES snes, PetscViewer viewer)
626 {
627   SNES_QN        *qn    = (SNES_QN*)snes->data;
628   PetscBool      iascii;
629   PetscErrorCode ierr;
630 
631   PetscFunctionBegin;
632   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &iascii);CHKERRQ(ierr);
633   if (iascii) {
634     ierr = PetscViewerASCIIPrintf(viewer,"  QN type is %s, restart type is %s, scale type is %s\n",SNESQNTypes[qn->type],SNESQNRestartTypes[qn->restart_type],SNESQNScaleTypes[qn->scale_type]);CHKERRQ(ierr);
635     ierr = PetscViewerASCIIPrintf(viewer,"  Stored subspace size: %d\n", qn->m);CHKERRQ(ierr);
636     if (qn->singlereduction) {
637       ierr = PetscViewerASCIIPrintf(viewer,"  Using the single reduction variant.\n");CHKERRQ(ierr);
638     }
639   }
640   PetscFunctionReturn(0);
641 }
642 
643 #undef __FUNCT__
644 #define __FUNCT__ "SNESQNSetRestartType"
645 /*@
646     SNESQNSetRestartType - Sets the restart type for SNESQN.
647 
648     Logically Collective on SNES
649 
650     Input Parameters:
651 +   snes - the iterative context
652 -   rtype - restart type
653 
654     Options Database:
655 +   -snes_qn_restart_type <powell,periodic,none> - set the restart type
656 -   -snes_qn_m <m> - sets the number of stored updates and the restart period for periodic
657 
658     Level: intermediate
659 
660     SNESQNRestartTypes:
661 +   SNES_QN_RESTART_NONE - never restart
662 .   SNES_QN_RESTART_POWELL - restart based upon descent criteria
663 -   SNES_QN_RESTART_PERIODIC - restart after a fixed number of iterations
664 
665 .keywords: SNES, SNESQN, restart, type, set SNESLineSearch, SNESQNRestartType
666 @*/
667 PetscErrorCode SNESQNSetRestartType(SNES snes, SNESQNRestartType rtype)
668 {
669   PetscErrorCode ierr;
670 
671   PetscFunctionBegin;
672   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
673   ierr = PetscTryMethod(snes,"SNESQNSetRestartType_C",(SNES,SNESQNRestartType),(snes,rtype));CHKERRQ(ierr);
674   PetscFunctionReturn(0);
675 }
676 
677 #undef __FUNCT__
678 #define __FUNCT__ "SNESQNSetScaleType"
679 /*@
680     SNESQNSetScaleType - Sets the scaling type for the inner inverse Jacobian in SNESQN.
681 
682     Logically Collective on SNES
683 
684     Input Parameters:
685 +   snes - the iterative context
686 -   stype - scale type
687 
688     Options Database:
689 .   -snes_qn_scale_type <shanno,none,linesearch,jacobian>
690 
691     Level: intermediate
692 
693     SNESQNScaleTypes:
694 +   SNES_QN_SCALE_NONE - don't scale the problem
695 .   SNES_QN_SCALE_SHANNO - use shanno scaling
696 .   SNES_QN_SCALE_LINESEARCH - scale based upon line search lambda
697 -   SNES_QN_SCALE_JACOBIAN - scale by inverting a previously computed Jacobian.
698 
699 .keywords: SNES, SNESQN, scaling, type, set SNESLineSearch, SNESQNScaleType
700 @*/
701 
702 PetscErrorCode SNESQNSetScaleType(SNES snes, SNESQNScaleType stype)
703 {
704   PetscErrorCode ierr;
705 
706   PetscFunctionBegin;
707   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
708   ierr = PetscTryMethod(snes,"SNESQNSetScaleType_C",(SNES,SNESQNScaleType),(snes,stype));CHKERRQ(ierr);
709   PetscFunctionReturn(0);
710 }
711 
712 #undef __FUNCT__
713 #define __FUNCT__ "SNESQNSetScaleType_QN"
714 PetscErrorCode SNESQNSetScaleType_QN(SNES snes, SNESQNScaleType stype)
715 {
716   SNES_QN *qn = (SNES_QN*)snes->data;
717 
718   PetscFunctionBegin;
719   qn->scale_type = stype;
720   PetscFunctionReturn(0);
721 }
722 
723 #undef __FUNCT__
724 #define __FUNCT__ "SNESQNSetRestartType_QN"
725 PetscErrorCode SNESQNSetRestartType_QN(SNES snes, SNESQNRestartType rtype)
726 {
727   SNES_QN *qn = (SNES_QN*)snes->data;
728 
729   PetscFunctionBegin;
730   qn->restart_type = rtype;
731   PetscFunctionReturn(0);
732 }
733 
734 #undef __FUNCT__
735 #define __FUNCT__ "SNESQNSetType"
736 /*@
737     SNESQNSetType - Sets the quasi-Newton variant to be used in SNESQN.
738 
739     Logically Collective on SNES
740 
741     Input Parameters:
742 +   snes - the iterative context
743 -   qtype - variant type
744 
745     Options Database:
746 .   -snes_qn_type <lbfgs,broyden,badbroyden>
747 
748     Level: beginner
749 
750     SNESQNTypes:
751 +   SNES_QN_LBFGS - LBFGS variant
752 .   SNES_QN_BROYDEN - Broyden variant
753 -   SNES_QN_BADBROYDEN - Bad Broyden variant
754 
755 .keywords: SNES, SNESQN, type, set, SNESQNType
756 @*/
757 
758 PetscErrorCode SNESQNSetType(SNES snes, SNESQNType qtype)
759 {
760   PetscErrorCode ierr;
761 
762   PetscFunctionBegin;
763   PetscValidHeaderSpecific(snes,SNES_CLASSID,1);
764   ierr = PetscTryMethod(snes,"SNESQNSetType_C",(SNES,SNESQNType),(snes,qtype));CHKERRQ(ierr);
765   PetscFunctionReturn(0);
766 }
767 
768 #undef __FUNCT__
769 #define __FUNCT__ "SNESQNSetType_QN"
770 PetscErrorCode SNESQNSetType_QN(SNES snes, SNESQNType qtype)
771 {
772   SNES_QN *qn = (SNES_QN*)snes->data;
773 
774   PetscFunctionBegin;
775   qn->type = qtype;
776   PetscFunctionReturn(0);
777 }
778 
779 /* -------------------------------------------------------------------------- */
780 /*MC
781       SNESQN - Limited-Memory Quasi-Newton methods for the solution of nonlinear systems.
782 
783       Options Database:
784 
785 +     -snes_qn_m <m> - Number of past states saved for the L-Broyden methods.
786 +     -snes_qn_restart_type <powell,periodic,none> - set the restart type
787 .     -snes_qn_powell_angle - Angle condition for restart.
788 .     -snes_qn_powell_descent - Descent condition for restart.
789 .     -snes_qn_type <lbfgs,broyden,badbroyden> - QN type
790 .     -snes_qn_scale_type <shanno,none,linesearch,jacobian> - scaling performed on inner Jacobian
791 .     -snes_linesearch_type <cp, l2, basic> - Type of line search.
792 -     -snes_qn_monitor - Monitors the quasi-newton Jacobian.
793 
794       Notes: This implements the L-BFGS, Broyden, and "Bad" Broyden algorithms for the solution of F(x) = b using
795       previous change in F(x) and x to form the approximate inverse Jacobian using a series of multiplicative rank-one
796       updates.
797 
798       When using a nonlinear preconditioner, one has two options as to how the preconditioner is applied.  The first of
799       these options, sequential, uses the preconditioner to generate a new solution and function and uses those at this
800       iteration as the current iteration's values when constructing the approximate Jacobian.  The second, composed,
801       perturbs the problem the Jacobian represents to be P(x, b) - x = 0, where P(x, b) is the preconditioner.
802 
803       References:
804 
805       Kelley, C.T., Iterative Methods for Linear and Nonlinear Equations, Chapter 8, SIAM, 1995.
806 
807       R. Byrd, J. Nocedal, R. Schnabel, Representations of Quasi-Newton Matrices and their use in Limited Memory Methods,
808       Technical Report, Northwestern University, June 1992.
809 
810       Peter N. Brown, Alan C. Hindmarsh, Homer F. Walker, Experiments with Quasi-Newton Methods in Solving Stiff ODE
811       Systems, SIAM J. Sci. Stat. Comput. Vol 6(2), April 1985.
812 
813 
814       Level: beginner
815 
816 .seealso:  SNESCreate(), SNES, SNESSetType(), SNESNEWTONLS, SNESNEWTONTR
817 
818 M*/
819 #undef __FUNCT__
820 #define __FUNCT__ "SNESCreate_QN"
821 PETSC_EXTERN PetscErrorCode SNESCreate_QN(SNES snes)
822 {
823   PetscErrorCode ierr;
824   SNES_QN        *qn;
825 
826   PetscFunctionBegin;
827   snes->ops->setup          = SNESSetUp_QN;
828   snes->ops->solve          = SNESSolve_QN;
829   snes->ops->destroy        = SNESDestroy_QN;
830   snes->ops->setfromoptions = SNESSetFromOptions_QN;
831   snes->ops->view           = SNESView_QN;
832   snes->ops->reset          = SNESReset_QN;
833 
834   snes->pcside = PC_LEFT;
835 
836   snes->usespc  = PETSC_TRUE;
837   snes->usesksp = PETSC_FALSE;
838 
839   if (!snes->tolerancesset) {
840     snes->max_funcs = 30000;
841     snes->max_its   = 10000;
842   }
843 
844   ierr                = PetscNewLog(snes,&qn);CHKERRQ(ierr);
845   snes->data          = (void*) qn;
846   qn->m               = 10;
847   qn->scaling         = 1.0;
848   qn->U               = NULL;
849   qn->V               = NULL;
850   qn->dXtdF           = NULL;
851   qn->dFtdX           = NULL;
852   qn->dXdFmat         = NULL;
853   qn->monitor         = NULL;
854   qn->singlereduction = PETSC_TRUE;
855   qn->powell_gamma    = 0.9999;
856   qn->scale_type      = SNES_QN_SCALE_DEFAULT;
857   qn->restart_type    = SNES_QN_RESTART_DEFAULT;
858   qn->type            = SNES_QN_LBFGS;
859 
860   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetScaleType_C",SNESQNSetScaleType_QN);CHKERRQ(ierr);
861   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetRestartType_C",SNESQNSetRestartType_QN);CHKERRQ(ierr);
862   ierr = PetscObjectComposeFunction((PetscObject)snes,"SNESQNSetType_C",SNESQNSetType_QN);CHKERRQ(ierr);
863   PetscFunctionReturn(0);
864 }
865