mirror of https://github.com/k3s-io/k3s
271 lines
7.7 KiB
Go
271 lines
7.7 KiB
Go
// Copyright ©2015 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
|
|
|
|
// Undirect converts a directed graph to an undirected graph.
|
|
type Undirect struct {
|
|
G Directed
|
|
}
|
|
|
|
var _ Undirected = Undirect{}
|
|
|
|
// Node returns the node with the given ID if it exists in the graph,
|
|
// and nil otherwise.
|
|
func (g Undirect) Node(id int64) Node { return g.G.Node(id) }
|
|
|
|
// Nodes returns all the nodes in the graph.
|
|
func (g Undirect) Nodes() Nodes { return g.G.Nodes() }
|
|
|
|
// From returns all nodes in g that can be reached directly from u.
|
|
func (g Undirect) From(uid int64) Nodes {
|
|
return newNodeFilterIterator(g.G.From(uid), g.G.To(uid))
|
|
}
|
|
|
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
|
func (g Undirect) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
|
|
|
// 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.
|
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
|
// the edge is determined by applying the Merge func to the weights of the
|
|
// edges between u and v.
|
|
func (g Undirect) Edge(uid, vid int64) Edge { return g.EdgeBetween(uid, vid) }
|
|
|
|
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
|
// applying the Merge func to the weights of edges between x and y.
|
|
func (g Undirect) EdgeBetween(xid, yid int64) Edge {
|
|
fe := g.G.Edge(xid, yid)
|
|
re := g.G.Edge(yid, xid)
|
|
if fe == nil && re == nil {
|
|
return nil
|
|
}
|
|
|
|
return EdgePair{fe, re}
|
|
}
|
|
|
|
// UndirectWeighted converts a directed weighted graph to an undirected weighted graph,
|
|
// resolving edge weight conflicts.
|
|
type UndirectWeighted struct {
|
|
G WeightedDirected
|
|
|
|
// Absent is the value used to
|
|
// represent absent edge weights
|
|
// passed to Merge if the reverse
|
|
// edge is present.
|
|
Absent float64
|
|
|
|
// Merge defines how discordant edge
|
|
// weights in G are resolved. A merge
|
|
// is performed if at least one edge
|
|
// exists between the nodes being
|
|
// considered. The edges corresponding
|
|
// to the two weights are also passed,
|
|
// in the same order.
|
|
// The order of weight parameters
|
|
// passed to Merge is not defined, so
|
|
// the function should be commutative.
|
|
// If Merge is nil, the arithmetic
|
|
// mean is used to merge weights.
|
|
Merge func(x, y float64, xe, ye Edge) float64
|
|
}
|
|
|
|
var (
|
|
_ Undirected = UndirectWeighted{}
|
|
_ WeightedUndirected = UndirectWeighted{}
|
|
)
|
|
|
|
// Node returns the node with the given ID if it exists in the graph,
|
|
// and nil otherwise.
|
|
func (g UndirectWeighted) Node(id int64) Node { return g.G.Node(id) }
|
|
|
|
// Nodes returns all the nodes in the graph.
|
|
func (g UndirectWeighted) Nodes() Nodes { return g.G.Nodes() }
|
|
|
|
// From returns all nodes in g that can be reached directly from u.
|
|
func (g UndirectWeighted) From(uid int64) Nodes {
|
|
return newNodeFilterIterator(g.G.From(uid), g.G.To(uid))
|
|
}
|
|
|
|
// HasEdgeBetween returns whether an edge exists between nodes x and y.
|
|
func (g UndirectWeighted) HasEdgeBetween(xid, yid int64) bool { return g.G.HasEdgeBetween(xid, yid) }
|
|
|
|
// 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.
|
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
|
// the edge is determined by applying the Merge func to the weights of the
|
|
// edges between u and v.
|
|
func (g UndirectWeighted) Edge(uid, vid int64) Edge { return g.WeightedEdgeBetween(uid, vid) }
|
|
|
|
// WeightedEdge returns the weighted 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.
|
|
// If an edge exists, the Edge returned is an EdgePair. The weight of
|
|
// the edge is determined by applying the Merge func to the weights of the
|
|
// edges between u and v.
|
|
func (g UndirectWeighted) WeightedEdge(uid, vid int64) WeightedEdge {
|
|
return g.WeightedEdgeBetween(uid, vid)
|
|
}
|
|
|
|
// EdgeBetween returns the edge between nodes x and y. If an edge exists, the
|
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
|
// applying the Merge func to the weights of edges between x and y.
|
|
func (g UndirectWeighted) EdgeBetween(xid, yid int64) Edge {
|
|
return g.WeightedEdgeBetween(xid, yid)
|
|
}
|
|
|
|
// WeightedEdgeBetween returns the weighted edge between nodes x and y. If an edge exists, the
|
|
// Edge returned is an EdgePair. The weight of the edge is determined by
|
|
// applying the Merge func to the weights of edges between x and y.
|
|
func (g UndirectWeighted) WeightedEdgeBetween(xid, yid int64) WeightedEdge {
|
|
fe := g.G.Edge(xid, yid)
|
|
re := g.G.Edge(yid, xid)
|
|
if fe == nil && re == nil {
|
|
return nil
|
|
}
|
|
|
|
f, ok := g.G.Weight(xid, yid)
|
|
if !ok {
|
|
f = g.Absent
|
|
}
|
|
r, ok := g.G.Weight(yid, xid)
|
|
if !ok {
|
|
r = g.Absent
|
|
}
|
|
|
|
var w float64
|
|
if g.Merge == nil {
|
|
w = (f + r) / 2
|
|
} else {
|
|
w = g.Merge(f, r, fe, re)
|
|
}
|
|
return WeightedEdgePair{EdgePair: [2]Edge{fe, re}, W: w}
|
|
}
|
|
|
|
// Weight returns the weight for the edge between x and y if Edge(x, y) returns a non-nil Edge.
|
|
// If x and y are the same node the internal node weight is returned. If there is no joining
|
|
// edge between the two nodes the weight value returned is zero. Weight returns true if an edge
|
|
// exists between x and y or if x and y have the same ID, false otherwise.
|
|
func (g UndirectWeighted) Weight(xid, yid int64) (w float64, ok bool) {
|
|
fe := g.G.Edge(xid, yid)
|
|
re := g.G.Edge(yid, xid)
|
|
|
|
f, fOk := g.G.Weight(xid, yid)
|
|
if !fOk {
|
|
f = g.Absent
|
|
}
|
|
r, rOK := g.G.Weight(yid, xid)
|
|
if !rOK {
|
|
r = g.Absent
|
|
}
|
|
ok = fOk || rOK
|
|
|
|
if g.Merge == nil {
|
|
return (f + r) / 2, ok
|
|
}
|
|
return g.Merge(f, r, fe, re), ok
|
|
}
|
|
|
|
// EdgePair is an opposed pair of directed edges.
|
|
type EdgePair [2]Edge
|
|
|
|
// From returns the from node of the first non-nil edge, or nil.
|
|
func (e EdgePair) From() Node {
|
|
if e[0] != nil {
|
|
return e[0].From()
|
|
} else if e[1] != nil {
|
|
return e[1].From()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// To returns the to node of the first non-nil edge, or nil.
|
|
func (e EdgePair) To() Node {
|
|
if e[0] != nil {
|
|
return e[0].To()
|
|
} else if e[1] != nil {
|
|
return e[1].To()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ReversedEdge returns a new Edge with the end point of the
|
|
// edges in the pair swapped.
|
|
func (e EdgePair) ReversedEdge() Edge {
|
|
if e[0] != nil {
|
|
e[0] = e[0].ReversedEdge()
|
|
}
|
|
if e[1] != nil {
|
|
e[1] = e[1].ReversedEdge()
|
|
}
|
|
return e
|
|
}
|
|
|
|
// WeightedEdgePair is an opposed pair of directed edges.
|
|
type WeightedEdgePair struct {
|
|
EdgePair
|
|
W float64
|
|
}
|
|
|
|
// ReversedEdge returns a new Edge with the end point of the
|
|
// edges in the pair swapped.
|
|
func (e WeightedEdgePair) ReversedEdge() Edge {
|
|
e.EdgePair = e.EdgePair.ReversedEdge().(EdgePair)
|
|
return e
|
|
}
|
|
|
|
// Weight returns the merged edge weights of the two edges.
|
|
func (e WeightedEdgePair) Weight() float64 { return e.W }
|
|
|
|
// nodeFilterIterator combines two Nodes to produce a single stream of
|
|
// unique nodes.
|
|
type nodeFilterIterator struct {
|
|
a, b Nodes
|
|
|
|
// unique indicates the node in b with the key ID is unique.
|
|
unique map[int64]bool
|
|
}
|
|
|
|
func newNodeFilterIterator(a, b Nodes) *nodeFilterIterator {
|
|
n := nodeFilterIterator{a: a, b: b, unique: make(map[int64]bool)}
|
|
for n.b.Next() {
|
|
n.unique[n.b.Node().ID()] = true
|
|
}
|
|
n.b.Reset()
|
|
for n.a.Next() {
|
|
n.unique[n.a.Node().ID()] = false
|
|
}
|
|
n.a.Reset()
|
|
return &n
|
|
}
|
|
|
|
func (n *nodeFilterIterator) Len() int {
|
|
return len(n.unique)
|
|
}
|
|
|
|
func (n *nodeFilterIterator) Next() bool {
|
|
n.Len()
|
|
if n.a.Next() {
|
|
return true
|
|
}
|
|
for n.b.Next() {
|
|
if n.unique[n.b.Node().ID()] {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (n *nodeFilterIterator) Node() Node {
|
|
if n.a.Len() != 0 {
|
|
return n.a.Node()
|
|
}
|
|
return n.b.Node()
|
|
}
|
|
|
|
func (n *nodeFilterIterator) Reset() {
|
|
n.a.Reset()
|
|
n.b.Reset()
|
|
}
|