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