Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/sets/finite_set_map_cy.pyx
4072 views
1
"""
2
Data structures for maps between finite sets
3
4
This module implements several fast Cython data structures for maps
5
between two finite set. Those classes are not intended to be used
6
directly. Instead, such a map should be constructed via its parent,
7
using the class :class:`~sage.sets.finite_set_maps.FiniteSetMaps`.
8
9
EXAMPLES:
10
11
To create a map between two sets, one first creates the set of such maps::
12
13
sage: M = FiniteSetMaps(["a", "b"], [3, 4, 5])
14
15
The map can then be constructed either from a function::
16
17
sage: f1 = M(lambda c: ord(c)-94); f1
18
map: a -> 3, b -> 4
19
20
or from a dictionary::
21
22
sage: f2 = M.from_dict({'a':3, 'b':4}); f2
23
map: a -> 3, b -> 4
24
25
The two created maps are equal::
26
27
sage: f1 == f2
28
True
29
30
Internally, maps are represented as the list of the ranks of the
31
images ``f(x)`` in the co-domain, in the order of the domain::
32
33
sage: list(f2)
34
[0, 1]
35
36
A third fast way to create a map it to use such a list. it should be
37
kept for internal use::
38
39
sage: f3 = M._from_list_([0, 1]); f3
40
map: a -> 3, b -> 4
41
sage: f1 == f3
42
True
43
44
AUTHORS:
45
46
- Florent Hivert
47
"""
48
#*****************************************************************************
49
# Copyright (C) 2010 Florent Hivert <[email protected]>,
50
#
51
# Distributed under the terms of the GNU General Public License (GPL)
52
# http://www.gnu.org/licenses/
53
#*****************************************************************************
54
55
import sage
56
from sage.structure.list_clone cimport ClonableIntArray
57
from sage.structure.parent cimport Parent
58
from sage.structure.element cimport generic_power_c
59
from sage.sets.set import Set_object_enumerated
60
61
62
cpdef fibers(f, domain):
63
r"""
64
Returns the fibers of the function ``f`` on the finite set ``domain``
65
66
INPUT:
67
68
- ``f`` -- a function or callable
69
- ``domain`` -- a finite iterable
70
71
OUTPUT:
72
73
- a dictionary ``d`` such that ``d[y]`` is the set of all ``x`` in
74
``domain`` such that ``f(x) = y``
75
76
EXAMPLES::
77
78
sage: from sage.sets.finite_set_map_cy import fibers, fibers_args
79
sage: fibers(lambda x: 1, [])
80
{}
81
sage: fibers(lambda x: x^2, [-1, 2, -3, 1, 3, 4])
82
{16: {4}, 1: {1, -1}, 4: {2}, 9: {3, -3}}
83
sage: fibers(lambda x: 1, [-1, 2, -3, 1, 3, 4])
84
{1: {1, 2, 3, 4, -3, -1}}
85
sage: fibers(lambda x: 1, [1,1,1])
86
{1: {1}}
87
88
.. seealso:: :func:`fibers_args` if one needs to pass extra
89
arguments to ``f``.
90
"""
91
result = {}
92
for x in domain:
93
y = f(x)
94
result.setdefault(y, set()).add(x)
95
for x, v in result.iteritems():
96
result[x] = Set_object_enumerated(v)
97
return result
98
99
100
def fibers_args(f, domain, *args, **opts):
101
r"""
102
Returns the fibers of the function ``f`` on the finite set ``domain``
103
104
It is the same as :func:`fibers` except that one can pass extra
105
argument for ``f`` (with a small overhead)
106
107
EXAMPLES::
108
109
sage: from sage.sets.finite_set_map_cy import fibers_args
110
sage: fibers_args(operator.pow, [-1, 2, -3, 1, 3, 4], 2)
111
{16: {4}, 1: {1, -1}, 4: {2}, 9: {3, -3}}
112
"""
113
return fibers(lambda x: f(x, *args, **opts), domain)
114
115
116
cdef class FiniteSetMap_MN(ClonableIntArray):
117
"""
118
Data structure for maps from ``range(m)`` to ``range(n)``.
119
120
We assume that the parent given as argument is such that:
121
122
- ``m`` is stored in ``self.parent()._m``
123
- ``n`` is stored in ``self.parent()._n``
124
- the domain is in ``self.parent().domain()``
125
- the codomain is in ``self.parent().codomain()``
126
"""
127
128
def __call__(self, int i):
129
"""
130
Returns the image of ``i`` under the map ``self``
131
132
INPUT:
133
134
- ``i`` -- an int
135
136
OUTPUT:
137
138
an int
139
140
EXAMPLES::
141
142
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
143
sage: fs(0), fs(1), fs(2), fs(3)
144
(1, 0, 2, 1)
145
"""
146
return self._getitem(i)
147
148
# Needed by generic power which refuses to compute 0^0
149
def __nonzero__(self):
150
"""
151
Returns whether ``self`` is non zero; this is always ``True``.
152
153
EXAMPLES::
154
155
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
156
sage: bool(fs)
157
True
158
"""
159
return True
160
161
cpdef domain(self):
162
"""
163
Returns the domain of ``self``
164
165
EXAMPLES::
166
167
sage: FiniteSetMaps(4, 3)([1, 0, 2, 1]).domain()
168
{0, .., 3}
169
"""
170
return self._parent.domain()
171
172
cpdef codomain(self):
173
"""
174
Returns the codomain of ``self``
175
176
EXAMPLES::
177
178
sage: FiniteSetMaps(4, 3)([1, 0, 2, 1]).codomain()
179
{0, .., 2}
180
"""
181
return self._parent.codomain()
182
183
cpdef _setimage(self, int i, int j):
184
"""
185
Set the image of ``i`` as ``j`` in ``self``
186
187
This is a fast internal version where ``i`` and ``j`` are both int's.
188
189
.. warning:: ``self`` must be mutable; otherwise an exception is raised.
190
191
INPUT:
192
193
- ``i``, ``j`` -- two ``int``'s
194
195
OUTPUT: ``None``
196
197
EXAMPLES::
198
199
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
200
sage: fs2 = copy(fs)
201
sage: fs2._setimage(2, 1)
202
sage: fs2
203
[1, 0, 1, 1]
204
sage: with fs.clone() as fs3:
205
... fs3._setimage(0, 2)
206
... fs3._setimage(1, 2)
207
sage: fs3
208
[2, 2, 2, 1]
209
210
TESTS::
211
212
sage: with fs.clone() as fs3:
213
... fs3._setimage(6, 2)
214
Traceback (most recent call last):
215
...
216
IndexError: list index out of range
217
sage: with fs.clone() as fs3:
218
... fs3._setimage(1, 4)
219
Traceback (most recent call last):
220
...
221
AssertionError: Wrong value self(1) = 4
222
"""
223
self._setitem(i, j)
224
225
cpdef _getimage(self, int i):
226
"""
227
Returns the image of ``i`` by ``self``
228
229
This is a fast internal version where ``i`` is an int.
230
231
INPUT:
232
233
- ``i`` -- an ``int``
234
235
EXAMPLES::
236
237
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
238
sage: fs._getimage(0), fs._getimage(1), fs._getimage(2), fs._getimage(3)
239
(1, 0, 2, 1)
240
"""
241
return self._getitem(i)
242
243
cpdef setimage(self, i, j):
244
"""
245
Set the image of ``i`` as ``j`` in ``self``
246
247
.. warning:: ``self`` must be mutable; otherwise an exception is raised.
248
249
INPUT:
250
251
- ``i``, ``j`` -- two ``object``'s
252
253
OUTPUT: ``None``
254
255
.. note:: if you need speed, please use instead :meth:`_setimage`
256
257
EXAMPLES::
258
259
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
260
sage: fs2 = copy(fs)
261
sage: fs2.setimage(2, 1)
262
sage: fs2
263
[1, 0, 1, 1]
264
sage: with fs.clone() as fs3:
265
... fs3.setimage(0, 2)
266
... fs3.setimage(1, 2)
267
sage: fs3
268
[2, 2, 2, 1]
269
"""
270
self._setitem(int(i), int(j))
271
272
cpdef getimage(self, i):
273
"""
274
Returns the image of ``i`` by ``self``
275
276
INPUT:
277
278
- ``i`` -- any object.
279
280
.. note:: if you need speed, please use instead :meth:`_getimage`
281
282
EXAMPLES::
283
284
sage: fs = FiniteSetMaps(4, 3)([1, 0, 2, 1])
285
sage: fs.getimage(0), fs.getimage(1), fs.getimage(2), fs.getimage(3)
286
(1, 0, 2, 1)
287
"""
288
return self._getitem(int(i))
289
290
cpdef image_set(self):
291
"""
292
Returns the image set of ``self``
293
294
EXAMPLES::
295
296
sage: FiniteSetMaps(4, 3)([1, 0, 2, 1]).image_set()
297
{0, 1, 2}
298
sage: FiniteSetMaps(4, 3)([1, 0, 0, 1]).image_set()
299
{0, 1}
300
"""
301
return Set_object_enumerated(self)
302
303
cpdef fibers(self):
304
"""
305
Returns the fibers of ``self``
306
307
OUTPUT:
308
309
a dictionary ``d`` such that ``d[y]`` is the set of all ``x`` in
310
``domain`` such that ``f(x) = y``
311
312
EXAMPLES::
313
314
sage: FiniteSetMaps(4, 3)([1, 0, 2, 1]).fibers()
315
{0: {1}, 1: {0, 3}, 2: {2}}
316
sage: F = FiniteSetMaps(["a", "b", "c"])
317
sage: F.from_dict({"a": "b", "b": "a", "c": "b"}).fibers()
318
{'a': {'b'}, 'b': {'a', 'c'}}
319
"""
320
return fibers(self, self.domain())
321
322
cpdef items(self):
323
"""
324
The items of ``self``
325
326
Return the list of the ordered pairs ``(x, self(x))``
327
328
EXAMPLES::
329
330
sage: FiniteSetMaps(4, 3)([1, 0, 2, 1]).items()
331
[(0, 1), (1, 0), (2, 2), (3, 1)]
332
"""
333
return [(i, self._getimage(i)) for i in self.domain()]
334
335
cpdef check(self):
336
"""
337
Performs checks on ``self``
338
339
Check that ``self`` is a proper function and then calls
340
``parent.check_element(self)`` where ``parent`` is the parent
341
of ``self``.
342
343
TESTS::
344
345
sage: fs = FiniteSetMaps(3, 2)
346
sage: for el in fs: el.check()
347
sage: fs([1,1])
348
Traceback (most recent call last):
349
...
350
AssertionError: Wrong number of values
351
sage: fs([0,0,2])
352
Traceback (most recent call last):
353
...
354
AssertionError: Wrong value self(2) = 2
355
"""
356
cdef int i, m, n
357
m = self._parent._m
358
n = self._parent._n
359
assert self._len == m, "Wrong number of values"
360
for i in range(m):
361
assert 0 <= self._list[i] < n, "Wrong value self(%i) = %i"%(i, self._list[i])
362
if hasattr(self._parent, 'check_element'):
363
self._parent.check_element(self)
364
365
cpdef FiniteSetMap_MN _compose_internal_(self, FiniteSetMap_MN other,
366
Parent resParent):
367
"""
368
TESTS::
369
370
sage: FSM = FiniteSetMaps(3)
371
sage: fs1 = FSM([1, 0, 2])
372
sage: fs2 = FSM([0, 1, 2])
373
sage: el = fs1*fs2; el
374
[1, 0, 2]
375
sage: el.check()
376
"""
377
cdef FiniteSetMap_MN res = PY_NEW_SAME_TYPE(self)
378
res._parent = resParent
379
res._alloc_(self._len)
380
for i in range(self._len):
381
res._list[i] = other._list[self._list[i]]
382
res.set_immutable()
383
return res
384
385
386
cdef class FiniteSetMap_Set(FiniteSetMap_MN):
387
"""
388
Data structure for maps
389
390
We assume that the parent given as argument is such that:
391
392
- the domain is in ``parent.domain()``
393
- the codomain is in ``parent.codomain()``
394
- ``parent._m`` contains the cardinality of the domain
395
- ``parent._n`` contains the cardinality of the codomain
396
- ``parent._unrank_domain`` and ``parent._rank_domain`` is a pair of
397
reciprocal rank and unrank functions beween the domain and
398
``range(parent._m)``.
399
- ``parent._unrank_codomain`` and ``parent._rank_codomain`` is a pair of
400
reciprocal rank and unrank functions beween the codomain and
401
``range(parent._n)``.
402
"""
403
404
def __init__(self, parent, fun, check=True):
405
"""
406
EXAMPLES::
407
408
sage: F = FiniteSetMaps(["a", "b", "c", "d"], ["u", "v", "w"])
409
sage: F(lambda x: "v")
410
map: a -> v, b -> v, c -> v, d -> v
411
"""
412
# For speed we initialize self by hand.
413
# super(FiniteSetMap_Set, self).__init__(parent, [], check=False)
414
self._parent = parent
415
self._alloc_(int(parent._m))
416
for i, el in enumerate(parent.domain().list()):
417
self._setitem(i, parent._rank_codomain(fun(el)))
418
self.set_immutable()
419
if check: self.check()
420
421
from_list = classmethod(FiniteSetMap_Set_from_list)
422
from_dict = classmethod(FiniteSetMap_Set_from_dict)
423
424
def __call__(self, i):
425
"""
426
Returns the image of ``i`` under the map ``self``
427
428
INPUT:
429
430
- ``i`` -- an int
431
432
OUTPUT:
433
434
an int
435
436
EXAMPLES::
437
438
sage: F = FiniteSetMaps(["a", "b"], [3, 4, 5])
439
sage: fs = F.from_dict({"a": 3, "b": 5})
440
sage: fs('a'), fs('b')
441
(3, 5)
442
"""
443
parent = self._parent
444
return parent._unrank_codomain(self._getitem(parent._rank_domain(i)))
445
446
cpdef image_set(self):
447
"""
448
Returns the image set of ``self``
449
450
EXAMPLES::
451
452
sage: F = FiniteSetMaps(["a", "b", "c"])
453
sage: F.from_dict({"a": "b", "b": "a", "c": "b"}).image_set()
454
{'a', 'b'}
455
sage: F = FiniteSetMaps(["a", "b", "c"])
456
sage: F(lambda x: "c").image_set()
457
{'c'}
458
"""
459
image_i = self._parent._unrank_codomain
460
return Set_object_enumerated([image_i(i) for i in self])
461
462
cpdef setimage(self, i, j):
463
"""
464
Set the image of ``i`` as ``j`` in ``self``
465
466
.. warning:: ``self`` must be mutable otherwise an exception is raised.
467
468
INPUT:
469
470
- ``i``, ``j`` -- two ``object``'s
471
472
OUTPUT: ``None``
473
474
EXAMPLES::
475
476
sage: F = FiniteSetMaps(["a", "b", "c", "d"], ["u", "v", "w"])
477
sage: fs = F(lambda x: "v")
478
sage: fs2 = copy(fs)
479
sage: fs2.setimage("a", "w")
480
sage: fs2
481
map: a -> w, b -> v, c -> v, d -> v
482
sage: with fs.clone() as fs3:
483
... fs3.setimage("a", "u")
484
... fs3.setimage("c", "w")
485
sage: fs3
486
map: a -> u, b -> v, c -> w, d -> v
487
488
TESTS::
489
490
sage: with fs.clone() as fs3:
491
... fs3.setimage("z", 2)
492
Traceback (most recent call last):
493
...
494
ValueError: 'z' is not in list
495
496
sage: with fs.clone() as fs3:
497
... fs3.setimage(1, 4)
498
Traceback (most recent call last):
499
...
500
ValueError: 1 is not in list
501
"""
502
parent = self._parent
503
return self._setitem(parent._rank_domain(i), parent._rank_codomain(j))
504
505
cpdef getimage(self, i):
506
"""
507
Returns the image of ``i`` by ``self``
508
509
INPUT:
510
511
- ``i`` -- an ``int``
512
513
EXAMPLES::
514
515
sage: F = FiniteSetMaps(["a", "b", "c", "d"], ["u", "v", "w"])
516
sage: fs = F._from_list_([1, 0, 2, 1])
517
sage: map(fs.getimage, ["a", "b", "c", "d"])
518
['v', 'u', 'w', 'v']
519
"""
520
parent = self._parent
521
return parent._unrank_codomain(self._getitem(parent._rank_domain(i)))
522
523
cpdef items(self):
524
"""
525
The items of ``self``
526
527
Return the list of the couple ``(x, self(x))``
528
529
EXAMPLES::
530
531
sage: F = FiniteSetMaps(["a", "b", "c"])
532
sage: F.from_dict({"a": "b", "b": "a", "c": "b"}).items()
533
[('a', 'b'), ('b', 'a'), ('c', 'b')]
534
535
TESTS::
536
537
sage: all(F.from_dict(dict(f.items())) == f for f in F)
538
True
539
"""
540
parent = self._parent
541
return [(parent._unrank_domain(i),
542
parent._unrank_codomain(self._getitem(i)))
543
for i in range(parent._m)]
544
545
def _repr_(self):
546
"""
547
TESTS::
548
549
sage: F = FiniteSetMaps(["a", "b"], [3, 4, 5])
550
sage: F._from_list_([0, 2])
551
map: a -> 3, b -> 5
552
"""
553
return "map: "+", ".join([("%s -> %s"%(i, self(i))) for i in self.domain()])
554
555
556
cpdef FiniteSetMap_Set FiniteSetMap_Set_from_list(cls, Parent parent, list lst):
557
"""
558
Creates a ``FiniteSetMap`` from a list
559
560
.. warning:: no check is performed !
561
562
TESTS::
563
564
sage: from sage.sets.finite_set_map_cy import FiniteSetMap_Set_from_list as from_list
565
sage: F = FiniteSetMaps(["a", "b"], [3, 4, 5])
566
sage: f = from_list(F.element_class, F, [0,2]); f.check(); f
567
map: a -> 3, b -> 5
568
sage: f.parent() is F
569
True
570
sage: f.is_immutable()
571
True
572
"""
573
cdef FiniteSetMap_MN res
574
res = PY_NEW(cls)
575
super(FiniteSetMap_MN, res).__init__(parent, lst)
576
return res
577
578
cpdef FiniteSetMap_Set FiniteSetMap_Set_from_dict(cls, Parent parent, dict d):
579
"""
580
Creates a ``FiniteSetMap`` from a dictionary
581
582
.. warning:: no check is performed !
583
584
TESTS::
585
586
sage: from sage.sets.finite_set_map_cy import FiniteSetMap_Set_from_dict as from_dict
587
sage: F = FiniteSetMaps(["a", "b"], [3, 4, 5])
588
sage: f = from_dict(F.element_class, F, {"a": 3, "b": 5}); f.check(); f
589
map: a -> 3, b -> 5
590
sage: f.parent() is F
591
True
592
sage: f.is_immutable()
593
True
594
"""
595
cdef FiniteSetMap_Set res
596
res = PY_NEW(cls)
597
res.__init__(parent, d.__getitem__)
598
return res
599
600
601
cdef class FiniteSetEndoMap_N(FiniteSetMap_MN):
602
"""
603
Maps from ``range(n)`` to itself.
604
605
.. seealso:: :class:`FiniteSetMap_MN` for assumptions on the parent
606
607
TESTS::
608
609
sage: fs = FiniteSetMaps(3)([1, 0, 2])
610
sage: TestSuite(fs).run()
611
"""
612
613
def __mul__(FiniteSetEndoMap_N self, FiniteSetEndoMap_N other):
614
"""
615
TESTS::
616
617
sage: F = FiniteSetMaps(3)
618
sage: F([1, 0, 2]) * F([2, 1, 0])
619
[2, 0, 1]
620
sage: F = FiniteSetMaps(3, action="right")
621
sage: F([1, 0, 2]) * F([2, 1, 0])
622
[1, 2, 0]
623
"""
624
assert(self._parent is other._parent), "Parent mismatch"
625
if self._parent._action == "right":
626
return self._compose_internal_(other, self._parent)
627
else:
628
return other._compose_internal_(self, self._parent)
629
630
def __pow__(self, n, dummy):
631
"""
632
Return the ``n``-th power of ``self``.
633
634
INPUT::
635
636
- ``n`` -- a positive integer
637
- ``dummy`` -- not used; must be set to ``None`` (for compatibility only).
638
639
EXAMPLES::
640
641
sage: fs = FiniteSetMaps(3)([1,0,2])
642
sage: fs^2
643
[0, 1, 2]
644
sage: fs^0
645
[0, 1, 2]
646
sage: fs.__pow__(2)
647
[0, 1, 2]
648
"""
649
if dummy is not None:
650
raise RuntimeError, "__pow__ dummy argument not used"
651
return generic_power_c(self, n, self.parent().one())
652
653
654
cdef class FiniteSetEndoMap_Set(FiniteSetMap_Set):
655
"""
656
Maps from a set to itself
657
658
.. seealso:: :class:`FiniteSetMap_Set` for assumptions on the parent
659
660
TESTS::
661
662
sage: F = FiniteSetMaps(["a", "b", "c"])
663
sage: f = F.from_dict({"a": "b", "b": "a", "c": "b"}); f
664
map: a -> b, b -> a, c -> b
665
sage: TestSuite(f).run()
666
"""
667
668
def __mul__(FiniteSetEndoMap_Set self, FiniteSetEndoMap_Set other):
669
"""
670
TESTS::
671
672
sage: F = FiniteSetMaps(["a", "b", "c"])
673
sage: f = F.from_dict({"a": "b", "b": "a", "c": "b"}); f
674
map: a -> b, b -> a, c -> b
675
sage: g = F.from_dict({"a": "c", "b": "c", "c": "a"}); g
676
map: a -> c, b -> c, c -> a
677
sage: f * g
678
map: a -> b, b -> b, c -> b
679
sage: g * f
680
map: a -> c, b -> c, c -> c
681
"""
682
assert(self._parent is other._parent), "Parent mismatch"
683
if self._parent._action == "right":
684
return self._compose_internal_(other, self._parent)
685
else:
686
return other._compose_internal_(self, self._parent)
687
688
def __pow__(self, n, dummy):
689
"""
690
Return the ``n``-th power of self.
691
692
INPUT::
693
694
- ``n`` -- a positive integer
695
- ``dummy`` -- not used; must be set to None (for compatibility only).
696
697
EXAMPLES::
698
699
sage: F = FiniteSetMaps(["a", "b", "c"])
700
sage: f = F.from_dict({"a": "b", "b": "a", "c": "b"}); f
701
map: a -> b, b -> a, c -> b
702
sage: f^2
703
map: a -> a, b -> b, c -> a
704
sage: f^3 == f
705
True
706
"""
707
if dummy is not None:
708
raise RuntimeError, "__pow__ dummy argument not used"
709
return generic_power_c(self, n, self.parent().one())
710
711