对于这个模糊的问题感到抱歉,但我希望有经验的Haskeller这是一个明智的选择。
我必须表示和操纵对称矩阵,因此数据类型基本上有三种不同的选择:
完整矩阵存储(i,j)
和(j,i)
元素,但m(i,j) = m(j,i)
Data.Array(Int,Int)Int
地图,仅存储(i,j)
元素i <= j
(上三角矩阵)
Data.Map(Int,Int)Int
由k
索引的向量,存储上三角矩阵给定一些向量顺序f(i,j) = k
Data.Array Int Int
在矩阵上需要进行许多操作,更新单个元素,查询行和列等。但是,它们主要用作容器,不需要线性代数运算(反转,det等)。
如果矩阵的维数大约为20x20
,那么哪个选项通常是最快的?当我理解正确时,每次更新(在数组的情况下为(//)
)都需要完整副本,因此在案例2或3中从20x20=400
元素转到20*21/2 = 210
元素会使很有意义,但是案例2的访问速度较慢.3。在某些时候需要转换。
有没有指导方针?
顺便说一下:第三个选项不是很好,因为计算f^-1
需要平方根。
答案 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。快速浏览表明操纵矩阵的问题已经解决了好几次。