Skip to content

Commit 23ae8ac

Browse files
authored
Merge pull request #4 from yourbasic/tip
Tip
2 parents fe61a98 + 12be2c9 commit 23ae8ac

13 files changed

+94
-109
lines changed

bipart.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ func Bipartition(g Iterator) (part []int, ok bool) {
1919
colors[v] = white
2020
whiteCount++
2121
for queue := []int{v}; len(queue) > 0; {
22-
v, queue = queue[0], queue[1:]
22+
v := queue[0]
23+
queue = queue[1:]
2324
if g.Visit(v, func(w int, _ int64) (skip bool) {
2425
switch {
2526
case colors[w] != none:

build/build.go

+25-24
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
// to turn on caching for any component. This gives constant time
2424
// performance for all basic operations on that component.
2525
//
26-
// Example usage
26+
// Tutorial
2727
//
28-
// The package examples show how to build graphs from standard components
29-
// using composition and filtering. They also demonstrate how to apply
30-
// a cost function to a virtual graph.
28+
// The Euclid and Maxflow examples show how to build graphs from
29+
// standard components using composition and filtering. They also
30+
// demonstrate how to apply a cost function to a virtual graph.
3131
//
3232
package build
3333

@@ -41,21 +41,25 @@ import (
4141
// by composing and filtering a set of standard graphs, or by writing
4242
// functions that describe the edges of a graph.
4343
type Virtual struct {
44+
// The `order` field is, in fact, a constant function.
45+
// It returns the number of vertices in the graph.
4446
order int
45-
// The edge and cost functions define a weighted graph without self-loops.
47+
48+
// The `edge` and `cost` functions define a weighted graph without self-loops.
4649
//
4750
// • edge(v, w) returns true whenever (v, w) belongs to the graph;
4851
// the value is disregarded when v == w.
4952
//
50-
// • cost(v, w) returns the cost of (v, w); the value is disregarded
51-
// when edge(v, w) is false.
53+
// • cost(v, w) returns the cost of (v, w);
54+
// the value is disregarded when edge(v, w) is false.
55+
//
5256
edge func(v, w int) bool
5357
cost func(v, w int) int64
5458

55-
// These functions can be used to improve performance.
56-
// They MUST BE CONSISTENT with edge and cost.
57-
// The generic() factory method contains a basic implementation.
58-
// The Consistent test function should be used to check compliance.
59+
// The `degree` and `visit` functions can be used to improve performance.
60+
// They MUST BE CONSISTENT with edge and cost. If not implemented,
61+
// the `generic` or `generic0` implementation is used instead.
62+
// The `Consistent` test function should be used to check compliance.
5963
//
6064
// • degree(v) returns the outdegree of vertex v.
6165
//
@@ -64,12 +68,13 @@ type Virtual struct {
6468
// If a call to do returns true, visit MUST ABORT the iteration
6569
// and return true; if successful it should return false.
6670
// Precondition: a ≥ 0.
71+
//
6772
degree func(v int) int
6873
visit func(v int, a int, do func(w int, c int64) (skip bool)) (aborted bool)
6974
}
7075

7176
// FilterFunc is a function that tells if there is a directed edge from v to w.
72-
// The nil value represents an edge functions that always returns true.
77+
// The nil value represents an edge function that always returns true.
7378
type FilterFunc func(v, w int) bool
7479

7580
// CostFunc is a function that computes the cost of an edge from v to w.
@@ -107,7 +112,7 @@ func max(m, n int) int {
107112
return m
108113
}
109114

110-
// null is the null graph; a graph of order 0.
115+
// null is the null graph; a graph with no vertices.
111116
var null = new(Virtual)
112117

113118
// singleton returns a graph with one vertex.
@@ -126,7 +131,7 @@ func edge() *Virtual {
126131
g := &Virtual{
127132
order: 2,
128133
cost: zero,
129-
edge: func(v, w int) bool { return v != w },
134+
edge: alwaysEdge,
130135
degree: degreeOne,
131136
}
132137
g.visit = func(v int, a int, do func(w int, c int64) bool) (aborted bool) {
@@ -260,17 +265,16 @@ func Generic(n int, edge FilterFunc) *Virtual {
260265
return generic0(n, edge)
261266
}
262267

263-
// Specific returns a cached copy of g with constant time performance
264-
// for all basic operations. It uses space proportional to
265-
// the size of the graph.
268+
// Specific returns a cached copy of g with constant time performance for
269+
// all basic operations. It uses space proportional to the size of the graph.
266270
//
267271
// This function does not accept multigraphs and graphs with self-loops.
268272
func Specific(g graph.Iterator) *Virtual {
269-
stats := graph.Check(g)
273+
h := graph.Sort(g)
274+
stats := graph.Check(h)
270275
if stats.Multi != 0 || stats.Loops != 0 {
271276
panic("Virtual doesn't support multiple edges or self-loops")
272277
}
273-
h := graph.Sort(g)
274278
res := &Virtual{
275279
order: h.Order(),
276280
edge: h.Edge,
@@ -282,7 +286,7 @@ func Specific(g graph.Iterator) *Virtual {
282286
return res
283287
}
284288
res.cost = func(v, w int) (cost int64) {
285-
if !res.edge(v, w) {
289+
if !h.Edge(v, w) {
286290
return 0
287291
}
288292
h.VisitFrom(v, w, func(w int, c int64) (skip bool) {
@@ -353,10 +357,7 @@ func (g *Virtual) Complement() *Virtual {
353357
return singleton()
354358
}
355359
res := generic0(n, func(v, w int) (edge bool) {
356-
if v != w {
357-
return !g.edge(v, w)
358-
}
359-
return
360+
return v != w && !g.edge(v, w)
360361
})
361362
res.degree = func(v int) int { return n - 1 - g.degree(v) }
362363
res.visit = func(v int, a int, do func(w int, c int64) bool) (aborted bool) {

build/edgeset.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ func (g *Virtual) Delete(e EdgeSet) *Virtual {
6262
})
6363
}
6464

65-
// NewEdges returns a virtual graph with n vertices and all edges
65+
// newEdges returns a virtual graph with n vertices and all edges
6666
// belonging to the edge set.
6767
func newEdges(n int, e EdgeSet) *Virtual {
6868
switch {

build/join.go

-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ func (g1 *Virtual) Join(g2 *Virtual, bridge EdgeSet) *Virtual {
2828
default:
2929
return bridge.Cost(v, w)
3030
}
31-
return bridge.Cost(v, w)
3231
}
3332

3433
var noFilter bool

build/vertexset.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type interval struct {
2222
index int // index of a in the whole set
2323
}
2424

25-
// updates the index values.
25+
// update updates the index values.
2626
func (s VertexSet) update() {
2727
prev := 0
2828
for i, in := range s.set {
@@ -46,7 +46,7 @@ func Range(a, b int) VertexSet {
4646

4747
// Vertex returns a set containing the single vertex v.
4848
func Vertex(v int) VertexSet {
49-
return Range(v, v+1)
49+
return VertexSet{[]interval{{v, v + 1, 0}}}
5050
}
5151

5252
// size returns the number of elements in this set, or -1 for the universe.

euler.go

+40-48
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@ package graph
44
// If no such walk exists, it returns an empty walk and sets ok to false.
55
func EulerDirected(g Iterator) (walk []int, ok bool) {
66
n := g.Order()
7-
// Compute outdegree - indegree for each vertex.
8-
degree := make([]int, n)
7+
degree := make([]int, n) // outdegree - indegree for each vertex
8+
edgeCount := 0
99
for v := range degree {
1010
g.Visit(v, func(w int, _ int64) (skip bool) {
11+
edgeCount++
1112
degree[v]++
1213
degree[w]--
1314
return
1415
})
1516
}
17+
if edgeCount == 0 {
18+
return []int{}, true
19+
}
1620

1721
start, end := -1, -1
1822
for v := range degree {
@@ -28,42 +32,38 @@ func EulerDirected(g Iterator) (walk []int, ok bool) {
2832
}
2933

3034
// Make a copy of g
31-
edgeCount := 0
3235
h := make([][]int, n)
3336
for v := range h {
3437
g.Visit(v, func(w int, _ int64) (skip bool) {
3538
h[v] = append(h[v], w)
36-
edgeCount++
3739
return
3840
})
3941
}
40-
if edgeCount == 0 {
41-
return []int{}, true
42-
}
4342

4443
// Find a starting point with neighbors.
45-
for v := 0; v < n && start == -1; v++ {
46-
if len(h[v]) > 0 {
47-
start = v
44+
if start == -1 {
45+
for v, neighbors := range h {
46+
if len(neighbors) > 0 {
47+
start = v
48+
break
49+
}
4850
}
4951
}
5052

51-
stack := []int{start}
52-
for len(stack) > 0 {
53-
v := stack[len(stack)-1]
54-
stack = stack[:len(stack)-1]
53+
for stack := []int{start}; len(stack) > 0; {
54+
n := len(stack)
55+
v := stack[n-1]
56+
stack = stack[:n-1]
5557
for len(h[v]) > 0 {
5658
stack = append(stack, v)
5759
v, h[v] = h[v][0], h[v][1:]
5860
edgeCount--
5961
}
6062
walk = append(walk, v)
6163
}
62-
63-
if edgeCount != 0 {
64+
if edgeCount > 0 {
6465
return []int{}, false
6566
}
66-
6767
for i, j := 0, len(walk)-1; i < j; i, j = i+1, j-1 {
6868
walk[i], walk[j] = walk[j], walk[i]
6969
}
@@ -75,16 +75,20 @@ func EulerDirected(g Iterator) (walk []int, ok bool) {
7575
// and sets ok to false.
7676
func EulerUndirected(g Iterator) (walk []int, ok bool) {
7777
n := g.Order()
78-
// Compute outdegree for each vertex.
79-
out := make([]int, n)
78+
out := make([]int, n) // outdegree for each vertex
79+
edgeCount := 0
8080
for v := range out {
8181
g.Visit(v, func(w int, _ int64) (skip bool) {
82+
edgeCount++
8283
if v != w {
8384
out[v]++
8485
}
8586
return
8687
})
8788
}
89+
if edgeCount == 0 {
90+
return []int{}, true
91+
}
8892

8993
start, oddDeg := -1, 0
9094
for v := range out {
@@ -97,52 +101,40 @@ func EulerUndirected(g Iterator) (walk []int, ok bool) {
97101
return []int{}, false
98102
}
99103

100-
// Make a copy of g.
101-
edgeCount := 0
102-
h := New(n)
103-
for v := 0; v < n; v++ {
104-
g.Visit(v, func(w int, _ int64) (skip bool) {
105-
h.Add(v, w)
106-
edgeCount++
107-
return
108-
})
109-
}
110-
if edgeCount == 0 {
111-
return []int{}, true
112-
}
113-
114104
// Find a starting point with neighbors.
115-
for v := 0; v < n && start == -1; v++ {
116-
h.Visit(v, func(w int, _ int64) (skip bool) {
117-
start = w
118-
return true
119-
})
105+
if start == -1 {
106+
for v := 0; v < n; v++ {
107+
if g.Visit(v, func(w int, _ int64) (skip bool) {
108+
start = w
109+
return true
110+
}) {
111+
break
112+
}
113+
}
120114
}
121115

122-
stack := []int{start}
123-
for len(stack) > 0 {
124-
v := stack[len(stack)-1]
125-
stack = stack[:len(stack)-1]
116+
h := Copy(g)
117+
for stack := []int{start}; len(stack) > 0; {
118+
n := len(stack)
119+
v := stack[n-1]
120+
stack = stack[:n-1]
126121
for h.Degree(v) > 0 {
127122
stack = append(stack, v)
128123
var w int
129124
h.Visit(v, func(u int, _ int64) (skip bool) {
130125
w = u
131126
return true
132127
})
128+
h.DeleteBoth(v, w)
129+
edgeCount--
133130
if v != w {
134-
h.DeleteBoth(v, w)
135-
edgeCount -= 2
136-
} else {
137-
h.Delete(v, v)
138131
edgeCount--
139132
}
140133
v = w
141134
}
142135
walk = append(walk, v)
143136
}
144-
145-
if edgeCount != 0 {
137+
if edgeCount > 0 {
146138
return []int{}, false
147139
}
148140
return walk, true

example_dfs_test.go

+1-2
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,7 @@ func (d *DFSData) dfsVisit(g graph.Iterator, v int) {
6464
d.Finish[v] = d.Time
6565
}
6666

67-
// An implementation of depth-first search
68-
// demonstrating how to use this package.
67+
// Show how to use this package by implementing a complete depth-first search.
6968
func Example_dFS() {
7069
// Build a small directed graph:
7170
//

examples_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import (
55
"github.com/yourbasic/graph"
66
)
77

8-
// How to iterate over the edges of a graph.
8+
// Build a plain graph and visit all of its edges.
99
func Example_basics() {
1010
// Build a graph with four vertices and four undirected edges.
1111
// (Each of these edges are, in fact, represented by two directed

graph.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,12 @@
3636
// by composing and filtering a set of standard graphs, or by writing
3737
// functions that describe the edges of a graph.
3838
//
39-
// Example usage
39+
// Tutorial
4040
//
41-
// The package examples show how to build plain graphs and how to efficiently
42-
// use the Visit iterator, the vital abstraction of this package.
41+
// The Basics example shows how to build a plain graph and how to
42+
// efficiently use the Visit iterator, the key abstraction of this package.
43+
//
44+
// The DFS example contains a full implementation of depth-first search.
4345
//
4446
package graph
4547

@@ -63,7 +65,7 @@ type Iterator interface {
6365
// • The calls to the do function may occur in any order,
6466
// and the order may vary.
6567
//
66-
Visit(v int, Do func(w int, c int64) (skip bool)) (aborted bool)
68+
Visit(v int, do func(w int, c int64) (skip bool)) (aborted bool)
6769
}
6870

6971
// The maximum and minum value of an edge cost.

0 commit comments

Comments
 (0)