Alex Botev
Alex Botev

Reputation: 1399

Cython - how to properly call operator with references

I have the following code in my Cython wrapper to a C++ code:

# distutils: language = c++
# distutils: sources = symbolic.cpp
from libcpp.vector cimport vector
from libcpp.pair cimport pair
from libcpp.string cimport string
from libcpp cimport bool

cdef extern from "symbolic.h" namespace "metadiff::symbolic":
    cdef cppclass SymbolicMonomial:
        vector[pair[int, int]] powers
        long long coefficient;
        SymbolicMonomial()
        SymbolicMonomial(long)
        SymbolicMonomial(const SymbolicMonomial&)
        bool is_constant()
        long long int eval(vector[int]&)
        long long int eval()
        string to_string()
        string to_string_with_star() const

    cdef SymbolicMonomial mul_mm"operator*"(const SymbolicMonomial&, const SymbolicMonomial&)
    # SymbolicMonomial operator*(long long, const SymbolicMonomial&)
    # SymbolicMonomial operator*(const SymbolicMonomial&, long long)


cdef class SymMonomial:
    cdef SymbolicMonomial* thisptr      # hold a C++ instance which we're wrapping
    def __cinit__(self):
        self.thisptr = new SymbolicMonomial()
    def __cinit__(self, int value):
        self.thisptr = new SymbolicMonomial(value)
    def __dealloc__(self):
        del self.thisptr
    def is_constant(self):
        return self.thisptr.is_constant()
    def eval(self):
        return self.thisptr.eval()
    def __str__(self):
        return self.to_string_with_star()
    def to_string(self):
        return self.thisptr.to_string().decode('UTF-8')
    def to_string_with_star(self):
        return self.thisptr.to_string_with_star().decode('UTF-8')
    def __mul__(self, other):
        return mul_mm(self.thisptr, other)
def variable(variable_id):
    monomial = SymMonomial()
    monomial.thisptr.powers.push_back((variable_id, 1))
    return monomial

However, I never figured it out how to call the mul_mm method correctly. It keeps saying Cannot convert 'SymbolicMonomial' to Python object or vice versa. The thing is I need to be able to multiply two SymMonomials in this way. However for some reason I can not get the hang of it of how to do it properly. Any advices?

Upvotes: 0

Views: 383

Answers (1)

DavidW
DavidW

Reputation: 30910

You have a number of issues:

  1. You can't return C++ objects directly to Python - you need to return your wrapper type (assign to thisptr of the wrapper)

  2. You can't guarantee either self or other is of the correct type at the point the function is called (see the note in http://docs.cython.org/src/userguide/special_methods.html#arithmetic-methods about how the methods can be called with the operands in either order). To use the C/C++ members of a Cython class you need to ensure Cython knows that object is indeed of that class. I recommend using the <Classname?> style cast (note the question mark) which throws an exception if it doesn't match.

  3. You need to get thisptr from other too, rather than just passing the Python wrapper class to your C++ function.

The following should work.

def __mul__(self,other):
    cdef SymMonomial tmp = SymMonomial()
    cdef SymMonomial self2, other2
    try:
        self2 = <SymMonomial?>self
        other2 = <SymMonomial?>other
    except TypeError:
        return NotImplemented # this is what Python expects for operators
                      # that don't know what to do
    tmp.thisptr[0] = mul_mm(self2.thisptr[0],other2.thisptr[0])
    return tmp

Upvotes: 1

Related Questions