xref: /petsc/src/tao/constrained/impls/almm/almm.c (revision 606f75f6cc59668c96bea874c028626c3caf5cd3)
1954e39ddSJose E. Roman #include <../src/tao/constrained/impls/almm/almm.h> /*I "petsctao.h" I*/
2661095bbSAlp Dener #include <petsctao.h>
3661095bbSAlp Dener #include <petsc/private/petscimpl.h>
4661095bbSAlp Dener #include <petsc/private/vecimpl.h>
5661095bbSAlp Dener 
6661095bbSAlp Dener static PetscErrorCode TaoALMMCombinePrimal_Private(Tao, Vec, Vec, Vec);
7661095bbSAlp Dener static PetscErrorCode TaoALMMCombineDual_Private(Tao, Vec, Vec, Vec);
8661095bbSAlp Dener static PetscErrorCode TaoALMMSplitPrimal_Private(Tao, Vec, Vec, Vec);
9661095bbSAlp Dener static PetscErrorCode TaoALMMComputeOptimalityNorms_Private(Tao);
10661095bbSAlp Dener static PetscErrorCode TaoALMMComputeAugLagAndGradient_Private(Tao);
11661095bbSAlp Dener static PetscErrorCode TaoALMMComputePHRLagAndGradient_Private(Tao);
12661095bbSAlp Dener 
13d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSolve_ALMM(Tao tao)
14d71ae5a4SJacob Faibussowitsch {
15661095bbSAlp Dener   TAO_ALMM          *auglag = (TAO_ALMM *)tao->data;
16661095bbSAlp Dener   TaoConvergedReason reason;
17661095bbSAlp Dener   PetscReal          updated;
18661095bbSAlp Dener 
19661095bbSAlp Dener   PetscFunctionBegin;
20661095bbSAlp Dener   /* reset initial multiplier/slack guess */
21661095bbSAlp Dener   if (!tao->recycle) {
22661095bbSAlp Dener     if (tao->ineq_constrained) {
239566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(auglag->Ps));
249566063dSJacob Faibussowitsch       PetscCall(TaoALMMCombinePrimal_Private(tao, auglag->Px, auglag->Ps, auglag->P));
259a09327dSAlp Dener       PetscCall(VecSet(auglag->Yi, 1.0));
26661095bbSAlp Dener     }
279a09327dSAlp Dener     if (tao->eq_constrained) PetscCall(VecSet(auglag->Ye, 1.0));
28661095bbSAlp Dener   }
29661095bbSAlp Dener 
30661095bbSAlp Dener   /* compute initial nonlinear Lagrangian and its derivatives */
319566063dSJacob Faibussowitsch   PetscCall((*auglag->sub_obj)(tao));
329566063dSJacob Faibussowitsch   PetscCall(TaoALMMComputeOptimalityNorms_Private(tao));
33661095bbSAlp Dener   /* print initial step and check convergence */
349566063dSJacob Faibussowitsch   PetscCall(PetscInfo(tao, "Solving with %s formulation\n", TaoALMMTypes[auglag->type]));
359566063dSJacob Faibussowitsch   PetscCall(TaoLogConvergenceHistory(tao, auglag->Lval, auglag->gnorm, auglag->cnorm, tao->ksp_its));
369566063dSJacob Faibussowitsch   PetscCall(TaoMonitor(tao, tao->niter, auglag->fval, auglag->gnorm, auglag->cnorm, 0.0));
37dbbe0bcdSBarry Smith   PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
38661095bbSAlp Dener   /* set initial penalty factor and inner solver tolerance */
39661095bbSAlp Dener   switch (auglag->type) {
40d71ae5a4SJacob Faibussowitsch   case TAO_ALMM_CLASSIC:
41d71ae5a4SJacob Faibussowitsch     auglag->mu = auglag->mu0;
42d71ae5a4SJacob Faibussowitsch     break;
437721a36fSStefano Zampini   case TAO_ALMM_PHR:
44661095bbSAlp Dener     auglag->cenorm = 0.0;
4548a46eb9SPierre Jolivet     if (tao->eq_constrained) PetscCall(VecDot(auglag->Ce, auglag->Ce, &auglag->cenorm));
46661095bbSAlp Dener     auglag->cinorm = 0.0;
47661095bbSAlp Dener     if (tao->ineq_constrained) {
489566063dSJacob Faibussowitsch       PetscCall(VecCopy(auglag->Ci, auglag->Ciwork));
499566063dSJacob Faibussowitsch       PetscCall(VecScale(auglag->Ciwork, -1.0));
509566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMax(auglag->Ciwork, auglag->Cizero, auglag->Ciwork));
519566063dSJacob Faibussowitsch       PetscCall(VecDot(auglag->Ciwork, auglag->Ciwork, &auglag->cinorm));
52661095bbSAlp Dener     }
53661095bbSAlp Dener     /* determine initial penalty factor based on the balance of constraint violation and objective function value */
54661095bbSAlp Dener     auglag->mu = PetscMax(1.e-6, PetscMin(10.0, 2.0 * PetscAbsReal(auglag->fval) / (auglag->cenorm + auglag->cinorm)));
55661095bbSAlp Dener     break;
56d71ae5a4SJacob Faibussowitsch   default:
57d71ae5a4SJacob Faibussowitsch     break;
58661095bbSAlp Dener   }
59661095bbSAlp Dener   auglag->gtol = auglag->gtol0;
6063a3b9bcSJacob Faibussowitsch   PetscCall(PetscInfo(tao, "Initial penalty: %.2g\n", (double)auglag->mu));
61661095bbSAlp Dener 
62661095bbSAlp Dener   /* start aug-lag outer loop */
63661095bbSAlp Dener   while (tao->reason == TAO_CONTINUE_ITERATING) {
64661095bbSAlp Dener     ++tao->niter;
65661095bbSAlp Dener     /* update subsolver tolerance */
6663a3b9bcSJacob Faibussowitsch     PetscCall(PetscInfo(tao, "Subsolver tolerance: ||G|| <= %e\n", (double)auglag->gtol));
679566063dSJacob Faibussowitsch     PetscCall(TaoSetTolerances(auglag->subsolver, auglag->gtol, 0.0, 0.0));
68661095bbSAlp Dener     /* solve the bound-constrained or unconstrained subproblem */
699a09327dSAlp Dener     PetscCall(VecCopy(auglag->P, auglag->subsolver->solution));
709566063dSJacob Faibussowitsch     PetscCall(TaoSolve(auglag->subsolver));
719a09327dSAlp Dener     PetscCall(VecCopy(auglag->subsolver->solution, auglag->P));
729566063dSJacob Faibussowitsch     PetscCall(TaoGetConvergedReason(auglag->subsolver, &reason));
73661095bbSAlp Dener     tao->ksp_its += auglag->subsolver->ksp_its;
7448a46eb9SPierre Jolivet     if (reason != TAO_CONVERGED_GATOL) PetscCall(PetscInfo(tao, "Subsolver failed to converge, reason: %s\n", TaoConvergedReasons[reason]));
75661095bbSAlp Dener     /* evaluate solution and test convergence */
769566063dSJacob Faibussowitsch     PetscCall((*auglag->sub_obj)(tao));
779566063dSJacob Faibussowitsch     PetscCall(TaoALMMComputeOptimalityNorms_Private(tao));
78661095bbSAlp Dener     /* decide whether to update multipliers or not */
79661095bbSAlp Dener     updated = 0.0;
80661095bbSAlp Dener     if (auglag->cnorm <= auglag->ytol) {
8163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(tao, "Multipliers updated: ||C|| <= %e\n", (double)auglag->ytol));
82661095bbSAlp Dener       /* constraints are good, update multipliers and convergence tolerances */
83661095bbSAlp Dener       if (tao->eq_constrained) {
849566063dSJacob Faibussowitsch         PetscCall(VecAXPY(auglag->Ye, auglag->mu, auglag->Ce));
859566063dSJacob Faibussowitsch         PetscCall(VecSet(auglag->Cework, auglag->ye_max));
869566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMin(auglag->Ye, auglag->Cework, auglag->Ye));
879566063dSJacob Faibussowitsch         PetscCall(VecSet(auglag->Cework, auglag->ye_min));
889566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMax(auglag->Ye, auglag->Cework, auglag->Ye));
89661095bbSAlp Dener       }
90661095bbSAlp Dener       if (tao->ineq_constrained) {
919566063dSJacob Faibussowitsch         PetscCall(VecAXPY(auglag->Yi, auglag->mu, auglag->Ci));
929566063dSJacob Faibussowitsch         PetscCall(VecSet(auglag->Ciwork, auglag->yi_max));
939566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMin(auglag->Yi, auglag->Ciwork, auglag->Yi));
949566063dSJacob Faibussowitsch         PetscCall(VecSet(auglag->Ciwork, auglag->yi_min));
959566063dSJacob Faibussowitsch         PetscCall(VecPointwiseMax(auglag->Yi, auglag->Ciwork, auglag->Yi));
96661095bbSAlp Dener       }
97661095bbSAlp Dener       /* tolerances are updated only for non-PHR methods */
98661095bbSAlp Dener       if (auglag->type != TAO_ALMM_PHR) {
99661095bbSAlp Dener         auglag->ytol = PetscMax(tao->catol, auglag->ytol / PetscPowReal(auglag->mu, auglag->mu_pow_good));
100661095bbSAlp Dener         auglag->gtol = PetscMax(tao->gatol, auglag->gtol / auglag->mu);
101661095bbSAlp Dener       }
102661095bbSAlp Dener       updated = 1.0;
103661095bbSAlp Dener     } else {
104661095bbSAlp Dener       /* constraints are bad, update penalty factor */
105661095bbSAlp Dener       auglag->mu = PetscMin(auglag->mu_max, auglag->mu_fac * auglag->mu);
106661095bbSAlp Dener       /* tolerances are reset only for non-PHR methods */
107661095bbSAlp Dener       if (auglag->type != TAO_ALMM_PHR) {
108661095bbSAlp Dener         auglag->ytol = PetscMax(tao->catol, 0.1 / PetscPowReal(auglag->mu, auglag->mu_pow_bad));
109661095bbSAlp Dener         auglag->gtol = PetscMax(tao->gatol, 1.0 / auglag->mu);
110661095bbSAlp Dener       }
11163a3b9bcSJacob Faibussowitsch       PetscCall(PetscInfo(tao, "Penalty increased: mu = %.2g\n", (double)auglag->mu));
112661095bbSAlp Dener     }
1139566063dSJacob Faibussowitsch     PetscCall(TaoLogConvergenceHistory(tao, auglag->fval, auglag->gnorm, auglag->cnorm, tao->ksp_its));
1149566063dSJacob Faibussowitsch     PetscCall(TaoMonitor(tao, tao->niter, auglag->fval, auglag->gnorm, auglag->cnorm, updated));
115dbbe0bcdSBarry Smith     PetscUseTypeMethod(tao, convergencetest, tao->cnvP);
116661095bbSAlp Dener   }
1173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
118661095bbSAlp Dener }
119661095bbSAlp Dener 
120d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoView_ALMM(Tao tao, PetscViewer viewer)
121d71ae5a4SJacob Faibussowitsch {
122661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
123661095bbSAlp Dener   PetscBool isascii;
124661095bbSAlp Dener 
125661095bbSAlp Dener   PetscFunctionBegin;
1269566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPushTab(viewer));
1279566063dSJacob Faibussowitsch   PetscCall(TaoView(auglag->subsolver, viewer));
1289566063dSJacob Faibussowitsch   PetscCall(PetscViewerASCIIPopTab(viewer));
1299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
130661095bbSAlp Dener   if (isascii) {
1319566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPushTab(viewer));
1329566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPrintf(viewer, "ALMM Formulation Type: %s\n", TaoALMMTypes[auglag->type]));
1339566063dSJacob Faibussowitsch     PetscCall(PetscViewerASCIIPopTab(viewer));
134661095bbSAlp Dener   }
1353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
136661095bbSAlp Dener }
137661095bbSAlp Dener 
138d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetUp_ALMM(Tao tao)
139d71ae5a4SJacob Faibussowitsch {
140661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
141661095bbSAlp Dener   VecType   vec_type;
142661095bbSAlp Dener   Vec       SL, SU;
143661095bbSAlp Dener   PetscBool is_cg = PETSC_FALSE, is_lmvm = PETSC_FALSE;
144661095bbSAlp Dener 
145661095bbSAlp Dener   PetscFunctionBegin;
14669d47153SPierre Jolivet   PetscCheck(!tao->ineq_doublesided, PetscObjectComm((PetscObject)tao), PETSC_ERR_ARG_WRONGSTATE, "TAOALMM does not support double-sided inequality constraint definition. Please restructure your inequality constraint to fit the form c(x) >= 0.");
1473c859ba3SBarry Smith   PetscCheck(tao->eq_constrained || tao->ineq_constrained, PetscObjectComm((PetscObject)tao), PETSC_ERR_ORDER, "Equality and/or inequality constraints must be defined before solver setup.");
1489566063dSJacob Faibussowitsch   PetscCall(TaoComputeVariableBounds(tao));
149661095bbSAlp Dener   /* alias base vectors and create extras */
1509566063dSJacob Faibussowitsch   PetscCall(VecGetType(tao->solution, &vec_type));
151661095bbSAlp Dener   auglag->Px = tao->solution;
152661095bbSAlp Dener   if (!tao->gradient) { /* base gradient */
1539566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution, &tao->gradient));
154661095bbSAlp Dener   }
155661095bbSAlp Dener   auglag->LgradX = tao->gradient;
156661095bbSAlp Dener   if (!auglag->Xwork) { /* opt var work vector */
1579566063dSJacob Faibussowitsch     PetscCall(VecDuplicate(tao->solution, &auglag->Xwork));
158661095bbSAlp Dener   }
159661095bbSAlp Dener   if (tao->eq_constrained) {
160661095bbSAlp Dener     auglag->Ce = tao->constraints_equality;
161661095bbSAlp Dener     auglag->Ae = tao->jacobian_equality;
162661095bbSAlp Dener     if (!auglag->Ye) { /* equality multipliers */
1639566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ce, &auglag->Ye));
164661095bbSAlp Dener     }
16548a46eb9SPierre Jolivet     if (!auglag->Cework) PetscCall(VecDuplicate(auglag->Ce, &auglag->Cework));
166661095bbSAlp Dener   }
167661095bbSAlp Dener   if (tao->ineq_constrained) {
168661095bbSAlp Dener     auglag->Ci = tao->constraints_inequality;
169661095bbSAlp Dener     auglag->Ai = tao->jacobian_inequality;
170661095bbSAlp Dener     if (!auglag->Yi) { /* inequality multipliers */
1719566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &auglag->Yi));
172661095bbSAlp Dener     }
17348a46eb9SPierre Jolivet     if (!auglag->Ciwork) PetscCall(VecDuplicate(auglag->Ci, &auglag->Ciwork));
174661095bbSAlp Dener     if (!auglag->Cizero) {
1759566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &auglag->Cizero));
1769566063dSJacob Faibussowitsch       PetscCall(VecZeroEntries(auglag->Cizero));
177661095bbSAlp Dener     }
178661095bbSAlp Dener     if (!auglag->Ps) { /* slack vars */
1799566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &auglag->Ps));
180661095bbSAlp Dener     }
181661095bbSAlp Dener     if (!auglag->LgradS) { /* slack component of Lagrangian gradient */
1829566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &auglag->LgradS));
183661095bbSAlp Dener     }
184661095bbSAlp Dener     /* create vector for combined primal space and the associated communication objects */
185661095bbSAlp Dener     if (!auglag->P) {
1869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(2, &auglag->Parr));
1879371c9d4SSatish Balay       auglag->Parr[0] = auglag->Px;
1889371c9d4SSatish Balay       auglag->Parr[1] = auglag->Ps;
1899566063dSJacob Faibussowitsch       PetscCall(VecConcatenate(2, auglag->Parr, &auglag->P, &auglag->Pis));
1909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(2, &auglag->Pscatter));
1919566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(auglag->P, auglag->Pis[0], auglag->Px, NULL, &auglag->Pscatter[0]));
1929566063dSJacob Faibussowitsch       PetscCall(VecScatterCreate(auglag->P, auglag->Pis[1], auglag->Ps, NULL, &auglag->Pscatter[1]));
193661095bbSAlp Dener     }
194661095bbSAlp Dener     if (tao->eq_constrained) {
195661095bbSAlp Dener       /* create vector for combined dual space and the associated communication objects */
196661095bbSAlp Dener       if (!auglag->Y) {
1979566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(2, &auglag->Yarr));
1989371c9d4SSatish Balay         auglag->Yarr[0] = auglag->Ye;
1999371c9d4SSatish Balay         auglag->Yarr[1] = auglag->Yi;
2009566063dSJacob Faibussowitsch         PetscCall(VecConcatenate(2, auglag->Yarr, &auglag->Y, &auglag->Yis));
2019566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(2, &auglag->Yscatter));
2029566063dSJacob Faibussowitsch         PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[0], auglag->Ye, NULL, &auglag->Yscatter[0]));
2039566063dSJacob Faibussowitsch         PetscCall(VecScatterCreate(auglag->Y, auglag->Yis[1], auglag->Yi, NULL, &auglag->Yscatter[1]));
204661095bbSAlp Dener       }
20548a46eb9SPierre Jolivet       if (!auglag->C) PetscCall(VecDuplicate(auglag->Y, &auglag->C));
2069371c9d4SSatish Balay     } else {
207ad540459SPierre Jolivet       if (!auglag->C) auglag->C = auglag->Ci;
208ad540459SPierre Jolivet       if (!auglag->Y) auglag->Y = auglag->Yi;
209661095bbSAlp Dener     }
210661095bbSAlp Dener   } else {
211ad540459SPierre Jolivet     if (!auglag->P) auglag->P = auglag->Px;
212ad540459SPierre Jolivet     if (!auglag->G) auglag->G = auglag->LgradX;
213ad540459SPierre Jolivet     if (!auglag->C) auglag->C = auglag->Ce;
214ad540459SPierre Jolivet     if (!auglag->Y) auglag->Y = auglag->Ye;
215661095bbSAlp Dener   }
2169a09327dSAlp Dener   /* create tao primal solution and gradient to interface with subsolver */
2179a09327dSAlp Dener   PetscCall(VecDuplicate(auglag->P, &auglag->Psub));
2189a09327dSAlp Dener   PetscCall(VecDuplicate(auglag->P, &auglag->G));
219661095bbSAlp Dener   /* initialize parameters */
220661095bbSAlp Dener   if (auglag->type == TAO_ALMM_PHR) {
221661095bbSAlp Dener     auglag->mu_fac = 10.0;
222661095bbSAlp Dener     auglag->yi_min = 0.0;
223661095bbSAlp Dener     auglag->ytol0  = 0.5;
224661095bbSAlp Dener     auglag->gtol0  = tao->gatol;
225*606f75f6SBarry Smith     if (tao->gatol != tao->default_gatol && tao->catol != tao->default_catol) {
2269566063dSJacob Faibussowitsch       PetscCall(PetscInfo(tao, "TAOALMM with PHR: different gradient and constraint tolerances are not supported, setting catol = gatol\n"));
227661095bbSAlp Dener       tao->catol = tao->gatol;
228661095bbSAlp Dener     }
229661095bbSAlp Dener   }
230661095bbSAlp Dener   /* set the Lagrangian formulation type for the subsolver */
231661095bbSAlp Dener   switch (auglag->type) {
232d71ae5a4SJacob Faibussowitsch   case TAO_ALMM_CLASSIC:
233d71ae5a4SJacob Faibussowitsch     auglag->sub_obj = TaoALMMComputeAugLagAndGradient_Private;
234d71ae5a4SJacob Faibussowitsch     break;
235d71ae5a4SJacob Faibussowitsch   case TAO_ALMM_PHR:
236d71ae5a4SJacob Faibussowitsch     auglag->sub_obj = TaoALMMComputePHRLagAndGradient_Private;
237d71ae5a4SJacob Faibussowitsch     break;
238d71ae5a4SJacob Faibussowitsch   default:
239d71ae5a4SJacob Faibussowitsch     break;
240661095bbSAlp Dener   }
241661095bbSAlp Dener   /* set up the subsolver */
2429a09327dSAlp Dener   PetscCall(TaoSetSolution(auglag->subsolver, auglag->Psub));
2439566063dSJacob Faibussowitsch   PetscCall(TaoSetObjective(auglag->subsolver, TaoALMMSubsolverObjective_Private, (void *)auglag));
2449566063dSJacob Faibussowitsch   PetscCall(TaoSetObjectiveAndGradient(auglag->subsolver, NULL, TaoALMMSubsolverObjectiveAndGradient_Private, (void *)auglag));
245661095bbSAlp Dener   if (tao->bounded) {
246661095bbSAlp Dener     /* make sure that the subsolver is a bound-constrained method */
2479566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)auglag->subsolver, TAOCG, &is_cg));
2489566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)auglag->subsolver, TAOLMVM, &is_lmvm));
249661095bbSAlp Dener     if (is_cg) {
2509566063dSJacob Faibussowitsch       PetscCall(TaoSetType(auglag->subsolver, TAOBNCG));
2519d3446b2SPierre Jolivet       PetscCall(PetscInfo(tao, "TAOCG detected for bound-constrained problem, switching to TAOBNCG.\n"));
252661095bbSAlp Dener     }
253661095bbSAlp Dener     if (is_lmvm) {
2549566063dSJacob Faibussowitsch       PetscCall(TaoSetType(auglag->subsolver, TAOBQNLS));
2559d3446b2SPierre Jolivet       PetscCall(PetscInfo(tao, "TAOLMVM detected for bound-constrained problem, switching to TAOBQNLS.\n"));
256661095bbSAlp Dener     }
257661095bbSAlp Dener     /* create lower and upper bound clone vectors for subsolver */
25848a46eb9SPierre Jolivet     if (!auglag->PL) PetscCall(VecDuplicate(auglag->P, &auglag->PL));
25948a46eb9SPierre Jolivet     if (!auglag->PU) PetscCall(VecDuplicate(auglag->P, &auglag->PU));
260661095bbSAlp Dener     if (tao->ineq_constrained) {
261661095bbSAlp Dener       /* create lower and upper bounds for slack, set lower to 0 */
2629566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &SL));
2639566063dSJacob Faibussowitsch       PetscCall(VecSet(SL, 0.0));
2649566063dSJacob Faibussowitsch       PetscCall(VecDuplicate(auglag->Ci, &SU));
2659566063dSJacob Faibussowitsch       PetscCall(VecSet(SU, PETSC_INFINITY));
266661095bbSAlp Dener       /* combine opt var bounds with slack bounds */
2679566063dSJacob Faibussowitsch       PetscCall(TaoALMMCombinePrimal_Private(tao, tao->XL, SL, auglag->PL));
2689566063dSJacob Faibussowitsch       PetscCall(TaoALMMCombinePrimal_Private(tao, tao->XU, SU, auglag->PU));
269661095bbSAlp Dener       /* destroy work vectors */
2709566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&SL));
2719566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&SU));
272661095bbSAlp Dener     } else {
273661095bbSAlp Dener       /* no inequality constraints, just copy bounds into the subsolver */
2749566063dSJacob Faibussowitsch       PetscCall(VecCopy(tao->XL, auglag->PL));
2759566063dSJacob Faibussowitsch       PetscCall(VecCopy(tao->XU, auglag->PU));
276661095bbSAlp Dener     }
2779566063dSJacob Faibussowitsch     PetscCall(TaoSetVariableBounds(auglag->subsolver, auglag->PL, auglag->PU));
278661095bbSAlp Dener   }
2799566063dSJacob Faibussowitsch   PetscCall(TaoSetUp(auglag->subsolver));
2803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
281661095bbSAlp Dener }
282661095bbSAlp Dener 
283d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoDestroy_ALMM(Tao tao)
284d71ae5a4SJacob Faibussowitsch {
285661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
286661095bbSAlp Dener 
287661095bbSAlp Dener   PetscFunctionBegin;
2889566063dSJacob Faibussowitsch   PetscCall(TaoDestroy(&auglag->subsolver));
2899a09327dSAlp Dener   PetscCall(VecDestroy(&auglag->Psub));
2909a09327dSAlp Dener   PetscCall(VecDestroy(&auglag->G));
291661095bbSAlp Dener   if (tao->setupcalled) {
2929a09327dSAlp Dener     PetscCall(VecDestroy(&auglag->Xwork));
293661095bbSAlp Dener     if (tao->eq_constrained) {
2949566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Ye));     /* equality multipliers */
2959566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Cework)); /* equality work vector */
296661095bbSAlp Dener     }
297661095bbSAlp Dener     if (tao->ineq_constrained) {
2989566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Ps));     /* slack vars */
2999566063dSJacob Faibussowitsch       PetscCall(PetscFree(auglag->Parr));     /* array of primal vectors */
3009566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->LgradS)); /* slack grad */
3019566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Cizero)); /* zero vector for pointwise max */
3029566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Yi));     /* inequality multipliers */
3039566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->Ciwork)); /* inequality work vector */
3049a09327dSAlp Dener       PetscCall(VecDestroy(&auglag->P));      /* combo primal solution */
3059566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&auglag->Pis[0]));  /* index set for X inside P */
3069566063dSJacob Faibussowitsch       PetscCall(ISDestroy(&auglag->Pis[1]));  /* index set for S inside P */
3079566063dSJacob Faibussowitsch       PetscCall(PetscFree(auglag->Pis));      /* array of P index sets */
3089566063dSJacob Faibussowitsch       PetscCall(VecScatterDestroy(&auglag->Pscatter[0]));
3099566063dSJacob Faibussowitsch       PetscCall(VecScatterDestroy(&auglag->Pscatter[1]));
3109566063dSJacob Faibussowitsch       PetscCall(PetscFree(auglag->Pscatter));
311661095bbSAlp Dener       if (tao->eq_constrained) {
3129566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&auglag->Y));     /* combo multipliers */
3139566063dSJacob Faibussowitsch         PetscCall(PetscFree(auglag->Yarr));    /* array of dual vectors */
3149566063dSJacob Faibussowitsch         PetscCall(VecDestroy(&auglag->C));     /* combo constraints */
3159566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&auglag->Yis[0])); /* index set for Ye inside Y */
3169566063dSJacob Faibussowitsch         PetscCall(ISDestroy(&auglag->Yis[1])); /* index set for Yi inside Y */
3179566063dSJacob Faibussowitsch         PetscCall(PetscFree(auglag->Yis));
3189566063dSJacob Faibussowitsch         PetscCall(VecScatterDestroy(&auglag->Yscatter[0]));
3199566063dSJacob Faibussowitsch         PetscCall(VecScatterDestroy(&auglag->Yscatter[1]));
3209566063dSJacob Faibussowitsch         PetscCall(PetscFree(auglag->Yscatter));
321661095bbSAlp Dener       }
322661095bbSAlp Dener     }
323661095bbSAlp Dener     if (tao->bounded) {
3249566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->PL)); /* lower bounds for subsolver */
3259566063dSJacob Faibussowitsch       PetscCall(VecDestroy(&auglag->PU)); /* upper bounds for subsolver */
326661095bbSAlp Dener     }
327661095bbSAlp Dener   }
3282e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetType_C", NULL));
3292e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetType_C", NULL));
3302e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetSubsolver_C", NULL));
3312e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetSubsolver_C", NULL));
3322e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetMultipliers_C", NULL));
3332e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetMultipliers_C", NULL));
3342e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetPrimalIS_C", NULL));
3352e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetDualIS_C", NULL));
3369566063dSJacob Faibussowitsch   PetscCall(PetscFree(tao->data));
3373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
338661095bbSAlp Dener }
339661095bbSAlp Dener 
340d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoSetFromOptions_ALMM(Tao tao, PetscOptionItems *PetscOptionsObject)
341d71ae5a4SJacob Faibussowitsch {
342661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
343661095bbSAlp Dener   PetscInt  i;
344661095bbSAlp Dener 
345661095bbSAlp Dener   PetscFunctionBegin;
34671075aafSSatish Balay   PetscOptionsHeadBegin(PetscOptionsObject, "Augmented Lagrangian multiplier method solves problems with general constraints by converting them into a sequence of unconstrained problems.");
3479566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_mu_init", "initial penalty parameter", "", auglag->mu0, &auglag->mu0, NULL));
3489566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_mu_factor", "increase factor for the penalty parameter", "", auglag->mu_fac, &auglag->mu_fac, NULL));
3499566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_mu_power_good", "exponential for penalty parameter when multiplier update is accepted", "", auglag->mu_pow_good, &auglag->mu_pow_good, NULL));
3509566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_mu_power_bad", "exponential for penalty parameter when multiplier update is rejected", "", auglag->mu_pow_bad, &auglag->mu_pow_bad, NULL));
3519566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_mu_max", "maximum safeguard for penalty parameter updates", "", auglag->mu_max, &auglag->mu_max, NULL));
3529566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_ye_min", "minimum safeguard for equality multiplier updates", "", auglag->ye_min, &auglag->ye_min, NULL));
3539566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_ye_max", "maximum safeguard for equality multipliers updates", "", auglag->ye_max, &auglag->ye_max, NULL));
3549566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_yi_min", "minimum safeguard for inequality multipliers updates", "", auglag->yi_min, &auglag->yi_min, NULL));
3559566063dSJacob Faibussowitsch   PetscCall(PetscOptionsReal("-tao_almm_yi_max", "maximum safeguard for inequality multipliers updates", "", auglag->yi_max, &auglag->yi_max, NULL));
3569566063dSJacob Faibussowitsch   PetscCall(PetscOptionsEnum("-tao_almm_type", "augmented Lagrangian formulation type for the subproblem", "TaoALMMType", TaoALMMTypes, (PetscEnum)auglag->type, (PetscEnum *)&auglag->type, NULL));
357d0609cedSBarry Smith   PetscOptionsHeadEnd();
3589566063dSJacob Faibussowitsch   PetscCall(TaoSetOptionsPrefix(auglag->subsolver, ((PetscObject)tao)->prefix));
3599566063dSJacob Faibussowitsch   PetscCall(TaoAppendOptionsPrefix(auglag->subsolver, "tao_almm_subsolver_"));
3609566063dSJacob Faibussowitsch   PetscCall(TaoSetFromOptions(auglag->subsolver));
361661095bbSAlp Dener   for (i = 0; i < tao->numbermonitors; i++) {
3629566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)tao->monitorcontext[i]));
36310978b7dSBarry Smith     PetscCall(TaoMonitorSet(auglag->subsolver, tao->monitor[i], tao->monitorcontext[i], tao->monitordestroy[i]));
36410978b7dSBarry Smith     if (tao->monitor[i] == TaoMonitorDefault || tao->monitor[i] == TaoMonitorConstraintNorm || tao->monitor[i] == TaoMonitorGlobalization || tao->monitor[i] == TaoMonitorDefaultShort) auglag->info = PETSC_TRUE;
365661095bbSAlp Dener   }
3663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
367661095bbSAlp Dener }
368661095bbSAlp Dener 
369661095bbSAlp Dener /* -------------------------------------------------------- */
370661095bbSAlp Dener 
371661095bbSAlp Dener /*MC
372c0298470SBarry Smith   TAOALMM - Augmented Lagrangian multiplier method for solving nonlinear optimization problems with general constraints.
373661095bbSAlp Dener 
374661095bbSAlp Dener   Options Database Keys:
375661095bbSAlp Dener + -tao_almm_mu_init <real>       - initial penalty parameter (default: 10.)
376661095bbSAlp Dener . -tao_almm_mu_factor <real>     - increase factor for the penalty parameter (default: 100.)
377661095bbSAlp Dener . -tao_almm_mu_max <real>        - maximum safeguard for penalty parameter updates (default: 1.e20)
378661095bbSAlp Dener . -tao_almm_mu_power_good <real> - exponential for penalty parameter when multiplier update is accepted (default: 0.9)
379661095bbSAlp Dener . -tao_almm_mu_power_bad <real>  - exponential for penalty parameter when multiplier update is rejected (default: 0.1)
380661095bbSAlp Dener . -tao_almm_ye_min <real>        - minimum safeguard for equality multiplier updates (default: -1.e20)
381661095bbSAlp Dener . -tao_almm_ye_max <real>        - maximum safeguard for equality multiplier updates (default: 1.e20)
382661095bbSAlp Dener . -tao_almm_yi_min <real>        - minimum safeguard for inequality multiplier updates (default: -1.e20)
383661095bbSAlp Dener . -tao_almm_yi_max <real>        - maximum safeguard for inequality multiplier updates (default: 1.e20)
3849a09327dSAlp Dener - -tao_almm_type <phr,classic>   - change formulation of the augmented Lagrangian merit function for the subproblem (default: phr)
385661095bbSAlp Dener 
386661095bbSAlp Dener   Level: beginner
387661095bbSAlp Dener 
388661095bbSAlp Dener   Notes:
389661095bbSAlp Dener   This method converts a constrained problem into a sequence of unconstrained problems via the augmented
390661095bbSAlp Dener   Lagrangian merit function. Bound constraints are pushed down to the subproblem without any modifications.
391661095bbSAlp Dener 
392661095bbSAlp Dener   Two formulations are offered for the subproblem: canonical Hestenes-Powell augmented Lagrangian with slack
393661095bbSAlp Dener   variables for inequality constraints, and a slack-less Powell-Hestenes-Rockafellar (PHR) formulation utilizing a
3949a09327dSAlp Dener   pointwise max() penalty on inequality constraints. The canonical augmented Lagrangian formulation may converge
3959a09327dSAlp Dener   faster for smaller problems but is highly susceptible to poor step lengths in the subproblem due to the positivity
3969a09327dSAlp Dener   constraint on slack variables. PHR avoids this issue by eliminating the slack variables entirely, and is highly
3979a09327dSAlp Dener   desirable for problems with a large number of inequality constraints.
398661095bbSAlp Dener 
3999a09327dSAlp Dener   The subproblem is solved using a nested first-order TAO solver (default: `TAOBQNLS`). The user can retrieve a
4009a09327dSAlp Dener   pointer to the subsolver via `TaoALMMGetSubsolver()` or pass command line arguments to it using the
4019a09327dSAlp Dener   "-tao_almm_subsolver_" prefix. Currently, `TAOALMM` does not support second-order methods for the subproblem.
402661095bbSAlp Dener 
403661095bbSAlp Dener .vb
404661095bbSAlp Dener   while unconverged
405661095bbSAlp Dener     solve argmin_x L(x) s.t. l <= x <= u
406661095bbSAlp Dener     if ||c|| <= y_tol
407661095bbSAlp Dener       if ||c|| <= c_tol && ||Lgrad|| <= g_tol:
408661095bbSAlp Dener         problem converged, return solution
409661095bbSAlp Dener       else
410661095bbSAlp Dener         constraints sufficiently improved
411661095bbSAlp Dener         update multipliers and tighten tolerances
412661095bbSAlp Dener       endif
413661095bbSAlp Dener     else
414661095bbSAlp Dener       constraints did not improve
415661095bbSAlp Dener       update penalty and loosen tolerances
416661095bbSAlp Dener     endif
417661095bbSAlp Dener   endwhile
418661095bbSAlp Dener .ve
419661095bbSAlp Dener 
420c0298470SBarry Smith .seealso: `TAOALMM`, `Tao`, `TaoALMMGetType()`, `TaoALMMSetType()`, `TaoALMMSetSubsolver()`, `TaoALMMGetSubsolver()`,
421db781477SPatrick Sanan           `TaoALMMGetMultipliers()`, `TaoALMMSetMultipliers()`, `TaoALMMGetPrimalIS()`, `TaoALMMGetDualIS()`
422661095bbSAlp Dener M*/
423d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode TaoCreate_ALMM(Tao tao)
424d71ae5a4SJacob Faibussowitsch {
425661095bbSAlp Dener   TAO_ALMM *auglag;
426661095bbSAlp Dener 
427661095bbSAlp Dener   PetscFunctionBegin;
4284dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&auglag));
429661095bbSAlp Dener 
430661095bbSAlp Dener   tao->ops->destroy        = TaoDestroy_ALMM;
431661095bbSAlp Dener   tao->ops->setup          = TaoSetUp_ALMM;
432661095bbSAlp Dener   tao->ops->setfromoptions = TaoSetFromOptions_ALMM;
433661095bbSAlp Dener   tao->ops->view           = TaoView_ALMM;
434661095bbSAlp Dener   tao->ops->solve          = TaoSolve_ALMM;
435661095bbSAlp Dener 
436*606f75f6SBarry Smith   PetscCall(TaoParametersInitialize(tao));
437*606f75f6SBarry Smith   PetscObjectParameterSetDefault(tao, gatol, 1.e-5);
438*606f75f6SBarry Smith   PetscObjectParameterSetDefault(tao, grtol, 0.0);
439*606f75f6SBarry Smith   PetscObjectParameterSetDefault(tao, gttol, 0.0);
440*606f75f6SBarry Smith   PetscObjectParameterSetDefault(tao, catol, 1.e-5);
441*606f75f6SBarry Smith   PetscObjectParameterSetDefault(tao, crtol, 0.0);
442661095bbSAlp Dener 
443661095bbSAlp Dener   tao->data           = (void *)auglag;
444661095bbSAlp Dener   auglag->parent      = tao;
445661095bbSAlp Dener   auglag->mu0         = 10.0;
446661095bbSAlp Dener   auglag->mu          = auglag->mu0;
447661095bbSAlp Dener   auglag->mu_fac      = 10.0;
448661095bbSAlp Dener   auglag->mu_max      = PETSC_INFINITY;
449661095bbSAlp Dener   auglag->mu_pow_good = 0.9;
450661095bbSAlp Dener   auglag->mu_pow_bad  = 0.1;
451661095bbSAlp Dener   auglag->ye_min      = PETSC_NINFINITY;
452661095bbSAlp Dener   auglag->ye_max      = PETSC_INFINITY;
453661095bbSAlp Dener   auglag->yi_min      = PETSC_NINFINITY;
454661095bbSAlp Dener   auglag->yi_max      = PETSC_INFINITY;
455661095bbSAlp Dener   auglag->ytol0       = 0.1 / PetscPowReal(auglag->mu0, auglag->mu_pow_bad);
456661095bbSAlp Dener   auglag->ytol        = auglag->ytol0;
457661095bbSAlp Dener   auglag->gtol0       = 1.0 / auglag->mu0;
458661095bbSAlp Dener   auglag->gtol        = auglag->gtol0;
459661095bbSAlp Dener 
460661095bbSAlp Dener   auglag->sub_obj = TaoALMMComputeAugLagAndGradient_Private;
4619a09327dSAlp Dener   auglag->type    = TAO_ALMM_PHR;
462661095bbSAlp Dener   auglag->info    = PETSC_FALSE;
463661095bbSAlp Dener 
4649566063dSJacob Faibussowitsch   PetscCall(TaoCreate(PetscObjectComm((PetscObject)tao), &auglag->subsolver));
4659a09327dSAlp Dener   PetscCall(TaoSetType(auglag->subsolver, TAOBQNLS));
4669566063dSJacob Faibussowitsch   PetscCall(TaoSetTolerances(auglag->subsolver, auglag->gtol, 0.0, 0.0));
4679566063dSJacob Faibussowitsch   PetscCall(TaoSetMaximumIterations(auglag->subsolver, 1000));
4689566063dSJacob Faibussowitsch   PetscCall(TaoSetMaximumFunctionEvaluations(auglag->subsolver, 10000));
4699566063dSJacob Faibussowitsch   PetscCall(TaoSetFunctionLowerBound(auglag->subsolver, PETSC_NINFINITY));
4709566063dSJacob Faibussowitsch   PetscCall(PetscObjectIncrementTabLevel((PetscObject)auglag->subsolver, (PetscObject)tao, 1));
471661095bbSAlp Dener 
4729566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetType_C", TaoALMMGetType_Private));
4739566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetType_C", TaoALMMSetType_Private));
4749566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetSubsolver_C", TaoALMMGetSubsolver_Private));
4759566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetSubsolver_C", TaoALMMSetSubsolver_Private));
4769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetMultipliers_C", TaoALMMGetMultipliers_Private));
4779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMSetMultipliers_C", TaoALMMSetMultipliers_Private));
4789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetPrimalIS_C", TaoALMMGetPrimalIS_Private));
4799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)tao, "TaoALMMGetDualIS_C", TaoALMMGetDualIS_Private));
4803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
481661095bbSAlp Dener }
482661095bbSAlp Dener 
483d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMCombinePrimal_Private(Tao tao, Vec X, Vec S, Vec P)
484d71ae5a4SJacob Faibussowitsch {
485661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
486661095bbSAlp Dener 
487661095bbSAlp Dener   PetscFunctionBegin;
488661095bbSAlp Dener   if (tao->ineq_constrained) {
4899566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(auglag->Pscatter[0], X, P, INSERT_VALUES, SCATTER_REVERSE));
4909566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(auglag->Pscatter[0], X, P, INSERT_VALUES, SCATTER_REVERSE));
4919566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(auglag->Pscatter[1], S, P, INSERT_VALUES, SCATTER_REVERSE));
4929566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(auglag->Pscatter[1], S, P, INSERT_VALUES, SCATTER_REVERSE));
493661095bbSAlp Dener   } else {
4949566063dSJacob Faibussowitsch     PetscCall(VecCopy(X, P));
495661095bbSAlp Dener   }
4963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
497661095bbSAlp Dener }
498661095bbSAlp Dener 
499d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMCombineDual_Private(Tao tao, Vec EQ, Vec IN, Vec Y)
500d71ae5a4SJacob Faibussowitsch {
501661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
502661095bbSAlp Dener 
503661095bbSAlp Dener   PetscFunctionBegin;
504661095bbSAlp Dener   if (tao->eq_constrained) {
505661095bbSAlp Dener     if (tao->ineq_constrained) {
5069566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(auglag->Yscatter[0], EQ, Y, INSERT_VALUES, SCATTER_REVERSE));
5079566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(auglag->Yscatter[0], EQ, Y, INSERT_VALUES, SCATTER_REVERSE));
5089566063dSJacob Faibussowitsch       PetscCall(VecScatterBegin(auglag->Yscatter[1], IN, Y, INSERT_VALUES, SCATTER_REVERSE));
5099566063dSJacob Faibussowitsch       PetscCall(VecScatterEnd(auglag->Yscatter[1], IN, Y, INSERT_VALUES, SCATTER_REVERSE));
510661095bbSAlp Dener     } else {
5119566063dSJacob Faibussowitsch       PetscCall(VecCopy(EQ, Y));
512661095bbSAlp Dener     }
513661095bbSAlp Dener   } else {
5149566063dSJacob Faibussowitsch     PetscCall(VecCopy(IN, Y));
515661095bbSAlp Dener   }
5163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
517661095bbSAlp Dener }
518661095bbSAlp Dener 
519d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMSplitPrimal_Private(Tao tao, Vec P, Vec X, Vec S)
520d71ae5a4SJacob Faibussowitsch {
521661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
522661095bbSAlp Dener 
523661095bbSAlp Dener   PetscFunctionBegin;
524661095bbSAlp Dener   if (tao->ineq_constrained) {
5259566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(auglag->Pscatter[0], P, X, INSERT_VALUES, SCATTER_FORWARD));
5269566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(auglag->Pscatter[0], P, X, INSERT_VALUES, SCATTER_FORWARD));
5279566063dSJacob Faibussowitsch     PetscCall(VecScatterBegin(auglag->Pscatter[1], P, S, INSERT_VALUES, SCATTER_FORWARD));
5289566063dSJacob Faibussowitsch     PetscCall(VecScatterEnd(auglag->Pscatter[1], P, S, INSERT_VALUES, SCATTER_FORWARD));
529661095bbSAlp Dener   } else {
5309566063dSJacob Faibussowitsch     PetscCall(VecCopy(P, X));
531661095bbSAlp Dener   }
5323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
533661095bbSAlp Dener }
534661095bbSAlp Dener 
535661095bbSAlp Dener /* this assumes that the latest constraints are stored in Ce and Ci, and also combined in C */
536d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMComputeOptimalityNorms_Private(Tao tao)
537d71ae5a4SJacob Faibussowitsch {
538661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
539661095bbSAlp Dener 
540661095bbSAlp Dener   PetscFunctionBegin;
541661095bbSAlp Dener   /* if bounded, project the gradient */
5421baa6e33SBarry Smith   if (tao->bounded) PetscCall(VecBoundGradientProjection(auglag->LgradX, auglag->Px, tao->XL, tao->XU, auglag->LgradX));
543661095bbSAlp Dener   if (auglag->type == TAO_ALMM_PHR) {
5449566063dSJacob Faibussowitsch     PetscCall(VecNorm(auglag->LgradX, NORM_INFINITY, &auglag->gnorm));
545661095bbSAlp Dener     auglag->cenorm = 0.0;
54648a46eb9SPierre Jolivet     if (tao->eq_constrained) PetscCall(VecNorm(auglag->Ce, NORM_INFINITY, &auglag->cenorm));
547661095bbSAlp Dener     auglag->cinorm = 0.0;
548661095bbSAlp Dener     if (tao->ineq_constrained) {
5499566063dSJacob Faibussowitsch       PetscCall(VecCopy(auglag->Yi, auglag->Ciwork));
5509566063dSJacob Faibussowitsch       PetscCall(VecScale(auglag->Ciwork, -1.0 / auglag->mu));
5519566063dSJacob Faibussowitsch       PetscCall(VecPointwiseMax(auglag->Ciwork, auglag->Ci, auglag->Ciwork));
5529566063dSJacob Faibussowitsch       PetscCall(VecNorm(auglag->Ciwork, NORM_INFINITY, &auglag->cinorm));
553661095bbSAlp Dener     }
554661095bbSAlp Dener     auglag->cnorm_old = auglag->cnorm;
555661095bbSAlp Dener     auglag->cnorm     = PetscMax(auglag->cenorm, auglag->cinorm);
556661095bbSAlp Dener     auglag->ytol      = auglag->ytol0 * auglag->cnorm_old;
557661095bbSAlp Dener   } else {
5589566063dSJacob Faibussowitsch     PetscCall(VecNorm(auglag->LgradX, NORM_2, &auglag->gnorm));
5599566063dSJacob Faibussowitsch     PetscCall(VecNorm(auglag->C, NORM_2, &auglag->cnorm));
560661095bbSAlp Dener   }
5613ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
562661095bbSAlp Dener }
563661095bbSAlp Dener 
5649a09327dSAlp Dener static PetscErrorCode TaoALMMEvaluateIterate_Private(Tao tao)
565d71ae5a4SJacob Faibussowitsch {
566661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
567661095bbSAlp Dener 
568661095bbSAlp Dener   PetscFunctionBegin;
569661095bbSAlp Dener   /* split solution into primal and slack components */
5709566063dSJacob Faibussowitsch   PetscCall(TaoALMMSplitPrimal_Private(tao, auglag->P, auglag->Px, auglag->Ps));
571661095bbSAlp Dener 
572661095bbSAlp Dener   /* compute f, df/dx and the constraints */
5739566063dSJacob Faibussowitsch   PetscCall(TaoComputeObjectiveAndGradient(tao, auglag->Px, &auglag->fval, auglag->LgradX));
574661095bbSAlp Dener   if (tao->eq_constrained) {
5759566063dSJacob Faibussowitsch     PetscCall(TaoComputeEqualityConstraints(tao, auglag->Px, auglag->Ce));
5769566063dSJacob Faibussowitsch     PetscCall(TaoComputeJacobianEquality(tao, auglag->Px, auglag->Ae, auglag->Ae));
577661095bbSAlp Dener   }
578661095bbSAlp Dener   if (tao->ineq_constrained) {
5799566063dSJacob Faibussowitsch     PetscCall(TaoComputeInequalityConstraints(tao, auglag->Px, auglag->Ci));
5809566063dSJacob Faibussowitsch     PetscCall(TaoComputeJacobianInequality(tao, auglag->Px, auglag->Ai, auglag->Ai));
581661095bbSAlp Dener     switch (auglag->type) {
5827721a36fSStefano Zampini     case TAO_ALMM_CLASSIC:
583661095bbSAlp Dener       /* classic formulation converts inequality to equality constraints via slack variables */
5849566063dSJacob Faibussowitsch       PetscCall(VecAXPY(auglag->Ci, -1.0, auglag->Ps));
585661095bbSAlp Dener       break;
5867721a36fSStefano Zampini     case TAO_ALMM_PHR:
587661095bbSAlp Dener       /* PHR is based on Ci <= 0 while TAO defines Ci >= 0 so we hit it with a negative sign */
5889566063dSJacob Faibussowitsch       PetscCall(VecScale(auglag->Ci, -1.0));
5899566063dSJacob Faibussowitsch       PetscCall(MatScale(auglag->Ai, -1.0));
590661095bbSAlp Dener       break;
591d71ae5a4SJacob Faibussowitsch     default:
592d71ae5a4SJacob Faibussowitsch       break;
593661095bbSAlp Dener     }
594661095bbSAlp Dener   }
595661095bbSAlp Dener   /* combine constraints into one vector */
5969566063dSJacob Faibussowitsch   PetscCall(TaoALMMCombineDual_Private(tao, auglag->Ce, auglag->Ci, auglag->C));
5973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
598661095bbSAlp Dener }
599661095bbSAlp Dener 
600661095bbSAlp Dener /*
601661095bbSAlp Dener Lphr = f + 0.5*mu*[ (Ce + Ye/mu)^T (Ce + Ye/mu) + pmin(0, Ci + Yi/mu)^T pmin(0, Ci + Yi/mu)]
602661095bbSAlp Dener 
603661095bbSAlp Dener dLphr/dX = dF/dX + mu*[ (Ce + Ye/mu)^T Ae + pmin(0, Ci + Yi/mu)^T Ai]
604661095bbSAlp Dener 
605661095bbSAlp Dener dLphr/dS = 0
606661095bbSAlp Dener */
607d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMComputePHRLagAndGradient_Private(Tao tao)
608d71ae5a4SJacob Faibussowitsch {
609661095bbSAlp Dener   TAO_ALMM *auglag  = (TAO_ALMM *)tao->data;
610661095bbSAlp Dener   PetscReal eq_norm = 0.0, ineq_norm = 0.0;
611661095bbSAlp Dener 
612661095bbSAlp Dener   PetscFunctionBegin;
6139a09327dSAlp Dener   PetscCall(TaoALMMEvaluateIterate_Private(tao));
614661095bbSAlp Dener   if (tao->eq_constrained) {
615661095bbSAlp Dener     /* Ce_work = mu*(Ce + Ye/mu) */
6169566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(auglag->Cework, 1.0 / auglag->mu, auglag->Ye, auglag->Ce));
6179566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Cework, auglag->Cework, &eq_norm)); /* contribution to scalar Lagrangian */
6189566063dSJacob Faibussowitsch     PetscCall(VecScale(auglag->Cework, auglag->mu));
619661095bbSAlp Dener     /* dL/dX += mu*(Ce + Ye/mu)^T Ae */
6209566063dSJacob Faibussowitsch     PetscCall(MatMultTransposeAdd(auglag->Ae, auglag->Cework, auglag->LgradX, auglag->LgradX));
621661095bbSAlp Dener   }
622661095bbSAlp Dener   if (tao->ineq_constrained) {
623661095bbSAlp Dener     /* Ci_work = mu * pmax(0, Ci + Yi/mu) where pmax() is pointwise max() */
6249566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(auglag->Ciwork, 1.0 / auglag->mu, auglag->Yi, auglag->Ci));
6259566063dSJacob Faibussowitsch     PetscCall(VecPointwiseMax(auglag->Ciwork, auglag->Cizero, auglag->Ciwork));
6269566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Ciwork, auglag->Ciwork, &ineq_norm)); /* contribution to scalar Lagrangian */
627661095bbSAlp Dener     /* dL/dX += mu * pmax(0, Ci + Yi/mu)^T Ai */
6289566063dSJacob Faibussowitsch     PetscCall(VecScale(auglag->Ciwork, auglag->mu));
6299566063dSJacob Faibussowitsch     PetscCall(MatMultTransposeAdd(auglag->Ai, auglag->Ciwork, auglag->LgradX, auglag->LgradX));
630a5b23f4aSJose E. Roman     /* dL/dS = 0 because there are no slacks in PHR */
6319566063dSJacob Faibussowitsch     PetscCall(VecZeroEntries(auglag->LgradS));
632661095bbSAlp Dener   }
633661095bbSAlp Dener   /* combine gradient together */
6349566063dSJacob Faibussowitsch   PetscCall(TaoALMMCombinePrimal_Private(tao, auglag->LgradX, auglag->LgradS, auglag->G));
635661095bbSAlp Dener   /* compute L = f + 0.5 * mu * [(Ce + Ye/mu)^T (Ce + Ye/mu) + pmax(0, Ci + Yi/mu)^T pmax(0, Ci + Yi/mu)] */
6365f80ce2aSJacob Faibussowitsch   auglag->Lval = auglag->fval + 0.5 * auglag->mu * (eq_norm + ineq_norm);
6373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
638661095bbSAlp Dener }
639661095bbSAlp Dener 
640661095bbSAlp Dener /*
641661095bbSAlp Dener Lc = F + Ye^TCe + Yi^T(Ci - S) + 0.5*mu*[Ce^TCe + (Ci - S)^T(Ci - S)]
642661095bbSAlp Dener 
643661095bbSAlp Dener dLc/dX = dF/dX + Ye^TAe + Yi^TAi + 0.5*mu*[Ce^TAe + (Ci - S)^TAi]
644661095bbSAlp Dener 
645661095bbSAlp Dener dLc/dS = -[Yi + mu*(Ci - S)]
646661095bbSAlp Dener */
647d71ae5a4SJacob Faibussowitsch static PetscErrorCode TaoALMMComputeAugLagAndGradient_Private(Tao tao)
648d71ae5a4SJacob Faibussowitsch {
649661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)tao->data;
650661095bbSAlp Dener   PetscReal yeTce = 0.0, yiTcims = 0.0, ceTce = 0.0, cimsTcims = 0.0;
651661095bbSAlp Dener 
652661095bbSAlp Dener   PetscFunctionBegin;
6539a09327dSAlp Dener   PetscCall(TaoALMMEvaluateIterate_Private(tao));
654661095bbSAlp Dener   if (tao->eq_constrained) {
655661095bbSAlp Dener     /* compute scalar contributions */
6569566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Ye, auglag->Ce, &yeTce));
6579566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Ce, auglag->Ce, &ceTce));
658661095bbSAlp Dener     /* dL/dX += ye^T Ae */
6599566063dSJacob Faibussowitsch     PetscCall(MatMultTransposeAdd(auglag->Ae, auglag->Ye, auglag->LgradX, auglag->LgradX));
6609a09327dSAlp Dener     /* dL/dX += 0.5 * mu * ce^T Ae */
6619566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(auglag->Ae, auglag->Ce, auglag->Xwork));
6629a09327dSAlp Dener     PetscCall(VecAXPY(auglag->LgradX, 0.5 * auglag->mu, auglag->Xwork));
663661095bbSAlp Dener   }
664661095bbSAlp Dener   if (tao->ineq_constrained) {
665661095bbSAlp Dener     /* compute scalar contributions */
6669566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Yi, auglag->Ci, &yiTcims));
6679566063dSJacob Faibussowitsch     PetscCall(VecDot(auglag->Ci, auglag->Ci, &cimsTcims));
668661095bbSAlp Dener     /* dL/dX += yi^T Ai */
6699566063dSJacob Faibussowitsch     PetscCall(MatMultTransposeAdd(auglag->Ai, auglag->Yi, auglag->LgradX, auglag->LgradX));
6709a09327dSAlp Dener     /* dL/dX += 0.5 * mu * (ci - s)^T Ai */
6719566063dSJacob Faibussowitsch     PetscCall(MatMultTranspose(auglag->Ai, auglag->Ci, auglag->Xwork));
6729a09327dSAlp Dener     PetscCall(VecAXPY(auglag->LgradX, 0.5 * auglag->mu, auglag->Xwork));
673661095bbSAlp Dener     /* dL/dS = -[yi + mu*(ci - s)] */
6749566063dSJacob Faibussowitsch     PetscCall(VecWAXPY(auglag->LgradS, auglag->mu, auglag->Ci, auglag->Yi));
6759566063dSJacob Faibussowitsch     PetscCall(VecScale(auglag->LgradS, -1.0));
676661095bbSAlp Dener   }
677661095bbSAlp Dener   /* combine gradient together */
6789566063dSJacob Faibussowitsch   PetscCall(TaoALMMCombinePrimal_Private(tao, auglag->LgradX, auglag->LgradS, auglag->G));
679661095bbSAlp Dener   /* compute L = f + ye^T ce + yi^T (ci - s) + 0.5*mu*||ce||^2 + 0.5*mu*||ci - s||^2 */
680661095bbSAlp Dener   auglag->Lval = auglag->fval + yeTce + yiTcims + 0.5 * auglag->mu * (ceTce + cimsTcims);
6813ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
682661095bbSAlp Dener }
683661095bbSAlp Dener 
684d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoALMMSubsolverObjective_Private(Tao tao, Vec P, PetscReal *Lval, void *ctx)
685d71ae5a4SJacob Faibussowitsch {
6867721a36fSStefano Zampini   TAO_ALMM *auglag = (TAO_ALMM *)ctx;
6877721a36fSStefano Zampini 
6887721a36fSStefano Zampini   PetscFunctionBegin;
6899566063dSJacob Faibussowitsch   PetscCall(VecCopy(P, auglag->P));
6909566063dSJacob Faibussowitsch   PetscCall((*auglag->sub_obj)(auglag->parent));
6917721a36fSStefano Zampini   *Lval = auglag->Lval;
6923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6937721a36fSStefano Zampini }
6947721a36fSStefano Zampini 
695d71ae5a4SJacob Faibussowitsch PetscErrorCode TaoALMMSubsolverObjectiveAndGradient_Private(Tao tao, Vec P, PetscReal *Lval, Vec G, void *ctx)
696d71ae5a4SJacob Faibussowitsch {
697661095bbSAlp Dener   TAO_ALMM *auglag = (TAO_ALMM *)ctx;
698661095bbSAlp Dener 
699661095bbSAlp Dener   PetscFunctionBegin;
7009566063dSJacob Faibussowitsch   PetscCall(VecCopy(P, auglag->P));
7019566063dSJacob Faibussowitsch   PetscCall((*auglag->sub_obj)(auglag->parent));
7029566063dSJacob Faibussowitsch   PetscCall(VecCopy(auglag->G, G));
703661095bbSAlp Dener   *Lval = auglag->Lval;
7043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
705661095bbSAlp Dener }
706