2016-08-24 6 views
0

많은 내용을 읽었습니다. documentation을 읽었습니다. 내가 놓친 부분을 발견하면 만족 스러울 것입니다. 배경으로, 3.2.7 고유 라이브러리를 사용하여 Visual Studio 2015에서 x86 Windows 10에서 컴파일 중입니다. 3.2.7 버전은 5 월부터 출시되었으며, 그 이후 릴리스가있는 동안 changelog에서 내 문제가 해결되었다는 것을 알지 못했습니다.큰 블록 계수 곱셈은 Eigen 라이브러리 C++에서 실패합니다

이 문제는 특정 크기를 초과하는 행렬에만 나타납니다. 이것이 내 시스템에 고유 한 무엇인가 또는 Eigen 고유의 것의 부산물인지 나는 모른다.

다음 코드는 디버그 모드와 릴리스 모드 모두에서 액세스 위반을 생성합니다.

int mx1Rows = 255, cols = 254; 
{//this has an access violation at the assignment of mx2 
     Eigen::MatrixXd mx1(mx1Rows, cols); 
     Eigen::MatrixXd mx2(mx1Rows + 1, cols); 
     Eigen::Block<Eigen::MatrixXd, -1, -1, false> temp = mx2.topRows(mx1Rows); 
     mx2 = temp.array() * mx1.array();//error 
} 

나는 결과가 aliased을해야하기 때문에 계수 현명한 곱셈의 할당이 안전하다고 생각합니다.

이 문제는 mx1Rows가 값 254로 줄어들면 액세스 위반이 나타나지 않는 경우에 흥미로워집니다. 256x254의 mx2 크기로 문제가 발생하지만 255x254 크기는 문제가되지 않습니다. 열 크기를 늘리면 액세스 위반도 발생할 수 있으므로 문제는 총 항목 수와 관련이 있습니다. mx1 및 mx2에 값이 채워지더라도 문제가 재현 될 필요는 없습니다. 채워진 행렬을 사용하면 문제를 재현 할 필요가 없습니다.

temp에 topRows() 블록을 할당하지 않은 유사한 코드는 릴리스 모드에서 액세스 위반을 생성하지 않습니다. 원래 코드에서이 문제를 발견 한 이후로는 훨씬 복잡한 것이었고 특정 수의 루프 (행 크기가 행렬간에 일관성이 있음) 이후에만 나타 났기 때문에 더 많은 것이 있다고 생각합니다. 내 코드에서 너무 많이 진행되어 특정 수의 루프 이후에만 액세스 위반이 나타나는 조건을 격리 할 수 ​​없었습니다. 내가 알고 궁금 무엇

1) 나는 몇 가지 분명히 잘못된 방법으로 아이겐를 사용하고있다?

2)이 문제를 재현 할 수 있습니까? (귀하의 환경에 대한 자세한 내용은 무엇입니까?)

3) Eigen 라이브러리의 버그입니까?

블록이 아닌 임시 매트릭스에 블록을 할당하면이 문제를 해결할 수 있습니다. 비효율적이라 할지라도이 문제에 대해서는 관심이 없습니다.

+1

부정적인 1 개의 인덱스가 허용되는 것으로 가정하고 버그처럼 보입니다. 행렬을 초기화하면 작은 값의 mx1Rows 및 cols에서도 배열 mult에 가비지를 넣는 것을 볼 수 있습니다. 'temp.array(). eval(). array()'를 실행하면 문제가 없습니다. 데이터 외부에서 앨리어싱을하지 않습니다. x64로 실행되지만 잘못되었습니다. 그것은 단지 잘못이 아닙니다. – doug

답변

2

문제는 tempmx2 보유 계수를 참조하지만, 표현식이 평가되기 전에 마지막 할당에서, mx2 먼저 크기를 조정할 것입니다. 따라서 표현식을 실제로 평가하는 동안 temp은 쓰레기를 참조합니다.더 정확하게, 여기에 실제로 (단순화 된 방식으로) 생성되는 것입니다 :

double* temp_data = mx2.data; 
free(mx2.data); 
mx2.data = malloc(sizeof(double)*mx1Rows*cols); 
for(j=0;j<cols;++j) 
    for(i=0;i<mx1Rows;++i) 
    mx2(i,j) = temp_data[i+j*(mw1Rows+1)] * mx1(i,j); 

