schubmult 2.0.4__py3-none-any.whl → 3.0.1__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.
Files changed (58) hide show
  1. schubmult/__init__.py +96 -1
  2. schubmult/perm_lib.py +254 -819
  3. schubmult/poly_lib/__init__.py +31 -0
  4. schubmult/poly_lib/poly_lib.py +276 -0
  5. schubmult/poly_lib/schub_poly.py +148 -0
  6. schubmult/poly_lib/variables.py +204 -0
  7. schubmult/rings/__init__.py +18 -0
  8. schubmult/rings/_quantum_schubert_polynomial_ring.py +752 -0
  9. schubmult/rings/_schubert_polynomial_ring.py +1031 -0
  10. schubmult/rings/_tensor_schub_ring.py +128 -0
  11. schubmult/rings/_utils.py +55 -0
  12. schubmult/{sage_integration → sage}/__init__.py +4 -1
  13. schubmult/{sage_integration → sage}/_fast_double_schubert_polynomial_ring.py +67 -109
  14. schubmult/{sage_integration → sage}/_fast_schubert_polynomial_ring.py +33 -28
  15. schubmult/{sage_integration → sage}/_indexing.py +9 -5
  16. schubmult/schub_lib/__init__.py +51 -0
  17. schubmult/{schubmult_double/_funcs.py → schub_lib/double.py} +532 -596
  18. schubmult/{schubmult_q/_funcs.py → schub_lib/quantum.py} +54 -53
  19. schubmult/schub_lib/quantum_double.py +954 -0
  20. schubmult/schub_lib/schub_lib.py +659 -0
  21. schubmult/{schubmult_py/_funcs.py → schub_lib/single.py} +45 -35
  22. schubmult/schub_lib/tests/__init__.py +0 -0
  23. schubmult/schub_lib/tests/legacy_perm_lib.py +946 -0
  24. schubmult/schub_lib/tests/test_vs_old.py +109 -0
  25. schubmult/scripts/__init__.py +0 -0
  26. schubmult/scripts/schubmult_double.py +378 -0
  27. schubmult/scripts/schubmult_py.py +84 -0
  28. schubmult/scripts/schubmult_q.py +109 -0
  29. schubmult/scripts/schubmult_q_double.py +207 -0
  30. schubmult/utils/__init__.py +0 -0
  31. schubmult/{_base_argparse.py → utils/argparse.py} +29 -5
  32. schubmult/utils/logging.py +16 -0
  33. schubmult/utils/parsing.py +20 -0
  34. schubmult/utils/perm_utils.py +135 -0
  35. schubmult/utils/test_utils.py +65 -0
  36. schubmult-3.0.1.dist-info/METADATA +1234 -0
  37. schubmult-3.0.1.dist-info/RECORD +41 -0
  38. {schubmult-2.0.4.dist-info → schubmult-3.0.1.dist-info}/WHEEL +1 -1
  39. schubmult-3.0.1.dist-info/entry_points.txt +5 -0
  40. schubmult/_tests.py +0 -24
  41. schubmult/schubmult_double/__init__.py +0 -12
  42. schubmult/schubmult_double/__main__.py +0 -6
  43. schubmult/schubmult_double/_script.py +0 -474
  44. schubmult/schubmult_py/__init__.py +0 -12
  45. schubmult/schubmult_py/__main__.py +0 -6
  46. schubmult/schubmult_py/_script.py +0 -97
  47. schubmult/schubmult_q/__init__.py +0 -8
  48. schubmult/schubmult_q/__main__.py +0 -6
  49. schubmult/schubmult_q/_script.py +0 -166
  50. schubmult/schubmult_q_double/__init__.py +0 -10
  51. schubmult/schubmult_q_double/__main__.py +0 -6
  52. schubmult/schubmult_q_double/_funcs.py +0 -540
  53. schubmult/schubmult_q_double/_script.py +0 -396
  54. schubmult-2.0.4.dist-info/METADATA +0 -542
  55. schubmult-2.0.4.dist-info/RECORD +0 -30
  56. schubmult-2.0.4.dist-info/entry_points.txt +0 -5
  57. {schubmult-2.0.4.dist-info → schubmult-3.0.1.dist-info}/licenses/LICENSE +0 -0
  58. {schubmult-2.0.4.dist-info → schubmult-3.0.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,1031 @@
1
+ import multiprocessing
2
+ from functools import cache, cached_property
3
+
4
+ import sympy
5
+ from symengine import Add, S, Symbol, expand, sympify
6
+ from sympy import Basic
7
+ from sympy.core.expr import Expr
8
+ from sympy.core.kind import NumberKind
9
+ from sympy.printing.str import StrPrinter
10
+
11
+ import schubmult.rings._quantum_schubert_polynomial_ring as qsr
12
+ import schubmult.rings._tensor_schub_ring as tsr
13
+ import schubmult.rings._utils as utils
14
+ import schubmult.schub_lib.double as yz
15
+
16
+ # from schubmult.poly_lib.schub_poly import pull_out_var
17
+ import schubmult.schub_lib.schub_lib as schub_lib
18
+ import schubmult.schub_lib.single as py
19
+ from schubmult.perm_lib import Permutation, inv
20
+ from schubmult.poly_lib.poly_lib import complete_sym_poly, elem_sym_poly, xreplace_genvars
21
+ from schubmult.poly_lib.schub_poly import schubpoly_classical_from_elems, schubpoly_from_elems
22
+ from schubmult.poly_lib.variables import CustomGeneratingSet, GeneratingSet, GeneratingSet_base, MaskedGeneratingSet
23
+ from schubmult.utils.logging import get_logger
24
+ from schubmult.utils.perm_utils import add_perm_dict
25
+
26
+ ## EMULATE POLYTOOLS
27
+
28
+ _def_printer = StrPrinter({"order": "none"})
29
+ # _def_printer = StrPrinter()
30
+
31
+ logger = get_logger(__name__)
32
+
33
+ # numpy arrays
34
+ # sympy parsing
35
+ # quantum
36
+
37
+ # COPRODUCT
38
+
39
+
40
+ class NotEnoughGeneratorsError(ValueError):
41
+ pass
42
+
43
+
44
+ def _varstr(v):
45
+ if v == utils.NoneVar:
46
+ return "NoneVar"
47
+ if v == utils.ZeroVar:
48
+ return "0"
49
+ return f"'{v}'"
50
+
51
+
52
+ def domul(t1, dict2):
53
+ _vstr, kd, vd, basis, best_effort_positive = t1
54
+ this_dict = {}
55
+ for k, v in dict2:
56
+ did_positive = False
57
+ to_mul = v * vd
58
+ if best_effort_positive:
59
+ try:
60
+ # logger.critical(f"{to_mul=} {kd=} {k=}")
61
+ this_dict = add_perm_dict(this_dict, {k1: v1 * to_mul for k1, v1 in basis.cached_positive_product(kd, k[0], _vstr, k[1]).items()})
62
+ did_positive = True
63
+ except Exception:
64
+ # logger.debug("Failed to compute")
65
+ did_positive = False
66
+ if not did_positive:
67
+ this_dict = add_perm_dict(this_dict, {k1: v1 * to_mul for k1, v1 in basis.cached_product(kd, k[0], _vstr, k[1]).items()})
68
+ return this_dict
69
+
70
+
71
+ def _mul_schub_dicts(dict1, dict2, basis, best_effort_positive=True):
72
+ by_var = {}
73
+
74
+ none_dict = {}
75
+ for k, v in dict1.items():
76
+ if k[1] == utils.NoneVar: # or k[1] == utils.ZeroVar:
77
+ none_dict[k[0]] = v
78
+ else:
79
+ if k[1] not in by_var:
80
+ by_var[k[1]] = {}
81
+ by_var[k[1]][k[0]] = v
82
+
83
+ results = {}
84
+ # import sys
85
+
86
+ for _vstr, _dict in by_var.items():
87
+ if BasisSchubertAlgebraElement.do_parallel:
88
+ result_list = []
89
+ mul_funcs = [(_vstr, kd, vd, basis, best_effort_positive) for kd, vd in _dict.items()]
90
+ itemlist = list(dict2.items())
91
+
92
+ def add_result(result):
93
+ result_list.append(result)
94
+
95
+ with multiprocessing.Pool(processes=6) as pool:
96
+ for mulf in mul_funcs:
97
+ pool.apply_async(domul, args=(mulf, itemlist), callback=add_result)
98
+ pool.close()
99
+ pool.join()
100
+ for res in result_list:
101
+ results = add_perm_dict(results, res)
102
+ else:
103
+ this_dict = {}
104
+ for k, v in dict2.items():
105
+ for kd, vd in _dict.items():
106
+ did_positive = False
107
+ to_mul = v * vd
108
+ if best_effort_positive:
109
+ try:
110
+ # logger.critical(f"{to_mul=} {kd=} {k=}")
111
+ this_dict = add_perm_dict(this_dict, {k1: v1 * to_mul for k1, v1 in basis.cached_positive_product(kd, k[0], _vstr, k[1]).items()})
112
+ did_positive = True
113
+ except Exception:
114
+ # logger.debug("Failed to compute")
115
+ did_positive = False
116
+ if not did_positive:
117
+ this_dict = add_perm_dict(this_dict, {k1: v1 * to_mul for k1, v1 in basis.cached_product(kd, k[0], _vstr, k[1]).items()})
118
+ results = add_perm_dict(results, this_dict)
119
+
120
+ by_var2 = {}
121
+ none_dict2 = {}
122
+ for k, v in dict2.items():
123
+ if k[1] == utils.NoneVar: # or k[1] == utils.ZeroVar:
124
+ none_dict2[k[0]] = v
125
+ else:
126
+ if k[1] not in by_var2:
127
+ by_var2[k[1]] = {}
128
+ by_var2[k[1]][k[0]] = v
129
+
130
+ for _vstr, _dict in by_var2.items():
131
+ this_dict = {}
132
+ for k, v in none_dict.items():
133
+ if not best_effort_positive:
134
+ this_dict = add_perm_dict(this_dict, {(k1, _vstr): v1 * v for k1, v1 in basis.double_mul(_dict, k, utils.poly_ring(_vstr), utils.poly_ring(utils.NoneVar)).items()})
135
+ else:
136
+ this_dict = add_perm_dict(this_dict, {(k1, _vstr): expand(v1) * v for k1, v1 in basis.double_mul(_dict, k, utils.poly_ring(_vstr), utils.poly_ring(utils.NoneVar)).items()})
137
+ results = add_perm_dict(results, this_dict)
138
+
139
+ none_dict, none_dict2 = sorted([none_dict, none_dict2], key=lambda x: -len(x.keys()))
140
+ for k, v in none_dict2.items():
141
+ results = add_perm_dict(results, {(k1, utils.NoneVar): v1 * v for k1, v1 in basis.single_mul(none_dict, k).items()})
142
+
143
+ return results
144
+
145
+
146
+ class BasisSchubertAlgebraElement(Expr):
147
+ _op_priority = 1e200
148
+ _kind = NumberKind
149
+ is_commutative = False
150
+ # precedence = 40
151
+ do_parallel = False
152
+
153
+ def __new__(cls, _dict, basis):
154
+ obj = Expr.__new__(cls)
155
+ obj._dict = {k: sympify(v) for k, v in _dict.items() if expand(v) != S.Zero}
156
+ if len(obj._dict.keys()) == 1 and next(iter(obj._dict.values())) == S.One:
157
+ obj.precedence = 1000
158
+ else:
159
+ obj.precedence = 40
160
+ obj._basis = basis
161
+ return obj
162
+
163
+ # 217 per night
164
+ # 569 per night
165
+ @property
166
+ def args(self):
167
+ return (sympy.Dict(self._dict), self._basis)
168
+
169
+ @property
170
+ def coeff_dict(self):
171
+ return self._dict
172
+
173
+ @property
174
+ def genset(self):
175
+ return self.basis.genset
176
+
177
+ @property
178
+ def basis(self):
179
+ return self._basis
180
+
181
+ def _hashable_content(self):
182
+ return self.args
183
+
184
+ # def prune(self):
185
+ # keys = list(self._dict.keys())
186
+ # for k in keys:
187
+ # if expand(self._dict[k]) == S.Zero:
188
+ # del self._dict[k]
189
+ # return self
190
+
191
+ def mult_poly(self, poly):
192
+ res_dict2 = {}
193
+ # poly = self.genset[i + 1] - self.genset[i]
194
+ for k, v in self.coeff_dict.items():
195
+ if k[1] == utils.ZeroVar or k[1] == utils.NoneVar:
196
+ dict2 = self.basis.mult_poly_single({k[0]: v}, poly, self.genset)
197
+ else:
198
+ dict2 = self.basis.mult_poly_double({k[0]: v}, poly, self.genset, utils.poly_ring(k[1]))
199
+ res_dict2 = add_perm_dict(res_dict2, {(k2, k[1]): v for k2, v in dict2.items()})
200
+ # logger.debug(f"{res_dict2=}")
201
+ return self.basis._from_dict(res_dict2)
202
+
203
+ def in_SEM_basis(self):
204
+ result = S.Zero
205
+ for k, v in self.coeff_dict.items():
206
+ result += v * schubpoly_from_elems(k[0], self.genset, utils.poly_ring(k[1]), elem_func=self.basis.symbol_elem_func)
207
+ return result
208
+
209
+ def in_classical_EM_basis(self):
210
+ result = S.Zero
211
+ for k, v in self.coeff_dict.items():
212
+ result += v * schubpoly_classical_from_elems(k[0], self.genset, utils.poly_ring(k[1]), elem_func=self.basis.symbol_elem_func)
213
+ return result
214
+
215
+ def _sympystr(self, printer):
216
+ if printer.order in ("old", "none"): # needed to avoid infinite recursion
217
+ return printer._print_Add(self, order="lex")
218
+ return printer._print_Add(self)
219
+
220
+ def _pretty(self, printer):
221
+ if printer.order in ("old", "none"): # needed to avoid infinite recursion
222
+ return printer._print_Add(self, order="lex")
223
+ return printer._print_Add(self)
224
+
225
+ def _latex(self, printer):
226
+ if printer.order in ("old", "none"): # needed to avoid infinite recursion
227
+ return printer._print_Add(self, order="lex")
228
+ return printer._print_Add(self)
229
+
230
+ def as_terms(self):
231
+ if len(self.coeff_dict.keys()) == 0:
232
+ return [sympy.sympify(S.Zero)]
233
+ return [
234
+ (sympy.sympify(self.coeff_dict[k]) if k[0] == Permutation([]) else sympy.Mul(self.coeff_dict[k], self.basis.single_element_class(k, self.basis)))
235
+ for k in sorted(self.coeff_dict.keys(), key=lambda bob: (inv(bob[0]), str(bob[1]), *bob[0]))
236
+ ]
237
+
238
+ def as_ordered_terms(self, *_, **__):
239
+ return self.as_terms()
240
+
241
+ # def _eval_simplify(self, *args, measure, **kwargs):
242
+ # return self.basis._from_dict({k: sympify(sympy.simplify(v, *args, measure=measure, **kwargs)) for k, v in self.coeff_dict.items()})
243
+
244
+ # def __iadd__(self, other):
245
+ # return self.__add__(other)
246
+
247
+ def __add__(self, other):
248
+ # if isinstance(self)
249
+ # # logger.debug(f"{type(other)=} {self.genset=}")
250
+ try:
251
+ other = self.basis(other)
252
+ except Exception:
253
+ return sympify(other) + self.as_polynomial()
254
+ return self.basis._from_dict(add_perm_dict(self.coeff_dict, other.coeff_dict))
255
+
256
+ def __radd__(self, other):
257
+ # logger.debug(f"{type(other)=}")
258
+ try:
259
+ other = self.basis(other)
260
+ except Exception:
261
+ # logger.debug(f"{other=} {list(self.genset)=}")
262
+ return sympify(other) + self.as_polynomial()
263
+ return self.basis._from_dict(add_perm_dict(other.coeff_dict, self.coeff_dict))
264
+
265
+ def __sub__(self, other):
266
+ # logger.debug(f"{type(other)=}")
267
+ try:
268
+ other = self.basis(other)
269
+ except Exception:
270
+ # logger.debug(f"{other=} {list(self.genset)=}")
271
+ return self.as_polynomial() - sympify(other)
272
+ double_dict = add_perm_dict(self.coeff_dict, {k: -v for k, v in other.coeff_dict.items()})
273
+ return self.basis._from_dict(double_dict)
274
+
275
+ def __rsub__(self, other):
276
+ # logger.debug(f"{type(other)=}")
277
+ try:
278
+ other = self.basis(other)
279
+ except Exception:
280
+ # logger.debug(f"{other=} {list(self.genset)=}")
281
+ return sympify(other) - self.as_polynomial()
282
+ double_dict = add_perm_dict(other.coeff_dict, {k: -v for k, v in self.coeff_dict.items()})
283
+ return self.basis._from_dict(double_dict)
284
+
285
+ def __neg__(self):
286
+ elem = self
287
+ if self.is_Add or self.is_Mul:
288
+ elem = self.doit()
289
+ double_dict = {k: -sympify(v) for k, v in elem.coeff_dict.items()}
290
+ return self.basis._from_dict(double_dict)
291
+
292
+ def __mul__(self, other):
293
+ try:
294
+ o = sympify(other)
295
+ return self.mult_poly(o)
296
+ except Exception:
297
+ try:
298
+ other = self.basis(other)
299
+ return self.basis._from_dict(_mul_schub_dicts(self.coeff_dict, other.coeff_dict, self.basis))
300
+ except Exception:
301
+ return self.as_polynomial() * sympify(other)
302
+
303
+ def __rmul__(self, other):
304
+ # logger.debug(f"{type(other)=}")
305
+ try:
306
+ o = sympify(other)
307
+ return self.mult_poly(o)
308
+ except Exception:
309
+ try:
310
+ other = self.basis(other)
311
+ return self.basis._from_dict(_mul_schub_dicts(other.coeff_dict, self.coeff_dict, self.basis))
312
+ except Exception:
313
+ return self.as_polynomial() * sympify(other)
314
+
315
+ # def equals(self, other):
316
+ # return self.__eq__(other)
317
+
318
+ # def test_equality(self, other, disp=False):
319
+ # elem1 = self
320
+ # elem2 = other
321
+ # done = set()
322
+ # import sys
323
+
324
+ # for k, v in elem1.coeff_dict.items():
325
+ # done.add(k)
326
+ # if expand(v - elem2.coeff_dict.get(k, 0)) != 0:
327
+ # if disp:
328
+ # # print(f"{k=} {v=} {elem2.coeff_dict.get(k, 0)=} {expand(v - elem2.coeff_dict.get(k, 0))=}", file=sys.stderr)
329
+ # return False
330
+ # for k, v in elem2.coeff_dict.items():
331
+ # if k in done:
332
+ # continue
333
+ # if expand(v - elem1.coeff_dict.get(k, 0)) != 0:
334
+ # if disp:
335
+ # # print(f"{k=} {v=} {expand(v - elem1.coeff_dict.get(k, 0))=}", file=sys.stderr)
336
+ # return False
337
+ # return True
338
+
339
+ # def __eq__(self, other):
340
+ # if self.is_Add or self.is_Mul:
341
+ # return self.doit().equals(other)
342
+ # cv = "y"
343
+ # elem1 = self
344
+ # elem2 = other
345
+
346
+ # if not elem1.test_equality(elem2):
347
+ # elem1_o = elem1.change_vars(cv)
348
+ # elem2_o = elem2.change_vars(cv)
349
+ # return elem1_o.test_equality(elem2_o)
350
+ # return True
351
+ # assert all([k[1] == cv for k in elem1.coeff_dict.keys()])
352
+ # assert all([k[1] == cv for k in elem2.coeff_dict.keys()])
353
+
354
+ # def __str__(self):
355
+ # pieces = []
356
+ # keys = list(self.coeff_dict.keys())
357
+ # for k in sorted(keys, key=lambda b: (inv(b[0]), b[1], *b[0])):
358
+ # v = self.coeff_dict[k]
359
+ # dvar = "D"
360
+ # if sympy.expand(v) != 0:
361
+ # pieces += [
362
+ # sympy.Mul(
363
+ # v,
364
+ # sympy.Symbol(
365
+ # f"{dvar}S{DSx._base_var}({list(k[0])}, {_varstr(k[1])})",
366
+ # commutative=False,
367
+ # )
368
+ # if k[0] != Permutation([])
369
+ # else 1,
370
+ # ),
371
+ # ]
372
+ # return sympy.sstr(sympy.Add(*pieces, evaluate=False), order="none")
373
+
374
+ # def __repr__(self):
375
+ # return str(self)
376
+ # def _as_ordered_terms(self, *args, **kwargs):
377
+
378
+ @cache
379
+ def change_vars(self, cv):
380
+ # result = {}
381
+ # fix
382
+ # for k, v in self.coeff_dict.items():
383
+ # result = add_perm_dict(result, {k1: v1 * v for k1, v1 in self.basis.cached_positive_product(Permutation([]), k[0], cv, k[1]).items()})
384
+ # # result = {(k, cv): v for k, v in self.basis.mul_double(Permutation([]),utils.poly_ring)}
385
+ # return self.basis._from_dict(result)
386
+ return self.basis([], cv) * self
387
+
388
+ def as_coefficients_dict(self):
389
+ return sympy.Dict({self.basis.single_element_class(k, self.basis): sympy.sympify(v) for k, v in self.coeff_dict.items()})
390
+
391
+ def expand(self, deep=True, *args, **kwargs): # noqa: ARG002
392
+ if not deep:
393
+ return self.basis._from_dict({k: expand(v) for k, v in self.coeff_dict.items()})
394
+ return sympy.sympify(expand(sympify(self.as_polynomial())))
395
+
396
+ def as_polynomial(self):
397
+ return sympy.sympify(Add(*[v * self.basis.cached_schubpoly(k) for k, v in self.coeff_dict.items()]))
398
+
399
+ def as_classical(self):
400
+ return self.basis.in_classical_basis(self)
401
+
402
+ def as_quantum(self):
403
+ return self.basis.in_quantum_basis(self)
404
+
405
+
406
+ class DoubleSchubertAlgebraElement(BasisSchubertAlgebraElement):
407
+ """Algebra with sympy coefficients
408
+ and a dict basis
409
+ """
410
+
411
+ # __slots__ = ("_dict", "_parent")
412
+ # is_polynomial = True
413
+
414
+ # default_coeff_var = "y"
415
+
416
+ def __new__(cls, _dict, basis):
417
+ return BasisSchubertAlgebraElement.__new__(cls, _dict, basis)
418
+
419
+ def divdiff(self, i):
420
+ return self.basis._from_dict({(k[0].swap(i - 1, i), k[1]): v for k, v in self.coeff_dict.items() if i - 1 in k[0].descents()})
421
+
422
+ def simpleref(self, i):
423
+ return self + self.divdiff(i).mult_poly(self.genset[i + 1] - self.genset[i])
424
+
425
+ def act(self, perm):
426
+ perm = Permutation(perm)
427
+ dset = perm.descents()
428
+ if len(dset) == 0:
429
+ return self
430
+ i = next(iter(dset))
431
+ return self.simpleref(i + 1).act(perm.swap(i, i + 1))
432
+
433
+ def max_index(self):
434
+ return max([max([0, *list(k[0].descents(zero_indexed=False))]) for k in self.coeff_dict.keys()])
435
+
436
+ def subs(self, old, new):
437
+ result = 0
438
+ if self.genset.index(old) != -1:
439
+ result = 0
440
+ index = self.genset.index(old)
441
+ mindex = self.max_index()
442
+ if mindex < index:
443
+ return self
444
+ # if already equal to the max index, we don't want to move it over
445
+ perm = Permutation([]).swap(index - 1, mindex) # index to max index + 1
446
+ # logger.debug(f"{mindex=}")
447
+ # logger.debug(f"{perm=}")
448
+ transf = self.act(perm)
449
+ # # logger.debug(f"{transf=}")
450
+ # # logger.debug(f"{self.expand()=}")
451
+ # # logger.debug(f"{transf.expand().expand()=}")
452
+ # transf2 = transf.coproduct([i for i in range(1,self.max_index()+1)],coeff_var=utils.NoneVar)
453
+ # # logger.debug(f"{transf2=}")
454
+ # for (k1, k2), v in transf2.coeff_dict.items():
455
+ # result += self.basis._from_dict({k1: v}) * (new**k2[0].inv)
456
+ # don't want to go nuts
457
+ # res_dict = {}
458
+ for k, v in transf.coeff_dict.items():
459
+ perm = k[0]
460
+ coeff_var = k[1]
461
+ coeff_gens = utils.poly_ring(coeff_var)
462
+ # cached mul_poly
463
+ L = schub_lib.pull_out_var(mindex + 1, perm)
464
+ # # logger.debug(f"{perm=} {L=}")
465
+ for index_list, new_perm in L:
466
+ result += self.basis._from_dict({(new_perm, k[1]): v}).mult_poly(sympy.prod([(new - coeff_gens[index2]) for index2 in index_list]))
467
+ return result
468
+
469
+ for k, v in self.coeff_dict.items():
470
+ if k[1] == utils.ZeroVar or k[1] == utils.NoneVar:
471
+ add_dict = {k: v.subs(old, new)}
472
+ else:
473
+ coeff_genset = utils.poly_ring(k[1])
474
+ if coeff_genset.index(old) != -1:
475
+ genset_list = [coeff_genset[i] for i in range(len(coeff_genset))]
476
+ genset_list[coeff_genset.index(old)] = 0
477
+ custom_genset = CustomGeneratingSet(genset_list)
478
+ new_add_dict = {k2: sympify(v2).subs(old, new) for k2, v2 in yz.schubmult_double({(): v}, k[0], custom_genset, coeff_genset).items()} # remove the variable
479
+ add_dict = {}
480
+ for k3, v3 in new_add_dict.items():
481
+ # convert back to coeff_genset
482
+ to_add_dict = {(k4, k[1]): v4 for k4, v4 in yz.schubmult_double({(): v3}, k3, coeff_genset, custom_genset).items()}
483
+ add_dict = add_perm_dict(add_dict, to_add_dict)
484
+ else:
485
+ add_dict = {k: sympify(v).subs(old, new)}
486
+ for k5, v5 in add_dict.items():
487
+ if any(self.genset.index(s) != -1 for s in sympify(v5).free_symbols):
488
+ result += self.basis._from_dict({k5: 1}).mult_poly(v5)
489
+ else:
490
+ result += self.basis._from_dict({k5: v5})
491
+ # check correct, change vars to zeroed coeff var for coeff
492
+ return result
493
+
494
+ # for k, v in self.coeff_dict.items():
495
+ # # can permute it to the end and substitute
496
+ # perm = k[0]
497
+ # coeff_var = k[1]
498
+
499
+ @property
500
+ def free_symbols(self):
501
+ ret = set()
502
+ for k, v in self.coeff_dict.items():
503
+ ret.update(v.free_symbols)
504
+ perm = k[0]
505
+ coeff_var = k[1]
506
+ if len(perm.descents()) > 0:
507
+ ret.update([self.genset[i] for i in range(1, max(perm.descents()) + 2)])
508
+ if coeff_var != utils.NoneVar and coeff_var != utils.ZeroVar:
509
+ genset2 = utils.poly_ring(coeff_var)
510
+ perm2 = ~perm
511
+ if len(perm2.descents()) > 0:
512
+ ret.update([genset2[i] for i in range(1, max(perm2.descents()) + 2)])
513
+ return ret
514
+
515
+ # def _eval_Eq(self, other):
516
+ # # this will prevent sympy from acting like an idiot
517
+ # return self.__eq__(other)
518
+
519
+ # def _eval_subs(self, old, new):
520
+ # b_old = sympify(old)
521
+ # b_new = sympify(new)
522
+ # result = {}
523
+ # stuff_to_do = False
524
+ # lots_of_stuff_to_do = False
525
+ # if b_new in utils.poly_ring(self._base_var):
526
+ # stuff_to_do = True
527
+ # if b_old in utils.poly_ring(self._base_var):
528
+ # lots_of_stuff_to_do = True
529
+ # for k, v in self.coeff_dict.items():
530
+ # if lots_of_stuff_to_do:
531
+ # poley = sympify(self.basis._from_dict({k: 1}).change_vars(0).expand() * v)
532
+ # if b_old in poley.free_symbols:
533
+ # poley = poley.subs(b_old, b_new)
534
+ # new_dict = yz.mult_poly_double({(1, 2): 1}, poley, utils.poly_ring(self._base_var), utils.poly_ring(k[1]))
535
+ # new_p = {(koifle, k[1]): voifle for koifle, voifle in new_dict.items()}
536
+ # result = add_perm_dict(result, new_p)
537
+ # elif stuff_to_do:
538
+ # this_p = self.basis._from_dict({k: v}).change_vars(0)
539
+ # for kkk, vvv in this_p.coeff_dict.items():
540
+ # vvvv = sympify(vvv).subs(b_old, b_new)
541
+ # if b_new in sympify(vvvv).free_symbols:
542
+ # s_dict = {kkk[0]: 1}
543
+ # r_dict = py.mult_poly_py(s_dict, vvvv, utils.poly_ring(self._base_var))
544
+ # else:
545
+ # r_dict = {kkk[0]: vvvv}
546
+ # r_dict = {(kk, 0): voif for kk, voif in r_dict.items()}
547
+ # new_p = self.basis._from_dict(r_dict).change_vars(k[1])
548
+ # result = add_perm_dict(result, new_p.coeff_dict)
549
+ # else:
550
+ # result[k] = result.get(k, 0) + sympify(v).subs(b_old, b_new)
551
+ # return self.basis._from_dict(result)
552
+
553
+ def coproduct(self, indices, coeff_var="y", gname1=None, gname2=None):
554
+ result_dict = {}
555
+ if gname1 is None:
556
+ gname1 = f"{self.genset.label}_A"
557
+ if gname2 is None:
558
+ gname2 = f"{self.genset.label}_B"
559
+ gens2 = MaskedGeneratingSet(self.genset, indices)
560
+ # logger.debug(f"{indices=}")
561
+ gens1 = gens2.complement()
562
+ # logger.debug(f"{gens1.index_mask=}")
563
+ # logger.debug(f"{list(gens1)=}")
564
+ # logger.debug(f"{gens2.index_mask=}")
565
+ # logger.debug(f"{list(gens2)=}")
566
+ gens1.set_label(gname1)
567
+ gens2.set_label(gname2)
568
+ for k, v in self.coeff_dict.items():
569
+ key = k[0]
570
+ var_str = k[1]
571
+ # print(f"{var_str=}")
572
+ # print(f"{coeff_var=}")
573
+ if var_str in (utils.NoneVar, utils.ZeroVar) and coeff_var in (utils.NoneVar, utils.ZeroVar):
574
+ coprod_dict = py.schub_coprod_py(key, indices)
575
+ else:
576
+ coprod_dict = yz.schub_coprod_double(key, indices, utils.poly_ring(var_str), utils.poly_ring(coeff_var))
577
+ # print(f"{coprod_dict=}")
578
+ result_dict = add_perm_dict(result_dict, {((k1, var_str), (k2, coeff_var)): v * v2 for (k1, k2), v2 in coprod_dict.items()})
579
+ basis = tsr.TensorAlgebraBasis(DoubleSchubertAlgebraElement_basis(gens1), DoubleSchubertAlgebraElement_basis(gens2))
580
+ return basis._from_dict(result_dict)
581
+
582
+ # def normalize_coefficients(self, coeff_var):
583
+ # return DSx([1, 2], coeff_var) * self
584
+
585
+ # def expand(self, *_a, **_):
586
+ # if isinstance(self, SchubAdd):
587
+ # return self.doit().expand()
588
+ # if isinstance(self, SchubMul):
589
+ # return self.doit().expand()
590
+ # return expand(Add(*[v * schubpoly(k[0], self.genset, utils.poly_ring(k[1])) for k, v in self.coeff_dict.items()]))
591
+
592
+ @cached_property
593
+ def max_gens(self):
594
+ return max([max(k[0].descents()) for k in self.coeff_dict.keys()])
595
+
596
+
597
+ _pretty_schub_char = "𝔖" # noqa: RUF001
598
+
599
+
600
+ # Atomic Schubert polynomial
601
+ class DSchubPoly(DoubleSchubertAlgebraElement):
602
+ is_Atom = True
603
+
604
+ def __new__(cls, k, basis):
605
+ return DSchubPoly.__xnew_cached__(cls, k, basis)
606
+
607
+ @staticmethod
608
+ def __xnew__(_class, k, basis):
609
+ _coeff_dict = sympy.Dict({(Permutation(k[0]), k[1]): 1})
610
+ # if not isinstance(genset, GeneratingSet_base):
611
+ # raise TypeError
612
+ obj = DoubleSchubertAlgebraElement.__new__(_class, _coeff_dict, basis)
613
+ obj._key = k
614
+ obj._genset = basis.genset
615
+ obj._coeff_dict = _coeff_dict
616
+ obj._basis = basis
617
+ return obj
618
+
619
+ # @property
620
+ # def coeff_dict(self):
621
+ # return self._coeff_dict
622
+
623
+ @property
624
+ def perm(self):
625
+ return self._key[0]
626
+
627
+ @property
628
+ def args(self):
629
+ return (sympy.Tuple(*self._key), self._basis)
630
+
631
+ @staticmethod
632
+ @cache
633
+ def __xnew_cached__(_class, k, basis):
634
+ return DSchubPoly.__xnew__(_class, k, basis)
635
+
636
+ def _sympystr(self, printer):
637
+ if self._key[0] == Permutation([]):
638
+ return printer.doprint(1)
639
+ if self._key[1] == 0 or self._key[1] == utils.NoneVar:
640
+ return printer.doprint(f"S{self.genset.label}({printer.doprint(self._key[0])})")
641
+ return printer.doprint(f"DS{self.genset.label}({printer.doprint(self._key[0])}, {_varstr(self._key[1])})")
642
+
643
+ def _pretty(self, printer):
644
+ if self._key[0] == Permutation([]):
645
+ return printer._print(1)
646
+ subscript = printer._print(int("".join([str(i) for i in self._key[0]])))
647
+ if self._key[1] == 0 or self._key[1] == utils.NoneVar:
648
+ return printer._print_Function(sympy.Function(f"{_pretty_schub_char}_{subscript}")(sympy.Symbol(self.genset.label)))
649
+ return printer._print_Function(sympy.Function(f"{_pretty_schub_char}_{subscript}")(sympy.Symbol(f"{self.genset.label}; {self._key[1]}")))
650
+
651
+ def _latex(self, printer):
652
+ if self._key[0] == Permutation([]):
653
+ return printer._print(1)
654
+ subscript = printer._print(self._key[0])
655
+ if self._key[1] == 0 or self._key[1] == utils.NoneVar:
656
+ return printer._print_Function(sympy.Function("\\mathfrak{S}" + f"_{'{' + subscript + '}'}")(sympy.Symbol(self.genset.label)))
657
+ return printer._print_Function(sympy.Function("\\mathfrak{S}" + f"_{'{' + subscript + '}'}")(sympy.Symbol(f"{self.genset.label}; {self._key[1]}")))
658
+
659
+
660
+ # def elem_func(p, k, vx, vy):
661
+ # return DSx(elem_func_q(p, k, vx, vy), "y")
662
+
663
+ # A = schubpoly_from_elems([4,1,3,2], DSx.genset, poly_ring("y"),elem_func)
664
+
665
+
666
+ # None is faster to store
667
+ class DoubleSchubertAlgebraElement_basis(Basic):
668
+ def __new__(cls, genset):
669
+ return Basic.__new__(cls, genset)
670
+
671
+ @property
672
+ def symbol_elem_func(self):
673
+ def elem_func(p, k, varl1, varl2): # noqa: ARG001
674
+ if p == 0 and k >= 0:
675
+ return 1
676
+ if p < 0 or p > k:
677
+ return 0
678
+ return sympy.Add(*[(Symbol(f"e_{p - i}_{k}") if p - i > 0 else 1) * complete_sym_poly(i, k + 1 - p, [-v for v in varl2]) for i in range(p + 1)])
679
+
680
+ return elem_func
681
+
682
+ def elem_sym_subs(self, kk):
683
+ elems = []
684
+ for k in range(1, kk + 1):
685
+ for p in range(1, k + 1):
686
+ elems += [(sympy.Symbol(f"e_{p}_{k}"), elem_sym_poly(p, k, self.genset[1:], utils.poly_ring(0)))]
687
+ return dict(elems)
688
+
689
+ # def in_SEM_basis(self, elem):
690
+ # return
691
+
692
+ @property
693
+ def genset(self):
694
+ return self.args[0]
695
+
696
+ def _from_dict(self, _dict):
697
+ return DoubleSchubertAlgebraElement(_dict, self)
698
+
699
+ @property
700
+ def single_element_class(self):
701
+ return DSchubPoly
702
+
703
+ def in_quantum_basis(self, elem):
704
+ result = S.Zero
705
+ for k, v in elem.coeff_dict.items():
706
+ result += v * self.quantum_schubpoly(k[0], k[1])
707
+ return result
708
+
709
+ def in_classical_basis(self, elem):
710
+ return elem
711
+
712
+ @cache
713
+ def quantum_schubpoly(self, perm, coeff_var="y"):
714
+ return schubpoly_classical_from_elems(perm, self.genset, utils.poly_ring(coeff_var), self.quantum_elem_func(coeff_var))
715
+
716
+ @cache
717
+ def cached_product(self, u, v, va, vb):
718
+ return {(k, va): xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_double_pair_generic(u, v).items()}
719
+
720
+ @cache
721
+ def cached_positive_product(self, u, v, va, vb):
722
+ return {(k, va): xreplace_genvars(x, utils.poly_ring(va), utils.poly_ring(vb)) for k, x in yz.schubmult_generic_partial_posify(u, v).items()}
723
+
724
+ @property
725
+ def double_mul(self):
726
+ return yz.schubmult_double
727
+
728
+ @property
729
+ def single_mul(self):
730
+ return py.schubmult_py
731
+
732
+ @property
733
+ def mult_poly_single(self):
734
+ return py.mult_poly_py
735
+
736
+ @property
737
+ def mult_poly_double(self):
738
+ return yz.mult_poly_double
739
+
740
+ def quantum_elem_func(self, coeff_var):
741
+ basis = qsr.QuantumDoubleSchubertAlgebraElement_basis(self.genset)
742
+
743
+ def elem_func(p, k, varl1, varl2, xstart=0, ystart=0):
744
+ if p > k:
745
+ return basis(0, coeff_var)
746
+ if p == 0:
747
+ return basis([], coeff_var)
748
+ if p == 1:
749
+ res = basis(varl1[xstart] - varl2[ystart], coeff_var)
750
+ for i in range(1, k):
751
+ res += basis(varl1[xstart + i] - varl2[ystart + i], coeff_var)
752
+ return res
753
+ if p == k:
754
+ res = basis((varl1[xstart] - varl2[ystart]) * (varl1[xstart + 1] - varl2[ystart]), coeff_var)
755
+ for i in range(2, k):
756
+ res *= basis(varl1[i + xstart] - varl2[ystart], coeff_var)
757
+ return res
758
+ mid = k // 2
759
+ xsm = xstart + mid
760
+ ysm = ystart + mid
761
+ kmm = k - mid
762
+ res = elem_func(p, mid, varl1, varl2, xstart, ystart) + elem_func(
763
+ p,
764
+ kmm,
765
+ varl1,
766
+ varl2,
767
+ xsm,
768
+ ysm,
769
+ )
770
+ for p2 in range(max(1, p - kmm), min(p, mid + 1)):
771
+ res += elem_func(p2, mid, varl1, varl2, xstart, ystart) * elem_func(
772
+ p - p2,
773
+ kmm,
774
+ varl1,
775
+ varl2,
776
+ xsm,
777
+ ysm - p2,
778
+ )
779
+ # logger.debug(f"{res=}")
780
+ return res
781
+
782
+ return elem_func
783
+
784
+ # @cache
785
+ # def cached_schubpoly_oink(self, u):
786
+ # return yz.schubpoly(u)
787
+
788
+ @cache
789
+ def cached_schubpoly(self, k):
790
+ # return yz.schubpoly(u)
791
+ return schubpoly_classical_from_elems(k[0], self.genset, utils.poly_ring(k[1]), elem_func=elem_sym_poly)
792
+
793
+ def __call__(self, x, cv=None):
794
+ # print(f"frivol {x=} {cv=}")
795
+ genset = self.genset
796
+ if not isinstance(genset, GeneratingSet_base):
797
+ raise TypeError
798
+ # logger.debug(f"{type(x)=}")
799
+ # if isinstance(x, Mul) or isinstance(x, Add):
800
+ # raise TypeError
801
+ if isinstance(x, list) or isinstance(x, tuple):
802
+ if cv is None:
803
+ cv = "y"
804
+ p_x = Permutation(x)
805
+ if max([0, *list(p_x.descents())]) > len(self.genset):
806
+ raise NotEnoughGeneratorsError(f"Not enough generators {p_x=} {len(genset)=}")
807
+ elem = self._from_dict({(p_x, cv): 1})
808
+ elif isinstance(x, Permutation):
809
+ if cv is None:
810
+ cv = "y"
811
+ if max([0, *list(x.descents())]) > len(self.genset):
812
+ raise NotEnoughGeneratorsError(f"Not enough generators {p_x=} {len(genset)=}")
813
+ elem = self._from_dict({(x, cv): 1})
814
+
815
+ elif isinstance(x, DoubleSchubertAlgebraElement):
816
+ # logger.debug("Line record")
817
+ if x.is_Add or x.is_Mul:
818
+ return x.doit()
819
+ if x.genset == genset:
820
+ return x
821
+ raise ValueError("Different generating set")
822
+ # poly
823
+ # elif isinstance(x, sympy.Poly):
824
+ # # eject generators we don't want
825
+ # if not x.has_only_gens():
826
+ # x, _ = sympy.poly_from_expr(x.as_expr())
827
+ # new_gens = [g for g in x.gens if self.genset.index(g) != -1]
828
+ # # end_gens = [g for g in x.gens if self.genset.index(g) == -1]
829
+ # if len(new_gens) == 0:
830
+ # # logger.debug(f"Didn't find any gens in {x=}")
831
+ # return self(x.as_expr())
832
+ # new_gens.sort(key=lambda g: self.genset.index(g))
833
+ # # expand_gens = [self.genset[i] for i in range(self.genset.index(new_gens[-1])+1)] + end_gens
834
+ # x = sympy.poly(x, gens=tuple(new_gens))
835
+ # dct = x.as_dict()
836
+ # result = 0
837
+ # for monom, coeff in dct.items():
838
+ # srt_perm = Permutation.sorting_perm([-i for i in monom])
839
+ # # srt_perm.reverse()
840
+ # # srt_perm = Permutation(srt_perm)
841
+ # # print(sorted(monom,reverse=True))
842
+ # schub_perm = uncode(sorted(monom, reverse=True))
843
+ # result += self._from_dict({(schub_perm, utils.NoneVar): coeff}).act(srt_perm)
844
+ # return result
845
+ else:
846
+ # logger.debug(f"{x=}")
847
+ x = sympify(x)
848
+ if cv is None or cv == utils.NoneVar:
849
+ cv = utils.NoneVar
850
+ result = py.mult_poly_py({Permutation([]): 1}, x, genset)
851
+ else:
852
+ # print("splinterfish")
853
+ result = yz.mult_poly_double({Permutation([]): 1}, x, genset, utils.poly_ring(cv))
854
+ elem = self._from_dict({(k, cv): v for k, v in result.items()})
855
+ # logger.debug(f"Returning {elem=}")
856
+ return elem
857
+
858
+
859
+ # def _do_schub_mul(a, b):
860
+ # A = DSx(a)
861
+ # B = DSx(b)
862
+ # return self.basis._from_dict(_mul_schub_dicts(A.coeff_dict, B.coeff_dict))
863
+
864
+
865
+ # def _do_schub_add(a, b):
866
+ # A = DSx(a)
867
+ # B = DSx(b)
868
+ # return self.basis._from_dict(add_perm_dict(A.coeff_dict, B.coeff_dict))
869
+
870
+
871
+ # def get_postprocessor(cls):
872
+ # if cls is Mul:
873
+ # return lambda expr: SchubMul(*expr.args) # .doit()
874
+ # if cls is Add:
875
+ # return lambda expr: SchubAdd(*expr.args) # .doit()
876
+ # return None
877
+
878
+
879
+ # Basic._constructor_postprocessor_mapping[BasisSchubertAlgebraElement] = {
880
+ # "Mul": [get_postprocessor(Mul)],
881
+ # "Add": [get_postprocessor(Add)],
882
+ # }
883
+
884
+ # add.register_handlerclass((Expr, SchubAdd), SchubAdd)
885
+ # mul.register_handlerclass((Expr, SchubMul), SchubMul)
886
+
887
+
888
+ DoubleSchubertPolynomial = DoubleSchubertAlgebraElement
889
+
890
+
891
+ # class SchubAdd(Add):
892
+ # is_Add = True
893
+
894
+ # def __new__(cls, *args, evaluate=False, _sympify=True, **_):
895
+ # obj = sympy.Add.__new__(cls, *args, evaluate=evaluate, _sympify=_sympify)
896
+ # obj._args = args
897
+ # if evaluate:
898
+ # return obj.doit()
899
+ # return obj
900
+
901
+ # @property
902
+ # def args(self):
903
+ # return self._args
904
+
905
+ # def doit(self):
906
+ # ret = self.args[0]
907
+ # # logger.debug(f"ADD {self.args=}")
908
+ # for arg in self.args[1:]:
909
+ # # logger.debug(f"{arg=} {type(arg)=}")
910
+ # # logger.debug(f"{ret=} {type(ret)=}")
911
+ # ret += sympy.expand(arg)
912
+ # return ret
913
+
914
+ # def _sympystr(self, printer):
915
+ # return printer._print_Add(self)
916
+
917
+ # def expand(self, deep=True, *_, **__):
918
+ # return SchubAdd(*[sympy.expand(arg) for arg in self.args]).doit()
919
+
920
+
921
+ # class SchubMul(sympy.Mul):
922
+ # is_Mul = True
923
+
924
+ # def __new__(cls, *args, evaluate=False, _sympify=True, **_):
925
+ # # args, a, b = Mul.flatten(list(args))
926
+ # # if len(args) == 0:
927
+ # # return 1
928
+ # obj = Mul.__new__(cls, *args, evaluate=evaluate, _sympify=_sympify)
929
+ # obj._args = args
930
+ # if evaluate:
931
+ # return obj.doit()
932
+ # return obj
933
+
934
+ # @property
935
+ # def args(self):
936
+ # return self._args
937
+
938
+ # def doit(self):
939
+ # ret = self.args[0]
940
+ # # logger.debug(f"MUL {self.args=}")
941
+ # for arg in self.args[1:]:
942
+ # # logger.debug(f"{arg=} {type(arg)=}")
943
+ # ret *= sympy.expand(arg)
944
+ # return ret
945
+
946
+ # def _sympystr(self, printer):
947
+ # return printer._print_Mul(self)
948
+
949
+ # def __neg__(self):
950
+ # return SchubMul(sympy.Integer(-1), self)
951
+
952
+ # def _eval_expand_mul(self, *_, **__):
953
+ # # logger.debug(f"Pringles {self.args=}")
954
+ # return SchubMul(*[sympy.expand(arg) for arg in self.args]).doit()
955
+
956
+
957
+ # Basic._constructor_postprocessor_mapping[DoubleSchubertAlgebraElement] = {
958
+ # "Mul": [get_postprocessor(Mul)],
959
+ # "Add": [get_postprocessor(Add)],
960
+ # }
961
+
962
+ DSx = DoubleSchubertAlgebraElement_basis(GeneratingSet("x"))
963
+ """DSx: Double Schubert polynomial generator
964
+ DSx is an alias for a DoubleSchubertAlgebraElement_basis object with
965
+ GeneratingSet being variables with name x_i for i an integer up to 99.
966
+ It is a callable object, and the signature is
967
+
968
+ DSx(x, cv=None, genset=None)
969
+
970
+ x is either a tuple, a list, a schubmult.Permutation, or a sympy
971
+ or symengine object that you are trying to express in terms of
972
+ double Schubert polynomials. cv is a string that is the name of
973
+ the base GeneratingSet for the coefficient variable (defaults to
974
+ "y"), and genset is the "x" variable generating set by default,
975
+ but can be subsituted with a custom GeneratingSet_base object.
976
+ """
977
+
978
+
979
+ # def Sx(x):
980
+ # return DSx(x, utils.NoneVar)
981
+
982
+
983
+ class SchubertAlgebraElement_basis(DoubleSchubertAlgebraElement_basis):
984
+ def __new__(cls, genset):
985
+ return DoubleSchubertAlgebraElement_basis.__new__(cls, genset)
986
+
987
+ def __hash__(self):
988
+ return hash((*self.args, utils.NoneVar))
989
+
990
+ def _from_single_dict(self, _dict):
991
+ return DoubleSchubertAlgebraElement({(k, utils.NoneVar): v for k, v in _dict.items()}, self)
992
+
993
+ def __call__(self, x):
994
+ genset = self.genset
995
+ # logger.debug(f"{x=} {type(x)=}")
996
+ if not genset:
997
+ genset = self.genset
998
+ if not isinstance(genset, GeneratingSet_base):
999
+ raise TypeError
1000
+ if isinstance(x, list) or isinstance(x, tuple):
1001
+ elem = self._from_single_dict({Permutation(x): 1})
1002
+ elif isinstance(x, Permutation):
1003
+ elem = self._from_single_dict({x: 1})
1004
+ # elif isinstance(x, spr.SchubertPolynomial):
1005
+ # if x._parent._base_var == self._base_var:
1006
+ # elem_dict = {(x, utils.NoneVar): v for k, v in x.coeff_dict.items()}
1007
+ # elem = QuantumDoubleSchubertAlgebraElement(elem_dict, self)
1008
+ # if cv is not None:
1009
+ # elem = self([1, 2], cv) * elem
1010
+ # else:
1011
+ # return self(x.expand(), cv)
1012
+ elif isinstance(x, DoubleSchubertAlgebraElement):
1013
+ if x.is_Add or x.is_Mul:
1014
+ return x
1015
+ if x.genset == genset:
1016
+ elem = DoubleSchubertAlgebraElement(x.coeff_dict, self) # , self)
1017
+ else:
1018
+ return self(x.expand())
1019
+ # elif isinstance(x, spr.DoubleSchubertAlgebraElement):
1020
+ # if x.genset == self.genset:
1021
+ # return x.as_quantum()
1022
+ else:
1023
+ x = sympify(x)
1024
+ result = py.mult_poly_py({Permutation([]): 1}, x, genset)
1025
+ elem = self._from_single_dict(result)
1026
+ return elem
1027
+
1028
+
1029
+ Sx = SchubertAlgebraElement_basis(GeneratingSet("x"))
1030
+
1031
+ ybas = SchubertAlgebraElement_basis(GeneratingSet("y"))