Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/combinat/enumeration_mod_permgroup.pyx
4068 views
1
r"""
2
Tools for enumeration modulo the action of a permutation group
3
"""
4
#*****************************************************************************
5
# Copyright (C) 2010-12 Nicolas Borie <nicolas.borie at math dot u-psud.fr>
6
#
7
# Distributed under the terms of the GNU General Public License (GPL)
8
#
9
# The full text of the GPL is available at:
10
# http://www.gnu.org/licenses/
11
#*****************************************************************************
12
from sage.structure.list_clone cimport ClonableIntArray
13
from sage.groups.perm_gps.permgroup_element cimport PermutationGroupElement
14
from cpython cimport bool
15
16
cpdef list all_children(ClonableIntArray v, int max_part):
17
r"""
18
Returns all the children of an integer vector (:class:`~sage.structure.list_clone.ClonableIntArray`)
19
``v`` in the tree of enumeration by lexicographic order. The children of
20
an integer vector ``v`` whose entries have the sum `n` are all integer
21
vectors of sum `n+1` which follow ``v`` in the lexicographic order.
22
23
That means this function adds `1` on the last non zero entries and the
24
following ones. For an integer vector `v` such that
25
26
.. math::
27
28
v = [ \dots, a , 0, 0 ] \text{ with } a \neq 0,
29
30
then, the list of children is
31
32
.. math::
33
34
[ [ \dots, a+1 , 0, 0 ] , [ \dots, a , 1, 0 ], [ \dots, a , 0, 1 ] ].
35
36
EXAMPLES::
37
38
sage: from sage.combinat.enumeration_mod_permgroup import all_children
39
sage: from sage.structure.list_clone import IncreasingIntArrays
40
sage: v = IncreasingIntArrays()([1,2,3,4])
41
sage: all_children(v, -1)
42
[[1, 2, 3, 5]]
43
"""
44
cdef int l, j
45
cdef list all_children
46
cdef ClonableIntArray child
47
l = len(v)
48
all_children = []
49
j = l - 1
50
while v._list[j] == 0 and j >= 1:
51
j = j - 1
52
for i in range(j,l):
53
if (max_part < 0) or ((v[i]+1) <= max_part):
54
child = v.clone()
55
child._list[i] = v._list[i]+1
56
child.set_immutable()
57
all_children.append(child)
58
return all_children
59
60
cpdef int lex_cmp_partial(ClonableIntArray v1, ClonableIntArray v2, int step):
61
r"""
62
Partial comparison of the two lists according the lexicographic
63
order. It compares the ``step``-th first entries.
64
65
EXAMPLES::
66
67
sage: from sage.combinat.enumeration_mod_permgroup import lex_cmp_partial
68
sage: from sage.structure.list_clone import IncreasingIntArrays
69
sage: IA = IncreasingIntArrays()
70
sage: lex_cmp_partial(IA([0,1,2,3]),IA([0,1,2,4]),3)
71
0
72
sage: lex_cmp_partial(IA([0,1,2,3]),IA([0,1,2,4]),4)
73
-1
74
"""
75
cdef int i
76
if step < 0 or step > v1._len or step > v2._len:
77
raise IndexError, "list index out of range"
78
79
for i in range(step):
80
if v1._list[i] != v2._list[i]:
81
break
82
if i<step:
83
if v1._list[i] > v2._list[i]:
84
return 1
85
if v1._list[i] < v2._list[i]:
86
return -1
87
return 0
88
89
cpdef int lex_cmp(ClonableIntArray v1, ClonableIntArray v2):
90
"""
91
Lexicographic comparison of :class:`~sage.structure.list_clone.ClonableIntArray`.
92
93
INPUT:
94
95
Two instances `v_1, v_2` of :class:`~sage.structure.list_clone.ClonableIntArray`
96
97
OUPUT:
98
99
``-1,0,1``, depending on whether `v_1` is lexicographically smaller, equal, or
100
greater than `v_2`.
101
102
EXAMPLES::
103
104
sage: I = IntegerVectorsModPermutationGroup(SymmetricGroup(5),5)
105
sage: I = IntegerVectorsModPermutationGroup(SymmetricGroup(5))
106
sage: J = IntegerVectorsModPermutationGroup(SymmetricGroup(6))
107
sage: v1 = I([2,3,1,2,3], check=False)
108
sage: v2 = I([2,3,2,3,2], check=False)
109
sage: v3 = J([2,3,1,2,3,1], check=False)
110
sage: from sage.combinat.enumeration_mod_permgroup import lex_cmp
111
sage: lex_cmp(v1, v1)
112
0
113
sage: lex_cmp(v1, v2)
114
-1
115
sage: lex_cmp(v2, v1)
116
1
117
sage: lex_cmp(v1, v3)
118
-1
119
sage: lex_cmp(v3, v1)
120
1
121
122
"""
123
cdef int i
124
cdef int step = min(v1._len,v2._len)
125
for i in range(step):
126
if v1._list[i] != v2._list[i]:
127
break
128
if i<step:
129
if v1._list[i] > v2._list[i]:
130
return 1
131
if v1._list[i] < v2._list[i]:
132
return -1
133
if v1._len==v2._len:
134
return 0
135
if v1._len<v2._len:
136
return -1
137
return 1
138
139
cpdef bool is_canonical(list sgs, ClonableIntArray v):
140
r"""
141
Returns ``True`` if the integer vector `v` is maximal with respect to
142
the lexicographic order in its orbit under the action of the
143
permutation group whose strong generating system is ``sgs``. Such
144
vectors are said to be canonical.
145
146
Let `G` to be the permutation group which admit ``sgs`` as a strong
147
generating system. An integer vector `v` is said to be
148
canonical under the action of `G` if and only if:
149
150
.. math::
151
152
v = \max_{\text{lex order}} \{g \cdot v | g \in G \}
153
154
EXAMPLES::
155
156
sage: from sage.combinat.enumeration_mod_permgroup import is_canonical
157
sage: G = PermutationGroup([[(1,2,3,4)]])
158
sage: sgs = G.strong_generating_system()
159
sage: from sage.structure.list_clone import IncreasingIntArrays
160
sage: IA = IncreasingIntArrays()
161
sage: is_canonical(sgs, IA([1,2,3,6]))
162
False
163
"""
164
cdef int l, i, comp
165
cdef set to_analyse, new_to_analyse
166
cdef ClonableIntArray list_test, child
167
cdef PermutationGroupElement x
168
cdef list transversal
169
l = len(v)
170
to_analyse = set([v])
171
for i in range(l-1):
172
new_to_analyse = set([])
173
transversal = sgs[i]
174
for list_test in to_analyse:
175
for x in transversal:
176
child = x._act_on_array_on_position(list_test)
177
comp = lex_cmp_partial(v,child,i+1)
178
if comp == -1:
179
return False
180
if comp == 0:
181
new_to_analyse.add(child)
182
to_analyse = new_to_analyse
183
return True
184
185
cpdef ClonableIntArray canonical_representative_of_orbit_of(list sgs, ClonableIntArray v):
186
r"""
187
Returns the maximal vector for the lexicographic order living in
188
the orbit of `v` under the action of the permutation group whose
189
strong generating system is ``sgs``. The maximal vector is also
190
called "canonical". Hence, this method returns the canonical
191
vector inside the orbit of `v`. If `v` is already canonical,
192
the method returns `v`.
193
194
Let `G` to be the permutation group which admits ``sgs`` as a strong
195
generating system. An integer vector `v` is said to be
196
canonical under the action of `G` if and only if:
197
198
.. math::
199
200
v = \max_{\text{lex order}} \{g \cdot v | g \in G \}
201
202
EXAMPLES::
203
204
sage: from sage.combinat.enumeration_mod_permgroup import canonical_representative_of_orbit_of
205
sage: G = PermutationGroup([[(1,2,3,4)]])
206
sage: sgs = G.strong_generating_system()
207
sage: from sage.structure.list_clone import IncreasingIntArrays
208
sage: IA = IncreasingIntArrays()
209
sage: canonical_representative_of_orbit_of(sgs, IA([1,2,3,5]))
210
[5, 1, 2, 3]
211
"""
212
cdef int l,i,comp
213
cdef set to_analyse, new_to_analyse
214
cdef ClonableIntArray representative, list_test, child
215
cdef PermutationGroupElement x
216
representative = v
217
l = len(v)
218
to_analyse = set([v])
219
for i in range(l-1):
220
new_to_analyse = set([])
221
for list_test in to_analyse:
222
for x in sgs[i]:
223
child = x._act_on_array_on_position(list_test)
224
comp = lex_cmp_partial(representative,child,i+1)
225
if comp <= 0:
226
new_to_analyse.add(child)
227
to_analyse = new_to_analyse
228
representative = max(to_analyse)
229
return representative
230
231
cpdef list canonical_children(list sgs, ClonableIntArray v, int max_part):
232
r"""
233
Returns the canonical children of the integer vector ``v``. This
234
function computes all children of the integer vector ``v`` via the
235
function :func:`all_children` and returns from this list only
236
these which are canonicals identified via the function
237
:func:`is_canonical`.
238
239
EXAMPLES::
240
241
sage: from sage.combinat.enumeration_mod_permgroup import canonical_children
242
sage: G = PermutationGroup([[(1,2,3,4)]])
243
sage: sgs = G.strong_generating_system()
244
sage: from sage.structure.list_clone import IncreasingIntArrays
245
sage: IA = IncreasingIntArrays()
246
sage: canonical_children(sgs, IA([1,2,3,5]), -1)
247
[]
248
"""
249
cdef ClonableIntArray child
250
return [child for child in all_children(v, max_part) if is_canonical(sgs, child)]
251
252
cpdef set orbit(list sgs, ClonableIntArray v):
253
r"""
254
Returns the orbit of the integer vector ``v`` under the action of the
255
permutation group whose strong generating system is ``sgs``.
256
257
NOTE:
258
259
The returned orbit is a set. In the doctests, we convert it into a
260
sorted list.
261
262
EXAMPLES::
263
264
sage: from sage.combinat.enumeration_mod_permgroup import orbit, lex_cmp
265
sage: G = PermutationGroup([[(1,2,3,4)]])
266
sage: sgs = G.strong_generating_system()
267
sage: from sage.structure.list_clone import IncreasingIntArrays
268
sage: IA = IncreasingIntArrays()
269
sage: sorted(orbit(sgs, IA([1,2,3,4])), cmp=lex_cmp)
270
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
271
"""
272
cdef i,l
273
cdef set to_analyse, new_to_analyse
274
cdef ClonableIntArray list_test, child
275
cdef PermutationGroupElement x
276
cdef list out
277
l = len(v)
278
to_analyse = set([v])
279
for i in range(l-1):
280
new_to_analyse = set([])
281
for list_test in to_analyse:
282
for x in sgs[i]:
283
child = x._act_on_array_on_position(list_test)
284
new_to_analyse.add(child)
285
to_analyse = new_to_analyse
286
return to_analyse
287
288