1 #include <../src/tao/constrained/impls/almm/almm.h> /*I "petsctao.h" I*/ /*I "petscvec.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 Parameters: 10 . tao - the `Tao` context for the `TAOALMM` solver 11 12 Output Parameters: 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(0); 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(0); 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(0); 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(0); 64 } 65 66 /*@ 67 TaoALMMGetSubsolver - Retrieve the subsolver being used by `TAOALMM`. 68 69 Input Parameters: 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(0); 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(0); 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(0); 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(0); 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(0); 145 } 146 147 /*@ 148 TaoALMMGetMultipliers - Retrieve a pointer to the Lagrange multipliers. 149 150 Input Parameters: 151 . tao - the `Tao` context for the `TAOALMM` solver 152 153 Output Parameters: 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(0); 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(0); 183 } 184 185 /*@ 186 TaoALMMSetMultipliers - Set user-defined Lagrange multipliers. The vector type and 187 parallel structure of the given vectormust match equality and 188 inequality constraints. The vector must have a local size equal 189 to the sum of the local sizes for the constraint vectors, and a 190 global size equal to the sum of the global sizes of the constraint 191 vectors. 192 193 Input Parameters: 194 + tao - the `Tao` context for the `TAOALMM` solver 195 - Y - vector of Lagrange multipliers 196 197 Level: advanced 198 199 Notes: 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 retreive 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(0); 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(0); 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(0); 275 } 276 277 /*@ 278 TaoALMMGetPrimalIS - Retrieve a pointer to the index set that identifies optimization 279 and slack variable components of the subsolver's solution vector. 280 Not valid for problems with only equality constraints. 281 282 Input Parameter: 283 . tao - the `Tao` context for the `TAOALMM` solver 284 285 Output Parameters: 286 + opt_is - index set associated with the optimization variables (NULL if not needed) 287 - slack_is - index set associated with the slack variables (NULL if not needed) 288 289 Level: advanced 290 291 .seealso: `TAOALMM`, `Tao`, `IS`, `TaoALMMGetPrimalVector()` 292 @*/ 293 PetscErrorCode TaoALMMGetPrimalIS(Tao tao, IS *opt_is, IS *slack_is) 294 { 295 PetscFunctionBegin; 296 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 297 PetscUseMethod(tao, "TaoALMMGetPrimalIS_C", (Tao, IS *, IS *), (tao, opt_is, slack_is)); 298 PetscFunctionReturn(0); 299 } 300 301 PetscErrorCode TaoALMMGetPrimalIS_Private(Tao tao, IS *opt_is, IS *slack_is) 302 { 303 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 304 305 PetscFunctionBegin; 306 PetscCheck(tao->ineq_constrained, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Primal space has index sets only for inequality constrained problems"); 307 PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed"); 308 if (opt_is) *opt_is = auglag->Pis[0]; 309 if (slack_is) *slack_is = auglag->Pis[1]; 310 PetscFunctionReturn(0); 311 } 312 313 /*@ 314 TaoALMMGetDualIS - Retrieve a pointer to the index set that identifies equality 315 and inequality constraint components of the dual vector returned 316 by `TaoALMMGetMultipliers()`. Not valid for problems with only one 317 type of constraint. 318 319 Input Parameter: 320 . tao - the Tao context for the `TAOALMM` solver 321 322 Output Parameters: 323 + eq_is - index set associated with the equality constraints (NULL if not needed) 324 - ineq_is - index set associated with the inequality constraints (NULL if not needed) 325 326 Level: advanced 327 328 .seealso: `TAOALMM`, `Tao`, `TaoALMMGetMultipliers()` 329 @*/ 330 PetscErrorCode TaoALMMGetDualIS(Tao tao, IS *eq_is, IS *ineq_is) 331 { 332 PetscFunctionBegin; 333 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 334 PetscUseMethod(tao, "TaoALMMGetDualIS_C", (Tao, IS *, IS *), (tao, eq_is, ineq_is)); 335 PetscFunctionReturn(0); 336 } 337 338 PetscErrorCode TaoALMMGetDualIS_Private(Tao tao, IS *eq_is, IS *ineq_is) 339 { 340 TAO_ALMM *auglag = (TAO_ALMM *)tao->data; 341 342 PetscFunctionBegin; 343 PetscValidHeaderSpecific(tao, TAO_CLASSID, 1); 344 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"); 345 PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed"); 346 if (eq_is) *eq_is = auglag->Yis[0]; 347 if (ineq_is) *ineq_is = auglag->Yis[1]; 348 PetscFunctionReturn(0); 349 } 350