Actual source code: bqpip.c

petsc-3.8.4 2018-03-24
Report Typos and Errors
  1: /*
  2:     This file implements a Mehrotra predictor-corrector method for
  3:     bound-constrained quadratic programs.

  5:  */

  7:  #include <../src/tao/bound/impls/bqpip/bqpipimpl.h>
  8:  #include <petscksp.h>

 10: static PetscErrorCode QPIPComputeResidual(TAO_BQPIP *qp,Tao tao)
 11: {
 13:   PetscReal      dtmp = 1.0 - qp->psteplength;

 16:   /* Compute R3 and R5 */

 18:   VecScale(qp->R3,dtmp);
 19:   VecScale(qp->R5,dtmp);
 20:   qp->pinfeas=dtmp*qp->pinfeas;

 22:   VecCopy(qp->S,tao->gradient);
 23:   VecAXPY(tao->gradient,-1.0,qp->Z);

 25:   MatMult(tao->hessian,tao->solution,qp->RHS);
 26:   VecScale(qp->RHS,-1.0);
 27:   VecAXPY(qp->RHS,-1.0,qp->C);
 28:   VecAXPY(tao->gradient,-1.0,qp->RHS);

 30:   VecNorm(tao->gradient,NORM_1,&qp->dinfeas);
 31:   qp->rnorm=(qp->dinfeas+qp->pinfeas)/(qp->m+qp->n);
 32:   return(0);
 33: }

 35: static PetscErrorCode  QPIPSetInitialPoint(TAO_BQPIP *qp, Tao tao)
 36: {
 38:   PetscReal      two=2.0,p01=1;
 39:   PetscReal      gap1,gap2,fff,mu;

 42:   /* Compute function, Gradient R=Hx+b, and Hessian */
 43:   MatMult(tao->hessian,tao->solution,tao->gradient);
 44:   VecCopy(qp->C,qp->Work);
 45:   VecAXPY(qp->Work,0.5,tao->gradient);
 46:   VecAXPY(tao->gradient,1.0,qp->C);
 47:   VecDot(tao->solution,qp->Work,&fff);
 48:   qp->pobj = fff + qp->d;

 50:   if (PetscIsInfOrNanReal(qp->pobj)) SETERRQ(PETSC_COMM_SELF,1, "User provided data contains Inf or NaN");

 52:   /* Initialize slack vectors */
 53:   /* T = XU - X; G = X - XL */
 54:   VecCopy(qp->XU,qp->T);
 55:   VecAXPY(qp->T,-1.0,tao->solution);
 56:   VecCopy(tao->solution,qp->G);
 57:   VecAXPY(qp->G,-1.0,qp->XL);

 59:   VecSet(qp->GZwork,p01);
 60:   VecSet(qp->TSwork,p01);

 62:   VecPointwiseMax(qp->G,qp->G,qp->GZwork);
 63:   VecPointwiseMax(qp->T,qp->T,qp->TSwork);

 65:   /* Initialize Dual Variable Vectors */
 66:   VecCopy(qp->G,qp->Z);
 67:   VecReciprocal(qp->Z);

 69:   VecCopy(qp->T,qp->S);
 70:   VecReciprocal(qp->S);

 72:   MatMult(tao->hessian,qp->Work,qp->RHS);
 73:   VecAbs(qp->RHS);
 74:   VecSet(qp->Work,p01);
 75:   VecPointwiseMax(qp->RHS,qp->RHS,qp->Work);

 77:   VecPointwiseDivide(qp->RHS,tao->gradient,qp->RHS);
 78:   VecNorm(qp->RHS,NORM_1,&gap1);
 79:   mu = PetscMin(10.0,(gap1+10.0)/qp->m);

 81:   VecScale(qp->S,mu);
 82:   VecScale(qp->Z,mu);

 84:   VecSet(qp->TSwork,p01);
 85:   VecSet(qp->GZwork,p01);
 86:   VecPointwiseMax(qp->S,qp->S,qp->TSwork);
 87:   VecPointwiseMax(qp->Z,qp->Z,qp->GZwork);

 89:   qp->mu=0;qp->dinfeas=1.0;qp->pinfeas=1.0;
 90:   while ((qp->dinfeas+qp->pinfeas)/(qp->m+qp->n) >= qp->mu) {
 91:     VecScale(qp->G,two);
 92:     VecScale(qp->Z,two);
 93:     VecScale(qp->S,two);
 94:     VecScale(qp->T,two);

 96:     QPIPComputeResidual(qp,tao);

 98:     VecCopy(tao->solution,qp->R3);
 99:     VecAXPY(qp->R3,-1.0,qp->G);
100:     VecAXPY(qp->R3,-1.0,qp->XL);

102:     VecCopy(tao->solution,qp->R5);
103:     VecAXPY(qp->R5,1.0,qp->T);
104:     VecAXPY(qp->R5,-1.0,qp->XU);

106:     VecNorm(qp->R3,NORM_INFINITY,&gap1);
107:     VecNorm(qp->R5,NORM_INFINITY,&gap2);
108:     qp->pinfeas=PetscMax(gap1,gap2);

110:     /* Compute the duality gap */
111:     VecDot(qp->G,qp->Z,&gap1);
112:     VecDot(qp->T,qp->S,&gap2);

114:     qp->gap  = gap1+gap2;
115:     qp->dobj = qp->pobj - qp->gap;
116:     if (qp->m>0) {
117:       qp->mu=qp->gap/(qp->m);
118:     } else {
119:       qp->mu=0.0;
120:     }
121:     qp->rgap=qp->gap/(PetscAbsReal(qp->dobj) + PetscAbsReal(qp->pobj) + 1.0);
122:   }
123:   return(0);
124: }

