// 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() }