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 }