1

I am working with Toby Segaran's collective intelligence code for genetic programming and I wanted to speed it up using Cython. I'm starting to realize I probably bit off more than I can chew for a first time Cython project. I've Googled and searched for an answer to how to make this work, but just can't seem to find the right combination of examples.

Here is the actual code in question:

# Function Wrapper Code
class fwrapper:

    def __init__(self, funct, params, name):
        self.function = funct
        self.params = params
        self.name = name


# Functions with 2 parameters
addw = fwrapper(lambda p: p[0] + p[1], 2, 'add')
subw = fwrapper(lambda p: p[0] - p[1], 2, 'subtract')
mulw = fwrapper(lambda p: p[0] * p[1], 2, 'multiply')
# If and > Function
def iffunc(l):
    if l[0] > 0:
        return l[1]
    else:
        return l[2]

ifw = fwrapper(iffunc, 3, 'if')


def isgreater(l):
    if l[0] > l[1]:
        return 1
    else:
        return 0
gtw = fwrapper(isgreater, 2, 'isgreater')

# List of possible functions
flist = [addw, mulw, ifw, gtw, subw]

So because Toby uses a Python class as a wrapper for the functions he uses in his genetic programming algorithm, I have to first "Cythonize" (I don't mean the actual cythonize call) the class itself. But the function wrapper class passes a function in. Worse yet, that function that is getting passed in wants a single parameter that is a Python list.

So trying to speed this up in Cython is problematic due to the fact that it requires some advanced topics that I can't seem to figure out.

First problem: I can't figure out how to pass in a c-style function into a "cythonized" version of this class. This solution will work, but isn't fast because it still treats the function I pass in as a slow python function:

# Function Wrapper Code
cdef class fwrapper:
    cdef public object function
    cdef public int params 
    cdef public object name

    def __init__(self, funct, int params, name):
        self.function = funct
        self.params = params
        self.name = name


# Functions with 2 parameters
cdef add(double param1, double param2):
    return param1 + param2
addw = fwrapper(add, 2, 'add')

cdef subtract(double param1, double param2):
    return param1 - param2
subw = fwrapper(subtract, 2, 'subtract')

cdef multiply(double param1, double param2):
    return param1 * param2
mulw = fwrapper(multiply, 2, 'multiply')

# If and > Function - 3 parameter functions
cdef iffunc(double param1, double param2, double param3):
    if param1 > 0:
        return param2
    else:
        return param3

ifw = fwrapper(iffunc, 3, 'if')


cdef isgreater(double param1, double param2):
    if param1 > param2:
        return 1
    else:
        return 0

gtw = fwrapper(isgreater, 2, 'isgreater')

# List of possible functions
flist = [addw, mulw, ifw, gtw, subw]

I've tried playing with ctypedef to no avail. That's probably the correct answer, but following this link (Cython: How to expose void* and function pointer in struct?) doesn't seem to work out right.

Bruce Nielson
  • 753
  • 8
  • 23
  • Possible duplicate of [Mixing cdef and regular python attributes in cdef class](https://stackoverflow.com/questions/42632297/mixing-cdef-and-regular-python-attributes-in-cdef-class) – ead Jul 14 '19 at 04:07
  • I'm going to update my question shortly to make it not a duplicate to that question. I did find that I can just declare it an object and it will work, but without speed up. So still looking for answer on how to pass a c function. – Bruce Nielson Jul 14 '19 at 04:34
  • Okay, the question is now not a duplicate of the link you added. But I don't see a way to remove it. – Bruce Nielson Jul 14 '19 at 05:13
  • Possible duplicate of [Function pointer in cython extension type](https://stackoverflow.com/q/55918787/5769463) – ead Jul 14 '19 at 07:08
  • Hmmm... maybe. Looks a lot like the link I included that didn't work for me. But it does seem closer. I'll try it out tonight and get back to you. – Bruce Nielson Jul 14 '19 at 13:31
  • ead, I read that link. It strikes me as a really poor solution. The idea that you have to write a function that allows you to pass a string so that it knows that function to pass back is going to be severely limited. I really just want to pass the function itself like you can in both C and Python. – Bruce Nielson Jul 14 '19 at 21:25
  • So part of the problem seems to be that the functions I want to pass can have 2 or 3 parameters. So it's not clear to me how to ctypedef it. Is this maybe just impossible in Cython? That's so hard to believe. – Bruce Nielson Jul 14 '19 at 21:31
  • https://stackoverflow.com/questions/5833094/get-a-timestamp-in-c-in-microseconds seems to be a solution to my question about getting time, but it also seems to be only a partial solution, so I'm struggling to make sense of it. I think it assumed more than I actually do. – Bruce Nielson Jul 14 '19 at 22:01

0 Answers0