source: coopr.pysp/trunk/coopr/pysp/ef_writer_script.py @ 2842

Last change on this file since 2842 was 2842, checked in by jwatson, 11 years ago

Adding --keep-solver-files option to the PySP runef script, to aid debugging.

  • Property svn:executable set to *
File size: 10.3 KB
Line 
1#  _________________________________________________________________________
2#
3#  Coopr: A COmmon Optimization Python Repository
4#  Copyright (c) 2009 Sandia Corporation.
5#  This software is distributed under the BSD License.
6#  Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
7#  the U.S. Government retains certain rights in this software.
8#  For more information, see the Coopr README.txt file.
9#  _________________________________________________________________________
10
11
12import sys
13import os
14from optparse import OptionParser
15
16import pyutilib.services
17import textwrap
18import traceback
19try:
20    import cProfile as profile
21except ImportError:
22    import profile
23import pstats
24import gc
25
26from coopr.pysp.ef import *
27
28from coopr.opt.base import SolverFactory
29from coopr.opt.parallel import SolverManagerFactory
30
31#
32# utility method to construct an option parser for ef writer arguments
33#
34
35def construct_ef_writer_options_parser(usage_string):
36
37   parser = OptionParser()
38   parser.add_option("--verbose",
39                     help="Generate verbose output, beyond the usual status output. Default is False.",
40                     action="store_true",
41                     dest="verbose",
42                     default=False)
43   parser.add_option("--model-directory",
44                     help="The directory in which all model (reference and scenario) definitions are stored. Default is \".\".",
45                     action="store",
46                     dest="model_directory",
47                     type="string",
48                     default=".")
49   parser.add_option("--instance-directory",
50                     help="The directory in which all instance (reference and scenario) definitions are stored. Default is \".\".",
51                     action="store",
52                     dest="instance_directory",
53                     type="string",
54                     default=".")
55   parser.add_option("--generate-weighted-cvar",
56                     help="Add a weighted CVaR term to the primary objective",
57                     action="store_true",
58                     dest="generate_weighted_cvar",
59                     default=False)
60   parser.add_option("--cvar-weight",
61                     help="The weight associated with the CVaR term in the risk-weighted objective formulation. Default is 1.0. If the weight is 0, then *only* a non-weighted CVaR cost will appear in the EF objective - the expected cost component will be dropped.",
62                     action="store",
63                     dest="cvar_weight",
64                     type="float",
65                     default=1.0)
66   parser.add_option("--risk-alpha",
67                     help="The probability threshold associated with cvar (or any future) risk-oriented performance metrics. Default is 0.95.",
68                     action="store",
69                     dest="risk_alpha",
70                     type="float",
71                     default=0.95)
72   parser.add_option("--output-file",
73                     help="Specify the name of the extensive form output file",
74                     action="store",
75                     dest="output_file",
76                     type="string",
77                     default="efout.lp")
78   parser.add_option("--solve",
79                     help="Following write of the extensive form model, solve it.",
80                     action="store_true",
81                     dest="solve_ef",
82                     default=False)
83   parser.add_option("--solver",
84                     help="The type of solver used to solve scenario sub-problems. Default is cplex.",
85                     action="store",
86                     dest="solver_type",
87                     type="string",
88                     default="cplex")
89   parser.add_option("--solver-manager",
90                     help="The type of solver manager used to coordinate scenario sub-problem solves. Default is serial.",
91                     action="store",
92                     dest="solver_manager_type",
93                     type="string",
94                     default="serial")
95   parser.add_option("--solver-options",
96                     help="Solver options for the extension form problem.",
97                     action="append",
98                     dest="solver_options",
99                     type="string",
100                     default=[])
101   parser.add_option("--mipgap",
102                     help="Specifies the mipgap for the EF solve.",
103                     action="store",
104                     dest="mipgap",
105                     type="float",
106                     default=None)   
107   parser.add_option("--output-solver-log",
108                     help="Output solver log during the extensive form solve.",
109                     action="store_true",
110                     dest="output_solver_log",
111                     default=False)
112   parser.add_option("--keep-solver-files",
113                     help="Retain temporary input and output files for solve.",
114                     action="store_true",
115                     dest="keep_solver_files",
116                     default=False)   
117   parser.add_option("--profile",
118                     help="Enable profiling of Python code.  The value of this option is the number of functions that are summarized.",
119                     action="store",
120                     dest="profile",
121                     default=0)
122   parser.add_option("--disable-gc",
123                     help="Disable the python garbage collecter. Default is False.",
124                     action="store_true",
125                     dest="disable_gc",
126                     default=False)
127   parser.usage=usage_string
128
129   return parser
130   
131def run_ef_writer(options, args):
132
133   # if the user enabled the addition of the weighted cvar term to the objective,
134   # then validate the associated parameters.
135   generate_weighted_cvar = False
136   cvar_weight = None
137   risk_alpha = None
138
139   if options.generate_weighted_cvar is True:
140
141      generate_weighted_cvar = True
142      cvar_weight = options.cvar_weight
143      risk_alpha = options.risk_alpha
144
145   scenario_tree, binding_instance, scenario_instances = write_ef_from_scratch(os.path.expanduser(options.model_directory),
146                                                                               os.path.expanduser(options.instance_directory),
147                                                                               os.path.expanduser(options.output_file),
148                                                                               options.verbose,
149                                                                               generate_weighted_cvar, cvar_weight, risk_alpha)
150
151   if (scenario_tree is None) or (binding_instance is None) or (scenario_instances is None):
152      raise RuntimeError, "Failed to write extensive form."     
153
154   if options.solve_ef is True:
155
156      ef_solver = SolverFactory(options.solver_type)
157      if ef_solver is None:
158         raise ValueError, "Failed to create solver of type="+options.solver_type+" for use in extensive form solve"
159      if len(options.solver_options) > 0:
160         print "Initializing ef solver with options="+str(options.solver_options)         
161         ef_solver.set_options("".join(options.solver_options))
162      if options.mipgap is not None:
163         if (options.mipgap < 0.0) or (options.mipgap > 1.0):
164            raise ValueError, "Value of the mipgap parameter for the EF solve must be on the unit interval; value specified=" + `options.mipgap`
165         else:
166            ef_solver.mipgap = options.mipgap
167      if options.keep_solver_files is True:
168         ef_solver.keepFiles = True         
169
170      ef_solver_manager = SolverManagerFactory(options.solver_manager_type)
171      if ef_solver is None:
172         raise ValueError, "Failed to create solver manager of type="+options.solver_type+" for use in extensive form solve"
173
174      # at this point you have a specific solver - communicate solver capabilities
175      # to the writer via the instance.
176      binding_instance.has_capability = ef_solver.has_capability
177      for scenario_name, scenario_instance in scenario_instances.items():
178         scenario_instance.has_capability = ef_solver.has_capability
179
180      print "Queuing extensive form solve"
181      ef_action_handle = ef_solver_manager.queue(os.path.expanduser(options.output_file), opt=ef_solver, warmstart=False, tee=options.output_solver_log)
182      print "Waiting for extensive form solve"
183      ef_results = ef_solver_manager.wait_for(ef_action_handle)
184      load_ef_solution(ef_results, binding_instance, scenario_instances)
185      scenario_tree.snapshotSolutionFromInstances(scenario_instances)
186      print ""
187      print "Extensive form solution:"
188      scenario_tree.pprintSolution()
189      print ""
190      print "Extensive form costs:"
191      scenario_tree.pprintCosts(scenario_instances)
192
193def run(args=None):
194
195    #
196    # Top-level command that executes the extensive form writer.
197    # This is segregated from run_ef_writer to enable profiling.
198    #
199
200    #
201    # Parse command-line options.
202    #
203    try:
204       options_parser = construct_ef_writer_options_parser("runef [options]")
205       (options, args) = options_parser.parse_args(args=args)
206    except SystemExit:
207       # the parser throws a system exit if "-h" is specified - catch
208       # it to exit gracefully.
209       return
210
211    if options.disable_gc is True:
212       gc.disable()
213    else:
214       gc.enable()
215
216    if options.profile > 0:
217        #
218        # Call the main ef writer with profiling.
219        #
220        tfile = pyutilib.services.TempfileManager.create_tempfile(suffix=".profile")
221        tmp = profile.runctx('run_ef_writer(options,args)',globals(),locals(),tfile)
222        p = pstats.Stats(tfile).strip_dirs()
223        p.sort_stats('time', 'cum')
224        options.profile = eval(options.profile)
225        p = p.print_stats(options.profile)
226        p.print_callers(options.profile)
227        p.print_callees(options.profile)
228        p = p.sort_stats('cum','calls')
229        p.print_stats(options.profile)
230        p.print_callers(options.profile)
231        p.print_callees(options.profile)
232        p = p.sort_stats('calls')
233        p.print_stats(options.profile)
234        p.print_callers(options.profile)
235        p.print_callees(options.profile)
236        pyutilib.services.TempfileManager.clear_tempfiles()
237        ans = [tmp, None]
238    else:
239        #
240        # Call the main EF writer without profiling.
241        #
242        ans = run_ef_writer(options, args)
243
244    gc.enable()
245   
246    return ans
247
Note: See TracBrowser for help on using the repository browser.