I'm working on mixing python with c++ algorithms for signal processing applications. I've come to the conclusion that wrapping std::vector is a good choice for containers. I'm pretty happy now with the basic design, and I'd like to share it. This boost-python module wraps (currently) std::vector<double> and std::vector<complex<double>>. It implements (currently) basic arithmetic: vector<T> op vector<T> vector<T> op T vector<T> op complex<T> vector<complex<T>> op vector<complex<T>> vector<complex<T>> op complex<T> vector<complex<T>> op vector<T> vector<complex<T>> op T "in-place" ops not yet implemented.
"Neal D. Becker" <ndbecker2@verizon.net> writes:
I'm working on mixing python with c++ algorithms for signal processing applications.
I've come to the conclusion that wrapping std::vector is a good choice for containers.
I'm pretty happy now with the basic design, and I'd like to share it. This boost-python module wraps (currently) std::vector<double> and std::vector<complex<double>>. It implements (currently) basic arithmetic:
vector<T> op vector<T> vector<T> op T vector<T> op complex<T>
vector<complex<T>> op vector<complex<T>> vector<complex<T>> op complex<T> vector<complex<T>> op vector<T> vector<complex<T>> op T
"in-place" ops not yet implemented.
1. Why not use the vector_indexing_suite? 2. Why all the ugly macros when you could use function templates? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams wrote:
"Neal D. Becker" <ndbecker2@verizon.net> writes:
I'm working on mixing python with c++ algorithms for signal processing applications.
I've come to the conclusion that wrapping std::vector is a good choice for containers.
I'm pretty happy now with the basic design, and I'd like to share it. This boost-python module wraps (currently) std::vector<double> and std::vector<complex<double>>. It implements (currently) basic arithmetic:
vector<T> op vector<T> vector<T> op T vector<T> op complex<T>
vector<complex<T>> op vector<complex<T>> vector<complex<T>> op complex<T> vector<complex<T>> op vector<T> vector<complex<T>> op T
"in-place" ops not yet implemented.
1. Why not use the vector_indexing_suite?
It is used. What did you mean?
2. Why all the ugly macros when you could use function templates?
How can I use function template to define a function "operator op" where "op" is a variable? For example, VVOP(double,double,double,+,plus<double>()) macro defines operator+(const std::vector<double>&, const std::vector<double>&)
"Neal D. Becker" <ndbecker2@verizon.net> writes:
David Abrahams wrote:
"Neal D. Becker" <ndbecker2@verizon.net> writes:
I'm working on mixing python with c++ algorithms for signal processing applications.
I've come to the conclusion that wrapping std::vector is a good choice for containers.
I'm pretty happy now with the basic design, and I'd like to share it. This boost-python module wraps (currently) std::vector<double> and std::vector<complex<double>>. It implements (currently) basic arithmetic:
vector<T> op vector<T> vector<T> op T vector<T> op complex<T>
vector<complex<T>> op vector<complex<T>> vector<complex<T>> op complex<T> vector<complex<T>> op vector<T> vector<complex<T>> op T
"in-place" ops not yet implemented.
1. Why not use the vector_indexing_suite?
It is used. What did you mean?
Sorry, I missed it.
2. Why all the ugly macros when you could use function templates?
How can I use function template to define a function "operator op" where "op" is a variable?
For example, VVOP(double,double,double,+,plus<double>()) macro defines operator+(const std::vector<double>&, const std::vector<double>&)
That's not what I meant. Why: #define VECIMP(TYPE, PROXY) \ class_<std::vector<TYPE> >("vector_"#TYPE) \ .def(init<size_t>()) \ .def(init<size_t,TYPE>()) \ .def(init<const std::vector<TYPE>&>()) \ .def("size", &std::vector<TYPE>::size) \ .def("resize", (void (std::vector<TYPE>::*)(size_t, const TYPE&) )&std::vector<TYPE>::resize) \ .def("resize", (void (std::vector<TYPE>::*)(size_t) )&std::vector<TYPE>::resize) \ .def(self + self) \ .def(self - self) \ .def(self * self) \ .def(self / self) \ .def(self + TYPE()) \ .def(self - TYPE()) \ .def(self * TYPE()) \ .def(self / TYPE()) \ .def(self + std::complex<TYPE>()) \ .def(self - std::complex<TYPE>()) \ .def(self * std::complex<TYPE>()) \ .def(self / std::complex<TYPE>()) \ .def(vector_indexing_suite<std::vector<TYPE>, PROXY >()) \ ; ? I realize you're generating the vector name, but it'd be more principled to do the rest with a template. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
OK, I agree the previous version sucked. Here is a new one I think is much better. The boost-python code is simple, and I'm not including it. The harder part is to supply the underlying c++ library for doing the vector-vector and vector-scalar arithmetic. I think I have a pretty good design for that, which I'd like to share. The tests at the bottom compile with gcc34/boost-cvs.
Neal Becker <ndbecker2@verizon.net> writes:
OK, I agree the previous version sucked.
I wouldn't go that far.
Here is a new one I think is much better.
The boost-python code is simple, and I'm not including it. The harder part is to supply the underlying c++ library for doing the vector-vector and vector-scalar arithmetic. I think I have a pretty good design for that, which I'd like to share.
I think you're posting in the wrong forum then. I have only 2 quick comments in this one: 1. You should never use std::[binary|unary]_function because it suppresses EBO. Consider what happens when you have a compressed_pair<minus<int>,plus<int> >. 2. Isn't something appropriate already present in uBlas? Cheers, -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
David Abrahams wrote:
Neal Becker <ndbecker2@verizon.net> writes:
OK, I agree the previous version sucked.
I wouldn't go that far.
Here is a new one I think is much better.
The boost-python code is simple, and I'm not including it. The harder part is to supply the underlying c++ library for doing the vector-vector and vector-scalar arithmetic. I think I have a pretty good design for that, which I'd like to share.
I think you're posting in the wrong forum then.
Vector processing is in my view one of the primary interests for boost-python. By processing vectors, the overhead involved with python and the python-c++ interface becomes acceptable. I believe a suitable container for interfacing between python and c++ is of fundamental interest to the boost-python community. I'm sure there must be a lot of interest in this subject. I have tried to investigate 3 candidates. 1) std::vector 2) ublas 3) numarray So far the results are: 1) std::vector - pros: universal availability easily understood supports required operations (insert, erase...) vector_indexing_suite already implemented (could be optimized more) cons: lacks vector arithmetic - but I just implemented this and it isn't difficult even for an amateur like myself 2) ublas: pros: already has vector arithmetic cons: lacks required operations (e.g., erase) no indexing_suite (see above) 3) numarray pros: ? cons: I had a hard time finding documentation. Heavy-weight interface -> high learning curve Summary: It appears that std::vector is a good choice. Ublas might be better in the future, but at present it lacks some required functionality. A ublas vector does not fulfill all the requirements of Sequence. This topic is known to ublas developers and may be addressed in the future.
I have only 2 quick comments in this one:
1. You should never use std::[binary|unary]_function because it suppresses EBO. Consider what happens when you have a compressed_pair<minus<int>,plus<int> >.
OK. I assume this means "Empty Base Optimization?"
2. Isn't something appropriate already present in uBlas?
See above.
In case anyone else is interested, here is complete code that seems to be fully functional:
"Neal D. Becker" <ndbecker2@verizon.net> writes:
David Abrahams wrote:
Neal Becker <ndbecker2@verizon.net> writes:
OK, I agree the previous version sucked.
I wouldn't go that far.
Here is a new one I think is much better.
The boost-python code is simple, and I'm not including it. The harder part is to supply the underlying c++ library for doing the vector-vector and vector-scalar arithmetic. I think I have a pretty good design for that, which I'd like to share.
I think you're posting in the wrong forum then.
Vector processing is in my view one of the primary interests for boost-python. By processing vectors, the overhead involved with python and the python-c++ interface becomes acceptable.
I believe a suitable container for interfacing between python and c++ is of fundamental interest to the boost-python community. I'm sure there must be a lot of interest in this subject.
Sure, but if you're writing good mathematical vector components, there ought to be more interest in the whole Boost developer community at large.
I have tried to investigate 3 candidates.
1) std::vector 2) ublas 3) numarray
So far the results are:
1) std::vector - pros: universal availability easily understood supports required operations (insert, erase...) vector_indexing_suite already implemented (could be optimized more)
cons: lacks vector arithmetic - but I just implemented this and it isn't difficult even for an amateur like myself
Depends how fast you need it, I guess.
2) ublas: pros: already has vector arithmetic
cons: lacks required operations (e.g., erase) no indexing_suite (see above)
3) numarray pros: ?
cons: I had a hard time finding documentation. Heavy-weight interface -> high learning curve
Summary: It appears that std::vector is a good choice. Ublas might be better in the future, but at present it lacks some required functionality. A ublas vector does not fulfill all the requirements of Sequence. This topic is known to ublas developers and may be addressed in the future.
Yeah, I know.
I have only 2 quick comments in this one:
1. You should never use std::[binary|unary]_function because it suppresses EBO. Consider what happens when you have a compressed_pair<minus<int>,plus<int> >.
OK. I assume this means "Empty Base Optimization?"
Yep. -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
I have only 2 quick comments in this one:
1. You should never use std::[binary|unary]_function because it suppresses EBO. Consider what happens when you have a compressed_pair<minus<int>,plus<int> >.
OK. I assume this means "Empty Base Optimization?"
Yep.
Why is this important? Is this comment just made as a general principle, or does it relate to the actual use in the vector arithmetic I wrote? I assume the only signficance of EBO is a size issue, in which case it wouldn't matter in the way I used it for vector arithmetic. Or, is there something I'm missing? (I went ahead and made the change you suggested anyway, but I'm curious).
"Neal D. Becker" <ndbecker2@verizon.net> writes:
I have only 2 quick comments in this one:
1. You should never use std::[binary|unary]_function because it suppresses EBO. Consider what happens when you have a compressed_pair<minus<int>,plus<int> >.
OK. I assume this means "Empty Base Optimization?"
Yep.
Why is this important?
consider the size of bind(times, bind(plus, _1, _2), bind(minus, _1, _2))
Is this comment just made as a general principle, or does it relate to the actual use in the vector arithmetic I wrote?
It will probably be relevant eventually since you seem to be trying to write general-purpose standalone vector arithmetic. Who knows how your vectors (etc.) may be used? -- Dave Abrahams Boost Consulting http://www.boost-consulting.com
participants (3)
-
David Abrahams -
Neal Becker -
Neal D. Becker