Actual source code: ipm.c

  1: #include <petsctaolinesearch.h>
  2: #include <../src/tao/constrained/impls/ipm/ipm.h>

  4: /*
  5:    x,d in R^n
  6:    f in R
  7:    nb = mi + nlb+nub
  8:    s in R^nb is slack vector CI(x) / x-XL / -x+XU
  9:    bin in R^mi (tao->constraints_inequality)
 10:    beq in R^me (tao->constraints_equality)
 11:    lambdai in R^nb (ipmP->lambdai)
 12:    lambdae in R^me (ipmP->lambdae)
 13:    Jeq in R^(me x n) (tao->jacobian_equality)
 14:    Jin in R^(mi x n) (tao->jacobian_inequality)
 15:    Ai in  R^(nb x n) (ipmP->Ai)
 16:    H in R^(n x n) (tao->hessian)
 17:    min f=(1/2)*x'*H*x + d'*x
 18:    s.t.  CE(x) == 0
 19:          CI(x) >= 0
 20:          x >= tao->XL
 21:          -x >= -tao->XU
 22: */

 24: static PetscErrorCode IPMComputeKKT(Tao tao);
 25: static PetscErrorCode IPMPushInitialPoint(Tao tao);
 26: static PetscErrorCode IPMEvaluate(Tao tao);
 27: static PetscErrorCode IPMUpdateK(Tao tao);
 28: static PetscErrorCode IPMUpdateAi(Tao tao);
 29: static PetscErrorCode IPMGatherRHS(Tao tao, Vec, Vec, Vec, Vec, Vec);
 30: static PetscErrorCode IPMScatterStep(Tao tao, Vec, Vec, Vec, Vec, Vec);
 31: static PetscErrorCode IPMInitializeBounds(Tao tao);

 33: static PetscErrorCode TaoSolve_IPM(Tao tao)
 34: {
 35:   TAO_IPM    *ipmP = (TAO_IPM *)tao->data;
 36:   PetscInt    its, i;
 37:   PetscScalar stepsize = 1.0;
 38:   PetscScalar step_s, step_l, alpha, tau, sigma, phi_target;

 40:   PetscFunctionBegin;
 41:   /* Push initial point away from bounds */
 42:   PetscCall(IPMInitializeBounds(tao));
 43:   PetscCall(IPMPushInitialPoint(tao));
 44:   PetscCall(VecCopy(tao->solution, ipmP->rhs_x));
 45:   PetscCall(IPMEvaluate(tao));
 46:   PetscCall(IPMComputeKKT(tao));

 48:   tao->reason = TAO_CONTINUE_ITERATING;
 49:   PetscCall(TaoLogConvergenceHistory(tao, ipmP->kkt_f, ipmP->phi, 0.0, tao->ksp_its));
 50:   PetscCall(TaoMonitor(tao, tao->niter, ipmP->kkt_f, ipmP->phi, 0.0, 1.0));
 51:   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);

 53:   while (tao->reason == TAO_CONTINUE_ITERATING) {
 54:     /* Call general purpose update function */
 55:     PetscTryTypeMethod(tao, update, tao->niter, tao->user_update);

 57:     tao->ksp_its = 0;
 58:     PetscCall(IPMUpdateK(tao));
 59:     /*
 60:        rhs.x    = -rd
 61:        rhs.lame = -rpe
 62:        rhs.lami = -rpi
 63:        rhs.com  = -com
 64:     */

 66:     PetscCall(VecCopy(ipmP->rd, ipmP->rhs_x));
 67:     if (ipmP->me > 0) PetscCall(VecCopy(ipmP->rpe, ipmP->rhs_lambdae));
 68:     if (ipmP->nb > 0) {
 69:       PetscCall(VecCopy(ipmP->rpi, ipmP->rhs_lambdai));
 70:       PetscCall(VecCopy(ipmP->complementarity, ipmP->rhs_s));
 71:     }
 72:     PetscCall(IPMGatherRHS(tao, ipmP->bigrhs, ipmP->rhs_x, ipmP->rhs_lambdae, ipmP->rhs_lambdai, ipmP->rhs_s));
 73:     PetscCall(VecScale(ipmP->bigrhs, -1.0));

 75:     /* solve K * step = rhs */
 76:     PetscCall(KSPSetOperators(tao->ksp, ipmP->K, ipmP->K));
 77:     PetscCall(KSPSolve(tao->ksp, ipmP->bigrhs, ipmP->bigstep));

 79:     PetscCall(IPMScatterStep(tao, ipmP->bigstep, tao->stepdirection, ipmP->ds, ipmP->dlambdae, ipmP->dlambdai));
 80:     PetscCall(KSPGetIterationNumber(tao->ksp, &its));
 81:     tao->ksp_its += its;
 82:     tao->ksp_tot_its += its;
 83:     /* Find distance along step direction to closest bound */
 84:     if (ipmP->nb > 0) {
 85:       PetscCall(VecStepBoundInfo(ipmP->s, ipmP->ds, ipmP->Zero_nb, ipmP->Inf_nb, &step_s, NULL, NULL));
 86:       PetscCall(VecStepBoundInfo(ipmP->lambdai, ipmP->dlambdai, ipmP->Zero_nb, ipmP->Inf_nb, &step_l, NULL, NULL));
 87:       alpha        = PetscMin(step_s, step_l);
 88:       alpha        = PetscMin(alpha, 1.0);
 89:       ipmP->alpha1 = alpha;
 90:     } else {
 91:       ipmP->alpha1 = alpha = 1.0;
 92:     }

 94:     /* x_aff = x + alpha*d */
 95:     PetscCall(VecCopy(tao->solution, ipmP->save_x));
 96:     if (ipmP->me > 0) PetscCall(VecCopy(ipmP->lambdae, ipmP->save_lambdae));
 97:     if (ipmP->nb > 0) {
 98:       PetscCall(VecCopy(ipmP->lambdai, ipmP->save_lambdai));
 99:       PetscCall(VecCopy(ipmP->s, ipmP->save_s));
100:     }

102:     PetscCall(VecAXPY(tao->solution, alpha, tao->stepdirection));
103:     if (ipmP->me > 0) PetscCall(VecAXPY(ipmP->lambdae, alpha, ipmP->dlambdae));
104:     if (ipmP->nb > 0) {
105:       PetscCall(VecAXPY(ipmP->lambdai, alpha, ipmP->dlambdai));
106:       PetscCall(VecAXPY(ipmP->s, alpha, ipmP->ds));
107:     }

109:     /* Recompute kkt to find centering parameter sigma = (new_mu/old_mu)^3 */
110:     if (ipmP->mu == 0.0) {
111:       sigma = 0.0;
112:     } else {
113:       sigma = 1.0 / ipmP->mu;
114:     }
115:     PetscCall(IPMComputeKKT(tao));
116:     sigma *= ipmP->mu;
117:     sigma *= sigma * sigma;

119:     /* revert kkt info */
120:     PetscCall(VecCopy(ipmP->save_x, tao->solution));
121:     if (ipmP->me > 0) PetscCall(VecCopy(ipmP->save_lambdae, ipmP->lambdae));
122:     if (ipmP->nb > 0) {
123:       PetscCall(VecCopy(ipmP->save_lambdai, ipmP->lambdai));
124:       PetscCall(VecCopy(ipmP->save_s, ipmP->s));
125:     }
126:     PetscCall(IPMComputeKKT(tao));

128:     /* update rhs with new complementarity vector */
129:     if (ipmP->nb > 0) {
130:       PetscCall(VecCopy(ipmP->complementarity, ipmP->rhs_s));
131:       PetscCall(VecScale(ipmP->rhs_s, -1.0));
132:       PetscCall(VecShift(ipmP->rhs_s, sigma * ipmP->mu));
133:     }
134:     PetscCall(IPMGatherRHS(tao, ipmP->bigrhs, NULL, NULL, NULL, ipmP->rhs_s));

136:     /* solve K * step = rhs */
137:     PetscCall(KSPSetOperators(tao->ksp, ipmP->K, ipmP->K));
138:     PetscCall(KSPSolve(tao->ksp, ipmP->bigrhs, ipmP->bigstep));

140:     PetscCall(IPMScatterStep(tao, ipmP->bigstep, tao->stepdirection, ipmP->ds, ipmP->dlambdae, ipmP->dlambdai));
141:     PetscCall(KSPGetIterationNumber(tao->ksp, &its));
142:     tao->ksp_its += its;
143:     tao->ksp_tot_its += its;
144:     if (ipmP->nb > 0) {
145:       /* Get max step size and apply frac-to-boundary */
146:       tau = PetscMax(ipmP->taumin, 1.0 - ipmP->mu);
147:       tau = PetscMin(tau, 1.0);
148:       if (tau != 1.0) {
149:         PetscCall(VecScale(ipmP->s, tau));
150:         PetscCall(VecScale(ipmP->lambdai, tau));
151:       }
152:       PetscCall(VecStepBoundInfo(ipmP->s, ipmP->ds, ipmP->Zero_nb, ipmP->Inf_nb, &step_s, NULL, NULL));
153:       PetscCall(VecStepBoundInfo(ipmP->lambdai, ipmP->dlambdai, ipmP->Zero_nb, ipmP->Inf_nb, &step_l, NULL, NULL));
154:       if (tau != 1.0) {
155:         PetscCall(VecCopy(ipmP->save_s, ipmP->s));
156:         PetscCall(VecCopy(ipmP->save_lambdai, ipmP->lambdai));
157:       }
158:       alpha = PetscMin(step_s, step_l);
159:       alpha = PetscMin(alpha, 1.0);
160:     } else {
161:       alpha = 1.0;
162:     }
163:     ipmP->alpha2 = alpha;
164:     /* TODO make phi_target meaningful */
165:     phi_target = ipmP->dec * ipmP->phi;
166:     for (i = 0; i < 11; i++) {
167:       PetscCall(VecAXPY(tao->solution, alpha, tao->stepdirection));
168:       if (ipmP->nb > 0) {
169:         PetscCall(VecAXPY(ipmP->s, alpha, ipmP->ds));
170:         PetscCall(VecAXPY(ipmP->lambdai, alpha, ipmP->dlambdai));
171:       }
172:       if (ipmP->me > 0) PetscCall(VecAXPY(ipmP->lambdae, alpha, ipmP->dlambdae));

174:       /* update dual variables */
175:       if (ipmP->me > 0) PetscCall(VecCopy(ipmP->lambdae, tao->DE));

177:       PetscCall(IPMEvaluate(tao));
178:       PetscCall(IPMComputeKKT(tao));
179:       if (ipmP->phi <= phi_target) break;
180:       alpha /= 2.0;
181:     }

183:     PetscCall(TaoLogConvergenceHistory(tao, ipmP->kkt_f, ipmP->phi, 0.0, tao->ksp_its));
184:     PetscCall(TaoMonitor(tao, tao->niter, ipmP->kkt_f, ipmP->phi, 0.0, stepsize));
185:     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
186:     tao->niter++;
187:   }
188:   PetscFunctionReturn(PETSC_SUCCESS);
189: }

