Skip to content
This repository has been archived by the owner on Feb 4, 2021. It is now read-only.

Commit

Permalink
Actually use the DirectedGraph interface: implement & test Transpose()
Browse files Browse the repository at this point in the history
  • Loading branch information
sdboyer committed Mar 14, 2014
1 parent 2b9b277 commit deb8976
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 9 deletions.
26 changes: 26 additions & 0 deletions directed.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ func NewDirected() *Directed {
var _ Graph = list
var _ SimpleGraph = list
var _ MutableGraph = list
var _ DirectedGraph = list

return list
}
Expand Down Expand Up @@ -167,3 +168,28 @@ func (g *Directed) RemoveEdges(edges ...Edge) {
}
}
}

func (g *Directed) Transpose() DirectedGraph {
g.mu.RLock()
defer g.mu.RUnlock()

g2 := &Directed{}
g2.list = make(map[Vertex]map[Vertex]struct{})

// Guess at average indegree by looking at ratio of edges to vertices, use that to initially size the adjacency maps
startcap := int(g.Size() / g.Order())

for source, adjacent := range g.list {
if !g2.hasVertex(source) {
g2.list[source] = make(map[Vertex]struct{}, startcap+1)
}
for target, _ := range adjacent {
if !g2.hasVertex(target) {
g2.list[target] = make(map[Vertex]struct{}, startcap+1)
}
g2.list[target][source] = keyExists
}
}

return g2
}
2 changes: 0 additions & 2 deletions graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ type SimpleGraph interface {
type DirectedGraph interface {
Graph
Transpose() DirectedGraph
IsAcyclic() bool
GetCycles() [][]Vertex
}

type WeightedGraph interface {
Expand Down
52 changes: 45 additions & 7 deletions graph_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,13 @@ var _ = fmt.Println
func Test(t *testing.T) { TestingT(t) }

var edgeSet = []Edge{
&BaseEdge{"foo", "bar"},
&BaseEdge{"bar", "baz"},
BaseEdge{"foo", "bar"},
BaseEdge{"bar", "baz"},
}

// swap method is useful for some testing shorthand
func (e BaseEdge) swap() Edge {
return BaseEdge{e.V, e.U}
}

// This function automatically sets up suites of black box unit tests for
Expand All @@ -26,8 +31,14 @@ var edgeSet = []Edge{
// Passing a graph to this method for testing is the most official way to
// determine whether or not it complies with not just the interfaces, but also
// the graph semantics defined by gogl.
func SetUpSimpleGraphTests(g Graph, directed bool) bool {
func SetUpSimpleGraphTests(g Graph) bool {
gf := &GraphFactory{g}
var directed bool

if dg, ok := g.(DirectedGraph); ok {
directed = true
Suite(&DirectedGraphSuite{Graph: dg, Factory: gf})
}

// Set up the basic Graph suite unconditionally
Suite(&GraphSuite{Graph: g, Factory: gf, Directed: directed})
Expand All @@ -52,10 +63,10 @@ func SetUpSimpleGraphTests(g Graph, directed bool) bool {
}

// Set up suites for all of gogl's graphs.
var _ = SetUpSimpleGraphTests(NewDirected(), true)
var _ = SetUpSimpleGraphTests(NewUndirected(), false)
var _ = SetUpSimpleGraphTests(NewWeightedDirected(), true)
var _ = SetUpSimpleGraphTests(NewWeightedUndirected(), false)
var _ = SetUpSimpleGraphTests(NewDirected())
var _ = SetUpSimpleGraphTests(NewUndirected())
var _ = SetUpSimpleGraphTests(NewWeightedDirected())
var _ = SetUpSimpleGraphTests(NewWeightedUndirected())

/* The GraphFactory - this generates graph instances for the tests. */

Expand Down Expand Up @@ -95,6 +106,10 @@ func (gf *GraphFactory) CreateGraphFromEdges(edges ...Edge) Graph {
return gf.graphFromEdges(edges...)
}

func (gf *GraphFactory) CreateDirectedGraphFromEdges(edges ...Edge) DirectedGraph {
return gf.graphFromEdges(edges...).(DirectedGraph)
}

func (gf *GraphFactory) CreateEmptySimpleGraph() SimpleGraph {
return gf.create().(SimpleGraph)
}
Expand Down Expand Up @@ -137,6 +152,10 @@ type SimpleGraphCreator interface {
CreateSimpleGraphFromEdges(edges ...Edge) SimpleGraph
}

type DirectedGraphCreator interface {
CreateDirectedGraphFromEdges(edges ...Edge) DirectedGraph
}

type MutableGraphCreator interface {
CreateMutableGraph() MutableGraph
}
Expand Down Expand Up @@ -253,6 +272,25 @@ func (s *GraphSuite) TestOrder(c *C) {
c.Assert(g.Size(), Equals, 0)
}

/* DirectedGraphSuite - tests for directed graph methods */

type DirectedGraphSuite struct {
Graph Graph
Factory DirectedGraphCreator
}

func (s *DirectedGraphSuite) TestTranspose(c *C) {
g := s.Factory.CreateDirectedGraphFromEdges(edgeSet...)

g2 := g.Transpose()

c.Assert(g2.HasEdge(edgeSet[0].(BaseEdge).swap()), Equals, true)
c.Assert(g2.HasEdge(edgeSet[1].(BaseEdge).swap()), Equals, true)

c.Assert(g2.HasEdge(edgeSet[0].(BaseEdge)), Equals, false)
c.Assert(g2.HasEdge(edgeSet[1].(BaseEdge)), Equals, false)
}

/* SimpleGraphSuite - tests for simple graph methods */

type SimpleGraphSuite struct {
Expand Down
27 changes: 27 additions & 0 deletions weighted.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func NewWeightedDirected() MutableWeightedGraph {
// Type assertions to ensure interfaces are met
var _ Graph = list
var _ SimpleGraph = list
var _ DirectedGraph = list
var _ WeightedGraph = list
var _ MutableWeightedGraph = list

Expand Down Expand Up @@ -286,6 +287,32 @@ func (g *weightedDirected) RemoveEdges(edges ...WeightedEdge) {
}
}

func (g *weightedDirected) Transpose() DirectedGraph {
g.mu.RLock()
defer g.mu.RUnlock()

g2 := &weightedDirected{}
g2.list = make(map[Vertex]map[Vertex]int)

// Guess at average indegree by looking at ratio of edges to vertices, use that to initially size the adjacency maps
startcap := int(g.Size() / g.Order())

for source, adjacent := range g.list {
if !g2.hasVertex(source) {
g2.list[source] = make(map[Vertex]int, startcap+1)
}

for target, weight := range adjacent {
if !g2.hasVertex(target) {
g2.list[target] = make(map[Vertex]int, startcap+1)
}
g2.list[target][source] = weight
}
}

return g2
}

/* UndirectedWeighted implementation */

type weightedUndirected struct {
Expand Down

0 comments on commit deb8976

Please sign in to comment.