126: static PetscErrorCode QPIPStepLength(TAO_BQPIP *qp)
127: {
128:   PetscReal      tstep1,tstep2,tstep3,tstep4,tstep;

132:   /* Compute stepsize to the boundary */
133:   VecStepMax(qp->G,qp->DG,&tstep1);
134:   VecStepMax(qp->T,qp->DT,&tstep2);
135:   VecStepMax(qp->S,qp->DS,&tstep3);
136:   VecStepMax(qp->Z,qp->DZ,&tstep4);

138:   tstep = PetscMin(tstep1,tstep2);
139:   qp->psteplength = PetscMin(0.95*tstep,1.0);

141:   tstep = PetscMin(tstep3,tstep4);
142:   qp->dsteplength = PetscMin(0.95*tstep,1.0);

144:   qp->psteplength = PetscMin(qp->psteplength,qp->dsteplength);
145:   qp->dsteplength = qp->psteplength;
146:   return(0);
147: }

149: static PetscErrorCode QPIPComputeNormFromCentralPath(TAO_BQPIP *qp,PetscReal *norm)
150: {
152:   PetscReal      gap[2],mu[2],nmu;

155:   VecPointwiseMult(qp->GZwork,qp->G,qp->Z);
156:   VecPointwiseMult(qp->TSwork,qp->T,qp->S);
157:   VecNorm(qp->TSwork,NORM_1,&mu[0]);
158:   VecNorm(qp->GZwork,NORM_1,&mu[1]);

160:   nmu=-(mu[0]+mu[1])/qp->m;

162:   VecShift(qp->GZwork,nmu);
163:   VecShift(qp->TSwork,nmu);

165:   VecNorm(qp->GZwork,NORM_2,&gap[0]);
166:   VecNorm(qp->TSwork,NORM_2,&gap[1]);
167:   gap[0]*=gap[0];
168:   gap[1]*=gap[1];

170:   qp->pathnorm=PetscSqrtScalar(gap[0]+gap[1]);
171:   *norm=qp->pathnorm;
172:   return(0);
173: }

175: static PetscErrorCode QPIPComputeStepDirection(TAO_BQPIP *qp,Tao tao)
176: {

180:   /* Calculate DG */
181:   VecCopy(tao->stepdirection,qp->DG);
182:   VecAXPY(qp->DG,1.0,qp->R3);

184:   /* Calculate DT */
185:   VecCopy(tao->stepdirection,qp->DT);
186:   VecScale(qp->DT,-1.0);
187:   VecAXPY(qp->DT,-1.0,qp->R5);

189:   /* Calculate DZ */
190:   VecAXPY(qp->DZ,-1.0,qp->Z);
191:   VecPointwiseDivide(qp->GZwork,qp->DG,qp->G);
192:   VecPointwiseMult(qp->GZwork,qp->GZwork,qp->Z);
193:   VecAXPY(qp->DZ,-1.0,qp->GZwork);

195:   /* Calculate DS */
196:   VecAXPY(qp->DS,-1.0,qp->S);
197:   VecPointwiseDivide(qp->TSwork,qp->DT,qp->T);
198:   VecPointwiseMult(qp->TSwork,qp->TSwork,qp->S);
199:   VecAXPY(qp->DS,-1.0,qp->TSwork);
200:   return(0);
201: }

