-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Python bindings for MathematicalProgram #4771
Comments
Does swig work with typedef instead of using? I can change it to template<int rows>
typedef MatrixDecisionVariable<rows, 1> VectorDecisionVariable; How did swig works with |
Making that change produces 35,841 lines of error messages, the first of which is:
I think you can't typedef inside a teplate, at least not in that way 😉 We haven't seen this with |
I've pulled in the |
The more fundamental issue remains, however: should I even bother? This will be a substantial effort, which might just get tossed out when we move away from SWIG. |
@mwoehlke-kitware should start working on the Boost::Python port next week. |
I guess I won't bother, then. |
Have been thinking a bit more, and it's becoming clear to me just how enabling it would be if we could get python bindings working for MathematicalProgram. In addition to @rdeits , I could see @patmarion and others using these for working with point cloud perception right in director. MathematicalProgram is at a point where having more (expert) users could make it get a lot better fast. @hongkai-dai and @soonho-tri are adding features fast, but they've got a long list! @jwnimmer-tri , @david-german-tri , @jamiesnape , et al -- what's the best way to make this happen? |
swig_matlab
can't wrap MathematicalProgram
FWIW - there would be a ton of value for getting the bindings to matlab, too. @mposa and others might start using it. That might be a strong argument for swig. |
Maybe the Boost::Python spike should be redirected to creating new python bindings for MathematicalProgram, instead of backend-swapping the current pydrake APIs? We could choose to wrap only the APIs that we feel are more stabilized, for now. |
Summary of conversation elsewhere: The swig MATLAB bindings have no users and @RussTedrake has decided we don't need to continue support for them. @rdeits will spike-test Python bindings for MathematicalProgram using SWIG 3.0.11, and will also nuke the MATLAB swig outputs. If the spike test works well, we have the option to replace swig-matlab with modern upstream SWIG (most likely as a binary dependency), or to use @mwoehlke-kitware: As a user of MathematicalProgram, @rdeits knows exactly the API he wants to expose, and plans to have the SWIG bindings done ASAP. Once they're available, we should focus Sounds good? Consistent with everyone's understanding? |
SWIG 3.0.2 is in trusty-backports, SWIG 3.0.8 is in xenial, which makes life easier. |
Annoyingly, only SWIG 3.0.11 supports the |
That is very unfortunate. I retract my "makes life easier" comment. |
Brief update on this: Basically, I'm stuck on how to handle the Eigen Vectors of decision variables (which, ironically, I was a strong proponent of in the first place). Nothing I've tried has gotten SWIG to even try to generate proper bindings for I decided to also give pybind11 a try, just to see how it was. Handling Eigen matrices with numeric scalar types is amazingly easy in pybind11 (as in, took basically no effort instead of the days that were required to get SWIG working). Unfortunately, their support for Eigen types with non-numeric arguments seems to be weaker. So far, I haven't gotten it working. I'm going to keep playing with both approaches. For reference, the particular API I'm trying to wrap is basically what's used in import numpy as np
import pydrake.mathematicalprogram as mp
prog = mp.MathematicalProgram()
x = prog.NewBinaryVariables(3, "x")
c = np.array([-1.0, -1.0, -2.0])
prog.AddLinearCost(c)
a1 = np.array([[1.0, 2.0, 3.0]])
prog.AddLinearConstraint(a1, -np.inf, 4) etc. Anyway, not giving up quite yet, but wrapping Eigen with user-defined scalar types has turned out to be difficult. |
Follow-up: from discussion with one of the pybind11 devs, automagic wrapping of something like |
The conclusion is probably similar in SWIG: magic wrapping of Matrix to and from Numpy arrays is unlikely to work, but we can create a wrapper and implement the API ourselves. This is, in fact, exactly what the |
Does anyone have input/suggestions on wrapping Eigen types like this? Going down the route that |
That is unfortunate, we are using other types as the scalar in Eigen::Matrix, such as |
Yeah, and I still think that's the right thing to do in C++. It just makes this step more challenging 😉 |
Just to be clear, in a perfect world I would be able to take a C++ method that returns a |
@patmarion had some useful advice. I had been trying to get the conversion from Matrix to numpy array to happen magically in the binding layer, but it's really not that hard to make that magic happen by just writing some python code. The idea would be:
That leaves the option open for a future clever person to come along and figure out all the magic type conversion under the hood without changing the API. |
I'm going to try to make a quick prototype of this idea in SWIG and pybind, outside of Drake. |
Prototype is here: https://github.com/rdeits/mathprog-wrapper-exploration Pybind11The summary is that implementing @patmarion's suggestion was really easy in pybind11. A surprising number of things just work. For example, if I overload x = Variable("x")
y = Variable("y")
xy = numpy.array([x, y])
return np.sum(xy) and get an Integrating it with cmake was also amazingly easy: https://github.com/rdeits/mathprog-wrapper-exploration/blob/master/pybind/CMakeLists.txt#L24 SwigImplementing it with SWIG was...well...I haven't actually gotten it to work yet. The problem is that in order to generate a wrapper for In SWIG's defense, the parts of the API that it could wrap, it did automatically, while in pybind11 I had to declare each method that I wanted to be wrapped. By the way, I haven't been trying Boost::Python simply because I have no experience with it at all. I'm sure it's also a good option, but right now I'm more interested in the general comparison of SWIG vs not-SWIG, with pybind11 being my not-SWIG of choice. |
hoorah! |
This is super exciting, kudos @rdeits! @mwoehlke-kitware, you should read recent developments on this thread if you haven't already.
Are you planning to continue exploring the SWIG avenue, or is not-SWIG the approach of choice at this point?
It looks like others have already worked out how to do it in Bazel as well: bazelbuild/bazel#1475
@mwoehlke-kitware From my notes, you thought EDIT: Thinking about it for a moment, though, why would interop be hard? There are Python functions, produced by whatever underlying wrapper technology, and Python code calls them. Right? |
Personally, I like |
From what I can tell, pybind11 is a fork of Boost::Python that has been extracted from the rest of Boost and is updated to use modern C++... with one important difference: it has some Eigen wrapping bits built in. We'd apparently need an extra external to get that with Boost::Python.
Due to requiring a C++11 compiler (and C++14 awareness), it does some things much more "cleanly" than Boost::Python (less use of macros, particularly). I'm not sure if Boost::Python supports exporting lambdas as Python functions; pybind11 definitely does. CMake integration with pybind11 is really easy. As discussed in today's meeting, I would guess that Boost::Python code can be converted fairly easily to pybind11. The API's are very similar, so it "ought" to be a matter of switching includes, and changing the namespace prefix on Boost::Python calls. (Possibly even just changing a namespace alias.) |
FTR all of the above sounds great with me. (I had raised the concern with David about making sure we inter-operate with Boost::Python; I think the above plan is solid and I'm not worried anymore.) |
I am currently rewriting the IRIS python bindings in pybind11, both in order to fix the build issues like #4914 and to make sure I'm happy with the tool. So far, it's great. |
https://github.com/rdeits/drake/tree/pybind-rbtree now has all python tests passing using pybind11 bindings instead of SWIG. There's some more work to be done to expose some IK constraints that aren't being tested but that Director probably needs, and to clean up the build, but overall this is really nice. |
https://github.com/rdeits/drake/tree/pybind-mathprog can now run a very basic mathematicalprogram example from python: https://github.com/rdeits/drake/blob/7bffb37628e62e59ea4181963e70a6bd2bdc5a2b/drake/bindings/python/pydrake/test/testMathematicalProgram.py#L15 prog = mathematicalprogram.MathematicalProgram()
x = prog.NewBinaryVariables(3, "x")
c = np.array([-1.0, -1.0, -2.0])
prog.AddLinearCost(c, x)
a = np.array([[1.0, 2.0, 3.0]])
prog.AddLinearConstraint(a, -np.inf, 4, x)
a2 = np.array([1.0, 1.0])
prog.AddLinearConstraint(a2, 1, np.inf, x[:2])
result = prog.Solve()
self.assertEqual(result, mathematicalprogram.SolutionResult.kSolutionFound)
# Test that we got the right solution for all x
x_expected = np.array([1.0, 0.0, 1.0])
self.assertTrue(np.all(np.isclose(prog.GetSolution(x), x_expected))) |
hoorah! |
I was investigating today what it would take to make
MathematicalProgram
usable from Python/Matlab. So far, I haven't been able to wrapdecision_variable.h
because of its use of alias-using
directives (liketemplate <int rows> using VectorDecisionVariable = MatrixDecisionVariable<rows, 1>;
).Mainline SWIG added support for these directives in 3.0.11, which came out in December 2016, but the SWIG + matlab fork we're using doesn't have those changes.
It might be possible to pull in the changes from mainline SWIG and get this working.
Of course, this is all moot if the SWIG code is going to be thrown away soon. What's the status of that?
The text was updated successfully, but these errors were encountered: