xref: /petsc/src/tao/unconstrained/impls/lmvm/lmvm.c (revision ec9796c4f88c0039d05d273918e252d002ea08fe)
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 
7d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_LMVM(Tao tao)
8d71ae5a4SJacob Faibussowitsch {
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;
1648a46eb9SPierre Jolivet   if (tao->XL || tao->XU || tao->ops->computebounds) PetscCall(PetscInfo(tao, "WARNING: Variable bounds have been set but will be ignored by lmvm algorithm\n"));
17a7e14dcfSSatish Balay 
18a7e14dcfSSatish Balay   /*  Check convergence criteria */
199566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
209566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
21a9603a14SPatrick Farrell 
223c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
23a7e14dcfSSatish Balay 
243ecd9318SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
259566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
269566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, step));
27dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
283ba16761SJacob Faibussowitsch   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(PETSC_SUCCESS);
29a7e14dcfSSatish Balay 
30a7e14dcfSSatish Balay   /*  Set counter for gradient/reset steps */
31cd929ea3SAlp Dener   if (!lmP->recycle) {
32a7e14dcfSSatish Balay     lmP->bfgs = 0;
33a7e14dcfSSatish Balay     lmP->grad = 0;
349566063dSJacob Faibussowitsch     PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
35de6ffafeSAlp Dener   }
36a7e14dcfSSatish Balay 
37a7e14dcfSSatish Balay   /*  Have not converged; continue with Newton method */
383ecd9318SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
39e1e80dc8SAlp Dener     /* Call general purpose update function */
40dbbe0bcdSBarry Smith     PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);
41e1e80dc8SAlp Dener 
42a7e14dcfSSatish Balay     /*  Compute direction */
43cd929ea3SAlp Dener     if (lmP->H0) {
449566063dSJacob Faibussowitsch       PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
45cd929ea3SAlp Dener       stepType = LMVM_STEP_BFGS;
46cd929ea3SAlp Dener     }
479566063dSJacob Faibussowitsch     PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
489566063dSJacob Faibussowitsch     PetscCall(MatSolve(lmP->M, tao->gradient, lmP->D));
499566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(lmP->M, &nupdates));
50cd929ea3SAlp Dener     if (nupdates > 0) stepType = LMVM_STEP_BFGS;
51a7e14dcfSSatish Balay 
52a7e14dcfSSatish Balay     /*  Check for success (descent direction) */
53bbb72809SHansol Suh     PetscCall(VecDotRealPart(lmP->D, tao->gradient, &gdx));
54a7e14dcfSSatish Balay     if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
55a7e14dcfSSatish Balay       /* Step is not descent or direction produced not a number
56a7e14dcfSSatish Balay          We can assert bfgsUpdates > 1 in this case because
57a7e14dcfSSatish Balay          the first solve produces the scaled gradient direction,
58a7e14dcfSSatish Balay          which is guaranteed to be descent
59a7e14dcfSSatish Balay 
60a7e14dcfSSatish Balay          Use steepest descent direction (scaled)
61a7e14dcfSSatish Balay       */
62a7e14dcfSSatish Balay 
639566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
649566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
659566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
669566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M, tao->gradient, lmP->D));
67a7e14dcfSSatish Balay 
68a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
69a7e14dcfSSatish Balay          scaled gradient step.  No need to check for this condition. */
70cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
71a7e14dcfSSatish Balay     }
729566063dSJacob Faibussowitsch     PetscCall(VecScale(lmP->D, -1.0));
73a7e14dcfSSatish Balay 
74a7e14dcfSSatish Balay     /*  Perform the linesearch */
75a7e14dcfSSatish Balay     fold = f;
769566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution, lmP->Xold));
779566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->gradient, lmP->Gold));
78a7e14dcfSSatish Balay 
799566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step, &ls_status));
809566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
81a7e14dcfSSatish Balay 
82cd929ea3SAlp Dener     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER && (stepType != LMVM_STEP_GRAD)) {
83a7e14dcfSSatish Balay       /*  Reset factors and use scaled gradient step */
84a7e14dcfSSatish Balay       f = fold;
859566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
869566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
87a7e14dcfSSatish Balay 
88a7e14dcfSSatish Balay       /*  Failed to obtain acceptable iterate with BFGS step */
89a7e14dcfSSatish Balay       /*  Attempt to use the scaled gradient direction */
90a7e14dcfSSatish Balay 
919566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
929566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
939566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
949566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M, tao->solution, tao->gradient));
95a7e14dcfSSatish Balay 
96a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
97a7e14dcfSSatish Balay           scaled gradient step.  No need to check for this condition. */
98cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
999566063dSJacob Faibussowitsch       PetscCall(VecScale(lmP->D, -1.0));
100a7e14dcfSSatish Balay 
101a7e14dcfSSatish Balay       /*  Perform the linesearch */
1029566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step, &ls_status));
1039566063dSJacob Faibussowitsch       PetscCall(TaoAddLineSearchCounts(tao));
104a7e14dcfSSatish Balay     }
105a7e14dcfSSatish Balay 
10687f595a5SBarry Smith     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
107a7e14dcfSSatish Balay       /*  Failed to find an improving point */
108a7e14dcfSSatish Balay       f = fold;
1099566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
1109566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
111a7e14dcfSSatish Balay       step        = 0.0;
112a7e14dcfSSatish Balay       tao->reason = TAO_DIVERGED_LS_FAILURE;
113cd929ea3SAlp Dener     } else {
114cd929ea3SAlp Dener       /* LS found valid step, so tally up step type */
115cd929ea3SAlp Dener       switch (stepType) {
116d71ae5a4SJacob Faibussowitsch       case LMVM_STEP_BFGS:
117d71ae5a4SJacob Faibussowitsch         ++lmP->bfgs;
118d71ae5a4SJacob Faibussowitsch         break;
119d71ae5a4SJacob Faibussowitsch       case LMVM_STEP_GRAD:
120d71ae5a4SJacob Faibussowitsch         ++lmP->grad;
121d71ae5a4SJacob Faibussowitsch         break;
122d71ae5a4SJacob Faibussowitsch       default:
123d71ae5a4SJacob Faibussowitsch         break;
124cd929ea3SAlp Dener       }
125cd929ea3SAlp Dener       /*  Compute new gradient norm */
1269566063dSJacob Faibussowitsch       PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
127a7e14dcfSSatish Balay     }
128a9603a14SPatrick Farrell 
129cd929ea3SAlp Dener     /* Check convergence */
1308931d482SJason Sarich     tao->niter++;
1319566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
1329566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, step));
133dbbe0bcdSBarry Smith     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
134a7e14dcfSSatish Balay   }
1353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
136a7e14dcfSSatish Balay }
13787f595a5SBarry Smith 
138d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_LMVM(Tao tao)
139d71ae5a4SJacob Faibussowitsch {
140a7e14dcfSSatish Balay   TAO_LMVM *lmP = (TAO_LMVM *)tao->data;
141a7e14dcfSSatish Balay   PetscInt  n, N;
142b94d7dedSBarry Smith   PetscBool is_set, is_spd;
143a7e14dcfSSatish Balay 
144a7e14dcfSSatish Balay   PetscFunctionBegin;
145a7e14dcfSSatish Balay   /* Existence of tao->solution checked in TaoSetUp() */
1469566063dSJacob Faibussowitsch   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
1479566063dSJacob Faibussowitsch   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
1489566063dSJacob Faibussowitsch   if (!lmP->D) PetscCall(VecDuplicate(tao->solution, &lmP->D));
1499566063dSJacob Faibussowitsch   if (!lmP->Xold) PetscCall(VecDuplicate(tao->solution, &lmP->Xold));
1509566063dSJacob Faibussowitsch   if (!lmP->Gold) PetscCall(VecDuplicate(tao->solution, &lmP->Gold));
151a7e14dcfSSatish Balay 
152a7e14dcfSSatish Balay   /*  Create matrix for the limited memory approximation */
1539566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(tao->solution, &n));
1549566063dSJacob Faibussowitsch   PetscCall(VecGetSize(tao->solution, &N));
1559566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(lmP->M, n, n, N, N));
1569566063dSJacob Faibussowitsch   PetscCall(MatLMVMAllocate(lmP->M, tao->solution, tao->gradient));
157b94d7dedSBarry Smith   PetscCall(MatIsSPDKnown(lmP->M, &is_set, &is_spd));
158b94d7dedSBarry Smith   PetscCheck(is_set && is_spd, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix is not symmetric positive-definite.");
159a9603a14SPatrick Farrell 
160a9603a14SPatrick Farrell   /* If the user has set a matrix to solve as the initial H0, set the options prefix here, and set up the KSP */
1611baa6e33SBarry Smith   if (lmP->H0) PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
1623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
163a7e14dcfSSatish Balay }
164a7e14dcfSSatish Balay 
165a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
166d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_LMVM(Tao tao)
167d71ae5a4SJacob Faibussowitsch {
168a7e14dcfSSatish Balay   TAO_LMVM *lmP = (TAO_LMVM *)tao->data;
169a7e14dcfSSatish Balay 
170a7e14dcfSSatish Balay   PetscFunctionBegin;
171a7e14dcfSSatish Balay   if (tao->setupcalled) {
1729566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Xold));
1739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Gold));
1749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->D));
175a7e14dcfSSatish Balay   }
1769566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lmP->M));
1771baa6e33SBarry Smith   if (lmP->H0) PetscCall(PetscObjectDereference((PetscObject)lmP->H0));
1789566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
1793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
180a7e14dcfSSatish Balay }
181a7e14dcfSSatish Balay 
182a7e14dcfSSatish Balay /*------------------------------------------------------------*/
183d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_LMVM(Tao tao, PetscOptionItems *PetscOptionsObject)
184d71ae5a4SJacob Faibussowitsch {
185cd929ea3SAlp Dener   TAO_LMVM *lm = (TAO_LMVM *)tao->data;
186a7e14dcfSSatish Balay 
187a7e14dcfSSatish Balay   PetscFunctionBegin;
188d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Limited-memory variable-metric method for unconstrained optimization");
1899566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-tao_lmvm_recycle", "enable recycling of the BFGS matrix between subsequent TaoSolve() calls", "", lm->recycle, &lm->recycle, NULL));
1909566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
1919566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(lm->M));
192d0609cedSBarry Smith   PetscOptionsHeadEnd();
1933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
194a7e14dcfSSatish Balay }
195a7e14dcfSSatish Balay 
196a7e14dcfSSatish Balay /*------------------------------------------------------------*/
197d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_LMVM(Tao tao, PetscViewer viewer)
198d71ae5a4SJacob Faibussowitsch {
199a7e14dcfSSatish Balay   TAO_LMVM *lm = (TAO_LMVM *)tao->data;
200cd929ea3SAlp Dener   PetscBool isascii;
2014d6623b4SAlp Dener   PetscInt  recycled_its;
202a7e14dcfSSatish Balay 
203a7e14dcfSSatish Balay   PetscFunctionBegin;
2049566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
205a7e14dcfSSatish Balay   if (isascii) {
206*ec9796c4SHansol Suh     PetscCall(PetscViewerASCIIPushTab(viewer));
20763a3b9bcSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "Gradient steps: %" PetscInt_FMT "\n", lm->grad));
208cd929ea3SAlp Dener     if (lm->recycle) {
2099566063dSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Recycle: on\n"));
210cd929ea3SAlp Dener       recycled_its = lm->bfgs + lm->grad;
21163a3b9bcSJacob Faibussowitsch       PetscCall(PetscViewerASCIIPrintf(viewer, "Total recycled iterations: %" PetscInt_FMT "\n", recycled_its));
212a0bfee83SAlp Dener     }
213*ec9796c4SHansol Suh     PetscCall(PetscViewerASCIIPrintf(viewer, "LMVM Matrix:\n"));
214*ec9796c4SHansol Suh     PetscCall(PetscViewerASCIIPushTab(viewer));
215*ec9796c4SHansol Suh     PetscCall(MatView(lm->M, viewer));
216*ec9796c4SHansol Suh     PetscCall(PetscViewerASCIIPopTab(viewer));
217*ec9796c4SHansol Suh     PetscCall(PetscViewerASCIIPopTab(viewer));
218a7e14dcfSSatish Balay   }
2193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
220a7e14dcfSSatish Balay }
221a7e14dcfSSatish Balay 
222a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
223a7e14dcfSSatish Balay 
2244aa34175SJason Sarich /*MC
2254aa34175SJason Sarich   TAOLMVM - Limited Memory Variable Metric method is a quasi-Newton
2264aa34175SJason Sarich   optimization solver for unconstrained minimization. It solves
2274aa34175SJason Sarich   the Newton step
2284aa34175SJason Sarich           Hkdk = - gk
2294aa34175SJason Sarich 
2304aa34175SJason Sarich   using an approximation Bk in place of Hk, where Bk is composed using
2314aa34175SJason Sarich   the BFGS update formula. A More-Thuente line search is then used
2324aa34175SJason Sarich   to computed the steplength in the dk direction
2330ad3a497SAlp Dener 
2344aa34175SJason Sarich   Options Database Keys:
235a2b725a8SWilliam Gropp +   -tao_lmvm_recycle - enable recycling LMVM updates between TaoSolve() calls
236a2b725a8SWilliam Gropp -   -tao_lmvm_no_scale - (developer) disables diagonal Broyden scaling on the LMVM approximation
2374aa34175SJason Sarich 
2381eb8069cSJason Sarich   Level: beginner
2394aa34175SJason Sarich M*/
2404aa34175SJason Sarich 
241d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_LMVM(Tao tao)
242d71ae5a4SJacob Faibussowitsch {
243a7e14dcfSSatish Balay   TAO_LMVM   *lmP;
2448caf6e8cSBarry Smith   const char *morethuente_type = TAOLINESEARCHMT;
245a7e14dcfSSatish Balay 
246a7e14dcfSSatish Balay   PetscFunctionBegin;
247a7e14dcfSSatish Balay   tao->ops->setup          = TaoSetUp_LMVM;
248a7e14dcfSSatish Balay   tao->ops->solve          = TaoSolve_LMVM;
249a7e14dcfSSatish Balay   tao->ops->view           = TaoView_LMVM;
250a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_LMVM;
251a7e14dcfSSatish Balay   tao->ops->destroy        = TaoDestroy_LMVM;
252a7e14dcfSSatish Balay 
2534dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&lmP));
25483c8fe1dSLisandro Dalcin   lmP->D       = NULL;
25583c8fe1dSLisandro Dalcin   lmP->M       = NULL;
25683c8fe1dSLisandro Dalcin   lmP->Xold    = NULL;
25783c8fe1dSLisandro Dalcin   lmP->Gold    = NULL;
258a9603a14SPatrick Farrell   lmP->H0      = NULL;
259cd929ea3SAlp Dener   lmP->recycle = PETSC_FALSE;
260a7e14dcfSSatish Balay 
261a7e14dcfSSatish Balay   tao->data = (void *)lmP;
2626552cf8aSJason Sarich   /* Override default settings (unless already changed) */
2636552cf8aSJason Sarich   if (!tao->max_it_changed) tao->max_it = 2000;
2646552cf8aSJason Sarich   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
265a7e14dcfSSatish Balay 
2669566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch));
2679566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
2689566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type));
2699566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao));
2709566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, tao->hdr.prefix));
271cd929ea3SAlp Dener 
2729566063dSJacob Faibussowitsch   PetscCall(KSPInitializePackage());
2739566063dSJacob Faibussowitsch   PetscCall(MatCreate(((PetscObject)tao)->comm, &lmP->M));
2749566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)lmP->M, (PetscObject)tao, 1));
2759566063dSJacob Faibussowitsch   PetscCall(MatSetType(lmP->M, MATLMVMBFGS));
2769566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(lmP->M, "tao_lmvm_"));
2773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
278a7e14dcfSSatish Balay }
279