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