Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/base/dense_graph.pyx
4057 views
1
r"""
2
Fast dense graphs
3
4
Usage Introduction
5
------------------
6
7
::
8
9
sage: from sage.graphs.base.dense_graph import DenseGraph
10
11
Dense graphs are initialized as follows::
12
13
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
14
15
This example initializes a dense graph with room for twenty vertices, the first
16
ten of which are in the graph. In general, the first ``nverts`` are "active."
17
For example, see that 9 is already in the graph::
18
19
sage: D._num_verts()
20
10
21
sage: D.add_vertex(9)
22
9
23
sage: D._num_verts()
24
10
25
26
But 10 is not, until we add it::
27
28
sage: D._num_verts()
29
10
30
sage: D.add_vertex(10)
31
10
32
sage: D._num_verts()
33
11
34
35
You can begin working right away as follows::
36
37
sage: D.add_arc(0,1)
38
sage: D.add_arc(1,2)
39
sage: D.add_arc(1,0)
40
sage: D.has_arc(7,3)
41
False
42
sage: D.has_arc(0,1)
43
True
44
sage: D.in_neighbors(1)
45
[0]
46
sage: D.out_neighbors(1)
47
[0, 2]
48
sage: D.del_all_arcs(0,1)
49
sage: D.has_arc(0,1)
50
False
51
sage: D.has_arc(1,2)
52
True
53
sage: D.del_vertex(7)
54
sage: D.has_arc(7,3)
55
False
56
sage: D._num_verts()
57
10
58
sage: D._num_arcs()
59
2
60
61
Dense graphs do not support multiple or labeled edges.
62
63
::
64
65
sage: T = DenseGraph(nverts = 3, extra_vertices = 2)
66
sage: T.add_arc(0,1)
67
sage: T.add_arc(1,2)
68
sage: T.add_arc(2,0)
69
sage: T.has_arc(0,1)
70
True
71
72
::
73
74
sage: for _ in range(10): D.add_arc(5,4)
75
sage: D.has_arc(5,4)
76
True
77
78
Dense graphs are by their nature directed. As of this writing, you need to do
79
operations in pairs to treat the undirected case (or use a backend or a Sage
80
graph)::
81
82
sage: T.has_arc(1,0)
83
False
84
85
The curious developer is encouraged to check out the ``unsafe`` functions,
86
which do not check input but which run in pure C.
87
88
Underlying Data Structure
89
-------------------------
90
91
The class ``DenseGraph`` contains the following variables which are inherited
92
from ``CGraph`` (for explanation, refer to the documentation there)::
93
94
cdef int num_verts
95
cdef int num_arcs
96
cdef int *in_degrees
97
cdef int *out_degrees
98
cdef bitset_t active_vertices
99
100
It also contains the following variables::
101
102
cdef int radix_div_shift
103
cdef int radix_mod_mask
104
cdef int num_longs
105
cdef unsigned long *edges
106
107
The array ``edges`` is a series of bits which are turned on or off, and due to
108
this, dense graphs only support graphs without edge labels and with no multiple
109
edges. The ints ``radix_div_shift`` and ``radix_mod_mask`` are simply for doing
110
efficient division by powers of two, and ``num_longs`` stores the length of the
111
``edges`` array. Recall that this length reflects the number of available
112
vertices, not the number of "actual" vertices. For more details about this,
113
refer to the documentation for ``CGraph``.
114
"""
115
116
#*******************************************************************************
117
# Copyright (C) 2008-9 Robert L. Miller <[email protected]>
118
#
119
# Distributed under the terms of the GNU General Public License (GPL)
120
# http://www.gnu.org/licenses/
121
#*******************************************************************************
122
123
include '../../misc/bitset.pxi'
124
125
cdef class DenseGraph(CGraph):
126
"""
127
Compiled dense graphs.
128
129
::
130
131
sage: from sage.graphs.base.dense_graph import DenseGraph
132
133
Dense graphs are initialized as follows::
134
135
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
136
137
INPUT:
138
139
- ``nverts`` - non-negative integer, the number of vertices.
140
- ``extra_vertices`` - non-negative integer (default: 0), how many extra
141
vertices to allocate.
142
- ``verts`` - optional list of vertices to add
143
- ``arcs`` - optional list of arcs to add
144
145
The first ``nverts`` are created as vertices of the graph, and the next
146
``extra_vertices`` can be freely added without reallocation. See top level
147
documentation for more details. The input ``verts`` and ``arcs`` are mainly
148
for use in pickling.
149
150
"""
151
152
def __cinit__(self, int nverts, int extra_vertices = 10, verts = None, arcs = None):
153
"""
154
Allocation and initialization happen in one place.
155
156
Memory usage is
157
158
O( (nverts + extra_vertices)^2 ).
159
160
EXAMPLE::
161
162
sage: from sage.graphs.base.dense_graph import DenseGraph
163
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
164
"""
165
if nverts == 0 and extra_vertices == 0:
166
raise RuntimeError('Dense graphs must allocate space for vertices!')
167
cdef int radix = sizeof(unsigned long) << 3
168
self.radix_mod_mask = radix - 1
169
cdef int i = 0
170
while ((<unsigned long>1)<<i) & self.radix_mod_mask:
171
i += 1
172
self.radix_div_shift = i
173
self.num_verts = nverts
174
cdef int total_verts = nverts + extra_vertices
175
self.num_arcs = 0
176
177
i = total_verts >> self.radix_div_shift
178
if total_verts & self.radix_mod_mask:
179
i += 1
180
self.num_longs = i
181
182
self.edges = <unsigned long *> sage_malloc(total_verts * self.num_longs * sizeof(unsigned long))
183
self.in_degrees = <int *> sage_malloc(total_verts * sizeof(int))
184
self.out_degrees = <int *> sage_malloc(total_verts * sizeof(int))
185
186
if not self.edges or not self.in_degrees or not self.out_degrees:
187
if self.edges: sage_free(self.edges)
188
if self.in_degrees: sage_free(self.in_degrees)
189
if self.out_degrees: sage_free(self.out_degrees)
190
raise RuntimeError("Failure allocating memory.")
191
for i from 0 <= i < self.num_longs * total_verts:
192
self.edges[i] = 0
193
for i from 0 <= i < total_verts:
194
self.in_degrees[i] = 0
195
self.out_degrees[i] = 0
196
bitset_init(self.active_vertices, total_verts)
197
bitset_set_first_n(self.active_vertices, self.num_verts)
198
199
if verts is not None:
200
self.add_vertices(verts)
201
202
if arcs is not None:
203
for u,v in arcs:
204
self.add_arc(u,v)
205
206
def __dealloc__(self):
207
"""
208
New and dealloc are both tested at class level.
209
"""
210
sage_free(self.edges)
211
sage_free(self.in_degrees)
212
sage_free(self.out_degrees)
213
bitset_free(self.active_vertices)
214
215
def __reduce__(self):
216
"""
217
Return a tuple used for pickling this graph.
218
219
TESTS::
220
221
sage: from sage.graphs.base.dense_graph import DenseGraph
222
sage: D = DenseGraph(nverts = 10, extra_vertices = 10)
223
sage: D.add_arc(0,1)
224
sage: D.has_arc(0,1)
225
1
226
sage: D.has_arc(1,2)
227
0
228
sage: LD = loads(dumps(D))
229
sage: LD.has_arc(0,1)
230
1
231
sage: LD.has_arc(1,2)
232
0
233
234
"""
235
from sage.graphs.all import DiGraph
236
D = DiGraph(implementation='c_graph', sparse=False)
237
D._backend._cg = self
238
cdef int i
239
D._backend.vertex_labels = {}
240
for i from 0 <= i < self.active_vertices.size:
241
if bitset_in(self.active_vertices, i):
242
D._backend.vertex_labels[i] = i
243
D._backend.vertex_ints = D._backend.vertex_labels
244
return (DenseGraph, (0, self.active_vertices.size, self.verts(), D.edges(labels=False)))
245
246
cpdef realloc(self, int total_verts):
247
"""
248
Reallocate the number of vertices to use, without actually adding any.
249
250
INPUT:
251
252
- ``total`` - integer, the total size to make the array
253
254
Returns -1 and fails if reallocation would destroy any active vertices.
255
256
EXAMPLES::
257
258
sage: from sage.graphs.base.dense_graph import DenseGraph
259
sage: D = DenseGraph(nverts=4, extra_vertices=4)
260
sage: D.current_allocation()
261
8
262
sage: D.add_vertex(6)
263
6
264
sage: D.current_allocation()
265
8
266
sage: D.add_vertex(10)
267
10
268
sage: D.current_allocation()
269
16
270
sage: D.add_vertex(40)
271
Traceback (most recent call last):
272
...
273
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
274
sage: D.realloc(50)
275
sage: D.add_vertex(40)
276
40
277
sage: D.current_allocation()
278
50
279
sage: D.realloc(30)
280
-1
281
sage: D.current_allocation()
282
50
283
sage: D.del_vertex(40)
284
sage: D.realloc(30)
285
sage: D.current_allocation()
286
30
287
288
"""
289
cdef int i, j
290
if total_verts == 0:
291
raise RuntimeError('Dense graphs must allocate space for vertices!')
292
cdef bitset_t bits
293
cdef int min_verts, min_longs, old_longs = self.num_longs
294
if total_verts < self.active_vertices.size:
295
min_verts = total_verts
296
min_longs = -1
297
bitset_init(bits, self.active_vertices.size)
298
bitset_set_first_n(bits, total_verts)
299
if not bitset_issubset(self.active_vertices, bits):
300
bitset_free(bits)
301
return -1
302
bitset_free(bits)
303
else:
304
min_verts = self.active_vertices.size
305
min_longs = self.num_longs
306
307
i = total_verts >> self.radix_div_shift
308
if total_verts & self.radix_mod_mask:
309
i += 1
310
self.num_longs = i
311
if min_longs == -1: min_longs = self.num_longs
312
313
cdef unsigned long *new_edges = <unsigned long *> sage_malloc(total_verts * self.num_longs * sizeof(unsigned long))
314
315
for i from 0 <= i < min_verts:
316
for j from 0 <= j < min_longs:
317
new_edges[i*self.num_longs + j] = self.edges[i*old_longs + j]
318
for j from min_longs <= j < self.num_longs:
319
new_edges[i*self.num_longs + j] = 0
320
for i from min_verts <= i < total_verts:
321
for j from 0 <= j < self.num_longs:
322
new_edges[i*self.num_longs + j] = 0
323
sage_free(self.edges)
324
self.edges = new_edges
325
326
self.in_degrees = <int *> sage_realloc(self.in_degrees, total_verts * sizeof(int))
327
self.out_degrees = <int *> sage_realloc(self.out_degrees, total_verts * sizeof(int))
328
329
cdef int first_limb
330
cdef unsigned long zero_gate
331
if total_verts > self.active_vertices.size:
332
first_limb = (self.active_vertices.size >> self.radix_div_shift)
333
zero_gate = (<unsigned long>1) << (self.active_vertices.size & self.radix_mod_mask)
334
zero_gate -= 1
335
for i from 0 <= i < total_verts:
336
self.edges[first_limb] &= zero_gate
337
for j from first_limb < j < self.num_longs:
338
self.edges[j] = 0
339
340
for i from self.active_vertices.size <= i < total_verts:
341
self.in_degrees[i] = 0
342
self.out_degrees[i] = 0
343
bitset_realloc(self.active_vertices, total_verts)
344
345
###################################
346
# Unlabeled arc functions
347
###################################
348
349
cdef int add_arc_unsafe(self, int u, int v):
350
"""
351
Adds arc (u, v) to the graph.
352
353
INPUT:
354
u, v -- non-negative integers
355
356
"""
357
cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift)
358
cdef unsigned long word = (<unsigned long>1) << (v & self.radix_mod_mask)
359
if not self.edges[place] & word:
360
self.in_degrees[v] += 1
361
self.out_degrees[u] += 1
362
self.num_arcs += 1
363
self.edges[place] |= word
364
365
cpdef add_arc(self, int u, int v):
366
"""
367
Adds arc ``(u, v)`` to the graph.
368
369
INPUT:
370
371
- ``u, v`` -- non-negative integers, must be in self
372
373
EXAMPLE::
374
375
sage: from sage.graphs.base.dense_graph import DenseGraph
376
sage: G = DenseGraph(5)
377
sage: G.add_arc(0,1)
378
sage: G.add_arc(4,7)
379
Traceback (most recent call last):
380
...
381
LookupError: Vertex (7) is not a vertex of the graph.
382
sage: G.has_arc(1,0)
383
False
384
sage: G.has_arc(0,1)
385
True
386
387
"""
388
self.check_vertex(u)
389
self.check_vertex(v)
390
self.add_arc_unsafe(u,v)
391
392
cdef int has_arc_unsafe(self, int u, int v):
393
"""
394
Checks whether arc (u, v) is in the graph.
395
396
INPUT:
397
u, v -- non-negative integers, must be in self
398
399
OUTPUT:
400
0 -- False
401
1 -- True
402
403
"""
404
cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift)
405
cdef unsigned long word = (<unsigned long>1) << (v & self.radix_mod_mask)
406
if self.edges[place] & word:
407
return 1
408
else:
409
return 0
410
411
cpdef bint has_arc(self, int u, int v):
412
"""
413
Checks whether arc ``(u, v)`` is in the graph.
414
415
INPUT:
416
u, v -- integers
417
418
EXAMPLE::
419
420
sage: from sage.graphs.base.dense_graph import DenseGraph
421
sage: G = DenseGraph(5)
422
sage: G.add_arc(0,1)
423
sage: G.has_arc(1,0)
424
False
425
sage: G.has_arc(0,1)
426
True
427
428
"""
429
if u < 0 or u >= self.active_vertices.size or not bitset_in(self.active_vertices, u):
430
return False
431
if v < 0 or v >= self.active_vertices.size or not bitset_in(self.active_vertices, v):
432
return False
433
return self.has_arc_unsafe(u,v) == 1
434
435
cdef int del_arc_unsafe(self, int u, int v):
436
"""
437
Deletes the arc from u to v, if it exists.
438
439
INPUT:
440
u, v -- non-negative integers, must be in self
441
442
"""
443
cdef int place = (u * self.num_longs) + (v >> self.radix_div_shift)
444
cdef unsigned long word = (<unsigned long>1) << (v & self.radix_mod_mask)
445
if self.edges[place] & word:
446
self.in_degrees[v] -= 1
447
self.out_degrees[u] -= 1
448
self.num_arcs -= 1
449
self.edges[place] &= ~word
450
451
cpdef del_all_arcs(self, int u, int v):
452
"""
453
Deletes the arc from ``u`` to ``v``.
454
455
INPUT:
456
- ``u, v`` - integers
457
458
NOTE:
459
The naming of this function is for consistency with ``SparseGraph``. Of
460
course, there can be at most one arc for a ``DenseGraph``.
461
462
EXAMPLE::
463
464
sage: from sage.graphs.base.dense_graph import DenseGraph
465
sage: G = DenseGraph(5)
466
sage: G.add_arc(0,1)
467
sage: G.has_arc(0,1)
468
True
469
sage: G.del_all_arcs(0,1)
470
sage: G.has_arc(0,1)
471
False
472
473
"""
474
self.check_vertex(u)
475
self.check_vertex(v)
476
self.del_arc_unsafe(u,v)
477
478
###################################
479
# Neighbor functions
480
###################################
481
482
cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size):
483
"""
484
Gives all v such that (u, v) is an arc of the graph.
485
486
INPUT:
487
u -- non-negative integer, must be in self
488
neighbors -- must be a pointer to an (allocated) integer array
489
size -- the length of the array
490
491
OUTPUT:
492
nonnegative integer -- the number of v such that (u, v) is an arc
493
-1 -- indicates that the array has been filled with neighbors, but
494
there were more
495
496
"""
497
cdef int place = (u * self.num_longs), num_nbrs = 0
498
cdef int i, v = 0
499
cdef unsigned long word, data
500
for i from 0 <= i < self.num_longs:
501
data = self.edges[place + i]
502
word = 1
503
while word:
504
if word & data:
505
if num_nbrs == size:
506
return -1
507
neighbors[num_nbrs] = v
508
num_nbrs += 1
509
word = word << 1
510
v += 1
511
return num_nbrs
512
513
cpdef list out_neighbors(self, int u):
514
"""
515
Gives all ``v`` such that ``(u, v)`` is an arc of the graph.
516
517
INPUT:
518
- ``u`` - integer
519
520
EXAMPLES::
521
522
sage: from sage.graphs.base.dense_graph import DenseGraph
523
sage: G = DenseGraph(5)
524
sage: G.add_arc(0,1)
525
sage: G.add_arc(1,2)
526
sage: G.add_arc(1,3)
527
sage: G.out_neighbors(0)
528
[1]
529
sage: G.out_neighbors(1)
530
[2, 3]
531
532
"""
533
cdef int i, num_nbrs
534
self.check_vertex(u)
535
if self.out_degrees[u] == 0:
536
return []
537
cdef int size = self.out_degrees[u]
538
cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))
539
if not neighbors:
540
raise RuntimeError("Failure allocating memory.")
541
num_nbrs = self.out_neighbors_unsafe(u, neighbors, size)
542
output = [neighbors[i] for i from 0 <= i < num_nbrs]
543
sage_free(neighbors)
544
return output
545
546
cdef int in_neighbors_unsafe(self, int v, int *neighbors, int size):
547
"""
548
Gives all u such that (u, v) is an arc of the graph.
549
550
INPUT:
551
v -- non-negative integer, must be in self
552
neighbors -- must be a pointer to an (allocated) integer array
553
size -- the length of the array
554
555
OUTPUT:
556
nonnegative integer -- the number of u such that (u, v) is an arc
557
-1 -- indicates that the array has been filled with neighbors, but
558
there were more
559
560
"""
561
cdef int place = v >> self.radix_div_shift
562
cdef unsigned long word = (<unsigned long>1) << (v & self.radix_mod_mask)
563
cdef int i, num_nbrs = 0
564
for i from 0 <= i < self.active_vertices.size:
565
if self.edges[place + i*self.num_longs] & word:
566
if num_nbrs == size:
567
return -1
568
neighbors[num_nbrs] = i
569
num_nbrs += 1
570
return num_nbrs
571
572
cpdef list in_neighbors(self, int v):
573
"""
574
Gives all ``u`` such that ``(u, v)`` is an arc of the graph.
575
576
INPUT:
577
- ``v`` - integer
578
579
EXAMPLES::
580
581
sage: from sage.graphs.base.dense_graph import DenseGraph
582
sage: G = DenseGraph(5)
583
sage: G.add_arc(0,1)
584
sage: G.add_arc(3,1)
585
sage: G.add_arc(1,3)
586
sage: G.in_neighbors(1)
587
[0, 3]
588
sage: G.in_neighbors(3)
589
[1]
590
591
"""
592
cdef int i, num_nbrs
593
self.check_vertex(v)
594
if self.in_degrees[v] == 0:
595
return []
596
cdef int size = self.in_degrees[v]
597
cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))
598
if not neighbors:
599
raise RuntimeError("Failure allocating memory.")
600
num_nbrs = self.in_neighbors_unsafe(v, neighbors, size)
601
output = [neighbors[i] for i from 0 <= i < num_nbrs]
602
sage_free(neighbors)
603
return output
604
605
##############################
606
# Further tests. Unit tests for methods, functions, classes defined with cdef.
607
##############################
608
609
def random_stress():
610
"""
611
Randomly search for mistakes in the code.
612
613
DOCTEST (No output indicates that no errors were found)::
614
615
sage: from sage.graphs.base.dense_graph import random_stress
616
sage: for _ in xrange(400):
617
... random_stress()
618
619
"""
620
cdef int i, j, k, l, n
621
cdef DenseGraph Gnew
622
num_verts = 10
623
# This code deliberately uses random instead of sage.misc.prandom,
624
# so that every time it is run it does different tests, instead of
625
# doing the same random stress test every time. (Maybe it should
626
# use sage.misc.random_testing?)
627
from random import randint
628
from sage.graphs.all import DiGraph
629
from sage.misc.misc import uniq
630
Gnew = DenseGraph(num_verts)
631
Gold = DiGraph(num_verts, loops=True, implementation='networkx')
632
for n from 0 <= n < 100:
633
i = randint(0,num_verts-1)
634
j = randint(0,num_verts-1)
635
k = randint(0,num_verts-1)
636
if k != 0:
637
Gold.add_edge(i,j)
638
Gnew.add_arc_unsafe(i,j)
639
else:
640
Gold.delete_edge(i,j)
641
Gnew.del_arc_unsafe(i,j)
642
if Gnew.num_arcs != Gold.size():
643
raise RuntimeError( "NO" )
644
for i from 0 <= i < num_verts:
645
if Gnew.out_degrees[i] != Gold.out_degree(i):
646
raise RuntimeError( "NO" )
647
if Gnew.in_degrees[i] != Gold.in_degree(i):
648
raise RuntimeError( "NO" )
649
650
def _test_adjacency_sequence_out():
651
"""
652
Randomly test the method ``DenseGraph.adjacency_sequence_out()``. No output
653
indicates that no errors were found.
654
655
TESTS::
656
657
sage: from sage.graphs.base.dense_graph import _test_adjacency_sequence_out
658
sage: _test_adjacency_sequence_out() # long time
659
"""
660
from sage.graphs.digraph import DiGraph
661
from sage.graphs.graph_generators import GraphGenerators
662
from sage.misc.prandom import randint, random
663
low = 0
664
high = 500
665
randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random()))
666
n = randg.order()
667
cdef DenseGraph g = DenseGraph(n,
668
verts=randg.vertices(),
669
arcs=randg.edges(labels=False))
670
assert g._num_verts() == randg.order(), (
671
"Graph order mismatch: %s vs. %s" % (g._num_verts(), randg.order()))
672
assert g._num_arcs() == randg.size(), (
673
"Graph size mismatch: %s vs. %s" % (g._num_arcs(), randg.size()))
674
M = randg.adjacency_matrix()
675
cdef int *V = <int *>sage_malloc(n * sizeof(int))
676
cdef int i = 0
677
for v in randg.vertex_iterator():
678
V[i] = v
679
i += 1
680
cdef int *seq
681
for 0 <= i < randint(50, 101):
682
u = randint(low, n - 1)
683
seq = g.adjacency_sequence_out(n, V, u)
684
A = [seq[k] for k in range(n)]
685
try:
686
assert A == list(M[u])
687
except AssertionError:
688
sage_free(V)
689
sage_free(seq)
690
raise AssertionError("Graph adjacency mismatch")
691
sage_free(seq)
692
sage_free(V)
693
694
###########################################
695
# Dense Graph Backend
696
###########################################
697
698
from c_graph import CGraphBackend
699
from c_graph cimport check_vertex, vertex_label, get_vertex
700
701
class DenseGraphBackend(CGraphBackend):
702
"""
703
Backend for Sage graphs using DenseGraphs.
704
705
::
706
707
sage: from sage.graphs.base.dense_graph import DenseGraphBackend
708
709
This class is only intended for use by the Sage Graph and DiGraph class.
710
If you are interested in using a DenseGraph, you probably want to do
711
something like the following example, which creates a Sage Graph instance
712
which wraps a DenseGraph object::
713
714
sage: G = Graph(30, implementation="c_graph", sparse=False)
715
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
716
sage: G.edges(labels=False)
717
[(0, 1), (0, 3), (4, 5), (9, 23)]
718
719
Note that Sage graphs using the backend are more flexible than DenseGraphs
720
themselves. This is because DenseGraphs (by design) do not deal with Python
721
objects::
722
723
sage: G.add_vertex((0,1,2))
724
sage: G.vertices()
725
[0,
726
...
727
29,
728
(0, 1, 2)]
729
sage: from sage.graphs.base.dense_graph import DenseGraph
730
sage: DG = DenseGraph(30)
731
sage: DG.add_vertex((0,1,2))
732
Traceback (most recent call last):
733
...
734
TypeError: an integer is required
735
736
"""
737
738
def __init__(self, n, directed=True):
739
"""
740
Initialize a dense graph with n vertices.
741
742
EXAMPLE:
743
744
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
745
sage: D.add_edge(0,1,None,False)
746
sage: list(D.iterator_edges(range(9), True))
747
[(0, 1, None)]
748
749
"""
750
self._cg = DenseGraph(n)
751
self._cg_rev = None
752
self._directed = directed
753
self.vertex_labels = {}
754
self.vertex_ints = {}
755
756
def add_edge(self, object u, object v, object l, bint directed):
757
"""
758
Adds the edge ``(u,v)`` to self.
759
760
INPUT:
761
762
- ``u,v`` - the vertices of the edge
763
- ``l`` - the edge label (ignored)
764
- ``directed`` - if False, also add ``(v,u)``
765
766
NOTE:
767
The input ``l`` is for consistency with other backends.
768
769
EXAMPLE::
770
771
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
772
sage: D.add_edge(0,1,None,False)
773
sage: list(D.iterator_edges(range(9), True))
774
[(0, 1, None)]
775
776
"""
777
if u is None: u = self.add_vertex(None)
778
if v is None: v = self.add_vertex(None)
779
780
cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,
781
self._cg, None, 0)
782
cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,
783
self._cg, None, 0)
784
785
if directed or u_int == v_int:
786
self._cg.add_arc(u_int, v_int)
787
else:
788
self._cg.add_arc(u_int, v_int)
789
self._cg.add_arc(v_int, u_int)
790
791
def add_edges(self, object edges, bint directed):
792
"""
793
Add edges from a list.
794
795
INPUT:
796
797
- ``edges`` - the edges to be added - can either be of the form
798
``(u,v)`` or ``(u,v,l)``
799
- ``directed`` - if False, add ``(v,u)`` as well as ``(u,v)``
800
801
EXAMPLE::
802
803
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
804
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
805
sage: list(D.iterator_edges(range(9), True))
806
[(0, 1, None),
807
(2, 3, None),
808
(4, 5, None),
809
(5, 6, None)]
810
811
"""
812
for e in edges:
813
u,v = e[:2]
814
self.add_edge(u,v,None,directed)
815
816
def del_edge(self, object u, object v, object l, bint directed):
817
"""
818
Delete edge ``(u,v)``.
819
820
INPUT:
821
822
- ``u,v`` - the vertices of the edge
823
- ``l`` - the edge label (ignored)
824
- ``directed`` - if False, also delete ``(v,u,l)``
825
826
NOTE:
827
The input ``l`` is for consistency with other backends.
828
829
EXAMPLE::
830
831
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
832
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
833
sage: list(D.iterator_edges(range(9), True))
834
[(0, 1, None),
835
(2, 3, None),
836
(4, 5, None),
837
(5, 6, None)]
838
sage: D.del_edge(0,1,None,True)
839
sage: list(D.iterator_out_edges(range(9), True))
840
[(1, 0, None),
841
(2, 3, None),
842
(3, 2, None),
843
(4, 5, None),
844
(5, 4, None),
845
(5, 6, None),
846
(6, 5, None)]
847
848
"""
849
if not ( self.has_vertex(u) and self.has_vertex(v) ):
850
return
851
cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,
852
self._cg, None, 0)
853
cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,
854
self._cg, None, 0)
855
if v is None:
856
u, v = u[:2]
857
if directed:
858
self._cg.del_all_arcs(u_int, v_int)
859
else:
860
self._cg.del_all_arcs(u_int, v_int)
861
self._cg.del_all_arcs(v_int, u_int)
862
863
def get_edge_label(self, object u, object v):
864
"""
865
Returns the edge label for ``(u,v)``. Always None, since dense graphs
866
do not support edge labels.
867
868
INPUT:
869
870
- ``u,v`` - the vertices of the edge
871
872
EXAMPLE::
873
874
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
875
sage: D.add_edges([(0,1), (2,3,7), (4,5), (5,6)], False)
876
sage: list(D.iterator_edges(range(9), True))
877
[(0, 1, None),
878
(2, 3, None),
879
(4, 5, None),
880
(5, 6, None)]
881
sage: D.del_edge(0,1,None,True)
882
sage: list(D.iterator_out_edges(range(9), True))
883
[(1, 0, None),
884
(2, 3, None),
885
(3, 2, None),
886
(4, 5, None),
887
(5, 4, None),
888
(5, 6, None),
889
(6, 5, None)]
890
sage: D.get_edge_label(2,3)
891
sage: D.get_edge_label(2,4)
892
Traceback (most recent call last):
893
...
894
LookupError: (2, 4) is not an edge of the graph.
895
896
"""
897
if not self.has_edge(u, v, None):
898
raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u), repr(v)))
899
return None
900
901
def has_edge(self, object u, object v, object l):
902
"""
903
Returns whether this graph has edge ``(u,v)``.
904
905
NOTE:
906
The input ``l`` is for consistency with other backends.
907
908
INPUT:
909
910
- ``u,v`` - the vertices of the edge
911
- ``l`` - the edge label (ignored)
912
913
EXAMPLE::
914
915
sage: D = sage.graphs.base.dense_graph.DenseGraphBackend(9)
916
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
917
sage: D.has_edge(0,1,None)
918
True
919
920
"""
921
if not ( self.has_vertex(u) and self.has_vertex(v) ):
922
return False
923
cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,
924
self._cg)
925
cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
926
self._cg)
927
return self._cg.has_arc(u_int, v_int)
928
929
def iterator_edges(self, object vertices, bint labels):
930
"""
931
Iterate over the edges incident to a sequence of vertices. Edges are
932
assumed to be undirected.
933
934
INPUT:
935
- ``vertices`` - a list of vertex labels
936
- ``labels`` - boolean, whether to return labels as well
937
938
EXAMPLE::
939
940
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
941
sage: G.add_edge(1,2,None,False)
942
sage: list(G.iterator_edges(range(9), False))
943
[(1, 2)]
944
sage: list(G.iterator_edges(range(9), True))
945
[(1, 2, None)]
946
947
"""
948
cdef object v
949
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
950
self._cg) for v in vertices if self.has_vertex(v)]
951
cdef int u_int, v_int
952
if labels:
953
return iter([tuple(sorted(
954
(vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg),
955
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
956
)))+(None,)
957
for v_int in vertices
958
for u_int in self._cg.out_neighbors(v_int)
959
if u_int >= v_int or u_int not in vertices])
960
else:
961
return iter([tuple(sorted(
962
(vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg),
963
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
964
)))
965
for v_int in vertices
966
for u_int in self._cg.out_neighbors(v_int)
967
if u_int >= v_int or u_int not in vertices])
968
969
def iterator_in_edges(self, object vertices, bint labels):
970
"""
971
Iterate over the incoming edges incident to a sequence of vertices.
972
973
INPUT:
974
- ``vertices`` - a list of vertex labels
975
- ``labels`` - boolean, whether to return labels as well
976
977
EXAMPLE::
978
979
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
980
sage: G.add_edge(1,2,None,True)
981
sage: list(G.iterator_in_edges([1], False))
982
[]
983
sage: list(G.iterator_in_edges([2], False))
984
[(1, 2)]
985
sage: list(G.iterator_in_edges([2], True))
986
[(1, 2, None)]
987
988
"""
989
cdef object v
990
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
991
self._cg) for v in vertices if self.has_vertex(v)]
992
cdef int u_int, v_int
993
if labels:
994
return iter([
995
(vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
996
vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg),
997
None)
998
for v_int in vertices
999
for u_int in self._cg.in_neighbors(v_int)])
1000
else:
1001
return iter([
1002
(vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
1003
vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg))
1004
for v_int in vertices
1005
for u_int in self._cg.in_neighbors(v_int)])
1006
1007
def iterator_out_edges(self, object vertices, bint labels):
1008
"""
1009
Iterate over the outbound edges incident to a sequence of vertices.
1010
1011
INPUT:
1012
- ``vertices`` - a list of vertex labels
1013
- ``labels`` - boolean, whether to return labels as well
1014
1015
EXAMPLE::
1016
1017
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1018
sage: G.add_edge(1,2,None,True)
1019
sage: list(G.iterator_out_edges([2], False))
1020
[]
1021
sage: list(G.iterator_out_edges([1], False))
1022
[(1, 2)]
1023
sage: list(G.iterator_out_edges([1], True))
1024
[(1, 2, None)]
1025
1026
"""
1027
cdef object u, v
1028
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
1029
self._cg) for v in vertices if self.has_vertex(v)]
1030
cdef int u_int, v_int
1031
if labels:
1032
return iter([
1033
(vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg),
1034
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
1035
None)
1036
for v_int in vertices
1037
for u_int in self._cg.out_neighbors(v_int)])
1038
else:
1039
return iter([
1040
(vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg),
1041
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg))
1042
for v_int in vertices
1043
for u_int in self._cg.out_neighbors(v_int)])
1044
1045
def multiple_edges(self, new):
1046
"""
1047
Get/set whether or not ``self`` allows multiple edges.
1048
1049
INPUT:
1050
1051
- ``new`` - boolean (to set) or ``None`` (to get)
1052
1053
EXAMPLES::
1054
1055
sage: import sage.graphs.base.dense_graph
1056
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1057
sage: G.multiple_edges(True)
1058
Traceback (most recent call last):
1059
...
1060
NotImplementedError: Dense graphs do not support multiple edges.
1061
sage: G.multiple_edges(None)
1062
False
1063
1064
"""
1065
if new is None:
1066
return False
1067
if new:
1068
raise NotImplementedError("Dense graphs do not support multiple edges.")
1069
1070
def set_edge_label(self, object u, object v, object l, bint directed):
1071
"""
1072
Label the edge ``(u,v)`` by ``l``.
1073
1074
INPUT:
1075
1076
- ``u,v`` - the vertices of the edge
1077
- ``l`` - the edge label
1078
- ``directed`` - if False, also set ``(v,u)`` with label ``l``
1079
1080
EXAMPLE::
1081
1082
sage: import sage.graphs.base.dense_graph
1083
sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1084
sage: G.set_edge_label(1,2,'a',True)
1085
Traceback (most recent call last):
1086
...
1087
NotImplementedError: Dense graphs do not support edge labels.
1088
"""
1089
raise NotImplementedError("Dense graphs do not support edge labels.")
1090
1091