对称矩阵的Data.Map与Data.Array?

时间:2011-11-15 03:30:05

标签: arrays haskell map

对于这个模糊的问题感到抱歉,但我希望有经验的Haskeller这是一个明智的选择。

我必须表示和操纵对称矩阵,因此数据类型基本上有三种不同的选择:

  1. 完整矩阵存储(i,j)(j,i)元素,但m(i,j) = m(j,i)

    Data.Array(Int,Int)Int

  2. 地图,仅存储(i,j)元素i <= j(上三角矩阵)

    Data.Map(Int,Int)Int

  3. k索引的向量,存储上三角矩阵给定一些向量顺序f(i,j) = k

    Data.Array Int Int

  4. 在矩阵上需要进行许多操作,更新单个元素,查询行和列等。但是,它们主要用作容器,不需要线性代数运算(反转,det等)。

    如果矩阵的维数大约为20x20,那么哪个选项通常是最快的?当我理解正确时,每次更新(在数组的情况下为(//))都需要完整副本,因此在案例2或3中从20x20=400元素转到20*21/2 = 210元素会使很有意义,但是案例2的访问速度较慢.3。在某些时候需要转换。

    有没有指导方针?

    顺便说一下:第三个选项不是很好,因为计算f^-1需要平方根。

2 个答案:

答案 0 :(得分:8)

您可以尝试使用仅生成矩阵上半部分的专用Ix类使用Data.Array:

newtype Symmetric = Symmetric { pair :: (Int, Int) } deriving (Ord, Eq)

instance Ix Symmetric where
    range ((Symmetric (x1,y1)), (Symmetric (x2,y2))) =
        map Symmetric [(x,y) | x <- range (x1,x2), y <- range (y1,y2), x >= y]
    inRange (lo,hi) i = x <= hix && x >= lox && y <= hiy && y >= loy && x >= y
        where
          (lox,loy) = pair lo
          (hix,hiy) = pair hi
          (x,y) = pair i
    index (lo,hi) i
        | inRange (lo,hi) i  = (x-loy)+(sum$take(y-loy)[hix-lox, hix-lox-1..])
        | otherwise = error "Error in array index"
        where
          (lox,loy) = pair lo
          (hix,hiy) = pair hi
          (x,y) = pair i

sym x y 
    | x < y = Symmetric (y,x)
    | otherwise = Symmetric (x,y)



*Main Data.Ix> let a = listArray (sym 0 0, sym 6 6) [0..]
*Main Data.Ix> a ! sym 3 2
14
*Main Data.Ix> a ! sym 2 3
14
*Main Data.Ix> a ! sym 2 2
13
*Main Data.Ix> length $ elems a
28
*Main Data.Ix> let b = listArray (sym 0 0, sym 19 19) [0..]
*Main Data.Ix> length $ elems b
210

答案 1 :(得分:4)

还有第四种选择:使用数量逐渐减小的数组。我会使用选项1(使用完整数组并只存储每个元素两次)或最后一个。如果您打算更新很多元素,我强烈建议使用一个可变数组; IOArray和STArray是受欢迎的选择。

除非这是家庭作业或其他什么,否则你也应该看看Hackage。快速浏览表明操纵矩阵的问题已经解决了好几次。