xref: /petsc/src/tao/unconstrained/impls/bmrm/bmrm.c (revision a7e14dcfba0d07adf6226a919460249440ec94c7)
1*a7e14dcfSSatish Balay #include "bmrm.h"
2*a7e14dcfSSatish Balay 
3*a7e14dcfSSatish Balay static PetscErrorCode init_df_solver(TAO_DF*);
4*a7e14dcfSSatish Balay static PetscErrorCode ensure_df_space(PetscInt, TAO_DF*);
5*a7e14dcfSSatish Balay static PetscErrorCode destroy_df_solver(TAO_DF*);
6*a7e14dcfSSatish Balay static PetscReal phi(PetscReal*,PetscInt,PetscReal,PetscReal*,
7*a7e14dcfSSatish Balay 		     PetscReal,PetscReal*,PetscReal*,PetscReal*);
8*a7e14dcfSSatish Balay static PetscInt project(PetscInt,PetscReal*,PetscReal,PetscReal*,
9*a7e14dcfSSatish Balay 			PetscReal*,PetscReal*,PetscReal*,PetscReal*,TAO_DF*);
10*a7e14dcfSSatish Balay 
11*a7e14dcfSSatish Balay static PetscErrorCode solve(TAO_DF*);
12*a7e14dcfSSatish Balay 
13*a7e14dcfSSatish Balay 
14*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
15*a7e14dcfSSatish Balay /* The main solver function
16*a7e14dcfSSatish Balay 
17*a7e14dcfSSatish Balay    f = Remp(W)		This is what the user provides us from the application layer
18*a7e14dcfSSatish Balay    So the ComputeGradient function for instance should get us back the subgradient of Remp(W)
19*a7e14dcfSSatish Balay 
20*a7e14dcfSSatish Balay    Regularizer assumed to be L2 norm = lambda*0.5*W'W ()
21*a7e14dcfSSatish Balay */
22*a7e14dcfSSatish Balay 
23*a7e14dcfSSatish Balay #undef __FUNCT__
24*a7e14dcfSSatish Balay #define __FUNCT__ "make_grad_node"
25*a7e14dcfSSatish Balay static PetscErrorCode make_grad_node(Vec X, Vec_Chain **p)
26*a7e14dcfSSatish Balay {
27*a7e14dcfSSatish Balay   PetscErrorCode ierr;
28*a7e14dcfSSatish Balay 
29*a7e14dcfSSatish Balay   PetscFunctionBegin;
30*a7e14dcfSSatish Balay 
31*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(Vec_Chain), p); CHKERRQ(ierr);
32*a7e14dcfSSatish Balay   ierr = VecDuplicate(X, &(*p)->V); CHKERRQ(ierr);
33*a7e14dcfSSatish Balay   ierr = VecCopy(X, (*p)->V); CHKERRQ(ierr);
34*a7e14dcfSSatish Balay   (*p)->next = PETSC_NULL;
35*a7e14dcfSSatish Balay 
36*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
37*a7e14dcfSSatish Balay }
38*a7e14dcfSSatish Balay 
39*a7e14dcfSSatish Balay 
40*a7e14dcfSSatish Balay #undef __FUNCT__
41*a7e14dcfSSatish Balay #define __FUNCT__ "destroy_grad_list"
42*a7e14dcfSSatish Balay static PetscErrorCode destroy_grad_list(Vec_Chain *head)
43*a7e14dcfSSatish Balay {
44*a7e14dcfSSatish Balay   PetscErrorCode ierr;
45*a7e14dcfSSatish Balay   Vec_Chain *p = head->next, *q;
46*a7e14dcfSSatish Balay 
47*a7e14dcfSSatish Balay   PetscFunctionBegin;
48*a7e14dcfSSatish Balay   while(p) {
49*a7e14dcfSSatish Balay     q = p->next;
50*a7e14dcfSSatish Balay     ierr = VecDestroy(&p->V); CHKERRQ(ierr);
51*a7e14dcfSSatish Balay     ierr = PetscFree(p); CHKERRQ(ierr);
52*a7e14dcfSSatish Balay     p = q;
53*a7e14dcfSSatish Balay   }
54*a7e14dcfSSatish Balay   head->next = PETSC_NULL;
55*a7e14dcfSSatish Balay 
56*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
57*a7e14dcfSSatish Balay }
58*a7e14dcfSSatish Balay 
59*a7e14dcfSSatish Balay 
60*a7e14dcfSSatish Balay #undef __FUNCT__
61*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSolve_BMRM"
62*a7e14dcfSSatish Balay static PetscErrorCode TaoSolve_BMRM(TaoSolver tao)
63*a7e14dcfSSatish Balay {
64*a7e14dcfSSatish Balay   PetscErrorCode ierr;
65*a7e14dcfSSatish Balay   TaoSolverTerminationReason reason;
66*a7e14dcfSSatish Balay   TAO_DF df;
67*a7e14dcfSSatish Balay   TAO_BMRM *bmrm = (TAO_BMRM*)tao->data;
68*a7e14dcfSSatish Balay 
69*a7e14dcfSSatish Balay   /* Values and pointers to parts of the optimization problem */
70*a7e14dcfSSatish Balay   PetscReal f = 0.0;
71*a7e14dcfSSatish Balay   Vec W = tao->solution;
72*a7e14dcfSSatish Balay   Vec G = tao->gradient;
73*a7e14dcfSSatish Balay   PetscReal lambda;
74*a7e14dcfSSatish Balay 
75*a7e14dcfSSatish Balay   PetscReal bt;
76*a7e14dcfSSatish Balay   Vec_Chain grad_list, *tail_glist, *pgrad;
77*a7e14dcfSSatish Balay 
78*a7e14dcfSSatish Balay   PetscInt iter = 0;
79*a7e14dcfSSatish Balay   PetscInt i;
80*a7e14dcfSSatish Balay   PetscMPIInt rank;
81*a7e14dcfSSatish Balay 
82*a7e14dcfSSatish Balay   /* Used in termination criteria check */
83*a7e14dcfSSatish Balay   PetscReal reg;
84*a7e14dcfSSatish Balay   PetscReal jtwt, max_jtwt, pre_epsilon, epsilon, jw, min_jw;
85*a7e14dcfSSatish Balay   PetscReal innerSolverTol;
86*a7e14dcfSSatish Balay 
87*a7e14dcfSSatish Balay   PetscFunctionBegin;
88*a7e14dcfSSatish Balay 
89*a7e14dcfSSatish Balay   ierr = MPI_Comm_rank(PETSC_COMM_WORLD, &rank); CHKERRQ(ierr);
90*a7e14dcfSSatish Balay   lambda = bmrm->lambda;
91*a7e14dcfSSatish Balay 
92*a7e14dcfSSatish Balay   /* Check Stopping Condition */
93*a7e14dcfSSatish Balay   tao->step = 1.0;
94*a7e14dcfSSatish Balay   max_jtwt = -BMRM_INFTY;
95*a7e14dcfSSatish Balay   min_jw = BMRM_INFTY;
96*a7e14dcfSSatish Balay   innerSolverTol = 1.0;
97*a7e14dcfSSatish Balay   epsilon = 0.0;
98*a7e14dcfSSatish Balay 
99*a7e14dcfSSatish Balay   if (rank == 0) {
100*a7e14dcfSSatish Balay     ierr = init_df_solver(&df); CHKERRQ(ierr);
101*a7e14dcfSSatish Balay     grad_list.next = NULL;
102*a7e14dcfSSatish Balay     tail_glist = &grad_list;
103*a7e14dcfSSatish Balay   }
104*a7e14dcfSSatish Balay 
105*a7e14dcfSSatish Balay   df.tol = 1e-6;
106*a7e14dcfSSatish Balay   reason = TAO_CONTINUE_ITERATING;
107*a7e14dcfSSatish Balay 
108*a7e14dcfSSatish Balay   /*-----------------Algorithm Begins------------------------*/
109*a7e14dcfSSatish Balay   /* make the scatter */
110*a7e14dcfSSatish Balay   ierr = VecScatterCreateToZero(W, &bmrm->scatter, &bmrm->local_w); CHKERRQ(ierr);
111*a7e14dcfSSatish Balay   ierr = VecAssemblyBegin(bmrm->local_w); CHKERRQ(ierr);
112*a7e14dcfSSatish Balay   ierr = VecAssemblyEnd(bmrm->local_w); CHKERRQ(ierr);
113*a7e14dcfSSatish Balay 
114*a7e14dcfSSatish Balay 	/* NOTE: In application pass the sub-gradient of Remp(W) */
115*a7e14dcfSSatish Balay   ierr = TaoComputeObjectiveAndGradient(tao, W, &f, G); CHKERRQ(ierr);
116*a7e14dcfSSatish Balay   ierr = TaoMonitor(tao,iter,f,1.0,0.0,tao->step,&reason); CHKERRQ(ierr);
117*a7e14dcfSSatish Balay   while (reason == TAO_CONTINUE_ITERATING) {
118*a7e14dcfSSatish Balay     /* compute bt = Remp(Wt-1) - <Wt-1, At> */
119*a7e14dcfSSatish Balay     ierr = VecDot(W, G, &bt); CHKERRQ(ierr);
120*a7e14dcfSSatish Balay     bt = f - bt;
121*a7e14dcfSSatish Balay 
122*a7e14dcfSSatish Balay     /* First gather the gradient to the master node */
123*a7e14dcfSSatish Balay     ierr = VecScatterBegin(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
124*a7e14dcfSSatish Balay     ierr = VecScatterEnd(bmrm->scatter, G, bmrm->local_w, INSERT_VALUES, SCATTER_FORWARD); CHKERRQ(ierr);
125*a7e14dcfSSatish Balay 
126*a7e14dcfSSatish Balay     /* Bring up the inner solver */
127*a7e14dcfSSatish Balay     if (rank == 0) {
128*a7e14dcfSSatish Balay       ierr = ensure_df_space(iter+1, &df);  CHKERRQ(ierr);
129*a7e14dcfSSatish Balay       ierr = make_grad_node(bmrm->local_w, &pgrad); CHKERRQ(ierr);
130*a7e14dcfSSatish Balay       tail_glist->next = pgrad;
131*a7e14dcfSSatish Balay       tail_glist = pgrad;
132*a7e14dcfSSatish Balay 
133*a7e14dcfSSatish Balay       df.a[iter] = 1.0;
134*a7e14dcfSSatish Balay       df.f[iter] = -bt;
135*a7e14dcfSSatish Balay       df.u[iter] = 1.0;
136*a7e14dcfSSatish Balay       df.l[iter] = 0.0;
137*a7e14dcfSSatish Balay 
138*a7e14dcfSSatish Balay       /* set up the Q */
139*a7e14dcfSSatish Balay       pgrad = grad_list.next;
140*a7e14dcfSSatish Balay       for (i=0; i<=iter; i++) {
141*a7e14dcfSSatish Balay         ierr = VecDot(pgrad->V, bmrm->local_w, &reg); CHKERRQ(ierr);
142*a7e14dcfSSatish Balay         df.Q[i][iter] = df.Q[iter][i] = reg / lambda;
143*a7e14dcfSSatish Balay         pgrad = pgrad->next;
144*a7e14dcfSSatish Balay       }
145*a7e14dcfSSatish Balay 
146*a7e14dcfSSatish Balay       if (iter > 0) {
147*a7e14dcfSSatish Balay         df.x[iter] = 0.0;
148*a7e14dcfSSatish Balay         ierr = solve(&df);  CHKERRQ(ierr);
149*a7e14dcfSSatish Balay       }
150*a7e14dcfSSatish Balay       else
151*a7e14dcfSSatish Balay 	df.x[0] = 1.0;
152*a7e14dcfSSatish Balay 
153*a7e14dcfSSatish Balay       /* now computing Jt*(alpha_t) which should be = Jt(wt) to check convergence */
154*a7e14dcfSSatish Balay       jtwt = 0.0;
155*a7e14dcfSSatish Balay       ierr = VecSet(bmrm->local_w, 0.0);  CHKERRQ(ierr);
156*a7e14dcfSSatish Balay       pgrad = grad_list.next;
157*a7e14dcfSSatish Balay       for (i=0; i<=iter; i++) {
158*a7e14dcfSSatish Balay         jtwt -= df.x[i] * df.f[i];
159*a7e14dcfSSatish Balay         ierr = VecAXPY(bmrm->local_w, -df.x[i] / lambda, pgrad->V);  CHKERRQ(ierr);
160*a7e14dcfSSatish Balay         pgrad = pgrad->next;
161*a7e14dcfSSatish Balay       }
162*a7e14dcfSSatish Balay 
163*a7e14dcfSSatish Balay       ierr = VecNorm(bmrm->local_w, NORM_2, &reg);  CHKERRQ(ierr);
164*a7e14dcfSSatish Balay       reg = 0.5*lambda*reg*reg;
165*a7e14dcfSSatish Balay       jtwt -= reg;
166*a7e14dcfSSatish Balay     } /* end if rank == 0 */
167*a7e14dcfSSatish Balay 
168*a7e14dcfSSatish Balay     /* scatter the new W to all nodes */
169*a7e14dcfSSatish Balay     ierr = VecScatterBegin(bmrm->scatter,bmrm->local_w,W,INSERT_VALUES,SCATTER_REVERSE); CHKERRQ(ierr);
170*a7e14dcfSSatish Balay     ierr = VecScatterEnd(bmrm->scatter,bmrm->local_w,W,INSERT_VALUES,SCATTER_REVERSE); CHKERRQ(ierr);
171*a7e14dcfSSatish Balay 
172*a7e14dcfSSatish Balay     ierr = TaoComputeObjectiveAndGradient(tao, W, &f, G); CHKERRQ(ierr);
173*a7e14dcfSSatish Balay 
174*a7e14dcfSSatish Balay     MPI_Bcast(&jtwt,1,MPI_DOUBLE,0,PETSC_COMM_WORLD);
175*a7e14dcfSSatish Balay     MPI_Bcast(&reg,1,MPI_DOUBLE,0,PETSC_COMM_WORLD);
176*a7e14dcfSSatish Balay 
177*a7e14dcfSSatish Balay     jw = reg + f;					/* J(w) = regularizer + Remp(w) */
178*a7e14dcfSSatish Balay     if (jw < min_jw)
179*a7e14dcfSSatish Balay       min_jw = jw;
180*a7e14dcfSSatish Balay     if (jtwt > max_jtwt)
181*a7e14dcfSSatish Balay       max_jtwt = jtwt;
182*a7e14dcfSSatish Balay 
183*a7e14dcfSSatish Balay     pre_epsilon = epsilon;
184*a7e14dcfSSatish Balay     epsilon = min_jw - jtwt;
185*a7e14dcfSSatish Balay 
186*a7e14dcfSSatish Balay     if (rank == 0) {
187*a7e14dcfSSatish Balay       if (innerSolverTol > epsilon)
188*a7e14dcfSSatish Balay         innerSolverTol = epsilon;
189*a7e14dcfSSatish Balay       else if (innerSolverTol < 1e-7)
190*a7e14dcfSSatish Balay         innerSolverTol = 1e-7;
191*a7e14dcfSSatish Balay 
192*a7e14dcfSSatish Balay       /* if the annealing doesn't work well, lower the inner solver tolerance */
193*a7e14dcfSSatish Balay       if(pre_epsilon < epsilon)
194*a7e14dcfSSatish Balay         innerSolverTol *= 0.2;
195*a7e14dcfSSatish Balay 
196*a7e14dcfSSatish Balay       df.tol = innerSolverTol*0.5;
197*a7e14dcfSSatish Balay     }
198*a7e14dcfSSatish Balay 
199*a7e14dcfSSatish Balay     iter++;
200*a7e14dcfSSatish Balay     ierr = TaoMonitor(tao,iter,min_jw,epsilon,0.0,tao->step,&reason); CHKERRQ(ierr);
201*a7e14dcfSSatish Balay   }
202*a7e14dcfSSatish Balay 
203*a7e14dcfSSatish Balay   /* free all the memory */
204*a7e14dcfSSatish Balay   if (rank == 0) {
205*a7e14dcfSSatish Balay     ierr = destroy_grad_list(&grad_list); 	CHKERRQ(ierr);
206*a7e14dcfSSatish Balay     ierr = destroy_df_solver(&df); CHKERRQ(ierr);
207*a7e14dcfSSatish Balay   }
208*a7e14dcfSSatish Balay 
209*a7e14dcfSSatish Balay   ierr = VecDestroy(&bmrm->local_w); CHKERRQ(ierr);
210*a7e14dcfSSatish Balay   ierr = VecScatterDestroy(&bmrm->scatter); CHKERRQ(ierr);
211*a7e14dcfSSatish Balay 
212*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
213*a7e14dcfSSatish Balay }
214*a7e14dcfSSatish Balay 
215*a7e14dcfSSatish Balay 
216*a7e14dcfSSatish Balay /* ---------------------------------------------------------- */
217*a7e14dcfSSatish Balay 
218*a7e14dcfSSatish Balay #undef __FUNCT__
219*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSetup_BMRM"
220*a7e14dcfSSatish Balay static PetscErrorCode TaoSetup_BMRM(TaoSolver tao) {
221*a7e14dcfSSatish Balay 
222*a7e14dcfSSatish Balay   PetscErrorCode      ierr;
223*a7e14dcfSSatish Balay 
224*a7e14dcfSSatish Balay   PetscFunctionBegin;
225*a7e14dcfSSatish Balay 
226*a7e14dcfSSatish Balay   /* Allocate some arrays */
227*a7e14dcfSSatish Balay   if (!tao->gradient) {
228*a7e14dcfSSatish Balay     ierr = VecDuplicate(tao->solution, &tao->gradient);    CHKERRQ(ierr);
229*a7e14dcfSSatish Balay   }
230*a7e14dcfSSatish Balay 
231*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
232*a7e14dcfSSatish Balay }
233*a7e14dcfSSatish Balay 
234*a7e14dcfSSatish Balay 
235*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
236*a7e14dcfSSatish Balay 
237*a7e14dcfSSatish Balay #undef __FUNCT__
238*a7e14dcfSSatish Balay #define __FUNCT__ "TaoDestroy_BMRM"
239*a7e14dcfSSatish Balay static PetscErrorCode TaoDestroy_BMRM(TaoSolver tao)
240*a7e14dcfSSatish Balay {
241*a7e14dcfSSatish Balay   PetscErrorCode      ierr;
242*a7e14dcfSSatish Balay 
243*a7e14dcfSSatish Balay   /* Free allocated memory in custom BMRM structure */
244*a7e14dcfSSatish Balay   PetscFunctionBegin;
245*a7e14dcfSSatish Balay   ierr = PetscFree(tao->data); CHKERRQ(ierr);
246*a7e14dcfSSatish Balay   tao->data = PETSC_NULL;
247*a7e14dcfSSatish Balay 
248*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
249*a7e14dcfSSatish Balay }
250*a7e14dcfSSatish Balay 
251*a7e14dcfSSatish Balay 
252*a7e14dcfSSatish Balay #undef __FUNCT__
253*a7e14dcfSSatish Balay #define __FUNCT__ "TaoSetFromOptions_BMRM"
254*a7e14dcfSSatish Balay static PetscErrorCode TaoSetFromOptions_BMRM(TaoSolver tao)
255*a7e14dcfSSatish Balay {
256*a7e14dcfSSatish Balay   PetscErrorCode      ierr;
257*a7e14dcfSSatish Balay   TAO_BMRM*           bmrm = (TAO_BMRM*)tao->data;
258*a7e14dcfSSatish Balay   PetscBool           flg;
259*a7e14dcfSSatish Balay 
260*a7e14dcfSSatish Balay   PetscFunctionBegin;
261*a7e14dcfSSatish Balay   ierr = PetscOptionsHead("BMRM for regularized risk minimization");CHKERRQ(ierr);
262*a7e14dcfSSatish Balay   ierr = PetscOptionsReal("-tao_bmrm_lambda", "regulariser weight","", 100,&bmrm->lambda,&flg);  CHKERRQ(ierr);
263*a7e14dcfSSatish Balay   ierr = PetscOptionsTail();CHKERRQ(ierr);
264*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
265*a7e14dcfSSatish Balay }
266*a7e14dcfSSatish Balay 
267*a7e14dcfSSatish Balay 
268*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
269*a7e14dcfSSatish Balay #undef __FUNCT__
270*a7e14dcfSSatish Balay #define __FUNCT__ "TaoView_BMRM"
271*a7e14dcfSSatish Balay static PetscErrorCode TaoView_BMRM(TaoSolver tao, PetscViewer viewer)
272*a7e14dcfSSatish Balay {
273*a7e14dcfSSatish Balay   PetscBool           isascii;
274*a7e14dcfSSatish Balay   PetscErrorCode      ierr;
275*a7e14dcfSSatish Balay 
276*a7e14dcfSSatish Balay   PetscFunctionBegin;
277*a7e14dcfSSatish Balay   ierr = PetscObjectTypeCompare((PetscObject)viewer,PETSCVIEWERASCII,&isascii);CHKERRQ(ierr);
278*a7e14dcfSSatish Balay   if (isascii) {
279*a7e14dcfSSatish Balay     ierr = PetscViewerASCIIPushTab(viewer); CHKERRQ(ierr);
280*a7e14dcfSSatish Balay     ierr = PetscViewerASCIIPopTab(viewer); CHKERRQ(ierr);
281*a7e14dcfSSatish Balay   }
282*a7e14dcfSSatish Balay   else{
283*a7e14dcfSSatish Balay     SETERRQ1(((PetscObject)tao)->comm,PETSC_ERR_SUP,"Viewer type %s not supported for TAO BMRM",((PetscObject)viewer)->type_name);
284*a7e14dcfSSatish Balay   }
285*a7e14dcfSSatish Balay 
286*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
287*a7e14dcfSSatish Balay }
288*a7e14dcfSSatish Balay 
289*a7e14dcfSSatish Balay 
290*a7e14dcfSSatish Balay /*------------------------------------------------------------*/
291*a7e14dcfSSatish Balay EXTERN_C_BEGIN
292*a7e14dcfSSatish Balay #undef __FUNCT__
293*a7e14dcfSSatish Balay #define __FUNCT__ "TaoCreate_BMRM"
294*a7e14dcfSSatish Balay PetscErrorCode TaoCreate_BMRM(TaoSolver tao)
295*a7e14dcfSSatish Balay {
296*a7e14dcfSSatish Balay   TAO_BMRM *bmrm;
297*a7e14dcfSSatish Balay   PetscErrorCode      ierr;
298*a7e14dcfSSatish Balay 
299*a7e14dcfSSatish Balay   PetscFunctionBegin;
300*a7e14dcfSSatish Balay   tao->ops->setup = TaoSetup_BMRM;
301*a7e14dcfSSatish Balay   tao->ops->solve = TaoSolve_BMRM;
302*a7e14dcfSSatish Balay   tao->ops->view  = TaoView_BMRM;
303*a7e14dcfSSatish Balay   tao->ops->setfromoptions = TaoSetFromOptions_BMRM;
304*a7e14dcfSSatish Balay   tao->ops->destroy = TaoDestroy_BMRM;
305*a7e14dcfSSatish Balay 
306*a7e14dcfSSatish Balay   ierr = PetscNewLog(tao,TAO_BMRM,&bmrm); CHKERRQ(ierr);
307*a7e14dcfSSatish Balay   bmrm->lambda = 1.0;
308*a7e14dcfSSatish Balay   tao->data = (void*)bmrm;
309*a7e14dcfSSatish Balay 
310*a7e14dcfSSatish Balay   /* Note: May need to be tuned! */
311*a7e14dcfSSatish Balay   tao->max_it = 2048;
312*a7e14dcfSSatish Balay   tao->max_funcs = 300000;
313*a7e14dcfSSatish Balay   tao->fatol = 1e-20;
314*a7e14dcfSSatish Balay   tao->frtol = 1e-25;
315*a7e14dcfSSatish Balay   tao->gatol = 1e-25;
316*a7e14dcfSSatish Balay   tao->grtol = 1e-25;
317*a7e14dcfSSatish Balay 
318*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
319*a7e14dcfSSatish Balay }
320*a7e14dcfSSatish Balay EXTERN_C_END
321*a7e14dcfSSatish Balay 
322*a7e14dcfSSatish Balay 
323*a7e14dcfSSatish Balay 
324*a7e14dcfSSatish Balay #undef __FUNCT__
325*a7e14dcfSSatish Balay #define __FUNCT__ "init_df_solver"
326*a7e14dcfSSatish Balay PetscErrorCode init_df_solver(TAO_DF *df)
327*a7e14dcfSSatish Balay {
328*a7e14dcfSSatish Balay   PetscInt i, n = INCRE_DIM;
329*a7e14dcfSSatish Balay   PetscErrorCode ierr;
330*a7e14dcfSSatish Balay 
331*a7e14dcfSSatish Balay   PetscFunctionBegin;
332*a7e14dcfSSatish Balay 
333*a7e14dcfSSatish Balay   /* default values */
334*a7e14dcfSSatish Balay   df->maxProjIter = 200;
335*a7e14dcfSSatish Balay   df->maxPGMIter = 300000;
336*a7e14dcfSSatish Balay   df->b = 1.0;
337*a7e14dcfSSatish Balay 
338*a7e14dcfSSatish Balay   /* memory space required by Dai-Fletcher */
339*a7e14dcfSSatish Balay   df->cur_num_cp = n;
340*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->f);  CHKERRQ(ierr);
341*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->a);  CHKERRQ(ierr);
342*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->l);  CHKERRQ(ierr);
343*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->u);  CHKERRQ(ierr);
344*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->x);  CHKERRQ(ierr);
345*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal*)*n, &df->Q);  CHKERRQ(ierr);
346*a7e14dcfSSatish Balay 
347*a7e14dcfSSatish Balay   for (i = 0; i < n; i ++) {
348*a7e14dcfSSatish Balay     ierr = PetscMalloc(sizeof(PetscReal)*n, &df->Q[i]);  CHKERRQ(ierr);
349*a7e14dcfSSatish Balay   }
350*a7e14dcfSSatish Balay 
351*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->g);  CHKERRQ(ierr);
352*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->y);  CHKERRQ(ierr);
353*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->tempv);  CHKERRQ(ierr);
354*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->d);  CHKERRQ(ierr);
355*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->Qd);  CHKERRQ(ierr);
356*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->t);  CHKERRQ(ierr);
357*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->xplus);  CHKERRQ(ierr);
358*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->tplus);  CHKERRQ(ierr);
359*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->sk);  CHKERRQ(ierr);
360*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->yk);  CHKERRQ(ierr);
361*a7e14dcfSSatish Balay 
362*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->ipt);  CHKERRQ(ierr);
363*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->ipt2);  CHKERRQ(ierr);
364*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->uv);  CHKERRQ(ierr);
365*a7e14dcfSSatish Balay 
366*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
367*a7e14dcfSSatish Balay }
368*a7e14dcfSSatish Balay 
369*a7e14dcfSSatish Balay 
370*a7e14dcfSSatish Balay #undef __FUNCT__
371*a7e14dcfSSatish Balay #define __FUNCT__ "ensure_df_space"
372*a7e14dcfSSatish Balay PetscErrorCode ensure_df_space(PetscInt dim, TAO_DF *df)
373*a7e14dcfSSatish Balay {
374*a7e14dcfSSatish Balay   PetscErrorCode ierr;
375*a7e14dcfSSatish Balay   PetscReal *tmp, **tmp_Q;
376*a7e14dcfSSatish Balay   PetscInt i, n, old_n;
377*a7e14dcfSSatish Balay 
378*a7e14dcfSSatish Balay   df->dim = dim;
379*a7e14dcfSSatish Balay   if (dim <= df->cur_num_cp)
380*a7e14dcfSSatish Balay     return 0;
381*a7e14dcfSSatish Balay 
382*a7e14dcfSSatish Balay   PetscFunctionBegin;
383*a7e14dcfSSatish Balay 
384*a7e14dcfSSatish Balay   old_n = df->cur_num_cp;
385*a7e14dcfSSatish Balay   df->cur_num_cp += INCRE_DIM;
386*a7e14dcfSSatish Balay   n = df->cur_num_cp;
387*a7e14dcfSSatish Balay 
388*a7e14dcfSSatish Balay   /* memory space required by dai-fletcher */
389*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp);  CHKERRQ(ierr);
390*a7e14dcfSSatish Balay   ierr = PetscMemcpy(tmp, df->f, sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
391*a7e14dcfSSatish Balay   ierr = PetscFree(df->f);  CHKERRQ(ierr);
392*a7e14dcfSSatish Balay   df->f = tmp;
393*a7e14dcfSSatish Balay 
394*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp);  CHKERRQ(ierr);
395*a7e14dcfSSatish Balay   ierr = PetscMemcpy(tmp, df->a, sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
396*a7e14dcfSSatish Balay   ierr = PetscFree(df->a);  CHKERRQ(ierr);
397*a7e14dcfSSatish Balay   df->a = tmp;
398*a7e14dcfSSatish Balay 
399*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp);  CHKERRQ(ierr);
400*a7e14dcfSSatish Balay   ierr = PetscMemcpy(tmp, df->l, sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
401*a7e14dcfSSatish Balay   ierr = PetscFree(df->l);  CHKERRQ(ierr);
402*a7e14dcfSSatish Balay   df->l = tmp;
403*a7e14dcfSSatish Balay 
404*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp);  CHKERRQ(ierr);
405*a7e14dcfSSatish Balay   ierr = PetscMemcpy(tmp, df->u, sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
406*a7e14dcfSSatish Balay   ierr = PetscFree(df->u);  CHKERRQ(ierr);
407*a7e14dcfSSatish Balay   df->u = tmp;
408*a7e14dcfSSatish Balay 
409*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp);  CHKERRQ(ierr);
410*a7e14dcfSSatish Balay   ierr = PetscMemcpy(tmp, df->x, sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
411*a7e14dcfSSatish Balay   ierr = PetscFree(df->x);  CHKERRQ(ierr);
412*a7e14dcfSSatish Balay   df->x = tmp;
413*a7e14dcfSSatish Balay 
414*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal*)*n, &tmp_Q);  CHKERRQ(ierr);
415*a7e14dcfSSatish Balay   for (i = 0; i < n; i ++)
416*a7e14dcfSSatish Balay   {
417*a7e14dcfSSatish Balay     ierr = PetscMalloc(sizeof(PetscReal)*n, &tmp_Q[i]);  CHKERRQ(ierr);
418*a7e14dcfSSatish Balay     if (i < old_n)
419*a7e14dcfSSatish Balay     {
420*a7e14dcfSSatish Balay       ierr = PetscMemcpy(tmp_Q[i], df->Q[i], sizeof(PetscReal)*old_n);  CHKERRQ(ierr);
421*a7e14dcfSSatish Balay       ierr = PetscFree(df->Q[i]);  CHKERRQ(ierr);
422*a7e14dcfSSatish Balay     }
423*a7e14dcfSSatish Balay   }
424*a7e14dcfSSatish Balay 
425*a7e14dcfSSatish Balay   ierr = PetscFree(df->Q);  CHKERRQ(ierr);
426*a7e14dcfSSatish Balay   df->Q = tmp_Q;
427*a7e14dcfSSatish Balay 
428*a7e14dcfSSatish Balay   ierr = PetscFree(df->g);  CHKERRQ(ierr);
429*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->g);  CHKERRQ(ierr);
430*a7e14dcfSSatish Balay 
431*a7e14dcfSSatish Balay   ierr = PetscFree(df->y);  CHKERRQ(ierr);
432*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->y);  CHKERRQ(ierr);
433*a7e14dcfSSatish Balay 
434*a7e14dcfSSatish Balay   ierr = PetscFree(df->tempv);  CHKERRQ(ierr);
435*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->tempv);  CHKERRQ(ierr);
436*a7e14dcfSSatish Balay 
437*a7e14dcfSSatish Balay   ierr = PetscFree(df->d);  CHKERRQ(ierr);
438*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->d);  CHKERRQ(ierr);
439*a7e14dcfSSatish Balay 
440*a7e14dcfSSatish Balay   ierr = PetscFree(df->Qd);  CHKERRQ(ierr);
441*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->Qd);  CHKERRQ(ierr);
442*a7e14dcfSSatish Balay 
443*a7e14dcfSSatish Balay   ierr = PetscFree(df->t);  CHKERRQ(ierr);
444*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->t);  CHKERRQ(ierr);
445*a7e14dcfSSatish Balay 
446*a7e14dcfSSatish Balay   ierr = PetscFree(df->xplus);  CHKERRQ(ierr);
447*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->xplus);  CHKERRQ(ierr);
448*a7e14dcfSSatish Balay 
449*a7e14dcfSSatish Balay   ierr = PetscFree(df->tplus);  CHKERRQ(ierr);
450*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->tplus);  CHKERRQ(ierr);
451*a7e14dcfSSatish Balay 
452*a7e14dcfSSatish Balay   ierr = PetscFree(df->sk);  CHKERRQ(ierr);
453*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->sk);  CHKERRQ(ierr);
454*a7e14dcfSSatish Balay 
455*a7e14dcfSSatish Balay   ierr = PetscFree(df->yk);  CHKERRQ(ierr);
456*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscReal)*n, &df->yk);  CHKERRQ(ierr);
457*a7e14dcfSSatish Balay 
458*a7e14dcfSSatish Balay   ierr = PetscFree(df->ipt);  CHKERRQ(ierr);
459*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->ipt);  CHKERRQ(ierr);
460*a7e14dcfSSatish Balay 
461*a7e14dcfSSatish Balay   ierr = PetscFree(df->ipt2);  CHKERRQ(ierr);
462*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->ipt2);  CHKERRQ(ierr);
463*a7e14dcfSSatish Balay 
464*a7e14dcfSSatish Balay   ierr = PetscFree(df->uv);  CHKERRQ(ierr);
465*a7e14dcfSSatish Balay   ierr = PetscMalloc(sizeof(PetscInt)*n, &df->uv);  CHKERRQ(ierr);
466*a7e14dcfSSatish Balay 
467*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
468*a7e14dcfSSatish Balay }
469*a7e14dcfSSatish Balay 
470*a7e14dcfSSatish Balay 
471*a7e14dcfSSatish Balay #undef __FUNCT__
472*a7e14dcfSSatish Balay #define __FUNCT__ "destroy_df_solver"
473*a7e14dcfSSatish Balay PetscErrorCode destroy_df_solver(TAO_DF *df)
474*a7e14dcfSSatish Balay {
475*a7e14dcfSSatish Balay   PetscErrorCode ierr;
476*a7e14dcfSSatish Balay   PetscInt i;
477*a7e14dcfSSatish Balay   PetscFunctionBegin;
478*a7e14dcfSSatish Balay 
479*a7e14dcfSSatish Balay   if (df->f)   {
480*a7e14dcfSSatish Balay     ierr = PetscFree(df->f);  CHKERRQ(ierr);    df->f = PETSC_NULL;
481*a7e14dcfSSatish Balay   }
482*a7e14dcfSSatish Balay 
483*a7e14dcfSSatish Balay   if (df->a)   {
484*a7e14dcfSSatish Balay     ierr = PetscFree(df->a);  CHKERRQ(ierr);    df->a = PETSC_NULL;
485*a7e14dcfSSatish Balay   }
486*a7e14dcfSSatish Balay 
487*a7e14dcfSSatish Balay   if (df->l)   {
488*a7e14dcfSSatish Balay     ierr = PetscFree(df->l);  CHKERRQ(ierr);    df->l = PETSC_NULL;
489*a7e14dcfSSatish Balay   }
490*a7e14dcfSSatish Balay 
491*a7e14dcfSSatish Balay   if (df->u)   {
492*a7e14dcfSSatish Balay     ierr = PetscFree(df->u);  CHKERRQ(ierr);    df->u = PETSC_NULL;
493*a7e14dcfSSatish Balay   }
494*a7e14dcfSSatish Balay 
495*a7e14dcfSSatish Balay   if (df->x)   {
496*a7e14dcfSSatish Balay     ierr = PetscFree(df->x);  CHKERRQ(ierr);    df->x = PETSC_NULL;
497*a7e14dcfSSatish Balay   }
498*a7e14dcfSSatish Balay 
499*a7e14dcfSSatish Balay   for (i = 0; i < df->cur_num_cp; i ++)
500*a7e14dcfSSatish Balay   {
501*a7e14dcfSSatish Balay     ierr = PetscFree(df->Q[i]);  CHKERRQ(ierr);
502*a7e14dcfSSatish Balay   }
503*a7e14dcfSSatish Balay   ierr = PetscFree(df->Q);  CHKERRQ(ierr);
504*a7e14dcfSSatish Balay 
505*a7e14dcfSSatish Balay 
506*a7e14dcfSSatish Balay   if (df->ipt)   {
507*a7e14dcfSSatish Balay     ierr = PetscFree(df->ipt);  CHKERRQ(ierr);    df->ipt = PETSC_NULL;
508*a7e14dcfSSatish Balay   }
509*a7e14dcfSSatish Balay   if (df->ipt2)   {
510*a7e14dcfSSatish Balay     ierr = PetscFree(df->ipt2);  CHKERRQ(ierr);    df->ipt2 = PETSC_NULL;
511*a7e14dcfSSatish Balay   }
512*a7e14dcfSSatish Balay   if (df->uv)   {
513*a7e14dcfSSatish Balay     ierr = PetscFree(df->uv);  CHKERRQ(ierr);    df->uv = PETSC_NULL;
514*a7e14dcfSSatish Balay   }
515*a7e14dcfSSatish Balay   if (df->g)   {
516*a7e14dcfSSatish Balay     ierr = PetscFree(df->g);  CHKERRQ(ierr);    df->g = PETSC_NULL;
517*a7e14dcfSSatish Balay   }
518*a7e14dcfSSatish Balay   if (df->y)   {
519*a7e14dcfSSatish Balay     ierr = PetscFree(df->y);  CHKERRQ(ierr);    df->y = PETSC_NULL;
520*a7e14dcfSSatish Balay   }
521*a7e14dcfSSatish Balay   if (df->tempv)   {
522*a7e14dcfSSatish Balay     ierr = PetscFree(df->tempv);  CHKERRQ(ierr);    df->tempv = PETSC_NULL;
523*a7e14dcfSSatish Balay   }
524*a7e14dcfSSatish Balay   if (df->d)   {
525*a7e14dcfSSatish Balay     ierr = PetscFree(df->d);  CHKERRQ(ierr);    df->d = PETSC_NULL;
526*a7e14dcfSSatish Balay   }
527*a7e14dcfSSatish Balay   if (df->Qd)   {
528*a7e14dcfSSatish Balay     ierr = PetscFree(df->Qd);  CHKERRQ(ierr);    df->Qd = PETSC_NULL;
529*a7e14dcfSSatish Balay   }
530*a7e14dcfSSatish Balay   if (df->t)   {
531*a7e14dcfSSatish Balay     ierr = PetscFree(df->t);  CHKERRQ(ierr);    df->t = PETSC_NULL;
532*a7e14dcfSSatish Balay   }
533*a7e14dcfSSatish Balay   if (df->xplus)   {
534*a7e14dcfSSatish Balay     ierr = PetscFree(df->xplus);  CHKERRQ(ierr);    df->xplus = PETSC_NULL;
535*a7e14dcfSSatish Balay   }
536*a7e14dcfSSatish Balay   if (df->tplus)   {
537*a7e14dcfSSatish Balay     ierr = PetscFree(df->tplus);  CHKERRQ(ierr);    df->tplus = PETSC_NULL;
538*a7e14dcfSSatish Balay   }
539*a7e14dcfSSatish Balay   if (df->sk)   {
540*a7e14dcfSSatish Balay     ierr = PetscFree(df->sk);  CHKERRQ(ierr);    df->sk = PETSC_NULL;
541*a7e14dcfSSatish Balay   }
542*a7e14dcfSSatish Balay   if (df->yk)   {
543*a7e14dcfSSatish Balay     ierr = PetscFree(df->yk);  CHKERRQ(ierr);    df->yk = PETSC_NULL;
544*a7e14dcfSSatish Balay   }
545*a7e14dcfSSatish Balay 
546*a7e14dcfSSatish Balay   PetscFunctionReturn(0);
547*a7e14dcfSSatish Balay }
548*a7e14dcfSSatish Balay 
549*a7e14dcfSSatish Balay 
550*a7e14dcfSSatish Balay /* Piecewise linear monotone target function for the Dai-Fletcher projector */
551*a7e14dcfSSatish Balay #undef __FUNCT__
552*a7e14dcfSSatish Balay #define __FUNCT__ "phi"
553*a7e14dcfSSatish Balay PetscReal phi(PetscReal *x,
554*a7e14dcfSSatish Balay            PetscInt n,
555*a7e14dcfSSatish Balay            PetscReal lambda,
556*a7e14dcfSSatish Balay            PetscReal *a,
557*a7e14dcfSSatish Balay            PetscReal b,
558*a7e14dcfSSatish Balay            PetscReal *c,
559*a7e14dcfSSatish Balay            PetscReal *l,
560*a7e14dcfSSatish Balay            PetscReal *u)
561*a7e14dcfSSatish Balay {
562*a7e14dcfSSatish Balay   PetscReal r = 0.0;
563*a7e14dcfSSatish Balay   PetscInt i;
564*a7e14dcfSSatish Balay 
565*a7e14dcfSSatish Balay   for (i = 0; i < n; i++){
566*a7e14dcfSSatish Balay     x[i] = -c[i] + lambda*a[i];
567*a7e14dcfSSatish Balay     if (x[i] > u[i])
568*a7e14dcfSSatish Balay       x[i] = u[i];
569*a7e14dcfSSatish Balay     else if(x[i] < l[i])
570*a7e14dcfSSatish Balay       x[i] = l[i];
571*a7e14dcfSSatish Balay     r += a[i]*x[i];
572*a7e14dcfSSatish Balay   }
573*a7e14dcfSSatish Balay   return r - b;
574*a7e14dcfSSatish Balay }
575*a7e14dcfSSatish Balay 
576*a7e14dcfSSatish Balay 
577*a7e14dcfSSatish Balay 
578*a7e14dcfSSatish Balay /** Modified Dai-Fletcher QP projector solves the problem:
579*a7e14dcfSSatish Balay  *
580*a7e14dcfSSatish Balay  *      minimise  0.5*x'*x - c'*x
581*a7e14dcfSSatish Balay  *      subj to   a'*x = b
582*a7e14dcfSSatish Balay  *                l \leq x \leq u
583*a7e14dcfSSatish Balay  *
584*a7e14dcfSSatish Balay  *  \param c The point to be projected onto feasible set
585*a7e14dcfSSatish Balay  */
586*a7e14dcfSSatish Balay #undef __FUNCT__
587*a7e14dcfSSatish Balay #define __FUNCT__ "project"
588*a7e14dcfSSatish Balay PetscInt project(PetscInt n,
589*a7e14dcfSSatish Balay             PetscReal *a,
590*a7e14dcfSSatish Balay             PetscReal b,
591*a7e14dcfSSatish Balay             PetscReal *c,
592*a7e14dcfSSatish Balay             PetscReal *l,
593*a7e14dcfSSatish Balay             PetscReal *u,
594*a7e14dcfSSatish Balay             PetscReal *x,
595*a7e14dcfSSatish Balay             PetscReal *lam_ext,
596*a7e14dcfSSatish Balay             TAO_DF *df)
597*a7e14dcfSSatish Balay {
598*a7e14dcfSSatish Balay   PetscReal lambda, lambdal, lambdau, dlambda, lambda_new;
599*a7e14dcfSSatish Balay   PetscReal r, rl, ru, s;
600*a7e14dcfSSatish Balay   PetscInt    innerIter;
601*a7e14dcfSSatish Balay   PetscBool nonNegativeSlack = PETSC_FALSE;
602*a7e14dcfSSatish Balay /*   PetscBool nonNegativeSlack = PETSC_TRUE; */
603*a7e14dcfSSatish Balay 
604*a7e14dcfSSatish Balay   *lam_ext = 0;
605*a7e14dcfSSatish Balay   lambda  = 0;
606*a7e14dcfSSatish Balay   dlambda = 0.5;
607*a7e14dcfSSatish Balay   innerIter = 1;
608*a7e14dcfSSatish Balay 
609*a7e14dcfSSatish Balay   /*  \phi(x;lambda) := 0.5*x'*x + c'*x - lambda*(a'*x-b)
610*a7e14dcfSSatish Balay    *
611*a7e14dcfSSatish Balay    *  Optimality conditions for \phi:
612*a7e14dcfSSatish Balay    *
613*a7e14dcfSSatish Balay    *  1. lambda   <= 0
614*a7e14dcfSSatish Balay    *  2. r        <= 0
615*a7e14dcfSSatish Balay    *  3. r*lambda == 0
616*a7e14dcfSSatish Balay    */
617*a7e14dcfSSatish Balay 
618*a7e14dcfSSatish Balay   /* Bracketing Phase */
619*a7e14dcfSSatish Balay   r = phi(x, n, lambda, a, b, c, l, u);
620*a7e14dcfSSatish Balay 
621*a7e14dcfSSatish Balay   if(nonNegativeSlack)
622*a7e14dcfSSatish Balay   {
623*a7e14dcfSSatish Balay     /* inequality constraint, i.e., with \xi >= 0 constraint */
624*a7e14dcfSSatish Balay     if (r < TOL_R)
625*a7e14dcfSSatish Balay       return 0;
626*a7e14dcfSSatish Balay   }
627*a7e14dcfSSatish Balay   else
628*a7e14dcfSSatish Balay   {
629*a7e14dcfSSatish Balay     /* equality constraint ,i.e., without \xi >= 0 constraint */
630*a7e14dcfSSatish Balay     if (fabs(r) < TOL_R)
631*a7e14dcfSSatish Balay       return 0;
632*a7e14dcfSSatish Balay   }
633*a7e14dcfSSatish Balay 
634*a7e14dcfSSatish Balay   if (r < 0.0){
635*a7e14dcfSSatish Balay     lambdal = lambda;
636*a7e14dcfSSatish Balay     rl      = r;
637*a7e14dcfSSatish Balay     lambda  = lambda + dlambda;
638*a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
639*a7e14dcfSSatish Balay     while (r < 0.0 && dlambda < BMRM_INFTY)  {
640*a7e14dcfSSatish Balay       lambdal = lambda;
641*a7e14dcfSSatish Balay       s       = rl/r - 1.0;
642*a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
643*a7e14dcfSSatish Balay       dlambda = dlambda + dlambda/s;
644*a7e14dcfSSatish Balay       lambda  = lambda + dlambda;
645*a7e14dcfSSatish Balay       rl      = r;
646*a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
647*a7e14dcfSSatish Balay     }
648*a7e14dcfSSatish Balay     lambdau = lambda;
649*a7e14dcfSSatish Balay     ru      = r;
650*a7e14dcfSSatish Balay   }
651*a7e14dcfSSatish Balay   else {
652*a7e14dcfSSatish Balay     lambdau = lambda;
653*a7e14dcfSSatish Balay     ru      = r;
654*a7e14dcfSSatish Balay     lambda  = lambda - dlambda;
655*a7e14dcfSSatish Balay     r       = phi(x, n, lambda, a, b, c, l, u);
656*a7e14dcfSSatish Balay     while (r > 0.0 && dlambda > -BMRM_INFTY) {
657*a7e14dcfSSatish Balay       lambdau = lambda;
658*a7e14dcfSSatish Balay       s       = ru/r - 1.0;
659*a7e14dcfSSatish Balay       if (s < 0.1) s = 0.1;
660*a7e14dcfSSatish Balay       dlambda = dlambda + dlambda/s;
661*a7e14dcfSSatish Balay       lambda  = lambda - dlambda;
662*a7e14dcfSSatish Balay       ru      = r;
663*a7e14dcfSSatish Balay       r       = phi(x, n, lambda, a, b, c, l, u);
664*a7e14dcfSSatish Balay     }
665*a7e14dcfSSatish Balay     lambdal = lambda;
666*a7e14dcfSSatish Balay     rl      = r;
667*a7e14dcfSSatish Balay   }
668*a7e14dcfSSatish Balay 
669*a7e14dcfSSatish Balay   if(fabs(dlambda) > BMRM_INFTY) {
670*a7e14dcfSSatish Balay     PetscPrintf(PETSC_COMM_SELF, "ERROR: L2N2_DaiFletcherPGM detected Infeasible QP problem!\n");
671*a7e14dcfSSatish Balay     exit(0);
672*a7e14dcfSSatish Balay   }
673*a7e14dcfSSatish Balay 
674*a7e14dcfSSatish Balay   if(ru == 0){
675*a7e14dcfSSatish Balay     lambda = lambdau;
676*a7e14dcfSSatish Balay     r = phi(x, n, lambda, a, b, c, l, u);
677*a7e14dcfSSatish Balay     return innerIter;
678*a7e14dcfSSatish Balay   }
679*a7e14dcfSSatish Balay 
680*a7e14dcfSSatish Balay   /* Secant Phase */
681*a7e14dcfSSatish Balay   s       = 1.0 - rl/ru;
682*a7e14dcfSSatish Balay   dlambda = dlambda/s;
683*a7e14dcfSSatish Balay   lambda  = lambdau - dlambda;
684*a7e14dcfSSatish Balay   r       = phi(x, n, lambda, a, b, c, l, u);
685*a7e14dcfSSatish Balay 
686*a7e14dcfSSatish Balay   while (fabs(r) > TOL_R
687*a7e14dcfSSatish Balay          && dlambda > TOL_LAM * (1.0 + fabs(lambda))
688*a7e14dcfSSatish Balay          && innerIter < df->maxProjIter){
689*a7e14dcfSSatish Balay     innerIter++;
690*a7e14dcfSSatish Balay     if (r > 0.0){
691*a7e14dcfSSatish Balay       if (s <= 2.0){
692*a7e14dcfSSatish Balay         lambdau = lambda;
693*a7e14dcfSSatish Balay         ru      = r;
694*a7e14dcfSSatish Balay         s       = 1.0 - rl/ru;
695*a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
696*a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
697*a7e14dcfSSatish Balay       }
698*a7e14dcfSSatish Balay       else {
699*a7e14dcfSSatish Balay         s          = ru/r-1.0;
700*a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
701*a7e14dcfSSatish Balay         dlambda    = (lambdau - lambda) / s;
702*a7e14dcfSSatish Balay         lambda_new = 0.75*lambdal + 0.25*lambda;
703*a7e14dcfSSatish Balay         if (lambda_new < (lambda - dlambda))
704*a7e14dcfSSatish Balay           lambda_new = lambda - dlambda;
705*a7e14dcfSSatish Balay         lambdau    = lambda;
706*a7e14dcfSSatish Balay         ru         = r;
707*a7e14dcfSSatish Balay         lambda     = lambda_new;
708*a7e14dcfSSatish Balay         s          = (lambdau - lambdal) / (lambdau - lambda);
709*a7e14dcfSSatish Balay       }
710*a7e14dcfSSatish Balay     }
711*a7e14dcfSSatish Balay     else {
712*a7e14dcfSSatish Balay       if (s >= 2.0){
713*a7e14dcfSSatish Balay         lambdal = lambda;
714*a7e14dcfSSatish Balay         rl      = r;
715*a7e14dcfSSatish Balay         s       = 1.0 - rl/ru;
716*a7e14dcfSSatish Balay         dlambda = (lambdau - lambdal) / s;
717*a7e14dcfSSatish Balay         lambda  = lambdau - dlambda;
718*a7e14dcfSSatish Balay       }
719*a7e14dcfSSatish Balay       else {
720*a7e14dcfSSatish Balay         s          = rl/r - 1.0;
721*a7e14dcfSSatish Balay         if (s < 0.1) s = 0.1;
722*a7e14dcfSSatish Balay         dlambda    = (lambda-lambdal) / s;
723*a7e14dcfSSatish Balay         lambda_new = 0.75*lambdau + 0.25*lambda;
724*a7e14dcfSSatish Balay         if (lambda_new > (lambda + dlambda))
725*a7e14dcfSSatish Balay           lambda_new = lambda + dlambda;
726*a7e14dcfSSatish Balay         lambdal    = lambda;
727*a7e14dcfSSatish Balay         rl         = r;
728*a7e14dcfSSatish Balay         lambda     = lambda_new;
729*a7e14dcfSSatish Balay         s          = (lambdau - lambdal) / (lambdau-lambda);
730*a7e14dcfSSatish Balay       }
731*a7e14dcfSSatish Balay     }
732*a7e14dcfSSatish Balay     r = phi(x, n, lambda, a, b, c, l, u);
733*a7e14dcfSSatish Balay   }
734*a7e14dcfSSatish Balay 
735*a7e14dcfSSatish Balay   *lam_ext = lambda;
736*a7e14dcfSSatish Balay   if(innerIter >= df->maxProjIter)
737*a7e14dcfSSatish Balay     PetscPrintf(PETSC_COMM_SELF, "WARNING: DaiFletcher max iterations\n");
738*a7e14dcfSSatish Balay 
739*a7e14dcfSSatish Balay   return innerIter;
740*a7e14dcfSSatish Balay }
741*a7e14dcfSSatish Balay 
742*a7e14dcfSSatish Balay 
743*a7e14dcfSSatish Balay #undef __FUNCT__
744*a7e14dcfSSatish Balay #define __FUNCT__ "solve"
745*a7e14dcfSSatish Balay PetscErrorCode solve(TAO_DF *df)
746*a7e14dcfSSatish Balay {
747*a7e14dcfSSatish Balay   PetscErrorCode ierr;
748*a7e14dcfSSatish Balay   PetscInt    i, j, innerIter, it, it2, luv, info, lscount = 0, projcount = 0;
749*a7e14dcfSSatish Balay   PetscReal gd, max, ak, bk, akold, bkold, lamnew, alpha, kktlam=0.0, lam_ext;
750*a7e14dcfSSatish Balay   PetscReal DELTAsv, ProdDELTAsv;
751*a7e14dcfSSatish Balay   PetscReal c, *tempQ;
752*a7e14dcfSSatish Balay   PetscReal *x = df->x, *a = df->a, b = df->b, *l = df->l, *u = df->u, tol = df->tol;
753*a7e14dcfSSatish Balay   PetscReal *tempv = df->tempv, *y = df->y, *g = df->g, *d = df->d, *Qd = df->Qd;
754*a7e14dcfSSatish Balay   PetscReal *xplus = df->xplus, *tplus = df->tplus, *sk = df->sk, *yk = df->yk;
755*a7e14dcfSSatish Balay   PetscReal **Q = df->Q, *f = df->f, *t = df->t;
756*a7e14dcfSSatish Balay   PetscInt dim = df->dim, *ipt = df->ipt, *ipt2 = df->ipt2, *uv = df->uv;
757*a7e14dcfSSatish Balay 
758*a7e14dcfSSatish Balay   /*** variables for the adaptive nonmonotone linesearch ***/
759*a7e14dcfSSatish Balay   PetscInt    L, llast;
760*a7e14dcfSSatish Balay   PetscReal fr, fbest, fv, fc, fv0;
761*a7e14dcfSSatish Balay   c = BMRM_INFTY;
762*a7e14dcfSSatish Balay 
763*a7e14dcfSSatish Balay   DELTAsv = EPS_SV;
764*a7e14dcfSSatish Balay   if (tol <= 1.0e-5 || dim <= 20)
765*a7e14dcfSSatish Balay     ProdDELTAsv = 0.0F;
766*a7e14dcfSSatish Balay   else
767*a7e14dcfSSatish Balay     ProdDELTAsv = EPS_SV;
768*a7e14dcfSSatish Balay 
769*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++)
770*a7e14dcfSSatish Balay     tempv[i] = -x[i];
771*a7e14dcfSSatish Balay 
772*a7e14dcfSSatish Balay   lam_ext = 0.0;
773*a7e14dcfSSatish Balay 
774*a7e14dcfSSatish Balay   /* Project the initial solution */
775*a7e14dcfSSatish Balay   projcount += project(dim, a, b, tempv, l, u, x, &lam_ext, df);
776*a7e14dcfSSatish Balay 
777*a7e14dcfSSatish Balay   /* Compute gradient
778*a7e14dcfSSatish Balay      g = Q*x + f; */
779*a7e14dcfSSatish Balay 
780*a7e14dcfSSatish Balay   it = 0;
781*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++)
782*a7e14dcfSSatish Balay     if (fabs(x[i]) > ProdDELTAsv)
783*a7e14dcfSSatish Balay       ipt[it++] = i;
784*a7e14dcfSSatish Balay 
785*a7e14dcfSSatish Balay   ierr = PetscMemzero(t, dim*sizeof(PetscReal));  CHKERRQ(ierr);
786*a7e14dcfSSatish Balay   for (i = 0; i < it; i++){
787*a7e14dcfSSatish Balay     tempQ = Q[ipt[i]];
788*a7e14dcfSSatish Balay     for (j = 0; j < dim; j++)
789*a7e14dcfSSatish Balay       t[j] += (tempQ[j]*x[ipt[i]]);
790*a7e14dcfSSatish Balay   }
791*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++){
792*a7e14dcfSSatish Balay     g[i] = t[i] + f[i];
793*a7e14dcfSSatish Balay   }
794*a7e14dcfSSatish Balay 
795*a7e14dcfSSatish Balay 
796*a7e14dcfSSatish Balay   /* y = -(x_{k} - g_{k}) */
797*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++){
798*a7e14dcfSSatish Balay     y[i] = g[i] - x[i];
799*a7e14dcfSSatish Balay   }
800*a7e14dcfSSatish Balay 
801*a7e14dcfSSatish Balay   /* Project x_{k} - g_{k} */
802*a7e14dcfSSatish Balay   projcount += project(dim, a, b, y, l, u, tempv, &lam_ext, df);
803*a7e14dcfSSatish Balay 
804*a7e14dcfSSatish Balay   /* y = P(x_{k} - g_{k}) - x_{k} */
805*a7e14dcfSSatish Balay   max = ALPHA_MIN;
806*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++){
807*a7e14dcfSSatish Balay     y[i] = tempv[i] - x[i];
808*a7e14dcfSSatish Balay     if (fabs(y[i]) > max)
809*a7e14dcfSSatish Balay       max = fabs(y[i]);
810*a7e14dcfSSatish Balay   }
811*a7e14dcfSSatish Balay 
812*a7e14dcfSSatish Balay   if (max < tol*1e-3){
813*a7e14dcfSSatish Balay     lscount = 0;
814*a7e14dcfSSatish Balay     innerIter    = 0;
815*a7e14dcfSSatish Balay     return 0;
816*a7e14dcfSSatish Balay   }
817*a7e14dcfSSatish Balay 
818*a7e14dcfSSatish Balay   alpha = 1.0 / max;
819*a7e14dcfSSatish Balay 
820*a7e14dcfSSatish Balay   /* fv0 = f(x_{0}). Recall t = Q x_{k}  */
821*a7e14dcfSSatish Balay   fv0   = 0.0;
822*a7e14dcfSSatish Balay   for (i = 0; i < dim; i++)
823*a7e14dcfSSatish Balay     fv0 += x[i] * (0.5*t[i] + f[i]);
824*a7e14dcfSSatish Balay 
825*a7e14dcfSSatish Balay   /*** adaptive nonmonotone linesearch ***/
826*a7e14dcfSSatish Balay   L     = 2;
827*a7e14dcfSSatish Balay   fr    = ALPHA_MAX;
828*a7e14dcfSSatish Balay   fbest = fv0;
829*a7e14dcfSSatish Balay   fc    = fv0;
830*a7e14dcfSSatish Balay   llast = 0;
831*a7e14dcfSSatish Balay   akold = bkold = 0.0;
832*a7e14dcfSSatish Balay 
833*a7e14dcfSSatish Balay   /***      Iterator begins     ***/
834*a7e14dcfSSatish Balay   for (innerIter = 1; innerIter <= df->maxPGMIter; innerIter++) {
835*a7e14dcfSSatish Balay 
836*a7e14dcfSSatish Balay     /* tempv = -(x_{k} - alpha*g_{k}) */
837*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
838*a7e14dcfSSatish Balay       tempv[i] = alpha*g[i] - x[i];
839*a7e14dcfSSatish Balay 
840*a7e14dcfSSatish Balay     /* Project x_{k} - alpha*g_{k} */
841*a7e14dcfSSatish Balay     projcount += project(dim, a, b, tempv, l, u, y, &lam_ext, df);
842*a7e14dcfSSatish Balay 
843*a7e14dcfSSatish Balay 
844*a7e14dcfSSatish Balay     /* gd = \inner{d_{k}}{g_{k}}
845*a7e14dcfSSatish Balay         d = P(x_{k} - alpha*g_{k}) - x_{k}
846*a7e14dcfSSatish Balay     */
847*a7e14dcfSSatish Balay     gd = 0.0;
848*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++){
849*a7e14dcfSSatish Balay       d[i] = y[i] - x[i];
850*a7e14dcfSSatish Balay       gd  += d[i] * g[i];
851*a7e14dcfSSatish Balay     }
852*a7e14dcfSSatish Balay 
853*a7e14dcfSSatish Balay     /* Gradient computation  */
854*a7e14dcfSSatish Balay 
855*a7e14dcfSSatish Balay     /* compute Qd = Q*d  or  Qd = Q*y - t depending on their sparsity */
856*a7e14dcfSSatish Balay 
857*a7e14dcfSSatish Balay     it = it2 = 0;
858*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
859*a7e14dcfSSatish Balay       if (fabs(d[i]) > (ProdDELTAsv*1.0e-2))
860*a7e14dcfSSatish Balay         ipt[it++]   = i;
861*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
862*a7e14dcfSSatish Balay       if (fabs(y[i]) > ProdDELTAsv)
863*a7e14dcfSSatish Balay         ipt2[it2++] = i;
864*a7e14dcfSSatish Balay 
865*a7e14dcfSSatish Balay     ierr = PetscMemzero(Qd, dim*sizeof(PetscReal));  CHKERRQ(ierr);
866*a7e14dcfSSatish Balay     /* compute Qd = Q*d */
867*a7e14dcfSSatish Balay     if (it < it2){
868*a7e14dcfSSatish Balay       for (i = 0; i < it; i++){
869*a7e14dcfSSatish Balay         tempQ = Q[ipt[i]];
870*a7e14dcfSSatish Balay         for (j = 0; j < dim; j++)
871*a7e14dcfSSatish Balay           Qd[j] += (tempQ[j] * d[ipt[i]]);
872*a7e14dcfSSatish Balay       }
873*a7e14dcfSSatish Balay     }
874*a7e14dcfSSatish Balay     else { /* compute Qd = Q*y-t */
875*a7e14dcfSSatish Balay       for (i = 0; i < it2; i++){
876*a7e14dcfSSatish Balay         tempQ = Q[ipt2[i]];
877*a7e14dcfSSatish Balay         for (j = 0; j < dim; j++)
878*a7e14dcfSSatish Balay           Qd[j] += (tempQ[j] * y[ipt2[i]]);
879*a7e14dcfSSatish Balay       }
880*a7e14dcfSSatish Balay       for (j = 0; j < dim; j++)
881*a7e14dcfSSatish Balay         Qd[j] -= t[j];
882*a7e14dcfSSatish Balay     }
883*a7e14dcfSSatish Balay 
884*a7e14dcfSSatish Balay 
885*a7e14dcfSSatish Balay     /* ak = inner{d_{k}}{d_{k}} */
886*a7e14dcfSSatish Balay     ak = 0.0;
887*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
888*a7e14dcfSSatish Balay       ak += d[i] * d[i];
889*a7e14dcfSSatish Balay 
890*a7e14dcfSSatish Balay     bk = 0.0;
891*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
892*a7e14dcfSSatish Balay       bk += d[i]*Qd[i];
893*a7e14dcfSSatish Balay 
894*a7e14dcfSSatish Balay     if (bk > EPS*ak && gd < 0.0)    /* ak is normd */
895*a7e14dcfSSatish Balay       lamnew = -gd/bk;
896*a7e14dcfSSatish Balay     else
897*a7e14dcfSSatish Balay       lamnew = 1.0;
898*a7e14dcfSSatish Balay 
899*a7e14dcfSSatish Balay     /* fv is computing f(x_{k} + d_{k}) */
900*a7e14dcfSSatish Balay     fv = 0.0;
901*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++){
902*a7e14dcfSSatish Balay       xplus[i] = x[i] + d[i];
903*a7e14dcfSSatish Balay       tplus[i] = t[i] + Qd[i];
904*a7e14dcfSSatish Balay       fv      += xplus[i] * (0.5*tplus[i] + f[i]);
905*a7e14dcfSSatish Balay     }
906*a7e14dcfSSatish Balay 
907*a7e14dcfSSatish Balay     /* fr is fref */
908*a7e14dcfSSatish Balay     if ((innerIter == 1 && fv >= fv0) || (innerIter > 1 && fv >= fr)){
909*a7e14dcfSSatish Balay       lscount++;
910*a7e14dcfSSatish Balay       fv = 0.0;
911*a7e14dcfSSatish Balay       for (i = 0; i < dim; i++){
912*a7e14dcfSSatish Balay         xplus[i] = x[i] + lamnew*d[i];
913*a7e14dcfSSatish Balay         tplus[i] = t[i] + lamnew*Qd[i];
914*a7e14dcfSSatish Balay         fv      += xplus[i] * (0.5*tplus[i] + f[i]);
915*a7e14dcfSSatish Balay       }
916*a7e14dcfSSatish Balay     }
917*a7e14dcfSSatish Balay 
918*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++){
919*a7e14dcfSSatish Balay       sk[i] = xplus[i] - x[i];
920*a7e14dcfSSatish Balay       yk[i] = tplus[i] - t[i];
921*a7e14dcfSSatish Balay       x[i]  = xplus[i];
922*a7e14dcfSSatish Balay       t[i]  = tplus[i];
923*a7e14dcfSSatish Balay       g[i]  = t[i] + f[i];
924*a7e14dcfSSatish Balay     }
925*a7e14dcfSSatish Balay 
926*a7e14dcfSSatish Balay 
927*a7e14dcfSSatish Balay     /* update the line search control parameters */
928*a7e14dcfSSatish Balay 
929*a7e14dcfSSatish Balay     if (fv < fbest){
930*a7e14dcfSSatish Balay       fbest = fv;
931*a7e14dcfSSatish Balay       fc    = fv;
932*a7e14dcfSSatish Balay       llast = 0;
933*a7e14dcfSSatish Balay     }
934*a7e14dcfSSatish Balay     else {
935*a7e14dcfSSatish Balay       fc = (fc > fv ? fc : fv);
936*a7e14dcfSSatish Balay       llast++;
937*a7e14dcfSSatish Balay       if (llast == L){
938*a7e14dcfSSatish Balay         fr    = fc;
939*a7e14dcfSSatish Balay         fc    = fv;
940*a7e14dcfSSatish Balay         llast = 0;
941*a7e14dcfSSatish Balay       }
942*a7e14dcfSSatish Balay     }
943*a7e14dcfSSatish Balay 
944*a7e14dcfSSatish Balay     ak = bk = 0.0;
945*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++){
946*a7e14dcfSSatish Balay       ak += sk[i] * sk[i];
947*a7e14dcfSSatish Balay       bk += sk[i] * yk[i];
948*a7e14dcfSSatish Balay     }
949*a7e14dcfSSatish Balay 
950*a7e14dcfSSatish Balay     if (bk <= EPS*ak)
951*a7e14dcfSSatish Balay       alpha = ALPHA_MAX;
952*a7e14dcfSSatish Balay     else{
953*a7e14dcfSSatish Balay       if (bkold < EPS*akold)
954*a7e14dcfSSatish Balay         alpha = ak/bk;
955*a7e14dcfSSatish Balay       else
956*a7e14dcfSSatish Balay         alpha = (akold+ak)/(bkold+bk);
957*a7e14dcfSSatish Balay 
958*a7e14dcfSSatish Balay       if (alpha > ALPHA_MAX)
959*a7e14dcfSSatish Balay         alpha = ALPHA_MAX;
960*a7e14dcfSSatish Balay       else if (alpha < ALPHA_MIN)
961*a7e14dcfSSatish Balay         alpha = ALPHA_MIN;
962*a7e14dcfSSatish Balay     }
963*a7e14dcfSSatish Balay 
964*a7e14dcfSSatish Balay     akold = ak;
965*a7e14dcfSSatish Balay     bkold = bk;
966*a7e14dcfSSatish Balay 
967*a7e14dcfSSatish Balay 
968*a7e14dcfSSatish Balay     /*** stopping criterion based on KKT conditions ***/
969*a7e14dcfSSatish Balay     /* at optimal, gradient of lagrangian w.r.t. x is zero */
970*a7e14dcfSSatish Balay 
971*a7e14dcfSSatish Balay     bk = 0.0;
972*a7e14dcfSSatish Balay     for (i = 0; i < dim; i++)
973*a7e14dcfSSatish Balay       bk +=  x[i] * x[i];
974*a7e14dcfSSatish Balay 
975*a7e14dcfSSatish Balay     if (sqrt(ak) < tol*10 * sqrt(bk)){
976*a7e14dcfSSatish Balay       it     = 0;
977*a7e14dcfSSatish Balay       luv    = 0;
978*a7e14dcfSSatish Balay       kktlam = 0.0;
979*a7e14dcfSSatish Balay       for (i = 0; i < dim; i++){
980*a7e14dcfSSatish Balay         /* x[i] is active hence lagrange multipliers for box constraints
981*a7e14dcfSSatish Balay                 are zero. The lagrange multiplier for ineq. const. is then
982*a7e14dcfSSatish Balay                 defined as below
983*a7e14dcfSSatish Balay         */
984*a7e14dcfSSatish Balay         if ((x[i] > DELTAsv) && (x[i] < c-DELTAsv)){
985*a7e14dcfSSatish Balay           ipt[it++] = i;
986*a7e14dcfSSatish Balay           kktlam    = kktlam - a[i]*g[i];
987*a7e14dcfSSatish Balay         }
988*a7e14dcfSSatish Balay         else
989*a7e14dcfSSatish Balay           uv[luv++] = i;
990*a7e14dcfSSatish Balay       }
991*a7e14dcfSSatish Balay 
992*a7e14dcfSSatish Balay       if (it == 0 && sqrt(ak) < tol*0.5 * sqrt(bk))
993*a7e14dcfSSatish Balay         return 0;
994*a7e14dcfSSatish Balay       else {
995*a7e14dcfSSatish Balay         kktlam = kktlam/it;
996*a7e14dcfSSatish Balay         info   = 1;
997*a7e14dcfSSatish Balay         for (i = 0; i < it; i++) {
998*a7e14dcfSSatish Balay           if (fabs(a[ipt[i]] * g[ipt[i]] + kktlam) > tol) {
999*a7e14dcfSSatish Balay             info = 0;
1000*a7e14dcfSSatish Balay             break;
1001*a7e14dcfSSatish Balay           }
1002*a7e14dcfSSatish Balay         }
1003*a7e14dcfSSatish Balay         if (info == 1)  {
1004*a7e14dcfSSatish Balay           for (i = 0; i < luv; i++)  {
1005*a7e14dcfSSatish Balay             if (x[uv[i]] <= DELTAsv){
1006*a7e14dcfSSatish Balay               /* x[i] == lower bound, hence, lagrange multiplier (say, beta) for lower bound may
1007*a7e14dcfSSatish Balay                      not be zero. So, the gradient without beta is > 0
1008*a7e14dcfSSatish Balay               */
1009*a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam*a[uv[i]] < -tol){
1010*a7e14dcfSSatish Balay                 info = 0;
1011*a7e14dcfSSatish Balay                 break;
1012*a7e14dcfSSatish Balay               }
1013*a7e14dcfSSatish Balay             }
1014*a7e14dcfSSatish Balay             else {
1015*a7e14dcfSSatish Balay               /* x[i] == upper bound, hence, lagrange multiplier (say, eta) for upper bound may
1016*a7e14dcfSSatish Balay                      not be zero. So, the gradient without eta is < 0
1017*a7e14dcfSSatish Balay               */
1018*a7e14dcfSSatish Balay               if (g[uv[i]] + kktlam*a[uv[i]] > tol) {
1019*a7e14dcfSSatish Balay                 info = 0;
1020*a7e14dcfSSatish Balay                 break;
1021*a7e14dcfSSatish Balay               }
1022*a7e14dcfSSatish Balay             }
1023*a7e14dcfSSatish Balay           }
1024*a7e14dcfSSatish Balay         }
1025*a7e14dcfSSatish Balay 
1026*a7e14dcfSSatish Balay         if (info == 1)
1027*a7e14dcfSSatish Balay           return 0;
1028*a7e14dcfSSatish Balay       }
1029*a7e14dcfSSatish Balay     }
1030*a7e14dcfSSatish Balay   }
1031*a7e14dcfSSatish Balay   return 0;
1032*a7e14dcfSSatish Balay }
1033*a7e14dcfSSatish Balay 
1034*a7e14dcfSSatish Balay 
1035