diff --git a/doc/src/spokes.rst b/doc/src/spokes.rst index 6c3f47c69..b006bac80 100644 --- a/doc/src/spokes.rst +++ b/doc/src/spokes.rst @@ -62,30 +62,7 @@ is a sample json file: ph_ob ^^^^^ -This bounder is similar to the Lagrangian bounder, except that it executes a PH -algorithm to obtain its own W values. The idea is that it can use lower rho values -so as to obtain better outer (lower when minimizing) bounds. It can also provide -a Lagrangian bound even if the hub does not provide lagrangian multipliers. - -The easiest way to use ``ph_ob`` is via the vanilla ``ph_ob_spoke`` method -as illustrated in ``examples.farmer.archive.farmer_cylinders.py``. This method takes values -from the config object (assuming the config object's ``ph_ob`` method -was called as shown in the function ``examples.farmer.archive.farmer_cylinders._parse_args``) -and sets up the options for the spoke. - -The option ``ph-ob-initial-rho-rescale-factor`` defaults to 0.1, so if nothing -other than ``--ph-ob`` is given on the command line, the ph_ob spoke will use -one tenth the default rho (it might use one tenth of rho from -a rho setter if one is configured in the cylinders program and passed to the ph_ob -constructor). Additional control over rho values -is provided by the ``phob-rho-rescale-factors-json`` option which is a json -file that provides a dictionary with keys that are iteration numbers and values -that are rescale factors. Note that all rescaling is cummulative. - -See ``examples.uc.gradient_uc_cylinders.py`` for an example that uses a cost-based -rho setter for the uc problem in the ph_ob cylinder. - -As of August, 2024 use of a gradient based rho with ph_ob is untested. +This cylinder was deprecated in August of 2025 in favor of ph_dual. Reduced Costs ^^^^^^^^^^^^^ diff --git a/examples/afew.py b/examples/afew.py index d5d72cecd..c7f351317 100644 --- a/examples/afew.py +++ b/examples/afew.py @@ -48,10 +48,6 @@ def do_one(dirname, progname, np, argstring): # for farmer, the first arg is num_scens and is required -do_one("farmer/archive", "farmer_cylinders.py", 3, - "--num-scens=3 --bundles-per-rank=0 --max-iterations=50 " - "--default-rho=1 --sep-rho --display-convergence-detail " - "--solver-name={} --xhatshuffle --lagrangian --use-norm-rho-updater".format(solver_name)) do_one("farmer", "farmer_lshapedhub.py", 2, "--num-scens=3 --bundles-per-rank=0 --max-iterations=50 " "--solver-name={} --rel-gap=0.0 " diff --git a/examples/distr/distr_admm_cylinders.py b/examples/distr/distr_admm_cylinders.py index 82ead40dc..c5bb16080 100644 --- a/examples/distr/distr_admm_cylinders.py +++ b/examples/distr/distr_admm_cylinders.py @@ -32,7 +32,6 @@ def _parse_args(): cfg.aph_args() cfg.xhatxbar_args() cfg.lagrangian_args() - cfg.ph_ob_args() cfg.tracking_args() cfg.add_to_config("run_async", description="Run with async projective hedging instead of progressive hedging", @@ -46,7 +45,7 @@ def _parse_args(): # This need to be executed long before the cylinders are created def _count_cylinders(cfg): count = 1 - cfglist = ["xhatxbar", "lagrangian", "ph_ob"] # All the cfg arguments that create a new cylinders + cfglist = ["xhatxbar", "lagrangian"] # All the cfg arguments that create a new cylinders # Add to this list any cfg attribute that would create a spoke for cylname in cfglist: if cfg[cylname]: @@ -133,12 +132,7 @@ def main(): rho_setter = None) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = None, - variable_probability=variable_probability) + # ph outer bounder spoke removed August 2025 (use ph_dual) # xhat looper bound spoke if cfg.xhatxbar: @@ -147,8 +141,6 @@ def main(): list_of_spoke_dict = list() if cfg.lagrangian: list_of_spoke_dict.append(lagrangian_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.xhatxbar: list_of_spoke_dict.append(xhatxbar_spoke) diff --git a/examples/farmer/CI/farmer_rho_demo.py b/examples/farmer/CI/farmer_rho_demo.py index b9ae42a47..b3035bb01 100644 --- a/examples/farmer/CI/farmer_rho_demo.py +++ b/examples/farmer/CI/farmer_rho_demo.py @@ -43,7 +43,6 @@ def _parse_args(): cfg.fwph_args() cfg.lagrangian_args() cfg.lagranger_args() - cfg.ph_ob_args() cfg.xhatshuffle_args() cfg.dynamic_gradient_args() # gets gradient args for free cfg.add_to_config("crops_mult", @@ -144,11 +143,7 @@ def main(): scenario_creator_kwargs=scenario_creator_kwargs, rho_setter = rho_setter) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = rho_setter) + # ph outer bounder spoke was removed August 2025 # xhat looper bound spoke if cfg.xhatlooper: @@ -165,8 +160,6 @@ def main(): list_of_spoke_dict.append(lagrangian_spoke) if cfg.lagranger: list_of_spoke_dict.append(lagranger_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.xhatlooper: list_of_spoke_dict.append(xhatlooper_spoke) if cfg.xhatshuffle: diff --git a/examples/farmer/archive/farmer_cylinders.py b/examples/farmer/archive/farmer_cylinders.py index 7d961afd3..371b5514c 100644 --- a/examples/farmer/archive/farmer_cylinders.py +++ b/examples/farmer/archive/farmer_cylinders.py @@ -43,7 +43,6 @@ def _parse_args(): cfg.fwph_args() cfg.lagrangian_args() cfg.lagranger_args() - cfg.ph_ob_args() cfg.xhatshuffle_args() cfg.converger_args() cfg.wxbar_read_write_args() @@ -154,15 +153,7 @@ def main(): lagranger_spoke = vanilla.lagranger_spoke(*beans, scenario_creator_kwargs=scenario_creator_kwargs, rho_setter = rho_setter) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = rho_setter) - if cfg.sep_rho: - vanilla.add_sep_rho(ph_ob_spoke, cfg) - if cfg.coeff_rho: - vanilla.add_coeff_rho(ph_ob_spoke, cfg) + # ph outer bounder spoke removed August 2025 # xhat looper bound spoke if cfg.xhatlooper: @@ -184,8 +175,6 @@ def main(): list_of_spoke_dict.append(lagrangian_spoke) if cfg.lagranger: list_of_spoke_dict.append(lagranger_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.xhatlooper: list_of_spoke_dict.append(xhatlooper_spoke) if cfg.xhatshuffle: diff --git a/examples/run_all.py b/examples/run_all.py index 88cf8da83..8fcde1b67 100644 --- a/examples/run_all.py +++ b/examples/run_all.py @@ -386,7 +386,7 @@ def do_one_mmw(dirname, modname, runefstring, npyfile, mmwargstring): do_one("uc", "gradient_uc_cylinders.py", 15, "--bundles-per-rank=0 --max-iterations=100 --default-rho=1 " - "--xhatshuffle --ph-ob --num-scens=5 --max-solver-threads=2 " + "--xhatshuffle --lagrangian --num-scens=5 --max-solver-threads=2 " "--lagrangian-iter0-mipgap=1e-7 --ph-mipgaps-json=phmipgaps.json " f"--solver-name={solver_name} --xhatpath uc_cyl_nonants.npy " "--rel-gap 0.00001 --abs-gap=1 --intra-hub-conv-thresh=-1 " @@ -412,7 +412,7 @@ def do_one_mmw(dirname, modname, runefstring, npyfile, mmwargstring): "--solver-name={}".format(solver_name)) # as of May 2022, this one works well, but outputs some crazy messages do_one("uc", "uc_ama.py", 3, - "--bundles-per-rank=0 --max-iterations=2 " + "--bundles-per-rank=0 --max-iterations=2 " "--default-rho=1 --num-scens=3 " "--fixer-tol=1e-2 --lagranger --xhatshuffle " "--solver-name={}".format(solver_name)) diff --git a/examples/stoch_distr/stoch_distr_admm_cylinders.py b/examples/stoch_distr/stoch_distr_admm_cylinders.py index cfe0a7db6..fc87b6da5 100644 --- a/examples/stoch_distr/stoch_distr_admm_cylinders.py +++ b/examples/stoch_distr/stoch_distr_admm_cylinders.py @@ -35,7 +35,6 @@ def _parse_args(): cfg.xhatxbar_args() cfg.fwph_args() cfg.lagrangian_args() - cfg.ph_ob_args() cfg.tracking_args() cfg.add_to_config("run_async", description="Run with async projective hedging instead of progressive hedging", @@ -52,7 +51,7 @@ def _parse_args(): def _count_cylinders(cfg): count = 1 - cfglist = ["xhatxbar", "lagrangian", "ph_ob"] # All the cfg arguments that create a new cylinders + cfglist = ["xhatxbar", "lagrangian"] # All the cfg arguments that create a new cylinders # Add to this list any cfg attribute that would create a spoke for cylname in cfglist: if cfg[cylname]: @@ -127,13 +126,7 @@ def _wheel_creator(cfg, n_cylinders, scenario_creator, variable_probability, all if cfg.fwph: fw_spoke = vanilla.fwph_spoke(*beans, scenario_creator_kwargs=scenario_creator_kwargs) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = None, - all_nodenames=all_nodenames, - variable_probability=variable_probability) + # ph outer bounder spoke removed August 2025 (replace with ph_dual) # xhat looper bound spoke if cfg.xhatxbar: @@ -148,8 +141,6 @@ def _wheel_creator(cfg, n_cylinders, scenario_creator, variable_probability, all list_of_spoke_dict.append(fw_spoke) if cfg.lagrangian: list_of_spoke_dict.append(lagrangian_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.xhatxbar: list_of_spoke_dict.append(xhatxbar_spoke) diff --git a/examples/uc/gradient_uc_cylinders.py b/examples/uc/gradient_uc_cylinders.py index a2be8a6e1..d918fa285 100644 --- a/examples/uc/gradient_uc_cylinders.py +++ b/examples/uc/gradient_uc_cylinders.py @@ -41,7 +41,6 @@ def _parse_args(): cfg.xhatshuffle_args() cfg.cross_scenario_cuts_args() cfg.dynamic_gradient_args() # gets you gradient_args for free - cfg.ph_ob_args() cfg.add_to_config("ph_mipgaps_json", description="json file with mipgap schedule (default None)", domain=str, @@ -176,11 +175,7 @@ def main(): if xhatlooper: xhatlooper_spoke = vanilla.xhatlooper_spoke(*beans, scenario_creator_kwargs=scenario_creator_kwargs) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = rho_setter) + # ph outer bounder spoke removed August 2025 # xhat shuffle bound spoke if xhatshuffle: @@ -195,8 +190,6 @@ def main(): list_of_spoke_dict.append(fw_spoke) if lagrangian: list_of_spoke_dict.append(lagrangian_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if xhatlooper: list_of_spoke_dict.append(xhatlooper_spoke) if xhatshuffle: diff --git a/mpisppy/cylinders/ph_ob.py b/mpisppy/cylinders/ph_ob.py deleted file mode 100644 index 08d163254..000000000 --- a/mpisppy/cylinders/ph_ob.py +++ /dev/null @@ -1,187 +0,0 @@ -############################################################################### -# mpi-sppy: MPI-based Stochastic Programming in PYthon -# -# Copyright (c) 2024, Lawrence Livermore National Security, LLC, Alliance for -# Sustainable Energy, LLC, The Regents of the University of California, et al. -# All rights reserved. Please see the files COPYRIGHT.md and LICENSE.md for -# full copyright and license information. -############################################################################### -# Runs PH with smaller rhos in order to compute a lower bound -# By default rescale the hub "default-rho" values (multiply by rf) but there are other options to set rho: -# - set rho manually (use _hack_set_rho) -# - use rho rescale factors written in a json file -# - use gradient-based rho (to be tested) - -import json -import mpisppy.cylinders.spoke -import mpisppy.utils.find_rho as find_rho -import mpisppy.utils.gradient as grad -import mpisppy.utils.sputils as sputils -from mpisppy.utils.wtracker import WTracker - -class PhOuterBound(mpisppy.cylinders.spoke.OuterBoundSpoke): - """Updates its own W and x using its own rho. - """ - converger_spoke_char = 'B' - - def ph_ob_prep(self): - # Scenarios are created here - self.opt.PH_Prep(attach_prox=True) - self.opt._reenable_W() - self.opt._create_solvers() - if "ph_ob_rho_rescale_factors_json" in self.opt.options and\ - self.opt.options["ph_ob_rho_rescale_factors_json"] is not None: - with open(self.opt.options["ph_ob_rho_rescale_factors_json"], "r") as fin: - din = json.load(fin) - self.rho_rescale_factors = {int(i): float(din[i]) for i in din} - else: - self.rho_rescale_factors = None - - # use gradient rho - self.use_gradient_rho = False - if "ph_ob_gradient_rho" in self.opt.options: - assert self.opt.options["ph_ob_gradient_rho"]["cfg"] is not None, "You need to give a cfg to use gradient rho." - self.use_gradient_rho = True - print("PH Outer Bounder uses an iterative gradient-based rho setter") - self.cfg = self.opt.options["ph_ob_gradient_rho"]["cfg"] - if "rho_denom" in self.opt.options["ph_ob_gradient_rho"]: - self.cfg.grad_rho_denom = self.opt.options["ph_ob_gradient_rho"]["rho_denom"] - self.cfg.grad_cost_file_out = '_temp_grad_cost_file_ph_ob.csv' - self.cfg.grad_rho_file_out = '_temp_grad_rho_file_ph_ob.csv' # out??? xxxx tbd - # the xhat used here is the same as in the hub - self.grad_object = grad.Find_Grad(self.opt, self.cfg) - self.rho_setter = find_rho.Set_Rho(self.cfg).rho_setter - self.grad_object.write_grad_cost() - - - def _phsolve(self, iternum): - verbose = self.opt.options['verbose'] - teeme = False - if "tee-rank0-solves" in self.opt.options and self.opt.cylinder_rank == 0: - teeme = self.opt.options['tee-rank0-solves'] - - self.opt.solve_loop( - solver_options=self.opt.current_solver_options, - dtiming=False, - gripe=True, - tee=teeme, - verbose=verbose, - warmstart=True, - need_solution=True, - ) - if iternum == 0: - return self.opt.Ebound(verbose) - return None - - def _phboundsolve(self, iternum): - self.opt._disable_prox() - verbose = self.opt.options['verbose'] - teeme = False - if "tee-rank0-solves" in self.opt.options and self.opt.cylinder_rank == 0: - teeme = self.opt.options['tee-rank0-solves'] - if iternum == 0: - warmstart = sputils.WarmstartStatus.USER_SOLUTION - else: - warmstart = True - self.opt.solve_loop( - solver_options=self.opt.current_solver_options, - dtiming=False, - gripe=True, - tee=teeme, - verbose=verbose, - warmstart=warmstart, - need_solution=False, - ) - self.opt._reenable_prox() - # Compute the resulting bound - return self.opt.Ebound(verbose) - - - def _rescale_rho(self, rf): - # IMPORTANT: the scalings accumulate. - # E.g., 0.5 then 2.0 gets you back where you started. - for (sname, scenario) in self.opt.local_scenarios.items(): - for ndn_i, xvar in scenario._mpisppy_data.nonant_indices.items(): - scenario._mpisppy_model.rho[ndn_i] *= rf - - def _display_rho_values(self): - for sname, scenario in self.opt.local_scenarios.items(): - rho_list = [scenario._mpisppy_model.rho[ndn_i]._value - for ndn_i in scenario._mpisppy_data.nonant_indices.keys()] - print(sname, 'PH OB rho values: ', rho_list[:5]) - break - - def _display_W_values(self): - for (sname, scenario) in self.opt.local_scenarios.items(): - W_list = [w._value for w in scenario._mpisppy_model.W.values()] - print(sname, 'W values: ', W_list) - break - - def _display_xbar_values(self): - for (sname, scenario) in self.opt.local_scenarios.items(): - xbar_list = [scenario._mpisppy_model.xbars[ndn_i]._value - for ndn_i in scenario._mpisppy_data.nonant_indices.keys()] - print(sname, 'PH OB xbar values: ', xbar_list) - break - - def _set_gradient_rho(self): - self.grad_object.write_grad_rho() - rho_setter_kwargs = self.opt.options['rho_setter_kwargs'] \ - if 'rho_setter_kwargs' in self.opt.options \ - else dict() - for sname, scenario in self.opt.local_scenarios.items(): - rholist = self.rho_setter(scenario, **rho_setter_kwargs) - for (vid, rho) in rholist: - (ndn, i) = scenario._mpisppy_data.varid_to_nonant_index[vid] - scenario._mpisppy_model.rho[(ndn, i)] = rho - - def _hack_set_rho(self): - # HACK to set specific rho values - rhoval = 0.002 - for sname, scenario in self.opt.local_scenarios.items(): - for ndn_i in scenario._mpisppy_data.nonant_indices.keys(): - scenario._mpisppy_model.rho[ndn_i] = rhoval - - def _update_weights_and_solve(self, iternum): - verbose = self.opt.options["verbose"] - self.opt.Compute_Xbar(verbose=verbose) - self.opt.Update_W(verbose=verbose) - # see if rho should be rescaled - if self.use_gradient_rho and iternum == 0: - self._set_gradient_rho() - self._display_rho_values() - if self.rho_rescale_factors is not None\ - and iternum in self.rho_rescale_factors: - self._rescale_rho(self.rho_rescale_factors[iternum]) - bound = self._phboundsolve(iternum) # keep it before calling _phsolve - self._phsolve(iternum) - return bound - - def main(self): - self.ph_ob_prep() - self._rescale_rho(self.opt.options["ph_ob_initial_rho_rescale_factor"] ) - - self.trivial_bound = self._phsolve(0) - self.send_bound(self.trivial_bound) - self.opt.current_solver_options = self.opt.iterk_solver_options - - self.B_iter = 1 - self.opt.B_iter = self.B_iter - wtracker = WTracker(self.opt) - - while not self.got_kill_signal(): - # because of aph, do not check for new data, just go for it - self.send_bound(self._update_weights_and_solve(self.B_iter)) - self.B_iter += 1 - self.opt.B_iter = self.B_iter - wtracker.grab_local_Ws() - - def finalize(self): - ''' - Do one final lagrangian pass with the final - PH weights. Useful for when PH convergence - and/or iteration limit is the cause of termination - ''' - self.final_bound = self._update_weights_and_solve(self.B_iter) - self.send_bound(self.final_bound) - return self.final_bound diff --git a/mpisppy/generic_cylinders.py b/mpisppy/generic_cylinders.py index 716059596..5157ae815 100644 --- a/mpisppy/generic_cylinders.py +++ b/mpisppy/generic_cylinders.py @@ -87,7 +87,6 @@ def _parse_args(m): cfg.relaxed_ph_args() cfg.fwph_args() cfg.lagrangian_args() - cfg.ph_ob_args() cfg.subgradient_bounder_args() cfg.xhatshuffle_args() cfg.xhatxbar_args() @@ -334,20 +333,6 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ if cfg.lagrangian_starting_mipgap is not None: vanilla.add_gapper(lagrangian_spoke, cfg, "lagrangian") - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = rho_setter, - all_nodenames = all_nodenames, - ) - if cfg.sep_rho: - vanilla.add_sep_rho(ph_ob_spoke, cfg) - if cfg.coeff_rho: - vanilla.add_coeff_rho(ph_ob_spoke, cfg) - if cfg.sensi_rho: - vanilla.add_sensi_rho(ph_ob_spoke, cfg) - # dual ph spoke if cfg.ph_dual: ph_dual_spoke = vanilla.ph_dual_spoke(*beans, @@ -361,6 +346,8 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ vanilla.add_coeff_rho(ph_dual_spoke, cfg) if cfg.sensi_rho: vanilla.add_sensi_rho(ph_dual_spoke, cfg) + # TBD xxxxx add grad rho asap after PR#559 is merged + # Note: according to DLW, it is non-trivial to deal with the cfg args # relaxed ph spoke if cfg.relaxed_ph: @@ -421,8 +408,6 @@ def _do_decomp(module, cfg, scenario_creator, scenario_creator_kwargs, scenario_ list_of_spoke_dict.append(fw_spoke) if cfg.lagrangian: list_of_spoke_dict.append(lagrangian_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.ph_dual: list_of_spoke_dict.append(ph_dual_spoke) if cfg.relaxed_ph: diff --git a/mpisppy/tests/examples/stoch_distr/stoch_distr_admm_cylinders.py b/mpisppy/tests/examples/stoch_distr/stoch_distr_admm_cylinders.py index c53974be4..2b859d182 100644 --- a/mpisppy/tests/examples/stoch_distr/stoch_distr_admm_cylinders.py +++ b/mpisppy/tests/examples/stoch_distr/stoch_distr_admm_cylinders.py @@ -39,7 +39,6 @@ def _parse_args(): cfg.xhatxbar_args() cfg.fwph_args() cfg.lagrangian_args() - cfg.ph_ob_args() cfg.tracking_args() cfg.add_to_config("run_async", description="Run with async projective hedging instead of progressive hedging", @@ -52,7 +51,7 @@ def _parse_args(): def _count_cylinders(cfg): count = 1 - cfglist = ["xhatxbar", "lagrangian", "ph_ob", "fwph"] #all the cfg arguments that create a new cylinders + cfglist = ["xhatxbar", "lagrangian", "fwph"] #all the cfg arguments that create a new cylinders for cylname in cfglist: if cfg[cylname]: count += 1 @@ -127,13 +126,7 @@ def _wheel_creator(cfg, n_cylinders, scenario_creator, variable_probability, all if cfg.fwph: fw_spoke = vanilla.fwph_spoke(*beans, scenario_creator_kwargs=scenario_creator_kwargs) - # ph outer bounder spoke - if cfg.ph_ob: - ph_ob_spoke = vanilla.ph_ob_spoke(*beans, - scenario_creator_kwargs=scenario_creator_kwargs, - rho_setter = None, - all_nodenames=all_nodenames, - variable_probability=variable_probability) + # ph outer bounder spoke removed August 2025 # xhat looper bound spoke if cfg.xhatxbar: @@ -148,8 +141,6 @@ def _wheel_creator(cfg, n_cylinders, scenario_creator, variable_probability, all list_of_spoke_dict.append(fw_spoke) if cfg.lagrangian: list_of_spoke_dict.append(lagrangian_spoke) - if cfg.ph_ob: - list_of_spoke_dict.append(ph_ob_spoke) if cfg.xhatxbar: list_of_spoke_dict.append(xhatxbar_spoke) diff --git a/mpisppy/tests/straight_tests.py b/mpisppy/tests/straight_tests.py index 72cca9dbe..808ff1223 100644 --- a/mpisppy/tests/straight_tests.py +++ b/mpisppy/tests/straight_tests.py @@ -22,17 +22,6 @@ def _doone(cmdstr): badguys.append(f"Test failed with code {ret}:\n{cmdstr}") ##################################################### -# farmer -example_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'examples', 'farmer', 'archive') -fpath = os.path.join(example_dir, 'farmer_cylinders.py') - -cmdstr = f"python {fpath} --help" -_doone(cmdstr) - -cmdstr = f"mpiexec -np 1 python {fpath} --help" -_doone(cmdstr) - - # aircond example_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', 'examples', 'aircond') fpath = os.path.join(example_dir, 'aircond_cylinders.py') diff --git a/mpisppy/utils/cfg_vanilla.py b/mpisppy/utils/cfg_vanilla.py index 8037d0720..24f86c80c 100644 --- a/mpisppy/utils/cfg_vanilla.py +++ b/mpisppy/utils/cfg_vanilla.py @@ -27,7 +27,6 @@ from mpisppy.cylinders.lagrangian_bounder import LagrangianOuterBound from mpisppy.cylinders.lagranger_bounder import LagrangerOuterBound from mpisppy.cylinders.subgradient_bounder import SubgradientOuterBound -from mpisppy.cylinders.ph_ob import PhOuterBound from mpisppy.cylinders.xhatlooper_bounder import XhatLooperInnerBound from mpisppy.cylinders.xhatxbar_bounder import XhatXbarInnerBound from mpisppy.cylinders.xhatspecific_bounder import XhatSpecificInnerBound @@ -682,7 +681,7 @@ def reduced_costs_spoke( # special lagrangian: computes its own xhat and W (does not seem to work well) -# ph_ob_spoke is probably better +# ph_dual is probably better def lagranger_spoke( cfg, scenario_creator, @@ -1074,43 +1073,4 @@ def cross_scenario_cuts_spoke( return cut_spoke # run PH with smaller rho to compute LB -def ph_ob_spoke( - cfg, - scenario_creator, - scenario_denouement, - all_scenario_names, - scenario_creator_kwargs=None, - rho_setter=None, - all_nodenames=None, - variable_probability=None, -): - shoptions = shared_options(cfg) - ph_ob_spoke = { - "spoke_class": PhOuterBound, - "opt_class": PHBase, - "opt_kwargs": { - "options": shoptions, - "all_scenario_names": all_scenario_names, - "scenario_creator": scenario_creator, - "scenario_creator_kwargs": scenario_creator_kwargs, - 'scenario_denouement': scenario_denouement, - "rho_setter": rho_setter, - "all_nodenames": all_nodenames, - "variable_probability": variable_probability, - } - } - if cfg.ph_ob_rho_rescale_factors_json is not None: - ph_ob_spoke["opt_kwargs"]["options"]\ - ["ph_ob_rho_rescale_factors_json"]\ - = cfg.ph_ob_rho_rescale_factors_json - ph_ob_spoke["opt_kwargs"]["options"]["ph_ob_initial_rho_rescale_factor"]\ - = cfg.ph_ob_initial_rho_rescale_factor - if cfg.ph_ob_gradient_rho: - ph_ob_spoke["opt_kwargs"]["options"]\ - ["ph_ob_gradient_rho"]\ - = dict() - ph_ob_spoke["opt_kwargs"]["options"]\ - ["ph_ob_gradient_rho"]["cfg"]\ - = cfg - - return ph_ob_spoke +##def ph_ob_spoke( deprecated and replaced with ph_dual diff --git a/mpisppy/utils/config.py b/mpisppy/utils/config.py index ab9c8f16b..e10d9fedd 100644 --- a/mpisppy/utils/config.py +++ b/mpisppy/utils/config.py @@ -732,24 +732,7 @@ def subgradient_bounder_args(self): def ph_ob_args(self): - - self.add_to_config("ph_ob", - description="use PH to compute outer bound", - domain=bool, - default=False) - self.add_to_config("ph_ob_rho_rescale_factors_json", - description="json file with {iternum: rho rescale factor} (default None)", - domain=str, - default=None) - self.add_to_config("ph_ob_initial_rho_rescale_factor", - description="Used to rescale rho initially (will be done regardless of other rescaling (default 0.1)", - domain=float, - default=0.1) - self.add_to_config("ph_ob_gradient_rho", - description="use gradient-based rho in PH OB", - domain=bool, - default=False) - + raise RuntimeError("ph_ob (the --ph-ob option) and ph_ob_args were deprecated and replaced with ph_dual August 2025") def relaxed_ph_args(self):