Actual source code: taotermquadratic.c

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

      3: typedef struct _n_TaoTerm_Quadratic TaoTerm_Quadratic;

      5: struct _n_TaoTerm_Quadratic {
      6:   Mat A;
      7:   Vec _diff;
      8:   Vec Adiff;
      9: };

     11: static PetscErrorCode TaoTermDestroy_Quadratic(TaoTerm term)
     12: {
     13:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;

     15:   PetscFunctionBegin;
     16:   PetscCall(MatDestroy(&quad->A));
     17:   PetscCall(VecDestroy(&quad->_diff));
     18:   PetscCall(VecDestroy(&quad->Adiff));
     19:   PetscCall(PetscFree(quad));
     20:   term->data = NULL;
     21:   PetscCall(TaoTermDestroy_ElementwiseDivergence_Internal(term));
     22:   PetscCall(PetscObjectComposeFunction((PetscObject)term, "TaoTermQuadraticSetMat_C", NULL));
     23:   PetscCall(PetscObjectComposeFunction((PetscObject)term, "TaoTermQuadraticGetMat_C", NULL));
     24:   PetscFunctionReturn(PETSC_SUCCESS);
     25: }

     27: static PetscErrorCode TaoTermView_Quadratic(TaoTerm term, PetscViewer viewer)
     28: {
     29:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;

     31:   PetscFunctionBegin;
     32:   if (quad->A) {
     33:     PetscBool iascii;

     35:     PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &iascii));

     37:     if (iascii) {
     38:       PetscViewerFormat format;
     39:       PetscBool         pop = PETSC_FALSE;

     41:       PetscCall(PetscViewerGetFormat(viewer, &format));
     42:       if (format != PETSC_VIEWER_ASCII_INFO_DETAIL) {
     43:         PetscCall(PetscViewerPushFormat(viewer, PETSC_VIEWER_ASCII_INFO));
     44:         pop = PETSC_TRUE;
     45:       }
     46:       PetscCall(MatView(quad->A, viewer));
     47:       if (pop) PetscCall(PetscViewerPopFormat(viewer));
     48:     }
     49:   }
     50:   PetscFunctionReturn(PETSC_SUCCESS);
     51: }

     53: static PetscErrorCode TaoTermQuadraticDiff(TaoTerm term, Vec x, Vec params, Vec *diff)
     54: {
     55:   PetscFunctionBegin;
     56:   *diff = x;
     57:   if (params) {
     58:     TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;
     59:     if (quad->_diff == NULL) PetscCall(VecDuplicate(x, &quad->_diff));
     60:     PetscCall(VecCopy(x, quad->_diff));
     61:     PetscCall(VecAXPY(quad->_diff, -1.0, params));
     62:     *diff = quad->_diff;
     63:   }
     64:   PetscFunctionReturn(PETSC_SUCCESS);
     65: }

     67: static PetscErrorCode TaoTermComputeObjective_Quadratic(TaoTerm term, Vec x, Vec params, PetscReal *value)
     68: {
     69:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;
     70:   Vec                diff;
     71:   PetscScalar        sval;

     73:   PetscFunctionBegin;
     74:   PetscCheck(quad->A, PetscObjectComm((PetscObject)term), PETSC_ERR_ORDER, "Quadratic matrix not set, call TaoTermQuadraticSetMat() first");
     75:   PetscCall(TaoTermQuadraticDiff(term, x, params, &diff));
     76:   if (quad->Adiff == NULL) PetscCall(VecDuplicate(diff, &quad->Adiff));
     77:   PetscCall(MatMult(quad->A, diff, quad->Adiff));
     78:   PetscCall(VecDot(diff, quad->Adiff, &sval));
     79:   *value = 0.5 * PetscRealPart(sval);
     80:   PetscFunctionReturn(PETSC_SUCCESS);
     81: }

     83: static PetscErrorCode TaoTermComputeGradient_Quadratic(TaoTerm term, Vec x, Vec params, Vec g)
     84: {
     85:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;
     86:   Vec                diff;

     88:   PetscFunctionBegin;
     89:   PetscCheck(quad->A, PetscObjectComm((PetscObject)term), PETSC_ERR_ORDER, "Quadratic matrix not set, call TaoTermQuadraticSetMat() first");
     90:   PetscCall(TaoTermQuadraticDiff(term, x, params, &diff));
     91:   PetscCall(MatMult(quad->A, diff, g));
     92:   PetscFunctionReturn(PETSC_SUCCESS);
     93: }

     95: static PetscErrorCode TaoTermComputeObjectiveAndGradient_Quadratic(TaoTerm term, Vec x, Vec params, PetscReal *value, Vec g)
     96: {
     97:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;
     98:   Vec                diff;
     99:   PetscScalar        sval;

    101:   PetscFunctionBegin;
    102:   PetscCheck(quad->A, PetscObjectComm((PetscObject)term), PETSC_ERR_ORDER, "Quadratic matrix not set, call TaoTermQuadraticSetMat() first");
    103:   PetscCall(TaoTermQuadraticDiff(term, x, params, &diff));
    104:   PetscCall(MatMult(quad->A, diff, g));
    105:   PetscCall(VecDot(diff, g, &sval));
    106:   *value = 0.5 * PetscRealPart(sval);
    107:   PetscFunctionReturn(PETSC_SUCCESS);
    108: }

    110: static PetscErrorCode TaoTermComputeHessian_Quadratic(TaoTerm term, Vec x, Vec params, Mat H, Mat Hpre)
    111: {
    112:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;

    114:   PetscFunctionBegin;
    115:   PetscCheck(quad->A, PetscObjectComm((PetscObject)term), PETSC_ERR_ORDER, "Quadratic matrix not set, call TaoTermQuadraticSetMat() first");
    116:   // TODO caching to avoid unnecessary computation
    117:   if (H) PetscCall(MatCopy(quad->A, H, UNKNOWN_NONZERO_PATTERN));
    118:   if (Hpre && Hpre != H) PetscCall(MatCopy(quad->A, Hpre, UNKNOWN_NONZERO_PATTERN));
    119:   PetscFunctionReturn(PETSC_SUCCESS);
    120: }

    122: static PetscErrorCode TaoTermCreateHessianMatrices_Quadratic(TaoTerm term, Mat *H, Mat *Hpre)
    123: {
    124:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;

    126:   PetscFunctionBegin;
    127:   PetscCheck(quad->A, PetscObjectComm((PetscObject)term), PETSC_ERR_ORDER, "Quadratic matrix not set, call TaoTermQuadraticSetMat() first");
    128:   PetscCall(PetscInfo(term, "%s: Creating TAOTERMQUADRATIC Hessian Matrices by duplicating quadratic matrix set by TaoTermQuadraticSetMat, overriding custom MatType options.\n", ((PetscObject)term)->prefix));
    129:   if (H) PetscCall(MatDuplicate(quad->A, MAT_DO_NOT_COPY_VALUES, H));
    130:   if (Hpre) {
    131:     if (term->Hpre_is_H && H) {
    132:       PetscCall(PetscObjectReference((PetscObject)*H));
    133:       *Hpre = *H;
    134:     } else PetscCall(MatDuplicate(quad->A, MAT_DO_NOT_COPY_VALUES, Hpre));
    135:   }
    136:   PetscFunctionReturn(PETSC_SUCCESS);
    137: }

    139: /*@
    140:   TaoTermQuadraticGetMat - Get the matrix defining a `TaoTerm` of type `TAOTERMQUADRATIC`

    142:   Not collective

    144:   Input Parameter:
    145: . term - a `TaoTerm` of type `TAOTERMQUADRATIC`

    147:   Output Parameter:
    148: . A - the matrix

    150:   Level: intermediate

    152:   Note:
    153:   This function will return `NULL` if the term is not a `TAOTERMQUADRATIC`.

    155: .seealso: [](sec_tao_term),
    156:           `TaoTerm`,
    157:           `TAOTERMQUADRATIC`,
    158:           `TaoTermQuadraticSetMat()`
    159: @*/
    160: PetscErrorCode TaoTermQuadraticGetMat(TaoTerm term, Mat *A)
    161: {
    162:   PetscFunctionBegin;
    164:   PetscAssertPointer(A, 2);
    165:   *A = NULL;
    166:   PetscTryMethod(term, "TaoTermQuadraticGetMat_C", (TaoTerm, Mat *), (term, A));
    167:   PetscFunctionReturn(PETSC_SUCCESS);
    168: }

    170: static PetscErrorCode TaoTermQuadraticGetMat_Quadratic(TaoTerm term, Mat *A)
    171: {
    172:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;

    174:   PetscFunctionBegin;
    175:   *A = quad->A;
    176:   PetscFunctionReturn(PETSC_SUCCESS);
    177: }

    179: /*@
    180:   TaoTermQuadraticSetMat - Set the matrix defining a `TaoTerm` of type `TAOTERMQUADRATIC`

    182:   Collective

    184:   Input Parameters:
    185: + term - a `TaoTerm` of type `TAOTERMQUADRATIC`
    186: - A    - the matrix

    188:   Level: intermediate

    190: .seealso: [](sec_tao_term),
    191:           `TaoTerm`,
    192:           `TAOTERMQUADRATIC`,
    193:           `TaoTermQuadraticGetMat()`
    194: @*/
    195: PetscErrorCode TaoTermQuadraticSetMat(TaoTerm term, Mat A)
    196: {
    197:   PetscFunctionBegin;
    200:   PetscCheckSameComm(term, 1, A, 2);
    201:   PetscTryMethod(term, "TaoTermQuadraticSetMat_C", (TaoTerm, Mat), (term, A));
    202:   PetscFunctionReturn(PETSC_SUCCESS);
    203: }

    205: static PetscErrorCode TaoTermQuadraticSetMat_Quadratic(TaoTerm term, Mat A)
    206: {
    207:   TaoTerm_Quadratic *quad = (TaoTerm_Quadratic *)term->data;
    208:   PetscLayout        rmap, cmap;
    209:   VecType            vec_type;
    210:   PetscBool          is_square;

    212:   PetscFunctionBegin;
    213:   if (A != quad->A) {
    214:     MatType mat_type;
    215:     PetscCall(MatGetLayouts(A, &rmap, &cmap));
    216:     PetscCall(PetscLayoutCompare(rmap, cmap, &is_square));
    217:     PetscCheck(is_square, PetscObjectComm((PetscObject)A), PETSC_ERR_ARG_SIZ, "Matrix for quadratic term must be square");
    218:     PetscCall(PetscObjectReference((PetscObject)A));
    219:     PetscCall(MatDestroy(&quad->A));
    220:     PetscCall(VecDestroy(&quad->_diff));
    221:     PetscCall(VecDestroy(&quad->Adiff));
    222:     quad->A = A;
    223:     PetscCall(MatGetVecType(A, &vec_type));
    224:     PetscCall(TaoTermSetSolutionVecType(term, vec_type));
    225:     PetscCall(TaoTermSetParametersVecType(term, vec_type));
    226:     PetscCall(TaoTermSetSolutionLayout(term, rmap));
    227:     PetscCall(TaoTermSetParametersLayout(term, rmap));
    228:     PetscCall(PetscFree(term->H_mattype));
    229:     PetscCall(PetscFree(term->Hpre_mattype));
    230:     PetscCall(MatGetType(A, &mat_type));
    231:     PetscCall(PetscStrallocpy(mat_type, (char **)&term->H_mattype));
    232:     PetscCall(PetscStrallocpy(mat_type, (char **)&term->Hpre_mattype));
    233:   }
    234:   PetscFunctionReturn(PETSC_SUCCESS);
    235: }

    237: static PetscErrorCode TaoTermIsComputeHessianFDPossible_Quadratic(TaoTerm term, PetscBool3 *ispossible)
    238: {
    239:   PetscFunctionBegin;
    240:   *ispossible = PETSC_BOOL3_FALSE;
    241:   PetscFunctionReturn(PETSC_SUCCESS);
    242: }

    244: /*MC
    245:   TAOTERMQUADRATIC - A `TaoTerm` that computes $\tfrac{1}{2}(x - p)^T A (x - p)$, for a fixed matrix $A$, solution $x$ and parameters $p$.

    247:   Level: intermediate

    249:   Notes:
    250:   This term is `TAOTERM_PARAMETERS_OPTIONAL`.  If the parameters argument is `NULL` for
    251:   evaluation routines the term computes $\tfrac{1}{2}x^T A x$.

    253:   The matrix $A$ must be symmetric.

    255:   The default Hessian creation mode (see `TaoTermGetCreateHessianMode()`) is `H == Hpre` and `TaoTermCreateHessianMatrices()`
    256:   will create a matrix with the same type as $A$.

    258: .seealso: [](sec_tao_term),
    259:           `TaoTerm`,
    260:           `TaoTermType`,
    261:           `TaoTermCreateQuadratic()`,
    262:           `TAOTERMHALFL2SQUARED`,
    263:           `TAOTERML1`, `TaoTermQuadraticSetMat()`
    264: M*/
    265: PETSC_INTERN PetscErrorCode TaoTermCreate_Quadratic(TaoTerm term)
    266: {
    267:   TaoTerm_Quadratic *quad;

    269:   PetscFunctionBegin;
    270:   PetscCall(TaoTermCreate_ElementwiseDivergence_Internal(term));
    271:   PetscCall(PetscNew(&quad));
    272:   term->data = (void *)quad;

    274:   PetscCall(PetscFree(term->H_mattype));
    275:   PetscCall(PetscFree(term->Hpre_mattype));

    277:   term->ops->destroy                    = TaoTermDestroy_Quadratic;
    278:   term->ops->view                       = TaoTermView_Quadratic;
    279:   term->ops->objective                  = TaoTermComputeObjective_Quadratic;
    280:   term->ops->gradient                   = TaoTermComputeGradient_Quadratic;
    281:   term->ops->objectiveandgradient       = TaoTermComputeObjectiveAndGradient_Quadratic;
    282:   term->ops->hessian                    = TaoTermComputeHessian_Quadratic;
    283:   term->ops->createhessianmatrices      = TaoTermCreateHessianMatrices_Quadratic;
    284:   term->ops->iscomputehessianfdpossible = TaoTermIsComputeHessianFDPossible_Quadratic;

    286:   term->Hpre_is_H = PETSC_TRUE;

    288:   PetscCall(PetscObjectComposeFunction((PetscObject)term, "TaoTermQuadraticGetMat_C", TaoTermQuadraticGetMat_Quadratic));
    289:   PetscCall(PetscObjectComposeFunction((PetscObject)term, "TaoTermQuadraticSetMat_C", TaoTermQuadraticSetMat_Quadratic));
    290:   PetscFunctionReturn(PETSC_SUCCESS);
    291: }

    293: /*@
    294:   TaoTermCreateQuadratic - Create a `TAOTERMQUADRATIC` for a given matrix

    296:   Collective

    298:   Input Parameter:
    299: . A - a square matrix

    301:   Output Parameter:
    302: . term - a `TaoTerm` that implements $\tfrac{1}{2}(x - p)^T A (x - p)$

    304:   Level: beginner

    306: .seealso: [](sec_tao_term),
    307:           `TaoTerm`,
    308:           `TaoTermCreate()`,
    309:           `TAOTERMQUADRATIC`,
    310:           `TaoTermCreateHalfL2Squared()`,
    311:           `TaoTermCreateL1()`, `TaoTermQuadraticSetMat()`
    312: @*/
    313: PetscErrorCode TaoTermCreateQuadratic(Mat A, TaoTerm *term)
    314: {
    315:   TaoTerm _term;

    317:   PetscFunctionBegin;
    319:   PetscAssertPointer(term, 2);
    320:   PetscCall(TaoTermCreate(PetscObjectComm((PetscObject)A), &_term));
    321:   PetscCall(TaoTermSetType(_term, TAOTERMQUADRATIC));
    322:   PetscCall(TaoTermQuadraticSetMat(_term, A));
    323:   *term = _term;
    324:   PetscFunctionReturn(PETSC_SUCCESS);
    325: }