xref: /petsc/src/tao/unconstrained/impls/bmrm/bmrm.c (revision d0609ced746bc51b019815ca91d747429db24893)
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 
19a7e14dcfSSatish Balay static PetscErrorCode make_grad_node(Vec X, Vec_Chain **p)
20a7e14dcfSSatish Balay {
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 
29a7e14dcfSSatish Balay static PetscErrorCode destroy_grad_list(Vec_Chain *head)
30a7e14dcfSSatish Balay {
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 
44441846f8SBarry Smith static PetscErrorCode TaoSolve_BMRM(Tao tao)
45a7e14dcfSSatish Balay {
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));
969566063dSJacob Faibussowitsch   PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
973ecd9318SAlp Dener 
983ecd9318SAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
99e1e80dc8SAlp Dener     /* Call general purpose update function */
100e1e80dc8SAlp Dener     if (tao->ops->update) {
1019566063dSJacob Faibussowitsch       PetscCall((*tao->ops->update)(tao, tao->niter, tao->user_update));
102e1e80dc8SAlp Dener     }
103e1e80dc8SAlp Dener 
104a7e14dcfSSatish Balay     /* compute bt = Remp(Wt-1) - <Wt-1, At> */
1059566063dSJacob Faibussowitsch     PetscCall(VecDot(W, G, &bt));
106a7e14dcfSSatish Balay     bt = f - bt;
107a7e14dcfSSatish Balay 
1089dddd249SSatish Balay     /* First gather the gradient to the rank-0 node */
1099566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD));
1109566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD));
111a7e14dcfSSatish Balay 
112a7e14dcfSSatish Balay     /* Bring up the inner solver */
113dd400576SPatrick Sanan     if (rank == 0) {
1149566063dSJacob Faibussowitsch       PetscCall(ensure_df_space(tao->niter+1, &df));
1159566063dSJacob Faibussowitsch       PetscCall(make_grad_node(bmrm->local_w, &pgrad));
116a7e14dcfSSatish Balay       tail_glist->next = pgrad;
117a7e14dcfSSatish Balay       tail_glist = pgrad;
118a7e14dcfSSatish Balay 
1198931d482SJason Sarich       df.a[tao->niter] = 1.0;
1208931d482SJason Sarich       df.f[tao->niter] = -bt;
1218931d482SJason Sarich       df.u[tao->niter] = 1.0;
1228931d482SJason Sarich       df.l[tao->niter] = 0.0;
123a7e14dcfSSatish Balay 
124a7e14dcfSSatish Balay       /* set up the Q */
125a7e14dcfSSatish Balay       pgrad = grad_list.next;
1268931d482SJason Sarich       for (i=0; i<=tao->niter; i++) {
1273c859ba3SBarry Smith         PetscCheck(pgrad,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Assert that there are at least tao->niter+1 pgrad available");
1289566063dSJacob Faibussowitsch         PetscCall(VecDot(pgrad->V, bmrm->local_w, &reg));
1298931d482SJason Sarich         df.Q[i][tao->niter] = df.Q[tao->niter][i] = reg / lambda;
130a7e14dcfSSatish Balay         pgrad = pgrad->next;
131a7e14dcfSSatish Balay       }
132a7e14dcfSSatish Balay 
1338931d482SJason Sarich       if (tao->niter > 0) {
1348931d482SJason Sarich         df.x[tao->niter] = 0.0;
1359566063dSJacob Faibussowitsch         PetscCall(solve(&df));
1360e660641SBarry Smith       } else
137a7e14dcfSSatish Balay         df.x[0] = 1.0;
138a7e14dcfSSatish Balay 
139a7e14dcfSSatish Balay       /* now computing Jt*(alpha_t) which should be = Jt(wt) to check convergence */
140a7e14dcfSSatish Balay       jtwt = 0.0;
1419566063dSJacob Faibussowitsch       PetscCall(VecSet(bmrm->local_w, 0.0));
142a7e14dcfSSatish Balay       pgrad = grad_list.next;
1438931d482SJason Sarich       for (i=0; i<=tao->niter; i++) {
144a7e14dcfSSatish Balay         jtwt -= df.x[i] * df.f[i];
1459566063dSJacob Faibussowitsch         PetscCall(VecAXPY(bmrm->local_w, -df.x[i] / lambda, pgrad->V));
146a7e14dcfSSatish Balay         pgrad = pgrad->next;
147a7e14dcfSSatish Balay       }
148a7e14dcfSSatish Balay 
1499566063dSJacob Faibussowitsch       PetscCall(VecNorm(bmrm->local_w, NORM_2, &reg));
150a7e14dcfSSatish Balay       reg = 0.5*lambda*reg*reg;
151a7e14dcfSSatish Balay       jtwt -= reg;
152a7e14dcfSSatish Balay     } /* end if rank == 0 */
153a7e14dcfSSatish Balay 
154a7e14dcfSSatish Balay     /* scatter the new W to all nodes */
1559566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(bmrm->scatter,bmrm->local_w,W,INSERT_VALUES,SCATTER_REVERSE));
1569566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(bmrm->scatter,bmrm->local_w,W,INSERT_VALUES,SCATTER_REVERSE));
157a7e14dcfSSatish Balay 
1589566063dSJacob Faibussowitsch     PetscCall(TaoComputeObjectiveAndGradient(tao, W, &f, G));
159a7e14dcfSSatish Balay 
1609566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&jtwt,1,MPIU_REAL,0,comm));
1619566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Bcast(&reg,1,MPIU_REAL,0,comm));
162a7e14dcfSSatish Balay 
163a7e14dcfSSatish Balay     jw = reg + f;                                       /* J(w) = regularizer + Remp(w) */
1640e660641SBarry Smith     if (jw < min_jw) min_jw = jw;
1650e660641SBarry Smith     if (jtwt > max_jtwt) max_jtwt = jtwt;
166a7e14dcfSSatish Balay 
167a7e14dcfSSatish Balay     pre_epsilon = epsilon;
168a7e14dcfSSatish Balay     epsilon = min_jw - jtwt;
169a7e14dcfSSatish Balay 
170dd400576SPatrick Sanan     if (rank == 0) {
1710e660641SBarry Smith       if (innerSolverTol > epsilon) innerSolverTol = epsilon;
1720e660641SBarry Smith       else if (innerSolverTol < 1e-7) innerSolverTol = 1e-7;
173a7e14dcfSSatish Balay 
174a7e14dcfSSatish Balay       /* if the annealing doesn't work well, lower the inner solver tolerance */
1750e660641SBarry Smith       if (pre_epsilon < epsilon) innerSolverTol *= 0.2;
176a7e14dcfSSatish Balay 
177a7e14dcfSSatish Balay       df.tol = innerSolverTol*0.5;
178a7e14dcfSSatish Balay     }
179a7e14dcfSSatish Balay 
1808931d482SJason Sarich     tao->niter++;
1819566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao,min_jw,epsilon,0.0,tao->ksp_its));
1829566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao,tao->niter,min_jw,epsilon,0.0,tao->step));
1839566063dSJacob Faibussowitsch     PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
184a7e14dcfSSatish Balay   }
185a7e14dcfSSatish Balay 
186a7e14dcfSSatish Balay   /* free all the memory */
187dd400576SPatrick Sanan   if (rank == 0) {
1889566063dSJacob Faibussowitsch     PetscCall(destroy_grad_list(&grad_list));
1899566063dSJacob Faibussowitsch     PetscCall(destroy_df_solver(&df));
190a7e14dcfSSatish Balay   }
191a7e14dcfSSatish Balay 
1929566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&bmrm->local_w));
1939566063dSJacob Faibussowitsch   PetscCall(VecScatterDestroy(&bmrm->scatter));
194a7e14dcfSSatish Balay   PetscFunctionReturn(0);
195a7e14dcfSSatish Balay }
196a7e14dcfSSatish Balay 
197a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
198a7e14dcfSSatish Balay 
199441846f8SBarry Smith static PetscErrorCode TaoSetup_BMRM(Tao tao)
2000e660641SBarry Smith {
201a7e14dcfSSatish Balay   PetscFunctionBegin;
202a7e14dcfSSatish Balay   /* Allocate some arrays */
2039566063dSJacob Faibussowitsch   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
204a7e14dcfSSatish Balay   PetscFunctionReturn(0);
205a7e14dcfSSatish Balay }
206a7e14dcfSSatish Balay 
207a7e14dcfSSatish Balay /*------------------------------------------------------------*/
208441846f8SBarry Smith static PetscErrorCode TaoDestroy_BMRM(Tao tao)
209a7e14dcfSSatish Balay {
210a7e14dcfSSatish Balay   PetscFunctionBegin;
2119566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
212a7e14dcfSSatish Balay   PetscFunctionReturn(0);
213a7e14dcfSSatish Balay }
214a7e14dcfSSatish Balay 
2154416b707SBarry Smith static PetscErrorCode TaoSetFromOptions_BMRM(PetscOptionItems *PetscOptionsObject,Tao tao)
216a7e14dcfSSatish Balay {
217a7e14dcfSSatish Balay   TAO_BMRM*      bmrm = (TAO_BMRM*)tao->data;
218a7e14dcfSSatish Balay 
219a7e14dcfSSatish Balay   PetscFunctionBegin;
220*d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"BMRM for regularized risk minimization");
2219566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_bmrm_lambda", "regulariser weight","", 100,&bmrm->lambda,NULL));
222*d0609cedSBarry Smith   PetscOptionsHeadEnd();
223a7e14dcfSSatish Balay   PetscFunctionReturn(0);
224a7e14dcfSSatish Balay }
225a7e14dcfSSatish Balay 
226a7e14dcfSSatish Balay /*------------------------------------------------------------*/
227441846f8SBarry Smith static PetscErrorCode TaoView_BMRM(Tao tao, PetscViewer viewer)
228a7e14dcfSSatish Balay {
229a7e14dcfSSatish Balay   PetscBool      isascii;
230a7e14dcfSSatish Balay 
231a7e14dcfSSatish Balay   PetscFunctionBegin;
2329566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii));
233a7e14dcfSSatish Balay   if (isascii) {
2349566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
2359566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
236a7e14dcfSSatish Balay   }
237a7e14dcfSSatish Balay   PetscFunctionReturn(0);
238a7e14dcfSSatish Balay }
239a7e14dcfSSatish Balay 
240a7e14dcfSSatish Balay /*------------------------------------------------------------*/
2411522df2eSJason Sarich /*MC
2421522df2eSJason Sarich   TAOBMRM - bundle method for regularized risk minimization
2431522df2eSJason Sarich 
2441522df2eSJason Sarich   Options Database Keys:
2451522df2eSJason Sarich . - tao_bmrm_lambda - regulariser weight
2461522df2eSJason Sarich 
2471eb8069cSJason Sarich   Level: beginner
2481522df2eSJason Sarich M*/
2491522df2eSJason Sarich 
250728e0ed0SBarry Smith PETSC_EXTERN PetscErrorCode TaoCreate_BMRM(Tao tao)
251a7e14dcfSSatish Balay {
252a7e14dcfSSatish Balay   TAO_BMRM       *bmrm;
253a7e14dcfSSatish Balay 
254a7e14dcfSSatish Balay   PetscFunctionBegin;
255a7e14dcfSSatish Balay   tao->ops->setup = TaoSetup_BMRM;
256a7e14dcfSSatish Balay   tao->ops->solve = TaoSolve_BMRM;
257a7e14dcfSSatish Balay   tao->ops->view  = TaoView_BMRM;
258a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_BMRM;
259a7e14dcfSSatish Balay   tao->ops->destroy = TaoDestroy_BMRM;
260a7e14dcfSSatish Balay 
2619566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(tao,&bmrm));
262a7e14dcfSSatish Balay   bmrm->lambda = 1.0;
263a7e14dcfSSatish Balay   tao->data = (void*)bmrm;
264a7e14dcfSSatish Balay 
2656552cf8aSJason Sarich   /* Override default settings (unless already changed) */
2666552cf8aSJason Sarich   if (!tao->max_it_changed) tao->max_it = 2000;
2676552cf8aSJason Sarich   if (!tao->max_funcs_changed) tao->max_funcs = 4000;
2686552cf8aSJason Sarich   if (!tao->gatol_changed) tao->gatol = 1.0e-12;
2696552cf8aSJason Sarich   if (!tao->grtol_changed) tao->grtol = 1.0e-12;
270a7e14dcfSSatish Balay 
271a7e14dcfSSatish Balay   PetscFunctionReturn(0);
272a7e14dcfSSatish Balay }
273a7e14dcfSSatish Balay 
274a7e14dcfSSatish Balay PetscErrorCode init_df_solver(TAO_DF *df)
275a7e14dcfSSatish Balay {
276a7e14dcfSSatish Balay   PetscInt       i, n = INCRE_DIM;
277a7e14dcfSSatish Balay 
278a7e14dcfSSatish Balay   PetscFunctionBegin;
279a7e14dcfSSatish Balay   /* default values */
280a7e14dcfSSatish Balay   df->maxProjIter = 200;
281a7e14dcfSSatish Balay   df->maxPGMIter = 300000;
282a7e14dcfSSatish Balay   df->b = 1.0;
283a7e14dcfSSatish Balay 
284a7e14dcfSSatish Balay   /* memory space required by Dai-Fletcher */
285a7e14dcfSSatish Balay   df->cur_num_cp = n;
2869566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->f));
2879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->a));
2889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->l));
2899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->u));
2909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->x));
2919566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Q));
292a7e14dcfSSatish Balay 
293a7e14dcfSSatish Balay   for (i = 0; i < n; i ++) {
2949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &df->Q[i]));
295a7e14dcfSSatish Balay   }
296a7e14dcfSSatish Balay 
2979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->g));
2989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->y));
2999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tempv));
3009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->d));
3019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Qd));
3029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->t));
3039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->xplus));
3049566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tplus));
3059566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->sk));
3069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->yk));
307a7e14dcfSSatish Balay 
3089566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt));
3099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt2));
3109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->uv));
311a7e14dcfSSatish Balay   PetscFunctionReturn(0);
312a7e14dcfSSatish Balay }
313a7e14dcfSSatish Balay 
314a7e14dcfSSatish Balay PetscErrorCode ensure_df_space(PetscInt dim, TAO_DF *df)
315a7e14dcfSSatish Balay {
316a7e14dcfSSatish Balay   PetscReal      *tmp, **tmp_Q;
317a7e14dcfSSatish Balay   PetscInt       i, n, old_n;
318a7e14dcfSSatish Balay 
319a7e14dcfSSatish Balay   PetscFunctionBegin;
32053506e15SBarry Smith   df->dim = dim;
32153506e15SBarry Smith   if (dim <= df->cur_num_cp) PetscFunctionReturn(0);
322a7e14dcfSSatish Balay 
323a7e14dcfSSatish Balay   old_n = df->cur_num_cp;
324a7e14dcfSSatish Balay   df->cur_num_cp += INCRE_DIM;
325a7e14dcfSSatish Balay   n = df->cur_num_cp;
326a7e14dcfSSatish Balay 
327a7e14dcfSSatish Balay   /* memory space required by dai-fletcher */
3289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3299566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->f, old_n));
3309566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->f));
331a7e14dcfSSatish Balay   df->f = tmp;
332a7e14dcfSSatish Balay 
3339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3349566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->a, old_n));
3359566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->a));
336a7e14dcfSSatish Balay   df->a = tmp;
337a7e14dcfSSatish Balay 
3389566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3399566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->l, old_n));
3409566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->l));
341a7e14dcfSSatish Balay   df->l = tmp;
342a7e14dcfSSatish Balay 
3439566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3449566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->u, old_n));
3459566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->u));
346a7e14dcfSSatish Balay   df->u = tmp;
347a7e14dcfSSatish Balay 
3489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp));
3499566063dSJacob Faibussowitsch   PetscCall(PetscArraycpy(tmp, df->x, old_n));
3509566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->x));
351a7e14dcfSSatish Balay   df->x = tmp;
352a7e14dcfSSatish Balay 
3539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &tmp_Q));
35453506e15SBarry Smith   for (i = 0; i < n; i ++) {
3559566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(n, &tmp_Q[i]));
35653506e15SBarry Smith     if (i < old_n) {
3579566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(tmp_Q[i], df->Q[i], old_n));
3589566063dSJacob Faibussowitsch       PetscCall(PetscFree(df->Q[i]));
359a7e14dcfSSatish Balay     }
360a7e14dcfSSatish Balay   }
361a7e14dcfSSatish Balay 
3629566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Q));
363a7e14dcfSSatish Balay   df->Q = tmp_Q;
364a7e14dcfSSatish Balay 
3659566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->g));
3669566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->g));
367a7e14dcfSSatish Balay 
3689566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->y));
3699566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->y));
370a7e14dcfSSatish Balay 
3719566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tempv));
3729566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tempv));
373a7e14dcfSSatish Balay 
3749566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->d));
3759566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->d));
376a7e14dcfSSatish Balay 
3779566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Qd));
3789566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->Qd));
379a7e14dcfSSatish Balay 
3809566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->t));
3819566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->t));
382a7e14dcfSSatish Balay 
3839566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->xplus));
3849566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->xplus));
385a7e14dcfSSatish Balay 
3869566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tplus));
3879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->tplus));
388a7e14dcfSSatish Balay 
3899566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->sk));
3909566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->sk));
391a7e14dcfSSatish Balay 
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->yk));
3939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->yk));
394a7e14dcfSSatish Balay 
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt));
3969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt));
397a7e14dcfSSatish Balay 
3989566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt2));
3999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->ipt2));
400a7e14dcfSSatish Balay 
4019566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->uv));
4029566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(n, &df->uv));
403a7e14dcfSSatish Balay   PetscFunctionReturn(0);
404a7e14dcfSSatish Balay }
405a7e14dcfSSatish Balay 
406a7e14dcfSSatish Balay PetscErrorCode destroy_df_solver(TAO_DF *df)
407a7e14dcfSSatish Balay {
408a7e14dcfSSatish Balay   PetscInt       i;
4096c23d075SBarry Smith 
410a7e14dcfSSatish Balay   PetscFunctionBegin;
4119566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->f));
4129566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->a));
4139566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->l));
4149566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->u));
4159566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->x));
416a7e14dcfSSatish Balay 
4176c23d075SBarry Smith   for (i = 0; i < df->cur_num_cp; i ++) {
4189566063dSJacob Faibussowitsch     PetscCall(PetscFree(df->Q[i]));
419a7e14dcfSSatish Balay   }
4209566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Q));
4219566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt));
4229566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->ipt2));
4239566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->uv));
4249566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->g));
4259566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->y));
4269566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tempv));
4279566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->d));
4289566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->Qd));
4299566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->t));
4309566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->xplus));
4319566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->tplus));
4329566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->sk));
4339566063dSJacob Faibussowitsch   PetscCall(PetscFree(df->yk));
434a7e14dcfSSatish Balay   PetscFunctionReturn(0);
435a7e14dcfSSatish Balay }
436a7e14dcfSSatish Balay 
437a7e14dcfSSatish Balay /* Piecewise linear monotone target function for the Dai-Fletcher projector */
4386c23d075SBarry Smith PetscReal phi(PetscReal *x,PetscInt n,PetscReal lambda,PetscReal *a,PetscReal b,PetscReal *c,PetscReal *l,PetscReal *u)
439a7e14dcfSSatish Balay {
440a7e14dcfSSatish Balay   PetscReal r = 0.0;
441a7e14dcfSSatish Balay   PetscInt  i;
442a7e14dcfSSatish Balay 
443a7e14dcfSSatish Balay   for (i = 0; i < n; i++) {
444a7e14dcfSSatish Balay     x[i] = -c[i] + lambda*a[i];
4456c23d075SBarry Smith     if (x[i] > u[i])     x[i] = u[i];
4466c23d075SBarry Smith     else if (x[i] < l[i]) x[i] = l[i];
447a7e14dcfSSatish Balay     r += a[i]*x[i];
448a7e14dcfSSatish Balay   }
449a7e14dcfSSatish Balay   return r - b;
450a7e14dcfSSatish Balay }
451a7e14dcfSSatish Balay 
452a7e14dcfSSatish Balay /** Modified Dai-Fletcher QP projector solves the problem:
453a7e14dcfSSatish Balay  *
454a7e14dcfSSatish Balay  *      minimise  0.5*x'*x - c'*x
455a7e14dcfSSatish Balay  *      subj to   a'*x = b
456a7e14dcfSSatish Balay  *                l \leq x \leq u
457a7e14dcfSSatish Balay  *
458a7e14dcfSSatish Balay  *  \param c The point to be projected onto feasible set
459a7e14dcfSSatish Balay  */
4606c23d075SBarry Smith PetscInt project(PetscInt n,PetscReal *a,PetscReal b,PetscReal *c,PetscReal *l,PetscReal *u,PetscReal *x,PetscReal *lam_ext,TAO_DF *df)
461a7e14dcfSSatish Balay {
462a7e14dcfSSatish Balay   PetscReal      lambda, lambdal, lambdau, dlambda, lambda_new;
463a7e14dcfSSatish Balay   PetscReal      r, rl, ru, s;
464a7e14dcfSSatish Balay   PetscInt       innerIter;
465a7e14dcfSSatish Balay   PetscBool      nonNegativeSlack = PETSC_FALSE;
466a7e14dcfSSatish Balay 
467a7e14dcfSSatish Balay   *lam_ext = 0;
468a7e14dcfSSatish Balay   lambda  = 0;
469a7e14dcfSSatish Balay   dlambda = 0.5;
470a7e14dcfSSatish Balay   innerIter = 1;
471a7e14dcfSSatish Balay 
472a7e14dcfSSatish Balay   /*  \phi(x;lambda) := 0.5*x'*x + c'*x - lambda*(a'*x-b)
473a7e14dcfSSatish Balay    *
474a7e14dcfSSatish Balay    *  Optimality conditions for \phi:
475a7e14dcfSSatish Balay    *
476a7e14dcfSSatish Balay    *  1. lambda   <= 0
477a7e14dcfSSatish Balay    *  2. r        <= 0
478a7e14dcfSSatish Balay    *  3. r*lambda == 0
479a7e14dcfSSatish Balay    */
480a7e14dcfSSatish Balay 
481a7e14dcfSSatish Balay   /* Bracketing Phase */
482a7e14dcfSSatish Balay   r = phi(x, n, lambda, a, b, c, l, u);
483a7e14dcfSSatish Balay 
4846c23d075SBarry Smith   if (nonNegativeSlack) {
485a7e14dcfSSatish Balay     /* inequality constraint, i.e., with \xi >= 0 constraint */
48653506e15SBarry Smith     if (r < TOL_R) return 0;
4876c23d075SBarry Smith   } else  {
488a7e14dcfSSatish Balay     /* equality constraint ,i.e., without \xi >= 0 constraint */
4891118d4bcSLisandro Dalcin     if (PetscAbsReal(r) < TOL_R) return 0;
490a7e14dcfSSatish Balay   }
491a7e14dcfSSatish Balay 
492a7e14dcfSSatish Balay   if (r < 0.0) {
493a7e14dcfSSatish Balay     lambdal = lambda;
494a7e14dcfSSatish Balay     rl      = r;
495a7e14dcfSSatish Balay     lambda  = lambda + dlambda;
496a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
497a7e14dcfSSatish Balay     while (r < 0.0 && dlambda < BMRM_INFTY)  {
498a7e14dcfSSatish Balay       lambdal = lambda;
499a7e14dcfSSatish Balay       s       = rl/r - 1.0;
500a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
501a7e14dcfSSatish Balay       dlambda = dlambda + dlambda/s;
502a7e14dcfSSatish Balay       lambda  = lambda + dlambda;
503a7e14dcfSSatish Balay       rl      = r;
504a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
505a7e14dcfSSatish Balay     }
506a7e14dcfSSatish Balay     lambdau = lambda;
507a7e14dcfSSatish Balay     ru      = r;
5086c23d075SBarry Smith   } else {
509a7e14dcfSSatish Balay     lambdau = lambda;
510a7e14dcfSSatish Balay     ru      = r;
511a7e14dcfSSatish Balay     lambda  = lambda - dlambda;
512a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
513a7e14dcfSSatish Balay     while (r > 0.0 && dlambda > -BMRM_INFTY) {
514a7e14dcfSSatish Balay       lambdau = lambda;
515a7e14dcfSSatish Balay       s       = ru/r - 1.0;
516a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
517a7e14dcfSSatish Balay       dlambda = dlambda + dlambda/s;
518a7e14dcfSSatish Balay       lambda  = lambda - dlambda;
519a7e14dcfSSatish Balay       ru      = r;
520a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
521a7e14dcfSSatish Balay     }
522a7e14dcfSSatish Balay     lambdal = lambda;
523a7e14dcfSSatish Balay     rl      = r;
524a7e14dcfSSatish Balay   }
525a7e14dcfSSatish Balay 
5263c859ba3SBarry Smith   PetscCheck(PetscAbsReal(dlambda) <= BMRM_INFTY,PETSC_COMM_SELF,PETSC_ERR_PLIB,"L2N2_DaiFletcherPGM detected Infeasible QP problem!");
527a7e14dcfSSatish Balay 
528a7e14dcfSSatish Balay   if (ru == 0) {
529a7e14dcfSSatish Balay     return innerIter;
530a7e14dcfSSatish Balay   }
531a7e14dcfSSatish Balay 
532a7e14dcfSSatish Balay   /* Secant Phase */
533a7e14dcfSSatish Balay   s       = 1.0 - rl/ru;
534a7e14dcfSSatish Balay   dlambda = dlambda/s;
535a7e14dcfSSatish Balay   lambda  = lambdau - dlambda;
536a7e14dcfSSatish Balay   r       = phi(x, n, lambda, a, b, c, l, u);
537a7e14dcfSSatish Balay 
5381118d4bcSLisandro Dalcin   while (PetscAbsReal(r) > TOL_R
5391118d4bcSLisandro Dalcin          && dlambda > TOL_LAM * (1.0 + PetscAbsReal(lambda))
540a7e14dcfSSatish Balay          && innerIter < df->maxProjIter) {
541a7e14dcfSSatish Balay     innerIter++;
542a7e14dcfSSatish Balay     if (r > 0.0) {
543a7e14dcfSSatish Balay       if (s <= 2.0) {
544a7e14dcfSSatish Balay         lambdau = lambda;
545a7e14dcfSSatish Balay         ru      = r;
546a7e14dcfSSatish Balay         s       = 1.0 - rl/ru;
547a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
548a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
54953506e15SBarry Smith       } else {
550a7e14dcfSSatish Balay         s          = ru/r-1.0;
551a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
552a7e14dcfSSatish Balay         dlambda    = (lambdau - lambda) / s;
553a7e14dcfSSatish Balay         lambda_new = 0.75*lambdal + 0.25*lambda;
554a7e14dcfSSatish Balay         if (lambda_new < (lambda - dlambda))
555a7e14dcfSSatish Balay           lambda_new = lambda - dlambda;
556a7e14dcfSSatish Balay         lambdau    = lambda;
557a7e14dcfSSatish Balay         ru         = r;
558a7e14dcfSSatish Balay         lambda     = lambda_new;
559a7e14dcfSSatish Balay         s          = (lambdau - lambdal) / (lambdau - lambda);
560a7e14dcfSSatish Balay       }
56153506e15SBarry Smith     } else {
562a7e14dcfSSatish Balay       if (s >= 2.0) {
563a7e14dcfSSatish Balay         lambdal = lambda;
564a7e14dcfSSatish Balay         rl      = r;
565a7e14dcfSSatish Balay         s       = 1.0 - rl/ru;
566a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
567a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
56853506e15SBarry Smith       } else {
569a7e14dcfSSatish Balay         s          = rl/r - 1.0;
570a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
571a7e14dcfSSatish Balay         dlambda    = (lambda-lambdal) / s;
572a7e14dcfSSatish Balay         lambda_new = 0.75*lambdau + 0.25*lambda;
573a7e14dcfSSatish Balay         if (lambda_new > (lambda + dlambda))
574a7e14dcfSSatish Balay           lambda_new = lambda + dlambda;
575a7e14dcfSSatish Balay         lambdal    = lambda;
576a7e14dcfSSatish Balay         rl         = r;
577a7e14dcfSSatish Balay         lambda     = lambda_new;
578a7e14dcfSSatish Balay         s          = (lambdau - lambdal) / (lambdau-lambda);
579a7e14dcfSSatish Balay       }
580a7e14dcfSSatish Balay     }
581a7e14dcfSSatish Balay     r = phi(x, n, lambda, a, b, c, l, u);
582a7e14dcfSSatish Balay   }
583a7e14dcfSSatish Balay 
584a7e14dcfSSatish Balay   *lam_ext = lambda;
58553506e15SBarry Smith   if (innerIter >= df->maxProjIter) {
5869566063dSJacob Faibussowitsch     PetscCall(PetscInfo(NULL,"WARNING: DaiFletcher max iterations\n"));
58753506e15SBarry Smith   }
588a7e14dcfSSatish Balay   return innerIter;
589a7e14dcfSSatish Balay }
590a7e14dcfSSatish Balay 
591a7e14dcfSSatish Balay PetscErrorCode solve(TAO_DF *df)
592a7e14dcfSSatish Balay {
593bd026e97SJed Brown   PetscInt       i, j, innerIter, it, it2, luv, info, lscount = 0;
594a7e14dcfSSatish Balay   PetscReal      gd, max, ak, bk, akold, bkold, lamnew, alpha, kktlam=0.0, lam_ext;
595a7e14dcfSSatish Balay   PetscReal      DELTAsv, ProdDELTAsv;
596a7e14dcfSSatish Balay   PetscReal      c, *tempQ;
597a7e14dcfSSatish Balay   PetscReal      *x = df->x, *a = df->a, b = df->b, *l = df->l, *u = df->u, tol = df->tol;
598a7e14dcfSSatish Balay   PetscReal      *tempv = df->tempv, *y = df->y, *g = df->g, *d = df->d, *Qd = df->Qd;
599a7e14dcfSSatish Balay   PetscReal      *xplus = df->xplus, *tplus = df->tplus, *sk = df->sk, *yk = df->yk;
600a7e14dcfSSatish Balay   PetscReal      **Q = df->Q, *f = df->f, *t = df->t;
601a7e14dcfSSatish Balay   PetscInt       dim = df->dim, *ipt = df->ipt, *ipt2 = df->ipt2, *uv = df->uv;
602a7e14dcfSSatish Balay 
6030e3d61c9SBarry Smith   /* variables for the adaptive nonmonotone linesearch */
604a7e14dcfSSatish Balay   PetscInt    L, llast;
605a7e14dcfSSatish Balay   PetscReal   fr, fbest, fv, fc, fv0;
60653506e15SBarry Smith 
607a7e14dcfSSatish Balay   c = BMRM_INFTY;
608a7e14dcfSSatish Balay 
609a7e14dcfSSatish Balay   DELTAsv = EPS_SV;
61053506e15SBarry Smith   if (tol <= 1.0e-5 || dim <= 20) ProdDELTAsv = 0.0F;
61153506e15SBarry Smith   else  ProdDELTAsv = EPS_SV;
612a7e14dcfSSatish Balay 
61353506e15SBarry Smith   for (i = 0; i < dim; i++)  tempv[i] = -x[i];
614a7e14dcfSSatish Balay 
615a7e14dcfSSatish Balay   lam_ext = 0.0;
616a7e14dcfSSatish Balay 
617a7e14dcfSSatish Balay   /* Project the initial solution */
618bd026e97SJed Brown   project(dim, a, b, tempv, l, u, x, &lam_ext, df);
619a7e14dcfSSatish Balay 
620a7e14dcfSSatish Balay   /* Compute gradient
621a7e14dcfSSatish Balay      g = Q*x + f; */
622a7e14dcfSSatish Balay 
623a7e14dcfSSatish Balay   it = 0;
62453506e15SBarry Smith   for (i = 0; i < dim; i++) {
6251118d4bcSLisandro Dalcin     if (PetscAbsReal(x[i]) > ProdDELTAsv) ipt[it++] = i;
62653506e15SBarry Smith   }
627a7e14dcfSSatish Balay 
6289566063dSJacob Faibussowitsch   PetscCall(PetscArrayzero(t, dim));
629a7e14dcfSSatish Balay   for (i = 0; i < it; i++) {
630a7e14dcfSSatish Balay     tempQ = Q[ipt[i]];
63153506e15SBarry Smith     for (j = 0; j < dim; j++) t[j] += (tempQ[j]*x[ipt[i]]);
632a7e14dcfSSatish Balay   }
633a7e14dcfSSatish Balay   for (i = 0; i < dim; i++) {
634a7e14dcfSSatish Balay     g[i] = t[i] + f[i];
635a7e14dcfSSatish Balay   }
636a7e14dcfSSatish Balay 
637a7e14dcfSSatish Balay   /* y = -(x_{k} - g_{k}) */
638a7e14dcfSSatish Balay   for (i = 0; i < dim; i++) {
639a7e14dcfSSatish Balay     y[i] = g[i] - x[i];
640a7e14dcfSSatish Balay   }
641a7e14dcfSSatish Balay 
642a7e14dcfSSatish Balay   /* Project x_{k} - g_{k} */
643bd026e97SJed Brown   project(dim, a, b, y, l, u, tempv, &lam_ext, df);
644a7e14dcfSSatish Balay 
645a7e14dcfSSatish Balay   /* y = P(x_{k} - g_{k}) - x_{k} */
646a7e14dcfSSatish Balay   max = ALPHA_MIN;
647a7e14dcfSSatish Balay   for (i = 0; i < dim; i++) {
648a7e14dcfSSatish Balay     y[i] = tempv[i] - x[i];
6491118d4bcSLisandro Dalcin     if (PetscAbsReal(y[i]) > max) max = PetscAbsReal(y[i]);
650a7e14dcfSSatish Balay   }
651a7e14dcfSSatish Balay 
652a7e14dcfSSatish Balay   if (max < tol*1e-3) {
653a7e14dcfSSatish Balay     return 0;
654a7e14dcfSSatish Balay   }
655a7e14dcfSSatish Balay 
656a7e14dcfSSatish Balay   alpha = 1.0 / max;
657a7e14dcfSSatish Balay 
658a7e14dcfSSatish Balay   /* fv0 = f(x_{0}). Recall t = Q x_{k}  */
659a7e14dcfSSatish Balay   fv0   = 0.0;
66053506e15SBarry Smith   for (i = 0; i < dim; i++) fv0 += x[i] * (0.5*t[i] + f[i]);
661a7e14dcfSSatish Balay 
6620e3d61c9SBarry Smith   /* adaptive nonmonotone linesearch */
663a7e14dcfSSatish Balay   L     = 2;
664a7e14dcfSSatish Balay   fr    = ALPHA_MAX;
665a7e14dcfSSatish Balay   fbest = fv0;
666a7e14dcfSSatish Balay   fc    = fv0;
667a7e14dcfSSatish Balay   llast = 0;
668a7e14dcfSSatish Balay   akold = bkold = 0.0;
669a7e14dcfSSatish Balay 
6700e3d61c9SBarry Smith   /*     Iterator begins     */
671a7e14dcfSSatish Balay   for (innerIter = 1; innerIter <= df->maxPGMIter; innerIter++) {
672a7e14dcfSSatish Balay 
673a7e14dcfSSatish Balay     /* tempv = -(x_{k} - alpha*g_{k}) */
67453506e15SBarry Smith     for (i = 0; i < dim; i++)  tempv[i] = alpha*g[i] - x[i];
675a7e14dcfSSatish Balay 
676a7e14dcfSSatish Balay     /* Project x_{k} - alpha*g_{k} */
677bd026e97SJed Brown     project(dim, a, b, tempv, l, u, y, &lam_ext, df);
678a7e14dcfSSatish Balay 
679a7e14dcfSSatish Balay     /* gd = \inner{d_{k}}{g_{k}}
680a7e14dcfSSatish Balay         d = P(x_{k} - alpha*g_{k}) - x_{k}
681a7e14dcfSSatish Balay     */
682a7e14dcfSSatish Balay     gd = 0.0;
683a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
684a7e14dcfSSatish Balay       d[i] = y[i] - x[i];
685a7e14dcfSSatish Balay       gd  += d[i] * g[i];
686a7e14dcfSSatish Balay     }
687a7e14dcfSSatish Balay 
688a7e14dcfSSatish Balay     /* Gradient computation  */
689a7e14dcfSSatish Balay 
690a7e14dcfSSatish Balay     /* compute Qd = Q*d  or  Qd = Q*y - t depending on their sparsity */
691a7e14dcfSSatish Balay 
692a7e14dcfSSatish Balay     it = it2 = 0;
69353506e15SBarry Smith     for (i = 0; i < dim; i++) {
6941118d4bcSLisandro Dalcin       if (PetscAbsReal(d[i]) > (ProdDELTAsv*1.0e-2)) ipt[it++]   = i;
69553506e15SBarry Smith     }
69653506e15SBarry Smith     for (i = 0; i < dim; i++) {
6971118d4bcSLisandro Dalcin       if (PetscAbsReal(y[i]) > ProdDELTAsv) ipt2[it2++] = i;
69853506e15SBarry Smith     }
699a7e14dcfSSatish Balay 
7009566063dSJacob Faibussowitsch     PetscCall(PetscArrayzero(Qd, dim));
701a7e14dcfSSatish Balay     /* compute Qd = Q*d */
702a7e14dcfSSatish Balay     if (it < it2) {
703a7e14dcfSSatish Balay       for (i = 0; i < it; i++) {
704a7e14dcfSSatish Balay         tempQ = Q[ipt[i]];
70553506e15SBarry Smith         for (j = 0; j < dim; j++) Qd[j] += (tempQ[j] * d[ipt[i]]);
706a7e14dcfSSatish Balay       }
70753506e15SBarry Smith     } else { /* compute Qd = Q*y-t */
708a7e14dcfSSatish Balay       for (i = 0; i < it2; i++) {
709a7e14dcfSSatish Balay         tempQ = Q[ipt2[i]];
71053506e15SBarry Smith         for (j = 0; j < dim; j++) Qd[j] += (tempQ[j] * y[ipt2[i]]);
711a7e14dcfSSatish Balay       }
71253506e15SBarry Smith       for (j = 0; j < dim; j++) Qd[j] -= t[j];
713a7e14dcfSSatish Balay     }
714a7e14dcfSSatish Balay 
715a7e14dcfSSatish Balay     /* ak = inner{d_{k}}{d_{k}} */
716a7e14dcfSSatish Balay     ak = 0.0;
71753506e15SBarry Smith     for (i = 0; i < dim; i++) ak += d[i] * d[i];
718a7e14dcfSSatish Balay 
719a7e14dcfSSatish Balay     bk = 0.0;
72053506e15SBarry Smith     for (i = 0; i < dim; i++) bk += d[i]*Qd[i];
721a7e14dcfSSatish Balay 
72253506e15SBarry Smith     if (bk > EPS*ak && gd < 0.0)  lamnew = -gd/bk;
72353506e15SBarry Smith     else lamnew = 1.0;
724a7e14dcfSSatish Balay 
725a7e14dcfSSatish Balay     /* fv is computing f(x_{k} + d_{k}) */
726a7e14dcfSSatish Balay     fv = 0.0;
727a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
728a7e14dcfSSatish Balay       xplus[i] = x[i] + d[i];
729a7e14dcfSSatish Balay       tplus[i] = t[i] + Qd[i];
730a7e14dcfSSatish Balay       fv      += xplus[i] * (0.5*tplus[i] + f[i]);
731a7e14dcfSSatish Balay     }
732a7e14dcfSSatish Balay 
733a7e14dcfSSatish Balay     /* fr is fref */
734a7e14dcfSSatish Balay     if ((innerIter == 1 && fv >= fv0) || (innerIter > 1 && fv >= fr)) {
735a7e14dcfSSatish Balay       lscount++;
736a7e14dcfSSatish Balay       fv = 0.0;
737a7e14dcfSSatish Balay       for (i = 0; i < dim; i++) {
738a7e14dcfSSatish Balay         xplus[i] = x[i] + lamnew*d[i];
739a7e14dcfSSatish Balay         tplus[i] = t[i] + lamnew*Qd[i];
740a7e14dcfSSatish Balay         fv      += xplus[i] * (0.5*tplus[i] + f[i]);
741a7e14dcfSSatish Balay       }
742a7e14dcfSSatish Balay     }
743a7e14dcfSSatish Balay 
744a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
745a7e14dcfSSatish Balay       sk[i] = xplus[i] - x[i];
746a7e14dcfSSatish Balay       yk[i] = tplus[i] - t[i];
747a7e14dcfSSatish Balay       x[i]  = xplus[i];
748a7e14dcfSSatish Balay       t[i]  = tplus[i];
749a7e14dcfSSatish Balay       g[i]  = t[i] + f[i];
750a7e14dcfSSatish Balay     }
751a7e14dcfSSatish Balay 
752a7e14dcfSSatish Balay     /* update the line search control parameters */
753a7e14dcfSSatish Balay     if (fv < fbest) {
754a7e14dcfSSatish Balay       fbest = fv;
755a7e14dcfSSatish Balay       fc    = fv;
756a7e14dcfSSatish Balay       llast = 0;
75753506e15SBarry Smith     } else {
758a7e14dcfSSatish Balay       fc = (fc > fv ? fc : fv);
759a7e14dcfSSatish Balay       llast++;
760a7e14dcfSSatish Balay       if (llast == L) {
761a7e14dcfSSatish Balay         fr    = fc;
762a7e14dcfSSatish Balay         fc    = fv;
763a7e14dcfSSatish Balay         llast = 0;
764a7e14dcfSSatish Balay       }
765a7e14dcfSSatish Balay     }
766a7e14dcfSSatish Balay 
767a7e14dcfSSatish Balay     ak = bk = 0.0;
768a7e14dcfSSatish Balay     for (i = 0; i < dim; i++) {
769a7e14dcfSSatish Balay       ak += sk[i] * sk[i];
770a7e14dcfSSatish Balay       bk += sk[i] * yk[i];
771a7e14dcfSSatish Balay     }
772a7e14dcfSSatish Balay 
77353506e15SBarry Smith     if (bk <= EPS*ak) alpha = ALPHA_MAX;
774a7e14dcfSSatish Balay     else {
77553506e15SBarry Smith       if (bkold < EPS*akold) alpha = ak/bk;
77653506e15SBarry Smith       else alpha = (akold+ak)/(bkold+bk);
777a7e14dcfSSatish Balay 
77853506e15SBarry Smith       if (alpha > ALPHA_MAX) alpha = ALPHA_MAX;
77953506e15SBarry Smith       else if (alpha < ALPHA_MIN) alpha = ALPHA_MIN;
780a7e14dcfSSatish Balay     }
781a7e14dcfSSatish Balay 
782a7e14dcfSSatish Balay     akold = ak;
783a7e14dcfSSatish Balay     bkold = bk;
784a7e14dcfSSatish Balay 
7850e3d61c9SBarry Smith     /* stopping criterion based on KKT conditions */
786a7e14dcfSSatish Balay     /* at optimal, gradient of lagrangian w.r.t. x is zero */
787a7e14dcfSSatish Balay 
788a7e14dcfSSatish Balay     bk = 0.0;
78953506e15SBarry Smith     for (i = 0; i < dim; i++) bk +=  x[i] * x[i];
790a7e14dcfSSatish Balay 
79153506e15SBarry Smith     if (PetscSqrtReal(ak) < tol*10 * PetscSqrtReal(bk)) {
792a7e14dcfSSatish Balay       it     = 0;
793a7e14dcfSSatish Balay       luv    = 0;
794a7e14dcfSSatish Balay       kktlam = 0.0;
795a7e14dcfSSatish Balay       for (i = 0; i < dim; i++) {
796a7e14dcfSSatish Balay         /* x[i] is active hence lagrange multipliers for box constraints
797a7e14dcfSSatish Balay                 are zero. The lagrange multiplier for ineq. const. is then
798a7e14dcfSSatish Balay                 defined as below
799a7e14dcfSSatish Balay         */
800a7e14dcfSSatish Balay         if ((x[i] > DELTAsv) && (x[i] < c-DELTAsv)) {
801a7e14dcfSSatish Balay           ipt[it++] = i;
802a7e14dcfSSatish Balay           kktlam    = kktlam - a[i]*g[i];
80353506e15SBarry Smith         } else  uv[luv++] = i;
804a7e14dcfSSatish Balay       }
805a7e14dcfSSatish Balay 
80653506e15SBarry Smith       if (it == 0 && PetscSqrtReal(ak) < tol*0.5 * PetscSqrtReal(bk)) return 0;
807a7e14dcfSSatish Balay       else {
808a7e14dcfSSatish Balay         kktlam = kktlam/it;
809a7e14dcfSSatish Balay         info   = 1;
810a7e14dcfSSatish Balay         for (i = 0; i < it; i++) {
8111118d4bcSLisandro Dalcin           if (PetscAbsReal(a[ipt[i]] * g[ipt[i]] + kktlam) > tol) {
812a7e14dcfSSatish Balay             info = 0;
813a7e14dcfSSatish Balay             break;
814a7e14dcfSSatish Balay           }
815a7e14dcfSSatish Balay         }
816a7e14dcfSSatish Balay         if (info == 1)  {
817a7e14dcfSSatish Balay           for (i = 0; i < luv; i++)  {
818a7e14dcfSSatish Balay             if (x[uv[i]] <= DELTAsv) {
819a7e14dcfSSatish Balay               /* x[i] == lower bound, hence, lagrange multiplier (say, beta) for lower bound may
820a7e14dcfSSatish Balay                      not be zero. So, the gradient without beta is > 0
821a7e14dcfSSatish Balay               */
822a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam*a[uv[i]] < -tol) {
823a7e14dcfSSatish Balay                 info = 0;
824a7e14dcfSSatish Balay                 break;
825a7e14dcfSSatish Balay               }
82653506e15SBarry Smith             } else {
827a7e14dcfSSatish Balay               /* x[i] == upper bound, hence, lagrange multiplier (say, eta) for upper bound may
828a7e14dcfSSatish Balay                      not be zero. So, the gradient without eta is < 0
829a7e14dcfSSatish Balay               */
830a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam*a[uv[i]] > tol) {
831a7e14dcfSSatish Balay                 info = 0;
832a7e14dcfSSatish Balay                 break;
833a7e14dcfSSatish Balay               }
834a7e14dcfSSatish Balay             }
835a7e14dcfSSatish Balay           }
836a7e14dcfSSatish Balay         }
837a7e14dcfSSatish Balay 
83853506e15SBarry Smith         if (info == 1) return 0;
839a7e14dcfSSatish Balay       }
840a7e14dcfSSatish Balay     }
841a7e14dcfSSatish Balay   }
842a7e14dcfSSatish Balay   return 0;
843a7e14dcfSSatish Balay }
844