Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/base/c_graph.pyx
8815 views
1
"""
2
Fast compiled graphs
3
4
This is a Cython implementation of the base class for sparse and dense graphs
5
in Sage. It is not intended for use on its own. Specific graph types should
6
extend this base class and implement missing functionalities. Whenever
7
possible, specific methods should also be overridden with implementations that
8
suit the graph type under consideration.
9
10
11
Data structure
12
--------------
13
14
The class ``CGraph`` maintains the following variables:
15
16
- ``cdef int num_verts``
17
- ``cdef int num_arcs``
18
- ``cdef int *in_degrees``
19
- ``cdef int *out_degrees``
20
- ``cdef bitset_t active_vertices``
21
22
The bitset ``active_vertices`` is a list of all available vertices for use, but
23
only the ones which are set are considered to actually be in the graph. The
24
variables ``num_verts`` and ``num_arcs`` are self-explanatory. Note that
25
``num_verts`` is the number of bits set in ``active_vertices``, not the full
26
length of the bitset. The arrays ``in_degrees`` and ``out_degrees`` are of the
27
same length as the bitset.
28
29
For more information about active vertices, see the documentation for the
30
method :meth:`realloc <sage.graphs.base.c_graph.CGraph.realloc>`.
31
"""
32
33
#**************************************************************************
34
# Copyright (C) 2008-9 Robert L. Miller <[email protected]>
35
#
36
# Distributed under the terms of the GNU General Public License (GPL)
37
# http://www.gnu.org/licenses/
38
#**************************************************************************
39
40
include "sage/misc/bitset.pxi"
41
42
from graph_backends import GenericGraphBackend
43
from sage.rings.integer cimport Integer
44
45
cdef class CGraph:
46
"""
47
Compiled sparse and dense graphs.
48
"""
49
50
###################################
51
# Vertex Functions
52
###################################
53
54
cpdef bint has_vertex(self, int n):
55
"""
56
Determine whether the vertex ``n`` is in ``self``.
57
58
This method is different from :meth:`check_vertex`. The current method
59
returns a boolean to signify whether or not ``n`` is a vertex of this
60
graph. On the other hand, :meth:`check_vertex` raises an error if
61
``n`` is not a vertex of this graph.
62
63
INPUT:
64
65
- ``n`` -- a nonnegative integer representing a vertex.
66
67
OUTPUT:
68
69
- ``True`` if ``n`` is a vertex of this graph; ``False`` otherwise.
70
71
.. SEEALSO::
72
73
- :meth:`check_vertex`
74
-- raise an error if this graph does not contain a specific
75
vertex.
76
77
EXAMPLES:
78
79
Upon initialization, a
80
:class:`SparseGraph <sage.graphs.base.sparse_graph.SparseGraph>`
81
or
82
:class:`DenseGraph <sage.graphs.base.dense_graph.DenseGraph>`
83
has the first ``nverts`` vertices::
84
85
sage: from sage.graphs.base.sparse_graph import SparseGraph
86
sage: S = SparseGraph(nverts=10, expected_degree=3, extra_vertices=10)
87
sage: S.has_vertex(6)
88
True
89
sage: S.has_vertex(12)
90
False
91
sage: S.has_vertex(24)
92
False
93
sage: S.has_vertex(-19)
94
False
95
96
::
97
98
sage: from sage.graphs.base.dense_graph import DenseGraph
99
sage: D = DenseGraph(nverts=10, extra_vertices=10)
100
sage: D.has_vertex(6)
101
True
102
sage: D.has_vertex(12)
103
False
104
sage: D.has_vertex(24)
105
False
106
sage: D.has_vertex(-19)
107
False
108
"""
109
return (n >= 0 and
110
n < self.active_vertices.size and
111
bitset_in(self.active_vertices, n))
112
113
cpdef check_vertex(self, int n):
114
"""
115
Checks that ``n`` is a vertex of ``self``.
116
117
This method is different from :meth:`has_vertex`. The current method
118
raises an error if ``n`` is not a vertex of this graph. On the other
119
hand, :meth:`has_vertex` returns a boolean to signify whether or not
120
``n`` is a vertex of this graph.
121
122
INPUT:
123
124
- ``n`` -- a nonnegative integer representing a vertex.
125
126
OUTPUT:
127
128
- Raise an error if ``n`` is not a vertex of this graph.
129
130
.. SEEALSO::
131
132
- :meth:`has_vertex`
133
-- determine whether this graph has a specific vertex.
134
135
EXAMPLES::
136
137
sage: from sage.graphs.base.sparse_graph import SparseGraph
138
sage: S = SparseGraph(nverts=10, expected_degree=3, extra_vertices=10)
139
sage: S.check_vertex(4)
140
sage: S.check_vertex(12)
141
Traceback (most recent call last):
142
...
143
LookupError: Vertex (12) is not a vertex of the graph.
144
sage: S.check_vertex(24)
145
Traceback (most recent call last):
146
...
147
LookupError: Vertex (24) is not a vertex of the graph.
148
sage: S.check_vertex(-19)
149
Traceback (most recent call last):
150
...
151
LookupError: Vertex (-19) is not a vertex of the graph.
152
153
::
154
155
sage: from sage.graphs.base.dense_graph import DenseGraph
156
sage: D = DenseGraph(nverts=10, extra_vertices=10)
157
sage: D.check_vertex(4)
158
sage: D.check_vertex(12)
159
Traceback (most recent call last):
160
...
161
LookupError: Vertex (12) is not a vertex of the graph.
162
sage: D.check_vertex(24)
163
Traceback (most recent call last):
164
...
165
LookupError: Vertex (24) is not a vertex of the graph.
166
sage: D.check_vertex(-19)
167
Traceback (most recent call last):
168
...
169
LookupError: Vertex (-19) is not a vertex of the graph.
170
"""
171
if not self.has_vertex(n):
172
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(n))
173
174
cdef int add_vertex_unsafe(self, int k):
175
"""
176
Adds the vertex ``k`` to the graph.
177
178
INPUT:
179
180
- ``k`` -- nonnegative integer or ``-1``. For `k >= 0`, add the
181
vertex ``k`` to this graph if the vertex is not already in the graph.
182
If `k = -1`, this function will find the first available vertex
183
that is not in ``self`` and add that vertex to this graph.
184
185
OUTPUT:
186
187
- ``-1`` -- indicates that no vertex was added because the current
188
allocation is already full or the vertex is out of range.
189
190
- nonnegative integer -- this vertex is now guaranteed to be in the
191
graph.
192
193
.. WARNING::
194
195
This method is potentially unsafe. You should instead use
196
:meth:`add_vertex`.
197
"""
198
if k == -1:
199
k = bitset_first_in_complement(self.active_vertices)
200
elif self.active_vertices.size <= k:
201
k = -1
202
if k != -1:
203
if not bitset_in(self.active_vertices, k):
204
self.num_verts += 1
205
bitset_add(self.active_vertices, k)
206
return k
207
208
def add_vertex(self, int k=-1):
209
"""
210
Adds vertex ``k`` to the graph.
211
212
INPUT:
213
214
- ``k`` -- nonnegative integer or ``-1`` (default: ``-1``). If
215
`k = -1`, a new vertex is added and the integer used is returned.
216
That is, for `k = -1`, this function will find the first available
217
vertex that is not in ``self`` and add that vertex to this graph.
218
219
OUTPUT:
220
221
- ``-1`` -- indicates that no vertex was added because the current
222
allocation is already full or the vertex is out of range.
223
224
- nonnegative integer -- this vertex is now guaranteed to be in the
225
graph.
226
227
.. SEEALSO::
228
229
- ``add_vertex_unsafe`` -- add a vertex to a graph. This
230
method is potentially unsafe. You should instead use
231
:meth:`add_vertex`.
232
233
- ``add_vertices`` -- add a bunch of vertices to a graph.
234
235
EXAMPLES:
236
237
Adding vertices to a sparse graph::
238
239
sage: from sage.graphs.base.sparse_graph import SparseGraph
240
sage: G = SparseGraph(3, extra_vertices=3)
241
sage: G.add_vertex(3)
242
3
243
sage: G.add_arc(2, 5)
244
Traceback (most recent call last):
245
...
246
LookupError: Vertex (5) is not a vertex of the graph.
247
sage: G.add_arc(1, 3)
248
sage: G.has_arc(1, 3)
249
True
250
sage: G.has_arc(2, 3)
251
False
252
253
Adding vertices to a dense graph::
254
255
sage: from sage.graphs.base.dense_graph import DenseGraph
256
sage: G = DenseGraph(3, extra_vertices=3)
257
sage: G.add_vertex(3)
258
3
259
sage: G.add_arc(2,5)
260
Traceback (most recent call last):
261
...
262
LookupError: Vertex (5) is not a vertex of the graph.
263
sage: G.add_arc(1, 3)
264
sage: G.has_arc(1, 3)
265
True
266
sage: G.has_arc(2, 3)
267
False
268
269
Repeatedly adding a vertex using `k = -1` will allocate more memory
270
as required::
271
272
sage: from sage.graphs.base.sparse_graph import SparseGraph
273
sage: G = SparseGraph(3, extra_vertices=0)
274
sage: G.verts()
275
[0, 1, 2]
276
sage: for i in range(10):
277
... _ = G.add_vertex(-1);
278
...
279
sage: G.verts()
280
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
281
282
::
283
284
sage: from sage.graphs.base.dense_graph import DenseGraph
285
sage: G = DenseGraph(3, extra_vertices=0)
286
sage: G.verts()
287
[0, 1, 2]
288
sage: for i in range(12):
289
... _ = G.add_vertex(-1);
290
...
291
sage: G.verts()
292
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
293
294
TESTS::
295
296
sage: from sage.graphs.base.sparse_graph import SparseGraph
297
sage: G = SparseGraph(3, extra_vertices=0)
298
sage: G.add_vertex(6)
299
Traceback (most recent call last):
300
...
301
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
302
303
::
304
305
sage: from sage.graphs.base.dense_graph import DenseGraph
306
sage: G = DenseGraph(3, extra_vertices=0)
307
sage: G.add_vertex(6)
308
Traceback (most recent call last):
309
...
310
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
311
"""
312
if k >= (2 * self.active_vertices.size):
313
raise RuntimeError(
314
"Requested vertex is past twice the allocated range: "
315
"use realloc.")
316
if (k >= self.active_vertices.size or
317
(k == -1 and self.active_vertices.size == self.num_verts)):
318
self.realloc(2 * self.active_vertices.size)
319
return self.add_vertex_unsafe(k)
320
321
cpdef add_vertices(self, object verts):
322
"""
323
Adds vertices from the iterable ``verts``.
324
325
INPUT:
326
327
- ``verts`` -- an iterable of vertices. Value -1 has a special
328
meaning -- for each such value an unused vertex name is found,
329
used to create a new vertex and returned.
330
331
OUTPUT:
332
333
List of generated labels if there is any -1 in ``verts``.
334
None otherwise.
335
336
.. SEEALSO::
337
338
- :meth:`add_vertex`
339
-- add a vertex to a graph.
340
341
EXAMPLE:
342
343
Adding vertices for sparse graphs::
344
345
sage: from sage.graphs.base.sparse_graph import SparseGraph
346
sage: S = SparseGraph(nverts=4, extra_vertices=4)
347
sage: S.verts()
348
[0, 1, 2, 3]
349
sage: S.add_vertices([3,-1,4,9])
350
[5]
351
sage: S.verts()
352
[0, 1, 2, 3, 4, 5, 9]
353
sage: S.realloc(20)
354
sage: S.verts()
355
[0, 1, 2, 3, 4, 5, 9]
356
357
Adding vertices for dense graphs::
358
359
sage: from sage.graphs.base.dense_graph import DenseGraph
360
sage: D = DenseGraph(nverts=4, extra_vertices=4)
361
sage: D.verts()
362
[0, 1, 2, 3]
363
sage: D.add_vertices([3,-1,4,9])
364
[5]
365
sage: D.verts()
366
[0, 1, 2, 3, 4, 5, 9]
367
sage: D.realloc(20)
368
sage: D.verts()
369
[0, 1, 2, 3, 4, 5, 9]
370
"""
371
cdef int v
372
cdef int nones = 0
373
for v in verts:
374
if v > -1:
375
self.add_vertex(v)
376
else:
377
nones += 1
378
379
new_names = []
380
while nones > 0:
381
new_names.append(self.add_vertex())
382
nones -= 1
383
384
return new_names if new_names != [] else None
385
386
cdef int del_vertex_unsafe(self, int v):
387
"""
388
Deletes the vertex ``v``, along with all edges incident to it.
389
390
INPUT:
391
392
- ``v`` -- nonnegative integer representing a vertex.
393
394
OUTPUT:
395
396
- None.
397
398
.. WARNING::
399
400
This method is potentially unsafe. Use :meth:`del_vertex` instead.
401
"""
402
cdef int size = 0
403
cdef int num_nbrs
404
cdef int i
405
cdef int *neighbors
406
if self.in_degrees[v] > size:
407
size = self.in_degrees[v]
408
if self.out_degrees[v] > size:
409
size = self.out_degrees[v]
410
if size > 0:
411
neighbors = <int *> sage_malloc(size * sizeof(int))
412
if not neighbors:
413
raise RuntimeError("Failure allocating memory.")
414
# delete each arc incident with v
415
num_nbrs = self.in_neighbors_unsafe(v, neighbors, size)
416
for i from 0 <= i < num_nbrs:
417
self.del_arc_unsafe(neighbors[i], v)
418
num_nbrs = self.out_neighbors_unsafe(v, neighbors, size)
419
for i from 0 <= i < num_nbrs:
420
self.del_arc_unsafe(v, neighbors[i])
421
sage_free(neighbors)
422
423
self.num_verts -= 1
424
bitset_remove(self.active_vertices, v)
425
426
cpdef del_vertex(self, int v):
427
"""
428
Deletes the vertex ``v``, along with all edges incident to it. If ``v``
429
is not in ``self``, fails silently.
430
431
INPUT:
432
433
- ``v`` -- a nonnegative integer representing a vertex.
434
435
OUTPUT:
436
437
- None.
438
439
.. SEEALSO::
440
441
- ``del_vertex_unsafe`` -- delete a vertex from a graph. This method
442
is potentially unsafe. Use :meth:`del_vertex` instead.
443
444
EXAMPLES:
445
446
Deleting vertices of sparse graphs::
447
448
sage: from sage.graphs.base.sparse_graph import SparseGraph
449
sage: G = SparseGraph(3)
450
sage: G.add_arc(0, 1)
451
sage: G.add_arc(0, 2)
452
sage: G.add_arc(1, 2)
453
sage: G.add_arc(2, 0)
454
sage: G.del_vertex(2)
455
sage: for i in range(2):
456
... for j in range(2):
457
... if G.has_arc(i, j):
458
... print i, j
459
0 1
460
sage: G = SparseGraph(3)
461
sage: G.add_arc(0, 1)
462
sage: G.add_arc(0, 2)
463
sage: G.add_arc(1, 2)
464
sage: G.add_arc(2, 0)
465
sage: G.del_vertex(1)
466
sage: for i in xrange(3):
467
... for j in xrange(3):
468
... if G.has_arc(i, j):
469
... print i, j
470
0 2
471
2 0
472
473
Deleting vertices of dense graphs::
474
475
sage: from sage.graphs.base.dense_graph import DenseGraph
476
sage: G = DenseGraph(4)
477
sage: G.add_arc(0, 1); G.add_arc(0, 2)
478
sage: G.add_arc(3, 1); G.add_arc(3, 2)
479
sage: G.add_arc(1, 2)
480
sage: G.verts()
481
[0, 1, 2, 3]
482
sage: G.del_vertex(3); G.verts()
483
[0, 1, 2]
484
sage: for i in range(3):
485
... for j in range(3):
486
... if G.has_arc(i, j):
487
... print i, j
488
...
489
0 1
490
0 2
491
1 2
492
493
If the vertex to be deleted is not in this graph, then fail silently::
494
495
sage: from sage.graphs.base.sparse_graph import SparseGraph
496
sage: G = SparseGraph(3)
497
sage: G.verts()
498
[0, 1, 2]
499
sage: G.has_vertex(3)
500
False
501
sage: G.del_vertex(3)
502
sage: G.verts()
503
[0, 1, 2]
504
505
::
506
507
sage: from sage.graphs.base.dense_graph import DenseGraph
508
sage: G = DenseGraph(5)
509
sage: G.verts()
510
[0, 1, 2, 3, 4]
511
sage: G.has_vertex(6)
512
False
513
sage: G.del_vertex(6)
514
sage: G.verts()
515
[0, 1, 2, 3, 4]
516
"""
517
if self.has_vertex(v):
518
self.del_vertex_unsafe(v)
519
520
cpdef int current_allocation(self):
521
"""
522
Report the number of vertices allocated.
523
524
INPUT:
525
526
- None.
527
528
OUTPUT:
529
530
- The number of vertices allocated. This number is usually different
531
from the order of a graph. We may have allocated enough memory for
532
a graph to hold `n > 0` vertices, but the order (actual number of
533
vertices) of the graph could be less than `n`.
534
535
EXAMPLES::
536
537
sage: from sage.graphs.base.sparse_graph import SparseGraph
538
sage: S = SparseGraph(nverts=4, extra_vertices=4)
539
sage: S.current_allocation()
540
8
541
sage: S.add_vertex(6)
542
6
543
sage: S.current_allocation()
544
8
545
sage: S.add_vertex(10)
546
10
547
sage: S.current_allocation()
548
16
549
sage: S.add_vertex(40)
550
Traceback (most recent call last):
551
...
552
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
553
sage: S.realloc(50)
554
sage: S.add_vertex(40)
555
40
556
sage: S.current_allocation()
557
50
558
sage: S.realloc(30)
559
-1
560
sage: S.current_allocation()
561
50
562
sage: S.del_vertex(40)
563
sage: S.realloc(30)
564
sage: S.current_allocation()
565
30
566
567
The actual number of vertices in a graph might be less than the
568
number of vertices allocated for the graph::
569
570
sage: from sage.graphs.base.dense_graph import DenseGraph
571
sage: G = DenseGraph(nverts=3, extra_vertices=2)
572
sage: order = len(G.verts())
573
sage: order
574
3
575
sage: G.current_allocation()
576
5
577
sage: order < G.current_allocation()
578
True
579
"""
580
return self.active_vertices.size
581
582
cpdef list verts(self):
583
"""
584
Returns a list of the vertices in ``self``.
585
586
INPUT:
587
588
- None.
589
590
OUTPUT:
591
592
- A list of all vertices in this graph.
593
594
EXAMPLE::
595
596
sage: from sage.graphs.base.sparse_graph import SparseGraph
597
sage: S = SparseGraph(nverts=4, extra_vertices=4)
598
sage: S.verts()
599
[0, 1, 2, 3]
600
sage: S.add_vertices([3,5,7,9])
601
sage: S.verts()
602
[0, 1, 2, 3, 5, 7, 9]
603
sage: S.realloc(20)
604
sage: S.verts()
605
[0, 1, 2, 3, 5, 7, 9]
606
607
::
608
609
sage: from sage.graphs.base.dense_graph import DenseGraph
610
sage: G = DenseGraph(3, extra_vertices=2)
611
sage: G.verts()
612
[0, 1, 2]
613
sage: G.del_vertex(0)
614
sage: G.verts()
615
[1, 2]
616
"""
617
cdef int i
618
return [i for i from 0 <= i < self.active_vertices.size
619
if bitset_in(self.active_vertices, i)]
620
621
cpdef realloc(self, int total):
622
"""
623
Reallocate the number of vertices to use, without actually adding any.
624
625
INPUT:
626
627
- ``total`` -- integer; the total size to make the array of vertices.
628
629
OUTPUT:
630
631
- Raise a ``NotImplementedError``. This method is not implemented in
632
this base class. A child class should provide a suitable
633
implementation.
634
635
.. SEEALSO::
636
637
- :meth:`realloc <sage.graphs.base.sparse_graph.SparseGraph.realloc>`
638
-- a ``realloc`` implementation for sparse graphs.
639
640
- :meth:`realloc <sage.graphs.base.dense_graph.DenseGraph.realloc>`
641
-- a ``realloc`` implementation for dense graphs.
642
643
EXAMPLES:
644
645
First, note that :meth:`realloc` is implemented for
646
:class:`SparseGraph <sage.graphs.base.sparse_graph.SparseGraph>`
647
and
648
:class:`DenseGraph <sage.graphs.base.dense_graph.DenseGraph>`
649
differently, and is not implemented at the
650
:class:`CGraph` level::
651
652
sage: from sage.graphs.base.c_graph import CGraph
653
sage: G = CGraph()
654
sage: G.realloc(20)
655
Traceback (most recent call last):
656
...
657
NotImplementedError
658
659
The ``realloc`` implementation for sparse graphs::
660
661
sage: from sage.graphs.base.sparse_graph import SparseGraph
662
sage: S = SparseGraph(nverts=4, extra_vertices=4)
663
sage: S.current_allocation()
664
8
665
sage: S.add_vertex(6)
666
6
667
sage: S.current_allocation()
668
8
669
sage: S.add_vertex(10)
670
10
671
sage: S.current_allocation()
672
16
673
sage: S.add_vertex(40)
674
Traceback (most recent call last):
675
...
676
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
677
sage: S.realloc(50)
678
sage: S.add_vertex(40)
679
40
680
sage: S.current_allocation()
681
50
682
sage: S.realloc(30)
683
-1
684
sage: S.current_allocation()
685
50
686
sage: S.del_vertex(40)
687
sage: S.realloc(30)
688
sage: S.current_allocation()
689
30
690
691
The ``realloc`` implementation for dense graphs::
692
693
sage: from sage.graphs.base.dense_graph import DenseGraph
694
sage: D = DenseGraph(nverts=4, extra_vertices=4)
695
sage: D.current_allocation()
696
8
697
sage: D.add_vertex(6)
698
6
699
sage: D.current_allocation()
700
8
701
sage: D.add_vertex(10)
702
10
703
sage: D.current_allocation()
704
16
705
sage: D.add_vertex(40)
706
Traceback (most recent call last):
707
...
708
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
709
sage: D.realloc(50)
710
sage: D.add_vertex(40)
711
40
712
sage: D.current_allocation()
713
50
714
sage: D.realloc(30)
715
-1
716
sage: D.current_allocation()
717
50
718
sage: D.del_vertex(40)
719
sage: D.realloc(30)
720
sage: D.current_allocation()
721
30
722
"""
723
raise NotImplementedError()
724
725
###################################
726
# Edge Functions
727
###################################
728
729
cdef int add_arc_unsafe(self, int u, int v) except? -1:
730
raise NotImplementedError()
731
732
cdef int has_arc_unsafe(self, int u, int v) except? -1:
733
raise NotImplementedError()
734
735
cdef int del_arc_unsafe(self, int u, int v) except? -1:
736
raise NotImplementedError()
737
738
cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except? -2:
739
raise NotImplementedError()
740
741
cdef int in_neighbors_unsafe(self, int u, int *neighbors, int size) except? -2:
742
raise NotImplementedError()
743
744
cpdef add_arc(self, int u, int v):
745
"""
746
Add the given arc to this graph.
747
748
INPUT:
749
750
- ``u`` -- integer; the tail of an arc.
751
752
- ``v`` -- integer; the head of an arc.
753
754
OUTPUT:
755
756
- Raise ``NotImplementedError``. This method is not implemented at
757
the :class:`CGraph` level. A child class should provide a suitable
758
implementation.
759
760
.. SEEALSO::
761
762
- :meth:`add_arc <sage.graphs.base.sparse_graph.SparseGraph.add_arc>`
763
-- ``add_arc`` method for sparse graphs.
764
765
- :meth:`add_arc <sage.graphs.base.dense_graph.DenseGraph.add_arc>`
766
-- ``add_arc`` method for dense graphs.
767
768
EXAMPLE::
769
770
sage: from sage.graphs.base.c_graph import CGraph
771
sage: G = CGraph()
772
sage: G.add_arc(0, 1)
773
Traceback (most recent call last):
774
...
775
NotImplementedError
776
"""
777
raise NotImplementedError()
778
779
cpdef bint has_arc(self, int u, int v) except -1:
780
"""
781
Determine whether or not the given arc is in this graph.
782
783
INPUT:
784
785
- ``u`` -- integer; the tail of an arc.
786
787
- ``v`` -- integer; the head of an arc.
788
789
OUTPUT:
790
791
- Print a ``Not Implemented!`` message. This method is not implemented
792
at the :class:`CGraph` level. A child class should provide a
793
suitable implementation.
794
795
.. SEEALSO::
796
797
- :meth:`has_arc <sage.graphs.base.sparse_graph.SparseGraph.has_arc>`
798
-- ``has_arc`` method for sparse graphs.
799
800
- :meth:`has_arc <sage.graphs.base.dense_graph.DenseGraph.has_arc>`
801
-- ``has_arc`` method for dense graphs.
802
803
EXAMPLE::
804
805
sage: from sage.graphs.base.c_graph import CGraph
806
sage: G = CGraph()
807
sage: G.has_arc(0, 1)
808
Not Implemented!
809
False
810
"""
811
# The following is due to a hard to reproduce bug in Cython where except,
812
# cpdef, and classes don't play well together:
813
print "Not Implemented!"
814
# raise NotImplementedError() ... results in:
815
# Exception exceptions.NotImplementedError: NotImplementedError() in 'sage.graphs.base.c_graph.CGraph.has_arc' ignored
816
# False
817
818
cpdef del_all_arcs(self, int u, int v):
819
"""
820
Delete all arcs from ``u`` to ``v``.
821
822
INPUT:
823
824
- ``u`` -- integer; the tail of an arc.
825
826
- ``v`` -- integer; the head of an arc.
827
828
OUTPUT:
829
830
- Raise ``NotImplementedError``. This method is not implemented at the
831
:class:`CGraph` level. A child class should provide a suitable
832
implementation.
833
834
.. SEEALSO::
835
836
- :meth:`del_all_arcs <sage.graphs.base.sparse_graph.SparseGraph.del_all_arcs>`
837
-- ``del_all_arcs`` method for sparse graphs.
838
839
- :meth:`del_all_arcs <sage.graphs.base.dense_graph.DenseGraph.del_all_arcs>`
840
-- ``del_all_arcs`` method for dense graphs.
841
842
EXAMPLE::
843
844
sage: from sage.graphs.base.c_graph import CGraph
845
sage: G = CGraph()
846
sage: G.del_all_arcs(0,1)
847
Traceback (most recent call last):
848
...
849
NotImplementedError
850
"""
851
raise NotImplementedError()
852
853
cdef adjacency_sequence_in(self, int n, int *vertices, int v, int* sequence):
854
r"""
855
Computes the adjacency sequence corresponding to a list of vertices
856
and a vertex.
857
858
This method fills the array ``sequence``, whose i-th element is set to
859
`1` iff ``(v,vertices[i])`` is an edge.
860
861
See the function ``_test_adjacency_sequence()`` of
862
``dense_graph.pyx`` and ``sparse_graph.pyx`` for unit tests.
863
864
INPUT:
865
866
- ``n`` -- nonnegative integer; the maximum index in
867
``vertices`` up to which we want to consider. If ``n = 0``,
868
we only want to know if ``(vertices[0],v)`` is an edge. If
869
``n = 1``, we want to know whether ``(vertices[0],v)`` and
870
``(vertices[1],v)`` are edges. Let ``k`` be the length of
871
``vertices``. If ``0 <= n < k``, then we want to know if
872
``v`` is adjacent to each of ``vertices[0], vertices[1],
873
..., vertices[n]``. Where ``n = k - 1``, then we consider
874
all elements in the list ``vertices``.
875
876
- ``vertices`` -- list of vertices.
877
878
- ``v`` -- a vertex.
879
880
- ``sequence`` (int *) -- the memory segment of length `>= n` that is to
881
be filled.
882
883
.. SEEALSO::
884
885
- :meth:`adjacency_sequence_out` -- Similar method for
886
``(v, vertices[i])`` instead of ``(vertices[i], v)`` (the
887
difference only matters for digraphs).
888
"""
889
cdef int i = 0
890
for 0 <= i < n:
891
sequence[i] = self.has_arc_unsafe(vertices[i], v)
892
893
cdef adjacency_sequence_out(self, int n, int *vertices, int v, int* sequence):
894
r"""
895
Returns the adjacency sequence corresponding to a list of vertices
896
and a vertex.
897
898
This method fills the array ``sequence``, whose i-th element is set to
899
`1` iff ``(v,vertices[i])`` is an edge.
900
901
See the function ``_test_adjacency_sequence()`` of
902
``dense_graph.pyx`` and ``sparse_graph.pyx`` for unit tests.
903
904
INPUT:
905
906
- ``n`` -- nonnegative integer; the maximum index in
907
``vertices`` up to which we want to consider. If ``n = 0``,
908
we only want to know if ``(v, vertices[0])`` is an edge. If
909
``n = 1``, we want to know whether ``(v, vertices[0])`` and
910
``(v, vertices[1])`` are edges. Let ``k`` be the length of
911
``vertices``. If ``0 <= n < k``, then we want to know if
912
each of ``vertices[0], vertices[1], ..., vertices[n]`` is
913
adjacent to ``v``. Where ``n = k - 1``, then we consider all
914
elements in the list ``vertices``.
915
916
- ``vertices`` -- list of vertices.
917
918
- ``v`` -- a vertex.
919
920
- ``sequence`` (int *) -- the memory segment of length `>= n` that is to
921
be filled.
922
923
.. SEEALSO::
924
925
- :meth:`adjacency_sequence_in` -- Similar method for
926
``(vertices[i],v)`` instead of ``(v,vertices[i])`` (the
927
difference only matters for digraphs).
928
929
"""
930
cdef int i = 0
931
for 0 <= i < n:
932
sequence[i] = self.has_arc_unsafe(v, vertices[i])
933
934
cpdef list all_arcs(self, int u, int v):
935
"""
936
Return the labels of all arcs from ``u`` to ``v``.
937
938
INPUT:
939
940
- ``u`` -- integer; the tail of an arc.
941
942
- ``v`` -- integer; the head of an arc.
943
944
OUTPUT:
945
946
- Raise ``NotImplementedError``. This method is not implemented at the
947
:class:`CGraph` level. A child class should provide a suitable
948
implementation.
949
950
.. SEEALSO::
951
952
- :meth:`all_arcs <sage.graphs.base.sparse_graph.SparseGraph.all_arcs>`
953
-- ``all_arcs`` method for sparse graphs.
954
955
EXAMPLE::
956
957
sage: from sage.graphs.base.c_graph import CGraph
958
sage: G = CGraph()
959
sage: G.all_arcs(0, 1)
960
Traceback (most recent call last):
961
...
962
NotImplementedError
963
"""
964
raise NotImplementedError()
965
966
cpdef list in_neighbors(self, int v):
967
"""
968
Gives the in-neighbors of the vertex ``v``.
969
970
INPUT:
971
972
- ``v`` -- integer representing a vertex of this graph.
973
974
OUTPUT:
975
976
- Raise ``NotImplementedError``. This method is not implemented at
977
the :class:`CGraph` level. A child class should provide a suitable
978
implementation.
979
980
.. SEEALSO::
981
982
- :meth:`in_neighbors <sage.graphs.base.sparse_graph.SparseGraph.in_neighbors>`
983
-- ``in_neighbors`` method for sparse graphs.
984
985
- :meth:`in_neighbors <sage.graphs.base.dense_graph.DenseGraph.in_neighbors>`
986
-- ``in_neighbors`` method for dense graphs.
987
988
EXAMPLE::
989
990
sage: from sage.graphs.base.c_graph import CGraph
991
sage: G = CGraph()
992
sage: G.in_neighbors(0)
993
Traceback (most recent call last):
994
...
995
NotImplementedError
996
"""
997
raise NotImplementedError()
998
999
cpdef list out_neighbors(self, int u):
1000
"""
1001
Gives the out-neighbors of the vertex ``u``.
1002
1003
INPUT:
1004
1005
- ``u`` -- integer representing a vertex of this graph.
1006
1007
OUTPUT:
1008
1009
- Raise ``NotImplementedError``. This method is not implemented at the
1010
:class:`CGraph` level. A child class should provide a suitable
1011
implementation.
1012
1013
.. SEEALSO::
1014
1015
- :meth:`out_neighbors <sage.graphs.base.sparse_graph.SparseGraph.out_neighbors>`
1016
-- ``out_neighbors`` implementation for sparse graphs.
1017
1018
- :meth:`out_neighbors <sage.graphs.base.dense_graph.DenseGraph.out_neighbors>`
1019
-- ``out_neighbors`` implementation for dense graphs.
1020
1021
EXAMPLE::
1022
1023
sage: from sage.graphs.base.c_graph import CGraph
1024
sage: G = CGraph()
1025
sage: G.out_neighbors(0)
1026
Traceback (most recent call last):
1027
...
1028
NotImplementedError
1029
"""
1030
raise NotImplementedError()
1031
1032
def _in_degree(self, int v):
1033
"""
1034
Return the number of edges coming into ``v``.
1035
1036
INPUT:
1037
1038
- ``v`` -- a vertex of this graph.
1039
1040
OUTPUT:
1041
1042
- The number of in-neighbors of ``v``.
1043
1044
EXAMPLE::
1045
1046
sage: from sage.graphs.base.sparse_graph import SparseGraph
1047
sage: SparseGraph(7)._in_degree(3)
1048
0
1049
1050
TEST::
1051
1052
sage: g = Graph({1: [2,5], 2: [1,5,3,4], 3: [2,5], 4: [3], 5: [2,3]}, implementation="c_graph")
1053
sage: g._backend.degree(5, False)
1054
3
1055
"""
1056
if not self.has_vertex(v):
1057
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(v))
1058
return self.in_degrees[v]
1059
1060
def _out_degree(self, int v):
1061
"""
1062
Return the number of edges coming out of ``v``.
1063
1064
INPUT:
1065
1066
- ``v`` -- a vertex of this graph.
1067
1068
OUTPUT:
1069
1070
- The number of out-neighbors of ``v``.
1071
1072
EXAMPLE::
1073
1074
sage: from sage.graphs.base.sparse_graph import SparseGraph
1075
sage: SparseGraph(7)._out_degree(3)
1076
0
1077
"""
1078
if not self.has_vertex(v):
1079
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(v))
1080
return self.out_degrees[v]
1081
1082
def _num_verts(self):
1083
"""
1084
Return the number of vertices in the (di)graph.
1085
1086
INPUT:
1087
1088
- None.
1089
1090
OUTPUT:
1091
1092
- The order of this graph.
1093
1094
EXAMPLE::
1095
1096
sage: from sage.graphs.base.sparse_graph import SparseGraph
1097
sage: SparseGraph(7)._num_verts()
1098
7
1099
"""
1100
return self.num_verts
1101
1102
def _num_arcs(self):
1103
"""
1104
Return the number of arcs in ``self``.
1105
1106
INPUT:
1107
1108
- None.
1109
1110
OUTPUT:
1111
1112
- The size of this graph.
1113
1114
EXAMPLE::
1115
1116
sage: from sage.graphs.base.sparse_graph import SparseGraph
1117
sage: SparseGraph(7)._num_arcs()
1118
0
1119
"""
1120
return self.num_arcs
1121
1122
cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels,
1123
CGraph G) except ? -2:
1124
"""
1125
Returns an int representing the arbitrary hashable vertex u (whether or not
1126
u is actually in the graph), or -1 if a new association must be made for u
1127
to be a vertex.
1128
1129
TESTS:
1130
1131
We check that the bug described in :trac:`8406` is gone::
1132
1133
sage: G = Graph()
1134
sage: R.<a> = GF(3**3)
1135
sage: S.<x> = R[]
1136
sage: G.add_vertex(a**2)
1137
sage: G.add_vertex(x)
1138
sage: G.vertices()
1139
[a^2, x]
1140
1141
And that the bug described in :trac:`9610` is gone::
1142
1143
sage: n = 20
1144
sage: k = 3
1145
sage: g = DiGraph()
1146
sage: g.add_edges( (i,Mod(i+j,n)) for i in range(n) for j in range(1,k+1) )
1147
sage: g.vertices()
1148
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
1149
sage: g.strongly_connected_components()
1150
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]
1151
1152
The bug in :trac:`14967` and :trac:`14853` is fixed::
1153
1154
sage: DiGraph({0: {}, 1/2: {}})
1155
Multi-digraph on 2 vertices
1156
sage: A = Set([RDF.random_element(min=0, max=10) for k in range(10)])
1157
sage: G = Graph()
1158
sage: G.add_vertices(A)
1159
sage: Set(G.vertices()) == A
1160
True
1161
1162
"""
1163
cdef int u_int
1164
if u in vertex_ints:
1165
return vertex_ints[u]
1166
try:
1167
u_int = u
1168
except Exception:
1169
return -1
1170
if u_int < 0 or u_int >= G.active_vertices.size or u_int in vertex_labels or u_int != u:
1171
return -1
1172
return u_int
1173
1174
cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels,
1175
CGraph G):
1176
"""
1177
Returns the object represented by u_int, or None if this does not represent
1178
a vertex.
1179
"""
1180
if u_int in vertex_labels:
1181
return vertex_labels[u_int]
1182
elif bitset_in(G.active_vertices, u_int):
1183
return u_int
1184
else:
1185
return None
1186
1187
cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels,
1188
CGraph G, CGraph G_rev, bint reverse) except ? -1:
1189
"""
1190
Returns an int representing the arbitrary hashable vertex u, and updates,
1191
if necessary, the translation dict and list. Adds a vertex if the label
1192
is new.
1193
"""
1194
cdef int u_int = get_vertex(u, vertex_ints, vertex_labels, G)
1195
if u_int != -1:
1196
if not bitset_in(G.active_vertices, u_int):
1197
bitset_add(G.active_vertices, u_int)
1198
G.num_verts += 1
1199
if reverse:
1200
bitset_add(G_rev.active_vertices, u_int)
1201
G_rev.num_verts += 1
1202
return u_int
1203
u_int = bitset_first_in_complement(G.active_vertices)
1204
if u_int == -1:
1205
G.realloc(2*G.active_vertices.size)
1206
if reverse:
1207
G_rev.realloc(2*G_rev.active_vertices.size)
1208
return check_vertex(u, vertex_ints, vertex_labels, G, G_rev, reverse)
1209
vertex_labels[u_int] = u
1210
vertex_ints[u] = u_int
1211
G.add_vertex(u_int)
1212
if reverse:
1213
G_rev.add_vertex(u_int)
1214
return u_int
1215
1216
class CGraphBackend(GenericGraphBackend):
1217
"""
1218
Base class for sparse and dense graph backends.
1219
1220
::
1221
1222
sage: from sage.graphs.base.c_graph import CGraphBackend
1223
1224
This class is extended by
1225
:class:`SparseGraphBackend <sage.graphs.base.sparse_graph.SparseGraphBackend>`
1226
and
1227
:class:`DenseGraphBackend <sage.graphs.base.dense_graph.DenseGraphBackend>`,
1228
which are fully functional backends. This class is mainly just for vertex
1229
functions, which are the same for both. A :class:`CGraphBackend` will not
1230
work on its own::
1231
1232
sage: from sage.graphs.base.c_graph import CGraphBackend
1233
sage: CGB = CGraphBackend()
1234
sage: CGB.degree(0, True)
1235
Traceback (most recent call last):
1236
...
1237
AttributeError: 'CGraphBackend' object has no attribute 'vertex_ints'
1238
1239
The appropriate way to use these backends is via Sage graphs::
1240
1241
sage: G = Graph(30, implementation="c_graph")
1242
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
1243
sage: G.edges(labels=False)
1244
[(0, 1), (0, 3), (4, 5), (9, 23)]
1245
1246
.. SEEALSO::
1247
1248
- :class:`SparseGraphBackend <sage.graphs.base.sparse_graph.SparseGraphBackend>`
1249
-- backend for sparse graphs.
1250
1251
- :class:`DenseGraphBackend <sage.graphs.base.dense_graph.DenseGraphBackend>`
1252
-- backend for dense graphs.
1253
"""
1254
1255
_cg = None
1256
_cg_rev = None
1257
_directed = None
1258
1259
def has_vertex(self, v):
1260
"""
1261
Returns whether ``v`` is a vertex of ``self``.
1262
1263
INPUT:
1264
1265
- ``v`` -- any object.
1266
1267
OUTPUT:
1268
1269
- ``True`` if ``v`` is a vertex of this graph; ``False`` otherwise.
1270
1271
EXAMPLE::
1272
1273
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1274
sage: B = SparseGraphBackend(7)
1275
sage: B.has_vertex(6)
1276
True
1277
sage: B.has_vertex(7)
1278
False
1279
"""
1280
cdef v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
1281
self._cg)
1282
if v_int == -1:
1283
return False
1284
if not bitset_in((<CGraph>self._cg).active_vertices, v_int):
1285
return False
1286
return True
1287
1288
def degree(self, v, directed):
1289
"""
1290
Return the degree of the vertex ``v``.
1291
1292
INPUT:
1293
1294
- ``v`` -- a vertex of the graph.
1295
1296
- ``directed`` -- boolean; whether to take into account the
1297
orientation of this graph in counting the degree of ``v``.
1298
1299
OUTPUT:
1300
1301
- The degree of vertex ``v``.
1302
1303
EXAMPLE::
1304
1305
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1306
sage: B = SparseGraphBackend(7)
1307
sage: B.degree(3, False)
1308
0
1309
1310
TESTS:
1311
1312
Ensure that ticket :trac:`8395` is fixed. ::
1313
1314
sage: def my_add_edges(G, m, n):
1315
... for i in range(m):
1316
... u = randint(0, n)
1317
... v = randint(0, n)
1318
... G.add_edge(u, v)
1319
sage: G = Graph({1:[1]}); G
1320
Looped graph on 1 vertex
1321
sage: G.edges(labels=False)
1322
[(1, 1)]
1323
sage: G.degree(); G.size()
1324
[2]
1325
1
1326
sage: sum(G.degree()) == 2 * G.size()
1327
True
1328
sage: G = Graph({1:[1,2], 2:[2,3]}, loops=True); G
1329
Looped graph on 3 vertices
1330
sage: my_add_edges(G, 100, 50)
1331
sage: sum(G.degree()) == 2 * G.size()
1332
True
1333
sage: G = Graph({1:[2,2], 2:[3]}); G
1334
Multi-graph on 3 vertices
1335
sage: G.edges(labels=False)
1336
[(1, 2), (1, 2), (2, 3)]
1337
sage: G.degree(); G.size()
1338
[2, 3, 1]
1339
3
1340
sage: sum(G.degree()) == 2 * G.size()
1341
True
1342
sage: G.allow_loops(True); G
1343
Looped multi-graph on 3 vertices
1344
sage: my_add_edges(G, 100, 50)
1345
sage: sum(G.degree()) == 2 * G.size()
1346
True
1347
sage: D = DiGraph({1:[2], 2:[1,3]}); D
1348
Digraph on 3 vertices
1349
sage: D.edges(labels=False)
1350
[(1, 2), (2, 1), (2, 3)]
1351
sage: D.degree(); D.size()
1352
[2, 3, 1]
1353
3
1354
sage: sum(D.degree()) == 2 * D.size()
1355
True
1356
sage: D.allow_loops(True); D
1357
Looped digraph on 3 vertices
1358
sage: my_add_edges(D, 100, 50)
1359
sage: sum(D.degree()) == 2 * D.size()
1360
True
1361
sage: D.allow_multiple_edges(True)
1362
sage: my_add_edges(D, 200, 50)
1363
sage: sum(D.degree()) == 2 * D.size()
1364
True
1365
sage: G = Graph({1:[2,2,2]})
1366
sage: G.allow_loops(True)
1367
sage: G.add_edge(1,1)
1368
sage: G.add_edge(1,1)
1369
sage: G.edges(labels=False)
1370
[(1, 1), (1, 1), (1, 2), (1, 2), (1, 2)]
1371
sage: G.degree(1)
1372
7
1373
sage: G.allow_loops(False)
1374
sage: G.edges(labels=False)
1375
[(1, 2), (1, 2), (1, 2)]
1376
sage: G.degree(1)
1377
3
1378
sage: G = Graph({1:{2:['a','a','a']}})
1379
sage: G.allow_loops(True)
1380
sage: G.add_edge(1,1,'b')
1381
sage: G.add_edge(1,1,'b')
1382
sage: G.add_edge(1,1)
1383
sage: G.add_edge(1,1)
1384
sage: G.edges()
1385
[(1, 1, None), (1, 1, None), (1, 1, 'b'), (1, 1, 'b'), (1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1386
sage: G.degree(1)
1387
11
1388
sage: G.allow_loops(False)
1389
sage: G.edges()
1390
[(1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1391
sage: G.degree(1)
1392
3
1393
sage: G = Graph({1:{2:['a','a','a']}})
1394
sage: G.allow_loops(True)
1395
sage: G.add_edge(1,1,'b')
1396
sage: G.add_edge(1,1,'b')
1397
sage: G.edges()
1398
[(1, 1, 'b'), (1, 1, 'b'), (1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1399
sage: G.degree(1)
1400
7
1401
sage: G.allow_loops(False)
1402
sage: G.edges()
1403
[(1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1404
sage: G.degree(1)
1405
3
1406
1407
Ensure that :trac:`13664` is fixed ::
1408
1409
sage: W = WeylGroup(["A",1])
1410
sage: G = W.cayley_graph()
1411
sage: Graph(G).degree()
1412
[1, 1]
1413
sage: h = Graph()
1414
sage: h.add_edge(1,2,"a")
1415
sage: h.add_edge(1,2,"a")
1416
sage: h.degree()
1417
[1, 1]
1418
"""
1419
cdef v_int = get_vertex(v,
1420
self.vertex_ints,
1421
self.vertex_labels,
1422
self._cg)
1423
if directed:
1424
return self._cg._in_degree(v_int) + self._cg._out_degree(v_int)
1425
d = 0
1426
if self._loops and self.has_edge(v, v, None):
1427
if self._multiple_edges:
1428
d += len(self.get_edge_label(v, v))
1429
else:
1430
d += 1
1431
return self._cg._out_degree(v_int) + d
1432
1433
1434
def out_degree(self, v):
1435
r"""
1436
Returns the out-degree of v
1437
1438
INPUT:
1439
1440
- ``v`` -- a vertex of the graph.
1441
1442
- ``directed`` -- boolean; whether to take into account the
1443
orientation of this graph in counting the degree of ``v``.
1444
1445
1446
EXAMPLE::
1447
1448
1449
sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } )
1450
sage: D.out_degree(1)
1451
2
1452
"""
1453
cdef v_int = get_vertex(v,
1454
self.vertex_ints,
1455
self.vertex_labels,
1456
self._cg)
1457
if self._directed:
1458
return self._cg._out_degree(v_int)
1459
d = 0
1460
if self._loops and self.has_edge(v, v, None):
1461
if self._multiple_edges:
1462
d += len(self.get_edge_label(v, v))
1463
else:
1464
d += 1
1465
1466
return self._cg._out_degree(v_int) + d
1467
1468
1469
def add_vertex(self, object name):
1470
"""
1471
Add a vertex to ``self``.
1472
1473
INPUT:
1474
1475
- ``name`` -- the vertex to be added (must be hashable). If ``None``,
1476
a new name is created.
1477
1478
OUTPUT:
1479
1480
- If name=None, the new vertex name is returned.
1481
None otherwise.
1482
1483
.. SEEALSO::
1484
1485
- :meth:`add_vertices`
1486
-- add a bunch of vertices of this graph.
1487
1488
- :meth:`has_vertex`
1489
-- returns whether or not this graph has a specific vertex.
1490
1491
EXAMPLE::
1492
1493
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1494
sage: D.add_vertex(10)
1495
sage: D.add_vertex([])
1496
Traceback (most recent call last):
1497
...
1498
TypeError: unhashable type: 'list'
1499
1500
::
1501
1502
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1503
sage: S.add_vertex(10)
1504
sage: S.add_vertex([])
1505
Traceback (most recent call last):
1506
...
1507
TypeError: unhashable type: 'list'
1508
"""
1509
retval = None
1510
if name is None:
1511
name = 0
1512
while name in self.vertex_ints or (
1513
name not in self.vertex_labels and
1514
bitset_in((<CGraph>self._cg).active_vertices, name)):
1515
name += 1
1516
retval = name
1517
1518
check_vertex(name,
1519
self.vertex_ints,
1520
self.vertex_labels,
1521
self._cg,
1522
self._cg_rev,
1523
(self._directed and
1524
self._cg_rev is not None)) # this will add the vertex
1525
1526
return retval
1527
1528
def add_vertices(self, object vertices):
1529
"""
1530
Add vertices to ``self``.
1531
1532
INPUT:
1533
1534
- ``vertices``: iterator of vertex labels. A new name is created, used and returned in
1535
the output list for all ``None`` values in ``vertices``.
1536
1537
OUTPUT:
1538
1539
Generated names of new vertices if there is at least one ``None`` value
1540
present in ``vertices``. ``None`` otherwise.
1541
1542
.. SEEALSO::
1543
1544
- :meth:`add_vertex`
1545
-- add a vertex to this graph.
1546
1547
EXAMPLE::
1548
1549
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(1)
1550
sage: D.add_vertices([1,2,3])
1551
sage: D.add_vertices([None]*4)
1552
[4, 5, 6, 7]
1553
1554
::
1555
1556
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(0)
1557
sage: G.add_vertices([0,1])
1558
sage: list(G.iterator_verts(None))
1559
[0, 1]
1560
sage: list(G.iterator_edges([0,1], True))
1561
[]
1562
1563
::
1564
1565
sage: import sage.graphs.base.dense_graph
1566
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1567
sage: D.add_vertices([10,11,12])
1568
"""
1569
cdef object v
1570
cdef int nones = 0
1571
for v in vertices:
1572
if v is not None:
1573
self.add_vertex(v)
1574
else:
1575
nones += 1
1576
1577
new_names = []
1578
while nones > 0:
1579
new_names.append(self.add_vertex(None))
1580
nones -= 1
1581
1582
return new_names if new_names != [] else None
1583
1584
def del_vertex(self, v):
1585
"""
1586
Delete a vertex in ``self``, failing silently if the vertex is not
1587
in the graph.
1588
1589
INPUT:
1590
1591
- ``v`` -- vertex to be deleted.
1592
1593
OUTPUT:
1594
1595
- None.
1596
1597
.. SEEALSO::
1598
1599
- :meth:`del_vertices`
1600
-- delete a bunch of vertices from this graph.
1601
1602
EXAMPLE::
1603
1604
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1605
sage: D.del_vertex(0)
1606
sage: D.has_vertex(0)
1607
False
1608
1609
::
1610
1611
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1612
sage: S.del_vertex(0)
1613
sage: S.has_vertex(0)
1614
False
1615
"""
1616
if not self.has_vertex(v):
1617
return
1618
cdef int v_int = get_vertex(v,
1619
self.vertex_ints,
1620
self.vertex_labels,
1621
self._cg)
1622
1623
# delete each arc incident with v and v
1624
self._cg.del_vertex(v_int)
1625
if self._cg_rev is not None:
1626
self._cg_rev.del_vertex(v_int)
1627
1628
# add v to unused vertices
1629
if v_int in self.vertex_labels:
1630
self.vertex_ints.pop(v)
1631
self.vertex_labels.pop(v_int)
1632
1633
def del_vertices(self, vertices):
1634
"""
1635
Delete vertices from an iterable container.
1636
1637
INPUT:
1638
1639
- ``vertices`` -- iterator of vertex labels.
1640
1641
OUTPUT:
1642
1643
- Same as for :meth:`del_vertex`.
1644
1645
.. SEEALSO::
1646
1647
- :meth:`del_vertex`
1648
-- delete a vertex of this graph.
1649
1650
EXAMPLE::
1651
1652
sage: import sage.graphs.base.dense_graph
1653
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1654
sage: D.del_vertices([7,8])
1655
sage: D.has_vertex(7)
1656
False
1657
sage: D.has_vertex(6)
1658
True
1659
1660
::
1661
1662
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1663
sage: D.del_vertices([1,2,3])
1664
sage: D.has_vertex(1)
1665
False
1666
sage: D.has_vertex(0)
1667
True
1668
"""
1669
cdef object v
1670
for v in vertices:
1671
self.del_vertex(v)
1672
1673
def iterator_nbrs(self, v):
1674
"""
1675
Returns an iterator over the neighbors of ``v``.
1676
1677
INPUT:
1678
1679
- ``v`` -- a vertex of this graph.
1680
1681
OUTPUT:
1682
1683
- An iterator over the neighbors the vertex ``v``.
1684
1685
.. SEEALSO::
1686
1687
- :meth:`iterator_in_nbrs`
1688
-- returns an iterator over the in-neighbors of a vertex.
1689
1690
- :meth:`iterator_out_nbrs`
1691
-- returns an iterator over the out-neighbors of a vertex.
1692
1693
- :meth:`iterator_verts`
1694
-- returns an iterator over a given set of vertices.
1695
1696
EXAMPLE::
1697
1698
sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")
1699
sage: list(P._backend.iterator_nbrs(0))
1700
[1, 4, 5]
1701
"""
1702
if not self._directed:
1703
return self.iterator_out_nbrs(v)
1704
1705
return iter(set(self.iterator_in_nbrs(v)) |
1706
set(self.iterator_out_nbrs(v)))
1707
1708
def iterator_in_nbrs(self, v):
1709
"""
1710
Returns an iterator over the incoming neighbors of ``v``.
1711
1712
INPUT:
1713
1714
- ``v`` -- a vertex of this graph.
1715
1716
OUTPUT:
1717
1718
- An iterator over the in-neighbors of the vertex ``v``.
1719
1720
.. SEEALSO::
1721
1722
- :meth:`iterator_nbrs`
1723
-- returns an iterator over the neighbors of a vertex.
1724
1725
- :meth:`iterator_out_nbrs`
1726
-- returns an iterator over the out-neighbors of a vertex.
1727
1728
EXAMPLE::
1729
1730
sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph")
1731
sage: list(P._backend.iterator_in_nbrs(0))
1732
[1, 4, 5]
1733
"""
1734
cdef int u_int
1735
cdef int v_int = get_vertex(v,
1736
self.vertex_ints,
1737
self.vertex_labels,
1738
self._cg)
1739
# Sparse
1740
if self._cg_rev is not None:
1741
for u_int in self._cg_rev.out_neighbors(v_int):
1742
yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1743
1744
# Dense
1745
else:
1746
for u_int in self._cg.in_neighbors(v_int):
1747
yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1748
1749
def iterator_out_nbrs(self, v):
1750
"""
1751
Returns an iterator over the outgoing neighbors of ``v``.
1752
1753
INPUT:
1754
1755
- ``v`` -- a vertex of this graph.
1756
1757
OUTPUT:
1758
1759
- An iterator over the out-neighbors of the vertex ``v``.
1760
1761
.. SEEALSO::
1762
1763
- :meth:`iterator_nbrs`
1764
-- returns an iterator over the neighbors of a vertex.
1765
1766
- :meth:`iterator_in_nbrs`
1767
-- returns an iterator over the in-neighbors of a vertex.
1768
1769
EXAMPLE::
1770
1771
sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph")
1772
sage: list(P._backend.iterator_out_nbrs(0))
1773
[1, 4, 5]
1774
"""
1775
cdef u_int
1776
cdef int v_int = get_vertex(v,
1777
self.vertex_ints,
1778
self.vertex_labels,
1779
self._cg)
1780
1781
for u_int in self._cg.out_neighbors(v_int):
1782
yield vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1783
1784
def iterator_verts(self, verts=None):
1785
"""
1786
Returns an iterator over the vertices of ``self`` intersected with
1787
``verts``.
1788
1789
INPUT:
1790
1791
- ``verts`` -- an iterable container of objects (default: ``None``).
1792
1793
OUTPUT:
1794
1795
- If ``verts=None``, return an iterator over all vertices of this
1796
graph.
1797
1798
- If ``verts`` is an iterable container of vertices, find the
1799
intersection of ``verts`` with the vertex set of this graph and
1800
return an iterator over the resulting intersection.
1801
1802
.. SEEALSO::
1803
1804
- :meth:`iterator_nbrs`
1805
-- returns an iterator over the neighbors of a vertex.
1806
1807
EXAMPLE::
1808
1809
sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")
1810
sage: list(P._backend.iterator_verts(P))
1811
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1812
sage: list(P._backend.iterator_verts())
1813
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1814
sage: list(P._backend.iterator_verts([1, 2, 3]))
1815
[1, 2, 3]
1816
sage: list(P._backend.iterator_verts([1, 2, 10]))
1817
[1, 2]
1818
"""
1819
cdef int i
1820
cdef object v
1821
if verts is None:
1822
S = set(self.vertex_ints.iterkeys())
1823
for i from 0 <= i < (<CGraph>self._cg).active_vertices.size:
1824
if (i not in self.vertex_labels and
1825
bitset_in((<CGraph>self._cg).active_vertices, i)):
1826
S.add(i)
1827
return iter(S)
1828
is_hashable = False
1829
try:
1830
v = hash(verts)
1831
is_hashable = True
1832
except Exception:
1833
pass
1834
if is_hashable and self.has_vertex(verts):
1835
return iter([verts])
1836
else:
1837
L = []
1838
for v in verts:
1839
if self.has_vertex(v):
1840
L.append(v)
1841
return iter(L)
1842
1843
def loops(self, new=None):
1844
"""
1845
Returns whether loops are allowed in this graph.
1846
1847
INPUT:
1848
1849
- ``new`` -- (default: ``None``); boolean (to set) or ``None``
1850
(to get).
1851
1852
OUTPUT:
1853
1854
- If ``new=None``, return ``True`` if this graph allows self-loops or
1855
``False`` if self-loops are not allowed.
1856
1857
- If ``new`` is a boolean, set the self-loop permission of this graph
1858
according to the boolean value of ``new``.
1859
1860
EXAMPLE::
1861
1862
sage: G = Graph(implementation='c_graph')
1863
sage: G._backend.loops()
1864
False
1865
sage: G._backend.loops(True)
1866
sage: G._backend.loops()
1867
True
1868
"""
1869
if new is None:
1870
return self._loops
1871
if new:
1872
self._loops = True
1873
else:
1874
self._loops = False
1875
1876
def num_edges(self, directed):
1877
"""
1878
Returns the number of edges in ``self``.
1879
1880
INPUT:
1881
1882
- ``directed`` -- boolean; whether to count ``(u,v)`` and ``(v,u)``
1883
as one or two edges.
1884
1885
OUTPUT:
1886
1887
- If ``directed=True``, counts the number of directed edges in this
1888
graph. Otherwise, return the size of this graph.
1889
1890
.. SEEALSO::
1891
1892
- :meth:`num_verts`
1893
-- return the order of this graph.
1894
1895
EXAMPLE::
1896
1897
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
1898
sage: G._backend.num_edges(False)
1899
15
1900
1901
TESTS:
1902
1903
Ensure that ticket #8395 is fixed. ::
1904
1905
sage: G = Graph({1:[1]}); G
1906
Looped graph on 1 vertex
1907
sage: G.edges(labels=False)
1908
[(1, 1)]
1909
sage: G.size()
1910
1
1911
sage: G = Graph({1:[2,2]}); G
1912
Multi-graph on 2 vertices
1913
sage: G.edges(labels=False)
1914
[(1, 2), (1, 2)]
1915
sage: G.size()
1916
2
1917
sage: G = Graph({1:[1,1]}); G
1918
Looped multi-graph on 1 vertex
1919
sage: G.edges(labels=False)
1920
[(1, 1), (1, 1)]
1921
sage: G.size()
1922
2
1923
sage: D = DiGraph({1:[1]}); D
1924
Looped digraph on 1 vertex
1925
sage: D.edges(labels=False)
1926
[(1, 1)]
1927
sage: D.size()
1928
1
1929
sage: D = DiGraph({1:[2,2], 2:[1,1]}); D
1930
Multi-digraph on 2 vertices
1931
sage: D.edges(labels=False)
1932
[(1, 2), (1, 2), (2, 1), (2, 1)]
1933
sage: D.size()
1934
4
1935
sage: D = DiGraph({1:[1,1]}); D
1936
Looped multi-digraph on 1 vertex
1937
sage: D.edges(labels=False)
1938
[(1, 1), (1, 1)]
1939
sage: D.size()
1940
2
1941
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1942
sage: S = SparseGraphBackend(7)
1943
sage: S.num_edges(directed=False)
1944
0
1945
sage: S.loops(True)
1946
sage: S.add_edge(1, 1, None, directed=False)
1947
sage: S.num_edges(directed=False)
1948
1
1949
sage: S.multiple_edges(True)
1950
sage: S.add_edge(1, 1, None, directed=False)
1951
sage: S.num_edges(directed=False)
1952
2
1953
sage: from sage.graphs.base.dense_graph import DenseGraphBackend
1954
sage: D = DenseGraphBackend(7)
1955
sage: D.num_edges(directed=False)
1956
0
1957
sage: D.loops(True)
1958
sage: D.add_edge(1, 1, None, directed=False)
1959
sage: D.num_edges(directed=False)
1960
1
1961
"""
1962
if directed:
1963
return self._cg._num_arcs()
1964
else:
1965
i = self._cg._num_arcs()
1966
k = 0
1967
if self.loops(None):
1968
if self.multiple_edges(None):
1969
for j in self.iterator_verts():
1970
if self.has_edge(j, j, None):
1971
k += len(self.get_edge_label(j, j))
1972
else:
1973
for j in self.iterator_verts():
1974
if self.has_edge(j, j, None):
1975
k += 1
1976
i = (i - k) / 2
1977
return i + k
1978
1979
def num_verts(self):
1980
"""
1981
Returns the number of vertices in ``self``.
1982
1983
INPUT:
1984
1985
- None.
1986
1987
OUTPUT:
1988
1989
- The order of this graph.
1990
1991
.. SEEALSO::
1992
1993
- :meth:`num_edges`
1994
-- return the number of (directed) edges in this graph.
1995
1996
EXAMPLE::
1997
1998
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
1999
sage: G._backend.num_verts()
2000
10
2001
"""
2002
return (<CGraph>self._cg).num_verts
2003
2004
def relabel(self, perm, directed):
2005
"""
2006
Relabels the graph according to ``perm``.
2007
2008
INPUT:
2009
2010
- ``perm`` -- anything which represents a permutation as
2011
``v --> perm[v]``, for example a dict or a list.
2012
2013
- ``directed`` -- ignored (this is here for compatibility with other
2014
backends).
2015
2016
EXAMPLES::
2017
2018
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2019
sage: G._backend.relabel(range(9,-1,-1), False)
2020
sage: G.edges()
2021
[(0, 2, None),
2022
(0, 3, None),
2023
(0, 5, None),
2024
(1, 3, None),
2025
(1, 4, None),
2026
(1, 6, None),
2027
(2, 4, None),
2028
(2, 7, None),
2029
(3, 8, None),
2030
(4, 9, None),
2031
(5, 6, None),
2032
(5, 9, None),
2033
(6, 7, None),
2034
(7, 8, None),
2035
(8, 9, None)]
2036
"""
2037
cdef int i
2038
cdef object v
2039
cdef dict new_vx_ints = {}
2040
cdef dict new_vx_labels = {}
2041
for v in self.iterator_verts(None):
2042
i = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg)
2043
new_vx_ints[perm[v]] = i
2044
new_vx_labels[i] = perm[v]
2045
self.vertex_ints = new_vx_ints
2046
self.vertex_labels = new_vx_labels
2047
2048
def shortest_path(self, x, y):
2049
r"""
2050
Returns the shortest path between ``x`` and ``y``.
2051
2052
INPUT:
2053
2054
- ``x`` -- the starting vertex in the shortest path from ``x`` to
2055
``y``.
2056
2057
- ``y`` -- the end vertex in the shortest path from ``x`` to ``y``.
2058
2059
OUTPUT:
2060
2061
- A list of vertices in the shortest path from ``x`` to ``y``.
2062
2063
EXAMPLE::
2064
2065
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2066
sage: G.shortest_path(0, 1)
2067
[0, 1]
2068
"""
2069
if x == y:
2070
return 0
2071
2072
# The function being mostly symmetric in x and y, their roles are
2073
# reversed at the end of each loop. For this reason is defined, for
2074
# example, two dictionaries dist_y and dist_x containing the distances
2075
# to x and y, and a dictionary dist_current and dist_other, pointing
2076
# toward the previous two, alternatively.
2077
#
2078
# Besides, there is another difference in the fact that for directed
2079
# graphs we are interested in paths leaving x toward y, so we are
2080
# considering the out_neighbors on x's side, and in_neighbors on
2081
# y's side.
2082
2083
cdef int x_int = get_vertex(x,
2084
self.vertex_ints,
2085
self.vertex_labels,
2086
self._cg)
2087
cdef int y_int = get_vertex(y,
2088
self.vertex_ints,
2089
self.vertex_labels,
2090
self._cg)
2091
cdef int u = 0
2092
cdef int v = 0
2093
cdef int w = 0
2094
2095
# Each vertex knows its predecessors in the search, for each side
2096
cdef dict pred_x = {}
2097
cdef dict pred_y = {}
2098
cdef dict pred_current = pred_x
2099
cdef dict pred_other = pred_y
2100
2101
# Stores the distances from x and y
2102
cdef dict dist_x = {}
2103
cdef dict dist_y = {}
2104
cdef dict dist_current = dist_x
2105
cdef dict dist_other = dist_y
2106
dist_x[x_int] = 0
2107
dist_y[y_int] = 0
2108
2109
# Lists of vertices whose neighbors have not been explored yet
2110
cdef list next_x = [x_int]
2111
cdef list next_y = [y_int]
2112
cdef list next_current = next_x
2113
cdef list next_other = next_y
2114
cdef list next_temporary = []
2115
cdef list neighbors
2116
2117
cdef list shortest_path = []
2118
2119
# We are interested in edges leaving x and entering y, so we
2120
# are dealing with two different "neighbors" functions
2121
cdef int out = 1
2122
2123
# As long as the current side (x or y) is not totally explored ...
2124
while next_current:
2125
next_temporary = []
2126
2127
# Take the next vertex in the list, and study all of its neighbors.
2128
# When a new neighbor is found, it is added into a temporary list.
2129
# When all the vertices in the list are tested
2130
# and next_current is replaced by the temporary list
2131
#
2132
# After this, current and other are reversed, and the loop restarts
2133
for u in next_current:
2134
if out == 1:
2135
neighbors = self._cg.out_neighbors(u)
2136
elif self._cg_rev is not None: # Sparse
2137
neighbors = self._cg_rev.out_neighbors(u)
2138
else: # Dense
2139
neighbors = self._cg.in_neighbors(u)
2140
for v in neighbors:
2141
# If the neighbor is new, updates the distances and adds
2142
# to the list.
2143
if v not in dist_current:
2144
dist_current[v] = dist_current[u] + 1
2145
pred_current[v] = u
2146
next_current.append(v)
2147
2148
# If the new neighbor is already known by the other
2149
# side ...
2150
if v in dist_other:
2151
# build the shortest path and returns in.
2152
w = v
2153
2154
while w != x_int:
2155
shortest_path.append(
2156
vertex_label(w,
2157
self.vertex_ints,
2158
self.vertex_labels,
2159
self._cg))
2160
w = pred_x[w]
2161
2162
shortest_path.append(x)
2163
shortest_path.reverse()
2164
2165
if v == y_int:
2166
return shortest_path
2167
2168
w = pred_y[v]
2169
while w != y_int:
2170
shortest_path.append(
2171
vertex_label(w,
2172
self.vertex_ints,
2173
self.vertex_labels,
2174
self._cg))
2175
w = pred_y[w]
2176
shortest_path.append(y)
2177
2178
return shortest_path
2179
2180
next_current = next_temporary
2181
pred_current, pred_other = pred_other, pred_current
2182
dist_current, dist_other = dist_other, dist_current
2183
next_current, next_other = next_other, next_current
2184
out = -out
2185
2186
return []
2187
2188
def bidirectional_dijkstra(self, x, y):
2189
r"""
2190
Returns the shortest path between ``x`` and ``y`` using a
2191
bidirectional version of Dijkstra's algorithm.
2192
2193
INPUT:
2194
2195
- ``x`` -- the starting vertex in the shortest path from ``x`` to
2196
``y``.
2197
2198
- ``y`` -- the end vertex in the shortest path from ``x`` to ``y``.
2199
2200
OUTPUT:
2201
2202
- A list of vertices in the shortest path from ``x`` to ``y``.
2203
2204
EXAMPLE::
2205
2206
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2207
sage: for (u,v) in G.edges(labels=None):
2208
... G.set_edge_label(u,v,1)
2209
sage: G.shortest_path(0, 1, by_weight=True)
2210
[0, 1]
2211
2212
TEST:
2213
2214
Bugfix from #7673 ::
2215
2216
sage: G = Graph(implementation="networkx")
2217
sage: G.add_edges([(0,1,9),(0,2,8),(1,2,7)])
2218
sage: Gc = G.copy(implementation='c_graph')
2219
sage: sp = G.shortest_path_length(0,1,by_weight=True)
2220
sage: spc = Gc.shortest_path_length(0,1,by_weight=True)
2221
sage: sp == spc
2222
True
2223
"""
2224
if x == y:
2225
return 0
2226
2227
# ****************** WARNING **********************
2228
# Use Python to maintain a heap...
2229
# Rewrite this in Cython as soon as possible !
2230
# *************************************************
2231
from heapq import heappush, heappop
2232
2233
# As for shortest_path, the roles of x and y are symmetric, hence we
2234
# define dictionaries like pred_current and pred_other, which
2235
# represent alternatively pred_x or pred_y according to the side
2236
# studied.
2237
cdef int x_int = get_vertex(x,
2238
self.vertex_ints,
2239
self.vertex_labels,
2240
self._cg)
2241
cdef int y_int = get_vertex(y,
2242
self.vertex_ints,
2243
self.vertex_labels,
2244
self._cg)
2245
cdef int u = 0
2246
cdef int v = 0
2247
cdef int w = 0
2248
cdef int pred
2249
cdef float distance
2250
cdef float edge_label
2251
cdef int side
2252
cdef float f_tmp
2253
cdef object v_obj
2254
cdef object w_obj
2255
2256
# Each vertex knows its predecessors in the search, for each side
2257
cdef dict pred_x = {}
2258
cdef dict pred_y = {}
2259
cdef dict pred_current
2260
cdef dict pred_other
2261
2262
# Stores the distances from x and y
2263
cdef dict dist_x = {}
2264
cdef dict dist_y = {}
2265
cdef dict dist_current
2266
cdef dict dist_other
2267
2268
# Lists of vertices who are left to be explored. They are represented
2269
# as 4-tuples: (distance, side, predecessor ,name).
2270
# 1 indicates x's side, -1 indicates y's, the distance being
2271
# defined relatively.
2272
cdef list queue = [(0, 1, x_int, x_int), (0, -1, y_int, y_int)]
2273
cdef list neighbors
2274
2275
cdef list shortest_path = []
2276
2277
# Meeting_vertex is a vertex discovered through x and through y
2278
# which defines the shortest path found
2279
# (of length shortest_path_length).
2280
cdef int meeting_vertex = -1
2281
cdef float shortest_path_length
2282
2283
# As long as the current side (x or y) is not totally explored ...
2284
while queue:
2285
(distance, side, pred, v) = heappop(queue)
2286
if meeting_vertex != -1 and distance > shortest_path_length:
2287
break
2288
2289
if side == 1:
2290
dist_current, dist_other = dist_x, dist_y
2291
pred_current, pred_other = pred_x, pred_y
2292
else:
2293
dist_current, dist_other = dist_y, dist_x
2294
pred_current, pred_other = pred_y, pred_x
2295
2296
if v not in dist_current:
2297
pred_current[v] = pred
2298
dist_current[v] = distance
2299
2300
if v in dist_other:
2301
f_tmp = distance + dist_other[v]
2302
if meeting_vertex == -1 or f_tmp < shortest_path_length:
2303
meeting_vertex = v
2304
shortest_path_length = f_tmp
2305
2306
if side == 1:
2307
neighbors = self._cg.out_neighbors(v)
2308
elif self._cg_rev is not None: # Sparse
2309
neighbors = self._cg_rev.out_neighbors(v)
2310
else: # Dense
2311
neighbors = self._cg.in_neighbors(v)
2312
for w in neighbors:
2313
# If the neighbor is new, adds its non-found neighbors to
2314
# the queue.
2315
if w not in dist_current:
2316
v_obj = vertex_label(v, self.vertex_ints, self.vertex_labels, self._cg)
2317
w_obj = vertex_label(w, self.vertex_ints, self.vertex_labels, self._cg)
2318
edge_label = self.get_edge_label(v_obj, w_obj) if side == 1 else self.get_edge_label(w_obj, v_obj)
2319
heappush(queue, (distance + edge_label, side, v, w))
2320
2321
# No meeting point has been found
2322
if meeting_vertex == -1:
2323
return []
2324
else:
2325
# build the shortest path and returns it.
2326
w = meeting_vertex
2327
2328
while w != x_int:
2329
shortest_path.append(
2330
vertex_label(w,
2331
self.vertex_ints,
2332
self.vertex_labels,
2333
self._cg))
2334
w = pred_x[w]
2335
2336
shortest_path.append(x)
2337
shortest_path.reverse()
2338
2339
if meeting_vertex == y_int:
2340
return shortest_path
2341
2342
w = pred_y[meeting_vertex]
2343
while w != y_int:
2344
shortest_path.append(
2345
vertex_label(w,
2346
self.vertex_ints,
2347
self.vertex_labels,
2348
self._cg))
2349
w = pred_y[w]
2350
shortest_path.append(y)
2351
2352
return shortest_path
2353
2354
def shortest_path_all_vertices(self, v, cutoff=None):
2355
r"""
2356
Returns for each vertex ``u`` a shortest ``v-u`` path.
2357
2358
INPUT:
2359
2360
- ``v`` -- a starting vertex in the shortest path.
2361
2362
- ``cutoff`` -- maximal distance. Longer paths will not be returned.
2363
2364
OUTPUT:
2365
2366
- A list which associates to each vertex ``u`` the shortest path
2367
between ``u`` and ``v`` if there is one.
2368
2369
.. NOTE::
2370
2371
The weight of edges is not taken into account.
2372
2373
ALGORITHM:
2374
2375
This is just a breadth-first search.
2376
2377
EXAMPLES:
2378
2379
On the Petersen Graph::
2380
2381
sage: g = graphs.PetersenGraph()
2382
sage: paths = g._backend.shortest_path_all_vertices(0)
2383
sage: all([ len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v) for v in g])
2384
True
2385
2386
On a disconnected graph ::
2387
2388
sage: g = 2*graphs.RandomGNP(20,.3)
2389
sage: paths = g._backend.shortest_path_all_vertices(0)
2390
sage: all([ (not paths.has_key(v) and g.distance(0,v) == +Infinity) or len(paths[v])-1 == g.distance(0,v) for v in g])
2391
True
2392
"""
2393
cdef list current_layer
2394
cdef list next_layer
2395
cdef bitset_t seen
2396
cdef int v_int
2397
cdef int u_int
2398
cdef dict distances_int
2399
cdef dict distance
2400
cdef int d
2401
2402
distances = {}
2403
d = 0
2404
2405
v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg)
2406
2407
bitset_init(seen, (<CGraph>self._cg).active_vertices.size)
2408
bitset_set_first_n(seen, 0)
2409
bitset_add(seen, v_int)
2410
2411
current_layer = [(u_int, v_int)
2412
for u_int in self._cg.out_neighbors(v_int)]
2413
next_layer = []
2414
distances[v] = [v]
2415
2416
while current_layer:
2417
if cutoff is not None and d >= cutoff:
2418
break
2419
2420
while current_layer:
2421
v_int, u_int = current_layer.pop()
2422
2423
if bitset_not_in(seen, v_int):
2424
bitset_add(seen, v_int)
2425
distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = distances[vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)] + [vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)]
2426
next_layer.extend([(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)])
2427
2428
current_layer = next_layer
2429
next_layer = []
2430
d += 1
2431
2432
# If the graph is not connected, vertices which have not been
2433
# seen should be associated to the empty path
2434
2435
#for 0 <= v_int < (<CGraph>self._cg).active_vertices.size:
2436
# if bitset_in((<CGraph>self._cg).active_vertices, v_int) and not bitset_in(seen, v_int):
2437
# distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = []
2438
2439
bitset_free(seen)
2440
return distances
2441
2442
def depth_first_search(self, v, reverse=False, ignore_direction=False):
2443
r"""
2444
Returns a depth-first search from vertex ``v``.
2445
2446
INPUT:
2447
2448
- ``v`` -- a vertex from which to start the depth-first search.
2449
2450
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2451
to digraphs. If this is a digraph, consider the reversed graph in
2452
which the out-neighbors become the in-neighbors and vice versa.
2453
2454
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2455
relevant to digraphs. If this is a digraph, ignore all orientations
2456
and consider the graph as undirected.
2457
2458
ALGORITHM:
2459
2460
Below is a general template for depth-first search.
2461
2462
- **Input:** A directed or undirected graph `G = (V, E)` of order
2463
`n > 0`. A vertex `s` from which to start the search. The vertices
2464
are numbered from 1 to `n = |V|`, i.e. `V = \{1, 2, \dots, n\}`.
2465
2466
- **Output:** A list `D` of distances of all vertices from `s`. A
2467
tree `T` rooted at `s`.
2468
2469
#. `S \leftarrow [s]` # a stack of nodes to visit
2470
#. `D \leftarrow [\infty, \infty, \dots, \infty]` # `n` copies of `\infty`
2471
#. `D[s] \leftarrow 0`
2472
#. `T \leftarrow [\,]`
2473
#. while `\text{length}(S) > 0` do
2474
2475
#. `v \leftarrow \text{pop}(S)`
2476
#. for each `w \in \text{adj}(v)` do # for digraphs, use out-neighbor set `\text{oadj}(v)`
2477
2478
#. if `D[w] = \infty` then
2479
2480
#. `D[w] \leftarrow D[v] + 1`
2481
#. `\text{push}(S, w)`
2482
#. `\text{append}(T, vw)`
2483
#. return `(D, T)`
2484
2485
.. SEEALSO::
2486
2487
- :meth:`breadth_first_search`
2488
-- breadth-first search for fast compiled graphs.
2489
2490
- :meth:`breadth_first_search <sage.graphs.generic_graph.GenericGraph.breadth_first_search>`
2491
-- breadth-first search for generic graphs.
2492
2493
- :meth:`depth_first_search <sage.graphs.generic_graph.GenericGraph.depth_first_search>`
2494
-- depth-first search for generic graphs.
2495
2496
EXAMPLES:
2497
2498
Traversing the Petersen graph using depth-first search::
2499
2500
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2501
sage: list(G.depth_first_search(0))
2502
[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]
2503
2504
Visiting German cities using depth-first search::
2505
2506
sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],
2507
... "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
2508
... "Kassel": ["Frankfurt","Munchen"],
2509
... "Munchen": ["Kassel","Nurnberg","Augsburg"],
2510
... "Augsburg": ["Munchen","Karlsruhe"],
2511
... "Karlsruhe": ["Mannheim","Augsburg"],
2512
... "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
2513
... "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
2514
... "Stuttgart": ["Nurnberg"],
2515
... "Erfurt": ["Wurzburg"]}, implementation="c_graph")
2516
sage: list(G.depth_first_search("Frankfurt"))
2517
['Frankfurt', 'Wurzburg', 'Nurnberg', 'Munchen', 'Kassel', 'Augsburg', 'Karlsruhe', 'Mannheim', 'Stuttgart', 'Erfurt']
2518
"""
2519
return Search_iterator(self,
2520
v,
2521
direction=-1,
2522
reverse=reverse,
2523
ignore_direction=ignore_direction)
2524
2525
def breadth_first_search(self, v, reverse=False, ignore_direction=False):
2526
r"""
2527
Returns a breadth-first search from vertex ``v``.
2528
2529
INPUT:
2530
2531
- ``v`` -- a vertex from which to start the breadth-first search.
2532
2533
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2534
to digraphs. If this is a digraph, consider the reversed graph in
2535
which the out-neighbors become the in-neighbors and vice versa.
2536
2537
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2538
relevant to digraphs. If this is a digraph, ignore all orientations
2539
and consider the graph as undirected.
2540
2541
ALGORITHM:
2542
2543
Below is a general template for breadth-first search.
2544
2545
- **Input:** A directed or undirected graph `G = (V, E)` of order
2546
`n > 0`. A vertex `s` from which to start the search. The vertices
2547
are numbered from 1 to `n = |V|`, i.e. `V = \{1, 2, \dots, n\}`.
2548
2549
- **Output:** A list `D` of distances of all vertices from `s`. A
2550
tree `T` rooted at `s`.
2551
2552
#. `Q \leftarrow [s]` # a queue of nodes to visit
2553
#. `D \leftarrow [\infty, \infty, \dots, \infty]` # `n` copies of `\infty`
2554
#. `D[s] \leftarrow 0`
2555
#. `T \leftarrow [\,]`
2556
#. while `\text{length}(Q) > 0` do
2557
2558
#. `v \leftarrow \text{dequeue}(Q)`
2559
#. for each `w \in \text{adj}(v)` do # for digraphs, use out-neighbor set `\text{oadj}(v)`
2560
2561
#. if `D[w] = \infty` then
2562
2563
#. `D[w] \leftarrow D[v] + 1`
2564
#. `\text{enqueue}(Q, w)`
2565
#. `\text{append}(T, vw)`
2566
#. return `(D, T)`
2567
2568
.. SEEALSO::
2569
2570
- :meth:`breadth_first_search <sage.graphs.generic_graph.GenericGraph.breadth_first_search>`
2571
-- breadth-first search for generic graphs.
2572
2573
- :meth:`depth_first_search <sage.graphs.generic_graph.GenericGraph.depth_first_search>`
2574
-- depth-first search for generic graphs.
2575
2576
- :meth:`depth_first_search`
2577
-- depth-first search for fast compiled graphs.
2578
2579
EXAMPLES:
2580
2581
Breadth-first search of the Petersen graph starting at vertex 0::
2582
2583
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2584
sage: list(G.breadth_first_search(0))
2585
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2586
2587
Visiting German cities using breadth-first search::
2588
2589
sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],
2590
... "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
2591
... "Kassel": ["Frankfurt","Munchen"],
2592
... "Munchen": ["Kassel","Nurnberg","Augsburg"],
2593
... "Augsburg": ["Munchen","Karlsruhe"],
2594
... "Karlsruhe": ["Mannheim","Augsburg"],
2595
... "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
2596
... "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
2597
... "Stuttgart": ["Nurnberg"],
2598
... "Erfurt": ["Wurzburg"]}, implementation="c_graph")
2599
sage: list(G.breadth_first_search("Frankfurt"))
2600
['Frankfurt', 'Mannheim', 'Kassel', 'Wurzburg', 'Karlsruhe', 'Munchen', 'Erfurt', 'Nurnberg', 'Augsburg', 'Stuttgart']
2601
"""
2602
return Search_iterator(self,
2603
v,
2604
direction=0,
2605
reverse=reverse,
2606
ignore_direction=ignore_direction)
2607
2608
def is_connected(self):
2609
r"""
2610
Returns whether the graph is connected.
2611
2612
EXAMPLES:
2613
2614
Petersen's graph is connected::
2615
2616
sage: DiGraph(graphs.PetersenGraph(),implementation="c_graph").is_connected()
2617
True
2618
2619
While the disjoint union of two of them is not::
2620
2621
sage: DiGraph(2*graphs.PetersenGraph(),implementation="c_graph").is_connected()
2622
False
2623
2624
A graph with non-integer vertex labels::
2625
2626
sage: Graph(graphs.CubeGraph(3), implementation='c_graph').is_connected()
2627
True
2628
"""
2629
cdef int v_int
2630
cdef CGraph cg = <CGraph> self._cg
2631
2632
if cg.num_edges() < cg.num_verts - 1:
2633
return False
2634
2635
v_int = bitset_first(cg.active_vertices)
2636
2637
if v_int == -1:
2638
return True
2639
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, cg)
2640
return len(list(self.depth_first_search(v, ignore_direction=True))) == cg.num_verts
2641
2642
def is_strongly_connected(self):
2643
r"""
2644
Returns whether the graph is strongly connected.
2645
2646
EXAMPLES:
2647
2648
The circuit on 3 vertices is obviously strongly connected::
2649
2650
sage: g = DiGraph({0: [1], 1: [2], 2: [0]}, implementation="c_graph")
2651
sage: g.is_strongly_connected()
2652
True
2653
2654
But a transitive triangle is not::
2655
2656
sage: g = DiGraph({0: [1,2], 1: [2]}, implementation="c_graph")
2657
sage: g.is_strongly_connected()
2658
False
2659
"""
2660
cdef int v_int = 0
2661
2662
# Pick one vertex
2663
v_int = bitset_first((<CGraph>self._cg).active_vertices)
2664
2665
if v_int == -1:
2666
return True
2667
2668
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
2669
2670
return (<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v))) and \
2671
(<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v, reverse=True)))
2672
2673
def strongly_connected_component_containing_vertex(self, v):
2674
r"""
2675
Returns the strongly connected component containing the given vertex.
2676
2677
INPUT:
2678
2679
- ``v`` -- a vertex
2680
2681
EXAMPLES:
2682
2683
The digraph obtained from the ``PetersenGraph`` has an unique
2684
strongly connected component::
2685
2686
sage: g = DiGraph(graphs.PetersenGraph())
2687
sage: g.strongly_connected_component_containing_vertex(0)
2688
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2689
2690
In the Butterfly DiGraph, each vertex is a strongly connected
2691
component::
2692
2693
sage: g = digraphs.ButterflyGraph(3)
2694
sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v in g])
2695
True
2696
"""
2697
cdef int v_int = get_vertex(v,
2698
self.vertex_ints,
2699
self.vertex_labels,
2700
self._cg)
2701
cdef set a = set(self.depth_first_search(v))
2702
cdef set b = set(self.depth_first_search(v, reverse=True))
2703
return list(a & b)
2704
2705
def is_directed_acyclic(self, certificate = False):
2706
r"""
2707
Returns whether the graph is both directed and acylic (possibly with a
2708
certificate)
2709
2710
INPUT:
2711
2712
- ``certificate`` -- whether to return a certificate (``False`` by
2713
default).
2714
2715
OUTPUT:
2716
2717
When ``certificate=False``, returns a boolean value. When
2718
``certificate=True`` :
2719
2720
* If the graph is acyclic, returns a pair ``(True, ordering)`` where
2721
``ordering`` is a list of the vertices such that ``u`` appears
2722
before ``v`` in ``ordering`` if ``u, v`` is an edge.
2723
2724
* Else, returns a pair ``(False, cycle)`` where ``cycle`` is a list
2725
of vertices representing a circuit in the graph.
2726
2727
ALGORITHM:
2728
2729
We pick a vertex at random, think hard and find out that that if we are
2730
to remove the vertex from the graph we must remove all of its
2731
out-neighbors in the first place. So we put all of its out-neighbours in
2732
a stack, and repeat the same procedure with the vertex on top of the
2733
stack (when a vertex on top of the stack has no out-neighbors, we remove
2734
it immediately). Of course, for each vertex we only add its outneighbors
2735
to the end of the stack once : if for some reason the previous algorithm
2736
leads us to do it twice, it means we have found a circuit.
2737
2738
We keep track of the vertices whose out-neighborhood has been added to
2739
the stack once with a variable named ``tried``.
2740
2741
There is no reason why the graph should be empty at the end of this
2742
procedure, so we run it again on the remaining vertices until none are
2743
left or a circuit is found.
2744
2745
.. NOTE::
2746
2747
The graph is assumed to be directed. An exception is raised if it is
2748
not.
2749
2750
EXAMPLES:
2751
2752
At first, the following graph is acyclic::
2753
2754
sage: D = DiGraph({ 0:[1,2,3], 4:[2,5], 1:[8], 2:[7], 3:[7], 5:[6,7], 7:[8], 6:[9], 8:[10], 9:[10] })
2755
sage: D.plot(layout='circular').show()
2756
sage: D.is_directed_acyclic()
2757
True
2758
2759
Adding an edge from `9` to `7` does not change it::
2760
2761
sage: D.add_edge(9,7)
2762
sage: D.is_directed_acyclic()
2763
True
2764
2765
We can obtain as a proof an ordering of the vertices such that `u`
2766
appears before `v` if `uv` is an edge of the graph::
2767
2768
sage: D.is_directed_acyclic(certificate = True)
2769
(True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])
2770
2771
Adding an edge from 7 to 4, though, makes a difference::
2772
2773
sage: D.add_edge(7,4)
2774
sage: D.is_directed_acyclic()
2775
False
2776
2777
Indeed, it creates a circuit `7, 4, 5`::
2778
2779
sage: D.is_directed_acyclic(certificate = True)
2780
(False, [7, 4, 5])
2781
2782
Checking acyclic graphs are indeed acyclic ::
2783
2784
sage: def random_acyclic(n, p):
2785
... g = graphs.RandomGNP(n, p)
2786
... h = DiGraph()
2787
... h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
2788
... return h
2789
...
2790
sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time
2791
... for i in range(50)) # long time
2792
True
2793
"""
2794
2795
if not self._directed:
2796
raise ValueError("Input must be a directed graph.")
2797
2798
# Activated vertices
2799
cdef bitset_t activated
2800
bitset_init(activated, (<CGraph>self._cg).active_vertices.size)
2801
bitset_set_first_n(activated, (<CGraph>self._cg).active_vertices.size)
2802
2803
# Vertices whose neighbors have already been added to the stack
2804
cdef bitset_t tried
2805
bitset_init(tried, (<CGraph>self._cg).active_vertices.size)
2806
bitset_set_first_n(tried, 0)
2807
2808
# Parent of a vertex in the discovery tree
2809
cdef dict parent = {}
2810
2811
# The vertices left to be visited
2812
cdef list stack = []
2813
2814
# Final ordering, if the graph turns out to be acyclic
2815
cdef list ordering = []
2816
2817
# Circuit, if the graph turns out to contain one
2818
cdef list cycle
2819
2820
# We try any vertex as the source of the exploration tree
2821
for v in (<CGraph>self._cg).verts():
2822
2823
# We are not interested in trying de-activated vertices
2824
if bitset_not_in(activated, v):
2825
continue
2826
2827
stack = [v]
2828
2829
# For as long as some vertices are to be visited
2830
while stack:
2831
2832
# We take the last one (depth-first search)
2833
u = stack[-1]
2834
2835
# This vertex may have been deactivated since we added it.
2836
if bitset_not_in(activated, u):
2837
stack.pop(-1)
2838
continue
2839
2840
# If we tried this vertex already, it means that all of its
2841
# out-neighbors have been de-activated already, for we put them
2842
# *after* u in the stack.
2843
if bitset_in(tried, u):
2844
ordering.insert(0, vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
2845
bitset_discard(tried, u)
2846
bitset_discard(activated, u)
2847
stack.pop(-1)
2848
continue
2849
2850
2851
# If we never tried it, now is the time to do it. We also must
2852
# remember it
2853
bitset_add(tried, u)
2854
2855
# We append its out-neighbours to the stack.
2856
for uu in self._cg.out_neighbors(u):
2857
2858
# If we have found a new vertex, we put it at the end of the
2859
# stack. We ignored de-activated vertices.
2860
if bitset_not_in(tried, uu):
2861
if bitset_in(activated, uu):
2862
parent[uu] = u
2863
stack.append(uu)
2864
2865
# If we have already met this vertex, it means we have found
2866
# a circuit !
2867
else:
2868
bitset_free(activated)
2869
bitset_free(tried)
2870
2871
if not certificate:
2872
return False
2873
2874
# We build it, then return it
2875
# // answer = [u]
2876
cycle = [vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)]
2877
2878
tmp = u
2879
while u != uu:
2880
u = parent.get(u,uu)
2881
cycle.append(vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
2882
2883
cycle.reverse()
2884
return (False, cycle)
2885
2886
# No Cycle... Good news ! Let's return it.
2887
bitset_free(activated)
2888
bitset_free(tried)
2889
2890
if certificate:
2891
return (True, ordering)
2892
else:
2893
return True
2894
2895
cdef class Search_iterator:
2896
r"""
2897
An iterator for traversing a (di)graph.
2898
2899
This class is commonly used to perform a depth-first or breadth-first
2900
search. The class does not build all at once in memory the whole list of
2901
visited vertices. The class maintains the following variables:
2902
2903
- ``graph`` -- a graph whose vertices are to be iterated over.
2904
2905
- ``direction`` -- integer; this determines the position at which
2906
vertices to be visited are removed from the list ``stack``. For
2907
breadth-first search (BFS), element removal occurs at the start of the
2908
list, as signified by the value ``direction=0``. This is because in
2909
implementations of BFS, the list of vertices to visit are usually
2910
maintained by a queue, so element insertion and removal follow a
2911
first-in first-out (FIFO) protocol. For depth-first search (DFS),
2912
element removal occurs at the end of the list, as signified by the value
2913
``direction=-1``. The reason is that DFS is usually implemented using
2914
a stack to maintain the list of vertices to visit. Hence, element
2915
insertion and removal follow a last-in first-out (LIFO) protocol.
2916
2917
- ``stack`` -- a list of vertices to visit.
2918
2919
- ``seen`` -- a list of vertices that are already visited.
2920
2921
- ``test_out`` -- boolean; whether we want to consider the out-neighbors
2922
of the graph to be traversed. For undirected graphs, we consider both
2923
the in- and out-neighbors. However, for digraphs we only traverse along
2924
out-neighbors.
2925
2926
- ``test_in`` -- boolean; whether we want to consider the in-neighbors of
2927
the graph to be traversed. For undirected graphs, we consider both
2928
the in- and out-neighbors.
2929
2930
EXAMPLE::
2931
2932
sage: g = graphs.PetersenGraph()
2933
sage: list(g.breadth_first_search(0))
2934
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2935
"""
2936
2937
cdef graph
2938
cdef int direction
2939
cdef list stack
2940
cdef bitset_t seen
2941
cdef bint test_out
2942
cdef bint test_in
2943
2944
def __init__(self, graph, v, direction=0, reverse=False,
2945
ignore_direction=False):
2946
r"""
2947
Initialize an iterator for traversing a (di)graph.
2948
2949
INPUT:
2950
2951
- ``graph`` -- a graph to be traversed.
2952
2953
- ``v`` -- a vertex in ``graph`` from which to start the traversal.
2954
2955
- ``direction`` -- integer (default: ``0``). This determines the
2956
position at which vertices to be visited are removed from the list
2957
``stack`` of vertices to visit. For breadth-first search (BFS),
2958
element removal occurs at the start of the list, as signified by the
2959
value ``direction=0``. This is because in implementations of BFS,
2960
the list of vertices to visit are usually maintained by a queue, so
2961
element insertion and removal follow a first-in first-out (FIFO)
2962
protocol. For depth-first search (DFS), element removal occurs at
2963
the end of the list, as signified by the value ``direction=-1``. The
2964
reason is that DFS is usually implemented using a stack to maintain
2965
the list of vertices to visit. Hence, element insertion and removal
2966
follow a last-in first-out (LIFO) protocol.
2967
2968
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2969
to digraphs. If ``graph`` is a digraph, consider the reversed graph
2970
in which the out-neighbors become the in-neighbors and vice versa.
2971
2972
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2973
relevant to digraphs. If ``graph`` is a digraph, ignore all
2974
orientations and consider the graph as undirected.
2975
2976
EXAMPLE::
2977
2978
sage: g = graphs.PetersenGraph()
2979
sage: list(g.breadth_first_search(0))
2980
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2981
2982
TESTS:
2983
2984
A vertex which does not belong to the graph::
2985
2986
sage: list(g.breadth_first_search(-9))
2987
Traceback (most recent call last):
2988
...
2989
LookupError: Vertex (-9) is not a vertex of the graph.
2990
2991
An empty graph::
2992
2993
sage: list(Graph().breadth_first_search(''))
2994
Traceback (most recent call last):
2995
...
2996
LookupError: Vertex ('') is not a vertex of the graph.
2997
"""
2998
self.graph = graph
2999
self.direction = direction
3000
3001
bitset_init(self.seen, (<CGraph>self.graph._cg).active_vertices.size)
3002
bitset_set_first_n(self.seen, 0)
3003
3004
cdef int v_id = get_vertex(v,
3005
self.graph.vertex_ints,
3006
self.graph.vertex_labels,
3007
self.graph._cg)
3008
3009
if v_id == -1:
3010
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(repr(v)))
3011
3012
self.stack = [v_id]
3013
3014
if not self.graph.directed:
3015
ignore_direction = False
3016
3017
self.test_out = (not reverse) or ignore_direction
3018
self.test_in = reverse or ignore_direction
3019
3020
def __iter__(self):
3021
r"""
3022
Return an iterator object over a traversal of a graph.
3023
3024
EXAMPLE::
3025
3026
sage: g = graphs.PetersenGraph()
3027
sage: g.breadth_first_search(0)
3028
<generator object breadth_first_search at ...
3029
"""
3030
return self
3031
3032
def __next__(self):
3033
r"""
3034
Return the next vertex in a traversal of a graph.
3035
3036
EXAMPLE::
3037
3038
sage: g = graphs.PetersenGraph()
3039
sage: g.breadth_first_search(0)
3040
<generator object breadth_first_search at ...
3041
sage: g.breadth_first_search(0).next()
3042
0
3043
"""
3044
cdef int v_int
3045
cdef int w_int
3046
3047
while self.stack:
3048
v_int = self.stack.pop(self.direction)
3049
3050
if bitset_not_in(self.seen, v_int):
3051
value = vertex_label(v_int,
3052
self.graph.vertex_ints,
3053
self.graph.vertex_labels,
3054
self.graph._cg)
3055
bitset_add(self.seen, v_int)
3056
3057
if self.test_out:
3058
self.stack.extend(self.graph._cg.out_neighbors(v_int))
3059
if self.test_in:
3060
self.stack.extend(self.graph._cg_rev.out_neighbors(v_int))
3061
3062
break
3063
else:
3064
bitset_free(self.seen)
3065
raise StopIteration
3066
3067
return value
3068
3069