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