xref: /petsc/src/tao/unconstrained/impls/lmvm/lmvm.c (revision d0609ced746bc51b019815ca91d747429db24893)
1ba92ff59SBarry Smith #include <petsctaolinesearch.h>
2aaa7dc30SBarry Smith #include <../src/tao/unconstrained/impls/lmvm/lmvm.h>
3a7e14dcfSSatish Balay 
4cd929ea3SAlp Dener #define LMVM_STEP_BFGS     0
5cd929ea3SAlp Dener #define LMVM_STEP_GRAD     1
6a7e14dcfSSatish Balay 
7441846f8SBarry Smith static PetscErrorCode TaoSolve_LMVM(Tao tao)
8a7e14dcfSSatish Balay {
9a7e14dcfSSatish Balay   TAO_LMVM                     *lmP = (TAO_LMVM *)tao->data;
10a7e14dcfSSatish Balay   PetscReal                    f, fold, gdx, gnorm;
11a7e14dcfSSatish Balay   PetscReal                    step = 1.0;
12cd929ea3SAlp Dener   PetscInt                     stepType = LMVM_STEP_GRAD, nupdates;
13e4cb33bbSBarry Smith   TaoLineSearchConvergedReason ls_status = TAOLINESEARCH_CONTINUE_ITERATING;
14a7e14dcfSSatish Balay 
15a7e14dcfSSatish Balay   PetscFunctionBegin;
16a7e14dcfSSatish Balay 
17a7e14dcfSSatish Balay   if (tao->XL || tao->XU || tao->ops->computebounds) {
189566063dSJacob Faibussowitsch     PetscCall(PetscInfo(tao,"WARNING: Variable bounds have been set but will be ignored by lmvm algorithm\n"));
19a7e14dcfSSatish Balay   }
20a7e14dcfSSatish Balay 
21a7e14dcfSSatish Balay   /*  Check convergence criteria */
229566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
239566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm));
24a9603a14SPatrick Farrell 
253c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm),PetscObjectComm((PetscObject)tao),PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
26a7e14dcfSSatish Balay 
273ecd9318SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
289566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao,f,gnorm,0.0,tao->ksp_its));
299566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao,tao->niter,f,gnorm,0.0,step));
309566063dSJacob Faibussowitsch   PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
313ecd9318SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
32a7e14dcfSSatish Balay 
33a7e14dcfSSatish Balay   /*  Set counter for gradient/reset steps */
34cd929ea3SAlp Dener   if (!lmP->recycle) {
35a7e14dcfSSatish Balay     lmP->bfgs = 0;
36a7e14dcfSSatish Balay     lmP->grad = 0;
379566063dSJacob Faibussowitsch     PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
38de6ffafeSAlp Dener   }
39a7e14dcfSSatish Balay 
40a7e14dcfSSatish Balay   /*  Have not converged; continue with Newton method */
413ecd9318SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
42e1e80dc8SAlp Dener     /* Call general purpose update function */
43e1e80dc8SAlp Dener     if (tao->ops->update) {
449566063dSJacob Faibussowitsch       PetscCall((*tao->ops->update)(tao, tao->niter, tao->user_update));
45e1e80dc8SAlp Dener     }
46e1e80dc8SAlp Dener 
47a7e14dcfSSatish Balay     /*  Compute direction */
48cd929ea3SAlp Dener     if (lmP->H0) {
499566063dSJacob Faibussowitsch       PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
50cd929ea3SAlp Dener       stepType = LMVM_STEP_BFGS;
51cd929ea3SAlp Dener     }
529566063dSJacob Faibussowitsch     PetscCall(MatLMVMUpdate(lmP->M,tao->solution,tao->gradient));
539566063dSJacob Faibussowitsch     PetscCall(MatSolve(lmP->M, tao->gradient, lmP->D));
549566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(lmP->M, &nupdates));
55cd929ea3SAlp Dener     if (nupdates > 0) stepType = LMVM_STEP_BFGS;
56a7e14dcfSSatish Balay 
57a7e14dcfSSatish Balay     /*  Check for success (descent direction) */
589566063dSJacob Faibussowitsch     PetscCall(VecDot(lmP->D, tao->gradient, &gdx));
59a7e14dcfSSatish Balay     if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
60a7e14dcfSSatish Balay       /* Step is not descent or direction produced not a number
61a7e14dcfSSatish Balay          We can assert bfgsUpdates > 1 in this case because
62a7e14dcfSSatish Balay          the first solve produces the scaled gradient direction,
63a7e14dcfSSatish Balay          which is guaranteed to be descent
64a7e14dcfSSatish Balay 
65a7e14dcfSSatish Balay          Use steepest descent direction (scaled)
66a7e14dcfSSatish Balay       */
67a7e14dcfSSatish Balay 
689566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
699566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
709566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
719566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M,tao->gradient, lmP->D));
72a7e14dcfSSatish Balay 
73a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
74a7e14dcfSSatish Balay          scaled gradient step.  No need to check for this condition. */
75cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
76a7e14dcfSSatish Balay     }
779566063dSJacob Faibussowitsch     PetscCall(VecScale(lmP->D, -1.0));
78a7e14dcfSSatish Balay 
79a7e14dcfSSatish Balay     /*  Perform the linesearch */
80a7e14dcfSSatish Balay     fold = f;
819566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution, lmP->Xold));
829566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->gradient, lmP->Gold));
83a7e14dcfSSatish Balay 
849566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step,&ls_status));
859566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
86a7e14dcfSSatish Balay 
87cd929ea3SAlp Dener     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER && (stepType != LMVM_STEP_GRAD)) {
88a7e14dcfSSatish Balay       /*  Reset factors and use scaled gradient step */
89a7e14dcfSSatish Balay       f = fold;
909566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
919566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
92a7e14dcfSSatish Balay 
93a7e14dcfSSatish Balay       /*  Failed to obtain acceptable iterate with BFGS step */
94a7e14dcfSSatish Balay       /*  Attempt to use the scaled gradient direction */
95a7e14dcfSSatish Balay 
969566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
979566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
989566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
999566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M, tao->solution, tao->gradient));
100a7e14dcfSSatish Balay 
101a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
102a7e14dcfSSatish Balay           scaled gradient step.  No need to check for this condition. */
103cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
1049566063dSJacob Faibussowitsch       PetscCall(VecScale(lmP->D, -1.0));
105a7e14dcfSSatish Balay 
106a7e14dcfSSatish Balay       /*  Perform the linesearch */
1079566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step, &ls_status));
1089566063dSJacob Faibussowitsch       PetscCall(TaoAddLineSearchCounts(tao));
109a7e14dcfSSatish Balay     }
110a7e14dcfSSatish Balay 
11187f595a5SBarry Smith     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
112a7e14dcfSSatish Balay       /*  Failed to find an improving point */
113a7e14dcfSSatish Balay       f = fold;
1149566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
1159566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
116a7e14dcfSSatish Balay       step = 0.0;
117a7e14dcfSSatish Balay       tao->reason = TAO_DIVERGED_LS_FAILURE;
118cd929ea3SAlp Dener     } else {
119cd929ea3SAlp Dener       /* LS found valid step, so tally up step type */
120cd929ea3SAlp Dener       switch (stepType) {
121cd929ea3SAlp Dener       case LMVM_STEP_BFGS:
122cd929ea3SAlp Dener         ++lmP->bfgs;
123cd929ea3SAlp Dener         break;
124cd929ea3SAlp Dener       case LMVM_STEP_GRAD:
125cd929ea3SAlp Dener         ++lmP->grad;
126cd929ea3SAlp Dener         break;
127cd929ea3SAlp Dener       default:
128cd929ea3SAlp Dener         break;
129cd929ea3SAlp Dener       }
130cd929ea3SAlp Dener       /*  Compute new gradient norm */
1319566063dSJacob Faibussowitsch       PetscCall(TaoGradientNorm(tao, tao->gradient,NORM_2,&gnorm));
132a7e14dcfSSatish Balay     }
133a9603a14SPatrick Farrell 
134cd929ea3SAlp Dener     /* Check convergence */
1358931d482SJason Sarich     tao->niter++;
1369566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao,f,gnorm,0.0,tao->ksp_its));
1379566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao,tao->niter,f,gnorm,0.0,step));
1389566063dSJacob Faibussowitsch     PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
139a7e14dcfSSatish Balay   }
140a7e14dcfSSatish Balay   PetscFunctionReturn(0);
141a7e14dcfSSatish Balay }
14287f595a5SBarry Smith 
143441846f8SBarry Smith static PetscErrorCode TaoSetUp_LMVM(Tao tao)
144a7e14dcfSSatish Balay {
145a7e14dcfSSatish Balay   TAO_LMVM       *lmP = (TAO_LMVM *)tao->data;
146a7e14dcfSSatish Balay   PetscInt       n,N;
147d5ae2380SAlp Dener   PetscBool      is_spd;
148a7e14dcfSSatish Balay 
149a7e14dcfSSatish Balay   PetscFunctionBegin;
150a7e14dcfSSatish Balay   /* Existence of tao->solution checked in TaoSetUp() */
1519566063dSJacob Faibussowitsch   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution,&tao->gradient));
1529566063dSJacob Faibussowitsch   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution,&tao->stepdirection));
1539566063dSJacob Faibussowitsch   if (!lmP->D) PetscCall(VecDuplicate(tao->solution,&lmP->D));
1549566063dSJacob Faibussowitsch   if (!lmP->Xold) PetscCall(VecDuplicate(tao->solution,&lmP->Xold));
1559566063dSJacob Faibussowitsch   if (!lmP->Gold) PetscCall(VecDuplicate(tao->solution,&lmP->Gold));
156a7e14dcfSSatish Balay 
157a7e14dcfSSatish Balay   /*  Create matrix for the limited memory approximation */
1589566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(tao->solution,&n));
1599566063dSJacob Faibussowitsch   PetscCall(VecGetSize(tao->solution,&N));
1609566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(lmP->M, n, n, N, N));
1619566063dSJacob Faibussowitsch   PetscCall(MatLMVMAllocate(lmP->M,tao->solution,tao->gradient));
1629566063dSJacob Faibussowitsch   PetscCall(MatGetOption(lmP->M, MAT_SPD, &is_spd));
1633c859ba3SBarry Smith   PetscCheck(is_spd,PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix is not symmetric positive-definite.");
164a9603a14SPatrick Farrell 
165a9603a14SPatrick Farrell   /* If the user has set a matrix to solve as the initial H0, set the options prefix here, and set up the KSP */
166a9603a14SPatrick Farrell   if (lmP->H0) {
1679566063dSJacob Faibussowitsch     PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
168a9603a14SPatrick Farrell   }
169a9603a14SPatrick Farrell 
170a7e14dcfSSatish Balay   PetscFunctionReturn(0);
171a7e14dcfSSatish Balay }
172a7e14dcfSSatish Balay 
173a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
174441846f8SBarry Smith static PetscErrorCode TaoDestroy_LMVM(Tao tao)
175a7e14dcfSSatish Balay {
176a7e14dcfSSatish Balay   TAO_LMVM       *lmP = (TAO_LMVM *)tao->data;
177a7e14dcfSSatish Balay 
178a7e14dcfSSatish Balay   PetscFunctionBegin;
179a7e14dcfSSatish Balay   if (tao->setupcalled) {
1809566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Xold));
1819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Gold));
1829566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->D));
183a7e14dcfSSatish Balay   }
1849566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lmP->M));
185a9603a14SPatrick Farrell   if (lmP->H0) {
1869566063dSJacob Faibussowitsch     PetscCall(PetscObjectDereference((PetscObject)lmP->H0));
187a9603a14SPatrick Farrell   }
1889566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
189a9603a14SPatrick Farrell 
190a7e14dcfSSatish Balay   PetscFunctionReturn(0);
191a7e14dcfSSatish Balay }
192a7e14dcfSSatish Balay 
193a7e14dcfSSatish Balay /*------------------------------------------------------------*/
1944416b707SBarry Smith static PetscErrorCode TaoSetFromOptions_LMVM(PetscOptionItems *PetscOptionsObject,Tao tao)
195a7e14dcfSSatish Balay {
196cd929ea3SAlp Dener   TAO_LMVM       *lm = (TAO_LMVM *)tao->data;
197a7e14dcfSSatish Balay 
198a7e14dcfSSatish Balay   PetscFunctionBegin;
199*d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"Limited-memory variable-metric method for unconstrained optimization");
2009566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-tao_lmvm_recycle","enable recycling of the BFGS matrix between subsequent TaoSolve() calls","",lm->recycle,&lm->recycle,NULL));
2019566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
2029566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(lm->M));
203*d0609cedSBarry Smith   PetscOptionsHeadEnd();
204a7e14dcfSSatish Balay   PetscFunctionReturn(0);
205a7e14dcfSSatish Balay }
206a7e14dcfSSatish Balay 
207a7e14dcfSSatish Balay /*------------------------------------------------------------*/
208441846f8SBarry Smith static PetscErrorCode TaoView_LMVM(Tao tao, PetscViewer viewer)
209a7e14dcfSSatish Balay {
210a7e14dcfSSatish Balay   TAO_LMVM       *lm = (TAO_LMVM *)tao->data;
211cd929ea3SAlp Dener   PetscBool      isascii;
2124d6623b4SAlp Dener   PetscInt       recycled_its;
213a7e14dcfSSatish Balay 
214a7e14dcfSSatish Balay   PetscFunctionBegin;
2159566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
216a7e14dcfSSatish Balay   if (isascii) {
2179566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "  Gradient steps: %D\n", lm->grad));
218cd929ea3SAlp Dener     if (lm->recycle) {
2199566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Recycle: on\n"));
220cd929ea3SAlp Dener       recycled_its = lm->bfgs + lm->grad;
2219566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "  Total recycled iterations: %D\n", recycled_its));
222a0bfee83SAlp Dener     }
223a7e14dcfSSatish Balay   }
224a7e14dcfSSatish Balay   PetscFunctionReturn(0);
225a7e14dcfSSatish Balay }
226a7e14dcfSSatish Balay 
227a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
228a7e14dcfSSatish Balay 
2294aa34175SJason Sarich /*MC
2304aa34175SJason Sarich   TAOLMVM - Limited Memory Variable Metric method is a quasi-Newton
2314aa34175SJason Sarich   optimization solver for unconstrained minimization. It solves
2324aa34175SJason Sarich   the Newton step
2334aa34175SJason Sarich           Hkdk = - gk
2344aa34175SJason Sarich 
2354aa34175SJason Sarich   using an approximation Bk in place of Hk, where Bk is composed using
2364aa34175SJason Sarich   the BFGS update formula. A More-Thuente line search is then used
2374aa34175SJason Sarich   to computed the steplength in the dk direction
2380ad3a497SAlp Dener 
2394aa34175SJason Sarich   Options Database Keys:
240a2b725a8SWilliam Gropp +   -tao_lmvm_recycle - enable recycling LMVM updates between TaoSolve() calls
241a2b725a8SWilliam Gropp -   -tao_lmvm_no_scale - (developer) disables diagonal Broyden scaling on the LMVM approximation
2424aa34175SJason Sarich 
2431eb8069cSJason Sarich   Level: beginner
2444aa34175SJason Sarich M*/
2454aa34175SJason Sarich 
246728e0ed0SBarry Smith PETSC_EXTERN PetscErrorCode TaoCreate_LMVM(Tao tao)
247a7e14dcfSSatish Balay {
248a7e14dcfSSatish Balay   TAO_LMVM       *lmP;
2498caf6e8cSBarry Smith   const char     *morethuente_type = TAOLINESEARCHMT;
250a7e14dcfSSatish Balay 
251a7e14dcfSSatish Balay   PetscFunctionBegin;
252a7e14dcfSSatish Balay   tao->ops->setup = TaoSetUp_LMVM;
253a7e14dcfSSatish Balay   tao->ops->solve = TaoSolve_LMVM;
254a7e14dcfSSatish Balay   tao->ops->view = TaoView_LMVM;
255a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_LMVM;
256a7e14dcfSSatish Balay   tao->ops->destroy = TaoDestroy_LMVM;
257a7e14dcfSSatish Balay 
2589566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(tao,&lmP));
25983c8fe1dSLisandro Dalcin   lmP->D = NULL;
26083c8fe1dSLisandro Dalcin   lmP->M = NULL;
26183c8fe1dSLisandro Dalcin   lmP->Xold = NULL;
26283c8fe1dSLisandro Dalcin   lmP->Gold = NULL;
263a9603a14SPatrick Farrell   lmP->H0   = NULL;
264cd929ea3SAlp Dener   lmP->recycle = PETSC_FALSE;
265a7e14dcfSSatish Balay 
266a7e14dcfSSatish Balay   tao->data = (void*)lmP;
2676552cf8aSJason Sarich   /* Override default settings (unless already changed) */
2686552cf8aSJason Sarich   if (!tao->max_it_changed) tao->max_it = 2000;
2696552cf8aSJason Sarich   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
270a7e14dcfSSatish Balay 
2719566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm,&tao->linesearch));
2729566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
2739566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetType(tao->linesearch,morethuente_type));
2749566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch,tao));
2759566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch,tao->hdr.prefix));
276cd929ea3SAlp Dener 
2779566063dSJacob Faibussowitsch   PetscCall(KSPInitializePackage());
2789566063dSJacob Faibussowitsch   PetscCall(MatCreate(((PetscObject)tao)->comm, &lmP->M));
2799566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)lmP->M, (PetscObject)tao, 1));
2809566063dSJacob Faibussowitsch   PetscCall(MatSetType(lmP->M, MATLMVMBFGS));
2819566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(lmP->M, "tao_lmvm_"));
282a7e14dcfSSatish Balay   PetscFunctionReturn(0);
283a7e14dcfSSatish Balay }
284