Removed vertex set from GonumGraph, it was superfluous

This commit is contained in:
Jsor
2013-07-25 05:19:18 -07:00
parent 2c6094861d
commit bf998eb8e5
2 changed files with 29 additions and 27 deletions

View File

@@ -4,10 +4,15 @@ import (
"sort" "sort"
) )
// A GonumGraph is a very generalized graph that can handle an arbitrary number of vertices and edges -- as well as act as either directed or undirected.
//
// Internally, it uses a map of successors AND predecessors, to speed up some operations (such as getting all successors/predecessors). It also speeds up thing like adding edges (assuming both edges exist).
//
// However, its generality is also its weakness (and partially a flaw in needing to satisfy MutableGraph). For most purposes, creating your own graph is probably better. For instance, see discrete.TileGraph for an example
// of an immutable 2D grid of tiles that also implements the Graph interface, but would be more suitable if all you needed was a simple undirected 2D grid.
type GonumGraph struct { type GonumGraph struct {
successors map[int]map[int]float64 successors map[int]map[int]float64
predecessors map[int]map[int]float64 predecessors map[int]map[int]float64
vertices *Set
directed bool directed bool
} }
@@ -15,7 +20,6 @@ func NewGonumGraph(directed bool) *GonumGraph {
return &GonumGraph{ return &GonumGraph{
successors: make(map[int]map[int]float64), successors: make(map[int]map[int]float64),
predecessors: make(map[int]map[int]float64), predecessors: make(map[int]map[int]float64),
vertices: NewSet(),
directed: directed, directed: directed,
} }
} }
@@ -24,7 +28,6 @@ func NewPreAllocatedGonumGraph(directed bool, numVertices int) *GonumGraph {
return &GonumGraph{ return &GonumGraph{
successors: make(map[int]map[int]float64, numVertices), successors: make(map[int]map[int]float64, numVertices),
predecessors: make(map[int]map[int]float64, numVertices), predecessors: make(map[int]map[int]float64, numVertices),
vertices: NewSet(),
directed: directed, directed: directed,
} }
} }
@@ -47,7 +50,7 @@ func (graph *GonumGraph) NewNode(successors []int) (id int) {
} }
func (graph *GonumGraph) AddNode(id int, successors []int) { func (graph *GonumGraph) AddNode(id int, successors []int) {
if graph.vertices.Contains(id) { if _, ok := graph.successors[id]; ok {
return return
} }
graph.vertices.Add(id) graph.vertices.Add(id)
@@ -61,7 +64,7 @@ func (graph *GonumGraph) AddNode(id int, successors []int) {
graph.successors[id][succ] = 1.0 graph.successors[id][succ] = 1.0
// Always add the reciprocal node to the graph // Always add the reciprocal node to the graph
if !graph.vertices.Contains(succ) { if _, ok := graph.successors[succ]; !ok {
graph.vertices.Add(succ) graph.vertices.Add(succ)
graph.predecessors[succ] = make(map[int]float64) graph.predecessors[succ] = make(map[int]float64)
graph.successors[succ] = make(map[int]float64) graph.successors[succ] = make(map[int]float64)
@@ -78,11 +81,11 @@ func (graph *GonumGraph) AddNode(id int, successors []int) {
} }
func (graph *GonumGraph) AddEdge(id, successor int) { func (graph *GonumGraph) AddEdge(id, successor int) {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return return
} }
if !graph.vertices.Contains(successor) { if _, ok := graph.successors[successor]; !ok {
graph.vertices.Add(successor) graph.vertices.Add(successor)
graph.successors[successor] = make(map[int]float64) graph.successors[successor] = make(map[int]float64)
graph.predecessors[successor] = make(map[int]float64) graph.predecessors[successor] = make(map[int]float64)
@@ -99,7 +102,7 @@ func (graph *GonumGraph) AddEdge(id, successor int) {
func (graph *GonumGraph) SetEdgeCost(id, successor int, cost float64) { func (graph *GonumGraph) SetEdgeCost(id, successor int, cost float64) {
// Normally I'd use graph.vertices.Contains(id) as above, but this is equivalent and a bit easier to read here // Normally I'd use graph.vertices.Contains(id) as above, but this is equivalent and a bit easier to read here
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return return
} else if _, ok := graph.successors[id][successor]; !ok { } else if _, ok := graph.successors[id][successor]; !ok {
return return
@@ -115,7 +118,7 @@ func (graph *GonumGraph) SetEdgeCost(id, successor int, cost float64) {
} }
func (graph *GonumGraph) RemoveNode(id int) { func (graph *GonumGraph) RemoveNode(id int) {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; ok {
return return
} }
@@ -129,12 +132,12 @@ func (graph *GonumGraph) RemoveNode(id int) {
} }
delete(graph.predecessors, id) delete(graph.predecessors, id)
graph.vertices.Remove(id)
} }
func (graph *GonumGraph) RemoveEdge(id, succ int) { func (graph *GonumGraph) RemoveEdge(id, succ int) {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return
} else if _, ok := graph.successors[succ]; !ok {
return return
} }
@@ -147,16 +150,15 @@ func (graph *GonumGraph) RemoveEdge(id, succ int) {
} }
func (graph *GonumGraph) EmptyGraph() { func (graph *GonumGraph) EmptyGraph() {
if graph.vertices.Cardinality() == 0 { if len(graph.successors) == 0 {
return return
} }
graph.vertices = NewSet()
graph.successors = make(map[int]map[int]float64) graph.successors = make(map[int]map[int]float64)
graph.predecessors = make(map[int]map[int]float64) graph.predecessors = make(map[int]map[int]float64)
} }
func (graph *GonumGraph) SetDirected(directed bool) { func (graph *GonumGraph) SetDirected(directed bool) {
if graph.vertices.Cardinality() > 0 { if len(graph.successors) > 0 {
return return
} }
graph.directed = directed graph.directed = directed
@@ -165,7 +167,7 @@ func (graph *GonumGraph) SetDirected(directed bool) {
/* Graph implementation */ /* Graph implementation */
func (graph *GonumGraph) Successors(id int) []int { func (graph *GonumGraph) Successors(id int) []int {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return nil return nil
} }
@@ -178,7 +180,7 @@ func (graph *GonumGraph) Successors(id int) []int {
} }
func (graph *GonumGraph) IsSuccessor(id, succ int) bool { func (graph *GonumGraph) IsSuccessor(id, succ int) bool {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return false return false
} }
@@ -188,7 +190,7 @@ func (graph *GonumGraph) IsSuccessor(id, succ int) bool {
} }
func (graph *GonumGraph) Predecessors(id int) []int { func (graph *GonumGraph) Predecessors(id int) []int {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return nil return nil
} }
@@ -201,7 +203,7 @@ func (graph *GonumGraph) Predecessors(id int) []int {
} }
func (graph *GonumGraph) IsPredecessor(id, pred int) bool { func (graph *GonumGraph) IsPredecessor(id, pred int) bool {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return false return false
} }
@@ -211,7 +213,7 @@ func (graph *GonumGraph) IsPredecessor(id, pred int) bool {
} }
func (graph *GonumGraph) IsAdjacent(id, neighbor int) bool { func (graph *GonumGraph) IsAdjacent(id, neighbor int) bool {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return false return false
} }
@@ -222,11 +224,13 @@ func (graph *GonumGraph) IsAdjacent(id, neighbor int) bool {
} }
func (graph *GonumGraph) NodeExists(id int) bool { func (graph *GonumGraph) NodeExists(id int) bool {
return graph.vertices.Contains(id) _, ok := graph.successors[id]
return ok
} }
func (graph *GonumGraph) Degree(id int) int { func (graph *GonumGraph) Degree(id int) int {
if !graph.vertices.Contains(id) { if _, ok := graph.successors[id]; !ok {
return 0 return 0
} }
@@ -245,10 +249,8 @@ func (graph *GonumGraph) EdgeList() [][2]int {
} }
func (graph *GonumGraph) NodeList() []int { func (graph *GonumGraph) NodeList() []int {
rawNodes := graph.vertices.Elements() for node, _ := range graph.successors {
nodes := make([]int, 0, len(rawNodes)) nodes = append(nodes, node)
for _, rawNode := range rawNodes {
nodes = append(nodes, rawNode.(int))
} }
return nodes return nodes

View File

@@ -198,7 +198,7 @@ func BellmanFord(source int, graph Graph, Cost func(int, int) float64) (paths ma
// It makes use of Bellman-Ford and a dummy graph. It creates a dummy node containing edges with a cost of zero to every other node. Then it runs Bellman-Ford with this // It makes use of Bellman-Ford and a dummy graph. It creates a dummy node containing edges with a cost of zero to every other node. Then it runs Bellman-Ford with this
// dummy node as the source. // dummy node as the source.
// //
// Finally, it removes the dummy node and run Dijkstra's starting at every node. // Finally, it removes the dummy node and runs Dijkstra's starting at every node.
// //
// This algorithm is fairly slow. Its purpose is to remove negative edge weights to allow Dijkstra's to function properly. It's probably not worth it to run this algorithm if you have // This algorithm is fairly slow. Its purpose is to remove negative edge weights to allow Dijkstra's to function properly. It's probably not worth it to run this algorithm if you have
// all non-negative edge weights. Also note that this implementation copies your whole graph into a GonumGraph (so it can add/remove the dummy node and edges and reweight the graph). // all non-negative edge weights. Also note that this implementation copies your whole graph into a GonumGraph (so it can add/remove the dummy node and edges and reweight the graph).