def minimize_ipopt(fun, x0, args=(), kwargs=None, method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None): """ Minimize a function using ipopt. The call signature is exactly like for `scipy.optimize.mimize`. In options, all options are directly passed to ipopt. Check [http://www.coin-or.org/Ipopt/documentation/node39.html] for details. The options `disp` and `maxiter` are automatically mapped to their ipopt-equivalents `print_level` and `max_iter`. """ _x0 = np.atleast_1d(x0) problem = IpoptProblemWrapper(fun, args=args, kwargs=kwargs, jac=jac, hess=hess, hessp=hessp, constraints=constraints) lb, ub = get_bounds(bounds) cl, cu = get_constraint_bounds(constraints, x0) if options is None: options = {} nlp = cyipopt.problem(n = len(_x0), m = len(cl), problem_obj=problem, lb=lb, ub=ub, cl=cl, cu=cu) # Rename some default scipy options replace_option(options, 'disp', 'print_level') replace_option(options, 'maxiter', 'max_iter') if 'print_level' not in options: options['print_level'] = 0 if 'tol' not in options: options['tol'] = tol or 1e-8 if 'mu_strategy' not in options: options['mu_strategy'] = 'adaptive' if 'hessian_approximation' not in options: if hess is None and hessp is None: options['hessian_approximation'] = 'limited-memory' for option, value in options.items(): try: nlp.addOption(option, value) except TypeError as e: raise TypeError('Invalid option for IPOPT: {0}: {1} (Original message: "{2}")'.format(option, value, e)) x, info = nlp.solve(_x0) if np.asarray(x0).shape == (): x = x[0] return OptimizeResult(x=x, success=info['status'] == 0, status=info['status'], message=info['status_msg'], fun=info['obj_val'], info=info, nfev=problem.nfev, njev=problem.njev, nit=problem.nit)
def test_non_pep8_class_name_deprecation(hs071_defintion_instance_fixture, hs071_initial_guess_fixture, hs071_variable_lower_bounds_fixture, hs071_variable_upper_bounds_fixture, hs071_constraint_lower_bounds_fixture, hs071_constraint_upper_bounds_fixture, ): """Ensure use of old non-PEP8 classes API raises FutureWarning to user.""" expected_warning_msg = ("The class named 'problem' will soon be " "deprecated in CyIpopt. Please replace all uses " "and use 'Problem' going forward.") with pytest.warns(FutureWarning, match=expected_warning_msg): _ = cyipopt.problem(n=len(hs071_initial_guess_fixture), m=len(hs071_constraint_lower_bounds_fixture), problem_obj=hs071_defintion_instance_fixture, lb=hs071_variable_lower_bounds_fixture, ub=hs071_variable_upper_bounds_fixture, cl=hs071_constraint_lower_bounds_fixture, cu=hs071_constraint_upper_bounds_fixture, )
def fit(self, loss='exponential', w0=None, verbose=0): t0 = time.time() if loss not in ['exponential', 'squared_hinge']: raise ValueError( "'loss' should be either 'exponential' or 'squared_hinge'") N, U, D = self.N, self.U, self.D if verbose > 0: print('\nC: {:g}, {:g}, {:g}'.format(self.C1, self.C2, self.C3)) num_vars = (U + N + 1) * D + N num_cons = int(self.Y.sum()) if w0 is None: w0 = self._init_vars() if w0.shape != (num_vars, ): raise ValueError('ERROR: incorrect dimention for initial weights.') # solve using IPOPT problem = RankPrimal(X=self.X, Y=self.Y, C1=self.C1, C2=self.C2, C3=self.C3, cliques=self.cliques, data_helper=self.data_helper, loss=loss, verbose=verbose) if verbose > 0: print('[IPOPT] {:,d} variables, {:,d} constraints.'.format( num_vars, num_cons)) problem.compute_constraint_info() nlp = cyipopt.problem( problem_obj=problem, # problem instance n=num_vars, # number of variables m=num_cons, # number of constraints lb=None, # lower bounds on variables ub=None, # upper bounds on variables cl=np.zeros(num_cons), # lower bounds on constraints cu=None # upper bounds on constraints ) # ROOT_URL = www.coin-or.org/Ipopt/documentation # set solver options: $ROOT_URL/node40.html # nlp.addOption(b'max_iter', int(1e3)) # nlp.addOption(b'mu_strategy', b'adaptive') # nlp.addOption(b'tol', 1e-7) # nlp.addOption(b'acceptable_tol', 1e-5) # nlp.addOption(b'acceptable_constr_viol_tol', 1e-6) # linear solver for the augmented linear system: $ROOT_URL/node51.html, www.hsl.rl.ac.uk/ipopt/ # nlp.addOption(b'linear_solver', b'ma27') # default # nlp.addOption(b'linear_solver', b'ma57') # small/medium problem nlp.addOption(b'linear_solver', b'ma86') # large problem # gradient checking for objective and constraints: $ROOT_URL/node30.html # nlp.addOption(b'derivative_test', b'first-order') # nlp.addOption(b'derivative_test_print_all', b'yes') nlp.addOption(b'print_level', 1) w, info = nlp.solve(w0) # print(info['status'], info['status_msg']) print('\n[IPOPT] %s\n' % info['status_msg'].decode('utf-8')) self.V = w[:U * D].reshape(U, D) self.W = w[U * D:(U + N) * D].reshape(N, D) self.mu = w[(U + N) * D:(U + N + 1) * D] self.xi = w[(U + N + 1) * D:] self.pl2u = problem.pl2u self.trained = True self.status = info['status'] self.status_msg = info['status_msg'] if verbose > 0: print('Training finished in %.1f seconds' % (time.time() - t0))
def minimize_ipopt(fun, x0, args=(), kwargs=None, method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None): """ Minimize a function using ipopt. The call signature is exactly like for `scipy.optimize.mimize`. In options, all options are directly passed to ipopt. Check [http://www.coin-or.org/Ipopt/documentation/node39.html] for details. The options `disp` and `maxiter` are automatically mapped to their ipopt-equivalents `print_level` and `max_iter`. """ if not SCIPY_INSTALLED: raise ImportError( 'Install SciPy to use the `minimize_ipopt` function.') _x0 = np.atleast_1d(x0) problem = IpoptProblemWrapper(fun, args=args, kwargs=kwargs, jac=jac, hess=hess, hessp=hessp, constraints=constraints) lb, ub = get_bounds(bounds) cl, cu = get_constraint_bounds(constraints, x0) if options is None: options = {} nlp = cyipopt.problem(n=len(_x0), m=len(cl), problem_obj=problem, lb=lb, ub=ub, cl=cl, cu=cu) # python3 compatibility convert_to_bytes(options) # Rename some default scipy options replace_option(options, b'disp', b'print_level') replace_option(options, b'maxiter', b'max_iter') if b'print_level' not in options: options[b'print_level'] = 0 if b'tol' not in options: options[b'tol'] = tol or 1e-8 if b'mu_strategy' not in options: options[b'mu_strategy'] = b'adaptive' if b'hessian_approximation' not in options: if hess is None and hessp is None: options[b'hessian_approximation'] = b'limited-memory' for option, value in options.items(): try: nlp.addOption(option, value) except TypeError as e: raise TypeError( 'Invalid option for IPOPT: {0}: {1} (Original message: "{2}")'. format(option, value, e)) x, info = nlp.solve(_x0) if np.asarray(x0).shape == (): x = x[0] return OptimizeResult(x=x, success=info['status'] == 0, status=info['status'], message=info['status_msg'], fun=info['obj_val'], info=info, nfev=problem.nfev, njev=problem.njev, nit=problem.nit)
def fit(self, loss='exponential', regu='l2', max_iter=1e3, use_all_constraints=False, w0=None, fnpy=None): assert loss in ['exponential', 'squared_hinge'] assert regu in ['l1', 'l2'] M, N, U, D = self.M, self.N, self.U, self.D verbose = self.verbose if verbose > 0: t0 = time.time() print('\nC: %g' % self.C) num_vars = (U + N + 1) * D + N max_num_cons = M * N - self.Y.sum() if w0 is None: if fnpy is None: w0 = self._init_vars() else: try: assert type(fnpy) == str assert fnpy.endswith('.npy') w0 = np.load(fnpy, allow_pickle=False) print('Restore from %s' % fnpy) except (IOError, ValueError): w0 = self._init_vars() assert w0.shape == (num_vars, ) # solve using IPOPT and cutting-plane method # first create an optimisation problem and solve it, # then add constraints violated by current solution, # create a new optimisation problem (same objective, update constraints) # keep doing this until termination criteria satisfied. w = w0 cp_iter = 0 current_constraints = None print( '[CUTTING-PLANE] %d variables, %d maximum possible constraints.' % (num_vars, max_num_cons)) while cp_iter < max_iter: cp_iter += 1 problem = RankPrimal(X=self.X, Y=self.Y, C=self.C, cliques=self.cliques, data_helper=self.data_helper, loss=loss, regu=regu, verbose=verbose) if use_all_constraints is True: problem.generate_all_constraints() print('[CUTTING-PLANE] All constraints will be used.') if current_constraints is not None: problem.add_constraints( current_constraints) # restore constraints num_cons = problem.get_num_constraints() if num_cons > 0: problem.compute_constraint_info() else: problem.jacobian = None problem.jacobianstructure = None print('[CUTTING-PLANE] Iter %d: %d constraints.' % (cp_iter, num_cons)) nlp = cyipopt.problem( problem_obj=problem, # problem instance n=num_vars, # number of variables m=num_cons, # number of constraints lb=None, # lower bounds on variables ub=None, # upper bounds on variables cl=None, # lower bounds on constraints cu=np.zeros(num_cons) # upper bounds on constraints ) # ROOT_URL = www.coin-or.org/Ipopt/documentation # set solver options: $ROOT_URL/node40.html nlp.addOption(b'max_iter', int(1e5)) # nlp.addOption(b'mu_strategy', b'adaptive') # nlp.addOption(b'tol', 1e-7) # nlp.addOption(b'acceptable_tol', 1e-5) # nlp.addOption(b'acceptable_constr_viol_tol', 1e-6) # linear solver for the augmented linear system: $ROOT_URL/node51.html, www.hsl.rl.ac.uk/ipopt/ # nlp.addOption(b'linear_solver', b'ma27') # default nlp.addOption(b'linear_solver', b'ma57') # small/medium problem # nlp.addOption(b'linear_solver', b'ma86') # large problem # gradient checking for objective and constraints: $ROOT_URL/node30.html # nlp.addOption(b'derivative_test', b'first-order') # nlp.addOption(b'print_level', 6) # w = self._init_vars() # cold start, comment this line for warm start w, info = nlp.solve(w) # print(info['status'], info['status_msg']) print('\n[IPOPT] %s\n' % info['status_msg'].decode('utf-8')) if use_all_constraints is True: break problem.update_constraints(w) if problem.all_constraints_satisfied is True: print('[CUTTING-PLANE] All constraints satisfied.') break elif num_cons == problem.get_num_constraints(): print( '[CUTTING-PLANE] No more effective constraints, violations are considered acceptable by IPOPT.' ) break else: current_constraints = problem.get_current_constraints() if fnpy is not None: try: np.save(fnpy, w, allow_pickle=False) if verbose > 0: print('Save to %s' % fnpy) except (OSError, IOError, ValueError) as err: sys.stderr.write( 'Save intermediate weights failed: {0}\n'.format(err)) if cp_iter >= max_iter: print('[CUTTING-PLANE] Reaching max number of iterations.') self.mu = w[:D] self.V = w[D:(U + 1) * D].reshape(U, D) self.W = w[(U + 1) * D:(U + N + 1) * D].reshape(N, D) self.xi = w[(U + N + 1) * D:] self.trained = True if verbose > 0: print('Training finished in %.1f seconds' % (time.time() - t0))
def minimize_ipopt_sparse(fun, x0, jacobianstructure, args=(), kwargs=None, method=None, jac=None, hess=None, hessp=None, bounds=None, constraints=(), tol=None, callback=None, options=None): if not CYIPOPT_INSTALLED: raise ImportError(''' IPOPT functionality unavailable because cyipopt is not installed properly. Please visit https://github.com/matthias-k/cyipopt. The package is best installed using the Anaconda environment.''') import cyipopt from ipopt.ipopt_wrapper import IpoptProblemWrapper, get_constraint_bounds, \ replace_option, convert_to_bytes, get_bounds class SparseIpoptProblemWrapper(IpoptProblemWrapper): def __init__(self, jacobianstructure, *args, **kwargs): super().__init__(*args, **kwargs) self.jacobianstructure = lambda: jacobianstructure def jacobian(self, x): return self._constraint_jacs[0](x, *self._constraint_args[0]).data _x0 = np.atleast_1d(x0) problem = SparseIpoptProblemWrapper(jacobianstructure, fun, args=args, kwargs=kwargs, jac=jac, hess=hess, hessp=hessp, constraints=constraints) lb, ub = get_bounds(bounds) cl, cu = get_constraint_bounds(constraints, x0) if options is None: options = {} nlp = cyipopt.problem(n=len(_x0), m=len(cl), problem_obj=problem, lb=lb, ub=ub, cl=cl, cu=cu) # python3 compatibility convert_to_bytes(options) # Rename some default scipy options replace_option(options, b'disp', b'print_level') replace_option(options, b'maxiter', b'max_iter') if b'print_level' not in options: options[b'print_level'] = 0 if b'tol' not in options: options[b'tol'] = tol or 1e-8 if b'mu_strategy' not in options: options[b'mu_strategy'] = b'adaptive' if b'hessian_approximation' not in options: if hess is None and hessp is None: options[b'hessian_approximation'] = b'limited-memory' for option, value in options.items(): try: nlp.addOption(option, value) except TypeError as e: raise TypeError( 'Invalid option for IPOPT: {0}: {1} (Original message: "{2}")'. format(option, value, e)) x, info = nlp.solve(_x0) if np.asarray(x0).shape == (): x = x[0] from scipy.optimize import OptimizeResult return OptimizeResult(x=x, success=info['status'] == 0, status=info['status'], message=info['status_msg'], fun=info['obj_val'], info=info, nfev=problem.nfev, njev=problem.njev, nit=problem.nit)
def fit(self, w0=None, verbose=0): N, U, D = self.N, self.U, self.D if verbose > 0: t0 = time.time() print('\nC: %g, %g, %g' % (self.C1, self.C2, self.C3)) problem = RankPrimal(X=self.X, Y=self.Y, C1=self.C1, C2=self.C2, C3=self.C3, cliques=self.cliques, data_helper=self.data_helper, verbose=verbose) problem.compute_constraint_info() LB = np.full(self.num_vars, -cyipopt.INF, dtype=np.float) LB[-N:] = 0. # print(type(self.num_cons)) nlp = cyipopt.problem( problem_obj=problem, # problem instance n=self.num_vars, # number of variables m=self.num_cons, # number of constraints lb=LB, # lower bounds on variables ub=None, # upper bounds on variables cl=None, # lower bounds on constraints cu=np.zeros(self.num_cons) # upper bounds on constraints ) # ROOT_URL = www.coin-or.org/Ipopt/documentation # set solver options: $ROOT_URL/node40.html nlp.addOption(b'max_iter', int(1e4)) # nlp.addOption(b'mu_strategy', b'adaptive') # nlp.addOption(b'tol', 1e-7) # nlp.addOption(b'acceptable_tol', 1e-5) # nlp.addOption(b'acceptable_constr_viol_tol', 1e-6) # linear solver for the augmented linear system: $ROOT_URL/node51.html, www.hsl.rl.ac.uk/ipopt/ # nlp.addOption(b'linear_solver', b'ma27') # default nlp.addOption(b'linear_solver', b'ma57') # small/medium problem # nlp.addOption(b'linear_solver', b'ma86') # large problem # gradient checking for objective and constraints: $ROOT_URL/node30.html # nlp.addOption(b'derivative_test', b'first-order') # nlp.addOption(b'derivative_test_tol', 0.0009) # default is 0.0001 # nlp.addOption(b'print_level', 6) w0 = self._init_vars() w, info = nlp.solve(w0) # print(info['status'], info['status_msg']) print('\n[IPOPT] %s\n' % info['status_msg'].decode('utf-8')) self.mu = w[:D] self.V = w[D:(U + 1) * D].reshape(U, D) self.W = w[(U + 1) * D:(U + N + 1) * D].reshape(N, D) # self.xi = w[(U + N + 1) * D:(U + N + 1) * D + N] # self.delta = w[self.num_vars - N:self.num_vars] self.trained = True if verbose > 0: print('Training finished in %.1f seconds' % (time.time() - t0))