использование C ++ контейнеров в Cython - PullRequest
0 голосов
/ 23 апреля 2020

Я хотел бы использовать в коде Cython C ++ std :: priority_queue, где каждый элемент должен быть структурой или классом, но я не знаю, как определить компаратор.

Если я рассматриваю priority_queue, элементы которого являются стандартными типами, все выглядит нормально, как в следующем примере:

simple.pyx

# distutils: language = c++
cimport cython
from libcpp.queue cimport priority_queue

def testIntPriorityQueue():
    cdef priority_queue[int] q
    q.push(5)
    q.push(15)
    q.push(7)

    print('q.top (after pushing 5, 15, 7) = ',q.top())

    q.pop()
    print('q.top (after popping one item) = ',q.top())`

main.py

import simple 

def main():
    simple.testIntPriorityQueue()

main()

Когда я выполняю этот код, приоритет_, после правильного нажатия 5, 15 и 7, оказывается сверху наибольшим (15) (как это возвращает q.top) и после выталкивания одного элемента q.top возвращает 7, которое стало наибольшим после удаления 15.

Теперь я хотел бы иметь подобное поведение, но с помещенными в очередь элементами, которые не являются объектами стандартного типа но что-то более сложное.

Я пытался определить такую ​​структуру с помощью следующих вещей:

simple.pxd

cimport cython
ctypedef struct myType:
    int key
    float a
    float b

simple.pyx

# distutils: language = c++
cimport cython
from libc.stdlib cimport  malloc, free
from libcpp.queue cimport priority_queue
from libcpp.vector cimport vector

def testPriorityQueue():
    cdef myType * item

    cdef priority_queue[myType*] q

    item = <myType *> malloc(sizeof(myType)) 
    item.key = 20
    item.a = 3.
    item.b = 4.
    q.push(item)

    item = <myType *> malloc(sizeof(myType)) 
    item.key = 10
    item.a = 1.
    item.b = 2.
    q.push(item)

    item = q.top()
    print('q.top',item.key,item.a,item.b)

Теперь не сообщается об ошибке ни от компилятора, ни во время выполнения, но, конечно, порядок в priority_queue не может быть определен, и из выводов, которые я получаю, что элемент на вершина - это последнее нажатие.

* 103 2 * В C ++, чтобы сделать priority_queue для сортировки помещенных элементов в такой ситуации, метод сравнения должен быть предоставлен в качестве аргумента для создания экземпляра очереди, но это, как я обнаружил, должно быть сделано через перегрузку оператора less как в этом примере C ++:
struct ToastCompare
{
    bool operator()(const Toast &t1, const Toast &t2) const
    {
        int t1value = t1.bread * 1000 + t1.butter;
        int t2value = t2.bread * 1000 + t2.butter;
        return t1value < t2value;
    }
};

Я попытался определить аналогичную функцию в cython, добавив следующие строки в файл pyx:

simple.pyx

cdef extern from *:
    """
    struct itemCompare{
        bool operator() (self, myType *t1, myType *t2) const
        {
            return t1.key < t2.key;
        }
    };
    """
    ctypedef struct itemCompare
cdef priority_queue[myType*,vector[myType*],itemCompare] q

Но во время компиляции я получаю "шаблонный тип priority_queue получает 1 аргумент, получил ошибку 3" .

Возможно ли в Cython использовать контейнер C ++ priority_queue с объекты пользовательских классов?

Пытаясь следовать предложению @ead, я попытался изменить код следующим образом:

simple.pyx

cdef extern from *:
    """
    bool operator<(const myType t1, const myType t2)
    { return t1.key < t2.key;}
    """
def testPriorityQueue():
    cdef priority_queue[myType*] q

, оставив в simple. pxd

cimport cython
from libcpp cimport bool
ctypedef struct myType:
    int key
    float a
    float b

, но он не может скомпилировать, давая:

simple. cpp: 694: 26: error: myType не называет оператор типа bool <(const myType t1, const myType t2) </p>

Итак, я попытался переместить определение структуры в C -бразорном коде и удалить его из simple.pxd

simple.pyx

def extern from *:
    """
    typedef struct myType{
        int key;
        float a;
        float b;       
    } myType;

    bool operator<(const myType t1, const myType t2)
    {return t1.key < t2.key;}
    """
    ctypedef struct myType
def testPriorityQueue():
    cdef myType * item
    cdef priority_queue[myType*] q

    item = <myType *> malloc(sizeof(myType)) 

и теперь ошибка компиляции:

Невозможно принять размер неполного типа 'myType'

Если я оставлю определение структуры также в файле pxd, но удаляю ctypedef struct myType из pyx, ошибка компиляции не возникает, но очередь с приоритетами не сортирует элементы, как будто перегрузка не была выполнена.

Где моя ошибка?

1 Ответ

0 голосов
/ 01 мая 2020

Для ответа на мой вопрос использовался следующий файл pxd :

cimport cython
from libcpp cimport bool

cdef extern from *:
    """
    typedef struct {
        int key;
        float a;
        float b;       
    } myType;

    bool operator<(const myType t1, const myType t2) {
        return t1.key < t2.key;
    }
    """
    ctypedef struct myType:
        int key
        float a
        float b

Спасибо @ead за помощь

...