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