이는 aliasing issue라고합니다.

당신은 임시의 발현을 평가하여 해결할 수 있습니다 :

MatrixXd temp = mx2.topRows(mx1Rows); 
mx2 = temp.array() * mx1.array(); 

또 다른 솔루션을 평가하는 것입니다 :

mx2 = (temp.array() * mx1.array()).eval(); 

또 다른 방법은 자체 메모리를 잡고 진정한 MatrixXdmx2.topRows(.)를 복사하는 것입니다 나중에 temp에 입력하고 크기를 조정하십시오.

Block<MatrixXd, -1, -1, false> temp = mx2.topRows(mx1Rows); 
temp = temp.array() * mx1.array(); 
mx2.conservativeResize(mx1Rows,cols); 
+0

이런 종류의 문제는 다른 곳에서 조작되는 (객체가 아닌) 객체에 대한 참조를 유지하는 상황에서 항상 발생합니다. – Walter

+0

Eigen에 용량 개념이 없다면 (STL의 문자열에 대한 용량 대 크기와 같은 경우가 아니라면) componentwise 곱셈은 재 할당을 요구하지 않아야합니다. 그것은 기본적으로 문제입니까? LHS는 더 이상 같은 크기를 가지지 않으므로 배열을 사용하기 때문에 RHS가 앨리어싱 된 행렬 곱셈을 사용하지 않기 때문에 이것이 재 할당됩니다. 만약 그렇다면 재배치 나 부패없이 다음이 성공할 수있을 것입니다. (mx1Rows) mx2.topRows –

+0

이것은 정확히 제가 제안한 최신 솔루션이지만 'temp'를 바로 가기로 사용합니다. 또한 기본적으로 MatrixXd에는 열 주요 저장 공간이 있으므로 'temp'열은 순차적으로 메모리에 저장되지 않습니다. 그래서 여기에서 'conservativeResize'는 마지막 바이트를 해제하기 전에 먼저 메모리 복사본을 통해 열을 압축해야합니다. 물론, 크기 조정을 생략하고 나머지 계산에서'mx2' 대신'temp'를 사용할 수도 있습니다. – ggael

-2

작은 크기에도 영향을주는 버그처럼 보입니다. 올바른 결과를 얻으려면 버그 유도 라인에서 주석을 제거하십시오.

수정. ggael의 답변에서 알 수 있듯이, 별칭입니다. 그것은 종종 동일한 객체에서 나중에 사용되는 임시 변수를 만들기 위해 자동을 사용하여 발생하는 유형입니다.

#include <iostream> 
#include <Eigen/Dense> 

int main() 
{//this has an access violation at the assignment of mx2 
    //const int mx1Rows = 255, cols = 254; 
    const int mx1Rows = 3, cols = 2; 
    Eigen::MatrixXd mx1(mx1Rows, cols); 
    int value = 0; 
    for (int j = 0; j < cols; j++) 
     for (int i = 0; i < mx1Rows; i++) 
      mx1(i,j)=value++; 
    Eigen::MatrixXd mx2(mx1Rows + 1, cols); 
    for (int j = 0; j < cols; j++) 
     for (int i = 0; i < mx1Rows+1; i++) 
      mx2(i,j)=value++; 
    Eigen::Block<Eigen::MatrixXd, -1, -1> temp = mx2.topRows(mx1Rows); 
    mx2 = temp.array()/*.eval().array()*/ * mx1.array();r 
    std::cout << mx2.array() << std::endl; 
} 

// with /*.eval().array()*/ uncommented 
//0 30 
//7 44 
//16 60 

// Original showing bug 
//-0 -4.37045e+144 
//-1.45682e+144 -5.82726e+144 
//-2.91363e+144 -7.28408e+144 
+0

이것은 문제를 설명하지는 않지만 단순히 설명에 적합한 방식으로 설명하지만 대답은 아닙니다. – Walter

+0

@Walter Agreed. 자동을 사용할 때 여러 줄 "temps"에서도 발생하는 앨리어싱 유형입니다. 효과적으로'Eigen :: Block temp'는 temp를 MatrixXd로 선언하고 오른쪽에있는 Block을 사용하기보다는 그것을합니다. 나는 그것을보아야 만했다. – doug