blob: 36266ec905c6444d9cb179b95ad4ebc1da86b626 [file] [edit]
// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package graph
// A Subgraph is a Graph that consists of a subset of the nodes and
// vertices from another, underlying Graph.
type Subgraph interface {
Graph
// Underlying returns the underlying graph that this is a
// subgraph of.
Underlying() Graph
// NodeMap transduces a node property map on the underlying
// graph into a node property map on this graph.
NodeMap(underlyingMap func(node int) interface{}) func(node int) interface{}
// EdgeMap transduces an edge property map on the underlying
// graph into an edge property map on this graph.
EdgeMap(underlyingMap func(node, edge int) interface{}) func(node, edge int) interface{}
}
// SubgraphKeep returns a subgraph of g that keeps the given nodes and
// edges. Subgraph node i corresponds to nodes[i] in g.
func SubgraphKeep(g Graph, nodes []int, edges []Edge) Subgraph {
// Create old-to-new node mapping.
gNodes := g.NumNodes()
oldToNew := make(map[int]int, len(nodes))
for newNode, oldNode := range nodes {
if oldNode < 0 || oldNode >= gNodes {
panic("node not in underlying graph")
}
if _, ok := oldToNew[oldNode]; ok {
panic("duplicate node")
}
oldToNew[oldNode] = newNode
}
// Construct new nodes.
newNodes := make([]listSubgraphNode, len(nodes))
for i, oldNode := range nodes {
newNodes[i].oldNode = oldNode
}
// Map old edge indexes to new node IDs.
for _, oldEdge := range edges {
newNode := &newNodes[oldToNew[oldEdge.Node]]
oldTo := g.Out(oldEdge.Node)[oldEdge.Edge]
newTo := oldToNew[oldTo]
newNode.out = append(newNode.out, newTo)
newNode.oldEdges = append(newNode.oldEdges, oldEdge.Edge)
}
return &listSubgraph{g, newNodes}
}
// SubgraphRemove returns a subgraph of g that removes the given nodes
// and edges from g, as well as all edges incident to those nodes.
func SubgraphRemove(g Graph, nodes []int, edges []Edge) Subgraph {
// Collect the set of nodes and edges to remove.
rmNodes := make(map[int]struct{}, len(nodes))
for _, node := range nodes {
rmNodes[node] = struct{}{}
}
rmEdges := make(map[Edge]struct{}, len(edges))
for _, edge := range edges {
rmEdges[edge] = struct{}{}
}
// Create new-to-old and old-to-new node mappings.
newNodes := make([]listSubgraphNode, 0, g.NumNodes()-len(rmNodes))
oldToNew := make(map[int]int, cap(newNodes))
for oldNode := 0; oldNode < g.NumNodes(); oldNode++ {
if _, ok := rmNodes[oldNode]; ok {
continue
}
newNode := len(newNodes)
newNodes = append(newNodes, listSubgraphNode{oldNode: oldNode})
oldToNew[oldNode] = newNode
}
// Create edge mappings.
for i := range newNodes {
newNode := &newNodes[i]
oldNode := newNode.oldNode
oldOut := g.Out(oldNode)
for j, oldNode2 := range oldOut {
if _, ok := rmNodes[oldNode2]; ok {
// Target node removed.
continue
}
if _, ok := rmEdges[Edge{oldNode, j}]; ok {
// Edge removed.
continue
}
newNode.out = append(newNode.out, oldToNew[oldNode2])
newNode.oldEdges = append(newNode.oldEdges, j)
}
}
return &listSubgraph{g, newNodes}
}
type listSubgraph struct {
underlying Graph
nodes []listSubgraphNode
}
type listSubgraphNode struct {
out []int // Adjacency list
oldNode int // Node ID in underlying graph
oldEdges []int // New edge index -> old edge index
}
func (s *listSubgraph) NumNodes() int {
return len(s.nodes)
}
func (s *listSubgraph) Out(node int) []int {
return s.nodes[node].out
}
func (s *listSubgraph) Underlying() Graph {
return s.underlying
}
func (s *listSubgraph) NodeMap(underlyingMap func(node int) interface{}) func(node int) interface{} {
return func(node int) interface{} {
return underlyingMap(s.nodes[node].oldNode)
}
}
func (s *listSubgraph) EdgeMap(underlyingMap func(node, edge int) interface{}) func(node, edge int) interface{} {
return func(node, edge int) interface{} {
newNode := &s.nodes[node]
return underlyingMap(newNode.oldNode, newNode.oldEdges[edge])
}
}