Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/base/c_graph.pyx
4056 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 "../../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 int * adjacency_sequence_in(self, int n, int *vertices, int v):
854
r"""
855
Returns the adjacency sequence corresponding to a list of vertices
856
and a vertex.
857
858
See the OUTPUT section for a formal definition.
859
860
See the function ``_test_adjacency_sequence()`` of
861
``dense_graph.pyx`` and ``sparse_graph.pyx`` for unit tests.
862
863
INPUT:
864
865
- ``n`` -- nonnegative integer; the maximum index in
866
``vertices`` up to which we want to consider. If ``n = 0``,
867
we only want to know if ``(vertices[0],v)`` is an edge. If
868
``n = 1``, we want to know whether ``(vertices[0],v)`` and
869
``(vertices[1],v)`` are edges. Let ``k`` be the length of
870
``vertices``. If ``0 <= n < k``, then we want to know if
871
``v`` is adjacent to each of ``vertices[0], vertices[1],
872
..., vertices[n]``. Where ``n = k - 1``, then we consider
873
all elements in the list ``vertices``.
874
875
- ``vertices`` -- list of vertices.
876
877
- ``v`` -- a vertex.
878
879
- ``reverse`` (bool) -- if set to ``True``, considers the
880
edges ``(v,vertices[i])`` instead of ``(v,vertices[i])``
881
(only useful for digraphs).
882
883
OUTPUT:
884
885
Returns a list of ``n`` integers, whose i-th element is set to
886
`1` iff ``(v,vertices[i])`` is an edge.
887
888
.. SEEALSO::
889
890
- :meth:`adjacency_sequence_out` -- Similar method for
891
``(v, vertices[i])`` instead of ``(vertices[i], v)`` (the
892
difference only matters for digraphs).
893
"""
894
cdef int i = 0
895
cdef int *seq = <int *>sage_malloc(n * sizeof(int))
896
for 0 <= i < n:
897
seq[i] = 1 if self.has_arc_unsafe(vertices[i], v) else 0
898
899
return seq
900
901
cdef int * adjacency_sequence_out(self, int n, int *vertices, int v):
902
r"""
903
Returns the adjacency sequence corresponding to a list of vertices
904
and a vertex.
905
906
See the OUTPUT section for a formal definition.
907
908
See the function ``_test_adjacency_sequence()`` of
909
``dense_graph.pyx`` and ``sparse_graph.pyx`` for unit tests.
910
911
INPUT:
912
913
- ``n`` -- nonnegative integer; the maximum index in
914
``vertices`` up to which we want to consider. If ``n = 0``,
915
we only want to know if ``(v, vertices[0])`` is an edge. If
916
``n = 1``, we want to know whether ``(v, vertices[0])`` and
917
``(v, vertices[1])`` are edges. Let ``k`` be the length of
918
``vertices``. If ``0 <= n < k``, then we want to know if
919
each of ``vertices[0], vertices[1], ..., vertices[n]`` is
920
adjacent to ``v``. Where ``n = k - 1``, then we consider all
921
elements in the list ``vertices``.
922
923
- ``vertices`` -- list of vertices.
924
925
- ``v`` -- a vertex.
926
927
OUTPUT:
928
929
Returns a list of ``n`` integers, whose i-th element is set to
930
`1` iff ``(v,vertices[i])`` is an edge.
931
932
.. SEEALSO::
933
934
- :meth:`adjacency_sequence_in` -- Similar method for
935
``(vertices[i],v)`` instead of ``(v,vertices[i])`` (the
936
difference only matters for digraphs).
937
938
"""
939
cdef int i = 0
940
cdef int *seq = <int *>sage_malloc(n * sizeof(int))
941
for 0 <= i < n:
942
seq[i] = 1 if self.has_arc_unsafe(v, vertices[i]) else 0
943
944
return seq
945
946
947
cpdef list all_arcs(self, int u, int v):
948
"""
949
Return the labels of all arcs from ``u`` to ``v``.
950
951
INPUT:
952
953
- ``u`` -- integer; the tail of an arc.
954
955
- ``v`` -- integer; the head of an arc.
956
957
OUTPUT:
958
959
- Raise ``NotImplementedError``. This method is not implemented at the
960
:class:`CGraph` level. A child class should provide a suitable
961
implementation.
962
963
.. SEEALSO::
964
965
- :meth:`all_arcs <sage.graphs.base.sparse_graph.SparseGraph.all_arcs>`
966
-- ``all_arcs`` method for sparse graphs.
967
968
EXAMPLE::
969
970
sage: from sage.graphs.base.c_graph import CGraph
971
sage: G = CGraph()
972
sage: G.all_arcs(0, 1)
973
Traceback (most recent call last):
974
...
975
NotImplementedError
976
"""
977
raise NotImplementedError()
978
979
cpdef list in_neighbors(self, int v):
980
"""
981
Gives the in-neighbors of the vertex ``v``.
982
983
INPUT:
984
985
- ``v`` -- integer representing a vertex of this graph.
986
987
OUTPUT:
988
989
- Raise ``NotImplementedError``. This method is not implemented at
990
the :class:`CGraph` level. A child class should provide a suitable
991
implementation.
992
993
.. SEEALSO::
994
995
- :meth:`in_neighbors <sage.graphs.base.sparse_graph.SparseGraph.in_neighbors>`
996
-- ``in_neighbors`` method for sparse graphs.
997
998
- :meth:`in_neighbors <sage.graphs.base.dense_graph.DenseGraph.in_neighbors>`
999
-- ``in_neighbors`` method for dense graphs.
1000
1001
EXAMPLE::
1002
1003
sage: from sage.graphs.base.c_graph import CGraph
1004
sage: G = CGraph()
1005
sage: G.in_neighbors(0)
1006
Traceback (most recent call last):
1007
...
1008
NotImplementedError
1009
"""
1010
raise NotImplementedError()
1011
1012
cpdef list out_neighbors(self, int u):
1013
"""
1014
Gives the out-neighbors of the vertex ``u``.
1015
1016
INPUT:
1017
1018
- ``u`` -- integer representing a vertex of this graph.
1019
1020
OUTPUT:
1021
1022
- Raise ``NotImplementedError``. This method is not implemented at the
1023
:class:`CGraph` level. A child class should provide a suitable
1024
implementation.
1025
1026
.. SEEALSO::
1027
1028
- :meth:`out_neighbors <sage.graphs.base.sparse_graph.SparseGraph.out_neighbors>`
1029
-- ``out_neighbors`` implementation for sparse graphs.
1030
1031
- :meth:`out_neighbors <sage.graphs.base.dense_graph.DenseGraph.out_neighbors>`
1032
-- ``out_neighbors`` implementation for dense graphs.
1033
1034
EXAMPLE::
1035
1036
sage: from sage.graphs.base.c_graph import CGraph
1037
sage: G = CGraph()
1038
sage: G.out_neighbors(0)
1039
Traceback (most recent call last):
1040
...
1041
NotImplementedError
1042
"""
1043
raise NotImplementedError()
1044
1045
def _in_degree(self, int v):
1046
"""
1047
Return the number of edges coming into ``v``.
1048
1049
INPUT:
1050
1051
- ``v`` -- a vertex of this graph.
1052
1053
OUTPUT:
1054
1055
- The number of in-neighbors of ``v``.
1056
1057
EXAMPLE::
1058
1059
sage: from sage.graphs.base.sparse_graph import SparseGraph
1060
sage: SparseGraph(7)._in_degree(3)
1061
0
1062
1063
TEST::
1064
1065
sage: g = Graph({1: [2,5], 2: [1,5,3,4], 3: [2,5], 4: [3], 5: [2,3]}, implementation="c_graph")
1066
sage: g._backend.degree(5, False)
1067
3
1068
"""
1069
if not self.has_vertex(v):
1070
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(v))
1071
return self.in_degrees[v]
1072
1073
def _out_degree(self, int v):
1074
"""
1075
Return the number of edges coming out of ``v``.
1076
1077
INPUT:
1078
1079
- ``v`` -- a vertex of this graph.
1080
1081
OUTPUT:
1082
1083
- The number of out-neighbors of ``v``.
1084
1085
EXAMPLE::
1086
1087
sage: from sage.graphs.base.sparse_graph import SparseGraph
1088
sage: SparseGraph(7)._out_degree(3)
1089
0
1090
"""
1091
if not self.has_vertex(v):
1092
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(v))
1093
return self.out_degrees[v]
1094
1095
def _num_verts(self):
1096
"""
1097
Return the number of vertices in the (di)graph.
1098
1099
INPUT:
1100
1101
- None.
1102
1103
OUTPUT:
1104
1105
- The order of this graph.
1106
1107
EXAMPLE::
1108
1109
sage: from sage.graphs.base.sparse_graph import SparseGraph
1110
sage: SparseGraph(7)._num_verts()
1111
7
1112
"""
1113
return self.num_verts
1114
1115
def _num_arcs(self):
1116
"""
1117
Return the number of arcs in ``self``.
1118
1119
INPUT:
1120
1121
- None.
1122
1123
OUTPUT:
1124
1125
- The size of this graph.
1126
1127
EXAMPLE::
1128
1129
sage: from sage.graphs.base.sparse_graph import SparseGraph
1130
sage: SparseGraph(7)._num_arcs()
1131
0
1132
"""
1133
return self.num_arcs
1134
1135
cdef int get_vertex(object u, dict vertex_ints, dict vertex_labels,
1136
CGraph G) except ? -2:
1137
"""
1138
Returns an int representing the arbitrary hashable vertex u (whether or not
1139
u is actually in the graph), or -1 if a new association must be made for u
1140
to be a vertex.
1141
1142
TESTS:
1143
1144
We check that the bug described in #8406 is gone::
1145
1146
sage: G = Graph()
1147
sage: R.<a> = GF(3**3)
1148
sage: S.<x> = R[]
1149
sage: G.add_vertex(a**2)
1150
sage: G.add_vertex(x)
1151
sage: G.vertices()
1152
[a^2, x]
1153
1154
And that the bug described in #9610 is gone::
1155
1156
sage: n = 20
1157
sage: k = 3
1158
sage: g = DiGraph()
1159
sage: g.add_edges( (i,Mod(i+j,n)) for i in range(n) for j in range(1,k+1) )
1160
sage: g.vertices()
1161
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
1162
sage: g.strongly_connected_components()
1163
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]]
1164
1165
"""
1166
cdef int u_int
1167
if u in vertex_ints:
1168
return vertex_ints[u]
1169
try:
1170
u_int = u
1171
except:
1172
return -1
1173
if u_int < 0 or u_int >= G.active_vertices.size or u_int in vertex_labels:
1174
return -1
1175
return u_int
1176
1177
cdef object vertex_label(int u_int, dict vertex_ints, dict vertex_labels,
1178
CGraph G):
1179
"""
1180
Returns the object represented by u_int, or None if this does not represent
1181
a vertex.
1182
"""
1183
if u_int in vertex_labels:
1184
return vertex_labels[u_int]
1185
elif bitset_in(G.active_vertices, u_int):
1186
return u_int
1187
else:
1188
return None
1189
1190
cdef int check_vertex(object u, dict vertex_ints, dict vertex_labels,
1191
CGraph G, CGraph G_rev, bint reverse) except ? -1:
1192
"""
1193
Returns an int representing the arbitrary hashable vertex u, and updates,
1194
if necessary, the translation dict and list. Adds a vertex if the label
1195
is new.
1196
"""
1197
cdef int u_int = get_vertex(u, vertex_ints, vertex_labels, G)
1198
if u_int != -1:
1199
if not bitset_in(G.active_vertices, u_int):
1200
bitset_add(G.active_vertices, u_int)
1201
G.num_verts += 1
1202
if reverse:
1203
bitset_add(G_rev.active_vertices, u_int)
1204
G_rev.num_verts += 1
1205
return u_int
1206
u_int = bitset_first_in_complement(G.active_vertices)
1207
if u_int == -1:
1208
G.realloc(2*G.active_vertices.size)
1209
if reverse:
1210
G_rev.realloc(2*G_rev.active_vertices.size)
1211
return check_vertex(u, vertex_ints, vertex_labels, G, G_rev, reverse)
1212
vertex_labels[u_int] = u
1213
vertex_ints[u] = u_int
1214
G.add_vertex(u_int)
1215
if reverse:
1216
G_rev.add_vertex(u_int)
1217
return u_int
1218
1219
class CGraphBackend(GenericGraphBackend):
1220
"""
1221
Base class for sparse and dense graph backends.
1222
1223
::
1224
1225
sage: from sage.graphs.base.c_graph import CGraphBackend
1226
1227
This class is extended by
1228
:class:`SparseGraphBackend <sage.graphs.base.sparse_graph.SparseGraphBackend>`
1229
and
1230
:class:`DenseGraphBackend <sage.graphs.base.dense_graph.DenseGraphBackend>`,
1231
which are fully functional backends. This class is mainly just for vertex
1232
functions, which are the same for both. A :class:`CGraphBackend` will not
1233
work on its own::
1234
1235
sage: from sage.graphs.base.c_graph import CGraphBackend
1236
sage: CGB = CGraphBackend()
1237
sage: CGB.degree(0, True)
1238
Traceback (most recent call last):
1239
...
1240
AttributeError: 'CGraphBackend' object has no attribute 'vertex_ints'
1241
1242
The appropriate way to use these backends is via Sage graphs::
1243
1244
sage: G = Graph(30, implementation="c_graph")
1245
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
1246
sage: G.edges(labels=False)
1247
[(0, 1), (0, 3), (4, 5), (9, 23)]
1248
1249
.. SEEALSO::
1250
1251
- :class:`SparseGraphBackend <sage.graphs.base.sparse_graph.SparseGraphBackend>`
1252
-- backend for sparse graphs.
1253
1254
- :class:`DenseGraphBackend <sage.graphs.base.dense_graph.DenseGraphBackend>`
1255
-- backend for dense graphs.
1256
"""
1257
1258
_cg = None
1259
_cg_rev = None
1260
_directed = None
1261
1262
def has_vertex(self, v):
1263
"""
1264
Returns whether ``v`` is a vertex of ``self``.
1265
1266
INPUT:
1267
1268
- ``v`` -- any object.
1269
1270
OUTPUT:
1271
1272
- ``True`` if ``v`` is a vertex of this graph; ``False`` otherwise.
1273
1274
EXAMPLE::
1275
1276
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1277
sage: B = SparseGraphBackend(7)
1278
sage: B.has_vertex(6)
1279
True
1280
sage: B.has_vertex(7)
1281
False
1282
"""
1283
cdef v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
1284
self._cg)
1285
if v_int == -1:
1286
return False
1287
if not bitset_in((<CGraph>self._cg).active_vertices, v_int):
1288
return False
1289
return True
1290
1291
def degree(self, v, directed):
1292
"""
1293
Return the degree of the vertex ``v``.
1294
1295
INPUT:
1296
1297
- ``v`` -- a vertex of the graph.
1298
1299
- ``directed`` -- boolean; whether to take into account the
1300
orientation of this graph in counting the degree of ``v``.
1301
1302
OUTPUT:
1303
1304
- The degree of vertex ``v``.
1305
1306
EXAMPLE::
1307
1308
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1309
sage: B = SparseGraphBackend(7)
1310
sage: B.degree(3, False)
1311
0
1312
1313
TESTS:
1314
1315
Ensure that ticket #8395 is fixed. ::
1316
1317
sage: def my_add_edges(G, m, n):
1318
... for i in range(m):
1319
... u = randint(0, n)
1320
... v = randint(0, n)
1321
... G.add_edge(u, v)
1322
sage: G = Graph({1:[1]}); G
1323
Looped graph on 1 vertex
1324
sage: G.edges(labels=False)
1325
[(1, 1)]
1326
sage: G.degree(); G.size()
1327
[2]
1328
1
1329
sage: sum(G.degree()) == 2 * G.size()
1330
True
1331
sage: G = Graph({1:[1,2], 2:[2,3]}, loops=True); G
1332
Looped graph on 3 vertices
1333
sage: my_add_edges(G, 100, 50)
1334
sage: sum(G.degree()) == 2 * G.size()
1335
True
1336
sage: G = Graph({1:[2,2], 2:[3]}); G
1337
Multi-graph on 3 vertices
1338
sage: G.edges(labels=False)
1339
[(1, 2), (1, 2), (2, 3)]
1340
sage: G.degree(); G.size()
1341
[2, 3, 1]
1342
3
1343
sage: sum(G.degree()) == 2 * G.size()
1344
True
1345
sage: G.allow_loops(True); G
1346
Looped multi-graph on 3 vertices
1347
sage: my_add_edges(G, 100, 50)
1348
sage: sum(G.degree()) == 2 * G.size()
1349
True
1350
sage: D = DiGraph({1:[2], 2:[1,3]}); D
1351
Digraph on 3 vertices
1352
sage: D.edges(labels=False)
1353
[(1, 2), (2, 1), (2, 3)]
1354
sage: D.degree(); D.size()
1355
[2, 3, 1]
1356
3
1357
sage: sum(D.degree()) == 2 * D.size()
1358
True
1359
sage: D.allow_loops(True); D
1360
Looped digraph on 3 vertices
1361
sage: my_add_edges(D, 100, 50)
1362
sage: sum(D.degree()) == 2 * D.size()
1363
True
1364
sage: D.allow_multiple_edges(True)
1365
sage: my_add_edges(D, 200, 50)
1366
sage: sum(D.degree()) == 2 * D.size()
1367
True
1368
sage: G = Graph({1:[2,2,2]})
1369
sage: G.allow_loops(True)
1370
sage: G.add_edge(1,1)
1371
sage: G.add_edge(1,1)
1372
sage: G.edges(labels=False)
1373
[(1, 1), (1, 1), (1, 2), (1, 2), (1, 2)]
1374
sage: G.degree(1)
1375
7
1376
sage: G.allow_loops(False)
1377
sage: G.edges(labels=False)
1378
[(1, 2), (1, 2), (1, 2)]
1379
sage: G.degree(1)
1380
3
1381
sage: G = Graph({1:{2:['a','a','a']}})
1382
sage: G.allow_loops(True)
1383
sage: G.add_edge(1,1,'b')
1384
sage: G.add_edge(1,1,'b')
1385
sage: G.add_edge(1,1)
1386
sage: G.add_edge(1,1)
1387
sage: G.edges()
1388
[(1, 1, None), (1, 1, None), (1, 1, 'b'), (1, 1, 'b'), (1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1389
sage: G.degree(1)
1390
11
1391
sage: G.allow_loops(False)
1392
sage: G.edges()
1393
[(1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1394
sage: G.degree(1)
1395
3
1396
sage: G = Graph({1:{2:['a','a','a']}})
1397
sage: G.allow_loops(True)
1398
sage: G.add_edge(1,1,'b')
1399
sage: G.add_edge(1,1,'b')
1400
sage: G.edges()
1401
[(1, 1, 'b'), (1, 1, 'b'), (1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1402
sage: G.degree(1)
1403
7
1404
sage: G.allow_loops(False)
1405
sage: G.edges()
1406
[(1, 2, 'a'), (1, 2, 'a'), (1, 2, 'a')]
1407
sage: G.degree(1)
1408
3
1409
1410
"""
1411
cdef v_int = get_vertex(v,
1412
self.vertex_ints,
1413
self.vertex_labels,
1414
self._cg)
1415
if directed:
1416
return self._cg._in_degree(v_int) + self._cg._out_degree(v_int)
1417
d = 0
1418
if self._loops and self.has_edge(v, v, None):
1419
if self._multiple_edges:
1420
d += len(self.get_edge_label(v, v))
1421
else:
1422
d += 1
1423
return self._cg._out_degree(v_int) + d
1424
1425
1426
def out_degree(self, v):
1427
r"""
1428
Returns the out-degree of v
1429
1430
INPUT:
1431
1432
- ``v`` -- a vertex of the graph.
1433
1434
- ``directed`` -- boolean; whether to take into account the
1435
orientation of this graph in counting the degree of ``v``.
1436
1437
1438
EXAMPLE::
1439
1440
1441
sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } )
1442
sage: D.out_degree(1)
1443
2
1444
"""
1445
cdef v_int = get_vertex(v,
1446
self.vertex_ints,
1447
self.vertex_labels,
1448
self._cg)
1449
if self._directed:
1450
return self._cg._out_degree(v_int)
1451
d = 0
1452
if self._loops and self.has_edge(v, v, None):
1453
if self._multiple_edges:
1454
d += len(self.get_edge_label(v, v))
1455
else:
1456
d += 1
1457
1458
return self._cg._out_degree(v_int) + d
1459
1460
1461
def add_vertex(self, object name):
1462
"""
1463
Add a vertex to ``self``.
1464
1465
INPUT:
1466
1467
- ``name`` -- the vertex to be added (must be hashable). If ``None``,
1468
a new name is created.
1469
1470
OUTPUT:
1471
1472
- If name=None, the new vertex name is returned.
1473
None otherwise.
1474
1475
.. SEEALSO::
1476
1477
- :meth:`add_vertices`
1478
-- add a bunch of vertices of this graph.
1479
1480
- :meth:`has_vertex`
1481
-- returns whether or not this graph has a specific vertex.
1482
1483
EXAMPLE::
1484
1485
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1486
sage: D.add_vertex(10)
1487
sage: D.add_vertex([])
1488
Traceback (most recent call last):
1489
...
1490
TypeError: unhashable type: 'list'
1491
1492
::
1493
1494
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1495
sage: S.add_vertex(10)
1496
sage: S.add_vertex([])
1497
Traceback (most recent call last):
1498
...
1499
TypeError: unhashable type: 'list'
1500
"""
1501
retval = None
1502
if name is None:
1503
name = 0
1504
while name in self.vertex_ints or (
1505
name not in self.vertex_labels and
1506
bitset_in((<CGraph>self._cg).active_vertices, name)):
1507
name += 1
1508
retval = name
1509
1510
check_vertex(name,
1511
self.vertex_ints,
1512
self.vertex_labels,
1513
self._cg,
1514
self._cg_rev,
1515
(self._directed and
1516
self._cg_rev is not None)) # this will add the vertex
1517
1518
return retval
1519
1520
def add_vertices(self, object vertices):
1521
"""
1522
Add vertices to ``self``.
1523
1524
INPUT:
1525
1526
- ``vertices``: iterator of vertex labels. A new name is created, used and returned in
1527
the output list for all ``None`` values in ``vertices``.
1528
1529
OUTPUT:
1530
1531
Generated names of new vertices if there is at least one ``None`` value
1532
present in ``vertices``. ``None`` otherwise.
1533
1534
.. SEEALSO::
1535
1536
- :meth:`add_vertex`
1537
-- add a vertex to this graph.
1538
1539
EXAMPLE::
1540
1541
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(1)
1542
sage: D.add_vertices([1,2,3])
1543
sage: D.add_vertices([None]*4)
1544
[4, 5, 6, 7]
1545
1546
::
1547
1548
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(0)
1549
sage: G.add_vertices([0,1])
1550
sage: list(G.iterator_verts(None))
1551
[0, 1]
1552
sage: list(G.iterator_edges([0,1], True))
1553
[]
1554
1555
::
1556
1557
sage: import sage.graphs.base.dense_graph
1558
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1559
sage: D.add_vertices([10,11,12])
1560
"""
1561
cdef object v
1562
cdef int nones = 0
1563
for v in vertices:
1564
if v is not None:
1565
self.add_vertex(v)
1566
else:
1567
nones += 1
1568
1569
new_names = []
1570
while nones > 0:
1571
new_names.append(self.add_vertex(None))
1572
nones -= 1
1573
1574
return new_names if new_names != [] else None
1575
1576
def del_vertex(self, v):
1577
"""
1578
Delete a vertex in ``self``, failing silently if the vertex is not
1579
in the graph.
1580
1581
INPUT:
1582
1583
- ``v`` -- vertex to be deleted.
1584
1585
OUTPUT:
1586
1587
- None.
1588
1589
.. SEEALSO::
1590
1591
- :meth:`del_vertices`
1592
-- delete a bunch of vertices from this graph.
1593
1594
EXAMPLE::
1595
1596
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1597
sage: D.del_vertex(0)
1598
sage: D.has_vertex(0)
1599
False
1600
1601
::
1602
1603
sage: S = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1604
sage: S.del_vertex(0)
1605
sage: S.has_vertex(0)
1606
False
1607
"""
1608
if not self.has_vertex(v):
1609
return
1610
cdef int v_int = get_vertex(v,
1611
self.vertex_ints,
1612
self.vertex_labels,
1613
self._cg)
1614
1615
# delete each arc incident with v and v
1616
self._cg.del_vertex(v_int)
1617
if self._cg_rev is not None:
1618
self._cg_rev.del_vertex(v_int)
1619
1620
# add v to unused vertices
1621
if v_int in self.vertex_labels:
1622
self.vertex_ints.pop(v)
1623
self.vertex_labels.pop(v_int)
1624
1625
def del_vertices(self, vertices):
1626
"""
1627
Delete vertices from an iterable container.
1628
1629
INPUT:
1630
1631
- ``vertices`` -- iterator of vertex labels.
1632
1633
OUTPUT:
1634
1635
- Same as for :meth:`del_vertex`.
1636
1637
.. SEEALSO::
1638
1639
- :meth:`del_vertex`
1640
-- delete a vertex of this graph.
1641
1642
EXAMPLE::
1643
1644
sage: import sage.graphs.base.dense_graph
1645
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1646
sage: D.del_vertices([7,8])
1647
sage: D.has_vertex(7)
1648
False
1649
sage: D.has_vertex(6)
1650
True
1651
1652
::
1653
1654
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1655
sage: D.del_vertices([1,2,3])
1656
sage: D.has_vertex(1)
1657
False
1658
sage: D.has_vertex(0)
1659
True
1660
"""
1661
cdef object v
1662
for v in vertices:
1663
self.del_vertex(v)
1664
1665
def iterator_nbrs(self, v):
1666
"""
1667
Returns an iterator over the neighbors of ``v``.
1668
1669
INPUT:
1670
1671
- ``v`` -- a vertex of this graph.
1672
1673
OUTPUT:
1674
1675
- An iterator over the neighbors the vertex ``v``.
1676
1677
.. SEEALSO::
1678
1679
- :meth:`iterator_in_nbrs`
1680
-- returns an iterator over the in-neighbors of a vertex.
1681
1682
- :meth:`iterator_out_nbrs`
1683
-- returns an iterator over the out-neighbors of a vertex.
1684
1685
- :meth:`iterator_verts`
1686
-- returns an iterator over a given set of vertices.
1687
1688
EXAMPLE::
1689
1690
sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")
1691
sage: list(P._backend.iterator_nbrs(0))
1692
[1, 4, 5]
1693
"""
1694
return iter(set(self.iterator_in_nbrs(v)) |
1695
set(self.iterator_out_nbrs(v)))
1696
1697
def iterator_in_nbrs(self, v):
1698
"""
1699
Returns an iterator over the incoming neighbors of ``v``.
1700
1701
INPUT:
1702
1703
- ``v`` -- a vertex of this graph.
1704
1705
OUTPUT:
1706
1707
- An iterator over the in-neighbors of the vertex ``v``.
1708
1709
.. SEEALSO::
1710
1711
- :meth:`iterator_nbrs`
1712
-- returns an iterator over the neighbors of a vertex.
1713
1714
- :meth:`iterator_out_nbrs`
1715
-- returns an iterator over the out-neighbors of a vertex.
1716
1717
EXAMPLE::
1718
1719
sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph")
1720
sage: list(P._backend.iterator_in_nbrs(0))
1721
[1, 4, 5]
1722
"""
1723
cdef int u_int
1724
cdef int v_int = get_vertex(v,
1725
self.vertex_ints,
1726
self.vertex_labels,
1727
self._cg)
1728
# Sparse
1729
if self._cg_rev is not None:
1730
return iter([vertex_label(u_int,
1731
self.vertex_ints,
1732
self.vertex_labels,
1733
self._cg)
1734
for u_int in self._cg_rev.out_neighbors(v_int)])
1735
# Dense
1736
else:
1737
return iter([vertex_label(u_int,
1738
self.vertex_ints,
1739
self.vertex_labels,
1740
self._cg)
1741
for u_int in self._cg.in_neighbors(v_int)])
1742
1743
def iterator_out_nbrs(self, v):
1744
"""
1745
Returns an iterator over the outgoing neighbors of ``v``.
1746
1747
INPUT:
1748
1749
- ``v`` -- a vertex of this graph.
1750
1751
OUTPUT:
1752
1753
- An iterator over the out-neighbors of the vertex ``v``.
1754
1755
.. SEEALSO::
1756
1757
- :meth:`iterator_nbrs`
1758
-- returns an iterator over the neighbors of a vertex.
1759
1760
- :meth:`iterator_in_nbrs`
1761
-- returns an iterator over the in-neighbors of a vertex.
1762
1763
EXAMPLE::
1764
1765
sage: P = DiGraph(graphs.PetersenGraph().to_directed(), implementation="c_graph")
1766
sage: list(P._backend.iterator_out_nbrs(0))
1767
[1, 4, 5]
1768
"""
1769
cdef u_int
1770
cdef int v_int = get_vertex(v,
1771
self.vertex_ints,
1772
self.vertex_labels,
1773
self._cg)
1774
return iter([vertex_label(u_int,
1775
self.vertex_ints,
1776
self.vertex_labels,
1777
self._cg)
1778
for u_int in self._cg.out_neighbors(v_int)])
1779
1780
def iterator_verts(self, verts=None):
1781
"""
1782
Returns an iterator over the vertices of ``self`` intersected with
1783
``verts``.
1784
1785
INPUT:
1786
1787
- ``verts`` -- an iterable container of objects (default: ``None``).
1788
1789
OUTPUT:
1790
1791
- If ``verts=None``, return an iterator over all vertices of this
1792
graph.
1793
1794
- If ``verts`` is an iterable container of vertices, find the
1795
intersection of ``verts`` with the vertex set of this graph and
1796
return an iterator over the resulting intersection.
1797
1798
.. SEEALSO::
1799
1800
- :meth:`iterator_nbrs`
1801
-- returns an iterator over the neighbors of a vertex.
1802
1803
EXAMPLE::
1804
1805
sage: P = Graph(graphs.PetersenGraph(), implementation="c_graph")
1806
sage: list(P._backend.iterator_verts(P))
1807
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1808
sage: list(P._backend.iterator_verts())
1809
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1810
sage: list(P._backend.iterator_verts([1, 2, 3]))
1811
[1, 2, 3]
1812
sage: list(P._backend.iterator_verts([1, 2, 10]))
1813
[1, 2]
1814
"""
1815
cdef int i
1816
cdef object v
1817
if verts is None:
1818
S = set(self.vertex_ints.iterkeys())
1819
for i from 0 <= i < (<CGraph>self._cg).active_vertices.size:
1820
if (i not in self.vertex_labels and
1821
bitset_in((<CGraph>self._cg).active_vertices, i)):
1822
S.add(i)
1823
return iter(S)
1824
is_hashable = False
1825
try:
1826
v = hash(verts)
1827
is_hashable = True
1828
except:
1829
pass
1830
if is_hashable and self.has_vertex(verts):
1831
return iter([verts])
1832
else:
1833
L = []
1834
for v in verts:
1835
if self.has_vertex(v):
1836
L.append(v)
1837
return iter(L)
1838
1839
def loops(self, new=None):
1840
"""
1841
Returns whether loops are allowed in this graph.
1842
1843
INPUT:
1844
1845
- ``new`` -- (default: ``None``); boolean (to set) or ``None``
1846
(to get).
1847
1848
OUTPUT:
1849
1850
- If ``new=None``, return ``True`` if this graph allows self-loops or
1851
``False`` if self-loops are not allowed.
1852
1853
- If ``new`` is a boolean, set the self-loop permission of this graph
1854
according to the boolean value of ``new``.
1855
1856
EXAMPLE::
1857
1858
sage: G = Graph(implementation='c_graph')
1859
sage: G._backend.loops()
1860
False
1861
sage: G._backend.loops(True)
1862
sage: G._backend.loops()
1863
True
1864
"""
1865
if new is None:
1866
return self._loops
1867
if new:
1868
self._loops = True
1869
else:
1870
self._loops = False
1871
1872
def name(self, new=None):
1873
"""
1874
Returns the name of this graph.
1875
1876
INPUT:
1877
1878
- ``new`` -- (default: ``None``); boolean (to set) or ``None``
1879
(to get).
1880
1881
OUTPUT:
1882
1883
- If ``new=None``, return the name of this graph. Otherwise, set the
1884
name of this graph to the value of ``new``.
1885
1886
EXAMPLE::
1887
1888
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
1889
sage: G._backend.name()
1890
'Petersen graph'
1891
sage: G._backend.name("Peter Pan's graph")
1892
sage: G._backend.name()
1893
"Peter Pan's graph"
1894
"""
1895
if new is None:
1896
return self._name
1897
self._name = new
1898
1899
def num_edges(self, directed):
1900
"""
1901
Returns the number of edges in ``self``.
1902
1903
INPUT:
1904
1905
- ``directed`` -- boolean; whether to count ``(u,v)`` and ``(v,u)``
1906
as one or two edges.
1907
1908
OUTPUT:
1909
1910
- If ``directed=True``, counts the number of directed edges in this
1911
graph. Otherwise, return the size of this graph.
1912
1913
.. SEEALSO::
1914
1915
- :meth:`num_verts`
1916
-- return the order of this graph.
1917
1918
EXAMPLE::
1919
1920
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
1921
sage: G._backend.num_edges(False)
1922
15
1923
1924
TESTS:
1925
1926
Ensure that ticket #8395 is fixed. ::
1927
1928
sage: G = Graph({1:[1]}); G
1929
Looped graph on 1 vertex
1930
sage: G.edges(labels=False)
1931
[(1, 1)]
1932
sage: G.size()
1933
1
1934
sage: G = Graph({1:[2,2]}); G
1935
Multi-graph on 2 vertices
1936
sage: G.edges(labels=False)
1937
[(1, 2), (1, 2)]
1938
sage: G.size()
1939
2
1940
sage: G = Graph({1:[1,1]}); G
1941
Looped multi-graph on 1 vertex
1942
sage: G.edges(labels=False)
1943
[(1, 1), (1, 1)]
1944
sage: G.size()
1945
2
1946
sage: D = DiGraph({1:[1]}); D
1947
Looped digraph on 1 vertex
1948
sage: D.edges(labels=False)
1949
[(1, 1)]
1950
sage: D.size()
1951
1
1952
sage: D = DiGraph({1:[2,2], 2:[1,1]}); D
1953
Multi-digraph on 2 vertices
1954
sage: D.edges(labels=False)
1955
[(1, 2), (1, 2), (2, 1), (2, 1)]
1956
sage: D.size()
1957
4
1958
sage: D = DiGraph({1:[1,1]}); D
1959
Looped multi-digraph on 1 vertex
1960
sage: D.edges(labels=False)
1961
[(1, 1), (1, 1)]
1962
sage: D.size()
1963
2
1964
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1965
sage: S = SparseGraphBackend(7)
1966
sage: S.num_edges(directed=False)
1967
0
1968
sage: S.loops(True)
1969
sage: S.add_edge(1, 1, None, directed=False)
1970
sage: S.num_edges(directed=False)
1971
1
1972
sage: S.multiple_edges(True)
1973
sage: S.add_edge(1, 1, None, directed=False)
1974
sage: S.num_edges(directed=False)
1975
2
1976
sage: from sage.graphs.base.dense_graph import DenseGraphBackend
1977
sage: D = DenseGraphBackend(7)
1978
sage: D.num_edges(directed=False)
1979
0
1980
sage: D.loops(True)
1981
sage: D.add_edge(1, 1, None, directed=False)
1982
sage: D.num_edges(directed=False)
1983
1
1984
"""
1985
if directed:
1986
return self._cg._num_arcs()
1987
else:
1988
i = self._cg._num_arcs()
1989
k = 0
1990
if self.loops(None):
1991
if self.multiple_edges(None):
1992
for j in self.iterator_verts():
1993
if self.has_edge(j, j, None):
1994
k += len(self.get_edge_label(j, j))
1995
else:
1996
for j in self.iterator_verts():
1997
if self.has_edge(j, j, None):
1998
k += 1
1999
i = (i - k) / 2
2000
return i + k
2001
2002
def num_verts(self):
2003
"""
2004
Returns the number of vertices in ``self``.
2005
2006
INPUT:
2007
2008
- None.
2009
2010
OUTPUT:
2011
2012
- The order of this graph.
2013
2014
.. SEEALSO::
2015
2016
- :meth:`num_edges`
2017
-- return the number of (directed) edges in this graph.
2018
2019
EXAMPLE::
2020
2021
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2022
sage: G._backend.num_verts()
2023
10
2024
"""
2025
return (<CGraph>self._cg).num_verts
2026
2027
def relabel(self, perm, directed):
2028
"""
2029
Relabels the graph according to ``perm``.
2030
2031
INPUT:
2032
2033
- ``perm`` -- anything which represents a permutation as
2034
``v --> perm[v]``, for example a dict or a list.
2035
2036
- ``directed`` -- ignored (this is here for compatibility with other
2037
backends).
2038
2039
EXAMPLES::
2040
2041
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2042
sage: G._backend.relabel(range(9,-1,-1), False)
2043
sage: G.edges()
2044
[(0, 2, None),
2045
(0, 3, None),
2046
(0, 5, None),
2047
(1, 3, None),
2048
(1, 4, None),
2049
(1, 6, None),
2050
(2, 4, None),
2051
(2, 7, None),
2052
(3, 8, None),
2053
(4, 9, None),
2054
(5, 6, None),
2055
(5, 9, None),
2056
(6, 7, None),
2057
(7, 8, None),
2058
(8, 9, None)]
2059
"""
2060
cdef int i
2061
cdef object v
2062
cdef dict new_vx_ints = {}
2063
cdef dict new_vx_labels = {}
2064
for v in self.iterator_verts(None):
2065
i = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg)
2066
new_vx_ints[perm[v]] = i
2067
new_vx_labels[i] = perm[v]
2068
self.vertex_ints = new_vx_ints
2069
self.vertex_labels = new_vx_labels
2070
2071
def shortest_path(self, x, y):
2072
r"""
2073
Returns the shortest path between ``x`` and ``y``.
2074
2075
INPUT:
2076
2077
- ``x`` -- the starting vertex in the shortest path from ``x`` to
2078
``y``.
2079
2080
- ``y`` -- the end vertex in the shortest path from ``x`` to ``y``.
2081
2082
OUTPUT:
2083
2084
- A list of vertices in the shortest path from ``x`` to ``y``.
2085
2086
EXAMPLE::
2087
2088
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2089
sage: G.shortest_path(0, 1)
2090
[0, 1]
2091
"""
2092
if x == y:
2093
return 0
2094
2095
# The function being mostly symmetric in x and y, their roles are
2096
# reversed at the end of each loop. For this reason is defined, for
2097
# example, two dictionaries dist_y and dist_x containing the distances
2098
# to x and y, and a dictionary dist_current and dist_other, pointing
2099
# toward the previous two, alternatively.
2100
#
2101
# Besides, there is another difference in the fact that for directed
2102
# graphs we are interested in paths leaving x toward y, so we are
2103
# considering the out_neighbors on x's side, and in_neighbors on
2104
# y's side.
2105
2106
cdef int x_int = get_vertex(x,
2107
self.vertex_ints,
2108
self.vertex_labels,
2109
self._cg)
2110
cdef int y_int = get_vertex(y,
2111
self.vertex_ints,
2112
self.vertex_labels,
2113
self._cg)
2114
cdef int u = 0
2115
cdef int v = 0
2116
cdef int w = 0
2117
2118
# Each vertex knows its predecessors in the search, for each side
2119
cdef dict pred_x = {}
2120
cdef dict pred_y = {}
2121
cdef dict pred_current = pred_x
2122
cdef dict pred_other = pred_y
2123
2124
# Stores the distances from x and y
2125
cdef dict dist_x = {}
2126
cdef dict dist_y = {}
2127
cdef dict dist_current = dist_x
2128
cdef dict dist_other = dist_y
2129
dist_x[x_int] = 0
2130
dist_y[y_int] = 0
2131
2132
# Lists of vertices whose neighbors have not been explored yet
2133
cdef list next_x = [x_int]
2134
cdef list next_y = [y_int]
2135
cdef list next_current = next_x
2136
cdef list next_other = next_y
2137
cdef list next_temporary = []
2138
cdef list neighbors
2139
2140
cdef list shortest_path = []
2141
2142
# We are interested in edges leaving x and entering y, so we
2143
# are dealing with two different "neighbors" functions
2144
cdef int out = 1
2145
2146
# As long as the current side (x or y) is not totally explored ...
2147
while next_current:
2148
next_temporary = []
2149
2150
# Take the next vertex in the list, and study all of its neighbors.
2151
# When a new neighbor is found, it is added into a temporary list.
2152
# When all the vertices in the list are tested
2153
# and next_current is replaced by the temporary list
2154
#
2155
# After this, current and other are reversed, and the loop restarts
2156
for u in next_current:
2157
if out == 1:
2158
neighbors = self._cg.out_neighbors(u)
2159
elif self._cg_rev is not None: # Sparse
2160
neighbors = self._cg_rev.out_neighbors(u)
2161
else: # Dense
2162
neighbors = self._cg.in_neighbors(u)
2163
for v in neighbors:
2164
# If the neighbor is new, updates the distances and adds
2165
# to the list.
2166
if v not in dist_current:
2167
dist_current[v] = dist_current[u] + 1
2168
pred_current[v] = u
2169
next_current.append(v)
2170
2171
# If the new neighbor is already known by the other
2172
# side ...
2173
if v in dist_other:
2174
# build the shortest path and returns in.
2175
w = v
2176
2177
while w != x_int:
2178
shortest_path.append(
2179
vertex_label(w,
2180
self.vertex_ints,
2181
self.vertex_labels,
2182
self._cg))
2183
w = pred_x[w]
2184
2185
shortest_path.append(x)
2186
shortest_path.reverse()
2187
2188
if v == y_int:
2189
return shortest_path
2190
2191
w = pred_y[v]
2192
while w != y_int:
2193
shortest_path.append(
2194
vertex_label(w,
2195
self.vertex_ints,
2196
self.vertex_labels,
2197
self._cg))
2198
w = pred_y[w]
2199
shortest_path.append(y)
2200
2201
return shortest_path
2202
2203
next_current = next_temporary
2204
pred_current, pred_other = pred_other, pred_current
2205
dist_current, dist_other = dist_other, dist_current
2206
next_current, next_other = next_other, next_current
2207
out = -out
2208
2209
return []
2210
2211
def bidirectional_dijkstra(self, x, y):
2212
r"""
2213
Returns the shortest path between ``x`` and ``y`` using a
2214
bidirectional version of Dijkstra's algorithm.
2215
2216
INPUT:
2217
2218
- ``x`` -- the starting vertex in the shortest path from ``x`` to
2219
``y``.
2220
2221
- ``y`` -- the end vertex in the shortest path from ``x`` to ``y``.
2222
2223
OUTPUT:
2224
2225
- A list of vertices in the shortest path from ``x`` to ``y``.
2226
2227
EXAMPLE::
2228
2229
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2230
sage: for (u,v) in G.edges(labels=None):
2231
... G.set_edge_label(u,v,1)
2232
sage: G.shortest_path(0, 1, by_weight=True)
2233
[0, 1]
2234
2235
TEST:
2236
2237
Bugfix from #7673 ::
2238
2239
sage: G = Graph(implementation="networkx")
2240
sage: G.add_edges([(0,1,9),(0,2,8),(1,2,7)])
2241
sage: Gc = G.copy(implementation='c_graph')
2242
sage: sp = G.shortest_path_length(0,1,by_weight=True)
2243
sage: spc = Gc.shortest_path_length(0,1,by_weight=True)
2244
sage: sp == spc
2245
True
2246
"""
2247
if x == y:
2248
return 0
2249
2250
# ****************** WARNING **********************
2251
# Use Python to maintain a heap...
2252
# Rewrite this in Cython as soon as possible !
2253
# *************************************************
2254
from heapq import heappush, heappop
2255
2256
# As for shortest_path, the roles of x and y are symmetric, hence we
2257
# define dictionaries like pred_current and pred_other, which
2258
# represent alternatively pred_x or pred_y according to the side
2259
# studied.
2260
cdef int x_int = get_vertex(x,
2261
self.vertex_ints,
2262
self.vertex_labels,
2263
self._cg)
2264
cdef int y_int = get_vertex(y,
2265
self.vertex_ints,
2266
self.vertex_labels,
2267
self._cg)
2268
cdef int u = 0
2269
cdef int v = 0
2270
cdef int w = 0
2271
cdef int pred
2272
cdef float distance
2273
cdef float edge_label
2274
cdef int side
2275
cdef float f_tmp
2276
cdef object v_obj
2277
cdef object w_obj
2278
2279
# Each vertex knows its predecessors in the search, for each side
2280
cdef dict pred_x = {}
2281
cdef dict pred_y = {}
2282
cdef dict pred_current
2283
cdef dict pred_other
2284
2285
# Stores the distances from x and y
2286
cdef dict dist_x = {}
2287
cdef dict dist_y = {}
2288
cdef dict dist_current
2289
cdef dict dist_other
2290
2291
# Lists of vertices who are left to be explored. They are represented
2292
# as 4-tuples: (distance, side, predecessor ,name).
2293
# 1 indicates x's side, -1 indicates y's, the distance being
2294
# defined relatively.
2295
cdef list queue = [(0, 1, x_int, x_int), (0, -1, y_int, y_int)]
2296
cdef list neighbors
2297
2298
cdef list shortest_path = []
2299
2300
# Meeting_vertex is a vertex discovered through x and through y
2301
# which defines the shortest path found
2302
# (of length shortest_path_length).
2303
cdef int meeting_vertex = -1
2304
cdef float shortest_path_length
2305
2306
# As long as the current side (x or y) is not totally explored ...
2307
while queue:
2308
(distance, side, pred, v) = heappop(queue)
2309
if meeting_vertex != -1 and distance > shortest_path_length:
2310
break
2311
2312
if side == 1:
2313
dist_current, dist_other = dist_x, dist_y
2314
pred_current, pred_other = pred_x, pred_y
2315
else:
2316
dist_current, dist_other = dist_y, dist_x
2317
pred_current, pred_other = pred_y, pred_x
2318
2319
if v not in dist_current:
2320
pred_current[v] = pred
2321
dist_current[v] = distance
2322
2323
if v in dist_other:
2324
f_tmp = distance + dist_other[v]
2325
if meeting_vertex == -1 or f_tmp < shortest_path_length:
2326
meeting_vertex = v
2327
shortest_path_length = f_tmp
2328
2329
if side == 1:
2330
neighbors = self._cg.out_neighbors(v)
2331
elif self._cg_rev is not None: # Sparse
2332
neighbors = self._cg_rev.out_neighbors(v)
2333
else: # Dense
2334
neighbors = self._cg.in_neighbors(v)
2335
for w in neighbors:
2336
# If the neighbor is new, adds its non-found neighbors to
2337
# the queue.
2338
if w not in dist_current:
2339
v_obj = vertex_label(v, self.vertex_ints, self.vertex_labels, self._cg)
2340
w_obj = vertex_label(w, self.vertex_ints, self.vertex_labels, self._cg)
2341
edge_label = self.get_edge_label(v_obj, w_obj) if side == 1 else self.get_edge_label(w_obj, v_obj)
2342
heappush(queue, (distance + edge_label, side, v, w))
2343
2344
# No meeting point has been found
2345
if meeting_vertex == -1:
2346
return []
2347
else:
2348
# build the shortest path and returns it.
2349
w = meeting_vertex
2350
2351
while w != x_int:
2352
shortest_path.append(
2353
vertex_label(w,
2354
self.vertex_ints,
2355
self.vertex_labels,
2356
self._cg))
2357
w = pred_x[w]
2358
2359
shortest_path.append(x)
2360
shortest_path.reverse()
2361
2362
if meeting_vertex == y_int:
2363
return shortest_path
2364
2365
w = pred_y[meeting_vertex]
2366
while w != y_int:
2367
shortest_path.append(
2368
vertex_label(w,
2369
self.vertex_ints,
2370
self.vertex_labels,
2371
self._cg))
2372
w = pred_y[w]
2373
shortest_path.append(y)
2374
2375
return shortest_path
2376
2377
def shortest_path_all_vertices(self, v, cutoff=None):
2378
r"""
2379
Returns for each vertex ``u`` a shortest ``v-u`` path.
2380
2381
INPUT:
2382
2383
- ``v`` -- a starting vertex in the shortest path.
2384
2385
- ``cutoff`` -- maximal distance. Longer paths will not be returned.
2386
2387
OUTPUT:
2388
2389
- A list which associates to each vertex ``u`` the shortest path
2390
between ``u`` and ``v`` if there is one.
2391
2392
.. NOTE::
2393
2394
The weight of edges is not taken into account.
2395
2396
ALGORITHM:
2397
2398
This is just a breadth-first search.
2399
2400
EXAMPLES:
2401
2402
On the Petersen Graph::
2403
2404
sage: g = graphs.PetersenGraph()
2405
sage: paths = g._backend.shortest_path_all_vertices(0)
2406
sage: all([ len(paths[v]) == 0 or len(paths[v])-1 == g.distance(0,v) for v in g])
2407
True
2408
2409
On a disconnected graph ::
2410
2411
sage: g = 2*graphs.RandomGNP(20,.3)
2412
sage: paths = g._backend.shortest_path_all_vertices(0)
2413
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])
2414
True
2415
"""
2416
cdef list current_layer
2417
cdef list next_layer
2418
cdef bitset_t seen
2419
cdef int v_int
2420
cdef int u_int
2421
cdef dict distances_int
2422
cdef dict distance
2423
cdef int d
2424
2425
distances = {}
2426
d = 0
2427
2428
v_int = get_vertex(v, self.vertex_ints, self.vertex_labels, self._cg)
2429
2430
bitset_init(seen, (<CGraph>self._cg).active_vertices.size)
2431
bitset_set_first_n(seen, 0)
2432
bitset_add(seen, v_int)
2433
2434
current_layer = [(u_int, v_int)
2435
for u_int in self._cg.out_neighbors(v_int)]
2436
next_layer = []
2437
distances[v] = [v]
2438
2439
while current_layer:
2440
if cutoff is not None and d >= cutoff:
2441
break
2442
2443
while current_layer:
2444
v_int, u_int = current_layer.pop()
2445
2446
if bitset_not_in(seen, v_int):
2447
bitset_add(seen, v_int)
2448
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)]
2449
next_layer.extend([(u_int, v_int) for u_int in self._cg.out_neighbors(v_int)])
2450
2451
current_layer = next_layer
2452
next_layer = []
2453
d += 1
2454
2455
# If the graph is not connected, vertices which have not been
2456
# seen should be associated to the empty path
2457
2458
#for 0 <= v_int < (<CGraph>self._cg).active_vertices.size:
2459
# if bitset_in((<CGraph>self._cg).active_vertices, v_int) and not bitset_in(seen, v_int):
2460
# distances[vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)] = []
2461
2462
bitset_free(seen)
2463
return distances
2464
2465
def depth_first_search(self, v, reverse=False, ignore_direction=False):
2466
r"""
2467
Returns a depth-first search from vertex ``v``.
2468
2469
INPUT:
2470
2471
- ``v`` -- a vertex from which to start the depth-first search.
2472
2473
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2474
to digraphs. If this is a digraph, consider the reversed graph in
2475
which the out-neighbors become the in-neighbors and vice versa.
2476
2477
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2478
relevant to digraphs. If this is a digraph, ignore all orientations
2479
and consider the graph as undirected.
2480
2481
ALGORITHM:
2482
2483
Below is a general template for depth-first search.
2484
2485
- **Input:** A directed or undirected graph `G = (V, E)` of order
2486
`n > 0`. A vertex `s` from which to start the search. The vertices
2487
are numbered from 1 to `n = |V|`, i.e. `V = \{1, 2, \dots, n\}`.
2488
2489
- **Output:** A list `D` of distances of all vertices from `s`. A
2490
tree `T` rooted at `s`.
2491
2492
#. `S \leftarrow [s]` # a stack of nodes to visit
2493
#. `D \leftarrow [\infty, \infty, \dots, \infty]` # `n` copies of `\infty`
2494
#. `D[s] \leftarrow 0`
2495
#. `T \leftarrow [\,]`
2496
#. while `\text{length}(S) > 0` do
2497
2498
#. `v \leftarrow \text{pop}(S)`
2499
#. for each `w \in \text{adj}(v)` do # for digraphs, use out-neighbor set `\text{oadj}(v)`
2500
2501
#. if `D[w] = \infty` then
2502
2503
#. `D[w] \leftarrow D[v] + 1`
2504
#. `\text{push}(S, w)`
2505
#. `\text{append}(T, vw)`
2506
#. return `(D, T)`
2507
2508
.. SEEALSO::
2509
2510
- :meth:`breadth_first_search`
2511
-- breadth-first search for fast compiled graphs.
2512
2513
- :meth:`breadth_first_search <sage.graphs.generic_graph.GenericGraph.breadth_first_search>`
2514
-- breadth-first search for generic graphs.
2515
2516
- :meth:`depth_first_search <sage.graphs.generic_graph.GenericGraph.depth_first_search>`
2517
-- depth-first search for generic graphs.
2518
2519
EXAMPLES:
2520
2521
Traversing the Petersen graph using depth-first search::
2522
2523
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2524
sage: list(G.depth_first_search(0))
2525
[0, 5, 8, 6, 9, 7, 2, 3, 4, 1]
2526
2527
Visiting German cities using depth-first search::
2528
2529
sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],
2530
... "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
2531
... "Kassel": ["Frankfurt","Munchen"],
2532
... "Munchen": ["Kassel","Nurnberg","Augsburg"],
2533
... "Augsburg": ["Munchen","Karlsruhe"],
2534
... "Karlsruhe": ["Mannheim","Augsburg"],
2535
... "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
2536
... "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
2537
... "Stuttgart": ["Nurnberg"],
2538
... "Erfurt": ["Wurzburg"]}, implementation="c_graph")
2539
sage: list(G.depth_first_search("Frankfurt"))
2540
['Frankfurt', 'Wurzburg', 'Nurnberg', 'Munchen', 'Kassel', 'Augsburg', 'Karlsruhe', 'Mannheim', 'Stuttgart', 'Erfurt']
2541
"""
2542
return Search_iterator(self,
2543
v,
2544
direction=-1,
2545
reverse=reverse,
2546
ignore_direction=ignore_direction)
2547
2548
def breadth_first_search(self, v, reverse=False, ignore_direction=False):
2549
r"""
2550
Returns a breadth-first search from vertex ``v``.
2551
2552
INPUT:
2553
2554
- ``v`` -- a vertex from which to start the breadth-first search.
2555
2556
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2557
to digraphs. If this is a digraph, consider the reversed graph in
2558
which the out-neighbors become the in-neighbors and vice versa.
2559
2560
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2561
relevant to digraphs. If this is a digraph, ignore all orientations
2562
and consider the graph as undirected.
2563
2564
ALGORITHM:
2565
2566
Below is a general template for breadth-first search.
2567
2568
- **Input:** A directed or undirected graph `G = (V, E)` of order
2569
`n > 0`. A vertex `s` from which to start the search. The vertices
2570
are numbered from 1 to `n = |V|`, i.e. `V = \{1, 2, \dots, n\}`.
2571
2572
- **Output:** A list `D` of distances of all vertices from `s`. A
2573
tree `T` rooted at `s`.
2574
2575
#. `Q \leftarrow [s]` # a queue of nodes to visit
2576
#. `D \leftarrow [\infty, \infty, \dots, \infty]` # `n` copies of `\infty`
2577
#. `D[s] \leftarrow 0`
2578
#. `T \leftarrow [\,]`
2579
#. while `\text{length}(Q) > 0` do
2580
2581
#. `v \leftarrow \text{dequeue}(Q)`
2582
#. for each `w \in \text{adj}(v)` do # for digraphs, use out-neighbor set `\text{oadj}(v)`
2583
2584
#. if `D[w] = \infty` then
2585
2586
#. `D[w] \leftarrow D[v] + 1`
2587
#. `\text{enqueue}(Q, w)`
2588
#. `\text{append}(T, vw)`
2589
#. return `(D, T)`
2590
2591
.. SEEALSO::
2592
2593
- :meth:`breadth_first_search <sage.graphs.generic_graph.GenericGraph.breadth_first_search>`
2594
-- breadth-first search for generic graphs.
2595
2596
- :meth:`depth_first_search <sage.graphs.generic_graph.GenericGraph.depth_first_search>`
2597
-- depth-first search for generic graphs.
2598
2599
- :meth:`depth_first_search`
2600
-- depth-first search for fast compiled graphs.
2601
2602
EXAMPLES:
2603
2604
Breadth-first search of the Petersen graph starting at vertex 0::
2605
2606
sage: G = Graph(graphs.PetersenGraph(), implementation="c_graph")
2607
sage: list(G.breadth_first_search(0))
2608
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2609
2610
Visiting German cities using breadth-first search::
2611
2612
sage: G = Graph({"Mannheim": ["Frankfurt","Karlsruhe"],
2613
... "Frankfurt": ["Mannheim","Wurzburg","Kassel"],
2614
... "Kassel": ["Frankfurt","Munchen"],
2615
... "Munchen": ["Kassel","Nurnberg","Augsburg"],
2616
... "Augsburg": ["Munchen","Karlsruhe"],
2617
... "Karlsruhe": ["Mannheim","Augsburg"],
2618
... "Wurzburg": ["Frankfurt","Erfurt","Nurnberg"],
2619
... "Nurnberg": ["Wurzburg","Stuttgart","Munchen"],
2620
... "Stuttgart": ["Nurnberg"],
2621
... "Erfurt": ["Wurzburg"]}, implementation="c_graph")
2622
sage: list(G.breadth_first_search("Frankfurt"))
2623
['Frankfurt', 'Mannheim', 'Kassel', 'Wurzburg', 'Karlsruhe', 'Munchen', 'Erfurt', 'Nurnberg', 'Augsburg', 'Stuttgart']
2624
"""
2625
return Search_iterator(self,
2626
v,
2627
direction=0,
2628
reverse=reverse,
2629
ignore_direction=ignore_direction)
2630
2631
def is_connected(self):
2632
r"""
2633
Returns whether the graph is connected.
2634
2635
EXAMPLES:
2636
2637
Petersen's graph is connected::
2638
2639
sage: DiGraph(graphs.PetersenGraph(),implementation="c_graph").is_connected()
2640
True
2641
2642
While the disjoint union of two of them is not::
2643
2644
sage: DiGraph(2*graphs.PetersenGraph(),implementation="c_graph").is_connected()
2645
False
2646
2647
A graph with non-integer vertex labels::
2648
sage: Graph(graphs.CubeGraph(3), implementation='c_graph').is_connected()
2649
True
2650
"""
2651
cdef int v_int = 0
2652
v_int = bitset_first((<CGraph>self._cg).active_vertices)
2653
2654
if v_int == -1:
2655
return True
2656
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
2657
return len(list(self.depth_first_search(v, ignore_direction=True))) == (<CGraph>self._cg).num_verts
2658
2659
def is_strongly_connected(self):
2660
r"""
2661
Returns whether the graph is strongly connected.
2662
2663
EXAMPLES:
2664
2665
The circuit on 3 vertices is obviously strongly connected::
2666
2667
sage: g = DiGraph({0: [1], 1: [2], 2: [0]}, implementation="c_graph")
2668
sage: g.is_strongly_connected()
2669
True
2670
2671
But a transitive triangle is not::
2672
2673
sage: g = DiGraph({0: [1,2], 1: [2]}, implementation="c_graph")
2674
sage: g.is_strongly_connected()
2675
False
2676
"""
2677
cdef int v_int = 0
2678
2679
# Pick one vertex
2680
v_int = bitset_first((<CGraph>self._cg).active_vertices)
2681
2682
if v_int == -1:
2683
return True
2684
2685
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
2686
2687
return (<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v))) and \
2688
(<CGraph>self._cg).num_verts == len(list(self.depth_first_search(v, reverse=True)))
2689
2690
def strongly_connected_component_containing_vertex(self, v):
2691
r"""
2692
Returns the strongly connected component containing the given vertex.
2693
2694
INPUT:
2695
2696
- ``v`` -- a vertex
2697
2698
EXAMPLES:
2699
2700
The digraph obtained from the ``PetersenGraph`` has an unique
2701
strongly connected component::
2702
2703
sage: g = DiGraph(graphs.PetersenGraph())
2704
sage: g.strongly_connected_component_containing_vertex(0)
2705
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2706
2707
In the Butterfly DiGraph, each vertex is a strongly connected
2708
component::
2709
2710
sage: g = digraphs.ButterflyGraph(3)
2711
sage: all([[v] == g.strongly_connected_component_containing_vertex(v) for v in g])
2712
True
2713
"""
2714
cdef int v_int = get_vertex(v,
2715
self.vertex_ints,
2716
self.vertex_labels,
2717
self._cg)
2718
cdef set a = set(self.depth_first_search(v))
2719
cdef set b = set(self.depth_first_search(v, reverse=True))
2720
return list(a & b)
2721
2722
def is_directed_acyclic(self, certificate = False):
2723
r"""
2724
Returns whether the graph is both directed and acylic (possibly with a
2725
certificate)
2726
2727
INPUT:
2728
2729
- ``certificate`` -- whether to return a certificate (``False`` by
2730
default).
2731
2732
OUTPUT:
2733
2734
When ``certificate=False``, returns a boolean value. When
2735
``certificate=True`` :
2736
2737
* If the graph is acyclic, returns a pair ``(True, ordering)`` where
2738
``ordering`` is a list of the vertices such that ``u`` appears
2739
before ``v`` in ``ordering`` if ``u, v`` is an edge.
2740
2741
* Else, returns a pair ``(False, cycle)`` where ``cycle`` is a list
2742
of vertices representing a circuit in the graph.
2743
2744
ALGORITHM:
2745
2746
We pick a vertex at random, think hard and find out that that if we are
2747
to remove the vertex from the graph we must remove all of its
2748
out-neighbors in the first place. So we put all of its out-neighbours in
2749
a stack, and repeat the same procedure with the vertex on top of the
2750
stack (when a vertex on top of the stack has no out-neighbors, we remove
2751
it immediately). Of course, for each vertex we only add its outneighbors
2752
to the end of the stack once : if for some reason the previous algorithm
2753
leads us to do it twice, it means we have found a circuit.
2754
2755
We keep track of the vertices whose out-neighborhood has been added to
2756
the stack once with a variable named ``tried``.
2757
2758
There is no reason why the graph should be empty at the end of this
2759
procedure, so we run it again on the remaining vertices until none are
2760
left or a circuit is found.
2761
2762
.. NOTE::
2763
2764
The graph is assumed to be directed. An exception is raised if it is
2765
not.
2766
2767
EXAMPLES:
2768
2769
At first, the following graph is acyclic::
2770
2771
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] })
2772
sage: D.plot(layout='circular').show()
2773
sage: D.is_directed_acyclic()
2774
True
2775
2776
Adding an edge from `9` to `7` does not change it::
2777
2778
sage: D.add_edge(9,7)
2779
sage: D.is_directed_acyclic()
2780
True
2781
2782
We can obtain as a proof an ordering of the vertices such that `u`
2783
appears before `v` if `uv` is an edge of the graph::
2784
2785
sage: D.is_directed_acyclic(certificate = True)
2786
(True, [4, 5, 6, 9, 0, 1, 2, 3, 7, 8, 10])
2787
2788
Adding an edge from 7 to 4, though, makes a difference::
2789
2790
sage: D.add_edge(7,4)
2791
sage: D.is_directed_acyclic()
2792
False
2793
2794
Indeed, it creates a circuit `7, 4, 5`::
2795
2796
sage: D.is_directed_acyclic(certificate = True)
2797
(False, [7, 4, 5])
2798
2799
Checking acyclic graphs are indeed acyclic ::
2800
2801
sage: def random_acyclic(n, p):
2802
... g = graphs.RandomGNP(n, p)
2803
... h = DiGraph()
2804
... h.add_edges([ ((u,v) if u<v else (v,u)) for u,v,_ in g.edges() ])
2805
... return h
2806
...
2807
sage: all( random_acyclic(100, .2).is_directed_acyclic() # long time
2808
... for i in range(50)) # long time
2809
True
2810
"""
2811
2812
if not self._directed:
2813
raise ValueError("Input must be a directed graph.")
2814
2815
# Activated vertices
2816
cdef bitset_t activated
2817
bitset_init(activated, (<CGraph>self._cg).active_vertices.size)
2818
bitset_set_first_n(activated, (<CGraph>self._cg).active_vertices.size)
2819
2820
# Vertices whose neighbors have already been added to the stack
2821
cdef bitset_t tried
2822
bitset_init(tried, (<CGraph>self._cg).active_vertices.size)
2823
bitset_set_first_n(tried, 0)
2824
2825
# Parent of a vertex in the discovery tree
2826
cdef dict parent = {}
2827
2828
# The vertices left to be visited
2829
cdef list stack = []
2830
2831
# Final ordering, if the graph turns out to be acyclic
2832
cdef list ordering = []
2833
2834
# Circuit, if the graph turns out to contain one
2835
cdef list cycle
2836
2837
# We try any vertex as the source of the exploration tree
2838
for v in (<CGraph>self._cg).verts():
2839
2840
# We are not interested in trying de-activated vertices
2841
if bitset_not_in(activated, v):
2842
continue
2843
2844
stack = [v]
2845
2846
# For as long as some vertices are to be visited
2847
while stack:
2848
2849
# We take the last one (depth-first search)
2850
u = stack[-1]
2851
2852
# This vertex may have been deactivated since we added it.
2853
if bitset_not_in(activated, u):
2854
stack.pop(-1)
2855
continue
2856
2857
# If we tried this vertex already, it means that all of its
2858
# out-neighbors have been de-activated already, for we put them
2859
# *after* u in the stack.
2860
if bitset_in(tried, u):
2861
ordering.insert(0, vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
2862
bitset_discard(tried, u)
2863
bitset_discard(activated, u)
2864
stack.pop(-1)
2865
continue
2866
2867
2868
# If we never tried it, now is the time to do it. We also must
2869
# remember it
2870
bitset_add(tried, u)
2871
2872
# We append its out-neighbours to the stack.
2873
for uu in self._cg.out_neighbors(u):
2874
2875
# If we have found a new vertex, we put it at the end of the
2876
# stack. We ignored de-activated vertices.
2877
if bitset_not_in(tried, uu):
2878
if bitset_in(activated, uu):
2879
parent[uu] = u
2880
stack.append(uu)
2881
2882
# If we have already met this vertex, it means we have found
2883
# a circuit !
2884
else:
2885
bitset_free(activated)
2886
bitset_free(tried)
2887
2888
if not certificate:
2889
return False
2890
2891
# We build it, then return it
2892
# // answer = [u]
2893
cycle = [vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg)]
2894
2895
tmp = u
2896
while u != uu:
2897
u = parent.get(u,uu)
2898
cycle.append(vertex_label(u, self.vertex_ints, self.vertex_labels, self._cg))
2899
2900
cycle.reverse()
2901
return (False, cycle)
2902
2903
# No Cycle... Good news ! Let's return it.
2904
bitset_free(activated)
2905
bitset_free(tried)
2906
2907
if certificate:
2908
return (True, ordering)
2909
else:
2910
return True
2911
2912
cdef class Search_iterator:
2913
r"""
2914
An iterator for traversing a (di)graph.
2915
2916
This class is commonly used to perform a depth-first or breadth-first
2917
search. The class does not build all at once in memory the whole list of
2918
visited vertices. The class maintains the following variables:
2919
2920
- ``graph`` -- a graph whose vertices are to be iterated over.
2921
2922
- ``direction`` -- integer; this determines the position at which
2923
vertices to be visited are removed from the list ``stack``. For
2924
breadth-first search (BFS), element removal occurs at the start of the
2925
list, as signified by the value ``direction=0``. This is because in
2926
implementations of BFS, the list of vertices to visit are usually
2927
maintained by a queue, so element insertion and removal follow a
2928
first-in first-out (FIFO) protocol. For depth-first search (DFS),
2929
element removal occurs at the end of the list, as signified by the value
2930
``direction=-1``. The reason is that DFS is usually implemented using
2931
a stack to maintain the list of vertices to visit. Hence, element
2932
insertion and removal follow a last-in first-out (LIFO) protocol.
2933
2934
- ``stack`` -- a list of vertices to visit.
2935
2936
- ``seen`` -- a list of vertices that are already visited.
2937
2938
- ``test_out`` -- boolean; whether we want to consider the out-neighbors
2939
of the graph to be traversed. For undirected graphs, we consider both
2940
the in- and out-neighbors. However, for digraphs we only traverse along
2941
out-neighbors.
2942
2943
- ``test_in`` -- boolean; whether we want to consider the in-neighbors of
2944
the graph to be traversed. For undirected graphs, we consider both
2945
the in- and out-neighbors.
2946
2947
EXAMPLE::
2948
2949
sage: g = graphs.PetersenGraph()
2950
sage: list(g.breadth_first_search(0))
2951
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2952
"""
2953
2954
cdef graph
2955
cdef int direction
2956
cdef list stack
2957
cdef bitset_t seen
2958
cdef bint test_out
2959
cdef bint test_in
2960
2961
def __init__(self, graph, v, direction=0, reverse=False,
2962
ignore_direction=False):
2963
r"""
2964
Initialize an iterator for traversing a (di)graph.
2965
2966
INPUT:
2967
2968
- ``graph`` -- a graph to be traversed.
2969
2970
- ``v`` -- a vertex in ``graph`` from which to start the traversal.
2971
2972
- ``direction`` -- integer (default: ``0``). This determines the
2973
position at which vertices to be visited are removed from the list
2974
``stack`` of vertices to visit. For breadth-first search (BFS),
2975
element removal occurs at the start of the list, as signified by the
2976
value ``direction=0``. This is because in implementations of BFS,
2977
the list of vertices to visit are usually maintained by a queue, so
2978
element insertion and removal follow a first-in first-out (FIFO)
2979
protocol. For depth-first search (DFS), element removal occurs at
2980
the end of the list, as signified by the value ``direction=-1``. The
2981
reason is that DFS is usually implemented using a stack to maintain
2982
the list of vertices to visit. Hence, element insertion and removal
2983
follow a last-in first-out (LIFO) protocol.
2984
2985
- ``reverse`` -- boolean (default: ``False``). This is only relevant
2986
to digraphs. If ``graph`` is a digraph, consider the reversed graph
2987
in which the out-neighbors become the in-neighbors and vice versa.
2988
2989
- ``ignore_direction`` -- boolean (default: ``False``). This is only
2990
relevant to digraphs. If ``graph`` is a digraph, ignore all
2991
orientations and consider the graph as undirected.
2992
2993
EXAMPLE::
2994
2995
sage: g = graphs.PetersenGraph()
2996
sage: list(g.breadth_first_search(0))
2997
[0, 1, 4, 5, 2, 6, 3, 9, 7, 8]
2998
2999
TESTS:
3000
3001
A vertex which does not belong to the graph::
3002
3003
sage: list(g.breadth_first_search(-9))
3004
Traceback (most recent call last):
3005
...
3006
LookupError: Vertex (-9) is not a vertex of the graph.
3007
3008
An empty graph::
3009
3010
sage: list(Graph().breadth_first_search(''))
3011
Traceback (most recent call last):
3012
...
3013
LookupError: Vertex ('') is not a vertex of the graph.
3014
"""
3015
self.graph = graph
3016
self.direction = direction
3017
3018
bitset_init(self.seen, (<CGraph>self.graph._cg).active_vertices.size)
3019
bitset_set_first_n(self.seen, 0)
3020
3021
cdef int v_id = get_vertex(v,
3022
self.graph.vertex_ints,
3023
self.graph.vertex_labels,
3024
self.graph._cg)
3025
3026
if v_id == -1:
3027
raise LookupError("Vertex ({0}) is not a vertex of the graph.".format(repr(v)))
3028
3029
self.stack = [v_id]
3030
3031
if not self.graph.directed:
3032
ignore_direction = False
3033
3034
self.test_out = (not reverse) or ignore_direction
3035
self.test_in = reverse or ignore_direction
3036
3037
def __iter__(self):
3038
r"""
3039
Return an iterator object over a traversal of a graph.
3040
3041
EXAMPLE::
3042
3043
sage: g = graphs.PetersenGraph()
3044
sage: g.breadth_first_search(0)
3045
<generator object breadth_first_search at ...
3046
"""
3047
return self
3048
3049
def __next__(self):
3050
r"""
3051
Return the next vertex in a traversal of a graph.
3052
3053
EXAMPLE::
3054
3055
sage: g = graphs.PetersenGraph()
3056
sage: g.breadth_first_search(0)
3057
<generator object breadth_first_search at ...
3058
sage: g.breadth_first_search(0).next()
3059
0
3060
"""
3061
cdef int v_int
3062
cdef int w_int
3063
3064
while self.stack:
3065
v_int = self.stack.pop(self.direction)
3066
3067
if bitset_not_in(self.seen, v_int):
3068
value = vertex_label(v_int,
3069
self.graph.vertex_ints,
3070
self.graph.vertex_labels,
3071
self.graph._cg)
3072
bitset_add(self.seen, v_int)
3073
3074
if self.test_out:
3075
self.stack.extend(self.graph._cg.out_neighbors(v_int))
3076
if self.test_in:
3077
self.stack.extend(self.graph._cg_rev.out_neighbors(v_int))
3078
3079
break
3080
else:
3081
bitset_free(self.seen)
3082
raise StopIteration
3083
3084
return value
3085
3086