schubmult 2.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 +1 -0
- schubmult/_base_argparse.py +174 -0
- schubmult/perm_lib.py +999 -0
- schubmult/sage_integration/__init__.py +25 -0
- schubmult/sage_integration/_fast_double_schubert_polynomial_ring.py +528 -0
- schubmult/sage_integration/_fast_schubert_polynomial_ring.py +356 -0
- schubmult/sage_integration/_indexing.py +44 -0
- schubmult/schubmult_double/__init__.py +18 -0
- schubmult/schubmult_double/__main__.py +5 -0
- schubmult/schubmult_double/_funcs.py +1590 -0
- schubmult/schubmult_double/_script.py +407 -0
- schubmult/schubmult_double/_vars.py +16 -0
- schubmult/schubmult_py/__init__.py +10 -0
- schubmult/schubmult_py/__main__.py +5 -0
- schubmult/schubmult_py/_funcs.py +111 -0
- schubmult/schubmult_py/_script.py +115 -0
- schubmult/schubmult_py/_vars.py +3 -0
- schubmult/schubmult_q/__init__.py +12 -0
- schubmult/schubmult_q/__main__.py +5 -0
- schubmult/schubmult_q/_funcs.py +304 -0
- schubmult/schubmult_q/_script.py +157 -0
- schubmult/schubmult_q/_vars.py +18 -0
- schubmult/schubmult_q_double/__init__.py +14 -0
- schubmult/schubmult_q_double/__main__.py +5 -0
- schubmult/schubmult_q_double/_funcs.py +507 -0
- schubmult/schubmult_q_double/_script.py +337 -0
- schubmult/schubmult_q_double/_vars.py +21 -0
- schubmult-2.0.0.dist-info/METADATA +455 -0
- schubmult-2.0.0.dist-info/RECORD +36 -0
- schubmult-2.0.0.dist-info/WHEEL +5 -0
- schubmult-2.0.0.dist-info/entry_points.txt +5 -0
- schubmult-2.0.0.dist-info/licenses/LICENSE +674 -0
- schubmult-2.0.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/test_fast_double_schubert.py +145 -0
- tests/test_fast_schubert.py +38 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
from sage.all import * # noqa: F403
|
2
|
+
|
3
|
+
from ._fast_schubert_polynomial_ring import (
|
4
|
+
FastSchubertPolynomialRing,
|
5
|
+
FastSchubertPolynomial,
|
6
|
+
FastSchubertPolynomialRing_base,
|
7
|
+
FastQuantumSchubertPolynomialRing,
|
8
|
+
)
|
9
|
+
from ._fast_double_schubert_polynomial_ring import (
|
10
|
+
FastDoubleSchubertPolynomialRing,
|
11
|
+
FastDoubleSchubertPolynomial,
|
12
|
+
FastDoubleSchubertPolynomialRing_base,
|
13
|
+
FastQuantumDoubleSchubertPolynomialRing,
|
14
|
+
)
|
15
|
+
|
16
|
+
__all__ = [
|
17
|
+
"FastSchubertPolynomialRing",
|
18
|
+
"FastSchubertPolynomial",
|
19
|
+
"FastSchubertPolynomialRing_base",
|
20
|
+
"FastDoubleSchubertPolynomialRing",
|
21
|
+
"FastDoubleSchubertPolynomial",
|
22
|
+
"FastDoubleSchubertPolynomialRing_base",
|
23
|
+
"FastQuantumSchubertPolynomialRing",
|
24
|
+
"FastQuantumDoubleSchubertPolynomialRing",
|
25
|
+
]
|
@@ -0,0 +1,528 @@
|
|
1
|
+
from sage.all import * # noqa: F403
|
2
|
+
from sage.categories.graded_bialgebras_with_basis import GradedBialgebrasWithBasis
|
3
|
+
from sage.categories.graded_algebras_with_basis import GradedAlgebrasWithBasis
|
4
|
+
from sage.combinat.free_module import CombinatorialFreeModule
|
5
|
+
from sage.categories.cartesian_product import cartesian_product
|
6
|
+
from sage.combinat.permutation import Permutations, Permutation, from_lehmer_code
|
7
|
+
from sage.misc.cachefunc import cached_method
|
8
|
+
from sage.rings.polynomial.multi_polynomial import MPolynomial
|
9
|
+
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
|
10
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
11
|
+
from sage.rings.polynomial.flatten import FlatteningMorphism
|
12
|
+
from sage.combinat.composition import (
|
13
|
+
Compositions,
|
14
|
+
Composition,
|
15
|
+
)
|
16
|
+
from . import (
|
17
|
+
FastSchubertPolynomialRing_base,
|
18
|
+
FastSchubertPolynomial,
|
19
|
+
)
|
20
|
+
from ._indexing import _coerce_index
|
21
|
+
|
22
|
+
|
23
|
+
import schubmult.schubmult_q_double as qyz
|
24
|
+
import schubmult.schubmult_double as yz
|
25
|
+
from sympy import sympify
|
26
|
+
import symengine as syme
|
27
|
+
|
28
|
+
|
29
|
+
def FastDoubleSchubertPolynomialRing(
|
30
|
+
R: Parent, # noqa: F405
|
31
|
+
num_vars: int,
|
32
|
+
base_variable_name: str,
|
33
|
+
coeff_variable_names: str | tuple[str],
|
34
|
+
*,
|
35
|
+
indices: tuple[int] = tuple([1]),
|
36
|
+
code_display: bool = False,
|
37
|
+
q_varname: str = "q",
|
38
|
+
is_quantum: bool = False,
|
39
|
+
):
|
40
|
+
"""Wrapper function to return a double Schubert polynomial Ring
|
41
|
+
|
42
|
+
Calls the _xbasis class to return a double or quantum double Schubert
|
43
|
+
polynomial ring with the indicated base ring, number of variables,
|
44
|
+
variable names (base variable, and then one or more sets of coefficient)
|
45
|
+
variables, coproduct indices, code_display representation option, q-ring
|
46
|
+
variable name, and whether the ring is quantum.
|
47
|
+
|
48
|
+
Example call:
|
49
|
+
|
50
|
+
```python
|
51
|
+
X = FastDoubleSchubertPolynomialRing(ZZ, 100, "x", ("y", "z"))
|
52
|
+
X([2, 4, 3, 1]) + X([2, 1, 4, 3], "z")
|
53
|
+
```
|
54
|
+
|
55
|
+
Args:
|
56
|
+
R (sage ring): The base ring
|
57
|
+
num_vars (int): Cardinality of the sets of variables
|
58
|
+
base_variable_name (str): Base variable name
|
59
|
+
coeff_variable_names (str | tuple[str]): Coefficient variable name(s)
|
60
|
+
indices (tuple[int], optional): Indicies of the variables to split on for the coproduct.
|
61
|
+
code_display (bool, optional): Whether to display the indices as the Lehmer code. Defaults to False.
|
62
|
+
q_varname (str, optional): Variable name of the q-ring. Defaults to "q".
|
63
|
+
is_quantum (bool, optional): Whether or not the ring is quantum. Defaults to False.
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
FastDoubleSchubertPolynomialRing_xbasis: Basis element generator of the ring
|
67
|
+
"""
|
68
|
+
QR = None
|
69
|
+
if is_quantum:
|
70
|
+
QR = PolynomialRing(R, num_vars, q_varname)
|
71
|
+
return FastDoubleSchubertPolynomialRing_xbasis(
|
72
|
+
R,
|
73
|
+
num_vars,
|
74
|
+
base_variable_name,
|
75
|
+
coeff_variable_names,
|
76
|
+
q_varname,
|
77
|
+
code_display,
|
78
|
+
indices,
|
79
|
+
is_quantum,
|
80
|
+
QR,
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
def FastQuantumDoubleSchubertPolynomialRing(
|
85
|
+
R: Parent, # noqa: F405
|
86
|
+
num_vars: int,
|
87
|
+
base_variable_name: str,
|
88
|
+
coeff_variable_names: str | tuple[str],
|
89
|
+
*,
|
90
|
+
code_display=False,
|
91
|
+
q_varname="q",
|
92
|
+
):
|
93
|
+
"""Quantum double Schubert ring generator
|
94
|
+
|
95
|
+
Wraps FastDoubleSchubertPolynomialRing(), omitting indices and setting
|
96
|
+
is_quantum to True.
|
97
|
+
|
98
|
+
Args:
|
99
|
+
R (sage ring): The base ring
|
100
|
+
num_vars (int): Cardinality of the sets of variables
|
101
|
+
base_variable_name (str): Base variable name
|
102
|
+
coeff_variable_names (str | tuple[str]): Coefficient variable name(s)
|
103
|
+
code_display (bool, optional): Whether to display the indices as the Lehmer code. Defaults to False.
|
104
|
+
q_varname (str, optional): Variable name of the q-ring. Defaults to "q".
|
105
|
+
|
106
|
+
Returns:
|
107
|
+
FastDoubleSchubertPolynomialRing_xbasis: Basis element generator of the quantum ring
|
108
|
+
"""
|
109
|
+
return FastDoubleSchubertPolynomialRing(
|
110
|
+
R,
|
111
|
+
num_vars,
|
112
|
+
base_variable_name,
|
113
|
+
coeff_variable_names,
|
114
|
+
code_display=code_display,
|
115
|
+
indices=tuple([1]),
|
116
|
+
is_quantum=True,
|
117
|
+
q_varname=q_varname,
|
118
|
+
)
|
119
|
+
|
120
|
+
|
121
|
+
class FastDoubleSchubertPolynomial_class(CombinatorialFreeModule.Element):
|
122
|
+
@property
|
123
|
+
def base_varname(self):
|
124
|
+
return self.parent()._base_varname
|
125
|
+
|
126
|
+
@property
|
127
|
+
def q_varname(self):
|
128
|
+
if not self.parent().is_quantum:
|
129
|
+
return None
|
130
|
+
else:
|
131
|
+
return self.parent()._q_varname
|
132
|
+
|
133
|
+
@property
|
134
|
+
def base_polynomial_ring(self):
|
135
|
+
return self.parent()._base_polynomial_ring
|
136
|
+
|
137
|
+
@property
|
138
|
+
def coeff_polynomial_ring(self):
|
139
|
+
return self.parent()._coeff_polynomial_ring
|
140
|
+
|
141
|
+
@property
|
142
|
+
def q_ring(self):
|
143
|
+
if not self.parent()._quantum:
|
144
|
+
return None
|
145
|
+
else:
|
146
|
+
return self.parent()._q_ring
|
147
|
+
|
148
|
+
def expand(self):
|
149
|
+
if self.parent()._quantum:
|
150
|
+
return sum(
|
151
|
+
[
|
152
|
+
qyz.schubpoly_quantum(
|
153
|
+
tuple(_coerce_index(k[0], self.parent()._ascode, False)),
|
154
|
+
self.parent()._base_polynomial_ring.gens(),
|
155
|
+
self.parent()._coeff_polynomial_rings[k[1]].gens(),
|
156
|
+
self.parent()._q_ring.gens(),
|
157
|
+
v,
|
158
|
+
)
|
159
|
+
for k, v in self.monomial_coefficients().items()
|
160
|
+
]
|
161
|
+
)
|
162
|
+
else:
|
163
|
+
return sum(
|
164
|
+
[
|
165
|
+
yz.schubmult(
|
166
|
+
{(1, 2): v},
|
167
|
+
tuple(_coerce_index(k[0], self.parent()._ascode, False)),
|
168
|
+
self.parent()._base_polynomial_ring.gens(),
|
169
|
+
self.parent()._coeff_polynomial_rings[k[1]].gens(),
|
170
|
+
).get((1, 2), 0)
|
171
|
+
for k, v in self.monomial_coefficients().items()
|
172
|
+
]
|
173
|
+
)
|
174
|
+
|
175
|
+
def __eq__(self, other):
|
176
|
+
ss = self.parent().one() * self
|
177
|
+
oo = self.parent().one() * other
|
178
|
+
return ss.monomial_coefficients() == oo.monomial_coefficients()
|
179
|
+
|
180
|
+
def __ne__(self, other):
|
181
|
+
ss = self.parent().one() * self
|
182
|
+
oo = self.parent().one() * other
|
183
|
+
return ss.monomial_coefficients() != oo.monomial_coefficients()
|
184
|
+
|
185
|
+
def root_coefficients(self, root_var_name):
|
186
|
+
num_vars = len(self.parent()._coeff_polynomial_ring.gens())
|
187
|
+
RR = PolynomialRing(self.parent().base_ring().base_ring(), num_vars, root_var_name)
|
188
|
+
r = [sum(RR._first_ngens(j)) for j in range(num_vars)]
|
189
|
+
subs_dict = {self.parent()._coeff_polynomial_ring.gens()[i]: r[i] for i in range(num_vars)}
|
190
|
+
# res = self
|
191
|
+
return self.map_coefficients(lambda foi: RR(foi.subs(subs_dict)))
|
192
|
+
|
193
|
+
|
194
|
+
class FastDoubleSchubertPolynomialRing_xbasis(CombinatorialFreeModule):
|
195
|
+
Element = FastDoubleSchubertPolynomial_class
|
196
|
+
|
197
|
+
def __init__(
|
198
|
+
self,
|
199
|
+
R,
|
200
|
+
num_vars,
|
201
|
+
base_variable_name,
|
202
|
+
coeff_variable_names,
|
203
|
+
q_varname,
|
204
|
+
code_display,
|
205
|
+
indices,
|
206
|
+
quantum,
|
207
|
+
QR,
|
208
|
+
):
|
209
|
+
self._name = f"{'Quantum double' if quantum else 'Double'} Schubert polynomial ring"
|
210
|
+
self._splitter = indices
|
211
|
+
self._repr_option_bracket = False
|
212
|
+
self._mixed = False
|
213
|
+
self._q_ring = QR
|
214
|
+
self._quantum = quantum
|
215
|
+
self._base_varname = base_variable_name
|
216
|
+
self._q_varname = q_varname
|
217
|
+
|
218
|
+
if isinstance(coeff_variable_names, tuple):
|
219
|
+
self._mixed = True
|
220
|
+
self._varlist = [*coeff_variable_names]
|
221
|
+
self._coeff_polynomial_rings = {
|
222
|
+
name: PolynomialRing(R if not quantum else QR, num_vars, name)
|
223
|
+
for name in self._varlist
|
224
|
+
}
|
225
|
+
|
226
|
+
self._coeff_polynomial_ring = R if not quantum else QR
|
227
|
+
for name, CR in self._coeff_polynomial_rings.items():
|
228
|
+
self._coeff_polynomial_ring = PolynomialRing(
|
229
|
+
self._coeff_polynomial_ring, num_vars, name
|
230
|
+
)
|
231
|
+
self._coeff_polynomial_ring = FlatteningMorphism(self._coeff_polynomial_ring).codomain()
|
232
|
+
else:
|
233
|
+
self._varlist = [coeff_variable_names]
|
234
|
+
self._coeff_polynomial_ring = PolynomialRing(
|
235
|
+
R if not quantum else QR, num_vars, coeff_variable_names
|
236
|
+
)
|
237
|
+
self._coeff_polynomial_rings = {}
|
238
|
+
self._coeff_polynomial_rings[coeff_variable_names] = self._coeff_polynomial_ring
|
239
|
+
|
240
|
+
index_set = Permutations()
|
241
|
+
self._ascode = False
|
242
|
+
|
243
|
+
if code_display:
|
244
|
+
index_set = Compositions()
|
245
|
+
self._ascode = True
|
246
|
+
|
247
|
+
self._base_polynomial_ring = PolynomialRing(
|
248
|
+
self._coeff_polynomial_ring, num_vars, base_variable_name
|
249
|
+
)
|
250
|
+
|
251
|
+
self._index_wrapper = cartesian_product([index_set, self._varlist])
|
252
|
+
cat = (
|
253
|
+
GradedAlgebrasWithBasis(self._coeff_polynomial_ring).Commutative()
|
254
|
+
if quantum
|
255
|
+
else GradedBialgebrasWithBasis(self._coeff_polynomial_ring).Commutative()
|
256
|
+
)
|
257
|
+
|
258
|
+
CombinatorialFreeModule.__init__(
|
259
|
+
self,
|
260
|
+
self._coeff_polynomial_ring,
|
261
|
+
self._index_wrapper,
|
262
|
+
category=cat,
|
263
|
+
prefix=f"{'Q' if quantum else ''}S{base_variable_name}",
|
264
|
+
)
|
265
|
+
self._populate_coercion_lists_()
|
266
|
+
|
267
|
+
@cached_method
|
268
|
+
def one_basis(self):
|
269
|
+
return (_coerce_index([1], False, self._ascode), self._varlist[0])
|
270
|
+
|
271
|
+
@property
|
272
|
+
def is_quantum(self):
|
273
|
+
return self._quantum
|
274
|
+
|
275
|
+
def set_coproduct_indices(self, indices):
|
276
|
+
self._splitter = indices
|
277
|
+
|
278
|
+
def _element_constructor_(self, *x):
|
279
|
+
if len(x) == 1:
|
280
|
+
x = x[0]
|
281
|
+
elif len(x) > 2:
|
282
|
+
raise ValueError("Bad index for element")
|
283
|
+
|
284
|
+
if (
|
285
|
+
isinstance(x, list)
|
286
|
+
or isinstance(x, tuple)
|
287
|
+
or isinstance(x, Permutation)
|
288
|
+
or isinstance(x, Composition)
|
289
|
+
):
|
290
|
+
# checking the input to avoid symmetrica crashing Sage, see trac 12924
|
291
|
+
if x in self._index_wrapper:
|
292
|
+
elem = self._from_dict({self._index_wrapper((x[0], x[1])): self.base_ring().one()})
|
293
|
+
else:
|
294
|
+
elem = self._from_dict(
|
295
|
+
{
|
296
|
+
self._index_wrapper(
|
297
|
+
(
|
298
|
+
_coerce_index(x, self._ascode, self._ascode),
|
299
|
+
self._varlist[0],
|
300
|
+
)
|
301
|
+
): self.base_ring().one()
|
302
|
+
}
|
303
|
+
)
|
304
|
+
elif isinstance(x, FastDoubleSchubertPolynomial):
|
305
|
+
if (
|
306
|
+
x.base_varname == self._base_varname
|
307
|
+
and (self._quantum == x.parent()._quantum)
|
308
|
+
and (not self._quantum or x.q_varname == self._q_varname)
|
309
|
+
):
|
310
|
+
elem = self._from_dict(
|
311
|
+
{
|
312
|
+
(_coerce_index(k[0], x.parent()._ascode, self._ascode), k[1]): v
|
313
|
+
for k, v in x.monomial_coefficients().items()
|
314
|
+
}
|
315
|
+
)
|
316
|
+
else:
|
317
|
+
return self(x.expand())
|
318
|
+
elif isinstance(x, FastSchubertPolynomial):
|
319
|
+
if (
|
320
|
+
x.base_varname == self._base_varname
|
321
|
+
and x.q_varname == self._q_varname
|
322
|
+
and (self._quantum == x.parent()._quantum)
|
323
|
+
and (not self._quantum or x.q_varname == self._q_varname)
|
324
|
+
):
|
325
|
+
elem_dict = {}
|
326
|
+
|
327
|
+
for k, v in x.monomial_coefficients().items():
|
328
|
+
if self._quantum:
|
329
|
+
res = qyz.schubmult_db(
|
330
|
+
{(1, 2): self._coeff_polynomial_ring(v)},
|
331
|
+
tuple(_coerce_index(k, x.parent()._ascode, False)),
|
332
|
+
self._coeff_polynomial_rings[self._varlist[0]].gens(),
|
333
|
+
[
|
334
|
+
0
|
335
|
+
for i in range(
|
336
|
+
len(self._coeff_polynomial_rings[self._varlist[0]].gens())
|
337
|
+
)
|
338
|
+
],
|
339
|
+
self._q_ring.gens(),
|
340
|
+
)
|
341
|
+
else:
|
342
|
+
res = yz.schubmult(
|
343
|
+
{(1, 2): self._coeff_polynomial_ring(v)},
|
344
|
+
tuple(_coerce_index(k, x.parent()._ascode, False)),
|
345
|
+
self._coeff_polynomial_rings[self._varlist[0]].gens(),
|
346
|
+
[
|
347
|
+
0
|
348
|
+
for i in range(
|
349
|
+
len(self._coeff_polynomial_rings[self._varlist[0]].gens())
|
350
|
+
)
|
351
|
+
],
|
352
|
+
)
|
353
|
+
for k0, c0 in res.items():
|
354
|
+
elem_dict[(_coerce_index(k0, False, self._ascode), self._varlist[0])] = (
|
355
|
+
elem_dict.get(
|
356
|
+
(_coerce_index(k0, False, self._ascode), self._varlist[0]),
|
357
|
+
self._coeff_polynomial_ring.zero(),
|
358
|
+
)
|
359
|
+
+ self._coeff_polynomial_ring(c0)
|
360
|
+
)
|
361
|
+
elem = self._from_dict(elem_dict)
|
362
|
+
else:
|
363
|
+
elem = self(x.expand())
|
364
|
+
elif isinstance(x, MPolynomial):
|
365
|
+
from sage.interfaces.sympy import sympy_init
|
366
|
+
|
367
|
+
sympy_init()
|
368
|
+
sympy_floff = sympify(str(x))
|
369
|
+
val = syme.sympify(sympy_floff)
|
370
|
+
if self._quantum:
|
371
|
+
result = qyz.mult_poly(
|
372
|
+
{(1, 2): 1},
|
373
|
+
val,
|
374
|
+
[syme.Symbol(str(g)) for g in self._base_polynomial_ring.gens()],
|
375
|
+
[
|
376
|
+
syme.Symbol(str(g))
|
377
|
+
for g in self._coeff_polynomial_rings[self._varlist[0]].gens()
|
378
|
+
],
|
379
|
+
[syme.Symbol(str(g)) for g in self._q_ring.gens()],
|
380
|
+
)
|
381
|
+
else:
|
382
|
+
result = yz.mult_poly(
|
383
|
+
{(1, 2): 1},
|
384
|
+
val,
|
385
|
+
[syme.Symbol(str(g)) for g in self._base_polynomial_ring.gens()],
|
386
|
+
[
|
387
|
+
syme.Symbol(str(g))
|
388
|
+
for g in self._coeff_polynomial_rings[self._varlist[0]].gens()
|
389
|
+
],
|
390
|
+
)
|
391
|
+
elem = self._from_dict(
|
392
|
+
{
|
393
|
+
(
|
394
|
+
_coerce_index(k, False, self._ascode),
|
395
|
+
self._varlist[0],
|
396
|
+
): self._coeff_polynomial_ring(str(v))
|
397
|
+
for k, v in result.items()
|
398
|
+
}
|
399
|
+
)
|
400
|
+
else:
|
401
|
+
raise TypeError
|
402
|
+
|
403
|
+
return elem
|
404
|
+
|
405
|
+
def some_elements(self):
|
406
|
+
return [
|
407
|
+
self.one(),
|
408
|
+
self(_coerce_index([1], False, self._ascode))
|
409
|
+
+ 2 * self(_coerce_index([2, 1], False, self._ascode)),
|
410
|
+
self(_coerce_index([4, 2, 1, 3], False, self._ascode))
|
411
|
+
- self(_coerce_index([3, 2, 1], False, self._ascode)),
|
412
|
+
]
|
413
|
+
|
414
|
+
def product_on_basis(self, left, right):
|
415
|
+
le = tuple(left[0])
|
416
|
+
ri = tuple(right[0])
|
417
|
+
var_y = [
|
418
|
+
self._coeff_polynomial_ring(g) for g in self._coeff_polynomial_rings[left[1]].gens()
|
419
|
+
]
|
420
|
+
var_z = [
|
421
|
+
self._coeff_polynomial_ring(g) for g in self._coeff_polynomial_rings[right[1]].gens()
|
422
|
+
]
|
423
|
+
if self._quantum:
|
424
|
+
result = qyz.schubmult_db(
|
425
|
+
{tuple(_coerce_index(le, self._ascode, False)): 1},
|
426
|
+
tuple(_coerce_index(ri, self._ascode, False)),
|
427
|
+
var_y,
|
428
|
+
var_z,
|
429
|
+
self._q_ring.gens(),
|
430
|
+
)
|
431
|
+
else:
|
432
|
+
result = yz.schubmult(
|
433
|
+
{tuple(_coerce_index(le, self._ascode, False)): 1},
|
434
|
+
tuple(_coerce_index(ri, self._ascode, False)),
|
435
|
+
var_y,
|
436
|
+
var_z,
|
437
|
+
)
|
438
|
+
result = {k: v for k, v in result.items() if v != 0}
|
439
|
+
return sum(
|
440
|
+
[
|
441
|
+
self._coeff_polynomial_ring(v)
|
442
|
+
* self((_coerce_index(k, False, self._ascode), left[1]))
|
443
|
+
for k, v in result.items()
|
444
|
+
]
|
445
|
+
)
|
446
|
+
|
447
|
+
def _coerce_map_from_(self, S):
|
448
|
+
if isinstance(S, MPolynomialRing_base):
|
449
|
+
return True
|
450
|
+
if isinstance(S, FastSchubertPolynomialRing_base):
|
451
|
+
return True
|
452
|
+
if isinstance(S, FastDoubleSchubertPolynomialRing_base):
|
453
|
+
return True
|
454
|
+
return super().has_coerce_map_from(S)
|
455
|
+
|
456
|
+
def coproduct_on_basis(self, indm):
|
457
|
+
if self._quantum:
|
458
|
+
raise NotImplementedError("Quantum double Schubert polynomials have no coproduct")
|
459
|
+
indices = self._splitter
|
460
|
+
indices = sorted(indices)
|
461
|
+
subs_dict_coprod = {}
|
462
|
+
mperm = indm[0]
|
463
|
+
mperm = _coerce_index(mperm, self._ascode, False)
|
464
|
+
RR = self._coeff_polynomial_rings[indm[1]]
|
465
|
+
RBase = self._coeff_polynomial_rings[self._varlist[0]]
|
466
|
+
k = len(indices)
|
467
|
+
n = len(mperm)
|
468
|
+
kcd = [indices[i] - i - 1 for i in range(len(indices))] + [n + 1 - k for i in range(k, n)]
|
469
|
+
max_required = max([kcd[i] + i for i in range(len(kcd))])
|
470
|
+
kcd2 = kcd + [0 for i in range(len(kcd), max_required)] + [0]
|
471
|
+
N = len(kcd)
|
472
|
+
kperm = from_lehmer_code(kcd2).inverse()
|
473
|
+
# r = [sum(self.base_ring()._first_ngens(j)) for j in range(100)]
|
474
|
+
vn = [f"soible_{i}" for i in range(N * 2 + 1)]
|
475
|
+
TR = PolynomialRing(self.base_ring(), N * 2 + 1, vn)
|
476
|
+
|
477
|
+
for i in range(N * 2 + 1):
|
478
|
+
if i <= N:
|
479
|
+
subs_dict_coprod[TR.gens()[i]] = self._coeff_polynomial_ring(RR.gens()[i])
|
480
|
+
else:
|
481
|
+
subs_dict_coprod[TR.gens()[i]] = self._coeff_polynomial_ring(RBase.gens()[i - N])
|
482
|
+
|
483
|
+
coeff_dict = {tuple(kperm): 1}
|
484
|
+
coeff_dict = yz.schubmult(
|
485
|
+
coeff_dict,
|
486
|
+
tuple(mperm),
|
487
|
+
list(TR.gens()),
|
488
|
+
RR.gens(),
|
489
|
+
)
|
490
|
+
|
491
|
+
inv_kperm = kperm.number_of_inversions()
|
492
|
+
inverse_kperm = kperm.inverse()
|
493
|
+
total_sum = 0
|
494
|
+
for perm, val in coeff_dict.items():
|
495
|
+
pperm = Permutation(list(perm))
|
496
|
+
downperm = pperm.left_action_product(inverse_kperm)
|
497
|
+
if downperm.number_of_inversions() == pperm.number_of_inversions() - inv_kperm:
|
498
|
+
flag = True
|
499
|
+
for i in range(N):
|
500
|
+
if downperm[i] > N:
|
501
|
+
flag = False
|
502
|
+
break
|
503
|
+
if not flag:
|
504
|
+
continue
|
505
|
+
firstperm = Permutation(list(downperm[0:N]))
|
506
|
+
secondperm = Permutation([downperm[i] - N for i in range(N, len(downperm))])
|
507
|
+
val = TR(val).subs(subs_dict_coprod)
|
508
|
+
total_sum += self._coeff_polynomial_ring(val) * self(
|
509
|
+
(_coerce_index(firstperm, False, self._ascode), indm[1])
|
510
|
+
).tensor(
|
511
|
+
self(
|
512
|
+
(
|
513
|
+
_coerce_index(secondperm, False, self._ascode),
|
514
|
+
self._varlist[0],
|
515
|
+
)
|
516
|
+
)
|
517
|
+
)
|
518
|
+
return total_sum
|
519
|
+
|
520
|
+
def _repr_(self):
|
521
|
+
return (
|
522
|
+
f"Ring of {'quantum' if self._quantum else ''} double Schubert polynomials in {self._base_varname}{',' + self._q_varname if self._quantum else ''} with {len(self._base_polynomial_ring.gens())} variables with"
|
523
|
+
f" coefficient variables {','.join(self._varlist)} over the ring {self._coeff_polynomial_ring.base_ring()} indexed by {'the Lehmer code' if self._ascode else 'permutations'}"
|
524
|
+
)
|
525
|
+
|
526
|
+
|
527
|
+
FastDoubleSchubertPolynomial = FastDoubleSchubertPolynomial_class
|
528
|
+
FastDoubleSchubertPolynomialRing_base = FastDoubleSchubertPolynomialRing_xbasis
|