[
  {
    "path": ".gitignore",
    "content": ".*\n*.html\n# EXCEPTIONS\n!README\n!.gitignore\nbuild\npyipopt.so\n"
  },
  {
    "path": "Changelog",
    "content": "List of changes\n\n\tVersion 0.1 List works\n\n\tVersion 0.2 Use Numpy arrays instead of lists for efficiency\n\n\tVersion 0.3 Change the module interface to allocate more nlp instances instead of one\n\tnow use nlp = pyipopt.create(xxx)\n\t\tand nlp.solve\n\t\t\tnlp.close()\n\tnow we can create multiple instance of nlp. [Tested]\n\n\tVersion 0.4 Move all the pointers to the \n\tPyObject (callback function in Python) to the user_data field\n\tTherefore, the C callback function here can just dispatch it to the Python\n\tcallable object in the user_data [DONE]\n\t[We wrap the user_data twice]\n\n\tVersion 0.5: Bug in H matrix fixed\n\n\tVersion 0.5.1: some stupid spelling error in the source file and comments fixed.\n\n\tVersion 0.6: Fixed a memory leak problem (at least valgrind won't complain).\n\n\tVersion 0.7: Fixed a bug for the value of m and n, a bug for reference counting.\n\t\n\tVersion 0.8: Merged patches submitted by others, now supporting intermediate_callback (requires Ipopt>=3.9.1)\n\n\tVersion 0.8.1: Updated the README doc. \n\n\tVersion 0.8.2: Merged a change from Guillaume Jacquenot, now there is no GOTO in the source code.\n"
  },
  {
    "path": "README.md",
    "content": "PyIpopt\n=======\n\nPyIpopt 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.\n\nInstallation\n------------\n\n### Dependencies\n\nPyIpopt depends on the following packages:\n\n1. A compiler and a linker, e.g. gcc, ld\n2. [Ipopt](https://projects.coin-or.org/Ipopt)\n3. [Numpy](http://numpy.scipy.org/)\n4. Python.h (part of the python source code, you can download it from [Python.org](http://python.org))\n\n### Install\n\nFirst, get the latest source code using:\n\n  $ git clone http://github.com/xuy/pyipopt.git\n\nIn your PyIpopt folder, edit setup.py to reflect the configuration of your system, then do\n\n\t$ python setup.py build\n\t$ sudo python setup.py install\n\n### Test\n\n  $ python hs071.py\n\nYou should be able to see the result of solving the toy problem.\n\nUsage\n-----\nYou can use PyIpopt like this:\n\n\timport pyipopt\n\t# define your call back functions\n\tnlp = pyipopt.create(...)\n\tnlp.solve(...)\n\tnlp.close()\n\nYou can also check out hs071.py to see how to use PyIpopt.\n\nPyIpopt as a module comes with docstring. You can poke around \nit by using Python's $help()$ command.\n\nTesting\n-------\n\nI have included an example \n\nTo see if you have PyIpopt ready, use the following command under the pyipopt's directory. \n\n\t\tpython hs071.py\n\t\nThe 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. \n\nPyipopt 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. \n\n**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).\n\nContributing\n------------\n\n1. Fork it.\n2. Create a branch (`git checkout -b my_pyipopt`)\n3. Commit your changes (`git commit -am \"your awesome message\"`)\n4. Push to the branch (`git push origin my_pyipopt`)\n5. Create a pull request\n6. Nag me about it if I am lazy.\n\nTroubleshooting\n---------------\n\n### Check Ipopt\n\nPyIpopt links to Ipopt's C library. If that library is not available PyIpopt will fail\nduring module initialization. To check the availability of this library, you can go to\n\t$IPOPT_DIR/Ipopt/examples/hs071_c/\nand issue $make to ensure you can compile and run the toy example supplied by Ipopt. \n\n### Miscellaneous problems\n\n* Error:\n\timport pyipopt\n\tImportError: can not find  libipopt.so.0\n\n* Solution:\n    find it and copy it to a folder that ld can access\n\n* Error:\n\timport pyipopt\n\tImportError: /usr/lib/libipopt.so.0: undefined symbol: _gfortran_XXX\n\n* Solution: \n    check if your `hs071_c` example work. It is very likely that your ipopt library is not correctly compiled. \n\n\n* Error:\n\timport pyipopt\n\tImportError: /usr/lib/libipopt.so.0: undefined symbol: SetIntermediateCallback\n\n* Solution:\n\tSetIntermediateCallback is a function added since Ipopt 3.9.1. (see https://projects.coin-or.org/Ipopt/changeset/1830 )\n\tMake sure you have an Ipopt version >= 3.9.1\n\n* Error:\n\timport pyipopt\n\tImportError: /usr/lib/libipopt.so.0: undefined symbol: ma19ad_\n\n* Solution:\n\tFirst, use \n\t\tnm /usr/lib/libipopt.so.0 | grep ma19ad_ \n\tto 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\n\tby adding -lcoinhsl in the makefile of pyipopt. It seems to me that this happens in the recent versions of ipopt. Eventually\n\tpyipopt will have a better building mechanism, and I will fix this soon. \n\n* Error:\n\timport pyipopt\n\tImportError: /usr/lib/libipopt.so.0: undefined symbol: SomeKindOfSymbol\n\t\n* Solution:\n\tI 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. \n\tFirst, use \n\t\tnm /usr/lib/libipopt.so.0 | grep SomeKindOfSymbol\n\tto see if this symbol is indeed missing. Do a Google search to find the library file, and \n\tadd -lWhateverLibrary in the makefile of pyipopt. \n\t\n\tIpopt is built using various third-party libraries. Different machines may have different set of libraries. You should \n\ttry to locate these dependencies and indicate them when compiling pyipopt. This is just a limitation of dynamic linking libraries and \n\tis 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. \n\t\n\nContact\n--------\n\nEric Xu <xu.mathena@gmail.com>\n\nSoftware Engineer @ Google\n\n\n"
  },
  {
    "path": "examples/hs071.py",
    "content": "#!/usr/bin/python\n\n# Author: Eric Xu. Washington University\n#  The same model as Ipopt/examples/hs071\nfrom __future__ import print_function\n\nimport pyipopt\nfrom numpy import *\n\nnvar = 4\nx_L = ones((nvar), dtype=float_) * 1.0\nx_U = ones((nvar), dtype=float_) * 5.0\n\nncon = 2\n\ng_L = array([25.0, 40.0])\ng_U = array([2.0*pow(10.0, 19), 40.0]) \n\ndef eval_f(x, user_data = None):\n    assert len(x) == 4\n    return x[0] * x[3] * (x[0] + x[1] + x[2]) + x[2]\n\ndef eval_grad_f(x, user_data = None):\n    assert len(x) == 4\n    grad_f = array([\n        x[0] * x[3] + x[3] * (x[0] + x[1] + x[2]) , \n        x[0] * x[3],\n        x[0] * x[3] + 1.0,\n        x[0] * (x[0] + x[1] + x[2])\n        ], float_)\n    return grad_f;\n\ndef eval_g(x, user_data= None):\n    assert len(x) == 4\n    return array([\n        x[0] * x[1] * x[2] * x[3], \n        x[0]*x[0] + x[1]*x[1] + x[2]*x[2] + x[3]*x[3]\n        ], float_)\n\nnnzj = 8\ndef eval_jac_g(x, flag, user_data = None):\n    if flag:\n        return (array([0, 0, 0, 0, 1, 1, 1, 1]),\n                array([0, 1, 2, 3, 0, 1, 2, 3]))\n    else:\n        assert len(x) == 4\n        return array([ x[1]*x[2]*x[3], \n            x[0]*x[2]*x[3], \n            x[0]*x[1]*x[3], \n            x[0]*x[1]*x[2],\n            2.0*x[0], \n            2.0*x[1], \n            2.0*x[2], \n            2.0*x[3] ])\n\nnnzh = 10\ndef eval_h(x, lagrange, obj_factor, flag, user_data = None):\n    if flag:\n        hrow = [0, 1, 1, 2, 2, 2, 3, 3, 3, 3]\n        hcol = [0, 0, 1, 0, 1, 2, 0, 1, 2, 3]\n        return (array(hcol), array(hrow))\n    else:\n        values = zeros((10), float_)\n        values[0] = obj_factor * (2*x[3])\n        values[1] = obj_factor * (x[3])\n        values[2] = 0\n        values[3] = obj_factor * (x[3])\n        values[4] = 0\n        values[5] = 0\n        values[6] = obj_factor * (2*x[0] + x[1] + x[2])\n        values[7] = obj_factor * (x[0])\n        values[8] = obj_factor * (x[0])\n        values[9] = 0\n        values[1] += lagrange[0] * (x[2] * x[3])\n\n        values[3] += lagrange[0] * (x[1] * x[3])\n        values[4] += lagrange[0] * (x[0] * x[3])\n\n        values[6] += lagrange[0] * (x[1] * x[2])\n        values[7] += lagrange[0] * (x[0] * x[2])\n        values[8] += lagrange[0] * (x[0] * x[1])\n        values[0] += lagrange[1] * 2\n        values[2] += lagrange[1] * 2\n        values[5] += lagrange[1] * 2\n        values[9] += lagrange[1] * 2\n        return values\n\ndef apply_new(x):\n    return True\n\nnlp = pyipopt.create(nvar, x_L, x_U, ncon, g_L, g_U, nnzj, nnzh, eval_f, eval_grad_f, eval_g, eval_jac_g)\n\nx0 = array([1.0, 5.0, 5.0, 1.0])\npi0 = array([1.0, 1.0])\n\n\"\"\"\nprint x0\nprint nvar, ncon, nnzj\nprint x_L,  x_U\nprint g_L, g_U\nprint eval_f(x0)\nprint eval_grad_f(x0)\nprint eval_g(x0)\na =  eval_jac_g(x0, True)\nprint \"a = \", a[1], a[0]\nprint eval_jac_g(x0, False)\nprint eval_h(x0, pi0, 1.0, False)\nprint eval_h(x0, pi0, 1.0, True)\n\"\"\"\n\n\"\"\" You can set Ipopt options by calling nlp.num_option, nlp.str_option\nor nlp.int_option. For instance, to set the tolarance by calling\n\n    nlp.num_option('tol', 1e-8)\n\nFor a complete list of Ipopt options, refer to\n\n    http://www.coin-or.org/Ipopt/documentation/node59.html\n\nNote that Ipopt distinguishs between Int, Num, and Str options, yet sometimes\ndoes not explicitly tell you which option is which.  If you are not sure about\nthe option's type, just try it in PyIpopt.  If you try to set one type of\noption using the wrong function, Pyipopt will remind you of it. \"\"\"\n\nprint(\"Going to call solve\")\nprint(\"x0 = {}\".format(x0))\nx, zl, zu, constraint_multipliers, obj, status = nlp.solve(x0)\n# import pdb; pdb.set_trace()\nnlp.close()\n\ndef print_variable(variable_name, value):\n    for i in range(len(value)):\n        print(\"{} {}\".format(variable_name + \"[\"+str(i)+\"] =\", value[i]))\n\nprint(\"Solution of the primal variables, x\")\nprint_variable(\"x\", x)\n\nprint(\"Solution of the bound multipliers, z_L and z_U\")\nprint_variable(\"z_L\", zl)\nprint_variable(\"z_U\", zu)\n\nprint(\"Solution of the constraint multipliers, lambda\")\nprint_variable(\"lambda\", constraint_multipliers)\n\nprint(\"Objective value\")\nprint(\"f(x*) = {}\".format(obj))\n\n"
  },
  {
    "path": "examples/rosen.py",
    "content": "\"\"\"\nIs the hessian even supported by pyipopt?\n\nThere is a comment here\nhttp://www.wstein.org/home/wstein/www/home/was/patches/\nopenopt-0.24/src/openopt/solvers/CoinOr/ipopt_oo.py\nsuggesting that the pyipopt hessian support may be buggy.\nAlso check some bug reports here:\nhttp://code.google.com/p/pyipopt/issues/list\n?can=1&q=&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary&cells=tiles\n\"\"\"\nfrom __future__ import print_function\n\nimport numpy\nimport scipy.optimize\nimport pyipopt\n\ndef eval_f(X, user_data=None):\n    \"\"\"\n    Directly evaluate the objective function f.\n    \"\"\"\n    return scipy.optimize.rosen(X)\n\ndef eval_grad_f(X, user_data=None):\n    \"\"\"\n    Evaluate the gradient of the objective function f.\n    \"\"\"\n    return scipy.optimize.rosen_der(X)\n\ndef eval_g(X, user_data=None):\n    \"\"\"\n    Evaluate the constraint functions.\n    \"\"\"\n    return numpy.array([], dtype=float)\n\ndef eval_jac_g(X, flag, user_data=None):\n    \"\"\"\n    Evaluate the sparse Jacobian of constraint functions g.\n    @param X: parameter values\n    @param flag: this asks for the sparsity structure\n    \"\"\"\n    print('eval_jac_g')\n    print(X)\n    print(flag)\n    print(user_data)\n    print()\n    #XXX\n    if flag:\n        rows = numpy.array([], dtype=int)\n        cols = numpy.array([], dtype=int)\n        return (rows, cols)\n    else:\n        return numpy.array([], dtype=float)\n\ndef eval_h(X, lagrange, obj_factor, flag, user_data=None):\n    \"\"\"\n    Evaluate the sparse hessian of the Lagrangian.\n    @param X: parameter values\n    @param lagrange: something about the constraints\n    @param obj_factor: no clue what this is\n    @param flag: this asks for the sparsity structure\n    \"\"\"\n    #XXX\n    print('eval_h:')\n    print(X)\n    print(lagrange)\n    print(obj_factor)\n    print(flag)\n    print(user_data)\n    print()\n    rows = numpy.array([0, 1, 1], dtype=int)\n    cols = numpy.array([0, 0, 1], dtype=int)\n    if flag:\n        return (rows, cols)\n    else:\n        # XXX\n        # these values are meaningless\n        values = numpy.zeros(3, dtype=float)\n        #values[0] = obj_factor*2\n        #values[1] = 0\n        #values[2] = obj_factor*2\n        H = scipy.optimize.rosen_hess(X)\n        for i, (r, c) in enumerate(zip(rows, cols)):\n            values[i] = H[r, c] * obj_factor\n        return values\n\ndef apply_new(X):\n    \"\"\"\n    What is this?\n    \"\"\"\n    #XXX\n    print('apply_new:')\n    print(X)\n    print()\n    return True\n\n\ndef main():\n\n    # verbose\n    pyipopt.set_loglevel(2)\n\n    # define the parameters and their box constraints\n    nvar = 2\n    x_L = numpy.array([-3, -3], dtype=float)\n    x_U = numpy.array([3, 3], dtype=float)\n\n    # define the inequality constraints\n    ncon = 0\n    g_L = numpy.array([], dtype=float)\n    g_U = numpy.array([], dtype=float)\n\n    # define the number of nonzeros in the jacobian and in the hessian\n    # there are no nonzeros in the constraint jacobian\n    nnzj = 0\n\n    # there are maximum nonzeros (nvar*(nvar+1))/2 in the lagrangian hessian\n    nnzh = 3\n\n    # create the nonlinear programming model\n    nlp = pyipopt.create(\n            nvar,\n            x_L,\n            x_U,\n            ncon,\n            g_L,\n            g_U,\n            nnzj,\n            nnzh,\n            eval_f,\n            eval_grad_f,\n            eval_g,\n            eval_jac_g,\n            eval_h,\n            apply_new,\n            )\n\n    # define the initial guess\n    x0 = numpy.array([-1.2, 1], dtype=float)\n\n    # compute the results using ipopt\n    results = nlp.solve(x0)\n\n    # free the model\n    nlp.close()\n\n    # report the results\n    print(results)\n\n\nif __name__ == '__main__':\n    main()\n\n"
  },
  {
    "path": "examples/unconstrained/himmelblau.py",
    "content": "\"\"\"\nMinimize a standard unconstrained test function.\n\nThis example uses algopy for the gradient and hessian.\n\"\"\"\nfrom __future__ import print_function\n\nimport functools\n\nimport numpy\nimport algopy\n\nimport pyipopt\n\ndef himmelblau(X):\n    \"\"\"\n    http://en.wikipedia.org/wiki/Himmelblau%27s_function\n    This function has four local minima where the value of the function is 0.\n    \"\"\"\n    x = X[0]\n    y = X[1]\n    a = x*x + y - 11\n    b = x + y*y - 7\n    return a*a + b*b\n\ndef eval_grad(f, theta):\n    theta = algopy.UTPM.init_jacobian(theta)\n    return algopy.UTPM.extract_jacobian(f(theta))\n\ndef eval_hess(f, theta):\n    theta = algopy.UTPM.init_hessian(theta)\n    return algopy.UTPM.extract_hessian(len(theta), f(theta))\n\ndef main():\n    pyipopt.set_loglevel(2)\n    x0 = numpy.array([-0.27, -0.9], dtype=float)\n    results = pyipopt.fmin_unconstrained(\n            himmelblau,\n            x0,\n            fprime=functools.partial(eval_grad, himmelblau),\n            fhess=functools.partial(eval_hess, himmelblau),\n            )\n    print(results)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "examples/unconstrained/rosen.py",
    "content": "\"\"\"\nMinimize the Rosenbrock function with the unconstrained minimization interface.\n\nSee the rosen.py example for more details.\n\"\"\"\nfrom __future__ import print_function\n\nimport numpy\nimport scipy.optimize\n\nimport pyipopt\n\ndef main():\n    pyipopt.set_loglevel(2)\n    x0 = numpy.array([-1.2, 1], dtype=float)\n    results = pyipopt.fmin_unconstrained(\n            scipy.optimize.rosen,\n            x0,\n            fprime=scipy.optimize.rosen_der,\n            fhess=scipy.optimize.rosen_hess,\n            )\n    print(results)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "examples/unconstrained/wood.py",
    "content": "\"\"\"\nMinimize a standard unconstrained test function.\n\nThis example uses algopy for the gradient and hessian.\n\"\"\"\nfrom __future__ import print_function\n\nimport functools\n\nimport numpy\nimport algopy\n\nimport pyipopt\n\ndef wood(X):\n    \"\"\"\n    The minimum is at [1, 1, 1, 1].\n    \"\"\"\n    x1 = X[0]\n    x2 = X[1]\n    x3 = X[2]\n    x4 = X[3]\n    return sum((\n        100*(x1*x1 - x2)**2,\n        (x1-1)**2,\n        (x3-1)**2,\n        90*(x3*x3 - x4)**2,\n        10.1*((x2-1)**2 + (x4-1)**2),\n        19.8*(x2-1)*(x4-1),\n        ))\n\ndef eval_grad(f, theta):\n    theta = algopy.UTPM.init_jacobian(theta)\n    return algopy.UTPM.extract_jacobian(f(theta))\n\ndef eval_hess(f, theta):\n    theta = algopy.UTPM.init_hessian(theta)\n    return algopy.UTPM.extract_hessian(len(theta), f(theta))\n\ndef main():\n    pyipopt.set_loglevel(2)\n    x0 = numpy.array([-3, -1, -3, -1], dtype=float)\n    results = pyipopt.fmin_unconstrained(\n            wood,\n            x0,\n            fprime=functools.partial(eval_grad, wood),\n            fhess=functools.partial(eval_hess, wood),\n            )\n    print(results)\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "pyipoptpackage/__init__.py",
    "content": "\"\"\"\nThis is a package for a python interface to ipopt.\n\nThe underlying C interface is in pyipoptcore.\n\"\"\"\nimport os\nimport sys\n\nsys.path.append(os.path.dirname(__file__))\n\nimport functools\n\nimport numpy\n\nfrom ipoptconst import *\nfrom pyipoptcore import *\nfrom ipoptunconstrained import fmin_unconstrained\n\n# verbose messages from the C interface\nset_loglevel(2)\n\n"
  },
  {
    "path": "pyipoptpackage/ipoptconst.py",
    "content": "\"\"\"\nThese are some constants.\n\"\"\"\n\n# http://www.coin-or.org/Ipopt/documentation/node35.html\n# FIXME: these are not actually constant but may be changed within ipopt\nNLP_LOWER_BOUND_INF = -1e19\nNLP_UPPER_BOUND_INF = 1e19\n"
  },
  {
    "path": "pyipoptpackage/ipoptunconstrained.py",
    "content": "\"\"\"\nUnconstrained function minimization.\n\nThis is supposed to have an interface like the old scipy.optimize interface.\nThe underlying C interface is in pyipoptcore.\n\"\"\"\n\nimport functools\n\nimport numpy\n\nimport pyipoptcore\nfrom ipoptconst import NLP_LOWER_BOUND_INF\nfrom ipoptconst import NLP_UPPER_BOUND_INF\n\n\ndef _eval_g(X, user_data=None):\n    return numpy.array([], dtype=float)\n\ndef _eval_jac_g(X, flag, user_data=None):\n    rows = numpy.array([], dtype=int)\n    cols = numpy.array([], dtype=int)\n    if flag:\n        return (rows, cols)\n    else:\n        raise Exception(\n                'this should not be called for unconstrained optimization')\n\ndef _eval_h(\n        h, nvar,\n        X, lagrange, obj_factor, flag, user_data=None):\n    \"\"\"\n    The first group of parameters should be applied using functools.partial.\n    The second group of parameters are passed from ipopt.\n    @param h: a function to compute the hessian.\n    @param nvar: the number of parameters\n    @param X: parameter values\n    @param lagrange: something about the constraints\n    @param obj_factor: no clue what this is\n    @param flag: this asks for the sparsity structure\n    @param user_data: please do not use this yet\n    \"\"\"\n\n    # Get the nonzero (row, column) entries of a lower triangular matrix.\n    # This is related to the fact that the Hessian is symmetric,\n    # and that ipopt is designed to work with sparse matrices.\n    row_list = []\n    col_list = []\n    for row in range(nvar):\n        for col in range(row+1):\n            row_list.append(row)\n            col_list.append(col)\n    rows = numpy.array(row_list, dtype=int)\n    cols = numpy.array(col_list, dtype=int)\n\n    if flag:\n        return (rows, cols)\n    else:\n        if nvar != len(X):\n            raise Exception('parameter count mismatch')\n        if lagrange:\n            raise Exception('only unconstrained is implemented for now...')\n        values = numpy.zeros(len(rows), dtype=float)\n        H = h(X)\n        for i, (r, c) in enumerate(zip(rows, cols)):\n            #FIXME: am I using obj_factor correctly?\n            # I don't really know what it is...\n            values[i] = H[r, c] * obj_factor\n        return values\n\ndef _apply_new(X):\n    #FIXME: I don't really know what this does, but ipopt wants it.\n    return True\n\ndef _create(f, nvar, fprime, fhess=None):\n    \"\"\"\n    Creates an ipopt nlp object.\n    @param f: objective function to minimize\n    @param nvar: number of parameters\n    @param fprime: computes the gradient of the objective function\n    @param fhess: computes the hessian of the objective function\n    @return: a pyipopt nlp object which may be solved and then closed\n    \"\"\"\n\n    # no box constraints on the parameters\n    x_L = numpy.array([NLP_LOWER_BOUND_INF]*nvar, dtype=float)\n    x_U = numpy.array([NLP_UPPER_BOUND_INF]*nvar, dtype=float)\n    \n    # no other constraints\n    ncon = 0\n    g_L = numpy.array([], dtype=float)\n    g_U = numpy.array([], dtype=float)\n\n    # no constraint jacobian\n    nnzj = 0\n\n    # dense lower triangular hessian structure\n    nnzh = 0\n    if fhess:\n        nnzh = (nvar * (nvar + 1)) // 2\n\n    # define the nlp creation args\n    nlp_args = [\n            nvar,\n            x_L,\n            x_U,\n            ncon,\n            g_L,\n            g_U,\n            nnzj,\n            nnzh,\n            f,\n            fprime,\n            _eval_g,\n            _eval_jac_g,\n            ]\n    if fhess:\n        nlp_args.extend([\n            functools.partial(_eval_h, fhess, nvar),\n            _apply_new,\n            ])\n\n    # create the nlp object\n    return pyipoptcore.create(*nlp_args)\n\ndef fmin_unconstrained(f, x0, fprime, fhess=None):\n    \"\"\"\n    This is a utility function wrapping create_unconstrained.\n    @param f: objective function to minimize\n    @param x0: initial guess\n    @param fprime: computes the gradient of the objective function\n    @param fhess: computes the hessian of the objective function\n    @return: results in pyipoptcore format\n    \"\"\"\n    nvar = len(x0)\n    nlp = _create(f, nvar, fprime, fhess)\n    #FIXME: do something about this...\n    #http://www.coin-or.org/Ipopt/documentation/node68.html\n    nlp.num_option('tol', 1e-12)\n    results = nlp.solve(x0)\n    nlp.close()\n    return results\n\n"
  },
  {
    "path": "setup.py",
    "content": "# Originally contributed by Lorne McIntosh.\r\n# Modified by Eric Xu\r\n# Further modification by random internet people.\r\n\r\n# You will probably have to edit this file in unpredictable ways\r\n# if you want pyipopt to work for you, sorry.\r\n\r\n# When I installed Ipopt from source, I used the\r\n# --prefix=/usr/local\r\n# option, so this is where I want pyipopt to look for my ipopt installation.\r\n# I only installed from source because the ipopt packaging\r\n# for my linux distribution was buggy,\r\n# so by the time you read this the bugs have probably been fixed\r\n# and you will want to specify a different directory here.\r\nIPOPT_DIR = '/usr/local/'\r\n\r\nimport os\r\nfrom distutils.core import setup\r\nfrom distutils.extension import Extension\r\n\r\n# NumPy is much easier to install than pyipopt,\r\n# and is a pyipopt dependency, so require it here.\r\n# We need it to tell us where the numpy header files are.\r\nimport numpy\r\nnumpy_include = numpy.get_include()\r\n\r\n# I personally do not need support for lib64 but I'm keeping it in the code.\r\ndef get_ipopt_lib():\r\n    for lib_suffix in ('lib', 'lib64'):\r\n        d = os.path.join(IPOPT_DIR, lib_suffix)\r\n        if os.path.isdir(d):\r\n            return d\r\n\r\nIPOPT_LIB = get_ipopt_lib()\r\nif IPOPT_LIB is None:\r\n    raise Exception('failed to find ipopt lib')\r\n\r\nIPOPT_INC = os.path.join(IPOPT_DIR, 'include/coin/')\r\n\r\nFILES = ['src/callback.c', 'src/pyipoptcoremodule.c']\r\n\r\n# The extra_link_args is commented out here;\r\n# that line was causing my pyipopt install to not work.\r\n# Also I am using coinmumps instead of coinhsl.\r\npyipopt_extension = Extension(\r\n        'pyipoptcore',\r\n        FILES,\r\n        #extra_link_args=['-Wl,--rpath','-Wl,'+ IPOPT_LIB],\r\n        library_dirs=[IPOPT_LIB],\r\n        libraries=[\r\n            'ipopt', 'coinblas',\r\n            #'coinhsl',\r\n            'coinmumps',\r\n            'coinmetis',\r\n            'coinlapack','dl','m',\r\n            ],\r\n        include_dirs=[numpy_include, IPOPT_INC],\r\n        )\r\n\r\nsetup(\r\n        name=\"pyipopt\",\r\n        version=\"0.8\",\r\n        description=\"An IPOPT connector for Python\",\r\n        author=\"Eric Xu\",\r\n        author_email=\"xu.mathena@gmail.com\",\r\n        url=\"https://github.com/xuy/pyipopt\",\r\n        packages=['pyipopt'],\r\n        package_dir={'pyipopt' : 'pyipoptpackage'},\r\n        ext_package='pyipopt',\r\n        ext_modules=[pyipopt_extension],\r\n        )\r\n\r\n"
  },
  {
    "path": "src/callback.c",
    "content": "/*\n * Copyright (c) 2008, Eric You Xu, Washington University All rights\n * reserved. Redistribution and use in source and binary forms, with or\n * without modification, are permitted provided that the following conditions\n * are met:\n * \n * Redistributions of source code must retain the above copyright notice, this\n * list of conditions and the following disclaimer. * Redistributions in\n * binary form must reproduce the above copyright notice, this list of\n * conditions and the following disclaimer in the documentation and/or other\n * materials provided with the distribution. * Neither the name of the\n * Washington University nor the names of its contributors may be used to\n * endorse or promote products derived from this software without specific\n * prior written permission.\n * \n * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS \"AS IS\" AND ANY\n * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\n * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\n * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR\n * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\n * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\n * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\n * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\n * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\n * SUCH DAMAGE.\n */\n\n/* \n * Added \"eval_intermediate_callback\" by \n * OpenMDAO at NASA Glenn Research Center, 2010 and 2011\n *\n * Changed logger from code contributed by alanfalloon  \n*/\n\n#include \"hook.h\"\n#include <unistd.h>\n\nvoid logger(const char *fmt, ...)\n{\n\tif (user_log_level == VERBOSE) {\n\t\tva_list ap;\n\t\tva_start(ap, fmt);\n\t\tPySys_WriteStdout(fmt, ap);\n\t\tva_end(ap);\n\t\tPySys_WriteStdout(\"\\n\");\n\t}\n}\n\nBool eval_intermediate_callback(Index alg_mod,\t/* 0 is regular, 1 is resto */\n\t\t\t\tIndex iter_count, Number obj_value,\n\t\t\t\tNumber inf_pr, Number inf_du,\n\t\t\t\tNumber mu, Number d_norm,\n\t\t\t\tNumber regularization_size,\n\t\t\t\tNumber alpha_du, Number alpha_pr,\n\t\t\t\tIndex ls_trials, UserDataPtr data)\n{\n\t//logger(\"[Callback:E]intermediate_callback\");\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\tlong result_as_long;\n\tBool result_as_bool;\n\n\tPyObject *python_algmod = Py_BuildValue(\"i\", alg_mod);\n\tPyObject *python_iter_count = Py_BuildValue(\"i\", iter_count);\n\tPyObject *python_obj_value = Py_BuildValue(\"d\", obj_value);\n\tPyObject *python_inf_pr = Py_BuildValue(\"d\", inf_pr);\n\tPyObject *python_inf_du = Py_BuildValue(\"d\", inf_du);\n\tPyObject *python_mu = Py_BuildValue(\"d\", mu);\n\tPyObject *python_d_norm = Py_BuildValue(\"d\", d_norm);\n\tPyObject *python_regularization_size =\n\t    Py_BuildValue(\"d\", regularization_size);\n\tPyObject *python_alpha_du = Py_BuildValue(\"d\", alpha_du);\n\tPyObject *python_alpha_pr = Py_BuildValue(\"d\", alpha_pr);\n\tPyObject *python_ls_trials = Py_BuildValue(\"i\", ls_trials);\n\n\tPyObject *arglist = NULL;\n\n\tif (user_data != NULL)\n\t\targlist = Py_BuildValue(\"(OOOOOOOOOOOO)\",\n\t\t\t\t\tpython_algmod,\n\t\t\t\t\tpython_iter_count,\n\t\t\t\t\tpython_obj_value,\n\t\t\t\t\tpython_inf_pr,\n\t\t\t\t\tpython_inf_du,\n\t\t\t\t\tpython_mu,\n\t\t\t\t\tpython_d_norm,\n\t\t\t\t\tpython_regularization_size,\n\t\t\t\t\tpython_alpha_du,\n\t\t\t\t\tpython_alpha_pr,\n\t\t\t\t\tpython_ls_trials,\n\t\t\t\t\t(PyObject *) user_data);\n\telse\n\t\targlist = Py_BuildValue(\"(OOOOOOOOOOO)\",\n\t\t\t\t\tpython_algmod,\n\t\t\t\t\tpython_iter_count,\n\t\t\t\t\tpython_obj_value,\n\t\t\t\t\tpython_inf_pr,\n\t\t\t\t\tpython_inf_du,\n\t\t\t\t\tpython_mu,\n\t\t\t\t\tpython_d_norm,\n\t\t\t\t\tpython_regularization_size,\n\t\t\t\t\tpython_alpha_du,\n\t\t\t\t\tpython_alpha_pr, python_ls_trials);\n\n\tPyObject *result =\n\t    PyObject_CallObject(myowndata->eval_intermediate_callback_python,\n\t\t\t\targlist);\n\n\tif (!result)\n\t\tPyErr_Print();\n\n\tresult_as_long = PyLong_AsLong(result);\n\tresult_as_bool = (Bool) result_as_long;\n\n\tPy_DECREF(result);\n\tPy_CLEAR(arglist);\n\t//logger(\"[Callback:R] intermediate_callback\");\n\treturn result_as_bool;\n}\n\nBool\neval_f(Index n, Number * x, Bool new_x, Number * obj_value, UserDataPtr data)\n{\n\t//logger(\"[Callback:E] eval_f\");\n\n\tnpy_intp dims[1];\n\tdims[0] = n;\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\t// import_array ();\n\n\timport_array1(FALSE);\n\tPyObject *arrayx =\n\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x);\n\tif (!arrayx)\n\t\treturn FALSE;\n\n\tif (new_x && myowndata->apply_new_python) {\n\t\t/* Call the python function to applynew */\n\t\tPyObject *arg1;\n\t\targ1 = Py_BuildValue(\"(O)\", arrayx);\n\t\tPyObject *tempresult = PyObject_CallObject(\n        myowndata->apply_new_python, arg1);\n\t\tif (tempresult == NULL) {\n\t\t\tlogger(\"[Error] Python function apply_new returns NULL\");\n      PyErr_Print();\n\t\t\tPy_DECREF(arg1);\n\t\t\treturn FALSE;\n\t\t}\n\t\tPy_DECREF(arg1);\n\t\tPy_DECREF(tempresult);\n\t}\n\n\tPyObject *arglist;\n\tif (user_data != NULL) {\n\t\targlist = Py_BuildValue(\"(OO)\", arrayx, (PyObject *) user_data);\n  } else {\n\t\targlist = Py_BuildValue(\"(O)\", arrayx);\n  }\n\n\tPyObject *result = PyObject_CallObject(myowndata->eval_f_python, arglist);\n\n\tif (result == NULL) {\n    logger(\"[Error] Python function eval_f returns NULL\");\n\t\tPyErr_Print();\n\t\tPy_DECREF(arrayx);\n\t\tPy_CLEAR(arglist);\n\t\treturn FALSE;\n\t}\n\n\t*obj_value = PyFloat_AsDouble(result);\n\n  if (PyErr_Occurred()) {\n    logger(\"[Error] Python function eval_f returns non-PyFloat\");\n\t\tPyErr_Print();\n\t\tPy_DECREF(result);\n\t\tPy_DECREF(arrayx);\n\t\tPy_CLEAR(arglist);\n\t\treturn FALSE;\n  }\n\n\tPy_DECREF(result);\n\tPy_DECREF(arrayx);\n\tPy_CLEAR(arglist);\n\t//logger(\"[Callback:R] eval_f\");\n\treturn TRUE;\n}\n\nBool\neval_grad_f(Index n, Number * x, Bool new_x, Number * grad_f, UserDataPtr data)\n{\n\t//logger(\"[Callback:E] eval_grad_f\");\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\tif (myowndata->eval_grad_f_python == NULL)\n\t\tPyErr_Print();\n\n\t/* int dims[1]; */\n\tnpy_intp dims[1];\n\tdims[0] = n;\n\t// import_array ();\n\n\timport_array1(FALSE);\n\n\t/*\n\t * PyObject *arrayx = PyArray_FromDimsAndData(1, dims, PyArray_DOUBLE\n\t * , (char*) x);\n\t */\n\tPyObject *arrayx =\n\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x);\n\tif (!arrayx)\n\t\treturn FALSE;\n\n\tif (new_x && myowndata->apply_new_python) {\n\t\t/* Call the python function to applynew */\n\t\tPyObject *arg1 = Py_BuildValue(\"(O)\", arrayx);\n\t\tPyObject *tempresult = PyObject_CallObject(\n        myowndata->apply_new_python, arg1);\n\t\tif (tempresult == NULL) {\n\t\t\tlogger(\"[Error] Python function apply_new returns NULL\");\n      PyErr_Print();\n\t\t\tPy_DECREF(arg1);\n\t\t\treturn FALSE;\n\t\t}\n\t\tPy_DECREF(arg1);\n\t\tPy_DECREF(tempresult);\n\t}\n\n\tPyObject *arglist;\n\tif (user_data != NULL)\n\t\targlist = Py_BuildValue(\"(OO)\", arrayx, (PyObject *) user_data);\n\telse\n\t\targlist = Py_BuildValue(\"(O)\", arrayx);\n\n\tPyArrayObject *result = (PyArrayObject *) PyObject_CallObject(\n      myowndata->eval_grad_f_python, arglist);\n\n\tif (result == NULL) {\n    logger(\"[Error] Python function eval_grad_f returns NULL\");\n\t\tPyErr_Print();\n    return FALSE;\n  }\n  \n  if (!PyArray_Check(result)) {\n    logger(\"[Error] Python function eval_grad_f returns non-PyArray\");\n    Py_DECREF(result);\n    return FALSE;\n  }\n\n\tdouble *tempdata = (double *)result->data;\n\tint i;\n\tfor (i = 0; i < n; i++)\n\t\tgrad_f[i] = tempdata[i];\n\n\tPy_DECREF(result);\n\tPy_CLEAR(arrayx);\n\tPy_CLEAR(arglist);\n\t//logger(\"[Callback:R] eval_grad_f\");\n\treturn TRUE;\n}\n\nBool\neval_g(Index n, Number * x, Bool new_x, Index m, Number * g, UserDataPtr data)\n{\n\n\t//logger(\"[Callback:E] eval_g\");\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\tif (myowndata->eval_g_python == NULL)\n\t\tPyErr_Print();\n\t/* int dims[1]; */\n\tnpy_intp dims[1];\n\tint i;\n\tdouble *tempdata;\n\n\tdims[0] = n;\n\t// import_array ();\n\n\timport_array1(FALSE);\n\n\t/*\n\t * PyObject *arrayx = PyArray_FromDimsAndData(1, dims, PyArray_DOUBLE\n\t * , (char*) x);\n\t */\n\tPyObject *arrayx =\n\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE, (char *)x);\n\tif (!arrayx)\n\t\treturn FALSE;\n\n\tif (new_x && myowndata->apply_new_python) {\n\t\t/* Call the python function to applynew */\n\t\tPyObject *arg1 = Py_BuildValue(\"(O)\", arrayx);\n\t\tPyObject *tempresult = PyObject_CallObject(\n        myowndata->apply_new_python, arg1);\n\t\tif (tempresult == NULL) {\n\t\t\tlogger(\"[Error] Python function apply_new returns NULL\");\n      PyErr_Print();\n\t\t\tPy_DECREF(arg1);\n\t\t\treturn FALSE;\n\t\t}\n\t\tPy_DECREF(arg1);\n\t\tPy_DECREF(tempresult);\n\t}\n\n\tPyObject *arglist;\n\tif (user_data != NULL)\n\t\targlist = Py_BuildValue(\"(OO)\", arrayx, (PyObject *) user_data);\n\telse\n\t\targlist = Py_BuildValue(\"(O)\", arrayx);\n\n\tPyArrayObject *result = (PyArrayObject *) PyObject_CallObject(\n      myowndata->eval_g_python, arglist);\n\n  if (result == NULL) {\n    logger(\"[Error] Python function eval_g returns NULL\");\n\t\tPyErr_Print();\n    return FALSE;\n  }\n  \n  if (!PyArray_Check(result)) {\n    logger(\"[Error] Python function eval_g returns non-PyArray\");\n    Py_DECREF(result);\n    return FALSE;\n  }\n\n\ttempdata = (double *)result->data;\n\tfor (i = 0; i < m; i++) {\n\t\tg[i] = tempdata[i];\n\t}\n\n\tPy_DECREF(result);\n\tPy_CLEAR(arrayx);\n\tPy_CLEAR(arglist);\n\t//logger(\"[Callback:R] eval_g\");\n\treturn TRUE;\n}\n\nBool\neval_jac_g(Index n, Number * x, Bool new_x,\n\t   Index m, Index nele_jac,\n\t   Index * iRow, Index * jCol, Number * values, UserDataPtr data)\n{\n\n\t//logger(\"[Callback:E] eval_jac_g\");\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\tint i;\n\tlong *rowd = NULL;\n\tlong *cold = NULL;\n\n\t/* int dims[1]; */\n\tnpy_intp dims[1];\n\tdims[0] = n;\n\n\tdouble *tempdata;\n\n\tif (myowndata->eval_grad_f_python == NULL)\t/* Why??? */\n\t\tPyErr_Print();\n\n\tif (values == NULL) {\n\t\t/* import_array (); */\n\t\timport_array1(FALSE);\n\n\t\tPyObject *arrayx =\n\t\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE,\n\t\t\t\t\t      (char *)x);\n\t\tif (!arrayx)\n\t\t\treturn FALSE;\n\n\t\tPyObject *arglist;\n\n\t\tif (user_data != NULL)\n\t\t\targlist = Py_BuildValue(\"(OOO)\",\n\t\t\t\t\t\tarrayx, Py_True,\n\t\t\t\t\t\t(PyObject *) user_data);\n\t\telse\n\t\t\targlist = Py_BuildValue(\"(OO)\", arrayx, Py_True);\n\n\t\tPyObject *result =\n\t\t    PyObject_CallObject(myowndata->eval_jac_g_python, arglist);\n\t\tif (!result) {\n\n\t\t\tlogger(\"[PyIPOPT] return from eval_jac_g is null\\n\");\n\t\t\t/* TODO: need to deal with reference counting here */\n\t\t\treturn FALSE;\n\t\t}\n\t\tif (!PyTuple_Check(result)) {\n\t\t\tPyErr_Print();\n\t\t}\n\t\tPyArrayObject *row =\n\t\t    (PyArrayObject *) PyTuple_GetItem(result, 0);\n\t\tPyArrayObject *col =\n\t\t    (PyArrayObject *) PyTuple_GetItem(result, 1);\n\n\t\tif (!row || !col || !PyArray_Check(row) || !PyArray_Check(col)) {\n\t\t\tlogger\n\t\t\t    (\"[Error] there are problems with row or col in eval_jac_g.\\n\");\n\t\t\tPyErr_Print();\n\t\t}\n\t\trowd = (long *)row->data;\n\t\tcold = (long *)col->data;\n\n\t\tfor (i = 0; i < nele_jac; i++) {\n\t\t\tiRow[i] = (Index) rowd[i];\n\t\t\tjCol[i] = (Index) cold[i];\n\t\t}\n\t\tPy_CLEAR(arrayx);\n\t\tPy_DECREF(result);\n\t\tPy_CLEAR(arglist);\n\t\t//logger(\"[Callback:R] eval_jac_g(1)\");\n\t} else {\n\t\tPyObject *arrayx =\n\t\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE,\n\t\t\t\t\t      (char *)x);\n\n\t\tif (!arrayx)\n\t\t\treturn FALSE;\n\n\t\tif (new_x && myowndata->apply_new_python) {\n\t\t\t/* Call the python function to applynew */\n\t\t\tPyObject *arg1 = Py_BuildValue(\"(O)\", arrayx);\n\t\t\tPyObject *tempresult =\n\t\t\t    PyObject_CallObject(myowndata->apply_new_python,\n\t\t\t\t\t\targ1);\n\t\t\tif (tempresult == NULL) {\n\t\t\t\tlogger(\"[Error] Python function apply_new returns NULL\");\n\t\t\t\tPy_DECREF(arg1);\n\t\t\t\treturn FALSE;\n\t\t\t}\n\t\t\tPy_DECREF(arg1);\n\t\t\tPy_DECREF(tempresult);\n\t\t}\n\t\tPyObject *arglist;\n\t\tif (user_data != NULL)\n\t\t\targlist = Py_BuildValue(\"(OOO)\",\n\t\t\t\t\t\tarrayx, Py_False,\n\t\t\t\t\t\t(PyObject *) user_data);\n\t\telse\n\t\t\targlist = Py_BuildValue(\"(OO)\", arrayx, Py_False);\n\n\t\tPyArrayObject *result = (PyArrayObject *) PyObject_CallObject(\n        myowndata->eval_jac_g_python, arglist);\n\n\t\tif (result == NULL) {\n      logger(\"[Error] Python function eval_jac_g returns NULL\");\n\t\t\tPyErr_Print();\n      return FALSE;\n    }\n\n    if (!PyArray_Check(result)) {\n      logger(\"[Error] Python function eval_jac_g returns non-PyArray\");\n      Py_DECREF(result);\n      return FALSE;\n    }\n\n\t\t/*\n\t\t * Code is buggy here. We assume that result is a double\n\t\t * array\n\t\t */\n\t\tassert(result->descr->type == 'd');\n\t\ttempdata = (double *)result->data;\n\n\t\tfor (i = 0; i < nele_jac; i++)\n\t\t\tvalues[i] = tempdata[i];\n\n\t\tPy_DECREF(result);\n\t\tPy_CLEAR(arrayx);\n\t\tPy_CLEAR(arglist);\n\t\t//logger(\"[Callback:R] eval_jac_g(2)\");\n\t}\n\t//logger(\"[Callback:R] eval_jac_g\");\n\treturn TRUE;\n}\n\nBool\neval_h(Index n, Number * x, Bool new_x, Number obj_factor,\n       Index m, Number * lambda, Bool new_lambda,\n       Index nele_hess, Index * iRow, Index * jCol,\n       Number * values, UserDataPtr data)\n{\n\t//logger(\"[Callback:E] eval_h\");\n\n\tDispatchData *myowndata = (DispatchData *) data;\n\tUserDataPtr user_data = (UserDataPtr) myowndata->userdata;\n\n\tint i;\n\tnpy_intp dims[1];\n\tnpy_intp dims2[1];\n\n\tif (myowndata->eval_h_python == NULL) {\n\t\tlogger(\"[Error] There is no eval_h assigned\");\n\t\treturn FALSE;\n\t}\n\tif (values == NULL) {\n    //logger(\"[Callback:E] eval_h (1a)\");\n\t\tPyObject *newx = Py_True;\n\t\tPyObject *objfactor = Py_BuildValue(\"d\", obj_factor);\n\t\tPyObject *lagrange = Py_True;\n\n\t\tPyObject *arglist;\n\n\t\tif (user_data != NULL) {\n\t\t\targlist = Py_BuildValue(\n          \"(OOOOO)\", newx, lagrange, objfactor, Py_True,\n          (PyObject *) user_data);\n    } else {\n\t\t\targlist = Py_BuildValue(\n          \"(OOOO)\", newx, lagrange, objfactor, Py_True);\n    }\n\n    if (arglist == NULL) {\n      logger(\"[Error] failed to build arglist for eval_h\");\n\t\t\tPyErr_Print();\n      return FALSE;\n    } else {\n      logger(\"[Logspam] built arglist for eval_h\");\n    }\n\n\t\tPyObject *result = PyObject_CallObject(myowndata->eval_h_python, arglist);\n\n    if (result == NULL) {\n      logger(\"[Error] Python function eval_h returns NULL\");\n\t\t\tPyErr_Print();\n      return FALSE;\n    } else {\n      logger(\"[Logspam] Python function eval_h returns non-NULL\");\n    }\n\n    int result_size = PyTuple_Size(result);\n\n    if (result_size == -1) {\n      logger(\"[Error] Python function eval_h returns non-PyTuple\");\n      Py_DECREF(result);\n      return FALSE;\n    }\n\n    if (result_size != 2) {\n      logger(\"[Error] Python function eval_h returns a tuple whose len != 2\");\n      Py_DECREF(result);\n      return FALSE;\n    }\n\n    //logger(\"[Callback:E] eval_h (tuple is the right length)\");\n\n\t\tPyArrayObject *row = (PyArrayObject *) PyTuple_GetItem(result, 0);\n\t\tPyArrayObject *col = (PyArrayObject *) PyTuple_GetItem(result, 1);\n\n\t\tlong *rdata = (long *)row->data;\n\t\tlong *cdata = (long *)col->data;\n\n\t\tfor (i = 0; i < nele_hess; i++) {\n\t\t\tiRow[i] = (Index) rdata[i];\n\t\t\tjCol[i] = (Index) cdata[i];\n\t\t\t/*\n\t\t\t * logger(\"PyIPOPT_DEBUG %d, %d\\n\", iRow[i],\n\t\t\t * jCol[i]);\n\t\t\t */\n\t\t}\n\n    //logger(\"[Callback:E] eval_h (clearing stuff now)\");\n\n\t\tPy_DECREF(objfactor);\n\t\tPy_DECREF(result);\n\t\tPy_CLEAR(arglist);\n\t\t//logger(\"[Callback:R] eval_h (1b)\");\n\t} else {\n\t\t//logger(\"[Callback:R] eval_h (2a)\");\n\n\t\tPyObject *objfactor = Py_BuildValue(\"d\", obj_factor);\n\n\t\tdims[0] = n;\n\t\tPyObject *arrayx =\n\t\t    PyArray_SimpleNewFromData(1, dims, PyArray_DOUBLE,\n\t\t\t\t\t      (char *)x);\n\t\tif (!arrayx)\n\t\t\treturn FALSE;\n\n\t\tif (new_x && myowndata->apply_new_python) {\n\t\t\t/* Call the python function to applynew  */\n\t\t\tPyObject *arg1 = Py_BuildValue(\"(O)\", arrayx);\n\t\t\tPyObject *tempresult = PyObject_CallObject(\n          myowndata->apply_new_python, arg1);\n\t\t\tif (tempresult == NULL) {\n\t\t\t\tlogger(\"[Error] Python function apply_new returns NULL\");\n        PyErr_Print();\n\t\t\t\tPy_DECREF(arg1);\n\t\t\t\treturn FALSE;\n\t\t\t}\n\t\t\tPy_DECREF(arg1);\n\t\t\tPy_DECREF(tempresult);\n\t\t}\n\t\tdims2[0] = m;\n\t\tPyObject *lagrangex = PyArray_SimpleNewFromData(\n        1, dims2, PyArray_DOUBLE, (char *)lambda);\n\t\tif (!lagrangex)\n\t\t\treturn FALSE;\n\n\t\tPyObject *arglist;\n\n\t\tif (user_data != NULL) {\n\t\t\targlist = Py_BuildValue(\n          \"(OOOOO)\", arrayx, lagrangex, objfactor, Py_False,\n          (PyObject *) user_data);\n    } else {\n\t\t\targlist = Py_BuildValue(\n          \"(OOOO)\", arrayx, lagrangex, objfactor, Py_False);\n    }\n\t\tPyArrayObject *result = (PyArrayObject *) PyObject_CallObject(\n        myowndata->eval_h_python, arglist);\n\n\t\tif (result == NULL) {\n      logger(\"[Error] Python function eval_h returns NULL\");\n\t\t\tPyErr_Print();\n      return FALSE;\n    }\n\n    if (!PyArray_Check(result)) {\n      logger(\"[Error] Python function eval_h returns non-PyArray\");\n      Py_DECREF(result);\n      return FALSE;\n    }\n\n\t\tdouble *tempdata = (double *)result->data;\n\t\tfor (i = 0; i < nele_hess; i++) {\n\t\t\tvalues[i] = tempdata[i];\n\t\t}\n\t\tPy_CLEAR(arrayx);\n\t\tPy_CLEAR(lagrangex);\n\t\tPy_CLEAR(objfactor);\n\t\tPy_DECREF(result);\n\t\tPy_CLEAR(arglist);\n\t\t//logger(\"[Callback:R] eval_h (2b)\");\n\t}\n\treturn TRUE;\n}\n"
  },
  {
    "path": "src/hook.h",
    "content": "//  Author: Eric Xu\n//  Licensed under BSD\n\n#include \"Python.h\"\n#include \"IpStdCInterface.h\"\n#include <stdio.h>\n#include \"numpy/arrayobject.h\"\n\n#ifndef PY_IPOPT_HOOK_\n#define PY_IPOPT_HOOK_\n\n// A series of callback functions used by Ipopt C Interface\nBool eval_f(Index n,\n\t    Number * x, Bool new_x, Number * obj_value, UserDataPtr user_data);\n\nBool eval_grad_f(Index n,\n\t\t Number * x,\n\t\t Bool new_x, Number * grad_f, UserDataPtr user_data);\n\nBool eval_g(Index n,\n\t    Number * x, Bool new_x, Index m, Number * g, UserDataPtr user_data);\n\nBool eval_jac_g(Index n, Number * x, Bool new_x,\n\t\tIndex m, Index nele_jac,\n\t\tIndex * iRow, Index * jCol, Number * values,\n\t\tUserDataPtr user_data);\n\nBool eval_h(Index n, Number * x, Bool new_x, Number obj_factor,\n\t    Index m, Number * lambda, Bool new_lambda,\n\t    Index nele_hess, Index * iRow, Index * jCol,\n\t    Number * values, UserDataPtr user_data);\n\nBool eval_intermediate_callback(Index alg_mod,\n\t\t\t\tIndex iter_count, Number obj_value,\n\t\t\t\tNumber inf_pr, Number inf_du,\n\t\t\t\tNumber mu, Number d_norm,\n\t\t\t\tNumber regularization_size,\n\t\t\t\tNumber alpha_du, Number alpha_pr,\n\t\t\t\tIndex ls_trials, UserDataPtr data);\n\ntypedef struct {\n\tPyObject *eval_f_python;\n\tPyObject *eval_grad_f_python;\n\tPyObject *eval_g_python;\n\tPyObject *eval_jac_g_python;\n\tPyObject *eval_h_python;\n\tPyObject *apply_new_python;\n\tPyObject *eval_intermediate_callback_python;\n\tPyObject *userdata;\n} DispatchData;\n\n\n#if PY_MAJOR_VERSION < 3\nPyObject *problem_getattr(PyObject * self, char *attrname);\n#endif\n\n/* Logging */\n#define VERBOSE 2\n#define IPOPT_OUTPUT 1\n#define TERSE 0\nextern int user_log_level;\nvoid logger(const char *fmt, ...);\n\ntypedef struct {\n\tPyObject_HEAD IpoptProblem nlp;\n\tDispatchData *data;\n\tIndex n_variables;\n\tIndex m_constraints;\n} problem;\n\n#endif\t\t\t\t//  PY_IPOPT_HOOK_\n"
  },
  {
    "path": "src/pyipoptcoremodule.c",
    "content": "/*  Author: Eric Xu                                       */\n/*  Licensed under BSD                                    */\n/*                                                        */\n/*  Modifications on logger made by                       */\n/*  OpenMDAO at NASA Glenn Research Center, 2010 and 2011 */\n/*  Modifications on the SAFE_FREE macro made by          */\n/*  Guillaume Jacquenot, 2012                             */\n\n#include \"hook.h\"\n\n#ifndef SAFE_FREE\n#define SAFE_FREE(p) {if (p) {free(p); (p)= NULL;}}\n#endif\n\n/*\n * Let's put the static char docs at the beginning of this file...\n */\n\nstatic char PYIPOPT_SOLVE_DOC[] = \"solve(x) -> (x, ml, mu, obj)\\n \\\n  \\n                                                        \\\n  Call Ipopt to solve problem created before and return  \\n \\\n  a tuple that contains final solution x, upper and lower\\n \\\n  bound for multiplier, final objective function obj, \\n \\\n  and the return status of ipopt. \\n\";\n\nstatic char PYIPOPT_SET_INTERMEDIATE_CALLBACK_DOC[] =\n    \"set_intermediate_callback(callback_function)\\n \\\n  \\n                                              \\\n  Set the intermediate callback function.         \\\n  This gets called each iteration.\";\n\nstatic char PYIPOPT_CLOSE_DOC[] = \"After all the solving, close the model\\n\";\n\nstatic char PYIPOPT_ADD_STR_OPTION_DOC[] =\n    \"Set the String (char* in C) option for Ipopt. Refer to the Ipopt \\n \\\n     document for more information about Ipopt options, or use \\n \\\n       ipopt --print-options \\n \\\n     to see a list of available options.\";\n\nstatic char PYIPOPT_ADD_INT_OPTION_DOC[] =\n    \"Set the Int (int in C) option for Ipopt. Refer to the Ipopt \\n \\\n     document for more information about Ipopt options, or use \\n \\\n       ipopt --print-options \\n \\\n     to see a list of available options.\";\n\nstatic char PYIPOPT_ADD_NUM_OPTION_DOC[] =\n    \"Set the Number (double in C) option for Ipopt. Refer to the Ipopt \\n \\\n     document for more information about Ipopt options, or use \\n \\\n       ipopt --print-options \\n \\\n     to see a list of available options.\";\n\nstatic char PYIPOPT_CREATE_DOC[] =\n    \"create(n, xl, xu, m, gl, gu, nnzj, nnzh, eval_f, eval_grad_f, eval_g, eval_jac_g) -> Boolean\\n \\\n       \\n \\\n       Create a problem instance and return True if succeed  \\n \\\n       \\n \\\n       n is the number of variables, \\n \\\n       xl is the lower bound of x as bounded constraints \\n \\\n       xu is the upper bound of x as bounded constraints \\n \\\n               both xl, xu should be one dimension arrays with length n \\n \\\n       \\n \\\n       m is the number of constraints, \\n \\\n       gl is the lower bound of constraints \\n \\\n       gu is the upper bound of constraints \\n \\\n               both gl, gu should be one dimension arrays with length m \\n \\\n       nnzj is the number of nonzeros in Jacobi matrix \\n \\\n       nnzh is the number of non-zeros in Hessian matrix, you can set it to 0 \\n \\\n       \\n \\\n       eval_f is the call back function to calculate objective value, \\n \\\n               it takes one single argument x as input vector \\n \\\n       eval_grad_f calculates gradient for objective function \\n \\\n       eval_g calculates the constraint values and return an array \\n \\\n       eval_jac_g calculates the Jacobi matrix. It takes two arguments, \\n \\\n               the first is the variable x and the second is a Boolean flag \\n \\\n               if the flag is true, it supposed to return a tuple (row, col) \\n \\\n                       to indicate the sparse Jacobi matrix's structure. \\n \\\n               if the flag is false if returns the values of the Jacobi matrix \\n \\\n                       with length nnzj \\n \\\n       eval_h calculates the hessian matrix, it's optional. \\n \\\n               if omitted, please set nnzh to 0 and Ipopt will use approximated hessian \\n \\\n               which will make the convergence slower. \";\n\nstatic char PYIPOPT_LOG_DOC[] = \"set_loglevel(level)\\n \\\n    \\n \\\n    Set the log level of PyIPOPT \\n \\\n    levels: \\n \\\n        0:  Terse,    no log from pyipopt \\n \\\n        1:  Moderate, logs for ipopt \\n \\\n        2:  Verbose,  logs for both ipopt and pyipopt. \\n\";\n\n\n\nint user_log_level = TERSE;\n\n/* Object Section */\n/* sig of this is void foo(PyO*) */\nstatic void problem_dealloc(PyObject * self)\n{\n\tproblem *temp = (problem *) self;\n\tSAFE_FREE(temp->data);\n\tPy_TYPE(self)->tp_free((PyObject*)self);\n}\n\nPyObject *solve(PyObject * self, PyObject * args);\nPyObject *set_intermediate_callback(PyObject * self, PyObject * args);\nPyObject *close_model(PyObject * self, PyObject * args);\n\nstatic PyObject *add_str_option(PyObject * self, PyObject * args)\n{\n\tproblem *temp = (problem *) self;\n\tIpoptProblem nlp = (IpoptProblem) (temp->nlp);\n\tchar *param;\n\tchar *value;\n\tBool ret;\n\n\tif (!PyArg_ParseTuple(args, \"ss:str_option\", &param, &value)) {\n\t\treturn NULL;\n\t}\n\tret = AddIpoptStrOption(nlp, (char *)param, value);\n\tif (ret) {\n\t\tPy_INCREF(Py_True);\n\t\treturn Py_True;\n\t} else {\n\t\treturn PyErr_Format(PyExc_ValueError,\n\t\t\t\t    \"%s is not a valid string option\", param);\n\t}\n}\n\nstatic PyObject *add_int_option(PyObject * self, PyObject * args)\n{\n\n\tproblem *temp = (problem *) self;\n\tIpoptProblem nlp = (IpoptProblem) (temp->nlp);\n\n\tchar *param;\n\tint value;\n\n\tBool ret;\n\n\tif (!PyArg_ParseTuple(args, \"si:int_option\", &param, &value)) {\n\t\treturn NULL;\n\t}\n\tret = AddIpoptIntOption(nlp, (char *)param, value);\n\tif (ret) {\n\t\tPy_INCREF(Py_True);\n\t\treturn Py_True;\n\t} else {\n\t\treturn PyErr_Format(PyExc_ValueError,\n\t\t\t\t    \"%s is not a valid int option\", param);\n\t}\n}\n\nstatic PyObject *add_num_option(PyObject * self, PyObject * args)\n{\n\tproblem *temp = (problem *) self;\n\tIpoptProblem nlp = (IpoptProblem) (temp->nlp);\n\n\tchar *param;\n\tdouble value;\n\n\tBool ret;\n\n\tif (!PyArg_ParseTuple(args, \"sd:num_option\", &param, &value)) {\n\t\treturn NULL;\n\t}\n\tret = AddIpoptNumOption(nlp, (char *)param, value);\n\tif (ret) {\n\t\tPy_INCREF(Py_True);\n\t\treturn Py_True;\n\t} else {\n\t\treturn PyErr_Format(PyExc_ValueError,\n\t\t\t\t    \"%s is not a valid num option\", param);\n\t}\n}\n\nPyMethodDef problem_methods[] = {\n\t{\"solve\", solve, METH_VARARGS, PYIPOPT_SOLVE_DOC}\n\t,\n\t{\"set_intermediate_callback\", set_intermediate_callback, METH_VARARGS,\n\t PYIPOPT_SET_INTERMEDIATE_CALLBACK_DOC}\n\t,\n\t{\"close\", close_model, METH_VARARGS, PYIPOPT_CLOSE_DOC}\n\t,\n\t{\"int_option\", add_int_option, METH_VARARGS, PYIPOPT_ADD_INT_OPTION_DOC}\n\t,\n\t{\"str_option\", add_str_option, METH_VARARGS, PYIPOPT_ADD_STR_OPTION_DOC}\n\t,\n\t{\"num_option\", add_num_option, METH_VARARGS, PYIPOPT_ADD_NUM_OPTION_DOC}\n\t,\n\t{NULL, NULL}\n\t,\n};\n\n#if PY_MAJOR_VERSION < 3\nPyObject *problem_getattr(PyObject * self, char *attrname)\n{\n\tPyObject *result = NULL;\n\tresult = Py_FindMethod(problem_methods, self, attrname);\n\treturn result;\n}\n\n\n/*\n * had to replace PyObject_HEAD_INIT(&PyType_Type) in order to get this to\n * compile on Windows\n */\nPyTypeObject IpoptProblemType = {\n\tPyObject_HEAD_INIT(NULL)\n\t    0,\t\t\t/* ob_size */\n\t\"pyipoptcore.Problem\",\t/* tp_name */\n\tsizeof(problem),\t/* tp_basicsize */\n\t0,\t\t\t/* tp_itemsize */\n\tproblem_dealloc,\t/* tp_dealloc */\n\t0,\t\t\t/* tp_print */\n\tproblem_getattr,\t/* tp_getattr */\n\t0,\t\t\t/* tp_setattr */\n\t0,\t\t\t/* tp_compare */\n\t0,\t\t\t/* tp_repr */\n\t0,\t\t\t/* tp_as_number */\n\t0,\t\t\t/* tp_as_sequence */\n\t0,\t\t\t/* tp_as_mapping */\n\t0,\t\t\t/* tp_hash */\n\t0,\t\t\t/* tp_call */\n\t0,\t\t\t/* tp_str */\n\t0,\t\t\t/* tp_getattro */\n\t0,\t\t\t/* tp_setattro */\n\t0,\t\t\t/* tp_as_buffer */\n\tPy_TPFLAGS_DEFAULT,\t/* tp_flags */\n\t\"The IPOPT problem object in python\",\t/* tp_doc */\n};\n\n#else\n\nPyDoc_STRVAR(IpoptProblemType__doc__, \"The IPOPT problem object in python\");\n\nPyTypeObject IpoptProblemType = {\n    PyVarObject_HEAD_INIT(NULL, 0)\n    \"pyipoptcore.Problem\",\t/* tp_name */\n    sizeof(problem),         /*tp_basicsize*/\n    0,                       /*tp_itemsize*/\n    /* methods */\n    (destructor)problem_dealloc,   /*tp_dealloc*/\n    (printfunc)0,           /*tp_print*/\n    0,                      /*tp_getattr*/\n    0,                      /*tp_setattr*/\n    0,                      /*tp_reserved*/\n    (reprfunc)0,            /*tp_repr*/\n    0,                      /*tp_as_number*/\n    0,                      /*tp_as_sequence*/\n    0,                      /*tp_as_mapping*/\n    (hashfunc)0,            /*tp_hash*/\n    (ternaryfunc)0,         /*tp_call*/\n    (reprfunc)0,            /*tp_str*/\n    (getattrofunc)0,        /* tp_getattro */\n    (setattrofunc)0,        /* tp_setattro */\n    0,                      /* tp_as_buffer */\n    Py_TPFLAGS_DEFAULT,     /*tp_flags*/\n    IpoptProblemType__doc__,    /* tp_doc - Documentation string */\n    (traverseproc)0,        /* tp_traverse */\n    (inquiry)0,                /* tp_clear */\n    0,                              /* tp_richcompare */\n    0,                              /* tp_weaklistoffset */\n    0,                              /* tp_iter */\n    0,                              /* tp_iternext */\n    problem_methods,               /* tp_methods */\n};\n#endif\n\n/*\n * FIXME: use module or package constants for the log levels,\n * either in pyipoptcore or in the parent package.\n * They are currently #defined in a header file.\n */\nstatic PyObject *set_loglevel(PyObject * obj, PyObject * args)\n{\n\tint l;\n\tif (!PyArg_ParseTuple(args, \"i\", &l)) {\n\t\tPySys_WriteStdout(\"l is %d \\n\", l);\n\t\treturn NULL;\n\t}\n\tif (l < 0 || l > 2) {\n\t\treturn NULL;\n\t}\n\tuser_log_level = l;\n\tPy_INCREF(Py_True);\n\treturn Py_True;\n}\n\nstatic PyObject *create(PyObject * obj, PyObject * args)\n{\n\tPyObject *f = NULL;\n\tPyObject *gradf = NULL;\n\tPyObject *g = NULL;\n\tPyObject *jacg = NULL;\n\tPyObject *h = NULL;\n\tPyObject *applynew = NULL;\n\n\tDispatchData myowndata;\n\n\t/*\n\t * I have to create a new python object here, return this python object\n\t */\n\n\tint n;\t\t\t/* Number of variables */\n\tPyArrayObject *xL = NULL;\n\tPyArrayObject *xU = NULL;\n\tint m;\t\t\t/* Number of constraints */\n\tPyArrayObject *gL = NULL;\n\tPyArrayObject *gU = NULL;\n\n\tproblem *object = NULL;\n\n\tint nele_jac;\n\tint nele_hess;\n\n\tNumber *x_L = NULL;\t/* lower bounds on x */\n\tNumber *x_U = NULL;\t/* upper bounds on x */\n\tNumber *g_L = NULL;\t/* lower bounds on g */\n\tNumber *g_U = NULL;\t/* upper bounds on g */\n\n\tdouble *xldata, *xudata;\n\tdouble *gldata, *gudata;\n\n\tint i;\n\n\tDispatchData *dp = NULL;\n\n\tPyObject *retval = NULL;\n\n\t/* Init the myowndata field */\n\tmyowndata.eval_f_python = NULL;\n\tmyowndata.eval_grad_f_python = NULL;\n\tmyowndata.eval_g_python = NULL;\n\tmyowndata.eval_jac_g_python = NULL;\n\tmyowndata.eval_h_python = NULL;\n\tmyowndata.apply_new_python = NULL;\n\tmyowndata.userdata = NULL;\n\n\t/* \"O!\", &PyArray_Type &a_x  */\n\tif (!PyArg_ParseTuple(args, \"iO!O!iO!O!iiOOOO|OO:pyipoptcreate\",\n\t\t\t      &n, &PyArray_Type, &xL,\n\t\t\t      &PyArray_Type, &xU,\n\t\t\t      &m,\n\t\t\t      &PyArray_Type, &gL,\n\t\t\t      &PyArray_Type, &gU,\n\t\t\t      &nele_jac, &nele_hess,\n\t\t\t      &f, &gradf, &g, &jacg, &h, &applynew)) {\n\t\tretval = NULL;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n\tif (!PyCallable_Check(f) ||\n\t    !PyCallable_Check(gradf) ||\n\t    !PyCallable_Check(g) || !PyCallable_Check(jacg)) {\n\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\"Need a callable object for callback functions\");\n\t\tretval = NULL;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n\tmyowndata.eval_f_python = f;\n\tmyowndata.eval_grad_f_python = gradf;\n\tmyowndata.eval_g_python = g;\n\tmyowndata.eval_jac_g_python = jacg;\n\n\tif (h != NULL) {\n\t\tif (PyCallable_Check(h)) {\n\t\t\tmyowndata.eval_h_python = h;\n\t\t} else {\n\t\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\t\"Need a callable object for function h.\");\n\t\t\tretval = NULL;\n\t\t\tSAFE_FREE(x_L);\n\t\t\tSAFE_FREE(x_U);\n\t\t\tSAFE_FREE(g_L);\n\t\t\tSAFE_FREE(g_U);\n\t\t\treturn retval;\n\t\t}\n\t} else {\n\t\tlogger(\"[PyIPOPT] Ipopt will use Hessian approximation.\\n\");\n\t}\n\n\tif (applynew != NULL) {\n\t\tif (PyCallable_Check(applynew)) {\n\t\t\tmyowndata.apply_new_python = applynew;\n\t\t} else {\n\t\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\t\"Need a callable object for function applynew.\");\n\t\t\tretval = NULL;\n\t\t\tSAFE_FREE(x_L);\n\t\t\tSAFE_FREE(x_U);\n\t\t\tSAFE_FREE(g_L);\n\t\t\tSAFE_FREE(g_U);\n\t\t\treturn retval;\n\t\t}\n\t}\n\tif (m < 0 || n < 0) {\n\t\tPyErr_SetString(PyExc_TypeError, \"m or n can't be negative\");\n\t\tretval = NULL;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n\tx_L = (Number *) malloc(sizeof(Number) * n);\n\tx_U = (Number *) malloc(sizeof(Number) * n);\n\tif (!x_L || !x_U) {\n\t\tretval = PyErr_NoMemory();\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n\txldata = (double *)xL->data;\n\txudata = (double *)xU->data;\n\tfor (i = 0; i < n; i++) {\n\t\tx_L[i] = xldata[i];\n\t\tx_U[i] = xudata[i];\n\t}\n\n\tg_L = (Number *) malloc(sizeof(Number) * m);\n\tg_U = (Number *) malloc(sizeof(Number) * m);\n\tif (!g_L || !g_U)\n\t\tPyErr_NoMemory();\n\n\tgldata = (double *)gL->data;\n\tgudata = (double *)gU->data;\n\n\tfor (i = 0; i < m; i++) {\n\t\tg_L[i] = gldata[i];\n\t\tg_U[i] = gudata[i];\n\t}\n\n  /* Grab the callback objects because we want to use them later. */\n  Py_XINCREF(f);\n  Py_XINCREF(gradf);\n  Py_XINCREF(g);\n  Py_XINCREF(jacg);\n  Py_XINCREF(h);\n  Py_XINCREF(applynew);\n\n\t/* create the Ipopt Problem */\n\n\tint C_indexstyle = 0;\n\tIpoptProblem thisnlp = CreateIpoptProblem(n,\n\t\t\t\t\t\t  x_L, x_U, m, g_L, g_U,\n\t\t\t\t\t\t  nele_jac, nele_hess,\n\t\t\t\t\t\t  C_indexstyle,\n\t\t\t\t\t\t  &eval_f, &eval_g,\n\t\t\t\t\t\t  &eval_grad_f,\n\t\t\t\t\t\t  &eval_jac_g, &eval_h);\n\tlogger(\"[PyIPOPT] Problem created\");\n\tif (!thisnlp) {\n\t\tPyErr_SetString(PyExc_MemoryError, \"Cannot create IpoptProblem instance\");\n\t\tretval = NULL;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n\tobject = PyObject_NEW(problem, &IpoptProblemType);\n\n\tif (object != NULL) {\n\t\tobject->n_variables = n;\n\t\tobject->m_constraints = m;\n\t\tobject->nlp = thisnlp;\n\t\tdp = (DispatchData *) malloc(sizeof(DispatchData));\n\t\tif (!dp) {\n\t\t\tretval = PyErr_NoMemory();\n\t\t\tSAFE_FREE(x_L);\n\t\t\tSAFE_FREE(x_U);\n\t\t\tSAFE_FREE(g_L);\n\t\t\tSAFE_FREE(g_U);\n\t\t\treturn retval;\n\t\t}\n\t\tmemcpy((void *)dp, (void *)&myowndata, sizeof(DispatchData));\n\t\tobject->data = dp;\n\t\tretval = (PyObject *) object;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t} else {\n\t\tPyErr_SetString(PyExc_MemoryError, \"Can't create a new Problem instance\");\n\t\tretval = NULL;\n\t\tSAFE_FREE(x_L);\n\t\tSAFE_FREE(x_U);\n\t\tSAFE_FREE(g_L);\n\t\tSAFE_FREE(g_U);\n\t\treturn retval;\n\t}\n}\n\nPyObject *set_intermediate_callback(PyObject * self, PyObject * args)\n{\n\tPyObject *intermediate_callback;\n\tproblem *temp = (problem *) self;\n\tIpoptProblem nlp = (IpoptProblem) (temp->nlp);\n\tDispatchData myowndata;\n\tDispatchData *bigfield = (DispatchData *) (temp->data);\n\n\t/* Init the myowndata field */\n\tmyowndata.eval_intermediate_callback_python = NULL;\n\n\tif (!PyArg_ParseTuple(args, \"O\", &intermediate_callback)) {\n\t\treturn NULL;\n\t}\n\tif (!PyCallable_Check(intermediate_callback)) {\n\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\"Need a callable object for function!\");\n\t\treturn NULL;\n\t} else {\n\n\t\tbigfield->eval_intermediate_callback_python =\n\t\t    intermediate_callback;\n\n\t\t/* Put a Python function object into this data structure */\n\t\t/*\n\t\t * myowndata.eval_intermediate_callback_python =\n\t\t * intermediate_callback;\n\t\t */\n\n\t\t/* DispatchData *dp = malloc(sizeof(DispatchData)); */\n\t\t/*\n\t\t * memcpy((void*)dp, (void*)&myowndata,\n\t\t * sizeof(DispatchData));\n\t\t */\n\t\t/* bigfield = dp; */\n\t\t/*\n\t\t * logger( \"qqq: inside set_intermediate_callback, bigfield\n\t\t * is %p\\n\", bigfield ) ;\n\t\t */\n\t\t/*\n\t\t * logger(\"[PyIPOPT] User specified data field to callback\n\t\t * function.\\n\");\n\t\t */\n\n\t\tSetIntermediateCallback(nlp, eval_intermediate_callback);\n\t\tPy_INCREF(Py_True);\n\t\treturn Py_True;\n\t}\n}\n\nPyObject *solve(PyObject * self, PyObject * args)\n{\n\tenum ApplicationReturnStatus status;\t/* Solve return code */\n\tint i;\n\tint n;\n\n\t/* Return values */\n\tproblem *temp = (problem *) self;\n\n\tIpoptProblem nlp = (IpoptProblem) (temp->nlp);\n\tDispatchData *bigfield = (DispatchData *) (temp->data);\n\tint m = temp->m_constraints;\n\n\t/* int dX[1]; */\n\tnpy_intp dX[1];\n\tnpy_intp dlambda[1];\n\n\tPyArrayObject *x = NULL, *mL = NULL, *mU = NULL, *lambda = NULL;\n\tNumber obj;\t\t/* objective value */\n\n\tPyObject *retval = NULL;\n\tPyArrayObject *x0 = NULL;\n\n\tPyObject *myuserdata = NULL;\n\n\tNumber *newx0 = NULL;\n\n\tif (!PyArg_ParseTuple(args, \"O!|O\", &PyArray_Type, &x0, &myuserdata)) {\n\t\tretval = NULL;\n\t\t/* clean up and return */\n\t\tif (retval == NULL) {\n\t\t\tPy_XDECREF(x);\n\t\t\tPy_XDECREF(mL);\n\t\t\tPy_XDECREF(mU);\n\t\t\tPy_XDECREF(lambda);\n\t\t}\n\t\tSAFE_FREE(newx0);\n\t\treturn retval;\n\t}\n\tif (x0->nd != 1){ //If x0 is not 1-dimensional then solve will fail and cause a segmentation fault.\n\t\tlogger(\"[ERROR] x0 must be a 1-dimensional array\");\n\t\tPy_XDECREF(x);\n\t\tPy_XDECREF(mL);\n\t\tPy_XDECREF(mU);\n\t\tPy_XDECREF(lambda);\n\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\"x0 passed to solve is not 1-dimensional.\");\n\t\treturn NULL;\n\t}\n\n\tif (myuserdata != NULL) {\n\t\tbigfield->userdata = myuserdata;\n\t\t/*\n\t\t * logger(\"[PyIPOPT] User specified data field to callback\n\t\t * function.\\n\");\n\t\t */\n\t}\n\tif (nlp == NULL) {\n\t\tPyErr_SetString(PyExc_TypeError,\n\t\t\t\t\"nlp objective passed to solve is NULL\\n Problem created?\\n\");\n\t\tretval = NULL;\n\t\t/* clean up and return */\n\t\tif (retval == NULL) {\n\t\t\tPy_XDECREF(x);\n\t\t\tPy_XDECREF(mL);\n\t\t\tPy_XDECREF(mU);\n\t\t\tPy_XDECREF(lambda);\n\t\t}\n\t\tSAFE_FREE(newx0);\n\t\treturn retval;\n\t}\n\tif (bigfield->eval_h_python == NULL) {\n\t\tAddIpoptStrOption(nlp, \"hessian_approximation\", \"limited-memory\");\n\t\t/* logger(\"Can't find eval_h callback function\\n\"); */\n\t}\n\t/* allocate space for the initial point and set the values */\n\tnpy_intp *dim = ((PyArrayObject *) x0)->dimensions;\n\tn = dim[0];\n\tdX[0] = n;\n\n\tx = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE);\n\tif (!x) {\n\t\tretval = PyErr_NoMemory();\n\t\t/* clean up and return */\n\t\tif (retval == NULL) {\n\t\t\tPy_XDECREF(x);\n\t\t\tPy_XDECREF(mL);\n\t\t\tPy_XDECREF(mU);\n\t\t\tPy_XDECREF(lambda);\n\t\t}\n\t\tSAFE_FREE(newx0);\n\t\treturn retval;\n\t}\n\tnewx0 = (Number *) malloc(sizeof(Number) * n);\n\tif (!newx0) {\n\t\tretval = PyErr_NoMemory();\n\t\t/* clean up and return */\n\t\tif (retval == NULL) {\n\t\t\tPy_XDECREF(x);\n\t\t\tPy_XDECREF(mL);\n\t\t\tPy_XDECREF(mU);\n\t\t\tPy_XDECREF(lambda);\n\t\t}\n\t\tSAFE_FREE(newx0);\n\t\treturn retval;\n\t}\n\tdouble *xdata = (double *)x0->data;\n\tfor (i = 0; i < n; i++)\n\t\tnewx0[i] = xdata[i];\n\n\t/* Allocate multiplier arrays */ \n\n\tmL = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE);\n\tmU = (PyArrayObject *) PyArray_SimpleNew(1, dX, PyArray_DOUBLE);\n\tdlambda[0] = m;\n\tlambda = (PyArrayObject *) PyArray_SimpleNew(1, dlambda, \n\t\t\t\t\t\t     PyArray_DOUBLE);\n\n\t/* For status code, see IpReturnCodes_inc.h in Ipopt */\n\n\tstatus =\n\t  IpoptSolve(nlp, newx0, NULL, &obj, (double *)lambda->data, \n\t\t     (double *)mL->data, (double *)mU->data, \n\t\t     (UserDataPtr) bigfield);\n\tdouble *return_x_data = (double *)x->data;\n\tfor (i = 0; i < n; i++) {\n\t\treturn_x_data[i] = newx0[i];\n\t}\n\tretval = Py_BuildValue(\"OOOOdi\", \n\t\t\t       PyArray_Return(x),\n\t\t\t       PyArray_Return(mL),\n\t\t\t       PyArray_Return(mU),\n\t\t\t       PyArray_Return(lambda),\n\t\t\t       obj, status\n\t    );\n\t/* clean up and return */\n\n\tPy_XDECREF(x);\n\tPy_XDECREF(mL);\n\tPy_XDECREF(mU);\n\tPy_XDECREF(lambda);\n\n\tSAFE_FREE(newx0);\n\treturn retval;\n}\n\nPyObject *close_model(PyObject * self, PyObject * args)\n{\n\tproblem *obj = (problem *) self;\n  DispatchData *dp = obj->data;\n\n  /* Ungrab the callback functions because we do not need them anymore. */\n  Py_XDECREF(dp->eval_f_python);\n\tPy_XDECREF(dp->eval_grad_f_python);\n\tPy_XDECREF(dp->eval_g_python);\n\tPy_XDECREF(dp->eval_jac_g_python);\n\tPy_XDECREF(dp->eval_h_python);\n\tPy_XDECREF(dp->apply_new_python);\n\n\tFreeIpoptProblem(obj->nlp);\n\tobj->nlp = NULL;\n\tPy_INCREF(Py_True);\n\treturn Py_True;\n}\n\n/* static char PYTEST[] = \"TestCreate\\n\"; */\n\n/* static PyObject *test(PyObject *self, PyObject *args) */\n/* { */\n/* IpoptProblem thisnlp = NULL; */\n/* problem *object = NULL; */\n/* object = PyObject_NEW(problem , &IpoptProblemType); */\n/* if (object != NULL) */\n/* object->nlp = thisnlp; */\n/* /\\*        problem *object = problem_new(thisnlp); *\\/ */\n/* return (PyObject *)object; */\n/* } */\n\n/* Begin Python Module code section */\nstatic PyMethodDef ipoptMethods[] = {\n    /* { \"solve\", solve, METH_VARARGS, PYIPOPT_SOLVE_DOC}, */\n    {\"create\", create, METH_VARARGS, PYIPOPT_CREATE_DOC},\n    /* { \"close\",  close_model, METH_VARARGS, PYIPOPT_CLOSE_DOC},  */\n    /* { \"test\",   test,                 METH_VARARGS, PYTEST}, */\n    {\"set_loglevel\", set_loglevel, METH_VARARGS, PYIPOPT_LOG_DOC},\n    {NULL, NULL}\n};\n\n#if PY_MAJOR_VERSION >= 3\n  #define MOD_ERROR_VAL NULL\n  #define MOD_SUCCESS_VAL(val) val\n  #define MOD_INIT(name) PyMODINIT_FUNC PyInit_##name(void)\n  #define MOD_DEF(ob, name, doc, methods) \\\n          static struct PyModuleDef moduledef = { \\\n            PyModuleDef_HEAD_INIT, name, doc, -1, methods, }; \\\n          ob = PyModule_Create(&moduledef);\n#else\n  #define MOD_ERROR_VAL\n  #define MOD_SUCCESS_VAL(val)\n  #define MOD_INIT(name) void init##name(void)\n  #define MOD_DEF(ob, name, doc, methods) \\\n          ob = Py_InitModule3(name, methods, doc);\n#endif\n\nMOD_INIT(pyipoptcore)\n{\n    PyObject * m;\n    /* Finish initialization of the problem type */\n    if (PyType_Ready(&IpoptProblemType) < 0) {\n        return MOD_ERROR_VAL;\n    }\n\n    MOD_DEF(m, \"pyipoptcore\", \"A hook between Ipopt and Python\", ipoptMethods)\n\n    if (m == NULL)\n        return MOD_ERROR_VAL;\n\n    /* Initialize numpy. */\n    /* A segfault will occur if I use numarray without this.. */\n    import_array();\n    if (PyErr_Occurred()) {\n        Py_FatalError(\"Unable to initialize module pyipoptcore\");\n    }\n\n    return MOD_SUCCESS_VAL(m);\n}\n\n/* End Python Module code section */\n"
  }
]