|
9 | 9 |
|
10 | 10 | import numpy as np
|
11 | 11 |
|
12 |
| -import pyomo.environ as pyo |
13 |
| -from pyomo.contrib.pynumero.linalg.scipy_interface import ScipyLU |
14 | 12 |
|
15 | 13 | import mpisppy.extensions.extension
|
16 | 14 | import mpisppy.MPI as MPI
|
17 |
| -from mpisppy.utils.kkt.interface import InteriorPointInterface |
| 15 | +from mpisppy.utils.nonant_sensitivities import nonant_sensitivies |
18 | 16 |
|
19 | 17 |
|
20 | 18 | class SensiRho(mpisppy.extensions.extension.Extension):
|
@@ -142,81 +140,15 @@ def pre_iter0(self):
|
142 | 140 | def post_iter0(self):
|
143 | 141 | ph = self.ph
|
144 | 142 |
|
145 |
| - # first, solve the subproblems with Ipopt, |
146 |
| - # and gather sensitivity information |
147 |
| - ipopt = pyo.SolverFactory("ipopt") |
148 |
| - nonant_sensis = {} |
| 143 | + nonant_sensis = dict() # dict of dicts [s][ndn_i] |
149 | 144 | for k, s in ph.local_subproblems.items():
|
150 |
| - solution_cache = pyo.ComponentMap() |
151 |
| - for var in s.component_data_objects(pyo.Var): |
152 |
| - solution_cache[var] = var._value |
153 |
| - relax_int = pyo.TransformationFactory('core.relax_integer_vars') |
154 |
| - relax_int.apply_to(s) |
155 |
| - |
156 |
| - assert hasattr(s, "_relaxed_integer_vars") |
157 |
| - |
158 |
| - # add the needed suffixes / remove later |
159 |
| - s.ipopt_zL_out = pyo.Suffix(direction=pyo.Suffix.IMPORT) |
160 |
| - s.ipopt_zU_out = pyo.Suffix(direction=pyo.Suffix.IMPORT) |
161 |
| - s.dual = pyo.Suffix(direction=pyo.Suffix.IMPORT_EXPORT) |
162 |
| - |
163 |
| - results = ipopt.solve(s) |
164 |
| - pyo.assert_optimal_termination(results) |
165 |
| - |
166 |
| - kkt_builder = InteriorPointInterface(s) |
167 |
| - kkt_builder.set_barrier_parameter(1e-9) |
168 |
| - kkt_builder.set_bounds_relaxation_factor(1e-8) |
169 |
| - #rhs = kkt_builder.evaluate_primal_dual_kkt_rhs() |
170 |
| - #print(f"{rhs}") |
171 |
| - #print(f"{rhs.flatten()}") |
172 |
| - kkt = kkt_builder.evaluate_primal_dual_kkt_matrix() |
173 |
| - |
174 |
| - # print(f"{kkt=}") |
175 |
| - # could do better than SuperLU |
176 |
| - kkt_lu = ScipyLU() |
177 |
| - # always regularize equality constraints |
178 |
| - kkt_builder.regularize_equality_gradient(kkt=kkt, coef=-1e-8, copy_kkt=False) |
179 |
| - kkt_lu.do_numeric_factorization(kkt, raise_on_error=True) |
180 |
| - |
181 |
| - grad_vec = np.zeros(kkt.shape[1]) |
182 |
| - grad_vec[0:kkt_builder._nlp.n_primals()] = kkt_builder._nlp.evaluate_grad_objective() |
183 |
| - |
184 |
| - grad_vec_kkt_inv = kkt_lu._lu.solve(grad_vec, "T") |
185 |
| - |
186 |
| - for scenario_name in s.scen_list: |
187 |
| - nonant_sensis[scenario_name] = {} |
188 |
| - rho = ph.local_scenarios[scenario_name]._mpisppy_model.rho |
189 |
| - for ndn_i, v in ph.local_scenarios[scenario_name]._mpisppy_data.nonant_indices.items(): |
190 |
| - var_idx = kkt_builder._nlp._vardata_to_idx[v] |
191 |
| - |
192 |
| - y_vec = np.zeros(kkt.shape[0]) |
193 |
| - y_vec[var_idx] = 1.0 |
194 |
| - |
195 |
| - x_denom = y_vec.T @ kkt_lu._lu.solve(y_vec) |
196 |
| - x = (-1 / x_denom) |
197 |
| - e_x = x * y_vec |
198 |
| - |
199 |
| - sensitivity = grad_vec_kkt_inv @ -e_x |
200 |
| - # print(f"df/d{v.name}: {sensitivity:.2e}, ∂f/∂{v.name}: {grad_vec[var_idx]:.2e}, " |
201 |
| - # f"rho {v.name}: {ph.local_scenarios[scenario_name]._mpisppy_model.rho[ndn_i]._value:.2e}, ", |
202 |
| - # f"value: {v._value:.2e}" |
203 |
| - # ) |
204 |
| - |
205 |
| - rho[ndn_i]._value = abs(sensitivity) |
206 |
| - |
207 |
| - relax_int.apply_to(s, options={"undo":True}) |
208 |
| - assert not hasattr(s, "_relaxed_integer_vars") |
209 |
| - del s.ipopt_zL_out |
210 |
| - del s.ipopt_zU_out |
211 |
| - del s.dual |
212 |
| - for var, val in solution_cache.items(): |
213 |
| - var._value = val |
214 |
| - |
| 145 | + nonant_sensis[s] = nonant_sensitivies(s, ph) |
| 146 | + |
215 | 147 | for s in ph.local_scenarios.values():
|
216 | 148 | xbars = s._mpisppy_model.xbars
|
217 | 149 | for ndn_i, rho in s._mpisppy_model.rho.items():
|
218 | 150 | nv = s._mpisppy_data.nonant_indices[ndn_i] # var_data object
|
219 |
| - rho._value = rho._value / max(1, abs(nv._value - xbars[ndn_i]._value)) |
| 151 | + rho._value = abs(nonant_sensis[s][ndn_i]) / max(1, abs(nv._value - xbars[ndn_i]._value)) |
220 | 152 | rho._value *= self.multiplier
|
221 | 153 | # if ph.cylinder_rank == 0:
|
222 | 154 | # print(f"{s.name=}, {nv.name=}, {rho.value=}")
|
|
0 commit comments