Skip to content
This repository has been archived by the owner on Apr 26, 2019. It is now read-only.

Commit

Permalink
split into new packages
Browse files Browse the repository at this point in the history
  • Loading branch information
soniakeys committed Jan 31, 2014
1 parent 215626e commit 185452f
Show file tree
Hide file tree
Showing 10 changed files with 1,078 additions and 1,061 deletions.
107 changes: 107 additions & 0 deletions concrete/concrete_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package concrete_test

import (
"testing"

"github.com/gonum/graph"
"github.com/gonum/graph/concrete"
)

// Asserts that out concrete graphs implement the correct interfaces
var _ graph.DirectedGraph = (*concrete.GonumGraph)(nil)
var _ graph.MutableGraph = (*concrete.GonumGraph)(nil)
var _ graph.UndirectedGraph = (*concrete.TileGraph)(nil)

func TestTileGraph(t *testing.T) {
tg := concrete.NewTileGraph(4, 4, false)

if tg == nil || tg.String() != "▀▀▀▀\n▀▀▀▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Tile graph not generated correctly")
}

tg.SetPassability(0, 1, true)
if tg == nil || tg.String() != "▀ ▀▀\n▀▀▀▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(0, 1, false)
if tg == nil || tg.String() != "▀▀▀▀\n▀▀▀▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(0, 1, true)
if tg == nil || tg.String() != "▀ ▀▀\n▀▀▀▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(0, 2, true)
if tg == nil || tg.String() != "▀ ▀\n▀▀▀▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(1, 2, true)
if tg == nil || tg.String() != "▀ ▀\n▀▀ ▀\n▀▀▀▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(2, 2, true)
if tg == nil || tg.String() != "▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀▀▀" {
t.Fatal("Passability set incorrectly")
}

tg.SetPassability(3, 2, true)
if tg == nil || tg.String() != "▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀" {
t.Fatal("Passability set incorrectly")
}

if tg2, err := concrete.GenerateTileGraph("▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀"); err != nil {
t.Error("Tile graph errored on interpreting valid template string\n▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀")
} else if tg2.String() != "▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀" {
t.Error("Tile graph failed to generate properly with input string\n▀ ▀\n▀▀ ▀\n▀▀ ▀\n▀▀ ▀")
}

if tg.CoordsToID(0, 0) != 0 {
t.Error("Coords to ID fails on 0,0")
} else if tg.CoordsToID(3, 3) != 15 {
t.Error("Coords to ID fails on 3,3")
} else if tg.CoordsToID(0, 3) != 3 {
t.Error("Coords to ID fails on 0,3")
} else if tg.CoordsToID(3, 0) != 12 {
t.Error("Coords to ID fails on 3,0")
}

if r, c := tg.IDToCoords(0); r != 0 || c != 0 {
t.Error("ID to Coords fails on 0,0")
} else if r, c := tg.IDToCoords(15); r != 3 || c != 3 {
t.Error("ID to Coords fails on 3,3")
} else if r, c := tg.IDToCoords(3); r != 0 || c != 3 {
t.Error("ID to Coords fails on 0,3")
} else if r, c := tg.IDToCoords(12); r != 3 || c != 0 {
t.Error("ID to Coords fails on 3,0")
}

if succ := tg.Neighbors(concrete.GonumNode(0)); succ != nil || len(succ) != 0 {
t.Error("Successors for impassable tile not 0")
}

if succ := tg.Neighbors(concrete.GonumNode(2)); succ == nil || len(succ) != 2 {
t.Error("Incorrect number of successors for (0,2)")
} else {
for _, s := range succ {
if s.ID() != 1 && s.ID() != 6 {
t.Error("Successor for (0,2) neither (0,1) nor (1,2)")
}
}
}

if tg.Degree(concrete.GonumNode(2)) != 4 {
t.Error("Degree returns incorrect number for (0,2)")
}
if tg.Degree(concrete.GonumNode(1)) != 2 {
t.Error("Degree returns incorrect number for (0,2)")
}
if tg.Degree(concrete.GonumNode(0)) != 0 {
t.Error("Degree returns incorrect number for impassable tile (0,0)")
}

}
72 changes: 47 additions & 25 deletions concretegraph.go → concrete/concretegraph.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@
package graph
package concrete

