Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nonant bounds buffer #500

Draft
wants to merge 46 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
9dc3a6e
towards generic communicators
bknueven Mar 7, 2025
da2e00b
work towards automatic field length computation
bknueven Mar 7, 2025
ad1f6b9
automatically register send fields based on class attributes
bknueven Mar 7, 2025
dd91f14
remove has_*_spokes
bknueven Mar 7, 2025
d89676c
more generic receive logic
bknueven Mar 7, 2025
f5baab5
remove converger_spoke_types
bknueven Mar 7, 2025
3d7b47e
communicators exchange send data
bknueven Mar 7, 2025
d846615
remove optional_recieve_fields
bknueven Mar 7, 2025
c547777
fix API for register_extension_recv_field
bknueven Mar 7, 2025
4d3b668
unifying register_receive_fields
bknueven Mar 7, 2025
f2ff331
better validation; code cleanup
bknueven Mar 10, 2025
36b1a0e
remove *_to_* methods; nothing was really pushed anyways...
bknueven Mar 10, 2025
8675a82
add coverage for RC rho
bknueven Mar 10, 2025
c4b4efc
update RC rho for PR #476
bknueven Mar 10, 2025
4e2085e
remove hub_from_spoke
bknueven Mar 10, 2025
091a2c8
remove spoke_from_hub
bknueven Mar 10, 2025
2769a54
fixing a few bugs
bknueven Mar 10, 2025
a94c2dd
extensions have to do nearly everything anyways; might as well be exp…
bknueven Mar 11, 2025
3948b2f
spokes can get DUALS and NONANTs from whereever, as long as the provi…
bknueven Mar 11, 2025
62a3da9
cleaning up windows; errata
bknueven Mar 26, 2025
a549c7d
Use `Free` for older version of mpi4py
bknueven Mar 26, 2025
1a0ceb8
bring back explicit window creation / distruction
bknueven Mar 26, 2025
5fdb1f0
look up nonants/cost in cross scenario spoke
bknueven Mar 27, 2025
821bc31
remove implicit field update for spokes: spokes must now explicitly u…
bknueven Mar 31, 2025
dd09700
add Field for lower/upper bounds
bknueven Mar 27, 2025
10496da
allow communicator to register its own buffer to receive
bknueven Mar 27, 2025
cd1cadd
promote `Spoke.update_receive_buffers` to SPCommuicator
bknueven Mar 27, 2025
0e7e71c
adding method to update nonant bounds; call that method where appropr…
bknueven Mar 27, 2025
968e494
trying to pass LB/UB from RC Spoke
bknueven Mar 28, 2025
952935b
getting new bounds in hub; doesn't exactly match extension
bknueven Mar 28, 2025
00ab113
partially revert 4e970cdc1fa0541d5d84f293fd1f21c93dca7810
bknueven Mar 31, 2025
912195c
Revert "promote `Spoke.update_receive_buffers` to SPCommuicator"
bknueven Mar 31, 2025
5589d8e
switch to `receive_` paradigm for nonant bounds
bknueven Mar 31, 2025
c8e1363
nonant bound update now matches existing extension
bknueven Mar 31, 2025
a35cd7d
terminate even if signal is stale; faster termination for shuffle bou…
bknueven Mar 31, 2025
f270c3f
terminate even if signal is stale; faster termination for shuffle bou…
bknueven Mar 31, 2025
1712eac
keep best bounding dual function per variable
bknueven Mar 31, 2025
1c8bcbf
re-do termination synchronization
bknueven Mar 31, 2025
1ca8ff9
re-do termination synchronization
bknueven Mar 31, 2025
252166c
refactor bounds sync to base class
bknueven Apr 1, 2025
fd45471
Merge remote-tracking branch 'upstream/main' into communicator_refactor
bknueven Apr 1, 2025
a21143d
Merge branch 'communicator_refactor' into nonant_bounds_buffer
bknueven Apr 2, 2025
988a064
Revert "allow communicator to register its own buffer to receive"
bknueven Apr 2, 2025
a1c640f
cleanup merge; add bound updater for RC spoke
bknueven Apr 2, 2025
7a6dbfc
remove bound setter; replace with send_bound
bknueven Apr 2, 2025
42f36e3
Merge branch 'communicator_refactor' into nonant_bounds_buffer
bknueven Apr 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/run_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ def do_one_mmw(dirname, runefstring, npyfile, mmwargstring):
"--integer-relax-then-enforce "
"--integer-relax-then-enforce-ratio=0.95 "
"--lagrangian "
"--max-iterations=100 --default-rho=1 "
"--max-iterations=100 --default-rho=1 --reduced-costs-rho "
"--reduced-costs --rc-fixer --xhatshuffle "
"--linearize-proximal-terms "
"--rel-gap=0.0 --surrogate-nonant "
Expand Down
4 changes: 4 additions & 0 deletions examples/sslp/sslp_cylinders.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def _parse_args():
cfg.xhatshuffle_args()
cfg.subgradient_bounder_args()
cfg.reduced_costs_args()
cfg.reduced_costs_rho_args()
cfg.coeff_rho_args()
cfg.integer_relax_then_enforce_args()
cfg.parse_command_line("sslp_cylinders")
Expand Down Expand Up @@ -96,6 +97,9 @@ def main():
if cfg.coeff_rho:
vanilla.add_coeff_rho(hub_dict, cfg)

