2017-02-09 4 views
0

Я использую EIGEN для оптимизации и функций с разреженной матрицей. Все «работает» хорошо, за исключением некоторых случаев, и я не могу понять этот случай.EIGEN: Малое умножение матрицы, не создающее обрезанный результат

Вот вещь:

Matrix A 
2 0 0 
0 2 0 
0 0 2 

Matrix B 
6 3 
0 1 
2 8 

Result 
12 6 
0 2 
4 16 

Как вы можете видеть, что это правильный результат, и я всегда иметь правильный результат.

Проблема заключается в значениях, которые считаются «Non Zero». В этом случае:

SparseMatrix<int, RowMajor> A; 
SparseMatrix<int, RowMajor> B; 
//Parsing and initializing matrix 
SparseMatrix<int, RowMajor> result = A*B; 
result.pruned(); 
cout << result.nonZeros(); 

Результат nonZeros() составляет 5, что является «нормальным» случай, так как результат получил только 5 не равен нулю значения. Теперь давайте рассмотрим этот код:

SparseMatrix<int, RowMajor> A; 
SparseMatrix<int, RowMajor> B; 
//Parsing and initializing matrix 
SparseMatrix<int, RowMajor> result = (A*B).pruned(); 
cout << result.nonZeros(); 

Результат nonZeros() равно 6. Я не понимаю, почему это синтаксис доступен на the documentation.

А теперь самое странное, что на очень большой матрицы result = A*B; result.pruned() иногда и экономить 0 в ноль, но меньше, чем если бы я использовал (A*B).pruned();

У меня три вопроса:

  • Почему result = (A*B).pruned() и result=A*B;result.pruned(); дает разные результаты относительно значений nonZero (а не эффективный результат, который является правильным в обоих случаях)?
  • Почему значения 0 из продукта иногда не считаются нулевыми значениями?
  • У вас такой же результат, как у меня?

Я использую Visual Studio Professional 2013 и Eigen 3.3.2, используя режим DEBUG и предназначенный для WIN32.

Благодарим за помощь.

EDIT: Контрольный показатель разреженного умножения с VS2013, режим DEBUG/Release для W32 (с набором инструкций SSE2 или без него, одинаковые результаты в обоих случаях); результат всегда правильный, поэтому я не вставляю его здесь, он не приносит никакой информации.С:

1 = SparseMatrix<int, RowMajor> resultA = A*B;

2 = SparseMatrix<int, RowMajor> resultB = (A*B);resultB.pruned();

3 = SparseMatrix<int, RowMajor> resultC = (A*B).pruned();

Случай 1

Matrix A 
2 0 0 
0 2 0 
0 0 2 

Matrix B 
5 3 
0 1 
2 8 

Ожидаемое значение = 5

1 = 5

2 = 5

3 = 6

Случай 2 матрицы являются слишком большими, here является файл

Ожидаемое значение = 0

1 = 1444

2 = 1444

3 = 0

Как вы можете видеть, в зависимости как от входа и, как я звоню функции, результат оптимизируется или нет, и ни один из 1, 2 или 3 работает в каждом конкретном случае.

EDIT²: Проблема устранена решением ggael (спасибо).

ответ

1

Мой предыдущий ответ (ниже) был неправильным. Исправлена ​​проблема there.

Это потому, что вы ориентируетесь win32 и, таким образом, вы ударяете классические проблемы с расширенной точностью регистров FPU. По умолчанию по умолчанию, pruned удаляют записи, которые строго равны 0, но с FPU, может быть, что ноль становится равным нулю только после того, как будет скопирован из своего регистра в память. Обновите флаги компилятора либо целевому набору инструкций SSE2, либо чтобы убить дополнительную точность FPU .

+0

Я просто изменил флаг компилятора на набор инструкций SSE2 и по-прежнему считал 0 значениями нуля. Что вы имеете в виду, убивая дополнительную точность FPU? Написание чего-то вроде конвертера? Я сделал тест, и, следуя результатам, я не уверен, что это проблема точности, потому что в зависимости от того, какой порядок вы вызываете, результаты разные. Я собираюсь добавить это в первый пост. – Spazz

+0

Вы правы. Проблема исправлена ​​в 3.3 и ветви девела. – ggael