191: static PetscErrorCode TaoSetup_IPM(Tao tao)
192: {
193:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

195:   PetscFunctionBegin;
196:   ipmP->nb = ipmP->mi = ipmP->me = 0;
197:   ipmP->K                        = NULL;
198:   PetscCall(VecGetSize(tao->solution, &ipmP->n));
199:   if (!tao->gradient) PetscCall(VecDuplicate(tao->solution, &tao->gradient));
200:   if (!tao->stepdirection) PetscCall(VecDuplicate(tao->solution, &tao->stepdirection));
201:   if (!ipmP->rd) PetscCall(VecDuplicate(tao->solution, &ipmP->rd));
202:   if (!ipmP->rhs_x) PetscCall(VecDuplicate(tao->solution, &ipmP->rhs_x));
203:   if (!ipmP->work) PetscCall(VecDuplicate(tao->solution, &ipmP->work));
204:   if (!ipmP->save_x) PetscCall(VecDuplicate(tao->solution, &ipmP->save_x));
205:   if (tao->constraints_equality) {
206:     PetscCall(VecGetSize(tao->constraints_equality, &ipmP->me));
207:     PetscCall(VecDuplicate(tao->constraints_equality, &ipmP->lambdae));
208:     PetscCall(VecDuplicate(tao->constraints_equality, &ipmP->dlambdae));
209:     PetscCall(VecDuplicate(tao->constraints_equality, &ipmP->rhs_lambdae));
210:     PetscCall(VecDuplicate(tao->constraints_equality, &ipmP->save_lambdae));
211:     PetscCall(VecDuplicate(tao->constraints_equality, &ipmP->rpe));
212:     PetscCall(VecDuplicate(tao->constraints_equality, &tao->DE));
213:   }
214:   if (tao->constraints_inequality) PetscCall(VecDuplicate(tao->constraints_inequality, &tao->DI));
215:   PetscFunctionReturn(PETSC_SUCCESS);
216: }

218: static PetscErrorCode IPMInitializeBounds(Tao tao)
219: {
220:   TAO_IPM        *ipmP = (TAO_IPM *)tao->data;
221:   Vec             xtmp;
222:   PetscInt        xstart, xend;
223:   PetscInt        ucstart, ucend;   /* user ci */
224:   PetscInt        ucestart, uceend; /* user ce */
225:   PetscInt        sstart = 0, send = 0;
226:   PetscInt        bigsize;
227:   PetscInt        i, counter, nloc;
228:   PetscInt       *cind, *xind, *ucind, *uceind, *stepind;
229:   VecType         vtype;
230:   const PetscInt *xli, *xui;
231:   PetscInt        xl_offset, xu_offset;
232:   IS              bigxl, bigxu, isuc, isc, isx, sis, is1;
233:   MPI_Comm        comm;

235:   PetscFunctionBegin;
236:   cind = xind = ucind = uceind = stepind = NULL;
237:   ipmP->mi                               = 0;
238:   ipmP->nxlb                             = 0;
239:   ipmP->nxub                             = 0;
240:   ipmP->nb                               = 0;
241:   ipmP->nslack                           = 0;

243:   PetscCall(VecDuplicate(tao->solution, &xtmp));
244:   PetscCall(TaoComputeVariableBounds(tao));
245:   if (tao->XL) {
246:     PetscCall(VecSet(xtmp, PETSC_NINFINITY));
247:     PetscCall(VecWhichGreaterThan(tao->XL, xtmp, &ipmP->isxl));
248:     PetscCall(ISGetSize(ipmP->isxl, &ipmP->nxlb));
249:   } else {
250:     ipmP->nxlb = 0;
251:   }
252:   if (tao->XU) {
253:     PetscCall(VecSet(xtmp, PETSC_INFINITY));
254:     PetscCall(VecWhichLessThan(tao->XU, xtmp, &ipmP->isxu));
255:     PetscCall(ISGetSize(ipmP->isxu, &ipmP->nxub));
256:   } else {
257:     ipmP->nxub = 0;
258:   }
259:   PetscCall(VecDestroy(&xtmp));
260:   if (tao->constraints_inequality) {
261:     PetscCall(VecGetSize(tao->constraints_inequality, &ipmP->mi));
262:   } else {
263:     ipmP->mi = 0;
264:   }
265:   ipmP->nb = ipmP->nxlb + ipmP->nxub + ipmP->mi;

267:   PetscCall(PetscObjectGetComm((PetscObject)tao->solution, &comm));

269:   bigsize = ipmP->n + 2 * ipmP->nb + ipmP->me;
270:   PetscCall(PetscMalloc1(bigsize, &stepind));
271:   PetscCall(PetscMalloc1(ipmP->n, &xind));
272:   PetscCall(PetscMalloc1(ipmP->me, &uceind));
273:   PetscCall(VecGetOwnershipRange(tao->solution, &xstart, &xend));

275:   if (ipmP->nb > 0) {
276:     PetscCall(VecCreate(comm, &ipmP->s));
277:     PetscCall(VecSetSizes(ipmP->s, PETSC_DECIDE, ipmP->nb));
278:     PetscCall(VecSetFromOptions(ipmP->s));
279:     PetscCall(VecDuplicate(ipmP->s, &ipmP->ds));
280:     PetscCall(VecDuplicate(ipmP->s, &ipmP->rhs_s));
281:     PetscCall(VecDuplicate(ipmP->s, &ipmP->complementarity));
282:     PetscCall(VecDuplicate(ipmP->s, &ipmP->ci));

284:     PetscCall(VecDuplicate(ipmP->s, &ipmP->lambdai));
285:     PetscCall(VecDuplicate(ipmP->s, &ipmP->dlambdai));
286:     PetscCall(VecDuplicate(ipmP->s, &ipmP->rhs_lambdai));
287:     PetscCall(VecDuplicate(ipmP->s, &ipmP->save_lambdai));

289:     PetscCall(VecDuplicate(ipmP->s, &ipmP->save_s));
290:     PetscCall(VecDuplicate(ipmP->s, &ipmP->rpi));
291:     PetscCall(VecDuplicate(ipmP->s, &ipmP->Zero_nb));
292:     PetscCall(VecSet(ipmP->Zero_nb, 0.0));
293:     PetscCall(VecDuplicate(ipmP->s, &ipmP->One_nb));
294:     PetscCall(VecSet(ipmP->One_nb, 1.0));
295:     PetscCall(VecDuplicate(ipmP->s, &ipmP->Inf_nb));
296:     PetscCall(VecSet(ipmP->Inf_nb, PETSC_INFINITY));

298:     PetscCall(PetscMalloc1(ipmP->nb, &cind));
299:     PetscCall(PetscMalloc1(ipmP->mi, &ucind));
300:     PetscCall(VecGetOwnershipRange(ipmP->s, &sstart, &send));

302:     if (ipmP->mi > 0) {
303:       PetscCall(VecGetOwnershipRange(tao->constraints_inequality, &ucstart, &ucend));
304:       counter = 0;
305:       for (i = ucstart; i < ucend; i++) cind[counter++] = i;
306:       PetscCall(ISCreateGeneral(comm, counter, cind, PETSC_COPY_VALUES, &isuc));
307:       PetscCall(ISCreateGeneral(comm, counter, cind, PETSC_COPY_VALUES, &isc));
308:       PetscCall(VecScatterCreate(tao->constraints_inequality, isuc, ipmP->ci, isc, &ipmP->ci_scat));

310:       PetscCall(ISDestroy(&isuc));
311:       PetscCall(ISDestroy(&isc));
312:     }
313:     /* need to know how may xbound indices are on each process */
314:     /* TODO better way */
315:     if (ipmP->nxlb) {
316:       PetscCall(ISAllGather(ipmP->isxl, &bigxl));
317:       PetscCall(ISGetIndices(bigxl, &xli));
318:       /* find offsets for this processor */
319:       xl_offset = ipmP->mi;
320:       for (i = 0; i < ipmP->nxlb; i++) {
321:         if (xli[i] < xstart) {
322:           xl_offset++;
323:         } else break;
324:       }
325:       PetscCall(ISRestoreIndices(bigxl, &xli));

327:       PetscCall(ISGetIndices(ipmP->isxl, &xli));
328:       PetscCall(ISGetLocalSize(ipmP->isxl, &nloc));
329:       for (i = 0; i < nloc; i++) {
330:         xind[i] = xli[i];
331:         cind[i] = xl_offset + i;
332:       }

334:       PetscCall(ISCreateGeneral(comm, nloc, xind, PETSC_COPY_VALUES, &isx));
335:       PetscCall(ISCreateGeneral(comm, nloc, cind, PETSC_COPY_VALUES, &isc));
336:       PetscCall(VecScatterCreate(tao->XL, isx, ipmP->ci, isc, &ipmP->xl_scat));
337:       PetscCall(ISDestroy(&isx));
338:       PetscCall(ISDestroy(&isc));
339:       PetscCall(ISDestroy(&bigxl));
340:     }

342:     if (ipmP->nxub) {
343:       PetscCall(ISAllGather(ipmP->isxu, &bigxu));
344:       PetscCall(ISGetIndices(bigxu, &xui));
345:       /* find offsets for this processor */
346:       xu_offset = ipmP->mi + ipmP->nxlb;
347:       for (i = 0; i < ipmP->nxub; i++) {
348:         if (xui[i] < xstart) {
349:           xu_offset++;
350:         } else break;
351:       }
352:       PetscCall(ISRestoreIndices(bigxu, &xui));

354:       PetscCall(ISGetIndices(ipmP->isxu, &xui));
355:       PetscCall(ISGetLocalSize(ipmP->isxu, &nloc));
356:       for (i = 0; i < nloc; i++) {
357:         xind[i] = xui[i];
358:         cind[i] = xu_offset + i;
359:       }

361:       PetscCall(ISCreateGeneral(comm, nloc, xind, PETSC_COPY_VALUES, &isx));
362:       PetscCall(ISCreateGeneral(comm, nloc, cind, PETSC_COPY_VALUES, &isc));
363:       PetscCall(VecScatterCreate(tao->XU, isx, ipmP->ci, isc, &ipmP->xu_scat));
364:       PetscCall(ISDestroy(&isx));
365:       PetscCall(ISDestroy(&isc));
366:       PetscCall(ISDestroy(&bigxu));
367:     }
368:   }
369:   PetscCall(VecCreate(comm, &ipmP->bigrhs));
370:   PetscCall(VecGetType(tao->solution, &vtype));
371:   PetscCall(VecSetType(ipmP->bigrhs, vtype));
372:   PetscCall(VecSetSizes(ipmP->bigrhs, PETSC_DECIDE, bigsize));
373:   PetscCall(VecSetFromOptions(ipmP->bigrhs));
374:   PetscCall(VecDuplicate(ipmP->bigrhs, &ipmP->bigstep));

376:   /* create scatters for step->x and x->rhs */
377:   for (i = xstart; i < xend; i++) {
378:     stepind[i - xstart] = i;
379:     xind[i - xstart]    = i;
380:   }
381:   PetscCall(ISCreateGeneral(comm, xend - xstart, stepind, PETSC_COPY_VALUES, &sis));
382:   PetscCall(ISCreateGeneral(comm, xend - xstart, xind, PETSC_COPY_VALUES, &is1));
383:   PetscCall(VecScatterCreate(ipmP->bigstep, sis, tao->solution, is1, &ipmP->step1));
384:   PetscCall(VecScatterCreate(tao->solution, is1, ipmP->bigrhs, sis, &ipmP->rhs1));
385:   PetscCall(ISDestroy(&sis));
386:   PetscCall(ISDestroy(&is1));

388:   if (ipmP->nb > 0) {
389:     for (i = sstart; i < send; i++) {
390:       stepind[i - sstart] = i + ipmP->n;
391:       cind[i - sstart]    = i;
392:     }
393:     PetscCall(ISCreateGeneral(comm, send - sstart, stepind, PETSC_COPY_VALUES, &sis));
394:     PetscCall(ISCreateGeneral(comm, send - sstart, cind, PETSC_COPY_VALUES, &is1));
395:     PetscCall(VecScatterCreate(ipmP->bigstep, sis, ipmP->s, is1, &ipmP->step2));
396:     PetscCall(ISDestroy(&sis));

398:     for (i = sstart; i < send; i++) {
399:       stepind[i - sstart] = i + ipmP->n + ipmP->me;
400:       cind[i - sstart]    = i;
401:     }
402:     PetscCall(ISCreateGeneral(comm, send - sstart, stepind, PETSC_COPY_VALUES, &sis));
403:     PetscCall(VecScatterCreate(ipmP->s, is1, ipmP->bigrhs, sis, &ipmP->rhs3));
404:     PetscCall(ISDestroy(&sis));
405:     PetscCall(ISDestroy(&is1));
406:   }

408:   if (ipmP->me > 0) {
409:     PetscCall(VecGetOwnershipRange(tao->constraints_equality, &ucestart, &uceend));
410:     for (i = ucestart; i < uceend; i++) {
411:       stepind[i - ucestart] = i + ipmP->n + ipmP->nb;
412:       uceind[i - ucestart]  = i;
413:     }

415:     PetscCall(ISCreateGeneral(comm, uceend - ucestart, stepind, PETSC_COPY_VALUES, &sis));
416:     PetscCall(ISCreateGeneral(comm, uceend - ucestart, uceind, PETSC_COPY_VALUES, &is1));
417:     PetscCall(VecScatterCreate(ipmP->bigstep, sis, tao->constraints_equality, is1, &ipmP->step3));
418:     PetscCall(ISDestroy(&sis));

420:     for (i = ucestart; i < uceend; i++) stepind[i - ucestart] = i + ipmP->n;

422:     PetscCall(ISCreateGeneral(comm, uceend - ucestart, stepind, PETSC_COPY_VALUES, &sis));
423:     PetscCall(VecScatterCreate(tao->constraints_equality, is1, ipmP->bigrhs, sis, &ipmP->rhs2));
424:     PetscCall(ISDestroy(&sis));
425:     PetscCall(ISDestroy(&is1));
426:   }

428:   if (ipmP->nb > 0) {
429:     for (i = sstart; i < send; i++) {
430:       stepind[i - sstart] = i + ipmP->n + ipmP->nb + ipmP->me;
431:       cind[i - sstart]    = i;
432:     }
433:     PetscCall(ISCreateGeneral(comm, send - sstart, cind, PETSC_COPY_VALUES, &is1));
434:     PetscCall(ISCreateGeneral(comm, send - sstart, stepind, PETSC_COPY_VALUES, &sis));
435:     PetscCall(VecScatterCreate(ipmP->bigstep, sis, ipmP->s, is1, &ipmP->step4));
436:     PetscCall(VecScatterCreate(ipmP->s, is1, ipmP->bigrhs, sis, &ipmP->rhs4));
437:     PetscCall(ISDestroy(&sis));
438:     PetscCall(ISDestroy(&is1));
439:   }

441:   PetscCall(PetscFree(stepind));
442:   PetscCall(PetscFree(cind));
443:   PetscCall(PetscFree(ucind));
444:   PetscCall(PetscFree(uceind));
445:   PetscCall(PetscFree(xind));
446:   PetscFunctionReturn(PETSC_SUCCESS);
447: }

