Я пишу обертку для Eigen для личного использования, и я столкнулся со следующим странным поведением:
void get_QR(MatrixXd A, MatrixXd& Q, MatrixXd& R) {
HouseholderQR<MatrixXd> qr(A);
Q = qr.householderQ()*(MatrixXd::Identity(A.rows(),A.cols()));
R = qr.matrixQR().block(0,0,A.cols(),A.cols()).triangularView<Upper>();
}
void get_QR(double* A, int m, int n, double*& Q, double*& R) {
// Maps the double to MatrixXd.
Map<MatrixXd> A_E(A, m, n);
// Obtains the QR of A_E.
MatrixXd Q_E, R_E;
get_QR(A_E, Q_E, R_E);
// Maps the MatrixXd to double.
Q = Q_E.data();
R = R_E.data();
}
Ниже приведен тест:
int main(int argc, char* argv[]) {
srand(time(NULL));
int m = atoi(argv[1]);
int n = atoi(argv[2]);
// Check the double version.
double* A = new double[m*n];
double* Q;
double* R;
double RANDMAX = double(RAND_MAX);
// Initialize A as a random matrix.
for (int index=0; index<m*n; ++index) {
A[index] = rand()/RANDMAX;
}
get_QR(A, m, n, Q, R);
std::cout << Q[0] << std::endl;
// Check the MatrixXd version.
Map<MatrixXd> A_E(A, m, n);
MatrixXd Q_E(m,n), R_E(n,n);
get_QR(A_E, Q_E, R_E);
std::cout << Q[0] << std::endl;
}
Я получаю разные значения Q [0]. Например, я получаю "-0.421857" и "-1.49563".
благодаря
Ответ Джорджа правильный, но он страдает от ненужных копий. Лучшее решение состоит в отображении Q и R:
void get_QR(const double* A, int m, int n, double*& Q, double*& R) {
Map<const MatrixXd> A_E(A, m, n);
Map<MatrixXd> Q_E(Q, m, n);
Map<MatrixXd> R_E(Q, n, n);
HouseholderQR<MatrixXd> qr(A_E);
Q_E = qr.householderQ()*(MatrixXd::Identity(m,n));
R_E = qr.matrixQR().block(0,0,n,n).triangularView<Upper>();
}
Чтобы иметь возможность повторно использовать функцию get_QR
беря объект Eigen, используйте Ref<MatrixXd>
вместо MatrixXd
:
void get_QR(Ref<const MatrixXd> A, Ref<MatrixXd> Q, Ref<MatrixXd> R) {
HouseholderQR<MatrixXd> qr(A);
Q = qr.householderQ()*(MatrixXd::Identity(A.rows(),A.cols()));
R = qr.matrixQR().block(0,0,A.cols(),A.cols()).triangularView<Upper>();
}
void get_QR(const double* A, int m, int n, double* Q, double* R) {
Map<const MatrixXd> A_E(A, m, n);
Map<MatrixXd> Q_E(Q, m, n);
Map<MatrixXd> R_E(R, n, n);
get_QR(A_E, Q_E, R_E);
}
Ref<MatrixXd>
может обернуть любой объект Eigen, который похож на MatrixXd
без какой-либо копии. Это включает в себя MatrixXd
, а также выражения Map
и Block
. Для этого требуется Eigen 3.2.
Я не думаю, что это имеет какое-то отношение к Эйгену.
Похоже, вы назначаете указатель Q на ячейку памяти, принадлежащую локальной переменной Q_E
Q = Q_E.data();
который утечки предыдущего распределения памяти
double* Q = new double[m*n];
и не имеет смысла или неопределенна вне функции get_QR()
.
Вместо этого вы должны использовать memcpy:
memcpy(Q, Q_E.data(), m*n*sizeof(double));
get_QR(MatrixXd A, MatrixXd& Q, MatrixXd& R)
вместо переписывания этого кода? (В настоящее время это то, что у меня есть, но, кажется, повторение ненужного кода).