Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/graphs/base/sparse_graph.pyx
8815 views
1
r"""
2
Fast sparse graphs
3
4
Usage Introduction
5
------------------
6
7
::
8
9
sage: from sage.graphs.base.sparse_graph import SparseGraph
10
11
Sparse graphs are initialized as follows::
12
13
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
14
15
This example initializes a sparse 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: S._num_verts()
20
10
21
sage: S.add_vertex(9)
22
9
23
sage: S._num_verts()
24
10
25
26
But 10 is not, until we add it::
27
28
sage: S._num_verts()
29
10
30
sage: S.add_vertex(10)
31
10
32
sage: S._num_verts()
33
11
34
35
You can begin working with unlabeled arcs right away as follows::
36
37
sage: S.add_arc(0,1)
38
sage: S.add_arc(1,2)
39
sage: S.add_arc(1,0)
40
sage: S.has_arc(7,3)
41
False
42
sage: S.has_arc(0,1)
43
True
44
sage: S.in_neighbors(1)
45
[0]
46
sage: S.out_neighbors(1)
47
[0, 2]
48
sage: S.del_all_arcs(0,1)
49
sage: S.all_arcs(0,1)
50
[]
51
sage: S.all_arcs(1,2)
52
[0]
53
sage: S.del_vertex(7)
54
sage: S.all_arcs(7,3)
55
Traceback (most recent call last):
56
...
57
LookupError: Vertex (7) is not a vertex of the graph.
58
sage: S._num_verts()
59
10
60
sage: S._num_arcs()
61
2
62
63
Sparse graphs support multiple edges and labeled edges, but requires that the
64
labels be positive integers (the case label = 0 is treated as no label).
65
66
::
67
68
sage: S.add_arc_label(0,1,-1)
69
Traceback (most recent call last):
70
...
71
ValueError: Label (-1) must be a nonnegative integer.
72
sage: S.add_arc(0,1)
73
sage: S.arc_label(0,1)
74
0
75
76
Note that ``arc_label`` only returns the first edge label found in the specified
77
place, and this can be in any order (if you want all arc labels, use
78
``all_arcs``)::
79
80
sage: S.add_arc_label(0,1,1)
81
sage: S.arc_label(0,1)
82
1
83
sage: S.all_arcs(0,1)
84
[0, 1]
85
86
Zero specifies only that there is no labeled arc::
87
88
sage: S.arc_label(1,2)
89
0
90
91
So do not be fooled::
92
93
sage: S.all_arcs(1,2)
94
[0]
95
sage: S.add_arc(1,2)
96
sage: S.arc_label(1,2)
97
0
98
99
Instead, if you work with unlabeled edges, be sure to use the right functions::
100
101
sage: T = SparseGraph(nverts = 3, expected_degree = 2)
102
sage: T.add_arc(0,1)
103
sage: T.add_arc(1,2)
104
sage: T.add_arc(2,0)
105
sage: T.has_arc(0,1)
106
True
107
108
Sparse graphs are by their nature directed. As of this writing, you need to do
109
operations in pairs to treat the undirected case (or use a backend or a Sage
110
graph)::
111
112
sage: T.has_arc(1,0)
113
False
114
115
Multiple unlabeled edges are also possible::
116
117
sage: for _ in range(10): S.add_arc(5,4)
118
sage: S.all_arcs(5,4)
119
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
120
121
The curious developer is encouraged to check out the ``unsafe`` functions,
122
which do not check input but which run in pure C.
123
124
Underlying Data Structure
125
-------------------------
126
127
The class ``SparseGraph`` contains the following variables which are inherited
128
from ``CGraph`` (for explanation, refer to the documentation there)::
129
130
cdef int num_verts
131
cdef int num_arcs
132
cdef int *in_degrees
133
cdef int *out_degrees
134
cdef bitset_t active_vertices
135
136
It also contains the following variables::
137
138
cdef int hash_length
139
cdef int hash_mask
140
cdef SparseGraphBTNode **vertices
141
142
For each vertex ``u``, a hash table of length ``hash_length`` is instantiated.
143
An arc ``(u, v)`` is stored at ``u * hash_length + hash(v)`` of the array
144
``vertices``, where ``hash`` should be thought of as an arbitrary but fixed hash
145
function which takes values in ``0 <= hash < hash_length``. Each address may
146
represent different arcs, say ``(u, v1)`` and ``(u, v2)`` where
147
``hash(v1) == hash(v2)``. Thus, a binary tree structure is used at this step to
148
speed access to individual arcs, whose nodes (each of which represents a pair
149
``(u,v)``) are instances of the following type::
150
151
cdef struct SparseGraphBTNode:
152
int vertex
153
int number
154
SparseGraphLLNode *labels
155
SparseGraphBTNode *left
156
SparseGraphBTNode *right
157
158
Which range of the ``vertices`` array the root of the tree is in determines
159
``u``, and ``vertex`` stores ``v``. The integer ``number`` stores only the
160
number of unlabeled arcs from ``u`` to ``v``.
161
162
Currently, labels are stored in a simple linked list, whose nodes are instances
163
of the following type::
164
165
cdef struct SparseGraphLLNode:
166
int label
167
int number
168
SparseGraphLLNode *next
169
170
The int ``label`` must be a positive integer, since 0 indicates no label, and
171
negative numbers indicate errors. The int ``number`` is the number of arcs with
172
the given label.
173
174
TODO: Optimally, edge labels would also be represented by a binary tree, which
175
would help performance in graphs with many overlapping edges. Also, a more
176
efficient binary tree structure could be used, although in practice the trees
177
involved will usually have very small order, unless the degree of vertices
178
becomes significantly larger than the ``expected_degree`` given, because this is
179
the size of each hash table. Indeed, the expected size of the binary trees is
180
`\frac{\text{actual degree}}{\text{expected degree}}`. Ryan Dingman, e.g., is
181
working on a general-purpose Cython-based red black tree, which would be optimal
182
for both of these uses.
183
"""
184
185
#*******************************************************************************
186
# Copyright (C) 2008-9 Robert L. Miller <[email protected]>
187
#
188
# Distributed under the terms of the GNU General Public License (GPL)
189
# http://www.gnu.org/licenses/
190
#*******************************************************************************
191
192
include 'sage/misc/bitset.pxi'
193
194
cdef enum:
195
BT_REORDERING_CONSTANT = 145533211
196
# Since the binary tree will often see vertices coming in already sorted,
197
# we don't use the normal ordering on integers, instead multiplying by a
198
# randomly chosen number and (after reducing mod the size of integers)
199
# comparing the result. This isn't necessarily the most efficient way to do
200
# things, but it may just be on binary trees that are never bigger than two
201
# or three nodes.
202
203
cdef inline int compare(int a, int b):
204
# Here we rely on the fact that C performs arithmetic on unsigned
205
# ints modulo 2^wordsize.
206
cdef unsigned int aa = a, bb = b # signed ints lead to badness like a>b>c>a...
207
if aa*BT_REORDERING_CONSTANT > bb*BT_REORDERING_CONSTANT:
208
return 1
209
elif aa*BT_REORDERING_CONSTANT < bb*BT_REORDERING_CONSTANT:
210
return -1
211
return 0
212
213
class id_dict:
214
"""
215
This is a helper class for pickling sparse graphs. It emulates a dictionary
216
``d`` which contains all objects, and always, ``d[x] == x``.
217
218
EXAMPLE::
219
220
sage: from sage.graphs.base.sparse_graph import id_dict
221
sage: d = id_dict()
222
sage: d[None] is None
223
True
224
sage: d[7]
225
7
226
sage: d[{}]
227
{}
228
sage: d[()]
229
()
230
231
"""
232
def __getitem__(self, x):
233
"""
234
Implements d[x].
235
236
EXAMPLE:
237
238
sage: from sage.graphs.base.sparse_graph import id_dict
239
sage: d = id_dict()
240
sage: d[None] is None
241
True
242
sage: d[7]
243
7
244
sage: d[{}]
245
{}
246
sage: d[()]
247
()
248
249
"""
250
return x
251
252
cdef class SparseGraph(CGraph):
253
"""
254
Compiled sparse graphs.
255
256
::
257
258
sage: from sage.graphs.base.sparse_graph import SparseGraph
259
260
Sparse graphs are initialized as follows::
261
262
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
263
264
INPUT:
265
266
- ``nverts`` - non-negative integer, the number of vertices.
267
- ``expected_degree`` - non-negative integer (default: 16), expected upper
268
bound on degree of vertices.
269
- ``extra_vertices`` - non-negative integer (default: 0), how many extra
270
vertices to allocate.
271
- ``verts`` - optional list of vertices to add
272
- ``arcs`` - optional list of arcs to add
273
274
The first ``nverts`` are created as vertices of the graph, and the next
275
``extra_vertices`` can be freely added without reallocation. See top level
276
documentation for more details. The input ``verts`` and ``arcs`` are mainly
277
for use in pickling.
278
279
"""
280
281
def __cinit__(self, int nverts, int expected_degree = 16, int extra_vertices = 10, verts=None, arcs=None):
282
"""
283
Allocation and initialization happen in one place.
284
285
Memory usage is roughly
286
287
O( (nverts + extra_vertices)*expected_degree + num_arcs ).
288
289
EXAMPLE::
290
291
sage: from sage.graphs.base.sparse_graph import SparseGraph
292
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
293
294
TESTS::
295
296
sage: Graph(-1)
297
Traceback (most recent call last):
298
...
299
ValueError: The number of vertices cannot be strictly negative!
300
"""
301
cdef int i = 1
302
if nverts < 0:
303
raise ValueError("The number of vertices cannot be strictly negative!")
304
if nverts == 0 and extra_vertices == 0:
305
raise RuntimeError('Sparse graphs must allocate space for vertices!')
306
self.num_verts = nverts
307
nverts += extra_vertices
308
self.num_arcs = 0
309
while i < expected_degree:
310
i = i << 1
311
self.hash_length = i
312
self.hash_mask = i - 1
313
314
# Allocating memory
315
self.vertices = <SparseGraphBTNode **> \
316
sage_malloc(nverts * self.hash_length * sizeof(SparseGraphBTNode *))
317
self.in_degrees = <int *> sage_malloc(nverts * sizeof(int))
318
self.out_degrees = <int *> sage_malloc(nverts * sizeof(int))
319
320
# Checking the memory was actually allocated
321
if not self.vertices or not self.in_degrees or not self.out_degrees:
322
if self.vertices: sage_free(self.vertices)
323
if self.in_degrees: sage_free(self.in_degrees)
324
if self.out_degrees: sage_free(self.out_degrees)
325
raise RuntimeError("Failure allocating memory.")
326
327
# Initializing variables:
328
#
329
# self.vertices[i] = 0
330
memset(self.vertices, <int> NULL, nverts * self.hash_length * sizeof(SparseGraphBTNode *))
331
332
# self.in_degrees[i] = 0
333
memset(self.in_degrees, 0, nverts * sizeof(int))
334
335
# self.out_degrees[i] = 0
336
memset(self.out_degrees, 0, nverts * sizeof(int))
337
338
bitset_init(self.active_vertices, self.num_verts + extra_vertices)
339
bitset_set_first_n(self.active_vertices, self.num_verts)
340
341
if verts is not None:
342
self.add_vertices(verts)
343
344
if arcs is not None:
345
for u,v,l in arcs:
346
self.add_arc_label(u,v,l)
347
348
def __dealloc__(self):
349
"""
350
New and dealloc are both tested at class level.
351
"""
352
cdef SparseGraphBTNode **temp
353
cdef SparseGraphLLNode *label_temp
354
cdef int i
355
356
# Freeing the list of arcs attached to each vertex
357
for i from 0 <= i < self.active_vertices.size * self.hash_length:
358
temp = &(self.vertices[i])
359
360
# While temp[0]=self.vertices[i] is not NULL, find a leaf in the
361
# tree rooted at temp[0] and free it. Then go back to temp[0] and do
362
# it again. When self.vertices[i] is NULL, go for self.vertices[i+1]
363
while temp[0] != NULL:
364
if temp[0].left != NULL:
365
temp = &(temp[0].left)
366
elif temp[0].right != NULL:
367
temp = &(temp[0].right)
368
else:
369
label_temp = temp[0].labels
370
while label_temp != NULL:
371
temp[0].labels = label_temp.next
372
sage_free(label_temp)
373
label_temp = temp[0].labels
374
sage_free(temp[0])
375
temp[0] = NULL
376
temp = &(self.vertices[i])
377
378
sage_free(self.vertices)
379
sage_free(self.in_degrees)
380
sage_free(self.out_degrees)
381
bitset_free(self.active_vertices)
382
383
def __reduce__(self):
384
"""
385
Return a tuple used for pickling this graph.
386
387
TESTS::
388
389
sage: from sage.graphs.base.sparse_graph import SparseGraph
390
sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
391
sage: S.add_arc(0,1)
392
sage: S.add_arc(0,1)
393
sage: S.all_arcs(0,1)
394
[0, 0]
395
sage: S.all_arcs(1,2)
396
[]
397
sage: S.add_arc_label(0,0,3)
398
sage: S.all_arcs(0,0)
399
[3]
400
sage: LS = loads(dumps(S))
401
sage: LS.all_arcs(0,1)
402
[0, 0]
403
sage: LS.all_arcs(1,2)
404
[]
405
sage: LS.all_arcs(0,0)
406
[3]
407
408
Test for the trac 10916 -- are multiedges and loops pickled
409
correctly?::
410
411
sage: DG = DiGraph({0:{0:[0, 1], 1:[0, 1]}})
412
sage: loads(dumps(DG)).edges()
413
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)]
414
415
"""
416
from sage.graphs.all import DiGraph
417
D = DiGraph(implementation='c_graph', sparse=True, multiedges=True, loops=True)
418
D._backend._cg = self
419
cdef int i
420
D._backend.vertex_labels = {}
421
for i from 0 <= i < self.active_vertices.size:
422
if bitset_in(self.active_vertices, i):
423
D._backend.vertex_labels[i] = i
424
D._backend.vertex_ints = D._backend.vertex_labels
425
D._backend.edge_labels = id_dict()
426
arcs = [(u,v,l) if l is not None else (u,v,0) for u,v,l in D.edges(labels=True)]
427
return (SparseGraph, (0, self.hash_length, self.active_vertices.size, self.verts(), arcs))
428
429
cpdef realloc(self, int total):
430
"""
431
Reallocate the number of vertices to use, without actually adding any.
432
433
INPUT:
434
435
- ``total`` - integer, the total size to make the array
436
437
Returns -1 and fails if reallocation would destroy any active vertices.
438
439
EXAMPLES::
440
441
sage: from sage.graphs.base.sparse_graph import SparseGraph
442
sage: S = SparseGraph(nverts=4, extra_vertices=4)
443
sage: S.current_allocation()
444
8
445
sage: S.add_vertex(6)
446
6
447
sage: S.current_allocation()
448
8
449
sage: S.add_vertex(10)
450
10
451
sage: S.current_allocation()
452
16
453
sage: S.add_vertex(40)
454
Traceback (most recent call last):
455
...
456
RuntimeError: Requested vertex is past twice the allocated range: use realloc.
457
sage: S.realloc(50)
458
sage: S.add_vertex(40)
459
40
460
sage: S.current_allocation()
461
50
462
sage: S.realloc(30)
463
-1
464
sage: S.current_allocation()
465
50
466
sage: S.del_vertex(40)
467
sage: S.realloc(30)
468
sage: S.current_allocation()
469
30
470
471
"""
472
if total == 0:
473
raise RuntimeError('Sparse graphs must allocate space for vertices!')
474
cdef bitset_t bits
475
if total < self.active_vertices.size:
476
bitset_init(bits, self.active_vertices.size)
477
bitset_set_first_n(bits, total)
478
if not bitset_issubset(self.active_vertices, bits):
479
bitset_free(bits)
480
return -1
481
bitset_free(bits)
482
483
self.vertices = <SparseGraphBTNode **> sage_realloc(self.vertices, total * self.hash_length * sizeof(SparseGraphBTNode *))
484
self.in_degrees = <int *> sage_realloc(self.in_degrees, total * sizeof(int))
485
self.out_degrees = <int *> sage_realloc(self.out_degrees, total * sizeof(int))
486
487
cdef int new_vertices = total - self.active_vertices.size
488
489
# Initializing the entries corresponding to new vertices if any
490
if new_vertices>0:
491
492
# self.vertices
493
memset(self.vertices+self.active_vertices.size * self.hash_length,
494
<int> NULL,
495
new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))
496
497
# self.int_degrees
498
memset(self.in_degrees+self.active_vertices.size, 0, new_vertices * sizeof(int))
499
500
# self.out_degrees
501
memset(self.out_degrees+self.active_vertices.size, 0, new_vertices * sizeof(int))
502
503
# self.active_vertices
504
bitset_realloc(self.active_vertices, total)
505
506
###################################
507
# Unlabeled arc functions
508
###################################
509
510
cdef int add_arc_unsafe(self, int u, int v) except? -1:
511
"""
512
Adds arc (u, v) to the graph with no label.
513
514
INPUT:
515
u, v -- non-negative integers
516
"""
517
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
518
cdef int compared
519
cdef SparseGraphBTNode **ins_pt = &(self.vertices[i])
520
while ins_pt[0] != NULL:
521
compared = compare(ins_pt[0].vertex, v)
522
if compared > 0:
523
ins_pt = &(ins_pt[0].left)
524
elif compared < 0:
525
ins_pt = &(ins_pt[0].right)
526
else:
527
ins_pt[0].number += 1
528
break
529
if ins_pt[0] == NULL:
530
ins_pt[0] = <SparseGraphBTNode *> sage_malloc(sizeof(SparseGraphBTNode))
531
if not ins_pt[0]:
532
raise RuntimeError("Failure allocating memory.")
533
ins_pt[0].vertex = v
534
ins_pt[0].number = 1
535
ins_pt[0].left = NULL
536
ins_pt[0].right = NULL
537
ins_pt[0].labels = NULL
538
self.in_degrees[v] += 1
539
self.out_degrees[u] += 1
540
self.num_arcs += 1
541
542
cpdef add_arc(self, int u, int v):
543
"""
544
Adds arc ``(u, v)`` to the graph with no label.
545
546
INPUT:
547
548
- ``u, v`` -- non-negative integers, must be in self
549
550
EXAMPLE::
551
552
sage: from sage.graphs.base.sparse_graph import SparseGraph
553
sage: G = SparseGraph(5)
554
sage: G.add_arc(0,1)
555
sage: G.add_arc(4,7)
556
Traceback (most recent call last):
557
...
558
LookupError: Vertex (7) is not a vertex of the graph.
559
sage: G.has_arc(1,0)
560
False
561
sage: G.has_arc(0,1)
562
True
563
564
"""
565
self.check_vertex(u)
566
self.check_vertex(v)
567
self.add_arc_unsafe(u,v)
568
569
cdef int has_arc_unsafe(self, int u, int v):
570
"""
571
Checks whether arc (u, v) is in the graph.
572
573
INPUT:
574
u, v -- non-negative integers, must be in self
575
576
OUTPUT:
577
0 -- False
578
1 -- True
579
580
"""
581
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
582
cdef SparseGraphBTNode *temp = self.vertices[i]
583
while temp != NULL:
584
if temp.vertex == v:
585
return 1
586
if compare(temp.vertex, v) > 0:
587
temp = temp.left
588
else: # note compare < 0
589
temp = temp.right
590
return 0
591
592
cpdef bint has_arc(self, int u, int v):
593
"""
594
Checks whether arc ``(u, v)`` is in the graph.
595
596
INPUT:
597
- ``u, v`` - integers
598
599
EXAMPLE::
600
601
sage: from sage.graphs.base.sparse_graph import SparseGraph
602
sage: G = SparseGraph(5)
603
sage: G.add_arc_label(0,1)
604
sage: G.has_arc(1,0)
605
False
606
sage: G.has_arc(0,1)
607
True
608
609
"""
610
if u < 0 or u >= self.active_vertices.size or not bitset_in(self.active_vertices, u):
611
return False
612
if v < 0 or v >= self.active_vertices.size or not bitset_in(self.active_vertices, v):
613
return False
614
return self.has_arc_unsafe(u,v)
615
616
cdef int del_arc_unsafe(self, int u, int v):
617
"""
618
Deletes *all* arcs from u to v.
619
620
INPUT:
621
u, v -- non-negative integers, must be in self
622
623
OUTPUT:
624
0 -- No error.
625
1 -- No arc to delete.
626
627
"""
628
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
629
cdef int compared, left_len, right_len
630
cdef SparseGraphBTNode *temp, **left_child, **right_child
631
cdef SparseGraphBTNode **parent = &self.vertices[i]
632
cdef SparseGraphLLNode *labels
633
634
# Assigning to parent the SparseGraphBTNode corresponding to arc (u,v)
635
while parent[0] != NULL:
636
compared = compare(parent[0].vertex, v)
637
if compared > 0:
638
parent = &(parent[0].left)
639
elif compared < 0:
640
parent = &(parent[0].right)
641
else:# if parent[0].vertex == v:
642
break
643
644
# If not found, there is no arc to delete !
645
if parent[0] == NULL:
646
return 1
647
648
# now parent[0] points to the BT node corresponding to (u,v)
649
labels = parent[0].labels
650
i = parent[0].number
651
self.in_degrees[v] -= i
652
self.out_degrees[u] -= i
653
self.num_arcs -= i
654
655
# Freeing the labels
656
while labels != NULL:
657
i = labels.number
658
parent[0].labels = parent[0].labels.next
659
sage_free(labels)
660
labels = parent[0].labels
661
self.in_degrees[v] -= i
662
self.out_degrees[u] -= i
663
self.num_arcs -= i
664
665
# Now, if the SparseGraphBTNode element is to be removed, it has to be
666
# replaced in the binary tree by one of its children.
667
668
# If there is no left child
669
if parent[0].left == NULL:
670
temp = parent[0]
671
parent[0] = parent[0].right
672
sage_free(temp)
673
return 0
674
675
# If there is no right child
676
elif parent[0].right == NULL:
677
temp = parent[0]
678
parent[0] = parent[0].left
679
sage_free(temp)
680
return 0
681
682
# Both children
683
else:
684
left_len = 0
685
right_len = 0
686
left_child = &(parent[0].left)
687
right_child = &(parent[0].right)
688
689
# left_len is equal to the maximum length of a path LR...R. The
690
# last element of this path is the value of left_child
691
692
while left_child[0].right != NULL:
693
left_len += 1
694
left_child = &(left_child[0].right)
695
# right_len is equal to the maximum length of a path RL...L. The
696
# last element of this path is the value of right_child
697
698
while right_child[0].left != NULL:
699
right_len += 1
700
right_child = &(right_child[0].left)
701
702
# According to the respective lengths, replace parent by the left or
703
# right child and place the other child at its expected place.
704
if left_len > right_len:
705
left_child[0].right = parent[0].right
706
temp = parent[0]
707
parent[0] = left_child[0]
708
left_child[0] = left_child[0].left
709
parent[0].left = temp.left
710
sage_free(temp)
711
return 0
712
else:
713
right_child[0].left = parent[0].left
714
temp = parent[0]
715
parent[0] = right_child[0]
716
right_child[0] = right_child[0].right
717
parent[0].right = temp.right
718
sage_free(temp)
719
return 0
720
721
cpdef del_all_arcs(self, int u, int v):
722
"""
723
Deletes all arcs from ``u`` to ``v``.
724
725
INPUT:
726
- ``u, v`` - integers
727
728
EXAMPLE::
729
730
sage: from sage.graphs.base.sparse_graph import SparseGraph
731
sage: G = SparseGraph(5)
732
sage: G.add_arc_label(0,1,0)
733
sage: G.add_arc_label(0,1,1)
734
sage: G.add_arc_label(0,1,2)
735
sage: G.add_arc_label(0,1,3)
736
sage: G.del_all_arcs(0,1)
737
sage: G.has_arc(0,1)
738
False
739
sage: G.arc_label(0,1)
740
0
741
sage: G.del_all_arcs(0,1)
742
743
"""
744
self.check_vertex(u)
745
self.check_vertex(v)
746
self.del_arc_unsafe(u,v)
747
748
###################################
749
# Neighbor functions
750
###################################
751
752
cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except? -2:
753
"""
754
Gives all v such that (u, v) is an arc of the graph.
755
756
INPUT:
757
u -- non-negative integer, must be in self
758
neighbors -- must be a pointer to an (allocated) integer array
759
size -- the length of the array
760
761
OUTPUT:
762
nonnegative integer -- the number of v such that (u, v) is an arc
763
-1 -- indicates that the array has been filled with neighbors, but
764
there were more
765
766
"""
767
cdef int i, num_nbrs = 0, current_nbr = 0
768
if self.out_degrees[u] == 0:
769
return 0
770
cdef SparseGraphBTNode **pointers = <SparseGraphBTNode **> \
771
sage_malloc(size * sizeof(SparseGraphBTNode *))
772
if not pointers:
773
raise RuntimeError("Failure allocating memory.")
774
for i from u * self.hash_length <= i < (u+1) * self.hash_length:
775
if self.vertices[i] == NULL:
776
continue
777
if num_nbrs == size:
778
sage_free(pointers)
779
return -1
780
pointers[num_nbrs] = self.vertices[i]
781
neighbors[num_nbrs] = self.vertices[i].vertex
782
num_nbrs += 1
783
784
# While all the neighbors have not been added to the list, explore
785
# element pointers[current_nbr] and append its children to the end
786
# of pointers if necessary, the increment current_nbr.
787
while current_nbr < num_nbrs:
788
if pointers[current_nbr].left != NULL:
789
if num_nbrs == size:
790
sage_free(pointers)
791
return -1
792
pointers[num_nbrs] = pointers[current_nbr].left
793
neighbors[num_nbrs] = pointers[current_nbr].left.vertex
794
num_nbrs += 1
795
if pointers[current_nbr].right != NULL:
796
if num_nbrs == size:
797
sage_free(pointers)
798
return -1
799
pointers[num_nbrs] = pointers[current_nbr].right
800
neighbors[num_nbrs] = pointers[current_nbr].right.vertex
801
num_nbrs += 1
802
current_nbr += 1
803
sage_free(pointers)
804
return num_nbrs
805
806
cpdef list out_neighbors(self, int u):
807
"""
808
Gives all ``v`` such that ``(u, v)`` is an arc of the graph.
809
810
INPUT:
811
- ``u`` - integer
812
813
EXAMPLES::
814
815
sage: from sage.graphs.base.sparse_graph import SparseGraph
816
sage: G = SparseGraph(5)
817
sage: G.add_arc(0,1)
818
sage: G.add_arc(1,2)
819
sage: G.add_arc(1,3)
820
sage: G.out_neighbors(0)
821
[1]
822
sage: G.out_neighbors(1)
823
[2, 3]
824
825
"""
826
cdef int i, num_nbrs
827
self.check_vertex(u)
828
if self.out_degrees[u] == 0:
829
return []
830
cdef int size = self.out_degrees[u]
831
cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))
832
if not neighbors:
833
raise RuntimeError("Failure allocating memory.")
834
num_nbrs = self.out_neighbors_unsafe(u, neighbors, size)
835
output = [neighbors[i] for i from 0 <= i < num_nbrs]
836
sage_free(neighbors)
837
return output
838
839
cpdef int out_degree(self, int u):
840
"""
841
Returns the out-degree of ``v``
842
843
INPUT:
844
- ``u`` - integer
845
846
EXAMPLES::
847
848
sage: from sage.graphs.base.sparse_graph import SparseGraph
849
sage: G = SparseGraph(5)
850
sage: G.add_arc(0,1)
851
sage: G.add_arc(1,2)
852
sage: G.add_arc(1,3)
853
sage: G.out_degree(0)
854
1
855
sage: G.out_degree(1)
856
2
857
"""
858
return self.out_degrees[u]
859
860
861
cdef int in_neighbors_unsafe(self, int v, int *neighbors, int size):
862
"""
863
Gives all u such that (u, v) is an arc of the graph.
864
865
INPUT:
866
v -- non-negative integer, must be in self
867
neighbors -- must be a pointer to an (allocated) integer array
868
size -- the length of the array
869
870
OUTPUT:
871
nonnegative integer -- the number of u such that (u, v) is an arc
872
-1 -- indicates that the array has been filled with neighbors, but
873
there were more
874
875
NOTE: Due to the implementation of SparseGraph, this method is much more
876
expensive than out_neighbors_unsafe.
877
878
"""
879
cdef int i, num_nbrs = 0
880
if self.in_degrees[v] == 0:
881
return 0
882
for i from 0 <= i < self.active_vertices.size:
883
if not bitset_in(self.active_vertices, i): continue
884
if self.has_arc_unsafe(i, v):
885
if num_nbrs == size:
886
return -1
887
neighbors[num_nbrs] = i
888
num_nbrs += 1
889
return num_nbrs
890
891
cpdef list in_neighbors(self, int v):
892
"""
893
Gives all ``u`` such that ``(u, v)`` is an arc of the graph.
894
895
INPUT:
896
- ``v`` - integer
897
898
EXAMPLES::
899
900
sage: from sage.graphs.base.sparse_graph import SparseGraph
901
sage: G = SparseGraph(5)
902
sage: G.add_arc(0,1)
903
sage: G.add_arc(3,1)
904
sage: G.add_arc(1,3)
905
sage: G.in_neighbors(1)
906
[0, 3]
907
sage: G.in_neighbors(3)
908
[1]
909
910
NOTE: Due to the implementation of SparseGraph, this method is much more
911
expensive than neighbors_unsafe.
912
"""
913
cdef int i, num_nbrs
914
self.check_vertex(v)
915
if self.in_degrees[v] == 0:
916
return []
917
cdef int size = self.in_degrees[v]
918
cdef int *neighbors = <int *> sage_malloc(size * sizeof(int))
919
if not neighbors:
920
raise RuntimeError("Failure allocating memory.")
921
num_nbrs = self.in_neighbors_unsafe(v, neighbors, size)
922
output = [neighbors[i] for i from 0 <= i < num_nbrs]
923
sage_free(neighbors)
924
return output
925
926
cpdef int in_degree(self, int u):
927
"""
928
Returns the in-degree of ``v``
929
930
INPUT:
931
- ``u`` - integer
932
933
EXAMPLES::
934
935
sage: from sage.graphs.base.sparse_graph import SparseGraph
936
sage: G = SparseGraph(5)
937
sage: G.add_arc(0,1)
938
sage: G.add_arc(1,2)
939
sage: G.add_arc(1,3)
940
sage: G.in_degree(0)
941
0
942
sage: G.in_degree(1)
943
1
944
"""
945
return self.in_degrees[u]
946
947
948
###################################
949
# Labeled arc functions
950
###################################
951
952
cdef int add_arc_label_unsafe(self, int u, int v, int l) except? -1:
953
"""
954
Adds arc (u, v) to the graph with label l.
955
956
INPUT:
957
u, v -- non-negative integers
958
l -- a positive integer label, or zero for no label
959
960
OUTPUT:
961
0 -- No error.
962
963
"""
964
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
965
cdef int compared
966
cdef SparseGraphBTNode **ins_pt = &(self.vertices[i])
967
cdef SparseGraphLLNode *label_ptr
968
while ins_pt[0] != NULL:
969
compared = compare(ins_pt[0].vertex, v)
970
if compared > 0:
971
ins_pt = &(ins_pt[0].left)
972
elif compared < 0:
973
ins_pt = &(ins_pt[0].right)
974
else:
975
break
976
if ins_pt[0] == NULL:
977
ins_pt[0] = <SparseGraphBTNode *> sage_malloc(sizeof(SparseGraphBTNode))
978
if not ins_pt[0]:
979
raise RuntimeError("Failure allocating memory.")
980
ins_pt[0].number = 0
981
ins_pt[0].vertex = v
982
ins_pt[0].left = NULL
983
ins_pt[0].right = NULL
984
ins_pt[0].labels = NULL
985
if l:
986
label_ptr = ins_pt[0].labels
987
while label_ptr != NULL and label_ptr.label != l:
988
label_ptr = label_ptr.next
989
if label_ptr == NULL:
990
label_ptr = <SparseGraphLLNode *> sage_malloc(sizeof(SparseGraphLLNode))
991
if not label_ptr:
992
sage_free(ins_pt[0])
993
raise RuntimeError("Failure allocating memory.")
994
label_ptr.label = l
995
label_ptr.number = 1
996
label_ptr.next = ins_pt[0].labels
997
ins_pt[0].labels = label_ptr
998
else:
999
label_ptr.number += 1
1000
else:
1001
ins_pt[0].number += 1
1002
self.in_degrees[v] += 1
1003
self.out_degrees[u] += 1
1004
self.num_arcs += 1
1005
1006
def add_arc_label(self, int u, int v, int l=0):
1007
"""
1008
Adds arc ``(u, v)`` to the graph with label ``l``.
1009
1010
INPUT:
1011
- ``u, v`` - non-negative integers, must be in self
1012
- ``l`` - a positive integer label, or zero for no label
1013
1014
EXAMPLE::
1015
1016
sage: from sage.graphs.base.sparse_graph import SparseGraph
1017
sage: G = SparseGraph(5)
1018
sage: G.add_arc_label(0,1)
1019
sage: G.add_arc_label(4,7)
1020
Traceback (most recent call last):
1021
...
1022
LookupError: Vertex (7) is not a vertex of the graph.
1023
sage: G.has_arc(1,0)
1024
False
1025
sage: G.has_arc(0,1)
1026
True
1027
sage: G.add_arc_label(1,2,2)
1028
sage: G.arc_label(1,2)
1029
2
1030
1031
"""
1032
self.check_vertex(u)
1033
self.check_vertex(v)
1034
if l < 0:
1035
raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))
1036
self.add_arc_label_unsafe(u,v,l)
1037
1038
cdef int arc_label_unsafe(self, int u, int v):
1039
"""
1040
Retrieves the first label found associated with (u, v) (a positive
1041
integer).
1042
1043
INPUT:
1044
u, v -- integers from 0, ..., n-1, where n is the number of vertices
1045
1046
OUTPUT:
1047
positive integer -- indicates that there is a label on (u, v).
1048
0 -- either the arc (u, v) is unlabeled, or there is no arc at all.
1049
1050
"""
1051
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1052
cdef int compared
1053
cdef SparseGraphBTNode *temp = self.vertices[i]
1054
while temp != NULL:
1055
compared = compare(temp.vertex, v)
1056
if compared > 0:
1057
temp = temp.left
1058
elif compared < 0:
1059
temp = temp.right
1060
else:
1061
break
1062
if temp == NULL or temp.labels == NULL:
1063
return 0
1064
return temp.labels.label
1065
1066
cpdef int arc_label(self, int u, int v):
1067
"""
1068
Retrieves the first label found associated with ``(u, v)``.
1069
1070
INPUT:
1071
- ``u, v`` - non-negative integers, must be in self
1072
1073
OUTPUT:
1074
- positive integer - indicates that there is a label on ``(u, v)``.
1075
- 0 - either the arc ``(u, v)`` is unlabeled, or there is no arc at all.
1076
1077
EXAMPLE::
1078
1079
sage: from sage.graphs.base.sparse_graph import SparseGraph
1080
sage: G = SparseGraph(5)
1081
sage: G.add_arc_label(3,4,7)
1082
sage: G.arc_label(3,4)
1083
7
1084
1085
NOTES:
1086
1087
To this function, an unlabeled arc is indistinguishable from a non-arc::
1088
1089
sage: G.add_arc_label(1,0)
1090
sage: G.arc_label(1,0)
1091
0
1092
sage: G.arc_label(1,1)
1093
0
1094
1095
This function only returns the *first* label it finds from ``u`` to ``v``::
1096
1097
sage: G.add_arc_label(1,2,1)
1098
sage: G.add_arc_label(1,2,2)
1099
sage: G.arc_label(1,2)
1100
2
1101
1102
"""
1103
self.check_vertex(u)
1104
self.check_vertex(v)
1105
return self.arc_label_unsafe(u,v)
1106
1107
cdef int all_arcs_unsafe(self, int u, int v, int *arc_labels, int size):
1108
"""
1109
Gives the labels of all arcs (u, v).
1110
1111
INPUT:
1112
u, v -- integers from 0, ..., n-1, where n is the number of vertices
1113
arc_labels -- must be a pointer to an (allocated) integer array
1114
size -- the length of the array
1115
1116
OUTPUT:
1117
integer -- the number of arcs (u, v)
1118
-1 -- indicates that the array has been filled with labels, but
1119
there were more
1120
1121
"""
1122
cdef int i = (u * self.hash_length) + (v & self.hash_mask), j
1123
cdef int compared, num_arcs
1124
cdef SparseGraphBTNode *temp = self.vertices[i]
1125
cdef SparseGraphLLNode *label
1126
while temp != NULL:
1127
compared = compare(temp.vertex, v)
1128
if compared > 0:
1129
temp = temp.left
1130
elif compared < 0:
1131
temp = temp.right
1132
else: # temp.vertex == v:
1133
break
1134
if temp == NULL:
1135
return 0
1136
j = 0
1137
num_arcs = temp.number
1138
while j < num_arcs and j < size:
1139
arc_labels[j] = 0
1140
j += 1
1141
label = temp.labels
1142
while label != NULL:
1143
num_arcs += label.number
1144
while j < num_arcs and j < size:
1145
arc_labels[j] = label.label
1146
j += 1
1147
label = label.next
1148
if j == size and label != NULL:
1149
return -1
1150
return num_arcs
1151
1152
cpdef list all_arcs(self, int u, int v):
1153
"""
1154
Gives the labels of all arcs ``(u, v)``. An unlabeled arc is interpreted as
1155
having label 0.
1156
1157
EXAMPLE::
1158
1159
sage: from sage.graphs.base.sparse_graph import SparseGraph
1160
sage: G = SparseGraph(5)
1161
sage: G.add_arc_label(1,2,1)
1162
sage: G.add_arc_label(1,2,2)
1163
sage: G.add_arc_label(1,2,2)
1164
sage: G.add_arc_label(1,2,2)
1165
sage: G.add_arc_label(1,2,3)
1166
sage: G.add_arc_label(1,2,3)
1167
sage: G.add_arc_label(1,2,4)
1168
sage: G.all_arcs(1,2)
1169
[4, 3, 3, 2, 2, 2, 1]
1170
1171
"""
1172
cdef int size, num_arcs, i
1173
cdef int *arc_labels
1174
cdef list output
1175
self.check_vertex(u)
1176
self.check_vertex(v)
1177
if self.in_degrees[v] < self.out_degrees[u]:
1178
size = self.in_degrees[v]
1179
else:
1180
size = self.out_degrees[u]
1181
arc_labels = <int *> sage_malloc(size * sizeof(int))
1182
if not arc_labels:
1183
raise RuntimeError("Failure allocating memory.")
1184
num_arcs = self.all_arcs_unsafe(u, v, arc_labels, size)
1185
if num_arcs == -1:
1186
sage_free(arc_labels)
1187
raise RuntimeError("There was an error: there seem to be more arcs than self.in_degrees or self.out_degrees indicate.")
1188
output = [arc_labels[i] for i from 0 <= i < num_arcs]
1189
sage_free(arc_labels)
1190
return output
1191
1192
cdef int del_arc_label_unsafe(self, int u, int v, int l):
1193
"""
1194
Delete an arc (u, v) with label l.
1195
1196
INPUT:
1197
u, v -- integers from 0, ..., n-1, where n is the number of vertices
1198
l -- a positive integer label, or zero for no label
1199
1200
OUTPUT:
1201
0 -- No error.
1202
1 -- No arc with label l.
1203
1204
"""
1205
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1206
cdef int compared
1207
cdef SparseGraphBTNode **parent = &self.vertices[i]
1208
cdef SparseGraphLLNode **labels, *label
1209
while parent[0] != NULL:
1210
compared = compare(parent[0].vertex, v)
1211
if compared > 0:
1212
parent = &(parent[0].left)
1213
elif compared < 0:
1214
parent = &(parent[0].right)
1215
else: # if parent[0].vertex == v:
1216
break
1217
if parent[0] == NULL:
1218
return 1 # indicate an error
1219
if l == 0:
1220
if parent[0].number > 1: parent[0].number -= 1
1221
elif parent[0].number == 1:
1222
if parent[0].labels == NULL:
1223
self.del_arc_unsafe(u, v)
1224
return 0
1225
else: parent[0].number -= 1
1226
else: return 1 # indicate an error
1227
else:
1228
labels = &(parent[0].labels)
1229
while labels[0] != NULL and labels[0].label != l:
1230
labels = &(labels[0].next)
1231
if labels[0] == NULL:
1232
return 1
1233
label = labels[0]
1234
if label.number > 1:
1235
label.number -= 1
1236
else:
1237
labels[0] = labels[0].next
1238
sage_free(label)
1239
if labels == &(parent[0].labels) and labels[0] == NULL and parent[0].number == 0:
1240
# here we need to delete an "empty" binary tree node
1241
self.del_arc_unsafe(u, v)
1242
self.in_degrees[v] -= 1
1243
self.out_degrees[u] -= 1
1244
self.num_arcs -= 1
1245
1246
cpdef del_arc_label(self, int u, int v, int l):
1247
"""
1248
Delete an arc ``(u, v)`` with label ``l``.
1249
1250
INPUT:
1251
- ``u, v`` - non-negative integers, must be in self
1252
- ``l`` - a positive integer label, or zero for no label
1253
1254
EXAMPLE::
1255
1256
sage: from sage.graphs.base.sparse_graph import SparseGraph
1257
sage: G = SparseGraph(5)
1258
sage: G.add_arc_label(0,1,0)
1259
sage: G.add_arc_label(0,1,1)
1260
sage: G.add_arc_label(0,1,2)
1261
sage: G.add_arc_label(0,1,2)
1262
sage: G.add_arc_label(0,1,3)
1263
sage: G.del_arc_label(0,1,2)
1264
sage: G.all_arcs(0,1)
1265
[0, 3, 2, 1]
1266
sage: G.del_arc_label(0,1,0)
1267
sage: G.all_arcs(0,1)
1268
[3, 2, 1]
1269
1270
"""
1271
self.check_vertex(u)
1272
self.check_vertex(v)
1273
if l < 0:
1274
raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))
1275
self.del_arc_label_unsafe(u,v,l)
1276
1277
cdef int has_arc_label_unsafe(self, int u, int v, int l):
1278
"""
1279
Indicates whether there is an arc (u, v) with label l.
1280
1281
INPUT:
1282
u, v -- integers from 0, ..., n-1, where n is the number of vertices
1283
l -- a positive integer label, or zero for no label
1284
1285
OUTPUT:
1286
0 -- False
1287
1 -- True
1288
1289
"""
1290
cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1291
cdef int compared
1292
cdef SparseGraphBTNode *temp = self.vertices[i]
1293
cdef SparseGraphLLNode *label
1294
while temp != NULL:
1295
compared = compare(temp.vertex, v)
1296
if compared > 0:
1297
temp = temp.left
1298
elif compared < 0:
1299
temp = temp.right
1300
else:# if temp.vertex == v:
1301
break
1302
if temp == NULL:
1303
return 0
1304
if l == 0 and temp.number > 0:
1305
return 1
1306
label = temp.labels
1307
while label != NULL:
1308
if label.label == l:
1309
return 1
1310
label = label.next
1311
return 0
1312
1313
cpdef bint has_arc_label(self, int u, int v, int l):
1314
"""
1315
Indicates whether there is an arc ``(u, v)`` with label ``l``.
1316
1317
INPUT:
1318
- ``u, v`` -- non-negative integers, must be in self
1319
- ``l`` -- a positive integer label, or zero for no label
1320
1321
EXAMPLE::
1322
1323
sage: from sage.graphs.base.sparse_graph import SparseGraph
1324
sage: G = SparseGraph(5)
1325
sage: G.add_arc_label(0,1,0)
1326
sage: G.add_arc_label(0,1,1)
1327
sage: G.add_arc_label(0,1,2)
1328
sage: G.add_arc_label(0,1,2)
1329
sage: G.has_arc_label(0,1,1)
1330
True
1331
sage: G.has_arc_label(0,1,2)
1332
True
1333
sage: G.has_arc_label(0,1,3)
1334
False
1335
1336
"""
1337
self.check_vertex(u)
1338
self.check_vertex(v)
1339
if l < 0:
1340
raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))
1341
return self.has_arc_label_unsafe(u,v,l) == 1
1342
1343
##############################
1344
# Further tests. Unit tests for methods, functions, classes defined with cdef.
1345
##############################
1346
1347
def random_stress():
1348
"""
1349
Randomly search for mistakes in the code.
1350
1351
DOCTEST (No output indicates that no errors were found)::
1352
1353
sage: from sage.graphs.base.sparse_graph import random_stress
1354
sage: for _ in xrange(20):
1355
... random_stress()
1356
1357
"""
1358
cdef int i, j, k, l, m, n
1359
cdef SparseGraph Gnew
1360
num_verts = 10
1361
Gnew = SparseGraph(num_verts)
1362
# This code deliberately uses random instead of sage.misc.prandom,
1363
# so that every time it is run it does different tests, instead of
1364
# doing the same random stress test every time. (Maybe it should
1365
# use sage.misc.random_testing?)
1366
from random import randint
1367
from sage.graphs.all import DiGraph
1368
from sage.misc.misc import uniq
1369
Gold = DiGraph(multiedges=True, loops=True, implementation='networkx')
1370
Gold.add_vertices(xrange(num_verts))
1371
for n from 0 <= n < 10:
1372
i = randint(0,num_verts-1)
1373
j = randint(0,num_verts-1)
1374
l = randint(1,num_verts-1)
1375
k = randint(0,num_verts-1)
1376
if k > 7:
1377
# print 'G.add_arc_label(%d,%d,%d);'%( i, j, l ) + ' Gold.add_edge(%d,%d,%d)'%( i, j, l )
1378
if i not in Gold:
1379
Gnew.add_vertex(i)
1380
if j not in Gold:
1381
Gnew.add_vertex(j)
1382
Gold.add_edge(i,j,l)
1383
Gnew.add_arc_label_unsafe(i,j,l)
1384
elif k > 5:
1385
m = randint(1,7)
1386
# print 'G.add_vertices(range(num_verts, num_verts+%d)); '%m + ' Gold.add_vertices(range(num_verts, num_verts+%d));'%m + ' num_verts += %d'%m
1387
Gold.add_vertices(range(num_verts, num_verts+m))
1388
Gnew.add_vertices(range(num_verts, num_verts+m))
1389
num_verts += m
1390
elif k > 3:
1391
m = randint(0,num_verts-1)
1392
if m in Gold:
1393
# print 'G.del_vertex(%d); '%m + ' Gold.delete_vertex(%d); num_verts -= 1'%(m)
1394
Gold.delete_vertex(m)
1395
Gnew.del_vertex(m)
1396
num_verts -= 1
1397
elif k > 1:
1398
# print 'G.del_all_arcs(%d,%d);'%( i, j ) + ' Gold.delete_edges([(u,v,ll) for u,v,ll in Gold.edges() if u==%d and v==%d])'%(i,j)
1399
Gold.delete_edges([(u,v,ll) for u,v,ll in Gold.edges() if u==i and v==j])
1400
Gnew.del_arc_unsafe(i,j)
1401
else:
1402
# print 'G.del_arc_label(%d,%d,%d);'%( i, j, l ) + ' Gold.delete_edge(%d,%d,%d)'%( i, j, l )
1403
Gold.delete_edge(i,j,l)
1404
Gnew.del_arc_label_unsafe(i,j,l)
1405
if Gnew.num_arcs != Gold.size():
1406
#print Gnew.num_arcs, Gold.size()
1407
raise RuntimeError( "NO:size" )
1408
for i in Gold:
1409
if Gnew.out_degrees[i] != Gold.out_degree(i):
1410
raise RuntimeError( "NO:out degree" )
1411
if Gnew.in_degrees[i] != Gold.in_degree(i):
1412
raise RuntimeError( "NO:in degree" )
1413
if sorted(Gnew.out_neighbors(i)) != uniq([v for u,v,l in Gold.outgoing_edge_iterator(i)]):
1414
raise RuntimeError( "NO:out neighbors" )
1415
if sorted(Gnew.in_neighbors(i)) != uniq([u for u,v,l in Gold.incoming_edge_iterator(i)]):
1416
# print i
1417
# print list(Gold.incoming_edge_iterator(i))
1418
# print list(Gnew.in_neighbors(i))
1419
raise RuntimeError( "NO:in neighbors %s %s %s "%((i,uniq([u for u,v,l in Gold.incoming_edge_iterator(i)]),Gnew.in_neighbors(i))) )
1420
for j in Gold:
1421
l = Gnew.arc_label_unsafe(i,j)
1422
if l != 0:
1423
if not Gold.has_edge(i,j,l):
1424
raise RuntimeError( "NO:has_edge" )
1425
else:
1426
if Gold.has_edge(i,j):
1427
raise RuntimeError( "NO:has_edge" )
1428
list1 = Gnew.all_arcs(i,j)
1429
list2 = [l for (u,v,l) in Gold.edges() if u==i and v==j]
1430
if sorted(list1) != sorted(list2):
1431
raise RuntimeError("NO:edges")
1432
for l from 1 <= l < num_verts:
1433
if Gold.has_edge(i,j,l) != Gnew.has_arc_label(i,j,l):
1434
raise RuntimeError("NO:edges")
1435
Gnew = SparseGraph(num_verts)
1436
Gold = DiGraph(loops=True, multiedges=True, implementation='networkx')
1437
Gold.add_vertices(xrange(num_verts))
1438
for n from 0 <= n < 100:
1439
i = randint(0,num_verts-1)
1440
j = randint(0,num_verts-1)
1441
k = randint(0,num_verts-1)
1442
if k != 0:
1443
Gold.add_edge(i,j)
1444
Gnew.add_arc_unsafe(i,j)
1445
else:
1446
while Gold.has_edge(i,j):
1447
Gold.delete_edge(i,j)
1448
Gnew.del_arc_unsafe(i,j)
1449
if Gnew.num_arcs != Gold.size():
1450
raise RuntimeError( "NO" )
1451
for i from 0 <= i < num_verts:
1452
if Gnew.out_degrees[i] != Gold.out_degree(i):
1453
raise RuntimeError( "NO" )
1454
if Gnew.in_degrees[i] != Gold.in_degree(i):
1455
raise RuntimeError( "NO" )
1456
if sorted(Gnew.out_neighbors(i)) != uniq([v for u,v,_ in Gold.outgoing_edge_iterator(i)]):
1457
raise RuntimeError( "NO" )
1458
if sorted(Gnew.in_neighbors(i)) != uniq([u for u,v,_ in Gold.incoming_edge_iterator(i)]):
1459
raise RuntimeError( "NO" )
1460
for j from 0 <= j < num_verts:
1461
if Gnew.has_arc_unsafe(i,j) != Gold.has_edge(i,j):
1462
raise RuntimeError( "NO" )
1463
1464
def _test_adjacency_sequence_out():
1465
"""
1466
Randomly test the method ``SparseGraph.adjacency_sequence_out()``. No output
1467
indicates that no errors were found.
1468
1469
TESTS::
1470
1471
sage: from sage.graphs.base.sparse_graph import _test_adjacency_sequence_out
1472
sage: _test_adjacency_sequence_out() # long time
1473
"""
1474
from sage.graphs.digraph import DiGraph
1475
from sage.graphs.graph_generators import GraphGenerators
1476
from sage.misc.prandom import randint, random
1477
low = 0
1478
high = 1000
1479
randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random()))
1480
n = randg.order()
1481
# set all labels to 0
1482
E = [(u, v, 0) for u, v in randg.edges(labels=False)]
1483
cdef SparseGraph g = SparseGraph(n,
1484
verts=randg.vertices(),
1485
arcs=E)
1486
assert g._num_verts() == randg.order(), (
1487
"Graph order mismatch: %s vs. %s" % (g._num_verts(), randg.order()))
1488
assert g._num_arcs() == randg.size(), (
1489
"Graph size mismatch: %s vs. %s" % (g._num_arcs(), randg.size()))
1490
M = randg.adjacency_matrix()
1491
cdef int *V = <int *>sage_malloc(n * sizeof(int))
1492
cdef int i = 0
1493
for v in randg.vertex_iterator():
1494
V[i] = v
1495
i += 1
1496
cdef int *seq = <int *> sage_malloc(n * sizeof(int))
1497
for 0 <= i < randint(50, 101):
1498
u = randint(low, n - 1)
1499
g.adjacency_sequence_out(n, V, u, seq)
1500
A = [seq[k] for k in range(n)]
1501
try:
1502
assert A == list(M[u])
1503
except AssertionError:
1504
sage_free(V)
1505
sage_free(seq)
1506
raise AssertionError("Graph adjacency mismatch")
1507
sage_free(seq)
1508
sage_free(V)
1509
1510
###########################################
1511
# Sparse Graph Backend
1512
###########################################
1513
1514
from c_graph import CGraphBackend
1515
from c_graph cimport get_vertex, check_vertex, vertex_label
1516
1517
cdef int new_edge_label(object l, dict edge_labels):
1518
"""
1519
Returns a new unique int representing the arbitrary label l.
1520
"""
1521
if l is None:
1522
return 0
1523
cdef int l_int, max = 0
1524
for l_int in edge_labels:
1525
if max < l_int:
1526
max = l_int
1527
edge_labels[max+1] = l
1528
return max+1
1529
1530
class SparseGraphBackend(CGraphBackend):
1531
"""
1532
Backend for Sage graphs using SparseGraphs.
1533
1534
::
1535
1536
sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1537
1538
This class is only intended for use by the Sage Graph and DiGraph class.
1539
If you are interested in using a SparseGraph, you probably want to do
1540
something like the following example, which creates a Sage Graph instance
1541
which wraps a SparseGraph object::
1542
1543
sage: G = Graph(30, implementation="c_graph", sparse=True)
1544
sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
1545
sage: G.edges(labels=False)
1546
[(0, 1), (0, 3), (4, 5), (9, 23)]
1547
1548
Note that Sage graphs using the backend are more flexible than SparseGraphs
1549
themselves. This is because SparseGraphs (by design) do not deal with Python
1550
objects::
1551
1552
sage: G.add_vertex((0,1,2))
1553
sage: G.vertices()
1554
[0,
1555
...
1556
29,
1557
(0, 1, 2)]
1558
sage: from sage.graphs.base.sparse_graph import SparseGraph
1559
sage: SG = SparseGraph(30)
1560
sage: SG.add_vertex((0,1,2))
1561
Traceback (most recent call last):
1562
...
1563
TypeError: an integer is required
1564
1565
"""
1566
1567
def __init__(self, int n, directed=True):
1568
"""
1569
Initialize a sparse graph with n vertices.
1570
1571
EXAMPLE:
1572
1573
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1574
sage: D.add_edge(0,1,None,False)
1575
sage: list(D.iterator_edges(range(9), True))
1576
[(0, 1, None)]
1577
1578
"""
1579
self._cg = SparseGraph(n)
1580
self._cg_rev = SparseGraph(n) if directed else self._cg
1581
self._directed = directed
1582
self.vertex_labels = {}
1583
self.vertex_ints = {}
1584
self.edge_labels = {}
1585
1586
def add_edge(self, object u, object v, object l, bint directed):
1587
"""
1588
Adds the edge ``(u,v)`` to self.
1589
1590
INPUT:
1591
1592
- ``u,v`` - the vertices of the edge
1593
- ``l`` - the edge label
1594
- ``directed`` - if False, also add ``(v,u)``
1595
1596
EXAMPLE::
1597
1598
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1599
sage: D.add_edge(0,1,None,False)
1600
sage: list(D.iterator_edges(range(9), True))
1601
[(0, 1, None)]
1602
1603
TESTS::
1604
1605
sage: D = DiGraph(implementation='c_graph', sparse=True)
1606
sage: D.add_edge(0,1,2)
1607
sage: D.add_edge(0,1,3)
1608
sage: D.edges()
1609
[(0, 1, 3)]
1610
1611
"""
1612
if u is None: u = self.add_vertex(None)
1613
if v is None: v = self.add_vertex(None)
1614
1615
cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,
1616
self._cg, self._cg_rev, self._directed)
1617
cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,
1618
self._cg, self._cg_rev, self._directed)
1619
1620
cdef int l_int
1621
if l is None:
1622
l_int = 0
1623
else:
1624
l_int = new_edge_label(l, self.edge_labels)
1625
1626
if (not self.loops(None)) and u_int == v_int:
1627
return
1628
if not self.multiple_edges(None):
1629
if self._cg.has_arc_label(u_int, v_int, l_int):
1630
return
1631
else:
1632
self._cg.del_all_arcs(u_int, v_int)
1633
if not directed:
1634
self._cg.del_all_arcs(v_int, u_int)
1635
if directed:
1636
self._cg.add_arc_label(u_int, v_int, l_int)
1637
self._cg_rev.add_arc_label(v_int, u_int, l_int)
1638
elif u_int == v_int:
1639
self._cg.add_arc_label(u_int, v_int, l_int)
1640
else:
1641
self._cg.add_arc_label(u_int, v_int, l_int)
1642
self._cg.add_arc_label(v_int, u_int, l_int)
1643
1644
def add_edges(self, object edges, bint directed):
1645
"""
1646
Add edges from a list.
1647
1648
INPUT:
1649
1650
- ``edges`` - the edges to be added - can either be of the form
1651
``(u,v)`` or ``(u,v,l)``
1652
- ``directed`` - if False, add ``(v,u)`` as well as ``(u,v)``
1653
1654
EXAMPLE::
1655
1656
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1657
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
1658
sage: list(D.iterator_edges(range(9), True))
1659
[(0, 1, None),
1660
(2, 3, None),
1661
(4, 5, None),
1662
(5, 6, None)]
1663
1664
"""
1665
cdef object u,v,l,e
1666
for e in edges:
1667
try:
1668
u,v,l = e
1669
except Exception:
1670
u,v = e
1671
l = None
1672
self.add_edge(u,v,l,directed)
1673
1674
def del_edge(self, object u, object v, object l, bint directed):
1675
"""
1676
Delete edge ``(u,v,l)``.
1677
1678
INPUT:
1679
1680
- ``u,v`` - the vertices of the edge
1681
- ``l`` - the edge label
1682
- ``directed`` - if False, also delete ``(v,u,l)``
1683
1684
EXAMPLE::
1685
1686
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1687
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
1688
sage: list(D.iterator_edges(range(9), True))
1689
[(0, 1, None),
1690
(2, 3, None),
1691
(4, 5, None),
1692
(5, 6, None)]
1693
sage: D.del_edge(0,1,None,True)
1694
sage: list(D.iterator_out_edges(range(9), True))
1695
[(1, 0, None),
1696
(2, 3, None),
1697
(3, 2, None),
1698
(4, 5, None),
1699
(5, 4, None),
1700
(5, 6, None),
1701
(6, 5, None)]
1702
1703
TESTS::
1704
1705
sage: G = Graph(implementation='c_graph', sparse=True)
1706
sage: G.add_edge(0,1,2)
1707
sage: G.delete_edge(0,1)
1708
sage: G.edges()
1709
[]
1710
1711
sage: G = Graph(multiedges=True, implementation='c_graph', sparse=True)
1712
sage: G.add_edge(0,1,2)
1713
sage: G.add_edge(0,1,None)
1714
sage: G.delete_edge(0,1)
1715
sage: G.edges()
1716
[(0, 1, 2)]
1717
1718
Do we remove loops correctly? (:trac:`12135`)::
1719
1720
sage: g=Graph({0:[0,0,0]}, implementation='c_graph', sparse=True)
1721
sage: g.edges(labels=False)
1722
[(0, 0), (0, 0), (0, 0)]
1723
sage: g.delete_edge(0,0); g.edges(labels=False)
1724
[(0, 0), (0, 0)]
1725
"""
1726
if not ( self.has_vertex(u) and self.has_vertex(v) ):
1727
return
1728
cdef int u_int = check_vertex(u, self.vertex_ints, self.vertex_labels,
1729
self._cg, self._cg_rev, self._directed)
1730
cdef int v_int = check_vertex(v, self.vertex_ints, self.vertex_labels,
1731
self._cg, self._cg_rev, self._directed)
1732
1733
if l is None:
1734
if self._cg.has_arc_label(u_int, v_int, 0):
1735
l_int = 0
1736
else:
1737
l_int = self._cg.arc_label(u_int, v_int)
1738
else:
1739
for l_int in self.edge_labels:
1740
if self.edge_labels[l_int] == l and self._cg.has_arc_label(u_int, v_int, l_int):
1741
break
1742
else:
1743
return
1744
1745
if directed:
1746
self._cg.del_arc_label(u_int, v_int, l_int)
1747
self._cg_rev.del_arc_label(v_int, u_int, l_int)
1748
if l_int:
1749
self.edge_labels.pop(l_int)
1750
else:
1751
self._cg.del_arc_label(u_int, v_int, l_int)
1752
if v_int != u_int: self._cg.del_arc_label(v_int, u_int, l_int)
1753
if l_int:
1754
self.edge_labels.pop(l_int)
1755
1756
def get_edge_label(self, object u, object v):
1757
"""
1758
Returns the edge label for ``(u,v)``.
1759
1760
INPUT:
1761
1762
- ``u,v`` - the vertices of the edge
1763
1764
EXAMPLE::
1765
1766
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1767
sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)
1768
sage: list(D.iterator_edges(range(9), True))
1769
[(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]
1770
sage: D.get_edge_label(3,2)
1771
2
1772
1773
"""
1774
cdef int l_int
1775
if not self.has_vertex(u):
1776
raise LookupError("({0}) is not a vertex of the graph.".format(repr(u)))
1777
if not self.has_vertex(v):
1778
raise LookupError("({0}) is not a vertex of the graph.".format(repr(v)))
1779
cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,
1780
self._cg)
1781
cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
1782
self._cg)
1783
if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):
1784
raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u),repr(v)))
1785
if self.multiple_edges(None):
1786
return [self.edge_labels[l_int] if l_int != 0 else None
1787
for l_int in self._cg.all_arcs(u_int, v_int)]
1788
l_int = self._cg.arc_label(u_int, v_int)
1789
return self.edge_labels[l_int] if l_int else None
1790
1791
def has_edge(self, object u, object v, object l):
1792
"""
1793
Returns whether this graph has edge ``(u,v)`` with label ``l``. If ``l``
1794
is ``None``, return whether this graph has an edge ``(u,v)`` with any
1795
label.
1796
1797
INPUT:
1798
1799
- ``u,v`` - the vertices of the edge
1800
- ``l`` - the edge label, or ``None``
1801
1802
EXAMPLE::
1803
1804
sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1805
sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
1806
sage: D.has_edge(0,1,None)
1807
True
1808
1809
"""
1810
if not ( self.has_vertex(u) and self.has_vertex(v) ):
1811
return False
1812
cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,
1813
self._cg)
1814
cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
1815
self._cg)
1816
if l is None:
1817
return self._cg.has_arc(u_int, v_int)
1818
for l_int in self.edge_labels:
1819
if self.edge_labels[l_int] == l and self._cg.has_arc_label(u_int, v_int, l_int):
1820
return True
1821
return False
1822
1823
def iterator_edges(self, object vertices, bint labels):
1824
"""
1825
Iterate over the edges incident to a sequence of vertices. Edges are
1826
assumed to be undirected.
1827
1828
INPUT:
1829
1830
- ``vertices`` - a list of vertex labels
1831
- ``labels`` - boolean, whether to return labels as well
1832
1833
EXAMPLE::
1834
1835
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1836
sage: G.add_edge(1,2,3,False)
1837
sage: list(G.iterator_edges(range(9), False))
1838
[(1, 2)]
1839
sage: list(G.iterator_edges(range(9), True))
1840
[(1, 2, 3)]
1841
1842
"""
1843
# Improvement possible in the code below !
1844
#
1845
# It is through this function that Sage answers to G.edges(). That's so
1846
# inefficient that it hurts to see it. Basically, to answer G.edges(),
1847
# Sage first builds the list L of all vertices, then and returns all the
1848
# edges which have at least one endpoint in L. That is, absolutely *ALL*
1849
# the edges, but it checks this condition on the endpoints for each of
1850
# them. It tests containment in a LIST, not even a set. That should
1851
# REALLY be updated.
1852
cdef object u, v, l, L
1853
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
1854
self._cg) for v in vertices if self.has_vertex(v)]
1855
cdef int u_int, v_int, l_int
1856
if labels:
1857
for v_int in vertices:
1858
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1859
for u_int in self._cg.out_neighbors(v_int):
1860
if u_int >= v_int or u_int not in vertices:
1861
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1862
for l_int in self._cg.all_arcs(v_int, u_int):
1863
if l_int == 0:
1864
l = None
1865
else:
1866
l = self.edge_labels[l_int]
1867
yield tuple(sorted((v, u))) + (l,)
1868
else:
1869
for v_int in vertices:
1870
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1871
for u_int in self._cg.out_neighbors(v_int):
1872
if u_int >= v_int or u_int not in vertices:
1873
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1874
for l_int in self._cg.all_arcs(v_int, u_int):
1875
yield tuple(sorted((v, u)))
1876
1877
def iterator_in_edges(self, object vertices, bint labels):
1878
"""
1879
Iterate over the incoming edges incident to a sequence of vertices.
1880
1881
INPUT:
1882
1883
- ``vertices`` - a list of vertex labels
1884
- ``labels`` - boolean, whether to return labels as well
1885
1886
EXAMPLE::
1887
1888
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1889
sage: G.add_edge(1,2,3,True)
1890
sage: list(G.iterator_in_edges([1], False))
1891
[]
1892
sage: list(G.iterator_in_edges([2], False))
1893
[(1, 2)]
1894
sage: list(G.iterator_in_edges([2], True))
1895
[(1, 2, 3)]
1896
1897
"""
1898
cdef object u, v, L, l
1899
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
1900
self._cg) for v in vertices if self.has_vertex(v)]
1901
cdef int u_int, v_int, l_int
1902
if self.multiple_edges(None):
1903
if labels:
1904
for v_int in vertices:
1905
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1906
for u_int in self._cg_rev.out_neighbors(v_int):
1907
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1908
for l_int in self._cg.all_arcs(u_int, v_int):
1909
yield (u, v, None if l_int == 0 else self.edge_labels[l_int])
1910
else:
1911
for v_int in vertices:
1912
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1913
for u_int in self._cg_rev.out_neighbors(v_int):
1914
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1915
for l_int in self._cg.all_arcs(u_int, v_int):
1916
yield (u, v)
1917
else:
1918
if labels:
1919
for v_int in vertices:
1920
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1921
for u_int in self._cg_rev.out_neighbors(v_int):
1922
l_int = self._cg.arc_label(u_int, v_int)
1923
yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
1924
v,
1925
None if l_int == 0 else self.edge_labels[l_int])
1926
else:
1927
for v_int in vertices:
1928
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1929
for u_int in self._cg_rev.out_neighbors(v_int):
1930
yield (vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
1931
v)
1932
1933
def iterator_out_edges(self, object vertices, bint labels):
1934
"""
1935
Iterate over the outbound edges incident to a sequence of vertices.
1936
1937
INPUT:
1938
- ``vertices`` - a list of vertex labels
1939
- ``labels`` - boolean, whether to return labels as well
1940
1941
EXAMPLE::
1942
1943
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1944
sage: G.add_edge(1,2,3,True)
1945
sage: list(G.iterator_out_edges([2], False))
1946
[]
1947
sage: list(G.iterator_out_edges([1], False))
1948
[(1, 2)]
1949
sage: list(G.iterator_out_edges([1], True))
1950
[(1, 2, 3)]
1951
1952
"""
1953
cdef object u, v, L, l
1954
vertices = [get_vertex(v, self.vertex_ints, self.vertex_labels,
1955
self._cg) for v in vertices if self.has_vertex(v)]
1956
cdef int u_int, v_int, l_int
1957
if self.multiple_edges(None):
1958
if labels:
1959
for v_int in vertices:
1960
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1961
for u_int in self._cg.out_neighbors(v_int):
1962
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1963
for l_int in self._cg.all_arcs(v_int, u_int):
1964
yield (v, u, None if l_int == 0 else self.edge_labels[l_int])
1965
else:
1966
for v_int in vertices:
1967
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1968
for u_int in self._cg.out_neighbors(v_int):
1969
u = vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg)
1970
for l_int in self._cg.all_arcs(v_int, u_int):
1971
yield (v, u)
1972
else:
1973
if labels:
1974
for v_int in vertices:
1975
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1976
for u_int in self._cg.out_neighbors(v_int):
1977
l_int = self._cg.arc_label(v_int, u_int)
1978
yield (v,
1979
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg),
1980
None if l_int == 0 else self.edge_labels[l_int])
1981
else:
1982
for v_int in vertices:
1983
v = vertex_label(v_int, self.vertex_ints, self.vertex_labels, self._cg)
1984
for u_int in self._cg.out_neighbors(v_int):
1985
yield (v,
1986
vertex_label(u_int, self.vertex_ints, self.vertex_labels, self._cg))
1987
1988
def multiple_edges(self, new):
1989
"""
1990
Get/set whether or not ``self`` allows multiple edges.
1991
1992
INPUT:
1993
1994
- ``new`` - boolean (to set) or ``None`` (to get)
1995
1996
EXAMPLES::
1997
1998
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1999
sage: G.multiple_edges(True)
2000
sage: G.multiple_edges(None)
2001
True
2002
sage: G.multiple_edges(False)
2003
sage: G.multiple_edges(None)
2004
False
2005
sage: G.add_edge(0,1,0,True)
2006
sage: G.add_edge(0,1,0,True)
2007
sage: list(G.iterator_edges(range(9), True))
2008
[(0, 1, 0)]
2009
2010
"""
2011
if new is None:
2012
return self._multiple_edges
2013
self._multiple_edges = bool(new)
2014
2015
def set_edge_label(self, object u, object v, object l, bint directed):
2016
"""
2017
Label the edge ``(u,v)`` by ``l``.
2018
2019
INPUT:
2020
2021
- ``u,v`` - the vertices of the edge
2022
- ``l`` - the edge label
2023
- ``directed`` - if False, also set ``(v,u)`` with label ``l``
2024
2025
EXAMPLE::
2026
2027
sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
2028
sage: G.add_edge(1,2,None,True)
2029
sage: G.set_edge_label(1,2,'a',True)
2030
sage: list(G.iterator_edges(range(9), True))
2031
[(1, 2, 'a')]
2032
2033
Note that it fails silently if there is no edge there::
2034
2035
sage: G.set_edge_label(2,1,'b',True)
2036
sage: list(G.iterator_edges(range(9), True))
2037
[(1, 2, 'a')]
2038
2039
"""
2040
if not self.has_edge(u, v, None):
2041
return
2042
if self.multiple_edges(None):
2043
if len(self.get_edge_label(u, v)) > 1:
2044
raise RuntimeError("Cannot set edge label, since there are multiple edges from %s to %s."%(u,v))
2045
# now we know there is exactly one edge from u to v
2046
cdef int l_int, ll_int
2047
if l is None:
2048
l_int = 0
2049
else:
2050
l_int = new_edge_label(l, self.edge_labels)
2051
cdef int u_int = get_vertex(u, self.vertex_ints, self.vertex_labels,
2052
self._cg)
2053
cdef int v_int = get_vertex(v, self.vertex_ints, self.vertex_labels,
2054
self._cg)
2055
if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):
2056
return
2057
ll_int = (<SparseGraph>self._cg).arc_label_unsafe(u_int, v_int)
2058
if ll_int:
2059
self.edge_labels.pop(ll_int)
2060
if directed:
2061
self._cg.del_arc_label(u_int, v_int, ll_int)
2062
self._cg_rev.del_arc_label(v_int, u_int, ll_int)
2063
self._cg.add_arc_label(u_int, v_int, l_int)
2064
self._cg_rev.add_arc_label(v_int, u_int, l_int)
2065
elif u_int == v_int:
2066
self._cg.del_arc_label(u_int, v_int, ll_int)
2067
self._cg.add_arc_label(u_int, v_int, l_int)
2068
else:
2069
self._cg.del_arc_label(u_int, v_int, ll_int)
2070
self._cg.del_arc_label(v_int, u_int, ll_int)
2071
self._cg.add_arc_label(u_int, v_int, l_int)
2072
self._cg.add_arc_label(v_int, u_int, l_int)
2073
2074