mirror of
				https://github.com/gonum/gonum.git
				synced 2025-10-31 18:42:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			225 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			225 lines
		
	
	
		
			6.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{}
 | |
| 
 | |
| // Has returns whether the node exists within the graph.
 | |
| func (g Undirect) Has(n Node) bool { return g.G.Has(n) }
 | |
| 
 | |
| // Nodes returns all the nodes in the graph.
 | |
| func (g Undirect) Nodes() []Node { return g.G.Nodes() }
 | |
| 
 | |
| // From returns all nodes in g that can be reached directly from u.
 | |
| func (g Undirect) From(u Node) []Node {
 | |
| 	var nodes []Node
 | |
| 	seen := make(map[int64]struct{})
 | |
| 	for _, n := range g.G.From(u) {
 | |
| 		seen[n.ID()] = struct{}{}
 | |
| 		nodes = append(nodes, n)
 | |
| 	}
 | |
| 	for _, n := range g.G.To(u) {
 | |
| 		id := n.ID()
 | |
| 		if _, ok := seen[id]; ok {
 | |
| 			continue
 | |
| 		}
 | |
| 		seen[n.ID()] = struct{}{}
 | |
| 		nodes = append(nodes, n)
 | |
| 	}
 | |
| 	return nodes
 | |
| }
 | |
| 
 | |
| // HasEdgeBetween returns whether an edge exists between nodes x and y.
 | |
| func (g Undirect) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
 | |
| 
 | |
| // 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(u, v Node) Edge { return g.EdgeBetween(u, v) }
 | |
| 
 | |
| // 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(x, y Node) Edge {
 | |
| 	fe := g.G.Edge(x, y)
 | |
| 	re := g.G.Edge(y, x)
 | |
| 	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{}
 | |
| )
 | |
| 
 | |
| // Has returns whether the node exists within the graph.
 | |
| func (g UndirectWeighted) Has(n Node) bool { return g.G.Has(n) }
 | |
| 
 | |
| // Nodes returns all the nodes in the graph.
 | |
| func (g UndirectWeighted) Nodes() []Node { return g.G.Nodes() }
 | |
| 
 | |
| // From returns all nodes in g that can be reached directly from u.
 | |
| func (g UndirectWeighted) From(u Node) []Node {
 | |
| 	var nodes []Node
 | |
| 	seen := make(map[int64]struct{})
 | |
| 	for _, n := range g.G.From(u) {
 | |
| 		seen[n.ID()] = struct{}{}
 | |
| 		nodes = append(nodes, n)
 | |
| 	}
 | |
| 	for _, n := range g.G.To(u) {
 | |
| 		id := n.ID()
 | |
| 		if _, ok := seen[id]; ok {
 | |
| 			continue
 | |
| 		}
 | |
| 		seen[n.ID()] = struct{}{}
 | |
| 		nodes = append(nodes, n)
 | |
| 	}
 | |
| 	return nodes
 | |
| }
 | |
| 
 | |
| // HasEdgeBetween returns whether an edge exists between nodes x and y.
 | |
| func (g UndirectWeighted) HasEdgeBetween(x, y Node) bool { return g.G.HasEdgeBetween(x, y) }
 | |
| 
 | |
| // 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(u, v Node) Edge { return g.WeightedEdgeBetween(u, v) }
 | |
| 
 | |
| // 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(u, v Node) WeightedEdge { return g.WeightedEdgeBetween(u, v) }
 | |
| 
 | |
| // 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(x, y Node) Edge {
 | |
| 	return g.WeightedEdgeBetween(x, y)
 | |
| }
 | |
| 
 | |
| // 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(x, y Node) WeightedEdge {
 | |
| 	fe := g.G.Edge(x, y)
 | |
| 	re := g.G.Edge(y, x)
 | |
| 	if fe == nil && re == nil {
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	f, ok := g.G.Weight(x, y)
 | |
| 	if !ok {
 | |
| 		f = g.Absent
 | |
| 	}
 | |
| 	r, ok := g.G.Weight(y, x)
 | |
| 	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(x, y Node) (w float64, ok bool) {
 | |
| 	fe := g.G.Edge(x, y)
 | |
| 	re := g.G.Edge(y, x)
 | |
| 
 | |
| 	f, fOk := g.G.Weight(x, y)
 | |
| 	if !fOk {
 | |
| 		f = g.Absent
 | |
| 	}
 | |
| 	r, rOK := g.G.Weight(y, x)
 | |
| 	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
 | |
| }
 | |
| 
 | |
| // WeightedEdgePair is an opposed pair of directed edges.
 | |
| type WeightedEdgePair struct {
 | |
| 	EdgePair
 | |
| 	W float64
 | |
| }
 | |
| 
 | |
| // Weight returns the merged edge weights of the two edges.
 | |
| func (e WeightedEdgePair) Weight() float64 { return e.W }
 | 
