Date: 2022-03-04T17:39:48+00:00

Actual source code: taosolver_fg.c

      1: #include <petsc/private/taoimpl.h>

      3: /*@
      4:   TaoSetInitialVector - Sets the initial guess for the solve

      6:   Logically collective on Tao

      8:   Input Parameters:
      9: + tao - the Tao context
     10: - x0  - the initial guess

     12:   Level: beginner
     13: .seealso: TaoCreate(), TaoSolve()
     14: @*/

     16: PetscErrorCode TaoSetInitialVector(Tao tao, Vec x0)
     17: {

     22:   if (x0) {
     24:     PetscObjectReference((PetscObject)x0);
     25:   }
     26:   VecDestroy(&tao->solution);
     27:   tao->solution = x0;
     28:   return(0);
     29: }

     31: PetscErrorCode TaoTestGradient(Tao tao,Vec x,Vec g1)
     32: {
     33:   Vec               g2,g3;
     34:   PetscBool         complete_print = PETSC_FALSE,test = PETSC_FALSE;
     35:   PetscReal         hcnorm,fdnorm,hcmax,fdmax,diffmax,diffnorm;
     36:   PetscScalar       dot;
     37:   MPI_Comm          comm;
     38:   PetscViewer       viewer,mviewer;
     39:   PetscViewerFormat format;
     40:   PetscInt          tabs;
     41:   static PetscBool  directionsprinted = PETSC_FALSE;
     42:   PetscErrorCode    ierr;

     45:   PetscObjectOptionsBegin((PetscObject)tao);
     46:   PetscOptionsName("-tao_test_gradient","Compare hand-coded and finite difference Gradients","None",&test);
     47:   PetscOptionsViewer("-tao_test_gradient_view","View difference between hand-coded and finite difference Gradients element entries","None",&mviewer,&format,&complete_print);
     48:   PetscOptionsEnd();
     49:   if (!test) {
     50:     if (complete_print) {
     51:       PetscViewerDestroy(&mviewer);
     52:     }
     53:     return(0);
     54:   }

     56:   PetscObjectGetComm((PetscObject)tao,&comm);
     57:   PetscViewerASCIIGetStdout(comm,&viewer);
     58:   PetscViewerASCIIGetTab(viewer, &tabs);
     59:   PetscViewerASCIISetTab(viewer, ((PetscObject)tao)->tablevel);
     60:   PetscViewerASCIIPrintf(viewer,"  ---------- Testing Gradient -------------\n");
     61:   if (!complete_print && !directionsprinted) {
     62:     PetscViewerASCIIPrintf(viewer,"  Run with -tao_test_gradient_view and optionally -tao_test_gradient <threshold> to show difference\n");
     63:     PetscViewerASCIIPrintf(viewer,"    of hand-coded and finite difference gradient entries greater than <threshold>.\n");
     64:   }
     65:   if (!directionsprinted) {
     66:     PetscViewerASCIIPrintf(viewer,"  Testing hand-coded Gradient, if (for double precision runs) ||G - Gfd||/||G|| is\n");
     67:     PetscViewerASCIIPrintf(viewer,"    O(1.e-8), the hand-coded Gradient is probably correct.\n");
     68:     directionsprinted = PETSC_TRUE;
     69:   }
     70:   if (complete_print) {
     71:     PetscViewerPushFormat(mviewer,format);
     72:   }

     74:   VecDuplicate(x,&g2);
     75:   VecDuplicate(x,&g3);

     77:   /* Compute finite difference gradient, assume the gradient is already computed by TaoComputeGradient() and put into g1 */
     78:   TaoDefaultComputeGradient(tao,x,g2,NULL);

     80:   VecNorm(g2,NORM_2,&fdnorm);
     81:   VecNorm(g1,NORM_2,&hcnorm);
     82:   VecNorm(g2,NORM_INFINITY,&fdmax);
     83:   VecNorm(g1,NORM_INFINITY,&hcmax);
     84:   VecDot(g1,g2,&dot);
     85:   VecCopy(g1,g3);
     86:   VecAXPY(g3,-1.0,g2);
     87:   VecNorm(g3,NORM_2,&diffnorm);
     88:   VecNorm(g3,NORM_INFINITY,&diffmax);
     89:   PetscViewerASCIIPrintf(viewer,"  ||Gfd|| %g, ||G|| = %g, angle cosine = (Gfd'G)/||Gfd||||G|| = %g\n", (double)fdnorm, (double)hcnorm, (double)(PetscRealPart(dot)/(fdnorm*hcnorm)));
     90:   PetscViewerASCIIPrintf(viewer,"  2-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffnorm/PetscMax(hcnorm,fdnorm)),(double)diffnorm);
     91:   PetscViewerASCIIPrintf(viewer,"  max-norm ||G - Gfd||/||G|| = %g, ||G - Gfd|| = %g\n",(double)(diffmax/PetscMax(hcmax,fdmax)),(double)diffmax);

     93:   if (complete_print) {
     94:     PetscViewerASCIIPrintf(viewer,"  Hand-coded gradient ----------\n");
     95:     VecView(g1,mviewer);
     96:     PetscViewerASCIIPrintf(viewer,"  Finite difference gradient ----------\n");
     97:     VecView(g2,mviewer);
     98:     PetscViewerASCIIPrintf(viewer,"  Hand-coded minus finite-difference gradient ----------\n");
     99:     VecView(g3,mviewer);
    100:   }
    101:   VecDestroy(&g2);
    102:   VecDestroy(&g3);

    104:   if (complete_print) {
    105:     PetscViewerPopFormat(mviewer);
    106:     PetscViewerDestroy(&mviewer);
    107:   }
    108:   PetscViewerASCIISetTab(viewer,tabs);
    109:   return(0);
    110: }

    112: /*@
    113:   TaoComputeGradient - Computes the gradient of the objective function

    115:   Collective on Tao

    117:   Input Parameters:
    118: + tao - the Tao context
    119: - X - input vector

    121:   Output Parameter:
    122: . G - gradient vector

    124:   Options Database Keys:
    125: +    -tao_test_gradient - compare the user provided gradient with one compute via finite differences to check for errors
    126: -    -tao_test_gradient_view - display the user provided gradient, the finite difference gradient and the difference between them to help users detect the location of errors in the user provided gradient

    128:   Notes:
    129:     TaoComputeGradient() is typically used within minimization implementations,
    130:   so most users would not generally call this routine themselves.

    132:   Level: advanced

    134: .seealso: TaoComputeObjective(), TaoComputeObjectiveAndGradient(), TaoSetGradientRoutine()
    135: @*/
    136: PetscErrorCode TaoComputeGradient(Tao tao, Vec X, Vec G)
    137: {
    139:   PetscReal      dummy;

    147:   VecLockReadPush(X);
    148:   if (tao->ops->computegradient) {
    149:     PetscLogEventBegin(TAO_GradientEval,tao,X,G,NULL);
    150:     PetscStackPush("Tao user gradient evaluation routine");
    151:     (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);
    152:     PetscStackPop;
    153:     PetscLogEventEnd(TAO_GradientEval,tao,X,G,NULL);
    154:     tao->ngrads++;
    155:   } else if (tao->ops->computeobjectiveandgradient) {
    156:     PetscLogEventBegin(TAO_ObjGradEval,tao,X,G,NULL);
    157:     PetscStackPush("Tao user objective/gradient evaluation routine");
    158:     (*tao->ops->computeobjectiveandgradient)(tao,X,&dummy,G,tao->user_objgradP);
    159:     PetscStackPop;
    160:     PetscLogEventEnd(TAO_ObjGradEval,tao,X,G,NULL);
    161:     tao->nfuncgrads++;
    162:   } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetGradientRoutine() has not been called");
    163:   VecLockReadPop(X);

    165:   TaoTestGradient(tao,X,G);
    166:   return(0);
    167: }

    169: /*@
    170:   TaoComputeObjective - Computes the objective function value at a given point

    172:   Collective on Tao

    174:   Input Parameters:
    175: + tao - the Tao context
    176: - X - input vector

    178:   Output Parameter:
    179: . f - Objective value at X

    181:   Notes:
    182:     TaoComputeObjective() is typically used within minimization implementations,
    183:   so most users would not generally call this routine themselves.

    185:   Level: advanced

    187: .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjectiveRoutine()
    188: @*/
    189: PetscErrorCode TaoComputeObjective(Tao tao, Vec X, PetscReal *f)
    190: {
    192:   Vec            temp;

    198:   VecLockReadPush(X);
    199:   if (tao->ops->computeobjective) {
    200:     PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
    201:     PetscStackPush("Tao user objective evaluation routine");
    202:     (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);
    203:     PetscStackPop;
    204:     PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
    205:     tao->nfuncs++;
    206:   } else if (tao->ops->computeobjectiveandgradient) {
    207:     PetscInfo(tao,"Duplicating variable vector in order to call func/grad routine\n");
    208:     VecDuplicate(X,&temp);
    209:     PetscLogEventBegin(TAO_ObjGradEval,tao,X,NULL,NULL);
    210:     PetscStackPush("Tao user objective/gradient evaluation routine");
    211:     (*tao->ops->computeobjectiveandgradient)(tao,X,f,temp,tao->user_objgradP);
    212:     PetscStackPop;
    213:     PetscLogEventEnd(TAO_ObjGradEval,tao,X,NULL,NULL);
    214:     VecDestroy(&temp);
    215:     tao->nfuncgrads++;
    216:   }  else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjectiveRoutine() has not been called");
    217:   PetscInfo1(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));
    218:   VecLockReadPop(X);
    219:   return(0);
    220: }

    222: /*@
    223:   TaoComputeObjectiveAndGradient - Computes the objective function value at a given point

    225:   Collective on Tao

    227:   Input Parameters:
    228: + tao - the Tao context
    229: - X - input vector

    231:   Output Parameters:
    232: + f - Objective value at X
    233: - g - Gradient vector at X

    235:   Notes:
    236:     TaoComputeObjectiveAndGradient() is typically used within minimization implementations,
    237:   so most users would not generally call this routine themselves.

    239:   Level: advanced

    241: .seealso: TaoComputeGradient(), TaoComputeObjectiveAndGradient(), TaoSetObjectiveRoutine()
    242: @*/
    243: PetscErrorCode TaoComputeObjectiveAndGradient(Tao tao, Vec X, PetscReal *f, Vec G)
    244: {

    253:   VecLockReadPush(X);
    254:   if (tao->ops->computeobjectiveandgradient) {
    255:     PetscLogEventBegin(TAO_ObjGradEval,tao,X,G,NULL);
    256:     if (tao->ops->computegradient == TaoDefaultComputeGradient) {
    257:       TaoComputeObjective(tao,X,f);
    258:       TaoDefaultComputeGradient(tao,X,G,NULL);
    259:     } else {
    260:       PetscStackPush("Tao user objective/gradient evaluation routine");
    261:       (*tao->ops->computeobjectiveandgradient)(tao,X,f,G,tao->user_objgradP);
    262:       PetscStackPop;
    263:     }
    264:     PetscLogEventEnd(TAO_ObjGradEval,tao,X,G,NULL);
    265:     tao->nfuncgrads++;
    266:   } else if (tao->ops->computeobjective && tao->ops->computegradient) {
    267:     PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
    268:     PetscStackPush("Tao user objective evaluation routine");
    269:     (*tao->ops->computeobjective)(tao,X,f,tao->user_objP);
    270:     PetscStackPop;
    271:     PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
    272:     tao->nfuncs++;
    273:     PetscLogEventBegin(TAO_GradientEval,tao,X,G,NULL);
    274:     PetscStackPush("Tao user gradient evaluation routine");
    275:     (*tao->ops->computegradient)(tao,X,G,tao->user_gradP);
    276:     PetscStackPop;
    277:     PetscLogEventEnd(TAO_GradientEval,tao,X,G,NULL);
    278:     tao->ngrads++;
    279:   } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetObjectiveRoutine() or TaoSetGradientRoutine() not set");
    280:   PetscInfo1(tao,"TAO Function evaluation: %20.19e\n",(double)(*f));
    281:   VecLockReadPop(X);

    283:   TaoTestGradient(tao,X,G);
    284:   return(0);
    285: }

    287: /*@C
    288:   TaoSetObjectiveRoutine - Sets the function evaluation routine for minimization

    290:   Logically collective on Tao

    292:   Input Parameters:
    293: + tao - the Tao context
    294: . func - the objective function
    295: - ctx - [optional] user-defined context for private data for the function evaluation
    296:         routine (may be NULL)

    298:   Calling sequence of func:
    299: $      func (Tao tao, Vec x, PetscReal *f, void *ctx);

    301: + x - input vector
    302: . f - function value
    303: - ctx - [optional] user-defined function context

    305:   Level: beginner

    307: .seealso: TaoSetGradientRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
    308: @*/
    309: PetscErrorCode TaoSetObjectiveRoutine(Tao tao, PetscErrorCode (*func)(Tao, Vec, PetscReal*,void*),void *ctx)
    310: {
    313:   tao->user_objP = ctx;
    314:   tao->ops->computeobjective = func;
    315:   return(0);
    316: }

    318: /*@C
    319:   TaoSetResidualRoutine - Sets the residual evaluation routine for least-square applications

    321:   Logically collective on Tao

    323:   Input Parameters:
    324: + tao - the Tao context
    325: . func - the residual evaluation routine
    326: - ctx - [optional] user-defined context for private data for the function evaluation
    327:         routine (may be NULL)

    329:   Calling sequence of func:
    330: $      func (Tao tao, Vec x, Vec f, void *ctx);

    332: + x - input vector
    333: . f - function value vector
    334: - ctx - [optional] user-defined function context

    336:   Level: beginner

    338: .seealso: TaoSetObjectiveRoutine(), TaoSetJacobianRoutine()
    339: @*/
    340: PetscErrorCode TaoSetResidualRoutine(Tao tao, Vec res, PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
    341: {

    347:   PetscObjectReference((PetscObject)res);
    348:   if (tao->ls_res) {
    349:     VecDestroy(&tao->ls_res);
    350:   }
    351:   tao->ls_res = res;
    352:   tao->user_lsresP = ctx;
    353:   tao->ops->computeresidual = func;

    355:   return(0);
    356: }

    358: /*@
    359:   TaoSetResidualWeights - Give weights for the residual values. A vector can be used if only diagonal terms are used, otherwise a matrix can be give. If this function is not used, or if sigma_v and sigma_w are both NULL, then the default identity matrix will be used for weights.

    361:   Collective on Tao

    363:   Input Parameters:
    364: + tao - the Tao context
    365: . sigma_v - vector of weights (diagonal terms only)
    366: . n       - the number of weights (if using off-diagonal)
    367: . rows    - index list of rows for sigma_w
    368: . cols    - index list of columns for sigma_w
    369: - vals - array of weights

    371:   Note: Either sigma_v or sigma_w (or both) should be NULL

    373:   Level: intermediate

    375: .seealso: TaoSetResidualRoutine()
    376: @*/
    377: PetscErrorCode TaoSetResidualWeights(Tao tao, Vec sigma_v, PetscInt n, PetscInt *rows, PetscInt *cols, PetscReal *vals)
    378: {
    380:   PetscInt       i;
    383:   if (sigma_v) {
    385:     PetscObjectReference((PetscObject)sigma_v);
    386:   }
    387:   if (tao->res_weights_v) {
    388:     VecDestroy(&tao->res_weights_v);
    389:   }
    390:   tao->res_weights_v=sigma_v;
    391:   if (vals) {
    392:     if (tao->res_weights_n) {
    393:       PetscFree(tao->res_weights_rows);
    394:       PetscFree(tao->res_weights_cols);
    395:       PetscFree(tao->res_weights_w);
    396:     }
    397:     PetscMalloc1(n,&tao->res_weights_rows);
    398:     PetscMalloc1(n,&tao->res_weights_cols);
    399:     PetscMalloc1(n,&tao->res_weights_w);
    400:     tao->res_weights_n=n;
    401:     for (i=0;i<n;i++) {
    402:       tao->res_weights_rows[i]=rows[i];
    403:       tao->res_weights_cols[i]=cols[i];
    404:       tao->res_weights_w[i]=vals[i];
    405:     }
    406:   } else {
    407:     tao->res_weights_n=0;
    408:     tao->res_weights_rows=NULL;
    409:     tao->res_weights_cols=NULL;
    410:   }
    411:   return(0);
    412: }

    414: /*@
    415:   TaoComputeResidual - Computes a least-squares residual vector at a given point

    417:   Collective on Tao

    419:   Input Parameters:
    420: + tao - the Tao context
    421: - X - input vector

    423:   Output Parameter:
    424: . f - Objective vector at X

    426:   Notes:
    427:     TaoComputeResidual() is typically used within minimization implementations,
    428:   so most users would not generally call this routine themselves.

    430:   Level: advanced

    432: .seealso: TaoSetResidualRoutine()
    433: @*/
    434: PetscErrorCode TaoComputeResidual(Tao tao, Vec X, Vec F)
    435: {

    444:   if (tao->ops->computeresidual) {
    445:     PetscLogEventBegin(TAO_ObjectiveEval,tao,X,NULL,NULL);
    446:     PetscStackPush("Tao user least-squares residual evaluation routine");
    447:     (*tao->ops->computeresidual)(tao,X,F,tao->user_lsresP);
    448:     PetscStackPop;
    449:     PetscLogEventEnd(TAO_ObjectiveEval,tao,X,NULL,NULL);
    450:     tao->nfuncs++;
    451:   } else SETERRQ(PetscObjectComm((PetscObject)tao),PETSC_ERR_ARG_WRONGSTATE,"TaoSetResidualRoutine() has not been called");
    452:   PetscInfo(tao,"TAO least-squares residual evaluation.\n");
    453:   return(0);
    454: }

    456: /*@C
    457:   TaoSetGradientRoutine - Sets the gradient evaluation routine for minimization

    459:   Logically collective on Tao

    461:   Input Parameters:
    462: + tao - the Tao context
    463: . func - the gradient function
    464: - ctx - [optional] user-defined context for private data for the gradient evaluation
    465:         routine (may be NULL)

    467:   Calling sequence of func:
    468: $      func (Tao tao, Vec x, Vec g, void *ctx);

    470: + x - input vector
    471: . g - gradient value (output)
    472: - ctx - [optional] user-defined function context

    474:   Level: beginner

    476: .seealso: TaoSetObjectiveRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
    477: @*/
    478: PetscErrorCode TaoSetGradientRoutine(Tao tao, PetscErrorCode (*func)(Tao, Vec, Vec, void*),void *ctx)
    479: {
    482:   tao->user_gradP = ctx;
    483:   tao->ops->computegradient = func;
    484:   return(0);
    485: }

    487: /*@C
    488:   TaoSetObjectiveAndGradientRoutine - Sets a combined objective function and gradient evaluation routine for minimization

    490:   Logically collective on Tao

    492:   Input Parameters:
    493: + tao - the Tao context
    494: . func - the gradient function
    495: - ctx - [optional] user-defined context for private data for the gradient evaluation
    496:         routine (may be NULL)

    498:   Calling sequence of func:
    499: $      func (Tao tao, Vec x, PetscReal *f, Vec g, void *ctx);

    501: + x - input vector
    502: . f - objective value (output)
    503: . g - gradient value (output)
    504: - ctx - [optional] user-defined function context

    506:   Level: beginner

    508: .seealso: TaoSetObjectiveRoutine(), TaoSetHessianRoutine() TaoSetObjectiveAndGradientRoutine()
    509: @*/
    510: PetscErrorCode TaoSetObjectiveAndGradientRoutine(Tao tao, PetscErrorCode (*func)(Tao, Vec, PetscReal *, Vec, void*), void *ctx)
    511: {
    514:   tao->user_objgradP = ctx;
    515:   tao->ops->computeobjectiveandgradient = func;
    516:   return(0);
    517: }

    519: /*@
    520:   TaoIsObjectiveDefined -- Checks to see if the user has
    521:   declared an objective-only routine.  Useful for determining when
    522:   it is appropriate to call TaoComputeObjective() or
    523:   TaoComputeObjectiveAndGradient()

    525:   Collective on Tao

    527:   Input Parameters:
    528: + tao - the Tao context
    529: - ctx - PETSC_TRUE if objective function routine is set by user,
    530:         PETSC_FALSE otherwise
    531:   Level: developer

    533: .seealso: TaoSetObjectiveRoutine(), TaoIsGradientDefined(), TaoIsObjectiveAndGradientDefined()
    534: @*/
    535: PetscErrorCode TaoIsObjectiveDefined(Tao tao, PetscBool *flg)
    536: {
    539:   if (tao->ops->computeobjective == NULL) *flg = PETSC_FALSE;
    540:   else *flg = PETSC_TRUE;
    541:   return(0);
    542: }

    544: /*@
    545:   TaoIsGradientDefined -- Checks to see if the user has
    546:   declared an objective-only routine.  Useful for determining when
    547:   it is appropriate to call TaoComputeGradient() or
    548:   TaoComputeGradientAndGradient()

    550:   Not Collective

    552:   Input Parameters:
    553: + tao - the Tao context
    554: - ctx - PETSC_TRUE if gradient routine is set by user, PETSC_FALSE otherwise
    555:   Level: developer

    557: .seealso: TaoSetGradientRoutine(), TaoIsObjectiveDefined(), TaoIsObjectiveAndGradientDefined()
    558: @*/
    559: PetscErrorCode TaoIsGradientDefined(Tao tao, PetscBool *flg)
    560: {
    563:   if (tao->ops->computegradient == NULL) *flg = PETSC_FALSE;
    564:   else *flg = PETSC_TRUE;
    565:   return(0);
    566: }

    568: /*@
    569:   TaoIsObjectiveAndGradientDefined -- Checks to see if the user has
    570:   declared a joint objective/gradient routine.  Useful for determining when
    571:   it is appropriate to call TaoComputeObjective() or
    572:   TaoComputeObjectiveAndGradient()

    574:   Not Collective

    576:   Input Parameters:
    577: + tao - the Tao context
    578: - ctx - PETSC_TRUE if objective/gradient routine is set by user, PETSC_FALSE otherwise
    579:   Level: developer

    581: .seealso: TaoSetObjectiveAndGradientRoutine(), TaoIsObjectiveDefined(), TaoIsGradientDefined()
    582: @*/
    583: PetscErrorCode TaoIsObjectiveAndGradientDefined(Tao tao, PetscBool *flg)
    584: {
    587:   if (tao->ops->computeobjectiveandgradient == NULL) *flg = PETSC_FALSE;
    588:   else *flg = PETSC_TRUE;
    589:   return(0);
    590: }