xref: /petsc/src/tao/constrained/impls/almm/almmutils.c (revision 58d68138c660dfb4e9f5b03334792cd4f2ffd7cc)
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: `TAOALMM`, `TaoALMMSetType()`, `TaoALMMType`
18 @*/
19 PetscErrorCode TaoALMMGetType(Tao tao, TaoALMMType *type) {
20   PetscFunctionBegin;
21   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
22   PetscValidPointer(type, 2);
23   PetscUseMethod(tao, "TaoALMMGetType_C", (Tao, TaoALMMType *), (tao, type));
24   PetscFunctionReturn(0);
25 }
26 
27 PetscErrorCode TaoALMMGetType_Private(Tao tao, TaoALMMType *type) {
28   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
29 
30   PetscFunctionBegin;
31   *type = auglag->type;
32   PetscFunctionReturn(0);
33 }
34 
35 /*@
36    TaoALMMSetType - Determine the augmented Lagrangian formulation type for the subproblem.
37 
38    Input Parameters:
39 +  tao - the Tao context for the TAOALMM solver
40 -  type - augmented Lagragrangian type
41 
42    Level: advanced
43 
44 .seealso: `TAOALMM`, `TaoALMMGetType()`, `TaoALMMType`
45 @*/
46 PetscErrorCode TaoALMMSetType(Tao tao, TaoALMMType type) {
47   PetscFunctionBegin;
48   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
49   PetscTryMethod(tao, "TaoALMMSetType_C", (Tao, TaoALMMType), (tao, type));
50   PetscFunctionReturn(0);
51 }
52 
53 PetscErrorCode TaoALMMSetType_Private(Tao tao, TaoALMMType type) {
54   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
55 
56   PetscFunctionBegin;
57   PetscCheck(!tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoALMMSetType() must be called before TaoSetUp()");
58   auglag->type = type;
59   PetscFunctionReturn(0);
60 }
61 
62 /*@
63    TaoALMMGetSubsolver - Retrieve a pointer to the TAOALMM.
64 
65    Input Parameters:
66 .  tao - the Tao context for the TAOALMM solver
67 
68    Output Parameter:
69 .  subsolver - the Tao context for the subsolver
70 
71    Level: advanced
72 
73 .seealso: `TAOALMM`, `TaoALMMSetSubsolver()`
74 @*/
75 PetscErrorCode TaoALMMGetSubsolver(Tao tao, Tao *subsolver) {
76   PetscFunctionBegin;
77   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
78   PetscValidPointer(subsolver, 2);
79   PetscUseMethod(tao, "TaoALMMGetSubsolver_C", (Tao, Tao *), (tao, subsolver));
80   PetscFunctionReturn(0);
81 }
82 
83 PetscErrorCode TaoALMMGetSubsolver_Private(Tao tao, Tao *subsolver) {
84   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
85 
86   PetscFunctionBegin;
87   *subsolver = auglag->subsolver;
88   PetscFunctionReturn(0);
89 }
90 
91 /*@
92    TaoALMMSetSubsolver - Changes the subsolver inside TAOALMM with the user provided one.
93 
94    Input Parameters:
95 +  tao - the Tao context for the TAOALMM solver
96 -  subsolver - the Tao context for the subsolver
97 
98    Level: advanced
99 
100 .seealso: `TAOALMM`, `TaoALMMGetSubsolver()`
101 @*/
102 PetscErrorCode TaoALMMSetSubsolver(Tao tao, Tao subsolver) {
103   PetscFunctionBegin;
104   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
105   PetscValidHeaderSpecific(subsolver, TAO_CLASSID, 2);
106   PetscTryMethod(tao, "TaoALMMSetSubsolver_C", (Tao, Tao), (tao, subsolver));
107   PetscFunctionReturn(0);
108 }
109 
110 PetscErrorCode TaoALMMSetSubsolver_Private(Tao tao, Tao subsolver) {
111   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
112   PetscBool compatible;
113 
114   PetscFunctionBegin;
115   if (subsolver == auglag->subsolver) PetscFunctionReturn(0);
116   if (tao->bounded) {
117     PetscCall(PetscObjectTypeCompareAny((PetscObject)subsolver, &compatible, TAOSHELL, TAOBNCG, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, ""));
118     PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a bound-constrained first-order method");
119   } else {
120     PetscCall(PetscObjectTypeCompareAny((PetscObject)subsolver, &compatible, TAOSHELL, TAOCG, TAOLMVM, TAOBNCG, TAOBQNLS, TAOBQNKLS, TAOBQNKTR, TAOBQNKTL, ""));
121     PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a first-order method");
122   }
123   PetscCheck(compatible, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Subsolver must be a first-order method");
124   PetscCall(PetscObjectReference((PetscObject)subsolver));
125   PetscCall(TaoDestroy(&auglag->subsolver));
126   auglag->subsolver = subsolver;
127   if (tao->setupcalled) {
128     PetscCall(TaoSetSolution(auglag->subsolver, auglag->P));
129     PetscCall(TaoSetObjective(auglag->subsolver, TaoALMMSubsolverObjective_Private, (void *)auglag));
130     PetscCall(TaoSetObjectiveAndGradient(auglag->subsolver, NULL, TaoALMMSubsolverObjectiveAndGradient_Private, (void *)auglag));
131     PetscCall(TaoSetVariableBounds(auglag->subsolver, auglag->PL, auglag->PU));
132   }
133   PetscFunctionReturn(0);
134 }
135 
136 /*@
137    TaoALMMGetMultipliers - Retrieve a pointer to the Lagrange multipliers.
138 
139    Input Parameters:
140 .  tao - the Tao context for the TAOALMM solver
141 
142    Output Parameters:
143 .  Y - vector of Lagrange multipliers
144 
145    Level: advanced
146 
147    Notes:
148    For problems with both equality and inequality constraints,
149    the multipliers are combined together as Y = (Ye, Yi). Users
150    can recover copies of the subcomponents using index sets
151    provided by TaoALMMGetDualIS() and use VecGetSubVector().
152 
153 .seealso: `TAOALMM`, `TaoALMMSetMultipliers()`, `TaoALMMGetDualIS()`
154 @*/
155 PetscErrorCode TaoALMMGetMultipliers(Tao tao, Vec *Y) {
156   PetscFunctionBegin;
157   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
158   PetscValidPointer(Y, 2);
159   PetscUseMethod(tao, "TaoALMMGetMultipliers_C", (Tao, Vec *), (tao, Y));
160   PetscFunctionReturn(0);
161 }
162 
163 PetscErrorCode TaoALMMGetMultipliers_Private(Tao tao, Vec *Y) {
164   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
165 
166   PetscFunctionBegin;
167   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for scatters to be constructed");
168   *Y = auglag->Y;
169   PetscFunctionReturn(0);
170 }
171 
172 /*@
173    TaoALMMSetMultipliers - Set user-defined Lagrange multipliers. The vector type and
174                              parallel structure of the given vectormust match equality and
175                              inequality constraints. The vector must have a local size equal
176                              to the sum of the local sizes for the constraint vectors, and a
177                              global size equal to the sum of the global sizes of the constraint
178                              vectors.
179 
180    Input Parameters:
181 +  tao - the Tao context for the TAOALMM solver
182 -  Y - vector of Lagrange multipliers
183 
184    Level: advanced
185 
186    Notes:
187    This routine is only useful if the user wants to change the
188    parallel distribution of the combined dual vector in problems that
189    feature both equality and inequality constraints. For other tasks,
190    it is strongly recommended that the user retreive the dual vector
191    created by the solver using TaoALMMGetMultipliers().
192 
193 .seealso: `TAOALMM`, `TaoALMMGetMultipliers()`
194 @*/
195 PetscErrorCode TaoALMMSetMultipliers(Tao tao, Vec Y) {
196   PetscFunctionBegin;
197   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
198   PetscValidHeaderSpecific(Y, VEC_CLASSID, 2);
199   PetscTryMethod(tao, "TaoALMMSetMultipliers_C", (Tao, Vec), (tao, Y));
200   PetscFunctionReturn(0);
201 }
202 
203 PetscErrorCode TaoALMMSetMultipliers_Private(Tao tao, Vec Y) {
204   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
205   VecType   Ytype;
206   PetscInt  Nuser, Neq, Nineq, N;
207   PetscBool same = PETSC_FALSE;
208 
209   PetscFunctionBegin;
210   /* no-op if user provides vector from TaoALMMGetMultipliers() */
211   if (Y == auglag->Y) PetscFunctionReturn(0);
212   /* make sure vector type is same as equality and inequality constraints */
213   if (tao->eq_constrained) {
214     PetscCall(VecGetType(tao->constraints_equality, &Ytype));
215   } else {
216     PetscCall(VecGetType(tao->constraints_inequality, &Ytype));
217   }
218   PetscCall(PetscObjectTypeCompare((PetscObject)Y, Ytype, &same));
219   PetscCheck(same, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector for multipliers is not the same type as constraint vectors");
220   /* make sure global size matches sum of equality and inequality */
221   if (tao->eq_constrained) {
222     PetscCall(VecGetSize(tao->constraints_equality, &Neq));
223   } else {
224     Neq = 0;
225   }
226   if (tao->ineq_constrained) {
227     PetscCall(VecGetSize(tao->constraints_inequality, &Nineq));
228   } else {
229     Nineq = 0;
230   }
231   N = Neq + Nineq;
232   PetscCall(VecGetSize(Y, &Nuser));
233   PetscCheck(Nuser == N, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong global size");
234   /* if there is only one type of constraint, then we need the local size to match too */
235   if (Neq == 0) {
236     PetscCall(VecGetLocalSize(tao->constraints_inequality, &Nineq));
237     PetscCall(VecGetLocalSize(Y, &Nuser));
238     PetscCheck(Nuser == Nineq, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong local size");
239   }
240   if (Nineq == 0) {
241     PetscCall(VecGetLocalSize(tao->constraints_equality, &Neq));
242     PetscCall(VecGetLocalSize(Y, &Nuser));
243     PetscCheck(Nuser == Neq, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_INCOMP, "Given vector has wrong local size");
244   }
245   /* if we got here, the given vector is compatible so we can replace the current one */
246   PetscCall(PetscObjectReference((PetscObject)Y));
247   PetscCall(VecDestroy(&auglag->Y));
248   auglag->Y = Y;
249   /* if there are both types of constraints and the solver has already been set up,
250      then we need to regenerate VecScatter objects for the new combined dual vector */
251   if (tao->setupcalled && tao->eq_constrained && tao->ineq_constrained) {
252     PetscCall(VecDestroy(&auglag->C));
253     PetscCall(VecDuplicate(auglag->Y, &auglag->C));
254     PetscCall(VecScatterDestroy(&auglag->Yscatter[0]));
255     PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[0], auglag->Ye, NULL, &auglag->Yscatter[0]));
256     PetscCall(VecScatterDestroy(&auglag->Yscatter[1]));
257     PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[1], auglag->Yi, NULL, &auglag->Yscatter[1]));
258   }
259   PetscFunctionReturn(0);
260 }
261 
262 /*@
263    TaoALMMGetPrimalIS - Retrieve a pointer to the index set that identifies optimization
264                         and slack variable components of the subsolver's solution vector.
265                         Not valid for problems with only equality constraints.
266 
267    Input Parameter:
268 .  tao - the Tao context for the TAOALMM solver
269 
270    Output Parameters:
271 +  opt_is - index set associated with the optimization variables (NULL if not needed)
272 -  slack_is - index set associated with the slack variables (NULL if not needed)
273 
274    Level: advanced
275 
276 .seealso: `TAOALMM`, `TaoALMMGetPrimalVector()`
277 @*/
278 PetscErrorCode TaoALMMGetPrimalIS(Tao tao, IS *opt_is, IS *slack_is) {
279   PetscFunctionBegin;
280   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
281   PetscUseMethod(tao, "TaoALMMGetPrimalIS_C", (Tao, IS *, IS *), (tao, opt_is, slack_is));
282   PetscFunctionReturn(0);
283 }
284 
285 PetscErrorCode TaoALMMGetPrimalIS_Private(Tao tao, IS *opt_is, IS *slack_is) {
286   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
287 
288   PetscFunctionBegin;
289   PetscCheck(tao->ineq_constrained, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "Primal space has index sets only for inequality constrained problems");
290   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed");
291   if (opt_is) *opt_is = auglag->Pis[0];
292   if (slack_is) *slack_is = auglag->Pis[1];
293   PetscFunctionReturn(0);
294 }
295 
296 /*@
297    TaoALMMGetDualIS - Retrieve a pointer to the index set that identifies equality
298                       and inequality constraint components of the dual vector returned
299                       by TaoALMMGetMultipliers(). Not valid for problems with only one
300                       type of constraint.
301 
302    Input Parameter:
303 .  tao - the Tao context for the TAOALMM solver
304 
305    Output Parameters:
306 +  eq_is - index set associated with the equality constraints (NULL if not needed)
307 -  ineq_is - index set associated with the inequality constraints (NULL if not needed)
308 
309    Level: advanced
310 
311 .seealso: `TAOALMM`, `TaoALMMGetMultipliers()`
312 @*/
313 PetscErrorCode TaoALMMGetDualIS(Tao tao, IS *eq_is, IS *ineq_is) {
314   PetscFunctionBegin;
315   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
316   PetscUseMethod(tao, "TaoALMMGetDualIS_C", (Tao, IS *, IS *), (tao, eq_is, ineq_is));
317   PetscFunctionReturn(0);
318 }
319 
320 PetscErrorCode TaoALMMGetDualIS_Private(Tao tao, IS *eq_is, IS *ineq_is) {
321   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
322 
323   PetscFunctionBegin;
324   PetscValidHeaderSpecific(tao, TAO_CLASSID, 1);
325   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");
326   PetscCheck(tao->setupcalled, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "TaoSetUp() must be called first for index sets to be constructed");
327   if (eq_is) *eq_is = auglag->Yis[0];
328   if (ineq_is) *ineq_is = auglag->Yis[1];
329   PetscFunctionReturn(0);
330 }
331