if cfg.reduced_costs_rho:
vanilla.add_reduced_costs_rho(hub_dict, cfg)

if cfg.integer_relax_then_enforce:
vanilla.add_integer_relax_then_enforce(hub_dict, cfg)

Expand Down
34 changes: 22 additions & 12 deletions mpisppy/cylinders/cross_scen_spoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
from mpisppy import MPI
from mpisppy.utils.lshaped_cuts import LShapedCutGenerator
from mpisppy.cylinders.spwindow import Field
from mpisppy.cylinders.spoke import Spoke

import numpy as np
import pyomo.environ as pyo
import mpisppy.cylinders.spoke as spoke

class CrossScenarioCutSpoke(spoke.Spoke):
def __init__(self, spbase_object, fullcomm, strata_comm, cylinder_comm, options=None):
super().__init__(spbase_object, fullcomm, strata_comm, cylinder_comm, options=options)
class CrossScenarioCutSpoke(Spoke):

send_fields = (*Spoke.send_fields, Field.CROSS_SCENARIO_CUT)
receive_fields = (*Spoke.receive_fields, Field.NONANT, Field.CROSS_SCENARIO_COST)

def register_send_fields(self) -> None:

Expand All @@ -37,18 +38,28 @@ def register_send_fields(self) -> None:
(self.nonant_per_scen, remainder) = divmod(vbuflen, local_scen_count)
assert(remainder == 0)

## the _locals will also have the kill signal
self.all_nonant_len = vbuflen
self.all_eta_len = nscen*local_scen_count

self.all_nonants = self.register_recv_field(Field.NONANT, 0, vbuflen)
self.all_etas = self.register_recv_field(Field.CROSS_SCENARIO_COST, 0, nscen * nscen)

self.all_coefs = self.register_send_field(Field.CROSS_SCENARIO_CUT,
nscen*(self.nonant_per_scen + 1 + 1))
self.all_coefs = self.send_buffers[Field.CROSS_SCENARIO_CUT]

return

def register_receive_fields(self):
super().register_receive_fields()

nonant_ranks = self.opt.spcomm.fields_to_ranks[Field.NONANT]
cs_cost_ranks = self.opt.spcomm.fields_to_ranks[Field.CROSS_SCENARIO_COST]

assert len(nonant_ranks) == 1
assert len(cs_cost_ranks) == 1
assert nonant_ranks[0] == cs_cost_ranks[0]
source_rank = nonant_ranks[0]

self.all_nonants = self.register_recv_field(Field.NONANT, source_rank)
self.all_etas = self.register_recv_field(Field.CROSS_SCENARIO_COST, source_rank)

def prep_cs_cuts(self):
# create a map scenario -> index, this index is used for various lists containing scenario dependent info.
self.scenario_to_index = { scen : indx for indx, scen in enumerate(self.opt.all_scenario_names) }
Expand Down Expand Up @@ -135,7 +146,7 @@ def make_eta_lb_cut(self):
## this cut -- [ LB, -1, *0s ], i.e., -1*\eta + LB <= 0
all_coefs[row_len*idx] = self._eta_lb_array[idx]
all_coefs[row_len*idx+1] = -1
self.spoke_to_hub(all_coefs, Field.CROSS_SCENARIO_CUT)
self.put_send_buffer(all_coefs, Field.CROSS_SCENARIO_CUT)

def make_cut(self):

Expand Down Expand Up @@ -293,7 +304,7 @@ def make_cut(self):
all_coefs[row_len*idx:row_len*(idx+1)] = coef_dict[k]
elif feas_cuts:
all_coefs[row_len*idx:row_len*(idx+1)] = feas_cuts.pop()
self.spoke_to_hub(all_coefs, Field.CROSS_SCENARIO_CUT)
self.put_send_buffer(all_coefs, Field.CROSS_SCENARIO_CUT)

def main(self):
# call main cut generation routine
Expand All @@ -303,7 +314,6 @@ def main(self):

# main loop
while not (self.got_kill_signal()):
# if self._new_locals:
if self.all_nonants.is_new() and self.all_etas.is_new():
self.make_cut()
## End if
Expand Down
7 changes: 5 additions & 2 deletions mpisppy/cylinders/fwph_spoke.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@ def sync(self):
if not hasattr(self.opt, '_local_bound'):
return
# Tell the hub about the most recent bound
self.bound = self.opt._local_bound
self.send_bound(self.opt._local_bound)

# Update the nonant bounds, if possible
self.receive_nonant_bounds()

def finalize(self):
# The FWPH spoke can call "finalize" before it
Expand All @@ -34,6 +37,6 @@ def finalize(self):
# if we terminated early
if not hasattr(self.opt, '_local_bound'):
return
self.bound = self.opt._local_bound
self.send_bound(self.opt._local_bound)
self.final_bound = self.opt._local_bound
return self.final_bound
Loading
Loading