forked from soniakeys/graph
-
Notifications
You must be signed in to change notification settings - Fork 0
/
adj_RO.go
445 lines (419 loc) · 12.7 KB
/
adj_RO.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
// Copyright 2014 Sonia Keys
// License MIT: http://opensource.org/licenses/MIT
package graph
// adj_RO.go is code generated from adj_cg.go by directives in graph.go.
// Editing adj_cg.go is okay.
// DO NOT EDIT adj_RO.go. The RO is for Read Only.
import (
"errors"
"fmt"
"math/rand"
"github.com/soniakeys/bits"
)
// ArcDensity returns density for an simple directed graph.
//
// See also ArcDensity function.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ArcDensity() float64 {
return ArcDensity(len(g), g.ArcSize())
}
// ArcSize returns the number of arcs in g.
//
// Note that for an undirected graph without loops, the number of undirected
// edges -- the traditional meaning of graph size -- will be ArcSize()/2.
// On the other hand, if g is an undirected graph that has or may have loops,
// g.ArcSize()/2 is not a meaningful quantity.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ArcSize() int {
m := 0
for _, to := range g {
m += len(to)
}
return m
}
// BoundsOk validates that all arcs in g stay within the slice bounds of g.
//
// BoundsOk returns true when no arcs point outside the bounds of g.
// Otherwise it returns false and an example arc that points outside of g.
//
// Most methods of this package assume the BoundsOk condition and may
// panic when they encounter an arc pointing outside of the graph. This
// function can be used to validate a graph when the BoundsOk condition
// is unknown.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) BoundsOk() (ok bool, fr NI, to NI) {
for fr, to := range g {
for _, to := range to {
if to < 0 || to >= NI(len(g)) {
return false, NI(fr), to
}
}
}
return true, -1, to
}
// BreadthFirst traverses a directed or undirected graph in breadth
// first order.
//
// Traversal starts at node start and visits the nodes reachable from
// start. The function visit is called for each node visited. Nodes
// not reachable from start are not visited.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also alt.BreadthFirst, a variant with more options, and
// alt.BreadthFirst2, a direction optimizing variant.
func (g AdjacencyList) BreadthFirst(start NI, visit func(NI)) {
v := bits.New(len(g))
v.SetBit(int(start), 1)
visit(start)
var next []NI
for frontier := []NI{start}; len(frontier) > 0; {
for _, n := range frontier {
for _, nb := range g[n] {
if v.Bit(int(nb)) == 0 {
v.SetBit(int(nb), 1)
visit(nb)
next = append(next, nb)
}
}
}
frontier, next = next, frontier[:0]
}
}
// Copy makes a deep copy of g.
// Copy also computes the arc size ma, the number of arcs.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Copy() (c AdjacencyList, ma int) {
c = make(AdjacencyList, len(g))
for n, to := range g {
c[n] = append([]NI{}, to...)
ma += len(to)
}
return
}
// DepthFirst traverses a directed or undirected graph in depth
// first order.
//
// Traversal starts at node start and visits the nodes reachable from
// start. The function visit is called for each node visited. Nodes
// not reachable from start are not visited.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also alt.DepthFirst, a variant with more options.
func (g AdjacencyList) DepthFirst(start NI, visit func(NI)) {
v := bits.New(len(g))
var f func(NI)
f = func(n NI) {
visit(n)
v.SetBit(int(n), 1)
for _, to := range g[n] {
if v.Bit(int(to)) == 0 {
f(to)
}
}
}
f(start)
}
// Equal compares two graphs for equality.
//
// Note this is simple equality, not isomorphism. Graphs are equal if
// they have the same order and if corresponding nodes have the same
// arcs, although they do not need to be in the same order.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Equal(h AdjacencyList) bool {
if len(g) != len(h) {
return false
}
for n, gn := range g {
m := map[NI]int{}
for _, to := range gn {
m[to]++
}
for _, to := range h[n] {
m[to]--
}
for _, c := range m {
if c != 0 {
return false
}
}
}
return true
}
// HasArc returns true if g has any arc from node `fr` to node `to`.
//
// Also returned is the index within the slice of arcs from node `fr`.
// If no arc from `fr` to `to` is present, HasArc returns false, -1.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also the method ParallelArcs, which finds all parallel arcs from
// `fr` to `to`.
func (g AdjacencyList) HasArc(fr, to NI) (bool, int) {
for x, h := range g[fr] {
if h == to {
return true, x
}
}
return false, -1
}
// AnyLoop identifies if a graph contains a loop, an arc that leads from a
// a node back to the same node.
//
// If g contains a loop, the method returns true and an example of a node
// with a loop. If there are no loops in g, the method returns false, -1.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) AnyLoop() (bool, NI) {
for fr, to := range g {
for _, to := range to {
if NI(fr) == to {
return true, to
}
}
}
return false, -1
}
// AddNode maps a node in a supergraph to a subgraph node.
//
// Argument p must be an NI in supergraph s.Super. AddNode panics if
// p is not a valid node index of s.Super.
//
// AddNode is idempotent in that it does not add a new node to the subgraph if
// a subgraph node already exists mapped to supergraph node p.
//
// The mapped subgraph NI is returned.
func (s *Subgraph) AddNode(p NI) (b NI) {
if int(p) < 0 || int(p) >= s.Super.Order() {
panic(fmt.Sprint("AddNode: NI ", p, " not in supergraph"))
}
if b, ok := s.SubNI[p]; ok {
return b
}
a := s.AdjacencyList
b = NI(len(a))
s.AdjacencyList = append(a, nil)
s.SuperNI = append(s.SuperNI, p)
s.SubNI[p] = b
return
}
// AddArc adds an arc to a subgraph.
//
// Arguments fr, to must be NIs in supergraph s.Super. As with AddNode,
// AddArc panics if fr and to are not valid node indexes of s.Super.
//
// The arc specfied by fr, to must exist in s.Super. Further, the number of
// parallel arcs in the subgraph cannot exceed the number of corresponding
// parallel arcs in the supergraph. That is, each arc already added to the
// subgraph counts against the arcs available in the supergraph. If a matching
// arc is not available, AddArc returns an error.
//
// If a matching arc is available, subgraph nodes are added as needed, the
// subgraph arc is added, and the method returns nil.
func (s *Subgraph) AddArc(fr NI, to NI) error {
// verify supergraph NIs first, but without adding subgraph nodes just yet.
if int(fr) < 0 || int(fr) >= s.Super.Order() {
panic(fmt.Sprint("AddArc: NI ", fr, " not in supergraph"))
}
if int(to) < 0 || int(to) >= s.Super.Order() {
panic(fmt.Sprint("AddArc: NI ", to, " not in supergraph"))
}
// count existing matching arcs in subgraph
n := 0
a := s.AdjacencyList
if bf, ok := s.SubNI[fr]; ok {
if bt, ok := s.SubNI[to]; ok {
// both NIs already exist in subgraph, need to count arcs
bTo := to
bTo = bt
for _, t := range a[bf] {
if t == bTo {
n++
}
}
}
}
// verify matching arcs are available in supergraph
for _, t := range (*s.Super)[fr] {
if t == to {
if n > 0 {
n-- // match existing arc
continue
}
// no more existing arcs need to be matched. nodes can finally
// be added as needed and then the arc can be added.
bf := s.AddNode(fr)
to = s.AddNode(to)
s.AdjacencyList[bf] = append(s.AdjacencyList[bf], to)
return nil // success
}
}
return errors.New("arc not available in supergraph")
}
func (super AdjacencyList) induceArcs(sub map[NI]NI, sup []NI) AdjacencyList {
s := make(AdjacencyList, len(sup))
for b, p := range sup {
var a []NI
for _, to := range super[p] {
if bt, ok := sub[to]; ok {
to = bt
a = append(a, to)
}
}
s[b] = a
}
return s
}
// InduceList constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g. Argument l must be a list of
// NIs in receiver graph g. Receiver g becomes the supergraph of the induced
// subgraph.
//
// Duplicate NIs are allowed in list l. The duplicates are effectively removed
// and only a single corresponding node is created in the subgraph. Subgraph
// NIs are mapped in the order of list l, execpt for ignoring duplicates.
// NIs in l that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *AdjacencyList) InduceList(l []NI) *Subgraph {
sub, sup := mapList(l)
return &Subgraph{
Super: g,
SubNI: sub,
SuperNI: sup,
AdjacencyList: g.induceArcs(sub, sup)}
}
// InduceBits constructs a node-induced subgraph.
//
// The subgraph is induced on receiver graph g. Argument t must be a bitmap
// representing NIs in receiver graph g. Receiver g becomes the supergraph
// of the induced subgraph. NIs in t that are not in g will panic.
//
// Returned is the constructed Subgraph object containing the induced subgraph
// and the mappings to the supergraph.
func (g *AdjacencyList) InduceBits(t bits.Bits) *Subgraph {
sub, sup := mapBits(t)
return &Subgraph{
Super: g,
SubNI: sub,
SuperNI: sup,
AdjacencyList: g.induceArcs(sub, sup)}
}
// IsSimple checks for loops and parallel arcs.
//
// A graph is "simple" if it has no loops or parallel arcs.
//
// IsSimple returns true, -1 for simple graphs. If a loop or parallel arc is
// found, simple returns false and a node that represents a counterexample
// to the graph being simple.
//
// See also separate methods AnyLoop and AnyParallel.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) IsSimple() (ok bool, n NI) {
if lp, n := g.AnyLoop(); lp {
return false, n
}
if pa, n, _ := g.AnyParallel(); pa {
return false, n
}
return true, -1
}
// IsolatedNodes returns a bitmap of isolated nodes in receiver graph g.
//
// An isolated node is one with no arcs going to or from it.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) IsolatedNodes() (i bits.Bits) {
i = bits.New(len(g))
i.SetAll()
for fr, to := range g {
if len(to) > 0 {
i.SetBit(fr, 0)
for _, to := range to {
i.SetBit(int(to), 0)
}
}
}
return
}
// Order is the number of nodes in receiver g.
//
// It is simply a wrapper method for the Go builtin len().
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Order() int {
// Why a wrapper for len()? Mostly for Directed and Undirected.
// u.Order() is a little nicer than len(u.LabeledAdjacencyList).
return len(g)
}
// ParallelArcs identifies all arcs from node `fr` to node `to`.
//
// The returned slice contains an element for each arc from node `fr` to node `to`.
// The element value is the index within the slice of arcs from node `fr`.
//
// There are equivalent labeled and unlabeled versions of this method.
//
// See also the method HasArc, which stops after finding a single arc.
func (g AdjacencyList) ParallelArcs(fr, to NI) (p []int) {
for x, h := range g[fr] {
if h == to {
p = append(p, x)
}
}
return
}
// Permute permutes the node labeling of receiver g.
//
// Argument p must be a permutation of the node numbers of the graph,
// 0 through len(g)-1. A permutation returned by rand.Perm(len(g)) for
// example is acceptable.
//
// The graph is permuted in place. The graph keeps the same underlying
// memory but values of the graph representation are permuted to produce
// an isomorphic graph. The node previously labeled 0 becomes p[0] and so on.
// See example (or the code) for clarification.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) Permute(p []int) {
old := append(AdjacencyList{}, g...) // shallow copy
for fr, arcs := range old {
for i, to := range arcs {
arcs[i] = NI(p[to])
}
g[p[fr]] = arcs
}
}
// ShuffleArcLists shuffles the arc lists of each node of receiver g.
//
// For example a node with arcs leading to nodes 3 and 7 might have an
// arc list of either [3 7] or [7 3] after calling this method. The
// connectivity of the graph is not changed. The resulting graph stays
// equivalent but a traversal will encounter arcs in a different
// order.
//
// If Rand r is nil, the rand package default shared source is used.
//
// There are equivalent labeled and unlabeled versions of this method.
func (g AdjacencyList) ShuffleArcLists(r *rand.Rand) {
ri := rand.Intn
if r != nil {
ri = r.Intn
}
// Knuth-Fisher-Yates
for _, to := range g {
for i := len(to); i > 1; {
j := ri(i)
i--
to[i], to[j] = to[j], to[i]
}
}
}