449: static PetscErrorCode TaoDestroy_IPM(Tao tao)
450: {
451:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

453:   PetscFunctionBegin;
454:   PetscCall(VecDestroy(&ipmP->rd));
455:   PetscCall(VecDestroy(&ipmP->rpe));
456:   PetscCall(VecDestroy(&ipmP->rpi));
457:   PetscCall(VecDestroy(&ipmP->work));
458:   PetscCall(VecDestroy(&ipmP->lambdae));
459:   PetscCall(VecDestroy(&ipmP->lambdai));
460:   PetscCall(VecDestroy(&ipmP->s));
461:   PetscCall(VecDestroy(&ipmP->ds));
462:   PetscCall(VecDestroy(&ipmP->ci));

464:   PetscCall(VecDestroy(&ipmP->rhs_x));
465:   PetscCall(VecDestroy(&ipmP->rhs_lambdae));
466:   PetscCall(VecDestroy(&ipmP->rhs_lambdai));
467:   PetscCall(VecDestroy(&ipmP->rhs_s));

469:   PetscCall(VecDestroy(&ipmP->save_x));
470:   PetscCall(VecDestroy(&ipmP->save_lambdae));
471:   PetscCall(VecDestroy(&ipmP->save_lambdai));
472:   PetscCall(VecDestroy(&ipmP->save_s));

474:   PetscCall(VecScatterDestroy(&ipmP->step1));
475:   PetscCall(VecScatterDestroy(&ipmP->step2));
476:   PetscCall(VecScatterDestroy(&ipmP->step3));
477:   PetscCall(VecScatterDestroy(&ipmP->step4));

479:   PetscCall(VecScatterDestroy(&ipmP->rhs1));
480:   PetscCall(VecScatterDestroy(&ipmP->rhs2));
481:   PetscCall(VecScatterDestroy(&ipmP->rhs3));
482:   PetscCall(VecScatterDestroy(&ipmP->rhs4));

484:   PetscCall(VecScatterDestroy(&ipmP->ci_scat));
485:   PetscCall(VecScatterDestroy(&ipmP->xl_scat));
486:   PetscCall(VecScatterDestroy(&ipmP->xu_scat));

488:   PetscCall(VecDestroy(&ipmP->dlambdai));
489:   PetscCall(VecDestroy(&ipmP->dlambdae));
490:   PetscCall(VecDestroy(&ipmP->Zero_nb));
491:   PetscCall(VecDestroy(&ipmP->One_nb));
492:   PetscCall(VecDestroy(&ipmP->Inf_nb));
493:   PetscCall(VecDestroy(&ipmP->complementarity));

495:   PetscCall(VecDestroy(&ipmP->bigrhs));
496:   PetscCall(VecDestroy(&ipmP->bigstep));
497:   PetscCall(MatDestroy(&ipmP->Ai));
498:   PetscCall(MatDestroy(&ipmP->K));
499:   PetscCall(ISDestroy(&ipmP->isxu));
500:   PetscCall(ISDestroy(&ipmP->isxl));
501:   PetscCall(KSPDestroy(&tao->ksp));
502:   PetscCall(PetscFree(tao->data));
503:   PetscFunctionReturn(PETSC_SUCCESS);
504: }

