def _presolve(self, *args, **kwds): """ Peform presolves. """ TempfileManager.push() self._keepfiles = kwds.pop("keepfiles", False) self._define_signal_handlers = kwds.pop('use_signal_handling',None) OptSolver._presolve(self, *args, **kwds) # # Verify that the input problems exists # for filename in self._problem_files: if not os.path.exists(filename): msg = 'Solver failed to locate input problem file: %s' raise ValueError(msg % filename) # # Create command line # self._command = self.create_command_line( self.executable(), self._problem_files) self._log_file=self._command.log_file # # The pre-cleanup is probably unncessary, but also not harmful. # if (self._log_file is not None) and \ os.path.exists(self._log_file): os.remove(self._log_file) if (self._soln_file is not None) and \ os.path.exists(self._soln_file): os.remove(self._soln_file)
def tearDown(self): if os.path.exists("unknown.lp"): os.unlink("unknown.lp") TempfileManager.clear_tempfiles() if os.path.exists(os.path.join(currdir, 'result.yml')): os.remove(os.path.join(currdir, 'result.yml')) self.model = None
def _postsolve(self): # take care of the annoying (and empty) CPLEX temporary files in the current directory. # this approach doesn't seem overly efficient, but python os module functions don't # accept regular expression directly. filename_list = os.listdir(".") for filename in filename_list: # CPLEX temporary files come in two flavors - cplex.log and clone*.log. # the latter is the case for multi-processor environments. # IMPT: trap the possible exception raised by the file not existing. # this can occur in pyro environments where > 1 workers are # running CPLEX, and were started from the same directory. # these logs don't matter anyway (we redirect everything), # and are largely an annoyance. try: if re.match('cplex\.log', filename) != None: os.remove(filename) elif re.match('clone\d+\.log', filename) != None: os.remove(filename) except OSError: pass # let the base class deal with returning results. results = ILMLicensedSystemCallSolver._postsolve(self) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. does not # include, for example, the execution script. but does include # the warm-start file. TempfileManager.pop(remove=not self._keepfiles) return results
def _presolve(self, *args, **kwds): """ Peform presolves. """ TempfileManager.push() self._keepfiles = kwds.pop("keepfiles", False) OptSolver._presolve(self, *args, **kwds) # # Verify that the input problems exists # for filename in self._problem_files: if not os.path.exists(filename): msg = 'Solver failed to locate input problem file: %s' raise ValueError(msg % filename) # # Create command line # self._command = self.create_command_line( self.executable(), self._problem_files) self._log_file=self._command.log_file # # The pre-cleanup is probably unncessary, but also not harmful. # if (self._log_file is not None) and \ os.path.exists(self._log_file): os.remove(self._log_file) if (self._soln_file is not None) and \ os.path.exists(self._soln_file): os.remove(self._soln_file)
def _presolve(self, *args, **kwds): # create a context in the temporary file manager for # this plugin - is "pop"ed in the _postsolve method. TempfileManager.push() # if the first argument is a string (representing a filename), # then we don't have an instance => the solver is being applied # to a file. self._warm_start_solve = kwds.pop('warmstart', False) self._warm_start_file_name = kwds.pop('warmstart_file', None) user_warmstart = False if self._warm_start_file_name is not None: user_warmstart = True # the input argument can currently be one of two things: an instance or a filename. # if a filename is provided and a warm-start is indicated, we go ahead and # create the temporary file - assuming that the user has already, via some external # mechanism, invoked warm_start() with a instance to create the warm start file. if self._warm_start_solve and \ isinstance(args[0], string_types): # we assume the user knows what they are doing... pass elif self._warm_start_solve and \ (not isinstance(args[0], string_types)): # assign the name of the warm start file *before* calling the base class # presolve - the base class method ends up creating the command line, # and the warm start file-name is (obviously) needed there. if self._warm_start_file_name is None: assert not user_warmstart self._warm_start_file_name = TempfileManager.\ create_tempfile(suffix = '.cbc.soln') # let the base class handle any remaining keywords/actions. # let the base class handle any remaining keywords/actions. super(CBCSHELL, self)._presolve(*args, **kwds) # NB: we must let the base class presolve run first so that the # symbol_map is actually constructed! if (len(args) > 0) and (not isinstance(args[0], string_types)): if len(args) != 1: raise ValueError( "CBCplugin _presolve method can only handle a single " "problem instance - %s were supplied" % (len(args), )) # write the warm-start file - currently only supports MIPs. # we only know how to deal with a single problem instance. if self._warm_start_solve and (not user_warmstart): start_time = time.time() self._warm_start(args[0]) end_time = time.time() if self._report_timing is True: print("Warm start write time=%.2f seconds" % (end_time - start_time))
def run(args=None): # # Parse command-line options. # try: options_parser = \ construct_options_parser("scenariotreeserver [options] hostname") (options, arguments) = options_parser.parse_args(args=args) if arguments: assert len(arguments) == 1 options.host = arguments[0] else: options.host = None except SystemExit as _exc: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return _exc.code # for a one-pass execution, garbage collection doesn't make # much sense - so it is disabled by default. Because: It drops # the run-time by a factor of 3-4 on bigger instances. if options.disable_gc: gc.disable() else: gc.enable() if pstats_available and options.profile > 0: # # Call the main PH routine with profiling. # tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('run_server(options)',globals(),locals(),tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('cumulative','calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) TempfileManager.clear_tempfiles() ans = [tmp, None] else: # # Call the main routine without profiling. # ans = run_server(options) gc.enable() return ans
def run(args=None): # # Parse command-line options. # try: options_parser = \ construct_options_parser("scenariotreeserver [options] hostname") (options, arguments) = options_parser.parse_args(args=args) if arguments: assert len(arguments) == 1 options.host = arguments[0] else: options.host = None except SystemExit as _exc: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return _exc.code # for a one-pass execution, garbage collection doesn't make # much sense - so it is disabled by default. Because: It drops # the run-time by a factor of 3-4 on bigger instances. if options.disable_gc: gc.disable() else: gc.enable() if pstats_available and options.profile > 0: # # Call the main PH routine with profiling. # tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('run_server(options)', globals(), locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('cumulative', 'calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) TempfileManager.clear_tempfiles() ans = [tmp, None] else: # # Call the main routine without profiling. # ans = run_server(options) gc.enable() return ans
def solve(self, model, timer: HierarchicalTimer = None): self.available(exception_flag=True) if timer is None: timer = HierarchicalTimer() try: TempfileManager.push() if self.config.filename is None: self._filename = TempfileManager.create_tempfile() else: self._filename = self.config.filename TempfileManager.add_tempfile(self._filename + '.lp', exists=False) TempfileManager.add_tempfile(self._filename + '.log', exists=False) timer.start('write lp file') self._writer.write(model, self._filename + '.lp', timer=timer) timer.stop('write lp file') res = self._apply_solver(timer) if self.config.report_timing: logger.info('\n' + str(timer)) return res finally: # finally, clean any temporary files registered with the # temp file manager, created/populated *directly* by this # plugin. TempfileManager.pop(remove=not self.config.keepfiles) if not self.config.keepfiles: self._filename = None
def do_setup(self, flag): global tmpdir tmpdir = os.getcwd() os.chdir(currdir) TempfileManager.sequential_files(0) if flag: if not cplexamp_available: self.skipTest("The 'cplexamp' command is not available") self.asl = SolverFactory('asl:cplexamp') else: self.asl = SolverFactory('_mock_asl:cplexamp')
def _postsolve(self): # let the base class deal with returning results. results = super(CBCSHELL, self)._postsolve() # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. does not # include, for example, the execution script. but does include # the warm-start file. TempfileManager.pop(remove=not self._keepfiles) return results
def do_setup(self): global tmpdir tmpdir = os.getcwd() os.chdir(currdir) TempfileManager.sequential_files(0) self.scip = SolverFactory('scip', solver_io='nl') m = self.model = ConcreteModel() m.v = Var() m.o = Objective(expr=m.v) m.c = Constraint(expr=m.v >= 1)
def create_command_line(self, executable, problem_files): # # Define log file # if self._log_file is None: self._log_file = TempfileManager.create_tempfile( suffix='.glpk.log') # # Define solution file # self._glpfile = TempfileManager.create_tempfile(suffix='.glpk.glp') self._rawfile = TempfileManager.create_tempfile(suffix='.glpk.raw') self._soln_file = self._rawfile # # Define command line # cmd = [executable] if self._timer: cmd.insert(0, self._timer) for key in self.options: opt = self.options[key] if opt is None or (isinstance(opt, string_types) and opt.strip() == ''): # Handle the case for options that must be # specified without a value cmd.append("--%s" % key) else: cmd.extend(["--%s" % key, str(opt)]) #if isinstance(opt, basestring) and ' ' in opt: # cmd.append('--%s "%s"' % (key, str(opt))) #else: # cmd.append('--%s %s' % (key, str(opt))) if self._timelimit is not None and self._timelimit > 0.0: cmd.extend(['--tmlim', str(self._timelimit)]) cmd.extend(['--write', self._rawfile]) cmd.extend(['--wglp', self._glpfile]) if self._problem_format == ProblemFormat.cpxlp: cmd.extend(['--cpxlp', problem_files[0]]) elif self._problem_format == ProblemFormat.mps: cmd.extend(['--freemps', problem_files[0]]) elif self._problem_format == ProblemFormat.mod: cmd.extend(['--math', problem_files[0]]) for fname in problem_files[1:]: cmd.extend(['--data', fname]) return Bunch(cmd=cmd, log_file=self._log_file, env=None)
def create_command_line(self, executable, problem_files): # # Define log file # if self._log_file is None: self._log_file = TempfileManager.create_tempfile(suffix='.glpk.log') # # Define solution file # self._glpfile = TempfileManager.create_tempfile(suffix='.glpk.glp') self._rawfile = TempfileManager.create_tempfile(suffix='.glpk.raw') self._soln_file = self._rawfile # # Define command line # cmd = [executable] if self._timer: cmd.insert(0, self._timer) for key in self.options: opt = self.options[key] if opt is None or (isinstance(opt, string_types) and opt.strip() == ''): # Handle the case for options that must be # specified without a value cmd.append("--%s" % key) else: cmd.extend(["--%s" % key, str(opt)]) #if isinstance(opt, basestring) and ' ' in opt: # cmd.append('--%s "%s"' % (key, str(opt))) #else: # cmd.append('--%s %s' % (key, str(opt))) if self._timelimit is not None and self._timelimit > 0.0: cmd.extend(['--tmlim', str(self._timelimit)]) cmd.extend(['--write', self._rawfile]) cmd.extend(['--wglp', self._glpfile]) if self._problem_format == ProblemFormat.cpxlp: cmd.extend(['--cpxlp', problem_files[0]]) elif self._problem_format == ProblemFormat.mps: cmd.extend(['--freemps', problem_files[0]]) elif self._problem_format == ProblemFormat.mod: cmd.extend(['--math', problem_files[0]]) for fname in problem_files[1:]: cmd.extend(['--data', fname]) return Bunch(cmd=cmd, log_file=self._log_file, env=None)
def generate_scenario_tree_image(options): with ScenarioTreeInstanceFactory(options.model_location, options.scenario_tree_location) as factory: scenario_tree = factory.generate_scenario_tree( downsample_fraction=options.scenario_tree_downsample_fraction, bundles=options.scenario_bundle_specification, random_bundles=options.create_random_bundles, random_seed=options.scenario_tree_random_seed, verbose=options.verbose, ) with TempfileManager.push(): tmpdotfile = TempfileManager.create_tempfile(suffix=".dot") scenario_tree.save_to_dot(tmpdotfile) os.system("dot -Tpdf -o %s %s" % (options.output_file, tmpdotfile)) print("Output Saved To: %s" % (options.output_file))
def generate_scenario_tree_image(options): with ScenarioTreeInstanceFactory( options.model_location, options.scenario_tree_location) as factory: scenario_tree = factory.generate_scenario_tree( downsample_fraction=options.scenario_tree_downsample_fraction, bundles=options.scenario_bundle_specification, random_bundles=options.create_random_bundles, random_seed=options.scenario_tree_random_seed, verbose=options.verbose) with TempfileManager.push(): tmpdotfile = TempfileManager.create_tempfile(suffix=".dot") scenario_tree.save_to_dot(tmpdotfile) os.system('dot -Tpdf -o %s %s' % (options.output_file, tmpdotfile)) print("Output Saved To: %s" % (options.output_file))
def _postsolve(self): if self._log_file is not None: OUTPUT = open(self._log_file, "w") OUTPUT.write("Solver command line: " + str(self._command.cmd) + '\n') OUTPUT.write("\n") OUTPUT.write(self._log + '\n') OUTPUT.close() # JPW: The cleanup of the problem file probably shouldn't be here, but # rather in the base OptSolver class. That would require movement of # the keepfiles attribute and associated cleanup logic to the base # class, which I didn't feel like doing at this present time. the # base class remove_files method should clean up the problem file. if (self._log_file is not None) and \ (not os.path.exists(self._log_file)): msg = "File '%s' not generated while executing %s" raise IOError(msg % (self._log_file, self.path)) results = None if self._results_format is not None: results = self.process_output(self._rc) # # If keepfiles is true, then we pop the # TempfileManager context while telling it to # _not_ remove the files. # if not self._keepfiles: # in some cases, the solution filename is # not generated via the temp-file mechanism, # instead being automatically derived from # the input lp/nl filename. so, we may have # to clean it up manually. if (not self._soln_file is None) and \ os.path.exists(self._soln_file): os.remove(self._soln_file) TempfileManager.pop(remove=not self._keepfiles) return results
def _postsolve(self): if self._log_file is not None: OUTPUT=open(self._log_file,"w") OUTPUT.write("Solver command line: "+str(self._command.cmd)+'\n') OUTPUT.write("\n") OUTPUT.write(self._log+'\n') OUTPUT.close() # JPW: The cleanup of the problem file probably shouldn't be here, but # rather in the base OptSolver class. That would require movement of # the keepfiles attribute and associated cleanup logic to the base # class, which I didn't feel like doing at this present time. the # base class remove_files method should clean up the problem file. if (self._log_file is not None) and \ (not os.path.exists(self._log_file)): msg = "File '%s' not generated while executing %s" raise IOError(msg % (self._log_file, self.path)) results = None if self._results_format is not None: results = self.process_output(self._rc) # # If keepfiles is true, then we pop the # TempfileManager context while telling it to # _not_ remove the files. # if not self._keepfiles: # in some cases, the solution filename is # not generated via the temp-file mechanism, # instead being automatically derived from # the input lp/nl filename. so, we may have # to clean it up manually. if (not self._soln_file is None) and \ os.path.exists(self._soln_file): os.remove(self._soln_file) TempfileManager.pop(remove=not self._keepfiles) return results
def run_command(command=None, parser=None, args=None, name='unknown', data=None, options=None): """ Execute a function that processes command-line arguments and then calls a command-line driver. This function provides a generic facility for executing a command function is rather generic. This function is segregated from the driver to enable profiling of the command-line execution. Required: command: The name of a function that will be executed to perform process the command-line options with a parser object. parser: The parser object that is used by the command-line function. Optional: options: If this is not None, then ignore the args option and use this to specify command options. args: Command-line arguments that are parsed. If this value is `None`, then the arguments in `sys.argv` are used to parse the command-line. name: Specifying the name of the command-line (for error messages). data: A container of labeled data. Returned: retval: Return values from the command-line execution. errorcode: 0 if Pyomo ran successfully """ # # # Parse command-line options # # retval = None errorcode = 0 if options is None: try: if type(args) is argparse.Namespace: _options = args else: _options = parser.parse_args(args=args) # Replace the parser options object with a pyutilib.misc.Options object options = pyutilib.misc.Options() for key in dir(_options): if key[0] != '_': val = getattr(_options, key) if not isinstance(val, types.MethodType): options[key] = val except SystemExit: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return Container(retval=retval, errorcode=errorcode) # # Configure loggers # configure_loggers(options=options) # # Setup I/O redirect to a file # logfile = options.runtime.logfile if not logfile is None: pyutilib.misc.setup_redirect(logfile) # # Call the main Pyomo runner with profiling # TempfileManager.push() pcount = options.runtime.profile_count if pcount > 0: if not pstats_available: if not logfile is None: pyutilib.misc.reset_redirect() msg = "Cannot use the 'profile' option. The Python 'pstats' " \ 'package cannot be imported!' raise ValueError(msg) tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx( command.__name__ + '(options=options,parser=parser)', command.__globals__, locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) p = p.sort_stats('cumulative', 'calls') p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) p = p.sort_stats('calls') p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) retval = tmp else: # # Call the main Pyomo runner without profiling # TempfileManager.push() try: retval = command(options=options, parser=parser) except SystemExit: err = sys.exc_info()[1] # # If debugging is enabled or the 'catch' option is specified, then # exit. Otherwise, print an "Exiting..." message. # if __debug__ and (options.runtime.logging == 'debug' or options.runtime.catch_errors): sys.exit(0) print('Exiting %s: %s' % (name, str(err))) errorcode = err.code except Exception: err = sys.exc_info()[1] # # If debugging is enabled or the 'catch' option is specified, then # pass the exception up the chain (to pyomo_excepthook) # if __debug__ and (options.runtime.logging == 'debug' or options.runtime.catch_errors): if not logfile is None: pyutilib.misc.reset_redirect() TempfileManager.pop(remove=not options.runtime.keep_files) raise if not options.model is None and not options.model.save_file is None: model = "model " + options.model.save_file else: model = "model" global filter_excepthook if filter_excepthook: action = "loading" else: action = "running" msg = "Unexpected exception while %s %s:\n" % (action, model) # # This handles the case where the error is propagated by a KeyError. # KeyError likes to pass raw strings that don't handle newlines # (they translate "\n" to "\\n"), as well as tacking on single # quotes at either end of the error message. This undoes all that. # errStr = str(err) if type(err) == KeyError and errStr != "None": errStr = str(err).replace(r"\n", "\n")[1:-1] logging.getLogger('pyomo.core').error(msg + errStr) errorcode = 1 if not logfile is None: pyutilib.misc.reset_redirect() if options.runtime.disable_gc: gc.enable() TempfileManager.pop(remove=not options.runtime.keep_files) return Container(retval=retval, errorcode=errorcode)
def create_command_line(self, executable, problem_files): # # Define log file # The log file in CPLEX contains the solution trace, but the solver status can be found in the solution file. # if self._log_file is None: self._log_file = TempfileManager.\ create_tempfile(suffix = '.gurobi.log') # # Define solution file # As indicated above, contains (in XML) both the solution and solver status. # if self._soln_file is None: self._soln_file = TempfileManager.\ create_tempfile(suffix = '.gurobi.txt') # # Write the GUROBI execution script # problem_filename = self._problem_files[0] solution_filename = self._soln_file warmstart_filename = self._warm_start_file_name # translate the options into a normal python dictionary, from a # pyutilib SectionWrapper - the # gurobi_run function doesn't know about pyomo, so the translation # is necessary. options_dict = {} for key in self.options: options_dict[key] = self.options[key] # NOTE: the gurobi shell is independent of Pyomo python virtualized environment, so any # imports - specifically that required to get GUROBI_RUN - must be handled explicitly. # NOTE: The gurobi plugin (GUROBI.py) and GUROBI_RUN.py live in the same directory. script = "import sys\n" script += "from gurobipy import *\n" script += "sys.path.append(%r)\n" % os.path.dirname(__file__) script += "from GUROBI_RUN import *\n" script += "gurobi_run(" mipgap = float(self.options.mipgap) if \ self.options.mipgap is not None else \ None for x in (problem_filename, warmstart_filename, solution_filename, None, options_dict, self._suffixes): script += "%r," % x script += ")\n" script += "quit()\n" # dump the script and warm-start file names for the # user if we're keeping files around. if self._keepfiles: script_fname = TempfileManager.create_tempfile( suffix='.gurobi.script') script_file = open(script_fname, 'w') script_file.write(script) script_file.close() print("Solver script file: '%s'" % script_fname) if self._warm_start_solve and \ (self._warm_start_file_name is not None): print("Solver warm-start file: " + self._warm_start_file_name) # # Define command line # cmd = [executable] if self._timer: cmd.insert(0, self._timer) return Bunch(cmd=cmd, script=script, log_file=self._log_file, env=None)
def tearDownModule(): TempfileManager.clear_tempfiles() TempfileManager.tempdir = None TempfileManager.unique_files()
def launch_command(command, options, cmd_args=None, cmd_kwds=None, error_label="", disable_gc=False, profile_count=0, log_level=logging.INFO, traceback=False): # This is not the effective level, but the # level on the current logger. We want to # return the logger to its original state # before this function exits prev_log_level = logger.level logger.setLevel(log_level) if cmd_args is None: cmd_args = () if cmd_kwds is None: cmd_kwds = {} # # Control the garbage collector - more critical than I would like # at the moment. # with PauseGC(disable_gc) as pgc: # # Run command - precise invocation depends on whether we want # profiling output, traceback, etc. # rc = 0 if pstats_available and (profile_count > 0): # # Call the main routine with profiling. # try: tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('command(options, *cmd_args, **cmd_kwds)', globals(), locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('cumulative','calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) TempfileManager.clear_tempfiles() rc = tmp finally: logger.setLevel(prev_log_level) else: # # Call the main PH routine without profiling. # if traceback: try: rc = command(options, *cmd_args, **cmd_kwds) finally: logger.setLevel(prev_log_level) else: try: try: rc = command(options, *cmd_args, **cmd_kwds) except ValueError: sys.stderr.write(error_label+"VALUE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except KeyError: sys.stderr.write(error_label+"KEY ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except TypeError: sys.stderr.write(error_label+"TYPE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except NameError: sys.stderr.write(error_label+"NAME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except IOError: sys.stderr.write(error_label+"IO ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except ConverterError: sys.stderr.write(error_label+"CONVERTER ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except pyutilib.common.ApplicationError: sys.stderr.write(error_label+"APPLICATION ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except RuntimeError: sys.stderr.write(error_label+"RUN-TIME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except: sys.stderr.write(error_label+ "Encountered unhandled exception:\n") if len(sys.exc_info()) > 1: sys.stderr.write(str(sys.exc_info()[1])+"\n") else: traceback.print_exc(file=sys.stderr) raise except: sys.stderr.write("\n") sys.stderr.write( "To obtain further information regarding the " "source of the exception, use the " "--traceback option\n") rc = 1 # # TODO: Once we incorporate options registration into # all of the PySP commands we will assume the # options object is always a PySPConfigBlock # if isinstance(options, PySPConfigBlock): options.check_usage(error=False) logger.setLevel(prev_log_level) return rc
def _solve_impl(self, sp, keep_solver_files=False, output_solver_log=False, symbolic_solver_labels=False): if len(sp.scenario_tree.stages) > 2: raise ValueError("SD solver does not handle more " "than 2 time-stages") if sp.objective_sense == maximize: raise ValueError("SD solver does not yet handle " "maximization problems") TempfileManager.push() try: # # Setup the SD working directory # working_directory = TempfileManager.create_tempdir() config_filename = os.path.join(working_directory, "config.sd") sdinput_directory = os.path.join(working_directory, "sdinput", "pysp_model") sdoutput_directory = os.path.join(working_directory, "sdoutput", "pysp_model") logfile = os.path.join(working_directory, "sd.log") os.makedirs(sdinput_directory) assert os.path.exists(sdinput_directory) assert not os.path.exists(sdoutput_directory) self._write_config(config_filename) if self.get_option('single_replication'): solution_filename = os.path.join( sdoutput_directory, "pysp_model.detailed_rep_soln.out") else: solution_filename = os.path.join( sdoutput_directory, "pysp_model.detailed_soln.out") # # Create the SD input files # io_options = {'symbolic_solver_labels': symbolic_solver_labels} symbol_map = None if isinstance(sp, ImplicitSP): symbol_map = pyomo.pysp.smps.smpsutils.\ convert_implicit( sdinput_directory, "pysp_model", sp, core_format='mps', io_options=io_options) else: pyomo.pysp.smps.smpsutils.\ convert_explicit( sdinput_directory, "pysp_model", sp, core_format='mps', io_options=io_options) # # Launch SD # if keep_solver_files: print("Solver working directory: '%s'" % (working_directory)) print("Solver log file: '%s'" % (logfile)) start = time.time() rc, log = pyutilib.subprocess.run(self.get_option("sd_executable"), cwd=working_directory, stdin="pysp_model", outfile=logfile, tee=output_solver_log) stop = time.time() assert os.path.exists(sdoutput_directory) # # Parse the SD solution # xhat, results = self._read_solution(solution_filename) results.solver_time = stop - start if symbol_map is not None: # load the first stage variable solution into # the reference model for symbol, varvalue in xhat.items(): symbol_map.bySymbol[symbol]().value = varvalue else: # TODO: this is a hack for the non-implicit SP case # so that this solver can still be run using # the explicit scenario intput representation results.xhat = xhat finally: # # cleanup # TempfileManager.pop(remove=not keep_solver_files) return results
def launch_command(command, options, cmd_args=None, cmd_kwds=None, error_label="", disable_gc=False, profile_count=0, log_level=logging.INFO, traceback=False): # This is not the effective level, but the # level on the current logger. We want to # return the logger to its original state # before this function exits prev_log_level = logger.level logger.setLevel(log_level) if cmd_args is None: cmd_args = () if cmd_kwds is None: cmd_kwds = {} # # Control the garbage collector - more critical than I would like # at the moment. # with PauseGC(disable_gc) as pgc: # # Run command - precise invocation depends on whether we want # profiling output, traceback, etc. # rc = 0 if pstats_available and (profile_count > 0): # # Call the main routine with profiling. # try: tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('command(options, *cmd_args, **cmd_kwds)', globals(), locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('cumulative', 'calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) TempfileManager.clear_tempfiles() rc = tmp finally: logger.setLevel(prev_log_level) else: # # Call the main PH routine without profiling. # if traceback: try: rc = command(options, *cmd_args, **cmd_kwds) finally: logger.setLevel(prev_log_level) else: try: try: rc = command(options, *cmd_args, **cmd_kwds) except ValueError: sys.stderr.write(error_label + "VALUE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except KeyError: sys.stderr.write(error_label + "KEY ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except TypeError: sys.stderr.write(error_label + "TYPE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except NameError: sys.stderr.write(error_label + "NAME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except IOError: sys.stderr.write(error_label + "IO ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except ConverterError: sys.stderr.write(error_label + "CONVERTER ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except pyutilib.common.ApplicationError: sys.stderr.write(error_label + "APPLICATION ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except RuntimeError: sys.stderr.write(error_label + "RUN-TIME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1]) + "\n") raise except: sys.stderr.write(error_label + "Encountered unhandled exception:\n") if len(sys.exc_info()) > 1: sys.stderr.write(str(sys.exc_info()[1]) + "\n") else: traceback.print_exc(file=sys.stderr) raise except: sys.stderr.write("\n") sys.stderr.write( "To obtain further information regarding the " "source of the exception, use the " "--traceback option\n") rc = 1 # # TODO: Once we incorporate options registration into # all of the PySP commands we will assume the # options object is always a PySPConfigBlock # if isinstance(options, PySPConfigBlock): options.check_usage(error=False) logger.setLevel(prev_log_level) return rc
def create_command_line(self, executable, problem_files): # # Define the log file # if self._log_file is None: self._log_file = TempfileManager.create_tempfile(suffix=".cbc.log") # # Define the solution file # # the prefix of the problem filename is required because CBC has a specific # and automatic convention for generating the output solution filename. # the extracted prefix is the same name as the input filename, e.g., minus # the ".lp" extension. problem_filename_prefix = problem_files[0] if '.' in problem_filename_prefix: tmp = problem_filename_prefix.split('.') if len(tmp) > 2: problem_filename_prefix = '.'.join(tmp[:-1]) else: problem_filename_prefix = tmp[0] if self._results_format is ResultsFormat.sol: self._soln_file = problem_filename_prefix + ".sol" else: self._soln_file = problem_filename_prefix + ".soln" # # Define the results file (if the sol external parser is used) # # results in CBC are split across the log file (solver statistics) and # the solution file (solutions!) if self._results_format is ResultsFormat.sol: self._results_file = self._soln_file def _check_and_escape_options(options): for key, val in iteritems(self.options): tmp_k = str(key) _bad = ' ' in tmp_k tmp_v = str(val) if ' ' in tmp_v: if '"' in tmp_v: if "'" in tmp_v: _bad = True else: tmp_v = "'" + tmp_v + "'" else: tmp_v = '"' + tmp_v + '"' if _bad: raise ValueError("Unable to properly escape solver option:" "\n\t%s=%s" % (key, val)) yield (tmp_k, tmp_v) # # Define command line # cmd = [executable] if self._timer: cmd.insert(0, self._timer) if self._problem_format == ProblemFormat.nl: cmd.append(problem_files[0]) cmd.append('-AMPL') if self._timelimit is not None and self._timelimit > 0.0: cmd.extend(['-sec', str(self._timelimit)]) cmd.extend(['-timeMode', "elapsed"]) if "debug" in self.options: cmd.extend(["-log", "5"]) for key, val in _check_and_escape_options(self.options): if key == 'solver': continue cmd.append(key + "=" + val) os.environ['cbc_options'] = "printingOptions=all" #cmd.extend(["-printingOptions=all", #"-stat"]) else: if self._timelimit is not None and self._timelimit > 0.0: cmd.extend(['-sec', str(self._timelimit)]) cmd.extend(['-timeMode', "elapsed"]) if "debug" in self.options: cmd.extend(["-log", "5"]) # these must go after options that take a value action_options = [] for key, val in _check_and_escape_options(self.options): if val.strip() != '': cmd.extend(['-' + key, val]) else: action_options.append('-' + key) cmd.extend( ["-printingOptions", "all", "-import", problem_files[0]]) cmd.extend(action_options) if self._warm_start_solve: cmd.extend(["-mipstart", self._warm_start_file_name]) cmd.extend(["-stat=1", "-solve", "-solu", self._soln_file]) return Bunch(cmd=cmd, log_file=self._log_file, env=None)
def _postsolve(self): # the only suffixes that we extract from XPRESS are # constraint duals, constraint slacks, and variable # reduced-costs. scan through the solver suffix list # and throw an exception if the user has specified # any others. extract_duals = False extract_slacks = False extract_reduced_costs = False for suffix in self._suffixes: flag = False if re.match(suffix, "dual"): extract_duals = True flag = True if re.match(suffix, "slack"): extract_slacks = True flag = True if re.match(suffix, "rc"): extract_reduced_costs = True flag = True if not flag: raise RuntimeError( "***The xpress_direct solver plugin cannot extract solution suffix=" + suffix) xprob = self._solver_model xp = self._xpress xprob_attrs = xprob.attributes ## XPRESS's status codes depend on this ## (number of integer vars > 0) or (number of special order sets > 0) is_mip = (xprob_attrs.mipents > 0) or (xprob_attrs.sets > 0) if is_mip: if extract_reduced_costs: logger.warning("Cannot get reduced costs for MIP.") if extract_duals: logger.warning("Cannot get duals for MIP.") extract_reduced_costs = False extract_duals = False self.results = SolverResults() soln = Solution() self.results.solver.name = self._name self.results.solver.wallclock_time = self._opt_time if is_mip: status = xprob_attrs.mipstatus mip_sols = xprob_attrs.mipsols if status == xp.mip_not_loaded: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Model is not loaded; no solution information is available." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.unknown #no MIP solution, first LP did not solve, second LP did, third search started but incomplete elif status == xp.mip_lp_not_optimal \ or status == xp.mip_lp_optimal \ or status == xp.mip_no_sol_found: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Model is loaded, but no solution information is available." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.unknown elif status == xp.mip_solution: # some solution available self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Unable to satisfy optimality tolerances; a sub-optimal " \ "solution is available." self.results.solver.termination_condition = TerminationCondition.other soln.status = SolutionStatus.feasible elif status == xp.mip_infeas: # MIP proven infeasible self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Model was proven to be infeasible" self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif status == xp.mip_optimal: # optimal self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Model was solved to optimality (subject to tolerances), " \ "and an optimal solution is available." self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif status == xp.mip_unbounded and mip_sols > 0: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "LP relaxation was proven to be unbounded, " \ "but a solution is available." self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status == xp.mip_unbounded and mip_sols <= 0: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "LP relaxation was proven to be unbounded." self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded else: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = \ ("Unhandled Xpress solve status " "("+str(status)+")") self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error else: ## an LP, we'll check the lpstatus status = xprob_attrs.lpstatus if status == xp.lp_unstarted: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Model is not loaded; no solution information is available." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.unknown elif status == xp.lp_optimal: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Model was solved to optimality (subject to tolerances), " \ "and an optimal solution is available." self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif status == xp.lp_infeas: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Model was proven to be infeasible" self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif status == xp.lp_cutoff: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Optimal objective for model was proven to be worse than the " \ "cutoff value specified; a solution is available." self.results.solver.termination_condition = TerminationCondition.minFunctionValue soln.status = SolutionStatus.optimal elif status == xp.lp_unfinished: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization was terminated by the user." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error elif status == xp.lp_unbounded: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Model was proven to be unbounded." self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status == xp.lp_cutoff_in_dual: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Xpress reported the LP was cutoff in the dual." self.results.solver.termination_condition = TerminationCondition.minFunctionValue soln.status = SolutionStatus.optimal elif status == xp.lp_unsolved: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = "Optimization was terminated due to unrecoverable numerical " \ "difficulties." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error elif status == xp.lp_nonconvex: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = "Optimization was terminated because nonconvex quadratic data " \ "were found." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error else: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = \ ("Unhandled Xpress solve status " "("+str(status)+")") self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error self.results.problem.name = xprob_attrs.matrixname if xprob_attrs.objsense == 1.0: self.results.problem.sense = minimize elif xprob_attrs.objsense == -1.0: self.results.problem.sense = maximize else: raise RuntimeError( 'Unrecognized Xpress objective sense: {0}'.format( xprob_attrs.objsense)) self.results.problem.upper_bound = None self.results.problem.lower_bound = None if not is_mip: #LP or continuous problem try: self.results.problem.upper_bound = xprob_attrs.lpobjval self.results.problem.lower_bound = xprob_attrs.lpobjval except (self._XpressException, AttributeError): pass elif xprob_attrs.objsense == 1.0: # minimizing MIP try: self.results.problem.upper_bound = xprob_attrs.mipbestobjval except (self._XpressException, AttributeError): pass try: self.results.problem.lower_bound = xprob_attrs.bestbound except (self._XpressException, AttributeError): pass elif xprob_attrs.objsense == -1.0: # maximizing MIP try: self.results.problem.upper_bound = xprob_attrs.bestbound except (self._XpressException, AttributeError): pass try: self.results.problem.lower_bound = xprob_attrs.mipbestobjval except (self._XpressException, AttributeError): pass else: raise RuntimeError( 'Unrecognized xpress objective sense: {0}'.format( xprob_attrs.objsense)) try: soln.gap = self.results.problem.upper_bound - self.results.problem.lower_bound except TypeError: soln.gap = None self.results.problem.number_of_constraints = xprob_attrs.rows + xprob_attrs.sets + xprob_attrs.qconstraints self.results.problem.number_of_nonzeros = xprob_attrs.elems self.results.problem.number_of_variables = xprob_attrs.cols self.results.problem.number_of_integer_variables = xprob_attrs.mipents self.results.problem.number_of_continuous_variables = xprob_attrs.cols - xprob_attrs.mipents self.results.problem.number_of_objectives = 1 self.results.problem.number_of_solutions = xprob_attrs.mipsols if is_mip else 1 # if a solve was stopped by a limit, we still need to check to # see if there is a solution available - this may not always # be the case, both in LP and MIP contexts. if self._save_results: """ This code in this if statement is only needed for backwards compatability. It is more efficient to set _save_results to False and use load_vars, load_duals, etc. """ if xprob_attrs.lpstatus in \ [xp.lp_optimal, xp.lp_cutoff, xp.lp_cutoff_in_dual] or \ xprob_attrs.mipsols > 0: soln_variables = soln.variable soln_constraints = soln.constraint xpress_vars = list(self._solver_var_to_pyomo_var_map.keys()) var_vals = xprob.getSolution(xpress_vars) for xpress_var, val in zip(xpress_vars, var_vals): pyomo_var = self._solver_var_to_pyomo_var_map[xpress_var] if self._referenced_variables[pyomo_var] > 0: pyomo_var.stale = False soln_variables[xpress_var.name] = {"Value": val} if extract_reduced_costs: vals = xprob.getRCost(xpress_vars) for xpress_var, val in zip(xpress_vars, vals): pyomo_var = self._solver_var_to_pyomo_var_map[ xpress_var] if self._referenced_variables[pyomo_var] > 0: soln_variables[xpress_var.name]["Rc"] = val if extract_duals or extract_slacks: xpress_cons = list( self._solver_con_to_pyomo_con_map.keys()) for con in xpress_cons: soln_constraints[con.name] = {} if extract_duals: vals = xprob.getDual(xpress_cons) for val, con in zip(vals, xpress_cons): soln_constraints[con.name]["Dual"] = val if extract_slacks: vals = xprob.getSlack(xpress_cons) for con, val in zip(xpress_cons, vals): if con in self._range_constraints: ## for xpress, the slack on a range constraint ## is based on the upper bound lb = con.lb ub = con.ub ub_s = val expr_val = ub - ub_s lb_s = lb - expr_val if abs(ub_s) > abs(lb_s): soln_constraints[con.name]["Slack"] = ub_s else: soln_constraints[con.name]["Slack"] = lb_s else: soln_constraints[con.name]["Slack"] = val elif self._load_solutions: if xprob_attrs.lpstatus == xp.lp_optimal and \ ((not is_mip) or (xprob_attrs.mipsols > 0)): self._load_vars() if extract_reduced_costs: self._load_rc() if extract_duals: self._load_duals() if extract_slacks: self._load_slacks() self.results.solution.insert(soln) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. TempfileManager.pop(remove=not self._keepfiles) return DirectOrPersistentSolver._postsolve(self)
def main(args=None): # # Top-level command that executes the extensive form writer. # This is segregated from run_ef_writer to enable profiling. # # # Import plugins # import pyomo.environ # # Parse command-line options. # try: options_parser = construct_smps_options_parser("runph [options]") (options, args) = options_parser.parse_args(args=args) except SystemExit as _exc: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return _exc.code # # Control the garbage collector - more critical than I would like # at the moment. # if options.disable_gc: gc.disable() else: gc.enable() # # Run PH - precise invocation depends on whether we want profiling # output. # # if an exception is triggered and traceback is enabled, 'ans' # won't have a value and the return statement from this function # will flag an error, masking the stack trace that you really want # to see. ans = None if pstats_available and options.profile > 0: # # Call the main routine with profiling. # tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('exec_pysp2smps(options)',globals(),locals(),tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('cumulative','calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) TempfileManager.clear_tempfiles() ans = [tmp, None] else: # # Call the main routine without profiling. # if options.traceback: ans = exec_pysp2smps(options) else: try: try: ans = exec_pysp2smps(options) except ValueError: str = sys.exc_info()[1] print("VALUE ERROR:") print(str) raise except KeyError: str = sys.exc_info()[1] print("KEY ERROR:") print(str) raise except TypeError: str = sys.exc_info()[1] print("TYPE ERROR:") print(str) raise except NameError: str = sys.exc_info()[1] print("NAME ERROR:") print(str) raise except IOError: str = sys.exc_info()[1] print("IO ERROR:") print(str) raise except pyutilib.common.ApplicationError: str = sys.exc_info()[1] print("APPLICATION ERROR:") print(str) raise except RuntimeError: str = sys.exc_info()[1] print("RUN-TIME ERROR:") print(str) raise except: print("Encountered unhandled exception") traceback.print_exc() raise except: print("\n") print("To obtain further information regarding the " "source of the exception, use the --traceback option") gc.enable() return ans
def create_command_line(self, executable, problem_files): # # Define log file # The log file in XPRESS contains the solution trace, but the solver status can be found in the solution file. # if self._log_file is None: self._log_file = TempfileManager.\ create_tempfile(suffix = '.xpress.log') # # Define solution file # As indicated above, contains (in XML) both the solution and solver status. # self._soln_file = TempfileManager.\ create_tempfile(suffix = '.xpress.wrtsol') # # Write the XPRESS execution script # script = "" script = "setlogfile %s\n" % (self._log_file, ) if self._timelimit is not None and self._timelimit > 0.0: script += "maxtime=%s\n" % (self._timelimit, ) if (self.options.mipgap is not None) and (self.options.mipgap > 0.0): mipgap = self.options.pop('mipgap') script += "miprelstop=%s\n" % (mipgap, ) for option_name in self.options: script += "%s=%s\n" % (option_name, self.options[option_name]) script += "readprob %s\n" % (problem_files[0], ) # doesn't seem to be a global solve command for mip versus lp # solves if self.is_mip: script += "mipoptimize\n" else: script += "lpoptimize\n" # a quick explanation of the various flags used below: # p: outputs in full precision # n: output the name # t: output the type # a: output the activity (value) # c: outputs the costs for variables, slacks for constraints. # d: outputs the reduced costs for columns, duals for constraints script += "writesol %s -pnatcd\n" % (self._soln_file, ) script += "quit\n" # dump the script and warm-start file names for the # user if we're keeping files around. if self._keepfiles: script_fname = TempfileManager.create_tempfile( suffix='.xpress.script') tmp = open(script_fname, 'w') tmp.write(script) tmp.close() print("Solver script file=" + script_fname) # # Define command line # cmd = [executable] if self._timer: cmd.insert(0, self._timer) return Bunch(cmd=cmd, script=script, log_file=self._log_file, env=None)
def run_command(command=None, parser=None, args=None, name='unknown', data=None, options=None): """ Execute a function that processes command-line arguments and then calls a command-line driver. This function provides a generic facility for executing a command function is rather generic. This function is segregated from the driver to enable profiling of the command-line execution. Required: command: The name of a function that will be executed to perform process the command-line options with a parser object. parser: The parser object that is used by the command-line function. Optional: options: If this is not None, then ignore the args option and use this to specify command options. args: Command-line arguments that are parsed. If this value is `None`, then the arguments in `sys.argv` are used to parse the command-line. name: Specifying the name of the command-line (for error messages). data: A container of labeled data. Returned: retval: Return values from the command-line execution. errorcode: 0 if Pyomo ran successfully """ # # # Parse command-line options # # retval = None errorcode = 0 if options is None: try: if type(args) is argparse.Namespace: _options = args else: _options = parser.parse_args(args=args) # Replace the parser options object with a pyutilib.misc.Options object options = pyutilib.misc.Options() for key in dir(_options): if key[0] != '_': val = getattr(_options, key) if not isinstance(val, types.MethodType): options[key] = val except SystemExit: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return Container(retval=retval, errorcode=errorcode) # # Configure loggers # configure_loggers(options=options) # # Setup I/O redirect to a file # logfile = options.runtime.logfile if not logfile is None: pyutilib.misc.setup_redirect(logfile) # # Call the main Pyomo runner with profiling # TempfileManager.push() pcount = options.runtime.profile_count if pcount > 0: if not pstats_available: if not logfile is None: pyutilib.misc.reset_redirect() msg = "Cannot use the 'profile' option. The Python 'pstats' " \ 'package cannot be imported!' raise ValueError(msg) tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx( command.__name__ + '(options=options,parser=parser)', command.__globals__, locals(), tfile ) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) p = p.sort_stats('cumulative','calls') p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) p = p.sort_stats('calls') p.print_stats(pcount) p.print_callers(pcount) p.print_callees(pcount) retval = tmp else: # # Call the main Pyomo runner without profiling # TempfileManager.push() try: retval = command(options=options, parser=parser) except SystemExit: err = sys.exc_info()[1] # # If debugging is enabled or the 'catch' option is specified, then # exit. Otherwise, print an "Exiting..." message. # if __debug__ and (options.runtime.logging == 'debug' or options.runtime.catch_errors): sys.exit(0) print('Exiting %s: %s' % (name, str(err))) errorcode = err.code except Exception: err = sys.exc_info()[1] # # If debugging is enabled or the 'catch' option is specified, then # pass the exception up the chain (to pyomo_excepthook) # if __debug__ and (options.runtime.logging == 'debug' or options.runtime.catch_errors): if not logfile is None: pyutilib.misc.reset_redirect() TempfileManager.pop(remove=not options.runtime.keep_files) raise if not options.model is None and not options.model.save_file is None: model = "model " + options.model.save_file else: model = "model" global filter_excepthook if filter_excepthook: action = "loading" else: action = "running" msg = "Unexpected exception while %s %s:\n" % (action, model) # # This handles the case where the error is propagated by a KeyError. # KeyError likes to pass raw strings that don't handle newlines # (they translate "\n" to "\\n"), as well as tacking on single # quotes at either end of the error message. This undoes all that. # errStr = str(err) if type(err) == KeyError and errStr != "None": errStr = str(err).replace(r"\n","\n")[1:-1] logging.getLogger('pyomo.core').error(msg+errStr) errorcode = 1 if not logfile is None: pyutilib.misc.reset_redirect() if options.runtime.disable_gc: gc.enable() TempfileManager.pop(remove=not options.runtime.keep_files) return Container(retval=retval, errorcode=errorcode)
def tearDown(self): TempfileManager.clear_tempfiles()
def setUp(self): self.mock_model = self.get_mock_model() self.mock_cplex_shell = self.get_mock_cplex_shell(self.mock_model) self.mock_cplex_shell._priorities_file_name = TempfileManager.create_tempfile( suffix=".cplex.ord")
def _presolve(self, *args, **kwds): super(GJHSolver, self)._presolve(*args, **kwds) self._gjh_file = self._soln_file[:-3] + 'gjh' TempfileManager.add_tempfile(self._gjh_file, exists=False)
def _postsolve(self): # the only suffixes that we extract from GUROBI are # constraint duals, constraint slacks, and variable # reduced-costs. scan through the solver suffix list # and throw an exception if the user has specified # any others. extract_duals = False extract_slacks = False extract_reduced_costs = False for suffix in self._suffixes: flag = False if re.match(suffix, "dual"): extract_duals = True flag = True if re.match(suffix, "slack"): extract_slacks = True flag = True if re.match(suffix, "rc"): extract_reduced_costs = True flag = True if not flag: raise RuntimeError("***The gurobi_direct solver plugin cannot extract solution suffix="+suffix) gprob = self._solver_model grb = self._gurobipy.GRB status = gprob.Status if gprob.getAttr(self._gurobipy.GRB.Attr.IsMIP): if extract_reduced_costs: logger.warning("Cannot get reduced costs for MIP.") if extract_duals: logger.warning("Cannot get duals for MIP.") extract_reduced_costs = False extract_duals = False self.results = SolverResults() soln = Solution() self.results.solver.name = self._name self.results.solver.wallclock_time = gprob.Runtime if status == grb.LOADED: # problem is loaded, but no solution self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Model is loaded, but no solution information is available." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.unknown elif status == grb.OPTIMAL: # optimal self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Model was solved to optimality (subject to tolerances), " \ "and an optimal solution is available." self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif status == grb.INFEASIBLE: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Model was proven to be infeasible" self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif status == grb.INF_OR_UNBD: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Problem proven to be infeasible or unbounded." self.results.solver.termination_condition = TerminationCondition.infeasibleOrUnbounded soln.status = SolutionStatus.unsure elif status == grb.UNBOUNDED: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Model was proven to be unbounded." self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status == grb.CUTOFF: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimal objective for model was proven to be worse than the " \ "value specified in the Cutoff parameter. No solution " \ "information is available." self.results.solver.termination_condition = TerminationCondition.minFunctionValue soln.status = SolutionStatus.unknown elif status == grb.ITERATION_LIMIT: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization terminated because the total number of simplex " \ "iterations performed exceeded the value specified in the " \ "IterationLimit parameter." self.results.solver.termination_condition = TerminationCondition.maxIterations soln.status = SolutionStatus.stoppedByLimit elif status == grb.NODE_LIMIT: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization terminated because the total number of " \ "branch-and-cut nodes explored exceeded the value specified " \ "in the NodeLimit parameter" self.results.solver.termination_condition = TerminationCondition.maxEvaluations soln.status = SolutionStatus.stoppedByLimit elif status == grb.TIME_LIMIT: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization terminated because the time expended exceeded " \ "the value specified in the TimeLimit parameter." self.results.solver.termination_condition = TerminationCondition.maxTimeLimit soln.status = SolutionStatus.stoppedByLimit elif status == grb.SOLUTION_LIMIT: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization terminated because the number of solutions found " \ "reached the value specified in the SolutionLimit parameter." self.results.solver.termination_condition = TerminationCondition.unknown soln.status = SolutionStatus.stoppedByLimit elif status == grb.INTERRUPTED: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "Optimization was terminated by the user." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error elif status == grb.NUMERIC: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = "Optimization was terminated due to unrecoverable numerical " \ "difficulties." self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error elif status == grb.SUBOPTIMAL: self.results.solver.status = SolverStatus.warning self.results.solver.termination_message = "Unable to satisfy optimality tolerances; a sub-optimal " \ "solution is available." self.results.solver.termination_condition = TerminationCondition.other soln.status = SolutionStatus.feasible # note that USER_OBJ_LIMIT was added in Gurobi 7.0, so it may not be present elif (status is not None) and \ (status == getattr(grb,'USER_OBJ_LIMIT',None)): self.results.solver.status = SolverStatus.aborted self.results.solver.termination_message = "User specified an objective limit " \ "(a bound on either the best objective " \ "or the best bound), and that limit has " \ "been reached. Solution is available." self.results.solver.termination_condition = TerminationCondition.other soln.status = SolutionStatus.stoppedByLimit else: self.results.solver.status = SolverStatus.error self.results.solver.termination_message = \ ("Unhandled Gurobi solve status " "("+str(status)+")") self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error self.results.problem.name = gprob.ModelName if gprob.ModelSense == 1: self.results.problem.sense = minimize elif gprob.ModelSense == -1: self.results.problem.sense = maximize else: raise RuntimeError('Unrecognized gurobi objective sense: {0}'.format(gprob.ModelSense)) self.results.problem.upper_bound = None self.results.problem.lower_bound = None if (gprob.NumBinVars + gprob.NumIntVars) == 0: try: self.results.problem.upper_bound = gprob.ObjVal self.results.problem.lower_bound = gprob.ObjVal except (self._gurobipy.GurobiError, AttributeError): pass elif gprob.ModelSense == 1: # minimizing try: self.results.problem.upper_bound = gprob.ObjVal except (self._gurobipy.GurobiError, AttributeError): pass try: self.results.problem.lower_bound = gprob.ObjBound except (self._gurobipy.GurobiError, AttributeError): pass elif gprob.ModelSense == -1: # maximizing try: self.results.problem.upper_bound = gprob.ObjBound except (self._gurobipy.GurobiError, AttributeError): pass try: self.results.problem.lower_bound = gprob.ObjVal except (self._gurobipy.GurobiError, AttributeError): pass else: raise RuntimeError('Unrecognized gurobi objective sense: {0}'.format(gprob.ModelSense)) try: soln.gap = self.results.problem.upper_bound - self.results.problem.lower_bound except TypeError: soln.gap = None self.results.problem.number_of_constraints = gprob.NumConstrs + gprob.NumQConstrs + gprob.NumSOS self.results.problem.number_of_nonzeros = gprob.NumNZs self.results.problem.number_of_variables = gprob.NumVars self.results.problem.number_of_binary_variables = gprob.NumBinVars self.results.problem.number_of_integer_variables = gprob.NumIntVars self.results.problem.number_of_continuous_variables = gprob.NumVars - gprob.NumIntVars - gprob.NumBinVars self.results.problem.number_of_objectives = 1 self.results.problem.number_of_solutions = gprob.SolCount # if a solve was stopped by a limit, we still need to check to # see if there is a solution available - this may not always # be the case, both in LP and MIP contexts. if self._save_results: """ This code in this if statement is only needed for backwards compatability. It is more efficient to set _save_results to False and use load_vars, load_duals, etc. """ if gprob.SolCount > 0: soln_variables = soln.variable soln_constraints = soln.constraint gurobi_vars = self._solver_model.getVars() gurobi_vars = list(set(gurobi_vars).intersection(set(self._pyomo_var_to_solver_var_map.values()))) var_vals = self._solver_model.getAttr("X", gurobi_vars) names = self._solver_model.getAttr("VarName", gurobi_vars) for gurobi_var, val, name in zip(gurobi_vars, var_vals, names): pyomo_var = self._solver_var_to_pyomo_var_map[gurobi_var] if self._referenced_variables[pyomo_var] > 0: pyomo_var.stale = False soln_variables[name] = {"Value": val} if extract_reduced_costs: vals = self._solver_model.getAttr("Rc", gurobi_vars) for gurobi_var, val, name in zip(gurobi_vars, vals, names): pyomo_var = self._solver_var_to_pyomo_var_map[gurobi_var] if self._referenced_variables[pyomo_var] > 0: soln_variables[name]["Rc"] = val if extract_duals or extract_slacks: gurobi_cons = self._solver_model.getConstrs() con_names = self._solver_model.getAttr("ConstrName", gurobi_cons) for name in con_names: soln_constraints[name] = {} if self._version_major >= 5: gurobi_q_cons = self._solver_model.getQConstrs() q_con_names = self._solver_model.getAttr("QCName", gurobi_q_cons) for name in q_con_names: soln_constraints[name] = {} if extract_duals: vals = self._solver_model.getAttr("Pi", gurobi_cons) for val, name in zip(vals, con_names): soln_constraints[name]["Dual"] = val if self._version_major >= 5: q_vals = self._solver_model.getAttr("QCPi", gurobi_q_cons) for val, name in zip(q_vals, q_con_names): soln_constraints[name]["Dual"] = val if extract_slacks: gurobi_range_con_vars = set(self._solver_model.getVars()) - set(self._pyomo_var_to_solver_var_map.values()) vals = self._solver_model.getAttr("Slack", gurobi_cons) for gurobi_con, val, name in zip(gurobi_cons, vals, con_names): pyomo_con = self._solver_con_to_pyomo_con_map[gurobi_con] if pyomo_con in self._range_constraints: lin_expr = self._solver_model.getRow(gurobi_con) for i in reversed(range(lin_expr.size())): v = lin_expr.getVar(i) if v in gurobi_range_con_vars: Us_ = v.X Ls_ = v.UB - v.X if Us_ > Ls_: soln_constraints[name]["Slack"] = Us_ else: soln_constraints[name]["Slack"] = -Ls_ break else: soln_constraints[name]["Slack"] = val if self._version_major >= 5: q_vals = self._solver_model.getAttr("QCSlack", gurobi_q_cons) for val, name in zip(q_vals, q_con_names): soln_constraints[name]["Slack"] = val elif self._load_solutions: if gprob.SolCount > 0: self._load_vars() if extract_reduced_costs: self._load_rc() if extract_duals: self._load_duals() if extract_slacks: self._load_slacks() self.results.solution.insert(soln) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. TempfileManager.pop(remove=not self._keepfiles) return DirectOrPersistentSolver._postsolve(self)
def _presolve(self, *args, **kwds): super(GJHSolver, self)._presolve(*args, **kwds) self._gjh_file = self._soln_file[:-3]+'gjh' TempfileManager.add_tempfile(self._gjh_file, exists=False)
def tearDown(self): TempfileManager.clear_tempfiles() ReaderFactory.unregister('rtest3') ReaderFactory.unregister('stest3') ReaderFactory.unregister('wtest3')
def _postsolve(self): # the only suffixes that we extract from CPLEX are # constraint duals, constraint slacks, and variable # reduced-costs. scan through the solver suffix list # and throw an exception if the user has specified # any others. extract_duals = False extract_slacks = False extract_reduced_costs = False for suffix in self._suffixes: flag = False if re.match(suffix, "dual"): extract_duals = True flag = True if re.match(suffix, "slack"): extract_slacks = True flag = True if re.match(suffix, "rc"): extract_reduced_costs = True flag = True if not flag: raise RuntimeError("***The cplex_direct solver plugin cannot extract solution suffix="+suffix) cpxprob = self._solver_model status = cpxprob.solution.get_status() if cpxprob.get_problem_type() in [cpxprob.problem_type.MILP, cpxprob.problem_type.MIQP, cpxprob.problem_type.MIQCP]: if extract_reduced_costs: logger.warning("Cannot get reduced costs for MIP.") if extract_duals: logger.warning("Cannot get duals for MIP.") extract_reduced_costs = False extract_duals = False self.results = SolverResults() soln = Solution() self.results.solver.name = ("CPLEX {0}".format(cpxprob.get_version())) self.results.solver.wallclock_time = self._wallclock_time if status in [1, 101, 102]: self.results.solver.status = SolverStatus.ok self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif status in [2, 40, 118, 133, 134]: self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status in [4, 119, 134]: # Note: status of 4 means infeasible or unbounded # and 119 means MIP infeasible or unbounded self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = \ TerminationCondition.infeasibleOrUnbounded soln.status = SolutionStatus.unsure elif status in [3, 103]: self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif status in [10]: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_condition = TerminationCondition.maxIterations soln.status = SolutionStatus.stoppedByLimit elif status in [11, 25, 107, 131]: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_condition = TerminationCondition.maxTimeLimit soln.status = SolutionStatus.stoppedByLimit else: self.results.solver.status = SolverStatus.error self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error if cpxprob.objective.get_sense() == cpxprob.objective.sense.minimize: self.results.problem.sense = minimize elif cpxprob.objective.get_sense() == cpxprob.objective.sense.maximize: self.results.problem.sense = maximize else: raise RuntimeError('Unrecognized cplex objective sense: {0}'.\ format(cpxprob.objective.get_sense())) self.results.problem.upper_bound = None self.results.problem.lower_bound = None if (cpxprob.variables.get_num_binary() + cpxprob.variables.get_num_integer()) == 0: try: self.results.problem.upper_bound = cpxprob.solution.get_objective_value() self.results.problem.lower_bound = cpxprob.solution.get_objective_value() except self._cplex.exceptions.CplexError: pass elif cpxprob.objective.get_sense() == cpxprob.objective.sense.minimize: try: self.results.problem.upper_bound = cpxprob.solution.get_objective_value() except self._cplex.exceptions.CplexError: pass try: self.results.problem.lower_bound = cpxprob.solution.MIP.get_best_objective() except self._cplex.exceptions.CplexError: pass elif cpxprob.objective.get_sense() == cpxprob.objective.sense.maximize: try: self.results.problem.upper_bound = cpxprob.solution.MIP.get_best_objective() except self._cplex.exceptions.CplexError: pass try: self.results.problem.lower_bound = cpxprob.solution.get_objective_value() except self._cplex.exceptions.CplexError: pass else: raise RuntimeError('Unrecognized cplex objective sense: {0}'.\ format(cpxprob.objective.get_sense())) try: soln.gap = self.results.problem.upper_bound - self.results.problem.lower_bound except TypeError: soln.gap = None self.results.problem.name = cpxprob.get_problem_name() assert cpxprob.indicator_constraints.get_num() == 0 self.results.problem.number_of_constraints = \ (cpxprob.linear_constraints.get_num() + cpxprob.quadratic_constraints.get_num() + cpxprob.SOS.get_num()) self.results.problem.number_of_nonzeros = None self.results.problem.number_of_variables = cpxprob.variables.get_num() self.results.problem.number_of_binary_variables = cpxprob.variables.get_num_binary() self.results.problem.number_of_integer_variables = cpxprob.variables.get_num_integer() assert cpxprob.variables.get_num_semiinteger() == 0 assert cpxprob.variables.get_num_semicontinuous() == 0 self.results.problem.number_of_continuous_variables = \ (cpxprob.variables.get_num() - cpxprob.variables.get_num_binary() - cpxprob.variables.get_num_integer()) self.results.problem.number_of_objectives = 1 # only try to get objective and variable values if a solution exists if self._save_results: """ This code in this if statement is only needed for backwards compatability. It is more efficient to set _save_results to False and use load_vars, load_duals, etc. """ if cpxprob.solution.get_solution_type() > 0: soln_variables = soln.variable soln_constraints = soln.constraint var_names = self._solver_model.variables.get_names() var_names = list(set(var_names).intersection(set(self._pyomo_var_to_solver_var_map.values()))) var_vals = self._solver_model.solution.get_values(var_names) for i, name in enumerate(var_names): pyomo_var = self._solver_var_to_pyomo_var_map[name] if self._referenced_variables[pyomo_var] > 0: pyomo_var.stale = False soln_variables[name] = {"Value":var_vals[i]} if extract_reduced_costs: reduced_costs = self._solver_model.solution.get_reduced_costs(var_names) for i, name in enumerate(var_names): pyomo_var = self._solver_var_to_pyomo_var_map[name] if self._referenced_variables[pyomo_var] > 0: soln_variables[name]["Rc"] = reduced_costs[i] if extract_slacks: for con_name in self._solver_model.linear_constraints.get_names(): soln_constraints[con_name] = {} for con_name in self._solver_model.quadratic_constraints.get_names(): soln_constraints[con_name] = {} elif extract_duals: # CPLEX PYTHON API DOES NOT SUPPORT QUADRATIC DUAL COLLECTION for con_name in self._solver_model.linear_constraints.get_names(): soln_constraints[con_name] = {} if extract_duals: dual_values = self._solver_model.solution.get_dual_values() for i, con_name in enumerate(self._solver_model.linear_constraints.get_names()): soln_constraints[con_name]["Dual"] = dual_values[i] if extract_slacks: linear_slacks = self._solver_model.solution.get_linear_slacks() qudratic_slacks = self._solver_model.solution.get_quadratic_slacks() for i, con_name in enumerate(self._solver_model.linear_constraints.get_names()): pyomo_con = self._solver_con_to_pyomo_con_map[con_name] if pyomo_con in self._range_constraints: R_ = self._solver_model.linear_constraints.get_range_values(con_name) if R_ == 0: soln_constraints[con_name]["Slack"] = linear_slacks[i] else: Ls_ = linear_slacks[i] Us_ = R_ - Ls_ if abs(Us_) > abs(Ls_): soln_constraints[con_name]["Slack"] = Us_ else: soln_constraints[con_name]["Slack"] = -Ls_ else: soln_constraints[con_name]["Slack"] = linear_slacks[i] for i, con_name in enumerate(self._solver_model.quadratic_constraints.get_names()): soln_constraints[con_name]["Slack"] = qudratic_slacks[i] elif self._load_solutions: if cpxprob.solution.get_solution_type() > 0: self._load_vars() if extract_reduced_costs: self._load_rc() if extract_duals: self._load_duals() if extract_slacks: self._load_slacks() self.results.solution.insert(soln) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. TempfileManager.pop(remove=not self._keepfiles) return DirectOrPersistentSolver._postsolve(self)
def _solve_impl(self, sp, keep_solver_files=False, output_solver_log=False, symbolic_solver_labels=False): if len(sp.scenario_tree.stages) > 2: raise ValueError("SD solver does not handle more " "than 2 time-stages") if sp.objective_sense == maximize: raise ValueError("SD solver does not yet handle " "maximization problems") TempfileManager.push() try: # # Setup the SD working directory # working_directory = TempfileManager.create_tempdir() config_filename = os.path.join(working_directory, "config.sd") sdinput_directory = os.path.join(working_directory, "sdinput", "pysp_model") sdoutput_directory = os.path.join(working_directory, "sdoutput", "pysp_model") logfile = os.path.join(working_directory, "sd.log") os.makedirs(sdinput_directory) assert os.path.exists(sdinput_directory) assert not os.path.exists(sdoutput_directory) self._write_config(config_filename) if self.get_option('single_replication'): solution_filename = os.path.join( sdoutput_directory, "pysp_model.detailed_rep_soln.out") else: solution_filename = os.path.join( sdoutput_directory, "pysp_model.detailed_soln.out") # # Create the SD input files # io_options = {'symbolic_solver_labels': symbolic_solver_labels} symbol_map = None if isinstance(sp, ImplicitSP): symbol_map = pyomo.pysp.smps.smpsutils.\ convert_implicit( sdinput_directory, "pysp_model", sp, core_format='mps', io_options=io_options) else: pyomo.pysp.smps.smpsutils.\ convert_explicit( sdinput_directory, "pysp_model", sp, core_format='mps', io_options=io_options) # # Launch SD # if keep_solver_files: print("Solver working directory: '%s'" % (working_directory)) print("Solver log file: '%s'" % (logfile)) start = time.time() rc, log = pyutilib.subprocess.run( self.get_option("sd_executable"), cwd=working_directory, stdin="pysp_model", outfile=logfile, tee=output_solver_log) stop = time.time() assert os.path.exists(sdoutput_directory) # # Parse the SD solution # xhat, results = self._read_solution(solution_filename) results.solver_time = stop - start if symbol_map is not None: # load the first stage variable solution into # the reference model for symbol, varvalue in xhat.items(): symbol_map.bySymbol[symbol]().value = varvalue else: # TODO: this is a hack for the non-implicit SP case # so that this solver can still be run using # the explicit scenario intput representation results.xhat = xhat finally: # # cleanup # TempfileManager.pop( remove=not keep_solver_files) return results
def launch_command(command, options, cmd_args=None, cmd_kwds=None, error_label="", disable_gc=False, profile_count=0, traceback=False): if cmd_args is None: cmd_args = () if cmd_kwds is None: cmd_kwds = {} # # Control the garbage collector - more critical than I would like # at the moment. # with PauseGC(disable_gc) as pgc: # # Run command - precise invocation depends on whether we want # profiling output, traceback, etc. # rc = 0 if pstats_available and (profile_count > 0): # # Call the main routine with profiling. # tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('command(options, *cmd_args, **cmd_kwds)', globals(), locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('cumulative','calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) p = p.sort_stats('calls') p.print_stats(profile_count) p.print_callers(profile_count) p.print_callees(profile_count) TempfileManager.clear_tempfiles() rc = tmp else: # # Call the main PH routine without profiling. # if traceback: rc = command(options, *cmd_args, **cmd_kwds) else: try: try: rc = command(options, *cmd_args, **cmd_kwds) except ValueError: sys.stderr.write(error_label+"VALUE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except KeyError: sys.stderr.write(error_label+"KEY ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except TypeError: sys.stderr.write(error_label+"TYPE ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except NameError: sys.stderr.write(error_label+"NAME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except IOError: sys.stderr.write(error_label+"IO ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except ConverterError: sys.stderr.write(error_label+"CONVERTER ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except pyutilib.common.ApplicationError: sys.stderr.write(error_label+"APPLICATION ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except RuntimeError: sys.stderr.write(error_label+"RUN-TIME ERROR:\n") sys.stderr.write(str(sys.exc_info()[1])+"\n") raise except: sys.stderr.write(error_label+ "Encountered unhandled exception:\n") if len(sys.exc_info()) > 1: sys.stderr.write(str(sys.exc_info()[1])+"\n") else: traceback.print_exc(file=sys.stderr) raise except: sys.stderr.write("\n") sys.stderr.write( "To obtain further information regarding the " "source of the exception, use the " "--traceback option\n") rc = 1 # # TODO: Once we incorporate options registration into # all of the PySP commands we will assume the # options object is always a PySPConfigBlock # if isinstance(options, PySPConfigBlock): ignored_options = dict((_c._name, _c.value(False)) for _c in options.unused_user_values()) if len(ignored_options): print("") print("*** WARNING: The following options were " "explicitly set but never accessed during " "execution of this command:") for name in ignored_options: print(" - %s: %s" % (name, ignored_options[name])) print("*** If you believe this is a bug, please report it " "to the PySP developers.") print("") return rc
def tearDown(self): global tmpdir TempfileManager.clear_tempfiles() TempfileManager.unique_files() os.chdir(tmpdir)
def _postsolve(self): # the only suffixes that we extract from CPLEX are # constraint duals, constraint slacks, and variable # reduced-costs. scan through the solver suffix list # and throw an exception if the user has specified # any others. extract_duals = False extract_slacks = False extract_reduced_costs = False for suffix in self._suffixes: flag = False if re.match(suffix, "dual"): extract_duals = True flag = True if re.match(suffix, "slack"): extract_slacks = True flag = True if re.match(suffix, "rc"): extract_reduced_costs = True flag = True if not flag: raise RuntimeError("***The cplex_direct solver plugin cannot extract solution suffix="+suffix) cpxprob = self._solver_model status = cpxprob.solution.get_status() rtn_codes = cpxprob.solution.status if cpxprob.get_problem_type() in [cpxprob.problem_type.MILP, cpxprob.problem_type.MIQP, cpxprob.problem_type.MIQCP]: if extract_reduced_costs: logger.warning("Cannot get reduced costs for MIP.") if extract_duals: logger.warning("Cannot get duals for MIP.") extract_reduced_costs = False extract_duals = False self.results = SolverResults() soln = Solution() self.results.solver.name = ("CPLEX {0}".format(cpxprob.get_version())) self.results.solver.wallclock_time = self._wallclock_time self.results.solver.deterministic_time = self._deterministic_time if status in { rtn_codes.optimal, rtn_codes.MIP_optimal, rtn_codes.optimal_tolerance, }: self.results.solver.status = SolverStatus.ok self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif status in { rtn_codes.unbounded, 40, rtn_codes.MIP_unbounded, rtn_codes.relaxation_unbounded, 134, }: self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif status in { rtn_codes.infeasible_or_unbounded, rtn_codes.MIP_infeasible_or_unbounded, 134, }: # Note: status of 4 means infeasible or unbounded # and 119 means MIP infeasible or unbounded self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = \ TerminationCondition.infeasibleOrUnbounded soln.status = SolutionStatus.unsure elif status in {rtn_codes.infeasible, rtn_codes.MIP_infeasible}: self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif status in {rtn_codes.abort_iteration_limit}: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_condition = TerminationCondition.maxIterations soln.status = SolutionStatus.stoppedByLimit elif status in { rtn_codes.solution_limit, rtn_codes.node_limit_feasible, rtn_codes.mem_limit_feasible }: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_condition = TerminationCondition.unknown soln.status = SolutionStatus.stoppedByLimit elif status in { rtn_codes.abort_time_limit, rtn_codes.abort_dettime_limit, rtn_codes.MIP_time_limit_feasible, rtn_codes.MIP_dettime_limit_feasible, }: self.results.solver.status = SolverStatus.aborted self.results.solver.termination_condition = TerminationCondition.maxTimeLimit soln.status = SolutionStatus.stoppedByLimit elif status in { rtn_codes.MIP_time_limit_infeasible, rtn_codes.MIP_dettime_limit_infeasible, rtn_codes.node_limit_infeasible, rtn_codes.mem_limit_infeasible, rtn_codes.MIP_abort_infeasible, } or self._error_code == self._cplex.exceptions.error_codes.CPXERR_NO_SOLN: # CPLEX doesn't have a solution status for `noSolution` so we assume this from the combination of # maxTimeLimit + infeasible (instead of a generic `TerminationCondition.error`). self.results.solver.status = SolverStatus.warning self.results.solver.termination_condition = TerminationCondition.noSolution soln.status = SolutionStatus.unknown else: self.results.solver.status = SolverStatus.error self.results.solver.termination_condition = TerminationCondition.error soln.status = SolutionStatus.error self.results.solver.return_code = self._error_code self.results.solver.termination_message = cpxprob.solution.get_status_string(status) if cpxprob.objective.get_sense() == cpxprob.objective.sense.minimize: self.results.problem.sense = minimize elif cpxprob.objective.get_sense() == cpxprob.objective.sense.maximize: self.results.problem.sense = maximize else: raise RuntimeError('Unrecognized cplex objective sense: {0}'.\ format(cpxprob.objective.get_sense())) self.results.problem.upper_bound = None self.results.problem.lower_bound = None if cpxprob.solution.get_solution_type() != cpxprob.solution.type.none: if (cpxprob.variables.get_num_binary() + cpxprob.variables.get_num_integer()) == 0: self.results.problem.upper_bound = cpxprob.solution.get_objective_value() self.results.problem.lower_bound = cpxprob.solution.get_objective_value() elif cpxprob.objective.get_sense() == cpxprob.objective.sense.minimize: self.results.problem.upper_bound = cpxprob.solution.get_objective_value() self.results.problem.lower_bound = cpxprob.solution.MIP.get_best_objective() else: assert cpxprob.objective.get_sense() == cpxprob.objective.sense.maximize self.results.problem.upper_bound = cpxprob.solution.MIP.get_best_objective() self.results.problem.lower_bound = cpxprob.solution.get_objective_value() try: soln.gap = self.results.problem.upper_bound - self.results.problem.lower_bound except TypeError: soln.gap = None self.results.problem.name = cpxprob.get_problem_name() assert cpxprob.indicator_constraints.get_num() == 0 self.results.problem.number_of_constraints = \ (cpxprob.linear_constraints.get_num() + cpxprob.quadratic_constraints.get_num() + cpxprob.SOS.get_num()) self.results.problem.number_of_nonzeros = None self.results.problem.number_of_variables = cpxprob.variables.get_num() self.results.problem.number_of_binary_variables = cpxprob.variables.get_num_binary() self.results.problem.number_of_integer_variables = cpxprob.variables.get_num_integer() assert cpxprob.variables.get_num_semiinteger() == 0 assert cpxprob.variables.get_num_semicontinuous() == 0 self.results.problem.number_of_continuous_variables = \ (cpxprob.variables.get_num() - cpxprob.variables.get_num_binary() - cpxprob.variables.get_num_integer()) self.results.problem.number_of_objectives = 1 # only try to get objective and variable values if a solution exists if self._save_results: """ This code in this if statement is only needed for backwards compatability. It is more efficient to set _save_results to False and use load_vars, load_duals, etc. """ if cpxprob.solution.get_solution_type() > 0: soln_variables = soln.variable soln_constraints = soln.constraint var_names = self._solver_model.variables.get_names() var_names = list(set(var_names).intersection(set(self._pyomo_var_to_solver_var_map.values()))) var_vals = self._solver_model.solution.get_values(var_names) for i, name in enumerate(var_names): pyomo_var = self._solver_var_to_pyomo_var_map[name] if self._referenced_variables[pyomo_var] > 0: pyomo_var.stale = False soln_variables[name] = {"Value":var_vals[i]} if extract_reduced_costs: reduced_costs = self._solver_model.solution.get_reduced_costs(var_names) for i, name in enumerate(var_names): pyomo_var = self._solver_var_to_pyomo_var_map[name] if self._referenced_variables[pyomo_var] > 0: soln_variables[name]["Rc"] = reduced_costs[i] if extract_slacks: for con_name in self._solver_model.linear_constraints.get_names(): soln_constraints[con_name] = {} for con_name in self._solver_model.quadratic_constraints.get_names(): soln_constraints[con_name] = {} elif extract_duals: # CPLEX PYTHON API DOES NOT SUPPORT QUADRATIC DUAL COLLECTION for con_name in self._solver_model.linear_constraints.get_names(): soln_constraints[con_name] = {} if extract_duals: dual_values = self._solver_model.solution.get_dual_values() for i, con_name in enumerate(self._solver_model.linear_constraints.get_names()): soln_constraints[con_name]["Dual"] = dual_values[i] if extract_slacks: linear_slacks = self._solver_model.solution.get_linear_slacks() qudratic_slacks = self._solver_model.solution.get_quadratic_slacks() for i, con_name in enumerate(self._solver_model.linear_constraints.get_names()): pyomo_con = self._solver_con_to_pyomo_con_map[con_name] if pyomo_con in self._range_constraints: R_ = self._solver_model.linear_constraints.get_range_values(con_name) if R_ == 0: soln_constraints[con_name]["Slack"] = linear_slacks[i] else: Ls_ = linear_slacks[i] Us_ = R_ - Ls_ if abs(Us_) > abs(Ls_): soln_constraints[con_name]["Slack"] = Us_ else: soln_constraints[con_name]["Slack"] = -Ls_ else: soln_constraints[con_name]["Slack"] = linear_slacks[i] for i, con_name in enumerate(self._solver_model.quadratic_constraints.get_names()): soln_constraints[con_name]["Slack"] = qudratic_slacks[i] elif self._load_solutions: if cpxprob.solution.get_solution_type() > 0: self._load_vars() if extract_reduced_costs: self._load_rc() if extract_duals: self._load_duals() if extract_slacks: self._load_slacks() self.results.solution.insert(soln) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. TempfileManager.pop(remove=not self._keepfiles) return DirectOrPersistentSolver._postsolve(self)
def main(args=None): # # Top-level command that executes the extensive form writer. # This is segregated from run_ef_writer to enable profiling. # # # Import plugins # import pyomo.environ # # Parse command-line options. # try: options_parser = construct_smps_options_parser("runph [options]") (options, args) = options_parser.parse_args(args=args) except SystemExit as _exc: # the parser throws a system exit if "-h" is specified - catch # it to exit gracefully. return _exc.code # # Control the garbage collector - more critical than I would like # at the moment. # if options.disable_gc: gc.disable() else: gc.enable() # # Run PH - precise invocation depends on whether we want profiling # output. # # if an exception is triggered and traceback is enabled, 'ans' # won't have a value and the return statement from this function # will flag an error, masking the stack trace that you really want # to see. ans = None if pstats_available and options.profile > 0: # # Call the main routine with profiling. # tfile = TempfileManager.create_tempfile(suffix=".profile") tmp = profile.runctx('exec_pysp2smps(options)', globals(), locals(), tfile) p = pstats.Stats(tfile).strip_dirs() p.sort_stats('time', 'cumulative') p = p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('cumulative', 'calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) p = p.sort_stats('calls') p.print_stats(options.profile) p.print_callers(options.profile) p.print_callees(options.profile) TempfileManager.clear_tempfiles() ans = [tmp, None] else: # # Call the main routine without profiling. # if options.traceback: ans = exec_pysp2smps(options) else: try: try: ans = exec_pysp2smps(options) except ValueError: str = sys.exc_info()[1] print("VALUE ERROR:") print(str) raise except KeyError: str = sys.exc_info()[1] print("KEY ERROR:") print(str) raise except TypeError: str = sys.exc_info()[1] print("TYPE ERROR:") print(str) raise except NameError: str = sys.exc_info()[1] print("NAME ERROR:") print(str) raise except IOError: str = sys.exc_info()[1] print("IO ERROR:") print(str) raise except pyutilib.common.ApplicationError: str = sys.exc_info()[1] print("APPLICATION ERROR:") print(str) raise except RuntimeError: str = sys.exc_info()[1] print("RUN-TIME ERROR:") print(str) raise except: print("Encountered unhandled exception") traceback.print_exc() raise except: print("\n") print("To obtain further information regarding the " "source of the exception, use the --traceback option") gc.enable() return ans
def _postsolve(self): extract_duals = False extract_slacks = False extract_reduced_costs = False for suffix in self._suffixes: flag = False if re.match(suffix, "dual"): extract_duals = True flag = True if re.match(suffix, "slack"): extract_slacks = True flag = True if re.match(suffix, "rc"): extract_reduced_costs = True flag = True if not flag: raise RuntimeError( "***The mosek solver plugin cannot extract solution suffix=" + suffix) msk_task = self._solver_model msk = self._mosek itr_soltypes = [msk.problemtype.qo, msk.problemtype.qcqo] if (msk_task.getnumintvar() >= 1): self._whichsol = msk.soltype.itg if extract_reduced_costs: logger.warning("Cannot get reduced costs for MIP.") if extract_duals: logger.warning("Cannot get duals for MIP.") extract_reduced_costs = False extract_duals = False elif (msk_task.getprobtype() in itr_soltypes): self._whichsol = msk.soltype.itr whichsol = self._whichsol sol_status = msk_task.getsolsta(whichsol) pro_status = msk_task.getprosta(whichsol) self.results = SolverResults() soln = Solution() self.results.solver.name = self._name self.results.solver.wallclock_time = msk_task.getdouinf( msk.dinfitem.optimizer_time) SOLSTA_MAP = { msk.solsta.unknown: 'unknown', msk.solsta.optimal: 'optimal', msk.solsta.prim_and_dual_feas: 'pd_feas', msk.solsta.prim_feas: 'p_feas', msk.solsta.dual_feas: 'd_feas', msk.solsta.prim_infeas_cer: 'p_infeas', msk.solsta.dual_infeas_cer: 'd_infeas', msk.solsta.prim_illposed_cer: 'p_illposed', msk.solsta.dual_illposed_cer: 'd_illposed', msk.solsta.integer_optimal: 'optimal' } PROSTA_MAP = { msk.prosta.unknown: 'unknown', msk.prosta.prim_and_dual_feas: 'pd_feas', msk.prosta.prim_feas: 'p_feas', msk.prosta.dual_feas: 'd_feas', msk.prosta.prim_infeas: 'p_infeas', msk.prosta.dual_infeas: 'd_infeas', msk.prosta.prim_and_dual_feas: 'pd_infeas', msk.prosta.ill_posed: 'illposed', msk.prosta.prim_infeas_or_unbounded: 'p_inf_unb' } if self._version_major < 9: SOLSTA_OLD = { msk.solsta.near_optimal: 'optimal', msk.solsta.near_integer_optimal: 'optimal', msk.solsta.near_prim_feas: 'p_feas', msk.solsta.near_dual_feas: 'd_feas', msk.solsta.near_prim_and_dual_feas: 'pd_feas', msk.solsta.near_prim_infeas_cer: 'p_infeas', msk.solsta.near_dual_infeas_cer: 'd_infeas' } PROSTA_OLD = { msk.prosta.near_prim_and_dual_feas: 'pd_feas', msk.prosta.near_prim_feas: 'p_feas', msk.prosta.near_dual_feas: 'd_feas' } SOLSTA_MAP.update(SOLSTA_OLD) PROSTA_MAP.update(PROSTA_OLD) if self._termcode == msk.rescode.ok: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "" elif self._termcode == msk.rescode.trm_max_iterations: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Optimization terminated because the total number " \ "iterations performed exceeded the value specified in the " \ "IterationLimit parameter." self.results.solver.termination_condition = TerminationCondition.maxIterations soln.status = SolutionStatus.stoppedByLimit elif self._termcode == msk.rescode.trm_max_time: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Optimization terminated because the time expended exceeded " \ "the value specified in the TimeLimit parameter." self.results.solver.termination_condition = TerminationCondition.maxTimeLimit soln.status = SolutionStatus.stoppedByLimit elif self._termcode == msk.rescode.trm_user_callback: self.results.solver.status = SolverStatus.Aborted self.results.solver.termination_message = "Optimization terminated because of the user callback " self.results.solver.termination_condition = TerminationCondition.userInterrupt soln.status = SolutionStatus.unknown elif self._termcode in [ msk.rescode.trm_mio_num_relaxs, msk.rescode.trm_mio_num_branches, msk.rescode.trm_num_max_num_int_solutions ]: self.results.solver.status = SolverStatus.ok self.results.solver.termination_message = "Optimization terminated because maximum number of relaxations" \ " / branches / integer solutions exceeded " \ "the value specified in the TimeLimit parameter." self.results.solver.termination_condition = TerminationCondition.maxEvaluations soln.status = SolutionStatus.stoppedByLimit else: self.results.solver.termination_message = " Optimization terminated %s response code." \ "Check Mosek response code documentation for further explanation." % self._termcode self.results.solver.termination_condition = TerminationCondition.unknown if SOLSTA_MAP[sol_status] == 'unknown': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " Unknown solution status." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.unknown soln.status = SolutionStatus.unknown if PROSTA_MAP[pro_status] == 'd_infeas': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " Problem proven to be dual infeasible" self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.unbounded elif PROSTA_MAP[pro_status] == 'p_infeas': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " Problem proven to be primal infeasible." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif PROSTA_MAP[pro_status] == 'pd_infeas': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " Problem proven to be primal and dual infeasible." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible elif PROSTA_MAP[pro_status] == 'p_inf_unb': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " Problem proven to be infeasible or unbounded." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.infeasibleOrUnbounded soln.status = SolutionStatus.unsure if SOLSTA_MAP[sol_status] == 'optimal': self.results.solver.status = SolverStatus.ok self.results.solver.termination_message += " Model was solved to optimality, " \ "and an optimal solution is available." self.results.solver.termination_condition = TerminationCondition.optimal soln.status = SolutionStatus.optimal elif SOLSTA_MAP[sol_status] == 'pd_feas': self.results.solver.status = SolverStatus.ok self.results.solver.termination_message += " The solution is both primal and dual feasible" self.results.solver.termination_condition = TerminationCondition.feasible soln.status = SolutionStatus.feasible elif SOLSTA_MAP[sol_status] == 'p_feas': self.results.solver.status = SolverStatus.ok self.results.solver.termination_message += " Primal feasible solution is available." self.results.solver.termination_condition = TerminationCondition.feasible soln.status = SolutionStatus.feasible elif SOLSTA_MAP[sol_status] == 'd_feas': self.results.solver.status = SolverStatus.ok self.results.solver.termination_message += " Dual feasible solution is available." self.results.solver.termination_condition = TerminationCondition.feasible soln.status = SolutionStatus.feasible elif SOLSTA_MAP[sol_status] == 'd_infeas': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " The solution is dual infeasible." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.unbounded soln.status = SolutionStatus.infeasible elif SOLSTA_MAP[sol_status] == 'p_infeas': self.results.solver.status = SolverStatus.warning self.results.solver.termination_message += " The solution is primal infeasible." self.results.solver.Message = self.results.solver.termination_message self.results.solver.termination_condition = TerminationCondition.infeasible soln.status = SolutionStatus.infeasible self.results.problem.name = msk_task.gettaskname() if msk_task.getobjsense() == msk.objsense.minimize: self.results.problem.sense = minimize elif msk_task.getobjsense() == msk.objsense.maximize: self.results.problem.sense = maximize else: raise RuntimeError( 'Unrecognized Mosek objective sense: {0}'.format( msk_task.getobjname())) self.results.problem.upper_bound = None self.results.problem.lower_bound = None if msk_task.getnumintvar() == 0: try: if msk_task.getobjsense() == msk.objsense.minimize: self.results.problem.upper_bound = msk_task.getprimalobj( whichsol) self.results.problem.lower_bound = msk_task.getdualobj( whichsol) elif msk_task.getobjsense() == msk.objsense.maximize: self.results.problem.upper_bound = msk_task.getprimalobj( whichsol) self.results.problem.lower_bound = msk_task.getdualobj( whichsol) except (msk.MosekException, AttributeError): pass elif msk_task.getobjsense() == msk.objsense.minimize: # minimizing try: self.results.problem.upper_bound = msk_task.getprimalobj( whichsol) except (msk.MosekException, AttributeError): pass try: self.results.problem.lower_bound = msk_task.getdouinf( msk.dinfitem.mio_obj_bound) except (msk.MosekException, AttributeError): pass elif msk_task.getobjsense() == msk.objsense.maximize: # maximizing try: self.results.problem.upper_bound = msk_task.getdouinf( msk.dinfitem.mio_obj_bound) except (msk.MosekException, AttributeError): pass try: self.results.problem.lower_bound = msk_task.getprimalobj( whichsol) except (msk.MosekException, AttributeError): pass else: raise RuntimeError( 'Unrecognized Mosek objective sense: {0}'.format( msk_task.getobjsense())) try: soln.gap = self.results.problem.upper_bound - self.results.problem.lower_bound except TypeError: soln.gap = None self.results.problem.number_of_constraints = msk_task.getnumcon() self.results.problem.number_of_nonzeros = msk_task.getnumanz() self.results.problem.number_of_variables = msk_task.getnumvar() self.results.problem.number_of_integer_variables = msk_task.getnumintvar( ) self.results.problem.number_of_continuous_variables = msk_task.getnumvar() - \ msk_task.getnumintvar() self.results.problem.number_of_objectives = 1 self.results.problem.number_of_solutions = 1 # if a solve was stopped by a limit, we still need to check to # see if there is a solution available - this may not always # be the case, both in LP and MIP contexts. if self._save_results: """ This code in this if statement is only needed for backwards compatability. It is more efficient to set _save_results to False and use load_vars, load_duals, etc. """ if self.results.problem.number_of_solutions > 0: soln_variables = soln.variable soln_constraints = soln.constraint mosek_vars = list(range(msk_task.getnumvar())) mosek_vars = list( set(mosek_vars).intersection( set(self._pyomo_var_to_solver_var_map.values()))) var_vals = [0.0] * len(mosek_vars) self._solver_model.getxx(whichsol, var_vals) names = [] for i in mosek_vars: names.append(msk_task.getvarname(i)) for mosek_var, val, name in zip(mosek_vars, var_vals, names): pyomo_var = self._solver_var_to_pyomo_var_map[mosek_var] if self._referenced_variables[pyomo_var] > 0: pyomo_var.stale = False soln_variables[name] = {"Value": val} if extract_reduced_costs: vals = [0.0] * len(mosek_vars) msk_task.getreducedcosts(whichsol, 0, len(mosek_vars), vals) for mosek_var, val, name in zip(mosek_vars, vals, names): pyomo_var = self._solver_var_to_pyomo_var_map[ mosek_var] if self._referenced_variables[pyomo_var] > 0: soln_variables[name]["Rc"] = val if extract_duals or extract_slacks: mosek_cons = list(range(msk_task.getnumcon())) con_names = [] for con in mosek_cons: con_names.append(msk_task.getconname(con)) for name in con_names: soln_constraints[name] = {} if extract_duals: vals = [0.0] * msk_task.getnumcon() msk_task.gety(whichsol, vals) for val, name in zip(vals, con_names): soln_constraints[name]["Dual"] = val if extract_slacks: Ax = [0] * len(mosek_cons) msk_task.getxc(self._whichsol, Ax) for con, name in zip(mosek_cons, con_names): Us = Ls = 0 bk, lb, ub = msk_task.getconbound(con) if bk in [ msk.boundkey.fx, msk.boundkey.ra, msk.boundkey.up ]: Us = ub - Ax[con] if bk in [ msk.boundkey.fx, msk.boundkey.ra, msk.boundkey.lo ]: Ls = Ax[con] - lb if Us > Ls: soln_constraints[name]["Slack"] = Us else: soln_constraints[name]["Slack"] = -Ls elif self._load_solutions: if self.results.problem.number_of_solutions > 0: self._load_vars() if extract_reduced_costs: self._load_rc() if extract_duals: self._load_duals() if extract_slacks: self._load_slacks() self.results.solution.insert(soln) # finally, clean any temporary files registered with the temp file # manager, created populated *directly* by this plugin. TempfileManager.pop(remove=not self._keepfiles) return DirectOrPersistentSolver._postsolve(self)