def available(self, exception_flag=True): if not gurobipy_available: if exception_flag: gurobipy.log_import_warning(logger=__name__) raise ApplicationError( "No Python bindings available for %s solver plugin" % (type(self), )) return False if self._verified_license is None: with capture_output(capture_fd=True) as OUT: try: # verify that we can get a Gurobi license # Gurobipy writes out license file information when creating # the environment m = gurobipy.Model() m.dispose() GurobiDirect._verified_license = True except Exception as e: GurobiDirect._import_messages += \ "\nCould not create Model - gurobi message=%s\n" % (e,) GurobiDirect._verified_license = False if OUT.getvalue(): GurobiDirect._import_messages += "\n" + OUT.getvalue() if exception_flag and not self._verified_license: logger.warning(GurobiDirect._import_messages) raise ApplicationError( "Could not create a gurobipy Model for %s solver plugin" % (type(self), )) return self._verified_license
def apply(self, *args, **kwargs): """ Run the external pico_convert utility """ if len(args) != 3: raise ConverterError("Cannot apply pico_convert with more than one filename or model") _exe = pyomo.common.Executable("pico_convert") if not _exe: raise ConverterError("The 'pico_convert' application cannot be found") pico_convert_cmd = _exe.path() target=str(args[1]) if target=="cpxlp": target="lp" # NOTE: if you have an extra "." in the suffix, the pico_convert program fails to output to the correct filename. output_filename = TempfileManager.create_tempfile(suffix = 'pico_convert.' + target) if not isinstance(args[2], str): fname= TempfileManager.create_tempfile(suffix= 'pico_convert.' +str(args[0])) args[2].write(filename=fname, format=args[1]) cmd = pico_convert_cmd +" --output="+output_filename+" "+target+" "+fname else: cmd = pico_convert_cmd +" --output="+output_filename+" "+target for item in args[2:]: if not os.path.exists(item): raise ConverterError("File "+item+" does not exist!") cmd = cmd + " "+item print("Running command: "+cmd) subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if not os.path.exists(output_filename): #pragma:nocover raise ApplicationError(\ "Problem launching 'pico_convert' to create "+output_filename) return (output_filename,),None # no variable map at the moment
def _execute_command(self,command): """ Execute the command """ start_time = time.time() try: if 'script' in command: _input = command.script else: _input = None [rc, log] = run( command.cmd, stdin = _input, timelimit = self._timelimit if self._timelimit is None else self._timelimit + max(1, 0.01*self._timelimit), env = command.env, tee = self._tee, define_signal_handlers = self._define_signal_handlers ) except OSError: err = sys.exc_info()[1] msg = 'Could not execute the command: %s\tError message: %s' raise ApplicationError(msg % (command.cmd, err)) sys.stdout.flush() self._last_solve_time = time.time() - start_time return [rc,log]
def available(self, exception_flag=True): """True if the solver is available.""" _api = getattr(self, '_python_api_exists', False) if exception_flag and not _api: raise ApplicationError( "No Python bindings available for %s solver plugin" % (type(self), )) return bool(_api)
def available(self, exception_flag=True): """True if the solver is available.""" if exception_flag and not xpress_available: xpress.log_import_warning(logger=__name__) raise ApplicationError( "No Python bindings available for %s solver plugin" % (type(self), )) return bool(xpress_available)
def available(self, exception_flag=True): """True if the solver is available.""" if exception_flag is False: return self._python_api_exists else: if self._python_api_exists is False: raise ApplicationError(("No Python bindings available for {0} solver " + "plugin").format(type(self))) else: return True
def available(self, exception_flag=False): """ True if the solver is available """ if self._assert_available: return True if not OptSolver.available(self,exception_flag): return False try: ans = self.executable() except NotImplementedError: ans = None if ans is None: if exception_flag: msg = "No executable found for solver '%s'" raise ApplicationError(msg % self.name) return False return True
def available(self, exception_flag=False): """ True if the solver is available """ if self._assert_available: return True if not pyomo.opt.solver.shellcmd.SystemCallSolver.available( self, exception_flag): return False executable = pyomo.common.Executable("ilmlist") if executable: try: cmd = [executable.path()] if sys.platform[0:3] == "win": # on windows, the ilm license manager by default # pauses after displaying the token status, so that # the window doesn't disappear and the user can # actually read it. however, if we don't suppress # this behavior, this command will stall until the # user hits Ctrl-C. cmd.append("-batch") result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) except OSError: msg = sys.exc_info()[1] raise ApplicationError( "Could not execute the command: ilmtest\n\tError message: " + msg) sys.stdout.flush() for line in result.stdout.split("\n"): tokens = re.split('[\t ]+', line.strip()) if len(tokens) == 5 and tokens[0] == 'tokens' and tokens[ 1] == 'reserved:' and tokens[4] == os.environ.get( 'USER', None): if not (tokens[2] == 'none' or tokens[2] == '0'): return True return False elif len(tokens) == 3 and tokens[0] == 'available' and tokens[ 1] == 'tokens:': if tokens[2] == '0': return False break elif len(tokens) == 6 and tokens[1] == 'server' and tokens[ 5] == 'DOWN.': return False return True
def _execute_command(self, command): """ Execute the command """ start_time = time.time() if 'script' in command: _input = command.script else: _input = None timeout = self._timelimit if timeout is not None: timeout += max(1, 0.01 * self._timelimit) ostreams = [StringIO()] if self._tee: ostreams.append(sys.stdout) try: with TeeStream(*ostreams) as t: results = subprocess.run( command.cmd, input=_input, env=command.env, stdout=t.STDOUT, stderr=t.STDERR, timeout=timeout, universal_newlines=True, ) t.STDOUT.flush() t.STDERR.flush() rc = results.returncode log = ostreams[0].getvalue() except OSError: err = sys.exc_info()[1] msg = 'Could not execute the command: %s\tError message: %s' raise ApplicationError(msg % (command.cmd, err)) sys.stdout.flush() self._last_solve_time = time.time() - start_time return [rc, log]
def apply(self, *args, **kwargs): """Convert an instance of one type into another""" if not isinstance(args[2], str): raise ConverterError("Can only apply ampl to convert file data") _exec = pyomo.common.Executable("ampl") if not _exec: raise ConverterError("The 'ampl' executable cannot be found") script_filename = TempfileManager.create_tempfile(suffix='.ampl') if args[1] == ProblemFormat.nl: output_filename = TempfileManager.create_tempfile(suffix='.nl') else: output_filename = TempfileManager.create_tempfile(suffix='.mps') cmd = [_exec.path(), script_filename] # # Create the AMPL script # OUTPUT = open(script_filename, 'w') OUTPUT.write("#\n") OUTPUT.write("# AMPL script for converting the following files\n") OUTPUT.write("#\n") if len(args[2:]) == 1: OUTPUT.write('model ' + args[2] + ";\n") else: OUTPUT.write('model ' + args[2] + ";\n") OUTPUT.write('data ' + args[3] + ";\n") abs_ofile = os.path.abspath(output_filename) if args[1] == ProblemFormat.nl: OUTPUT.write('write g' + abs_ofile[:-3] + ";\n") else: OUTPUT.write('write m' + abs_ofile[:-4] + ";\n") OUTPUT.close() # # Execute command and cleanup # output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) if not os.path.exists(output_filename): #pragma:nocover raise ApplicationError( "Problem launching 'ampl' to create '%s': %s" % (output_filename, output.stdout)) return (output_filename, ), None # empty variable map
def available(self, exception_flag=False): """ True if the solver is available """ if self._assert_available: return True if not OptSolver.available(self, exception_flag): return False try: # HACK: Suppress logged warnings about the executable not # being found cm = nullcontext() if exception_flag else LoggingIntercept() with cm: ans = self.executable() except NotImplementedError: ans = None if ans is None: if exception_flag: msg = "No executable found for solver '%s'" raise ApplicationError(msg % self.name) return False return True
def set_callback(self, name, callback_fn=None): """ Set the callback function for a named callback. A call-back function has the form: def fn(solver, model): pass where 'solver' is the native solver interface object and 'model' is a Pyomo model instance object. """ if not self._allow_callbacks: raise ApplicationError( "Callbacks disabled for solver %s" % self.name) if callback_fn is None: if name in self._callback: del self._callback[name] else: self._callback[name] = callback_fn
def solve(self, *args, **kwds): """ Solve the problem """ self.available(exception_flag=True) # # If the inputs are models, then validate that they have been # constructed! Collect suffix names to try and import from solution. # from pyomo.core.base.block import _BlockData import pyomo.core.base.suffix from pyomo.core.kernel.block import IBlock import pyomo.core.kernel.suffix _model = None for arg in args: if isinstance(arg, (_BlockData, IBlock)): if isinstance(arg, _BlockData): if not arg.is_constructed(): raise RuntimeError( "Attempting to solve model=%s with unconstructed " "component(s)" % (arg.name,) ) _model = arg # import suffixes must be on the top-level model if isinstance(arg, _BlockData): model_suffixes = list(name for (name,comp) \ in pyomo.core.base.suffix.\ active_import_suffix_generator(arg)) else: assert isinstance(arg, IBlock) model_suffixes = list(comp.storage_key for comp in pyomo.core.kernel.suffix.\ import_suffix_generator(arg, active=True, descend_into=False)) if len(model_suffixes) > 0: kwds_suffixes = kwds.setdefault('suffixes',[]) for name in model_suffixes: if name not in kwds_suffixes: kwds_suffixes.append(name) # # Handle ephemeral solvers options here. These # will override whatever is currently in the options # dictionary, but we will reset these options to # their original value at the end of this method. # orig_options = self.options self.options = Bunch() self.options.update(orig_options) self.options.update(kwds.pop('options', {})) self.options.update( self._options_string_to_dict(kwds.pop('options_string', ''))) try: # we're good to go. initial_time = time.time() self._presolve(*args, **kwds) presolve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for presolve" % (presolve_completion_time - initial_time)) if not _model is None: self._initialize_callbacks(_model) _status = self._apply_solver() if hasattr(self, '_transformation_data'): del self._transformation_data if not hasattr(_status, 'rc'): logger.warning( "Solver (%s) did not return a solver status code.\n" "This is indicative of an internal solver plugin error.\n" "Please report this to the Pyomo developers." ) elif _status.rc: logger.error( "Solver (%s) returned non-zero return code (%s)" % (self.name, _status.rc,)) if self._tee: logger.error( "See the solver log above for diagnostic information." ) elif hasattr(_status, 'log') and _status.log: logger.error("Solver log:\n" + str(_status.log)) raise ApplicationError( "Solver (%s) did not exit normally" % self.name) solve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for solver" % (solve_completion_time - presolve_completion_time)) result = self._postsolve() result._smap_id = self._smap_id result._smap = None if _model: if isinstance(_model, IBlock): if len(result.solution) == 1: result.solution(0).symbol_map = \ getattr(_model, "._symbol_maps")[result._smap_id] result.solution(0).default_variable_value = \ self._default_variable_value if self._load_solutions: _model.load_solution(result.solution(0)) else: assert len(result.solution) == 0 # see the hack in the write method # we don't want this to stick around on the model # after the solve assert len(getattr(_model, "._symbol_maps")) == 1 delattr(_model, "._symbol_maps") del result._smap_id if self._load_solutions and \ (len(result.solution) == 0): logger.error("No solution is available") else: if self._load_solutions: _model.solutions.load_from( result, select=self._select_index, default_variable_value=self._default_variable_value) result._smap_id = None result.solution.clear() else: result._smap = _model.solutions.symbol_map[self._smap_id] _model.solutions.delete_symbol_map(self._smap_id) postsolve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for postsolve" % (postsolve_completion_time - solve_completion_time)) finally: # # Reset the options dict # self.options = orig_options return result
def _process_load(cmd, _model, _data, _default, options=None): #print("LOAD %s" % cmd) from pyomo.core import Set _cmd_len = len(cmd) _options = {} _options['filename'] = cmd[1] i = 2 while cmd[i] != ':': _options[cmd[i]] = cmd[i + 2] i += 3 i += 1 _Index = (None, []) if type(cmd[i]) is tuple: _Index = (None, cmd[i]) i += 1 elif i + 1 < _cmd_len and cmd[i + 1] == '=': _Index = (cmd[i], cmd[i + 2]) i += 3 _smap = OrderedDict() while i < _cmd_len: if i + 2 < _cmd_len and cmd[i + 1] == '=': _smap[cmd[i + 2]] = cmd[i] i += 3 else: _smap[cmd[i]] = cmd[i] i += 1 if len(cmd) < 2: raise IOError("The 'load' command must specify a filename") options = Options(**_options) for key in options: if not key in [ 'range', 'filename', 'format', 'using', 'driver', 'query', 'table', 'user', 'password', 'database' ]: raise ValueError("Unknown load option '%s'" % key) global Filename Filename = options.filename global Lineno Lineno = 0 # # TODO: process mapping info # if options.using is None: tmp = options.filename.split(".")[-1] data = DataManagerFactory(tmp) if (data is None) or \ isinstance(data, UnknownDataManager): raise ApplicationError("Data manager '%s' is not available." % tmp) else: try: data = DataManagerFactory(options.using) except: data = None if (data is None) or \ isinstance(data, UnknownDataManager): raise ApplicationError("Data manager '%s' is not available." % options.using) set_name = None # # Create symbol map # symb_map = _smap if len(symb_map) == 0: raise IOError( "Must specify at least one set or parameter name that will be loaded" ) # # Process index data # _index = None index_name = _Index[0] _select = None # # Set the 'set name' based on the format # _set = None if options.format == 'set' or options.format == 'set_array': if len(_smap) != 1: raise IOError( "A single set name must be specified when using format '%s'" % options.format) set_name = list(_smap.keys())[0] _set = set_name # # Set the 'param name' based on the format # _param = None if options.format == 'transposed_array' or options.format == 'array' or options.format == 'param': if len(_smap) != 1: raise IOError( "A single parameter name must be specified when using format '%s'" % options.format) if options.format in ('transposed_array', 'array', 'param', None): if _Index[0] is None: _index = None else: _index = _Index[0] _param = [] _select = list(_Index[1]) for key in _smap: _param.append(_smap[key]) _select.append(key) if options.format in ('transposed_array', 'array'): _select = None #print "YYY", _param, options if not _param is None and len( _param) == 1 and not _model is None and isinstance( getattr(_model, _param[0]), Set): _select = None _set = _param[0] _param = None _index = None #print "SELECT", _param, _select # data.initialize(model=options.model, filename=options.filename, index=_index, index_name=index_name, param_name=symb_map, set=_set, param=_param, format=options.format, range=options.range, query=options.query, using=options.using, table=options.table, select=_select, user=options.user, password=options.password, database=options.database) # data.open() try: data.read() except Exception: data.close() raise data.close() data.process(_model, _data, _default)
def apply(self, *args, **kwargs): """Convert an instance of one type into another""" if not isinstance(args[2], str): raise ConverterError("Can only apply glpsol to convert file data") _exec = pyomo.common.Executable("glpsol") if not _exec: raise ConverterError("The 'glpsol' executable cannot be found") cmd = [_exec.path(), "--math"] # # MPS->LP conversion is ignored in coverage because it's not being # used; instead, we're using pico_convert for this conversion # modfile = '' if args[1] == ProblemFormat.mps: #pragma:nocover ofile = TempfileManager.create_tempfile(suffix='.glpsol.mps') cmd.extend([ "--check", "--name", "MPS model derived from " + os.path.basename(args[2]), "--wfreemps", ofile ]) elif args[1] == ProblemFormat.cpxlp: ofile = TempfileManager.create_tempfile(suffix='.glpsol.lp') cmd.extend([ "--check", "--name", "MPS model derived from " + os.path.basename(args[2]), "--wcpxlp", ofile ]) if len(args[2:]) == 1: cmd.append(args[2]) else: # # Create a temporary model file, since GLPSOL can only # handle one input file # modfile = TempfileManager.create_tempfile(suffix='.glpsol.mod') OUTPUT = open(modfile, "w") flag = False # # Read the model file # INPUT = open(args[2]) for line in INPUT: line = line.strip() if line == "data;": raise ConverterError( "Problem composing mathprog model and data files - mathprog file already has data in it!" ) if line != "end;": OUTPUT.write(line + '\n') INPUT.close() OUTPUT.write("data;\n") # # Read the data files # for file in args[3:]: INPUT = open(file) for line in INPUT: line = line.strip() if line != "end;" and line != "data;": OUTPUT.write(line + '\n') INPUT.close() OUTPUT.write("end;\n") OUTPUT.close() cmd.append(modfile) subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) if not os.path.exists(ofile): #pragma:nocover raise ApplicationError("Problem launching 'glpsol' to create " + ofile) if os.path.exists(modfile): os.remove(modfile) return (ofile, ), None # empty variable map
def available(self, exception_flag=True): """Determine if this optimizer is available.""" if exception_flag: raise ApplicationError("Solver (%s) not available" % str(self.name)) return False
def solve(self, *args, **kwds): """ Solve the model. Keyword Arguments ----------------- suffixes: list of str The strings should represnt suffixes support by the solver. Examples include 'dual', 'slack', and 'rc'. options: dict Dictionary of solver options. See the solver documentation for possible solver options. warmstart: bool If True, the solver will be warmstarted. keepfiles: bool If True, the solver log file will be saved. logfile: str Name to use for the solver log file. load_solutions: bool If True and a solution exists, the solution will be loaded into the Pyomo model. report_timing: bool If True, then timing information will be printed. tee: bool If True, then the solver log will be printed. """ if self._pyomo_model is None: msg = 'Please use set_instance to set the instance before calling solve with the persistent' msg += ' solver interface.' raise RuntimeError(msg) if len(args) != 0: if self._pyomo_model is not args[0]: msg = 'The problem instance provided to the solve method is not the same as the instance provided' msg += ' to the set_instance method in the persistent solver interface. ' raise ValueError(msg) self.available(exception_flag=True) # Collect suffix names to try and import from solution. if isinstance(self._pyomo_model, _BlockData): model_suffixes = list(name for ( name, comp) in active_import_suffix_generator(self._pyomo_model)) else: assert isinstance(self._pyomo_model, IBlock) model_suffixes = list( comp.storage_key for comp in import_suffix_generator( self._pyomo_model, active=True, descend_into=False)) if len(model_suffixes) > 0: kwds_suffixes = kwds.setdefault('suffixes', []) for name in model_suffixes: if name not in kwds_suffixes: kwds_suffixes.append(name) # # Handle ephemeral solvers options here. These # will override whatever is currently in the options # dictionary, but we will reset these options to # their original value at the end of this method. # orig_options = self.options self.options = Options() self.options.update(orig_options) self.options.update(kwds.pop('options', {})) self.options.update( self._options_string_to_dict(kwds.pop('options_string', ''))) try: # we're good to go. initial_time = time.time() self._presolve(**kwds) presolve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for presolve" % (presolve_completion_time - initial_time)) if self._pyomo_model is not None: self._initialize_callbacks(self._pyomo_model) _status = self._apply_solver() if hasattr(self, '_transformation_data'): del self._transformation_data if not hasattr(_status, 'rc'): logger.warning( "Solver (%s) did not return a solver status code.\n" "This is indicative of an internal solver plugin error.\n" "Please report this to the Pyomo developers.") elif _status.rc: logger.error("Solver (%s) returned non-zero return code (%s)" % ( self.name, _status.rc, )) if self._tee: logger.error( "See the solver log above for diagnostic information.") elif hasattr(_status, 'log') and _status.log: logger.error("Solver log:\n" + str(_status.log)) raise ApplicationError("Solver (%s) did not exit normally" % self.name) solve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for solver" % (solve_completion_time - presolve_completion_time)) result = self._postsolve() # *********************************************************** # The following code is only needed for backwards compatability of load_solutions=False. # If we ever only want to support the load_vars, load_duals, etc. methods, then this can be deleted. if self._save_results: result._smap_id = self._smap_id result._smap = None _model = self._pyomo_model if _model: if isinstance(_model, IBlock): if len(result.solution) == 1: result.solution(0).symbol_map = \ getattr(_model, "._symbol_maps")[result._smap_id] result.solution(0).default_variable_value = \ self._default_variable_value if self._load_solutions: _model.load_solution(result.solution(0)) else: assert len(result.solution) == 0 # see the hack in the write method # we don't want this to stick around on the model # after the solve assert len(getattr(_model, "._symbol_maps")) == 1 delattr(_model, "._symbol_maps") del result._smap_id if self._load_solutions and \ (len(result.solution) == 0): logger.error("No solution is available") else: if self._load_solutions: _model.solutions.load_from( result, select=self._select_index, default_variable_value=self. _default_variable_value) result._smap_id = None result.solution.clear() else: result._smap = _model.solutions.symbol_map[ self._smap_id] _model.solutions.delete_symbol_map(self._smap_id) # ******************************************************** postsolve_completion_time = time.time() if self._report_timing: print(" %6.2f seconds required for postsolve" % (postsolve_completion_time - solve_completion_time)) finally: # # Reset the options dict # self.options = orig_options return result
def available(self, exception_flag=True): ans = super(LegacySolverInterface, self).available() if exception_flag and not ans: raise ApplicationError(f'Solver {self.__class__} is not available ({ans}).') return bool(ans)