Actual source code: almmutils.c

      1: #include <../src/tao/constrained/impls/almm/almm.h>
      2: #include <petsctao.h>
      3: #include <petsc/private/petscimpl.h>
      4: #include <petsc/private/vecimpl.h>

      6: /*@
      7:   TaoALMMGetType - Retrieve the augmented Lagrangian formulation type for the subproblem.

      9:   Input Parameter:
     10: . tao - the `Tao` context for the `TAOALMM` solver

     12:   Output Parameter:
     13: . type - augmented Lagragrangian type

     15:   Level: advanced

     17: .seealso: `Tao`, `TAOALMM`, `TaoALMMSetType()`, `TaoALMMType`
     18: @*/
     19: PetscErrorCode TaoALMMGetType(Tao tao, TaoALMMType *type)
     20: {
     21:   PetscFunctionBegin;
     23:   PetscAssertPointer(type, 2);
     24:   PetscUseMethod(tao, "TaoALMMGetType_C", (Tao, TaoALMMType *), (tao, type));
     25:   PetscFunctionReturn(PETSC_SUCCESS);
     26: }

     28: PetscErrorCode TaoALMMGetType_Private(Tao tao, TaoALMMType *type)
     29: {
     30:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

     32:   PetscFunctionBegin;
     33:   *type = auglag->type;
     34:   PetscFunctionReturn(PETSC_SUCCESS);
     35: }

     37: /*@
     38:   TaoALMMSetType - Determine the augmented Lagrangian formulation type for the subproblem.

     40:   Input Parameters:
     41: + tao  - the `Tao` context for the `TAOALMM` solver
     42: - type - augmented Lagragrangian type

     44:   Level: advanced

     46: .seealso: `Tao`, `TAOALMM`, `TaoALMMGetType()`, `TaoALMMType`
     47: @*/
     48: PetscErrorCode TaoALMMSetType(Tao tao, TaoALMMType type)
     49: {
     50:   PetscFunctionBegin;
     52:   PetscTryMethod(tao, "TaoALMMSetType_C", (Tao, TaoALMMType), (tao, type));
     53:   PetscFunctionReturn(PETSC_SUCCESS);
     54: }

     56: PetscErrorCode TaoALMMSetType_Private(Tao tao, TaoALMMType type)
     57: {
     58:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

     60:   PetscFunctionBegin;
     61:   PetscCheck(!tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoALMMSetType() must be called before TaoSetUp()");
     62:   auglag->type = type;
     63:   PetscFunctionReturn(PETSC_SUCCESS);
     64: }

     66: /*@
     67:   TaoALMMGetSubsolver - Retrieve the subsolver being used by `TAOALMM`.

     69:   Input Parameter:
     70: . tao - the `Tao` context for the `TAOALMM` solver

     72:   Output Parameter:
     73: . subsolver - the `Tao` context for the subsolver

     75:   Level: advanced

     77: .seealso: `Tao`, `TAOALMM`, `TaoALMMSetSubsolver()`
     78: @*/
     79: PetscErrorCode TaoALMMGetSubsolver(Tao tao, Tao *subsolver)
     80: {
     81:   PetscFunctionBegin;
     83:   PetscAssertPointer(subsolver, 2);
     84:   PetscUseMethod(tao, "TaoALMMGetSubsolver_C", (Tao, Tao *), (tao, subsolver));
     85:   PetscFunctionReturn(PETSC_SUCCESS);
     86: }

     88: PetscErrorCode TaoALMMGetSubsolver_Private(Tao tao, Tao *subsolver)
     89: {
     90:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

     92:   PetscFunctionBegin;
     93:   *subsolver = auglag->subsolver;
     94:   PetscFunctionReturn(PETSC_SUCCESS);
     95: }

     97: /*@
     98:   TaoALMMSetSubsolver - Changes the subsolver inside `TAOALMM` with the user provided one.

    100:   Input Parameters:
    101: + tao       - the `Tao` context for the `TAOALMM` solver
    102: - subsolver - the Tao context for the subsolver

    104:   Level: advanced

    106:   Note:
    107:   This is not recommended, instead call `TaoALMMGetSubsolver()` and set the type as desired.

    109: .seealso: `Tao`, `TAOALMM`, `TaoALMMGetSubsolver()`
    110: @*/
    111: PetscErrorCode TaoALMMSetSubsolver(Tao tao, Tao subsolver)
    112: {
    113:   PetscFunctionBegin;
    116:   PetscTryMethod(tao, "TaoALMMSetSubsolver_C", (Tao, Tao), (tao, subsolver));
    117:   PetscFunctionReturn(PETSC_SUCCESS);
    118: }

    120: PetscErrorCode TaoALMMSetSubsolver_Private(Tao tao, Tao subsolver)
    121: {
    122:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
    123:   PetscBool compatible;

    125:   PetscFunctionBegin;
    126:   if (subsolver == auglag->subsolver) PetscFunctionReturn(PETSC_SUCCESS);
    127:   if (tao->bounded) {
    128:     PetscCall(PetscObjectTypeCompareAny((PetscObject)subsolver, &compatible, TAOSHELL, TAOBNCG, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, ""));
    129:     PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a bound-constrained first-order method");
    130:   } else {
    131:     PetscCall(PetscObjectTypeCompareAny((PetscObject)subsolver, &compatible, TAOSHELL, TAOCG, TAOLMVM, TAOBNCG, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, ""));
    132:     PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a first-order method");
    133:   }
    134:   PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a first-order method");
    135:   PetscCall(PetscObjectReference((PetscObject)subsolver));
    136:   PetscCall(TaoDestroy(&auglag->subsolver));
    137:   auglag->subsolver = subsolver;
    138:   if (tao->setupcalled) {
    139:     PetscCall(TaoSetSolution(auglag->subsolver, auglag->P));
    140:     PetscCall(TaoSetObjective(auglag->subsolver, TaoALMMSubsolverObjective_Private, (void *)auglag));
    141:     PetscCall(TaoSetObjectiveAndGradient(auglag->subsolver, NULL, TaoALMMSubsolverObjectiveAndGradient_Private, (void *)auglag));
    142:     PetscCall(TaoSetVariableBounds(auglag->subsolver, auglag->PL, auglag->PU));
    143:   }
    144:   PetscFunctionReturn(PETSC_SUCCESS);
    145: }

    147: /*@
    148:   TaoALMMGetMultipliers - Retrieve a pointer to the Lagrange multipliers.

    150:   Input Parameter:
    151: . tao - the `Tao` context for the `TAOALMM` solver

    153:   Output Parameter:
    154: . Y - vector of Lagrange multipliers

    156:   Level: advanced

    158:   Notes:
    159:   For problems with both equality and inequality constraints,
    160:   the multipliers are combined together as Y = (Ye, Yi). Users
    161:   can recover copies of the subcomponents using index sets
    162:   provided by `TaoALMMGetDualIS()` and use `VecGetSubVector()`.

    164: .seealso: `TAOALMM`, `Tao`, `TaoALMMSetMultipliers()`, `TaoALMMGetDualIS()`
    165: @*/
    166: PetscErrorCode TaoALMMGetMultipliers(Tao tao, Vec *Y)
    167: {
    168:   PetscFunctionBegin;
    170:   PetscAssertPointer(Y, 2);
    171:   PetscUseMethod(tao, "TaoALMMGetMultipliers_C", (Tao, Vec *), (tao, Y));
    172:   PetscFunctionReturn(PETSC_SUCCESS);
    173: }

    175: PetscErrorCode TaoALMMGetMultipliers_Private(Tao tao, Vec *Y)
    176: {
    177:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

    179:   PetscFunctionBegin;
    180:   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for scatters to be constructed");
    181:   *Y = auglag->Y;
    182:   PetscFunctionReturn(PETSC_SUCCESS);
    183: }

    185: /*@
    186:   TaoALMMSetMultipliers - Set user-defined Lagrange multipliers.

    188:   Input Parameters:
    189: + tao - the `Tao` context for the `TAOALMM` solver
    190: - Y   - vector of Lagrange multipliers

    192:   Level: advanced

    194:   Notes:
    195:   The vector type and parallel layout must match the equality and inequality constraints.

    197:   The vector must have a local size equal to the sum of the local sizes for the constraint vectors, and a
    198:   global size equal to the sum of the global sizes of the constraint vectors.

    200:   This routine is only useful if the user wants to change the
    201:   parallel distribution of the combined dual vector in problems that
    202:   feature both equality and inequality constraints. For other tasks,
    203:   it is strongly recommended that the user retrieve the dual vector
    204:   created by the solver using `TaoALMMGetMultipliers()`.

    206: .seealso: `TAOALMM`, `Tao`, `TaoALMMGetMultipliers()`
    207: @*/
    208: PetscErrorCode TaoALMMSetMultipliers(Tao tao, Vec Y)
    209: {
    210:   PetscFunctionBegin;
    213:   PetscTryMethod(tao, "TaoALMMSetMultipliers_C", (Tao, Vec), (tao, Y));
    214:   PetscFunctionReturn(PETSC_SUCCESS);
    215: }

    217: PetscErrorCode TaoALMMSetMultipliers_Private(Tao tao, Vec Y)
    218: {
    219:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
    220:   VecType   Ytype;
    221:   PetscInt  Nuser, Neq, Nineq, N;
    222:   PetscBool same = PETSC_FALSE;

    224:   PetscFunctionBegin;
    225:   /* no-op if user provides vector from TaoALMMGetMultipliers() */
    226:   if (Y == auglag->Y) PetscFunctionReturn(PETSC_SUCCESS);
    227:   /* make sure vector type is same as equality and inequality constraints */
    228:   if (tao->eq_constrained) {
    229:     PetscCall(VecGetType(tao->constraints_equality, &Ytype));
    230:   } else {
    231:     PetscCall(VecGetType(tao->constraints_inequality, &Ytype));
    232:   }
    233:   PetscCall(PetscObjectTypeCompare((PetscObject)Y, Ytype, &same));
    234:   PetscCheck(same, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector for multipliers is not the same type as constraint vectors");
    235:   /* make sure global size matches sum of equality and inequality */
    236:   if (tao->eq_constrained) {
    237:     PetscCall(VecGetSize(tao->constraints_equality, &Neq));
    238:   } else {
    239:     Neq = 0;
    240:   }
    241:   if (tao->ineq_constrained) {
    242:     PetscCall(VecGetSize(tao->constraints_inequality, &Nineq));
    243:   } else {
    244:     Nineq = 0;
    245:   }
    246:   N = Neq + Nineq;
    247:   PetscCall(VecGetSize(Y, &Nuser));
    248:   PetscCheck(Nuser == N, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong global size");
    249:   /* if there is only one type of constraint, then we need the local size to match too */
    250:   if (Neq == 0) {
    251:     PetscCall(VecGetLocalSize(tao->constraints_inequality, &Nineq));
    252:     PetscCall(VecGetLocalSize(Y, &Nuser));
    253:     PetscCheck(Nuser == Nineq, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong local size");
    254:   }
    255:   if (Nineq == 0) {
    256:     PetscCall(VecGetLocalSize(tao->constraints_equality, &Neq));
    257:     PetscCall(VecGetLocalSize(Y, &Nuser));
    258:     PetscCheck(Nuser == Neq, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong local size");
    259:   }
    260:   /* if we got here, the given vector is compatible so we can replace the current one */
    261:   PetscCall(PetscObjectReference((PetscObject)Y));
    262:   PetscCall(VecDestroy(&auglag->Y));
    263:   auglag->Y = Y;
    264:   /* if there are both types of constraints and the solver has already been set up,
    265:      then we need to regenerate VecScatter objects for the new combined dual vector */
    266:   if (tao->setupcalled && tao->eq_constrained && tao->ineq_constrained) {
    267:     PetscCall(VecDestroy(&auglag->C));
    268:     PetscCall(VecDuplicate(auglag->Y, &auglag->C));
    269:     PetscCall(VecScatterDestroy(&auglag->Yscatter[0]));
    270:     PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[0], auglag->Ye, NULL, &auglag->Yscatter[0]));
    271:     PetscCall(VecScatterDestroy(&auglag->Yscatter[1]));
    272:     PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[1], auglag->Yi, NULL, &auglag->Yscatter[1]));
    273:   }
    274:   PetscFunctionReturn(PETSC_SUCCESS);
    275: }

    277: /*@
    278:   TaoALMMGetPrimalIS - Retrieve the index set that identifies optimization
    279:   and slack variable components of the subsolver's solution vector.

    281:   Input Parameter:
    282: . tao - the `Tao` context for the `TAOALMM` solver

    284:   Output Parameters:
    285: + opt_is   - index set associated with the optimization variables (`NULL` if not needed)
    286: - slack_is - index set associated with the slack variables (`NULL` if not needed)

    288:   Level: advanced

    290: .seealso: `TAOALMM`, `Tao`, `IS`, `TaoALMMGetPrimalVector()`
    291: @*/
    292: PetscErrorCode TaoALMMGetPrimalIS(Tao tao, IS *opt_is, IS *slack_is)
    293: {
    294:   PetscFunctionBegin;
    296:   PetscUseMethod(tao, "TaoALMMGetPrimalIS_C", (Tao, IS *, IS *), (tao, opt_is, slack_is));
    297:   PetscFunctionReturn(PETSC_SUCCESS);
    298: }

    300: PetscErrorCode TaoALMMGetPrimalIS_Private(Tao tao, IS *opt_is, IS *slack_is)
    301: {
    302:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

    304:   PetscFunctionBegin;
    305:   PetscCheck(tao->ineq_constrained, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Primal space has index sets only for inequality constrained problems");
    306:   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed");
    307:   if (opt_is) *opt_is = auglag->Pis[0];
    308:   if (slack_is) *slack_is = auglag->Pis[1];
    309:   PetscFunctionReturn(PETSC_SUCCESS);
    310: }

    312: /*@
    313:   TaoALMMGetDualIS - Retrieve the index set that identifies equality
    314:   and inequality constraint components of the dual vector returned
    315:   by `TaoALMMGetMultipliers()`.

    317:   Input Parameter:
    318: . tao - the Tao context for the `TAOALMM` solver

    320:   Output Parameters:
    321: + eq_is   - index set associated with the equality constraints (`NULL` if not needed)
    322: - ineq_is - index set associated with the inequality constraints (`NULL` if not needed)

    324:   Level: advanced

    326: .seealso: `TAOALMM`, `Tao`, `TaoALMMGetMultipliers()`
    327: @*/
    328: PetscErrorCode TaoALMMGetDualIS(Tao tao, IS *eq_is, IS *ineq_is)
    329: {
    330:   PetscFunctionBegin;
    332:   PetscUseMethod(tao, "TaoALMMGetDualIS_C", (Tao, IS *, IS *), (tao, eq_is, ineq_is));
    333:   PetscFunctionReturn(PETSC_SUCCESS);
    334: }

    336: PetscErrorCode TaoALMMGetDualIS_Private(Tao tao, IS *eq_is, IS *ineq_is)
    337: {
    338:   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;

    340:   PetscFunctionBegin;
    342:   PetscCheck(tao->ineq_constrained && tao->ineq_constrained, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Dual space has index sets only when problem has both equality and inequality constraints");
    343:   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed");
    344:   if (eq_is) *eq_is = auglag->Yis[0];
    345:   if (ineq_is) *ineq_is = auglag->Yis[1];
    346:   PetscFunctionReturn(PETSC_SUCCESS);
    347: }