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.
func (gen *generator) addEdgeStmt(dst encoding.Builder, e *ast.EdgeStmt) {
fs := gen.addVertex(dst, e.From)
ts := gen.addEdge(dst, e.To)
func (gen *generator) addEdgeStmt(dst encoding.Builder, stmt *ast.EdgeStmt) {
fs := gen.addVertex(dst, stmt.From)
ts := gen.addEdge(dst, stmt.To)
for _, f := range fs {
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 {
continue
}
for _, attr := range e.Attrs {
for _, attr := range stmt.Attrs {
a := encoding.Attribute{
Key: attr.Key,
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))
}
}
@@ -216,7 +218,8 @@ func (gen *generator) addEdge(dst encoding.Builder, to *ast.Edge) []graph.Node {
ts := gen.addEdge(dst, to.To)
for _, f := range fs {
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()}
}
// NewEdge adds a new edge from the source to the destination node to the graph,
// or returns the existing edge if already present.
// NewEdge returns a new Edge from the source to the destination node.
func (g *dotDirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil {
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
return &dotEdge{Edge: g.DirectedGraph.NewEdge(from, to)}
}
// DOTAttributers implements the dot.Attributers interface.
@@ -159,15 +153,9 @@ func (g *dotUndirectedGraph) NewNode() graph.Node {
return &dotNode{Node: g.UndirectedGraph.NewNode()}
}
// NewEdge adds a new edge from the source to the destination node to the graph,
// or returns the existing edge if already present.
// NewEdge returns a new Edge from the source to the destination node.
func (g *dotUndirectedGraph) NewEdge(from, to graph.Node) graph.Edge {
if e := g.Edge(from, to); e != nil {
return e
}
e := &dotEdge{Edge: simple.Edge{F: from, T: to}}
g.SetEdge(e)
return e
return &dotEdge{Edge: g.UndirectedGraph.NewEdge(from, to)}
}
// 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
// decoding of edge DOT label attributes.
type dotEdge struct {
simple.Edge
graph.Edge
// Edge label.
Label string
}

View File

@@ -11,9 +11,6 @@ import "gonum.org/v1/gonum/graph"
type Builder interface {
graph.Graph
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

View File

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

View File

@@ -93,13 +93,16 @@ type NodeRemover interface {
RemoveNode(Node)
}
// EdgeSetter is an interface for adding edges to a graph.
type EdgeSetter interface {
// EdgeAdder is an interface for adding edges to a graph.
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.
// If the graph supports node addition the nodes
// will be added if they do not exist, otherwise
// 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
// implementation-dependent.
SetEdge(e Edge)
@@ -116,7 +119,7 @@ type EdgeRemover interface {
// Builder is a graph that can have nodes and edges added.
type Builder interface {
NodeAdder
EdgeSetter
EdgeAdder
}
// UndirectedBuilder is an undirected graph builder.

View File

@@ -25,7 +25,7 @@ func init() {
// dynamic shortest path routine in path/dynamic: DStarLite.
var ShortestPathTests = []struct {
Name string
Graph func() graph.EdgeSetter
Graph func() graph.EdgeAdder
Edges []simple.Edge
HasNegativeWeight bool
HasNegativeCycle bool
@@ -40,7 +40,7 @@ var ShortestPathTests = []struct {
// Positive weighted graphs.
{
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)},
Weight: math.Inf(1),
@@ -49,7 +49,7 @@ var ShortestPathTests = []struct {
},
{
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)},
Weight: math.Inf(1),
@@ -58,7 +58,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node(0), T: simple.Node(1), W: 1},
},
@@ -74,7 +74,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node(0), T: simple.Node(1), W: 1},
},
@@ -90,7 +90,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node(0), T: simple.Node(1), W: 1},
},
@@ -106,7 +106,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node(0), T: simple.Node(2), W: 2},
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -125,7 +125,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node(0), T: simple.Node(2), W: 2},
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -144,7 +144,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -178,7 +178,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -212,7 +212,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -247,7 +247,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->5 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -282,7 +282,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -306,7 +306,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -333,7 +333,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->4 of weight 4
{F: simple.Node(0), T: simple.Node(1), W: 1},
@@ -363,7 +363,7 @@ var ShortestPathTests = []struct {
},
{
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{
// Add a path from 0->4 of weight 4
{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",
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{
// Add a path from 0->4 of weight 4
{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",
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{
// Add a path from 0->4 of weight 4
{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",
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 {
e := []simple.Edge{
// Add a path from 0->4 of weight 4
@@ -498,7 +498,7 @@ var ShortestPathTests = []struct {
},
{
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 {
e := []simple.Edge{
// 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",
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 {
e := []simple.Edge{
// Add a path from 0->4 of weight 4
@@ -579,7 +579,7 @@ var ShortestPathTests = []struct {
// Negative weighted graphs.
{
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{
{F: simple.Node(0), T: simple.Node(1), W: -1},
},
@@ -596,7 +596,7 @@ var ShortestPathTests = []struct {
},
{
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{
{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
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{
{F: simple.Node('w'), T: simple.Node('z'), W: 2},
{F: simple.Node('x'), T: simple.Node('w'), W: 6},
@@ -630,7 +630,7 @@ var ShortestPathTests = []struct {
},
{
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{
{F: simple.Node('a'), T: simple.Node('b'), W: -2},
{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())
}
// 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.
// It will panic if the IDs of the e.From and e.To are equal.
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())
}
// 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.
// It will panic if the IDs of the e.From and e.To are equal.
func (g *UndirectedGraph) SetEdge(e graph.Edge) {