什么是MATLAB pos函数的Haskell / hmatrix等价物?

时间:2014-01-02 01:40:58

标签: matlab haskell hmatrix

我正在使用hmatrix库将一些MATLAB代码翻译成Haskell。它进展顺利,但是 我对pos函数感到磕磕绊绊,因为我不知道它的作用或Haskell等价物是什么。

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会对矩阵大小做些什么吗?谷歌搜索“matlab pos功能”没有任何有用的东西,所以任何指针都非常感谢! (显然我不太了解MATLAB)

顺便提一下,这是TILT算法从嘈杂的扭曲图像中恢复低等级纹理。我对此感到非常兴奋,即使数学已超出我的范围!

看起来pos函数是在不同的MATLAB文件中定义的:

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

我无法破译这是做什么的。假设布尔值转为双精度,其中“True”== 1.0且“False”== 0.0

在这种情况下,它将负值变为零并保持正数不变?

2 个答案:

答案 0 :(得分:4)

看起来pos找到了矩阵的正面部分。您可以使用mapMatrix

直接实现此功能
pos :: (Storable a, Num a) => Matrix a -> Matrix a
pos = mapMatrix go where
  go x | x > 0     = x
       | otherwise = 0

虽然与Haskell不同,Matlab在MatrixVector之间没有区别。

但值得分析的是Matlab片段更多。每http://www.mathworks.com/help/matlab/ref/svd.html,第一行计算Y的“经济大小”奇异值分解,即三个矩阵

U * S * V = Y

其中,假设Ym x n,则Um x nSn x n和对角线,Vn x n。此外,UV都应该是正交的。在线性代数术语中,这将线性变换Y分成两个“旋转”分量和中心特征值缩放分量。

由于S是对角线,我们使用diag(S)将对角线提取为矢量,然后减去一个也必须是矢量的项tau。这个可能生成一个包含负值的对角线,这些值不能正确解释为特征值,因此pos可以修剪负特征值,将它们设置为0.然后我们使用{{1}将结果向量转换回对角矩阵并将这些片段重新组合在一起得到diagA的修改形式。

请注意,我们可以跳过Haskell中的一些步骤Y(及其“经济大小的”伙伴svd)返回特征值的向量,而不是大多数0'd对角矩阵。

thinSVD

高于(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 } Vector之前的Matrix。稍微考虑一下,很容易看出multiply只是max 0应用于单个元素。

答案 1 :(得分:1)

(A> 0)返回A的元素大于零的位置, 例如,如果你有

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 ]

因此,您需要编写自己的函数,该函数将返回正值,并将负值设置为零。

而且,uv的维度不匹配,对于一般的SVD分解,所以你实际上需要REDIAGONALIZE pos(diagS - Tau),以便u* diagnonalized_(diagS -tau) agrres到v