Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/sets/disjoint_set.pyx
8817 views
1
r"""
2
Disjoint-set data structure
3
4
The main entry point is :func:`DisjointSet` which chooses the appropriate
5
type to return. For more on the data structure, see :func:`DisjointSet`.
6
7
AUTHORS:
8
9
- Sebastien Labbe (2008) - Initial version.
10
- Sebastien Labbe (2009-11-24) - Pickling support
11
- Sebastien Labbe (2010-01) - Inclusion into sage (:trac:`6775`).
12
13
EXAMPLES:
14
15
Disjoint set of integers from ``0`` to ``n - 1``::
16
17
sage: s = DisjointSet(6)
18
sage: s
19
{{0}, {1}, {2}, {3}, {4}, {5}}
20
sage: s.union(2, 4)
21
sage: s.union(1, 3)
22
sage: s.union(5, 1)
23
sage: s
24
{{0}, {1, 3, 5}, {2, 4}}
25
sage: s.find(3)
26
1
27
sage: s.find(5)
28
1
29
sage: map(s.find, range(6))
30
[0, 1, 2, 1, 2, 1]
31
32
Disjoint set of hashables objects::
33
34
sage: d = DisjointSet('abcde')
35
sage: d
36
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
37
sage: d.union('a','b')
38
sage: d.union('b','c')
39
sage: d.union('c','d')
40
sage: d
41
{{'a', 'b', 'c', 'd'}, {'e'}}
42
sage: d.find('c')
43
'a'
44
"""
45
#*****************************************************************************
46
# Copyright (C) 2009 Sebastien Labbe <slabqc at gmail.com>
47
#
48
# Distributed under the terms of the GNU General Public License (GPL)
49
# http://www.gnu.org/licenses/
50
#*****************************************************************************
51
52
include '../groups/perm_gps/partn_ref/data_structures_pyx.pxi'
53
54
import itertools
55
from sage.rings.integer import Integer
56
from sage.structure.sage_object cimport SageObject
57
58
def DisjointSet(arg):
59
r"""
60
Constructs a disjoint set where each element of ``arg`` is in its
61
own set. If ``arg`` is an integer, then the disjoint set returned is
62
made of the integers from ``0`` to ``arg - 1``.
63
64
A disjoint-set data structure (sometimes called union-find data structure)
65
is a data structure that keeps track of a partitioning of a set into a
66
number of separate, nonoverlapping sets. It performs two operations:
67
68
- :meth:`~sage.sets.disjoint_set.DisjointSet_of_hashables.find` --
69
Determine which set a particular element is in.
70
- :meth:`~sage.sets.disjoint_set.DisjointSet_of_hashables.union` --
71
Combine or merge two sets into a single set.
72
73
REFERENCES:
74
75
- :wikipedia:`Disjoint-set_data_structure`
76
77
INPUT:
78
79
- ``arg`` -- non negative integer or an iterable of hashable objects.
80
81
EXAMPLES:
82
83
From a non-negative integer::
84
85
sage: DisjointSet(5)
86
{{0}, {1}, {2}, {3}, {4}}
87
88
From an iterable::
89
90
sage: DisjointSet('abcde')
91
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
92
sage: DisjointSet(range(6))
93
{{0}, {1}, {2}, {3}, {4}, {5}}
94
sage: DisjointSet(['yi',45,'cheval'])
95
{{'cheval'}, {'yi'}, {45}}
96
97
TESTS::
98
99
sage: DisjointSet(0)
100
{}
101
sage: DisjointSet('')
102
{}
103
sage: DisjointSet([])
104
{}
105
106
The argument must be a non negative integer::
107
108
sage: DisjointSet(-1)
109
Traceback (most recent call last):
110
...
111
ValueError: arg (=-1) must be a non negative integer
112
113
or an iterable::
114
115
sage: DisjointSet(4.3)
116
Traceback (most recent call last):
117
...
118
TypeError: 'sage.rings.real_mpfr.RealLiteral' object is not iterable
119
120
Moreover, the iterable must consist of hashable::
121
122
sage: DisjointSet([{}, {}])
123
Traceback (most recent call last):
124
...
125
TypeError: unhashable type: 'dict'
126
"""
127
if isinstance(arg, (Integer, int)):
128
if arg < 0:
129
raise ValueError, 'arg (=%s) must be a non negative integer'%arg
130
return DisjointSet_of_integers(arg)
131
else:
132
return DisjointSet_of_hashables(arg)
133
134
cdef class DisjointSet_class(SageObject):
135
r"""
136
Common class and methods for :class:`DisjointSet_of_integers` and
137
:class:`DisjointSet_of_hashables`.
138
"""
139
def _repr_(self):
140
r"""
141
Return ``self`` as a unique str.
142
143
EXAMPLES::
144
145
sage: e = DisjointSet(5)
146
sage: e.union(2,4); e._repr_()
147
'{{0}, {1}, {2, 4}, {3}}'
148
sage: e = DisjointSet(5)
149
sage: e.union(4,2); e._repr_()
150
'{{0}, {1}, {2, 4}, {3}}'
151
152
::
153
154
sage: e = DisjointSet(range(5))
155
sage: e.union(2,4); e._repr_()
156
'{{0}, {1}, {2, 4}, {3}}'
157
sage: e = DisjointSet(range(5))
158
sage: e.union(4,2); e._repr_()
159
'{{0}, {1}, {2, 4}, {3}}'
160
"""
161
res = []
162
for l in self.root_to_elements_dict().itervalues():
163
l.sort()
164
res.append('{%s}'% ', '.join(itertools.imap(repr, l)))
165
res.sort()
166
return '{%s}'% ', '.join(res)
167
168
def __cmp__(self, other):
169
r"""
170
Compare the disjoint sets ``self`` and ``other``.
171
172
EXAMPLES::
173
174
sage: d = DisjointSet(5)
175
sage: d == d
176
True
177
178
::
179
180
sage: e = DisjointSet(5)
181
sage: e == d
182
True
183
184
::
185
186
sage: d.union(0,3)
187
sage: d.union(3,4)
188
sage: e.union(4,0)
189
sage: e.union(3,0)
190
sage: e == d
191
True
192
193
::
194
195
sage: DisjointSet(3) == DisjointSet(5)
196
False
197
sage: DisjointSet(3) == 4
198
False
199
200
::
201
202
sage: d = DisjointSet('abcde')
203
sage: e = DisjointSet('abcde')
204
sage: d.union('a','b')
205
sage: d.union('b','c')
206
sage: e.union('c','a')
207
sage: e == d
208
False
209
sage: e.union('a','b')
210
sage: e == d
211
True
212
"""
213
from sage.sets.all import Set
214
s = Set(map(Set, self.root_to_elements_dict().values()))
215
t = Set(map(Set, other.root_to_elements_dict().values()))
216
return cmp(s,t)
217
218
def cardinality(self):
219
r"""
220
Return the number of elements in ``self``, *not* the number of subsets.
221
222
EXAMPLES::
223
224
sage: d = DisjointSet(5)
225
sage: d.cardinality()
226
5
227
sage: d.union(2, 4)
228
sage: d.cardinality()
229
5
230
sage: d = DisjointSet(range(5))
231
sage: d.cardinality()
232
5
233
sage: d.union(2, 4)
234
sage: d.cardinality()
235
5
236
"""
237
return self._nodes.degree
238
239
def number_of_subsets(self):
240
r"""
241
Return the number of subsets in ``self``.
242
243
EXAMPLES::
244
245
sage: d = DisjointSet(5)
246
sage: d.number_of_subsets()
247
5
248
sage: d.union(2, 4)
249
sage: d.number_of_subsets()
250
4
251
sage: d = DisjointSet(range(5))
252
sage: d.number_of_subsets()
253
5
254
sage: d.union(2, 4)
255
sage: d.number_of_subsets()
256
4
257
"""
258
return self._nodes.num_cells
259
260
cdef class DisjointSet_of_integers(DisjointSet_class):
261
r"""
262
Disjoint set of integers from ``0`` to ``n-1``.
263
264
EXAMPLES::
265
266
sage: d = DisjointSet(5)
267
sage: d
268
{{0}, {1}, {2}, {3}, {4}}
269
sage: d.union(2,4)
270
sage: d.union(0,2)
271
sage: d
272
{{0, 2, 4}, {1}, {3}}
273
sage: d.find(2)
274
2
275
276
TESTS::
277
278
sage: a = DisjointSet(5)
279
sage: a == loads(dumps(a))
280
True
281
282
::
283
284
sage: a.union(3,4)
285
sage: a == loads(dumps(a))
286
True
287
"""
288
def __init__(self, n):
289
r"""
290
Construction of the DisjointSet where each element (integers from ``0``
291
to ``n-1``) is in its own set.
292
293
INPUT:
294
295
- ``n`` -- Non negative integer
296
297
EXAMPLES::
298
299
sage: DisjointSet(6)
300
{{0}, {1}, {2}, {3}, {4}, {5}}
301
sage: DisjointSet(1)
302
{{0}}
303
sage: DisjointSet(0)
304
{}
305
"""
306
self._nodes = OP_new(n)
307
308
def __dealloc__(self):
309
r"""
310
Deallocates self, i.e. the self._nodes
311
312
EXAMPLES::
313
314
sage: d = DisjointSet(5)
315
sage: del d
316
"""
317
OP_dealloc(self._nodes)
318
319
def __reduce__(self):
320
r"""
321
Return a tuple of three elements:
322
323
- The function :func:`DisjointSet`
324
- Arguments for the function :func:`DisjointSet`
325
- The actual state of ``self``.
326
327
EXAMPLES::
328
329
sage: d = DisjointSet(5)
330
sage: d.__reduce__()
331
(<built-in function DisjointSet>, (5,), [0, 1, 2, 3, 4])
332
333
::
334
335
sage: d.union(2,4)
336
sage: d.union(1,3)
337
sage: d.__reduce__()
338
(<built-in function DisjointSet>, (5,), [0, 1, 2, 1, 2])
339
"""
340
return DisjointSet, (self._nodes.degree,), self.__getstate__()
341
342
def __getstate__(self):
343
r"""
344
Return a list of the parent of each node from ``0`` to ``n-1``.
345
346
EXAMPLES::
347
348
sage: d = DisjointSet(5)
349
sage: d.__getstate__()
350
[0, 1, 2, 3, 4]
351
sage: d.union(2,3)
352
sage: d.__getstate__()
353
[0, 1, 2, 2, 4]
354
sage: d.union(3,0)
355
sage: d.__getstate__()
356
[2, 1, 2, 2, 4]
357
358
Other parents are obtained when the operations are done is a
359
distinct order::
360
361
sage: d = DisjointSet(5)
362
sage: d.union(0,3)
363
sage: d.__getstate__()
364
[0, 1, 2, 0, 4]
365
sage: d.union(2,0)
366
sage: d.__getstate__()
367
[0, 1, 0, 0, 4]
368
"""
369
l = []
370
cdef int i
371
for i from 0 <= i < self.cardinality():
372
l.append(self._nodes.parent[i])
373
return l
374
375
def __setstate__(self, l):
376
r"""
377
Merge the nodes ``i`` and ``l[i]`` (using union) for ``i`` in
378
``range(len(l))``.
379
380
INPUT:
381
382
- ``l`` -- list of nodes
383
384
EXAMPLES::
385
386
sage: d = DisjointSet(5)
387
sage: d.__setstate__([0,1,2,3,4])
388
sage: d
389
{{0}, {1}, {2}, {3}, {4}}
390
391
::
392
393
sage: d = DisjointSet(5)
394
sage: d.__setstate__([1,2,3,4,0])
395
sage: d
396
{{0, 1, 2, 3, 4}}
397
398
::
399
400
sage: d = DisjointSet(5)
401
sage: d.__setstate__([1,1,1])
402
sage: d
403
{{0, 1, 2}, {3}, {4}}
404
405
::
406
407
sage: d = DisjointSet(5)
408
sage: d.__setstate__([3,3,3])
409
sage: d
410
{{0, 1, 2, 3}, {4}}
411
"""
412
for i,parent in enumerate(l):
413
self.union(parent, i)
414
415
def find(self, int i):
416
r"""
417
Return the representative of the set that ``i`` currently belongs to.
418
419
INPUT:
420
421
- ``i`` -- element in ``self``
422
423
EXAMPLES::
424
425
sage: e = DisjointSet(5)
426
sage: e.union(4,2)
427
sage: e
428
{{0}, {1}, {2, 4}, {3}}
429
sage: e.find(2)
430
4
431
sage: e.find(4)
432
4
433
sage: e.union(1,3)
434
sage: e
435
{{0}, {1, 3}, {2, 4}}
436
sage: e.find(1)
437
1
438
sage: e.find(3)
439
1
440
sage: e.union(3,2)
441
sage: e
442
{{0}, {1, 2, 3, 4}}
443
sage: [e.find(i) for i in range(5)]
444
[0, 1, 1, 1, 1]
445
sage: e.find(5)
446
Traceback (most recent call last):
447
...
448
ValueError: i(=5) must be between 0 and 4
449
"""
450
card = self.cardinality()
451
if i < 0 or i>= card:
452
raise ValueError, 'i(=%s) must be between 0 and %s'%(i, card-1)
453
return OP_find(self._nodes, i)
454
455
def union(self, int i, int j):
456
r"""
457
Combine the set of ``i`` and the set of ``j`` into one.
458
459
All elements in those two sets will share the same representative
460
that can be gotten using find.
461
462
INPUT:
463
464
- ``i`` - element in ``self``
465
- ``j`` - element in ``self``
466
467
EXAMPLES::
468
469
sage: d = DisjointSet(5)
470
sage: d
471
{{0}, {1}, {2}, {3}, {4}}
472
sage: d.union(0,1)
473
sage: d
474
{{0, 1}, {2}, {3}, {4}}
475
sage: d.union(2,4)
476
sage: d
477
{{0, 1}, {2, 4}, {3}}
478
sage: d.union(1,4)
479
sage: d
480
{{0, 1, 2, 4}, {3}}
481
sage: d.union(1,5)
482
Traceback (most recent call last):
483
...
484
ValueError: j(=5) must be between 0 and 4
485
"""
486
card = self.cardinality()
487
if i < 0 or i>= card:
488
raise ValueError, 'i(=%s) must be between 0 and %s'%(i, card-1)
489
if j < 0 or j>= card:
490
raise ValueError, 'j(=%s) must be between 0 and %s'%(j, card-1)
491
OP_join(self._nodes, i, j)
492
493
def root_to_elements_dict(self):
494
r"""
495
Return the dictionary where the keys are the roots of ``self`` and the
496
values are the elements in the same set as the root.
497
498
EXAMPLES::
499
500
sage: d = DisjointSet(5)
501
sage: d.root_to_elements_dict()
502
{0: [0], 1: [1], 2: [2], 3: [3], 4: [4]}
503
sage: d.union(2,3)
504
sage: d.root_to_elements_dict()
505
{0: [0], 1: [1], 2: [2, 3], 4: [4]}
506
sage: d.union(3,0)
507
sage: d.root_to_elements_dict()
508
{1: [1], 2: [0, 2, 3], 4: [4]}
509
sage: d
510
{{0, 2, 3}, {1}, {4}}
511
"""
512
s = {}
513
cdef int i
514
for i from 0 <= i < self.cardinality():
515
o = self.find(i)
516
if o not in s:
517
s[o] = []
518
s[o].append(i)
519
return s
520
521
def element_to_root_dict(self):
522
r"""
523
Return the dictionary where the keys are the elements of ``self`` and
524
the values are their representative inside a list.
525
526
EXAMPLES::
527
528
sage: d = DisjointSet(5)
529
sage: d.union(2,3)
530
sage: d.union(4,1)
531
sage: e = d.element_to_root_dict(); e
532
{0: 0, 1: 4, 2: 2, 3: 2, 4: 4}
533
sage: WordMorphism(e)
534
WordMorphism: 0->0, 1->4, 2->2, 3->2, 4->4
535
"""
536
d = {}
537
cdef int i
538
for i from 0 <= i < self.cardinality():
539
d[i] = self.find(i)
540
return d
541
542
def to_digraph(self):
543
r"""
544
Return the current digraph of ``self`` where `(a,b)` is an oriented
545
edge if `b` is the parent of `a`.
546
547
EXAMPLES::
548
549
sage: d = DisjointSet(5)
550
sage: d.union(2,3)
551
sage: d.union(4,1)
552
sage: d.union(3,4)
553
sage: d
554
{{0}, {1, 2, 3, 4}}
555
sage: g = d.to_digraph(); g
556
Looped digraph on 5 vertices
557
sage: g.edges()
558
[(0, 0, None), (1, 2, None), (2, 2, None), (3, 2, None), (4, 2, None)]
559
560
The result depends on the ordering of the union::
561
562
sage: d = DisjointSet(5)
563
sage: d.union(1,2)
564
sage: d.union(1,3)
565
sage: d.union(1,4)
566
sage: d
567
{{0}, {1, 2, 3, 4}}
568
sage: d.to_digraph().edges()
569
[(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)]
570
571
"""
572
d = {}
573
for i from 0 <= i < self.cardinality():
574
d[i] = [self._nodes.parent[i]]
575
from sage.graphs.graph import DiGraph
576
return DiGraph(d)
577
578
cdef class DisjointSet_of_hashables(DisjointSet_class):
579
r"""
580
Disjoint set of hashables.
581
582
EXAMPLES::
583
584
sage: d = DisjointSet('abcde')
585
sage: d
586
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
587
sage: d.union('a', 'c')
588
sage: d
589
{{'a', 'c'}, {'b'}, {'d'}, {'e'}}
590
sage: d.find('a')
591
'a'
592
593
TESTS::
594
595
sage: a = DisjointSet('abcdef')
596
sage: a == loads(dumps(a))
597
True
598
599
::
600
601
sage: a.union('a','c')
602
sage: a == loads(dumps(a))
603
True
604
"""
605
def __init__(self, iterable):
606
r"""
607
Construction of the trivial disjoint set where each element is in its
608
own set.
609
610
INPUT:
611
612
- ``iterable`` -- An iterable of hashable objects.
613
614
EXAMPLES::
615
616
sage: DisjointSet('abcde')
617
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
618
sage: DisjointSet(range(6))
619
{{0}, {1}, {2}, {3}, {4}, {5}}
620
sage: DisjointSet(['yi',45,'cheval'])
621
{{'cheval'}, {'yi'}, {45}}
622
sage: DisjointSet(set([0, 1, 2, 3, 4]))
623
{{0}, {1}, {2}, {3}, {4}}
624
"""
625
self._int_to_el = []
626
self._el_to_int = {}
627
for (i,e) in enumerate(iterable):
628
self._int_to_el.append(e)
629
self._el_to_int[e] = i
630
self._d = DisjointSet_of_integers(len(self._int_to_el))
631
self._nodes = self._d._nodes
632
633
def __reduce__(self):
634
r"""
635
Return a tuple of three elements :
636
637
- The function :func:`DisjointSet`
638
- Arguments for the function :func:`DisjointSet`
639
- The actual state of ``self``.
640
641
EXAMPLES::
642
643
sage: DisjointSet(range(5))
644
{{0}, {1}, {2}, {3}, {4}}
645
sage: d = _
646
sage: d.__reduce__()
647
(<built-in function DisjointSet>,
648
([0, 1, 2, 3, 4],),
649
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4)])
650
651
::
652
653
sage: d.union(2,4)
654
sage: d.union(1,3)
655
sage: d.__reduce__()
656
(<built-in function DisjointSet>,
657
([0, 1, 2, 3, 4],),
658
[(0, 0), (1, 1), (2, 2), (3, 1), (4, 2)])
659
"""
660
return DisjointSet, (self._int_to_el,), self.__getstate__()
661
662
def __getstate__(self):
663
r"""
664
Return a list of pairs (``n``, parent of ``n``) for each node ``n``.
665
666
EXAMPLES::
667
668
sage: d = DisjointSet('abcde')
669
sage: d.__getstate__()
670
[('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd'), ('e', 'e')]
671
sage: d.union('c','d')
672
sage: d.__getstate__()
673
[('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'c'), ('e', 'e')]
674
sage: d.union('d','a')
675
sage: d.__getstate__()
676
[('a', 'c'), ('b', 'b'), ('c', 'c'), ('d', 'c'), ('e', 'e')]
677
678
Other parents are obtained when the operations are done is a
679
different order::
680
681
sage: d = DisjointSet('abcde')
682
sage: d.union('d','c')
683
sage: d.__getstate__()
684
[('a', 'a'), ('b', 'b'), ('c', 'd'), ('d', 'd'), ('e', 'e')]
685
"""
686
gs = self._d.__getstate__()
687
l = []
688
cdef int i
689
for i from 0 <= i < self.cardinality():
690
l.append(self._int_to_el[gs[i]])
691
return zip(self._int_to_el, l)
692
693
def __setstate__(self, l):
694
r"""
695
Merge the nodes ``a`` and ``b`` for each pair of nodes
696
``(a,b)`` in ``l``.
697
698
INPUT:
699
700
- ``l`` -- list of pair of nodes
701
702
EXAMPLES::
703
704
sage: d = DisjointSet('abcde')
705
sage: d.__setstate__([('a','a'),('b','b'),('c','c')])
706
sage: d
707
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
708
709
::
710
711
sage: d = DisjointSet('abcde')
712
sage: d.__setstate__([('a','b'),('b','c'),('c','d'),('d','e')])
713
sage: d
714
{{'a', 'b', 'c', 'd', 'e'}}
715
"""
716
for a,b in l:
717
self.union(a, b)
718
719
def find(self, e):
720
r"""
721
Return the representative of the set that ``e`` currently belongs to.
722
723
INPUT:
724
725
- ``e`` -- element in ``self``
726
727
EXAMPLES::
728
729
sage: e = DisjointSet(range(5))
730
sage: e.union(4,2)
731
sage: e
732
{{0}, {1}, {2, 4}, {3}}
733
sage: e.find(2)
734
4
735
sage: e.find(4)
736
4
737
sage: e.union(1,3)
738
sage: e
739
{{0}, {1, 3}, {2, 4}}
740
sage: e.find(1)
741
1
742
sage: e.find(3)
743
1
744
sage: e.union(3,2)
745
sage: e
746
{{0}, {1, 2, 3, 4}}
747
sage: [e.find(i) for i in range(5)]
748
[0, 1, 1, 1, 1]
749
sage: e.find(5)
750
Traceback (most recent call last):
751
...
752
KeyError: 5
753
"""
754
i = self._el_to_int[e]
755
r = self._d.find(i)
756
return self._int_to_el[r]
757
758
def union(self, e, f):
759
r"""
760
Combine the set of ``e`` and the set of ``f`` into one.
761
762
All elements in those two sets will share the same representative
763
that can be gotten using find.
764
765
INPUT:
766
767
- ``e`` - element in ``self``
768
- ``f`` - element in ``self``
769
770
EXAMPLES::
771
772
sage: e = DisjointSet('abcde')
773
sage: e
774
{{'a'}, {'b'}, {'c'}, {'d'}, {'e'}}
775
sage: e.union('a','b')
776
sage: e
777
{{'a', 'b'}, {'c'}, {'d'}, {'e'}}
778
sage: e.union('c','e')
779
sage: e
780
{{'a', 'b'}, {'c', 'e'}, {'d'}}
781
sage: e.union('b','e')
782
sage: e
783
{{'a', 'b', 'c', 'e'}, {'d'}}
784
"""
785
i = self._el_to_int[e]
786
j = self._el_to_int[f]
787
self._d.union(i, j)
788
789
def root_to_elements_dict(self):
790
r"""
791
Return the dictionary where the keys are the roots of ``self`` and the
792
values are the elements in the same set.
793
794
EXAMPLES::
795
796
sage: d = DisjointSet(range(5))
797
sage: d.union(2,3)
798
sage: d.union(4,1)
799
sage: e = d.root_to_elements_dict(); e
800
{0: [0], 2: [2, 3], 4: [1, 4]}
801
"""
802
s = {}
803
for e in self._int_to_el:
804
r = self.find(e)
805
if r not in s:
806
s[r] = []
807
s[r].append(e)
808
return s
809
810
def element_to_root_dict(self):
811
r"""
812
Return the dictionary where the keys are the elements of ``self`` and
813
the values are their representative inside a list.
814
815
EXAMPLES::
816
817
sage: d = DisjointSet(range(5))
818
sage: d.union(2,3)
819
sage: d.union(4,1)
820
sage: e = d.element_to_root_dict(); e
821
{0: 0, 1: 4, 2: 2, 3: 2, 4: 4}
822
sage: WordMorphism(e)
823
WordMorphism: 0->0, 1->4, 2->2, 3->2, 4->4
824
"""
825
d = {}
826
for a in self._int_to_el:
827
d[a] = self.find(a)
828
return d
829
830
def to_digraph(self):
831
r"""
832
Return the current digraph of ``self`` where `(a,b)` is an oriented
833
edge if `b` is the parent of `a`.
834
835
EXAMPLES::
836
837
sage: d = DisjointSet(range(5))
838
sage: d.union(2,3)
839
sage: d.union(4,1)
840
sage: d.union(3,4)
841
sage: d
842
{{0}, {1, 2, 3, 4}}
843
sage: g = d.to_digraph(); g
844
Looped digraph on 5 vertices
845
sage: g.edges()
846
[(0, 0, None), (1, 2, None), (2, 2, None), (3, 2, None), (4, 2, None)]
847
848
The result depends on the ordering of the union::
849
850
sage: d = DisjointSet(range(5))
851
sage: d.union(1,2)
852
sage: d.union(1,3)
853
sage: d.union(1,4)
854
sage: d
855
{{0}, {1, 2, 3, 4}}
856
sage: d.to_digraph().edges()
857
[(0, 0, None), (1, 1, None), (2, 1, None), (3, 1, None), (4, 1, None)]
858
859
"""
860
d = {}
861
for i from 0 <= i < self.cardinality():
862
e = self._int_to_el[i]
863
p = self._int_to_el[self._nodes.parent[i]]
864
d[e] = [p]
865
from sage.graphs.graph import DiGraph
866
return DiGraph(d)
867
868
869