import (
"sort"

gr "github.com/gonum/graph"
)

// A simple int alias.
type GonumNode int

func (node GonumNode) ID() int {
return int(node)
}

// Just a collection of two nodes
type GonumEdge struct {
H, T gr.Node
}

func (edge GonumEdge) Head() gr.Node {
return edge.H
}

func (edge GonumEdge) Tail() gr.Node {
return edge.T
}

// 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).
Expand All @@ -13,7 +35,7 @@ import (
type GonumGraph struct {
successors map[int]map[int]float64
predecessors map[int]map[int]float64
nodeMap map[int]Node
nodeMap map[int]gr.Node
directed bool
}

Expand All @@ -35,7 +57,7 @@ func NewPreAllocatedGonumGraph(directed bool, numVertices int) *GonumGraph {

/* Mutable Graph implementation */

func (graph *GonumGraph) NewNode(successors []Node) (node Node) {
func (graph *GonumGraph) NewNode(successors []gr.Node) (node gr.Node) {
nodeList := graph.NodeList()
ids := make([]int, len(nodeList))
for i, node := range nodeList {
Expand All @@ -56,7 +78,7 @@ func (graph *GonumGraph) NewNode(successors []Node) (node Node) {
return GonumNode(newID)
}

func (graph *GonumGraph) AddNode(node Node, successors []Node) {
func (graph *GonumGraph) AddNode(node gr.Node, successors []gr.Node) {
id := node.ID()
if _, ok := graph.successors[id]; ok {
return
Expand Down Expand Up @@ -91,7 +113,7 @@ func (graph *GonumGraph) AddNode(node Node, successors []Node) {
}
}

func (graph *GonumGraph) AddEdge(e Edge) {
func (graph *GonumGraph) AddEdge(e gr.Edge) {
id := e.Head().ID()
successor := e.Tail().ID()
if _, ok := graph.successors[id]; !ok {
Expand All @@ -113,7 +135,7 @@ func (graph *GonumGraph) AddEdge(e Edge) {
}
}

func (graph *GonumGraph) SetEdgeCost(e Edge, cost float64) {
func (graph *GonumGraph) SetEdgeCost(e gr.Edge, cost float64) {
id := e.Head().ID()
successor := e.Tail().ID()
// Normally I'd use graph.vertices.Contains(id) as above, but this is equivalent and a bit easier to read here
Expand All @@ -132,7 +154,7 @@ func (graph *GonumGraph) SetEdgeCost(e Edge, cost float64) {
}
}

func (graph *GonumGraph) RemoveNode(node Node) {
func (graph *GonumGraph) RemoveNode(node gr.Node) {
id := node.ID()
if _, ok := graph.successors[id]; ok {
return
Expand All @@ -151,7 +173,7 @@ func (graph *GonumGraph) RemoveNode(node Node) {

}

func (graph *GonumGraph) RemoveEdge(e Edge) {
func (graph *GonumGraph) RemoveEdge(e gr.Edge) {
id := e.Head().ID()
succ := e.Tail().ID()
if _, ok := graph.successors[id]; !ok {
Expand All @@ -174,7 +196,7 @@ func (graph *GonumGraph) EmptyGraph() {
}
graph.successors = make(map[int]map[int]float64)
graph.predecessors = make(map[int]map[int]float64)
graph.nodeMap = make(map[int]Node)
graph.nodeMap = make(map[int]gr.Node)
}

func (graph *GonumGraph) SetDirected(directed bool) {
Expand All @@ -186,21 +208,21 @@ func (graph *GonumGraph) SetDirected(directed bool) {

/* Graph implementation */

func (graph *GonumGraph) Successors(node Node) []Node {
func (graph *GonumGraph) Successors(node gr.Node) []gr.Node {
id := node.ID()
if _, ok := graph.successors[id]; !ok {
return nil
}

successors := make([]Node, len(graph.successors[id]))
successors := make([]gr.Node, len(graph.successors[id]))
for succ, _ := range graph.successors[id] {
successors = append(successors, graph.nodeMap[succ])
}

return successors
}

func (graph *GonumGraph) IsSuccessor(node, successor Node) bool {
func (graph *GonumGraph) IsSuccessor(node, successor gr.Node) bool {
succ := successor.ID()
id := node.ID()
if _, ok := graph.successors[id]; !ok {
Expand All @@ -212,21 +234,21 @@ func (graph *GonumGraph) IsSuccessor(node, successor Node) bool {
return ok
}

func (graph *GonumGraph) Predecessors(node Node) []Node {
func (graph *GonumGraph) Predecessors(node gr.Node) []gr.Node {
id := node.ID()
if _, ok := graph.successors[id]; !ok {
return nil
}

predecessors := make([]Node, len(graph.predecessors[id]))
predecessors := make([]gr.Node, len(graph.predecessors[id]))
for pred, _ := range graph.predecessors[id] {
predecessors = append(predecessors, graph.nodeMap[pred])
}

return predecessors
}

func (graph *GonumGraph) IsPredecessor(node, predecessor Node) bool {
func (graph *GonumGraph) IsPredecessor(node, predecessor gr.Node) bool {
id := node.ID()
pred := predecessor.ID()
if _, ok := graph.successors[id]; !ok {
Expand All @@ -238,13 +260,13 @@ func (graph *GonumGraph) IsPredecessor(node, predecessor Node) bool {
return ok
}

func (graph *GonumGraph) Neighbors(node Node) []Node {
func (graph *GonumGraph) Neighbors(node gr.Node) []gr.Node {
id := node.ID()
if _, ok := graph.successors[id]; !ok {
return nil
}

neighbors := make([]Node, 0, len(graph.predecessors[id])+len(graph.successors[id]))
neighbors := make([]gr.Node, 0, len(graph.predecessors[id])+len(graph.successors[id]))
for succ, _ := range graph.successors[id] {
neighbors = append(neighbors, graph.nodeMap[succ])
}
Expand All @@ -259,7 +281,7 @@ func (graph *GonumGraph) Neighbors(node Node) []Node {
return neighbors
}

func (graph *GonumGraph) IsNeighbor(node, neigh Node) bool {
func (graph *GonumGraph) IsNeighbor(node, neigh gr.Node) bool {
id := node.ID()
neighbor := neigh.ID()
if _, ok := graph.successors[id]; !ok {
Expand All @@ -272,13 +294,13 @@ func (graph *GonumGraph) IsNeighbor(node, neigh Node) bool {
return succ || pred
}

func (graph *GonumGraph) NodeExists(node Node) bool {
func (graph *GonumGraph) NodeExists(node gr.Node) bool {
_, ok := graph.successors[node.ID()]

return ok
}

func (graph *GonumGraph) Degree(node Node) int {
func (graph *GonumGraph) Degree(node gr.Node) int {
id := node.ID()
if _, ok := graph.successors[id]; !ok {
return 0
Expand All @@ -287,8 +309,8 @@ func (graph *GonumGraph) Degree(node Node) int {
return len(graph.successors[id]) + len(graph.predecessors[id])
}

func (graph *GonumGraph) EdgeList() []Edge {
eList := make([]Edge, 0, len(graph.successors))
func (graph *GonumGraph) EdgeList() []gr.Edge {
eList := make([]gr.Edge, 0, len(graph.successors))
for id, succMap := range graph.successors {
for succ, _ := range succMap {
eList = append(eList, GonumEdge{graph.nodeMap[id], graph.nodeMap[succ]})
Expand All @@ -298,8 +320,8 @@ func (graph *GonumGraph) EdgeList() []Edge {
return eList
}

func (graph *GonumGraph) NodeList() []Node {
nodes := make([]Node, 0, len(graph.successors))
func (graph *GonumGraph) NodeList() []gr.Node {
nodes := make([]gr.Node, 0, len(graph.successors))
for _, node := range graph.nodeMap {
nodes = append(nodes, node)
}
Expand All @@ -311,6 +333,6 @@ func (graph *GonumGraph) IsDirected() bool {
return graph.directed
}

func (graph *GonumGraph) Cost(node, succ Node) float64 {
func (graph *GonumGraph) Cost(node, succ gr.Node) float64 {
return graph.successors[node.ID()][succ.ID()]
}
Loading

0 comments on commit 185452f

Please sign in to comment.