schubmult 2.0.3__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 +233 -880
- 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 +17 -15
- schubmult/{sage_integration → sage}/_fast_double_schubert_polynomial_ring.py +142 -220
- schubmult/{sage_integration → sage}/_fast_schubert_polynomial_ring.py +78 -72
- schubmult/sage/_indexing.py +51 -0
- schubmult/schub_lib/__init__.py +51 -0
- schubmult/{schubmult_double/_funcs.py → schub_lib/double.py} +618 -798
- schubmult/{schubmult_q/_funcs.py → schub_lib/quantum.py} +70 -72
- 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} +58 -48
- 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} +40 -11
- 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.3.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 -9
- schubmult/sage_integration/_indexing.py +0 -51
- schubmult/schubmult_double/__init__.py +0 -22
- schubmult/schubmult_double/__main__.py +0 -5
- schubmult/schubmult_double/_script.py +0 -474
- schubmult/schubmult_py/__init__.py +0 -13
- schubmult/schubmult_py/__main__.py +0 -5
- schubmult/schubmult_py/_script.py +0 -96
- schubmult/schubmult_q/__init__.py +0 -13
- schubmult/schubmult_q/__main__.py +0 -5
- schubmult/schubmult_q/_script.py +0 -160
- schubmult/schubmult_q_double/__init__.py +0 -17
- schubmult/schubmult_q_double/__main__.py +0 -5
- schubmult/schubmult_q_double/_funcs.py +0 -540
- schubmult/schubmult_q_double/_script.py +0 -398
- schubmult-2.0.3.dist-info/METADATA +0 -455
- schubmult-2.0.3.dist-info/RECORD +0 -30
- schubmult-2.0.3.dist-info/entry_points.txt +0 -5
- {schubmult-2.0.3.dist-info → schubmult-3.0.0.dist-info}/licenses/LICENSE +0 -0
- {schubmult-2.0.3.dist-info → schubmult-3.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,788 @@
|
|
1
|
+
# to encourage development
|
2
|
+
|
3
|
+
from bisect import bisect_left
|
4
|
+
from functools import cache
|
5
|
+
|
6
|
+
import sympy
|
7
|
+
from symengine import S, sympify
|
8
|
+
from sympy import Basic
|
9
|
+
|
10
|
+
import schubmult.rings._schubert_polynomial_ring as spr
|
11
|
+
import schubmult.rings._utils as utils
|
12
|
+
import schubmult.schub_lib.quantum as py
|
13
|
+
import schubmult.schub_lib.quantum_double as yz
|
14
|
+
from schubmult.perm_lib import Permutation, longest_element
|
15
|
+
from schubmult.poly_lib.poly_lib import elem_sym_poly, elem_sym_poly_q, xreplace_genvars
|
16
|
+
from schubmult.poly_lib.schub_poly import schubpoly_from_elems
|
17
|
+
from schubmult.poly_lib.variables import GeneratingSet, GeneratingSet_base
|
18
|
+
from schubmult.utils.logging import get_logger
|
19
|
+
from schubmult.utils.perm_utils import is_parabolic
|
20
|
+
|
21
|
+
## EMULATE POLYTOOLS
|
22
|
+
|
23
|
+
q_var = GeneratingSet("q")
|
24
|
+
# _def_printer = StrPrinter({"order": "none"})
|
25
|
+
|
26
|
+
logger = get_logger(__name__)
|
27
|
+
|
28
|
+
|
29
|
+
class QuantumDoubleSchubertAlgebraElement(spr.BasisSchubertAlgebraElement):
|
30
|
+
def __new__(cls, _dict, basis):
|
31
|
+
return spr.BasisSchubertAlgebraElement.__new__(cls, _dict, basis)
|
32
|
+
|
33
|
+
def subs(self, old, new):
|
34
|
+
logger.debug("ferefef")
|
35
|
+
elb = self.as_classical().subs(old, new).as_quantum()
|
36
|
+
logger.debug(f"{elb=}")
|
37
|
+
return elb
|
38
|
+
|
39
|
+
|
40
|
+
# # TODO: not a noncommutative symbol, something else
|
41
|
+
# # Atomic Schubert polynomial
|
42
|
+
class QDSchubPoly(QuantumDoubleSchubertAlgebraElement):
|
43
|
+
is_Atom = True
|
44
|
+
|
45
|
+
def __new__(cls, k, basis):
|
46
|
+
return QDSchubPoly.__xnew_cached__(cls, k, basis)
|
47
|
+
|
48
|
+
@staticmethod
|
49
|
+
def __xnew__(_class, k, basis):
|
50
|
+
obj = QuantumDoubleSchubertAlgebraElement.__new__(_class, sympy.Dict({(Permutation(k[0]), k[1]): 1}), basis)
|
51
|
+
obj._perm = k[0]
|
52
|
+
obj._coeff_var = k[1]
|
53
|
+
# obj._base_var = base_var
|
54
|
+
return obj
|
55
|
+
|
56
|
+
@staticmethod
|
57
|
+
@cache
|
58
|
+
def __xnew_cached__(_class, k, genset):
|
59
|
+
return QDSchubPoly.__xnew__(_class, k, genset)
|
60
|
+
|
61
|
+
def _sympystr(self, printer):
|
62
|
+
if self._coeff_var == 0 or self._coeff_var == utils.NoneVar:
|
63
|
+
return printer.doprint(f"QS{self.genset.label}({printer.doprint(self._perm)})")
|
64
|
+
return printer.doprint(f"QDS{self.genset.label}({printer.doprint(self._perm)}, {spr._varstr(self._coeff_var)})")
|
65
|
+
|
66
|
+
|
67
|
+
class ParabolicQuantumDoubleSchubertAlgebraElement(spr.BasisSchubertAlgebraElement):
|
68
|
+
def __new__(cls, _dict, basis):
|
69
|
+
return spr.BasisSchubertAlgebraElement.__new__(cls, _dict, basis)
|
70
|
+
|
71
|
+
@property
|
72
|
+
def index_comp(self):
|
73
|
+
return self.basis.index_comp
|
74
|
+
|
75
|
+
def kill_ideal(self):
|
76
|
+
length = sum(self.index_comp)
|
77
|
+
new_dict = {}
|
78
|
+
for k, v in self.coeff_dict.items():
|
79
|
+
if len(k[0]) <= length:
|
80
|
+
new_dict[k] = v
|
81
|
+
return self.basis._from_dict(new_dict)
|
82
|
+
|
83
|
+
|
84
|
+
class PQDSchubPoly(ParabolicQuantumDoubleSchubertAlgebraElement):
|
85
|
+
is_Atom = True
|
86
|
+
|
87
|
+
def __new__(cls, k, basis):
|
88
|
+
return PQDSchubPoly.__xnew_cached__(cls, k, basis)
|
89
|
+
|
90
|
+
@staticmethod
|
91
|
+
def __xnew__(_class, k, basis):
|
92
|
+
obj = ParabolicQuantumDoubleSchubertAlgebraElement.__new__(_class, sympy.Dict({(Permutation(k[0]), k[1]): 1}), basis)
|
93
|
+
obj._perm = k[0]
|
94
|
+
# obj._perm._print_as_code = True
|
95
|
+
obj._coeff_var = k[1]
|
96
|
+
# obj._base_var = base_var
|
97
|
+
return obj
|
98
|
+
|
99
|
+
@staticmethod
|
100
|
+
@cache
|
101
|
+
def __xnew_cached__(_class, k, genset):
|
102
|
+
return PQDSchubPoly.__xnew__(_class, k, genset)
|
103
|
+
|
104
|
+
def _sympystr(self, printer):
|
105
|
+
if self._coeff_var == 0 or self._coeff_var == utils.NoneVar:
|
106
|
+
return printer.doprint(f"QPS{self.genset.label}{(tuple(self.index_comp))}({printer.doprint(self._perm)})")
|
107
|
+
return printer.doprint(f"QPDS{self.genset.label}{tuple(self.index_comp)}({printer.doprint(self._perm)}, {spr._varstr(self._coeff_var)})")
|
108
|
+
|
109
|
+
|
110
|
+
class QuantumDoubleSchubertAlgebraElement_basis(Basic):
|
111
|
+
def __new__(cls, genset):
|
112
|
+
return Basic.__new__(cls, genset)
|
113
|
+
|
114
|
+
def _from_dict(self, _dict):
|
115
|
+
return QuantumDoubleSchubertAlgebraElement(_dict, self)
|
116
|
+
|
117
|
+
@property
|
118
|
+
def genset(self):
|
119
|
+
return self.args[0]
|
120
|
+
|
121
|
+
@cache
|
122
|
+
def cached_product(self, u, v, va, vb):
|
123
|
+
return {(k, va): xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_q_double_pair_generic(u, v).items()}
|
124
|
+
|
125
|
+
def in_quantum_basis(self, elem):
|
126
|
+
return elem
|
127
|
+
|
128
|
+
def in_classical_basis(self, elem):
|
129
|
+
result = S.Zero
|
130
|
+
for k, v in elem.coeff_dict.items():
|
131
|
+
result += v * self.quantum_as_classical_schubpoly(k[0], k[1])
|
132
|
+
return result
|
133
|
+
|
134
|
+
def classical_elem_func(self, coeff_var):
|
135
|
+
basis = spr.DoubleSchubertAlgebraElement_basis(self.genset)
|
136
|
+
q_var = yz._vars.q_var
|
137
|
+
|
138
|
+
def elem_func(p, k, varl1, varl2):
|
139
|
+
if p == 0 and k >= 0:
|
140
|
+
return basis([], coeff_var)
|
141
|
+
if p < 0 or p > k:
|
142
|
+
return basis(0, coeff_var)
|
143
|
+
return (varl1[k - 1] - varl2[k - p]) * elem_func(p - 1, k - 1, varl1, varl2) + elem_func(p, k - 1, varl1, varl2) + q_var[k - 1] * elem_func(p - 2, k - 2, varl1, varl2)
|
144
|
+
|
145
|
+
return elem_func
|
146
|
+
|
147
|
+
@property
|
148
|
+
def single_element_class(self):
|
149
|
+
return QDSchubPoly
|
150
|
+
|
151
|
+
@cache
|
152
|
+
def quantum_as_classical_schubpoly(self, perm, coeff_var="y"):
|
153
|
+
return schubpoly_from_elems(perm, self.genset, utils.poly_ring(coeff_var), self.classical_elem_func(coeff_var))
|
154
|
+
|
155
|
+
@cache
|
156
|
+
def cached_schubpoly(self, k):
|
157
|
+
return schubpoly_from_elems(k[0], self.genset, utils.poly_ring(k[1]), elem_func=elem_sym_poly_q) # yz.schubpoly_quantum(k[0], self.genset, utils.poly_ring(k[1]))
|
158
|
+
|
159
|
+
@cache
|
160
|
+
def cached_positive_product(self, u, v, va, vb):
|
161
|
+
return {(k, va): xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_q_generic_partial_posify(u, v).items()}
|
162
|
+
|
163
|
+
@property
|
164
|
+
def double_mul(self):
|
165
|
+
return yz.schubmult_q_double_fast
|
166
|
+
|
167
|
+
@property
|
168
|
+
def single_mul(self):
|
169
|
+
return py.schubmult_q_fast
|
170
|
+
|
171
|
+
@property
|
172
|
+
def mult_poly_single(self):
|
173
|
+
return py.mult_poly_q
|
174
|
+
|
175
|
+
@property
|
176
|
+
def mult_poly_double(self):
|
177
|
+
return yz.mult_poly_q_double
|
178
|
+
|
179
|
+
def __call__(self, x, cv=None):
|
180
|
+
genset = self.genset
|
181
|
+
# logger.debug(f"{x=} {type(x)=}")
|
182
|
+
if not genset:
|
183
|
+
genset = self.genset
|
184
|
+
if not isinstance(genset, GeneratingSet_base):
|
185
|
+
raise TypeError
|
186
|
+
if isinstance(x, list) or isinstance(x, tuple):
|
187
|
+
if cv is None:
|
188
|
+
cv = "y"
|
189
|
+
elem = self._from_dict({(Permutation(x), cv): 1})
|
190
|
+
elif isinstance(x, Permutation):
|
191
|
+
if cv is None:
|
192
|
+
cv = "y"
|
193
|
+
elem = self._from_dict({(x, cv): 1})
|
194
|
+
# elif isinstance(x, spr.SchubertPolynomial):
|
195
|
+
# if x._parent._base_var == self._base_var:
|
196
|
+
# elem_dict = {(x, utils.NoneVar): v for k, v in x.coeff_dict.items()}
|
197
|
+
# elem = QuantumDoubleSchubertAlgebraElement(elem_dict, self)
|
198
|
+
# if cv is not None:
|
199
|
+
# elem = self([1, 2], cv) * elem
|
200
|
+
# else:
|
201
|
+
# return self(x.expand(), cv)
|
202
|
+
elif isinstance(x, QuantumDoubleSchubertAlgebraElement):
|
203
|
+
if x.is_Add or x.is_Mul:
|
204
|
+
return x
|
205
|
+
if x.genset == genset:
|
206
|
+
elem = QuantumDoubleSchubertAlgebraElement(x.coeff_dict, self) # , self)
|
207
|
+
else:
|
208
|
+
return self(x.expand(), cv, genset)
|
209
|
+
elif isinstance(x, spr.DoubleSchubertAlgebraElement):
|
210
|
+
if x.genset == self.genset:
|
211
|
+
return self(x.expand(), cv, genset)
|
212
|
+
else:
|
213
|
+
logger.debug("bagelflap")
|
214
|
+
x = sympify(x)
|
215
|
+
if cv is None or cv == utils.NoneVar:
|
216
|
+
cv = utils.NoneVar
|
217
|
+
logger.debug(f"{x=} {list(genset)=}")
|
218
|
+
result = py.mult_poly_q({Permutation([]): 1}, x, genset)
|
219
|
+
logger.debug(f"{result=}")
|
220
|
+
else:
|
221
|
+
result = yz.mult_poly_q_double({Permutation([]): 1}, x, genset, utils.poly_ring(cv))
|
222
|
+
elem = QuantumDoubleSchubertAlgebraElement({(k, cv): v for k, v in result.items()}, self)
|
223
|
+
return elem
|
224
|
+
|
225
|
+
|
226
|
+
QDSx = QuantumDoubleSchubertAlgebraElement_basis(GeneratingSet("x"))
|
227
|
+
|
228
|
+
t = GeneratingSet("t")
|
229
|
+
a = GeneratingSet("a")
|
230
|
+
|
231
|
+
spunky_basis = spr.SchubertAlgebraElement_basis(t)
|
232
|
+
|
233
|
+
|
234
|
+
class QuantumSchubertAlgebraElement_basis(QuantumDoubleSchubertAlgebraElement_basis):
|
235
|
+
def __new__(cls, genset):
|
236
|
+
return QuantumDoubleSchubertAlgebraElement_basis.__new__(cls, genset)
|
237
|
+
|
238
|
+
def _from_single_dict(self, _dict):
|
239
|
+
return QuantumDoubleSchubertAlgebraElement({(k, utils.NoneVar): v for k, v in _dict.items()}, self)
|
240
|
+
|
241
|
+
def __call__(self, x):
|
242
|
+
genset = self.genset
|
243
|
+
# logger.debug(f"{x=} {type(x)=}")
|
244
|
+
if not genset:
|
245
|
+
genset = self.genset
|
246
|
+
if not isinstance(genset, GeneratingSet_base):
|
247
|
+
raise TypeError
|
248
|
+
if isinstance(x, list) or isinstance(x, tuple):
|
249
|
+
elem = self._from_single_dict({Permutation(x): 1})
|
250
|
+
elif isinstance(x, Permutation):
|
251
|
+
elem = self._from_single_dict({x: 1})
|
252
|
+
# elif isinstance(x, spr.SchubertPolynomial):
|
253
|
+
# if x._parent._base_var == self._base_var:
|
254
|
+
# elem_dict = {(x, utils.NoneVar): v for k, v in x.coeff_dict.items()}
|
255
|
+
# elem = QuantumDoubleSchubertAlgebraElement(elem_dict, self)
|
256
|
+
# if cv is not None:
|
257
|
+
# elem = self([1, 2], cv) * elem
|
258
|
+
# else:
|
259
|
+
# return self(x.expand(), cv)
|
260
|
+
elif isinstance(x, QuantumDoubleSchubertAlgebraElement):
|
261
|
+
if x.is_Add or x.is_Mul:
|
262
|
+
return x
|
263
|
+
if x.genset == genset:
|
264
|
+
elem = QuantumDoubleSchubertAlgebraElement(x.coeff_dict, self) # , self)
|
265
|
+
else:
|
266
|
+
return self(x.expand())
|
267
|
+
elif isinstance(x, spr.DoubleSchubertAlgebraElement):
|
268
|
+
if x.genset == self.genset:
|
269
|
+
return x.as_quantum()
|
270
|
+
elif isinstance(x, ParabolicQuantumDoubleSchubertAlgebraElement):
|
271
|
+
return x.as_quantum()
|
272
|
+
else:
|
273
|
+
x = sympify(x)
|
274
|
+
result = py.mult_poly_q({Permutation([]): 1}, x, genset)
|
275
|
+
elem = self._from_single_dict(result)
|
276
|
+
return elem
|
277
|
+
|
278
|
+
|
279
|
+
class ParabolicQuantumDoubleSchubertAlgebraElement_basis(Basic):
|
280
|
+
def __new__(cls, genset, index_comp):
|
281
|
+
obj = Basic.__new__(cls, genset, tuple(index_comp))
|
282
|
+
obj._quantum_basis = QuantumDoubleSchubertAlgebraElement_basis(genset)
|
283
|
+
obj._classical_basis = spr.DoubleSchubertAlgebraElement_basis(genset)
|
284
|
+
obj._n = list(index_comp)
|
285
|
+
obj._N = [sum(obj._n[:i]) for i in range(len(obj._n) + 1)]
|
286
|
+
# print(f"{obj._N=}")
|
287
|
+
# obj._D = []
|
288
|
+
# obj._E = {}
|
289
|
+
# from symengine import Matrix
|
290
|
+
# for j in range(1, len(obj._N)):
|
291
|
+
# m_arr = [[0 for i in range(obj._N[j])] for p in range(obj._N[j])]
|
292
|
+
# for i in range(obj._N[j]):
|
293
|
+
# m_arr[i][i] = a[i+1] - t[1] #genset[i+1] - t[1]
|
294
|
+
# if i < obj._N[j] - 1:
|
295
|
+
# m_arr[i][i+1] = -1
|
296
|
+
# for b in range(1, j):
|
297
|
+
# njm1 = obj._N[b + 1] - 1
|
298
|
+
# njp1 = obj._N[b - 1]
|
299
|
+
# # print(f"{b=}")
|
300
|
+
# # print(f"{njm1=} {njp1=}")
|
301
|
+
# if njp1 < obj._N[j] and njm1 < obj._N[j]:
|
302
|
+
# # print(f"{b=} {obj._n[b]=}")
|
303
|
+
# m_arr[njm1][njp1] = -(-1)**(obj._n[b])*q_var[b]
|
304
|
+
# # print(Matrix(m_arr))
|
305
|
+
# poly = Matrix(m_arr).det().simplify()
|
306
|
+
# # print(f"{poly=}")
|
307
|
+
# # def dongle(v):
|
308
|
+
# # return poly.subs(t[1], v)
|
309
|
+
# obj._D += [spunky_basis(poly)]
|
310
|
+
# obj._E[obj._N[j]] = {obj._N[j]: obj._D[-1]}
|
311
|
+
# for i in range(1,obj._N[j]):
|
312
|
+
# obj._E[obj._N[j]][obj._N[j] - i] = -obj._E[obj._N[j]][obj._N[j] - i + 1].divdiff(i)
|
313
|
+
# # print(obj._E)
|
314
|
+
# add_am = 6
|
315
|
+
# index_comp += [add_am]
|
316
|
+
# obj._N += [obj._N[-1] + add_am]
|
317
|
+
parabolic_index = []
|
318
|
+
start = 0
|
319
|
+
# 1, 2 | 3
|
320
|
+
for i in range(len(index_comp)):
|
321
|
+
end = start + index_comp[i]
|
322
|
+
parabolic_index += list(range(start + 1, end))
|
323
|
+
# start += int(args.parabolic[i])
|
324
|
+
start = end
|
325
|
+
obj._parabolic_index = parabolic_index
|
326
|
+
obj._otherlong = Permutation(list(range(obj._N[-1], 0, -1)))
|
327
|
+
obj._longest = obj._otherlong * longest_element(parabolic_index)
|
328
|
+
# obj._E[0] = obj._from_dict({(Permutation([]),utils.NoneVar): S.One})
|
329
|
+
return obj
|
330
|
+
|
331
|
+
@property
|
332
|
+
def parabolic_index(self):
|
333
|
+
return self._parabolic_index
|
334
|
+
|
335
|
+
@property
|
336
|
+
def quantum_basis(self):
|
337
|
+
return self._quantum_basis
|
338
|
+
|
339
|
+
@property
|
340
|
+
def classical_basis(self):
|
341
|
+
return self._classical_basis
|
342
|
+
|
343
|
+
# def elem_sym_poly(self, p, k, varl1, varl2, xstart=0, ystart=0):
|
344
|
+
# # print(f"{p=} {k=} {xstart=} {ystart=} {len(varl1)=} {len(varl2)=}")
|
345
|
+
# if p > k:
|
346
|
+
# return zero
|
347
|
+
# if p == 0:
|
348
|
+
# return one
|
349
|
+
# if p == 1:
|
350
|
+
# res = varl1[xstart] - varl2[ystart]
|
351
|
+
# for i in range(1, k):
|
352
|
+
# res += varl1[xstart + i] - varl2[ystart + i]
|
353
|
+
# return res
|
354
|
+
# if p == k:
|
355
|
+
# res = (varl1[xstart] - varl2[ystart]) * (varl1[xstart + 1] - varl2[ystart])
|
356
|
+
# for i in range(2, k):
|
357
|
+
# res *= varl1[i + xstart] - varl2[ystart]
|
358
|
+
# return res
|
359
|
+
# mid = k // 2
|
360
|
+
# xsm = xstart + mid
|
361
|
+
# ysm = ystart + mid
|
362
|
+
# kmm = k - mid
|
363
|
+
# res = elem_sym_poly(p, mid, varl1, varl2, xstart, ystart) + elem_sym_poly(
|
364
|
+
# p,
|
365
|
+
# kmm,
|
366
|
+
# varl1,
|
367
|
+
# varl2,
|
368
|
+
# xsm,
|
369
|
+
# ysm,
|
370
|
+
# )
|
371
|
+
# for p2 in range(max(1, p - kmm), min(p, mid + 1)):
|
372
|
+
# res += elem_sym_poly(p2, mid, varl1, varl2, xstart, ystart) * elem_sym_poly(
|
373
|
+
# p - p2,
|
374
|
+
# kmm,
|
375
|
+
# varl1,
|
376
|
+
# varl2,
|
377
|
+
# xsm,
|
378
|
+
# ysm - p2,
|
379
|
+
# )
|
380
|
+
# return res
|
381
|
+
|
382
|
+
def elem_sym(self):
|
383
|
+
def elem_func(p, k, varl1, varl2):
|
384
|
+
# print(f"{p=} {k=} {self._N=}")
|
385
|
+
if p < 0 or p > k:
|
386
|
+
return 0
|
387
|
+
if p == 0 and k >= 0:
|
388
|
+
return 1
|
389
|
+
if k <= self._N[1]:
|
390
|
+
return elem_sym_poly(p, k, varl1, varl2)
|
391
|
+
ret = 0
|
392
|
+
j = bisect_left(self._N, k)
|
393
|
+
if j < len(self._N) and k == self._N[j]:
|
394
|
+
ret = (-((-1) ** (self._n[j - 1]))) * q_var[j - 1] * elem_func(p - self._N[j] + self._N[j - 2], self._N[j - 2], varl1, varl2)
|
395
|
+
ret += elem_func(p, k - 1, varl1, varl2) + (varl1[k - 1] - varl2[k - p]) * elem_func(p - 1, k - 1, varl1, varl2)
|
396
|
+
return ret
|
397
|
+
|
398
|
+
return elem_func
|
399
|
+
|
400
|
+
def boingle_elem_sym(self):
|
401
|
+
def elem_func(p, k, varl1, varl2):
|
402
|
+
if p == 0 and k >= 0:
|
403
|
+
return S.One
|
404
|
+
if p < 0 or p > k:
|
405
|
+
return S.Zero
|
406
|
+
# print(f"{p=} {k=}")
|
407
|
+
spoink = self._E[k][p]
|
408
|
+
# print(f"{spoink=}")
|
409
|
+
# for i in range(1,k - p + 1):
|
410
|
+
# spoink = -spoink.divdiff(i)
|
411
|
+
return sympify(sympify(spoink.as_polynomial()).xreplace({t[i]: varl2[i - 1] for i in range(1, len(varl2) + 1)})).xreplace({a[i]: varl1[i - 1] for i in range(1, len(varl1) + 1)})
|
412
|
+
# TEMP
|
413
|
+
# varl2 = utils.poly_ring(0)
|
414
|
+
# if p < 0 or p > k:
|
415
|
+
# return 0
|
416
|
+
# if p == 0 and k >= 0:
|
417
|
+
# return 1
|
418
|
+
# if k == self._N[1]:
|
419
|
+
# return elem_sym_poly(p, k, varl1, varl2)
|
420
|
+
# print(f"{p=} {k=} {self._N=}")
|
421
|
+
# ret = 0
|
422
|
+
# j = bisect_left(self._N, k)
|
423
|
+
# if j < len(self._N) and k == self._N[j]:
|
424
|
+
# ret = (-((-1) ** (self._n[j - 1]))) * q_var[j - 1] * elem_func(p - self._N[j] + self._N[j - 2], self._N[j - 2], varl1, varl2)
|
425
|
+
# #ret += elem_func(p, self._N[j-1], varl1, varl2)
|
426
|
+
# # print(f"{self._n[j-1]=}")
|
427
|
+
# for i in range(min(p+1,self._n[j-1]+1)):
|
428
|
+
# # print(f"{p=} {p - i=} {i=} {self._N[j-1]-1=} {self._N[j-1]-1-i=} {len(varl2)=}")
|
429
|
+
# ret += varl1[self._N[j] - 1 - i] * elem_func(p - i, self._N[j-1], varl1, varl2)
|
430
|
+
# else:
|
431
|
+
# # print("Bob jones")
|
432
|
+
# return ret
|
433
|
+
|
434
|
+
return elem_func
|
435
|
+
|
436
|
+
# def classical_elem(self, k, coeff_var):
|
437
|
+
# if k <= self._N[1]:
|
438
|
+
# return self(uncode([1 for i in range(k)]), coeff_var)
|
439
|
+
|
440
|
+
def _from_dict(self, _dict):
|
441
|
+
return ParabolicQuantumDoubleSchubertAlgebraElement(_dict, self)
|
442
|
+
|
443
|
+
@property
|
444
|
+
def genset(self):
|
445
|
+
return self.args[0]
|
446
|
+
|
447
|
+
@property
|
448
|
+
def index_comp(self):
|
449
|
+
return self.args[1]
|
450
|
+
|
451
|
+
def process_coeff_dict(self, coeff_dict):
|
452
|
+
max_len = max(len(w) for w in coeff_dict)
|
453
|
+
parabolic_index = [*self._parabolic_index]
|
454
|
+
# parabolic_index += list(range(parabolic_index[-1] + 2, max_len + 1))
|
455
|
+
if max_len > len(self._longest):
|
456
|
+
parabolic_index = []
|
457
|
+
start = 0
|
458
|
+
# 1, 2 | 3
|
459
|
+
index_comp = [*self._n, max_len + 1 - self._N[-1]]
|
460
|
+
for i in range(len(index_comp)):
|
461
|
+
end = start + index_comp[i]
|
462
|
+
parabolic_index += list(range(start + 1, end))
|
463
|
+
# start += int(args.parabolic[i])
|
464
|
+
start = end
|
465
|
+
return yz.apply_peterson_woodward(coeff_dict, parabolic_index)
|
466
|
+
|
467
|
+
@cache
|
468
|
+
def cached_product(self, u, v, va, vb):
|
469
|
+
initial_dict = {k: xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_q_double_pair_generic(u, v).items()}
|
470
|
+
return {(k, va): v for k, v in self.process_coeff_dict(initial_dict).items()}
|
471
|
+
|
472
|
+
def in_quantum_basis(self, elem):
|
473
|
+
result = S.Zero
|
474
|
+
for k, v in elem.coeff_dict.items():
|
475
|
+
result += v * schubpoly_from_elems(k[0], self.genset, utils.poly_ring(k[1]), self.quantum_elem_func(k[1]))
|
476
|
+
# print(f"{result=}")
|
477
|
+
return result
|
478
|
+
|
479
|
+
def in_classical_basis(self, elem):
|
480
|
+
result = S.Zero
|
481
|
+
for k, v in elem.coeff_dict.items():
|
482
|
+
result += v * self.quantum_as_classical_schubpoly(k[0], k[1])
|
483
|
+
# print(f"{result=}")
|
484
|
+
return result
|
485
|
+
|
486
|
+
@cache
|
487
|
+
def classical_in_basis(self, k):
|
488
|
+
from symengine import expand
|
489
|
+
|
490
|
+
a = self.classical_basis(*k)
|
491
|
+
b = self(*k)
|
492
|
+
if expand(a.as_polynomial() - b.as_polynomial()) == S.Zero:
|
493
|
+
return b
|
494
|
+
cd = dict(b.as_classical().coeff_dict)
|
495
|
+
for k2, v in cd.items():
|
496
|
+
if k != k2:
|
497
|
+
b -= v * self.classical_in_basis(k2)
|
498
|
+
return b
|
499
|
+
|
500
|
+
def classical_elem_func(self, coeff_var):
|
501
|
+
basis = spr.DoubleSchubertAlgebraElement_basis(self.genset)
|
502
|
+
q_var = yz._vars.q_var
|
503
|
+
|
504
|
+
def elem_func(p, k, varl1, varl2):
|
505
|
+
# print(f"{p=} {k=} {varl1=} {varl2=}")
|
506
|
+
if p == 0 and k >= 0:
|
507
|
+
return basis([], coeff_var)
|
508
|
+
if p < 0 or p > k:
|
509
|
+
return basis(0, coeff_var)
|
510
|
+
if k <= self._N[1]:
|
511
|
+
return basis(elem_sym_poly(p, k, varl1, varl2), coeff_var)
|
512
|
+
ret = basis(0, coeff_var)
|
513
|
+
j = bisect_left(self._N, k)
|
514
|
+
if j < len(self._N) and k == self._N[j]:
|
515
|
+
ret = (-((-1) ** (self._n[j - 1]))) * q_var[j - 1] * elem_func(p - self._N[j] + self._N[j - 2], self._N[j - 2], varl1, varl2)
|
516
|
+
ret += elem_func(p, k - 1, varl1, varl2) + (varl1[k - 1] - varl2[k - p]) * elem_func(p - 1, k - 1, varl1, varl2)
|
517
|
+
# print(f"{ret=}")
|
518
|
+
return ret
|
519
|
+
|
520
|
+
return elem_func
|
521
|
+
|
522
|
+
def quantum_elem_func(self, coeff_var):
|
523
|
+
basis = QuantumDoubleSchubertAlgebraElement_basis(self.genset)
|
524
|
+
q_var = yz._vars.q_var
|
525
|
+
|
526
|
+
def elem_func(p, k, varl1, varl2):
|
527
|
+
# print(f"{p=} {k=} {varl1=} {varl2=}")
|
528
|
+
if p == 0 and k >= 0:
|
529
|
+
return basis([], coeff_var)
|
530
|
+
if p < 0 or p > k:
|
531
|
+
return basis(0, coeff_var)
|
532
|
+
if k <= self._N[1]:
|
533
|
+
return basis(elem_sym_poly(p, k, varl1, varl2), coeff_var)
|
534
|
+
ret = basis(0, coeff_var)
|
535
|
+
j = bisect_left(self._N, k)
|
536
|
+
if j < len(self._N) and k == self._N[j]:
|
537
|
+
ret = (-((-1) ** (self._n[j - 1]))) * q_var[j - 1] * elem_func(p - self._N[j] + self._N[j - 2], self._N[j - 2], varl1, varl2)
|
538
|
+
ret += elem_func(p, k - 1, varl1, varl2) + (varl1[k - 1] - varl2[k - p]) * elem_func(p - 1, k - 1, varl1, varl2)
|
539
|
+
# print(f"{ret=}")
|
540
|
+
return ret
|
541
|
+
|
542
|
+
return elem_func
|
543
|
+
|
544
|
+
@property
|
545
|
+
def single_element_class(self):
|
546
|
+
return PQDSchubPoly
|
547
|
+
|
548
|
+
@cache
|
549
|
+
def quantum_as_classical_schubpoly(self, perm, coeff_var="y"):
|
550
|
+
k = (perm, coeff_var)
|
551
|
+
# print(f"{k=}")
|
552
|
+
if len(k[0]) > len(self._longest):
|
553
|
+
parabolic_index = []
|
554
|
+
start = 0
|
555
|
+
# 1, 2 | 3
|
556
|
+
index_comp = [*self._n, len(k[0]) + 1 - self._N[-1]]
|
557
|
+
for i in range(len(index_comp)):
|
558
|
+
end = start + index_comp[i]
|
559
|
+
parabolic_index += list(range(start + 1, end))
|
560
|
+
# start += int(args.parabolic[i])
|
561
|
+
start = end
|
562
|
+
otherlong = Permutation(list(range(parabolic_index[-1] + 1, 0, -1)))
|
563
|
+
longpar = Permutation(longest_element(parabolic_index))
|
564
|
+
# print(f"{longpar=} {parabolic_index=}")
|
565
|
+
longest = otherlong * longpar
|
566
|
+
# print(f"new longest = {longest=}")
|
567
|
+
else:
|
568
|
+
longest = self._longest
|
569
|
+
return schubpoly_from_elems(perm, self.genset, utils.poly_ring(coeff_var), elem_func=self.classical_elem_func(coeff_var), mumu=~longest)
|
570
|
+
|
571
|
+
@cache
|
572
|
+
def cached_schubpoly(self, k):
|
573
|
+
if len(k[0]) > len(self._longest):
|
574
|
+
parabolic_index = []
|
575
|
+
start = 0
|
576
|
+
# 1, 2 | 3
|
577
|
+
index_comp = [*self._n, len(k[0]) + 1 - self._N[-1]]
|
578
|
+
for i in range(len(index_comp)):
|
579
|
+
end = start + index_comp[i]
|
580
|
+
parabolic_index += list(range(start + 1, end))
|
581
|
+
# start += int(args.parabolic[i])
|
582
|
+
start = end
|
583
|
+
otherlong = Permutation(list(range(parabolic_index[-1] + 1, 0, -1)))
|
584
|
+
longpar = Permutation(longest_element(parabolic_index))
|
585
|
+
# print(f"{longpar=} {parabolic_index=}")
|
586
|
+
longest = otherlong * longpar
|
587
|
+
# print(f"new longest = {longest=}")
|
588
|
+
else:
|
589
|
+
longest = self._longest
|
590
|
+
return schubpoly_from_elems(k[0], self.genset, utils.poly_ring(k[1]), elem_func=self.elem_sym(), mumu=~longest) # yz.schubpoly_quantum(k[0], self.genset, utils.poly_ring(k[1]))
|
591
|
+
|
592
|
+
@cache
|
593
|
+
def cached_positive_product(self, u, v, va, vb):
|
594
|
+
initial_dict = {k: xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_q_generic_partial_posify(u, v).items()}
|
595
|
+
return {(k, va): v for k, v in self.process_coeff_dict(initial_dict).items()}
|
596
|
+
|
597
|
+
@property
|
598
|
+
def double_mul(self):
|
599
|
+
return yz.schubmult_q_double_fast
|
600
|
+
|
601
|
+
@property
|
602
|
+
def single_mul(self):
|
603
|
+
return py.schubmult_q_fast
|
604
|
+
|
605
|
+
@property
|
606
|
+
def mult_poly_single(self):
|
607
|
+
return py.mult_poly_q
|
608
|
+
|
609
|
+
@property
|
610
|
+
def mult_poly_double(self):
|
611
|
+
return yz.mult_poly_q_double
|
612
|
+
|
613
|
+
def __call__(self, x, cv=None):
|
614
|
+
genset = self.genset
|
615
|
+
# logger.debug(f"{x=} {type(x)=}")
|
616
|
+
if not genset:
|
617
|
+
genset = self.genset
|
618
|
+
if not isinstance(genset, GeneratingSet_base):
|
619
|
+
raise TypeError
|
620
|
+
if isinstance(x, list) or isinstance(x, tuple):
|
621
|
+
if cv is None:
|
622
|
+
cv = "y"
|
623
|
+
perm = Permutation(x)
|
624
|
+
if not is_parabolic(perm, self.parabolic_index):
|
625
|
+
raise ValueError(f"Permutation must be parabolic: {perm} is not")
|
626
|
+
elem = self._from_dict({(perm, cv): 1})
|
627
|
+
elif isinstance(x, Permutation):
|
628
|
+
if cv is None:
|
629
|
+
cv = "y"
|
630
|
+
if not is_parabolic(x, self.parabolic_index):
|
631
|
+
raise ValueError(f"Permutation must be parabolic: {x} is not")
|
632
|
+
elem = self._from_dict({(x, cv): 1})
|
633
|
+
elif isinstance(x, ParabolicQuantumDoubleSchubertAlgebraElement):
|
634
|
+
return x
|
635
|
+
else:
|
636
|
+
dct = self.classical_basis(x, cv)
|
637
|
+
elem = 0
|
638
|
+
if not isinstance(dct, spr.BasisSchubertAlgebraElement):
|
639
|
+
return dct
|
640
|
+
try:
|
641
|
+
for k, v in dct.coeff_dict.items():
|
642
|
+
if elem == 0:
|
643
|
+
elem = v * self.classical_in_basis(k)
|
644
|
+
else:
|
645
|
+
elem += v * self.classical_in_basis(k)
|
646
|
+
except ValueError:
|
647
|
+
raise ValueError(f"Could not convert {x=} to quantum parabolic")
|
648
|
+
return elem
|
649
|
+
|
650
|
+
|
651
|
+
QSx = QuantumSchubertAlgebraElement_basis(GeneratingSet("x"))
|
652
|
+
|
653
|
+
QuantumDoubleSchubertPolynomial = QuantumDoubleSchubertAlgebraElement
|
654
|
+
|
655
|
+
|
656
|
+
def make_parabolic_quantum_basis(index_comp):
|
657
|
+
return ParabolicQuantumDoubleSchubertAlgebraElement_basis(GeneratingSet("x"), index_comp)
|
658
|
+
|
659
|
+
|
660
|
+
@cache
|
661
|
+
def QPDSx(*args):
|
662
|
+
return make_parabolic_quantum_basis(args)
|
663
|
+
|
664
|
+
|
665
|
+
# is_Add = True
|
666
|
+
# is_Mul = True
|
667
|
+
# is_Add
|
668
|
+
# is_AlgebraicNumber
|
669
|
+
# is_Atom
|
670
|
+
# is_Boolean
|
671
|
+
# is_Derivative
|
672
|
+
# is_Dummy
|
673
|
+
# is_Equality
|
674
|
+
# is_Float
|
675
|
+
# is_Function
|
676
|
+
# is_Indexed
|
677
|
+
# is_Integer
|
678
|
+
# is_MatAdd
|
679
|
+
# is_MatMul
|
680
|
+
# is_Matrix
|
681
|
+
# is_Mul
|
682
|
+
# is_Not
|
683
|
+
# is_Number
|
684
|
+
# is_NumberSymbol
|
685
|
+
# is_Order
|
686
|
+
# is_Piecewise
|
687
|
+
# is_Point
|
688
|
+
# is_Poly
|
689
|
+
# is_Pow
|
690
|
+
# is_Rational
|
691
|
+
# is_Relational
|
692
|
+
# is_Symbol
|
693
|
+
# is_Vector
|
694
|
+
# is_Wild
|
695
|
+
# is_algebraic
|
696
|
+
# is_algebraic_expr
|
697
|
+
# is_antihermitian
|
698
|
+
# is_commutative
|
699
|
+
# is_comparable
|
700
|
+
# is_complex
|
701
|
+
# is_composite
|
702
|
+
# is_constant
|
703
|
+
# is_even
|
704
|
+
# is_extended_negative
|
705
|
+
# is_extended_nonnegative
|
706
|
+
# is_extended_nonpositive
|
707
|
+
# is_extended_nonzero
|
708
|
+
# is_extended_positive
|
709
|
+
# is_extended_real
|
710
|
+
# is_finite
|
711
|
+
# is_hermitian
|
712
|
+
# is_hypergeometric
|
713
|
+
# is_imaginary
|
714
|
+
# is_infinite
|
715
|
+
# is_integer
|
716
|
+
# is_irrational
|
717
|
+
# is_meromorphic
|
718
|
+
# is_negative
|
719
|
+
# is_noninteger
|
720
|
+
# is_nonnegative
|
721
|
+
# is_nonpositive
|
722
|
+
# is_nonzero
|
723
|
+
# is_number
|
724
|
+
# is_odd
|
725
|
+
# is_polar
|
726
|
+
# is_polynomial
|
727
|
+
# is_positive
|
728
|
+
# is_prime
|
729
|
+
# is_rational
|
730
|
+
# is_rational_function
|
731
|
+
# is_real
|
732
|
+
# is_scalar
|
733
|
+
# is_symbol
|
734
|
+
# is_transcendental
|
735
|
+
# is_zero
|
736
|
+
# is_polynomial = True
|
737
|
+
# is_Symbol = True
|
738
|
+
|
739
|
+
|
740
|
+
# class SchubAdd(QuantumDoubleSchubertAlgebraElement, Add):
|
741
|
+
# is_Add = True
|
742
|
+
|
743
|
+
# def __new__(cls, *args, evaluate=True, _sympify=True):
|
744
|
+
# obj = Add.__new__(cls, *args, evaluate=evaluate, _sympify=_sympify)
|
745
|
+
# if evaluate:
|
746
|
+
# return obj.doit()
|
747
|
+
# return obj
|
748
|
+
|
749
|
+
# def doit(self):
|
750
|
+
# ret = self.args[0]
|
751
|
+
# for arg in self.args[1:]:
|
752
|
+
# if arg.is_Add or arg.is_Mul:
|
753
|
+
# arg = arg.doit()
|
754
|
+
# ret = _do_schub_add(ret, arg)
|
755
|
+
# return ret
|
756
|
+
|
757
|
+
# # def _sympystr(self, printer):
|
758
|
+
# # return _def_printer._print(f"SchubAdd({self.args}")
|
759
|
+
|
760
|
+
|
761
|
+
# class SchubMul(QuantumDoubleSchubertAlgebraElement, Mul):
|
762
|
+
# is_Mul = True
|
763
|
+
|
764
|
+
# def __new__(cls, *args, evaluate=True, _sympify=True):
|
765
|
+
# if len(args) == 0:
|
766
|
+
# return 1
|
767
|
+
# # args, a, b = Mul.flatten(list(args))
|
768
|
+
# # if len(args) == 0:
|
769
|
+
# # return 1
|
770
|
+
# obj = Mul.__new__(cls, *args, evaluate=evaluate, _sympify=_sympify)
|
771
|
+
|
772
|
+
# if evaluate:
|
773
|
+
# return obj.doit()
|
774
|
+
# return obj
|
775
|
+
|
776
|
+
# def doit(self):
|
777
|
+
# ret = self.args[0]
|
778
|
+
# for arg in self.args[1:]:
|
779
|
+
# if arg.is_Add or arg.is_Mul:
|
780
|
+
# arg = arg.doit()
|
781
|
+
# ret = _do_schub_mul(ret, arg)
|
782
|
+
# return ret
|
783
|
+
|
784
|
+
|
785
|
+
# Basic._constructor_postprocessor_mapping[DoubleSchubertAlgebraElement] = {
|
786
|
+
# "Mul": [get_postprocessor(Mul)],
|
787
|
+
# "Add": [get_postprocessor(Add)],
|
788
|
+
# }
|