github.com/gopherd/gonum@v0.0.4/graph/topo/clique_graph.go (about) 1 // Copyright ©2017 The Gonum Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package topo 6 7 import ( 8 "github.com/gopherd/gonum/graph" 9 "github.com/gopherd/gonum/graph/internal/ordered" 10 "github.com/gopherd/gonum/graph/internal/set" 11 ) 12 13 // Builder is a pure topological graph construction type. 14 type Builder interface { 15 AddNode(graph.Node) 16 SetEdge(graph.Edge) 17 } 18 19 // CliqueGraph builds the clique graph of g in dst using Clique and CliqueGraphEdge 20 // nodes and edges. The nodes returned by calls to Nodes on the nodes and edges of 21 // the constructed graph are the cliques and the common nodes between cliques 22 // respectively. The dst graph is not cleared. 23 func CliqueGraph(dst Builder, g graph.Undirected) { 24 cliques := BronKerbosch(g) 25 26 // Construct a consistent view of cliques in g. Sorting costs 27 // us a little, but not as much as the cliques themselves. 28 for _, c := range cliques { 29 ordered.ByID(c) 30 } 31 ordered.BySliceIDs(cliques) 32 33 cliqueNodes := make(cliqueNodeSets, len(cliques)) 34 for id, c := range cliques { 35 s := set.NewNodesSize(len(c)) 36 for _, n := range c { 37 s.Add(n) 38 } 39 ns := &nodeSet{Clique: Clique{id: int64(id), nodes: c}, nodes: s} 40 dst.AddNode(ns.Clique) 41 for _, n := range c { 42 nid := n.ID() 43 cliqueNodes[nid] = append(cliqueNodes[nid], ns) 44 } 45 } 46 47 for _, cliques := range cliqueNodes { 48 for i, uc := range cliques { 49 for _, vc := range cliques[i+1:] { 50 // Retain the nodes that contribute to the 51 // edge between the cliques. 52 var edgeNodes []graph.Node 53 switch 1 { 54 case len(uc.Clique.nodes): 55 edgeNodes = []graph.Node{uc.Clique.nodes[0]} 56 case len(vc.Clique.nodes): 57 edgeNodes = []graph.Node{vc.Clique.nodes[0]} 58 default: 59 for _, n := range set.IntersectionOfNodes(uc.nodes, vc.nodes) { 60 edgeNodes = append(edgeNodes, n) 61 } 62 ordered.ByID(edgeNodes) 63 } 64 65 dst.SetEdge(CliqueGraphEdge{from: uc.Clique, to: vc.Clique, nodes: edgeNodes}) 66 } 67 } 68 } 69 } 70 71 type cliqueNodeSets map[int64][]*nodeSet 72 73 type nodeSet struct { 74 Clique 75 nodes set.Nodes 76 } 77 78 // Clique is a node in a clique graph. 79 type Clique struct { 80 id int64 81 nodes []graph.Node 82 } 83 84 // ID returns the node ID. 85 func (n Clique) ID() int64 { return n.id } 86 87 // Nodes returns the nodes in the clique. 88 func (n Clique) Nodes() []graph.Node { return n.nodes } 89 90 // CliqueGraphEdge is an edge in a clique graph. 91 type CliqueGraphEdge struct { 92 from, to Clique 93 nodes []graph.Node 94 } 95 96 // From returns the from node of the edge. 97 func (e CliqueGraphEdge) From() graph.Node { return e.from } 98 99 // To returns the to node of the edge. 100 func (e CliqueGraphEdge) To() graph.Node { return e.to } 101 102 // ReversedEdge returns a new CliqueGraphEdge with 103 // the edge end points swapped. The nodes of the 104 // new edge are shared with the receiver. 105 func (e CliqueGraphEdge) ReversedEdge() graph.Edge { e.from, e.to = e.to, e.from; return e } 106 107 // Nodes returns the common nodes in the cliques of the underlying graph 108 // corresponding to the from and to nodes in the clique graph. 109 func (e CliqueGraphEdge) Nodes() []graph.Node { return e.nodes }