xref: /petsc/src/tao/constrained/impls/almm/almmutils.c (revision 43cdf1ebbcbfa05bee08e48007ef1bae3f20f4e9)
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