1*954e39ddSJose E. Roman #include <../src/tao/bound/impls/bqnk/bqnk.h> /*I "petsctao.h" I*/ 2e0ed867bSAlp Dener #include <petscksp.h> 3e0ed867bSAlp Dener 4d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoBQNKComputeHessian(Tao tao) 5d71ae5a4SJacob Faibussowitsch { 6e0ed867bSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 7e0ed867bSAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 865f5217aSAlp Dener PetscReal gnorm2, delta; 9e0ed867bSAlp Dener 10e0ed867bSAlp Dener PetscFunctionBegin; 11e0ed867bSAlp Dener /* Alias the LMVM matrix into the TAO hessian */ 1248a46eb9SPierre Jolivet if (tao->hessian) PetscCall(MatDestroy(&tao->hessian)); 1348a46eb9SPierre Jolivet if (tao->hessian_pre) PetscCall(MatDestroy(&tao->hessian_pre)); 149566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)bqnk->B)); 15e0ed867bSAlp Dener tao->hessian = bqnk->B; 169566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)bqnk->B)); 17e0ed867bSAlp Dener tao->hessian_pre = bqnk->B; 18e0ed867bSAlp Dener /* Update the Hessian with the latest solution */ 19f5766c09SAlp Dener if (bqnk->is_spd) { 2065f5217aSAlp Dener gnorm2 = bnk->gnorm * bnk->gnorm; 218cabe928SAlp Dener if (gnorm2 == 0.0) gnorm2 = PETSC_MACHINE_EPSILON; 228cabe928SAlp Dener if (bnk->f == 0.0) { 238cabe928SAlp Dener delta = 2.0 / gnorm2; 248cabe928SAlp Dener } else { 258cabe928SAlp Dener delta = 2.0 * PetscAbsScalar(bnk->f) / gnorm2; 268cabe928SAlp Dener } 279566063dSJacob Faibussowitsch PetscCall(MatLMVMSymBroydenSetDelta(bqnk->B, delta)); 28f5766c09SAlp Dener } 299566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(tao->hessian, tao->solution, bnk->unprojected_gradient)); 309566063dSJacob Faibussowitsch PetscCall(MatLMVMResetShift(tao->hessian)); 31e0ed867bSAlp Dener /* Prepare the reduced sub-matrices for the inactive set */ 329566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bnk->H_inactive)); 33e0ed867bSAlp Dener if (bnk->active_idx) { 349566063dSJacob Faibussowitsch PetscCall(MatCreateSubMatrixVirtual(tao->hessian, bnk->inactive_idx, bnk->inactive_idx, &bnk->H_inactive)); 359566063dSJacob Faibussowitsch PetscCall(PCLMVMSetIS(bqnk->pc, bnk->inactive_idx)); 36e0ed867bSAlp Dener } else { 379566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)tao->hessian)); 38e0ed867bSAlp Dener bnk->H_inactive = tao->hessian; 399566063dSJacob Faibussowitsch PetscCall(PCLMVMClearIS(bqnk->pc)); 40e0ed867bSAlp Dener } 419566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bnk->Hpre_inactive)); 429566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)bnk->H_inactive)); 43e0ed867bSAlp Dener bnk->Hpre_inactive = bnk->H_inactive; 44e0ed867bSAlp Dener PetscFunctionReturn(0); 45e0ed867bSAlp Dener } 46e0ed867bSAlp Dener 47d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoBQNKComputeStep(Tao tao, PetscBool shift, KSPConvergedReason *ksp_reason, PetscInt *step_type) 48d71ae5a4SJacob Faibussowitsch { 49e0ed867bSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 50e0ed867bSAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 51e0ed867bSAlp Dener 52e0ed867bSAlp Dener PetscFunctionBegin; 539566063dSJacob Faibussowitsch PetscCall(TaoBNKComputeStep(tao, shift, ksp_reason, step_type)); 54e0ed867bSAlp Dener if (*ksp_reason < 0) { 55e0ed867bSAlp Dener /* Krylov solver failed to converge so reset the LMVM matrix */ 569566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(bqnk->B, PETSC_FALSE)); 579566063dSJacob Faibussowitsch PetscCall(MatLMVMUpdate(bqnk->B, tao->solution, bnk->unprojected_gradient)); 58e0ed867bSAlp Dener } 59e0ed867bSAlp Dener PetscFunctionReturn(0); 60e0ed867bSAlp Dener } 61e0ed867bSAlp Dener 62d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSolve_BQNK(Tao tao) 63d71ae5a4SJacob Faibussowitsch { 64414d97d3SAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 65414d97d3SAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 66414d97d3SAlp Dener Mat_LMVM *lmvm = (Mat_LMVM *)bqnk->B->data; 67414d97d3SAlp Dener Mat_LMVM *J0; 68414d97d3SAlp Dener Mat_SymBrdn *diag_ctx; 69414d97d3SAlp Dener PetscBool flg = PETSC_FALSE; 70414d97d3SAlp Dener 71414d97d3SAlp Dener PetscFunctionBegin; 72414d97d3SAlp Dener if (!tao->recycle) { 739566063dSJacob Faibussowitsch PetscCall(MatLMVMReset(bqnk->B, PETSC_FALSE)); 74414d97d3SAlp Dener lmvm->nresets = 0; 75414d97d3SAlp Dener if (lmvm->J0) { 769566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)lmvm->J0, MATLMVM, &flg)); 77414d97d3SAlp Dener if (flg) { 78414d97d3SAlp Dener J0 = (Mat_LMVM *)lmvm->J0->data; 79414d97d3SAlp Dener J0->nresets = 0; 80414d97d3SAlp Dener } 81414d97d3SAlp Dener } 82414d97d3SAlp Dener flg = PETSC_FALSE; 839566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)bqnk->B, &flg, MATLMVMSYMBROYDEN, MATLMVMSYMBADBROYDEN, MATLMVMBFGS, MATLMVMDFP, "")); 84414d97d3SAlp Dener if (flg) { 85414d97d3SAlp Dener diag_ctx = (Mat_SymBrdn *)lmvm->ctx; 86414d97d3SAlp Dener J0 = (Mat_LMVM *)diag_ctx->D->data; 87414d97d3SAlp Dener J0->nresets = 0; 88414d97d3SAlp Dener } 89414d97d3SAlp Dener } 909566063dSJacob Faibussowitsch PetscCall((*bqnk->solve)(tao)); 91414d97d3SAlp Dener PetscFunctionReturn(0); 92414d97d3SAlp Dener } 93414d97d3SAlp Dener 94d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetUp_BQNK(Tao tao) 95d71ae5a4SJacob Faibussowitsch { 964f4fdda4SAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 974f4fdda4SAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 984f4fdda4SAlp Dener PetscInt n, N; 99b94d7dedSBarry Smith PetscBool is_lmvm, is_set, is_sym; 1004f4fdda4SAlp Dener 1014f4fdda4SAlp Dener PetscFunctionBegin; 1029566063dSJacob Faibussowitsch PetscCall(TaoSetUp_BNK(tao)); 1039566063dSJacob Faibussowitsch PetscCall(VecGetLocalSize(tao->solution, &n)); 1049566063dSJacob Faibussowitsch PetscCall(VecGetSize(tao->solution, &N)); 1059566063dSJacob Faibussowitsch PetscCall(MatSetSizes(bqnk->B, n, n, N, N)); 1069566063dSJacob Faibussowitsch PetscCall(MatLMVMAllocate(bqnk->B, tao->solution, bnk->unprojected_gradient)); 1079566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)bqnk->B, MATLMVM, &is_lmvm)); 1083c859ba3SBarry Smith PetscCheck(is_lmvm, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Matrix must be an LMVM-type"); 109b94d7dedSBarry Smith PetscCall(MatIsSymmetricKnown(bqnk->B, &is_set, &is_sym)); 110b94d7dedSBarry Smith PetscCheck(is_set && is_sym, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM matrix must be symmetric"); 1119566063dSJacob Faibussowitsch PetscCall(KSPGetPC(tao->ksp, &bqnk->pc)); 1129566063dSJacob Faibussowitsch PetscCall(PCSetType(bqnk->pc, PCLMVM)); 1139566063dSJacob Faibussowitsch PetscCall(PCLMVMSetMatLMVM(bqnk->pc, bqnk->B)); 1144f4fdda4SAlp Dener PetscFunctionReturn(0); 1154f4fdda4SAlp Dener } 1164f4fdda4SAlp Dener 117d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_BQNK(Tao tao, PetscOptionItems *PetscOptionsObject) 118d71ae5a4SJacob Faibussowitsch { 119e0ed867bSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 120e0ed867bSAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 121b94d7dedSBarry Smith PetscBool is_set; 122e0ed867bSAlp Dener 123e0ed867bSAlp Dener PetscFunctionBegin; 124dbbe0bcdSBarry Smith PetscCall(TaoSetFromOptions_BNK(tao, PetscOptionsObject)); 125e0ed867bSAlp Dener if (bnk->init_type == BNK_INIT_INTERPOLATION) bnk->init_type = BNK_INIT_DIRECTION; 1269566063dSJacob Faibussowitsch PetscCall(MatSetOptionsPrefix(bqnk->B, ((PetscObject)tao)->prefix)); 1279566063dSJacob Faibussowitsch PetscCall(MatAppendOptionsPrefix(bqnk->B, "tao_bqnk_")); 1289566063dSJacob Faibussowitsch PetscCall(MatSetFromOptions(bqnk->B)); 129b94d7dedSBarry Smith PetscCall(MatIsSPDKnown(bqnk->B, &is_set, &bqnk->is_spd)); 130b94d7dedSBarry Smith if (!is_set) bqnk->is_spd = PETSC_FALSE; 131e0ed867bSAlp Dener PetscFunctionReturn(0); 132e0ed867bSAlp Dener } 133e0ed867bSAlp Dener 134d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_BQNK(Tao tao, PetscViewer viewer) 135d71ae5a4SJacob Faibussowitsch { 136e0ed867bSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 137e0ed867bSAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 138e0ed867bSAlp Dener PetscBool isascii; 139e0ed867bSAlp Dener 140e0ed867bSAlp Dener PetscFunctionBegin; 1419566063dSJacob Faibussowitsch PetscCall(TaoView_BNK(tao, viewer)); 1429566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii)); 143e0ed867bSAlp Dener if (isascii) { 1449566063dSJacob Faibussowitsch PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO)); 1459566063dSJacob Faibussowitsch PetscCall(MatView(bqnk->B, viewer)); 1469566063dSJacob Faibussowitsch PetscCall(PetscViewerPopFormat(viewer)); 147e0ed867bSAlp Dener } 148e0ed867bSAlp Dener PetscFunctionReturn(0); 149e0ed867bSAlp Dener } 150e0ed867bSAlp Dener 151d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_BQNK(Tao tao) 152d71ae5a4SJacob Faibussowitsch { 153e0ed867bSAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 154e0ed867bSAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 155e0ed867bSAlp Dener 156e0ed867bSAlp Dener PetscFunctionBegin; 1579566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bnk->Hpre_inactive)); 1589566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bnk->H_inactive)); 1599566063dSJacob Faibussowitsch PetscCall(MatDestroy(&bqnk->B)); 1609566063dSJacob Faibussowitsch PetscCall(PetscFree(bnk->ctx)); 1619566063dSJacob Faibussowitsch PetscCall(TaoDestroy_BNK(tao)); 162e0ed867bSAlp Dener PetscFunctionReturn(0); 163e0ed867bSAlp Dener } 164e0ed867bSAlp Dener 165d71ae5a4SJacob Faibussowitsch PETSC_INTERN PetscErrorCode TaoCreate_BQNK(Tao tao) 166d71ae5a4SJacob Faibussowitsch { 167e0ed867bSAlp Dener TAO_BNK *bnk; 168e0ed867bSAlp Dener TAO_BQNK *bqnk; 169e0ed867bSAlp Dener 170e0ed867bSAlp Dener PetscFunctionBegin; 1719566063dSJacob Faibussowitsch PetscCall(TaoCreate_BNK(tao)); 172414d97d3SAlp Dener tao->ops->solve = TaoSolve_BQNK; 173e0ed867bSAlp Dener tao->ops->setfromoptions = TaoSetFromOptions_BQNK; 174e0ed867bSAlp Dener tao->ops->destroy = TaoDestroy_BQNK; 175e0ed867bSAlp Dener tao->ops->view = TaoView_BQNK; 1764f4fdda4SAlp Dener tao->ops->setup = TaoSetUp_BQNK; 177e0ed867bSAlp Dener 178e0ed867bSAlp Dener bnk = (TAO_BNK *)tao->data; 179e0ed867bSAlp Dener bnk->computehessian = TaoBQNKComputeHessian; 180e0ed867bSAlp Dener bnk->computestep = TaoBQNKComputeStep; 181e0ed867bSAlp Dener bnk->init_type = BNK_INIT_DIRECTION; 182e0ed867bSAlp Dener 1834dfa11a4SJacob Faibussowitsch PetscCall(PetscNew(&bqnk)); 184e0ed867bSAlp Dener bnk->ctx = (void *)bqnk; 185f5766c09SAlp Dener bqnk->is_spd = PETSC_TRUE; 186e0ed867bSAlp Dener 1879566063dSJacob Faibussowitsch PetscCall(MatCreate(PetscObjectComm((PetscObject)tao), &bqnk->B)); 1889566063dSJacob Faibussowitsch PetscCall(PetscObjectIncrementTabLevel((PetscObject)bqnk->B, (PetscObject)tao, 1)); 1899566063dSJacob Faibussowitsch PetscCall(MatSetType(bqnk->B, MATLMVMSR1)); 190e0ed867bSAlp Dener PetscFunctionReturn(0); 191e0ed867bSAlp Dener } 192f5766c09SAlp Dener 193414d97d3SAlp Dener /*@ 194414d97d3SAlp Dener TaoGetLMVMMatrix - Returns a pointer to the internal LMVM matrix. Valid 195414d97d3SAlp Dener only for quasi-Newton family of methods. 196414d97d3SAlp Dener 197414d97d3SAlp Dener Input Parameters: 198414d97d3SAlp Dener . tao - Tao solver context 199414d97d3SAlp Dener 200414d97d3SAlp Dener Output Parameters: 201414d97d3SAlp Dener . B - LMVM matrix 202414d97d3SAlp Dener 203414d97d3SAlp Dener Level: advanced 204414d97d3SAlp Dener 205db781477SPatrick Sanan .seealso: `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTL`, `TAOBQNKTR`, `MATLMVM`, `TaoSetLMVMMatrix()` 206414d97d3SAlp Dener @*/ 207d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoGetLMVMMatrix(Tao tao, Mat *B) 208d71ae5a4SJacob Faibussowitsch { 209f5766c09SAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 210f5766c09SAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 211414d97d3SAlp Dener PetscBool flg = PETSC_FALSE; 212f5766c09SAlp Dener 213f5766c09SAlp Dener PetscFunctionBegin; 2149566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)tao, &flg, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, "")); 2153c859ba3SBarry Smith PetscCheck(flg, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM Matrix only exists for quasi-Newton algorithms"); 216f5766c09SAlp Dener *B = bqnk->B; 217f5766c09SAlp Dener PetscFunctionReturn(0); 218f5766c09SAlp Dener } 219414d97d3SAlp Dener 220414d97d3SAlp Dener /*@ 221414d97d3SAlp Dener TaoSetLMVMMatrix - Sets an external LMVM matrix into the Tao solver. Valid 222414d97d3SAlp Dener only for quasi-Newton family of methods. 223414d97d3SAlp Dener 224414d97d3SAlp Dener QN family of methods create their own LMVM matrices and users who wish to 225414d97d3SAlp Dener manipulate this matrix should use TaoGetLMVMMatrix() instead. 226414d97d3SAlp Dener 227414d97d3SAlp Dener Input Parameters: 228414d97d3SAlp Dener + tao - Tao solver context 229414d97d3SAlp Dener - B - LMVM matrix 230414d97d3SAlp Dener 231414d97d3SAlp Dener Level: advanced 232414d97d3SAlp Dener 233db781477SPatrick Sanan .seealso: `TAOBQNLS`, `TAOBQNKLS`, `TAOBQNKTL`, `TAOBQNKTR`, `MATLMVM`, `TaoGetLMVMMatrix()` 234414d97d3SAlp Dener @*/ 235d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoSetLMVMMatrix(Tao tao, Mat B) 236d71ae5a4SJacob Faibussowitsch { 237414d97d3SAlp Dener TAO_BNK *bnk = (TAO_BNK *)tao->data; 238414d97d3SAlp Dener TAO_BQNK *bqnk = (TAO_BQNK *)bnk->ctx; 239414d97d3SAlp Dener PetscBool flg = PETSC_FALSE; 240414d97d3SAlp Dener 241414d97d3SAlp Dener PetscFunctionBegin; 2429566063dSJacob Faibussowitsch PetscCall(PetscObjectTypeCompareAny((PetscObject)tao, &flg, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, "")); 2433c859ba3SBarry Smith PetscCheck(flg, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "LMVM Matrix only exists for quasi-Newton algorithms"); 2449566063dSJacob Faibussowitsch PetscCall(PetscObjectBaseTypeCompare((PetscObject)B, MATLMVM, &flg)); 2453c859ba3SBarry Smith PetscCheck(flg, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given matrix is not an LMVM matrix"); 24648a46eb9SPierre Jolivet if (bqnk->B) PetscCall(MatDestroy(&bqnk->B)); 2479566063dSJacob Faibussowitsch PetscCall(PetscObjectReference((PetscObject)B)); 248414d97d3SAlp Dener bqnk->B = B; 249414d97d3SAlp Dener PetscFunctionReturn(0); 250414d97d3SAlp Dener } 251