1 #include <../src/tao/constrained/impls/almm/almm.h> /*I "petsctao.h" I*/ 2 #include <petsctao.h> 3 #include <petsc/private/petscimpl.h> 4 #include <petsc/private/vecimpl.h> 5 6 /*@ 7 TaoALMMGetType - Retrieve the augmented Lagrangian formulation type for the subproblem. 8 9 Input Parameter: 10 . tao - the `Tao` context for the `TAOALMM` solver 11 12 Output Parameter: 13 . type - augmented Lagragrangian type 14 15 Level: advanced 16 17 .seealso: `Tao`, `TAOALMM`, `TaoALMMSetType()`, `TaoALMMType` 18 @*/ 19 PetscErrorCode TaoALMMGetType(Tao tao, TaoALMMType *type) 20 { 21 PetscFunctionBegin; 22 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 23 PetscValidPointer(type, 2); 24 PetscUseMethod(tao, "TaoALMMGetType_C", (Tao, TaoALMMType *), (tao, type)); 25 PetscFunctionReturn(PETSC_SUCCESS); 26 } 27 28 PetscErrorCode TaoALMMGetType_Private(Tao tao, TaoALMMType *type) 29 { 30 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 31 32 PetscFunctionBegin; 33 *type = auglag->type; 34 PetscFunctionReturn(PETSC_SUCCESS); 35 } 36 37 /*@ 38 TaoALMMSetType - Determine the augmented Lagrangian formulation type for the subproblem. 39 40 Input Parameters: 41 + tao - the `Tao` context for the `TAOALMM` solver 42 - type - augmented Lagragrangian type 43 44 Level: advanced 45 46 .seealso: `Tao`, `TAOALMM`, `TaoALMMGetType()`, `TaoALMMType` 47 @*/ 48 PetscErrorCode TaoALMMSetType(Tao tao, TaoALMMType type) 49 { 50 PetscFunctionBegin; 51 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 52 PetscTryMethod(tao, "TaoALMMSetType_C", (Tao, TaoALMMType), (tao, type)); 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 PetscErrorCode TaoALMMSetType_Private(Tao tao, TaoALMMType type) 57 { 58 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 59 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 } 65 66 /*@ 67 TaoALMMGetSubsolver - Retrieve the subsolver being used by `TAOALMM`. 68 69 Input Parameter: 70 . tao - the `Tao` context for the `TAOALMM` solver 71 72 Output Parameter: 73 . subsolver - the `Tao` context for the subsolver 74 75 Level: advanced 76 77 .seealso: `Tao`, `TAOALMM`, `TaoALMMSetSubsolver()` 78 @*/ 79 PetscErrorCode TaoALMMGetSubsolver(Tao tao, Tao *subsolver) 80 { 81 PetscFunctionBegin; 82 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 83 PetscValidPointer(subsolver, 2); 84 PetscUseMethod(tao, "TaoALMMGetSubsolver_C", (Tao, Tao *), (tao, subsolver)); 85 PetscFunctionReturn(PETSC_SUCCESS); 86 } 87 88 PetscErrorCode TaoALMMGetSubsolver_Private(Tao tao, Tao *subsolver) 89 { 90 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 91 92 PetscFunctionBegin; 93 *subsolver = auglag->subsolver; 94 PetscFunctionReturn(PETSC_SUCCESS); 95 } 96 97 /*@ 98 TaoALMMSetSubsolver - Changes the subsolver inside `TAOALMM` with the user provided one. 99 100 Input Parameters: 101 + tao - the `Tao` context for the `TAOALMM` solver 102 - subsolver - the Tao context for the subsolver 103 104 Level: advanced 105 106 Note: 107 This is not recommended, instead call `TaoALMMGetSubsolver()` and set the type as desired. 108 109 .seealso: `Tao`, `TAOALMM`, `TaoALMMGetSubsolver()` 110 @*/ 111 PetscErrorCode TaoALMMSetSubsolver(Tao tao, Tao subsolver) 112 { 113 PetscFunctionBegin; 114 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 115 PetscValidHeaderSpecific(subsolver, TAO_CLASSID, 2); 116 PetscTryMethod(tao, "TaoALMMSetSubsolver_C", (Tao, Tao), (tao, subsolver)); 117 PetscFunctionReturn(PETSC_SUCCESS); 118 } 119 120 PetscErrorCode TaoALMMSetSubsolver_Private(Tao tao, Tao subsolver) 121 { 122 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 123 PetscBool compatible; 124 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 } 146 147 /*@ 148 TaoALMMGetMultipliers - Retrieve a pointer to the Lagrange multipliers. 149 150 Input Parameter: 151 . tao - the `Tao` context for the `TAOALMM` solver 152 153 Output Parameter: 154 . Y - vector of Lagrange multipliers 155 156 Level: advanced 157 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()`. 163 164 .seealso: `TAOALMM`, `Tao`, `TaoALMMSetMultipliers()`, `TaoALMMGetDualIS()` 165 @*/ 166 PetscErrorCode TaoALMMGetMultipliers(Tao tao, Vec *Y) 167 { 168 PetscFunctionBegin; 169 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 170 PetscValidPointer(Y, 2); 171 PetscUseMethod(tao, "TaoALMMGetMultipliers_C", (Tao, Vec *), (tao, Y)); 172 PetscFunctionReturn(PETSC_SUCCESS); 173 } 174 175 PetscErrorCode TaoALMMGetMultipliers_Private(Tao tao, Vec *Y) 176 { 177 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 178 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 } 184 185 /*@ 186 TaoALMMSetMultipliers - Set user-defined Lagrange multipliers. 187 188 Input Parameters: 189 + tao - the `Tao` context for the `TAOALMM` solver 190 - Y - vector of Lagrange multipliers 191 192 Level: advanced 193 194 Notes: 195 The vector type and parallel layout must match the equality and inequality constraints. 196 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. 199 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()`. 205 206 .seealso: `TAOALMM`, `Tao`, `TaoALMMGetMultipliers()` 207 @*/ 208 PetscErrorCode TaoALMMSetMultipliers(Tao tao, Vec Y) 209 { 210 PetscFunctionBegin; 211 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 212 PetscValidHeaderSpecific(Y, VEC_CLASSID, 2); 213 PetscTryMethod(tao, "TaoALMMSetMultipliers_C", (Tao, Vec), (tao, Y)); 214 PetscFunctionReturn(PETSC_SUCCESS); 215 } 216 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; 223 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 } 276 277 /*@ 278 TaoALMMGetPrimalIS - Retrieve the index set that identifies optimization 279 and slack variable components of the subsolver's solution vector. 280 281 Input Parameter: 282 . tao - the `Tao` context for the `TAOALMM` solver 283 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) 287 288 Level: advanced 289 290 .seealso: `TAOALMM`, `Tao`, `IS`, `TaoALMMGetPrimalVector()` 291 @*/ 292 PetscErrorCode TaoALMMGetPrimalIS(Tao tao, IS *opt_is, IS *slack_is) 293 { 294 PetscFunctionBegin; 295 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 296 PetscUseMethod(tao, "TaoALMMGetPrimalIS_C", (Tao, IS *, IS *), (tao, opt_is, slack_is)); 297 PetscFunctionReturn(PETSC_SUCCESS); 298 } 299 300 PetscErrorCode TaoALMMGetPrimalIS_Private(Tao tao, IS *opt_is, IS *slack_is) 301 { 302 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 303 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 } 311 312 /*@ 313 TaoALMMGetDualIS - Retrieve the index set that identifies equality 314 and inequality constraint components of the dual vector returned 315 by `TaoALMMGetMultipliers()`. 316 317 Input Parameter: 318 . tao - the Tao context for the `TAOALMM` solver 319 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) 323 324 Level: advanced 325 326 .seealso: `TAOALMM`, `Tao`, `TaoALMMGetMultipliers()` 327 @*/ 328 PetscErrorCode TaoALMMGetDualIS(Tao tao, IS *eq_is, IS *ineq_is) 329 { 330 PetscFunctionBegin; 331 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 332 PetscUseMethod(tao, "TaoALMMGetDualIS_C", (Tao, IS *, IS *), (tao, eq_is, ineq_is)); 333 PetscFunctionReturn(PETSC_SUCCESS); 334 } 335 336 PetscErrorCode TaoALMMGetDualIS_Private(Tao tao, IS *eq_is, IS *ineq_is) 337 { 338 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 339 340 PetscFunctionBegin; 341 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 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 } 348