I am trying to wrap a simple C++ class that uses shared pointers and a very simple inheritance. I have a class Point that is a base class and SphericalPoint is it's child class. I have a vector of shared pointers of Points. I want the vector to hold the child class objects in it i.e. Spherical Points. There can be many child classes of Point and Spherical Point is only shown here for representation. When I do this I get the following compilation error -
point.pyx:18:13: Object of type 'shared_ptr[Point]' has no attribute 'setCoordinate1'
Error compiling Cython file:
point = shared_ptr[Point](new SphericalPoint())
cdef double latitude, longitude
latitude = 0.
longitude = 0.
point.setCoordinate1(latitude)
point.setCoordinate2(longitude)
point.pyx:19:13: Object of type 'shared_ptr[Point]' has no attribute 'setCoordinate2'
Initially when googling for this I thought the cause of the problem maybe because I do not have the keyword public in the Cython code but when I do add the keyword public I get a whole bunch of other errors. In the following link Wrapping C++ with Cython there is no example that shows public in the .pxd file.
Here is a MVCE that reproduces the problem. How can I fix this error ? Cython version is 0.29.7
Point.h
class Point {
private:
double coordinate1,coordinate2;
public:
virtual double getCoordinate1();
virtual double getCoordinate2();
virtual void setCoordinate1(double coordinate1);
virtual void setCoordinate2(double coordinate2);
};
class SphericalPoint : public Point
{
private:
double longitude,latitude;
public:
double getCoordinate1();
double getCoordinate2();
void setCoordinate1(double latitude);
void setCoordinate2(double longitude);
};
and this is my point.pxd file
cdef extern from "Point.h":
cdef cppclass Point:
Point() except +
double getCoordinate1()
double getCoordinate2()
void setCoordinate1(double coordinate1)
void setCoordinate2(double coordinate2)
cdef cppclass SphericalPoint(Point):
SphericalPoint() except +
double getCoordinate1()
double getCoordinate2()
void setCoordinate1(double coordinate1)
void setCoordinate2(double coordinate2)
And my point.pyx file
from libcpp.memory cimport shared_ptr
from libcpp.vector cimport vector
from point cimport Point
cdef class PyA:
cdef vector[shared_ptr[Point]]* points
def __cinit__(self):
self.points = new vector[shared_ptr[Point]]()
def buildPoints(self):
cdef shared_ptr[Point] point
point = shared_ptr[Point](new SphericalPoint())
cdef double latitude, longitude
point.setCoordinate1(latitude)
point.setCoordinate2(longitude)
UPDATE
I just moved the instantiation of the child classes to it's own separate method because it is not really part of cinit. But I still get the same compilation errors. I am also wondering whether the instantiation of the subclass SphericalPoint is the cause of the problem i.e.
point = shared_ptr[Point](new SphericalPoint())
Is this the recommended way ?
Cython can work this out for regular pointer types and generate c++ code with ->, however it isn't able to work this out for types that implement a pointer interface with operator overloading.
Instead you should use cython.operator.dereference.
from cython.operator cimport dereference
# ...
dereference(point).setCoordinate1(instance)
Related
I am having a hard time with my first cython program, so please don't discourage me if I have a stupid question.
This is my example:
c_foo.h:
// c_foo.h
class foo:
{
public:
....
std::unique_ptr<2DVector> get_cFoo_unique_ptr(); // Vec2D<T> is a vector of vectors of T
// std::vector<std::vector<T>>
private:
std::unique_ptr<Vec2D> cFoo_unique_ptr; // Vec2D<T> is a vector of vectors of T
}
foo.pyx:
# foo.pyx
import cython
... # other import
from cython.operator cimport unique_ptr as cpp_unique_ptr
cdef extern from c_foo.h:
cdef cppclass c_foo:
...
cpp_unique_ptr get_cFoo_unique_ptr()
cdef class py_foo:
cdef c_foo* cFoo
...
def get_Vec2D(self):
return self.cFoo.get_cFoo_unique_ptr().get()
So, what I am trying to do here is getting data from C++ unique_ptr and return them in python.
And cython complains about it.
def get_Vec2D(self):
return self.cFoo.get_cFoo_unique_ptr().get()
----------------------------------------------------------
foo.pyx:xx:xx: Cannot convert 'T *' to Python object
Another attempt is that I try other way to declare cython unique_ptr of vectors:
# foo.pyx
import cython
... # other import
from cython.memory cimport unique_ptr as cpp_unique_ptr
from cython.vector cimport vector as cpp_vector
cdef extern from c_foo.h:
cdef cppclass c_foo:
...
cpp_unique_ptr[cpp_vector[cpp_vector[T]]] get_cFoo_unique_ptr()
cdef class py_foo:
cdef c_foo* cFoo
...
def get_Vec2D(self):
return self.cFoo.get_cFoo_unique_ptr().get()
And still the same error:
Cannot convert 'vector[vector[T]] *' to Python object
So, my question is how can I access the data of C++ unique_ptr in cython?
And is there any good practice that I should know for passing data between C++ and python via cython?
Thanks
This kind of thing confused me for a long time. I have only used Cython in a C environment, not C++, so I don't know about other options that might exist in your case. But I'll explain how I do it, and hope that will be helpful.
You must create Python objects at the end of your Cython function, since those are the only valid return values. That means, among other things, that you can't return a pointer or a C array. For example, suppose I have a Cython function f that calculates a double array:
def f():
cdef double aa[1000]
cdef int i
# ....
# some calculation that populates aa
# ....
# Now I can't just return aa because aa isn't a Python object.
# I have to convert it to a Python list:
a = []
for i in range(1000):
a.append(aa[i]) # Cython knows how convert one C float to one Python float
return a
I have a cdefed class in Cython which looks very similar to this:
cdef class AprilTagDetector:
cdef capriltag.apriltag_detector_t* _apriltag_detector
def __cinit__(self):
self._apriltag_detector = capriltag.apriltag_detector_create();
# standard null checks
# standard __dealloc__(self) here
property quad_decimate:
def __get__(self):
return self._apriltag_detector.quad_decimate
The corresponding .pxd file looks like this:
cdef extern from "apriltag.h":
# The detector itself
ctypedef struct apriltag_detector_t:
pass
# Detector constructor and destructor
apriltag_detector_t* apriltag_detector_create()
void apriltag_detector_destroy(apriltag_detector_t* td);
The problem is, when I go to compile this code, it spits out this error:
property quad_decimate:
def __get__(self):
return self._apriltag_detector.quad_decimate ^
------------------------------------------------------------
apriltags.pyx:47:14: Cannot convert 'apriltag_detector_t *' to Python object
What's going on here? I haven't been able to figure it out from the Cython docs.
I, thankfully, figured out the problem when working on this project with a friend at a hackerspace.
The problem is in the ctypedef struct apriltag_detector_t block.
When I wrote pass in the block, I thought that Cython would automatically work out the internal contents of the struct, and let me access the element(s) I needed - here, quad_decimate.
Not so.
To get Cython to understand the contents of a struct, you will have to tell it what's in the struct as so:
ctypedef struct apriltag_detector_t:
float quad_decimate
I am trying to wrap some C++ code into Cython and I came up with some trouble trying to pass a method from a class as an argument to a function.
I do not know if it makes it more clear, but class A represents a statistical model (so myAMethod uses not only the arguments passed but many instance variables) and B has different methods for minimizing the function passed.
In C++ I have something of this style:
class A
{
public:
double myAMethod(double*)
};
class B
{
public:
double myBMethod(A&, double (A::*f) (double*)
}
So what I am trying to do is to use instances of both A and B in Cython code. I had no trouble wrapping the classes, but when I try to use myBMethod, I don't know how to pass a pointer of the kind A::*myAMethod
If I do this:
myBMethod(ptrToAObj[0], &ptrToAObj.myAMethod),
then Cython compiles this code to [...] &ptrToAObj->myAMethod [...], and I get the message one would expect from g++:
"ISO C++ forbids taking the address of a bound member function to form a pointer to member function."
But if I try to point straight to the class method, and do myBMethod(ptrToAObj[0], A.myAMethod), then Cython won't compile and say that
myAMethod is not a static member from A.
And that's pretty much all I was able to advance. I could work at C++ level and avoid any of these anoyances, but if I were able to use instances of A and B in Python (via Cython) interactively, it would help me in speedig my development pace.
Any help will be really appreciated, and I apologize if this question as been already answered and/or is available in a referece - I search SO, Cython reference and Smith's "Cython" book and I did not found this theme adressed.
Thanks in advance!
I have a partial (if horrendous) solution. I'm prepared to believe there's a better way, but I don't know it.
In cpp_bit.hpp:
class A {
public:
double myAMethod(double*) { return 0.0; }
};
typedef double (A::*A_f_ptr)(double *);
class B {
public:
double myBMethod(A& a, A_f_ptr f) {
double x = 0.1;
return (a.*f)(&x);
}
};
A_f_ptr getAMethod() {
return &A::myAMethod;
}
I've given the functions very basic implementations, just so I can check for really obvious crashes. I've also created a function pointer which returns a pointer to myAMethod. You'll need to do this for every method you want to wrap.
In py_bit.pyx
# distutils: language = c++
from cython.operator import dereference
cdef extern from "cpp_bit.hpp":
cdef cppclass A:
double myAMethod(double*)
cdef cppclass A_f_ptr:
pass
cdef cppclass B:
double myBMethod(A&, A_f_ptr)
cdef A_f_ptr getAMethod()
cdef class PyA:
cdef A* thisptr
def __cinit__(self):
self.thisptr = new A()
def __dealloc__(self):
del self.thisptr
cpdef myAMethod(self,double[:] o):
return self.thisptr.myAMethod(&o[0])
cdef class PyB:
cdef B* thisptr
def __cinit__(self):
self.thisptr = new B()
def __dealloc__(self):
del self.thisptr
cpdef myBMethod(self,PyA a):
return self.thisptr.myBMethod(dereference(a.thisptr),getAMethod())
I couldn't figure out how to typedef a member function pointer in Cython, so instead I created an empty cppclass with the same name. This works because cython just seems to use it for type-checking and nothing more, and since it includes cpp_bit.hpp (where it's defined) you can use it no problem.
All I've done is left the task of getting the member function pointer to c++ (in getAMethod, which I call). I don't think it's entirely satisfactory, but it looks workable, and is only a short extra c++ function for every member function you want to access. You could play with where you put it to encapsulate it more cleanly.
An alternative, untested approach: (Edit: further thought suggests this might be very tricky! Attempt this at your own risk!)
Personally, I'd be tempted to change the c++ interface so that myBMethod is defined as
double myBMethod(std::function<double (double*)>)
(since presumably you always call it with the A instance it's passed with). Then use lambda functions in c++(11!) to wrap the A instance and function together
b.myBMethod([&](double* d){ return a.myAMethod(d) };
It may then take a bit of hugely complicated Cython wrapping that I haven't yet considered, but it should be possible to convert a simple double (double*) function pointer to the c++ function object, and so use it more directly.
It's also possible that your actual design is more complicated in ways I haven't considered, and this approach isn't flexible enough anyway.
I'm trying to wrap a C++ library in which the logic is implemented as templatized functors in .hpp files, and I'm struggling to find the right way to expose the C++ functors as Cython/Python functions. How are functors like the one below supposed to be wrapped in Cython?
I believe this should be possible, at least for template classes and functions, according to the Cython 0.20 docs.
Note: I think I've figured out how to wrap normal C++ functions—the problem occurs when I'm trying to wrap a templatized functor, i.e. a template struct that overloads the () operator (making it act like a function when a data type is fixed).
Disclaimer: I'm a total novice in C++ and very new to Cython so apologies if I'm making obvious mistakes here.
The functor I'm trying to wrap:
#include <vector>
#include "EMD_DEFS.hpp"
#include "flow_utils.hpp"
template<typename NUM_T, FLOW_TYPE_T FLOW_TYPE= NO_FLOW>
struct emd_hat_gd_metric {
NUM_T operator()(const std::vector<NUM_T>& P, const std::vector<NUM_T>& Q,
const std::vector< std::vector<NUM_T> >& C,
NUM_T extra_mass_penalty= -1,
std::vector< std::vector<NUM_T> >* F= NULL);
};
My wrapper.pyx file:
# distutils: language = c++
from libcpp.vector cimport vector
cdef extern from "lib/emd_hat.hpp":
# Apparently `cppclass` is necessary here even though
# `emd_hat_gd_metric` is not a class...?
cdef cppclass emd_hat_gd_metric[NUM_T]:
NUM_T operator()(vector[NUM_T]& P,
vector[NUM_T]& Q,
vector[vector[NUM_T]]& C) except +
cdef class EMD:
cdef emd_hat_gd_metric *__thisptr
def __cinit__(self):
self.__thisptr = new emd_hat_gd_metric()
def __dealloc__(self):
del self.__thisptr
def calculate(self, P, Q, C):
# What goes here? How do I call the functor as a function?
return self.__thisptr(P, Q, C)
The above just gives a Calling non-function type 'emd_hat_gd_metric[NUM_T]' error when I try to compile it with cython --cplus wrapper.pyx.
Here's the full library I'm trying to wrap.
End goal: to be able to call emd_hat_gd_metric as a Cython/Python function, with arguments being NumPy arrays.
I couldn't find a real solution, but here's a workaround (that requires modifying the C++ code): just instantiate the template function with the data type you need in the C++ header, then declare that function normally in your .pyx file.
It's a little unwieldy if you need many different data types, but I only needed double. It would also be nicer if it wasn't necessary to modify the external library… but it works.
In the C++ some_library.hpp file:
Instantiate the functor with the data type you need (say, double):
template<typename T>
struct some_template_functor {
T operator()(T x);
};
// Add this:
some_template_functor<double> some_template_functor_double;
In the Cython .pyx file:
Declare the function normally (no need for cppclass):
cdef extern from "path/to/some_library.hpp":
cdef double some_template_functor_double(double x)
Then you can call some_template_functor_double from within Cython.
This is a cross-post of a question I asked in the cython-user group a day and a half ago, but have not yet gotten any replies, so I am trying my luck in a more general forum
I have been trying every which way to wrap this following code, with various degrees of errors. Plenty of searching had me stumbling upon similar questions and also an outstanding wishlist ticket, but honestly I am not sure if I am even on the right path.
plow_types.h:
namespace Plow {
struct JobState {
enum type {
INITIALIZE = 0,
RUNNING = 1,
FINISHED = 2
};
};
...
class JobFilterT {
public:
...
std::vector<JobState::type> states;
...
So I am trying to wrap this Plow::JobState::type enum. The closest I got, after finding another similar post, was ending up with this attempt:
plow_types.pxd:
cdef extern from "rpc/plow_types.h" namespace "Plow":
enum JobState_type "Plow::JobState::type":
INITIALIZE "Plow::JobState::INITIALIZE"
RUNNING "Plow::JobState::RUNNING"
FINISHED "Plow::JobState::FINISHED"
struct JobState:
JobState_type type
...
cdef cppclass JobFilterT:
vector[JobState_type] states
And I get an error:
src/plow.cpp: In function ‘std::vector<Plow::JobState::type, std::allocator<Plow::JobState::type> > __pyx_convert_vector_from_py_enum__Plow_3a__3a_JobState_3a__3a_type(PyObject*)’:
src/plow.cpp:6688: error: invalid conversion from ‘long int’ to ‘Plow::JobState::type’
Either/or:
How can I properly wrap this nested enum?
Is this even necessary to try and wrap this exactly, or can I accomplish my goal of accessing these "namespaced" constants by some other means? Should I just completely ignore these structs, and define my own versions of the constants in my pyx, with matching int values?
I've tried to simply just define my own versions of the constants in my cython pyx and treat everything as int (vector[int] states) but the compiler complains about not knowing how to do conversions from int long to Plow::JobState::type.
I finally figured it out, after trying an unbelievable amount of combinations. It was not to far off from my last attempt before asking the question...
plow_types.pxd:
I needed to just forget about that JobState struct, and only wrap the enum. But I also needed to map them to new names in cython to avoid name collisions with other enums using that similar namespace technique.
cdef extern from "rpc/plow_types.h" namespace "Plow":
ctypedef enum JobState_type "Plow::JobState::type":
JOBSTATE_INITIALIZE "Plow::JobState::INITIALIZE"
JOBSTATE_RUNNING "Plow::JobState::RUNNING"
JOBSTATE_FINISHED "Plow::JobState::FINISHED"
Now I can refer to JobState_type in stuff like vector[JobState_type]. Then I used this approach to making my constants available in python, in a readonly way:
job.pyx:
cimport cython
#cython.internal
cdef class _JobState:
cdef:
readonly int INITIALIZE
readonly int RUNNING
readonly int FINISHED
def __cinit__(self):
self.INITIALIZE = JOBSTATE_INITIALIZE
self.RUNNING = JOBSTATE_RUNNING
self.FINISHED = JOBSTATE_FINISHED
JobState = _JobState()
This gives me a public instance of JobState, with readonly constant attributes.
And when needing to convert back from a list of python values to a vector[JobState_type], I would do this:
someList = [JobState.RUNNING]
...
cdef:
JobState_type i
vector[JobState_type] vec_states
for i in someList:
vec_states.push_back(i)