Установить коэффициент / элемент Eigen:: Matrix3d в Cython


Я пытаюсь создать оболочку в Cython для библиотеки, которая использует матрицы Eigen::Matrix3d. Как задать отдельный элемент / коэффициент объекта Matrix3d?

Я знаю, что могу получить значение с помощью метода coeff(row, col), но не смог найти никакой функции set_coeff(row, col, value) - или как бы это ни называлось - для установки значения.

После объявления Matrix3d с помощью

cdef decl_eigen.Matrix3d t = decl_eigen.Matrix3d()

Я хочу задать значения, но ни одна из следующих конструкций не работает в Cython:

t << 1,2,3,4,5,6,7,8,9
t(0,0) = 1
t[0][0] = 1

И Я не могу использовать конструктор со значениями, потому что, насколько мне известно, их не существует.

Вот файлы, которые я нашел до сих пор:

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)

Фу.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)

Спасибо.

1 2

1 ответ:

Это не так просто, как должно быть, но вы можете заставить его работать.

Доступ к элементам в Eigen в основном осуществляется через 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);

Поэтому нам нужно определить оператор (), чтобы вы могли получить к нему доступ в Cython. Я предположил, что он возвращает double& - я на самом деле не могу найти определение в Eigen, так как он глубоко похоронен в иерархии классов шаблонов (не очень важно, что он на самом деле возвращает - он действует так, как будто он возвращает двойное&, что должно быть хорошо достаточно).

К сожалению, operator() кажется немного нарушенным в Cython (см. Cython c++ wrapper operator() overloading error), поэтому мы должны псевдонимировать его как что-то другое. Я использовал 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)

В принципе мы просто хотели бы иметь возможность делать m.element(0,0) = 5. Однако Цитону это не нравится. Поэтому мне пришлось создать функцию, которая делает это через немного сложное назначение механизма типа указателя.

cdef void set_matrix_element(Matrix3d& m, int row, int col, double elm):
    cdef double* d = &(m.element(row,col))
    d[0] = elm

Поэтому, чтобы задать элемент матрицы, мы просто вызываем эта функция. Вот функция, которую я сделал, чтобы проверить ее:

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)