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