xref: /petsc/src/tao/unconstrained/impls/bmrm/bmrm.c (revision d71ae5a4db6382e7f06317b8d368875286fe9008)
1aaa7dc30SBarry Smith #include <../src/tao/unconstrained/impls/bmrm/bmrm.h>
2a7e14dcfSSatish Balay 
3a7e14dcfSSatish Balay static PetscErrorCode init_df_solver(TAO_DF *);
4a7e14dcfSSatish Balay static PetscErrorCode ensure_df_space(PetscInt, TAO_DF *);
5a7e14dcfSSatish Balay static PetscErrorCode destroy_df_solver(TAO_DF *);
60e660641SBarry Smith static PetscReal      phi(PetscReal *, PetscInt, PetscReal, PetscReal *, PetscReal, PetscReal *, PetscReal *, PetscReal *);
70e660641SBarry Smith static PetscInt       project(PetscInt, PetscReal *, PetscReal, PetscReal *, PetscReal *, PetscReal *, PetscReal *, PetscReal *, TAO_DF *);
8a7e14dcfSSatish Balay static PetscErrorCode solve(TAO_DF *);
9a7e14dcfSSatish Balay 
10a7e14dcfSSatish Balay /*------------------------------------------------------------*/
11a7e14dcfSSatish Balay /* The main solver function
12a7e14dcfSSatish Balay 
13a7e14dcfSSatish Balay    f = Remp(W)          This is what the user provides us from the application layer
14a7e14dcfSSatish Balay    So the ComputeGradient function for instance should get us back the subgradient of Remp(W)
15a7e14dcfSSatish Balay 
16a7e14dcfSSatish Balay    Regularizer assumed to be L2 norm = lambda*0.5*W'W ()
17a7e14dcfSSatish Balay */
18a7e14dcfSSatish Balay 
19*d71ae5a4SJacob Faibussowitsch static PetscErrorCode make_grad_node(Vec X, Vec_Chain **p)
20*d71ae5a4SJacob Faibussowitsch {
21a7e14dcfSSatish Balay   PetscFunctionBegin;
229566063dSJacob Faibussowitsch   PetscCall(PetscNew(p));
239566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(X, &(*p)->V));
249566063dSJacob Faibussowitsch   PetscCall(VecCopy(X, (*p)->V));
256c23d075SBarry Smith   (*p)->next = NULL;
26a7e14dcfSSatish Balay   PetscFunctionReturn(0);
27a7e14dcfSSatish Balay }
28a7e14dcfSSatish Balay 
29*d71ae5a4SJacob Faibussowitsch static PetscErrorCode destroy_grad_list(Vec_Chain *head)
30*d71ae5a4SJacob Faibussowitsch {
31a7e14dcfSSatish Balay   Vec_Chain *p = head->next, *q;
32a7e14dcfSSatish Balay 
33a7e14dcfSSatish Balay   PetscFunctionBegin;
34a7e14dcfSSatish Balay   while (p) {
35a7e14dcfSSatish Balay     q = p->next;
369566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&p->V));
379566063dSJacob Faibussowitsch     PetscCall(PetscFree(p));
38a7e14dcfSSatish Balay     p = q;
39a7e14dcfSSatish Balay   }
406c23d075SBarry Smith   head->next = NULL;
41a7e14dcfSSatish Balay   PetscFunctionReturn(0);
42a7e14dcfSSatish Balay }
43a7e14dcfSSatish Balay 
44*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_BMRM(Tao tao)
45*d71ae5a4SJacob Faibussowitsch {
46a7e14dcfSSatish Balay   TAO_DF    df;
47a7e14dcfSSatish Balay   TAO_BMRM *bmrm = (TAO_BMRM *)tao->data;
48a7e14dcfSSatish Balay 
49a7e14dcfSSatish Balay   /* Values and pointers to parts of the optimization problem */
50a7e14dcfSSatish Balay   PetscReal   f = 0.0;
51a7e14dcfSSatish Balay   Vec         W = tao->solution;
52a7e14dcfSSatish Balay   Vec         G = tao->gradient;
53a7e14dcfSSatish Balay   PetscReal   lambda;
54a7e14dcfSSatish Balay   PetscReal   bt;
55a7e14dcfSSatish Balay   Vec_Chain   grad_list, *tail_glist, *pgrad;
56a7e14dcfSSatish Balay   PetscInt    i;
57a7e14dcfSSatish Balay   PetscMPIInt rank;
58a7e14dcfSSatish Balay 
59e4cb33bbSBarry Smith   /* Used in converged criteria check */
60a7e14dcfSSatish Balay   PetscReal reg;
617fb8a5e4SKarl Rupp   PetscReal jtwt = 0.0, max_jtwt, pre_epsilon, epsilon, jw, min_jw;
62a7e14dcfSSatish Balay   PetscReal innerSolverTol;
63ba4b436cSBarry Smith   MPI_Comm  comm;
64a7e14dcfSSatish Balay 
65a7e14dcfSSatish Balay   PetscFunctionBegin;
669566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetComm((PetscObject)tao, &comm));
679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
68a7e14dcfSSatish Balay   lambda = bmrm->lambda;
69a7e14dcfSSatish Balay 
70a7e14dcfSSatish Balay   /* Check Stopping Condition */
71a7e14dcfSSatish Balay   tao->step      = 1.0;
72a7e14dcfSSatish Balay   max_jtwt       = -BMRM_INFTY;
73a7e14dcfSSatish Balay   min_jw         = BMRM_INFTY;
74a7e14dcfSSatish Balay   innerSolverTol = 1.0;
75a7e14dcfSSatish Balay   epsilon        = 0.0;
76a7e14dcfSSatish Balay 
77dd400576SPatrick Sanan   if (rank == 0) {
789566063dSJacob Faibussowitsch     PetscCall(init_df_solver(&df));
79a7e14dcfSSatish Balay     grad_list.next = NULL;
80a7e14dcfSSatish Balay     tail_glist     = &grad_list;
81a7e14dcfSSatish Balay   }
82a7e14dcfSSatish Balay 
83a7e14dcfSSatish Balay   df.tol      = 1e-6;
843ecd9318SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
85a7e14dcfSSatish Balay 
86a7e14dcfSSatish Balay   /*-----------------Algorithm Begins------------------------*/
87a7e14dcfSSatish Balay   /* make the scatter */
889566063dSJacob Faibussowitsch   PetscCall(VecScatterCreateToZero(W, &bmrm->scatter, &bmrm->local_w));
899566063dSJacob Faibussowitsch   PetscCall(VecAssemblyBegin(bmrm->local_w));
909566063dSJacob Faibussowitsch   PetscCall(VecAssemblyEnd(bmrm->local_w));
91a7e14dcfSSatish Balay 
92a7e14dcfSSatish Balay   /* NOTE: In application pass the sub-gradient of Remp(W) */
939566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, W, &f, G));
949566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, f, 1.0, 0.0, tao->ksp_its));
959566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, f, 1.0, 0.0, tao->step));
96dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
973ecd9318SAlp Dener 
983ecd9318SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
99e1e80dc8SAlp Dener     /* Call general purpose update function */
100dbbe0bcdSBarry Smith     PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);
101e1e80dc8SAlp Dener 
102a7e14dcfSSatish Balay     /* compute bt = Remp(Wt-1) - <Wt-1, At> */
1039566063dSJacob Faibussowitsch     PetscCall(VecDot(W, G, &bt));
104a7e14dcfSSatish Balay     bt = f - bt;
105a7e14dcfSSatish Balay 
1069dddd249SSatish Balay     /* First gather the gradient to the rank-0 node */
1079566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD));
1089566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD));
109a7e14dcfSSatish Balay 
110a7e14dcfSSatish Balay     /* Bring up the inner solver */
111dd400576SPatrick Sanan     if (rank == 0) {
1129566063dSJacob Faibussowitsch       PetscCall(ensure_df_space(tao->niter + 1, &df));
1139566063dSJacob Faibussowitsch       PetscCall(make_grad_node(bmrm->local_w, &pgrad));
114a7e14dcfSSatish Balay       tail_glist->next = pgrad;
115a7e14dcfSSatish Balay       tail_glist       = pgrad;
116a7e14dcfSSatish Balay 
1178931d482SJason Sarich       df.a[tao->niter] = 1.0;
1188931d482SJason Sarich       df.f[tao->niter] = -bt;
1198931d482SJason Sarich       df.u[tao->niter] = 1.0;
1208931d482SJason Sarich       df.l[tao->niter] = 0.0;
121a7e14dcfSSatish Balay 
122a7e14dcfSSatish Balay       /* set up the Q */
123a7e14dcfSSatish Balay       pgrad = grad_list.next;
1248931d482SJason Sarich       for (i = 0; i <= tao->niter; i++) {
1253c859ba3SBarry Smith         PetscCheck(pgrad, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Assert that there are at least tao->niter+1 pgrad available");
1269566063dSJacob Faibussowitsch         PetscCall(VecDot(pgrad->V, bmrm->local_w, &reg));
1278931d482SJason Sarich         df.Q[i][tao->niter] = df.Q[tao->niter][i] = reg / lambda;
128a7e14dcfSSatish Balay         pgrad                                     = pgrad->next;
129a7e14dcfSSatish Balay       }
130a7e14dcfSSatish Balay 
1318931d482SJason Sarich       if (tao->niter > 0) {
1328931d482SJason Sarich         df.x[tao->niter] = 0.0;
1339566063dSJacob Faibussowitsch         PetscCall(solve(&df));
1349371c9d4SSatish Balay       } else df.x[0] = 1.0;
135a7e14dcfSSatish Balay 
136a7e14dcfSSatish Balay       /* now computing Jt*(alpha_t) which should be = Jt(wt) to check convergence */
137a7e14dcfSSatish Balay       jtwt = 0.0;
1389566063dSJacob Faibussowitsch       PetscCall(VecSet(bmrm->local_w, 0.0));
139a7e14dcfSSatish Balay       pgrad = grad_list.next;
1408931d482SJason Sarich       for (i = 0; i <= tao->niter; i++) {
141a7e14dcfSSatish Balay         jtwt -= df.x[i] * df.f[i];
1429566063dSJacob Faibussowitsch         PetscCall(VecAXPY(bmrm->local_w, -df.x[i] / lambda, pgrad->V));
143a7e14dcfSSatish Balay         pgrad = pgrad->next;
144a7e14dcfSSatish Balay       }
145a7e14dcfSSatish Balay 
1469566063dSJacob Faibussowitsch       PetscCall(VecNorm(bmrm->local_w, NORM_2, &reg));
147a7e14dcfSSatish Balay       reg = 0.5 * lambda * reg * reg;
148a7e14dcfSSatish Balay       jtwt -= reg;
149a7e14dcfSSatish Balay     } /* end if rank == 0 */
150a7e14dcfSSatish Balay 
151a7e14dcfSSatish Balay     /* scatter the new W to all nodes */
1529566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(bmrm->scatter, bmrm->local_w, W, INSERT_VALUES, SCATTER_REVERSE));
1539566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(bmrm->scatter, bmrm->local_w, W, INSERT_VALUES, SCATTER_REVERSE));
154a7e14dcfSSatish Balay 
1559566063dSJacob Faibussowitsch     PetscCall(TaoComputeObjectiveAndGradient(tao, W, &f, G));
156a7e14dcfSSatish Balay 
1579566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&jtwt, 1, MPIU_REAL, 0, comm));
1589566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&reg, 1, MPIU_REAL, 0, comm));
159a7e14dcfSSatish Balay 
160a7e14dcfSSatish Balay     jw = reg + f; /* J(w) = regularizer + Remp(w) */
1610e660641SBarry Smith     if (jw < min_jw) min_jw = jw;
1620e660641SBarry Smith     if (jtwt > max_jtwt) max_jtwt = jtwt;
163a7e14dcfSSatish Balay 
164a7e14dcfSSatish Balay     pre_epsilon = epsilon;
165a7e14dcfSSatish Balay     epsilon     = min_jw - jtwt;
166a7e14dcfSSatish Balay 
167dd400576SPatrick Sanan     if (rank == 0) {
1680e660641SBarry Smith       if (innerSolverTol > epsilon) innerSolverTol = epsilon;
1690e660641SBarry Smith       else if (innerSolverTol < 1e-7) innerSolverTol = 1e-7;
170a7e14dcfSSatish Balay 
171a7e14dcfSSatish Balay       /* if the annealing doesn't work well, lower the inner solver tolerance */
1720e660641SBarry Smith       if (pre_epsilon < epsilon) innerSolverTol *= 0.2;
173a7e14dcfSSatish Balay 
174a7e14dcfSSatish Balay       df.tol = innerSolverTol * 0.5;
175a7e14dcfSSatish Balay     }
176a7e14dcfSSatish Balay 
1778931d482SJason Sarich     tao->niter++;
1789566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao, min_jw, epsilon, 0.0, tao->ksp_its));
1799566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao, tao->niter, min_jw, epsilon, 0.0, tao->step));
180dbbe0bcdSBarry Smith     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
181a7e14dcfSSatish Balay   }
182a7e14dcfSSatish Balay 
183a7e14dcfSSatish Balay   /* free all the memory */
184dd400576SPatrick Sanan   if (rank == 0) {
1859566063dSJacob Faibussowitsch     PetscCall(destroy_grad_list(&grad_list));
1869566063dSJacob Faibussowitsch     PetscCall(destroy_df_solver(&df));
187a7e14dcfSSatish Balay   }
188a7e14dcfSSatish Balay 
1899566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmrm->local_w));
1909566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&bmrm->scatter));
191a7e14dcfSSatish Balay   PetscFunctionReturn(0);
192a7e14dcfSSatish Balay }
193a7e14dcfSSatish Balay 
194a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
195a7e14dcfSSatish Balay 
196*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetup_BMRM(Tao tao)
197*d71ae5a4SJacob Faibussowitsch {
198a7e14dcfSSatish Balay   PetscFunctionBegin;
199a7e14dcfSSatish Balay   /* Allocate some arrays */
2009566063dSJacob Faibussowitsch   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
201a7e14dcfSSatish Balay   PetscFunctionReturn(0);
202a7e14dcfSSatish Balay }
203a7e14dcfSSatish Balay 
204a7e14dcfSSatish Balay /*------------------------------------------------------------*/
205*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_BMRM(Tao tao)
206*d71ae5a4SJacob Faibussowitsch {
207a7e14dcfSSatish Balay   PetscFunctionBegin;
2089566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
209a7e14dcfSSatish Balay   PetscFunctionReturn(0);
210a7e14dcfSSatish Balay }
211a7e14dcfSSatish Balay 
212*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_BMRM(Tao tao, PetscOptionItems *PetscOptionsObject)
213*d71ae5a4SJacob Faibussowitsch {
214a7e14dcfSSatish Balay   TAO_BMRM *bmrm = (TAO_BMRM *)tao->data;
215a7e14dcfSSatish Balay 
216a7e14dcfSSatish Balay   PetscFunctionBegin;
217d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "BMRM for regularized risk minimization");
2189566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bmrm_lambda", "regulariser weight", "", 100, &bmrm->lambda, NULL));
219d0609cedSBarry Smith   PetscOptionsHeadEnd();
220a7e14dcfSSatish Balay   PetscFunctionReturn(0);
221a7e14dcfSSatish Balay }
222a7e14dcfSSatish Balay 
223a7e14dcfSSatish Balay /*------------------------------------------------------------*/
224*d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_BMRM(Tao tao, PetscViewer viewer)
225*d71ae5a4SJacob Faibussowitsch {
226a7e14dcfSSatish Balay   PetscBool isascii;
227a7e14dcfSSatish Balay 
228a7e14dcfSSatish Balay   PetscFunctionBegin;
2299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
230a7e14dcfSSatish Balay   if (isascii) {
2319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
2329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
233a7e14dcfSSatish Balay   }
234a7e14dcfSSatish Balay   PetscFunctionReturn(0);
235a7e14dcfSSatish Balay }
236a7e14dcfSSatish Balay 
237a7e14dcfSSatish Balay /*------------------------------------------------------------*/
2381522df2eSJason Sarich /*MC
2391522df2eSJason Sarich   TAOBMRM - bundle method for regularized risk minimization
2401522df2eSJason Sarich 
2411522df2eSJason Sarich   Options Database Keys:
2421522df2eSJason Sarich . - tao_bmrm_lambda - regulariser weight
2431522df2eSJason Sarich 
2441eb8069cSJason Sarich   Level: beginner
2451522df2eSJason Sarich M*/
2461522df2eSJason Sarich 
247*d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_BMRM(Tao tao)
248*d71ae5a4SJacob Faibussowitsch {
249a7e14dcfSSatish Balay   TAO_BMRM *bmrm;
250a7e14dcfSSatish Balay 
251a7e14dcfSSatish Balay   PetscFunctionBegin;
252a7e14dcfSSatish Balay   tao->ops->setup          = TaoSetup_BMRM;
253a7e14dcfSSatish Balay   tao->ops->solve          = TaoSolve_BMRM;
254a7e14dcfSSatish Balay   tao->ops->view           = TaoView_BMRM;
255a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_BMRM;
256a7e14dcfSSatish Balay   tao->ops->destroy        = TaoDestroy_BMRM;
257a7e14dcfSSatish Balay 
2584dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&bmrm));
259a7e14dcfSSatish Balay   bmrm->lambda = 1.0;
260a7e14dcfSSatish Balay   tao->data    = (void *)bmrm;
261a7e14dcfSSatish Balay 
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;
2656552cf8aSJason Sarich   if (!tao->gatol_changed) tao->gatol = 1.0e-12;
2666552cf8aSJason Sarich   if (!tao->grtol_changed) tao->grtol = 1.0e-12;
267a7e14dcfSSatish Balay 
268a7e14dcfSSatish Balay   PetscFunctionReturn(0);
269a7e14dcfSSatish Balay }
270a7e14dcfSSatish Balay 
271*d71ae5a4SJacob Faibussowitsch PetscErrorCode init_df_solver(TAO_DF *df)
272*d71ae5a4SJacob Faibussowitsch {
273a7e14dcfSSatish Balay   PetscInt i, n = INCRE_DIM;
274a7e14dcfSSatish Balay 
275a7e14dcfSSatish Balay   PetscFunctionBegin;
276a7e14dcfSSatish Balay   /* default values */
277a7e14dcfSSatish Balay   df->maxProjIter = 200;
278a7e14dcfSSatish Balay   df->maxPGMIter  = 300000;
279a7e14dcfSSatish Balay   df->b           = 1.0;
280a7e14dcfSSatish Balay 
281a7e14dcfSSatish Balay   /* memory space required by Dai-Fletcher */
282a7e14dcfSSatish Balay   df->cur_num_cp = n;
2839566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->f));
2849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->a));
2859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->l));
2869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->u));
2879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->x));
2889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Q));
289a7e14dcfSSatish Balay 
29048a46eb9SPierre Jolivet   for (i = 0; i < n; i++) PetscCall(PetscMalloc1(n, &df->Q[i]));
291a7e14dcfSSatish Balay 
2929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->g));
2939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->y));
2949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tempv));
2959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->d));
2969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Qd));
2979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->t));
2989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->xplus));
2999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tplus));
3009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->sk));
3019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->yk));
302a7e14dcfSSatish Balay 
3039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt));
3049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt2));
3059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->uv));
306a7e14dcfSSatish Balay   PetscFunctionReturn(0);
307a7e14dcfSSatish Balay }
308a7e14dcfSSatish Balay 
309*d71ae5a4SJacob Faibussowitsch PetscErrorCode ensure_df_space(PetscInt dim, TAO_DF *df)
310*d71ae5a4SJacob Faibussowitsch {
311a7e14dcfSSatish Balay   PetscReal *tmp, **tmp_Q;
312a7e14dcfSSatish Balay   PetscInt   i, n, old_n;
313a7e14dcfSSatish Balay 
314a7e14dcfSSatish Balay   PetscFunctionBegin;
31553506e15SBarry Smith   df->dim = dim;
31653506e15SBarry Smith   if (dim <= df->cur_num_cp) PetscFunctionReturn(0);
317a7e14dcfSSatish Balay 
318a7e14dcfSSatish Balay   old_n = df->cur_num_cp;
319a7e14dcfSSatish Balay   df->cur_num_cp += INCRE_DIM;
320a7e14dcfSSatish Balay   n = df->cur_num_cp;
321a7e14dcfSSatish Balay 
322a7e14dcfSSatish Balay   /* memory space required by dai-fletcher */
3239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3249566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->f, old_n));
3259566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->f));
326a7e14dcfSSatish Balay   df->f = tmp;
327a7e14dcfSSatish Balay 
3289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3299566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->a, old_n));
3309566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->a));
331a7e14dcfSSatish Balay   df->a = tmp;
332a7e14dcfSSatish Balay 
3339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3349566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->l, old_n));
3359566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->l));
336a7e14dcfSSatish Balay   df->l = tmp;
337a7e14dcfSSatish Balay 
3389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3399566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->u, old_n));
3409566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->u));
341a7e14dcfSSatish Balay   df->u = tmp;
342a7e14dcfSSatish Balay 
3439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3449566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->x, old_n));
3459566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->x));
346a7e14dcfSSatish Balay   df->x = tmp;
347a7e14dcfSSatish Balay 
3489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp_Q));
34953506e15SBarry Smith   for (i = 0; i < n; i++) {
3509566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &tmp_Q[i]));
35153506e15SBarry Smith     if (i < old_n) {
3529566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp_Q[i], df->Q[i], old_n));
3539566063dSJacob Faibussowitsch       PetscCall(PetscFree(df->Q[i]));
354a7e14dcfSSatish Balay     }
355a7e14dcfSSatish Balay   }
356a7e14dcfSSatish Balay 
3579566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Q));
358a7e14dcfSSatish Balay   df->Q = tmp_Q;
359a7e14dcfSSatish Balay 
3609566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->g));
3619566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->g));
362a7e14dcfSSatish Balay 
3639566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->y));
3649566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->y));
365a7e14dcfSSatish Balay 
3669566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tempv));
3679566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tempv));
368a7e14dcfSSatish Balay 
3699566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->d));
3709566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->d));
371a7e14dcfSSatish Balay 
3729566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Qd));
3739566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Qd));
374a7e14dcfSSatish Balay 
3759566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->t));
3769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->t));
377a7e14dcfSSatish Balay 
3789566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->xplus));
3799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->xplus));
380a7e14dcfSSatish Balay 
3819566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tplus));
3829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tplus));
383a7e14dcfSSatish Balay 
3849566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->sk));
3859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->sk));
386a7e14dcfSSatish Balay 
3879566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->yk));
3889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->yk));
389a7e14dcfSSatish Balay 
3909566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt));
3919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt));
392a7e14dcfSSatish Balay 
3939566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt2));
3949566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt2));
395a7e14dcfSSatish Balay 
3969566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->uv));
3979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->uv));
398a7e14dcfSSatish Balay   PetscFunctionReturn(0);
399a7e14dcfSSatish Balay }
400a7e14dcfSSatish Balay 
401*d71ae5a4SJacob Faibussowitsch PetscErrorCode destroy_df_solver(TAO_DF *df)
402*d71ae5a4SJacob Faibussowitsch {
403a7e14dcfSSatish Balay   PetscInt i;
4046c23d075SBarry Smith 
405a7e14dcfSSatish Balay   PetscFunctionBegin;
4069566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->f));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->a));
4089566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->l));
4099566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->u));
4109566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->x));
411a7e14dcfSSatish Balay 
41248a46eb9SPierre Jolivet   for (i = 0; i < df->cur_num_cp; i++) PetscCall(PetscFree(df->Q[i]));
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Q));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt2));
4169566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->uv));
4179566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->g));
4189566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->y));
4199566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tempv));
4209566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->d));
4219566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Qd));
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->t));
4239566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->xplus));
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tplus));
4259566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->sk));
4269566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->yk));
427a7e14dcfSSatish Balay   PetscFunctionReturn(0);
428a7e14dcfSSatish Balay }
429a7e14dcfSSatish Balay 
430a7e14dcfSSatish Balay /* Piecewise linear monotone target function for the Dai-Fletcher projector */
431*d71ae5a4SJacob Faibussowitsch PetscReal phi(PetscReal *x, PetscInt n, PetscReal lambda, PetscReal *a, PetscReal b, PetscReal *c, PetscReal *l, PetscReal *u)
432*d71ae5a4SJacob Faibussowitsch {
433a7e14dcfSSatish Balay   PetscReal r = 0.0;
434a7e14dcfSSatish Balay   PetscInt  i;
435a7e14dcfSSatish Balay 
436a7e14dcfSSatish Balay   for (i = 0; i < n; i++) {
437a7e14dcfSSatish Balay     x[i] = -c[i] + lambda * a[i];
4386c23d075SBarry Smith     if (x[i] > u[i]) x[i] = u[i];
4396c23d075SBarry Smith     else if (x[i] < l[i]) x[i] = l[i];
440a7e14dcfSSatish Balay     r += a[i] * x[i];
441a7e14dcfSSatish Balay   }
442a7e14dcfSSatish Balay   return r - b;
443a7e14dcfSSatish Balay }
444a7e14dcfSSatish Balay 
445a7e14dcfSSatish Balay /** Modified Dai-Fletcher QP projector solves the problem:
446a7e14dcfSSatish Balay  *
447a7e14dcfSSatish Balay  *      minimise  0.5*x'*x - c'*x
448a7e14dcfSSatish Balay  *      subj to   a'*x = b
449a7e14dcfSSatish Balay  *                l \leq x \leq u
450a7e14dcfSSatish Balay  *
451a7e14dcfSSatish Balay  *  \param c The point to be projected onto feasible set
452a7e14dcfSSatish Balay  */
453*d71ae5a4SJacob Faibussowitsch PetscInt project(PetscInt n, PetscReal *a, PetscReal b, PetscReal *c, PetscReal *l, PetscReal *u, PetscReal *x, PetscReal *lam_ext, TAO_DF *df)
454*d71ae5a4SJacob Faibussowitsch {
455a7e14dcfSSatish Balay   PetscReal lambda, lambdal, lambdau, dlambda, lambda_new;
456a7e14dcfSSatish Balay   PetscReal r, rl, ru, s;
457a7e14dcfSSatish Balay   PetscInt  innerIter;
458a7e14dcfSSatish Balay   PetscBool nonNegativeSlack = PETSC_FALSE;
459a7e14dcfSSatish Balay 
460a7e14dcfSSatish Balay   *lam_ext  = 0;
461a7e14dcfSSatish Balay   lambda    = 0;
462a7e14dcfSSatish Balay   dlambda   = 0.5;
463a7e14dcfSSatish Balay   innerIter = 1;
464a7e14dcfSSatish Balay 
465a7e14dcfSSatish Balay   /*  \phi(x;lambda) := 0.5*x'*x + c'*x - lambda*(a'*x-b)
466a7e14dcfSSatish Balay    *
467a7e14dcfSSatish Balay    *  Optimality conditions for \phi:
468a7e14dcfSSatish Balay    *
469a7e14dcfSSatish Balay    *  1. lambda   <= 0
470a7e14dcfSSatish Balay    *  2. r        <= 0
471a7e14dcfSSatish Balay    *  3. r*lambda == 0
472a7e14dcfSSatish Balay    */
473a7e14dcfSSatish Balay 
474a7e14dcfSSatish Balay   /* Bracketing Phase */
475a7e14dcfSSatish Balay   r = phi(x, n, lambda, a, b, c, l, u);
476a7e14dcfSSatish Balay 
4776c23d075SBarry Smith   if (nonNegativeSlack) {
478a7e14dcfSSatish Balay     /* inequality constraint, i.e., with \xi >= 0 constraint */
47953506e15SBarry Smith     if (r < TOL_R) return 0;
4806c23d075SBarry Smith   } else {
481a7e14dcfSSatish Balay     /* equality constraint ,i.e., without \xi >= 0 constraint */
4821118d4bcSLisandro Dalcin     if (PetscAbsReal(r) < TOL_R) return 0;
483a7e14dcfSSatish Balay   }
484a7e14dcfSSatish Balay 
485a7e14dcfSSatish Balay   if (r < 0.0) {
486a7e14dcfSSatish Balay     lambdal = lambda;
487a7e14dcfSSatish Balay     rl      = r;
488a7e14dcfSSatish Balay     lambda  = lambda + dlambda;
489a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
490a7e14dcfSSatish Balay     while (r < 0.0 && dlambda < BMRM_INFTY) {
491a7e14dcfSSatish Balay       lambdal = lambda;
492a7e14dcfSSatish Balay       s       = rl / r - 1.0;
493a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
494a7e14dcfSSatish Balay       dlambda = dlambda + dlambda / s;
495a7e14dcfSSatish Balay       lambda  = lambda + dlambda;
496a7e14dcfSSatish Balay       rl      = r;
497a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
498a7e14dcfSSatish Balay     }
499a7e14dcfSSatish Balay     lambdau = lambda;
500a7e14dcfSSatish Balay     ru      = r;
5016c23d075SBarry Smith   } else {
502a7e14dcfSSatish Balay     lambdau = lambda;
503a7e14dcfSSatish Balay     ru      = r;
504a7e14dcfSSatish Balay     lambda  = lambda - dlambda;
505a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
506a7e14dcfSSatish Balay     while (r > 0.0 && dlambda > -BMRM_INFTY) {
507a7e14dcfSSatish Balay       lambdau = lambda;
508a7e14dcfSSatish Balay       s       = ru / r - 1.0;
509a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
510a7e14dcfSSatish Balay       dlambda = dlambda + dlambda / s;
511a7e14dcfSSatish Balay       lambda  = lambda - dlambda;
512a7e14dcfSSatish Balay       ru      = r;
513a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
514a7e14dcfSSatish Balay     }
515a7e14dcfSSatish Balay     lambdal = lambda;
516a7e14dcfSSatish Balay     rl      = r;
517a7e14dcfSSatish Balay   }
518a7e14dcfSSatish Balay 
5193c859ba3SBarry Smith   PetscCheck(PetscAbsReal(dlambda) <= BMRM_INFTY, PETSC_COMM_SELF, PETSC_ERR_PLIB, "L2N2_DaiFletcherPGM detected Infeasible QP problem!");
520a7e14dcfSSatish Balay 
521ad540459SPierre Jolivet   if (ru == 0) return innerIter;
522a7e14dcfSSatish Balay 
523a7e14dcfSSatish Balay   /* Secant Phase */
524a7e14dcfSSatish Balay   s       = 1.0 - rl / ru;
525a7e14dcfSSatish Balay   dlambda = dlambda / s;
526a7e14dcfSSatish Balay   lambda  = lambdau - dlambda;
527a7e14dcfSSatish Balay   r       = phi(x, n, lambda, a, b, c, l, u);
528a7e14dcfSSatish Balay 
5299371c9d4SSatish Balay   while (PetscAbsReal(r) > TOL_R && dlambda > TOL_LAM * (1.0 + PetscAbsReal(lambda)) && innerIter < df->maxProjIter) {
530a7e14dcfSSatish Balay     innerIter++;
531a7e14dcfSSatish Balay     if (r > 0.0) {
532a7e14dcfSSatish Balay       if (s <= 2.0) {
533a7e14dcfSSatish Balay         lambdau = lambda;
534a7e14dcfSSatish Balay         ru      = r;
535a7e14dcfSSatish Balay         s       = 1.0 - rl / ru;
536a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
537a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
53853506e15SBarry Smith       } else {
539a7e14dcfSSatish Balay         s = ru / r - 1.0;
540a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
541a7e14dcfSSatish Balay         dlambda    = (lambdau - lambda) / s;
542a7e14dcfSSatish Balay         lambda_new = 0.75 * lambdal + 0.25 * lambda;
5439371c9d4SSatish Balay         if (lambda_new < (lambda - dlambda)) lambda_new = lambda - dlambda;
544a7e14dcfSSatish Balay         lambdau = lambda;
545a7e14dcfSSatish Balay         ru      = r;
546a7e14dcfSSatish Balay         lambda  = lambda_new;
547a7e14dcfSSatish Balay         s       = (lambdau - lambdal) / (lambdau - lambda);
548a7e14dcfSSatish Balay       }
54953506e15SBarry Smith     } else {
550a7e14dcfSSatish Balay       if (s >= 2.0) {
551a7e14dcfSSatish Balay         lambdal = lambda;
552a7e14dcfSSatish Balay         rl      = r;
553a7e14dcfSSatish Balay         s       = 1.0 - rl / ru;
554a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
555a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
55653506e15SBarry Smith       } else {
557a7e14dcfSSatish Balay         s = rl / r - 1.0;
558a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
559a7e14dcfSSatish Balay         dlambda    = (lambda - lambdal) / s;
560a7e14dcfSSatish Balay         lambda_new = 0.75 * lambdau + 0.25 * lambda;
5619371c9d4SSatish Balay         if (lambda_new > (lambda + dlambda)) lambda_new = lambda + dlambda;
562a7e14dcfSSatish Balay         lambdal = lambda;
563a7e14dcfSSatish Balay         rl      = r;
564a7e14dcfSSatish Balay         lambda  = lambda_new;
565a7e14dcfSSatish Balay         s       = (lambdau - lambdal) / (lambdau - lambda);
566a7e14dcfSSatish Balay       }
567a7e14dcfSSatish Balay     }
568a7e14dcfSSatish Balay     r = phi(x, n, lambda, a, b, c, l, u);
569a7e14dcfSSatish Balay   }
570a7e14dcfSSatish Balay 
571a7e14dcfSSatish Balay   *lam_ext = lambda;
57248a46eb9SPierre Jolivet   if (innerIter >= df->maxProjIter) PetscCall(PetscInfo(NULL, "WARNING: DaiFletcher max iterations\n"));
573a7e14dcfSSatish Balay   return innerIter;
574a7e14dcfSSatish Balay }
575a7e14dcfSSatish Balay 
576*d71ae5a4SJacob Faibussowitsch PetscErrorCode solve(TAO_DF *df)
577*d71ae5a4SJacob Faibussowitsch {
578c599c493SJunchao Zhang   PetscInt    i, j, innerIter, it, it2, luv, info;
579a7e14dcfSSatish Balay   PetscReal   gd, max, ak, bk, akold, bkold, lamnew, alpha, kktlam = 0.0, lam_ext;
580a7e14dcfSSatish Balay   PetscReal   DELTAsv, ProdDELTAsv;
581a7e14dcfSSatish Balay   PetscReal   c, *tempQ;
582a7e14dcfSSatish Balay   PetscReal  *x = df->x, *a = df->a, b = df->b, *l = df->l, *u = df->u, tol = df->tol;
583a7e14dcfSSatish Balay   PetscReal  *tempv = df->tempv, *y = df->y, *g = df->g, *d = df->d, *Qd = df->Qd;
584a7e14dcfSSatish Balay   PetscReal  *xplus = df->xplus, *tplus = df->tplus, *sk = df->sk, *yk = df->yk;
585a7e14dcfSSatish Balay   PetscReal **Q = df->Q, *f = df->f, *t = df->t;
586a7e14dcfSSatish Balay   PetscInt    dim = df->dim, *ipt = df->ipt, *ipt2 = df->ipt2, *uv = df->uv;
587a7e14dcfSSatish Balay 
5880e3d61c9SBarry Smith   /* variables for the adaptive nonmonotone linesearch */
589a7e14dcfSSatish Balay   PetscInt  L, llast;
590a7e14dcfSSatish Balay   PetscReal fr, fbest, fv, fc, fv0;
59153506e15SBarry Smith 
592a7e14dcfSSatish Balay   c = BMRM_INFTY;
593a7e14dcfSSatish Balay 
594a7e14dcfSSatish Balay   DELTAsv = EPS_SV;
59553506e15SBarry Smith   if (tol <= 1.0e-5 || dim <= 20) ProdDELTAsv = 0.0F;
59653506e15SBarry Smith   else ProdDELTAsv = EPS_SV;
597a7e14dcfSSatish Balay 
59853506e15SBarry Smith   for (i = 0; i < dim; i++) tempv[i] = -x[i];
599a7e14dcfSSatish Balay 
600a7e14dcfSSatish Balay   lam_ext = 0.0;
601a7e14dcfSSatish Balay 
602a7e14dcfSSatish Balay   /* Project the initial solution */
603bd026e97SJed Brown   project(dim, a, b, tempv, l, u, x, &lam_ext, df);
604a7e14dcfSSatish Balay 
605a7e14dcfSSatish Balay   /* Compute gradient
606a7e14dcfSSatish Balay      g = Q*x + f; */
607a7e14dcfSSatish Balay 
608a7e14dcfSSatish Balay   it = 0;
60953506e15SBarry Smith   for (i = 0; i < dim; i++) {
6101118d4bcSLisandro Dalcin     if (PetscAbsReal(x[i]) > ProdDELTAsv) ipt[it++] = i;
61153506e15SBarry Smith   }
612a7e14dcfSSatish Balay 
6139566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(t, dim));
614a7e14dcfSSatish Balay   for (i = 0; i < it; i++) {
615a7e14dcfSSatish Balay     tempQ = Q[ipt[i]];
61653506e15SBarry Smith     for (j = 0; j < dim; j++) t[j] += (tempQ[j] * x[ipt[i]]);
617a7e14dcfSSatish Balay   }
618ad540459SPierre Jolivet   for (i = 0; i < dim; i++) g[i] = t[i] + f[i];
619a7e14dcfSSatish Balay 
620a7e14dcfSSatish Balay   /* y = -(x_{k} - g_{k}) */
621ad540459SPierre Jolivet   for (i = 0; i < dim; i++) y[i] = g[i] - x[i];
622a7e14dcfSSatish Balay 
623a7e14dcfSSatish Balay   /* Project x_{k} - g_{k} */
624bd026e97SJed Brown   project(dim, a, b, y, l, u, tempv, &lam_ext, df);
625a7e14dcfSSatish Balay 
626a7e14dcfSSatish Balay   /* y = P(x_{k} - g_{k}) - x_{k} */
627a7e14dcfSSatish Balay   max = ALPHA_MIN;
628a7e14dcfSSatish Balay   for (i = 0; i < dim; i++) {
629a7e14dcfSSatish Balay     y[i] = tempv[i] - x[i];
6301118d4bcSLisandro Dalcin     if (PetscAbsReal(y[i]) > max) max = PetscAbsReal(y[i]);
631a7e14dcfSSatish Balay   }
632a7e14dcfSSatish Balay 
633ad540459SPierre Jolivet   if (max < tol * 1e-3) return 0;
634a7e14dcfSSatish Balay 
635a7e14dcfSSatish Balay   alpha = 1.0 / max;
636a7e14dcfSSatish Balay 
637a7e14dcfSSatish Balay   /* fv0 = f(x_{0}). Recall t = Q x_{k}  */
638a7e14dcfSSatish Balay   fv0 = 0.0;
63953506e15SBarry Smith   for (i = 0; i < dim; i++) fv0 += x[i] * (0.5 * t[i] + f[i]);
640a7e14dcfSSatish Balay 
6410e3d61c9SBarry Smith   /* adaptive nonmonotone linesearch */
642a7e14dcfSSatish Balay   L     = 2;
643a7e14dcfSSatish Balay   fr    = ALPHA_MAX;
644a7e14dcfSSatish Balay   fbest = fv0;
645a7e14dcfSSatish Balay   fc    = fv0;
646a7e14dcfSSatish Balay   llast = 0;
647a7e14dcfSSatish Balay   akold = bkold = 0.0;
648a7e14dcfSSatish Balay 
6490e3d61c9SBarry Smith   /*     Iterator begins     */
650a7e14dcfSSatish Balay   for (innerIter = 1; innerIter <= df->maxPGMIter; innerIter++) {
651a7e14dcfSSatish Balay     /* tempv = -(x_{k} - alpha*g_{k}) */
65253506e15SBarry Smith     for (i = 0; i < dim; i++) tempv[i] = alpha * g[i] - x[i];
653a7e14dcfSSatish Balay 
654a7e14dcfSSatish Balay     /* Project x_{k} - alpha*g_{k} */
655bd026e97SJed Brown     project(dim, a, b, tempv, l, u, y, &lam_ext, df);
656a7e14dcfSSatish Balay 
657a7e14dcfSSatish Balay     /* gd = \inner{d_{k}}{g_{k}}
658a7e14dcfSSatish Balay         d = P(x_{k} - alpha*g_{k}) - x_{k}
659a7e14dcfSSatish Balay     */
660a7e14dcfSSatish Balay     gd = 0.0;
661a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
662a7e14dcfSSatish Balay       d[i] = y[i] - x[i];
663a7e14dcfSSatish Balay       gd += d[i] * g[i];
664a7e14dcfSSatish Balay     }
665a7e14dcfSSatish Balay 
666a7e14dcfSSatish Balay     /* Gradient computation  */
667a7e14dcfSSatish Balay 
668a7e14dcfSSatish Balay     /* compute Qd = Q*d  or  Qd = Q*y - t depending on their sparsity */
669a7e14dcfSSatish Balay 
670a7e14dcfSSatish Balay     it = it2 = 0;
67153506e15SBarry Smith     for (i = 0; i < dim; i++) {
6721118d4bcSLisandro Dalcin       if (PetscAbsReal(d[i]) > (ProdDELTAsv * 1.0e-2)) ipt[it++] = i;
67353506e15SBarry Smith     }
67453506e15SBarry Smith     for (i = 0; i < dim; i++) {
6751118d4bcSLisandro Dalcin       if (PetscAbsReal(y[i]) > ProdDELTAsv) ipt2[it2++] = i;
67653506e15SBarry Smith     }
677a7e14dcfSSatish Balay 
6789566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(Qd, dim));
679a7e14dcfSSatish Balay     /* compute Qd = Q*d */
680a7e14dcfSSatish Balay     if (it < it2) {
681a7e14dcfSSatish Balay       for (i = 0; i < it; i++) {
682a7e14dcfSSatish Balay         tempQ = Q[ipt[i]];
68353506e15SBarry Smith         for (j = 0; j < dim; j++) Qd[j] += (tempQ[j] * d[ipt[i]]);
684a7e14dcfSSatish Balay       }
68553506e15SBarry Smith     } else { /* compute Qd = Q*y-t */
686a7e14dcfSSatish Balay       for (i = 0; i < it2; i++) {
687a7e14dcfSSatish Balay         tempQ = Q[ipt2[i]];
68853506e15SBarry Smith         for (j = 0; j < dim; j++) Qd[j] += (tempQ[j] * y[ipt2[i]]);
689a7e14dcfSSatish Balay       }
69053506e15SBarry Smith       for (j = 0; j < dim; j++) Qd[j] -= t[j];
691a7e14dcfSSatish Balay     }
692a7e14dcfSSatish Balay 
693a7e14dcfSSatish Balay     /* ak = inner{d_{k}}{d_{k}} */
694a7e14dcfSSatish Balay     ak = 0.0;
69553506e15SBarry Smith     for (i = 0; i < dim; i++) ak += d[i] * d[i];
696a7e14dcfSSatish Balay 
697a7e14dcfSSatish Balay     bk = 0.0;
69853506e15SBarry Smith     for (i = 0; i < dim; i++) bk += d[i] * Qd[i];
699a7e14dcfSSatish Balay 
70053506e15SBarry Smith     if (bk > EPS * ak && gd < 0.0) lamnew = -gd / bk;
70153506e15SBarry Smith     else lamnew = 1.0;
702a7e14dcfSSatish Balay 
703a7e14dcfSSatish Balay     /* fv is computing f(x_{k} + d_{k}) */
704a7e14dcfSSatish Balay     fv = 0.0;
705a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
706a7e14dcfSSatish Balay       xplus[i] = x[i] + d[i];
707a7e14dcfSSatish Balay       tplus[i] = t[i] + Qd[i];
708a7e14dcfSSatish Balay       fv += xplus[i] * (0.5 * tplus[i] + f[i]);
709a7e14dcfSSatish Balay     }
710a7e14dcfSSatish Balay 
711a7e14dcfSSatish Balay     /* fr is fref */
712a7e14dcfSSatish Balay     if ((innerIter == 1 && fv >= fv0) || (innerIter > 1 && fv >= fr)) {
713a7e14dcfSSatish Balay       fv = 0.0;
714a7e14dcfSSatish Balay       for (i = 0; i < dim; i++) {
715a7e14dcfSSatish Balay         xplus[i] = x[i] + lamnew * d[i];
716a7e14dcfSSatish Balay         tplus[i] = t[i] + lamnew * Qd[i];
717a7e14dcfSSatish Balay         fv += xplus[i] * (0.5 * tplus[i] + f[i]);
718a7e14dcfSSatish Balay       }
719a7e14dcfSSatish Balay     }
720a7e14dcfSSatish Balay 
721a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
722a7e14dcfSSatish Balay       sk[i] = xplus[i] - x[i];
723a7e14dcfSSatish Balay       yk[i] = tplus[i] - t[i];
724a7e14dcfSSatish Balay       x[i]  = xplus[i];
725a7e14dcfSSatish Balay       t[i]  = tplus[i];
726a7e14dcfSSatish Balay       g[i]  = t[i] + f[i];
727a7e14dcfSSatish Balay     }
728a7e14dcfSSatish Balay 
729a7e14dcfSSatish Balay     /* update the line search control parameters */
730a7e14dcfSSatish Balay     if (fv < fbest) {
731a7e14dcfSSatish Balay       fbest = fv;
732a7e14dcfSSatish Balay       fc    = fv;
733a7e14dcfSSatish Balay       llast = 0;
73453506e15SBarry Smith     } else {
735a7e14dcfSSatish Balay       fc = (fc > fv ? fc : fv);
736a7e14dcfSSatish Balay       llast++;
737a7e14dcfSSatish Balay       if (llast == L) {
738a7e14dcfSSatish Balay         fr    = fc;
739a7e14dcfSSatish Balay         fc    = fv;
740a7e14dcfSSatish Balay         llast = 0;
741a7e14dcfSSatish Balay       }
742a7e14dcfSSatish Balay     }
743a7e14dcfSSatish Balay 
744a7e14dcfSSatish Balay     ak = bk = 0.0;
745a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
746a7e14dcfSSatish Balay       ak += sk[i] * sk[i];
747a7e14dcfSSatish Balay       bk += sk[i] * yk[i];
748a7e14dcfSSatish Balay     }
749a7e14dcfSSatish Balay 
75053506e15SBarry Smith     if (bk <= EPS * ak) alpha = ALPHA_MAX;
751a7e14dcfSSatish Balay     else {
75253506e15SBarry Smith       if (bkold < EPS * akold) alpha = ak / bk;
75353506e15SBarry Smith       else alpha = (akold + ak) / (bkold + bk);
754a7e14dcfSSatish Balay 
75553506e15SBarry Smith       if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;
75653506e15SBarry Smith       else if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;
757a7e14dcfSSatish Balay     }
758a7e14dcfSSatish Balay 
759a7e14dcfSSatish Balay     akold = ak;
760a7e14dcfSSatish Balay     bkold = bk;
761a7e14dcfSSatish Balay 
7620e3d61c9SBarry Smith     /* stopping criterion based on KKT conditions */
763a7e14dcfSSatish Balay     /* at optimal, gradient of lagrangian w.r.t. x is zero */
764a7e14dcfSSatish Balay 
765a7e14dcfSSatish Balay     bk = 0.0;
76653506e15SBarry Smith     for (i = 0; i < dim; i++) bk += x[i] * x[i];
767a7e14dcfSSatish Balay 
76853506e15SBarry Smith     if (PetscSqrtReal(ak) < tol * 10 * PetscSqrtReal(bk)) {
769a7e14dcfSSatish Balay       it     = 0;
770a7e14dcfSSatish Balay       luv    = 0;
771a7e14dcfSSatish Balay       kktlam = 0.0;
772a7e14dcfSSatish Balay       for (i = 0; i < dim; i++) {
773a7e14dcfSSatish Balay         /* x[i] is active hence lagrange multipliers for box constraints
774a7e14dcfSSatish Balay                 are zero. The lagrange multiplier for ineq. const. is then
775a7e14dcfSSatish Balay                 defined as below
776a7e14dcfSSatish Balay         */
777a7e14dcfSSatish Balay         if ((x[i] > DELTAsv) && (x[i] < c - DELTAsv)) {
778a7e14dcfSSatish Balay           ipt[it++] = i;
779a7e14dcfSSatish Balay           kktlam    = kktlam - a[i] * g[i];
78053506e15SBarry Smith         } else uv[luv++] = i;
781a7e14dcfSSatish Balay       }
782a7e14dcfSSatish Balay 
78353506e15SBarry Smith       if (it == 0 && PetscSqrtReal(ak) < tol * 0.5 * PetscSqrtReal(bk)) return 0;
784a7e14dcfSSatish Balay       else {
785a7e14dcfSSatish Balay         kktlam = kktlam / it;
786a7e14dcfSSatish Balay         info   = 1;
787a7e14dcfSSatish Balay         for (i = 0; i < it; i++) {
7881118d4bcSLisandro Dalcin           if (PetscAbsReal(a[ipt[i]] * g[ipt[i]] + kktlam) > tol) {
789a7e14dcfSSatish Balay             info = 0;
790a7e14dcfSSatish Balay             break;
791a7e14dcfSSatish Balay           }
792a7e14dcfSSatish Balay         }
793a7e14dcfSSatish Balay         if (info == 1) {
794a7e14dcfSSatish Balay           for (i = 0; i < luv; i++) {
795a7e14dcfSSatish Balay             if (x[uv[i]] <= DELTAsv) {
796a7e14dcfSSatish Balay               /* x[i] == lower bound, hence, lagrange multiplier (say, beta) for lower bound may
797a7e14dcfSSatish Balay                      not be zero. So, the gradient without beta is > 0
798a7e14dcfSSatish Balay               */
799a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam * a[uv[i]] < -tol) {
800a7e14dcfSSatish Balay                 info = 0;
801a7e14dcfSSatish Balay                 break;
802a7e14dcfSSatish Balay               }
80353506e15SBarry Smith             } else {
804a7e14dcfSSatish Balay               /* x[i] == upper bound, hence, lagrange multiplier (say, eta) for upper bound may
805a7e14dcfSSatish Balay                      not be zero. So, the gradient without eta is < 0
806a7e14dcfSSatish Balay               */
807a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam * a[uv[i]] > tol) {
808a7e14dcfSSatish Balay                 info = 0;
809a7e14dcfSSatish Balay                 break;
810a7e14dcfSSatish Balay               }
811a7e14dcfSSatish Balay             }
812a7e14dcfSSatish Balay           }
813a7e14dcfSSatish Balay         }
814a7e14dcfSSatish Balay 
81553506e15SBarry Smith         if (info == 1) return 0;
816a7e14dcfSSatish Balay       }
817a7e14dcfSSatish Balay     }
818a7e14dcfSSatish Balay   }
819a7e14dcfSSatish Balay   return 0;
820a7e14dcfSSatish Balay }
821