Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:redwil:15.4
python-pyipopt
pyipopt-0.8.2+git20180625.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pyipopt-0.8.2+git20180625.obscpio of Package python-pyipopt
07070100000000000081A40000000000000000000000015B316A530000003C000000000000000000000000000000000000002500000000pyipopt-0.8.2+git20180625/.gitignore.* *.html # EXCEPTIONS !README !.gitignore build pyipopt.so 07070100000001000081A40000000000000000000000015B316A5300000450000000000000000000000000000000000000002400000000pyipopt-0.8.2+git20180625/ChangelogList of changes Version 0.1 List works Version 0.2 Use Numpy arrays instead of lists for efficiency Version 0.3 Change the module interface to allocate more nlp instances instead of one now use nlp = pyipopt.create(xxx) and nlp.solve nlp.close() now we can create multiple instance of nlp. [Tested] Version 0.4 Move all the pointers to the PyObject (callback function in Python) to the user_data field Therefore, the C callback function here can just dispatch it to the Python callable object in the user_data [DONE] [We wrap the user_data twice] Version 0.5: Bug in H matrix fixed Version 0.5.1: some stupid spelling error in the source file and comments fixed. Version 0.6: Fixed a memory leak problem (at least valgrind won't complain). Version 0.7: Fixed a bug for the value of m and n, a bug for reference counting. Version 0.8: Merged patches submitted by others, now supporting intermediate_callback (requires Ipopt>=3.9.1) Version 0.8.1: Updated the README doc. Version 0.8.2: Merged a change from Guillaume Jacquenot, now there is no GOTO in the source code. 07070100000002000081A40000000000000000000000015B316A530000135D000000000000000000000000000000000000002400000000pyipopt-0.8.2+git20180625/README.mdPyIpopt ======= PyIpopt is a python module that allows you to use [Ipopt](http://www.coin-or.org/Ipopt/) in Python. It is developed by Eric Xu when he was a PhD student at [Washington University](https://wustl.edu/) and issued under the BSD license. Installation ------------ ### Dependencies PyIpopt depends on the following packages: 1. A compiler and a linker, e.g. gcc, ld 2. [Ipopt](https://projects.coin-or.org/Ipopt) 3. [Numpy](http://numpy.scipy.org/) 4. Python.h (part of the python source code, you can download it from [Python.org](http://python.org)) ### Install First, get the latest source code using: $ git clone http://github.com/xuy/pyipopt.git In your PyIpopt folder, edit setup.py to reflect the configuration of your system, then do $ python setup.py build $ sudo python setup.py install ### Test $ python hs071.py You should be able to see the result of solving the toy problem. Usage ----- You can use PyIpopt like this: import pyipopt # define your call back functions nlp = pyipopt.create(...) nlp.solve(...) nlp.close() You can also check out hs071.py to see how to use PyIpopt. PyIpopt as a module comes with docstring. You can poke around it by using Python's $help()$ command. Testing ------- I have included an example To see if you have PyIpopt ready, use the following command under the pyipopt's directory. python hs071.py The file "hs071.py" contains a toy optimization problem. If everything is OK, pyipopt will invoke Ipopt to solve it for you. This python file is self-documented and can be used as a template for writing your own optimization problems. Pyipopt is a legitimate Python module, you can inspect it by using standard Python commands like "dir" or "help". All functions in pyipopt are documented in details. **Hessian Estimation**: since Hessian estimation is usually tedious, Ipopt can solve problems without Hessian estimation. Pyipopt also supports this feature. The file "hs071.py" demonstrates the idea. If you provide the pyipopt.create function with an "eval_h" callback function as well as the "apply_new" callback function, Ipopt will delegate the Hessian matrix calculation to your function (otherwise Ipopt will approximate Hessian for you). Contributing ------------ 1. Fork it. 2. Create a branch (`git checkout -b my_pyipopt`) 3. Commit your changes (`git commit -am "your awesome message"`) 4. Push to the branch (`git push origin my_pyipopt`) 5. Create a pull request 6. Nag me about it if I am lazy. Troubleshooting --------------- ### Check Ipopt PyIpopt links to Ipopt's C library. If that library is not available PyIpopt will fail during module initialization. To check the availability of this library, you can go to $IPOPT_DIR/Ipopt/examples/hs071_c/ and issue $make to ensure you can compile and run the toy example supplied by Ipopt. ### Miscellaneous problems * Error: import pyipopt ImportError: can not find libipopt.so.0 * Solution: find it and copy it to a folder that ld can access * Error: import pyipopt ImportError: /usr/lib/libipopt.so.0: undefined symbol: _gfortran_XXX * Solution: check if your `hs071_c` example work. It is very likely that your ipopt library is not correctly compiled. * Error: import pyipopt ImportError: /usr/lib/libipopt.so.0: undefined symbol: SetIntermediateCallback * Solution: SetIntermediateCallback is a function added since Ipopt 3.9.1. (see https://projects.coin-or.org/Ipopt/changeset/1830 ) Make sure you have an Ipopt version >= 3.9.1 * Error: import pyipopt ImportError: /usr/lib/libipopt.so.0: undefined symbol: ma19ad_ * Solution: First, use nm /usr/lib/libipopt.so.0 | grep ma19ad_ to see if it is marked with U. It should. This means that libipopt.so.0 is not aware of libcoinhsl.so.0. You can fix this by adding -lcoinhsl in the makefile of pyipopt. It seems to me that this happens in the recent versions of ipopt. Eventually pyipopt will have a better building mechanism, and I will fix this soon. * Error: import pyipopt ImportError: /usr/lib/libipopt.so.0: undefined symbol: SomeKindOfSymbol * Solution: I can assure you that it is NOT a bug of pyipopt. It is very likely that you did not link the right package when compiling pyipopt. First, use nm /usr/lib/libipopt.so.0 | grep SomeKindOfSymbol to see if this symbol is indeed missing. Do a Google search to find the library file, and add -lWhateverLibrary in the makefile of pyipopt. Ipopt is built using various third-party libraries. Different machines may have different set of libraries. You should try to locate these dependencies and indicate them when compiling pyipopt. This is just a limitation of dynamic linking libraries and is not related to Pyipopt. Please do not report a missing symbol error as a "bug" to me unless you are 100% sure it is the problem of pyipopt. Contact -------- Eric Xu <xu.mathena@gmail.com> Software Engineer @ Google 07070100000003000041ED0000000000000000000000035B316A5300000000000000000000000000000000000000000000002300000000pyipopt-0.8.2+git20180625/examples07070100000004000081A40000000000000000000000015B316A5300001003000000000000000000000000000000000000002C00000000pyipopt-0.8.2+git20180625/examples/hs071.py#!/usr/bin/python # Author: Eric Xu. Washington University # The same model as Ipopt/examples/hs071 from __future__ import print_function import pyipopt from numpy import * nvar = 4 x_L = ones((nvar), dtype=float_) * 1.0 x_U = ones((nvar), dtype=float_) * 5.0 ncon = 2 g_L = array([25.0, 40.0]) g_U = array([2.0*pow(10.0, 19), 40.0]) def eval_f(x, user_data = None): assert len(x) == 4 return x[0] * x[3] * (x[0] + x[1] + x[2]) + x[2] def eval_grad_f(x, user_data = None): assert len(x) == 4 grad_f = array([ x[0] * x[3] + x[3] * (x[0] + x[1] + x[2]) , x[0] * x[3], x[0] * x[3] + 1.0, x[0] * (x[0] + x[1] + x[2]) ], float_) return grad_f; def eval_g(x, user_data= None): assert len(x) == 4 return array([ x[0] * x[1] * x[2] * x[3], x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3] ], float_) nnzj = 8 def eval_jac_g(x, flag, user_data = None): if flag: return (array([0, 0, 0, 0, 1, 1, 1, 1]), array([0, 1, 2, 3, 0, 1, 2, 3])) else: assert len(x) == 4 return array([ x[1]*x[2]*x[3], x[0]*x[2]*x[3], x[0]*x[1]*x[3], x[0]*x[1]*x[2], 2.0*x[0], 2.0*x[1], 2.0*x[2], 2.0*x[3] ]) nnzh = 10 def eval_h(x, lagrange, obj_factor, flag, user_data = None): if flag: hrow = [0, 1, 1, 2, 2, 2, 3, 3, 3, 3] hcol = [0, 0, 1, 0, 1, 2, 0, 1, 2, 3] return (array(hcol), array(hrow)) else: values = zeros((10), float_) values[0] = obj_factor * (2*x[3]) values[1] = obj_factor * (x[3]) values[2] = 0 values[3] = obj_factor * (x[3]) values[4] = 0 values[5] = 0 values[6] = obj_factor * (2*x[0] + x[1] + x[2]) values[7] = obj_factor * (x[0]) values[8] = obj_factor * (x[0]) values[9] = 0 values[1] += lagrange[0] * (x[2] * x[3]) values[3] += lagrange[0] * (x[1] * x[3]) values[4] += lagrange[0] * (x[0] * x[3]) values[6] += lagrange[0] * (x[1] * x[2]) values[7] += lagrange[0] * (x[0] * x[2]) values[8] += lagrange[0] * (x[0] * x[1]) values[0] += lagrange[1] * 2 values[2] += lagrange[1] * 2 values[5] += lagrange[1] * 2 values[9] += lagrange[1] * 2 return values def apply_new(x): return True nlp = pyipopt.create(nvar, x_L, x_U, ncon, g_L, g_U, nnzj, nnzh, eval_f, eval_grad_f, eval_g, eval_jac_g) x0 = array([1.0, 5.0, 5.0, 1.0]) pi0 = array([1.0, 1.0]) """ print x0 print nvar, ncon, nnzj print x_L, x_U print g_L, g_U print eval_f(x0) print eval_grad_f(x0) print eval_g(x0) a = eval_jac_g(x0, True) print "a = ", a[1], a[0] print eval_jac_g(x0, False) print eval_h(x0, pi0, 1.0, False) print eval_h(x0, pi0, 1.0, True) """ """ You can set Ipopt options by calling nlp.num_option, nlp.str_option or nlp.int_option. For instance, to set the tolarance by calling nlp.num_option('tol', 1e-8) For a complete list of Ipopt options, refer to http://www.coin-or.org/Ipopt/documentation/node59.html Note that Ipopt distinguishs between Int, Num, and Str options, yet sometimes does not explicitly tell you which option is which. If you are not sure about the option's type, just try it in PyIpopt. If you try to set one type of option using the wrong function, Pyipopt will remind you of it. """ print("Going to call solve") print("x0 = {}".format(x0)) x, zl, zu, constraint_multipliers, obj, status = nlp.solve(x0) # import pdb; pdb.set_trace() nlp.close() def print_variable(variable_name, value): for i in range(len(value)): print("{} {}".format(variable_name + "["+str(i)+"] =", value[i])) print("Solution of the primal variables, x") print_variable("x", x) print("Solution of the bound multipliers, z_L and z_U") print_variable("z_L", zl) print_variable("z_U", zu) print("Solution of the constraint multipliers, lambda") print_variable("lambda", constraint_multipliers) print("Objective value") print("f(x*) = {}".format(obj)) 07070100000005000081A40000000000000000000000015B316A5300000E30000000000000000000000000000000000000002C00000000pyipopt-0.8.2+git20180625/examples/rosen.py""" Is the hessian even supported by pyipopt? There is a comment here http://www.wstein.org/home/wstein/www/home/was/patches/ openopt-0.24/src/openopt/solvers/CoinOr/ipopt_oo.py suggesting that the pyipopt hessian support may be buggy. Also check some bug reports here: http://code.google.com/p/pyipopt/issues/list ?can=1&q=&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary&cells=tiles """ from __future__ import print_function import numpy import scipy.optimize import pyipopt def eval_f(X, user_data=None): """ Directly evaluate the objective function f. """ return scipy.optimize.rosen(X) def eval_grad_f(X, user_data=None): """ Evaluate the gradient of the objective function f. """ return scipy.optimize.rosen_der(X) def eval_g(X, user_data=None): """ Evaluate the constraint functions. """ return numpy.array([], dtype=float) def eval_jac_g(X, flag, user_data=None): """ Evaluate the sparse Jacobian of constraint functions g. @param X: parameter values @param flag: this asks for the sparsity structure """ print('eval_jac_g') print(X) print(flag) print(user_data) print() #XXX if flag: rows = numpy.array([], dtype=int) cols = numpy.array([], dtype=int) return (rows, cols) else: return numpy.array([], dtype=float) def eval_h(X, lagrange, obj_factor, flag, user_data=None): """ Evaluate the sparse hessian of the Lagrangian. @param X: parameter values @param lagrange: something about the constraints @param obj_factor: no clue what this is @param flag: this asks for the sparsity structure """ #XXX print('eval_h:') print(X) print(lagrange) print(obj_factor) print(flag) print(user_data) print() rows = numpy.array([0, 1, 1], dtype=int) cols = numpy.array([0, 0, 1], dtype=int) if flag: return (rows, cols) else: # XXX # these values are meaningless values = numpy.zeros(3, dtype=float) #values[0] = obj_factor*2 #values[1] = 0 #values[2] = obj_factor*2 H = scipy.optimize.rosen_hess(X) for i, (r, c) in enumerate(zip(rows, cols)): values[i] = H[r, c] * obj_factor return values def apply_new(X): """ What is this? """ #XXX print('apply_new:') print(X) print() return True def main(): # verbose pyipopt.set_loglevel(2) # define the parameters and their box constraints nvar = 2 x_L = numpy.array([-3, -3], dtype=float) x_U = numpy.array([3, 3], dtype=float) # define the inequality constraints ncon = 0 g_L = numpy.array([], dtype=float) g_U = numpy.array([], dtype=float) # define the number of nonzeros in the jacobian and in the hessian # there are no nonzeros in the constraint jacobian nnzj = 0 # there are maximum nonzeros (nvar*(nvar+1))/2 in the lagrangian hessian nnzh = 3 # create the nonlinear programming model nlp = pyipopt.create( nvar, x_L, x_U, ncon, g_L, g_U, nnzj, nnzh, eval_f, eval_grad_f, eval_g, eval_jac_g, eval_h, apply_new, ) # define the initial guess x0 = numpy.array([-1.2, 1], dtype=float) # compute the results using ipopt results = nlp.solve(x0) # free the model nlp.close() # report the results print(results) if __name__ == '__main__': main() 07070100000006000041ED0000000000000000000000025B316A5300000000000000000000000000000000000000000000003100000000pyipopt-0.8.2+git20180625/examples/unconstrained07070100000007000081A40000000000000000000000015B316A5300000441000000000000000000000000000000000000003F00000000pyipopt-0.8.2+git20180625/examples/unconstrained/himmelblau.py""" Minimize a standard unconstrained test function. This example uses algopy for the gradient and hessian. """ from __future__ import print_function import functools import numpy import algopy import pyipopt def himmelblau(X): """ http://en.wikipedia.org/wiki/Himmelblau%27s_function This function has four local minima where the value of the function is 0. """ x = X[0] y = X[1] a = x*x + y - 11 b = x + y*y - 7 return a*a + b*b def eval_grad(f, theta): theta = algopy.UTPM.init_jacobian(theta) return algopy.UTPM.extract_jacobian(f(theta)) def eval_hess(f, theta): theta = algopy.UTPM.init_hessian(theta) return algopy.UTPM.extract_hessian(len(theta), f(theta)) def main(): pyipopt.set_loglevel(2) x0 = numpy.array([-0.27, -0.9], dtype=float) results = pyipopt.fmin_unconstrained( himmelblau, x0, fprime=functools.partial(eval_grad, himmelblau), fhess=functools.partial(eval_hess, himmelblau), ) print(results) if __name__ == '__main__': main() 07070100000008000081A40000000000000000000000015B316A5300000232000000000000000000000000000000000000003A00000000pyipopt-0.8.2+git20180625/examples/unconstrained/rosen.py""" Minimize the Rosenbrock function with the unconstrained minimization interface. See the rosen.py example for more details. """ from __future__ import print_function import numpy import scipy.optimize import pyipopt def main(): pyipopt.set_loglevel(2) x0 = numpy.array([-1.2, 1], dtype=float) results = pyipopt.fmin_unconstrained( scipy.optimize.rosen, x0, fprime=scipy.optimize.rosen_der, fhess=scipy.optimize.rosen_hess, ) print(results) if __name__ == '__main__': main() 07070100000009000081A40000000000000000000000015B316A5300000466000000000000000000000000000000000000003900000000pyipopt-0.8.2+git20180625/examples/unconstrained/wood.py""" Minimize a standard unconstrained test function. This example uses algopy for the gradient and hessian. """ from __future__ import print_function import functools import numpy import algopy import pyipopt def wood(X): """ The minimum is at [1, 1, 1, 1]. """ x1 = X[0] x2 = X[1] x3 = X[2] x4 = X[3] return sum(( 100*(x1*x1 - x2)**2, (x1-1)**2, (x3-1)**2, 90*(x3*x3 - x4)**2, 10.1*((x2-1)**2 + (x4-1)**2), 19.8*(x2-1)*(x4-1), )) def eval_grad(f, theta): theta = algopy.UTPM.init_jacobian(theta) return algopy.UTPM.extract_jacobian(f(theta)) def eval_hess(f, theta): theta = algopy.UTPM.init_hessian(theta) return algopy.UTPM.extract_hessian(len(theta), f(theta)) def main(): pyipopt.set_loglevel(2) x0 = numpy.array([-3, -1, -3, -1], dtype=float) results = pyipopt.fmin_unconstrained( wood, x0, fprime=functools.partial(eval_grad, wood), fhess=functools.partial(eval_hess, wood), ) print(results) if __name__ == '__main__': main() 0707010000000A000041ED0000000000000000000000025B316A5300000000000000000000000000000000000000000000002900000000pyipopt-0.8.2+git20180625/pyipoptpackage0707010000000B000081A40000000000000000000000015B316A530000016B000000000000000000000000000000000000003500000000pyipopt-0.8.2+git20180625/pyipoptpackage/__init__.py""" This is a package for a python interface to ipopt. The underlying C interface is in pyipoptcore. """ import os import sys sys.path.append(os.path.dirname(__file__)) import functools import numpy from ipoptconst import * from pyipoptcore import * from ipoptunconstrained import fmin_unconstrained # verbose messages from the C interface set_loglevel(2) 0707010000000C000081A40000000000000000000000015B316A53000000DC000000000000000000000000000000000000003700000000pyipopt-0.8.2+git20180625/pyipoptpackage/ipoptconst.py""" These are some constants. """ # http://www.coin-or.org/Ipopt/documentation/node35.html # FIXME: these are not actually constant but may be changed within ipopt NLP_LOWER_BOUND_INF = -1e19 NLP_UPPER_BOUND_INF = 1e19 0707010000000D000081A40000000000000000000000015B316A5300001097000000000000000000000000000000000000003F00000000pyipopt-0.8.2+git20180625/pyipoptpackage/ipoptunconstrained.py""" Unconstrained function minimization. This is supposed to have an interface like the old scipy.optimize interface. The underlying C interface is in pyipoptcore. """ import functools import numpy import pyipoptcore from ipoptconst import NLP_LOWER_BOUND_INF from ipoptconst import NLP_UPPER_BOUND_INF def _eval_g(X, user_data=None): return numpy.array([], dtype=float) def _eval_jac_g(X, flag, user_data=None): rows = numpy.array([], dtype=int) cols = numpy.array([], dtype=int) if flag: return (rows, cols) else: raise Exception( 'this should not be called for unconstrained optimization') def _eval_h( h, nvar, X, lagrange, obj_factor, flag, user_data=None): """ The first group of parameters should be applied using functools.partial. The second group of parameters are passed from ipopt. @param h: a function to compute the hessian. @param nvar: the number of parameters @param X: parameter values @param lagrange: something about the constraints @param obj_factor: no clue what this is @param flag: this asks for the sparsity structure @param user_data: please do not use this yet """ # Get the nonzero (row, column) entries of a lower triangular matrix. # This is related to the fact that the Hessian is symmetric, # and that ipopt is designed to work with sparse matrices. row_list = [] col_list = [] for row in range(nvar): for col in range(row+1): row_list.append(row) col_list.append(col) rows = numpy.array(row_list, dtype=int) cols = numpy.array(col_list, dtype=int) if flag: return (rows, cols) else: if nvar != len(X): raise Exception('parameter count mismatch') if lagrange: raise Exception('only unconstrained is implemented for now...') values = numpy.zeros(len(rows), dtype=float) H = h(X) for i, (r, c) in enumerate(zip(rows, cols)): #FIXME: am I using obj_factor correctly? # I don't really know what it is... values[i] = H[r, c] * obj_factor return values def _apply_new(X): #FIXME: I don't really know what this does, but ipopt wants it. return True def _create(f, nvar, fprime, fhess=None): """ Creates an ipopt nlp object. @param f: objective function to minimize @param nvar: number of parameters @param fprime: computes the gradient of the objective function @param fhess: computes the hessian of the objective function @return: a pyipopt nlp object which may be solved and then closed """ # no box constraints on the parameters x_L = numpy.array([NLP_LOWER_BOUND_INF]*nvar, dtype=float) x_U = numpy.array([NLP_UPPER_BOUND_INF]*nvar, dtype=float) # no other constraints ncon = 0 g_L = numpy.array([], dtype=float) g_U = numpy.array([], dtype=float) # no constraint jacobian nnzj = 0 # dense lower triangular hessian structure nnzh = 0 if fhess: nnzh = (nvar * (nvar + 1)) // 2 # define the nlp creation args nlp_args = [ nvar, x_L, x_U, ncon, g_L, g_U, nnzj, nnzh, f, fprime, _eval_g, _eval_jac_g, ] if fhess: nlp_args.extend([ functools.partial(_eval_h, fhess, nvar), _apply_new, ]) # create the nlp object return pyipoptcore.create(*nlp_args) def fmin_unconstrained(f, x0, fprime, fhess=None): """ This is a utility function wrapping create_unconstrained. @param f: objective function to minimize @param x0: initial guess @param fprime: computes the gradient of the objective function @param fhess: computes the hessian of the objective function @return: results in pyipoptcore format """ nvar = len(x0) nlp = _create(f, nvar, fprime, fhess) #FIXME: do something about this... #http://www.coin-or.org/Ipopt/documentation/node68.html nlp.num_option('tol', 1e-12) results = nlp.solve(x0) nlp.close() return results 0707010000000E000081A40000000000000000000000015B316A5300000946000000000000000000000000000000000000002300000000pyipopt-0.8.2+git20180625/setup.py# Originally contributed by Lorne McIntosh. # Modified by Eric Xu # Further modification by random internet people. # You will probably have to edit this file in unpredictable ways # if you want pyipopt to work for you, sorry. # When I installed Ipopt from source, I used the # --prefix=/usr/local # option, so this is where I want pyipopt to look for my ipopt installation. # I only installed from source because the ipopt packaging # for my linux distribution was buggy, # so by the time you read this the bugs have probably been fixed # and you will want to specify a different directory here. IPOPT_DIR = '/usr/local/' import os from distutils.core import setup from distutils.extension import Extension # NumPy is much easier to install than pyipopt, # and is a pyipopt dependency, so require it here. # We need it to tell us where the numpy header files are. import numpy numpy_include = numpy.get_include() # I personally do not need support for lib64 but I'm keeping it in the code. def get_ipopt_lib(): for lib_suffix in ('lib', 'lib64'): d = os.path.join(IPOPT_DIR, lib_suffix) if os.path.isdir(d): return d IPOPT_LIB = get_ipopt_lib() if IPOPT_LIB is None: raise Exception('failed to find ipopt lib') IPOPT_INC = os.path.join(IPOPT_DIR, 'include/coin/') FILES = ['src/callback.c', 'src/pyipoptcoremodule.c'] # The extra_link_args is commented out here; # that line was causing my pyipopt install to not work. # Also I am using coinmumps instead of coinhsl. pyipopt_extension = Extension( 'pyipoptcore', FILES, #extra_link_args=['-Wl,--rpath','-Wl,'+ IPOPT_LIB], library_dirs=[IPOPT_LIB], libraries=[ 'ipopt', 'coinblas', #'coinhsl', 'coinmumps', 'coinmetis', 'coinlapack','dl','m', ], include_dirs=[numpy_include, IPOPT_INC], ) setup( name="pyipopt", version="0.8", description="An IPOPT connector for Python", author="Eric Xu", author_email="xu.mathena@gmail.com", url="https://github.com/xuy/pyipopt", packages=['pyipopt'], package_dir={'pyipopt' : 'pyipoptpackage'}, ext_package='pyipopt', ext_modules=[pyipopt_extension], ) 0707010000000F000041ED0000000000000000000000025B316A5300000000000000000000000000000000000000000000001E00000000pyipopt-0.8.2+git20180625/src07070100000010000081A40000000000000000000000015B316A530000420A000000000000000000000000000000000000002900000000pyipopt-0.8.2+git20180625/src/callback.c/* * Copyright (c) 2008, Eric You Xu, Washington University All rights * reserved. Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * Redistributions in * binary form must reproduce the above copyright notice, this list of * conditions and the following disclaimer in the documentation and/or other * materials provided with the distribution. * Neither the name of the * Washington University nor the names of its contributors may be used to * endorse or promote products derived from this software without specific * prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Added "eval_intermediate_callback" by * OpenMDAO at NASA Glenn Research Center, 2010 and 2011 * * Changed logger from code contributed by alanfalloon */ #include "hook.h" #include <unistd.h> void logger(const char *fmt, ...) { if (user_log_level == VERBOSE) { va_list ap; va_start(ap, fmt); PySys_WriteStdout(fmt, ap); va_end(ap); PySys_WriteStdout("\n"); } } Bool eval_intermediate_callback(Index alg_mod, /* 0 is regular, 1 is resto */ Index iter_count, Number obj_value, Number inf_pr, Number inf_du, Number mu, Number d_norm, Number regularization_size, Number alpha_du, Number alpha_pr, Index ls_trials, UserDataPtr data) { //logger("[Callback:E]intermediate_callback"); DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; long result_as_long; Bool result_as_bool; PyObject *python_algmod = Py_BuildValue("i", alg_mod); PyObject *python_iter_count = Py_BuildValue("i", iter_count); PyObject *python_obj_value = Py_BuildValue("d", obj_value); PyObject *python_inf_pr = Py_BuildValue("d", inf_pr); PyObject *python_inf_du = Py_BuildValue("d", inf_du); PyObject *python_mu = Py_BuildValue("d", mu); PyObject *python_d_norm = Py_BuildValue("d", d_norm); PyObject *python_regularization_size = Py_BuildValue("d", regularization_size); PyObject *python_alpha_du = Py_BuildValue("d", alpha_du); PyObject *python_alpha_pr = Py_BuildValue("d", alpha_pr); PyObject *python_ls_trials = Py_BuildValue("i", ls_trials); PyObject *arglist = NULL; if (user_data != NULL) arglist = Py_BuildValue("(OOOOOOOOOOOO)", python_algmod, python_iter_count, python_obj_value, python_inf_pr, python_inf_du, python_mu, python_d_norm, python_regularization_size, python_alpha_du, python_alpha_pr, python_ls_trials, (PyObject *) user_data); else arglist = Py_BuildValue("(OOOOOOOOOOO)", python_algmod, python_iter_count, python_obj_value, python_inf_pr, python_inf_du, python_mu, python_d_norm, python_regularization_size, python_alpha_du, python_alpha_pr, python_ls_trials); PyObject *result = PyObject_CallObject(myowndata->eval_intermediate_callback_python, arglist); if (!result) PyErr_Print(); result_as_long = PyLong_AsLong(result); result_as_bool = (Bool) result_as_long; Py_DECREF(result); Py_CLEAR(arglist); //logger("[Callback:R] intermediate_callback"); return result_as_bool; } Bool eval_f(Index n, Number * x, Bool new_x, Number * obj_value, UserDataPtr data) { //logger("[Callback:E] eval_f"); npy_intp dims[1]; dims[0] = n; DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; // import_array (); import_array1(FALSE); PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; if (new_x && myowndata->apply_new_python) { /* Call the python function to applynew */ PyObject *arg1; arg1 = Py_BuildValue("(O)", arrayx); PyObject *tempresult = PyObject_CallObject( myowndata->apply_new_python, arg1); if (tempresult == NULL) { logger("[Error] Python function apply_new returns NULL"); PyErr_Print(); Py_DECREF(arg1); return FALSE; } Py_DECREF(arg1); Py_DECREF(tempresult); } PyObject *arglist; if (user_data != NULL) { arglist = Py_BuildValue("(OO)", arrayx, (PyObject *) user_data); } else { arglist = Py_BuildValue("(O)", arrayx); } PyObject *result = PyObject_CallObject(myowndata->eval_f_python, arglist); if (result == NULL) { logger("[Error] Python function eval_f returns NULL"); PyErr_Print(); Py_DECREF(arrayx); Py_CLEAR(arglist); return FALSE; } *obj_value = PyFloat_AsDouble(result); if (PyErr_Occurred()) { logger("[Error] Python function eval_f returns non-PyFloat"); PyErr_Print(); Py_DECREF(result); Py_DECREF(arrayx); Py_CLEAR(arglist); return FALSE; } Py_DECREF(result); Py_DECREF(arrayx); Py_CLEAR(arglist); //logger("[Callback:R] eval_f"); return TRUE; } Bool eval_grad_f(Index n, Number * x, Bool new_x, Number * grad_f, UserDataPtr data) { //logger("[Callback:E] eval_grad_f"); DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; if (myowndata->eval_grad_f_python == NULL) PyErr_Print(); /* int dims[1]; */ npy_intp dims[1]; dims[0] = n; // import_array (); import_array1(FALSE); /* * PyObject *arrayx = PyArray_FromDimsAndData(1, dims, PyArray_DOUBLE * , (char*) x); */ PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; if (new_x && myowndata->apply_new_python) { /* Call the python function to applynew */ PyObject *arg1 = Py_BuildValue("(O)", arrayx); PyObject *tempresult = PyObject_CallObject( myowndata->apply_new_python, arg1); if (tempresult == NULL) { logger("[Error] Python function apply_new returns NULL"); PyErr_Print(); Py_DECREF(arg1); return FALSE; } Py_DECREF(arg1); Py_DECREF(tempresult); } PyObject *arglist; if (user_data != NULL) arglist = Py_BuildValue("(OO)", arrayx, (PyObject *) user_data); else arglist = Py_BuildValue("(O)", arrayx); PyArrayObject *result = (PyArrayObject *) PyObject_CallObject( myowndata->eval_grad_f_python, arglist); if (result == NULL) { logger("[Error] Python function eval_grad_f returns NULL"); PyErr_Print(); return FALSE; } if (!PyArray_Check(result)) { logger("[Error] Python function eval_grad_f returns non-PyArray"); Py_DECREF(result); return FALSE; } double *tempdata = (double *)result->data; int i; for (i = 0; i < n; i++) grad_f[i] = tempdata[i]; Py_DECREF(result); Py_CLEAR(arrayx); Py_CLEAR(arglist); //logger("[Callback:R] eval_grad_f"); return TRUE; } Bool eval_g(Index n, Number * x, Bool new_x, Index m, Number * g, UserDataPtr data) { //logger("[Callback:E] eval_g"); DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; if (myowndata->eval_g_python == NULL) PyErr_Print(); /* int dims[1]; */ npy_intp dims[1]; int i; double *tempdata; dims[0] = n; // import_array (); import_array1(FALSE); /* * PyObject *arrayx = PyArray_FromDimsAndData(1, dims, PyArray_DOUBLE * , (char*) x); */ PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; if (new_x && myowndata->apply_new_python) { /* Call the python function to applynew */ PyObject *arg1 = Py_BuildValue("(O)", arrayx); PyObject *tempresult = PyObject_CallObject( myowndata->apply_new_python, arg1); if (tempresult == NULL) { logger("[Error] Python function apply_new returns NULL"); PyErr_Print(); Py_DECREF(arg1); return FALSE; } Py_DECREF(arg1); Py_DECREF(tempresult); } PyObject *arglist; if (user_data != NULL) arglist = Py_BuildValue("(OO)", arrayx, (PyObject *) user_data); else arglist = Py_BuildValue("(O)", arrayx); PyArrayObject *result = (PyArrayObject *) PyObject_CallObject( myowndata->eval_g_python, arglist); if (result == NULL) { logger("[Error] Python function eval_g returns NULL"); PyErr_Print(); return FALSE; } if (!PyArray_Check(result)) { logger("[Error] Python function eval_g returns non-PyArray"); Py_DECREF(result); return FALSE; } tempdata = (double *)result->data; for (i = 0; i < m; i++) { g[i] = tempdata[i]; } Py_DECREF(result); Py_CLEAR(arrayx); Py_CLEAR(arglist); //logger("[Callback:R] eval_g"); return TRUE; } Bool eval_jac_g(Index n, Number * x, Bool new_x, Index m, Index nele_jac, Index * iRow, Index * jCol, Number * values, UserDataPtr data) { //logger("[Callback:E] eval_jac_g"); DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; int i; long *rowd = NULL; long *cold = NULL; /* int dims[1]; */ npy_intp dims[1]; dims[0] = n; double *tempdata; if (myowndata->eval_grad_f_python == NULL) /* Why??? */ PyErr_Print(); if (values == NULL) { /* import_array (); */ import_array1(FALSE); PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; PyObject *arglist; if (user_data != NULL) arglist = Py_BuildValue("(OOO)", arrayx, Py_True, (PyObject *) user_data); else arglist = Py_BuildValue("(OO)", arrayx, Py_True); PyObject *result = PyObject_CallObject(myowndata->eval_jac_g_python, arglist); if (!result) { logger("[PyIPOPT] return from eval_jac_g is null\n"); /* TODO: need to deal with reference counting here */ return FALSE; } if (!PyTuple_Check(result)) { PyErr_Print(); } PyArrayObject *row = (PyArrayObject *) PyTuple_GetItem(result, 0); PyArrayObject *col = (PyArrayObject *) PyTuple_GetItem(result, 1); if (!row || !col || !PyArray_Check(row) || !PyArray_Check(col)) { logger ("[Error] there are problems with row or col in eval_jac_g.\n"); PyErr_Print(); } rowd = (long *)row->data; cold = (long *)col->data; for (i = 0; i < nele_jac; i++) { iRow[i] = (Index) rowd[i]; jCol[i] = (Index) cold[i]; } Py_CLEAR(arrayx); Py_DECREF(result); Py_CLEAR(arglist); //logger("[Callback:R] eval_jac_g(1)"); } else { PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; if (new_x && myowndata->apply_new_python) { /* Call the python function to applynew */ PyObject *arg1 = Py_BuildValue("(O)", arrayx); PyObject *tempresult = PyObject_CallObject(myowndata->apply_new_python, arg1); if (tempresult == NULL) { logger("[Error] Python function apply_new returns NULL"); Py_DECREF(arg1); return FALSE; } Py_DECREF(arg1); Py_DECREF(tempresult); } PyObject *arglist; if (user_data != NULL) arglist = Py_BuildValue("(OOO)", arrayx, Py_False, (PyObject *) user_data); else arglist = Py_BuildValue("(OO)", arrayx, Py_False); PyArrayObject *result = (PyArrayObject *) PyObject_CallObject( myowndata->eval_jac_g_python, arglist); if (result == NULL) { logger("[Error] Python function eval_jac_g returns NULL"); PyErr_Print(); return FALSE; } if (!PyArray_Check(result)) { logger("[Error] Python function eval_jac_g returns non-PyArray"); Py_DECREF(result); return FALSE; } /* * Code is buggy here. We assume that result is a double * array */ assert(result->descr->type == 'd'); tempdata = (double *)result->data; for (i = 0; i < nele_jac; i++) values[i] = tempdata[i]; Py_DECREF(result); Py_CLEAR(arrayx); Py_CLEAR(arglist); //logger("[Callback:R] eval_jac_g(2)"); } //logger("[Callback:R] eval_jac_g"); return TRUE; } Bool eval_h(Index n, Number * x, Bool new_x, Number obj_factor, Index m, Number * lambda, Bool new_lambda, Index nele_hess, Index * iRow, Index * jCol, Number * values, UserDataPtr data) { //logger("[Callback:E] eval_h"); DispatchData *myowndata = (DispatchData *) data; UserDataPtr user_data = (UserDataPtr) myowndata->userdata; int i; npy_intp dims[1]; npy_intp dims2[1]; if (myowndata->eval_h_python == NULL) { logger("[Error] There is no eval_h assigned"); return FALSE; } if (values == NULL) { //logger("[Callback:E] eval_h (1a)"); PyObject *newx = Py_True; PyObject *objfactor = Py_BuildValue("d", obj_factor); PyObject *lagrange = Py_True; PyObject *arglist; if (user_data != NULL) { arglist = Py_BuildValue( "(OOOOO)", newx, lagrange, objfactor, Py_True, (PyObject *) user_data); } else { arglist = Py_BuildValue( "(OOOO)", newx, lagrange, objfactor, Py_True); } if (arglist == NULL) { logger("[Error] failed to build arglist for eval_h"); PyErr_Print(); return FALSE; } else { logger("[Logspam] built arglist for eval_h"); } PyObject *result = PyObject_CallObject(myowndata->eval_h_python, arglist); if (result == NULL) { logger("[Error] Python function eval_h returns NULL"); PyErr_Print(); return FALSE; } else { logger("[Logspam] Python function eval_h returns non-NULL"); } int result_size = PyTuple_Size(result); if (result_size == -1) { logger("[Error] Python function eval_h returns non-PyTuple"); Py_DECREF(result); return FALSE; } if (result_size != 2) { logger("[Error] Python function eval_h returns a tuple whose len != 2"); Py_DECREF(result); return FALSE; } //logger("[Callback:E] eval_h (tuple is the right length)"); PyArrayObject *row = (PyArrayObject *) PyTuple_GetItem(result, 0); PyArrayObject *col = (PyArrayObject *) PyTuple_GetItem(result, 1); long *rdata = (long *)row->data; long *cdata = (long *)col->data; for (i = 0; i < nele_hess; i++) { iRow[i] = (Index) rdata[i]; jCol[i] = (Index) cdata[i]; /* * logger("PyIPOPT_DEBUG %d, %d\n", iRow[i], * jCol[i]); */ } //logger("[Callback:E] eval_h (clearing stuff now)"); Py_DECREF(objfactor); Py_DECREF(result); Py_CLEAR(arglist); //logger("[Callback:R] eval_h (1b)"); } else { //logger("[Callback:R] eval_h (2a)"); PyObject *objfactor = Py_BuildValue("d", obj_factor); dims[0] = n; PyObject *arrayx = PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x); if (!arrayx) return FALSE; if (new_x && myowndata->apply_new_python) { /* Call the python function to applynew */ PyObject *arg1 = Py_BuildValue("(O)", arrayx); PyObject *tempresult = PyObject_CallObject( myowndata->apply_new_python, arg1); if (tempresult == NULL) { logger("[Error] Python function apply_new returns NULL"); PyErr_Print(); Py_DECREF(arg1); return FALSE; } Py_DECREF(arg1); Py_DECREF(tempresult); } dims2[0] = m; PyObject *lagrangex = PyArray_SimpleNewFromData( 1, dims2, PyArray_DOUBLE, (char *)lambda); if (!lagrangex) return FALSE; PyObject *arglist; if (user_data != NULL) { arglist = Py_BuildValue( "(OOOOO)", arrayx, lagrangex, objfactor, Py_False, (PyObject *) user_data); } else { arglist = Py_BuildValue( "(OOOO)", arrayx, lagrangex, objfactor, Py_False); } PyArrayObject *result = (PyArrayObject *) PyObject_CallObject( myowndata->eval_h_python, arglist); if (result == NULL) { logger("[Error] Python function eval_h returns NULL"); PyErr_Print(); return FALSE; } if (!PyArray_Check(result)) { logger("[Error] Python function eval_h returns non-PyArray"); Py_DECREF(result); return FALSE; } double *tempdata = (double *)result->data; for (i = 0; i < nele_hess; i++) { values[i] = tempdata[i]; } Py_CLEAR(arrayx); Py_CLEAR(lagrangex); Py_CLEAR(objfactor); Py_DECREF(result); Py_CLEAR(arglist); //logger("[Callback:R] eval_h (2b)"); } return TRUE; } 07070100000011000081A40000000000000000000000015B316A5300000714000000000000000000000000000000000000002500000000pyipopt-0.8.2+git20180625/src/hook.h// Author: Eric Xu // Licensed under BSD #include "Python.h" #include "IpStdCInterface.h" #include <stdio.h> #include "numpy/arrayobject.h" #ifndef PY_IPOPT_HOOK_ #define PY_IPOPT_HOOK_ // A series of callback functions used by Ipopt C Interface Bool eval_f(Index n, Number * x, Bool new_x, Number * obj_value, UserDataPtr user_data); Bool eval_grad_f(Index n, Number * x, Bool new_x, Number * grad_f, UserDataPtr user_data); Bool eval_g(Index n, Number * x, Bool new_x, Index m, Number * g, UserDataPtr user_data); Bool eval_jac_g(Index n, Number * x, Bool new_x, Index m, Index nele_jac, Index * iRow, Index * jCol, Number * values, UserDataPtr user_data); Bool eval_h(Index n, Number * x, Bool new_x, Number obj_factor, Index m, Number * lambda, Bool new_lambda, Index nele_hess, Index * iRow, Index * jCol, Number * values, UserDataPtr user_data); Bool eval_intermediate_callback(Index alg_mod, Index iter_count, Number obj_value, Number inf_pr, Number inf_du, Number mu, Number d_norm, Number regularization_size, Number alpha_du, Number alpha_pr, Index ls_trials, UserDataPtr data); typedef struct { PyObject *eval_f_python; PyObject *eval_grad_f_python; PyObject *eval_g_python; PyObject *eval_jac_g_python; PyObject *eval_h_python; PyObject *apply_new_python; PyObject *eval_intermediate_callback_python; PyObject *userdata; } DispatchData; #if PY_MAJOR_VERSION < 3 PyObject *problem_getattr(PyObject * self, char *attrname); #endif /* Logging */ #define VERBOSE 2 #define IPOPT_OUTPUT 1 #define TERSE 0 extern int user_log_level; void logger(const char *fmt, ...); typedef struct { PyObject_HEAD IpoptProblem nlp; DispatchData *data; Index n_variables; Index m_constraints; } problem; #endif // PY_IPOPT_HOOK_ 07070100000012000081A40000000000000000000000015B316A530000545D000000000000000000000000000000000000003200000000pyipopt-0.8.2+git20180625/src/pyipoptcoremodule.c/* Author: Eric Xu */ /* Licensed under BSD */ /* */ /* Modifications on logger made by */ /* OpenMDAO at NASA Glenn Research Center, 2010 and 2011 */ /* Modifications on the SAFE_FREE macro made by */ /* Guillaume Jacquenot, 2012 */ #include "hook.h" #ifndef SAFE_FREE #define SAFE_FREE(p) {if (p) {free(p); (p)= NULL;}} #endif /* * Let's put the static char docs at the beginning of this file... */ static char PYIPOPT_SOLVE_DOC[] = "solve(x) -> (x, ml, mu, obj)\n \ \n \ Call Ipopt to solve problem created before and return \n \ a tuple that contains final solution x, upper and lower\n \ bound for multiplier, final objective function obj, \n \ and the return status of ipopt. \n"; static char PYIPOPT_SET_INTERMEDIATE_CALLBACK_DOC[] = "set_intermediate_callback(callback_function)\n \ \n \ Set the intermediate callback function. \ This gets called each iteration."; static char PYIPOPT_CLOSE_DOC[] = "After all the solving, close the model\n"; static char PYIPOPT_ADD_STR_OPTION_DOC[] = "Set the String (char* in C) option for Ipopt. Refer to the Ipopt \n \ document for more information about Ipopt options, or use \n \ ipopt --print-options \n \ to see a list of available options."; static char PYIPOPT_ADD_INT_OPTION_DOC[] = "Set the Int (int in C) option for Ipopt. Refer to the Ipopt \n \ document for more information about Ipopt options, or use \n \ ipopt --print-options \n \ to see a list of available options."; static char PYIPOPT_ADD_NUM_OPTION_DOC[] = "Set the Number (double in C) option for Ipopt. Refer to the Ipopt \n \ document for more information about Ipopt options, or use \n \ ipopt --print-options \n \ to see a list of available options."; static char PYIPOPT_CREATE_DOC[] = "create(n, xl, xu, m, gl, gu, nnzj, nnzh, eval_f, eval_grad_f, eval_g, eval_jac_g) -> Boolean\n \ \n \ Create a problem instance and return True if succeed \n \ \n \ n is the number of variables, \n \ xl is the lower bound of x as bounded constraints \n \ xu is the upper bound of x as bounded constraints \n \ both xl, xu should be one dimension arrays with length n \n \ \n \ m is the number of constraints, \n \ gl is the lower bound of constraints \n \ gu is the upper bound of constraints \n \ both gl, gu should be one dimension arrays with length m \n \ nnzj is the number of nonzeros in Jacobi matrix \n \ nnzh is the number of non-zeros in Hessian matrix, you can set it to 0 \n \ \n \ eval_f is the call back function to calculate objective value, \n \ it takes one single argument x as input vector \n \ eval_grad_f calculates gradient for objective function \n \ eval_g calculates the constraint values and return an array \n \ eval_jac_g calculates the Jacobi matrix. It takes two arguments, \n \ the first is the variable x and the second is a Boolean flag \n \ if the flag is true, it supposed to return a tuple (row, col) \n \ to indicate the sparse Jacobi matrix's structure. \n \ if the flag is false if returns the values of the Jacobi matrix \n \ with length nnzj \n \ eval_h calculates the hessian matrix, it's optional. \n \ if omitted, please set nnzh to 0 and Ipopt will use approximated hessian \n \ which will make the convergence slower. "; static char PYIPOPT_LOG_DOC[] = "set_loglevel(level)\n \ \n \ Set the log level of PyIPOPT \n \ levels: \n \ 0: Terse, no log from pyipopt \n \ 1: Moderate, logs for ipopt \n \ 2: Verbose, logs for both ipopt and pyipopt. \n"; int user_log_level = TERSE; /* Object Section */ /* sig of this is void foo(PyO*) */ static void problem_dealloc(PyObject * self) { problem *temp = (problem *) self; SAFE_FREE(temp->data); Py_TYPE(self)->tp_free((PyObject*)self); } PyObject *solve(PyObject * self, PyObject * args); PyObject *set_intermediate_callback(PyObject * self, PyObject * args); PyObject *close_model(PyObject * self, PyObject * args); static PyObject *add_str_option(PyObject * self, PyObject * args) { problem *temp = (problem *) self; IpoptProblem nlp = (IpoptProblem) (temp->nlp); char *param; char *value; Bool ret; if (!PyArg_ParseTuple(args, "ss:str_option", ¶m, &value)) { return NULL; } ret = AddIpoptStrOption(nlp, (char *)param, value); if (ret) { Py_INCREF(Py_True); return Py_True; } else { return PyErr_Format(PyExc_ValueError, "%s is not a valid string option", param); } } static PyObject *add_int_option(PyObject * self, PyObject * args) { problem *temp = (problem *) self; IpoptProblem nlp = (IpoptProblem) (temp->nlp); char *param; int value; Bool ret; if (!PyArg_ParseTuple(args, "si:int_option", ¶m, &value)) { return NULL; } ret = AddIpoptIntOption(nlp, (char *)param, value); if (ret) { Py_INCREF(Py_True); return Py_True; } else { return PyErr_Format(PyExc_ValueError, "%s is not a valid int option", param); } } static PyObject *add_num_option(PyObject * self, PyObject * args) { problem *temp = (problem *) self; IpoptProblem nlp = (IpoptProblem) (temp->nlp); char *param; double value; Bool ret; if (!PyArg_ParseTuple(args, "sd:num_option", ¶m, &value)) { return NULL; } ret = AddIpoptNumOption(nlp, (char *)param, value); if (ret) { Py_INCREF(Py_True); return Py_True; } else { return PyErr_Format(PyExc_ValueError, "%s is not a valid num option", param); } } PyMethodDef problem_methods[] = { {"solve", solve, METH_VARARGS, PYIPOPT_SOLVE_DOC} , {"set_intermediate_callback", set_intermediate_callback, METH_VARARGS, PYIPOPT_SET_INTERMEDIATE_CALLBACK_DOC} , {"close", close_model, METH_VARARGS, PYIPOPT_CLOSE_DOC} , {"int_option", add_int_option, METH_VARARGS, PYIPOPT_ADD_INT_OPTION_DOC} , {"str_option", add_str_option, METH_VARARGS, PYIPOPT_ADD_STR_OPTION_DOC} , {"num_option", add_num_option, METH_VARARGS, PYIPOPT_ADD_NUM_OPTION_DOC} , {NULL, NULL} , }; #if PY_MAJOR_VERSION < 3 PyObject *problem_getattr(PyObject * self, char *attrname) { PyObject *result = NULL; result = Py_FindMethod(problem_methods, self, attrname); return result; } /* * had to replace PyObject_HEAD_INIT(&PyType_Type) in order to get this to * compile on Windows */ PyTypeObject IpoptProblemType = { PyObject_HEAD_INIT(NULL) 0, /* ob_size */ "pyipoptcore.Problem", /* tp_name */ sizeof(problem), /* tp_basicsize */ 0, /* tp_itemsize */ problem_dealloc, /* tp_dealloc */ 0, /* tp_print */ problem_getattr, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ 0, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ 0, /* tp_hash */ 0, /* tp_call */ 0, /* tp_str */ 0, /* tp_getattro */ 0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /* tp_flags */ "The IPOPT problem object in python", /* tp_doc */ }; #else PyDoc_STRVAR(IpoptProblemType__doc__, "The IPOPT problem object in python"); PyTypeObject IpoptProblemType = { PyVarObject_HEAD_INIT(NULL, 0) "pyipoptcore.Problem", /* tp_name */ sizeof(problem), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor)problem_dealloc, /*tp_dealloc*/ (printfunc)0, /*tp_print*/ 0, /*tp_getattr*/ 0, /*tp_setattr*/ 0, /*tp_reserved*/ (reprfunc)0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ (hashfunc)0, /*tp_hash*/ (ternaryfunc)0, /*tp_call*/ (reprfunc)0, /*tp_str*/ (getattrofunc)0, /* tp_getattro */ (setattrofunc)0, /* tp_setattro */ 0, /* tp_as_buffer */ Py_TPFLAGS_DEFAULT, /*tp_flags*/ IpoptProblemType__doc__, /* tp_doc - Documentation string */ (traverseproc)0, /* tp_traverse */ (inquiry)0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ problem_methods, /* tp_methods */ }; #endif /* * FIXME: use module or package constants for the log levels, * either in pyipoptcore or in the parent package. * They are currently #defined in a header file. */ static PyObject *set_loglevel(PyObject * obj, PyObject * args) { int l; if (!PyArg_ParseTuple(args, "i", &l)) { PySys_WriteStdout("l is %d \n", l); return NULL; } if (l < 0 || l > 2) { return NULL; } user_log_level = l; Py_INCREF(Py_True); return Py_True; } static PyObject *create(PyObject * obj, PyObject * args) { PyObject *f = NULL; PyObject *gradf = NULL; PyObject *g = NULL; PyObject *jacg = NULL; PyObject *h = NULL; PyObject *applynew = NULL; DispatchData myowndata; /* * I have to create a new python object here, return this python object */ int n; /* Number of variables */ PyArrayObject *xL = NULL; PyArrayObject *xU = NULL; int m; /* Number of constraints */ PyArrayObject *gL = NULL; PyArrayObject *gU = NULL; problem *object = NULL; int nele_jac; int nele_hess; Number *x_L = NULL; /* lower bounds on x */ Number *x_U = NULL; /* upper bounds on x */ Number *g_L = NULL; /* lower bounds on g */ Number *g_U = NULL; /* upper bounds on g */ double *xldata, *xudata; double *gldata, *gudata; int i; DispatchData *dp = NULL; PyObject *retval = NULL; /* Init the myowndata field */ myowndata.eval_f_python = NULL; myowndata.eval_grad_f_python = NULL; myowndata.eval_g_python = NULL; myowndata.eval_jac_g_python = NULL; myowndata.eval_h_python = NULL; myowndata.apply_new_python = NULL; myowndata.userdata = NULL; /* "O!", &PyArray_Type &a_x */ if (!PyArg_ParseTuple(args, "iO!O!iO!O!iiOOOO|OO:pyipoptcreate", &n, &PyArray_Type, &xL, &PyArray_Type, &xU, &m, &PyArray_Type, &gL, &PyArray_Type, &gU, &nele_jac, &nele_hess, &f, &gradf, &g, &jacg, &h, &applynew)) { retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } if (!PyCallable_Check(f) || !PyCallable_Check(gradf) || !PyCallable_Check(g) || !PyCallable_Check(jacg)) { PyErr_SetString(PyExc_TypeError, "Need a callable object for callback functions"); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } myowndata.eval_f_python = f; myowndata.eval_grad_f_python = gradf; myowndata.eval_g_python = g; myowndata.eval_jac_g_python = jacg; if (h != NULL) { if (PyCallable_Check(h)) { myowndata.eval_h_python = h; } else { PyErr_SetString(PyExc_TypeError, "Need a callable object for function h."); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } } else { logger("[PyIPOPT] Ipopt will use Hessian approximation.\n"); } if (applynew != NULL) { if (PyCallable_Check(applynew)) { myowndata.apply_new_python = applynew; } else { PyErr_SetString(PyExc_TypeError, "Need a callable object for function applynew."); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } } if (m < 0 || n < 0) { PyErr_SetString(PyExc_TypeError, "m or n can't be negative"); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } x_L = (Number *) malloc(sizeof(Number) * n); x_U = (Number *) malloc(sizeof(Number) * n); if (!x_L || !x_U) { retval = PyErr_NoMemory(); SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } xldata = (double *)xL->data; xudata = (double *)xU->data; for (i = 0; i < n; i++) { x_L[i] = xldata[i]; x_U[i] = xudata[i]; } g_L = (Number *) malloc(sizeof(Number) * m); g_U = (Number *) malloc(sizeof(Number) * m); if (!g_L || !g_U) PyErr_NoMemory(); gldata = (double *)gL->data; gudata = (double *)gU->data; for (i = 0; i < m; i++) { g_L[i] = gldata[i]; g_U[i] = gudata[i]; } /* Grab the callback objects because we want to use them later. */ Py_XINCREF(f); Py_XINCREF(gradf); Py_XINCREF(g); Py_XINCREF(jacg); Py_XINCREF(h); Py_XINCREF(applynew); /* create the Ipopt Problem */ int C_indexstyle = 0; IpoptProblem thisnlp = CreateIpoptProblem(n, x_L, x_U, m, g_L, g_U, nele_jac, nele_hess, C_indexstyle, &eval_f, &eval_g, &eval_grad_f, &eval_jac_g, &eval_h); logger("[PyIPOPT] Problem created"); if (!thisnlp) { PyErr_SetString(PyExc_MemoryError, "Cannot create IpoptProblem instance"); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } object = PyObject_NEW(problem, &IpoptProblemType); if (object != NULL) { object->n_variables = n; object->m_constraints = m; object->nlp = thisnlp; dp = (DispatchData *) malloc(sizeof(DispatchData)); if (!dp) { retval = PyErr_NoMemory(); SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } memcpy((void *)dp, (void *)&myowndata, sizeof(DispatchData)); object->data = dp; retval = (PyObject *) object; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } else { PyErr_SetString(PyExc_MemoryError, "Can't create a new Problem instance"); retval = NULL; SAFE_FREE(x_L); SAFE_FREE(x_U); SAFE_FREE(g_L); SAFE_FREE(g_U); return retval; } } PyObject *set_intermediate_callback(PyObject * self, PyObject * args) { PyObject *intermediate_callback; problem *temp = (problem *) self; IpoptProblem nlp = (IpoptProblem) (temp->nlp); DispatchData myowndata; DispatchData *bigfield = (DispatchData *) (temp->data); /* Init the myowndata field */ myowndata.eval_intermediate_callback_python = NULL; if (!PyArg_ParseTuple(args, "O", &intermediate_callback)) { return NULL; } if (!PyCallable_Check(intermediate_callback)) { PyErr_SetString(PyExc_TypeError, "Need a callable object for function!"); return NULL; } else { bigfield->eval_intermediate_callback_python = intermediate_callback; /* Put a Python function object into this data structure */ /* * myowndata.eval_intermediate_callback_python = * intermediate_callback; */ /* DispatchData *dp = malloc(sizeof(DispatchData)); */ /* * memcpy((void*)dp, (void*)&myowndata, * sizeof(DispatchData)); */ /* bigfield = dp; */ /* * logger( "qqq: inside set_intermediate_callback, bigfield * is %p\n", bigfield ) ; */ /* * logger("[PyIPOPT] User specified data field to callback * function.\n"); */ SetIntermediateCallback(nlp, eval_intermediate_callback); Py_INCREF(Py_True); return Py_True; } } PyObject *solve(PyObject * self, PyObject * args) { enum ApplicationReturnStatus status; /* Solve return code */ int i; int n; /* Return values */ problem *temp = (problem *) self; IpoptProblem nlp = (IpoptProblem) (temp->nlp); DispatchData *bigfield = (DispatchData *) (temp->data); int m = temp->m_constraints; /* int dX[1]; */ npy_intp dX[1]; npy_intp dlambda[1]; PyArrayObject *x = NULL, *mL = NULL, *mU = NULL, *lambda = NULL; Number obj; /* objective value */ PyObject *retval = NULL; PyArrayObject *x0 = NULL; PyObject *myuserdata = NULL; Number *newx0 = NULL; if (!PyArg_ParseTuple(args, "O!|O", &PyArray_Type, &x0, &myuserdata)) { retval = NULL; /* clean up and return */ if (retval == NULL) { Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); } SAFE_FREE(newx0); return retval; } if (x0->nd != 1){ //If x0 is not 1-dimensional then solve will fail and cause a segmentation fault. logger("[ERROR] x0 must be a 1-dimensional array"); Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); PyErr_SetString(PyExc_TypeError, "x0 passed to solve is not 1-dimensional."); return NULL; } if (myuserdata != NULL) { bigfield->userdata = myuserdata; /* * logger("[PyIPOPT] User specified data field to callback * function.\n"); */ } if (nlp == NULL) { PyErr_SetString(PyExc_TypeError, "nlp objective passed to solve is NULL\n Problem created?\n"); retval = NULL; /* clean up and return */ if (retval == NULL) { Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); } SAFE_FREE(newx0); return retval; } if (bigfield->eval_h_python == NULL) { AddIpoptStrOption(nlp, "hessian_approximation", "limited-memory"); /* logger("Can't find eval_h callback function\n"); */ } /* allocate space for the initial point and set the values */ npy_intp *dim = ((PyArrayObject *) x0)->dimensions; n = dim[0]; dX[0] = n; x = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE); if (!x) { retval = PyErr_NoMemory(); /* clean up and return */ if (retval == NULL) { Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); } SAFE_FREE(newx0); return retval; } newx0 = (Number *) malloc(sizeof(Number) * n); if (!newx0) { retval = PyErr_NoMemory(); /* clean up and return */ if (retval == NULL) { Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); } SAFE_FREE(newx0); return retval; } double *xdata = (double *)x0->data; for (i = 0; i < n; i++) newx0[i] = xdata[i]; /* Allocate multiplier arrays */ mL = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE); mU = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE); dlambda[0] = m; lambda = (PyArrayObject *) PyArray_SimpleNew(1, dlambda, PyArray_DOUBLE); /* For status code, see IpReturnCodes_inc.h in Ipopt */ status = IpoptSolve(nlp, newx0, NULL, &obj, (double *)lambda->data, (double *)mL->data, (double *)mU->data, (UserDataPtr) bigfield); double *return_x_data = (double *)x->data; for (i = 0; i < n; i++) { return_x_data[i] = newx0[i]; } retval = Py_BuildValue("OOOOdi", PyArray_Return(x), PyArray_Return(mL), PyArray_Return(mU), PyArray_Return(lambda), obj, status ); /* clean up and return */ Py_XDECREF(x); Py_XDECREF(mL); Py_XDECREF(mU); Py_XDECREF(lambda); SAFE_FREE(newx0); return retval; } PyObject *close_model(PyObject * self, PyObject * args) { problem *obj = (problem *) self; DispatchData *dp = obj->data; /* Ungrab the callback functions because we do not need them anymore. */ Py_XDECREF(dp->eval_f_python); Py_XDECREF(dp->eval_grad_f_python); Py_XDECREF(dp->eval_g_python); Py_XDECREF(dp->eval_jac_g_python); Py_XDECREF(dp->eval_h_python); Py_XDECREF(dp->apply_new_python); FreeIpoptProblem(obj->nlp); obj->nlp = NULL; Py_INCREF(Py_True); return Py_True; } /* static char PYTEST[] = "TestCreate\n"; */ /* static PyObject *test(PyObject *self, PyObject *args) */ /* { */ /* IpoptProblem thisnlp = NULL; */ /* problem *object = NULL; */ /* object = PyObject_NEW(problem , &IpoptProblemType); */ /* if (object != NULL) */ /* object->nlp = thisnlp; */ /* /\* problem *object = problem_new(thisnlp); *\/ */ /* return (PyObject *)object; */ /* } */ /* Begin Python Module code section */ static PyMethodDef ipoptMethods[] = { /* { "solve", solve, METH_VARARGS, PYIPOPT_SOLVE_DOC}, */ {"create", create, METH_VARARGS, PYIPOPT_CREATE_DOC}, /* { "close", close_model, METH_VARARGS, PYIPOPT_CLOSE_DOC}, */ /* { "test", test, METH_VARARGS, PYTEST}, */ {"set_loglevel", set_loglevel, METH_VARARGS, PYIPOPT_LOG_DOC}, {NULL, NULL} }; #if PY_MAJOR_VERSION >= 3 #define MOD_ERROR_VAL NULL #define MOD_SUCCESS_VAL(val) val #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void) #define MOD_DEF(ob, name, doc, methods) \ static struct PyModuleDef moduledef = { \ PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \ ob = PyModule_Create(&moduledef); #else #define MOD_ERROR_VAL #define MOD_SUCCESS_VAL(val) #define MOD_INIT(name) void init##name(void) #define MOD_DEF(ob, name, doc, methods) \ ob = Py_InitModule3(name, methods, doc); #endif MOD_INIT(pyipoptcore) { PyObject * m; /* Finish initialization of the problem type */ if (PyType_Ready(&IpoptProblemType) < 0) { return MOD_ERROR_VAL; } MOD_DEF(m, "pyipoptcore", "A hook between Ipopt and Python", ipoptMethods) if (m == NULL) return MOD_ERROR_VAL; /* Initialize numpy. */ /* A segfault will occur if I use numarray without this.. */ import_array(); if (PyErr_Occurred()) { Py_FatalError("Unable to initialize module pyipoptcore"); } return MOD_SUCCESS_VAL(m); } /* End Python Module code section */ 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!132 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor