Установить коэффициент / элемент 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 ответ:
Это не так просто, как должно быть, но вы можете заставить его работать.
Доступ к элементам в 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)