forked from Pyomo/mpi-sppy
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsubgradient.py
131 lines (113 loc) · 5.23 KB
/
subgradient.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
###############################################################################
# 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.
###############################################################################
import mpisppy.phbase
import mpisppy.MPI as _mpi
_global_rank = _mpi.COMM_WORLD.Get_rank()
class Subgradient(mpisppy.phbase.PHBase):
""" Subgradient Algorithm """
def subgradient_main(self, finalize=True):
""" Execute the subgradient algorithm.
Args:
finalize (bool, optional, default=True):
If True, call `PH.post_loops()`, if False, do not,
and return None for Eobj
Returns:
tuple:
Tuple containing
conv (float):
The convergence value (not easily interpretable).
Eobj (float or `None`):
If `finalize=True`, this is the expected, weighted
objective value. This value is not directly useful.
If `finalize=False`, this value is `None`.
trivial_bound (float):
The "trivial bound", computed by solving the model with no
nonanticipativity constraints (immediately after iter 0).
"""
verbose = self.options['verbose']
smoothed = self.options['smoothed']
if smoothed != 0:
raise RuntimeError("Cannnot use smoothing with Subgradient algorithm")
self.PH_Prep(attach_prox=False, attach_smooth=smoothed)
if (verbose):
print('Calling Subgradient Iter0 on global rank {}'.format(_global_rank))
trivial_bound = self.Iter0()
# set self.best_bound_obj_val if we don't have any additional fixed variables
if self._can_update_best_bound():
self.best_bound_obj_val = trivial_bound
if (verbose):
print('Completed Subgradient Iter0 on global rank {}'.format(_global_rank))
self.iterk_loop()
if finalize:
Eobj = self.post_loops(self.extensions)
else:
Eobj = None
return self.conv, Eobj, trivial_bound
def ph_main(self, finalize=True):
# for working with a PHHub
return self.subgradient_main(finalize=finalize)
def solve_loop(self,
solver_options=None,
use_scenarios_not_subproblems=False,
dtiming=False,
dis_W=False,
dis_prox=False,
gripe=False,
disable_pyomo_signal_handling=False,
tee=False,
verbose=False,
need_solution=True,
):
""" Loop over `local_subproblems` and solve them in a manner
dicated by the arguments.
In addition to changing the Var values in the scenarios, this function
also updates the `_PySP_feas_indictor` to indicate which scenarios were
feasible/infeasible.
Args:
solver_options (dict, optional):
The scenario solver options.
use_scenarios_not_subproblems (boolean, optional):
If True, solves individual scenario problems, not subproblems.
This distinction matters when using bundling. Default is False.
dtiming (boolean, optional):
If True, reports solve timing information. Default is False.
dis_W (boolean, optional):
If True, duals weights (Ws) are disabled before solve, then
re-enabled after solve. Default is False.
dis_prox (boolean, optional):
If True, prox terms are disabled before solve, then
re-enabled after solve. Default is False.
gripe (boolean, optional):
If True, output a message when a solve fails. Default is False.
disable_pyomo_signal_handling (boolean, optional):
True for asynchronous PH; ignored for persistent solvers.
Default False.
tee (boolean, optional):
If True, displays solver output. Default False.
verbose (boolean, optional):
If True, displays verbose output. Default False.
need_solution (boolean, optional):
If True, raises an exception if a solution is not available.
Default True
"""
super().solve_loop(
solver_options=solver_options,
use_scenarios_not_subproblems=use_scenarios_not_subproblems,
dtiming=dtiming,
dis_W=dis_W,
dis_prox=dis_prox,
gripe=gripe,
disable_pyomo_signal_handling=disable_pyomo_signal_handling,
tee=tee,
verbose=verbose,
need_solution=need_solution,
)
# set self.best_bound_obj_val if we don't have any additional fixed variables
if self._can_update_best_bound():
self.best_bound_obj_val = self.Ebound(verbose)