203: static PetscErrorCode TaoSetup_BQPIP(Tao tao)
204: {
205:   TAO_BQPIP      *qp =(TAO_BQPIP*)tao->data;

209:   /* Set pointers to Data */
210:   VecGetSize(tao->solution,&qp->n);

212:   /* Allocate some arrays */
213:   if (!tao->gradient) {
214:     VecDuplicate(tao->solution,&tao->gradient);
215:   }
216:   if (!tao->stepdirection) {
217:     VecDuplicate(tao->solution,&tao->stepdirection);
218:   }
219:   if (!tao->XL) {
220:     VecDuplicate(tao->solution,&tao->XL);
221:     VecSet(tao->XL,PETSC_NINFINITY);
222:   }
223:   if (!tao->XU) {
224:     VecDuplicate(tao->solution,&tao->XU);
225:     VecSet(tao->XU,PETSC_INFINITY);
226:   }

228:   VecDuplicate(tao->solution,&qp->Work);
229:   VecDuplicate(tao->solution,&qp->XU);
230:   VecDuplicate(tao->solution,&qp->XL);
231:   VecDuplicate(tao->solution,&qp->HDiag);
232:   VecDuplicate(tao->solution,&qp->DiagAxpy);
233:   VecDuplicate(tao->solution,&qp->RHS);
234:   VecDuplicate(tao->solution,&qp->RHS2);
235:   VecDuplicate(tao->solution,&qp->C);

237:   VecDuplicate(tao->solution,&qp->G);
238:   VecDuplicate(tao->solution,&qp->DG);
239:   VecDuplicate(tao->solution,&qp->S);
240:   VecDuplicate(tao->solution,&qp->Z);
241:   VecDuplicate(tao->solution,&qp->DZ);
242:   VecDuplicate(tao->solution,&qp->GZwork);
243:   VecDuplicate(tao->solution,&qp->R3);

245:   VecDuplicate(tao->solution,&qp->T);
246:   VecDuplicate(tao->solution,&qp->DT);
247:   VecDuplicate(tao->solution,&qp->DS);
248:   VecDuplicate(tao->solution,&qp->TSwork);
249:   VecDuplicate(tao->solution,&qp->R5);
250:   qp->m=2*qp->n;
251:   return(0);
252: }

