act/vendor/github.com/soniakeys/graph/graph.go
2019-02-06 22:36:13 -08:00

767 lines
23 KiB
Go

// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT
package graph
import (
"bytes"
"errors"
"fmt"
"math"
"reflect"
"text/template"
"github.com/soniakeys/bits"
)
// graph.go contains type definitions for all graph types and components.
// Also, go generate directives for source transformations.
//
// For readability, the types are defined in a dependency order:
//
// NI
// AdjacencyList
// Directed
// Undirected
// Bipartite
// Subgraph
// DirectedSubgraph
// UndirectedSubgraph
// LI
// Half
// fromHalf
// LabeledAdjacencyList
// LabeledDirected
// LabeledUndirected
// LabeledBipartite
// LabeledSubgraph
// LabeledDirectedSubgraph
// LabeledUndirectedSubgraph
// Edge
// LabeledEdge
// LabeledPath
// WeightFunc
// WeightedEdgeList
// TraverseOption
//go:generate cp adj_cg.go adj_RO.go
//go:generate gofmt -r "LabeledAdjacencyList -> AdjacencyList" -w adj_RO.go
//go:generate gofmt -r "n.To -> n" -w adj_RO.go
//go:generate gofmt -r "Half -> NI" -w adj_RO.go
//go:generate gofmt -r "LabeledSubgraph -> Subgraph" -w adj_RO.go
//go:generate cp dir_cg.go dir_RO.go
//go:generate gofmt -r "LabeledDirected -> Directed" -w dir_RO.go
//go:generate gofmt -r "LabeledDirectedSubgraph -> DirectedSubgraph" -w dir_RO.go
//go:generate gofmt -r "LabeledAdjacencyList -> AdjacencyList" -w dir_RO.go
//go:generate gofmt -r "labEulerian -> eulerian" -w dir_RO.go
//go:generate gofmt -r "newLabEulerian -> newEulerian" -w dir_RO.go
//go:generate gofmt -r "Half{n, -1} -> n" -w dir_RO.go
//go:generate gofmt -r "n.To -> n" -w dir_RO.go
//go:generate gofmt -r "Half -> NI" -w dir_RO.go
//go:generate cp undir_cg.go undir_RO.go
//go:generate gofmt -r "LabeledUndirected -> Undirected" -w undir_RO.go
//go:generate gofmt -r "LabeledBipartite -> Bipartite" -w undir_RO.go
//go:generate gofmt -r "LabeledUndirectedSubgraph -> UndirectedSubgraph" -w undir_RO.go
//go:generate gofmt -r "LabeledAdjacencyList -> AdjacencyList" -w undir_RO.go
//go:generate gofmt -r "newLabEulerian -> newEulerian" -w undir_RO.go
//go:generate gofmt -r "Half{n, -1} -> n" -w undir_RO.go
//go:generate gofmt -r "n.To -> n" -w undir_RO.go
//go:generate gofmt -r "Half -> NI" -w undir_RO.go
// An AdjacencyList represents a graph as a list of neighbors for each node.
// The "node ID" of a node is simply it's slice index in the AdjacencyList.
// For an AdjacencyList g, g[n] represents arcs going from node n to nodes
// g[n].
//
// Adjacency lists are inherently directed but can be used to represent
// directed or undirected graphs. See types Directed and Undirected.
type AdjacencyList [][]NI
// Directed represents a directed graph.
//
// Directed methods generally rely on the graph being directed, specifically
// that arcs do not have reciprocals.
type Directed struct {
AdjacencyList // embedded to include AdjacencyList methods
}
// Undirected represents an undirected graph.
//
// In an undirected graph, for each arc between distinct nodes there is also
// a reciprocal arc, an arc in the opposite direction. Loops do not have
// reciprocals.
//
// Undirected methods generally rely on the graph being undirected,
// specifically that every arc between distinct nodes has a reciprocal.
type Undirected struct {
AdjacencyList // embedded to include AdjacencyList methods
}
// Bipartite represents a bipartite graph.
//
// In a bipartite graph, nodes are partitioned into two sets, or
// "colors," such that every edge in the graph goes from one set to the
// other.
//
// Member Color represents the partition with a bitmap of length the same
// as the number of nodes in the graph. For convenience N0 stores the number
// of zero bits in Color.
//
// To construct a Bipartite object, if you can easily or efficiently use
// available information to construct the Color member, then you should do
// this and construct a Bipartite object with a Go struct literal.
//
// If partition information is not readily available, see the constructor
// Undirected.Bipartite.
//
// Alternatively, in some cases where the graph may have multiple connected
// components, the lower level Undirected.BipartiteComponent can be used to
// control color assignment by component.
type Bipartite struct {
Undirected
Color bits.Bits
N0 int
}
// Subgraph represents a subgraph mapped to a supergraph.
//
// The subgraph is the embedded AdjacencyList and so the Subgraph type inherits
// all methods of Adjacency list.
//
// The embedded subgraph mapped relative to a specific supergraph, member
// Super. A subgraph may have fewer nodes than its supergraph.
// Each node of the subgraph must map to a distinct node of the supergraph.
//
// The mapping giving the supergraph node for a given subgraph node is
// represented by member SuperNI, a slice parallel to the the subgraph.
//
// The mapping in the other direction, giving a subgraph NI for a given
// supergraph NI, is represented with map SubNI.
//
// Multiple Subgraphs can be created relative to a single supergraph.
// The Subgraph type represents a mapping to only a single supergraph however.
//
// See graph methods InduceList and InduceBits for construction of
// node-induced subgraphs.
//
// Alternatively an empty subgraph can be constructed with InduceList(nil).
// Arbitrary subgraphs can then be built up with methods AddNode and AddArc.
type Subgraph struct {
AdjacencyList // the subgraph
Super *AdjacencyList // the supergraph
SubNI map[NI]NI // subgraph NIs, indexed by supergraph NIs
SuperNI []NI // supergraph NIs indexed by subgraph NIs
}
// DirectedSubgraph represents a subgraph mapped to a supergraph.
//
// See additional doc at Subgraph type.
type DirectedSubgraph struct {
Directed
Super *Directed
SubNI map[NI]NI
SuperNI []NI
}
// UndirectedSubgraph represents a subgraph mapped to a supergraph.
//
// See additional doc at Subgraph type.
type UndirectedSubgraph struct {
Undirected
Super *Undirected
SubNI map[NI]NI
SuperNI []NI
}
// LI is a label integer, used for associating labels with arcs.
type LI int32
// Half is a half arc, representing a labeled arc and the "neighbor" node
// that the arc leads to.
//
// Halfs can be composed to form a labeled adjacency list.
type Half struct {
To NI // node ID, usable as a slice index
Label LI // half-arc ID for application data, often a weight
}
// fromHalf is a half arc, representing a labeled arc and the "neighbor" node
// that the arc originates from.
//
// This used internally in a couple of places. It used to be exported but is
// not currently needed anwhere in the API.
type fromHalf struct {
From NI
Label LI
}
// A LabeledAdjacencyList represents a graph as a list of neighbors for each
// node, connected by labeled arcs.
//
// Arc labels are not necessarily unique arc IDs. Different arcs can have
// the same label.
//
// Arc labels are commonly used to assocate a weight with an arc. Arc labels
// are general purpose however and can be used to associate arbitrary
// information with an arc.
//
// Methods implementing weighted graph algorithms will commonly take a
// weight function that turns a label int into a float64 weight.
//
// If only a small amount of information -- such as an integer weight or
// a single printable character -- needs to be associated, it can sometimes
// be possible to encode the information directly into the label int. For
// more generality, some lookup scheme will be needed.
//
// In an undirected labeled graph, reciprocal arcs must have identical labels.
// Note this does not preclude parallel arcs with different labels.
type LabeledAdjacencyList [][]Half
// LabeledDirected represents a directed labeled graph.
//
// This is the labeled version of Directed. See types LabeledAdjacencyList
// and Directed.
type LabeledDirected struct {
LabeledAdjacencyList // embedded to include LabeledAdjacencyList methods
}
// LabeledUndirected represents an undirected labeled graph.
//
// This is the labeled version of Undirected. See types LabeledAdjacencyList
// and Undirected.
type LabeledUndirected struct {
LabeledAdjacencyList // embedded to include LabeledAdjacencyList methods
}
// LabeledBipartite represents a bipartite graph.
//
// In a bipartite graph, nodes are partitioned into two sets, or
// "colors," such that every edge in the graph goes from one set to the
// other.
//
// Member Color represents the partition with a bitmap of length the same
// as the number of nodes in the graph. For convenience N0 stores the number
// of zero bits in Color.
//
// To construct a LabeledBipartite object, if you can easily or efficiently use
// available information to construct the Color member, then you should do
// this and construct a LabeledBipartite object with a Go struct literal.
//
// If partition information is not readily available, see the constructor
// Undirected.LabeledBipartite.
//
// Alternatively, in some cases where the graph may have multiple connected
// components, the lower level LabeledUndirected.BipartiteComponent can be used
// to control color assignment by component.
type LabeledBipartite struct {
LabeledUndirected
Color bits.Bits
N0 int
}
// LabeledSubgraph represents a subgraph mapped to a supergraph.
//
// See additional doc at Subgraph type.
type LabeledSubgraph struct {
LabeledAdjacencyList
Super *LabeledAdjacencyList
SubNI map[NI]NI
SuperNI []NI
}
// LabeledDirectedSubgraph represents a subgraph mapped to a supergraph.
//
// See additional doc at Subgraph type.
type LabeledDirectedSubgraph struct {
LabeledDirected
Super *LabeledDirected
SubNI map[NI]NI
SuperNI []NI
}
// LabeledUndirectedSubgraph represents a subgraph mapped to a supergraph.
//
// See additional doc at Subgraph type.
type LabeledUndirectedSubgraph struct {
LabeledUndirected
Super *LabeledUndirected
SubNI map[NI]NI
SuperNI []NI
}
// Edge is an undirected edge between nodes N1 and N2.
type Edge struct{ N1, N2 NI }
// LabeledEdge is an undirected edge with an associated label.
type LabeledEdge struct {
Edge
LI
}
// LabeledPath is a start node and a path of half arcs leading from start.
type LabeledPath struct {
Start NI
Path []Half
}
// Distance returns total path distance given WeightFunc w.
func (p LabeledPath) Distance(w WeightFunc) float64 {
d := 0.
for _, h := range p.Path {
d += w(h.Label)
}
return d
}
// WeightFunc returns a weight for a given label.
//
// WeightFunc is a parameter type for various search functions. The intent
// is to return a weight corresponding to an arc label. The name "weight"
// is an abstract term. An arc "weight" will typically have some application
// specific meaning other than physical weight.
type WeightFunc func(label LI) (weight float64)
// WeightedEdgeList is a graph representation.
//
// It is a labeled edge list, with an associated weight function to return
// a weight given an edge label.
//
// Also associated is the order, or number of nodes of the graph.
// All nodes occurring in the edge list must be strictly less than Order.
//
// WeigtedEdgeList sorts by weight, obtained by calling the weight function.
// If weight computation is expensive, consider supplying a cached or
// memoized version.
type WeightedEdgeList struct {
Order int
WeightFunc
Edges []LabeledEdge
}
// DistanceMatrix constructs a distance matrix corresponding to the weighted
// edges of l.
//
// An edge n1, n2 with WeightFunc return w is represented by both
// d[n1][n2] == w and d[n2][n1] = w. In case of parallel edges, the lowest
// weight is stored. The distance from any node to itself d[n][n] is 0, unless
// the node has a loop with a negative weight. If g has no edge between n1 and
// distinct n2, +Inf is stored for d[n1][n2] and d[n2][n1].
//
// The returned DistanceMatrix is suitable for DistanceMatrix.FloydWarshall.
func (l WeightedEdgeList) DistanceMatrix() (d DistanceMatrix) {
d = newDM(l.Order)
for _, e := range l.Edges {
n1 := e.Edge.N1
n2 := e.Edge.N2
wt := l.WeightFunc(e.LI)
// < to pick min of parallel arcs (also nicely ignores NaN)
if wt < d[n1][n2] {
d[n1][n2] = wt
d[n2][n1] = wt
}
}
return
}
// A DistanceMatrix is a square matrix representing some distance between
// nodes of a graph. If the graph is directected, d[from][to] represents
// some distance from node 'from' to node 'to'. Depending on context, the
// distance may be an arc weight or path distance. A value of +Inf typically
// means no arc or no path between the nodes.
type DistanceMatrix [][]float64
// little helper function, makes a blank distance matrix for FloydWarshall.
// could be exported?
func newDM(n int) DistanceMatrix {
inf := math.Inf(1)
d := make(DistanceMatrix, n)
for i := range d {
di := make([]float64, n)
for j := range di {
di[j] = inf
}
di[i] = 0
d[i] = di
}
return d
}
// FloydWarshall finds all pairs shortest distances for a weighted graph
// without negative cycles.
//
// It operates on a distance matrix representing arcs of a graph and
// destructively replaces arc weights with shortest path distances.
//
// In receiver d, d[fr][to] will be the shortest distance from node
// 'fr' to node 'to'. An element value of +Inf means no path exists.
// Any diagonal element < 0 indicates a negative cycle exists.
//
// See DistanceMatrix constructor methods of LabeledAdjacencyList and
// WeightedEdgeList for suitable inputs.
func (d DistanceMatrix) FloydWarshall() {
for k, dk := range d {
for _, di := range d {
dik := di[k]
for j := range d {
if d2 := dik + dk[j]; d2 < di[j] {
di[j] = d2
}
}
}
}
}
// PathMatrix is a return type for FloydWarshallPaths.
//
// It encodes all pairs shortest paths.
type PathMatrix [][]NI
// Path returns a shortest path from node start to end.
//
// Argument p is truncated, appended to, and returned as the result.
// Thus the underlying allocation is reused if possible.
// If there is no path from start to end, p is returned truncated to
// zero length.
//
// If receiver m is not a valid populated PathMatrix as returned by
// FloydWarshallPaths, behavior is undefined and a panic is likely.
func (m PathMatrix) Path(start, end NI, p []NI) []NI {
p = p[:0]
for {
p = append(p, start)
if start == end {
return p
}
start = m[start][end]
if start < 0 {
return p[:0]
}
}
}
// FloydWarshallPaths finds all pairs shortest paths for a weighted graph
// without negative cycles.
//
// It operates on a distance matrix representing arcs of a graph and
// destructively replaces arc weights with shortest path distances.
//
// In receiver d, d[fr][to] will be the shortest distance from node
// 'fr' to node 'to'. An element value of +Inf means no path exists.
// Any diagonal element < 0 indicates a negative cycle exists.
//
// The return value encodes the paths. See PathMatrix.Path.
//
// See DistanceMatrix constructor methods of LabeledAdjacencyList and
// WeightedEdgeList for suitable inputs.
//
// See also similar method FloydWarshallFromLists which has a richer
// return value.
func (d DistanceMatrix) FloydWarshallPaths() PathMatrix {
m := make(PathMatrix, len(d))
inf := math.Inf(1)
for i, di := range d {
mi := make([]NI, len(d))
for j, dij := range di {
if dij == inf {
mi[j] = -1
} else {
mi[j] = NI(j)
}
}
m[i] = mi
}
for k, dk := range d {
for i, di := range d {
mi := m[i]
dik := di[k]
for j := range d {
if d2 := dik + dk[j]; d2 < di[j] {
di[j] = d2
mi[j] = mi[k]
}
}
}
}
return m
}
// FloydWarshallFromLists finds all pairs shortest paths for a weighted
// graph without negative cycles.
//
// It operates on a distance matrix representing arcs of a graph and
// destructively replaces arc weights with shortest path distances.
//
// In receiver d, d[fr][to] will be the shortest distance from node
// 'fr' to node 'to'. An element value of +Inf means no path exists.
// Any diagonal element < 0 indicates a negative cycle exists.
//
// The return value encodes the paths. The FromLists are fully populated
// with Leaves and Len values. See for example FromList.PathTo for
// extracting paths. Note though that for i'th FromList of the return
// value, PathTo(j) will return the path from j's root, which will not
// be i in the case that there is no path from i to j. You must check
// the first node of the path to see if it is i. If not, there is no
// path from i to j. See example.
//
// See DistanceMatrix constructor methods of LabeledAdjacencyList and
// WeightedEdgeList for suitable inputs.
//
// See also similar method FloydWarshallPaths, which has a lighter
// weight return value.
func (d DistanceMatrix) FloydWarshallFromLists() []FromList {
l := make([]FromList, len(d))
inf := math.Inf(1)
for i, di := range d {
li := NewFromList(len(d))
p := li.Paths
for j, dij := range di {
if i == j || dij == inf {
p[j] = PathEnd{From: -1}
} else {
p[j] = PathEnd{From: NI(i)}
}
}
l[i] = li
}
for k, dk := range d {
pk := l[k].Paths
for i, di := range d {
dik := di[k]
pi := l[i].Paths
for j := range d {
if d2 := dik + dk[j]; d2 < di[j] {
di[j] = d2
pi[j] = pk[j]
}
}
}
}
for _, li := range l {
li.RecalcLeaves()
li.RecalcLen()
}
return l
}
// AddEdge adds an edge to a subgraph.
//
// For argument e, e.N1 and e.N2 must be NIs in supergraph s.Super. As with
// AddNode, AddEdge panics if e.N1 and e.N2 are not valid node indexes of
// s.Super.
//
// Edge e must exist in s.Super. Further, the number of
// parallel edges in the subgraph cannot exceed the number of corresponding
// parallel edges in the supergraph. That is, each edge already added to the
// subgraph counts against the edges available in the supergraph. If a matching
// edge is not available, AddEdge returns an error.
//
// If a matching edge is available, subgraph nodes are added as needed, the
// subgraph edge is added, and the method returns nil.
func (s *UndirectedSubgraph) AddEdge(n1, n2 NI) error {
// verify supergraph NIs first, but without adding subgraph nodes just yet.
if int(n1) < 0 || int(n1) >= s.Super.Order() {
panic(fmt.Sprint("AddEdge: NI ", n1, " not in supergraph"))
}
if int(n2) < 0 || int(n2) >= s.Super.Order() {
panic(fmt.Sprint("AddEdge: NI ", n2, " not in supergraph"))
}
// count existing matching edges in subgraph
n := 0
a := s.Undirected.AdjacencyList
if b1, ok := s.SubNI[n1]; ok {
if b2, ok := s.SubNI[n2]; ok {
// both NIs already exist in subgraph, need to count edges
for _, t := range a[b1] {
if t == b2 {
n++
}
}
if b1 != b2 {
// verify reciprocal arcs exist
r := 0
for _, t := range a[b2] {
if t == b1 {
r++
}
}
if r < n {
n = r
}
}
}
}
// verify matching edges are available in supergraph
m := 0
for _, t := range (*s.Super).AdjacencyList[n1] {
if t == n2 {
if m == n {
goto r // arc match after all existing arcs matched
}
m++
}
}
return errors.New("edge not available in supergraph")
r:
if n1 != n2 {
// verify reciprocal arcs
m = 0
for _, t := range (*s.Super).AdjacencyList[n2] {
if t == n1 {
if m == n {
goto good
}
m++
}
}
return errors.New("edge not available in supergraph")
}
good:
// matched enough edges. nodes can finally
// be added as needed and then the edge can be added.
b1 := s.AddNode(n1)
b2 := s.AddNode(n2)
s.Undirected.AddEdge(b1, b2)
return nil // success
}
// AddEdge adds an edge to a subgraph.
//
// For argument e, e.N1 and e.N2 must be NIs in supergraph s.Super. As with
// AddNode, AddEdge panics if e.N1 and e.N2 are not valid node indexes of
// s.Super.
//
// Edge e must exist in s.Super with label l. Further, the number of
// parallel edges in the subgraph cannot exceed the number of corresponding
// parallel edges in the supergraph. That is, each edge already added to the
// subgraph counts against the edges available in the supergraph. If a matching
// edge is not available, AddEdge returns an error.
//
// If a matching edge is available, subgraph nodes are added as needed, the
// subgraph edge is added, and the method returns nil.
func (s *LabeledUndirectedSubgraph) AddEdge(e Edge, l LI) error {
// verify supergraph NIs first, but without adding subgraph nodes just yet.
if int(e.N1) < 0 || int(e.N1) >= s.Super.Order() {
panic(fmt.Sprint("AddEdge: NI ", e.N1, " not in supergraph"))
}
if int(e.N2) < 0 || int(e.N2) >= s.Super.Order() {
panic(fmt.Sprint("AddEdge: NI ", e.N2, " not in supergraph"))
}
// count existing matching edges in subgraph
n := 0
a := s.LabeledUndirected.LabeledAdjacencyList
if b1, ok := s.SubNI[e.N1]; ok {
if b2, ok := s.SubNI[e.N2]; ok {
// both NIs already exist in subgraph, need to count edges
h := Half{b2, l}
for _, t := range a[b1] {
if t == h {
n++
}
}
if b1 != b2 {
// verify reciprocal arcs exist
r := 0
h.To = b1
for _, t := range a[b2] {
if t == h {
r++
}
}
if r < n {
n = r
}
}
}
}
// verify matching edges are available in supergraph
m := 0
h := Half{e.N2, l}
for _, t := range (*s.Super).LabeledAdjacencyList[e.N1] {
if t == h {
if m == n {
goto r // arc match after all existing arcs matched
}
m++
}
}
return errors.New("edge not available in supergraph")
r:
if e.N1 != e.N2 {
// verify reciprocal arcs
m = 0
h.To = e.N1
for _, t := range (*s.Super).LabeledAdjacencyList[e.N2] {
if t == h {
if m == n {
goto good
}
m++
}
}
return errors.New("edge not available in supergraph")
}
good:
// matched enough edges. nodes can finally
// be added as needed and then the edge can be added.
n1 := s.AddNode(e.N1)
n2 := s.AddNode(e.N2)
s.LabeledUndirected.AddEdge(Edge{n1, n2}, l)
return nil // success
}
// utility function called from all of the InduceList methods.
func mapList(l []NI) (sub map[NI]NI, sup []NI) {
sub = map[NI]NI{}
// one pass to collect unique NIs
for _, p := range l {
sub[NI(p)] = -1
}
if len(sub) == len(l) { // NIs in l are unique
sup = append([]NI{}, l...) // just copy them
for b, p := range l {
sub[p] = NI(b) // and fill in map
}
} else { // NIs in l not unique
sup = make([]NI, 0, len(sub))
for _, p := range l { // preserve ordering of first occurrences in l
if sub[p] < 0 {
sub[p] = NI(len(sup))
sup = append(sup, p)
}
}
}
return
}
// utility function called from all of the InduceBits methods.
func mapBits(t bits.Bits) (sub map[NI]NI, sup []NI) {
sup = make([]NI, 0, t.OnesCount())
sub = make(map[NI]NI, cap(sup))
t.IterateOnes(func(n int) bool {
sub[NI(n)] = NI(len(sup))
sup = append(sup, NI(n))
return true
})
return
}
// OrderMap formats maps for testable examples.
//
// OrderMap provides simple, no-frills formatting of maps in sorted order,
// convenient in some cases for output of testable examples.
func OrderMap(m interface{}) string {
// in particular exclude slices, which template would happily accept but
// which would probably represent a coding mistake
if reflect.TypeOf(m).Kind() != reflect.Map {
panic("not a map")
}
t := template.Must(template.New("").Parse(
`map[{{range $k, $v := .}}{{$k}}:{{$v}} {{end}}]`))
var b bytes.Buffer
if err := t.Execute(&b, m); err != nil {
panic(err)
}
return b.String()
}