haskell - 如何在 Haskell 中扩展矩阵

标签 haskell matrix

我一直在尝试创建一个函数,该函数返回给定矩阵并添加一行和一列,其数字是旁边行/列中数字的总和 数字列中数字的总和...

例如

(1 2
 3 4)

(1 2 3
 3 4 7
4 6 10)

我的第一个想法是这样的

> 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 类型类约束,这允许我使用 (+) 进行加法。

一个类似的函数,泛化并使用 Arrays 有一个类似的类型

extend1A :: Num a => Array (Int,Int) a -> Array (Int, Int) a

我们失去了知道 Array 的确切大小的能力,但它表明我们的函数采用某个大小的 Array 并返回另一个 具有相同索引且包含相同 Num 约束类型的数组

array 函数将一组边界作为其第一个参数。我们需要根据输入数组的 bounds 更新那些

extend1A ary0 = array bounds1 ... where
  ((minX, minY), (maxX, maxY)) = bounds ary0
  (maxX1, maxY1) = (succ maxX, succ maxY)
  bounds1 = ((minX, minY, (maxX1, maxY1))

然后 array 将“assocs”列表作为其第二个参数。我们可以将任何 Array ix a 视为(大致)等价于 assocs [(ix, a)] 的列表,其中列出的值表示“在索引处 ix 值为 a”。为此,我们必须知道我们之前管理的 ix 类型的 bounds

要使用旧数组的信息更新数组,我们可以修改旧数组的 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))

如果 extraInformation 为空 ([]),则 extend1A ary 在所有索引上都等于 ary在输入范围内 aryundefined 在其范围之外。我们需要在extraInformation中填写求和信息。

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))

如果我们想分三 block 扩展数组,extend1abcd标记的xExtension >,extend1acbd标记的yExtensiontotalExtension标记通过 abcdextend1 中,我们可以依次计算每个部分。

totalExtension 是最简单的——它只是 priorInformation 中每个 (i,a) 对的“值分量”的总和。它也可以是 xExtensionyExtension 的“值组件”之和,但为了尽可能明显正确,我们将选择第一个选项并将其安装在右下角。

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,它会反复出现。

然后我们可以将扩展计算为对 priorInformation 的列表理解。我们需要对旧关联收集一种特殊的总和——对一个索引固定的所有值求和。

xExtension = [( (maxX1, yix)
              , sumValues (filter (\((_, j), _) -> j == yix) priorInformation)
              )
             | yix <- [minY .. maxY]
             ]

yExtension = [( (xix, maxY1)
              , sumValues (filter (\((i, _), _) -> i == xix) priorInformation)
              )
             | xix <- [minX .. maxX]
             ]

然后我们就完成了。它效率不高,但所有部分协同工作。

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))

关于haskell - 如何在 Haskell 中扩展矩阵,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20218576/

相关文章:

haskell - 为什么 foldr 使用辅助函数?

java - 查找相同值的4个连续数字-垂直和对角线

haskell - 尝试简单的单例示例时出现模板 Haskell 错误

haskell - 如何在状态 monad 中使用 Debug.Trace.trace?

python - sympy: 'Transpose' 对象没有属性 tolist

java - 矩阵行中较大的值

matlab - 如何找到多个矩阵中对应元素的最大值?

python - 具有单位矩阵和正则矩阵的高效 Kronecker 积 - NumPy/Python

haskell - 如何在 Haskell 中使用 GNU 黄金链接器而不是 ld 链接

haskell - 为什么 (.) map 有这种类型?