254: static PetscErrorCode TaoSolve_BQPIP(Tao tao)
255: {
256:   TAO_BQPIP          *qp = (TAO_BQPIP*)tao->data;
257:   PetscErrorCode     ierr;
258:   PetscInt           its;
259:   PetscReal          d1,d2,ksptol,sigmamu;
260:   PetscReal          dstep,pstep,step=0;
261:   PetscReal          gap[4];
262:   PetscBool          getdiagop;
263:   TaoConvergedReason reason;

266:   qp->dobj        = 0.0;
267:   qp->pobj        = 1.0;
268:   qp->gap         = 10.0;
269:   qp->rgap        = 1.0;
270:   qp->mu          = 1.0;
271:   qp->dinfeas     = 1.0;
272:   qp->psteplength = 0.0;
273:   qp->dsteplength = 0.0;

275:   /* TODO
276:      - Remove fixed variables and treat them correctly
277:      - Use index sets for the infinite versus finite bounds
278:      - Update remaining code for fixed and free variables
279:      - Fix inexact solves for predictor and corrector
280:   */

282:   /* Tighten infinite bounds, things break when we don't do this
283:     -- see test_bqpip.c
284:   */
285:   TaoComputeVariableBounds(tao);
286:   VecSet(qp->XU,1.0e20);
287:   VecSet(qp->XL,-1.0e20);
288:   VecPointwiseMax(qp->XL,qp->XL,tao->XL);
289:   VecPointwiseMin(qp->XU,qp->XU,tao->XU);
290:   VecMedian(qp->XL,tao->solution,qp->XU,tao->solution);

292:   /* Evaluate gradient and Hessian at zero to get the correct values
293:      without contaminating them with numerical artifacts.
294:   */
295:   VecSet(qp->Work,0);
296:   TaoComputeObjectiveAndGradient(tao,qp->Work,&qp->d,qp->C);
297:   TaoComputeHessian(tao,qp->Work,tao->hessian,tao->hessian_pre);
298:   MatHasOperation(tao->hessian,MATOP_GET_DIAGONAL,&getdiagop);
299:   if (getdiagop) {
300:     MatGetDiagonal(tao->hessian,qp->HDiag);
301:   }

303:   /* Initialize starting point and residuals */
304:   QPIPSetInitialPoint(qp,tao);
305:   QPIPComputeResidual(qp,tao);

307:   /* Enter main loop */
308:   while (1) {

310:     /* Check Stopping Condition      */
311:     TaoMonitor(tao,tao->niter,qp->pobj,PetscSqrtScalar(qp->gap + qp->dinfeas),qp->pinfeas,step,&reason);
312:     if (reason != TAO_CONTINUE_ITERATING) break;
313:     tao->niter++;
314:     tao->ksp_its = 0;

316:     /*
317:        Dual Infeasibility Direction should already be in the right
318:        hand side from computing the residuals
319:     */

321:     QPIPComputeNormFromCentralPath(qp,&d1);

323:     VecSet(qp->DZ,0.0);
324:     VecSet(qp->DS,0.0);

326:     /*
327:        Compute the Primal Infeasiblitiy RHS and the
328:        Diagonal Matrix to be added to H and store in Work
329:     */
330:     VecPointwiseDivide(qp->DiagAxpy,qp->Z,qp->G);
331:     VecPointwiseMult(qp->GZwork,qp->DiagAxpy,qp->R3);
332:     VecAXPY(qp->RHS,-1.0,qp->GZwork);

334:     VecPointwiseDivide(qp->TSwork,qp->S,qp->T);
335:     VecAXPY(qp->DiagAxpy,1.0,qp->TSwork);
336:     VecPointwiseMult(qp->TSwork,qp->TSwork,qp->R5);
337:     VecAXPY(qp->RHS,-1.0,qp->TSwork);

339:     /*  Determine the solving tolerance */
340:     ksptol = qp->mu/10.0;
341:     ksptol = PetscMin(ksptol,0.001);
342:     KSPSetTolerances(tao->ksp,ksptol,1e-30,1e30,PetscMax(10,qp->n));

344:     /* Shift the diagonals of the Hessian matrix */
345:     MatDiagonalSet(tao->hessian,qp->DiagAxpy,ADD_VALUES);
346:     if (!getdiagop) {
347:       VecCopy(qp->DiagAxpy,qp->HDiag);
348:       VecScale(qp->HDiag,-1.0);
349:     }
350:     MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY);
351:     MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY);

353:     KSPSetOperators(tao->ksp,tao->hessian,tao->hessian_pre);
354:     KSPSolve(tao->ksp,qp->RHS,tao->stepdirection);
355:     KSPGetIterationNumber(tao->ksp,&its);
356:     tao->ksp_its += its;
357:     tao->ksp_tot_its += its;

359:     /* Restore the true diagonal of the Hessian matrix */
360:     if (getdiagop) {
361:       MatDiagonalSet(tao->hessian,qp->HDiag,INSERT_VALUES);
362:     } else {
363:       MatDiagonalSet(tao->hessian,qp->HDiag,ADD_VALUES);
364:     }
365:     MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY);
366:     MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY);
367:     QPIPComputeStepDirection(qp,tao);
368:     QPIPStepLength(qp);

370:     /* Calculate New Residual R1 in Work vector */
371:     MatMult(tao->hessian,tao->stepdirection,qp->RHS2);
372:     VecAXPY(qp->RHS2,1.0,qp->DS);
373:     VecAXPY(qp->RHS2,-1.0,qp->DZ);
374:     VecAYPX(qp->RHS2,qp->dsteplength,tao->gradient);

376:     VecNorm(qp->RHS2,NORM_2,&qp->dinfeas);
377:     VecDot(qp->DZ,qp->DG,gap);
378:     VecDot(qp->DS,qp->DT,gap+1);

