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 = pyutilib.misc.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 pyutilib.common.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 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. # _model = None for arg in args: if isinstance(arg, (_BlockData, IBlockStorage)): 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 active_import_suffix_generator(arg)) else: assert isinstance(arg, IBlockStorage) model_suffixes = list(name for ( name, comp ) in import_suffix_generator( arg, active=True, descend_into=False, return_key=True)) 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 = pyutilib.misc.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(*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 pyutilib.common.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 if _model: if isinstance(_model, IBlockStorage): 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 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 from pyomo.core.base.suffix import active_import_suffix_generator _model = None for arg in args: if isinstance(arg, _BlockData): if not arg.is_constructed(): raise RuntimeError( "Attempting to solve model=%s with unconstructed " "component(s)" % (arg.name, )) _model = arg model_suffixes = list(name for (name,comp) \ in active_import_suffix_generator(arg)) 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 = pyutilib.misc.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(*args, **kwds) presolve_completion_time = time.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 pyutilib.common.ApplicationError( "Solver (%s) did not exit normally" % self.name) solve_completion_time = time.time() result = self._postsolve() result._smap_id = self._smap_id result._smap = None if _model: 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("Presolve time=%0.2f seconds" % (presolve_completion_time - initial_time)) print("Solve time=%0.2f seconds" % (solve_completion_time - presolve_completion_time)) print("Postsolve time=%0.2f seconds" % (postsolve_completion_time - solve_completion_time)) finally: # # Reset the options dict # self.options = orig_options return result
def select(self, index=0, allow_consistent_values_for_fixed_vars=False, comparison_tolerance_for_fixed_vars=1e-5, ignore_invalid_labels=False, ignore_fixed_vars=True): """ Select a solution from the model's solutions. allow_consistent_values_for_fixed_vars: a flag that indicates whether a solution can specify consistent values for variables in the model that are fixed. ignore_invalid_labels: a flag that indicates whether labels in the solution that don't appear in the model yield an error. This allows for loading a results object generated from one model into another related, but not identical, model. """ instance = self._instance() # # Set the "stale" flag of each variable in the model prior to loading the # solution, so you known which variables have "real" values and which ones don't. # instance._flag_vars_as_stale() if not index is None: self.index = index soln = self.solutions[self.index] # # Generate the list of active import suffixes on this top level model # valid_import_suffixes = dict(active_import_suffix_generator(instance)) # # To ensure that import suffix data gets properly overwritten (e.g., # the case where nonzero dual values exist on the suffix and but only # sparse dual values exist in the results object) we clear all active # import suffixes. # for suffix in itervalues(valid_import_suffixes): suffix.clear_all_values() # # Load problem (model) level suffixes. These would only come from ampl # interfaced solution suffixes at this point in time. # for id_, (pobj,entry) in iteritems(soln._entry['problem']): for _attr_key, attr_value in iteritems(entry): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][pobj] = attr_value # # Load objective data (suffixes) # for id_, (odata, entry) in iteritems(soln._entry['objective']): odata = odata() for _attr_key, attr_value in iteritems(entry): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][odata] = attr_value # # Load variable data (suffixes and values) # for id_, (vdata, entry) in iteritems(soln._entry['variable']): vdata = vdata() val = entry['Value'] if vdata.fixed is True: if ignore_fixed_vars: continue if not allow_consistent_values_for_fixed_vars: msg = "Variable '%s' in model '%s' is currently fixed - new" \ ' value is not expected in solution' raise TypeError(msg % (vdata.name, instance.name)) if math.fabs(val - vdata.value) > comparison_tolerance_for_fixed_vars: raise TypeError("Variable '%s' in model '%s' is currently " "fixed - a value of '%s' in solution is " "not within tolerance=%s of the current " "value of '%s'" % (vdata.name, instance.name, str(val), str(comparison_tolerance_for_fixed_vars), str(vdata.value))) vdata.value = val vdata.stale = False for _attr_key, attr_value in iteritems(entry): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key == 'value': continue elif attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][vdata] = attr_value # # Load constraint data (suffixes) # for id_, (cdata, entry) in iteritems(soln._entry['constraint']): cdata = cdata() for _attr_key, attr_value in iteritems(entry): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][cdata] = attr_value
def select(self, index=0, allow_consistent_values_for_fixed_vars=False, comparison_tolerance_for_fixed_vars=1e-5, ignore_invalid_labels=False, ignore_fixed_vars=True): """ Select a solution from the model's solutions. allow_consistent_values_for_fixed_vars: a flag that indicates whether a solution can specify consistent values for variables in the model that are fixed. ignore_invalid_labels: a flag that indicates whether labels in the solution that don't appear in the model yield an error. This allows for loading a results object generated from one model into another related, but not identical, model. """ instance = self._instance() # # Set the "stale" flag of each variable in the model prior to loading the # solution, so you known which variables have "real" values and which ones don't. # instance._flag_vars_as_stale() if not index is None: self.index = index soln = self.solutions[self.index] # # Generate the list of active import suffixes on this top level model # valid_import_suffixes = dict(active_import_suffix_generator(instance)) # # To ensure that import suffix data gets properly overwritten (e.g., # the case where nonzero dual values exist on the suffix and but only # sparse dual values exist in the results object) we clear all active # import suffixes. # for suffix in valid_import_suffixes.values(): suffix.clear_all_values() # # Load problem (model) level suffixes. These would only come from ampl # interfaced solution suffixes at this point in time. # for id_, (pobj, entry) in soln._entry['problem'].items(): for _attr_key, attr_value in entry.items(): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][pobj] = attr_value # # Load objective data (suffixes) # for id_, (odata, entry) in soln._entry['objective'].items(): odata = odata() for _attr_key, attr_value in entry.items(): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][odata] = attr_value # # Load variable data (suffixes and values) # for id_, (vdata, entry) in soln._entry['variable'].items(): vdata = vdata() val = entry['Value'] if vdata.fixed is True: if ignore_fixed_vars: continue if not allow_consistent_values_for_fixed_vars: msg = "Variable '%s' in model '%s' is currently fixed - new" \ ' value is not expected in solution' raise TypeError(msg % (vdata.name, instance.name)) if math.fabs(val - vdata.value ) > comparison_tolerance_for_fixed_vars: raise TypeError("Variable '%s' in model '%s' is currently " "fixed - a value of '%s' in solution is " "not within tolerance=%s of the current " "value of '%s'" % (vdata.name, instance.name, str(val), str(comparison_tolerance_for_fixed_vars), str(vdata.value))) vdata.value = val vdata.stale = False for _attr_key, attr_value in entry.items(): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key == 'value': continue elif attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][vdata] = attr_value # # Load constraint data (suffixes) # for id_, (cdata, entry) in soln._entry['constraint'].items(): cdata = cdata() for _attr_key, attr_value in entry.items(): attr_key = _attr_key[0].lower() + _attr_key[1:] if attr_key in valid_import_suffixes: valid_import_suffixes[attr_key][cdata] = attr_value
def _get_task_data(self, ah, *args, **kwds): opt = kwds.pop('solver', kwds.pop('opt', None)) if opt is None: raise ActionManagerError( "No solver passed to %s, use keyword option 'solver'" % (type(self).__name__)) deactivate_opt = False if isinstance(opt, six.string_types): deactivate_opt = True opt = SolverFactory(opt, solver_io=kwds.pop('solver_io', None)) # # The following block of code is taken from the OptSolver.solve() # method, which we do not directly invoke with this interface # # # If the inputs are models, then validate that they have been # constructed! Collect suffix names to try and import from solution. # for arg in args: if isinstance(arg, Block): if not arg.is_constructed(): raise RuntimeError( "Attempting to solve model=%s with unconstructed " "component(s)" % (arg.name, )) model_suffixes = list(name for (name,comp) \ in active_import_suffix_generator(arg)) 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. # ephemeral_solver_options = {} ephemeral_solver_options.update(kwds.pop('options', {})) ephemeral_solver_options.update( OptSolver._options_string_to_dict(kwds.pop('options_string', ''))) # # Force pyomo.opt to ignore tests for availability, at least locally. # del_available = bool('available' not in kwds) kwds['available'] = True opt._presolve(*args, **kwds) problem_file_string = None with open(opt._problem_files[0], 'r') as f: problem_file_string = f.read() # # Delete this option, to ensure that the remote worker does the check for # availability. # if del_available: del kwds['available'] # # We can't pickle the options object itself - so extract a simple # dictionary of solver options and re-construct it on the other end. # solver_options = {} for key in opt.options: solver_options[key] = opt.options[key] solver_options.update(ephemeral_solver_options) # # NOTE: let the distributed node deal with the warm-start # pick up the warm-start file, if available. # warm_start_file_string = None warm_start_file_name = None if hasattr(opt, "_warm_start_solve"): if opt._warm_start_solve and \ (opt._warm_start_file_name is not None): warm_start_file_name = opt._warm_start_file_name with open(warm_start_file_name, 'r') as f: warm_start_file_string = f.read() data = pyutilib.misc.Bunch(opt=opt.type, \ file=problem_file_string, \ filename=opt._problem_files[0], \ warmstart_file=warm_start_file_string, \ warmstart_filename=warm_start_file_name, \ kwds=kwds, \ solver_options=solver_options, \ suffixes=opt._suffixes) self._args[ah.id] = args self._opt_data[ah.id] = (opt._smap_id, opt._load_solutions, opt._select_index, opt._default_variable_value) if deactivate_opt: opt.deactivate() return data
def _get_task_data(self, ah, *args, **kwds): opt = kwds.pop('solver', kwds.pop('opt', None)) if opt is None: raise ActionManagerError( "No solver passed to %s, use keyword option 'solver'" % (type(self).__name__) ) deactivate_opt = False if isinstance(opt, six.string_types): deactivate_opt = True opt = SolverFactory(opt, solver_io=kwds.pop('solver_io', None)) # # The following block of code is taken from the OptSolver.solve() # method, which we do not directly invoke with this interface # # # If the inputs are models, then validate that they have been # constructed! Collect suffix names to try and import from solution. # for arg in args: if isinstance(arg, Block): if not arg.is_constructed(): raise RuntimeError( "Attempting to solve model=%s with unconstructed " "component(s)" % (arg.name,) ) model_suffixes = list(name for (name,comp) \ in active_import_suffix_generator(arg)) 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. # ephemeral_solver_options = {} ephemeral_solver_options.update(kwds.pop('options', {})) ephemeral_solver_options.update( OptSolver._options_string_to_dict(kwds.pop('options_string', ''))) # # Force pyomo.opt to ignore tests for availability, at least locally. # del_available = bool('available' not in kwds) kwds['available'] = True opt._presolve(*args, **kwds) problem_file_string = None with open(opt._problem_files[0], 'r') as f: problem_file_string = f.read() # # Delete this option, to ensure that the remote worker does the check for # availability. # if del_available: del kwds['available'] # # We can't pickle the options object itself - so extract a simple # dictionary of solver options and re-construct it on the other end. # solver_options = {} for key in opt.options: solver_options[key]=opt.options[key] solver_options.update(ephemeral_solver_options) # # NOTE: let the distributed node deal with the warm-start # pick up the warm-start file, if available. # warm_start_file_string = None warm_start_file_name = None if hasattr(opt, "_warm_start_solve"): if opt._warm_start_solve and \ (opt._warm_start_file_name is not None): warm_start_file_name = opt._warm_start_file_name with open(warm_start_file_name, 'r') as f: warm_start_file_string = f.read() data = pyutilib.misc.Bunch(opt=opt.type, \ file=problem_file_string, \ filename=opt._problem_files[0], \ warmstart_file=warm_start_file_string, \ warmstart_filename=warm_start_file_name, \ kwds=kwds, \ solver_options=solver_options, \ suffixes=opt._suffixes) self._args[ah.id] = args self._opt_data[ah.id] = (opt._smap_id, opt._load_solutions, opt._select_index, opt._default_variable_value) if deactivate_opt: opt.deactivate() return data
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 import Block from pyomo.core.base.suffix import active_import_suffix_generator _model = None for arg in args: if isinstance(arg, Block): if not arg.is_constructed(): raise RuntimeError( "Attempting to solve model=%s with unconstructed " "component(s)" % (arg.name,) ) _model = arg model_suffixes = list(name for (name,comp) \ in active_import_suffix_generator(arg)) 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. # tmp_solver_options = kwds.pop('options', {}) tmp_solver_options.update( self._options_string_to_dict(kwds.pop('options_string', ''))) options_to_reset = {} options_to_delete = [] if tmp_solver_options is not None: for key in tmp_solver_options: if key in self.options: options_to_reset[key] = self.options[key] else: options_to_delete.append(key) # only modify the options dict after the above loop # completes, so that we only detect the original state for key in tmp_solver_options: self.options[key] = tmp_solver_options[key] try: # we're good to go. initial_time = time.time() self._presolve(*args, **kwds) presolve_completion_time = time.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 pyutilib.common.ApplicationError( "Solver (%s) did not exit normally" % self.name) solve_completion_time = time.time() result = self._postsolve() result._smap_id = self._smap_id result._smap = None if _model: 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("Presolve time=%0.2f seconds" % (presolve_completion_time - initial_time)) print("Solve time=%0.2f seconds" % (solve_completion_time - presolve_completion_time)) print("Postsolve time=%0.2f seconds" % (postsolve_completion_time - solve_completion_time)) finally: # # Reset the options dict (remove any ephemeral solver options # passed into this method) # for key in options_to_reset: self.options[key] = options_to_reset[key] for key in options_to_delete: if key in self.options: del self.options[key] return result
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. # _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 active_import_suffix_generator(arg)) else: assert isinstance(arg, IBlock) model_suffixes = list(comp.storage_key for comp in 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 = pyutilib.misc.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(*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 pyutilib.common.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 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 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 = pyutilib.misc.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 pyutilib.common.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