xref: /petsc/src/tao/bound/impls/bqnk/bqnk.c (revision 2fe279fdf3e687a416e4eadb7d3c7a82d60442c6)
1954e39ddSJose 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;
443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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   }
593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
1143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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;
1313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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   }
1483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
1623ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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));
1903ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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 
197*2fe279fdSBarry Smith    Input Parameter:
198*2fe279fdSBarry Smith .  tao - `Tao` solver context
199414d97d3SAlp Dener 
200*2fe279fdSBarry Smith    Output Parameter:
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;
2173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
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;
2493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
250414d97d3SAlp Dener }
251