2015-04-28 3 views
2

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

Я знаю, я могу получить значение с помощью метода 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) 

foo.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) 

Спасибо.

+0

У меня нет опыта работы с cython, поэтому, пожалуйста, несите меня. Существует 'data()' [function] (http://eigen.tuxfamily.org/dox/classEigen_1_1PlainObjectBase.html # a4663159a1450fa89214b1ab71f7ef5bf), который дает вам доступ к указателю на данные. Затем вы можете выполнить математику, чтобы назначить требуемое значение. Кроме того, вы указываете, что 'cdef decl_eigen.Matrix3d ​​t = decl_eigen.Matrix3d ​​()' не работает, а затем имеет 'cdef decl_eigen.Matrix3d ​​t = decl_eigen.Matrix3d ​​()' в 'foo.pyx'. Это верно? –

+0

Спасибо Ави за то, что он указал на эту несогласованность. Декларация 'cdef' действительно работает. Я немного перефразировал свой вопрос. – HaM

+0

Предложение Avi работает со следующими изменениями: – HaM

ответ

4

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

элемент доступ в Эйгене выглядит в основном осуществляться через 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) 
+0

Спасибо @DavidW за то, что поделились своим прозрением и продолжительным, но легко следовать, объяснение !! – HaM

Смежные вопросы