xref: /petsc/src/tao/constrained/impls/almm/almmutils.c (revision cfd92c66bdae16b66d27a6336fb90fa54c459cc4) !
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 @*/
TaoALMMGetType(Tao tao,TaoALMMType * type)19 PetscErrorCode TaoALMMGetType(Tao tao, TaoALMMType *type)
20 {
21   PetscFunctionBegin;
22   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
23   PetscAssertPointer(type, 2);
24   PetscUseMethod(tao, "TaoALMMGetType_C", (Tao, TaoALMMType *), (tao, type));
25   PetscFunctionReturn(PETSC_SUCCESS);
26 }
27 
TaoALMMGetType_Private(Tao tao,TaoALMMType * type)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 @*/
TaoALMMSetType(Tao tao,TaoALMMType type)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 
TaoALMMSetType_Private(Tao tao,TaoALMMType type)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 @*/
TaoALMMGetSubsolver(Tao tao,Tao * subsolver)79 PetscErrorCode TaoALMMGetSubsolver(Tao tao, Tao *subsolver)
80 {
81   PetscFunctionBegin;
82   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
83   PetscAssertPointer(subsolver, 2);
84   PetscUseMethod(tao, "TaoALMMGetSubsolver_C", (Tao, Tao *), (tao, subsolver));
85   PetscFunctionReturn(PETSC_SUCCESS);
86 }
87 
TaoALMMGetSubsolver_Private(Tao tao,Tao * subsolver)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 @*/
TaoALMMSetSubsolver(Tao tao,Tao subsolver)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 
TaoALMMSetSubsolver_Private(Tao tao,Tao subsolver)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 @*/
TaoALMMGetMultipliers(Tao tao,Vec * Y)166 PetscErrorCode TaoALMMGetMultipliers(Tao tao, Vec *Y)
167 {
168   PetscFunctionBegin;
169   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
170   PetscAssertPointer(Y, 2);
171   PetscUseMethod(tao, "TaoALMMGetMultipliers_C", (Tao, Vec *), (tao, Y));
172   PetscFunctionReturn(PETSC_SUCCESS);
173 }
174 
TaoALMMGetMultipliers_Private(Tao tao,Vec * Y)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 @*/
TaoALMMSetMultipliers(Tao tao,Vec Y)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 
TaoALMMSetMultipliers_Private(Tao tao,Vec Y)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 @*/
TaoALMMGetPrimalIS(Tao tao,IS * opt_is,IS * slack_is)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 
TaoALMMGetPrimalIS_Private(Tao tao,IS * opt_is,IS * slack_is)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 @*/
TaoALMMGetDualIS(Tao tao,IS * eq_is,IS * ineq_is)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 
TaoALMMGetDualIS_Private(Tao tao,IS * eq_is,IS * ineq_is)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