diff --git a/examples/farmer/farmer_rho_demo.py b/examples/farmer/farmer_rho_demo.py index 99c21322..b9ae42a4 100644 --- a/examples/farmer/farmer_rho_demo.py +++ b/examples/farmer/farmer_rho_demo.py @@ -84,7 +84,7 @@ def main(): if cfg.use_norm_rho_converger: if not cfg.use_norm_rho_updater: raise RuntimeError("--use-norm-rho-converger requires --use-norm-rho-updater") - elif cfg.grad_rho_setter: + elif cfg.grad_rho: raise RuntimeError("You cannot have--use-norm-rho-converger and --grad-rho-setter") else: ph_converger = NormRhoConverger @@ -103,7 +103,7 @@ def main(): beans = (cfg, scenario_creator, scenario_denouement, all_scenario_names) ext_classes = [] - if cfg.grad_rho_setter: + if cfg.grad_rho: ext_classes.append(Gradient_extension) if cfg.run_async: @@ -119,7 +119,7 @@ def main(): hub_dict['opt_kwargs']['extensions'] = MultiExtension # DLW: ???? (seems to not matter) #gradient extension kwargs - if cfg.grad_rho_setter: + if cfg.grad_rho: ext_classes.append(Gradient_extension) hub_dict['opt_kwargs']['options']['gradient_extension_options'] = {'cfg': cfg} diff --git a/examples/uc/gradient_uc_cylinders.py b/examples/uc/gradient_uc_cylinders.py index 03898d52..a2be8a6e 100644 --- a/examples/uc/gradient_uc_cylinders.py +++ b/examples/uc/gradient_uc_cylinders.py @@ -123,7 +123,7 @@ def main(): if cfg.xhat_closest_tree: ext_classes.append(XhatClosest) - if cfg.grad_rho_setter: + if cfg.grad_rho: ext_classes.append(Gradient_extension) hub_dict["opt_kwargs"]["extension_kwargs"] = {"ext_classes" : ext_classes} @@ -143,7 +143,7 @@ def main(): "keep_solution" : True } - if cfg.grad_rho_setter: + if cfg.grad_rho: hub_dict['opt_kwargs']['options']['gradient_extension_options'] = {'cfg': cfg} if cfg.ph_mipgaps_json is not None: diff --git a/mpisppy/cylinders/spoke.py b/mpisppy/cylinders/spoke.py index 1d59e58c..7be2d5a6 100644 --- a/mpisppy/cylinders/spoke.py +++ b/mpisppy/cylinders/spoke.py @@ -13,7 +13,6 @@ import os import math - from pyomo.environ import ComponentMap, Var from mpisppy import MPI from mpisppy.cylinders.spcommunicator import SPCommunicator, communicator_array @@ -100,7 +99,8 @@ def spoke_from_hub(self, values): window.Get((values, len(values), MPI.DOUBLE), 0) window.Unlock(0) - new_id = int(values[-1]) + # On rare occasions a NaN is seen... + new_id = int(values[-1]) if not math.isnan(values[-1]) else 0 local_val = np.array((new_id,-new_id), 'i') max_min_ids = np.zeros(2, 'i') self.cylinder_comm.Allreduce((local_val, MPI.INT), diff --git a/mpisppy/extensions/gradient_extension.py b/mpisppy/extensions/gradient_extension.py index ac3f8b57..d1009dbf 100644 --- a/mpisppy/extensions/gradient_extension.py +++ b/mpisppy/extensions/gradient_extension.py @@ -36,8 +36,7 @@ def __init__(self, opt, comm=None): # TBD: stop using files # TBD: restore the rho_setter? self.cfg_args_cache = {'rho_file_in': self.cfg.rho_file_in, - 'grad_rho_file_out': self.cfg.grad_rho_file_out, - 'rho_setter': self.cfg.grad_rho_setter} + 'grad_rho_file_out': self.cfg.grad_rho_file_out} if self.cfg.get('grad_cost_file_out', ifmissing="") == "": self.cfg.grad_cost_file_out = './_temp_grad_cost_file.csv' # else: diff --git a/mpisppy/generic_cylinders.py b/mpisppy/generic_cylinders.py index 37be1c5e..90bcf725 100644 --- a/mpisppy/generic_cylinders.py +++ b/mpisppy/generic_cylinders.py @@ -29,7 +29,6 @@ from mpisppy import MPI - def _parse_args(m): # m is the model file module cfg = config.Config() @@ -46,12 +45,6 @@ def _parse_args(m): description="The string used for a directory of ouput along with a csv and an npv file (default None, which means no soltion output)", domain=str, default=None) - cfg.add_to_config(name="run_async", - description="Use APH instead of PH (default False)", - domain=bool, - default=False) - - m.inparser_adder(cfg) # many models, e.g., farmer, need num_scens_required # in which case, it should go in the inparser_adder function @@ -136,7 +129,7 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ # Things needed for vanilla cylinders beans = (cfg, scenario_creator, scenario_denouement, all_scenario_names) - if cfg.run_async: + if cfg.APH: # Vanilla APH hub hub_dict = vanilla.aph_hub(*beans, scenario_creator_kwargs=scenario_creator_kwargs, @@ -178,7 +171,7 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ if cfg.rc_fixer: vanilla.add_reduced_costs_fixer(hub_dict, cfg) - if cfg.grad_rho_setter: + if cfg.grad_rho: ext_classes.append(Gradient_extension) hub_dict['opt_kwargs']['options']['gradient_extension_options'] = {'cfg': cfg} diff --git a/mpisppy/opt/presolve.py b/mpisppy/opt/presolve.py index 87edece5..4418c9e8 100644 --- a/mpisppy/opt/presolve.py +++ b/mpisppy/opt/presolve.py @@ -143,6 +143,10 @@ def presolve(self): print( f"Tightening bounds on nonant {var.name} in scenario {k} from {var.bounds} to {(lb, ub)} based on global bound information." ) + if np.isnan(lb): + lb = None + if np.isnan(ub): + ub = None var.bounds = (lb, ub) # Now do FBBT diff --git a/mpisppy/spbase.py b/mpisppy/spbase.py index 055a8c30..3516e83e 100644 --- a/mpisppy/spbase.py +++ b/mpisppy/spbase.py @@ -607,7 +607,9 @@ def report_var_values_at_rank0(self, header="", print_zero_prob_values=False, fi if len(header) != 0: print(header) - + if len(var_values) == 0: + print("No variables to report (perhaps all are fixed?)") + return scenario_names = sorted(set(x for (x,y) in var_values)) max_scenario_name_len = max(len(s) for s in scenario_names) variable_names = sorted(set(y for (x,y) in var_values)) diff --git a/mpisppy/tests/test_gradient_rho.py b/mpisppy/tests/test_gradient_rho.py index e1cddb28..058c7834 100644 --- a/mpisppy/tests/test_gradient_rho.py +++ b/mpisppy/tests/test_gradient_rho.py @@ -202,7 +202,7 @@ def test_compute_and_write_grad_rho(self): """ def test_rho_setter(self): - self.cfg.grad_rho_setter = True + self.cfg.grad_rho = True self.cfg.rho_file_in = './examples/rho_test_data/rho.csv' self.rho_object = find_rho.Find_Rho(self.ph_object, self.cfg) self.set_rho = find_rho.Set_Rho(self.cfg) diff --git a/mpisppy/utils/config.py b/mpisppy/utils/config.py index da5fa666..c92182bf 100644 --- a/mpisppy/utils/config.py +++ b/mpisppy/utils/config.py @@ -147,11 +147,14 @@ def _bad_rho_setters(msg): raise ValueError("Rho setter options do not make sense together:\n" f"{msg}") - if self.grad_rho_setter and self.sensi_rho: + if self.get("grad_rho") and self.get("sensi_rho"): _bad_rho_setters("Only one rho setter can be active.") - if not (self.grad_rho_setter or self.sensi_rho or self.sep_rho or self.reduced_costs_rho): - if self.dynamic_rho_primal_crit or self.dynamic_rho_dual_crit: + if not self.get("grad_rho") or self.get("sensi_rho") or self.get("sep_rho") or self.get("reduced_costs_rho"): + if self.get("dynamic_rho_primal_crit") or self.get("dynamic_rho_dual_crit"): _bad_rho_setters("dynamic rho only works with grad-, sensi-, and sep-rho") + if self.get("rc_fixer") and not self.get("reduced_costs"): + _bad_rho_setters("--rc-fixer requires --reduced-costs") + def add_solver_specs(self, prefix=""): sstr = f"{prefix}_solver" if prefix != "" else "solver" @@ -385,9 +388,12 @@ def mip_options(self): domain=float, default=None) - def aph_args(self): - + + self.add_to_config(name="APH", + description="Use APH instead of PH (default False)", + domain=bool, + default=False) self.add_to_config('aph_gamma', description='Gamma parameter associated with asychronous projective hedging (default 1.0)', domain=float, @@ -434,7 +440,7 @@ def reduced_costs_rho_args(self): def sep_rho_args(self): self.add_to_config("sep_rho", - description="have a SepRho extension", + description="have an extension that computes rho using the seprho method from the Watson/Woodruff CMS paper", domain=bool, default=False) self.add_to_config("sep_rho_multiplier", @@ -445,7 +451,7 @@ def sep_rho_args(self): def sensi_rho_args(self): self.add_to_config("sensi_rho", - description="have a SensiRho extension", + description="have an extension that sets rho values based on objective function sensitivity", domain=bool, default=False) self.add_to_config("sensi_rho_multiplier", @@ -833,8 +839,8 @@ def gradient_args(self): # domain=float, # default=0.1) - self.add_to_config('grad_rho_setter', - description="use rho setter from a rho file", + self.add_to_config('grad_rho', + description="use a gradient-based rho setter (if your problem is linear, use coeff-rho instead)", domain=bool, default=False) """