Reputation: 2527
I am just starting out with Haskell, I have read up to the defining data types section of LYAH and am attempting to implement the Sum-Product algorithm for Belief Propagation. One of the rudimentary tasks is to define the Probabilistic Graphical Model.
As shown below, I have attempted to create a graph by tying the knot to represent the graph where each node represents a Gaussian distribution and has constant weight links(for now) to it's neighbours. However, when trying to define the Mean and Covariance types I am having some difficulty in specifying the types of the Matrix and Vector types, i.e. Float or 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]
In this simple example, what is the syntax to define Mean as a Vector of type Double and Covariance as a Matrix of type Double. Additionally, how would one generalise so that Mean
and Covariance
can be of type Float or Double?
I currently get the following from 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.
I am using the hmatrix package as described here
Upvotes: 1
Views: 367
Reputation: 120711
Vector
and Matrix
are parameterised on the scalar type (so you can not only have matrices of floating-point “real numbers”, but also matrices of integers, complex numbers etc.). This is what GHC tells you by ‘Vector’ has kind ‘* -> *’
: by itself, Vector
is not a type (types have kind *
, aka Type
). Rather it is a type function mapping types of kind *
to types of kind *
. Scalars like Double
are already plain types, so you can just apply Vector
to them.
GHCi> :kind Vector
Vector :: * -> *
GHCi> :k Double
Double :: *
GHCi> :k Vector Double
Vector Double :: *
Thus you need
newtype Mean = Mean (Vector Double)
newtype Covariance = Covariance (Matrix Double)
(newtype
does the same thing as data
here, but it's a bit more efficient because no extra box/pointer is needed).
Alternatively, you may use more meaningfully-typed vector spaces, e.g.
import Math.LinearMap.Category
newtype Mean v = Mean v
newtype Covariance v = Covariance (v +> DualVector v)
The advantage of this is that dimensions are checked at compile time, which prevents nasty runtime errors (and can in principle also improve performance, though frankly the linearmap-category
library is not optimised at all yet).
You'd then also parameterise the other types over the vector space:
data Gaußian v = Gaußian (Mean v) (Covariance v)
data Node v = Node [Node v] (Gaussian v)
data Graph v = Graph [Node v]
Somewhat unrelated to your question: this knot-tying sure feels elegant, but it's not really a suitable way to represent a graph, because nodes can't be identity-checked. Any cycles in the graph lead to, for all distinguishable means, an infinite structure. In practice, you won't get around giving your nodes e.g. Int
labels and keeping a separate structure for the edges.
Upvotes: 2