xref: /petsc/src/tao/constrained/impls/almm/almm.c (revision b122ec5aa1bd4469eb4e0673542fb7de3f411254)
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 static PetscErrorCode TaoALMMCombinePrimal_Private(Tao,Vec,Vec,Vec);
7 static PetscErrorCode TaoALMMCombineDual_Private(Tao,Vec,Vec,Vec);
8 static PetscErrorCode TaoALMMSplitPrimal_Private(Tao,Vec,Vec,Vec);
9 static PetscErrorCode TaoALMMComputeOptimalityNorms_Private(Tao);
10 static PetscErrorCode TaoALMMComputeAugLagAndGradient_Private(Tao);
11 static PetscErrorCode TaoALMMComputePHRLagAndGradient_Private(Tao);
12 
13 static PetscErrorCode TaoSolve_ALMM(Tao tao)
14 {
15   TAO_ALMM           *auglag = (TAO_ALMM*)tao->data;
16   TaoConvergedReason reason;
17   PetscReal          updated;
18 
19   PetscFunctionBegin;
20   /* reset initial multiplier/slack guess */
21   if (!tao->recycle) {
22     if (tao->ineq_constrained) {
23       CHKERRQ(VecZeroEntries(auglag->Ps));
24       CHKERRQ(TaoALMMCombinePrimal_Private(tao, auglag->Px, auglag->Ps, auglag->P));
25       CHKERRQ(VecZeroEntries(auglag->Yi));
26     }
27     if (tao->eq_constrained) {
28       CHKERRQ(VecZeroEntries(auglag->Ye));
29     }
30   }
31 
32   /* compute initial nonlinear Lagrangian and its derivatives */
33   CHKERRQ((*auglag->sub_obj)(tao));
34   CHKERRQ(TaoALMMComputeOptimalityNorms_Private(tao));
35   /* print initial step and check convergence */
36   CHKERRQ(PetscInfo(tao,"Solving with %s formulation\n",TaoALMMTypes[auglag->type]));
37   CHKERRQ(TaoLogConvergenceHistory(tao, auglag->Lval, auglag->gnorm, auglag->cnorm, tao->ksp_its));
38   CHKERRQ(TaoMonitor(tao, tao->niter, auglag->fval, auglag->gnorm, auglag->cnorm, 0.0));
39   CHKERRQ((*tao->ops->convergencetest)(tao, tao->cnvP));
40   /* set initial penalty factor and inner solver tolerance */
41   switch (auglag->type) {
42     case TAO_ALMM_CLASSIC:
43       auglag->mu = auglag->mu0;
44       break;
45     case TAO_ALMM_PHR:
46       auglag->cenorm = 0.0;
47       if (tao->eq_constrained) {
48         CHKERRQ(VecDot(auglag->Ce, auglag->Ce, &auglag->cenorm));
49       }
50       auglag->cinorm = 0.0;
51       if (tao->ineq_constrained) {
52         CHKERRQ(VecCopy(auglag->Ci, auglag->Ciwork));
53         CHKERRQ(VecScale(auglag->Ciwork, -1.0));
54         CHKERRQ(VecPointwiseMax(auglag->Ciwork, auglag->Cizero, auglag->Ciwork));
55         CHKERRQ(VecDot(auglag->Ciwork, auglag->Ciwork, &auglag->cinorm));
56       }
57       /* determine initial penalty factor based on the balance of constraint violation and objective function value */
58       auglag->mu = PetscMax(1.e-6, PetscMin(10.0, 2.0*PetscAbsReal(auglag->fval)/(auglag->cenorm + auglag->cinorm)));
59       break;
60     default:
61       break;
62   }
63   auglag->gtol = auglag->gtol0;
64   CHKERRQ(PetscInfo(tao,"Initial penalty: %.2f\n",auglag->mu));
65 
66   /* start aug-lag outer loop */
67   while (tao->reason == TAO_CONTINUE_ITERATING) {
68     ++tao->niter;
69     /* update subsolver tolerance */
70     CHKERRQ(PetscInfo(tao,"Subsolver tolerance: ||G|| <= %e\n",auglag->gtol));
71     CHKERRQ(TaoSetTolerances(auglag->subsolver, auglag->gtol, 0.0, 0.0));
72     /* solve the bound-constrained or unconstrained subproblem */
73     CHKERRQ(TaoSolve(auglag->subsolver));
74     CHKERRQ(TaoGetConvergedReason(auglag->subsolver, &reason));
75     tao->ksp_its += auglag->subsolver->ksp_its;
76     if (reason != TAO_CONVERGED_GATOL) {
77       CHKERRQ(PetscInfo(tao,"Subsolver failed to converge, reason: %s\n",TaoConvergedReasons[reason]));
78     }
79     /* evaluate solution and test convergence */
80     CHKERRQ((*auglag->sub_obj)(tao));
81     CHKERRQ(TaoALMMComputeOptimalityNorms_Private(tao));
82     /* decide whether to update multipliers or not */
83     updated = 0.0;
84     if (auglag->cnorm <= auglag->ytol) {
85       CHKERRQ(PetscInfo(tao,"Multipliers updated: ||C|| <= %e\n",auglag->ytol));
86       /* constraints are good, update multipliers and convergence tolerances */
87       if (tao->eq_constrained) {
88         CHKERRQ(VecAXPY(auglag->Ye, auglag->mu, auglag->Ce));
89         CHKERRQ(VecSet(auglag->Cework, auglag->ye_max));
90         CHKERRQ(VecPointwiseMin(auglag->Ye, auglag->Cework, auglag->Ye));
91         CHKERRQ(VecSet(auglag->Cework, auglag->ye_min));
92         CHKERRQ(VecPointwiseMax(auglag->Ye, auglag->Cework, auglag->Ye));
93       }
94       if (tao->ineq_constrained) {
95         CHKERRQ(VecAXPY(auglag->Yi, auglag->mu, auglag->Ci));
96         CHKERRQ(VecSet(auglag->Ciwork, auglag->yi_max));
97         CHKERRQ(VecPointwiseMin(auglag->Yi, auglag->Ciwork, auglag->Yi));
98         CHKERRQ(VecSet(auglag->Ciwork, auglag->yi_min));
99         CHKERRQ(VecPointwiseMax(auglag->Yi, auglag->Ciwork, auglag->Yi));
100       }
101       /* tolerances are updated only for non-PHR methods */
102       if (auglag->type != TAO_ALMM_PHR) {
103         auglag->ytol = PetscMax(tao->catol, auglag->ytol/PetscPowReal(auglag->mu, auglag->mu_pow_good));
104         auglag->gtol = PetscMax(tao->gatol, auglag->gtol/auglag->mu);
105       }
106       updated = 1.0;
107     } else {
108       /* constraints are bad, update penalty factor */
109       auglag->mu = PetscMin(auglag->mu_max, auglag->mu_fac*auglag->mu);
110       /* tolerances are reset only for non-PHR methods */
111       if (auglag->type != TAO_ALMM_PHR) {
112         auglag->ytol = PetscMax(tao->catol, 0.1/PetscPowReal(auglag->mu, auglag->mu_pow_bad));
113         auglag->gtol = PetscMax(tao->gatol, 1.0/auglag->mu);
114       }
115       CHKERRQ(PetscInfo(tao,"Penalty increased: mu = %.2f\n",auglag->mu));
116     }
117     CHKERRQ(TaoLogConvergenceHistory(tao, auglag->fval, auglag->gnorm, auglag->cnorm, tao->ksp_its));
118     CHKERRQ(TaoMonitor(tao, tao->niter, auglag->fval, auglag->gnorm, auglag->cnorm, updated));
119     CHKERRQ((*tao->ops->convergencetest)(tao, tao->cnvP));
120   }
121 
122   PetscFunctionReturn(0);
123 }
124 
125 static PetscErrorCode TaoView_ALMM(Tao tao,PetscViewer viewer)
126 {
127   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
128   PetscBool      isascii;
129 
130   PetscFunctionBegin;
131   CHKERRQ(PetscViewerASCIIPushTab(viewer));
132   CHKERRQ(TaoView(auglag->subsolver,viewer));
133   CHKERRQ(PetscViewerASCIIPopTab(viewer));
134   CHKERRQ(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
135   if (isascii) {
136     CHKERRQ(PetscViewerASCIIPushTab(viewer));
137     CHKERRQ(PetscViewerASCIIPrintf(viewer, "ALMM Formulation Type: %s\n", TaoALMMTypes[auglag->type]));
138     CHKERRQ(PetscViewerASCIIPopTab(viewer));
139   }
140   PetscFunctionReturn(0);
141 }
142 
143 static PetscErrorCode TaoSetUp_ALMM(Tao tao)
144 {
145   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
146   VecType        vec_type;
147   Vec            SL, SU;
148   PetscBool      is_cg = PETSC_FALSE, is_lmvm = PETSC_FALSE;
149 
150   PetscFunctionBegin;
151   PetscCheck(!tao->ineq_doublesided,PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TAOALMM does not support double-sided inequality constraint definition. Please restructure your inequality constrainst to fit the form c(x) >= 0.");
152   PetscCheck(tao->eq_constrained || tao->ineq_constrained,PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "Equality and/or inequality constraints must be defined before solver setup.");
153   CHKERRQ(TaoComputeVariableBounds(tao));
154   /* alias base vectors and create extras */
155   CHKERRQ(VecGetType(tao->solution, &vec_type));
156   auglag->Px = tao->solution;
157   if (!tao->gradient) { /* base gradient */
158     CHKERRQ(VecDuplicate(tao->solution, &tao->gradient));
159   }
160   auglag->LgradX = tao->gradient;
161   if (!auglag->Xwork) { /* opt var work vector */
162     CHKERRQ(VecDuplicate(tao->solution, &auglag->Xwork));
163   }
164   if (tao->eq_constrained) {
165     auglag->Ce = tao->constraints_equality;
166     auglag->Ae = tao->jacobian_equality;
167     if (!auglag->Ye) { /* equality multipliers */
168       CHKERRQ(VecDuplicate(auglag->Ce, &auglag->Ye));
169     }
170     if (!auglag->Cework) {
171       CHKERRQ(VecDuplicate(auglag->Ce, &auglag->Cework));
172     }
173   }
174   if (tao->ineq_constrained) {
175     auglag->Ci = tao->constraints_inequality;
176     auglag->Ai = tao->jacobian_inequality;
177     if (!auglag->Yi) { /* inequality multipliers */
178       CHKERRQ(VecDuplicate(auglag->Ci, &auglag->Yi));
179     }
180     if (!auglag->Ciwork) {
181       CHKERRQ(VecDuplicate(auglag->Ci, &auglag->Ciwork));
182     }
183     if (!auglag->Cizero) {
184       CHKERRQ(VecDuplicate(auglag->Ci, &auglag->Cizero));
185       CHKERRQ(VecZeroEntries(auglag->Cizero));
186     }
187     if (!auglag->Ps) { /* slack vars */
188       CHKERRQ(VecDuplicate(auglag->Ci, &auglag->Ps));
189     }
190     if (!auglag->LgradS) { /* slack component of Lagrangian gradient */
191       CHKERRQ(VecDuplicate(auglag->Ci, &auglag->LgradS));
192     }
193     /* create vector for combined primal space and the associated communication objects */
194     if (!auglag->P) {
195       CHKERRQ(PetscMalloc1(2, &auglag->Parr));
196       auglag->Parr[0] = auglag->Px; auglag->Parr[1] = auglag->Ps;
197       CHKERRQ(VecConcatenate(2, auglag->Parr, &auglag->P, &auglag->Pis));
198       CHKERRQ(PetscMalloc1(2, &auglag->Pscatter));
199       CHKERRQ(VecScatterCreate(auglag->P, auglag->Pis[0], auglag->Px, NULL, &auglag->Pscatter[0]));
200       CHKERRQ(VecScatterCreate(auglag->P, auglag->Pis[1], auglag->Ps, NULL, &auglag->Pscatter[1]));
201     }
202     if (tao->eq_constrained) {
203       /* create vector for combined dual space and the associated communication objects */
204       if (!auglag->Y) {
205         CHKERRQ(PetscMalloc1(2, &auglag->Yarr));
206         auglag->Yarr[0] = auglag->Ye; auglag->Yarr[1] = auglag->Yi;
207         CHKERRQ(VecConcatenate(2, auglag->Yarr, &auglag->Y, &auglag->Yis));
208         CHKERRQ(PetscMalloc1(2, &auglag->Yscatter));
209         CHKERRQ(VecScatterCreate(auglag->Y, auglag->Yis[0], auglag->Ye, NULL, &auglag->Yscatter[0]));
210         CHKERRQ(VecScatterCreate(auglag->Y, auglag->Yis[1], auglag->Yi, NULL, &auglag->Yscatter[1]));
211       }
212       if (!auglag->C) {
213         CHKERRQ(VecDuplicate(auglag->Y, &auglag->C));
214       }
215     } else {
216       if (!auglag->C) {
217         auglag->C = auglag->Ci;
218       }
219       if (!auglag->Y) {
220         auglag->Y = auglag->Yi;
221       }
222     }
223   } else {
224     if (!auglag->P) {
225       auglag->P = auglag->Px;
226     }
227     if (!auglag->G) {
228       auglag->G = auglag->LgradX;
229     }
230     if (!auglag->C) {
231       auglag->C = auglag->Ce;
232     }
233     if (!auglag->Y) {
234       auglag->Y = auglag->Ye;
235     }
236   }
237   /* initialize parameters */
238   if (auglag->type == TAO_ALMM_PHR) {
239     auglag->mu_fac = 10.0;
240     auglag->yi_min = 0.0;
241     auglag->ytol0 = 0.5;
242     auglag->gtol0 = tao->gatol;
243     if (tao->gatol_changed && tao->catol_changed) {
244       CHKERRQ(PetscInfo(tao,"TAOALMM with PHR: different gradient and constraint tolerances are not supported, setting catol = gatol\n"));
245       tao->catol = tao->gatol;
246     }
247   }
248   /* set the Lagrangian formulation type for the subsolver */
249   switch (auglag->type) {
250     case TAO_ALMM_CLASSIC:
251       auglag->sub_obj = TaoALMMComputeAugLagAndGradient_Private;
252       break;
253     case TAO_ALMM_PHR:
254       auglag->sub_obj = TaoALMMComputePHRLagAndGradient_Private;
255       break;
256     default:
257       break;
258   }
259   /* set up the subsolver */
260   CHKERRQ(TaoSetSolution(auglag->subsolver, auglag->P));
261   CHKERRQ(TaoSetObjective(auglag->subsolver, TaoALMMSubsolverObjective_Private, (void*)auglag));
262   CHKERRQ(TaoSetObjectiveAndGradient(auglag->subsolver, NULL, TaoALMMSubsolverObjectiveAndGradient_Private, (void*)auglag));
263   if (tao->bounded) {
264     /* make sure that the subsolver is a bound-constrained method */
265     CHKERRQ(PetscObjectTypeCompare((PetscObject)auglag->subsolver, TAOCG, &is_cg));
266     CHKERRQ(PetscObjectTypeCompare((PetscObject)auglag->subsolver, TAOLMVM, &is_lmvm));
267     if (is_cg) {
268       CHKERRQ(TaoSetType(auglag->subsolver, TAOBNCG));
269       CHKERRQ(PetscInfo(tao,"TAOCG detected for bound-constrained problem, switching to TAOBNCG instead."));
270     }
271     if (is_lmvm) {
272       CHKERRQ(TaoSetType(auglag->subsolver, TAOBQNLS));
273       CHKERRQ(PetscInfo(tao,"TAOLMVM detected for bound-constrained problem, switching to TAOBQNLS instead."));
274     }
275     /* create lower and upper bound clone vectors for subsolver */
276     if (!auglag->PL) {
277       CHKERRQ(VecDuplicate(auglag->P, &auglag->PL));
278     }
279     if (!auglag->PU) {
280       CHKERRQ(VecDuplicate(auglag->P, &auglag->PU));
281     }
282     if (tao->ineq_constrained) {
283       /* create lower and upper bounds for slack, set lower to 0 */
284       CHKERRQ(VecDuplicate(auglag->Ci, &SL));
285       CHKERRQ(VecSet(SL, 0.0));
286       CHKERRQ(VecDuplicate(auglag->Ci, &SU));
287       CHKERRQ(VecSet(SU, PETSC_INFINITY));
288       /* combine opt var bounds with slack bounds */
289       CHKERRQ(TaoALMMCombinePrimal_Private(tao, tao->XL, SL, auglag->PL));
290       CHKERRQ(TaoALMMCombinePrimal_Private(tao, tao->XU, SU, auglag->PU));
291       /* destroy work vectors */
292       CHKERRQ(VecDestroy(&SL));
293       CHKERRQ(VecDestroy(&SU));
294     } else {
295       /* no inequality constraints, just copy bounds into the subsolver */
296       CHKERRQ(VecCopy(tao->XL, auglag->PL));
297       CHKERRQ(VecCopy(tao->XU, auglag->PU));
298     }
299     CHKERRQ(TaoSetVariableBounds(auglag->subsolver, auglag->PL, auglag->PU));
300   }
301   CHKERRQ(TaoSetUp(auglag->subsolver));
302   auglag->G = auglag->subsolver->gradient;
303 
304   PetscFunctionReturn(0);
305 }
306 
307 static PetscErrorCode TaoDestroy_ALMM(Tao tao)
308 {
309   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
310 
311   PetscFunctionBegin;
312   CHKERRQ(TaoDestroy(&auglag->subsolver));
313   if (tao->setupcalled) {
314     CHKERRQ(VecDestroy(&auglag->Xwork));              /* opt work */
315     if (tao->eq_constrained) {
316       CHKERRQ(VecDestroy(&auglag->Ye));               /* equality multipliers */
317       CHKERRQ(VecDestroy(&auglag->Cework));           /* equality work vector */
318     }
319     if (tao->ineq_constrained) {
320       CHKERRQ(VecDestroy(&auglag->Ps));               /* slack vars */
321       auglag->Parr[0] = NULL;                                     /* clear pointer to tao->solution, will be destroyed by TaoDestroy() shell */
322       CHKERRQ(PetscFree(auglag->Parr));               /* array of primal vectors */
323       CHKERRQ(VecDestroy(&auglag->LgradS));           /* slack grad */
324       CHKERRQ(VecDestroy(&auglag->Cizero));           /* zero vector for pointwise max */
325       CHKERRQ(VecDestroy(&auglag->Yi));               /* inequality multipliers */
326       CHKERRQ(VecDestroy(&auglag->Ciwork));           /* inequality work vector */
327       CHKERRQ(VecDestroy(&auglag->P));                /* combo primal */
328       CHKERRQ(ISDestroy(&auglag->Pis[0]));            /* index set for X inside P */
329       CHKERRQ(ISDestroy(&auglag->Pis[1]));            /* index set for S inside P */
330       CHKERRQ(PetscFree(auglag->Pis));                /* array of P index sets */
331       CHKERRQ(VecScatterDestroy(&auglag->Pscatter[0]));
332       CHKERRQ(VecScatterDestroy(&auglag->Pscatter[1]));
333       CHKERRQ(PetscFree(auglag->Pscatter));
334       if (tao->eq_constrained) {
335         CHKERRQ(VecDestroy(&auglag->Y));              /* combo multipliers */
336         CHKERRQ(PetscFree(auglag->Yarr));             /* array of dual vectors */
337         CHKERRQ(VecDestroy(&auglag->C));              /* combo constraints */
338         CHKERRQ(ISDestroy(&auglag->Yis[0]));          /* index set for Ye inside Y */
339         CHKERRQ(ISDestroy(&auglag->Yis[1]));          /* index set for Yi inside Y */
340         CHKERRQ(PetscFree(auglag->Yis));
341         CHKERRQ(VecScatterDestroy(&auglag->Yscatter[0]));
342         CHKERRQ(VecScatterDestroy(&auglag->Yscatter[1]));
343         CHKERRQ(PetscFree(auglag->Yscatter));
344       }
345     }
346     if (tao->bounded) {
347       CHKERRQ(VecDestroy(&auglag->PL));                /* lower bounds for subsolver */
348       CHKERRQ(VecDestroy(&auglag->PU));                /* upper bounds for subsolver */
349     }
350   }
351   CHKERRQ(PetscFree(tao->data));
352   PetscFunctionReturn(0);
353 }
354 
355 static PetscErrorCode TaoSetFromOptions_ALMM(PetscOptionItems *PetscOptionsObject,Tao tao)
356 {
357   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
358   PetscInt       i;
359 
360   PetscFunctionBegin;
361   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"Augmented Lagrangian multipler method solves problems with general constraints by converting them into a sequence of unconstrained problems."));
362   CHKERRQ(PetscOptionsReal("-tao_almm_mu_init","initial penalty parameter","",auglag->mu0,&auglag->mu0,NULL));
363   CHKERRQ(PetscOptionsReal("-tao_almm_mu_factor","increase factor for the penalty parameter","",auglag->mu_fac,&auglag->mu_fac,NULL));
364   CHKERRQ(PetscOptionsReal("-tao_almm_mu_power_good","exponential for penalty parameter when multiplier update is accepted","",auglag->mu_pow_good,&auglag->mu_pow_good,NULL));
365   CHKERRQ(PetscOptionsReal("-tao_almm_mu_power_bad","exponential for penalty parameter when multiplier update is rejected","",auglag->mu_pow_bad,&auglag->mu_pow_bad,NULL));
366   CHKERRQ(PetscOptionsReal("-tao_almm_mu_max","maximum safeguard for penalty parameter updates","",auglag->mu_max,&auglag->mu_max,NULL));
367   CHKERRQ(PetscOptionsReal("-tao_almm_ye_min","minimum safeguard for equality multiplier updates","",auglag->ye_min,&auglag->ye_min,NULL));
368   CHKERRQ(PetscOptionsReal("-tao_almm_ye_max","maximum safeguard for equality multipliers updates","",auglag->ye_max,&auglag->ye_max,NULL));
369   CHKERRQ(PetscOptionsReal("-tao_almm_yi_min","minimum safeguard for inequality multipliers updates","",auglag->yi_min,&auglag->yi_min,NULL));
370   CHKERRQ(PetscOptionsReal("-tao_almm_yi_max","maximum safeguard for inequality multipliers updates","",auglag->yi_max,&auglag->yi_max,NULL));
371   CHKERRQ(PetscOptionsEnum("-tao_almm_type","augmented Lagrangian formulation type for the subproblem","TaoALMMType",TaoALMMTypes,(PetscEnum)auglag->type,(PetscEnum*)&auglag->type,NULL));
372   CHKERRQ(PetscOptionsTail());
373   CHKERRQ(TaoSetOptionsPrefix(auglag->subsolver,((PetscObject)tao)->prefix));
374   CHKERRQ(TaoAppendOptionsPrefix(auglag->subsolver,"tao_almm_subsolver_"));
375   CHKERRQ(TaoSetFromOptions(auglag->subsolver));
376   for (i=0; i<tao->numbermonitors; i++) {
377     CHKERRQ(PetscObjectReference((PetscObject)tao->monitorcontext[i]));
378     CHKERRQ(TaoSetMonitor(auglag->subsolver, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]));
379     if (tao->monitor[i] == TaoMonitorDefault || tao->monitor[i] == TaoDefaultCMonitor || tao->monitor[i] == TaoDefaultGMonitor || tao->monitor[i] == TaoDefaultSMonitor) {
380       auglag->info = PETSC_TRUE;
381     }
382   }
383   PetscFunctionReturn(0);
384 }
385 
386 /* -------------------------------------------------------- */
387 
388 /*MC
389   TaoALMM - Augmented Lagrangian multiplier method for solving nonlinear optimization problems with general constraints.
390 
391   Options Database Keys:
392 + -tao_almm_mu_init <real>       - initial penalty parameter (default: 10.)
393 . -tao_almm_mu_factor <real>     - increase factor for the penalty parameter (default: 100.)
394 . -tao_almm_mu_max <real>        - maximum safeguard for penalty parameter updates (default: 1.e20)
395 . -tao_almm_mu_power_good <real> - exponential for penalty parameter when multiplier update is accepted (default: 0.9)
396 . -tao_almm_mu_power_bad <real>  - exponential for penalty parameter when multiplier update is rejected (default: 0.1)
397 . -tao_almm_ye_min <real>        - minimum safeguard for equality multiplier updates (default: -1.e20)
398 . -tao_almm_ye_max <real>        - maximum safeguard for equality multiplier updates (default: 1.e20)
399 . -tao_almm_yi_min <real>        - minimum safeguard for inequality multiplier updates (default: -1.e20)
400 . -tao_almm_yi_max <real>        - maximum safeguard for inequality multiplier updates (default: 1.e20)
401 - -tao_almm_type <classic,phr>   - change formulation of the augmented Lagrangian merit function for the subproblem (default: classic)
402 
403   Level: beginner
404 
405   Notes:
406   This method converts a constrained problem into a sequence of unconstrained problems via the augmented
407   Lagrangian merit function. Bound constraints are pushed down to the subproblem without any modifications.
408 
409   Two formulations are offered for the subproblem: canonical Hestenes-Powell augmented Lagrangian with slack
410   variables for inequality constraints, and a slack-less Powell-Hestenes-Rockafellar (PHR) formulation utilizing a
411   pointwise max() penalty on inequality constraints. The canonical augmented Lagrangian formulation typically
412   converges faster for most problems. However, PHR may be desirable for problems featuring a large number
413   of inequality constraints because it avoids inflating the size of the subproblem with slack variables.
414 
415   The subproblem is solved using a nested first-order TAO solver. The user can retrieve a pointer to
416   the subsolver via TaoALMMGetSubsolver() or pass command line arguments to it using the
417   "-tao_almm_subsolver_" prefix. Currently, TaoALMM does not support second-order methods for the
418   subproblem. It is also highly recommended that the subsolver chosen by the user utilize a trust-region
419   strategy for globalization (default: TAOBQNKTR) especially if the outer problem features bound constraints.
420 
421 .vb
422   while unconverged
423     solve argmin_x L(x) s.t. l <= x <= u
424     if ||c|| <= y_tol
425       if ||c|| <= c_tol && ||Lgrad|| <= g_tol:
426         problem converged, return solution
427       else
428         constraints sufficiently improved
429         update multipliers and tighten tolerances
430       endif
431     else
432       constraints did not improve
433       update penalty and loosen tolerances
434     endif
435   endwhile
436 .ve
437 
438 .seealso: TaoALMMGetType(), TaoALMMSetType(), TaoALMMSetSubsolver(), TaoALMMGetSubsolver(),
439           TaoALMMGetMultipliers(), TaoALMMSetMultipliers(), TaoALMMGetPrimalIS(), TaoALMMGetDualIS()
440 M*/
441 PETSC_EXTERN PetscErrorCode TaoCreate_ALMM(Tao tao)
442 {
443   TAO_ALMM       *auglag;
444 
445   PetscFunctionBegin;
446   CHKERRQ(PetscNewLog(tao, &auglag));
447 
448   tao->ops->destroy        = TaoDestroy_ALMM;
449   tao->ops->setup          = TaoSetUp_ALMM;
450   tao->ops->setfromoptions = TaoSetFromOptions_ALMM;
451   tao->ops->view           = TaoView_ALMM;
452   tao->ops->solve          = TaoSolve_ALMM;
453 
454   tao->gatol = 1.e-5;
455   tao->grtol = 0.0;
456   tao->gttol = 0.0;
457   tao->catol = 1.e-5;
458   tao->crtol = 0.0;
459 
460   tao->data           = (void*)auglag;
461   auglag->parent      = tao;
462   auglag->mu0         = 10.0;
463   auglag->mu          = auglag->mu0;
464   auglag->mu_fac      = 10.0;
465   auglag->mu_max      = PETSC_INFINITY;
466   auglag->mu_pow_good = 0.9;
467   auglag->mu_pow_bad  = 0.1;
468   auglag->ye_min      = PETSC_NINFINITY;
469   auglag->ye_max      = PETSC_INFINITY;
470   auglag->yi_min      = PETSC_NINFINITY;
471   auglag->yi_max      = PETSC_INFINITY;
472   auglag->ytol0       = 0.1/PetscPowReal(auglag->mu0, auglag->mu_pow_bad);
473   auglag->ytol        = auglag->ytol0;
474   auglag->gtol0       = 1.0/auglag->mu0;
475   auglag->gtol        = auglag->gtol0;
476 
477   auglag->sub_obj     = TaoALMMComputeAugLagAndGradient_Private;
478   auglag->type        = TAO_ALMM_CLASSIC;
479   auglag->info        = PETSC_FALSE;
480 
481   CHKERRQ(TaoCreate(PetscObjectComm((PetscObject)tao),&auglag->subsolver));
482   CHKERRQ(TaoSetType(auglag->subsolver, TAOBQNKTR));
483   CHKERRQ(TaoSetTolerances(auglag->subsolver, auglag->gtol, 0.0, 0.0));
484   CHKERRQ(TaoSetMaximumIterations(auglag->subsolver, 1000));
485   CHKERRQ(TaoSetMaximumFunctionEvaluations(auglag->subsolver, 10000));
486   CHKERRQ(TaoSetFunctionLowerBound(auglag->subsolver, PETSC_NINFINITY));
487   CHKERRQ(PetscObjectIncrementTabLevel((PetscObject)auglag->subsolver,(PetscObject)tao,1));
488 
489   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetType_C", TaoALMMGetType_Private));
490   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetType_C", TaoALMMSetType_Private));
491   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetSubsolver_C", TaoALMMGetSubsolver_Private));
492   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetSubsolver_C", TaoALMMSetSubsolver_Private));
493   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetMultipliers_C", TaoALMMGetMultipliers_Private));
494   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetMultipliers_C", TaoALMMSetMultipliers_Private));
495   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetPrimalIS_C", TaoALMMGetPrimalIS_Private));
496   CHKERRQ(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetDualIS_C", TaoALMMGetDualIS_Private));
497   PetscFunctionReturn(0);
498 }
499 
500 static PetscErrorCode TaoALMMCombinePrimal_Private(Tao tao, Vec X, Vec S, Vec P)
501 {
502   TAO_ALMM     *auglag = (TAO_ALMM*)tao->data;
503 
504   PetscFunctionBegin;
505   if (tao->ineq_constrained) {
506     CHKERRQ(VecScatterBegin(auglag->Pscatter[0], X, P, INSERT_VALUES, SCATTER_REVERSE));
507     CHKERRQ(VecScatterEnd(auglag->Pscatter[0], X, P, INSERT_VALUES, SCATTER_REVERSE));
508     CHKERRQ(VecScatterBegin(auglag->Pscatter[1], S, P, INSERT_VALUES, SCATTER_REVERSE));
509     CHKERRQ(VecScatterEnd(auglag->Pscatter[1], S, P, INSERT_VALUES, SCATTER_REVERSE));
510   } else {
511     CHKERRQ(VecCopy(X, P));
512   }
513   PetscFunctionReturn(0);
514 }
515 
516 static PetscErrorCode TaoALMMCombineDual_Private(Tao tao, Vec EQ, Vec IN, Vec Y)
517 {
518   TAO_ALMM     *auglag = (TAO_ALMM*)tao->data;
519 
520   PetscFunctionBegin;
521   if (tao->eq_constrained) {
522     if (tao->ineq_constrained) {
523       CHKERRQ(VecScatterBegin(auglag->Yscatter[0], EQ, Y, INSERT_VALUES, SCATTER_REVERSE));
524       CHKERRQ(VecScatterEnd(auglag->Yscatter[0], EQ, Y, INSERT_VALUES, SCATTER_REVERSE));
525       CHKERRQ(VecScatterBegin(auglag->Yscatter[1], IN, Y, INSERT_VALUES, SCATTER_REVERSE));
526       CHKERRQ(VecScatterEnd(auglag->Yscatter[1], IN, Y, INSERT_VALUES, SCATTER_REVERSE));
527     } else {
528       CHKERRQ(VecCopy(EQ, Y));
529     }
530   } else {
531     CHKERRQ(VecCopy(IN, Y));
532   }
533   PetscFunctionReturn(0);
534 }
535 
536 static PetscErrorCode TaoALMMSplitPrimal_Private(Tao tao, Vec P, Vec X, Vec S)
537 {
538   TAO_ALMM     *auglag = (TAO_ALMM*)tao->data;
539 
540   PetscFunctionBegin;
541   if (tao->ineq_constrained) {
542     CHKERRQ(VecScatterBegin(auglag->Pscatter[0], P, X, INSERT_VALUES, SCATTER_FORWARD));
543     CHKERRQ(VecScatterEnd(auglag->Pscatter[0], P, X, INSERT_VALUES, SCATTER_FORWARD));
544     CHKERRQ(VecScatterBegin(auglag->Pscatter[1], P, S, INSERT_VALUES, SCATTER_FORWARD));
545     CHKERRQ(VecScatterEnd(auglag->Pscatter[1], P, S, INSERT_VALUES, SCATTER_FORWARD));
546   } else {
547     CHKERRQ(VecCopy(P, X));
548   }
549   PetscFunctionReturn(0);
550 }
551 
552 /* this assumes that the latest constraints are stored in Ce and Ci, and also combined in C */
553 static PetscErrorCode TaoALMMComputeOptimalityNorms_Private(Tao tao)
554 {
555   TAO_ALMM     *auglag = (TAO_ALMM*)tao->data;
556 
557   PetscFunctionBegin;
558   /* if bounded, project the gradient */
559   if (tao->bounded) {
560     CHKERRQ(VecBoundGradientProjection(auglag->LgradX, auglag->Px, tao->XL, tao->XU, auglag->LgradX));
561   }
562   if (auglag->type == TAO_ALMM_PHR) {
563     CHKERRQ(VecNorm(auglag->LgradX, NORM_INFINITY, &auglag->gnorm));
564     auglag->cenorm = 0.0;
565     if (tao->eq_constrained) {
566       CHKERRQ(VecNorm(auglag->Ce, NORM_INFINITY, &auglag->cenorm));
567     }
568     auglag->cinorm = 0.0;
569     if (tao->ineq_constrained) {
570       CHKERRQ(VecCopy(auglag->Yi, auglag->Ciwork));
571       CHKERRQ(VecScale(auglag->Ciwork, -1.0/auglag->mu));
572       CHKERRQ(VecPointwiseMax(auglag->Ciwork, auglag->Ci, auglag->Ciwork));
573       CHKERRQ(VecNorm(auglag->Ciwork, NORM_INFINITY, &auglag->cinorm));
574     }
575     auglag->cnorm_old = auglag->cnorm;
576     auglag->cnorm = PetscMax(auglag->cenorm, auglag->cinorm);
577     auglag->ytol = auglag->ytol0 * auglag->cnorm_old;
578   } else {
579     CHKERRQ(VecNorm(auglag->LgradX, NORM_2, &auglag->gnorm));
580     CHKERRQ(VecNorm(auglag->C, NORM_2, &auglag->cnorm));
581   }
582   PetscFunctionReturn(0);
583 }
584 
585 static PetscErrorCode TaoALMMEvaluateIterate_Private(Tao tao, Vec P)
586 {
587   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
588 
589   PetscFunctionBegin;
590   /* split solution into primal and slack components */
591   CHKERRQ(TaoALMMSplitPrimal_Private(tao, auglag->P, auglag->Px, auglag->Ps));
592 
593   /* compute f, df/dx and the constraints */
594   CHKERRQ(TaoComputeObjectiveAndGradient(tao, auglag->Px, &auglag->fval, auglag->LgradX));
595   if (tao->eq_constrained) {
596     CHKERRQ(TaoComputeEqualityConstraints(tao, auglag->Px, auglag->Ce));
597     CHKERRQ(TaoComputeJacobianEquality(tao, auglag->Px, auglag->Ae, auglag->Ae));
598   }
599   if (tao->ineq_constrained) {
600     CHKERRQ(TaoComputeInequalityConstraints(tao, auglag->Px, auglag->Ci));
601     CHKERRQ(TaoComputeJacobianInequality(tao, auglag->Px, auglag->Ai, auglag->Ai));
602     switch (auglag->type) {
603       case TAO_ALMM_CLASSIC:
604         /* classic formulation converts inequality to equality constraints via slack variables */
605         CHKERRQ(VecAXPY(auglag->Ci, -1.0, auglag->Ps));
606         break;
607       case TAO_ALMM_PHR:
608         /* PHR is based on Ci <= 0 while TAO defines Ci >= 0 so we hit it with a negative sign */
609         CHKERRQ(VecScale(auglag->Ci, -1.0));
610         CHKERRQ(MatScale(auglag->Ai, -1.0));
611         break;
612       default:
613         break;
614     }
615   }
616   /* combine constraints into one vector */
617   CHKERRQ(TaoALMMCombineDual_Private(tao, auglag->Ce, auglag->Ci, auglag->C));
618   PetscFunctionReturn(0);
619 }
620 
621 /*
622 Lphr = f + 0.5*mu*[ (Ce + Ye/mu)^T (Ce + Ye/mu) + pmin(0, Ci + Yi/mu)^T pmin(0, Ci + Yi/mu)]
623 
624 dLphr/dX = dF/dX + mu*[ (Ce + Ye/mu)^T Ae + pmin(0, Ci + Yi/mu)^T Ai]
625 
626 dLphr/dS = 0
627 */
628 static PetscErrorCode TaoALMMComputePHRLagAndGradient_Private(Tao tao)
629 {
630   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
631   PetscReal      eq_norm=0.0, ineq_norm=0.0;
632 
633   PetscFunctionBegin;
634   CHKERRQ(TaoALMMEvaluateIterate_Private(tao, auglag->P));
635   if (tao->eq_constrained) {
636     /* Ce_work = mu*(Ce + Ye/mu) */
637     CHKERRQ(VecWAXPY(auglag->Cework, 1.0/auglag->mu, auglag->Ye, auglag->Ce));
638     CHKERRQ(VecDot(auglag->Cework, auglag->Cework, &eq_norm)); /* contribution to scalar Lagrangian */
639     CHKERRQ(VecScale(auglag->Cework, auglag->mu));
640     /* dL/dX += mu*(Ce + Ye/mu)^T Ae */
641     CHKERRQ(MatMultTransposeAdd(auglag->Ae, auglag->Cework, auglag->LgradX, auglag->LgradX));
642   }
643   if (tao->ineq_constrained) {
644     /* Ci_work = mu * pmax(0, Ci + Yi/mu) where pmax() is pointwise max() */
645     CHKERRQ(VecWAXPY(auglag->Ciwork, 1.0/auglag->mu, auglag->Yi, auglag->Ci));
646     CHKERRQ(VecPointwiseMax(auglag->Ciwork, auglag->Cizero, auglag->Ciwork));
647     CHKERRQ(VecDot(auglag->Ciwork, auglag->Ciwork, &ineq_norm)); /* contribution to scalar Lagrangian */
648     /* dL/dX += mu * pmax(0, Ci + Yi/mu)^T Ai */
649     CHKERRQ(VecScale(auglag->Ciwork, auglag->mu));
650     CHKERRQ(MatMultTransposeAdd(auglag->Ai, auglag->Ciwork, auglag->LgradX, auglag->LgradX));
651     /* dL/dS = 0 because there are no slacks in PHR */
652     CHKERRQ(VecZeroEntries(auglag->LgradS));
653   }
654   /* combine gradient together */
655   CHKERRQ(TaoALMMCombinePrimal_Private(tao, auglag->LgradX, auglag->LgradS, auglag->G));
656   /* compute L = f + 0.5 * mu * [(Ce + Ye/mu)^T (Ce + Ye/mu) + pmax(0, Ci + Yi/mu)^T pmax(0, Ci + Yi/mu)] */
657   auglag->Lval = auglag->fval + 0.5*auglag->mu*(eq_norm + ineq_norm);
658   PetscFunctionReturn(0);
659 }
660 
661 /*
662 Lc = F + Ye^TCe + Yi^T(Ci - S) + 0.5*mu*[Ce^TCe + (Ci - S)^T(Ci - S)]
663 
664 dLc/dX = dF/dX + Ye^TAe + Yi^TAi + 0.5*mu*[Ce^TAe + (Ci - S)^TAi]
665 
666 dLc/dS = -[Yi + mu*(Ci - S)]
667 */
668 static PetscErrorCode TaoALMMComputeAugLagAndGradient_Private(Tao tao)
669 {
670   TAO_ALMM       *auglag = (TAO_ALMM*)tao->data;
671   PetscReal      yeTce=0.0, yiTcims=0.0, ceTce=0.0, cimsTcims=0.0;
672 
673   PetscFunctionBegin;
674   CHKERRQ(TaoALMMEvaluateIterate_Private(tao, auglag->P));
675   if (tao->eq_constrained) {
676     /* compute scalar contributions */
677     CHKERRQ(VecDot(auglag->Ye, auglag->Ce, &yeTce));
678     CHKERRQ(VecDot(auglag->Ce, auglag->Ce, &ceTce));
679     /* dL/dX += ye^T Ae */
680     CHKERRQ(MatMultTransposeAdd(auglag->Ae, auglag->Ye, auglag->LgradX, auglag->LgradX));
681     /* dL/dX += mu * ce^T Ae */
682     CHKERRQ(MatMultTranspose(auglag->Ae, auglag->Ce, auglag->Xwork));
683     CHKERRQ(VecAXPY(auglag->LgradX, auglag->mu, auglag->Xwork));
684   }
685   if (tao->ineq_constrained) {
686     /* compute scalar contributions */
687     CHKERRQ(VecDot(auglag->Yi, auglag->Ci, &yiTcims));
688     CHKERRQ(VecDot(auglag->Ci, auglag->Ci, &cimsTcims));
689     /* dL/dX += yi^T Ai */
690     CHKERRQ(MatMultTransposeAdd(auglag->Ai, auglag->Yi, auglag->LgradX, auglag->LgradX));
691     /* dL/dX += mu * (ci - s)^T Ai */
692     CHKERRQ(MatMultTranspose(auglag->Ai, auglag->Ci, auglag->Xwork));
693     CHKERRQ(VecAXPY(auglag->LgradX, auglag->mu, auglag->Xwork));
694     /* dL/dS = -[yi + mu*(ci - s)] */
695     CHKERRQ(VecWAXPY(auglag->LgradS, auglag->mu, auglag->Ci, auglag->Yi));
696     CHKERRQ(VecScale(auglag->LgradS, -1.0));
697   }
698   /* combine gradient together */
699   CHKERRQ(TaoALMMCombinePrimal_Private(tao, auglag->LgradX, auglag->LgradS, auglag->G));
700   /* compute L = f + ye^T ce + yi^T (ci - s) + 0.5*mu*||ce||^2 + 0.5*mu*||ci - s||^2 */
701   auglag->Lval = auglag->fval + yeTce + yiTcims + 0.5*auglag->mu*(ceTce + cimsTcims);
702   PetscFunctionReturn(0);
703 }
704 
705 PetscErrorCode TaoALMMSubsolverObjective_Private(Tao tao, Vec P, PetscReal *Lval, void *ctx)
706 {
707   TAO_ALMM       *auglag = (TAO_ALMM*)ctx;
708 
709   PetscFunctionBegin;
710   CHKERRQ(VecCopy(P, auglag->P));
711   CHKERRQ((*auglag->sub_obj)(auglag->parent));
712   *Lval = auglag->Lval;
713   PetscFunctionReturn(0);
714 }
715 
716 PetscErrorCode TaoALMMSubsolverObjectiveAndGradient_Private(Tao tao, Vec P, PetscReal *Lval, Vec G, void *ctx)
717 {
718   TAO_ALMM       *auglag = (TAO_ALMM*)ctx;
719 
720   PetscFunctionBegin;
721   CHKERRQ(VecCopy(P, auglag->P));
722   CHKERRQ((*auglag->sub_obj)(auglag->parent));
723   CHKERRQ(VecCopy(auglag->G, G));
724   *Lval = auglag->Lval;
725   PetscFunctionReturn(0);
726 }
727