graph: move NewEdge method from encoding.Builder to graph.EdgeAdder

Also rename graph.EdgeSetter to graph.EdgeAdder.

Fixes #56.
This commit is contained in:
mewmew
2017-08-18 03:51:30 +02:00
parent a1f42c86ac
commit 0ebdd59ba5
8 changed files with 59 additions and 63 deletions

View File

@@ -167,21 +167,23 @@ func (gen *generator) addStmt(dst encoding.Builder, stmt ast.Stmt) {
} }
// addEdgeStmt adds the given edge statement to the graph. // addEdgeStmt adds the given edge statement to the graph.
func (gen *generator) addEdgeStmt(dst encoding.Builder, e *ast.EdgeStmt) { func (gen *generator) addEdgeStmt(dst encoding.Builder, stmt *ast.EdgeStmt) {
fs := gen.addVertex(dst, e.From) fs := gen.addVertex(dst, stmt.From)
ts := gen.addEdge(dst, e.To) ts := gen.addEdge(dst, stmt.To)
for _, f := range fs { for _, f := range fs {
for _, t := range ts { for _, t := range ts {
edge, ok := dst.NewEdge(f, t).(encoding.AttributeSetter) edge := dst.NewEdge(f, t)
dst.SetEdge(edge)
e, ok := edge.(encoding.AttributeSetter)
if !ok { if !ok {
continue continue
} }
for _, attr := range e.Attrs { for _, attr := range stmt.Attrs {
a := encoding.Attribute{ a := encoding.Attribute{
Key: attr.Key, Key: attr.Key,
Value: attr.Val, Value: attr.Val,
} }
if err := edge.SetAttribute(a); err != nil { if err := e.SetAttribute(a); err != nil {
panic(fmt.Errorf("unable to unmarshal edge DOT attribute (%s=%s)", a.Key, a.Value)) panic(fmt.Errorf("unable to unmarshal edge DOT attribute (%s=%s)", a.Key, a.Value))
} }
} }
@@ -216,7 +218,8 @@ func (gen *generator) addEdge(dst encoding.Builder, to *ast.Edge) []graph.Node {
ts := gen.addEdge(dst, to.To) ts := gen.addEdge(dst, to.To)
for _, f := range fs { for _, f := range fs {
for _, t := range ts { for _, t := range ts {
dst.NewEdge(f, t) edge := dst.NewEdge(f, t)
dst.SetEdge(edge)
} }
} }
} }

View File

@@ -118,15 +118,9 @@ func (g *dotDirectedGraph) NewNode() graph.Node {
return &dotNode{Node: g.DirectedGraph.NewNode()} return &dotNode{Node: g.DirectedGraph.NewNode()}
} }
// NewEdge adds a new edge from the source to the destination node to the graph, // NewEdge returns a new Edge from the source to the destination node.
// or returns the existing edge if already present.
func (g *dotDirectedGraph) NewEdge(from, to graph.Node) graph.Edge { func (g *dotDirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil { return &dotEdge{Edge: g.DirectedGraph.NewEdge(from, to)}
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
} }
// DOTAttributers implements the dot.Attributers interface. // DOTAttributers implements the dot.Attributers interface.
@@ -159,15 +153,9 @@ func (g *dotUndirectedGraph) NewNode() graph.Node {
return &dotNode{Node: g.UndirectedGraph.NewNode()} return &dotNode{Node: g.UndirectedGraph.NewNode()}
} }
// NewEdge adds a new edge from the source to the destination node to the graph, // NewEdge returns a new Edge from the source to the destination node.
// or returns the existing edge if already present.
func (g *dotUndirectedGraph) NewEdge(from, to graph.Node) graph.Edge { func (g *dotUndirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil { return &dotEdge{Edge: g.UndirectedGraph.NewEdge(from, to)}
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
} }
// DOTAttributers implements the dot.Attributers interface. // DOTAttributers implements the dot.Attributers interface.
@@ -222,7 +210,7 @@ func (n *dotNode) Attributes() []encoding.Attribute {
// dotEdge extends simple.Edge with a label field to test round-trip encoding and // dotEdge extends simple.Edge with a label field to test round-trip encoding and
// decoding of edge DOT label attributes. // decoding of edge DOT label attributes.
type dotEdge struct { type dotEdge struct {
simple.Edge graph.Edge
// Edge label. // Edge label.
Label string Label string
} }

View File

@@ -11,9 +11,6 @@ import "gonum.org/v1/gonum/graph"
type Builder interface { type Builder interface {
graph.Graph graph.Graph
graph.Builder graph.Builder
// NewEdge adds a new edge from the source to the destination node to the
// graph, or returns the existing edge if already present.
NewEdge(from, to graph.Node) graph.Edge
} }
// AttributeSetter is implemented by types that can set an encoded graph // AttributeSetter is implemented by types that can set an encoded graph

View File

@@ -163,12 +163,7 @@ func (g *directedGraph) NewNode() graph.Node {
} }
func (g *directedGraph) NewEdge(from, to graph.Node) graph.Edge { func (g *directedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil { return &edge{Edge: g.DirectedGraph.NewEdge(from, to)}
return e
}
e := &edge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
} }
type node struct { type node struct {
@@ -189,7 +184,7 @@ func (n *node) SetIDFromString(uid string) error {
} }
type edge struct { type edge struct {
simple.Edge graph.Edge
label string label string
} }

View File

@@ -93,13 +93,16 @@ type NodeRemover interface {
RemoveNode(Node) RemoveNode(Node)
} }
// EdgeSetter is an interface for adding edges to a graph. // EdgeAdder is an interface for adding edges to a graph.
type EdgeSetter interface { type EdgeAdder interface {
// NewEdge returns a new Edge from the source to the destination node.
NewEdge(from, to Node) Edge
// SetEdge adds an edge from one node to another. // SetEdge adds an edge from one node to another.
// If the graph supports node addition the nodes // If the graph supports node addition the nodes
// will be added if they do not exist, otherwise // will be added if they do not exist, otherwise
// SetEdge will panic. // SetEdge will panic.
// The behavior of an EdgeSetter when the IDs // The behavior of an EdgeAdder when the IDs
// returned by e.From and e.To are equal is // returned by e.From and e.To are equal is
// implementation-dependent. // implementation-dependent.
SetEdge(e Edge) SetEdge(e Edge)
@@ -116,7 +119,7 @@ type EdgeRemover interface {
// Builder is a graph that can have nodes and edges added. // Builder is a graph that can have nodes and edges added.
type Builder interface { type Builder interface {
NodeAdder NodeAdder
EdgeSetter EdgeAdder
} }
// UndirectedBuilder is an undirected graph builder. // UndirectedBuilder is an undirected graph builder.

View File

@@ -25,7 +25,7 @@ func init() {
// dynamic shortest path routine in path/dynamic: DStarLite. // dynamic shortest path routine in path/dynamic: DStarLite.
var ShortestPathTests = []struct { var ShortestPathTests = []struct {
Name string Name string
Graph func() graph.EdgeSetter Graph func() graph.EdgeAdder
Edges []simple.Edge Edges []simple.Edge
HasNegativeWeight bool HasNegativeWeight bool
HasNegativeCycle bool HasNegativeCycle bool
@@ -40,7 +40,7 @@ var ShortestPathTests = []struct {
// Positive weighted graphs. // Positive weighted graphs.
{ {
Name: "empty directed", Name: "empty directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)},
Weight: math.Inf(1), Weight: math.Inf(1),
@@ -49,7 +49,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "empty undirected", Name: "empty undirected",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)}, Query: simple.Edge{F: simple.Node(0), T: simple.Node(1)},
Weight: math.Inf(1), Weight: math.Inf(1),
@@ -58,7 +58,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "one edge directed", Name: "one edge directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
}, },
@@ -74,7 +74,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "one edge self directed", Name: "one edge self directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
}, },
@@ -90,7 +90,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "one edge undirected", Name: "one edge undirected",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
}, },
@@ -106,7 +106,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "two paths directed", Name: "two paths directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(2), W: 2}, {F: simple.Node(0), T: simple.Node(2), W: 2},
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -125,7 +125,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "two paths undirected", Name: "two paths undirected",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(2), W: 2}, {F: simple.Node(0), T: simple.Node(2), W: 2},
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -144,7 +144,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "confounding paths directed", Name: "confounding paths directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->5 of weight 4 // Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -178,7 +178,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "confounding paths undirected", Name: "confounding paths undirected",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->5 of weight 4 // Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -212,7 +212,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "confounding paths directed 2-step", Name: "confounding paths directed 2-step",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->5 of weight 4 // Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -247,7 +247,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "confounding paths undirected 2-step", Name: "confounding paths undirected 2-step",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->5 of weight 4 // Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -282,7 +282,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight cycle directed", Name: "zero-weight cycle directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -306,7 +306,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight cycle^2 directed", Name: "zero-weight cycle^2 directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -333,7 +333,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight cycle^2 confounding directed", Name: "zero-weight cycle^2 confounding directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -363,7 +363,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight cycle^3 directed", Name: "zero-weight cycle^3 directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -393,7 +393,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight 3·cycle^2 confounding directed", Name: "zero-weight 3·cycle^2 confounding directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -429,7 +429,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight reversed 3·cycle^2 confounding directed", Name: "zero-weight reversed 3·cycle^2 confounding directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1}, {F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -465,7 +465,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight |V|·cycle^(n/|V|) directed", Name: "zero-weight |V|·cycle^(n/|V|) directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: func() []simple.Edge { Edges: func() []simple.Edge {
e := []simple.Edge{ e := []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
@@ -498,7 +498,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight n·cycle directed", Name: "zero-weight n·cycle directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: func() []simple.Edge { Edges: func() []simple.Edge {
e := []simple.Edge{ e := []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
@@ -531,7 +531,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "zero-weight bi-directional tree with single exit directed", Name: "zero-weight bi-directional tree with single exit directed",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: func() []simple.Edge { Edges: func() []simple.Edge {
e := []simple.Edge{ e := []simple.Edge{
// Add a path from 0->4 of weight 4 // Add a path from 0->4 of weight 4
@@ -579,7 +579,7 @@ var ShortestPathTests = []struct {
// Negative weighted graphs. // Negative weighted graphs.
{ {
Name: "one edge directed negative", Name: "one edge directed negative",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(1), W: -1}, {F: simple.Node(0), T: simple.Node(1), W: -1},
}, },
@@ -596,7 +596,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "one edge undirected negative", Name: "one edge undirected negative",
Graph: func() graph.EdgeSetter { return simple.NewUndirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewUndirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node(0), T: simple.Node(1), W: -1}, {F: simple.Node(0), T: simple.Node(1), W: -1},
}, },
@@ -607,7 +607,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "wp graph negative", // http://en.wikipedia.org/w/index.php?title=Johnson%27s_algorithm&oldid=564595231 Name: "wp graph negative", // http://en.wikipedia.org/w/index.php?title=Johnson%27s_algorithm&oldid=564595231
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node('w'), T: simple.Node('z'), W: 2}, {F: simple.Node('w'), T: simple.Node('z'), W: 2},
{F: simple.Node('x'), T: simple.Node('w'), W: 6}, {F: simple.Node('x'), T: simple.Node('w'), W: 6},
@@ -630,7 +630,7 @@ var ShortestPathTests = []struct {
}, },
{ {
Name: "roughgarden negative", Name: "roughgarden negative",
Graph: func() graph.EdgeSetter { return simple.NewDirectedGraph(0, math.Inf(1)) }, Graph: func() graph.EdgeAdder { return simple.NewDirectedGraph(0, math.Inf(1)) },
Edges: []simple.Edge{ Edges: []simple.Edge{
{F: simple.Node('a'), T: simple.Node('b'), W: -2}, {F: simple.Node('a'), T: simple.Node('b'), W: -2},
{F: simple.Node('b'), T: simple.Node('c'), W: -1}, {F: simple.Node('b'), T: simple.Node('c'), W: -1},

View File

@@ -80,6 +80,11 @@ func (g *DirectedGraph) RemoveNode(n graph.Node) {
g.nodeIDs.release(n.ID()) g.nodeIDs.release(n.ID())
} }
// NewEdge returns a new Edge from the source to the destination node.
func (g *DirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
return &Edge{F: from, T: to}
}
// SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added. // SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added.
// It will panic if the IDs of the e.From and e.To are equal. // It will panic if the IDs of the e.From and e.To are equal.
func (g *DirectedGraph) SetEdge(e graph.Edge) { func (g *DirectedGraph) SetEdge(e graph.Edge) {

View File

@@ -72,6 +72,11 @@ func (g *UndirectedGraph) RemoveNode(n graph.Node) {
g.nodeIDs.release(n.ID()) g.nodeIDs.release(n.ID())
} }
// NewEdge returns a new Edge from the source to the destination node.
func (g *UndirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
return &Edge{F: from, T: to}
}
// SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added. // SetEdge adds e, an edge from one node to another. If the nodes do not exist, they are added.
// It will panic if the IDs of the e.From and e.To are equal. // It will panic if the IDs of the e.From and e.To are equal.
func (g *UndirectedGraph) SetEdge(e graph.Edge) { func (g *UndirectedGraph) SetEdge(e graph.Edge) {