Strange behaviour when creating python attributes in cython cdef class - cython

We have given Cython code:
cdef extern from "C_File_A.h":
cdef struct C_Obj_A:
pass
cdef extern from "C_File_B.h":
cdef struct C_Obj_B:
pass
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
cdef class pC_Obj_B:
cdef const C_Obj_B * _c_self
cdef class pC_Obj_C:
cdef const C_Obj_A * _c_a
cdef const C_Obj_B * _c_b
cdef class Obj_A_Wrap(pC_Obj_A):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_a
cdef class Obj_B_Wrap(pC_Obj_B):
def __init__(self, pC_Obj_C obj_c):
self._c_self = obj_c._c_b
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a._c_self = obj_c._c_a
self.obj_b = Obj_B_Wrap(obj_c)
# Working
self.obj_a = Obj_A_Wrap(obj_c)
self.obj_b._c_self = obj_c._c_b
# Not working
self.obj_a._c_self = obj_c._c_a
self.obj_b._c_self = obj_c._c_b
I need a python object Stack with attrubutes accessible from Python, so I have added to Stack class cdef public pC_Obj_A obj_a and cdef public pC_Obj_B obj_b.These objects are wrappers to the C struct pointers.
When I initialize these objects with intermediary wrappers i.e. Obj_A_Wrap everything is fine.
When I initialize one of these objects directly i.e. self.obj_a._c_self = obj_c._c_a also everything is fine.
When both obj_a and obj_b are initialized directly (# Not Working part of code) I have got strange behaviour of my C library that inlcude C_File_A and C_File_B and respectively the C structs definitions. The behaviour is similar to memory corruption, or overwriting some parts of the memory that should not be.
I have no idea why the direct initialization causes this strange behaviour. Maybe you know?

I have found the solution of my problem. When I was trying to solve this problem I have printed only _c_self attribute of the given object to check that the pointer was properly assigned and it was but when I printed entire object it turned out that python object is None instead of proper object declared as attribute.
print(self.obj_a, self.obj_b) # 66f000c0 66f000c0
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # None None
The solution is to add Create function to cdef class:
cdef class pC_Obj_A:
cdef const C_Obj_A * _c_self
#staticmethod
cdef Create(C_Obj_A * ptr):
cdef pC_Obj_A result = pC_Obj_A()
result._c_self = ptr
return result
And use it like this:
cdef class Stack:
cdef public pC_Obj_A obj_a
cdef public pC_Obj_B obj_b
def __init__(self, pC_Obj_C obj_c):
self.obj_a = pC_Obj_A.Create(obj_c._c_a)
self.obj_b = pC_Obj_B.Create(obj_c._c_b)
Then printout is:
print(self.obj_a, self.obj_b) # <pC_Obj_A object at 0x029FF610> <pC_Obj_B object at 0x029FF620>
print(f'{<int>self.obj_a._c_self:x} {<int>self.obj_b._c_self:x}') # 2134b9c 2134c08
And everything works great!

Related

How to cast a python function to a C function pointer? [duplicate]

Hello i've been trying to call a python user-defined callback from c++ using cython for a while. But it looks like it's impossible without changes on the c++ side or a static function buffer.
So, is there only one option for binding a propper callback (ctypes with CFUNCTYPE)?
Cython 0.29.23
A.hpp:
typedef void (*Callback) ();
class A{
Callback callback;
public:
A(){
this->callback = nullptr;
}
void set_callback(Callback callback){
this->callback = callback;
}
void call_callback(){
this->callback();
}
};
A.pxd:
cdef extern from "A.hpp":
ctypedef void (*Callback) ()
cdef cppclass A:
A() except +
void set_callback(Callback callback)
void call_callback()
B.pyx
from A cimport A, Callback
cdef class B:
cdef A *c_self
cdef object callback
def __cinit__(self):
self.c_self = new A()
def __dealloc__(self):
del self.c_self
cdef void callback_func(self) with gil:
print("I'm here")
self.callback()
def set_callback(self, callback):
self.callback = callback
self.c_self.set_callback(<Callback>self.callback_func)
def call_callback(self):
self.c_self.call_callback()
def print_():
print("hello")
b = B()
b.set_callback(print)
b.call_callback()
Output:
I'm here
[segmentation fault]
Looks like ctypes: get the actual address of a c function is a good one work-around, but it uses ctypes.
It scares me, but works:
B.pyx
from A cimport A, Callback
import ctypes
from libc.stdint cimport uintptr_t
cdef class B:
cdef A *c_self
cdef object callback
def __cinit__(self):
self.c_self = new A()
def __dealloc__(self):
del self.c_self
def set_callback(self, callback):
f = ctypes.CFUNCTYPE(None)(callback)
self.callback = f
cdef Callback c_callback = (<Callback*><uintptr_t>ctypes.addressof(f))[0]
self.c_self.set_callback(c_callback)
def call_callback(self):
self.c_self.call_callback()
def hello():
print("hello")
b = B()
b.set_callback(hello)
b.call_callback()
A function pointer does not have any space to store extra information. Therefore it is not possible to convert a Python callable to a function pointer in pure C. Similarly a cdef function of a cdef class must store the address of the instance to be usable and that is impossible too.
You have three options:
Use ctypes as in https://stackoverflow.com/a/34900829/4657412 (the bottom half of the answer shows how to do it). ctypes accomplishes this with runtime code generation (and thus only works on processors that it explicitly supports).
Use a std::function in C++ instead of a function pointer. These can store arbitrary information. You need to write an object wrapper (or re-use one from elsewhere) so it isn't completely pure Cython. See Pass a closure from Cython to C++. What you're trying to do is probably better covered by How to use a Cython cdef class member method in a native callback.
Use the class C scheme where the callback is of type
void (CallbackT)(/* any args */, void* user_data)
and is registered with:
void register_callback(CallbackT func, void* user_data)
In this case user_data would be the address of your B instances (and you'd need to make sure it was Py_INCREFed before setting the address and Py_DECREFed before unsetting the address). Cython callback with class method provides an example.

How to access the typed-memory view element of a class declared in cython?

I am a beginner and I am sure this question is too simple. I am trying to test memory views in cython to get to know them much better.In my code I pass each memory view element (like [1,2]) as the cy class element move.
cdef class cy:
cdef public long[:] move
def __init__(self, move):
self.move = move
lst = []
for i in range(100):
lst.append([i, i+1])
cdef long[:, :] memview = np.asarray(lst)
b0 = cy(memview[0])
print(b0.move)
When I print the results. I get this:
<MemoryView of 'ndarray' object> # I expect for sth like [12, 13]
I need cy class prints out a list. How can I fix it?
there is another problem which occurs to me when I use this code:
cdef class parent:
cdef public:
list children
list moves
def __init__(self):
self.children = []
def add_children(self, moves):
cdef int i = 0
cdef int N = len(moves)
for i in range(N):
self.children.append(cy(moves[i]))
cdef int[:, :] moves = np.asarray(lst, dtype=np.int32)
obj = parent()
for move in moves:
obj.add_children(move)
After running this code I always get this error:
TypeError: a bytes-like object is required, not 'int'.
What causes this error and how can I fix this one?
Your first issue is just that a memoryview doesn't have a useful __str__ function for print to use. You can either convert it to an object that does print nicely
print(list(b0.moves))
print(np.asarray(b0.moves))
Or you can iterate through it yourself:
for i in range(b0.moves.shape[0]):
print(b0.moves[i], end=' ') # need to have Cython set to use Python 3 syntax for this line
print()
Your second problem is harder to solve since you don't tell us what line the error comes from. I think it's the constructor of cy which expects a memoryview but you pass an integer to. (I get a slightly different error message though).

Wrapping a c++ singleton with cython

Using Cython to wrap some parts from a C++ API to python, I'm having misunderstandings that I couldn't fix by search similar questions. I like to access a Factory class that has the constructors private and a public method GetInstance.
namespace cpplibrary
{
class CppFactory
{
public:
static CppFactory& GetInstance();
private:
CppFactory(void);
CppFactory( const CppFactory& );
};
}
I'm trying a cython code like:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
CppFactory& GetInstance()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = GetInstance()
I've check with as many variants as I thought. With and without the declaration of the constructor in the extern. With different ways to define the _thisptr from different posted examples. And so on. But I couldn't find a singleton example like this.
Where is the mistake I can't see?
I think you've got two issues:
1) How to wrap static methods: the recommended way is to declare the function outside the class, and use a string to tell Cython what name it should use in C++
2) The assignment to thisptr, where you just need to use & to get a pointer from the reference.
Code:
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
CppFactory() except +
# declare outside the class and use a string to specify name
# unfortunately this doesn't seem to play well with namespace
# so we need to specify it again
cdef CppFactory& CppFactory_GetInstance "cpplibrary::CppFactory::GetInstance"()
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = &CppFactory_GetInstance()
One of the problem is indeed to wrap a static method (here Getinstance()).
You can do that by using the cython #staticmethod decorator (see Cython's doc here):
cdef extern from "cppFactory.h" namespace "cpplibrary":
cdef cppclass CppFactory:
#staticmember
CppFactory& GetInstance()
Then, the .pyx can be:
cdef class PyFactory:
cdef CppFactory* _thisptr
def __cinit__(self):
self._thisptr = new CppFactory()