380:     qp->rnorm = (qp->dinfeas+qp->psteplength*qp->pinfeas)/(qp->m+qp->n);
381:     pstep     = qp->psteplength;
382:     step      = PetscMin(qp->psteplength,qp->dsteplength);
383:     sigmamu   = (pstep*pstep*(gap[0]+gap[1]) + (1 - pstep)*qp->gap)/qp->m;

385:     if (qp->predcorr && step < 0.9) {
386:       if (sigmamu < qp->mu) {
387:         sigmamu = sigmamu/qp->mu;
388:         sigmamu = sigmamu*sigmamu*sigmamu;
389:       } else {
390:         sigmamu = 1.0;
391:       }
392:       sigmamu = sigmamu*qp->mu;

394:       /* Compute Corrector Step */
395:       VecPointwiseMult(qp->DZ,qp->DG,qp->DZ);
396:       VecScale(qp->DZ,-1.0);
397:       VecShift(qp->DZ,sigmamu);
398:       VecPointwiseDivide(qp->DZ,qp->DZ,qp->G);

400:       VecPointwiseMult(qp->DS,qp->DS,qp->DT);
401:       VecScale(qp->DS,-1.0);
402:       VecShift(qp->DS,sigmamu);
403:       VecPointwiseDivide(qp->DS,qp->DS,qp->T);

405:       VecCopy(qp->DZ,qp->RHS2);
406:       VecAXPY(qp->RHS2,-1.0,qp->DS);
407:       VecAXPY(qp->RHS2,1.0,qp->RHS);

409:       /* Approximately solve the linear system */
410:       MatDiagonalSet(tao->hessian,qp->DiagAxpy,ADD_VALUES);
411:       if (!getdiagop) {
412:         VecCopy(qp->DiagAxpy,qp->HDiag);
413:         VecScale(qp->HDiag,-1.0);
414:       }
415:       MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY);
416:       MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY);

418:       /* Solve using the previous tolerances that were set */
419:       KSPSolve(tao->ksp,qp->RHS2,tao->stepdirection);
420:       KSPGetIterationNumber(tao->ksp,&its);
421:       tao->ksp_its += its;
422:       tao->ksp_tot_its += its;

424:       if (getdiagop) {
425:         MatDiagonalSet(tao->hessian,qp->HDiag,INSERT_VALUES);
426:       } else {
427:         MatDiagonalSet(tao->hessian,qp->HDiag,ADD_VALUES);
428:       }
429:       MatAssemblyBegin(tao->hessian,MAT_FINAL_ASSEMBLY);
430:       MatAssemblyEnd(tao->hessian,MAT_FINAL_ASSEMBLY);
431:       QPIPComputeStepDirection(qp,tao);
432:       QPIPStepLength(qp);
433:     }  /* End Corrector step */


436:     /* Take the step */
437:     dstep = qp->dsteplength;

439:     VecAXPY(qp->Z,dstep,qp->DZ);
440:     VecAXPY(qp->S,dstep,qp->DS);
441:     VecAXPY(tao->solution,dstep,tao->stepdirection);
442:     VecAXPY(qp->G,dstep,qp->DG);
443:     VecAXPY(qp->T,dstep,qp->DT);

445:     /* Compute Residuals */
446:     QPIPComputeResidual(qp,tao);

448:     /* Evaluate quadratic function */
449:     MatMult(tao->hessian,tao->solution,qp->Work);

451:     VecDot(tao->solution,qp->Work,&d1);
452:     VecDot(tao->solution,qp->C,&d2);
453:     VecDot(qp->G,qp->Z,gap);
454:     VecDot(qp->T,qp->S,gap+1);

456:     /* Compute the duality gap */
457:     qp->pobj = d1/2.0 + d2+qp->d;
458:     qp->gap  = gap[0]+gap[1];
459:     qp->dobj = qp->pobj - qp->gap;
460:     if (qp->m > 0) {
461:       qp->mu = qp->gap/(qp->m);
462:     }
463:     qp->rgap = qp->gap/(PetscAbsReal(qp->dobj) + PetscAbsReal(qp->pobj) + 1.0);
464:   }  /* END MAIN LOOP  */
465:   return(0);
466: }

468: static PetscErrorCode TaoView_BQPIP(Tao tao,PetscViewer viewer)
469: {
471:   return(0);
472: }

