xref: /petsc/src/tao/quadratic/impls/bqpip/bqpip.c (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
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 
109371c9d4SSatish Balay static PetscErrorCode QPIPComputeResidual(TAO_BQPIP *qp, Tao tao) {
1174962610SAlp Dener   PetscReal dtmp = 1.0 - qp->psteplength;
1274962610SAlp Dener 
1374962610SAlp Dener   PetscFunctionBegin;
1474962610SAlp Dener   /* Compute R3 and R5 */
1574962610SAlp Dener 
169566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->R3, dtmp));
179566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->R5, dtmp));
1874962610SAlp Dener   qp->pinfeas = dtmp * qp->pinfeas;
1974962610SAlp Dener 
209566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->S, tao->gradient));
219566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient, -1.0, qp->Z));
2274962610SAlp Dener 
239566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian, tao->solution, qp->RHS));
249566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->RHS, -1.0));
259566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->RHS, -1.0, qp->C));
269566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient, -1.0, qp->RHS));
2774962610SAlp Dener 
289566063dSJacob Faibussowitsch   PetscCall(VecNorm(tao->gradient, NORM_1, &qp->dinfeas));
2974962610SAlp Dener   qp->rnorm = (qp->dinfeas + qp->pinfeas) / (qp->m + qp->n);
3074962610SAlp Dener   PetscFunctionReturn(0);
3174962610SAlp Dener }
3274962610SAlp Dener 
339371c9d4SSatish Balay static PetscErrorCode QPIPSetInitialPoint(TAO_BQPIP *qp, Tao tao) {
3474962610SAlp Dener   PetscReal two = 2.0, p01 = 1;
3574962610SAlp Dener   PetscReal gap1, gap2, fff, mu;
3674962610SAlp Dener 
3774962610SAlp Dener   PetscFunctionBegin;
3874962610SAlp Dener   /* Compute function, Gradient R=Hx+b, and Hessian */
399566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian, tao->solution, tao->gradient));
409566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->C, qp->Work));
419566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->Work, 0.5, tao->gradient));
429566063dSJacob Faibussowitsch   PetscCall(VecAXPY(tao->gradient, 1.0, qp->C));
439566063dSJacob Faibussowitsch   PetscCall(VecDot(tao->solution, qp->Work, &fff));
4474962610SAlp Dener   qp->pobj = fff + qp->d;
4574962610SAlp Dener 
463c859ba3SBarry Smith   PetscCheck(!PetscIsInfOrNanReal(qp->pobj), PETSC_COMM_SELF, PETSC_ERR_USER, "User provided data contains Inf or NaN");
4774962610SAlp Dener 
4874962610SAlp Dener   /* Initialize slack vectors */
4974962610SAlp Dener   /* T = XU - X; G = X - XL */
509566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->XU, qp->T));
519566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->T, -1.0, tao->solution));
529566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->solution, qp->G));
539566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->G, -1.0, qp->XL));
5474962610SAlp Dener 
559566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->GZwork, p01));
569566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->TSwork, p01));
5774962610SAlp Dener 
589566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->G, qp->G, qp->GZwork));
599566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->T, qp->T, qp->TSwork));
6074962610SAlp Dener 
6174962610SAlp Dener   /* Initialize Dual Variable Vectors */
629566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->G, qp->Z));
639566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(qp->Z));
6474962610SAlp Dener 
659566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->T, qp->S));
669566063dSJacob Faibussowitsch   PetscCall(VecReciprocal(qp->S));
6774962610SAlp Dener 
689566063dSJacob Faibussowitsch   PetscCall(MatMult(tao->hessian, qp->Work, qp->RHS));
699566063dSJacob Faibussowitsch   PetscCall(VecAbs(qp->RHS));
709566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->Work, p01));
719566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->RHS, qp->RHS, qp->Work));
7274962610SAlp Dener 
739566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->RHS, tao->gradient, qp->RHS));
749566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->RHS, NORM_1, &gap1));
7574962610SAlp Dener   mu = PetscMin(10.0, (gap1 + 10.0) / qp->m);
7674962610SAlp Dener 
779566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->S, mu));
789566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->Z, mu));
7974962610SAlp Dener 
809566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->TSwork, p01));
819566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->GZwork, p01));
829566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->S, qp->S, qp->TSwork));
839566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMax(qp->Z, qp->Z, qp->GZwork));
8474962610SAlp Dener 
859371c9d4SSatish Balay   qp->mu      = 0;
869371c9d4SSatish Balay   qp->dinfeas = 1.0;
879371c9d4SSatish Balay   qp->pinfeas = 1.0;
8874962610SAlp Dener   while ((qp->dinfeas + qp->pinfeas) / (qp->m + qp->n) >= qp->mu) {
899566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->G, two));
909566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->Z, two));
919566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->S, two));
929566063dSJacob Faibussowitsch     PetscCall(VecScale(qp->T, two));
9374962610SAlp Dener 
949566063dSJacob Faibussowitsch     PetscCall(QPIPComputeResidual(qp, tao));
9574962610SAlp Dener 
969566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution, qp->R3));
979566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R3, -1.0, qp->G));
989566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R3, -1.0, qp->XL));
9974962610SAlp Dener 
1009566063dSJacob Faibussowitsch     PetscCall(VecCopy(tao->solution, qp->R5));
1019566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R5, 1.0, qp->T));
1029566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->R5, -1.0, qp->XU));
10374962610SAlp Dener 
1049566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->R3, NORM_INFINITY, &gap1));
1059566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->R5, NORM_INFINITY, &gap2));
10674962610SAlp Dener     qp->pinfeas = PetscMax(gap1, gap2);
10774962610SAlp Dener 
10874962610SAlp Dener     /* Compute the duality gap */
1099566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->G, qp->Z, &gap1));
1109566063dSJacob 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 
1249371c9d4SSatish Balay static PetscErrorCode QPIPStepLength(TAO_BQPIP *qp) {
12574962610SAlp Dener   PetscReal tstep1, tstep2, tstep3, tstep4, tstep;
12674962610SAlp Dener 
12774962610SAlp Dener   PetscFunctionBegin;
12874962610SAlp Dener   /* Compute stepsize to the boundary */
1299566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->G, qp->DG, &tstep1));
1309566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->T, qp->DT, &tstep2));
1319566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->S, qp->DS, &tstep3));
1329566063dSJacob Faibussowitsch   PetscCall(VecStepMax(qp->Z, qp->DZ, &tstep4));
13374962610SAlp Dener 
13474962610SAlp Dener   tstep           = PetscMin(tstep1, tstep2);
13574962610SAlp Dener   qp->psteplength = PetscMin(0.95 * tstep, 1.0);
13674962610SAlp Dener 
13774962610SAlp Dener   tstep           = PetscMin(tstep3, tstep4);
13874962610SAlp Dener   qp->dsteplength = PetscMin(0.95 * tstep, 1.0);
13974962610SAlp Dener 
14074962610SAlp Dener   qp->psteplength = PetscMin(qp->psteplength, qp->dsteplength);
14174962610SAlp Dener   qp->dsteplength = qp->psteplength;
14274962610SAlp Dener   PetscFunctionReturn(0);
14374962610SAlp Dener }
14474962610SAlp Dener 
1459371c9d4SSatish Balay static PetscErrorCode QPIPComputeNormFromCentralPath(TAO_BQPIP *qp, PetscReal *norm) {
14674962610SAlp Dener   PetscReal gap[2], mu[2], nmu;
14774962610SAlp Dener 
14874962610SAlp Dener   PetscFunctionBegin;
1499566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->GZwork, qp->G, qp->Z));
1509566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->TSwork, qp->T, qp->S));
1519566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->TSwork, NORM_1, &mu[0]));
1529566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->GZwork, NORM_1, &mu[1]));
15374962610SAlp Dener 
15474962610SAlp Dener   nmu = -(mu[0] + mu[1]) / qp->m;
15574962610SAlp Dener 
1569566063dSJacob Faibussowitsch   PetscCall(VecShift(qp->GZwork, nmu));
1579566063dSJacob Faibussowitsch   PetscCall(VecShift(qp->TSwork, nmu));
15874962610SAlp Dener 
1599566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->GZwork, NORM_2, &gap[0]));
1609566063dSJacob Faibussowitsch   PetscCall(VecNorm(qp->TSwork, NORM_2, &gap[1]));
16174962610SAlp Dener   gap[0] *= gap[0];
16274962610SAlp Dener   gap[1] *= gap[1];
16374962610SAlp Dener 
16474962610SAlp Dener   qp->pathnorm = PetscSqrtScalar(gap[0] + gap[1]);
16574962610SAlp Dener   *norm        = qp->pathnorm;
16674962610SAlp Dener   PetscFunctionReturn(0);
16774962610SAlp Dener }
16874962610SAlp Dener 
1699371c9d4SSatish Balay static PetscErrorCode QPIPComputeStepDirection(TAO_BQPIP *qp, Tao tao) {
17074962610SAlp Dener   PetscFunctionBegin;
17174962610SAlp Dener   /* Calculate DG */
1729566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->stepdirection, qp->DG));
1739566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DG, 1.0, qp->R3));
17474962610SAlp Dener 
17574962610SAlp Dener   /* Calculate DT */
1769566063dSJacob Faibussowitsch   PetscCall(VecCopy(tao->stepdirection, qp->DT));
1779566063dSJacob Faibussowitsch   PetscCall(VecScale(qp->DT, -1.0));
1789566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DT, -1.0, qp->R5));
17974962610SAlp Dener 
18074962610SAlp Dener   /* Calculate DZ */
1819566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DZ, -1.0, qp->Z));
1829566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->GZwork, qp->DG, qp->G));
1839566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->GZwork, qp->GZwork, qp->Z));
1849566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DZ, -1.0, qp->GZwork));
18574962610SAlp Dener 
18674962610SAlp Dener   /* Calculate DS */
1879566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DS, -1.0, qp->S));
1889566063dSJacob Faibussowitsch   PetscCall(VecPointwiseDivide(qp->TSwork, qp->DT, qp->T));
1899566063dSJacob Faibussowitsch   PetscCall(VecPointwiseMult(qp->TSwork, qp->TSwork, qp->S));
1909566063dSJacob Faibussowitsch   PetscCall(VecAXPY(qp->DS, -1.0, qp->TSwork));
19174962610SAlp Dener   PetscFunctionReturn(0);
19274962610SAlp Dener }
19374962610SAlp Dener 
1949371c9d4SSatish Balay static PetscErrorCode TaoSetup_BQPIP(Tao tao) {
19574962610SAlp Dener   TAO_BQPIP *qp = (TAO_BQPIP *)tao->data;
19674962610SAlp Dener 
19774962610SAlp Dener   PetscFunctionBegin;
19874962610SAlp Dener   /* Set pointers to Data */
1999566063dSJacob Faibussowitsch   PetscCall(VecGetSize(tao->solution, &qp->n));
20074962610SAlp Dener 
20174962610SAlp Dener   /* Allocate some arrays */
20248a46eb9SPierre Jolivet   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
20348a46eb9SPierre Jolivet   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
20474962610SAlp Dener 
2059566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->Work));
2069566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->XU));
2079566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->XL));
2089566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->HDiag));
2099566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->DiagAxpy));
2109566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->RHS));
2119566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->RHS2));
2129566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->C));
21374962610SAlp Dener 
2149566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->G));
2159566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->DG));
2169566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->S));
2179566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->Z));
2189566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->DZ));
2199566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->GZwork));
2209566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->R3));
22174962610SAlp Dener 
2229566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->T));
2239566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->DT));
2249566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->DS));
2259566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->TSwork));
2269566063dSJacob Faibussowitsch   PetscCall(VecDuplicate(tao->solution, &qp->R5));
22774962610SAlp Dener   qp->m = 2 * qp->n;
22874962610SAlp Dener   PetscFunctionReturn(0);
22974962610SAlp Dener }
23074962610SAlp Dener 
2319371c9d4SSatish Balay static PetscErrorCode TaoSolve_BQPIP(Tao tao) {
23274962610SAlp Dener   TAO_BQPIP *qp = (TAO_BQPIP *)tao->data;
23374962610SAlp Dener   PetscInt   its;
23474962610SAlp Dener   PetscReal  d1, d2, ksptol, sigmamu;
23574962610SAlp Dener   PetscReal  gnorm, dstep, pstep, step = 0;
23674962610SAlp Dener   PetscReal  gap[4];
23774962610SAlp Dener   PetscBool  getdiagop;
23874962610SAlp Dener 
23974962610SAlp Dener   PetscFunctionBegin;
24074962610SAlp Dener   qp->dobj        = 0.0;
24174962610SAlp Dener   qp->pobj        = 1.0;
24274962610SAlp Dener   qp->gap         = 10.0;
24374962610SAlp Dener   qp->rgap        = 1.0;
24474962610SAlp Dener   qp->mu          = 1.0;
24574962610SAlp Dener   qp->dinfeas     = 1.0;
24674962610SAlp Dener   qp->psteplength = 0.0;
24774962610SAlp Dener   qp->dsteplength = 0.0;
24874962610SAlp Dener 
24974962610SAlp Dener   /* TODO
25074962610SAlp Dener      - Remove fixed variables and treat them correctly
25174962610SAlp Dener      - Use index sets for the infinite versus finite bounds
25274962610SAlp Dener      - Update remaining code for fixed and free variables
25374962610SAlp Dener      - Fix inexact solves for predictor and corrector
25474962610SAlp Dener   */
25574962610SAlp Dener 
25674962610SAlp Dener   /* Tighten infinite bounds, things break when we don't do this
25774962610SAlp Dener     -- see test_bqpip.c
25874962610SAlp Dener   */
2599566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
2609566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->XU, 1.0e20));
2619566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->XL, -1.0e20));
26276be6f4fSStefano Zampini   if (tao->XL) PetscCall(VecPointwiseMax(qp->XL, qp->XL, tao->XL));
26376be6f4fSStefano Zampini   if (tao->XU) PetscCall(VecPointwiseMin(qp->XU, qp->XU, tao->XU));
2649566063dSJacob Faibussowitsch   PetscCall(VecMedian(qp->XL, tao->solution, qp->XU, tao->solution));
26574962610SAlp Dener 
26674962610SAlp Dener   /* Evaluate gradient and Hessian at zero to get the correct values
26774962610SAlp Dener      without contaminating them with numerical artifacts.
26874962610SAlp Dener   */
2699566063dSJacob Faibussowitsch   PetscCall(VecSet(qp->Work, 0));
2709566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, qp->Work, &qp->d, qp->C));
2719566063dSJacob Faibussowitsch   PetscCall(TaoComputeHessian(tao, qp->Work, tao->hessian, tao->hessian_pre));
2729566063dSJacob Faibussowitsch   PetscCall(MatHasOperation(tao->hessian, MATOP_GET_DIAGONAL, &getdiagop));
2731baa6e33SBarry Smith   if (getdiagop) PetscCall(MatGetDiagonal(tao->hessian, qp->HDiag));
27474962610SAlp Dener 
27574962610SAlp Dener   /* Initialize starting point and residuals */
2769566063dSJacob Faibussowitsch   PetscCall(QPIPSetInitialPoint(qp, tao));
2779566063dSJacob Faibussowitsch   PetscCall(QPIPComputeResidual(qp, tao));
27874962610SAlp Dener 
27974962610SAlp Dener   /* Enter main loop */
28074962610SAlp Dener   tao->reason = TAO_CONTINUE_ITERATING;
28174962610SAlp Dener   while (1) {
28274962610SAlp Dener     /* Check Stopping Condition      */
28374962610SAlp Dener     gnorm = PetscSqrtScalar(qp->gap + qp->dinfeas);
2849566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao, qp->pobj, gnorm, qp->pinfeas, tao->ksp_its));
2859566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao, tao->niter, qp->pobj, gnorm, qp->pinfeas, step));
286dbbe0bcdSBarry Smith     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
28774962610SAlp Dener     if (tao->reason != TAO_CONTINUE_ITERATING) break;
288e1e80dc8SAlp Dener     /* Call general purpose update function */
289dbbe0bcdSBarry Smith     PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);
29074962610SAlp Dener     tao->niter++;
29174962610SAlp Dener     tao->ksp_its = 0;
29274962610SAlp Dener 
29374962610SAlp Dener     /*
29474962610SAlp Dener        Dual Infeasibility Direction should already be in the right
29574962610SAlp Dener        hand side from computing the residuals
29674962610SAlp Dener     */
29774962610SAlp Dener 
2989566063dSJacob Faibussowitsch     PetscCall(QPIPComputeNormFromCentralPath(qp, &d1));
29974962610SAlp Dener 
3009566063dSJacob Faibussowitsch     PetscCall(VecSet(qp->DZ, 0.0));
3019566063dSJacob Faibussowitsch     PetscCall(VecSet(qp->DS, 0.0));
30274962610SAlp Dener 
30374962610SAlp Dener     /*
30474962610SAlp Dener        Compute the Primal Infeasiblitiy RHS and the
30574962610SAlp Dener        Diagonal Matrix to be added to H and store in Work
30674962610SAlp Dener     */
3079566063dSJacob Faibussowitsch     PetscCall(VecPointwiseDivide(qp->DiagAxpy, qp->Z, qp->G));
3089566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(qp->GZwork, qp->DiagAxpy, qp->R3));
3099566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS, -1.0, qp->GZwork));
31074962610SAlp Dener 
3119566063dSJacob Faibussowitsch     PetscCall(VecPointwiseDivide(qp->TSwork, qp->S, qp->T));
3129566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->DiagAxpy, 1.0, qp->TSwork));
3139566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMult(qp->TSwork, qp->TSwork, qp->R5));
3149566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS, -1.0, qp->TSwork));
31574962610SAlp Dener 
31674962610SAlp Dener     /*  Determine the solving tolerance */
31774962610SAlp Dener     ksptol = qp->mu / 10.0;
31874962610SAlp Dener     ksptol = PetscMin(ksptol, 0.001);
3199566063dSJacob Faibussowitsch     PetscCall(KSPSetTolerances(tao->ksp, ksptol, 1e-30, 1e30, PetscMax(10, qp->n)));
32074962610SAlp Dener 
32174962610SAlp Dener     /* Shift the diagonals of the Hessian matrix */
3229566063dSJacob Faibussowitsch     PetscCall(MatDiagonalSet(tao->hessian, qp->DiagAxpy, ADD_VALUES));
32374962610SAlp Dener     if (!getdiagop) {
3249566063dSJacob Faibussowitsch       PetscCall(VecCopy(qp->DiagAxpy, qp->HDiag));
3259566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->HDiag, -1.0));
32674962610SAlp Dener     }
3279566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(tao->hessian, MAT_FINAL_ASSEMBLY));
3289566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(tao->hessian, MAT_FINAL_ASSEMBLY));
32974962610SAlp Dener 
3309566063dSJacob Faibussowitsch     PetscCall(KSPSetOperators(tao->ksp, tao->hessian, tao->hessian_pre));
3319566063dSJacob Faibussowitsch     PetscCall(KSPSolve(tao->ksp, qp->RHS, tao->stepdirection));
3329566063dSJacob Faibussowitsch     PetscCall(KSPGetIterationNumber(tao->ksp, &its));
33374962610SAlp Dener     tao->ksp_its += its;
33474962610SAlp Dener     tao->ksp_tot_its += its;
33574962610SAlp Dener 
33674962610SAlp Dener     /* Restore the true diagonal of the Hessian matrix */
33774962610SAlp Dener     if (getdiagop) {
3389566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian, qp->HDiag, INSERT_VALUES));
33974962610SAlp Dener     } else {
3409566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian, qp->HDiag, ADD_VALUES));
34174962610SAlp Dener     }
3429566063dSJacob Faibussowitsch     PetscCall(MatAssemblyBegin(tao->hessian, MAT_FINAL_ASSEMBLY));
3439566063dSJacob Faibussowitsch     PetscCall(MatAssemblyEnd(tao->hessian, MAT_FINAL_ASSEMBLY));
3449566063dSJacob Faibussowitsch     PetscCall(QPIPComputeStepDirection(qp, tao));
3459566063dSJacob Faibussowitsch     PetscCall(QPIPStepLength(qp));
34674962610SAlp Dener 
34774962610SAlp Dener     /* Calculate New Residual R1 in Work vector */
3489566063dSJacob Faibussowitsch     PetscCall(MatMult(tao->hessian, tao->stepdirection, qp->RHS2));
3499566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS2, 1.0, qp->DS));
3509566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->RHS2, -1.0, qp->DZ));
3519566063dSJacob Faibussowitsch     PetscCall(VecAYPX(qp->RHS2, qp->dsteplength, tao->gradient));
35274962610SAlp Dener 
3539566063dSJacob Faibussowitsch     PetscCall(VecNorm(qp->RHS2, NORM_2, &qp->dinfeas));
3549566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->DZ, qp->DG, gap));
3559566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->DS, qp->DT, gap + 1));
35674962610SAlp Dener 
35774962610SAlp Dener     qp->rnorm = (qp->dinfeas + qp->psteplength * qp->pinfeas) / (qp->m + qp->n);
35874962610SAlp Dener     pstep     = qp->psteplength;
35974962610SAlp Dener     step      = PetscMin(qp->psteplength, qp->dsteplength);
36074962610SAlp Dener     sigmamu   = (pstep * pstep * (gap[0] + gap[1]) + (1 - pstep) * qp->gap) / qp->m;
36174962610SAlp Dener 
36274962610SAlp Dener     if (qp->predcorr && step < 0.9) {
36374962610SAlp Dener       if (sigmamu < qp->mu) {
36474962610SAlp Dener         sigmamu = sigmamu / qp->mu;
36574962610SAlp Dener         sigmamu = sigmamu * sigmamu * sigmamu;
36674962610SAlp Dener       } else {
36774962610SAlp Dener         sigmamu = 1.0;
36874962610SAlp Dener       }
36974962610SAlp Dener       sigmamu = sigmamu * qp->mu;
37074962610SAlp Dener 
37174962610SAlp Dener       /* Compute Corrector Step */
3729566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(qp->DZ, qp->DG, qp->DZ));
3739566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->DZ, -1.0));
3749566063dSJacob Faibussowitsch       PetscCall(VecShift(qp->DZ, sigmamu));
3759566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(qp->DZ, qp->DZ, qp->G));
37674962610SAlp Dener 
3779566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMult(qp->DS, qp->DS, qp->DT));
3789566063dSJacob Faibussowitsch       PetscCall(VecScale(qp->DS, -1.0));
3799566063dSJacob Faibussowitsch       PetscCall(VecShift(qp->DS, sigmamu));
3809566063dSJacob Faibussowitsch       PetscCall(VecPointwiseDivide(qp->DS, qp->DS, qp->T));
38174962610SAlp Dener 
3829566063dSJacob Faibussowitsch       PetscCall(VecCopy(qp->DZ, qp->RHS2));
3839566063dSJacob Faibussowitsch       PetscCall(VecAXPY(qp->RHS2, -1.0, qp->DS));
3849566063dSJacob Faibussowitsch       PetscCall(VecAXPY(qp->RHS2, 1.0, qp->RHS));
38574962610SAlp Dener 
38674962610SAlp Dener       /* Approximately solve the linear system */
3879566063dSJacob Faibussowitsch       PetscCall(MatDiagonalSet(tao->hessian, qp->DiagAxpy, ADD_VALUES));
38874962610SAlp Dener       if (!getdiagop) {
3899566063dSJacob Faibussowitsch         PetscCall(VecCopy(qp->DiagAxpy, qp->HDiag));
3909566063dSJacob Faibussowitsch         PetscCall(VecScale(qp->HDiag, -1.0));
39174962610SAlp Dener       }
3929566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tao->hessian, MAT_FINAL_ASSEMBLY));
3939566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tao->hessian, MAT_FINAL_ASSEMBLY));
39474962610SAlp Dener 
39574962610SAlp Dener       /* Solve using the previous tolerances that were set */
3969566063dSJacob Faibussowitsch       PetscCall(KSPSolve(tao->ksp, qp->RHS2, tao->stepdirection));
3979566063dSJacob Faibussowitsch       PetscCall(KSPGetIterationNumber(tao->ksp, &its));
39874962610SAlp Dener       tao->ksp_its += its;
39974962610SAlp Dener       tao->ksp_tot_its += its;
40074962610SAlp Dener 
40174962610SAlp Dener       if (getdiagop) {
4029566063dSJacob Faibussowitsch         PetscCall(MatDiagonalSet(tao->hessian, qp->HDiag, INSERT_VALUES));
40374962610SAlp Dener       } else {
4049566063dSJacob Faibussowitsch         PetscCall(MatDiagonalSet(tao->hessian, qp->HDiag, ADD_VALUES));
40574962610SAlp Dener       }
4069566063dSJacob Faibussowitsch       PetscCall(MatAssemblyBegin(tao->hessian, MAT_FINAL_ASSEMBLY));
4079566063dSJacob Faibussowitsch       PetscCall(MatAssemblyEnd(tao->hessian, MAT_FINAL_ASSEMBLY));
4089566063dSJacob Faibussowitsch       PetscCall(QPIPComputeStepDirection(qp, tao));
4099566063dSJacob Faibussowitsch       PetscCall(QPIPStepLength(qp));
41074962610SAlp Dener     } /* End Corrector step */
41174962610SAlp Dener 
41274962610SAlp Dener     /* Take the step */
41374962610SAlp Dener     dstep = qp->dsteplength;
41474962610SAlp Dener 
4159566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->Z, dstep, qp->DZ));
4169566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->S, dstep, qp->DS));
4179566063dSJacob Faibussowitsch     PetscCall(VecAXPY(tao->solution, dstep, tao->stepdirection));
4189566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->G, dstep, qp->DG));
4199566063dSJacob Faibussowitsch     PetscCall(VecAXPY(qp->T, dstep, qp->DT));
42074962610SAlp Dener 
42174962610SAlp Dener     /* Compute Residuals */
4229566063dSJacob Faibussowitsch     PetscCall(QPIPComputeResidual(qp, tao));
42374962610SAlp Dener 
42474962610SAlp Dener     /* Evaluate quadratic function */
4259566063dSJacob Faibussowitsch     PetscCall(MatMult(tao->hessian, tao->solution, qp->Work));
42674962610SAlp Dener 
4279566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->solution, qp->Work, &d1));
4289566063dSJacob Faibussowitsch     PetscCall(VecDot(tao->solution, qp->C, &d2));
4299566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->G, qp->Z, gap));
4309566063dSJacob Faibussowitsch     PetscCall(VecDot(qp->T, qp->S, gap + 1));
43174962610SAlp Dener 
43274962610SAlp Dener     /* Compute the duality gap */
43374962610SAlp Dener     qp->pobj = d1 / 2.0 + d2 + qp->d;
43474962610SAlp Dener     qp->gap  = gap[0] + gap[1];
43574962610SAlp Dener     qp->dobj = qp->pobj - qp->gap;
436ad540459SPierre Jolivet     if (qp->m > 0) qp->mu = qp->gap / (qp->m);
43774962610SAlp Dener     qp->rgap = qp->gap / (PetscAbsReal(qp->dobj) + PetscAbsReal(qp->pobj) + 1.0);
43874962610SAlp Dener   } /* END MAIN LOOP  */
43974962610SAlp Dener   PetscFunctionReturn(0);
44074962610SAlp Dener }
44174962610SAlp Dener 
4429371c9d4SSatish Balay static PetscErrorCode TaoView_BQPIP(Tao tao, PetscViewer viewer) {
44374962610SAlp Dener   PetscFunctionBegin;
44474962610SAlp Dener   PetscFunctionReturn(0);
44574962610SAlp Dener }
44674962610SAlp Dener 
4479371c9d4SSatish Balay static PetscErrorCode TaoSetFromOptions_BQPIP(Tao tao, PetscOptionItems *PetscOptionsObject) {
44874962610SAlp Dener   TAO_BQPIP *qp = (TAO_BQPIP *)tao->data;
44974962610SAlp Dener 
45074962610SAlp Dener   PetscFunctionBegin;
451d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "Interior point method for bound constrained quadratic optimization");
4529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsInt("-tao_bqpip_predcorr", "Use a predictor-corrector method", "", qp->predcorr, &qp->predcorr, NULL));
453d0609cedSBarry Smith   PetscOptionsHeadEnd();
4549566063dSJacob Faibussowitsch   PetscCall(KSPSetFromOptions(tao->ksp));
45574962610SAlp Dener   PetscFunctionReturn(0);
45674962610SAlp Dener }
45774962610SAlp Dener 
4589371c9d4SSatish Balay static PetscErrorCode TaoDestroy_BQPIP(Tao tao) {
45974962610SAlp Dener   TAO_BQPIP *qp = (TAO_BQPIP *)tao->data;
46074962610SAlp Dener 
46174962610SAlp Dener   PetscFunctionBegin;
46274962610SAlp Dener   if (tao->setupcalled) {
4639566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->G));
4649566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DG));
4659566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->Z));
4669566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DZ));
4679566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->GZwork));
4689566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->R3));
4699566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->S));
4709566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DS));
4719566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->T));
47274962610SAlp Dener 
4739566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DT));
4749566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->TSwork));
4759566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->R5));
4769566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->HDiag));
4779566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->Work));
4789566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->XL));
4799566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->XU));
4809566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->DiagAxpy));
4819566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->RHS));
4829566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->RHS2));
4839566063dSJacob Faibussowitsch     PetscCall(VecDestroy(&qp->C));
48474962610SAlp Dener   }
485a958fbfcSStefano Zampini   PetscCall(KSPDestroy(&tao->ksp));
4869566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
48774962610SAlp Dener   PetscFunctionReturn(0);
48874962610SAlp Dener }
48974962610SAlp Dener 
4909371c9d4SSatish Balay static PetscErrorCode TaoComputeDual_BQPIP(Tao tao, Vec DXL, Vec DXU) {
49174962610SAlp Dener   TAO_BQPIP *qp = (TAO_BQPIP *)tao->data;
49274962610SAlp Dener 
49374962610SAlp Dener   PetscFunctionBegin;
4949566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->Z, DXL));
4959566063dSJacob Faibussowitsch   PetscCall(VecCopy(qp->S, DXU));
4969566063dSJacob Faibussowitsch   PetscCall(VecScale(DXU, -1.0));
49774962610SAlp Dener   PetscFunctionReturn(0);
49874962610SAlp Dener }
49974962610SAlp Dener 
50074962610SAlp Dener /*MC
50174962610SAlp Dener  TAOBQPIP - interior-point method for quadratic programs with
50274962610SAlp Dener     box constraints.
50374962610SAlp Dener 
50474962610SAlp Dener  Notes:
50574962610SAlp Dener     This algorithms solves quadratic problems only, the Hessian will
50674962610SAlp Dener         only be computed once.
50774962610SAlp Dener 
50874962610SAlp Dener  Options Database Keys:
50974962610SAlp Dener . -tao_bqpip_predcorr - use a predictor/corrector method
51074962610SAlp Dener 
51174962610SAlp Dener   Level: beginner
51274962610SAlp Dener M*/
51374962610SAlp Dener 
5149371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode TaoCreate_BQPIP(Tao tao) {
51574962610SAlp Dener   TAO_BQPIP *qp;
51674962610SAlp Dener 
51774962610SAlp Dener   PetscFunctionBegin;
518*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&qp));
51974962610SAlp Dener 
52074962610SAlp Dener   tao->ops->setup          = TaoSetup_BQPIP;
52174962610SAlp Dener   tao->ops->solve          = TaoSolve_BQPIP;
52274962610SAlp Dener   tao->ops->view           = TaoView_BQPIP;
52374962610SAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_BQPIP;
52474962610SAlp Dener   tao->ops->destroy        = TaoDestroy_BQPIP;
52574962610SAlp Dener   tao->ops->computedual    = TaoComputeDual_BQPIP;
52674962610SAlp Dener 
52774962610SAlp Dener   /* Override default settings (unless already changed) */
52874962610SAlp Dener   if (!tao->max_it_changed) tao->max_it = 100;
52974962610SAlp Dener   if (!tao->max_funcs_changed) tao->max_funcs = 500;
53074962610SAlp Dener #if defined(PETSC_USE_REAL_SINGLE)
53174962610SAlp Dener   if (!tao->catol_changed) tao->catol = 1e-6;
53274962610SAlp Dener #else
53374962610SAlp Dener   if (!tao->catol_changed) tao->catol = 1e-12;
53474962610SAlp Dener #endif
53574962610SAlp Dener 
53674962610SAlp Dener   /* Initialize pointers and variables */
53774962610SAlp Dener   qp->n = 0;
53874962610SAlp Dener   qp->m = 0;
53974962610SAlp Dener 
54074962610SAlp Dener   qp->predcorr = 1;
54174962610SAlp Dener   tao->data    = (void *)qp;
54274962610SAlp Dener 
5439566063dSJacob Faibussowitsch   PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
5449566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
5459566063dSJacob Faibussowitsch   PetscCall(KSPSetOptionsPrefix(tao->ksp, tao->hdr.prefix));
5469566063dSJacob Faibussowitsch   PetscCall(KSPSetType(tao->ksp, KSPCG));
5479566063dSJacob Faibussowitsch   PetscCall(KSPSetTolerances(tao->ksp, 1e-14, 1e-30, 1e30, PetscMax(10, qp->n)));
54874962610SAlp Dener   PetscFunctionReturn(0);
54974962610SAlp Dener }
550