Skip to content

Commit

Permalink
Merge branch 'main' of https://github.com/dominikbraun/graph
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikbraun committed Jun 20, 2022
2 parents f2a0cdd + 561e380 commit f67b7a8
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 0 deletions.
23 changes: 23 additions & 0 deletions directed.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,29 @@ func (d *directed[K, T]) CreatesCycleByHashes(sourceHash, targetHash K) (bool, e
return false, nil
}

func (d *directed[K, T]) Degree(vertex T) (int, error) {
sourceHash := d.hash(vertex)

return d.DegreeByHash(sourceHash)
}

func (d *directed[K, T]) DegreeByHash(vertexHash K) (int, error) {
if _, ok := d.vertices[vertexHash]; !ok {
return 0, fmt.Errorf("could not find vertex with hash %v", vertexHash)
}

degree := 0

if inEdges, ok := d.inEdges[vertexHash]; ok {
degree += len(inEdges)
}
if outEdges, ok := d.outEdges[vertexHash]; ok {
degree += len(outEdges)
}

return degree, nil
}

func (d *directed[K, T]) edgesAreEqual(a, b Edge[T]) bool {
aSourceHash := d.hash(a.Source)
aTargetHash := d.hash(a.Target)
Expand Down
38 changes: 38 additions & 0 deletions directed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,44 @@ func TestDirected_CreatesCycleByHashes(t *testing.T) {
}
}

func TestDirected_Degree(t *testing.T) {
TestDirected_DegreeByHash(t)
}

func TestDirected_DegreeByHash(t *testing.T) {
tests := map[string]struct {
vertices []int
edges []Edge[int]
vertexHash int
expectedDegree int
shouldFail bool
}{}

for name, test := range tests {
graph := newDirected(IntHash, &properties{})

for _, vertex := range test.vertices {
graph.Vertex(vertex)
}

for _, edge := range test.edges {
if err := graph.Edge(edge.Source, edge.Target); err != nil {
t.Fatalf("%s: failed to add edge: %s", name, err.Error())
}
}

degree, err := graph.DegreeByHash(test.vertexHash)

if test.shouldFail != (err != nil) {
t.Fatalf("%s: error expectancy doesn't match: expected %v, got %v (error: %v)", name, test.shouldFail, (err != nil), err)
}

if degree != test.expectedDegree {
t.Errorf("%s: degree expectancy doesn't match: expcted %v, got %v", name, test.expectedDegree, degree)
}
}
}

func TestDirected_edgesAreEqual(t *testing.T) {
tests := map[string]struct {
a Edge[int]
Expand Down
6 changes: 6 additions & 0 deletions graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ type Graph[K comparable, T any] interface {
// CreatesCycleByHashes does the same as CreatesCycle, but uses a hash value to identify the
// starting vertex.
CreatesCycleByHashes(sourceHash, targetHash K) (bool, error)

// Degree determines and returns the degree of a given vertex.
Degree(vertex T) (int, error)

// DegreeByHash does the same as Degree, but uses a hash value to identify the vertex.
DegreeByHash(vertexHash K) (int, error)
}

// Edge represents a graph edge with a source and target vertex as well as a weight, which has the
Expand Down
23 changes: 23 additions & 0 deletions undirected.go
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,29 @@ func (u *undirected[K, T]) CreatesCycleByHashes(sourceHash, targetHash K) (bool,
return false, nil
}

func (u *undirected[K, T]) Degree(vertex T) (int, error) {
sourceHash := u.hash(vertex)

return u.DegreeByHash(sourceHash)
}

func (u *undirected[K, T]) DegreeByHash(vertexHash K) (int, error) {
if _, ok := u.vertices[vertexHash]; !ok {
return 0, fmt.Errorf("could not find vertex with hash %v", vertexHash)
}

degree := 0

// Adding the number of ingoing edges is sufficient for undirected graphs, because all edges
// exist twice (as two directed edges in opposite directions). Either dividing the number of
// ingoing + outgoing edges by 2 or just using the number of ingoing edges is appropriate.
if inEdges, ok := u.inEdges[vertexHash]; ok {
degree += len(inEdges)
}

return degree, nil
}

func (u *undirected[K, T]) edgesAreEqual(a, b Edge[T]) bool {
aSourceHash := u.hash(a.Source)
aTargetHash := u.hash(a.Target)
Expand Down
38 changes: 38 additions & 0 deletions undirected_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,44 @@ func TestUndirected_CreatesCycleByHashes(t *testing.T) {
}
}

func TestUndirected_Degree(t *testing.T) {
TestDirected_Degree(t)
}

func TestUndirected_DegreeByHash(t *testing.T) {
tests := map[string]struct {
vertices []int
edges []Edge[int]
vertexHash int
expectedDegree int
shouldFail bool
}{}

for name, test := range tests {
graph := newUndirected(IntHash, &properties{})

for _, vertex := range test.vertices {
graph.Vertex(vertex)
}

for _, edge := range test.edges {
if err := graph.Edge(edge.Source, edge.Target); err != nil {
t.Fatalf("%s: failed to add edge: %s", name, err.Error())
}
}

degree, err := graph.DegreeByHash(test.vertexHash)

if test.shouldFail != (err != nil) {
t.Fatalf("%s: error expectancy doesn't match: expected %v, got %v (error: %v)", name, test.shouldFail, (err != nil), err)
}

if degree != test.expectedDegree {
t.Errorf("%s: degree expectancy doesn't match: expcted %v, got %v", name, test.expectedDegree, degree)
}
}
}

func TestUndirected_edgesAreEqual(t *testing.T) {
tests := map[string]struct {
a Edge[int]
Expand Down

0 comments on commit f67b7a8

Please sign in to comment.