def construct_junction_tree(cliques): "Construct a junction tree from a sequence of cliques." # construct a complete graph which has the clique intersections as edge weights g = bgl.Graph() clusters = g.add_vertex_property(type='object') for clique in cliques: clusters[g.add_vertex()] = set(clique) weights = g.add_edge_property(type='float') separators = g.add_edge_property(type='object') for v1 in g.vertices: for v2 in g.vertices: if v1 != v2 and None == g.edge(v1, v2): intersection = clusters[v1].intersection(clusters[v2]) if intersection: e = g.add_edge(v1, v2) separators[e] = intersection weights[e] = 1.0 / len(intersection) maximal_tree_edges = bgl.kruskal_minimum_spanning_tree(g, weights) # remove edges not in maximal tree for e in g.edges: if e not in maximal_tree_edges: g.remove_edge(e) return g, clusters, separators
# Copyright 2005 The Trustees of Indiana University. # Use, modification and distribution is subject to the Boost Software # License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http:#www.boost.org/LICENSE_1_0.txt) # Authors: Douglas Gregor # Andrew Lumsdaine import boost.graph as bgl # Load a graph from the GraphViz file 'mst.dot' graph = bgl.read_graphviz('mst.dot') # Compute the minimum spanning tree of the graph mst_edges = bgl.kruskal_minimum_spanning_tree(graph, graph.edge_properties['weight']) # Compute the weight of the minimum spanning tree print 'MST weight =',sum([e.weight for e in mst_edges]) # Put the weights into the label. Make MST edges solid while all other # edges remain dashed. for e in graph.edges: e.label = e.weight if e in mst_edges: e.style = 'solid' else: e.style = 'dashed' # Write out the graph in GraphViz DOT format graph.write_graphviz('mst-out.dot')
def build_tree(self, mi_threshold = 0.0): """ Builds a tree from the mutual information between the base distributions """ import boost.graph as bgl # first build an (undirected) graph of the (negative) mutual informations g = bgl.Graph() vertices = [ g.add_vertex() for i in xrange(self.K) ] weight_map = g.add_edge_property('weight', 'float') joint_probabilities = g.add_edge_property('joints') marginal_probabilities = g.add_vertex_property('marginals') # add the edges and marginal probs for i in xrange(self.K): marginal_probabilities[vertices[i]] = self.marginal[i] # add the edges and conditional probs for i in xrange(self.K): for j in xrange(i+1,self.K): if self.mutual_information[i,j] > mi_threshold: e = g.add_edge(vertices[i],vertices[j]) weight_map[e] = -self.mutual_information[i,j] joint_probabilities[e] = self.joint[i,j] # find the minimum spanning tree and remove those edges not in it spanning_tree = bgl.kruskal_minimum_spanning_tree(g,weight_map) for e in g.edges: if e not in spanning_tree: g.remove_edge(e) def index_of(v): for i in xrange(self.K): if vertices[i] == v: return i raise RuntimeError( 'Could not find vertex: ' + v ) # build a directed forest from the (undirected) graph def build_forest(g, root_idx = None): "Take a forest and build an isomorphic Digraph" import boost.graph as bgl vertices_visited = set() diforest = bgl.Digraph() edge_label = diforest.add_edge_property( 'label', 'string' ) di_conditionals = diforest.add_edge_property( 'conditionals' ) di_marginals = diforest.add_vertex_property( 'marginals' ) di_vertices = [ diforest.add_vertex() for i in xrange(self.K) ] def visit(i): if i in vertices_visited: return vertices_visited.add(i) v = vertices[i] di_v = di_vertices[i] di_marginals[di_v] = marginal_probabilities[v] for neighbour in g.adjacent_vertices(v): j = index_of(neighbour) if j not in vertices_visited: e = diforest.add_edge(di_v, di_vertices[j]) edge_label[e] = '%.3f' % (-weight_map[g.edge(v,vertices[j])]) joint = joint_probabilities[g.edge(v,neighbour)] if index_of(neighbour) < index_of(v): joint = joint.T # make sure we have correct orientation of joint di_conditionals[e] = joint_to_conditional(joint) visit(j) # recurse # visit all the vertices - starting with root if given if None != root_idx: visit(root_idx) for i in xrange(self.K): visit(i) # check each node has max one parent for v in diforest.vertices: assert diforest.in_degree(v) < 2 return diforest # set the root to have the highest MI root_idx = self.mutual_information.argmax() % self.mutual_information.shape[0] self.d = build_forest(g, root_idx = root_idx)
def build_tree(self, mi_threshold=0.0): """ Builds a tree from the mutual information between the base distributions """ import boost.graph as bgl # first build an (undirected) graph of the (negative) mutual informations g = bgl.Graph() vertices = [g.add_vertex() for i in xrange(self.K)] weight_map = g.add_edge_property('weight', 'float') joint_probabilities = g.add_edge_property('joints') marginal_probabilities = g.add_vertex_property('marginals') # add the edges and marginal probs for i in xrange(self.K): marginal_probabilities[vertices[i]] = self.marginal[i] # add the edges and conditional probs for i in xrange(self.K): for j in xrange(i + 1, self.K): if self.mutual_information[i, j] > mi_threshold: e = g.add_edge(vertices[i], vertices[j]) weight_map[e] = -self.mutual_information[i, j] joint_probabilities[e] = self.joint[i, j] # find the minimum spanning tree and remove those edges not in it spanning_tree = bgl.kruskal_minimum_spanning_tree(g, weight_map) for e in g.edges: if e not in spanning_tree: g.remove_edge(e) def index_of(v): for i in xrange(self.K): if vertices[i] == v: return i raise RuntimeError('Could not find vertex: ' + v) # build a directed forest from the (undirected) graph def build_forest(g, root_idx=None): "Take a forest and build an isomorphic Digraph" import boost.graph as bgl vertices_visited = set() diforest = bgl.Digraph() edge_label = diforest.add_edge_property('label', 'string') di_conditionals = diforest.add_edge_property('conditionals') di_marginals = diforest.add_vertex_property('marginals') di_vertices = [diforest.add_vertex() for i in xrange(self.K)] def visit(i): if i in vertices_visited: return vertices_visited.add(i) v = vertices[i] di_v = di_vertices[i] di_marginals[di_v] = marginal_probabilities[v] for neighbour in g.adjacent_vertices(v): j = index_of(neighbour) if j not in vertices_visited: e = diforest.add_edge(di_v, di_vertices[j]) edge_label[e] = '%.3f' % ( -weight_map[g.edge(v, vertices[j])]) joint = joint_probabilities[g.edge(v, neighbour)] if index_of(neighbour) < index_of(v): joint = joint.T # make sure we have correct orientation of joint di_conditionals[e] = joint_to_conditional(joint) visit(j) # recurse # visit all the vertices - starting with root if given if None != root_idx: visit(root_idx) for i in xrange(self.K): visit(i) # check each node has max one parent for v in diforest.vertices: assert diforest.in_degree(v) < 2 return diforest # set the root to have the highest MI root_idx = self.mutual_information.argmax( ) % self.mutual_information.shape[0] self.d = build_forest(g, root_idx=root_idx)
# which will be converted into Boost.Graph property maps. # In this case, we're only interested in the edge weights. bgl_graph, translation_map = graphviz_graph.to_bgl(edge_properties = ['weight']) # the returned translation_map is used to translate between the two # graph formats: # translation_map[boost_vertex] => corresponding yapgvb node # translation_map[boost_edge] => corresponding yapgvb edge # translation_map[yapgvb_node] => corresponding boost vertex # translation_map[yapgvb_edge] => corresponding boost edge weight_map = bgl_graph.edge_properties['weight'] # Compute the minimum spanning tree of the graph # Returns a list of boost edges mst_edges = bgl.kruskal_minimum_spanning_tree(bgl_graph, weight_map) # Color the minimum spanning tree edges red in the graphviz representation for bgl_edge in mst_edges: # Get the yapgvb edge corresponding to the boost edge graphviz_edge = translation_map[bgl_edge] graphviz_edge.color = yapgvb.colors.red print "Using dot for layout..." graphviz_graph.layout(yapgvb.engines.dot) print "Rendering mst.png..." graphviz_graph.render('mst.png')