forked from LaconicNetwork/kompose
174 lines
4.6 KiB
Go
174 lines
4.6 KiB
Go
// Copyright ©2014 The gonum 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
|
|
|
|
import "math"
|
|
|
|
// Node is a graph node. It returns a graph-unique integer ID.
|
|
type Node interface {
|
|
ID() int
|
|
}
|
|
|
|
// Edge is a graph edge. In directed graphs, the direction of the
|
|
// edge is given from -> to, otherwise the edge is semantically
|
|
// unordered.
|
|
type Edge interface {
|
|
From() Node
|
|
To() Node
|
|
}
|
|
|
|
// Graph is a generalized graph.
|
|
type Graph interface {
|
|
// Has returns whether the node exists within the graph.
|
|
Has(Node) bool
|
|
|
|
// Nodes returns all the nodes in the graph.
|
|
Nodes() []Node
|
|
|
|
// From returns all nodes that can be reached directly
|
|
// from the given node.
|
|
From(Node) []Node
|
|
|
|
// HasEdge returns whether an edge exists between
|
|
// nodes x and y without considering direction.
|
|
HasEdge(x, y Node) bool
|
|
|
|
// Edge returns the edge from u to v if such an edge
|
|
// exists and nil otherwise. The node v must be directly
|
|
// reachable from u as defined by the From method.
|
|
Edge(u, v Node) Edge
|
|
}
|
|
|
|
// Undirected is an undirected graph.
|
|
type Undirected interface {
|
|
Graph
|
|
|
|
// EdgeBetween returns the edge between nodes x and y.
|
|
EdgeBetween(x, y Node) Edge
|
|
}
|
|
|
|
// Directed is a directed graph.
|
|
type Directed interface {
|
|
Graph
|
|
|
|
// HasEdgeFromTo returns whether an edge exists
|
|
// in the graph from u to v.
|
|
HasEdgeFromTo(u, v Node) bool
|
|
|
|
// To returns all nodes that can reach directly
|
|
// to the given node.
|
|
To(Node) []Node
|
|
}
|
|
|
|
// Weighter defines graphs that can report edge weights.
|
|
type Weighter interface {
|
|
// Weight returns the weight for the given edge.
|
|
Weight(Edge) float64
|
|
}
|
|
|
|
// Mutable is an interface for generalized graph mutation.
|
|
type Mutable interface {
|
|
// NewNodeID returns a new unique arbitrary ID.
|
|
NewNodeID() int
|
|
|
|
// Adds a node to the graph. AddNode panics if
|
|
// the added node ID matches an existing node ID.
|
|
AddNode(Node)
|
|
|
|
// RemoveNode removes a node from the graph, as
|
|
// well as any edges attached to it. If the node
|
|
// is not in the graph it is a no-op.
|
|
RemoveNode(Node)
|
|
|
|
// SetEdge adds an edge from one node to another.
|
|
// If the nodes do not exist, they are added.
|
|
// SetEdge will panic if the IDs of the e.From
|
|
// and e.To are equal.
|
|
SetEdge(e Edge, cost float64)
|
|
|
|
// RemoveEdge removes the given edge, leaving the
|
|
// terminal nodes. If the edge does not exist it
|
|
// is a no-op.
|
|
RemoveEdge(Edge)
|
|
}
|
|
|
|
// MutableUndirected is an undirected graph that can be arbitrarily altered.
|
|
type MutableUndirected interface {
|
|
Undirected
|
|
Mutable
|
|
}
|
|
|
|
// MutableDirected is a directed graph that can be arbitrarily altered.
|
|
type MutableDirected interface {
|
|
Directed
|
|
Mutable
|
|
}
|
|
|
|
// WeightFunc is a mapping between an edge and an edge weight.
|
|
type WeightFunc func(Edge) float64
|
|
|
|
// UniformCost is a WeightFunc that returns an edge cost of 1 for a non-nil Edge
|
|
// and Inf for a nil Edge.
|
|
func UniformCost(e Edge) float64 {
|
|
if e == nil {
|
|
return math.Inf(1)
|
|
}
|
|
return 1
|
|
}
|
|
|
|
// CopyUndirected copies nodes and edges as undirected edges from the source to the
|
|
// destination without first clearing the destination. CopyUndirected will panic if
|
|
// a node ID in the source graph matches a node ID in the destination. If the source
|
|
// does not implement Weighter, UniformCost is used to define edge weights.
|
|
//
|
|
// Note that if the source is a directed graph and a fundamental cycle exists with
|
|
// two nodes where the edge weights differ, the resulting destination graph's edge
|
|
// weight between those nodes is undefined.
|
|
func CopyUndirected(dst MutableUndirected, src Graph) {
|
|
var weight WeightFunc
|
|
if g, ok := src.(Weighter); ok {
|
|
weight = g.Weight
|
|
} else {
|
|
weight = UniformCost
|
|
}
|
|
|
|
nodes := src.Nodes()
|
|
for _, n := range nodes {
|
|
dst.AddNode(n)
|
|
}
|
|
for _, u := range nodes {
|
|
for _, v := range src.From(u) {
|
|
edge := src.Edge(u, v)
|
|
dst.SetEdge(edge, weight(edge))
|
|
}
|
|
}
|
|
}
|
|
|
|
// CopyDirected copies nodes and edges as directed edges from the source to the
|
|
// destination without first clearing the destination. CopyDirected will panic if
|
|
// a node ID in the source graph matches a node ID in the destination. If the
|
|
// source is undirected both directions will be present in the destination after
|
|
// the copy is complete. If the source does not implement Weighter, UniformCost
|
|
// is used to define edge weights.
|
|
func CopyDirected(dst MutableDirected, src Graph) {
|
|
var weight WeightFunc
|
|
if g, ok := src.(Weighter); ok {
|
|
weight = g.Weight
|
|
} else {
|
|
weight = UniformCost
|
|
}
|
|
|
|
nodes := src.Nodes()
|
|
for _, n := range nodes {
|
|
dst.AddNode(n)
|
|
}
|
|
for _, u := range nodes {
|
|
for _, v := range src.From(u) {
|
|
edge := src.Edge(u, v)
|
|
dst.SetEdge(edge, weight(edge))
|
|
}
|
|
}
|
|
}
|