2017-01-30 6 views
0

Пусть A - симметричная матрица и v - вектор. Я выписку из блока п столбцов, начиная с J и умножить на V, используяC++ Собственная копия?

VectorXd a; 
a = A.middleCols(j,n).selfadjointView<Lower>() * v // does not compile 

, так как это не компилируется, тогда как это

a = MatrixXd(A.middleCols(j,n).selfadjointView<Lower>()) * v 

делает, мне интересно, имеет ли второй вариант копия

A.middleCols(j,n).selfadjointView<Lower>() 

или выполняет вычисления непосредственно?

Спасибо за любой намек.

EDIT: Я подозреваю, что проблема имеет что-то делать с типами аргументов, как я получаю сообщение об ошибке:

invalid argument type 'typename ConstSelfAdjointViewReturnType.... to unary expression' 

Действительно, аргумент функции передается по константной ссылке, используя один из

const MatrixXd& A 
const Ref<const MatrixXd>& A 

Вот пример:

// this version doesn't compile 
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){ 
// B is a symmetric matrix 

VectorXd a; 
a = A.middleCols(3, 4).selfadjointView<Lower>() * v; 
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix 
M.block(1, 2, 3, 4).triangularView<Lower>() += B.selfadjointView<Lower>(); 

return M; 
} 

// this version compiles 
MatrixXd returnSymmetricMatrix(const MatrixXd& A, const VectorXd& v, const MatrixXd& B){ 
// B is a symmetric matrix 

VectorXd a; 
a = MatrixXd(A.middleCols(3, 4).selfadjointView<Lower>()) * v; 
MatrixXd M(code_fill(){...}); 
// code_fill is the function filling the lower triangular part of a symmetric matrix 
Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

return M; 
} 

EDIT2 Что касается моего первоначального вопроса и примера, который я добавил в разделе «Редактирование», я немного смущен относительно копирования. Как я понимаю разницу между рабочим и нерабочих версий, линия

Matrix(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

работает, потому что его LHS рассказывает Эйген, что M.block (1, 2, 3, 4) .triangularView() на самом деле матрица, а не ссылка на матрицу. В противном случае оператор + = выполнил бы ошибку, чтобы этот оператор не был перегружен для .block(). Итак, мой первоначальный вопрос заключается в том, говорит ли Матрица (...), что это матрица, позволяющая вычислять, или, скорее, копировать ... в матрицу? Благодаря!

+0

Выражение (и работает) отлично подходит для меня. Можете ли вы дважды проверить и добавить какую-либо дополнительную информацию? –

+0

Да, первый должен работать нормально, я вижу, что он использует 'M' вместо' A' ... – ggael

+0

Можете ли вы использовать его для [MCVE]? –

ответ

1

следующее выражение:

A.middleCols(j,n).selfadjointView<Lower>() 

не создает копию.

С другой стороны, чтобы избежать временного результата продукта, вы можете добавить .noalias():

a.noalias() = M.middleCols(j,n).selfadjointView<Lower>() * v; 

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

a = M * a; 

вести себя так, как ожидалось.

EDIT:

относительно вашего вопроса компиляции, следующий отлично компилируется:

#include <Eigen/Dense> 
using namespace Eigen; 
int main() 
{ 
    int n = 10; 
    MatrixXd M = MatrixXd::Random(n,2*n); 
    VectorXd v = VectorXd::Random(n); 
    VectorXd a; 
    a.noalias() = M.middleCols(2,n).selfadjointView<Upper>() * v; 

    const Ref<const MatrixXd>& A = M; 
    a.noalias() = A.middleCols(2,n).selfadjointView<Upper>() * v; 
} 

EDIT2

Следующая строка:

MatrixXd(M.block(1, 2, 3, 4).triangularView<Lower>()) += B.selfadjointView<Lower>(); 

не имеет смысла, поскольку вы создаете временную копию, которую вы назначаете. Напомним, что здесь MatrixXd(whatever) вызывает конструктор Eigen::Matrix. Кроме того, назначение самосопряженного представления треугольному виду не имеет смысла. Я даже не могу думать о том, что может быть разумным поведением для этого. Если вы хотите обновить нижнюю треугольную часть, а затем сделать:

M.block(1, 2, 3, 4).triangularView<Lower>() += B; 

В этом случае triangularView ведет себя как пишущая маску.

+0

Большое спасибо за напоминание .noalias(), но в этом случае я действительно не понимаю, зачем нужен .noalias(), поскольку я вычисляю a = M * v (а не a = M * a). Я не пытаюсь избежать хранения, поскольку мне это действительно нужно для будущих вычислений. Тем не менее, я пытаюсь избежать копирования A.middleCols (j, n) .selfadjointView (), и я все еще озадачен тем, почему первая версия работает для вас, так как это не для меня (и да M вместо A - опечатка здесь, а не в моем коде). – itQ

+0

Это связано с тем, что во время компиляции мы не можем знать, выполняете ли вы = Mv или a = Ma, и даже во время выполнения это очень сложно в общем случае. Таким образом, по умолчанию a = Mv оценивается так, как будто существует псевдонимы между a и M или v, поэтому: 'tmp = M * v; а = TMP; '. – ggael

+0

Большое спасибо! Я получил вопрос .noalias()! – itQ