506: static PetscErrorCode TaoSetFromOptions_IPM(Tao tao, PetscOptionItems PetscOptionsObject)
507: {
508:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

510:   PetscFunctionBegin;
511:   PetscOptionsHeadBegin(PetscOptionsObject, "IPM method for constrained optimization");
512:   PetscCall(PetscOptionsBool("-tao_ipm_monitorkkt", "monitor kkt status", NULL, ipmP->monitorkkt, &ipmP->monitorkkt, NULL));
513:   PetscCall(PetscOptionsReal("-tao_ipm_pushs", "parameter to push initial slack variables away from bounds", NULL, ipmP->pushs, &ipmP->pushs, NULL));
514:   PetscCall(PetscOptionsReal("-tao_ipm_pushnu", "parameter to push initial (inequality) dual variables away from bounds", NULL, ipmP->pushnu, &ipmP->pushnu, NULL));
515:   PetscOptionsHeadEnd();
516:   PetscCall(KSPSetFromOptions(tao->ksp));
517:   PetscFunctionReturn(PETSC_SUCCESS);
518: }

520: static PetscErrorCode TaoView_IPM(Tao tao, PetscViewer viewer)
521: {
522:   return PETSC_SUCCESS;
523: }

525: /* IPMObjectiveAndGradient()
526:    f = d'x + 0.5 * x' * H * x
527:    rd = H*x + d + Ae'*lame - Ai'*lami
528:    rpe = Ae*x - be
529:    rpi = Ai*x - yi - bi
530:    mu = yi' * lami/mi;
531:    com = yi.*lami

533:    phi = ||rd|| + ||rpe|| + ||rpi|| + ||com||
534: */
535: /*
536: static PetscErrorCode IPMObjective(TaoLineSearch ls, Vec X, PetscReal *f, void *tptr)
537: {
538:   Tao tao = (Tao)tptr;
539:   TAO_IPM *ipmP = (TAO_IPM*)tao->data;

541:   PetscFunctionBegin;
542:   PetscCall(IPMComputeKKT(tao));
543:   *f = ipmP->phi;
544:   PetscFunctionReturn(PETSC_SUCCESS);
545: }
546: */

548: /*
549:    f = d'x + 0.5 * x' * H * x
550:    rd = H*x + d + Ae'*lame - Ai'*lami
551:        Ai =   jac_ineq
552:                I (w/lb)
553:               -I (w/ub)

555:    rpe = ce
556:    rpi = ci - s;
557:    com = s.*lami
558:    mu = yi' * lami/mi;

560:    phi = ||rd|| + ||rpe|| + ||rpi|| + ||com||
561: */
562: static PetscErrorCode IPMComputeKKT(Tao tao)
563: {
564:   TAO_IPM    *ipmP = (TAO_IPM *)tao->data;
565:   PetscScalar norm;

567:   PetscFunctionBegin;
568:   PetscCall(VecCopy(tao->gradient, ipmP->rd));

570:   if (ipmP->me > 0) {
571:     /* rd = gradient + Ae'*lambdae */
572:     PetscCall(MatMultTranspose(tao->jacobian_equality, ipmP->lambdae, ipmP->work));
573:     PetscCall(VecAXPY(ipmP->rd, 1.0, ipmP->work));

575:     /* rpe = ce(x) */
576:     PetscCall(VecCopy(tao->constraints_equality, ipmP->rpe));
577:   }
578:   if (ipmP->nb > 0) {
579:     /* rd = rd - Ai'*lambdai */
580:     PetscCall(MatMultTranspose(ipmP->Ai, ipmP->lambdai, ipmP->work));
581:     PetscCall(VecAXPY(ipmP->rd, -1.0, ipmP->work));

583:     /* rpi = cin - s */
584:     PetscCall(VecCopy(ipmP->ci, ipmP->rpi));
585:     PetscCall(VecAXPY(ipmP->rpi, -1.0, ipmP->s));

587:     /* com = s .* lami */
588:     PetscCall(VecPointwiseMult(ipmP->complementarity, ipmP->s, ipmP->lambdai));
589:   }
590:   /* phi = ||rd; rpe; rpi; com|| */
591:   PetscCall(VecDot(ipmP->rd, ipmP->rd, &norm));
592:   ipmP->phi = norm;
593:   if (ipmP->me > 0) {
594:     PetscCall(VecDot(ipmP->rpe, ipmP->rpe, &norm));
595:     ipmP->phi += norm;
596:   }
597:   if (ipmP->nb > 0) {
598:     PetscCall(VecDot(ipmP->rpi, ipmP->rpi, &norm));
599:     ipmP->phi += norm;
600:     PetscCall(VecDot(ipmP->complementarity, ipmP->complementarity, &norm));
601:     ipmP->phi += norm;
602:     /* mu = s'*lami/nb */
603:     PetscCall(VecDot(ipmP->s, ipmP->lambdai, &ipmP->mu));
604:     ipmP->mu /= ipmP->nb;
605:   } else {
606:     ipmP->mu = 1.0;
607:   }

609:   ipmP->phi = PetscSqrtScalar(ipmP->phi);
610:   PetscFunctionReturn(PETSC_SUCCESS);
611: }

613: /* evaluate user info at current point */
614: static PetscErrorCode IPMEvaluate(Tao tao)
615: {
616:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

618:   PetscFunctionBegin;
619:   PetscCall(TaoComputeObjectiveAndGradient(tao, tao->solution, &ipmP->kkt_f, tao->gradient));
620:   PetscCall(TaoComputeHessian(tao, tao->solution, tao->hessian, tao->hessian_pre));
621:   if (ipmP->me > 0) {
622:     PetscCall(TaoComputeEqualityConstraints(tao, tao->solution, tao->constraints_equality));
623:     PetscCall(TaoComputeJacobianEquality(tao, tao->solution, tao->jacobian_equality, tao->jacobian_equality_pre));
624:   }
625:   if (ipmP->mi > 0) {
626:     PetscCall(TaoComputeInequalityConstraints(tao, tao->solution, tao->constraints_inequality));
627:     PetscCall(TaoComputeJacobianInequality(tao, tao->solution, tao->jacobian_inequality, tao->jacobian_inequality_pre));
628:   }
629:   if (ipmP->nb > 0) {
630:     /* Ai' =   jac_ineq | I (w/lb) | -I (w/ub)  */
631:     PetscCall(IPMUpdateAi(tao));
632:   }
633:   PetscFunctionReturn(PETSC_SUCCESS);
634: }

636: /* Push initial point away from bounds */
637: static PetscErrorCode IPMPushInitialPoint(Tao tao)
638: {
639:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

641:   PetscFunctionBegin;
642:   PetscCall(TaoComputeVariableBounds(tao));
643:   PetscCall(VecMedian(tao->XL, tao->solution, tao->XU, tao->solution));
644:   if (ipmP->nb > 0) {
645:     PetscCall(VecSet(ipmP->s, ipmP->pushs));
646:     PetscCall(VecSet(ipmP->lambdai, ipmP->pushnu));
647:     if (ipmP->mi > 0) PetscCall(VecSet(tao->DI, ipmP->pushnu));
648:   }
649:   if (ipmP->me > 0) {
650:     PetscCall(VecSet(tao->DE, 1.0));
651:     PetscCall(VecSet(ipmP->lambdae, 1.0));
652:   }
653:   PetscFunctionReturn(PETSC_SUCCESS);
654: }