Set coefficient/element of Eigen::Matrix3d in Cython

I am trying to create a wrapper in Cython for a library which uses Eigen::Matrix3d matrices. How can I set an individual element/coefficient of the Matrix3d object?
I know, I can get the value with the coeff(row, col) method but could not find any function set_coeff(row, col, value) - or however that might be called - to set the value.
After declaring the Matrix3d with
cdef decl_eigen.Matrix3d t = decl_eigen.Matrix3d()
I want to set the values, but none of the following constructs work in Cython:
t << 1,2,3,4,5,6,7,8,9
t(0,0) = 1
t[0][0] = 1
and I cannot use a constructor with the values, because to my knowledge there does not exist any.
Here are the files I have come up so far:
decl_eigen.pxd:
cdef extern from "Eigen/Dense" namespace "Eigen":
cdef cppclass Vector3d:
Matrix3d() except +
double coeff(int row, int col)
decl_foo.pxd:
cimport decl_eigen
cdef extern from "../foo.hpp" namespace "MyFoo":
cdef cppclass Bar:
Bar() except +
void transform(decl_eigen.Matrix3d &transformation)
foo.pyx:
import decl_eigen
cimport decl_foo
cdef class Bar:
cdef decl_foo.Bar *thisptr
def __cinit__(self):
self.thisptr = new decl_foo.Bar()
def __dealloc__(self):
del self.thisptr
def transform(self, transformation):
cdef decl_eigen.Matrix3d t = decl_eigen.Matrix3d()
for i in range(3):
for j in range(3):
k = i*3 + j
# Set the coefficient of t(i,j) to transformation[k], but how????
self.thisptr.transform(t)
Thanks.
It's not as straightforward as it should be, but you can make it work.
Element access in Eigen looks to mostly be done through operator():
// (copied from http://eigen.tuxfamily.org/dox/GettingStarted.html)
MatrixXd m(2,2);
m(0,0) = 3;
m(1,0) = 2.5;
m(0,1) = -1;
m(1,1) = m(1,0) + m(0,1);
Therefore, we need to define operator() so you can access it in Cython. I've assumed it returns a double& - I can't actually find the definition in Eigen since it's buried deep in a template class hierarchy (It's not terribly important what it actually returns - it acts like it returns a double&, which should be good enough).
Unfortunately, operator() seems slightly broken in Cython (see Cython C++ wrapper operator() overloading error) so we have to alias it as something else. I've used element.
cdef extern from "eigen3/Eigen/Dense" namespace "Eigen":
# I'm also unsure if you want a Matrix3d or a Vector3d
# so I assumed matrix
cdef cppclass Matrix3d:
Matrix3d() except +
double& element "operator()"(int row,int col)
In principle we'd just like to be able to do m.element(0,0) = 5. However, Cython doesn't like this. Therefore, I've had to create a function which does this through a slightly complicated assignment to pointer type mechanism.
cdef void set_matrix_element(Matrix3d& m, int row, int col, double elm):
cdef double* d = &(m.element(row,col))
d[0] = elm
Therefore, to set a matrix element, we just call this function. Here's the function I made to test it on:
def get_numbers():
cdef Matrix3d m = Matrix3d()
cdef int i
for i in range(3):
set_matrix_element(m,i,i,i)
return m.element(0,0),m.element(1,1),m.element(2,2),m.element(1,2)
# returns 0,1,2, and something else (I get 0, but in principle
# I think it's undefined since it's never been specifically set)

c++ class in fused type

I wish to implement python wrapper for a bunch of c++ classes. Somewhere in pxd I have:
cdef cppclass FooImpl1:
FooImpl1()
int foo()
cdef cppclass FooImpl2
FooImpl2()
int foo()
I wonder if I can write something like this in pyx python wrapper:
ctypedef fused FooImpl:
FooImpl1*
FooImpl2*
cdef class Foo:
cdef FooImpl impl
def __cinit__(self, int selector):
if selector == 1:
self.impl = new FooImpl1()
else:
self.impl = new FooImpl2()
def func(self):
# depending on the object stored in impl FooImpl2::foo or FooImpl1::foo
# will be called
return self.impl.foo()
Is there a way to accomplish expected behavior? FooImpl1 and FooImpl2 don't share abstract interface, they are template specializations of a class.
As of this version (0.20), Cython doesn't support fused types in classes, only in function parameters and variables. Here are the docs.