Garmaine Staff asked 1 year ago

I have have the following C++ class, which I want to wrap around with Cython. The class contains more methods but I only included the important ones.

#include <cstdint>
#include <cassert>
#include <vector>

template<class T>
class HkCluster {
private:
    std::vector<T> matrix;
    std::vector<T> labels;
    int n_labels{};
    int cols{};
    int rows{};
public:
    HkCluster() = default;

    HkCluster(T *matrix, int cols, int rows) {
        this->cols = cols;
        this->rows = rows;
        this->n_labels = cols * rows / 2;
        this->labels = std::vector<T>(cols * rows, 0);
        this->matrix = std::vector<T>(matrix, matrix + cols * rows);
    }

    void setMatrix(T * matrix){
        this->matrix = std::vector<T>(matrix, matrix + this->cols * this->rows);
    }

    void setCols(int cols) {
        HkCluster::cols = cols;
    }

    void setRows(int rows) {
        HkCluster::rows = rows;
    }
};

This is how I wrap the class with Cython. This code is working but you can see that I created the object on the heap, which is not optimal

import numpy as np

cdef extern from "hk.cpp":
    cdef cppclass HkCluster[T]:
        HkCluster();
        HkCluster(T *matrix, int cols, int rows);
        T hk_cluster(T * ret);
        void setMatrix(T * matrix);
        void setCols(int cols);
        void setRows(int rows);

def hk(a not None):
    arr = a.copy()
    if not arr.flags['C_CONTIGUOUS']:
        arr = np.ascontiguousarray(arr)
    if arr.dtype != np.int32:
        arr = np.cast[np.int32](arr)
    cdef int[:, ::1] a_mem_view = arr
    cdef HkCluster[int] *cluster = new HkCluster[int](&(a_mem_view[0, 0]), a.shape[1], a.shape[0])
    cluster.setMatrix(&(a_mem_view[0, 0]))
    cluster.setRows(a.shape[0])
    cluster.setCols(a.shape[1])
    count = cluster.hk_cluster(&(a_mem_view[0, 0]))
    del cluster
    return count, arr

This is my attempt to create the object on the stack, which results in Segmentation Fault. I read the documentation of Cython from https://cython.readthedocs.io/en/latest/src/userguide/wrapping_CPlusPlus.html and the code shall work. What am I doing wrong?

import numpy as np

cdef extern from "hk.cpp":
    cdef cppclass HkCluster[T]:
        HkCluster();
        HkCluster(T *matrix, int cols, int rows);
        T hk_cluster(T * ret);
        void setMatrix(T * matrix);
        void setCols(int cols);
        void setRows(int rows);

def hk(a not None):
    arr = a.copy()
    if not arr.flags['C_CONTIGUOUS']:
        arr = np.ascontiguousarray(arr)
    if arr.dtype != np.int32:
        arr = np.cast[np.int32](arr)
    cdef int[:, ::1] a_mem_view = arr
    cdef HkCluster[int] cluster
    cluster.setMatrix(&(a_mem_view[0, 0]))
    cluster.setRows(a.shape[0])
    cluster.setCols(a.shape[1])
    count = cluster.hk_cluster(&(a_mem_view[0, 0]))
    return count, arr