2014-01-02 1 views
4

Я переводя код MATLAB в Haskell, используя библиотеку hmatrix. Все идет хорошо, но Я натыкаюсь на функцию pos, потому что я не знаю, что она делает или что это эквивалент Haskell.Что такое эквивалент Haskell/hmatrix функции MATLAB pos?

код MATLAB выглядит следующим образом:

[U,S,V] = svd(Y,0); 
diagS = diag(S); 
... 
A = U * diag(pos(diagS-tau)) * V'; 
E = sign(Y) .* pos(abs(Y) - lambda*tau); 
M = D - A - E; 

Мой Haskell перевод до сих пор:

(u,s,v) = svd y 
diagS = diag s 
a = u `multiply` (diagS - tau) `multiply` v 

Это на самом деле тип проверки в порядке, но, конечно, я пропускаю "Pos" звонок , и он выдает ошибку:

inconsistent dimensions in matrix product (3,3) x (4,4) 

Так что я предполагаю, что pos делает что-то с размером матрицы? Googling «Функция matlab pos» не принесла ничего полезного, поэтому любые указатели очень ценятся! (Очевидно, что я мало знаю MATLAB)

Кстати, это для алгоритма TILT для восстановления текстур низкого ранга из шумного искаженного изображения. Я очень взволнован этим, даже если математика вне меня!

Похоже функция поз определена в другом файле MATLAB:

function P = pos(A) 
P = A .* double(A > 0); 

Я не могу достаточно расшифровать, что это делает. Предполагая, что булевские значения приводят к удвоениям, где «True» == 1.0 и «False» == 0,0

В этом случае он превращает отрицательные значения в ноль и оставляет положительные числа неизменными?

+1

Возможно ли, что ' pos' определяется в другом месте в источнике Matlab? –

+0

Спасибо @ Даниэль Вагнер, это точно так. – nont

ответ

4

Похоже, что pos находит положительную часть матрицы. Вы могли бы реализовать это непосредственно mapMatrix

pos :: (Storable a, Num a) => Matrix a -> Matrix a 
pos = mapMatrix go where 
    go x | x > 0  = x 
     | otherwise = 0 

Хотя Matlab не делает различий между Matrix и Vector в отличие от Haskell.

Но стоит еще раз проанализировать этот фрагмент Matlab. Per http://www.mathworks.com/help/matlab/ref/svd.html первая строка вычисляет «эконом размера» сингулярное разложение Y, то есть три матрицы, что

U * S * V = Y 

где, предполагая Y является m x n то U является m x n, S является n x n и диагонали, и V является n x n. Далее, как U, так и V должны быть ортонормированными. В линейных алгебраических терминах это разделяет линейное преобразование Y на два компонента «вращения» и центральный компонент масштабирования собственных значений.

Так как S диагоналей, выделим, что по диагонали в качестве вектора с помощью diag(S), а затем вычесть термин tau, который также должен быть вектором. Это может создать диагональ, содержащую отрицательные значения, которые не могут быть правильно интерпретированы как собственные значения, поэтому pos можно обрезать отрицательные собственные значения, установив их на 0.Затем мы используем diag, чтобы преобразовать полученный вектор обратно в диагональную матрицу и умножить фрагменты назад, чтобы получить A, модифицированную форму Y.

Обратите внимание, что мы можем пропустить некоторые шаги в Haskell, так как svd (и его «экономичный» партнер thinSVD) возвращают векторы собственных значений вместо преимущественно 0'-диагональных матриц.

(u, s, v) = thinSVD y 

-- note the trans here, that was the ' in Matlab 
a = u `multiply` diag (fmap (max 0) s) `multiply` trans v 

Над fmap карты max 0 над Vector собственных s и затем diag (от Numeric.Container) reinflates в Vector в Matrix до начала multiply с. С небольшой мыслью легко заметить, что max 0 всего лишь pos применяется к одному элементу.

+0

Спасибо! Я смог использовать второе определение с помощью fmap 'из этого вопроса: http://stackoverflow.com/questions/15278221/how-do-you-make-a-functor-instance-of-matrix-and-vector- from-hmatrix-library Также спасибо за указание транспонирования, который я пропустил. – nont

1

(A> 0) возвращает позиции элементов множества А, которые больше нуля, так Forexample, если у вас есть

A = [ -1 2 -3 4 
     5 6 -7 -8 ] 

затем B = (A > 0) возвращается

B = [ 0 1 0 1 
     1 1 0 0] 

Обратите внимание, что мы имеем которые соответствуют элементу A, который больше нуля, и 0 в противном случае.

Теперь, если вы умножаете этот элемент на A с использованием нотации .*, вы умножаете каждый элемент A, который больше нуля с 1, и с нулем в противном случае. То есть, A .* B означает

[ -1*0 2*1 -3*0 4*1 
    5*1 6*1 -7*0 -8*0 ] 

даяние наконец,

[ 0 2 0 4 
    5 6 0 0 ] 

Таким образом, вы должны написать свою собственную функцию, которая будет возвращать положительные значения нетронутыми, и отрицательные значения, установленные в ноль.

А также, u и v не соответствует в размерности, для Generall разложения SVD, так что вы на самом деле должны были бы REDIAGONALIZE POS (DIAGS - Tau), так что u* diagnonalized_(diagS -tau) agrres к v

+0

Я нашел введение в hmatrix Альберто Руисом очень полезным (у него есть список командных переводов между haskell и matlab) – stian