1212
1313from pyomo .common .config import (
1414 ConfigBlock ,
15+ ConfigDict ,
1516 ConfigValue ,
1617 In ,
1718 document_kwargs_from_configdict ,
19+ document_class_CONFIG ,
20+ document_configdict ,
21+ ADVANCED_OPTION ,
1822)
23+
1924from pyomo .common .modeling import unique_component_name
2025from pyomo .common .dependencies import numpy as np
2126from pyomo .contrib .multistart .high_conf_stop import should_stop
2227from pyomo .contrib .multistart .reinit import reinitialize_variables , strategies
2328from pyomo .core import Objective , Var , minimize , value
29+ from pyomo .contrib .solver .common .base import SolverBase
30+ from pyomo .contrib .solver .common .config import SolverConfig
2431from pyomo .contrib .solver .common .factory import SolverFactory
2532from pyomo .contrib .solver .common .results import SolutionStatus
33+
2634from pyomo .common .dependencies .scipy import stats
2735from pyomo .common .dependencies import numpy as np
2836
2937logger = logging .getLogger ('pyomo.contrib.multistart' )
3038
3139
40+ @document_configdict ()
41+ class MultistartConfig (SolverConfig ):
42+ def __init__ (
43+ self ,
44+ description = None ,
45+ doc = None ,
46+ implicit = False ,
47+ implicit_domain = None ,
48+ visibility = 0 ,
49+ ):
50+ super ().__init__ (
51+ description = description ,
52+ doc = doc ,
53+ implicit = implicit ,
54+ implicit_domain = implicit_domain ,
55+ visibility = visibility ,
56+ )
57+
58+ self .strategy = self .declare (
59+ "strategy" ,
60+ ConfigValue (
61+ default = "rand" ,
62+ domain = In (strategies .keys ()),
63+ description = "Specify the restart strategy. Defaults to rand." ,
64+ doc = """Specify the restart strategy.
65+
66+ - "rand": random choice between variable bounds
67+ - "rand_vector": random choice, vectorized approach with sampler
68+ - "midpoint_guess_and_bound": midpoint between current value and farthest bound
69+ - "rand_guess_and_bound": random choice between current value and farthest bound
70+ - "rand_distributed": random choice among evenly distributed values
71+ - "midpoint": exact midpoint between the bounds. If using this option, multiple iterations are useless.
72+ """ ,
73+ ),
74+ )
75+ self .solver = self .declare (
76+ "solver" ,
77+ ConfigValue (
78+ default = "ipopt" ,
79+ description = "solver to use, defaults to ipopt"
80+ "Should also be able to accept solver objects. In progress" ,
81+ ),
82+ )
83+ self .solver_args = self .declare (
84+ "solver_args" ,
85+ ConfigValue (
86+ default = {},
87+ description = "Dictionary of keyword arguments to pass to the solver." ,
88+ ),
89+ )
90+ self .iterations = self .declare (
91+ "iterations" ,
92+ ConfigValue (
93+ default = 10 ,
94+ description = "Specify the number of iterations, defaults to 10. "
95+ "If -1 is specified, the high confidence stopping rule will be used" ,
96+ ),
97+ )
98+ self .stopping_mass = self .declare (
99+ "stopping_mass" ,
100+ ConfigValue (
101+ default = 0.5 ,
102+ description = "Maximum allowable estimated missing mass of optima." ,
103+ doc = """Maximum allowable estimated missing mass of optima for the
104+ high confidence stopping rule, only used with the random strategy.
105+ The lower the parameter, the stricter the rule.
106+ Value bounded in (0, 1].""" ,
107+ ),
108+ )
109+ self .stopping_delta = self .declare (
110+ "stopping_delta" ,
111+ ConfigValue (
112+ default = 0.5 ,
113+ description = "1 minus the confidence level required for the stopping rule." ,
114+ doc = """1 minus the confidence level required for the stopping rule for the
115+ high confidence stopping rule, only used with the random strategy.
116+ The lower the parameter, the stricter the rule.
117+ Value bounded in (0, 1].""" ,
118+ ),
119+ )
120+ # self.surpress_unbounded_warning = self.declare(
121+ # "suppress_unbounded_warning",
122+ # ConfigValue(
123+ # default=False,
124+ # domain=bool,
125+ # description="True to suppress warning for skipping unbounded variables.",
126+ # ),
127+ # )
128+ self .HCS_max_iterations = self .declare (
129+ "HCS_max_iterations" ,
130+ ConfigValue (
131+ default = 1000 ,
132+ description = "Maximum number of iterations before interrupting the high confidence stopping rule." ,
133+ ),
134+ )
135+ self .HCS_tolerance = self .declare (
136+ "HCS_tolerance" ,
137+ ConfigValue (
138+ default = 0 ,
139+ description = "Tolerance on HCS objective value equality. Defaults to Python float equality precision." ,
140+ ),
141+ )
142+ self .break_on_solution = self .declare (
143+ "break_on_solution" ,
144+ ConfigValue (
145+ default = False ,
146+ description = "Condition to break if a feasible or optimal solution is found. Defaults to False." ,
147+ ),
148+ )
149+ self .sampling_method = self .declare (
150+ "sampling_method" ,
151+ ConfigValue (
152+ default = "random_uniform" ,
153+ description = "Method for sampling random starting points for reinitialization step. "
154+ "Supported options are 'random_uniform', 'latin_hypercube', and 'sobol_sampling'. "
155+ "Only utilized when config.strategy is 'rand_vector'." ,
156+ ),
157+ )
158+ self .seed = self .declare (
159+ "seed" ,
160+ ConfigValue (
161+ default = None ,
162+ description = "Seed for reproducibility in random sampling methods." ,
163+ ),
164+ )
165+ self .rng = self .declare (
166+ "rng" ,
167+ ConfigValue (
168+ default = None ,
169+ description = "Random number generator for reproducibility in random sampling methods. \
170+ Preferred over seed." ,
171+ ),
172+ )
173+
174+
32175@SolverFactory .register ('multistart' , doc = 'MultiStart solver for NLPs' )
33- @document_kwargs_from_configdict ( 'CONFIG' )
34- class MultiStart :
176+ @document_class_CONFIG ( methods = [ 'solve' ] )
177+ class MultiStart ( SolverBase ) :
35178 """Solver wrapper that initializes at multiple starting points.
36179
37180 # TODO: also return appropriate duals
@@ -43,122 +186,7 @@ class MultiStart:
43186
44187 """
45188
46- CONFIG = ConfigBlock ("MultiStart" )
47- CONFIG .declare (
48- "strategy" ,
49- ConfigValue (
50- default = "rand" ,
51- domain = In (strategies .keys ()),
52- description = "Specify the restart strategy. Defaults to rand." ,
53- doc = """Specify the restart strategy.
54-
55- - "rand": random choice between variable bounds
56- - "rand_vector": random choice, vectorized approach with sampler
57- - "midpoint_guess_and_bound": midpoint between current value and farthest bound
58- - "rand_guess_and_bound": random choice between current value and farthest bound
59- - "rand_distributed": random choice among evenly distributed values
60- - "midpoint": exact midpoint between the bounds. If using this option, multiple iterations are useless.
61- """ ,
62- ),
63- )
64- CONFIG .declare (
65- "solver" ,
66- ConfigValue (
67- default = "ipopt" ,
68- description = "solver to use, defaults to ipopt"
69- "Should also be able to accept solver objects. In progress" ,
70- ),
71- )
72- CONFIG .declare (
73- "solver_args" ,
74- ConfigValue (
75- default = {},
76- description = "Dictionary of keyword arguments to pass to the solver." ,
77- ),
78- )
79- CONFIG .declare (
80- "iterations" ,
81- ConfigValue (
82- default = 10 ,
83- description = "Specify the number of iterations, defaults to 10. "
84- "If -1 is specified, the high confidence stopping rule will be used" ,
85- ),
86- )
87- CONFIG .declare (
88- "stopping_mass" ,
89- ConfigValue (
90- default = 0.5 ,
91- description = "Maximum allowable estimated missing mass of optima." ,
92- doc = """Maximum allowable estimated missing mass of optima for the
93- high confidence stopping rule, only used with the random strategy.
94- The lower the parameter, the stricter the rule.
95- Value bounded in (0, 1].""" ,
96- ),
97- )
98- CONFIG .declare (
99- "stopping_delta" ,
100- ConfigValue (
101- default = 0.5 ,
102- description = "1 minus the confidence level required for the stopping rule." ,
103- doc = """1 minus the confidence level required for the stopping rule for the
104- high confidence stopping rule, only used with the random strategy.
105- The lower the parameter, the stricter the rule.
106- Value bounded in (0, 1].""" ,
107- ),
108- )
109- CONFIG .declare (
110- "suppress_unbounded_warning" ,
111- ConfigValue (
112- default = False ,
113- domain = bool ,
114- description = "True to suppress warning for skipping unbounded variables." ,
115- ),
116- )
117- CONFIG .declare (
118- "HCS_max_iterations" ,
119- ConfigValue (
120- default = 1000 ,
121- description = "Maximum number of iterations before interrupting the high confidence stopping rule." ,
122- ),
123- )
124- CONFIG .declare (
125- "HCS_tolerance" ,
126- ConfigValue (
127- default = 0 ,
128- description = "Tolerance on HCS objective value equality. Defaults to Python float equality precision." ,
129- ),
130- )
131- CONFIG .declare (
132- "break_on_solution" ,
133- ConfigValue (
134- default = False ,
135- description = "Condition to break if a feasible or optimal solution is found. Defaults to False." ,
136- ),
137- )
138- CONFIG .declare (
139- "sampling_method" ,
140- ConfigValue (
141- default = "random_uniform" ,
142- description = "Method for sampling random starting points for reinitialization step. "
143- "Supported options are 'random_uniform', 'latin_hypercube', and 'sobol_sampling'. "
144- "Only utilized when config.strategy is 'rand_vector'." ,
145- ),
146- )
147- CONFIG .declare (
148- "seed" ,
149- ConfigValue (
150- default = None ,
151- description = "Seed for reproducibility in random sampling methods." ,
152- ),
153- )
154- CONFIG .declare (
155- "rng" ,
156- ConfigValue (
157- default = None ,
158- description = "Random number generator for reproducibility in random sampling methods. \
159- Preferred over seed." ,
160- ),
161- )
189+ CONFIG = MultistartConfig ()
162190
163191 def available (self , exception_flag = True ):
164192 """Check if solver is available.
@@ -169,6 +197,12 @@ def available(self, exception_flag=True):
169197 """
170198 return True
171199
200+ def version (self ):
201+ """Get solver version
202+ TODO: This is a solver wrapper, unsure how to define version in this case."""
203+
204+ return
205+
172206 def license_is_valid (self ):
173207 return True
174208
0 commit comments