xref: /petsc/src/tao/quadratic/impls/bqpip/bqpip.c (revision 9566063d113dddea24716c546802770db7481bc0)
174962610SAlp Dener /*
274962610SAlp Dener     This file implements a Mehrotra predictor-corrector method for
374962610SAlp Dener     bound-constrained quadratic programs.
474962610SAlp Dener 
574962610SAlp Dener  */
674962610SAlp Dener 
774962610SAlp Dener #include <../src/tao/quadratic/impls/bqpip/bqpipimpl.h>
874962610SAlp Dener #include <petscksp.h>
974962610SAlp Dener 
1074962610SAlp Dener static PetscErrorCode QPIPComputeResidual(TAO_BQPIP *qp,Tao tao)
1174962610SAlp Dener {
1274962610SAlp Dener   PetscReal      dtmp = 1.0 - qp->psteplength;
1374962610SAlp Dener 
1474962610SAlp Dener   PetscFunctionBegin;
1574962610SAlp Dener   /* Compute R3 and R5 */
1674962610SAlp Dener 
17*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->R3,dtmp));
18*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->R5,dtmp));
1974962610SAlp Dener   qp->pinfeas=dtmp*qp->pinfeas;
2074962610SAlp Dener 
21*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->S,tao->gradient));
22*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient,-1.0,qp->Z));
2374962610SAlp Dener 
24*9566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian,tao->solution,qp->RHS));
25*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->RHS,-1.0));
26*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->RHS,-1.0,qp->C));
27*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient,-1.0,qp->RHS));
2874962610SAlp Dener 
29*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(tao->gradient,NORM_1,&qp->dinfeas));
3074962610SAlp Dener   qp->rnorm=(qp->dinfeas+qp->pinfeas)/(qp->m+qp->n);
3174962610SAlp Dener   PetscFunctionReturn(0);
3274962610SAlp Dener }
3374962610SAlp Dener 
3474962610SAlp Dener static PetscErrorCode  QPIPSetInitialPoint(TAO_BQPIP *qp, Tao tao)
3574962610SAlp Dener {
3674962610SAlp Dener   PetscReal      two=2.0,p01=1;
3774962610SAlp Dener   PetscReal      gap1,gap2,fff,mu;
3874962610SAlp Dener 
3974962610SAlp Dener   PetscFunctionBegin;
4074962610SAlp Dener   /* Compute function, Gradient R=Hx+b, and Hessian */
41*9566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian,tao->solution,tao->gradient));
42*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->C,qp->Work));
43*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->Work,0.5,tao->gradient));
44*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient,1.0,qp->C));
45*9566063dSJacob Faibussowitsch   PetscCall(VecDot(tao->solution,qp->Work,&fff));
4674962610SAlp Dener   qp->pobj = fff + qp->d;
4774962610SAlp Dener 
483c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(qp->pobj),PETSC_COMM_SELF,PETSC_ERR_USER, "User provided data contains Inf or NaN");
4974962610SAlp Dener 
5074962610SAlp Dener   /* Initialize slack vectors */
5174962610SAlp Dener   /* T = XU - X; G = X - XL */
52*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->XU,qp->T));
53*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->T,-1.0,tao->solution));
54*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->solution,qp->G));
55*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->G,-1.0,qp->XL));
5674962610SAlp Dener 
57*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->GZwork,p01));
58*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->TSwork,p01));
5974962610SAlp Dener 
60*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->G,qp->G,qp->GZwork));
61*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->T,qp->T,qp->TSwork));
6274962610SAlp Dener 
6374962610SAlp Dener   /* Initialize Dual Variable Vectors */
64*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->G,qp->Z));
65*9566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(qp->Z));
6674962610SAlp Dener 
67*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->T,qp->S));
68*9566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(qp->S));
6974962610SAlp Dener 
70*9566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian,qp->Work,qp->RHS));
71*9566063dSJacob Faibussowitsch   PetscCall(VecAbs(qp->RHS));
72*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->Work,p01));
73*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->RHS,qp->RHS,qp->Work));
7474962610SAlp Dener 
75*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->RHS,tao->gradient,qp->RHS));
76*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->RHS,NORM_1,&gap1));
7774962610SAlp Dener   mu = PetscMin(10.0,(gap1+10.0)/qp->m);
7874962610SAlp Dener 
79*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->S,mu));
80*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->Z,mu));
8174962610SAlp Dener 
82*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->TSwork,p01));
83*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->GZwork,p01));
84*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->S,qp->S,qp->TSwork));
85*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->Z,qp->Z,qp->GZwork));
8674962610SAlp Dener 
8774962610SAlp Dener   qp->mu=0;qp->dinfeas=1.0;qp->pinfeas=1.0;
8874962610SAlp Dener   while ((qp->dinfeas+qp->pinfeas)/(qp->m+qp->n) >= qp->mu) {
89*9566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->G,two));
90*9566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->Z,two));
91*9566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->S,two));
92*9566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->T,two));
9374962610SAlp Dener 
94*9566063dSJacob Faibussowitsch     PetscCall(QPIPComputeResidual(qp,tao));
9574962610SAlp Dener 
96*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution,qp->R3));
97*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R3,-1.0,qp->G));
98*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R3,-1.0,qp->XL));
9974962610SAlp Dener 
100*9566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution,qp->R5));
101*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R5,1.0,qp->T));
102*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R5,-1.0,qp->XU));
10374962610SAlp Dener 
104*9566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->R3,NORM_INFINITY,&gap1));
105*9566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->R5,NORM_INFINITY,&gap2));
10674962610SAlp Dener     qp->pinfeas=PetscMax(gap1,gap2);
10774962610SAlp Dener 
10874962610SAlp Dener     /* Compute the duality gap */
109*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->G,qp->Z,&gap1));
110*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->T,qp->S,&gap2));
11174962610SAlp Dener 
11274962610SAlp Dener     qp->gap  = gap1+gap2;
11374962610SAlp Dener     qp->dobj = qp->pobj - qp->gap;
11474962610SAlp Dener     if (qp->m>0) {
11574962610SAlp Dener       qp->mu=qp->gap/(qp->m);
11674962610SAlp Dener     } else {
11774962610SAlp Dener       qp->mu=0.0;
11874962610SAlp Dener     }
11974962610SAlp Dener     qp->rgap=qp->gap/(PetscAbsReal(qp->dobj) + PetscAbsReal(qp->pobj) + 1.0);
12074962610SAlp Dener   }
12174962610SAlp Dener   PetscFunctionReturn(0);
12274962610SAlp Dener }
12374962610SAlp Dener 
12474962610SAlp Dener static PetscErrorCode QPIPStepLength(TAO_BQPIP *qp)
12574962610SAlp Dener {
12674962610SAlp Dener   PetscReal      tstep1,tstep2,tstep3,tstep4,tstep;
12774962610SAlp Dener 
12874962610SAlp Dener   PetscFunctionBegin;
12974962610SAlp Dener   /* Compute stepsize to the boundary */
130*9566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->G,qp->DG,&tstep1));
131*9566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->T,qp->DT,&tstep2));
132*9566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->S,qp->DS,&tstep3));
133*9566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->Z,qp->DZ,&tstep4));
13474962610SAlp Dener 
13574962610SAlp Dener   tstep = PetscMin(tstep1,tstep2);
13674962610SAlp Dener   qp->psteplength = PetscMin(0.95*tstep,1.0);
13774962610SAlp Dener 
13874962610SAlp Dener   tstep = PetscMin(tstep3,tstep4);
13974962610SAlp Dener   qp->dsteplength = PetscMin(0.95*tstep,1.0);
14074962610SAlp Dener 
14174962610SAlp Dener   qp->psteplength = PetscMin(qp->psteplength,qp->dsteplength);
14274962610SAlp Dener   qp->dsteplength = qp->psteplength;
14374962610SAlp Dener   PetscFunctionReturn(0);
14474962610SAlp Dener }
14574962610SAlp Dener 
14674962610SAlp Dener static PetscErrorCode QPIPComputeNormFromCentralPath(TAO_BQPIP *qp,PetscReal *norm)
14774962610SAlp Dener {
14874962610SAlp Dener   PetscReal      gap[2],mu[2],nmu;
14974962610SAlp Dener 
15074962610SAlp Dener   PetscFunctionBegin;
151*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->GZwork,qp->G,qp->Z));
152*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->TSwork,qp->T,qp->S));
153*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->TSwork,NORM_1,&mu[0]));
154*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->GZwork,NORM_1,&mu[1]));
15574962610SAlp Dener 
15674962610SAlp Dener   nmu=-(mu[0]+mu[1])/qp->m;
15774962610SAlp Dener 
158*9566063dSJacob Faibussowitsch   PetscCall(VecShift(qp->GZwork,nmu));
159*9566063dSJacob Faibussowitsch   PetscCall(VecShift(qp->TSwork,nmu));
16074962610SAlp Dener 
161*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->GZwork,NORM_2,&gap[0]));
162*9566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->TSwork,NORM_2,&gap[1]));
16374962610SAlp Dener   gap[0]*=gap[0];
16474962610SAlp Dener   gap[1]*=gap[1];
16574962610SAlp Dener 
16674962610SAlp Dener   qp->pathnorm=PetscSqrtScalar(gap[0]+gap[1]);
16774962610SAlp Dener   *norm=qp->pathnorm;
16874962610SAlp Dener   PetscFunctionReturn(0);
16974962610SAlp Dener }
17074962610SAlp Dener 
17174962610SAlp Dener static PetscErrorCode QPIPComputeStepDirection(TAO_BQPIP *qp,Tao tao)
17274962610SAlp Dener {
17374962610SAlp Dener   PetscFunctionBegin;
17474962610SAlp Dener   /* Calculate DG */
175*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->stepdirection,qp->DG));
176*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DG,1.0,qp->R3));
17774962610SAlp Dener 
17874962610SAlp Dener   /* Calculate DT */
179*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->stepdirection,qp->DT));
180*9566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->DT,-1.0));
181*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DT,-1.0,qp->R5));
18274962610SAlp Dener 
18374962610SAlp Dener   /* Calculate DZ */
184*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DZ,-1.0,qp->Z));
185*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->GZwork,qp->DG,qp->G));
186*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->GZwork,qp->GZwork,qp->Z));
187*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DZ,-1.0,qp->GZwork));
18874962610SAlp Dener 
18974962610SAlp Dener   /* Calculate DS */
190*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DS,-1.0,qp->S));
191*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->TSwork,qp->DT,qp->T));
192*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->TSwork,qp->TSwork,qp->S));
193*9566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DS,-1.0,qp->TSwork));
19474962610SAlp Dener   PetscFunctionReturn(0);
19574962610SAlp Dener }
19674962610SAlp Dener 
19774962610SAlp Dener static PetscErrorCode TaoSetup_BQPIP(Tao tao)
19874962610SAlp Dener {
19974962610SAlp Dener   TAO_BQPIP      *qp =(TAO_BQPIP*)tao->data;
20074962610SAlp Dener 
20174962610SAlp Dener   PetscFunctionBegin;
20274962610SAlp Dener   /* Set pointers to Data */
203*9566063dSJacob Faibussowitsch   PetscCall(VecGetSize(tao->solution,&qp->n));
20474962610SAlp Dener 
20574962610SAlp Dener   /* Allocate some arrays */
20674962610SAlp Dener   if (!tao->gradient) {
207*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->gradient));
20874962610SAlp Dener   }
20974962610SAlp Dener   if (!tao->stepdirection) {
210*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->stepdirection));
21174962610SAlp Dener   }
21274962610SAlp Dener   if (!tao->XL) {
213*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->XL));
214*9566063dSJacob Faibussowitsch     PetscCall(VecSet(tao->XL,PETSC_NINFINITY));
21574962610SAlp Dener   }
21674962610SAlp Dener   if (!tao->XU) {
217*9566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution,&tao->XU));
218*9566063dSJacob Faibussowitsch     PetscCall(VecSet(tao->XU,PETSC_INFINITY));
21974962610SAlp Dener   }
22074962610SAlp Dener 
221*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->Work));
222*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->XU));
223*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->XL));
224*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->HDiag));
225*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->DiagAxpy));
226*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->RHS));
227*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->RHS2));
228*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->C));
22974962610SAlp Dener 
230*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->G));
231*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->DG));
232*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->S));
233*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->Z));
234*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->DZ));
235*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->GZwork));
236*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->R3));
23774962610SAlp Dener 
238*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->T));
239*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->DT));
240*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->DS));
241*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->TSwork));
242*9566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution,&qp->R5));
24374962610SAlp Dener   qp->m=2*qp->n;
24474962610SAlp Dener   PetscFunctionReturn(0);
24574962610SAlp Dener }
24674962610SAlp Dener 
24774962610SAlp Dener static PetscErrorCode TaoSolve_BQPIP(Tao tao)
24874962610SAlp Dener {
24974962610SAlp Dener   TAO_BQPIP          *qp = (TAO_BQPIP*)tao->data;
25074962610SAlp Dener   PetscInt           its;
25174962610SAlp Dener   PetscReal          d1,d2,ksptol,sigmamu;
25274962610SAlp Dener   PetscReal          gnorm,dstep,pstep,step=0;
25374962610SAlp Dener   PetscReal          gap[4];
25474962610SAlp Dener   PetscBool          getdiagop;
25574962610SAlp Dener 
25674962610SAlp Dener   PetscFunctionBegin;
25774962610SAlp Dener   qp->dobj        = 0.0;
25874962610SAlp Dener   qp->pobj        = 1.0;
25974962610SAlp Dener   qp->gap         = 10.0;
26074962610SAlp Dener   qp->rgap        = 1.0;
26174962610SAlp Dener   qp->mu          = 1.0;
26274962610SAlp Dener   qp->dinfeas     = 1.0;
26374962610SAlp Dener   qp->psteplength = 0.0;
26474962610SAlp Dener   qp->dsteplength = 0.0;
26574962610SAlp Dener 
26674962610SAlp Dener   /* TODO
26774962610SAlp Dener      - Remove fixed variables and treat them correctly
26874962610SAlp Dener      - Use index sets for the infinite versus finite bounds
26974962610SAlp Dener      - Update remaining code for fixed and free variables
27074962610SAlp Dener      - Fix inexact solves for predictor and corrector
27174962610SAlp Dener   */
27274962610SAlp Dener 
27374962610SAlp Dener   /* Tighten infinite bounds, things break when we don't do this
27474962610SAlp Dener     -- see test_bqpip.c
27574962610SAlp Dener   */
276*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
277*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->XU,1.0e20));
278*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->XL,-1.0e20));
279*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->XL,qp->XL,tao->XL));
280*9566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMin(qp->XU,qp->XU,tao->XU));
281*9566063dSJacob Faibussowitsch   PetscCall(VecMedian(qp->XL,tao->solution,qp->XU,tao->solution));
28274962610SAlp Dener 
28374962610SAlp Dener   /* Evaluate gradient and Hessian at zero to get the correct values
28474962610SAlp Dener      without contaminating them with numerical artifacts.
28574962610SAlp Dener   */
286*9566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->Work,0));
287*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao,qp->Work,&qp->d,qp->C));
288*9566063dSJacob Faibussowitsch   PetscCall(TaoComputeHessian(tao,qp->Work,tao->hessian,tao->hessian_pre));
289*9566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(tao->hessian,MATOP_GET_DIAGONAL,&getdiagop));
29074962610SAlp Dener   if (getdiagop) {
291*9566063dSJacob Faibussowitsch     PetscCall(MatGetDiagonal(tao->hessian,qp->HDiag));
29274962610SAlp Dener   }
29374962610SAlp Dener 
29474962610SAlp Dener   /* Initialize starting point and residuals */
295*9566063dSJacob Faibussowitsch   PetscCall(QPIPSetInitialPoint(qp,tao));
296*9566063dSJacob Faibussowitsch   PetscCall(QPIPComputeResidual(qp,tao));
29774962610SAlp Dener 
29874962610SAlp Dener   /* Enter main loop */
29974962610SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
30074962610SAlp Dener   while (1) {
30174962610SAlp Dener 
30274962610SAlp Dener     /* Check Stopping Condition      */
30374962610SAlp Dener     gnorm = PetscSqrtScalar(qp->gap + qp->dinfeas);
304*9566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao,qp->pobj,gnorm,qp->pinfeas,tao->ksp_its));
305*9566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao,tao->niter,qp->pobj,gnorm,qp->pinfeas,step));
306*9566063dSJacob Faibussowitsch     PetscCall((*tao->ops->convergencetest)(tao,tao->cnvP));
30774962610SAlp Dener     if (tao->reason != TAO_CONTINUE_ITERATING) break;
308e1e80dc8SAlp Dener     /* Call general purpose update function */
309e1e80dc8SAlp Dener     if (tao->ops->update) {
310*9566063dSJacob Faibussowitsch       PetscCall((*tao->ops->update)(tao, tao->niter, tao->user_update));
311e1e80dc8SAlp Dener     }
31274962610SAlp Dener     tao->niter++;
31374962610SAlp Dener     tao->ksp_its = 0;
31474962610SAlp Dener 
31574962610SAlp Dener     /*
31674962610SAlp Dener        Dual Infeasibility Direction should already be in the right
31774962610SAlp Dener        hand side from computing the residuals
31874962610SAlp Dener     */
31974962610SAlp Dener 
320*9566063dSJacob Faibussowitsch     PetscCall(QPIPComputeNormFromCentralPath(qp,&d1));
32174962610SAlp Dener 
322*9566063dSJacob Faibussowitsch     PetscCall(VecSet(qp->DZ,0.0));
323*9566063dSJacob Faibussowitsch     PetscCall(VecSet(qp->DS,0.0));
32474962610SAlp Dener 
32574962610SAlp Dener     /*
32674962610SAlp Dener        Compute the Primal Infeasiblitiy RHS and the
32774962610SAlp Dener        Diagonal Matrix to be added to H and store in Work
32874962610SAlp Dener     */
329*9566063dSJacob Faibussowitsch     PetscCall(VecPointwiseDivide(qp->DiagAxpy,qp->Z,qp->G));
330*9566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(qp->GZwork,qp->DiagAxpy,qp->R3));
331*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS,-1.0,qp->GZwork));
33274962610SAlp Dener 
333*9566063dSJacob Faibussowitsch     PetscCall(VecPointwiseDivide(qp->TSwork,qp->S,qp->T));
334*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->DiagAxpy,1.0,qp->TSwork));
335*9566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(qp->TSwork,qp->TSwork,qp->R5));
336*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS,-1.0,qp->TSwork));
33774962610SAlp Dener 
33874962610SAlp Dener     /*  Determine the solving tolerance */
33974962610SAlp Dener     ksptol = qp->mu/10.0;
34074962610SAlp Dener     ksptol = PetscMin(ksptol,0.001);
341*9566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(tao->ksp,ksptol,1e-30,1e30,PetscMax(10,qp->n)));
34274962610SAlp Dener 
34374962610SAlp Dener     /* Shift the diagonals of the Hessian matrix */
344*9566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(tao->hessian,qp->DiagAxpy,ADD_VALUES));
34574962610SAlp Dener     if (!getdiagop) {
346*9566063dSJacob Faibussowitsch       PetscCall(VecCopy(qp->DiagAxpy,qp->HDiag));
347*9566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->HDiag,-1.0));
34874962610SAlp Dener     }
349*9566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY));
350*9566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY));
35174962610SAlp Dener 
352*9566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(tao->ksp,tao->hessian,tao->hessian_pre));
353*9566063dSJacob Faibussowitsch     PetscCall(KSPSolve(tao->ksp,qp->RHS,tao->stepdirection));
354*9566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(tao->ksp,&its));
35574962610SAlp Dener     tao->ksp_its += its;
35674962610SAlp Dener     tao->ksp_tot_its += its;
35774962610SAlp Dener 
35874962610SAlp Dener     /* Restore the true diagonal of the Hessian matrix */
35974962610SAlp Dener     if (getdiagop) {
360*9566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian,qp->HDiag,INSERT_VALUES));
36174962610SAlp Dener     } else {
362*9566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian,qp->HDiag,ADD_VALUES));
36374962610SAlp Dener     }
364*9566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY));
365*9566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY));
366*9566063dSJacob Faibussowitsch     PetscCall(QPIPComputeStepDirection(qp,tao));
367*9566063dSJacob Faibussowitsch     PetscCall(QPIPStepLength(qp));
36874962610SAlp Dener 
36974962610SAlp Dener     /* Calculate New Residual R1 in Work vector */
370*9566063dSJacob Faibussowitsch     PetscCall(MatMult(tao->hessian,tao->stepdirection,qp->RHS2));
371*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS2,1.0,qp->DS));
372*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS2,-1.0,qp->DZ));
373*9566063dSJacob Faibussowitsch     PetscCall(VecAYPX(qp->RHS2,qp->dsteplength,tao->gradient));
37474962610SAlp Dener 
375*9566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->RHS2,NORM_2,&qp->dinfeas));
376*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->DZ,qp->DG,gap));
377*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->DS,qp->DT,gap+1));
37874962610SAlp Dener 
37974962610SAlp Dener     qp->rnorm = (qp->dinfeas+qp->psteplength*qp->pinfeas)/(qp->m+qp->n);
38074962610SAlp Dener     pstep     = qp->psteplength;
38174962610SAlp Dener     step      = PetscMin(qp->psteplength,qp->dsteplength);
38274962610SAlp Dener     sigmamu   = (pstep*pstep*(gap[0]+gap[1]) + (1 - pstep)*qp->gap)/qp->m;
38374962610SAlp Dener 
38474962610SAlp Dener     if (qp->predcorr && step < 0.9) {
38574962610SAlp Dener       if (sigmamu < qp->mu) {
38674962610SAlp Dener         sigmamu = sigmamu/qp->mu;
38774962610SAlp Dener         sigmamu = sigmamu*sigmamu*sigmamu;
38874962610SAlp Dener       } else {
38974962610SAlp Dener         sigmamu = 1.0;
39074962610SAlp Dener       }
39174962610SAlp Dener       sigmamu = sigmamu*qp->mu;
39274962610SAlp Dener 
39374962610SAlp Dener       /* Compute Corrector Step */
394*9566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(qp->DZ,qp->DG,qp->DZ));
395*9566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->DZ,-1.0));
396*9566063dSJacob Faibussowitsch       PetscCall(VecShift(qp->DZ,sigmamu));
397*9566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(qp->DZ,qp->DZ,qp->G));
39874962610SAlp Dener 
399*9566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(qp->DS,qp->DS,qp->DT));
400*9566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->DS,-1.0));
401*9566063dSJacob Faibussowitsch       PetscCall(VecShift(qp->DS,sigmamu));
402*9566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(qp->DS,qp->DS,qp->T));
40374962610SAlp Dener 
404*9566063dSJacob Faibussowitsch       PetscCall(VecCopy(qp->DZ,qp->RHS2));
405*9566063dSJacob Faibussowitsch       PetscCall(VecAXPY(qp->RHS2,-1.0,qp->DS));
406*9566063dSJacob Faibussowitsch       PetscCall(VecAXPY(qp->RHS2,1.0,qp->RHS));
40774962610SAlp Dener 
40874962610SAlp Dener       /* Approximately solve the linear system */
409*9566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian,qp->DiagAxpy,ADD_VALUES));
41074962610SAlp Dener       if (!getdiagop) {
411*9566063dSJacob Faibussowitsch         PetscCall(VecCopy(qp->DiagAxpy,qp->HDiag));
412*9566063dSJacob Faibussowitsch         PetscCall(VecScale(qp->HDiag,-1.0));
41374962610SAlp Dener       }
414*9566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY));
415*9566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY));
41674962610SAlp Dener 
41774962610SAlp Dener       /* Solve using the previous tolerances that were set */
418*9566063dSJacob Faibussowitsch       PetscCall(KSPSolve(tao->ksp,qp->RHS2,tao->stepdirection));
419*9566063dSJacob Faibussowitsch       PetscCall(KSPGetIterationNumber(tao->ksp,&its));
42074962610SAlp Dener       tao->ksp_its += its;
42174962610SAlp Dener       tao->ksp_tot_its += its;
42274962610SAlp Dener 
42374962610SAlp Dener       if (getdiagop) {
424*9566063dSJacob Faibussowitsch         PetscCall(MatDiagonalSet(tao->hessian,qp->HDiag,INSERT_VALUES));
42574962610SAlp Dener       } else {
426*9566063dSJacob Faibussowitsch         PetscCall(MatDiagonalSet(tao->hessian,qp->HDiag,ADD_VALUES));
42774962610SAlp Dener       }
428*9566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY));
429*9566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY));
430*9566063dSJacob Faibussowitsch       PetscCall(QPIPComputeStepDirection(qp,tao));
431*9566063dSJacob Faibussowitsch       PetscCall(QPIPStepLength(qp));
43274962610SAlp Dener     }  /* End Corrector step */
43374962610SAlp Dener 
43474962610SAlp Dener     /* Take the step */
43574962610SAlp Dener     dstep = qp->dsteplength;
43674962610SAlp Dener 
437*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->Z,dstep,qp->DZ));
438*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->S,dstep,qp->DS));
439*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(tao->solution,dstep,tao->stepdirection));
440*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->G,dstep,qp->DG));
441*9566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->T,dstep,qp->DT));
44274962610SAlp Dener 
44374962610SAlp Dener     /* Compute Residuals */
444*9566063dSJacob Faibussowitsch     PetscCall(QPIPComputeResidual(qp,tao));
44574962610SAlp Dener 
44674962610SAlp Dener     /* Evaluate quadratic function */
447*9566063dSJacob Faibussowitsch     PetscCall(MatMult(tao->hessian,tao->solution,qp->Work));
44874962610SAlp Dener 
449*9566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->solution,qp->Work,&d1));
450*9566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->solution,qp->C,&d2));
451*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->G,qp->Z,gap));
452*9566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->T,qp->S,gap+1));
45374962610SAlp Dener 
45474962610SAlp Dener     /* Compute the duality gap */
45574962610SAlp Dener     qp->pobj = d1/2.0 + d2+qp->d;
45674962610SAlp Dener     qp->gap  = gap[0]+gap[1];
45774962610SAlp Dener     qp->dobj = qp->pobj - qp->gap;
45874962610SAlp Dener     if (qp->m > 0) {
45974962610SAlp Dener       qp->mu = qp->gap/(qp->m);
46074962610SAlp Dener     }
46174962610SAlp Dener     qp->rgap = qp->gap/(PetscAbsReal(qp->dobj) + PetscAbsReal(qp->pobj) + 1.0);
46274962610SAlp Dener   }  /* END MAIN LOOP  */
46374962610SAlp Dener   PetscFunctionReturn(0);
46474962610SAlp Dener }
46574962610SAlp Dener 
46674962610SAlp Dener static PetscErrorCode TaoView_BQPIP(Tao tao,PetscViewer viewer)
46774962610SAlp Dener {
46874962610SAlp Dener   PetscFunctionBegin;
46974962610SAlp Dener   PetscFunctionReturn(0);
47074962610SAlp Dener }
47174962610SAlp Dener 
47274962610SAlp Dener static PetscErrorCode TaoSetFromOptions_BQPIP(PetscOptionItems *PetscOptionsObject,Tao tao)
47374962610SAlp Dener {
47474962610SAlp Dener   TAO_BQPIP      *qp = (TAO_BQPIP*)tao->data;
47574962610SAlp Dener 
47674962610SAlp Dener   PetscFunctionBegin;
477*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsHead(PetscOptionsObject,"Interior point method for bound constrained quadratic optimization"));
478*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-tao_bqpip_predcorr","Use a predictor-corrector method","",qp->predcorr,&qp->predcorr,NULL));
479*9566063dSJacob Faibussowitsch   PetscCall(PetscOptionsTail());
480*9566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(tao->ksp));
48174962610SAlp Dener   PetscFunctionReturn(0);
48274962610SAlp Dener }
48374962610SAlp Dener 
48474962610SAlp Dener static PetscErrorCode TaoDestroy_BQPIP(Tao tao)
48574962610SAlp Dener {
48674962610SAlp Dener   TAO_BQPIP      *qp = (TAO_BQPIP*)tao->data;
48774962610SAlp Dener 
48874962610SAlp Dener   PetscFunctionBegin;
48974962610SAlp Dener   if (tao->setupcalled) {
490*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->G));
491*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DG));
492*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->Z));
493*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DZ));
494*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->GZwork));
495*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->R3));
496*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->S));
497*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DS));
498*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->T));
49974962610SAlp Dener 
500*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DT));
501*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->TSwork));
502*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->R5));
503*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->HDiag));
504*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->Work));
505*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->XL));
506*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->XU));
507*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DiagAxpy));
508*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->RHS));
509*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->RHS2));
510*9566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->C));
51174962610SAlp Dener   }
512*9566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
51374962610SAlp Dener   PetscFunctionReturn(0);
51474962610SAlp Dener }
51574962610SAlp Dener 
51674962610SAlp Dener static PetscErrorCode TaoComputeDual_BQPIP(Tao tao,Vec DXL,Vec DXU)
51774962610SAlp Dener {
51874962610SAlp Dener   TAO_BQPIP       *qp = (TAO_BQPIP*)tao->data;
51974962610SAlp Dener 
52074962610SAlp Dener   PetscFunctionBegin;
521*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->Z,DXL));
522*9566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->S,DXU));
523*9566063dSJacob Faibussowitsch   PetscCall(VecScale(DXU,-1.0));
52474962610SAlp Dener   PetscFunctionReturn(0);
52574962610SAlp Dener }
52674962610SAlp Dener 
52774962610SAlp Dener /*MC
52874962610SAlp Dener  TAOBQPIP - interior-point method for quadratic programs with
52974962610SAlp Dener     box constraints.
53074962610SAlp Dener 
53174962610SAlp Dener  Notes:
53274962610SAlp Dener     This algorithms solves quadratic problems only, the Hessian will
53374962610SAlp Dener         only be computed once.
53474962610SAlp Dener 
53574962610SAlp Dener  Options Database Keys:
53674962610SAlp Dener . -tao_bqpip_predcorr - use a predictor/corrector method
53774962610SAlp Dener 
53874962610SAlp Dener   Level: beginner
53974962610SAlp Dener M*/
54074962610SAlp Dener 
54174962610SAlp Dener PETSC_EXTERN PetscErrorCode TaoCreate_BQPIP(Tao tao)
54274962610SAlp Dener {
54374962610SAlp Dener   TAO_BQPIP      *qp;
54474962610SAlp Dener 
54574962610SAlp Dener   PetscFunctionBegin;
546*9566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(tao,&qp));
54774962610SAlp Dener 
54874962610SAlp Dener   tao->ops->setup = TaoSetup_BQPIP;
54974962610SAlp Dener   tao->ops->solve = TaoSolve_BQPIP;
55074962610SAlp Dener   tao->ops->view = TaoView_BQPIP;
55174962610SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BQPIP;
55274962610SAlp Dener   tao->ops->destroy = TaoDestroy_BQPIP;
55374962610SAlp Dener   tao->ops->computedual = TaoComputeDual_BQPIP;
55474962610SAlp Dener 
55574962610SAlp Dener   /* Override default settings (unless already changed) */
55674962610SAlp Dener   if (!tao->max_it_changed) tao->max_it=100;
55774962610SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 500;
55874962610SAlp Dener #if defined(PETSC_USE_REAL_SINGLE)
55974962610SAlp Dener   if (!tao->catol_changed) tao->catol=1e-6;
56074962610SAlp Dener #else
56174962610SAlp Dener   if (!tao->catol_changed) tao->catol=1e-12;
56274962610SAlp Dener #endif
56374962610SAlp Dener 
56474962610SAlp Dener   /* Initialize pointers and variables */
56574962610SAlp Dener   qp->n = 0;
56674962610SAlp Dener   qp->m = 0;
56774962610SAlp Dener 
56874962610SAlp Dener   qp->predcorr = 1;
56974962610SAlp Dener   tao->data    = (void*)qp;
57074962610SAlp Dener 
571*9566063dSJacob Faibussowitsch   PetscCall(KSPCreate(((PetscObject)tao)->comm,&tao->ksp));
572*9566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
573*9566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix));
574*9566063dSJacob Faibussowitsch   PetscCall(KSPSetType(tao->ksp,KSPCG));
575*9566063dSJacob Faibussowitsch   PetscCall(KSPSetTolerances(tao->ksp,1e-14,1e-30,1e30,PetscMax(10,qp->n)));
57674962610SAlp Dener   PetscFunctionReturn(0);
57774962610SAlp Dener }
578