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

Last change on this file since 3101 was 3101, checked in by khunter, 10 years ago

Reorganization of the runef command line options into logical
groups. Also alphabetized the options within the groups.

  • Property svn:executable set to *
File size: 11.5 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, OptionGroup
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
31from pyutilib.component.core import ExtensionPoint
32from coopr.pysp.solutionwriter import ISolutionWriterExtension
33
34#
35# utility method to construct an option parser for ef writer arguments
36#
37
38def construct_ef_writer_options_parser(usage_string):
39
40   parser = OptionParser()
41   parser.usage=usage_string
42
43   inputOpts  = OptionGroup( parser, 'Input Options' )
44   efOpts     = OptionGroup( parser, 'EF Options' )
45   solverOpts = OptionGroup( parser, 'Solver Options' )
46   outputOpts = OptionGroup( parser, 'Output Options' )
47   otherOpts  = OptionGroup( parser, 'Other Options' )
48   parser.add_option_group( inputOpts )
49   parser.add_option_group( efOpts )
50   parser.add_option_group( solverOpts )
51   parser.add_option_group( outputOpts )
52   parser.add_option_group( otherOpts )
53
54   inputOpts.add_option('--instance-directory',
55     help='The directory in which all instance (reference and scenario) definitions are stored. Default is ".".',
56     action='store',
57     dest='instance_directory',
58     type='string',
59     default='.')
60   inputOpts.add_option('--model-directory',
61     help='The directory in which all model (reference and scenario) definitions are stored. Default is ".".',
62     action='store',
63     dest='model_directory',
64     type='string',
65     default='.')
66
67   efOpts.add_option('--cvar-weight',
68     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.',
69     action='store',
70     dest='cvar_weight',
71     type='float',
72     default=1.0)
73   efOpts.add_option('--generate-weighted-cvar',
74     help='Add a weighted CVaR term to the primary objective',
75     action='store_true',
76     dest='generate_weighted_cvar',
77     default=False)
78   efOpts.add_option('--risk-alpha',
79     help='The probability threshold associated with cvar (or any future) risk-oriented performance metrics. Default is 0.95.',
80     action='store',
81     dest='risk_alpha',
82     type='float',
83     default=0.95)
84
85   solverOpts.add_option('--mipgap',
86     help='Specifies the mipgap for the EF solve.',
87     action='store',
88     dest='mipgap',
89     type='float',
90     default=None)
91   solverOpts.add_option('--solve',
92     help='Following write of the extensive form model, solve it.',
93     action='store_true',
94     dest='solve_ef',
95     default=False)
96   solverOpts.add_option('--solver',
97     help='The type of solver used to solve scenario sub-problems. Default is cplex.',
98     action='store',
99     dest='solver_type',
100     type='string',
101     default='cplex')
102   solverOpts.add_option('--solver-manager',
103     help='The type of solver manager used to coordinate scenario sub-problem solves. Default is serial.',
104     action='store',
105     dest='solver_manager_type',
106     type='string',
107     default='serial')
108   solverOpts.add_option('--solver-options',
109     help='Solver options for the extension form problem.',
110     action='append',
111     dest='solver_options',
112     type='string',
113     default=[])
114
115   outputOpts.add_option('--output-file',
116     help='Specify the name of the extensive form output file',
117     action='store',
118     dest='output_file',
119     type='string',
120     default='efout.lp')
121   outputOpts.add_option('--output-solver-log',
122     help='Output solver log during the extensive form solve.',
123     action='store_true',
124     dest='output_solver_log',
125     default=False)
126   outputOpts.add_option('--solution-writer',
127     help='The plugin invoked to write the scenario tree solution. Defaults to the empty list.',
128     action='append',
129     dest='solution_writer',
130     type='string',
131     default = [])
132   outputOpts.add_option('--verbose',
133     help='Generate verbose output, beyond the usual status output. Default is False.',
134     action='store_true',
135     dest='verbose',
136     default=False)
137
138   otherOpts.add_option('--disable-gc',
139     help='Disable the python garbage collecter. Default is False.',
140     action='store_true',
141     dest='disable_gc',
142     default=False)
143   otherOpts.add_option('--keep-solver-files',
144     help='Retain temporary input and output files for solve.',
145     action='store_true',
146     dest='keep_solver_files',
147     default=False)
148   otherOpts.add_option('--profile',
149     help='Enable profiling of Python code.  The value of this option is the number of functions that are summarized.',
150     action='store',
151     dest='profile',
152     default=0)
153   otherOpts.add_option('--traceback',
154     help='When an exception is thrown, show the entire call stack. Ignored if profiling is enabled. Default is False.',
155     action='store_true',
156     dest='traceback',
157     default=False)
158
159   return parser
160
161
162def run_ef_writer(options, args):
163
164   # if the user enabled the addition of the weighted cvar term to the objective,
165   # then validate the associated parameters.
166   generate_weighted_cvar = False
167   cvar_weight = None
168   risk_alpha = None
169
170   if options.generate_weighted_cvar is True:
171
172      generate_weighted_cvar = True
173      cvar_weight = options.cvar_weight
174      risk_alpha = options.risk_alpha
175
176   # validate the solution writer plugin exists, to avoid a lot of wasted work.
177   for solution_writer_name in options.solution_writer:
178      print "Trying to import solution writer="+solution_writer_name
179      __import__(solution_writer_name)
180      print "Module successfully loaded"
181
182   scenario_tree, binding_instance, scenario_instances = write_ef_from_scratch(os.path.expanduser(options.model_directory),
183                                                                               os.path.expanduser(options.instance_directory),
184                                                                               os.path.expanduser(options.output_file),
185                                                                               options.verbose,
186                                                                               generate_weighted_cvar, cvar_weight, risk_alpha)
187
188   if (scenario_tree is None) or (binding_instance is None) or (scenario_instances is None):
189      raise RuntimeError, "Failed to write extensive form."
190
191   if options.solve_ef is True:
192
193      ef_solver = SolverFactory(options.solver_type)
194      if ef_solver is None:
195         raise ValueError, "Failed to create solver of type="+options.solver_type+" for use in extensive form solve"
196      if len(options.solver_options) > 0:
197         print "Initializing ef solver with options="+str(options.solver_options)
198         ef_solver.set_options("".join(options.solver_options))
199      if options.mipgap is not None:
200         if (options.mipgap < 0.0) or (options.mipgap > 1.0):
201            raise ValueError, "Value of the mipgap parameter for the EF solve must be on the unit interval; value specified=" + `options.mipgap`
202         else:
203            ef_solver.mipgap = options.mipgap
204      if options.keep_solver_files is True:
205         ef_solver.keepFiles = True
206
207      ef_solver_manager = SolverManagerFactory(options.solver_manager_type)
208      if ef_solver is None:
209         raise ValueError, "Failed to create solver manager of type="+options.solver_type+" for use in extensive form solve"
210
211      # at this point you have a specific solver - communicate solver capabilities
212      # to the writer via the instance.
213      binding_instance.has_capability = ef_solver.has_capability
214      for scenario_name, scenario_instance in scenario_instances.items():
215         scenario_instance.has_capability = ef_solver.has_capability
216
217      print "Queuing extensive form solve"
218      ef_action_handle = ef_solver_manager.queue(os.path.expanduser(options.output_file), opt=ef_solver, tee=options.output_solver_log)
219      print "Waiting for extensive form solve"
220      ef_results = ef_solver_manager.wait_for(ef_action_handle)
221      load_ef_solution(ef_results, binding_instance, scenario_instances)
222      scenario_tree.snapshotSolutionFromInstances(scenario_instances)
223
224      # handle output of solution from the scenario tree.
225      print ""
226      print "Extensive form solution:"
227      scenario_tree.pprintSolution()
228      print ""
229      print "Extensive form costs:"
230      scenario_tree.pprintCosts(scenario_instances)
231
232      solution_writer_plugins = ExtensionPoint(ISolutionWriterExtension)
233      for plugin in solution_writer_plugins:
234         plugin.write(scenario_tree, "ef")
235
236def run(args=None):
237
238    #
239    # Top-level command that executes the extensive form writer.
240    # This is segregated from run_ef_writer to enable profiling.
241    #
242
243    #
244    # Parse command-line options.
245    #
246    try:
247       options_parser = construct_ef_writer_options_parser("runef [options]")
248       (options, args) = options_parser.parse_args(args=args)
249    except SystemExit:
250       # the parser throws a system exit if "-h" is specified - catch
251       # it to exit gracefully.
252       return
253
254    if options.disable_gc is True:
255       gc.disable()
256    else:
257       gc.enable()
258
259    if options.profile > 0:
260        #
261        # Call the main ef writer with profiling.
262        #
263        tfile = pyutilib.services.TempfileManager.create_tempfile(suffix=".profile")
264        tmp = profile.runctx('run_ef_writer(options,args)',globals(),locals(),tfile)
265        p = pstats.Stats(tfile).strip_dirs()
266        p.sort_stats('time', 'cum')
267        options.profile = eval(options.profile)
268        p = p.print_stats(options.profile)
269        p.print_callers(options.profile)
270        p.print_callees(options.profile)
271        p = p.sort_stats('cum','calls')
272        p.print_stats(options.profile)
273        p.print_callers(options.profile)
274        p.print_callees(options.profile)
275        p = p.sort_stats('calls')
276        p.print_stats(options.profile)
277        p.print_callers(options.profile)
278        p.print_callees(options.profile)
279        pyutilib.services.TempfileManager.clear_tempfiles()
280        ans = [tmp, None]
281    else:
282        #
283        # Call the main EF writer without profiling.
284        #
285        if options.traceback is True:
286           ans = run_ef_writer(options, args)
287        else:
288           try:
289              ans = run_ef_writer(options, args)
290           except ValueError, str:
291              print "VALUE ERROR:"
292              print str
293           except TypeError, str:
294              print "TYPE ERROR:"
295              print str
296           except NameError, str:
297              print "NAME ERROR:"
298              print str
299           except IOError, str:
300              print "IO ERROR:"
301              print str
302           except pyutilib.common.ApplicationError, str:
303              print "APPLICATION ERROR:"
304              print str
305           except RuntimeError, str:
306              print "RUN-TIME ERROR:"
307              print str
308           except:
309              print "Encountered unhandled exception"
310              traceback.print_exc()
311           sys.exit(0)
312
313    gc.enable()
314
315    return ans
316
Note: See TracBrowser for help on using the repository browser.