在FSharp中实现贝叶斯网络图

时间:2015-11-10 00:15:39

标签: python f#

我正在尝试将图形公式从Python转换为F#

python“Node”类:

class Node:
    """ A Node is the basic element of a graph.  In its most basic form a graph is just a list of nodes.  A Node is a really just a list of neighbors.
    """
    def __init__(self, id, index=-1, name="anonymous"):
        # This defines a list of edges to other nodes in the graph.
        self.neighbors = set()
        self.visited = False
        self.id = id
        # The index of this node within the list of nodes in the overall graph.
        self.index = index
        # Optional name, most usefull for debugging purposes.
        self.name = name

    def __lt__(self, other):
        # Defines a < operator for this class, which allows for easily sorting a list of nodes.
        return self.index < other.index

    def __hash__(self):
        return hash(self.id)

    def __eq__(self, right):
        return self.id == right.id

    def add_neighbor(self, node):
        """ Make node a neighbor if it is not alreadly.  This is a hack, we should be allowing self to be a neighbor of self in some graphs.  This should be enforced at the level of a graph, because that is where the type of the graph would disallow it.
        """
        if (not node in self.neighbors) and (not self == node):
            self.neighbors.add(node)

    def remove_neighbor(self, node):
        # Remove the node from the list of neighbors, effectively deleting that edge from
        # the graph.
        self.neighbors.remove(node)

    def is_neighbor(self, node):
        # Check if node is a member of neighbors.
        return node in self.neighbors

到目前为止我的F#课程:

type Node<'T>= string*'T
type Edge<'T,'G> = Node<'T>*Node<'T>*'G
type Graph = 
    | Undirected of seq(Node*list Edge) 
    | Directed of seq(Node*list Edge *list Edge)

1 个答案:

答案 0 :(得分:1)

是的,这与不变性有关。 F#的Set是一个不可变集合,它基于二进制树,支持在O(log n)时间内添加,删除和查找。

但是,因为集合是不可变的,所以add操作返回一个新的Set。

let originalSet = set [1; 2; 7]
let newSet = originalSet.Add(5)

最纯粹的功能解决方案可能是重建您的问题以完全消除可变性。这种方法可能会让您将节点类重构为不可变数据容器(没有方法),并在单独的模块中定义作用于该数据容器的函数。

module Nodes =
    /// creates a new node from an old node with a supplied neighbour node added.
    let addNeighbour neighbourNode node  =
        Node <| Set.add neighbourNode (node.Neighbours) 
        //Note: you'll need to replace the backwards pipe with brackets for pre-F# 4.0

有关更多示例,请参阅FSharp核心库中的不可变集合,例如List,Map等。

如果您更喜欢可变方法,则可以将neighbours变为可变,以便在地图更改时更新或仅使用可变集合(例如System.Collections.Generic.HashSet<'T>)。

当涉及到哈希码时,Set<'T>实际上并没有使用它。它要求可以包含在其中的对象实现IComparable接口。这用于生成二叉树所需的排序。看起来您的对象已经具有内置排序的概念,这种概念适合于提供此行为。