Пример #1
0
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)
Пример #2
0
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,
                            )
Пример #3
0
    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))
Пример #4
0
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)
Пример #5
0
    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))
Пример #6
0
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)
Пример #7
0
    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))