xref: /petsc/src/tao/unconstrained/impls/lmvm/lmvm.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
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 
7*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_LMVM(Tao tao)
8*d71ae5a4SJacob 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;
16a7e14dcfSSatish Balay 
1748a46eb9SPierre 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"));
18a7e14dcfSSatish Balay 
19a7e14dcfSSatish Balay   /*  Check convergence criteria */
209566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &f, tao->gradient));
219566063dSJacob Faibussowitsch   PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
22a9603a14SPatrick Farrell 
233c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(f) && !PetscIsInfOrNanReal(gnorm), PetscObjectComm((PetscObject)tao), PETSC_ERR_USER, "User provided compute function generated Inf or NaN");
24a7e14dcfSSatish Balay 
253ecd9318SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
269566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
279566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, step));
28dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
293ecd9318SAlp Dener   if (tao->reason != TAO_CONTINUE_ITERATING) PetscFunctionReturn(0);
30a7e14dcfSSatish Balay 
31a7e14dcfSSatish Balay   /*  Set counter for gradient/reset steps */
32cd929ea3SAlp Dener   if (!lmP->recycle) {
33a7e14dcfSSatish Balay     lmP->bfgs = 0;
34a7e14dcfSSatish Balay     lmP->grad = 0;
359566063dSJacob Faibussowitsch     PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
36de6ffafeSAlp Dener   }
37a7e14dcfSSatish Balay 
38a7e14dcfSSatish Balay   /*  Have not converged; continue with Newton method */
393ecd9318SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
40e1e80dc8SAlp Dener     /* Call general purpose update function */
41dbbe0bcdSBarry Smith     PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);
42e1e80dc8SAlp Dener 
43a7e14dcfSSatish Balay     /*  Compute direction */
44cd929ea3SAlp Dener     if (lmP->H0) {
459566063dSJacob Faibussowitsch       PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
46cd929ea3SAlp Dener       stepType = LMVM_STEP_BFGS;
47cd929ea3SAlp Dener     }
489566063dSJacob Faibussowitsch     PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
499566063dSJacob Faibussowitsch     PetscCall(MatSolve(lmP->M, tao->gradient, lmP->D));
509566063dSJacob Faibussowitsch     PetscCall(MatLMVMGetUpdateCount(lmP->M, &nupdates));
51cd929ea3SAlp Dener     if (nupdates > 0) stepType = LMVM_STEP_BFGS;
52a7e14dcfSSatish Balay 
53a7e14dcfSSatish Balay     /*  Check for success (descent direction) */
549566063dSJacob Faibussowitsch     PetscCall(VecDot(lmP->D, tao->gradient, &gdx));
55a7e14dcfSSatish Balay     if ((gdx <= 0.0) || PetscIsInfOrNanReal(gdx)) {
56a7e14dcfSSatish Balay       /* Step is not descent or direction produced not a number
57a7e14dcfSSatish Balay          We can assert bfgsUpdates > 1 in this case because
58a7e14dcfSSatish Balay          the first solve produces the scaled gradient direction,
59a7e14dcfSSatish Balay          which is guaranteed to be descent
60a7e14dcfSSatish Balay 
61a7e14dcfSSatish Balay          Use steepest descent direction (scaled)
62a7e14dcfSSatish Balay       */
63a7e14dcfSSatish Balay 
649566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
659566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
669566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
679566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M, tao->gradient, lmP->D));
68a7e14dcfSSatish Balay 
69a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
70a7e14dcfSSatish Balay          scaled gradient step.  No need to check for this condition. */
71cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
72a7e14dcfSSatish Balay     }
739566063dSJacob Faibussowitsch     PetscCall(VecScale(lmP->D, -1.0));
74a7e14dcfSSatish Balay 
75a7e14dcfSSatish Balay     /*  Perform the linesearch */
76a7e14dcfSSatish Balay     fold = f;
779566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution, lmP->Xold));
789566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->gradient, lmP->Gold));
79a7e14dcfSSatish Balay 
809566063dSJacob Faibussowitsch     PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step, &ls_status));
819566063dSJacob Faibussowitsch     PetscCall(TaoAddLineSearchCounts(tao));
82a7e14dcfSSatish Balay 
83cd929ea3SAlp Dener     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER && (stepType != LMVM_STEP_GRAD)) {
84a7e14dcfSSatish Balay       /*  Reset factors and use scaled gradient step */
85a7e14dcfSSatish Balay       f = fold;
869566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
879566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
88a7e14dcfSSatish Balay 
89a7e14dcfSSatish Balay       /*  Failed to obtain acceptable iterate with BFGS step */
90a7e14dcfSSatish Balay       /*  Attempt to use the scaled gradient direction */
91a7e14dcfSSatish Balay 
929566063dSJacob Faibussowitsch       PetscCall(MatLMVMReset(lmP->M, PETSC_FALSE));
939566063dSJacob Faibussowitsch       PetscCall(MatLMVMClearJ0(lmP->M));
949566063dSJacob Faibussowitsch       PetscCall(MatLMVMUpdate(lmP->M, tao->solution, tao->gradient));
959566063dSJacob Faibussowitsch       PetscCall(MatSolve(lmP->M, tao->solution, tao->gradient));
96a7e14dcfSSatish Balay 
97a7e14dcfSSatish Balay       /* On a reset, the direction cannot be not a number; it is a
98a7e14dcfSSatish Balay           scaled gradient step.  No need to check for this condition. */
99cd929ea3SAlp Dener       stepType = LMVM_STEP_GRAD;
1009566063dSJacob Faibussowitsch       PetscCall(VecScale(lmP->D, -1.0));
101a7e14dcfSSatish Balay 
102a7e14dcfSSatish Balay       /*  Perform the linesearch */
1039566063dSJacob Faibussowitsch       PetscCall(TaoLineSearchApply(tao->linesearch, tao->solution, &f, tao->gradient, lmP->D, &step, &ls_status));
1049566063dSJacob Faibussowitsch       PetscCall(TaoAddLineSearchCounts(tao));
105a7e14dcfSSatish Balay     }
106a7e14dcfSSatish Balay 
10787f595a5SBarry Smith     if (ls_status != TAOLINESEARCH_SUCCESS && ls_status != TAOLINESEARCH_SUCCESS_USER) {
108a7e14dcfSSatish Balay       /*  Failed to find an improving point */
109a7e14dcfSSatish Balay       f = fold;
1109566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Xold, tao->solution));
1119566063dSJacob Faibussowitsch       PetscCall(VecCopy(lmP->Gold, tao->gradient));
112a7e14dcfSSatish Balay       step        = 0.0;
113a7e14dcfSSatish Balay       tao->reason = TAO_DIVERGED_LS_FAILURE;
114cd929ea3SAlp Dener     } else {
115cd929ea3SAlp Dener       /* LS found valid step, so tally up step type */
116cd929ea3SAlp Dener       switch (stepType) {
117*d71ae5a4SJacob Faibussowitsch       case LMVM_STEP_BFGS:
118*d71ae5a4SJacob Faibussowitsch         ++lmP->bfgs;
119*d71ae5a4SJacob Faibussowitsch         break;
120*d71ae5a4SJacob Faibussowitsch       case LMVM_STEP_GRAD:
121*d71ae5a4SJacob Faibussowitsch         ++lmP->grad;
122*d71ae5a4SJacob Faibussowitsch         break;
123*d71ae5a4SJacob Faibussowitsch       default:
124*d71ae5a4SJacob Faibussowitsch         break;
125cd929ea3SAlp Dener       }
126cd929ea3SAlp Dener       /*  Compute new gradient norm */
1279566063dSJacob Faibussowitsch       PetscCall(TaoGradientNorm(tao, tao->gradient, NORM_2, &gnorm));
128a7e14dcfSSatish Balay     }
129a9603a14SPatrick Farrell 
130cd929ea3SAlp Dener     /* Check convergence */
1318931d482SJason Sarich     tao->niter++;
1329566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao, f, gnorm, 0.0, tao->ksp_its));
1339566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao, tao->niter, f, gnorm, 0.0, step));
134dbbe0bcdSBarry Smith     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
135a7e14dcfSSatish Balay   }
136a7e14dcfSSatish Balay   PetscFunctionReturn(0);
137a7e14dcfSSatish Balay }
13887f595a5SBarry Smith 
139*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_LMVM(Tao tao)
140*d71ae5a4SJacob Faibussowitsch {
141a7e14dcfSSatish Balay   TAO_LMVM *lmP = (TAO_LMVM *)tao->data;
142a7e14dcfSSatish Balay   PetscInt  n, N;
143b94d7dedSBarry Smith   PetscBool is_set, is_spd;
144a7e14dcfSSatish Balay 
145a7e14dcfSSatish Balay   PetscFunctionBegin;
146a7e14dcfSSatish Balay   /* Existence of tao->solution checked in TaoSetUp() */
1479566063dSJacob Faibussowitsch   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
1489566063dSJacob Faibussowitsch   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
1499566063dSJacob Faibussowitsch   if (!lmP->D) PetscCall(VecDuplicate(tao->solution, &lmP->D));
1509566063dSJacob Faibussowitsch   if (!lmP->Xold) PetscCall(VecDuplicate(tao->solution, &lmP->Xold));
1519566063dSJacob Faibussowitsch   if (!lmP->Gold) PetscCall(VecDuplicate(tao->solution, &lmP->Gold));
152a7e14dcfSSatish Balay 
153a7e14dcfSSatish Balay   /*  Create matrix for the limited memory approximation */
1549566063dSJacob Faibussowitsch   PetscCall(VecGetLocalSize(tao->solution, &n));
1559566063dSJacob Faibussowitsch   PetscCall(VecGetSize(tao->solution, &N));
1569566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(lmP->M, n, n, N, N));
1579566063dSJacob Faibussowitsch   PetscCall(MatLMVMAllocate(lmP->M, tao->solution, tao->gradient));
158b94d7dedSBarry Smith   PetscCall(MatIsSPDKnown(lmP->M, &is_set, &is_spd));
159b94d7dedSBarry Smith   PetscCheck(is_set && is_spd, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix is not symmetric positive-definite.");
160a9603a14SPatrick Farrell 
161a9603a14SPatrick Farrell   /* If the user has set a matrix to solve as the initial H0, set the options prefix here, and set up the KSP */
1621baa6e33SBarry Smith   if (lmP->H0) PetscCall(MatLMVMSetJ0(lmP->M, lmP->H0));
163a7e14dcfSSatish Balay   PetscFunctionReturn(0);
164a7e14dcfSSatish Balay }
165a7e14dcfSSatish Balay 
166a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
167*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_LMVM(Tao tao)
168*d71ae5a4SJacob Faibussowitsch {
169a7e14dcfSSatish Balay   TAO_LMVM *lmP = (TAO_LMVM *)tao->data;
170a7e14dcfSSatish Balay 
171a7e14dcfSSatish Balay   PetscFunctionBegin;
172a7e14dcfSSatish Balay   if (tao->setupcalled) {
1739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Xold));
1749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->Gold));
1759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&lmP->D));
176a7e14dcfSSatish Balay   }
1779566063dSJacob Faibussowitsch   PetscCall(MatDestroy(&lmP->M));
1781baa6e33SBarry Smith   if (lmP->H0) PetscCall(PetscObjectDereference((PetscObject)lmP->H0));
1799566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
180a7e14dcfSSatish Balay   PetscFunctionReturn(0);
181a7e14dcfSSatish Balay }
182a7e14dcfSSatish Balay 
183a7e14dcfSSatish Balay /*------------------------------------------------------------*/
184*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_LMVM(Tao tao, PetscOptionItems *PetscOptionsObject)
185*d71ae5a4SJacob Faibussowitsch {
186cd929ea3SAlp Dener   TAO_LMVM *lm = (TAO_LMVM *)tao->data;
187a7e14dcfSSatish Balay 
188a7e14dcfSSatish Balay   PetscFunctionBegin;
189d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Limited-memory variable-metric method for unconstrained optimization");
1909566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-tao_lmvm_recycle", "enable recycling of the BFGS matrix between subsequent TaoSolve() calls", "", lm->recycle, &lm->recycle, NULL));
1919566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetFromOptions(tao->linesearch));
1929566063dSJacob Faibussowitsch   PetscCall(MatSetFromOptions(lm->M));
193d0609cedSBarry Smith   PetscOptionsHeadEnd();
194a7e14dcfSSatish Balay   PetscFunctionReturn(0);
195a7e14dcfSSatish Balay }
196a7e14dcfSSatish Balay 
197a7e14dcfSSatish Balay /*------------------------------------------------------------*/
198*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_LMVM(Tao tao, PetscViewer viewer)
199*d71ae5a4SJacob Faibussowitsch {
200a7e14dcfSSatish Balay   TAO_LMVM *lm = (TAO_LMVM *)tao->data;
201cd929ea3SAlp Dener   PetscBool isascii;
2024d6623b4SAlp Dener   PetscInt  recycled_its;
203a7e14dcfSSatish Balay 
204a7e14dcfSSatish Balay   PetscFunctionBegin;
2059566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
206a7e14dcfSSatish Balay   if (isascii) {
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     }
213a7e14dcfSSatish Balay   }
214a7e14dcfSSatish Balay   PetscFunctionReturn(0);
215a7e14dcfSSatish Balay }
216a7e14dcfSSatish Balay 
217a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
218a7e14dcfSSatish Balay 
2194aa34175SJason Sarich /*MC
2204aa34175SJason Sarich   TAOLMVM - Limited Memory Variable Metric method is a quasi-Newton
2214aa34175SJason Sarich   optimization solver for unconstrained minimization. It solves
2224aa34175SJason Sarich   the Newton step
2234aa34175SJason Sarich           Hkdk = - gk
2244aa34175SJason Sarich 
2254aa34175SJason Sarich   using an approximation Bk in place of Hk, where Bk is composed using
2264aa34175SJason Sarich   the BFGS update formula. A More-Thuente line search is then used
2274aa34175SJason Sarich   to computed the steplength in the dk direction
2280ad3a497SAlp Dener 
2294aa34175SJason Sarich   Options Database Keys:
230a2b725a8SWilliam Gropp +   -tao_lmvm_recycle - enable recycling LMVM updates between TaoSolve() calls
231a2b725a8SWilliam Gropp -   -tao_lmvm_no_scale - (developer) disables diagonal Broyden scaling on the LMVM approximation
2324aa34175SJason Sarich 
2331eb8069cSJason Sarich   Level: beginner
2344aa34175SJason Sarich M*/
2354aa34175SJason Sarich 
236*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_LMVM(Tao tao)
237*d71ae5a4SJacob Faibussowitsch {
238a7e14dcfSSatish Balay   TAO_LMVM   *lmP;
2398caf6e8cSBarry Smith   const char *morethuente_type = TAOLINESEARCHMT;
240a7e14dcfSSatish Balay 
241a7e14dcfSSatish Balay   PetscFunctionBegin;
242a7e14dcfSSatish Balay   tao->ops->setup          = TaoSetUp_LMVM;
243a7e14dcfSSatish Balay   tao->ops->solve          = TaoSolve_LMVM;
244a7e14dcfSSatish Balay   tao->ops->view           = TaoView_LMVM;
245a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_LMVM;
246a7e14dcfSSatish Balay   tao->ops->destroy        = TaoDestroy_LMVM;
247a7e14dcfSSatish Balay 
2484dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&lmP));
24983c8fe1dSLisandro Dalcin   lmP->D       = NULL;
25083c8fe1dSLisandro Dalcin   lmP->M       = NULL;
25183c8fe1dSLisandro Dalcin   lmP->Xold    = NULL;
25283c8fe1dSLisandro Dalcin   lmP->Gold    = NULL;
253a9603a14SPatrick Farrell   lmP->H0      = NULL;
254cd929ea3SAlp Dener   lmP->recycle = PETSC_FALSE;
255a7e14dcfSSatish Balay 
256a7e14dcfSSatish Balay   tao->data = (void *)lmP;
2576552cf8aSJason Sarich   /* Override default settings (unless already changed) */
2586552cf8aSJason Sarich   if (!tao->max_it_changed) tao->max_it = 2000;
2596552cf8aSJason Sarich   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
260a7e14dcfSSatish Balay 
2619566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchCreate(((PetscObject)tao)->comm, &tao->linesearch));
2629566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->linesearch, (PetscObject)tao, 1));
2639566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetType(tao->linesearch, morethuente_type));
2649566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchUseTaoRoutines(tao->linesearch, tao));
2659566063dSJacob Faibussowitsch   PetscCall(TaoLineSearchSetOptionsPrefix(tao->linesearch, tao->hdr.prefix));
266cd929ea3SAlp Dener 
2679566063dSJacob Faibussowitsch   PetscCall(KSPInitializePackage());
2689566063dSJacob Faibussowitsch   PetscCall(MatCreate(((PetscObject)tao)->comm, &lmP->M));
2699566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)lmP->M, (PetscObject)tao, 1));
2709566063dSJacob Faibussowitsch   PetscCall(MatSetType(lmP->M, MATLMVMBFGS));
2719566063dSJacob Faibussowitsch   PetscCall(MatSetOptionsPrefix(lmP->M, "tao_lmvm_"));
272a7e14dcfSSatish Balay   PetscFunctionReturn(0);
273a7e14dcfSSatish Balay }
274