xref: /petsc/src/tao/linesearch/impls/owarmijo/owarmijo.c (revision 0c52818fde9aa1c27f4f3b782648e9c7dfa22d21)
1 #include "petscvec.h"
2 #include "taosolver.h"
3 #include "tao-private/taolinesearch_impl.h"
4 #include "owarmijo.h"
5 
6 #define REPLACE_FIFO 1
7 #define REPLACE_MRU  2
8 
9 #define REFERENCE_MAX  1
10 #define REFERENCE_AVE  2
11 #define REFERENCE_MEAN 3
12 
13 
14 
15 static PetscErrorCode ProjWork_OWLQN(Vec w,Vec x,Vec gv,PetscReal *gdx)
16 {
17   PetscReal *xptr,*wptr,*gptr;
18   PetscErrorCode ierr;
19   PetscInt low,high,low1,high1,low2,high2,i;
20 
21   PetscFunctionBegin;
22 
23   ierr=VecGetOwnershipRange(w,&low,&high);CHKERRQ(ierr);
24   ierr=VecGetOwnershipRange(x,&low1,&high1);CHKERRQ(ierr);
25   ierr=VecGetOwnershipRange(gv,&low2,&high2);CHKERRQ(ierr);
26 
27   *gdx=0.0;
28   ierr = VecGetArray(x,&xptr);CHKERRQ(ierr);
29   ierr = VecGetArray(w,&wptr);CHKERRQ(ierr);
30   ierr = VecGetArray(gv,&gptr);CHKERRQ(ierr);
31 
32   for (i=0;i<high-low;i++)
33     {
34       if (xptr[i]*wptr[i]<0.0)
35 	wptr[i]=0.0;
36 
37       *gdx = *gdx + gptr[i]*(wptr[i]-xptr[i]);
38     }
39   ierr = VecRestoreArray(w,&wptr);CHKERRQ(ierr);
40   ierr = VecRestoreArray(x,&xptr);CHKERRQ(ierr);
41   ierr = VecRestoreArray(gv,&gptr);CHKERRQ(ierr);
42 
43   PetscFunctionReturn(0);
44 }
45 
46 #undef __FUNCT__
47 #define __FUNCT__ "TaoLineSearchDestroy_OWArmijo"
48 static PetscErrorCode TaoLineSearchDestroy_OWArmijo(TaoLineSearch ls)
49 {
50   TAOLINESEARCH_OWARMIJO_CTX *armP = (TAOLINESEARCH_OWARMIJO_CTX *)ls->data;
51   PetscErrorCode ierr;
52 
53   PetscFunctionBegin;
54 
55   if (armP->memory != PETSC_NULL) {
56     ierr = PetscFree(armP->memory); CHKERRQ(ierr);
57     armP->memory = PETSC_NULL;
58   }
59   if (armP->x) {
60     ierr = PetscObjectDereference((PetscObject)armP->x); CHKERRQ(ierr);
61   }
62   ierr = VecDestroy(&armP->work); CHKERRQ(ierr);
63   ierr = PetscFree(ls->data); CHKERRQ(ierr);
64   ls->data = PETSC_NULL;
65   PetscFunctionReturn(0);
66 }
67 
68 #undef __FUNCT__
69 #define __FUNCT__ "TaoLineSearchSetFromOptions_OWArmijo"
70 static PetscErrorCode TaoLineSearchSetFromOptions_OWArmijo(TaoLineSearch ls)
71 {
72   TAOLINESEARCH_OWARMIJO_CTX *armP = (TAOLINESEARCH_OWARMIJO_CTX *)ls->data;
73   PetscErrorCode ierr;
74 
75   PetscFunctionBegin;
76   ierr = PetscOptionsHead("OWArmijo linesearch options");CHKERRQ(ierr);
77   ierr = PetscOptionsReal("-tao_ls_OWArmijo_alpha", "initial reference constant", "", armP->alpha, &armP->alpha, 0); CHKERRQ(ierr);
78   ierr = PetscOptionsReal("-tao_ls_OWArmijo_beta_inf", "decrease constant one", "", armP->beta_inf, &armP->beta_inf, 0); CHKERRQ(ierr);
79   ierr = PetscOptionsReal("-tao_ls_OWArmijo_beta", "decrease constant", "", armP->beta, &armP->beta, 0); CHKERRQ(ierr);
80   ierr = PetscOptionsReal("-tao_ls_OWArmijo_sigma", "acceptance constant", "", armP->sigma, &armP->sigma, 0); CHKERRQ(ierr);
81   ierr = PetscOptionsInt("-tao_ls_OWArmijo_memory_size", "number of historical elements", "", armP->memorySize, &armP->memorySize, 0); CHKERRQ(ierr);
82   ierr = PetscOptionsInt("-tao_ls_OWArmijo_reference_policy", "policy for updating reference value", "", armP->referencePolicy, &armP->referencePolicy, 0); CHKERRQ(ierr);
83   ierr = PetscOptionsInt("-tao_ls_OWArmijo_replacement_policy", "policy for updating memory", "", armP->replacementPolicy, &armP->replacementPolicy, 0); CHKERRQ(ierr);
84   ierr = PetscOptionsBool("-tao_ls_OWArmijo_nondescending","Use nondescending OWArmijo algorithm","",armP->nondescending,&armP->nondescending, 0); CHKERRQ(ierr);
85   ierr = PetscOptionsTail();CHKERRQ(ierr);
86   PetscFunctionReturn(0);
87 }
88 
89 #undef __FUNCT__
90 #define __FUNCT__ "TaoLineSearchView_OWArmijo"
91 static PetscErrorCode TaoLineSearchView_OWArmijo(TaoLineSearch ls, PetscViewer pv)
92 {
93   TAOLINESEARCH_OWARMIJO_CTX *armP = (TAOLINESEARCH_OWARMIJO_CTX *)ls->data;
94   PetscBool isascii;
95   PetscErrorCode ierr;
96 
97   PetscFunctionBegin;
98   ierr = PetscObjectTypeCompare((PetscObject)pv, PETSCVIEWERASCII, &isascii); CHKERRQ(ierr);
99   if (isascii) {
100     ierr = PetscViewerASCIIPrintf(pv,"  maxf=%d, ftol=%g, gtol=%g\n",ls->max_funcs, ls->rtol, ls->ftol); CHKERRQ(ierr);
101     ierr=PetscViewerASCIIPrintf(pv,"  OWArmijo linesearch",armP->alpha);CHKERRQ(ierr);
102     if (armP->nondescending) {
103       ierr = PetscViewerASCIIPrintf(pv, " (nondescending)"); CHKERRQ(ierr);
104     }
105     ierr=PetscViewerASCIIPrintf(pv,": alpha=%g beta=%g ",armP->alpha,armP->beta);CHKERRQ(ierr);
106     ierr=PetscViewerASCIIPrintf(pv,"sigma=%g ",armP->sigma);CHKERRQ(ierr);
107     ierr=PetscViewerASCIIPrintf(pv,"memsize=%d\n",armP->memorySize);CHKERRQ(ierr);
108   } else {
109     SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Viewer type %s not supported for OWArmijo TaoLineSearch",((PetscObject)pv)->type_name);
110   }
111   PetscFunctionReturn(0);
112 }
113 
114 #undef __FUNCT__
115 #define __FUNCT__ "TaoLineSearchApply_OWArmijo"
116 /* @ TaoApply_OWArmijo - This routine performs a linesearch. It
117    backtracks until the (nonmonotone) OWArmijo conditions are satisfied.
118 
119    Input Parameters:
120 +  tao - TAO_SOLVER context
121 .  X - current iterate (on output X contains new iterate, X + step*S)
122 .  S - search direction
123 .  f - merit function evaluated at X
124 .  G - gradient of merit function evaluated at X
125 .  W - work vector
126 -  step - initial estimate of step length
127 
128    Output parameters:
129 +  f - merit function evaluated at new iterate, X + step*S
130 .  G - gradient of merit function evaluated at new iterate, X + step*S
131 .  X - new iterate
132 -  step - final step length
133 
134    Info is set to one of:
135 .   0 - the line search succeeds; the sufficient decrease
136    condition and the directional derivative condition hold
137 
138    negative number if an input parameter is invalid
139 -   -1 -  step < 0
140 
141    positive number > 1 if the line search otherwise terminates
142 +    1 -  Step is at the lower bound, stepmin.
143 @ */
144 static PetscErrorCode TaoLineSearchApply_OWArmijo(TaoLineSearch ls, Vec x, PetscReal *f, Vec g, Vec s)
145 {
146   TAOLINESEARCH_OWARMIJO_CTX *armP = (TAOLINESEARCH_OWARMIJO_CTX *)ls->data;
147   PetscErrorCode ierr;
148   PetscInt i;
149   PetscReal fact, ref, gdx;
150   PetscInt idx;
151   PetscBool g_computed=PETSC_FALSE; /* to prevent extra gradient computation */
152 
153   Vec g_old;
154   PetscReal owlqn_minstep=0.005;
155   PetscReal partgdx;
156 
157   PetscFunctionBegin;
158 
159   fact = 0.0;
160   ls->nfeval=0;
161   ls->reason = TAOLINESEARCH_CONTINUE_ITERATING;
162   if (!armP->work) {
163     ierr = VecDuplicate(x,&armP->work); CHKERRQ(ierr);
164     armP->x = x;
165     ierr = PetscObjectReference((PetscObject)armP->x); CHKERRQ(ierr);
166   }
167   /* If x has changed, then recreate work */
168   else if (x != armP->x) {
169     ierr = VecDestroy(&armP->work); CHKERRQ(ierr);
170     ierr = VecDuplicate(x,&armP->work); CHKERRQ(ierr);
171     ierr = PetscObjectDereference((PetscObject)armP->x); CHKERRQ(ierr);
172     armP->x = x;
173     ierr = PetscObjectReference((PetscObject)armP->x); CHKERRQ(ierr);
174   }
175 
176   /* Check linesearch parameters */
177   if (armP->alpha < 1) {
178     ierr = PetscInfo1(ls,"OWArmijo line search error: alpha (%g) < 1\n", armP->alpha); CHKERRQ(ierr);
179     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
180   }
181 
182   else if ((armP->beta <= 0) || (armP->beta >= 1)) {
183     ierr = PetscInfo1(ls,"OWArmijo line search error: beta (%g) invalid\n", armP->beta); CHKERRQ(ierr);
184     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
185 
186   }
187 
188   else if ((armP->beta_inf <= 0) || (armP->beta_inf >= 1)) {
189     ierr = PetscInfo1(ls,"OWArmijo line search error: beta_inf (%g) invalid\n", armP->beta_inf); CHKERRQ(ierr);
190     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
191   }
192 
193   else if ((armP->sigma <= 0) || (armP->sigma >= 0.5)) {
194     ierr = PetscInfo1(ls,"OWArmijo line search error: sigma (%g) invalid\n", armP->sigma); CHKERRQ(ierr);
195     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
196   }
197 
198   else if (armP->memorySize < 1) {
199     ierr = PetscInfo1(ls,"OWArmijo line search error: memory_size (%d) < 1\n", armP->memorySize); CHKERRQ(ierr);
200     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
201   }
202 
203   else if ((armP->referencePolicy != REFERENCE_MAX) &&
204       (armP->referencePolicy != REFERENCE_AVE) &&
205       (armP->referencePolicy != REFERENCE_MEAN)) {
206     ierr = PetscInfo(ls,"OWArmijo line search error: reference_policy invalid\n"); CHKERRQ(ierr);
207     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
208 
209   }
210 
211   else if ((armP->replacementPolicy != REPLACE_FIFO) &&
212       (armP->replacementPolicy != REPLACE_MRU)) {
213     ierr = PetscInfo(ls,"OWArmijo line search error: replacement_policy invalid\n"); CHKERRQ(ierr);
214     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
215   }
216 
217   else if (PetscIsInfOrNanReal(*f)) {
218     ierr = PetscInfo(ls,"OWArmijo line search error: initial function inf or nan\n"); CHKERRQ(ierr);
219     ls->reason=TAOLINESEARCH_FAILED_BADPARAMETER;
220   }
221 
222   if (ls->reason != TAOLINESEARCH_CONTINUE_ITERATING) {
223     PetscFunctionReturn(0);
224   }
225 
226   /* Check to see of the memory has been allocated.  If not, allocate
227      the historical array and populate it with the initial function
228      values. */
229   if (armP->memory == PETSC_NULL) {
230     ierr = PetscMalloc(sizeof(PetscReal)*armP->memorySize, &armP->memory ); CHKERRQ(ierr);
231   }
232 
233   if (!armP->memorySetup) {
234     for (i = 0; i < armP->memorySize; i++) {
235       armP->memory[i] = armP->alpha*(*f);
236     }
237 
238     armP->current = 0;
239     armP->lastReference = armP->memory[0];
240     armP->memorySetup=PETSC_TRUE;
241   }
242 
243   /* Calculate reference value (MAX) */
244   ref = armP->memory[0];
245   idx = 0;
246 
247   for (i = 1; i < armP->memorySize; i++) {
248     if (armP->memory[i] > ref) {
249       ref = armP->memory[i];
250       idx = i;
251     }
252   }
253 
254   if (armP->referencePolicy == REFERENCE_AVE) {
255     ref = 0;
256     for (i = 0; i < armP->memorySize; i++) {
257       ref += armP->memory[i];
258     }
259     ref = ref / armP->memorySize;
260     ref = PetscMax(ref, armP->memory[armP->current]);
261   }
262   else if (armP->referencePolicy == REFERENCE_MEAN) {
263     ref = PetscMin(ref, 0.5*(armP->lastReference + armP->memory[armP->current]));
264   }
265 
266 
267   if (armP->nondescending) {
268     fact = armP->sigma;
269   }
270 
271   VecDuplicate(g,&g_old);
272   VecCopy(g,g_old);
273 
274   ls->step = ls->initstep;
275 
276   while (ls->step >= owlqn_minstep && ls->nfeval < ls->max_funcs) {
277     /* Calculate iterate */
278     ierr = VecCopy(x,armP->work); CHKERRQ(ierr);
279     ierr = VecAXPY(armP->work,ls->step,s); CHKERRQ(ierr);
280 
281     partgdx=0.0;
282     ierr = ProjWork_OWLQN(armP->work,x,g_old,&partgdx);
283     ierr = (PetscErrorCode)MPI_Allreduce(&partgdx,&gdx,1,MPI_DOUBLE,MPI_SUM,PETSC_COMM_WORLD); CHKERRQ(ierr);
284 
285     /* Check the condition of gdx */
286     if (PetscIsInfOrNanReal(gdx)) {
287       ierr = PetscInfo1(ls,"Initial Line Search step * g is Inf or Nan (%g)\n",gdx); CHKERRQ(ierr);
288       ls->reason=TAOLINESEARCH_FAILED_INFORNAN;
289       PetscFunctionReturn(0);
290     }
291     if (gdx >= 0.0) {
292       ierr = PetscInfo1(ls,"Initial Line Search step is not descent direction (g's=%g)\n",gdx); CHKERRQ(ierr);
293       ls->reason = TAOLINESEARCH_FAILED_ASCENT;
294       PetscFunctionReturn(0);
295     }
296 
297     /* Calculate function at new iterate */
298     ierr = TaoLineSearchComputeObjectiveAndGradient(ls,armP->work,f,g); CHKERRQ(ierr);
299     g_computed=PETSC_TRUE;
300 
301 
302     if (ls->step == ls->initstep) {
303       ls->f_fullstep = *f;
304     }
305 
306     if (PetscIsInfOrNanReal(*f)) {
307       ls->step *= armP->beta_inf;
308     }
309     else {
310       /* Check descent condition */
311       if (armP->nondescending && *f <= ref - ls->step*fact*ref)
312 	break;
313       if (!armP->nondescending && *f <= ref + armP->sigma * gdx) {
314         break;
315       }
316 
317       ls->step *= armP->beta;
318     }
319   }
320 
321   VecDestroy(&g_old);
322 
323   /* Check termination */
324   if (PetscIsInfOrNanReal(*f)) {
325     ierr = PetscInfo(ls, "Function is inf or nan.\n"); CHKERRQ(ierr);
326     ls->reason = TAOLINESEARCH_FAILED_BADPARAMETER;
327   } else if (ls->step < owlqn_minstep) {
328     ierr = PetscInfo(ls, "Step length is below tolerance.\n"); CHKERRQ(ierr);
329     ls->reason = TAOLINESEARCH_HALTED_RTOL;
330   } else if (ls->nfeval >= ls->max_funcs) {
331     ierr = PetscInfo2(ls, "Number of line search function evals (%d) > maximum allowed (%d)\n",ls->nfeval, ls->max_funcs); CHKERRQ(ierr);
332     ls->reason = TAOLINESEARCH_HALTED_MAXFCN;
333   }
334   if (ls->reason) {
335     PetscFunctionReturn(0);
336   }
337 
338   /* Successful termination, update memory */
339   armP->lastReference = ref;
340   if (armP->replacementPolicy == REPLACE_FIFO) {
341     armP->memory[armP->current++] = *f;
342     if (armP->current >= armP->memorySize) {
343       armP->current = 0;
344     }
345   } else {
346     armP->current = idx;
347     armP->memory[idx] = *f;
348   }
349 
350   /* Update iterate and compute gradient */
351   ierr = VecCopy(armP->work,x); CHKERRQ(ierr);
352   if (!g_computed) {
353     ierr = TaoLineSearchComputeGradient(ls, x, g); CHKERRQ(ierr);
354   }
355 
356   /* Finish computations */
357   ierr = PetscInfo2(ls, "%d function evals in line search, step = %10.4f\n",ls->nfeval, ls->step); CHKERRQ(ierr);
358 
359   PetscFunctionReturn(0);
360 }
361 
362 EXTERN_C_BEGIN
363 #undef __FUNCT__
364 #define __FUNCT__ "TaoLineSearchCreate_OWArmijo"
365 PetscErrorCode TaoLineSearchCreate_OWArmijo(TaoLineSearch ls)
366 {
367   TAOLINESEARCH_OWARMIJO_CTX *armP;
368   PetscErrorCode ierr;
369 
370   PetscFunctionBegin;
371   PetscValidHeaderSpecific(ls,TAOLINESEARCH_CLASSID,1);
372   ierr = PetscNewLog(ls,&armP);CHKERRQ(ierr);
373 
374   armP->memory = PETSC_NULL;
375   armP->alpha = 1.0;
376   armP->beta = 0.25;
377   armP->beta_inf = 0.25;
378   armP->sigma = 1e-4;
379   armP->memorySize = 1;
380   armP->referencePolicy = REFERENCE_MAX;
381   armP->replacementPolicy = REPLACE_MRU;
382   armP->nondescending=PETSC_FALSE;
383   ls->data = (void*)armP;
384   ls->initstep=0.1;
385   ls->ops->setup=0;
386   ls->ops->apply=TaoLineSearchApply_OWArmijo;
387   ls->ops->view = TaoLineSearchView_OWArmijo;
388   ls->ops->destroy = TaoLineSearchDestroy_OWArmijo;
389   ls->ops->setfromoptions = TaoLineSearchSetFromOptions_OWArmijo;
390 
391   PetscFunctionReturn(0);
392 }
393 EXTERN_C_END
394