474: static PetscErrorCode TaoSetFromOptions_BQPIP(PetscOptionItems *PetscOptionsObject,Tao tao)
475: {
476:   TAO_BQPIP      *qp = (TAO_BQPIP*)tao->data;

480:   PetscOptionsHead(PetscOptionsObject,"Interior point method for bound constrained quadratic optimization");
481:   PetscOptionsInt("-tao_bqpip_predcorr","Use a predictor-corrector method","",qp->predcorr,&qp->predcorr,0);
482:   PetscOptionsTail();
483:   KSPSetFromOptions(tao->ksp);
484:   return(0);
485: }

487: static PetscErrorCode TaoDestroy_BQPIP(Tao tao)
488: {
489:   TAO_BQPIP      *qp = (TAO_BQPIP*)tao->data;

493:   if (tao->setupcalled) {
494:     VecDestroy(&qp->G);
495:     VecDestroy(&qp->DG);
496:     VecDestroy(&qp->Z);
497:     VecDestroy(&qp->DZ);
498:     VecDestroy(&qp->GZwork);
499:     VecDestroy(&qp->R3);
500:     VecDestroy(&qp->S);
501:     VecDestroy(&qp->DS);
502:     VecDestroy(&qp->T);

504:     VecDestroy(&qp->DT);
505:     VecDestroy(&qp->TSwork);
506:     VecDestroy(&qp->R5);
507:     VecDestroy(&qp->HDiag);
508:     VecDestroy(&qp->Work);
509:     VecDestroy(&qp->XL);
510:     VecDestroy(&qp->XU);
511:     VecDestroy(&qp->DiagAxpy);
512:     VecDestroy(&qp->RHS);
513:     VecDestroy(&qp->RHS2);
514:     VecDestroy(&qp->C);
515:   }
516:   PetscFree(tao->data);
517:   return(0);
518: }

520: static PetscErrorCode TaoComputeDual_BQPIP(Tao tao,Vec DXL,Vec DXU)
521: {
522:   TAO_BQPIP       *qp = (TAO_BQPIP*)tao->data;
523:   PetscErrorCode  ierr;

526:   VecCopy(qp->Z,DXL);
527:   VecCopy(qp->S,DXU);
528:   VecScale(DXU,-1.0);
529:   return(0);
530: }

532: /*MC
533:  TAOBQPIP - interior-point method for quadratic programs with
534:     box constraints.

536:  Notes: This algorithms solves quadratic problems only, the Hessian will
537:         only be computed once.

539:  Options Database Keys:
540: . -tao_bqpip_predcorr - use a predictor/corrector method

542:   Level: beginner
543: M*/

545: PETSC_EXTERN PetscErrorCode TaoCreate_BQPIP(Tao tao)
546: {
547:   TAO_BQPIP      *qp;

551:   PetscNewLog(tao,&qp);

553:   tao->ops->setup = TaoSetup_BQPIP;
554:   tao->ops->solve = TaoSolve_BQPIP;
555:   tao->ops->view = TaoView_BQPIP;
556:   tao->ops->setfromoptions = TaoSetFromOptions_BQPIP;
557:   tao->ops->destroy = TaoDestroy_BQPIP;
558:   tao->ops->computedual = TaoComputeDual_BQPIP;

560:   /* Override default settings (unless already changed) */
561:   if (!tao->max_it_changed) tao->max_it=100;
562:   if (!tao->max_funcs_changed) tao->max_funcs = 500;
563: #if defined(PETSC_USE_REAL_SINGLE)
564:   if (!tao->catol_changed) tao->catol=1e-6;
565: #else
566:   if (!tao->catol_changed) tao->catol=1e-12;
567: #endif

569:   /* Initialize pointers and variables */
570:   qp->n = 0;
571:   qp->m = 0;

573:   qp->predcorr = 1;
574:   tao->data    = (void*)qp;

576:   KSPCreate(((PetscObject)tao)->comm,&tao->ksp);
577:   KSPSetOptionsPrefix(tao->ksp,tao->hdr.prefix);
578:   KSPSetType(tao->ksp,KSPCG);
579:   KSPSetTolerances(tao->ksp,1e-14,1e-30,1e30,PetscMax(10,qp->n));
580:   return(0);
581: }