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