【问题标题】:Haskell data type for hmatrix Vector and Matrix用于 hmatrix Vector 和 Matrix 的 Haskell 数据类型
【发布时间】:2017-03-25 22:37:18
【问题描述】:

我刚开始使用 Haskell,我已经阅读了 LYAH 的定义数据类型部分,并正在尝试为信念传播实现 Sum-Product 算法。基本任务之一是定义概率图形模型。

如下所示,我试图通过打结来创建一个图形,以表示每个节点代表一个高斯分布的图形,并且与它的邻居有恒定的权重链接(目前)。但是,在尝试定义 Mean 和 Covariance 类型时,我很难指定 Matrix 和 Vector 类型的类型,即 Float 或 Double。

module Graph(Graph) where

import Numeric.LinearAlgebra

data Mean = Mean Vector
data Covariance = Covariance Matrix
data Gaussian = Gaussian Mean Covariance

data Node = Node [Node] Gaussian
data Graph = Graph [Node]

在这个简单的示例中,将 Mean 定义为 Double 类型的 Vector 和 Covariance 定义为 Double 类型的 Matrix 的语法是什么。此外,如何进行概括以使 MeanCovariance 可以是 Float 或 Double 类型?

我目前从 GHCi 获得以下信息

Graph.hs:5:18: error:
    • Expecting one more argument to ‘Vector’
      Expected a type, but ‘Vector’ has kind ‘* -> *’
    • In the type ‘Vector’
      In the definition of data constructor ‘Mean’
      In the data declaration for ‘Mean’
Failed, modules loaded: none.

我正在使用 here 描述的 hmatrix 包

【问题讨论】:

    标签: haskell graph functional-programming ghci


    【解决方案1】:

    VectorMatrix 在标量类型上参数化(因此您不仅可以拥有浮点“实数”矩阵,还可以拥有整数矩阵、复数矩阵等)。这就是 GHC 通过 ‘Vector’ has kind ‘* -> *’ 告诉你的:就其本身而言,Vector 不是类型(类型有类型 *,又名 Type)。相反,它是将* 类型的类型映射到* 类型的类型的类型函数。像Double 这样的标量已经是普通类型,所以你可以将Vector 应用于它们。

    GHCi> :kind Vector
    Vector :: * -> *
    GHCi> :k Double
    Double :: *
    GHCi> :k Vector Double
    Vector Double :: *
    

    所以你需要

    newtype Mean = Mean (Vector Double)
    newtype Covariance = Covariance (Matrix Double)
    

    newtype 与此处的data 执行相同的操作,但效率更高,因为不需要额外的框/指针)。

    或者,您可以使用更有意义的类型向量空间,例如

    import Math.LinearMap.Category
    
    newtype Mean v = Mean v
    newtype Covariance v = Covariance (v +> DualVector v)
    

    这样做的好处是在编译时检查维度,这可以防止严重的运行时错误(原则上还可以提高性能,但坦率地说,linearmap-category 库还没有优化)。

    您还可以在向量空间上参数化其他类型:

    data Gaußian v = Gaußian (Mean v) (Covariance v)
    data Node v = Node [Node v] (Gaussian v)
    data Graph v = Graph [Node v]
    

    与您的问题有些无关:这种打结确实感觉很优雅,但它并不是真正适合表示图形的方式,因为无法对节点进行身份检查。对于所有可区分的手段,图中的任何循环都会导致无限结构。在实践中,你不会绕过给你的节点,例如Int 标签并为边缘保留单独的结构。

    【讨论】:

    • 多么棒的答案;谢谢你!这为我清除了一些事情。我确实对打结和无意中创造了一个无限的结构有些怀疑。另一种方式(保持邻接矩阵等)看起来很不优雅。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-29
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多