def _apply_solver(self, timer: HierarchicalTimer): config = self.config if config.time_limit is not None: timeout = config.time_limit + min(max(1, 0.01 * config.time_limit), 100) else: timeout = None ostreams = [LogStream(level=self.config.log_level, logger=self.config.solver_output_logger)] if self.config.stream_solver: ostreams.append(sys.stdout) cmd = [str(config.executable), self._filename + '.nl', '-AMPL', 'option_file_name=' + self._filename + '.opt'] if 'option_file_name' in self.solver_options: raise ValueError('Use Ipopt.config.filename to specify the name of the options file. ' 'Do not use Ipopt.solver_options["option_file_name"].') for k, v in self.solver_options.items(): cmd.append(str(k) + '=' + str(v)) with TeeStream(*ostreams) as t: timer.start('subprocess') cp = subprocess.run(cmd, timeout=timeout, stdout=t.STDOUT, stderr=t.STDERR, universal_newlines=True) timer.stop('subprocess') if cp.returncode != 0: if self.config.load_solution: raise RuntimeError('A feasible solution was not found, so no solution can be loaded.' 'Please set opt.config.load_solution=False and check ' 'results.termination_condition and ' 'results.best_feasible_objective before loading a solution.') results = Results() results.termination_condition = TerminationCondition.error results.best_feasible_objective = None self._primal_sol = None self._dual_sol = None else: timer.start('parse solution') results = self._parse_sol() timer.stop('parse solution') if self._writer.get_active_objective() is None: results.best_objective_bound = None else: if self._writer.get_active_objective().sense == minimize: results.best_objective_bound = -math.inf else: results.best_objective_bound = math.inf return results
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 solve(self, model, **kwds): config = self.config(kwds, preserve_implicit=True) if not isinstance(model, Block): raise ValueError("PyomoCyIpoptSolver.solve(model): model " "must be a Pyomo Block") # If this is a Pyomo model / block, then we need to create # the appropriate PyomoNLP, then wrap it in a CyIpoptNLP grey_box_blocks = list(model.component_data_objects( egb.ExternalGreyBoxBlock, active=True)) if grey_box_blocks: # nlp = pyomo_nlp.PyomoGreyBoxNLP(model) nlp = pyomo_grey_box.PyomoNLPWithGreyBoxBlocks(model) else: nlp = pyomo_nlp.PyomoNLP(model) problem = CyIpoptNLP(nlp, intermediate_callback=config.intermediate_callback) xl = problem.x_lb() xu = problem.x_ub() gl = problem.g_lb() gu = problem.g_ub() nx = len(xl) ng = len(gl) cyipopt_solver = cyipopt.Problem( n=nx, m=ng, problem_obj=problem, lb=xl, ub=xu, cl=gl, cu=gu ) # check if we need scaling obj_scaling, x_scaling, g_scaling = problem.scaling_factors() if any(_ is not None for _ in (obj_scaling, x_scaling, g_scaling)): # need to set scaling factors if obj_scaling is None: obj_scaling = 1.0 if x_scaling is None: x_scaling = np.ones(nx) if g_scaling is None: g_scaling = np.ones(ng) try: set_scaling = cyipopt_solver.set_problem_scaling except AttributeError: # Fall back to pre-1.0.0 API set_scaling = cyipopt_solver.setProblemScaling set_scaling(obj_scaling, x_scaling, g_scaling) # add options try: add_option = cyipopt_solver.add_option except AttributeError: # Fall back to pre-1.0.0 API add_option = cyipopt_solver.addOption for k, v in config.options.items(): add_option(k, v) timer = TicTocTimer() try: # We preemptively set up the TeeStream, even if we aren't # going to use it: the implementation is such that the # context manager does nothing (i.e., doesn't start up any # processing threads) until afer a client accesses # STDOUT/STDERR with TeeStream(sys.stdout) as _teeStream: if config.tee: try: fd = sys.stdout.fileno() except (io.UnsupportedOperation, AttributeError): # If sys,stdout doesn't have a valid fileno, # then create one using the TeeStream fd = _teeStream.STDOUT.fileno() else: fd = None with redirect_fd(fd=1, output=fd, synchronize=False): x, info = cyipopt_solver.solve(problem.x_init()) solverStatus = SolverStatus.ok except: msg = "Exception encountered during cyipopt solve:" logger.error(msg, exc_info=sys.exc_info()) solverStatus = SolverStatus.unknown raise wall_time = timer.toc(None) results = SolverResults() if config.load_solutions: nlp.set_primals(x) nlp.set_duals(info['mult_g']) nlp.load_state_into_pyomo( bound_multipliers=(info['mult_x_L'], info['mult_x_U'])) else: soln = results.solution.add() soln.variable.update( (i, {'Value':j, 'ipopt_zL_out': zl, 'ipopt_zU_out': zu}) for i,j,zl,zu in zip( nlp.variable_names(), x, info['mult_x_L'], info['mult_x_U'] ) ) soln.constraint.update( (i, {'Dual':j}) for i,j in zip( nlp.constraint_names(), info['mult_g'])) results.problem.name = model.name obj = next(model.component_data_objects(Objective, active=True)) if obj.sense == minimize: results.problem.sense = ProblemSense.minimize results.problem.upper_bound = info['obj_val'] else: results.problem.sense = ProblemSense.maximize results.problem.lower_bound = info['obj_val'] results.problem.number_of_objectives = 1 results.problem.number_of_constraints = ng results.problem.number_of_variables = nx results.problem.number_of_binary_variables = 0 results.problem.number_of_integer_variables = 0 results.problem.number_of_continuous_variables = nx # TODO: results.problem.number_of_nonzeros results.solver.name = 'cyipopt' results.solver.return_code = info['status'] results.solver.message = info['status_msg'] results.solver.wallclock_time = wall_time status_enum = _cyipopt_status_enum[info['status_msg']] results.solver.termination_condition = _ipopt_term_cond[status_enum] results.solver.status = TerminationCondition.to_solver_status( results.solver.termination_condition) if config.return_nlp: return results, nlp return results
def solve(self, x0=None, tee=False): xl = self._problem.x_lb() xu = self._problem.x_ub() gl = self._problem.g_lb() gu = self._problem.g_ub() if x0 is None: x0 = self._problem.x_init() xstart = x0 nx = len(xstart) ng = len(gl) cyipopt_solver = cyipopt.Problem( n=nx, m=ng, problem_obj=self._problem, lb=xl, ub=xu, cl=gl, cu=gu ) # check if we need scaling obj_scaling, x_scaling, g_scaling = self._problem.scaling_factors() if any(_ is not None for _ in (obj_scaling, x_scaling, g_scaling)): # need to set scaling factors if obj_scaling is None: obj_scaling = 1.0 if x_scaling is None: x_scaling = np.ones(nx) if g_scaling is None: g_scaling = np.ones(ng) try: set_scaling = cyipopt_solver.set_problem_scaling except AttributeError: # Fall back to pre-1.0.0 API set_scaling = cyipopt_solver.setProblemScaling set_scaling(obj_scaling, x_scaling, g_scaling) # add options try: add_option = cyipopt_solver.add_option except AttributeError: # Fall back to pre-1.0.0 API add_option = cyipopt_solver.addOption for k, v in self._options.items(): add_option(k, v) # We preemptively set up the TeeStream, even if we aren't # going to use it: the implementation is such that the # context manager does nothing (i.e., doesn't start up any # processing threads) until afer a client accesses # STDOUT/STDERR with TeeStream(sys.stdout) as _teeStream: if tee: try: fd = sys.stdout.fileno() except (io.UnsupportedOperation, AttributeError): # If sys,stdout doesn't have a valid fileno, # then create one using the TeeStream fd = _teeStream.STDOUT.fileno() else: fd = None with redirect_fd(fd=1, output=fd, synchronize=False): x, info = cyipopt_solver.solve(xstart) return x, info
def _apply_solver(self, timer: HierarchicalTimer): config = self.config if config.time_limit is not None: timeout = config.time_limit + min(max(1, 0.01 * config.time_limit), 100) else: timeout = None def _check_and_escape_options(): for key, val in self.solver_options.items(): 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 cmd = [str(config.executable)] action_options = list() if config.time_limit is not None: cmd.extend(['-sec', str(config.time_limit)]) cmd.extend(['-timeMode', 'elapsed']) for key, val in _check_and_escape_options(): if val.strip() != '': cmd.append('-'+key, val) else: action_options.append('-'+key) cmd.extend(['-printingOptions', 'all']) cmd.extend(['-import', self._filename + '.lp']) cmd.extend(action_options) cmd.extend(['-stat=1']) cmd.extend(['-solve']) cmd.extend(['-solu', self._filename + '.soln']) ostreams = [LogStream(level=self.config.log_level, logger=self.config.solver_output_logger)] if self.config.stream_solver: ostreams.append(sys.stdout) with TeeStream(*ostreams) as t: timer.start('subprocess') cp = subprocess.run(cmd, timeout=timeout, stdout=t.STDOUT, stderr=t.STDERR, universal_newlines=True) timer.stop('subprocess') if cp.returncode != 0: if self.config.load_solution: raise RuntimeError('A feasible solution was not found, so no solution can be loaded.' 'Please set opt.config.load_solution=False and check ' 'results.termination_condition and ' 'results.best_feasible_objective before loading a solution.') results = Results() results.termination_condition = TerminationCondition.error results.best_feasible_objective = None self._primal_sol = None self._dual_sol = None self._reduced_costs = None else: timer.start('parse solution') results = self._parse_soln() timer.stop('parse solution') if self._writer.get_active_objective() is None: results.best_feasible_objective = None results.best_objective_bound = None else: if self._writer.get_active_objective().sense == minimize: results.best_objective_bound = -math.inf else: results.best_objective_bound = math.inf return results
def _call_alamo(self): """ Method to call ALAMO executable from Python, passing the current .alm file as an argument. Args: None Returns: ALAMO: return code log: string of the text output from ALAMO """ if alamo.executable is None: raise FileNotFoundError( "Could not find ALAMO executable. Please ensure that ALAMO " "is installed and in the system path, or provide a path to " "the executable.") ostreams = [StringIO(), sys.stdout] if self._temp_context is None: self._get_files() # Set working directory cwd = os.getcwd() os.chdir(self._wrkdir) try: # Add lst file to temp file manager lstfname = os.path.splitext( os.path.basename(self._almfile))[0] + ".lst" lstpath = os.path.join(cwd, lstfname) self._temp_context.add_tempfile(lstpath, exists=False) with TeeStream(*ostreams) as t: results = subprocess.run( [alamo.executable, str(self._almfile)], stdout=t.STDOUT, stderr=t.STDERR, universal_newlines=True, ) t.STDOUT.flush() t.STDERR.flush() return_code = results.returncode alamo_log = ostreams[0].getvalue() except OSError: _log.error( f'Could not execute the command: alamo {str(self._almfile)}. ', f'Error message: {sys.exc_info()[1]}.') raise finally: # Revert cwd to where it started os.chdir(cwd) if "ALAMO terminated with termination code " in alamo_log: self._remove_temp_files() _log.warn("ALAMO executable returned non-zero return code. Check " "the ALAMO output for more information.") return return_code, alamo_log