schubmult 2.0.4__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- schubmult/__init__.py +94 -1
- schubmult/perm_lib.py +232 -819
- schubmult/poly_lib/__init__.py +31 -0
- schubmult/poly_lib/poly_lib.py +244 -0
- schubmult/poly_lib/schub_poly.py +148 -0
- schubmult/poly_lib/variables.py +204 -0
- schubmult/rings/__init__.py +17 -0
- schubmult/rings/_quantum_schubert_polynomial_ring.py +788 -0
- schubmult/rings/_schubert_polynomial_ring.py +1006 -0
- schubmult/rings/_tensor_schub_ring.py +128 -0
- schubmult/rings/_utils.py +55 -0
- schubmult/{sage_integration → sage}/__init__.py +4 -1
- schubmult/{sage_integration → sage}/_fast_double_schubert_polynomial_ring.py +67 -109
- schubmult/{sage_integration → sage}/_fast_schubert_polynomial_ring.py +33 -28
- schubmult/{sage_integration → sage}/_indexing.py +9 -5
- schubmult/schub_lib/__init__.py +51 -0
- schubmult/{schubmult_double/_funcs.py → schub_lib/double.py} +532 -596
- schubmult/{schubmult_q/_funcs.py → schub_lib/quantum.py} +54 -53
- schubmult/schub_lib/quantum_double.py +954 -0
- schubmult/schub_lib/schub_lib.py +659 -0
- schubmult/{schubmult_py/_funcs.py → schub_lib/single.py} +45 -35
- schubmult/schub_lib/tests/__init__.py +0 -0
- schubmult/schub_lib/tests/legacy_perm_lib.py +946 -0
- schubmult/schub_lib/tests/test_vs_old.py +109 -0
- schubmult/scripts/__init__.py +0 -0
- schubmult/scripts/schubmult_double.py +378 -0
- schubmult/scripts/schubmult_py.py +84 -0
- schubmult/scripts/schubmult_q.py +109 -0
- schubmult/scripts/schubmult_q_double.py +207 -0
- schubmult/utils/__init__.py +0 -0
- schubmult/{_base_argparse.py → utils/argparse.py} +29 -5
- schubmult/utils/logging.py +16 -0
- schubmult/utils/parsing.py +20 -0
- schubmult/utils/perm_utils.py +135 -0
- schubmult/utils/test_utils.py +65 -0
- schubmult-3.0.0.dist-info/METADATA +1234 -0
- schubmult-3.0.0.dist-info/RECORD +41 -0
- {schubmult-2.0.4.dist-info → schubmult-3.0.0.dist-info}/WHEEL +1 -1
- schubmult-3.0.0.dist-info/entry_points.txt +5 -0
- schubmult/_tests.py +0 -24
- schubmult/schubmult_double/__init__.py +0 -12
- schubmult/schubmult_double/__main__.py +0 -6
- schubmult/schubmult_double/_script.py +0 -474
- schubmult/schubmult_py/__init__.py +0 -12
- schubmult/schubmult_py/__main__.py +0 -6
- schubmult/schubmult_py/_script.py +0 -97
- schubmult/schubmult_q/__init__.py +0 -8
- schubmult/schubmult_q/__main__.py +0 -6
- schubmult/schubmult_q/_script.py +0 -166
- schubmult/schubmult_q_double/__init__.py +0 -10
- schubmult/schubmult_q_double/__main__.py +0 -6
- schubmult/schubmult_q_double/_funcs.py +0 -540
- schubmult/schubmult_q_double/_script.py +0 -396
- schubmult-2.0.4.dist-info/METADATA +0 -542
- schubmult-2.0.4.dist-info/RECORD +0 -30
- schubmult-2.0.4.dist-info/entry_points.txt +0 -5
- {schubmult-2.0.4.dist-info → schubmult-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {schubmult-2.0.4.dist-info → schubmult-3.0.0.dist-info}/top_level.txt +0 -0
schubmult/perm_lib.py
CHANGED
@@ -1,54 +1,198 @@
|
|
1
|
-
|
2
|
-
from functools import cache
|
3
|
-
from itertools import chain
|
1
|
+
import math
|
2
|
+
from functools import cache, cached_property
|
4
3
|
|
5
|
-
import
|
6
|
-
from symengine import
|
4
|
+
import sympy.combinatorics.permutations as spp
|
5
|
+
from symengine import sympify
|
6
|
+
from sympy import Basic, Tuple
|
7
|
+
|
8
|
+
import schubmult.utils.logging as lg
|
9
|
+
from schubmult.utils.perm_utils import cyclic_sort, permtrim_list, sg
|
10
|
+
|
11
|
+
# schubmult.poly_lib.variables import GeneratingSet
|
12
|
+
|
13
|
+
logger = lg.get_logger(__name__)
|
7
14
|
|
8
15
|
zero = sympify(0)
|
9
16
|
n = 100
|
10
17
|
|
11
|
-
|
18
|
+
# TODO: permutations act
|
19
|
+
|
20
|
+
|
21
|
+
class Permutation(Basic):
|
22
|
+
def __new__(cls, perm):
|
23
|
+
return Permutation.__xnew_cached__(cls, tuple(perm))
|
24
|
+
|
25
|
+
print_as_code = False
|
26
|
+
|
27
|
+
@staticmethod
|
28
|
+
@cache
|
29
|
+
def __xnew_cached__(_class, perm):
|
30
|
+
return Permutation.__xnew__(_class, perm)
|
31
|
+
|
32
|
+
@staticmethod
|
33
|
+
def __xnew__(_class, perm):
|
34
|
+
p = tuple(permtrim_list([*perm]))
|
35
|
+
s_perm = spp.Permutation._af_new([i - 1 for i in p])
|
36
|
+
obj = Basic.__new__(_class, Tuple(*perm))
|
37
|
+
obj._s_perm = s_perm
|
38
|
+
obj._perm = p
|
39
|
+
obj._hash_code = hash(p)
|
40
|
+
cd = s_perm.inversion_vector()
|
41
|
+
obj._unique_key = (len(p), sum([cd[i] * math.factorial(len(p) - 1 - i) for i in range(len(cd))]))
|
42
|
+
return obj
|
43
|
+
|
44
|
+
@classmethod
|
45
|
+
def sorting_perm(cls, itera):
|
46
|
+
L = [i + 1 for i in range(len(itera))]
|
47
|
+
L.sort(key=lambda i: itera[i - 1])
|
48
|
+
return Permutation(L)
|
49
|
+
|
50
|
+
def _sympystr(self, printer):
|
51
|
+
if Permutation.print_as_code:
|
52
|
+
return printer.doprint(trimcode(self))
|
53
|
+
return printer.doprint(self._perm)
|
54
|
+
|
55
|
+
def __call__(self, i):
|
56
|
+
"""1-indexed"""
|
57
|
+
return self[i - 1]
|
58
|
+
|
59
|
+
def descents(self, zero_indexed=True):
|
60
|
+
if zero_indexed:
|
61
|
+
return self._s_perm.descents()
|
62
|
+
return {i + 1 for i in self._s_perm.descents()}
|
63
|
+
|
64
|
+
def get_cycles(self):
|
65
|
+
return self.get_cycles_cached()
|
66
|
+
|
67
|
+
@cache
|
68
|
+
def get_cycles_cached(self):
|
69
|
+
return [tuple(cyclic_sort([i + 1 for i in c])) for c in self._s_perm.cyclic_form]
|
70
|
+
|
71
|
+
@property
|
72
|
+
def code(self):
|
73
|
+
return list(self.cached_code())
|
74
|
+
|
75
|
+
@cache
|
76
|
+
def cached_code(self):
|
77
|
+
return self._s_perm.inversion_vector()
|
78
|
+
|
79
|
+
@cached_property
|
80
|
+
def inv(self):
|
81
|
+
return self._s_perm.inversions()
|
82
|
+
|
83
|
+
def swap(self, i, j):
|
84
|
+
new_perm = [*self._perm]
|
85
|
+
# print(f"SWAP {new_perm=}")
|
86
|
+
if i > j:
|
87
|
+
i, j = j, i
|
88
|
+
if j >= len(new_perm):
|
89
|
+
# print(f"SWAP {j}>={new_perm=}")
|
90
|
+
new_perm += list(range(len(new_perm) + 1, j + 2))
|
91
|
+
# print(f"SWAP extended {new_perm=}")
|
92
|
+
new_perm[i], new_perm[j] = new_perm[j], new_perm[i]
|
93
|
+
# print(f"SWAP iddle {new_perm=}")
|
94
|
+
return Permutation(new_perm)
|
95
|
+
|
96
|
+
def __getitem__(self, i):
|
97
|
+
if isinstance(i, slice):
|
98
|
+
return [self[ii] for ii in range(i.start if i.start is not None else 0, i.stop if i.stop is not None else len(self))]
|
99
|
+
if i >= len(self._perm):
|
100
|
+
return i + 1
|
101
|
+
return self._perm[i]
|
102
|
+
|
103
|
+
def __setitem__(self, i, v):
|
104
|
+
raise NotImplementedError
|
105
|
+
|
106
|
+
def __hash__(self):
|
107
|
+
return self._hash_code
|
108
|
+
|
109
|
+
def __mul__(self, other):
|
110
|
+
new_sperm = other._s_perm * self._s_perm
|
111
|
+
new_perm = permtrim_list([new_sperm.array_form[i] + 1 for i in range(new_sperm.size)])
|
112
|
+
return Permutation(new_perm)
|
113
|
+
|
114
|
+
def __iter__(self):
|
115
|
+
yield from self._perm.__iter__()
|
116
|
+
|
117
|
+
def __getslice__(self, i, j):
|
118
|
+
return self._perm[i:j]
|
119
|
+
|
120
|
+
def __str__(self):
|
121
|
+
return str(self._perm)
|
122
|
+
|
123
|
+
def __add__(self, other):
|
124
|
+
if not isinstance(other, list):
|
125
|
+
raise NotImplementedError
|
126
|
+
permlist = [*self._perm, *other]
|
127
|
+
try:
|
128
|
+
return Permutation(permlist)
|
129
|
+
except Exception:
|
130
|
+
return permlist
|
131
|
+
|
132
|
+
def __radd__(self, other):
|
133
|
+
if not isinstance(other, list):
|
134
|
+
raise NotImplementedError
|
135
|
+
permlist = [*other, *self._perm]
|
136
|
+
try:
|
137
|
+
return Permutation(permlist)
|
138
|
+
except Exception:
|
139
|
+
return permlist
|
140
|
+
|
141
|
+
def __eq__(self, other):
|
142
|
+
if isinstance(other, Permutation):
|
143
|
+
# print(f"{other._perm= } {self._perm=} {type(self._perm)=}")
|
144
|
+
# return other._perm == self._perm
|
145
|
+
return other._unique_key == self._unique_key
|
146
|
+
if isinstance(other, list):
|
147
|
+
# print(f"{[*self._perm]= } {other=}")
|
148
|
+
return [*self._perm] == other
|
149
|
+
if isinstance(other, tuple):
|
150
|
+
# print(f"{self._perm=} {other=}")
|
151
|
+
return self._perm == other
|
152
|
+
return False
|
153
|
+
|
154
|
+
def __len__(self):
|
155
|
+
# print("REMOVE THIS")
|
156
|
+
return max(len(self._perm), 2)
|
157
|
+
|
158
|
+
def __invert__(self):
|
159
|
+
new_sperm = ~(self._s_perm)
|
160
|
+
new_perm = [new_sperm.array_form[i] + 1 for i in range(new_sperm.size)]
|
161
|
+
return Permutation(new_perm)
|
12
162
|
|
163
|
+
def __repr__(self):
|
164
|
+
return self.__str__()
|
13
165
|
|
14
|
-
def
|
15
|
-
|
16
|
-
return perm[index]
|
17
|
-
return index + 1
|
166
|
+
def __lt__(self, other):
|
167
|
+
return tuple(self) < tuple(other)
|
18
168
|
|
19
169
|
|
170
|
+
def ensure_perms(func):
|
171
|
+
def wrapper(*args):
|
172
|
+
return func(*[Permutation(arg) if (isinstance(arg, list) or isinstance(arg, tuple)) else arg for arg in args])
|
173
|
+
|
174
|
+
return wrapper
|
175
|
+
|
176
|
+
|
177
|
+
@ensure_perms
|
20
178
|
def inv(perm):
|
21
|
-
|
22
|
-
v = list(range(1, L + 1))
|
23
|
-
ans = 0
|
24
|
-
for i in range(L):
|
25
|
-
itr = bisect_left(v, perm[i])
|
26
|
-
ans += itr
|
27
|
-
v = v[:itr] + v[itr + 1 :]
|
28
|
-
return ans
|
179
|
+
return perm.inv
|
29
180
|
|
30
181
|
|
182
|
+
@ensure_perms
|
31
183
|
def code(perm):
|
32
|
-
|
33
|
-
ret = []
|
34
|
-
v = list(range(1, L + 1))
|
35
|
-
for i in range(L - 1):
|
36
|
-
itr = bisect_left(v, perm[i])
|
37
|
-
ret += [itr]
|
38
|
-
v = v[:itr] + v[itr + 1 :]
|
39
|
-
return ret
|
184
|
+
return perm.code
|
40
185
|
|
41
186
|
|
187
|
+
@ensure_perms
|
42
188
|
def mulperm(perm1, perm2):
|
43
|
-
|
44
|
-
return [perm1[perm2[i] - 1] if perm2[i] <= len(perm1) else perm2[i] for i in range(len(perm2))]
|
45
|
-
return [perm1[perm2[i] - 1] for i in range(len(perm2))] + perm1[len(perm2) :]
|
189
|
+
return perm1 * perm2
|
46
190
|
|
47
191
|
|
48
192
|
def uncode(cd):
|
49
193
|
cd2 = [*cd]
|
50
194
|
if cd2 == []:
|
51
|
-
return [
|
195
|
+
return Permutation([])
|
52
196
|
max_required = max([cd2[i] + i for i in range(len(cd2))])
|
53
197
|
cd2 += [0 for i in range(len(cd2), max_required)]
|
54
198
|
fullperm = [i + 1 for i in range(len(cd2) + 1)]
|
@@ -56,129 +200,19 @@ def uncode(cd):
|
|
56
200
|
for i in range(len(cd2)):
|
57
201
|
perm += [fullperm.pop(cd2[i])]
|
58
202
|
perm += [fullperm[0]]
|
59
|
-
return perm
|
60
|
-
|
61
|
-
|
62
|
-
def reversecode(perm):
|
63
|
-
ret = []
|
64
|
-
for i in range(len(perm) - 1, 0, -1):
|
65
|
-
ret = [0, *ret]
|
66
|
-
for j in range(i, -1, -1):
|
67
|
-
if perm[i] > perm[j]:
|
68
|
-
ret[-1] += 1
|
69
|
-
return ret
|
70
|
-
|
71
|
-
|
72
|
-
def reverseuncode(cd):
|
73
|
-
cd2 = list(cd)
|
74
|
-
if cd2 == []:
|
75
|
-
return [1, 2]
|
76
|
-
# max_required = max([cd2[i]+i for i in range(len(cd2))])
|
77
|
-
# cd2 += [0 for i in range(len(cd2),max_required)]
|
78
|
-
fullperm = [i + 1 for i in range(len(cd2) + 1)]
|
79
|
-
perm = []
|
80
|
-
for i in range(len(cd2) - 1, 0, -1):
|
81
|
-
perm = [fullperm[cd2[i]], *perm]
|
82
|
-
fullperm.pop(cd2[i])
|
83
|
-
perm += [fullperm[0]]
|
84
|
-
return perm
|
203
|
+
return Permutation(perm)
|
85
204
|
|
86
205
|
|
206
|
+
@ensure_perms
|
87
207
|
def inverse(perm):
|
88
|
-
|
89
|
-
for i in range(len(perm)):
|
90
|
-
retperm[perm[i] - 1] = i + 1
|
91
|
-
return retperm
|
208
|
+
return ~perm
|
92
209
|
|
93
210
|
|
94
211
|
def permtrim(perm):
|
95
|
-
|
96
|
-
while L > 2 and perm[-1] == L:
|
97
|
-
L = perm.pop() - 1
|
98
|
-
return perm
|
99
|
-
|
100
|
-
|
101
|
-
def has_bruhat_descent(perm, i, j):
|
102
|
-
if perm[i] < perm[j]:
|
103
|
-
return False
|
104
|
-
for p in range(i + 1, j):
|
105
|
-
if perm[i] > perm[p] and perm[p] > perm[j]:
|
106
|
-
return False
|
107
|
-
return True
|
108
|
-
|
109
|
-
|
110
|
-
def count_bruhat(perm, i, j):
|
111
|
-
up_amount = 0
|
112
|
-
if perm[i] < perm[j]:
|
113
|
-
up_amount = 1
|
114
|
-
else:
|
115
|
-
up_amount = -1
|
116
|
-
for k in range(i + 1, j):
|
117
|
-
if perm[i] < perm[k] and perm[k] < perm[j]:
|
118
|
-
up_amount += 2
|
119
|
-
elif perm[i] > perm[k] and perm[k] > perm[j]:
|
120
|
-
up_amount -= 2
|
121
|
-
return up_amount
|
122
|
-
|
123
|
-
|
124
|
-
def has_bruhat_ascent(perm, i, j):
|
125
|
-
if perm[i] > perm[j]:
|
126
|
-
return False
|
127
|
-
for p in range(i + 1, j):
|
128
|
-
if perm[i] < perm[p] and perm[p] < perm[j]:
|
129
|
-
return False
|
130
|
-
return True
|
131
|
-
|
132
|
-
|
133
|
-
def elem_sym_perms(orig_perm, p, k):
|
134
|
-
total_list = [(orig_perm, 0)]
|
135
|
-
up_perm_list = [(orig_perm, 1000000000)]
|
136
|
-
for pp in range(p):
|
137
|
-
perm_list = []
|
138
|
-
for up_perm, last in up_perm_list:
|
139
|
-
up_perm2 = [*up_perm, len(up_perm) + 1]
|
140
|
-
if len(up_perm2) < k + 1:
|
141
|
-
up_perm2 += [i + 1 for i in range(len(up_perm2), k + 2)]
|
142
|
-
pos_list = [i for i in range(k) if up_perm2[i] < last]
|
143
|
-
for j in range(k, len(up_perm2)):
|
144
|
-
if up_perm2[j] >= last:
|
145
|
-
continue
|
146
|
-
for i in pos_list:
|
147
|
-
if has_bruhat_ascent(up_perm2, i, j):
|
148
|
-
new_perm = [*up_perm2]
|
149
|
-
new_perm[i], new_perm[j] = new_perm[j], new_perm[i]
|
150
|
-
if new_perm[-1] == len(new_perm):
|
151
|
-
new_perm_add = tuple(new_perm[:-1])
|
152
|
-
else:
|
153
|
-
new_perm_add = tuple(new_perm)
|
154
|
-
perm_list += [(new_perm_add, up_perm2[j])]
|
155
|
-
total_list += [(new_perm_add, pp + 1)]
|
156
|
-
up_perm_list = perm_list
|
157
|
-
return total_list
|
158
|
-
|
159
|
-
|
160
|
-
def elem_sym_perms_op(orig_perm, p, k):
|
161
|
-
total_list = [(orig_perm, 0)]
|
162
|
-
up_perm_list = [(orig_perm, k)]
|
163
|
-
for pp in range(p):
|
164
|
-
perm_list = []
|
165
|
-
for up_perm, last in up_perm_list:
|
166
|
-
up_perm2 = [*up_perm]
|
167
|
-
if len(up_perm2) < k + 1:
|
168
|
-
up_perm2 += [i + 1 for i in range(len(up_perm2), k + 2)]
|
169
|
-
pos_list = [i for i in range(k) if getpermval(up_perm2, i) == getpermval(orig_perm, i)]
|
170
|
-
for j in range(last, len(up_perm2)):
|
171
|
-
for i in pos_list:
|
172
|
-
if has_bruhat_descent(up_perm2, i, j):
|
173
|
-
new_perm = [*up_perm2]
|
174
|
-
new_perm[i], new_perm[j] = new_perm[j], new_perm[i]
|
175
|
-
new_perm_add = tuple(permtrim(new_perm))
|
176
|
-
perm_list += [(new_perm_add, j)]
|
177
|
-
total_list += [(new_perm_add, pp + 1)]
|
178
|
-
up_perm_list = perm_list
|
179
|
-
return total_list
|
212
|
+
return Permutation(perm)
|
180
213
|
|
181
214
|
|
215
|
+
@ensure_perms
|
182
216
|
def strict_theta(u):
|
183
217
|
ret = [*trimcode(u)]
|
184
218
|
did_one = True
|
@@ -194,271 +228,20 @@ def strict_theta(u):
|
|
194
228
|
return ret
|
195
229
|
|
196
230
|
|
197
|
-
def elem_sym_perms_q(orig_perm, p, k, q_var=q_var):
|
198
|
-
total_list = [(orig_perm, 0, 1)]
|
199
|
-
up_perm_list = [(orig_perm, 1, 1000)]
|
200
|
-
for pp in range(p):
|
201
|
-
perm_list = []
|
202
|
-
for up_perm, val, last_j in up_perm_list:
|
203
|
-
up_perm2 = [*up_perm, len(up_perm) + 1]
|
204
|
-
if len(up_perm2) < k + 1:
|
205
|
-
up_perm2 += [i + 1 for i in range(len(up_perm2), k + 2)]
|
206
|
-
pos_list = [i for i in range(k) if (i >= len(orig_perm) and up_perm2[i] == i + 1) or (i < len(orig_perm) and up_perm2[i] == orig_perm[i])]
|
207
|
-
for j in range(min(len(up_perm2) - 1, last_j), k - 1, -1):
|
208
|
-
for i in pos_list:
|
209
|
-
ct = count_bruhat(up_perm2, i, j)
|
210
|
-
# print(f"{up_perm2=} {ct=} {i=} {j=} {k=} {pp=}")
|
211
|
-
if ct == 1 or ct == 2 * (i - j) + 1:
|
212
|
-
new_perm = [*up_perm2]
|
213
|
-
new_perm[i], new_perm[j] = new_perm[j], new_perm[i]
|
214
|
-
new_perm_add = tuple(permtrim(new_perm))
|
215
|
-
new_val = val
|
216
|
-
if ct < 0:
|
217
|
-
new_val *= np.prod([q_var[index] for index in range(i + 1, j + 1)])
|
218
|
-
perm_list += [(new_perm_add, new_val, j)]
|
219
|
-
total_list += [(new_perm_add, pp + 1, new_val)]
|
220
|
-
up_perm_list = perm_list
|
221
|
-
return total_list
|
222
|
-
|
223
|
-
|
224
|
-
def elem_sym_perms_q_op(orig_perm, p, k, n, q_var=q_var):
|
225
|
-
total_list = [(orig_perm, 0, 1)]
|
226
|
-
up_perm_list = [(orig_perm, 1, k)]
|
227
|
-
for pp in range(p):
|
228
|
-
perm_list = []
|
229
|
-
for up_perm, val, last_j in up_perm_list:
|
230
|
-
up_perm2 = [*up_perm]
|
231
|
-
if len(up_perm) < n:
|
232
|
-
up_perm2 += [i + 1 for i in range(len(up_perm2), n)]
|
233
|
-
pos_list = [i for i in range(k) if (i >= len(orig_perm) and up_perm2[i] == i + 1) or (i < len(orig_perm) and up_perm2[i] == orig_perm[i])]
|
234
|
-
for j in range(last_j, n):
|
235
|
-
for i in pos_list:
|
236
|
-
ct = count_bruhat(up_perm2, i, j)
|
237
|
-
# print(f"{up_perm2=} {ct=} {i=} {j=} {k=} {pp=}")
|
238
|
-
if ct == -1 or ct == 2 * (j - i) - 1:
|
239
|
-
new_perm = [*up_perm2]
|
240
|
-
new_perm[i], new_perm[j] = new_perm[j], new_perm[i]
|
241
|
-
new_perm_add = tuple(permtrim(new_perm))
|
242
|
-
new_val = val
|
243
|
-
if ct > 0:
|
244
|
-
new_val *= np.prod([q_var[index] for index in range(i + 1, j + 1)])
|
245
|
-
perm_list += [(new_perm_add, new_val, j)]
|
246
|
-
total_list += [(new_perm_add, pp + 1, new_val)]
|
247
|
-
up_perm_list = perm_list
|
248
|
-
return total_list
|
249
|
-
|
250
|
-
|
251
|
-
def q_vector(q_exp, q_var=q_var):
|
252
|
-
qvar_list = q_var.tolist()
|
253
|
-
ret = []
|
254
|
-
|
255
|
-
if q_exp == 1:
|
256
|
-
return ret
|
257
|
-
if q_exp in q_var:
|
258
|
-
i = qvar_list.index(q_exp)
|
259
|
-
return [0 for j in range(i - 1)] + [1]
|
260
|
-
if isinstance(q_exp, Pow):
|
261
|
-
qv = q_exp.args[0]
|
262
|
-
expon = int(q_exp.args[1])
|
263
|
-
i = qvar_list.index(qv)
|
264
|
-
return [0 for j in range(i - 1)] + [expon]
|
265
|
-
if isinstance(q_exp, Mul):
|
266
|
-
for a in q_exp.args:
|
267
|
-
v1 = q_vector(a)
|
268
|
-
v1 += [0 for i in range(len(v1), len(ret))]
|
269
|
-
ret += [0 for i in range(len(ret), len(v1))]
|
270
|
-
ret = [ret[i] + v1[i] for i in range(len(ret))]
|
271
|
-
return ret
|
272
|
-
|
273
|
-
return None
|
274
|
-
|
275
|
-
|
276
|
-
def omega(i, qv):
|
277
|
-
i = i - 1
|
278
|
-
if len(qv) == 0 or i > len(qv):
|
279
|
-
return 0
|
280
|
-
if i == 0:
|
281
|
-
if len(qv) == 1:
|
282
|
-
return 2 * qv[0]
|
283
|
-
return 2 * qv[0] - qv[1]
|
284
|
-
if i == len(qv):
|
285
|
-
return -qv[-1]
|
286
|
-
if i == len(qv) - 1:
|
287
|
-
return 2 * qv[-1] - qv[-2]
|
288
|
-
return 2 * qv[i] - qv[i - 1] - qv[i + 1]
|
289
|
-
|
290
|
-
|
291
|
-
def sg(i, w):
|
292
|
-
if i >= len(w) - 1 or w[i] < w[i + 1]:
|
293
|
-
return 0
|
294
|
-
return 1
|
295
|
-
|
296
|
-
|
297
|
-
def reduce_q_coeff(u, v, w, qv):
|
298
|
-
for i in range(len(qv)):
|
299
|
-
if sg(i, v) == 1 and sg(i, u) == 0 and sg(i, w) + omega(i + 1, qv) == 1:
|
300
|
-
ret_v = [*v]
|
301
|
-
ret_v[i], ret_v[i + 1] = ret_v[i + 1], ret_v[i]
|
302
|
-
ret_w = [*w] + [j + 1 for j in range(len(w), i + 2)]
|
303
|
-
ret_w[i], ret_w[i + 1] = ret_w[i + 1], ret_w[i]
|
304
|
-
qv_ret = [*qv]
|
305
|
-
if sg(i, w) == 0:
|
306
|
-
qv_ret[i] -= 1
|
307
|
-
return u, tuple(permtrim(ret_v)), tuple(permtrim(ret_w)), qv_ret, True
|
308
|
-
if (sg(i, u) == 1 and sg(i, v) == 0 and sg(i, w) + omega(i + 1, qv) == 1) or (sg(i, u) == 1 and sg(i, v) == 1 and sg(i, w) + omega(i + 1, qv) == 2):
|
309
|
-
ret_u = [*u]
|
310
|
-
ret_u[i], ret_u[i + 1] = ret_u[i + 1], ret_u[i]
|
311
|
-
ret_w = [*w] + [j + 1 for j in range(len(w), i + 2)]
|
312
|
-
ret_w[i], ret_w[i + 1] = ret_w[i + 1], ret_w[i]
|
313
|
-
qv_ret = [*qv]
|
314
|
-
if sg(i, w) == 0:
|
315
|
-
qv_ret[i] -= 1
|
316
|
-
return tuple(permtrim(ret_u)), v, tuple(permtrim(ret_w)), qv_ret, True
|
317
|
-
return u, v, w, qv, False
|
318
|
-
|
319
|
-
|
320
|
-
def reduce_q_coeff_u_only(u, v, w, qv):
|
321
|
-
for i in range(len(qv)):
|
322
|
-
if (sg(i, u) == 1 and sg(i, v) == 0 and sg(i, w) + omega(i + 1, qv) == 1) or (sg(i, u) == 1 and sg(i, v) == 1 and sg(i, w) + omega(i + 1, qv) == 2):
|
323
|
-
ret_u = [*u]
|
324
|
-
ret_u[i], ret_u[i + 1] = ret_u[i + 1], ret_u[i]
|
325
|
-
ret_w = [*w] + [j + 1 for j in range(len(w), i + 2)]
|
326
|
-
ret_w[i], ret_w[i + 1] = ret_w[i + 1], ret_w[i]
|
327
|
-
qv_ret = [*qv]
|
328
|
-
if sg(i, w) == 0:
|
329
|
-
qv_ret[i] -= 1
|
330
|
-
return tuple(permtrim(ret_u)), v, tuple(permtrim(ret_w)), qv_ret, True
|
331
|
-
return u, v, w, qv, False
|
332
|
-
|
333
|
-
|
334
231
|
def longest_element(indices):
|
335
|
-
perm = [1, 2]
|
232
|
+
perm = Permutation([1, 2])
|
336
233
|
did_one = True
|
337
234
|
while did_one:
|
338
235
|
did_one = False
|
339
236
|
for i in range(len(indices)):
|
340
237
|
j = indices[i] - 1
|
341
238
|
if sg(j, perm) == 0:
|
342
|
-
|
343
|
-
perm = perm + list(range(len(perm) + 1, j + 3))
|
344
|
-
perm[j], perm[j + 1] = perm[j + 1], perm[j]
|
239
|
+
perm = perm.swap(j, j + 1)
|
345
240
|
did_one = True
|
346
241
|
return permtrim(perm)
|
347
242
|
|
348
243
|
|
349
|
-
|
350
|
-
ct = 0
|
351
|
-
i = 0
|
352
|
-
while i < len(arr) and arr[i] < val:
|
353
|
-
i += 1
|
354
|
-
ct += 1
|
355
|
-
return ct
|
356
|
-
|
357
|
-
|
358
|
-
def is_parabolic(w, parabolic_index):
|
359
|
-
for i in parabolic_index:
|
360
|
-
if sg(i - 1, w) == 1:
|
361
|
-
return False
|
362
|
-
return True
|
363
|
-
|
364
|
-
|
365
|
-
def check_blocks(qv, parabolic_index):
|
366
|
-
blocks = []
|
367
|
-
cur_block = []
|
368
|
-
last_val = -1
|
369
|
-
for i in range(len(parabolic_index)):
|
370
|
-
if last_val == -1 or last_val + 1 == parabolic_index[i]:
|
371
|
-
last_val = parabolic_index[i]
|
372
|
-
cur_block += [last_val]
|
373
|
-
else:
|
374
|
-
blocks += [cur_block]
|
375
|
-
cur_block = []
|
376
|
-
for block in blocks:
|
377
|
-
for i in range(len(block)):
|
378
|
-
for j in range(i, len(block)):
|
379
|
-
val = 0
|
380
|
-
for k in range(i, j + 1):
|
381
|
-
val += omega(block[k], qv)
|
382
|
-
if val != 0 and val != -1:
|
383
|
-
return False
|
384
|
-
return True
|
385
|
-
|
386
|
-
|
387
|
-
# perms and inversion diff
|
388
|
-
def kdown_perms(perm, monoperm, p, k):
|
389
|
-
inv_m = inv(monoperm)
|
390
|
-
inv_p = inv(perm)
|
391
|
-
full_perm_list = []
|
392
|
-
|
393
|
-
if inv(mulperm(list(perm), monoperm)) == inv_m - inv_p:
|
394
|
-
full_perm_list += [(tuple(perm), 0, 1)]
|
395
|
-
|
396
|
-
down_perm_list = [(perm, 1)]
|
397
|
-
if len(perm) < k:
|
398
|
-
return full_perm_list
|
399
|
-
a2 = k - 1
|
400
|
-
for pp in range(1, p + 1):
|
401
|
-
down_perm_list2 = []
|
402
|
-
for perm2, s in down_perm_list:
|
403
|
-
L = len(perm2)
|
404
|
-
if k > L:
|
405
|
-
continue
|
406
|
-
s2 = -s
|
407
|
-
for b in chain(range(k - 1), range(k, L)):
|
408
|
-
if perm2[b] != perm[b]:
|
409
|
-
continue
|
410
|
-
if b < a2:
|
411
|
-
i, j = b, a2
|
412
|
-
else:
|
413
|
-
i, j, s2 = a2, b, s
|
414
|
-
if has_bruhat_descent(perm2, i, j):
|
415
|
-
new_perm = [*perm2]
|
416
|
-
new_perm[a2], new_perm[b] = new_perm[b], new_perm[a2]
|
417
|
-
permtrim(new_perm)
|
418
|
-
down_perm_list2 += [(new_perm, s2)]
|
419
|
-
if inv(mulperm(new_perm, monoperm)) == inv_m - inv_p + pp:
|
420
|
-
full_perm_list += [(tuple(new_perm), pp, s2)]
|
421
|
-
down_perm_list = down_perm_list2
|
422
|
-
return full_perm_list
|
423
|
-
|
424
|
-
|
425
|
-
def compute_vpathdicts(th, vmu, smpify=False):
|
426
|
-
vpathdicts = [{} for index in range(len(th))]
|
427
|
-
vpathdicts[-1][tuple(vmu)] = None
|
428
|
-
thL = len(th)
|
429
|
-
|
430
|
-
top = code(inverse(uncode(th)))
|
431
|
-
for i in range(thL - 1, -1, -1):
|
432
|
-
top2 = code(inverse(uncode(top)))
|
433
|
-
while top2[-1] == 0:
|
434
|
-
top2.pop()
|
435
|
-
top2.pop()
|
436
|
-
top = code(inverse(uncode(top2)))
|
437
|
-
monoperm = uncode(top)
|
438
|
-
if len(monoperm) < 2:
|
439
|
-
monoperm = [1, 2]
|
440
|
-
k = i + 1
|
441
|
-
for last_perm in vpathdicts[i]:
|
442
|
-
newperms = kdown_perms(last_perm, monoperm, th[i], k)
|
443
|
-
vpathdicts[i][last_perm] = newperms
|
444
|
-
if i > 0:
|
445
|
-
for trip in newperms:
|
446
|
-
vpathdicts[i - 1][trip[0]] = None
|
447
|
-
vpathdicts2 = [{} for i in range(len(th))]
|
448
|
-
for i in range(len(th)):
|
449
|
-
for key, valueset in vpathdicts[i].items():
|
450
|
-
for value in valueset:
|
451
|
-
key2 = value[0]
|
452
|
-
if key2 not in vpathdicts2[i]:
|
453
|
-
vpathdicts2[i][key2] = set()
|
454
|
-
v2 = value[2]
|
455
|
-
if smpify:
|
456
|
-
v2 = sympify(v2)
|
457
|
-
vpathdicts2[i][key2].add((key, value[1], v2))
|
458
|
-
# print(vpathdicts2)
|
459
|
-
return vpathdicts2
|
460
|
-
|
461
|
-
|
244
|
+
@ensure_perms
|
462
245
|
def theta(perm):
|
463
246
|
cd = code(perm)
|
464
247
|
for i in range(len(cd) - 1, 0, -1):
|
@@ -469,148 +252,30 @@ def theta(perm):
|
|
469
252
|
return cd
|
470
253
|
|
471
254
|
|
472
|
-
|
473
|
-
for k, v in d2.items():
|
474
|
-
d1[k] = d1.get(k, 0) + v
|
475
|
-
return d1
|
476
|
-
|
477
|
-
|
478
|
-
one = sympify(1)
|
479
|
-
|
480
|
-
|
481
|
-
def elem_sym_poly_q(p, k, varl1, varl2, q_var=q_var):
|
482
|
-
if p == 0 and k >= 0:
|
483
|
-
return one
|
484
|
-
if p < 0 or p > k:
|
485
|
-
return zero
|
486
|
-
return (
|
487
|
-
(varl1[k - 1] - varl2[k - p]) * elem_sym_poly_q(p - 1, k - 1, varl1, varl2, q_var)
|
488
|
-
+ elem_sym_poly_q(p, k - 1, varl1, varl2, q_var)
|
489
|
-
+ q_var[k - 1] * elem_sym_poly_q(p - 2, k - 2, varl1, varl2, q_var)
|
490
|
-
)
|
491
|
-
|
492
|
-
|
493
|
-
def elem_sym_poly(p, k, varl1, varl2, xstart=0, ystart=0):
|
494
|
-
if p > k:
|
495
|
-
return zero
|
496
|
-
if p == 0:
|
497
|
-
return one
|
498
|
-
if p == 1:
|
499
|
-
res = varl1[xstart] - varl2[ystart]
|
500
|
-
for i in range(1, k):
|
501
|
-
res += varl1[xstart + i] - varl2[ystart + i]
|
502
|
-
return res
|
503
|
-
if p == k:
|
504
|
-
res = (varl1[xstart] - varl2[ystart]) * (varl1[xstart + 1] - varl2[ystart])
|
505
|
-
for i in range(2, k):
|
506
|
-
res *= varl1[i + xstart] - varl2[ystart]
|
507
|
-
return res
|
508
|
-
mid = k // 2
|
509
|
-
xsm = xstart + mid
|
510
|
-
ysm = ystart + mid
|
511
|
-
kmm = k - mid
|
512
|
-
res = elem_sym_poly(p, mid, varl1, varl2, xstart, ystart) + elem_sym_poly(
|
513
|
-
p,
|
514
|
-
kmm,
|
515
|
-
varl1,
|
516
|
-
varl2,
|
517
|
-
xsm,
|
518
|
-
ysm,
|
519
|
-
)
|
520
|
-
for p2 in range(max(1, p - kmm), min(p, mid + 1)):
|
521
|
-
res += elem_sym_poly(p2, mid, varl1, varl2, xstart, ystart) * elem_sym_poly(
|
522
|
-
p - p2,
|
523
|
-
kmm,
|
524
|
-
varl1,
|
525
|
-
varl2,
|
526
|
-
xsm,
|
527
|
-
ysm - p2,
|
528
|
-
)
|
529
|
-
return res
|
530
|
-
|
531
|
-
|
532
|
-
@cache
|
533
|
-
def call_zvars(v1, v2, k, i): # noqa: ARG001
|
534
|
-
v3 = [*v2, *list(range(len(v2) + 1, i + 1))]
|
535
|
-
return [v3[i - 1]] + [v3[j] for j in range(len(v1), len(v3)) if v3[j] != j + 1 and j != i - 1] + [v3[j] for j in range(len(v1)) if v1[j] != v3[j] and j != i - 1]
|
536
|
-
|
537
|
-
|
538
|
-
def elem_sym_func(k, i, u1, u2, v1, v2, udiff, vdiff, varl1, varl2):
|
539
|
-
newk = k - udiff
|
540
|
-
if newk < vdiff:
|
541
|
-
return zero
|
542
|
-
if newk == vdiff:
|
543
|
-
return one
|
544
|
-
yvars = []
|
545
|
-
for j in range(min(len(u1), k)):
|
546
|
-
if u1[j] == u2[j]:
|
547
|
-
yvars += [varl1[u2[j]]]
|
548
|
-
for j in range(len(u1), min(k, len(u2))):
|
549
|
-
if u2[j] == j + 1:
|
550
|
-
yvars += [varl1[u2[j]]]
|
551
|
-
for j in range(len(u2), k):
|
552
|
-
yvars += [varl1[j + 1]]
|
553
|
-
zvars = [varl2[i] for i in call_zvars(v1, v2, k, i)]
|
554
|
-
return elem_sym_poly(newk - vdiff, newk, yvars, zvars)
|
555
|
-
|
556
|
-
|
557
|
-
def elem_sym_func_q(k, i, u1, u2, v1, v2, udiff, vdiff, varl1, varl2):
|
558
|
-
newk = k - udiff
|
559
|
-
if newk < vdiff:
|
560
|
-
return zero
|
561
|
-
if newk == vdiff:
|
562
|
-
return one
|
563
|
-
yvars = []
|
564
|
-
mlen = max(len(u1), len(u2))
|
565
|
-
u1 = [*u1] + [a + 1 for a in range(len(u1), mlen)]
|
566
|
-
u2 = [*u2] + [a + 1 for a in range(len(u2), mlen)]
|
567
|
-
for j in range(min(len(u1), k)):
|
568
|
-
if u1[j] == u2[j]:
|
569
|
-
yvars += [varl1[u2[j]]]
|
570
|
-
for j in range(len(u1), min(k, len(u2))):
|
571
|
-
if u2[j] == j + 1:
|
572
|
-
yvars += [varl1[u2[j]]]
|
573
|
-
for j in range(len(u2), k):
|
574
|
-
yvars += [varl1[j + 1]]
|
575
|
-
zvars = [varl2[a] for a in call_zvars(v1, v2, k, i)]
|
576
|
-
return elem_sym_poly(newk - vdiff, newk, yvars, zvars)
|
577
|
-
|
578
|
-
|
255
|
+
@ensure_perms
|
579
256
|
def trimcode(perm):
|
580
|
-
cd = code
|
257
|
+
cd = perm.code
|
581
258
|
while len(cd) > 0 and cd[-1] == 0:
|
582
259
|
cd.pop()
|
583
260
|
return cd
|
584
261
|
|
585
262
|
|
586
|
-
def p_trans(part):
|
587
|
-
newpart = []
|
588
|
-
if len(part) == 0 or part[0] == 0:
|
589
|
-
return [0]
|
590
|
-
for i in range(1, part[0] + 1):
|
591
|
-
cnt = 0
|
592
|
-
for j in range(len(part)):
|
593
|
-
if part[j] >= i:
|
594
|
-
cnt += 1
|
595
|
-
if cnt == 0:
|
596
|
-
break
|
597
|
-
newpart += [cnt]
|
598
|
-
return newpart
|
599
|
-
|
600
|
-
|
601
263
|
def cycle(p, q):
|
602
|
-
return list(range(1, p)) + [i + 1 for i in range(p, p + q)] + [p]
|
264
|
+
return Permutation(list(range(1, p)) + [i + 1 for i in range(p, p + q)] + [p])
|
603
265
|
|
604
266
|
|
267
|
+
@ensure_perms
|
605
268
|
def phi1(u):
|
606
|
-
c_star =
|
269
|
+
c_star = (~u).code
|
607
270
|
c_star.pop(0)
|
608
|
-
|
271
|
+
# print(f"{uncode(c_star)=}")
|
272
|
+
return ~(uncode(c_star))
|
609
273
|
|
610
274
|
|
275
|
+
@ensure_perms
|
611
276
|
def one_dominates(u, w):
|
612
|
-
c_star_u =
|
613
|
-
c_star_w =
|
277
|
+
c_star_u = (~u).code
|
278
|
+
c_star_w = (~w).code
|
614
279
|
|
615
280
|
a = c_star_u[0]
|
616
281
|
b = c_star_w[0]
|
@@ -624,303 +289,16 @@ def one_dominates(u, w):
|
|
624
289
|
|
625
290
|
|
626
291
|
def dominates(u, w):
|
627
|
-
u2 =
|
628
|
-
w2 =
|
629
|
-
while u2
|
292
|
+
u2 = u
|
293
|
+
w2 = w
|
294
|
+
while inv(u2) > 0 and one_dominates(u2, w2):
|
630
295
|
u2 = phi1(u2)
|
631
296
|
w2 = phi1(w2)
|
632
|
-
if u2 ==
|
297
|
+
if inv(u2) == 0:
|
633
298
|
return True
|
634
299
|
return False
|
635
300
|
|
636
301
|
|
637
|
-
def reduce_coeff(u, v, w):
|
638
|
-
t_mu_u_t = theta(inverse(u))
|
639
|
-
t_mu_v_t = theta(inverse(v))
|
640
|
-
|
641
|
-
mu_u_inv = uncode(t_mu_u_t)
|
642
|
-
mu_v_inv = uncode(t_mu_v_t)
|
643
|
-
|
644
|
-
t_mu_u = p_trans(t_mu_u_t)
|
645
|
-
t_mu_v = p_trans(t_mu_v_t)
|
646
|
-
|
647
|
-
t_mu_u += [0 for i in range(len(t_mu_u), max(len(t_mu_u), len(t_mu_v)))]
|
648
|
-
t_mu_v += [0 for i in range(len(t_mu_v), max(len(t_mu_u), len(t_mu_v)))]
|
649
|
-
|
650
|
-
t_mu_uv = [t_mu_u[i] + t_mu_v[i] for i in range(len(t_mu_u))]
|
651
|
-
t_mu_uv_t = p_trans(t_mu_uv)
|
652
|
-
|
653
|
-
mu_uv_inv = uncode(t_mu_uv_t)
|
654
|
-
|
655
|
-
if inv(mulperm(list(w), mu_uv_inv)) != inv(mu_uv_inv) - inv(w):
|
656
|
-
return u, v, w
|
657
|
-
|
658
|
-
umu = mulperm(list(u), mu_u_inv)
|
659
|
-
vmu = mulperm(list(v), mu_v_inv)
|
660
|
-
wmu = mulperm(list(w), mu_uv_inv)
|
661
|
-
|
662
|
-
t_mu_w = theta(inverse(wmu))
|
663
|
-
|
664
|
-
mu_w = uncode(t_mu_w)
|
665
|
-
|
666
|
-
w_prime = mulperm(wmu, mu_w)
|
667
|
-
|
668
|
-
if permtrim(list(w)) == permtrim(w_prime):
|
669
|
-
return (permtrim(list(u)), permtrim(list(v)), permtrim(list(w)))
|
670
|
-
|
671
|
-
A = []
|
672
|
-
B = []
|
673
|
-
indexA = 0
|
674
|
-
|
675
|
-
while len(t_mu_u_t) > 0 and t_mu_u_t[-1] == 0:
|
676
|
-
t_mu_u_t.pop()
|
677
|
-
|
678
|
-
while len(t_mu_v_t) > 0 and t_mu_v_t[-1] == 0:
|
679
|
-
t_mu_v_t.pop()
|
680
|
-
|
681
|
-
while len(t_mu_uv_t) > 0 and t_mu_uv_t[-1] == 0:
|
682
|
-
t_mu_uv_t.pop()
|
683
|
-
|
684
|
-
for index in range(len(t_mu_uv_t)):
|
685
|
-
if indexA < len(t_mu_u_t) and t_mu_uv_t[index] == t_mu_u_t[indexA]:
|
686
|
-
A += [index]
|
687
|
-
indexA += 1
|
688
|
-
else:
|
689
|
-
B += [index]
|
690
|
-
|
691
|
-
mu_w_A = uncode(mu_A(code(mu_w), A))
|
692
|
-
mu_w_B = uncode(mu_A(code(mu_w), B))
|
693
|
-
|
694
|
-
return (
|
695
|
-
permtrim(mulperm(umu, mu_w_A)),
|
696
|
-
permtrim(mulperm(vmu, mu_w_B)),
|
697
|
-
permtrim(w_prime),
|
698
|
-
)
|
699
|
-
|
700
|
-
|
701
|
-
def mu_A(mu, A):
|
702
|
-
mu_t = p_trans(mu)
|
703
|
-
mu_A_t = []
|
704
|
-
for i in range(len(A)):
|
705
|
-
if A[i] < len(mu_t):
|
706
|
-
mu_A_t += [mu_t[A[i]]]
|
707
|
-
return p_trans(mu_A_t)
|
708
|
-
|
709
|
-
|
710
|
-
def reduce_descents(u, v, w):
|
711
|
-
u2 = [*u]
|
712
|
-
v2 = [*v]
|
713
|
-
w2 = [*w]
|
714
|
-
found_one = True
|
715
|
-
while found_one:
|
716
|
-
found_one = False
|
717
|
-
if will_formula_work(u2, v2) or will_formula_work(v2, u2) or one_dominates(u2, w2) or is_reducible(v2) or inv(w2) - inv(u2) == 1:
|
718
|
-
break
|
719
|
-
for i in range(len(w2) - 2, -1, -1):
|
720
|
-
if w2[i] > w2[i + 1] and i < len(v2) - 1 and v2[i] > v2[i + 1] and (i >= len(u2) - 1 or u2[i] < u2[i + 1]):
|
721
|
-
w2[i], w2[i + 1] = w2[i + 1], w2[i]
|
722
|
-
v2[i], v2[i + 1] = v2[i + 1], v2[i]
|
723
|
-
found_one = True
|
724
|
-
elif w2[i] > w2[i + 1] and i < len(u2) - 1 and u2[i] > u2[i + 1] and (i >= len(v2) - 1 or v2[i] < v2[i + 1]):
|
725
|
-
w2[i], w2[i + 1] = w2[i + 1], w2[i]
|
726
|
-
u2[i], u2[i + 1] = u2[i + 1], u2[i]
|
727
|
-
found_one = True
|
728
|
-
if found_one:
|
729
|
-
break
|
730
|
-
return permtrim(u2), permtrim(v2), permtrim(w2)
|
731
|
-
|
732
|
-
|
733
|
-
def is_reducible(v):
|
734
|
-
c03 = code(v)
|
735
|
-
found0 = False
|
736
|
-
good = True
|
737
|
-
for i in range(len(c03)):
|
738
|
-
if c03[i] == 0:
|
739
|
-
found0 = True
|
740
|
-
elif c03[i] != 0 and found0:
|
741
|
-
good = False
|
742
|
-
break
|
743
|
-
return good
|
744
|
-
|
745
|
-
|
746
|
-
def try_reduce_v(u, v, w):
|
747
|
-
if is_reducible(v):
|
748
|
-
return tuple(permtrim([*u])), tuple(permtrim([*v])), tuple(permtrim([*w]))
|
749
|
-
u2 = [*u]
|
750
|
-
v2 = [*v]
|
751
|
-
w2 = [*w]
|
752
|
-
cv = code(v2)
|
753
|
-
for i in range(len(v2) - 2, -1, -1):
|
754
|
-
if cv[i] == 0 and i < len(cv) - 1 and cv[i + 1] != 0:
|
755
|
-
if i >= len(u2) - 1 or u2[i] < u2[i + 1]:
|
756
|
-
v2[i], v2[i + 1] = v2[i + 1], v2[i]
|
757
|
-
if i >= len(w2) - 1:
|
758
|
-
w2 += list(range(len(w2) + 1, i + 3))
|
759
|
-
w2[i + 1], w2[i] = w2[i], w2[i + 1]
|
760
|
-
if is_reducible(v2):
|
761
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
762
|
-
return try_reduce_v(u2, v2, w2)
|
763
|
-
if i < len(w2) - 1 and w2[i] > w2[i + 1]:
|
764
|
-
u2[i], u2[i + 1] = u2[i + 1], u2[i]
|
765
|
-
v2[i], v2[i + 1] = v2[i + 1], v2[i]
|
766
|
-
return try_reduce_v(u2, v2, w2)
|
767
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
768
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
769
|
-
|
770
|
-
|
771
|
-
def try_reduce_u(u, v, w):
|
772
|
-
if one_dominates(u, w):
|
773
|
-
return u, v, w
|
774
|
-
u2 = [*u]
|
775
|
-
v2 = [*v]
|
776
|
-
w2 = [*w]
|
777
|
-
cu = code(u)
|
778
|
-
for i in range(len(u2) - 2, -1, -1):
|
779
|
-
if cu[i] == 0 and i < len(cu) - 1 and cu[i + 1] != 0:
|
780
|
-
if i >= len(v2) - 1 or v2[i] < v2[i + 1]:
|
781
|
-
u2[i], u2[i + 1] = u2[i + 1], u2[i]
|
782
|
-
if i > len(w2) - 1:
|
783
|
-
w2 += list(range(len(w2) + 1, i + 3))
|
784
|
-
w2[i + 1], w2[i] = w2[i], w2[i + 1]
|
785
|
-
if one_dominates(u, w):
|
786
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
787
|
-
return try_reduce_u(u2, v2, w2)
|
788
|
-
if i < len(w2) - 1 and w2[i] > w2[i + 1]:
|
789
|
-
u2[i], u2[i + 1] = u2[i + 1], u2[i]
|
790
|
-
v2[i], v2[i + 1] = v2[i + 1], v2[i]
|
791
|
-
return try_reduce_u(u2, v2, w2)
|
792
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
793
|
-
return tuple(permtrim(u2)), tuple(permtrim(v2)), tuple(permtrim(w2))
|
794
|
-
|
795
|
-
|
796
|
-
def divdiffable(v, u):
|
797
|
-
inv_v = inv(v)
|
798
|
-
inv_u = inv(u)
|
799
|
-
perm2 = permtrim(mulperm(v, inverse(u)))
|
800
|
-
if inv(perm2) != inv_v - inv_u:
|
801
|
-
return []
|
802
|
-
return perm2
|
803
|
-
|
804
|
-
|
805
|
-
def will_formula_work(u, v):
|
806
|
-
muv = uncode(theta(v))
|
807
|
-
vn1muv = mulperm(inverse(v), muv)
|
808
|
-
while True:
|
809
|
-
found_one = False
|
810
|
-
for i in range(len(vn1muv) - 1):
|
811
|
-
if vn1muv[i] > vn1muv[i + 1]:
|
812
|
-
found_one = True
|
813
|
-
if i < len(u) - 1 and u[i] > u[i + 1]:
|
814
|
-
return False
|
815
|
-
vn1muv[i], vn1muv[i + 1] = vn1muv[i + 1], vn1muv[i]
|
816
|
-
break
|
817
|
-
if not found_one:
|
818
|
-
return True
|
819
|
-
|
820
|
-
|
821
|
-
def pull_out_var(vnum, v):
|
822
|
-
vup = [*v, len(v) + 1]
|
823
|
-
if vnum >= len(v):
|
824
|
-
return [[[], v]]
|
825
|
-
vpm_list = [(vup, 0)]
|
826
|
-
ret_list = []
|
827
|
-
for p in range(len(v) + 1 - vnum):
|
828
|
-
vpm_list2 = []
|
829
|
-
for vpm, b in vpm_list:
|
830
|
-
if vpm[vnum - 1] == len(v) + 1:
|
831
|
-
vpm2 = [*vpm]
|
832
|
-
vpm2.pop(vnum - 1)
|
833
|
-
vp = permtrim(vpm2)
|
834
|
-
ret_list += [
|
835
|
-
[
|
836
|
-
[v[i] for i in range(vnum, len(v)) if ((i > len(vp) and v[i] == i) or (i <= len(vp) and v[i] == vp[i - 1]))],
|
837
|
-
vp,
|
838
|
-
],
|
839
|
-
]
|
840
|
-
for j in range(vnum, len(vup)):
|
841
|
-
if vpm[j] <= b:
|
842
|
-
continue
|
843
|
-
for i in range(vnum):
|
844
|
-
if has_bruhat_ascent(vpm, i, j):
|
845
|
-
vpm[i], vpm[j] = vpm[j], vpm[i]
|
846
|
-
vpm_list2 += [([*vpm], vpm[i])]
|
847
|
-
vpm[i], vpm[j] = vpm[j], vpm[i]
|
848
|
-
vpm_list = vpm_list2
|
849
|
-
for vpm, b in vpm_list:
|
850
|
-
if vpm[vnum - 1] == len(v) + 1:
|
851
|
-
vpm2 = [*vpm]
|
852
|
-
vpm2.pop(vnum - 1)
|
853
|
-
vp = permtrim(vpm2)
|
854
|
-
ret_list += [
|
855
|
-
[
|
856
|
-
[v[i] for i in range(vnum, len(v)) if ((i > len(vp) and v[i] == i) or (i <= len(vp) and v[i] == vp[i - 1]))],
|
857
|
-
vp,
|
858
|
-
],
|
859
|
-
]
|
860
|
-
return ret_list
|
861
|
-
|
862
|
-
|
863
|
-
def get_cycles(perm):
|
864
|
-
cycle_set = []
|
865
|
-
done_vals = set()
|
866
|
-
for i in range(len(perm)):
|
867
|
-
p = i + 1
|
868
|
-
if perm[i] == p:
|
869
|
-
continue
|
870
|
-
if p in done_vals:
|
871
|
-
continue
|
872
|
-
cycle = []
|
873
|
-
m = -1
|
874
|
-
max_index = -1
|
875
|
-
while p not in done_vals:
|
876
|
-
cycle += [p]
|
877
|
-
done_vals.add(p)
|
878
|
-
if p > m:
|
879
|
-
m = p
|
880
|
-
max_index = len(cycle) - 1
|
881
|
-
p = perm[p - 1]
|
882
|
-
cycle = tuple(cycle[max_index + 1 :] + cycle[: max_index + 1])
|
883
|
-
cycle_set += [cycle]
|
884
|
-
return cycle_set
|
885
|
-
|
886
|
-
|
887
|
-
def double_elem_sym_q(u, p1, p2, k, q_var=q_var):
|
888
|
-
ret_list = {}
|
889
|
-
perms1 = elem_sym_perms_q(u, p1, k, q_var)
|
890
|
-
iu = inverse(u)
|
891
|
-
for perm1, udiff1, mul_val1 in perms1:
|
892
|
-
perms2 = elem_sym_perms_q(perm1, p2, k, q_var)
|
893
|
-
cycles1 = get_cycles(tuple(permtrim(mulperm(iu, [*perm1]))))
|
894
|
-
cycles1_dict = {}
|
895
|
-
for c in cycles1:
|
896
|
-
if c[-1] not in cycles1_dict:
|
897
|
-
cycles1_dict[c[-1]] = []
|
898
|
-
cycles1_dict[c[-1]] += [set(c)]
|
899
|
-
ip1 = inverse(perm1)
|
900
|
-
for perm2, udiff2, mul_val2 in perms2:
|
901
|
-
cycles2 = get_cycles(tuple(permtrim(mulperm(ip1, [*perm2]))))
|
902
|
-
good = True
|
903
|
-
for i in range(len(cycles2)):
|
904
|
-
c2 = cycles2[i]
|
905
|
-
if c2[-1] not in cycles1_dict:
|
906
|
-
continue
|
907
|
-
for c1_s in cycles1_dict[c2[-1]]:
|
908
|
-
for a in range(len(c2) - 2, -1, -1):
|
909
|
-
if c2[a] in c1_s:
|
910
|
-
good = False
|
911
|
-
break
|
912
|
-
if not good:
|
913
|
-
break
|
914
|
-
if not good:
|
915
|
-
break
|
916
|
-
|
917
|
-
if good:
|
918
|
-
if (perm1, udiff1, mul_val1) not in ret_list:
|
919
|
-
ret_list[(perm1, udiff1, mul_val1)] = []
|
920
|
-
ret_list[(perm1, udiff1, mul_val1)] += [(perm2, udiff2, mul_val2)]
|
921
|
-
return ret_list
|
922
|
-
|
923
|
-
|
924
302
|
def medium_theta(perm):
|
925
303
|
cd = code(perm)
|
926
304
|
found_one = True
|
@@ -932,8 +310,43 @@ def medium_theta(perm):
|
|
932
310
|
cd[i], cd[i + 1] = cd[i + 1] + 1, cd[i]
|
933
311
|
break
|
934
312
|
if cd[i] == cd[i + 1] and cd[i] != 0 and i > 0 and cd[i - 1] <= cd[i] + 1:
|
935
|
-
# if cd[i]==cd[i+1] and i>0 and cd[i-1]<=cd[i]+1:
|
936
313
|
cd[i] += 1
|
937
314
|
found_one = True
|
938
315
|
break
|
939
316
|
return cd
|
317
|
+
|
318
|
+
|
319
|
+
def split_perms(perms):
|
320
|
+
perms2 = [perms[0]]
|
321
|
+
for perm in perms[1:]:
|
322
|
+
cd = code(perm)
|
323
|
+
index = -1
|
324
|
+
not_zero = False
|
325
|
+
did = False
|
326
|
+
for i in range(len(cd)):
|
327
|
+
if cd[i] != 0:
|
328
|
+
not_zero = True
|
329
|
+
elif not_zero and cd[i] == 0:
|
330
|
+
not_zero = False
|
331
|
+
index = i
|
332
|
+
num_zeros_to_miss = 0
|
333
|
+
for j in range(index):
|
334
|
+
if cd[j] != 0:
|
335
|
+
num_zeros_to_miss = max(num_zeros_to_miss, cd[j] - (index - 1 - j))
|
336
|
+
num_zeros = 0
|
337
|
+
for j in range(index, len(cd)):
|
338
|
+
if cd[j] != 0:
|
339
|
+
break
|
340
|
+
num_zeros += 1
|
341
|
+
if num_zeros >= num_zeros_to_miss:
|
342
|
+
cd1 = cd[:index]
|
343
|
+
cd2 = [0 for i in range(index)] + cd[index:]
|
344
|
+
perms2 += [
|
345
|
+
uncode(cd1),
|
346
|
+
uncode(cd2),
|
347
|
+
]
|
348
|
+
did = True
|
349
|
+
break
|
350
|
+
if not did:
|
351
|
+
perms2 += [perm]
|
352
|
+
return perms2
|