如何在Haskell中扩展矩阵
我一直在尝试创建一个函数,该函数返回给定的矩阵,并添加一行和一列,其数字是旁边行/列中数字的总和 数字是列中数字的总和 例如 到 我的第一个想法是如何在Haskell中扩展矩阵,haskell,matrix,Haskell,Matrix,我一直在尝试创建一个函数,该函数返回给定的矩阵,并添加一行和一列,其数字是旁边行/列中数字的总和 数字是列中数字的总和 例如 到 我的第一个想法是 > extend1 :: Int -> Array (Int,Int) Int > extend1 ((a,b),(c,d)) = n where > n = array ((a,b),(c,d),(n,n)) 因为我必须使用“数组”。现在我不知道如何继续下去。这是正确的还是完全错误的?使用
> extend1 :: Int -> Array (Int,Int) Int
> extend1 ((a,b),(c,d)) = n where
> n = array ((a,b),(c,d),(n,n))
因为我必须使用“数组”。现在我不知道如何继续下去。这是正确的还是完全错误的?使用元组表示法,而不太注意一般性,这里有一个解决问题的方法
type Square2 a = ((a,a), (a,a))
type Square3 a = ((a,a,a), (a,a,a), (a,a,a))
extend1 :: Num a => Square2 a -> Square3 a
extend1 ((a,b), (c,d)) =
( (a, b, ab )
, (c, d, cd )
, (ac, bd, abcd) )
where
ab = a + b
cd = c + d
ac = a + c
bd = b + d
abcd = ab + cd
请注意,我如何使用从输入模式和where
子句中的定义中挑选的变量定义。还要注意我是如何在构建一个全新的输出时销毁和使用输入的——一些元素被重用,但结构本身被销毁了。最后请注意,我如何选择元组内部的类型为常量,并受Num
typeclass的约束,该类允许我使用(+)
进行添加
一个类似的函数,一般化并使用Array
s,其类型如下
extend1A :: Num a => Array (Int,Int) a -> Array (Int, Int) a
我们无法知道数组
的确切大小,但这表明我们的函数获取一个大小不同的数组
,并返回另一个索引相同且包含相同Num
约束类型的数组
array
函数的第一个参数是一组边界。我们需要根据输入数组的边界
更新这些值
extend1A ary0 = array bounds1 ... where
((minX, minY), (maxX, maxY)) = bounds ary0
(maxX1, maxY1) = (succ maxX, succ maxY)
bounds1 = ((minX, minY, (maxX1, maxY1))
然后,array
将“assocs”列表作为其第二个参数。我们可以将任何数组ix a
视为(大致)等同于一个assocs列表[(ix,a)]
,其中列出的值表示“在索引ix
处,值为a
”。要做到这一点,我们必须知道我们刚才管理的ix
类型的界限
要使用旧数组中的信息更新数组,我们可以修改旧数组的assocs
,以包含新信息。具体地说,这意味着extend1A
看起来有点像
extend1A ary0 = array bounds1 (priorInformation ++ extraInformation) where
priorInformation = assocs ary0
extraInformation = ...
((minX, minY), (maxX, maxY)) = bounds ary0
(maxX1, maxY1) = (succ maxX, succ maxY)
bounds1 = ((minX, minY, (maxX1, maxY1))
如果额外信息
为空([]
),则扩展的1a位
在输入的位
范围内的所有标记上等于位
,在其范围外的所有标记上等于未定义的
。我们需要用求和信息填写额外信息
extend1A ary0 = array bounds1 (priorInformation ++ extraInformation) where
priorInformation = assocs ary0
extraInformation = xExtension ++ yExtension ++ totalExtension
xExtension = ...
yExtension = ...
totalExtension = ...
((minX, minY), (maxX, maxY)) = bounds ary0
(maxX1, maxY1) = (succ maxX, succ maxY)
bounds1 = ((minX, minY, (maxX1, maxY1))
如果我们考虑将数组扩展为三个部分,则extend1
中由ab
和cd
标记的xExtension
,然后,我们可以依次计算extend1
中由ac
和bd
标记的yExtension
和extend1
中由abcd
标记的totalExtension
totalExtension
最简单——它只是prioriformation
中每个(i,a)
对的“值分量”之和。它也可以是xExtension
或yExtension
的“值组件”之和,但为了尽可能明显地正确,我们将选择第一个选项并将其安装在右下角
extend1A ary0 = array bounds1 (priorInformation ++ extraInformation) where
priorInformation = assocs ary0
extraInformation = xExtension ++ yExtension ++ totalExtension
sumValues asscs = sum (map snd asscs)
xExtension = ...
yExtension = ...
totalExtension = [((maxX1, maxY1), sumValues priorInformation)]
((minX, minY), (maxX, maxY)) = bounds ary0
(maxX1, maxY1) = (succ maxX, succ maxY)
bounds1 = ((minX, minY), (maxX1, maxY1))
请注意,我们可以使用where
子句来定义新函数,如sumValues
,它将反复出现
然后,我们可以将扩展计算为优先信息
上的列表理解。我们需要在旧的ASSOC上收集一种特殊的求和——在一个索引固定的情况下,求所有值的和
xExtension = [( (maxX1, yix)
, sumValues (filter (\((_, j), _) -> j == yix) priorInformation)
)
| yix <- [minY .. maxY]
]
yExtension = [( (xix, maxY1)
, sumValues (filter (\((i, _), _) -> i == xix) priorInformation)
)
| xix <- [minX .. maxX]
]
xExtension=[((maxX1,yix)
,sumValues(过滤器(\((\uj),\ux)->j==yix)优先信息)
)
|yix i==xix)优先信息)
)
|xix j==yix)优先信息)
)
|yix i==xix)优先信息)
)
|xix首先,您应该了解如何与haskell数组进行接口。数组
数据类型可在数据.数组
中找到,因此有关完整的详细信息,请查看该模块的文档
请注意,我省略了对所有这些函数的ixi
约束,这对于这种情况并不重要
bounds::Array i e->(i,i)
:此函数返回数组的最小和最大索引。对于1D数组,这些只是数字。对于2D数组,它位于左上角和右下角(对于矩阵)
array::(i,i)->[(i,e)]->array i e
:此函数从最小/最大对为边界创建一个数组,以及一个关联列表;即从索引到值的映射。您的初始示例可以写成array((0,0),(1,1))[(0,0),1),(0,1),2),(1,0),3),(1,1),4)]
assocs::Array i e->[(i,e)]
:这是Array
的“反面”。因此,arr==Array(bounds arr)(assocs arr)
现在,函数:
extendArray :: Num e => Array (Int, Int) e -> Array (Int, Int) e
extendArray arr =
let
arr' = assocs arr
((xMin, yMin), (xMax, yMax)) = bounds arr
newCol = [ ((n, yMax + 1) , sum [ v | ((x,_),v) <- arr', x == n] ) | n <- [xMin .. xMax]]
newRow = [ ((xMax + 1, n) , sum [ v | ((_,y),v) <- arr', y == n] ) | n <- [yMin .. yMax]]
newCorner = [((xMax + 1, yMax + 1), sum $ map snd arr')]
newArr = array ((xMin, yMin), (xMax + 1, yMax + 1)) (arr' ++ newCol ++ newRow ++ newCorner)
in newArr
请注意,此实现效率不高(无论多么简单)。在newRow
中,我们遍历整个矩阵xMax-xMin
次(每个n
值一次)。因为assocs
总是以相同的顺序返回元素(行从左到右,列从上到下)最好将列表arr'
拆分为每个列表的长度yMax-yMin
;这样可以得到一个行列表。但我将把这个优化留给您。使用hmatrix:
import Numeric.LinearAlgebra
import Numeric.LinearAlgebra.Util(col,row)
m = (2><2) [1 , 2
,3 , 4] :: Matrix Double
extend m = fromBlocks [[m ,sr]
,[sc, s]]
where
sr = col $ map sumElements (toRows m)
sc = row $ map sumElements (toColumns m)
s = scalar (sumElements sr)
main = do
print m
print $ extend m
(2><2)
[ 1.0, 2.0
, 3.0, 4.0 ]
(3><3)
[ 1.0, 2.0, 3.0
, 3.0, 4.0, 7.0
, 4.0, 6.0, 10.0 ]
导入Numeric.linearlgebra
导入Numeric.LinearAlgebra.Util(列,行)
m=(2>大多数矩阵库(据我所知)使用固定大小的数组,因此为了扩展一个数组,您必须构造一个正确大小的数组,并将原始数组的内容复制到新数组中。这基本上就是您在这里要做的事情,尽管这不会编译,因为您将n
重新用作数组和el
extend1A ary0 = array bounds1 (priorInformation ++ extraInformation) where
priorInformation = assocs ary0
extraInformation = xExtension ++ yExtension ++ totalExtension
xExtension = [( (maxX1, yix)
, sumValues (filter (\((_, j), _) -> j == yix) priorInformation)
)
| yix <- [minY .. maxY]
]
yExtension = [( (xix, maxY1)
, sumValues (filter (\((i, _), _) -> i == xix) priorInformation)
)
| xix <- [minX .. maxX]
]
totalExtension = [((maxX1, maxY1), sum xExtension)]
((minX, minY), (maxX, maxY)) = bounds ary0
(maxX1, maxY1) = (succ maxX, succ maxY)
bounds1 = ((minX, minY), (maxX1, maxY1))
extendArray :: Num e => Array (Int, Int) e -> Array (Int, Int) e
extendArray arr =
let
arr' = assocs arr
((xMin, yMin), (xMax, yMax)) = bounds arr
newCol = [ ((n, yMax + 1) , sum [ v | ((x,_),v) <- arr', x == n] ) | n <- [xMin .. xMax]]
newRow = [ ((xMax + 1, n) , sum [ v | ((_,y),v) <- arr', y == n] ) | n <- [yMin .. yMax]]
newCorner = [((xMax + 1, yMax + 1), sum $ map snd arr')]
newArr = array ((xMin, yMin), (xMax + 1, yMax + 1)) (arr' ++ newCol ++ newRow ++ newCorner)
in newArr
>let x = array ((0,0),(1,1)) [((0,0),1),((0,1),2),((1,0),3),((1,1),4)]
>x
array ((0,0),(1,1)) [((0,0),1),((0,1),2),((1,0),3),((1,1),4)]
>extendArray x
array ((0,0),(2,2)) [((0,0),1),((0,1),2),((0,2),3),((1,0),3),((1,1),4),((1,2),7),((2,0),4),((2,1),6),((2,2),10)]
import Numeric.LinearAlgebra
import Numeric.LinearAlgebra.Util(col,row)
m = (2><2) [1 , 2
,3 , 4] :: Matrix Double
extend m = fromBlocks [[m ,sr]
,[sc, s]]
where
sr = col $ map sumElements (toRows m)
sc = row $ map sumElements (toColumns m)
s = scalar (sumElements sr)
main = do
print m
print $ extend m
(2><2)
[ 1.0, 2.0
, 3.0, 4.0 ]
(3><3)
[ 1.0, 2.0, 3.0
, 3.0, 4.0, 7.0
, 4.0, 6.0, 10.0 ]