656: static PetscErrorCode IPMUpdateAi(Tao tao)
657: {
658:   /* Ai =     Ji
659:               I (w/lb)
660:              -I (w/ub) */

662:   /* Ci =    user->ci
663:              Xi - lb (w/lb)
664:              -Xi + ub (w/ub)  */

666:   TAO_IPM           *ipmP = (TAO_IPM *)tao->data;
667:   MPI_Comm           comm;
668:   PetscInt           i;
669:   PetscScalar        newval;
670:   PetscInt           newrow, newcol, ncols;
671:   const PetscScalar *vals;
672:   const PetscInt    *cols;
673:   PetscInt           astart, aend, jstart, jend;
674:   PetscInt          *nonzeros;
675:   PetscInt           r2, r3, r4;
676:   PetscMPIInt        size;
677:   Vec                solu;
678:   PetscInt           nloc;

680:   PetscFunctionBegin;
681:   r2 = ipmP->mi;
682:   r3 = r2 + ipmP->nxlb;
683:   r4 = r3 + ipmP->nxub;

685:   if (!ipmP->nb) PetscFunctionReturn(PETSC_SUCCESS);

687:   /* Create Ai matrix if it doesn't exist yet */
688:   if (!ipmP->Ai) {
689:     comm = ((PetscObject)tao->solution)->comm;
690:     PetscCallMPI(MPI_Comm_size(comm, &size));
691:     if (size == 1) {
692:       PetscCall(PetscMalloc1(ipmP->nb, &nonzeros));
693:       for (i = 0; i < ipmP->mi; i++) {
694:         PetscCall(MatGetRow(tao->jacobian_inequality, i, &ncols, NULL, NULL));
695:         nonzeros[i] = ncols;
696:         PetscCall(MatRestoreRow(tao->jacobian_inequality, i, &ncols, NULL, NULL));
697:       }
698:       for (i = r2; i < r4; i++) nonzeros[i] = 1;
699:     }
700:     PetscCall(MatCreate(comm, &ipmP->Ai));
701:     PetscCall(MatSetType(ipmP->Ai, MATAIJ));

703:     PetscCall(TaoGetSolution(tao, &solu));
704:     PetscCall(VecGetLocalSize(solu, &nloc));
705:     PetscCall(MatSetSizes(ipmP->Ai, PETSC_DECIDE, nloc, ipmP->nb, PETSC_DECIDE));
706:     PetscCall(MatSetFromOptions(ipmP->Ai));
707:     PetscCall(MatMPIAIJSetPreallocation(ipmP->Ai, ipmP->nb, NULL, ipmP->nb, NULL));
708:     PetscCall(MatSeqAIJSetPreallocation(ipmP->Ai, PETSC_DEFAULT, nonzeros));
709:     if (size == 1) PetscCall(PetscFree(nonzeros));
710:   }

712:   /* Copy values from user jacobian to Ai */
713:   PetscCall(MatGetOwnershipRange(ipmP->Ai, &astart, &aend));

715:   /* Ai w/lb */
716:   if (ipmP->mi) {
717:     PetscCall(MatZeroEntries(ipmP->Ai));
718:     PetscCall(MatGetOwnershipRange(tao->jacobian_inequality, &jstart, &jend));
719:     for (i = jstart; i < jend; i++) {
720:       PetscCall(MatGetRow(tao->jacobian_inequality, i, &ncols, &cols, &vals));
721:       newrow = i;
722:       PetscCall(MatSetValues(ipmP->Ai, 1, &newrow, ncols, cols, vals, INSERT_VALUES));
723:       PetscCall(MatRestoreRow(tao->jacobian_inequality, i, &ncols, &cols, &vals));
724:     }
725:   }

727:   /* I w/ xlb */
728:   if (ipmP->nxlb) {
729:     for (i = 0; i < ipmP->nxlb; i++) {
730:       if (i >= astart && i < aend) {
731:         newrow = i + r2;
732:         newcol = i;
733:         newval = 1.0;
734:         PetscCall(MatSetValues(ipmP->Ai, 1, &newrow, 1, &newcol, &newval, INSERT_VALUES));
735:       }
736:     }
737:   }
738:   if (ipmP->nxub) {
739:     /* I w/ xub */
740:     for (i = 0; i < ipmP->nxub; i++) {
741:       if (i >= astart && i < aend) {
742:         newrow = i + r3;
743:         newcol = i;
744:         newval = -1.0;
745:         PetscCall(MatSetValues(ipmP->Ai, 1, &newrow, 1, &newcol, &newval, INSERT_VALUES));
746:       }
747:     }
748:   }

750:   PetscCall(MatAssemblyBegin(ipmP->Ai, MAT_FINAL_ASSEMBLY));
751:   PetscCall(MatAssemblyEnd(ipmP->Ai, MAT_FINAL_ASSEMBLY));
752:   CHKMEMQ;

754:   PetscCall(VecSet(ipmP->ci, 0.0));

756:   /* user ci */
757:   if (ipmP->mi > 0) {
758:     PetscCall(VecScatterBegin(ipmP->ci_scat, tao->constraints_inequality, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
759:     PetscCall(VecScatterEnd(ipmP->ci_scat, tao->constraints_inequality, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
760:   }
761:   if (!ipmP->work) PetscCall(VecDuplicate(tao->solution, &ipmP->work));
762:   PetscCall(VecCopy(tao->solution, ipmP->work));
763:   if (tao->XL) {
764:     PetscCall(VecAXPY(ipmP->work, -1.0, tao->XL));

766:     /* lower bounds on variables */
767:     if (ipmP->nxlb > 0) {
768:       PetscCall(VecScatterBegin(ipmP->xl_scat, ipmP->work, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
769:       PetscCall(VecScatterEnd(ipmP->xl_scat, ipmP->work, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
770:     }
771:   }
772:   if (tao->XU) {
773:     /* upper bounds on variables */
774:     PetscCall(VecCopy(tao->solution, ipmP->work));
775:     PetscCall(VecScale(ipmP->work, -1.0));
776:     PetscCall(VecAXPY(ipmP->work, 1.0, tao->XU));
777:     if (ipmP->nxub > 0) {
778:       PetscCall(VecScatterBegin(ipmP->xu_scat, ipmP->work, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
779:       PetscCall(VecScatterEnd(ipmP->xu_scat, ipmP->work, ipmP->ci, INSERT_VALUES, SCATTER_FORWARD));
780:     }
781:   }
782:   PetscFunctionReturn(PETSC_SUCCESS);
783: }

785: /* create K = [ Hlag , 0 , Ae', -Ai'];
786:               [Ae , 0,   0  , 0];
787:               [Ai ,-I,   0 ,  0];
788:               [ 0 , S ,  0,   Y ];  */
789: static PetscErrorCode IPMUpdateK(Tao tao)
790: {
791:   TAO_IPM         *ipmP = (TAO_IPM *)tao->data;
792:   MPI_Comm         comm;
793:   PetscMPIInt      size;
794:   PetscInt         i, j, row;
795:   PetscInt         ncols, newcol, newcols[2], newrow;
796:   const PetscInt  *cols;
797:   const PetscReal *vals;
798:   const PetscReal *l, *y;
799:   PetscReal       *newvals;
800:   PetscReal        newval;
801:   PetscInt         subsize;
802:   const PetscInt  *indices;
803:   PetscInt        *nonzeros, *d_nonzeros, *o_nonzeros;
804:   PetscInt         bigsize;
805:   PetscInt         r1, r2, r3;
806:   PetscInt         c1, c2, c3;
807:   PetscInt         klocalsize;
808:   PetscInt         hstart, hend, kstart, kend;
809:   PetscInt         aistart, aiend, aestart, aeend;
810:   PetscInt         sstart, send;

812:   PetscFunctionBegin;
813:   comm = ((PetscObject)tao->solution)->comm;
814:   PetscCallMPI(MPI_Comm_size(comm, &size));
815:   PetscCall(IPMUpdateAi(tao));

817:   /* allocate workspace */
818:   subsize = PetscMax(ipmP->n, ipmP->nb);
819:   subsize = PetscMax(ipmP->me, subsize);
820:   subsize = PetscMax(2, subsize);
821:   PetscCall(PetscMalloc1(subsize, &indices));
822:   PetscCall(PetscMalloc1(subsize, &newvals));

824:   r1 = c1 = ipmP->n;
825:   r2      = r1 + ipmP->me;
826:   c2      = c1 + ipmP->nb;
827:   r3 = c3 = r2 + ipmP->nb;

829:   bigsize = ipmP->n + 2 * ipmP->nb + ipmP->me;
830:   PetscCall(VecGetOwnershipRange(ipmP->bigrhs, &kstart, &kend));
831:   PetscCall(MatGetOwnershipRange(tao->hessian, &hstart, &hend));
832:   klocalsize = kend - kstart;
833:   if (!ipmP->K) {
834:     if (size == 1) {
835:       PetscCall(PetscMalloc1(kend - kstart, &nonzeros));
836:       for (i = 0; i < bigsize; i++) {
837:         if (i < r1) {
838:           PetscCall(MatGetRow(tao->hessian, i, &ncols, NULL, NULL));
839:           nonzeros[i] = ncols;
840:           PetscCall(MatRestoreRow(tao->hessian, i, &ncols, NULL, NULL));
841:           nonzeros[i] += ipmP->me + ipmP->nb;
842:         } else if (i < r2) {
843:           nonzeros[i - kstart] = ipmP->n;
844:         } else if (i < r3) {
845:           nonzeros[i - kstart] = ipmP->n + 1;
846:         } else if (i < bigsize) {
847:           nonzeros[i - kstart] = 2;
848:         }
849:       }
850:       PetscCall(MatCreate(comm, &ipmP->K));
851:       PetscCall(MatSetType(ipmP->K, MATSEQAIJ));
852:       PetscCall(MatSetSizes(ipmP->K, klocalsize, klocalsize, PETSC_DETERMINE, PETSC_DETERMINE));
853:       PetscCall(MatSeqAIJSetPreallocation(ipmP->K, 0, nonzeros));
854:       PetscCall(MatSetFromOptions(ipmP->K));
855:       PetscCall(PetscFree(nonzeros));
856:     } else {
857:       PetscCall(PetscMalloc1(kend - kstart, &d_nonzeros));
858:       PetscCall(PetscMalloc1(kend - kstart, &o_nonzeros));
859:       for (i = kstart; i < kend; i++) {
860:         if (i < r1) {
861:           /* TODO fix preallocation for mpi mats */
862:           d_nonzeros[i - kstart] = PetscMin(ipmP->n + ipmP->me + ipmP->nb, kend - kstart);
863:           o_nonzeros[i - kstart] = PetscMin(ipmP->n + ipmP->me + ipmP->nb, bigsize - (kend - kstart));
864:         } else if (i < r2) {
865:           d_nonzeros[i - kstart] = PetscMin(ipmP->n, kend - kstart);
866:           o_nonzeros[i - kstart] = PetscMin(ipmP->n, bigsize - (kend - kstart));
867:         } else if (i < r3) {
868:           d_nonzeros[i - kstart] = PetscMin(ipmP->n + 2, kend - kstart);
869:           o_nonzeros[i - kstart] = PetscMin(ipmP->n + 2, bigsize - (kend - kstart));
870:         } else {
871:           d_nonzeros[i - kstart] = PetscMin(2, kend - kstart);
872:           o_nonzeros[i - kstart] = PetscMin(2, bigsize - (kend - kstart));
873:         }
874:       }
875:       PetscCall(MatCreate(comm, &ipmP->K));
876:       PetscCall(MatSetType(ipmP->K, MATMPIAIJ));
877:       PetscCall(MatSetSizes(ipmP->K, klocalsize, klocalsize, PETSC_DETERMINE, PETSC_DETERMINE));
878:       PetscCall(MatMPIAIJSetPreallocation(ipmP->K, 0, d_nonzeros, 0, o_nonzeros));
879:       PetscCall(PetscFree(d_nonzeros));
880:       PetscCall(PetscFree(o_nonzeros));
881:       PetscCall(MatSetFromOptions(ipmP->K));
882:     }
883:   }

885:   PetscCall(MatZeroEntries(ipmP->K));
886:   /* Copy H */
887:   for (i = hstart; i < hend; i++) {
888:     PetscCall(MatGetRow(tao->hessian, i, &ncols, &cols, &vals));
889:     if (ncols > 0) PetscCall(MatSetValues(ipmP->K, 1, &i, ncols, cols, vals, INSERT_VALUES));
890:     PetscCall(MatRestoreRow(tao->hessian, i, &ncols, &cols, &vals));
891:   }

893:   /* Copy Ae and Ae' */
894:   if (ipmP->me > 0) {
895:     PetscCall(MatGetOwnershipRange(tao->jacobian_equality, &aestart, &aeend));
896:     for (i = aestart; i < aeend; i++) {
897:       PetscCall(MatGetRow(tao->jacobian_equality, i, &ncols, &cols, &vals));
898:       if (ncols > 0) {
899:         /*Ae*/
900:         row = i + r1;
901:         PetscCall(MatSetValues(ipmP->K, 1, &row, ncols, cols, vals, INSERT_VALUES));
902:         /*Ae'*/
903:         for (j = 0; j < ncols; j++) {
904:           newcol = i + c2;
905:           newrow = cols[j];
906:           newval = vals[j];
907:           PetscCall(MatSetValues(ipmP->K, 1, &newrow, 1, &newcol, &newval, INSERT_VALUES));
908:         }
909:       }
910:       PetscCall(MatRestoreRow(tao->jacobian_equality, i, &ncols, &cols, &vals));
911:     }
912:   }

914:   if (ipmP->nb > 0) {
915:     PetscCall(MatGetOwnershipRange(ipmP->Ai, &aistart, &aiend));
916:     /* Copy Ai,and Ai' */
917:     for (i = aistart; i < aiend; i++) {
918:       row = i + r2;
919:       PetscCall(MatGetRow(ipmP->Ai, i, &ncols, &cols, &vals));
920:       if (ncols > 0) {
921:         /*Ai*/
922:         PetscCall(MatSetValues(ipmP->K, 1, &row, ncols, cols, vals, INSERT_VALUES));
923:         /*-Ai'*/
924:         for (j = 0; j < ncols; j++) {
925:           newcol = i + c3;
926:           newrow = cols[j];
927:           newval = -vals[j];
928:           PetscCall(MatSetValues(ipmP->K, 1, &newrow, 1, &newcol, &newval, INSERT_VALUES));
929:         }
930:       }
931:       PetscCall(MatRestoreRow(ipmP->Ai, i, &ncols, &cols, &vals));
932:     }

934:     /* -I */
935:     for (i = kstart; i < kend; i++) {
936:       if (i >= r2 && i < r3) {
937:         newrow = i;
938:         newcol = i - r2 + c1;
939:         newval = -1.0;
940:         PetscCall(MatSetValues(ipmP->K, 1, &newrow, 1, &newcol, &newval, INSERT_VALUES));
941:       }
942:     }

944:     /* Copy L,Y */
945:     PetscCall(VecGetOwnershipRange(ipmP->s, &sstart, &send));
946:     PetscCall(VecGetArrayRead(ipmP->lambdai, &l));
947:     PetscCall(VecGetArrayRead(ipmP->s, &y));

949:     for (i = sstart; i < send; i++) {
950:       newcols[0] = c1 + i;
951:       newcols[1] = c3 + i;
952:       newvals[0] = l[i - sstart];
953:       newvals[1] = y[i - sstart];
954:       newrow     = r3 + i;
955:       PetscCall(MatSetValues(ipmP->K, 1, &newrow, 2, newcols, newvals, INSERT_VALUES));
956:     }

958:     PetscCall(VecRestoreArrayRead(ipmP->lambdai, &l));
959:     PetscCall(VecRestoreArrayRead(ipmP->s, &y));
960:   }

962:   PetscCall(PetscFree(indices));
963:   PetscCall(PetscFree(newvals));
964:   PetscCall(MatAssemblyBegin(ipmP->K, MAT_FINAL_ASSEMBLY));
965:   PetscCall(MatAssemblyEnd(ipmP->K, MAT_FINAL_ASSEMBLY));
966:   PetscFunctionReturn(PETSC_SUCCESS);
967: }

969: static PetscErrorCode IPMGatherRHS(Tao tao, Vec RHS, Vec X1, Vec X2, Vec X3, Vec X4)
970: {
971:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

973:   PetscFunctionBegin;
974:   /* rhs = [x1      (n)
975:             x2     (me)
976:             x3     (nb)
977:             x4     (nb)] */
978:   if (X1) {
979:     PetscCall(VecScatterBegin(ipmP->rhs1, X1, RHS, INSERT_VALUES, SCATTER_FORWARD));
980:     PetscCall(VecScatterEnd(ipmP->rhs1, X1, RHS, INSERT_VALUES, SCATTER_FORWARD));
981:   }
982:   if (ipmP->me > 0 && X2) {
983:     PetscCall(VecScatterBegin(ipmP->rhs2, X2, RHS, INSERT_VALUES, SCATTER_FORWARD));
984:     PetscCall(VecScatterEnd(ipmP->rhs2, X2, RHS, INSERT_VALUES, SCATTER_FORWARD));
985:   }
986:   if (ipmP->nb > 0) {
987:     if (X3) {
988:       PetscCall(VecScatterBegin(ipmP->rhs3, X3, RHS, INSERT_VALUES, SCATTER_FORWARD));
989:       PetscCall(VecScatterEnd(ipmP->rhs3, X3, RHS, INSERT_VALUES, SCATTER_FORWARD));
990:     }
991:     if (X4) {
992:       PetscCall(VecScatterBegin(ipmP->rhs4, X4, RHS, INSERT_VALUES, SCATTER_FORWARD));
993:       PetscCall(VecScatterEnd(ipmP->rhs4, X4, RHS, INSERT_VALUES, SCATTER_FORWARD));
994:     }
995:   }
996:   PetscFunctionReturn(PETSC_SUCCESS);
997: }

999: static PetscErrorCode IPMScatterStep(Tao tao, Vec STEP, Vec X1, Vec X2, Vec X3, Vec X4)
1000: {
1001:   TAO_IPM *ipmP = (TAO_IPM *)tao->data;

1003:   PetscFunctionBegin;
1004:   CHKMEMQ;
1005:   /*        [x1    (n)
1006:              x2    (nb) may be 0
1007:              x3    (me) may be 0
1008:              x4    (nb) may be 0 */
1009:   if (X1) {
1010:     PetscCall(VecScatterBegin(ipmP->step1, STEP, X1, INSERT_VALUES, SCATTER_FORWARD));
1011:     PetscCall(VecScatterEnd(ipmP->step1, STEP, X1, INSERT_VALUES, SCATTER_FORWARD));
1012:   }
1013:   if (X2 && ipmP->nb > 0) {
1014:     PetscCall(VecScatterBegin(ipmP->step2, STEP, X2, INSERT_VALUES, SCATTER_FORWARD));
1015:     PetscCall(VecScatterEnd(ipmP->step2, STEP, X2, INSERT_VALUES, SCATTER_FORWARD));
1016:   }
1017:   if (X3 && ipmP->me > 0) {
1018:     PetscCall(VecScatterBegin(ipmP->step3, STEP, X3, INSERT_VALUES, SCATTER_FORWARD));
1019:     PetscCall(VecScatterEnd(ipmP->step3, STEP, X3, INSERT_VALUES, SCATTER_FORWARD));
1020:   }
1021:   if (X4 && ipmP->nb > 0) {
1022:     PetscCall(VecScatterBegin(ipmP->step4, STEP, X4, INSERT_VALUES, SCATTER_FORWARD));
1023:     PetscCall(VecScatterEnd(ipmP->step4, STEP, X4, INSERT_VALUES, SCATTER_FORWARD));
1024:   }
1025:   CHKMEMQ;
1026:   PetscFunctionReturn(PETSC_SUCCESS);
1027: }

1029: /*MC
1030:   TAOIPM - Interior point algorithm for generally constrained optimization.

1032:   Options Database Keys:
1033: +   -tao_ipm_pushnu - parameter to push initial dual variables away from bounds
1034: -   -tao_ipm_pushs  - parameter to push initial slack variables away from bounds

1036:   Notes:
1037:     This algorithm is more of a place-holder for future constrained optimization algorithms and should not yet be used for large problems or production code.
1038:   Level: beginner

1040: .seealso: `Tao`, `TAOPDIPM`, `TaoType`
1041: M*/

1043: PETSC_EXTERN PetscErrorCode TaoCreate_IPM(Tao tao)
1044: {
1045:   TAO_IPM *ipmP;

1047:   PetscFunctionBegin;
1048:   tao->ops->setup            = TaoSetup_IPM;
1049:   tao->ops->solve            = TaoSolve_IPM;
1050:   tao->ops->view             = TaoView_IPM;
1051:   tao->ops->setfromoptions   = TaoSetFromOptions_IPM;
1052:   tao->ops->destroy          = TaoDestroy_IPM;
1053:   tao->uses_gradient         = PETSC_TRUE;
1054:   tao->uses_hessian_matrices = PETSC_TRUE;
1055:   /* tao->ops->computedual = TaoComputeDual_IPM; */

1057:   PetscCall(PetscNew(&ipmP));
1058:   tao->data = (void *)ipmP;

1060:   /* Override default settings (unless already changed) */
1061:   PetscCall(TaoParametersInitialize(tao));
1062:   PetscObjectParameterSetDefault(tao, max_it, 200);
1063:   PetscObjectParameterSetDefault(tao, max_funcs, 500);

1065:   ipmP->dec        = 10000; /* line search criteria */
1066:   ipmP->taumin     = 0.995;
1067:   ipmP->monitorkkt = PETSC_FALSE;
1068:   ipmP->pushs      = 100;
1069:   ipmP->pushnu     = 100;
1070:   PetscCall(KSPCreate(((PetscObject)tao)->comm, &tao->ksp));
1071:   PetscCall(PetscObjectIncrementTabLevel((PetscObject)tao->ksp, (PetscObject)tao, 1));
1072:   PetscCall(KSPSetOptionsPrefix(tao->ksp, tao->hdr.prefix));
1073:   PetscFunctionReturn(PETSC_SUCCESS);
1074: }