2015-02-18 4 views
3

Короче говоря, вопрос заключается в том, чтобы передать объектИспользование Эйген :: Карта <Эйген :: MatrixXd> в качестве аргумента функции типа Эйгена :: MatrixXd

Eigen::Map<Eigen::MatrixXd> 

к функции, ожидающей

Eigen::MatrixXd 

объект.


Longer история:

У меня есть эта C++ функция объявления

void npMatrix(const Eigen::MatrixXd &data, Eigen::MatrixXd &result); 

вместе с этой реализации

void npMatrix(const Eigen::MatrixXd &data, Eigen::MatrixXd &result) 
{ 
//Just do s.th. with arguments 
std::cout << data << std::endl; 

result(1,1) = -5; 
std::cout << result << std::endl; 
} 

Я хочу, чтобы вызвать эту функцию из питона с помощью numpy.array как аргументы. Для этого я использую функцию-обертку, написанный на C++

void pyMatrix(const double* p_data, const int dimData[], 
           double* p_result, const int dimResult[]); 

, которая принимает указатель на данные, размер массива данных, указатель на результат, а размер результирующего массива. Указатель данных указывает на постоянный патч памяти, поскольку данные не должны изменяться, тогда как патч памяти, зарезервированный для результата, записывается. Реализация функции

void pyMatrix(const double *p_data, const int dimData[], double *p_result, const int dimResult[]) 
{ 
Eigen::Map<const Eigen::MatrixXd> dataMap(p_data, dimData[0], dimData[1]); 
Eigen::Map<Eigen::MatrixXd> resultMap(p_result, dimResult[0], dimResult[1]); 

resultMap(0,0) = 100; 

npMatrix(dataMap, resultMap); 
} 

определяет Eigen :: Map для данных и результатов соответственно. A Eigen :: Map позволяет получить доступ к необработанной памяти как к виду Eigen :: Matrix. DataMap имеет тип

<const Eigen::MatrixXd> 

поскольку связанная память считывается только; resultMap в отличие от этого типа

<Eigen::MatrixXd> 

так как он должен быть доступен для записи. Линия

resultMap(0,0) = 100; 

показывает, что resultMap записывается на бумаге. При передаче dataMap в npMatrix(), где ожидается работа const Eigen :: MatrixXd, я не смог найти способ передать resultMap таким же образом. Я уверен, проблема связана с тем, что первый аргумент npMatrix является const, а второй - нет. Возможное решение, которое я нашел, чтобы определить

Eigen::MatrixXd resultMatrix = resultMap; 

и передать эту resutlMatrix в npMatrix(). Однако, я думаю, это создает копию и, следовательно, убивает красивое отображение памяти Eigen :: Map. Так что мой вопрос.

Есть ли способ передать Eigen: Map для функции, которая ожидает не const const Eigen :: MatrixXd?

В качестве побочного примечания: я мог бы изменить npMatrix, чтобы ожидать Eigen :: Map, но поскольку в реальном проекте функции уже существуют и протестированы, я бы не стал их раздражать.

Чтобы завершить этот вопрос, вот файл питон вызвать pyMatrix()

import ctypes as ct 
import numpy as np 
import matplotlib.pyplot as plt 

# Load libfit and define input types 
ct.cdll.LoadLibrary("/home/wmader/Methods/fdmb-refactor/build/pyinterface/libpyfit.so") 
libfit = ct.CDLL("libpyfit.so") 

libfit.pyMatrix.argtypes = [np.ctypeslib.ndpointer(dtype=np.float64, ndim=2), 
                np.ctypeslib.ndpointer(dtype=np.int32, ndim=1), 
                np.ctypeslib.ndpointer(dtype=np.float64, ndim=2, flags='WRITEABLE'), 
                np.ctypeslib.ndpointer(dtype=np.int32, ndim=1) 
                ] 

data = np.array(np.random.randn(10, 2), dtype=np.float64, order='F') 
result = np.zeros_like(data, dtype=np.float64, order='F') 

libfit.pyMatrix(data, np.array(data.shape, dtype=np.int32), 
           result, np.array(result.shape, dtype=np.int32)) 

ответ

1

Pass как обычный указатель на данные, и Эйген :: Карта его там.В качестве альтернативы используйте template <typename Derived> и т. Д., Найденные в http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html Мой личный выбор является первым, хотя, как лучше иметь код, который не раскрывает все упрямство каждого API, который вы использовали. Кроме того, вы не потеряете совместимость ни с самим собой, ни с какой-либо другой библиотекой, которую вы (или кто-либо еще) можете использовать позже.

Существует также еще один трюк, я выяснил, что может быть использовано во многих случаях:

Eigen::MatrixXd a; //lets assume a data pointer like double* DATA that we want to map //Now we do new (&a) Eigen::Map<Eigen::Matrix<Double,Eigen::Dynamic,Eigen::Dynamic>> (DATA,DATA rows,DATA cols);

Это будет делать то, что вы спрашиваете, не теряя память. Я думаю, что это классный трюк, и a будет вести себя как матрица Xd, но я не проверял каждый раз. У него нет копии памяти. Однако перед назначением вам может потребоваться изменить размер a в нужном размере. Тем не менее, компилятор не будет сразу выделять всю память во время запроса операции resize, поэтому не будет больших бесполезных распределений памяти!

Будьте осторожны! Операции изменения размера могут быть перераспределить память, используемую собственной матрицей! Итак, если вы :: Карта памяти, но затем вы выполняете действие, которое изменяет размер матрицы, оно может быть отображено в другое место в памяти.

+0

Спасибо за ваш ответ. Я согласился с этим, так как считаю, что в целом это хорошее решение. Как я уже сказал в вопросе, я не хочу менять интерфейс функции для вызова. Поэтому мое решение - создать необходимую мне карту. Это приводит к трате памяти и времени процессора, но по сравнению с остальной частью программы это не имеет значения. – ReedWood

+0

Спасибо! Я подумал еще об этом, и я думаю, что нашел другой ответ, который будет делать именно то, что вы просите, и не изменяйте объявление функции. Я уточню свой ответ! –

+1

Прошло 18 месяцев, но у SO так много полезной информации. Здесь 'new (& a)' является версией места размещения и, таким образом, явным образом отбрасываю с объекта «Карта» на «Матрица», я полагаю (пожалуйста, поправьте меня, если я ошибаюсь). Я предполагаю, что изменение размера, на которое вы ссылаетесь, состоит в том, что 'a' не является владельцем данных, поэтому не может присваивать ему другую матрицу, используя, например, присваивание' operator = '. Я делаю это, отслеживая владение данными - изначально 'a' может не владеть данными, но перед назначением я изменяю его размер, когда он НЕ является владельцем или текущий размер не является правильным. – NameRakes

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