schubmult 1.2.11__tar.gz → 1.3.0__tar.gz
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-1.2.11 → schubmult-1.3.0}/PKG-INFO +5 -3
- {schubmult-1.2.11 → schubmult-1.3.0}/README.md +4 -2
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/perm_lib.py +46 -0
- schubmult-1.3.0/schubmult/schubmult_q/__init__.py +2 -0
- schubmult-1.3.0/schubmult/schubmult_q/__main__.py +5 -0
- schubmult-1.3.0/schubmult/schubmult_q/schubmult_q.py +105 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/schubmult_yz.py +165 -9
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/PKG-INFO +5 -3
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/SOURCES.txt +3 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/entry_points.txt +1 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/setup.py +3 -2
- {schubmult-1.2.11 → schubmult-1.3.0}/LICENSE +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/__init__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/__init__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/__main__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/schubmult_double.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/__init__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/__main__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/schubmult_py.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/__init__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/__main__.py +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/dependency_links.txt +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/requires.txt +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/top_level.txt +0 -0
- {schubmult-1.2.11 → schubmult-1.3.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: schubmult
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: Computing Littlewood-Richardson coefficients of Schubert polynomials
|
5
5
|
Home-page: https://github.com/matthematics/schubmult
|
6
6
|
Author: Matt Samuel
|
@@ -15,12 +15,13 @@ License-File: LICENSE
|
|
15
15
|
|
16
16
|
## Program and package for computing Littlewood-Richardson coefficients of Schubert polynomials
|
17
17
|
|
18
|
-
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
18
|
+
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. Since version 1.3.0, it also handles quantum Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
19
19
|
|
20
20
|
```
|
21
21
|
schubmult_py 1 2 4 9 11 6 8 12 3 5 7 10 - 6 8 1 2 3 4 7 10 12 14 5 9 11 13
|
22
22
|
schubmult_double 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
23
23
|
schubmult_yz 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
24
|
+
schubmult_q 5 1 4 3 2 - 2 1 3 5 4
|
24
25
|
```
|
25
26
|
|
26
27
|
The same execution with the Lehmer code:
|
@@ -29,6 +30,7 @@ The same execution with the Lehmer code:
|
|
29
30
|
schubmult_py -code 0 0 1 5 6 2 3 4 - 5 6 0 0 0 0 1 2 3 4
|
30
31
|
schubmult_double -code 0 1 1 2 - 1 0 2 3
|
31
32
|
schubmult_yz -code 0 1 1 2 - 1 0 2 3
|
33
|
+
schubmult_q -code 4 0 2 1 - 1 0 0 1
|
32
34
|
```
|
33
35
|
|
34
36
|
For coproducts:
|
@@ -50,7 +52,7 @@ Runtime will vary tremendously by case. The general problem is #P-hard. Though t
|
|
50
52
|
|
51
53
|
schubmult_py is for multiplying ordinary Schubert polynomials. schubmult_yz is for multiplying double Schubert polynomials in different sets of coefficient variables (labeled y and z), and schubmult_double is for multiplying double Schubert polynomials in the same set of coefficient variables. Both have the same command line syntax as schubmult. schubmult_double displays the result with nonnegative coefficients in terms of the negative simple roots. Both are of course slower than schubmult_py, and expressing the result positively for schubmult_double slows it down even more.
|
52
54
|
|
53
|
-
New in version 1.1.0,
|
55
|
+
New in version 1.1.0, schubmult_xx -coprod allows you to split (double) Schubert polynomials along certain indices (not available for schubmult_q). It takes one permutation as an argument, followed by a dash -, then the set of indices you would like to split on. These coefficients are always nonnegative since they occur as product coefficients (this is actually how they are computed).
|
54
56
|
|
55
57
|
When imported as a python package, the relevant packages are schubmult.perm_lib, which has various permutation manipulation functions, and three modules that have functions of the same name (function name is "schubmult"): schubmult.schubmult_py, schubmult.schubmult_yz, schubmult.schubmult_double. Function takes a permutation dictionary (keys are tuples of ints, which must be trimmed permutations, and values are either integers or symengine values, which can also be integers) as well as a permutation as its second argument, which is the (double) Schubert polynomial to multiply by. Returns a dictionary of the same form with the coefficients.
|
56
58
|
|
@@ -2,12 +2,13 @@
|
|
2
2
|
|
3
3
|
## Program and package for computing Littlewood-Richardson coefficients of Schubert polynomials
|
4
4
|
|
5
|
-
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
5
|
+
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. Since version 1.3.0, it also handles quantum Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
6
6
|
|
7
7
|
```
|
8
8
|
schubmult_py 1 2 4 9 11 6 8 12 3 5 7 10 - 6 8 1 2 3 4 7 10 12 14 5 9 11 13
|
9
9
|
schubmult_double 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
10
10
|
schubmult_yz 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
11
|
+
schubmult_q 5 1 4 3 2 - 2 1 3 5 4
|
11
12
|
```
|
12
13
|
|
13
14
|
The same execution with the Lehmer code:
|
@@ -16,6 +17,7 @@ The same execution with the Lehmer code:
|
|
16
17
|
schubmult_py -code 0 0 1 5 6 2 3 4 - 5 6 0 0 0 0 1 2 3 4
|
17
18
|
schubmult_double -code 0 1 1 2 - 1 0 2 3
|
18
19
|
schubmult_yz -code 0 1 1 2 - 1 0 2 3
|
20
|
+
schubmult_q -code 4 0 2 1 - 1 0 0 1
|
19
21
|
```
|
20
22
|
|
21
23
|
For coproducts:
|
@@ -37,7 +39,7 @@ Runtime will vary tremendously by case. The general problem is #P-hard. Though t
|
|
37
39
|
|
38
40
|
schubmult_py is for multiplying ordinary Schubert polynomials. schubmult_yz is for multiplying double Schubert polynomials in different sets of coefficient variables (labeled y and z), and schubmult_double is for multiplying double Schubert polynomials in the same set of coefficient variables. Both have the same command line syntax as schubmult. schubmult_double displays the result with nonnegative coefficients in terms of the negative simple roots. Both are of course slower than schubmult_py, and expressing the result positively for schubmult_double slows it down even more.
|
39
41
|
|
40
|
-
New in version 1.1.0,
|
42
|
+
New in version 1.1.0, schubmult_xx -coprod allows you to split (double) Schubert polynomials along certain indices (not available for schubmult_q). It takes one permutation as an argument, followed by a dash -, then the set of indices you would like to split on. These coefficients are always nonnegative since they occur as product coefficients (this is actually how they are computed).
|
41
43
|
|
42
44
|
When imported as a python package, the relevant packages are schubmult.perm_lib, which has various permutation manipulation functions, and three modules that have functions of the same name (function name is "schubmult"): schubmult.schubmult_py, schubmult.schubmult_yz, schubmult.schubmult_double. Function takes a permutation dictionary (keys are tuples of ints, which must be trimmed permutations, and values are either integers or symengine values, which can also be integers) as well as a permutation as its second argument, which is the (double) Schubert polynomial to multiply by. Returns a dictionary of the same form with the coefficients.
|
43
45
|
|
@@ -2,6 +2,11 @@ from symengine import *
|
|
2
2
|
from functools import cache
|
3
3
|
from itertools import chain
|
4
4
|
from bisect import bisect_left
|
5
|
+
import numpy as np
|
6
|
+
|
7
|
+
n = 100
|
8
|
+
|
9
|
+
q_var = symarray("q",n)
|
5
10
|
|
6
11
|
def inv(perm):
|
7
12
|
L = len(perm)
|
@@ -86,6 +91,20 @@ def has_bruhat_descent(perm,i,j):
|
|
86
91
|
return False
|
87
92
|
return True
|
88
93
|
|
94
|
+
def count_bruhat(perm,i,j):
|
95
|
+
up_amount = 0
|
96
|
+
if perm[i]<perm[j]:
|
97
|
+
up_amount = 1
|
98
|
+
else:
|
99
|
+
up_amount = -1
|
100
|
+
for k in range(i+1,j):
|
101
|
+
if perm[i]<perm[k] and perm[j]>perm[k]:
|
102
|
+
up_amount+=1
|
103
|
+
elif perm[i]>perm[k] and perm[j]<perm[k]:
|
104
|
+
up_amount-=1
|
105
|
+
return up_amount
|
106
|
+
|
107
|
+
|
89
108
|
def has_bruhat_ascent(perm,i,j):
|
90
109
|
if perm[i]>perm[j]:
|
91
110
|
return False
|
@@ -120,6 +139,33 @@ def elem_sym_perms(orig_perm,p,k):
|
|
120
139
|
up_perm_list = perm_list
|
121
140
|
return total_list
|
122
141
|
|
142
|
+
|
143
|
+
def elem_sym_perms_q(orig_perm,p,k):
|
144
|
+
total_list = [(orig_perm,0,1)]
|
145
|
+
up_perm_list = [(orig_perm,1,1000)]
|
146
|
+
for pp in range(p):
|
147
|
+
perm_list = []
|
148
|
+
for up_perm, last, last_j in up_perm_list:
|
149
|
+
up_perm2 = [*up_perm,len(up_perm)+1]
|
150
|
+
if len(up_perm2) < k + 1:
|
151
|
+
up_perm2 += [i+1 for i in range(len(up_perm2),k+2)]
|
152
|
+
pos_list = [i for i in range(k) if i>=len(orig_perm) or up_perm2[i] == orig_perm[i]]
|
153
|
+
for j in range(min(last_j,len(up_perm2)-1),k-1,-1):
|
154
|
+
for i in pos_list:
|
155
|
+
ct = count_bruhat(up_perm2,i,j)
|
156
|
+
if ct == 1 or ct == 2*(i-j)+1:
|
157
|
+
new_perm = [*up_perm2]
|
158
|
+
new_perm[i],new_perm[j] = new_perm[j],new_perm[i]
|
159
|
+
new_perm_add = tuple(permtrim(new_perm))
|
160
|
+
new_last = last
|
161
|
+
if ct<0:
|
162
|
+
new_last *= np.prod([q_var[index] for index in range(i+1,j+1)])
|
163
|
+
perm_list += [(new_perm_add,new_last,j)]
|
164
|
+
total_list+=[(new_perm_add,pp+1,new_last)]
|
165
|
+
up_perm_list = perm_list
|
166
|
+
return total_list
|
167
|
+
|
168
|
+
|
123
169
|
# perms and inversion diff
|
124
170
|
def kdown_perms(perm,monoperm,p,k):
|
125
171
|
inv_m = inv(monoperm)
|
@@ -0,0 +1,105 @@
|
|
1
|
+
from symengine import *
|
2
|
+
from functools import cache
|
3
|
+
from itertools import chain
|
4
|
+
from schubmult.perm_lib import *
|
5
|
+
import sys
|
6
|
+
|
7
|
+
def schubmult(perm_dict,v):
|
8
|
+
vn1 = inverse(v)
|
9
|
+
th = [len(v)-i for i in range(1,len(v))]
|
10
|
+
mu = permtrim(uncode(th))
|
11
|
+
vmu = permtrim(mulperm([*v],mu))
|
12
|
+
inv_vmu = inv(vmu)
|
13
|
+
inv_mu = inv(mu)
|
14
|
+
ret_dict = {}
|
15
|
+
vpaths = [([(vmu,0)],1)]
|
16
|
+
while th[-1] == 0:
|
17
|
+
th.pop()
|
18
|
+
thL = len(th)
|
19
|
+
vpathdicts = compute_vpathdicts(th,vmu,True)
|
20
|
+
for u,val in perm_dict.items():
|
21
|
+
inv_u = inv(u)
|
22
|
+
vpathsums = {u: {(1,2): val}}
|
23
|
+
for index in range(thL):
|
24
|
+
mx_th = 0
|
25
|
+
for vp in vpathdicts[index]:
|
26
|
+
for v2,vdiff,s in vpathdicts[index][vp]:
|
27
|
+
if th[index]-vdiff > mx_th:
|
28
|
+
mx_th = th[index] - vdiff
|
29
|
+
newpathsums = {}
|
30
|
+
for up in vpathsums:
|
31
|
+
newperms = elem_sym_perms_q(up,mx_th,th[index])
|
32
|
+
for vp in vpathsums[up]:
|
33
|
+
sumval = vpathsums[up][vp]
|
34
|
+
if sumval == 0:
|
35
|
+
continue
|
36
|
+
for v2,vdiff,s in vpathdicts[index][vp]:
|
37
|
+
addsumval = s*sumval
|
38
|
+
for up2, udiff, mul_val in newperms:
|
39
|
+
if vdiff + udiff == th[index]:
|
40
|
+
if up2 not in newpathsums:
|
41
|
+
newpathsums[up2]={}
|
42
|
+
newpathsums[up2][v2] = newpathsums[up2].get(v2,0)+mul_val*addsumval
|
43
|
+
vpathsums = newpathsums
|
44
|
+
toget = tuple(vmu)
|
45
|
+
ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
|
46
|
+
return ret_dict
|
47
|
+
|
48
|
+
|
49
|
+
def main():
|
50
|
+
try:
|
51
|
+
perms=[]
|
52
|
+
curperm = []
|
53
|
+
|
54
|
+
pr = True
|
55
|
+
ascode = False
|
56
|
+
try:
|
57
|
+
for s in sys.argv[1:]:
|
58
|
+
if s == "-np" or s == "--no-print":
|
59
|
+
pr = False
|
60
|
+
continue
|
61
|
+
if s == "-code":
|
62
|
+
ascode = True
|
63
|
+
continue
|
64
|
+
if s == "-":
|
65
|
+
perms += [curperm]
|
66
|
+
curperm = []
|
67
|
+
continue
|
68
|
+
curperm += [int(s)]
|
69
|
+
except Exception:
|
70
|
+
print("Usage: schubmult_q <-np|--no-print> <-code> perm1 - perm2 < - perm 3 ... >")
|
71
|
+
exit(1)
|
72
|
+
|
73
|
+
perms += [curperm]
|
74
|
+
|
75
|
+
|
76
|
+
if ascode:
|
77
|
+
for i in range(len(perms)):
|
78
|
+
perms[i] = uncode(perms[i])
|
79
|
+
|
80
|
+
coeff_dict = {tuple(permtrim([*perms[0]])): 1}
|
81
|
+
|
82
|
+
for perm in perms[1:]:
|
83
|
+
coeff_dict = schubmult(coeff_dict,tuple(permtrim([*perm])))
|
84
|
+
|
85
|
+
if pr:
|
86
|
+
if ascode:
|
87
|
+
width = max([len(str(trimcode(perm))) for perm in coeff_dict.keys()])
|
88
|
+
else:
|
89
|
+
width = max([len(str(perm)) for perm in coeff_dict.keys()])
|
90
|
+
|
91
|
+
coeff_perms = list(coeff_dict.keys())
|
92
|
+
coeff_perms.sort(key=lambda x: (inv(x),*x))
|
93
|
+
|
94
|
+
for perm in coeff_perms:
|
95
|
+
val = sympify(coeff_dict[perm]).expand()
|
96
|
+
if val != 0:
|
97
|
+
if ascode:
|
98
|
+
print(f"{str(trimcode(perm)):>{width}} {str(val).replace('**','^').replace('*',' ')}")
|
99
|
+
else:
|
100
|
+
print(f"{str(perm):>{width}} {str(val).replace('**','^').replace('*',' ')}")
|
101
|
+
except BrokenPipeError:
|
102
|
+
pass
|
103
|
+
|
104
|
+
if __name__ == "__main__":
|
105
|
+
main()
|
@@ -736,16 +736,43 @@ def is_hook(cd):
|
|
736
736
|
return True
|
737
737
|
return False
|
738
738
|
|
739
|
-
|
740
|
-
|
741
|
-
|
742
|
-
|
739
|
+
def div_diff(i,poly):
|
740
|
+
return sympify(sympy.div(sympy.sympify(poly - permy(poly,i)),sympy.sympify(var2[i]-var2[i+1]))[0])
|
741
|
+
|
742
|
+
def skew_div_diff(u,w,poly):
|
743
|
+
d = -1
|
744
|
+
for i in range(len(w)-1):
|
745
|
+
if w[i]>w[i+1]:
|
746
|
+
d = i
|
747
|
+
break
|
748
|
+
d2 = -1
|
749
|
+
for i in range(len(u)-1):
|
750
|
+
if u[i]>u[i+1]:
|
751
|
+
d2 = i
|
752
|
+
break
|
753
|
+
if d == -1:
|
754
|
+
if d2 == -1:
|
755
|
+
return poly
|
756
|
+
return 0
|
757
|
+
w2 = [*w]
|
758
|
+
w2[d], w2[d+1] = w2[d+1], w2[d]
|
759
|
+
if d<len(u)-1 and u[d]>u[d+1]:
|
760
|
+
u2 = [*u]
|
761
|
+
u2[d], u2[d+1] = u2[d+1], u2[d]
|
762
|
+
return skew_div_diff(u2,w2,permy(poly,d+1))
|
763
|
+
else:
|
764
|
+
return skew_div_diff(u,w2,div_diff(d+1,poly))
|
765
|
+
|
766
|
+
@cached(cache={}, key=lambda val, u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True,sign_only=False: hashkey(u2,v2,w2,var2,var3,msg,do_pos_neg,sign_only))
|
767
|
+
def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True,sign_only=False):
|
768
|
+
if inv(u2)+inv(v2) - inv(w2) == 0:
|
769
|
+
return val
|
743
770
|
cdv = code(v2)
|
744
771
|
if set(cdv) == set([0,1]) and do_pos_neg:
|
745
772
|
return val
|
746
773
|
#if is_hook(cdv):
|
747
774
|
# print(f"Could've {cdv}")
|
748
|
-
if expand(val) == 0:
|
775
|
+
if not sign_only and expand(val) == 0:
|
749
776
|
return 0
|
750
777
|
|
751
778
|
u, v, w = try_reduce_v(u2, v2, w2)
|
@@ -767,6 +794,9 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
767
794
|
u = tuple(u)
|
768
795
|
v = tuple(v)
|
769
796
|
w = tuple(w)
|
797
|
+
|
798
|
+
if w != w2 and sign_only:
|
799
|
+
return 0
|
770
800
|
|
771
801
|
if is_coeff_irreducible(u,v,w):
|
772
802
|
u3, v3, w3 = try_reduce_v(u, v, w)
|
@@ -777,8 +807,10 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
777
807
|
if not is_coeff_irreducible(u3,v3,w3):
|
778
808
|
u, v, w = u3, v3, w3
|
779
809
|
split_two_b, split_two = is_split_two(u,v,w)
|
780
|
-
|
810
|
+
|
781
811
|
if len([i for i in code(v) if i !=0]) == 1:
|
812
|
+
if sign_only:
|
813
|
+
return 0
|
782
814
|
cv = code(v)
|
783
815
|
for i in range(len(cv)):
|
784
816
|
if cv[i]!=0:
|
@@ -792,8 +824,12 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
792
824
|
hvarset = [w2[i] for i in range(min(len(w2),k))]+[i+1 for i in range(len(w2),k)] + [w2[b] for b in range(k,len(u)) if u[b]!=w2[b]]+[w2[b] for b in range(len(u),len(w2))]
|
793
825
|
val = elem_sym_poly(p-r,k+p-1,[-var3[i] for i in range(1,n)],[-var2[i] for i in hvarset])
|
794
826
|
elif (will_formula_work(v,u) or dominates(u,w)):
|
827
|
+
if sign_only:
|
828
|
+
return 0
|
795
829
|
val = dualcoeff(u,v,w,var2,var3)
|
796
830
|
elif inv(w) - inv(u) == 1:
|
831
|
+
if sign_only:
|
832
|
+
return 0
|
797
833
|
a, b = -1, -1
|
798
834
|
for i in range(len(w)):
|
799
835
|
if a == -1 and u[i] != w[i]:
|
@@ -847,6 +883,8 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
847
883
|
toadd *= schubpoly(v3,[0,var2[w[a]],var2[w[b]]],var3)
|
848
884
|
val += toadd
|
849
885
|
elif split_two_b:
|
886
|
+
if sign_only:
|
887
|
+
return 0
|
850
888
|
cycles = split_two
|
851
889
|
a1, b1 = cycles[0]
|
852
890
|
a2, b2 = cycles[1]
|
@@ -1000,7 +1038,53 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1000
1038
|
toadd*=tomul.subs(subs_dict3)
|
1001
1039
|
val += toadd
|
1002
1040
|
elif will_formula_work(u,v):
|
1041
|
+
if sign_only:
|
1042
|
+
return 0
|
1003
1043
|
val = forwardcoeff(u,v,w,var2,var3)
|
1044
|
+
#elif inv(w) - inv(u) == 2:
|
1045
|
+
# indices = []
|
1046
|
+
# for i in range(len(w)):
|
1047
|
+
# if i>=len(u) or u[i]!=w[i]:
|
1048
|
+
# indices += [i+1]
|
1049
|
+
# arr = [[[],v]]
|
1050
|
+
# d = -1
|
1051
|
+
# for i in range(len(v)-1):
|
1052
|
+
# if v[i]>v[i+1]:
|
1053
|
+
# d = i + 1
|
1054
|
+
# for i in range(d):
|
1055
|
+
# arr2 = []
|
1056
|
+
#
|
1057
|
+
# if i+1 in indices:
|
1058
|
+
# continue
|
1059
|
+
# i2 = 1
|
1060
|
+
# i2 += len([aa for aa in indices if i+1>aa])
|
1061
|
+
# for vr, v2 in arr:
|
1062
|
+
# dpret = pull_out_var(i2,[*v2])
|
1063
|
+
# for v3r, v3 in dpret:
|
1064
|
+
# arr2 += [[vr + [(v3r,i+1)],v3]]
|
1065
|
+
# arr = arr2
|
1066
|
+
# val = 0
|
1067
|
+
#
|
1068
|
+
# for L in arr:
|
1069
|
+
# v3 = [*L[-1]]
|
1070
|
+
# tomul = 1
|
1071
|
+
# pooly = skew_div_diff(u,w,schubpoly(v3,[0,*[var2[a] for a in indices]],var3))
|
1072
|
+
# coeff = compute_positive_rep(pooly,var2,var3,msg,False)
|
1073
|
+
# if coeff == -1:
|
1074
|
+
# return -1
|
1075
|
+
# tomul = sympify(coeff)
|
1076
|
+
# toadd = 1
|
1077
|
+
# for i in range(len(L[0])):
|
1078
|
+
# var_index = L[0][i][1]
|
1079
|
+
# oaf = L[0][i][0]
|
1080
|
+
# if var_index-1>=len(w):
|
1081
|
+
# yv = var_index
|
1082
|
+
# else:
|
1083
|
+
# yv = w[var_index-1]
|
1084
|
+
# for j in range(len(oaf)):
|
1085
|
+
# toadd*= var2[yv] - var3[oaf[j]]
|
1086
|
+
# toadd*=tomul#.subs(subs_dict3)
|
1087
|
+
# val += toadd
|
1004
1088
|
else:
|
1005
1089
|
c01 = code(u)
|
1006
1090
|
c02 = code(w)
|
@@ -1010,6 +1094,8 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1010
1094
|
c2 = code(inverse(w))
|
1011
1095
|
|
1012
1096
|
if one_dominates(u,w):
|
1097
|
+
if sign_only:
|
1098
|
+
return 0
|
1013
1099
|
while c1[0] != c2[0]:
|
1014
1100
|
w = [*w]
|
1015
1101
|
v = [*v]
|
@@ -1024,6 +1110,8 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1024
1110
|
|
1025
1111
|
|
1026
1112
|
if is_reducible(v):
|
1113
|
+
if sign_only:
|
1114
|
+
return 0
|
1027
1115
|
newc = []
|
1028
1116
|
elemc = []
|
1029
1117
|
for i in range(len(c03)):
|
@@ -1041,6 +1129,8 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1041
1129
|
newval = posify(newval,new_w,tuple(permtrim(uncode(newc))),w,var2,var3,msg,do_pos_neg)
|
1042
1130
|
val += tomul*shiftsubz(newval)
|
1043
1131
|
elif c01[0] == c02[0] and c01[0] != 0:
|
1132
|
+
if sign_only:
|
1133
|
+
return 0
|
1044
1134
|
varl = c01[0]
|
1045
1135
|
u3 = uncode([0] + c01[1:])
|
1046
1136
|
w3 = uncode([0] + c02[1:])
|
@@ -1050,6 +1140,8 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1050
1140
|
for i in range(varl):
|
1051
1141
|
val = permy(val,i+1)
|
1052
1142
|
elif c1[0] == c2[0]:
|
1143
|
+
if sign_only:
|
1144
|
+
return 0
|
1053
1145
|
vp = pull_out_var(c1[0]+1,[*v])
|
1054
1146
|
u3 = tuple(permtrim(phi1(u)))
|
1055
1147
|
w3 = tuple(permtrim(phi1(w)))
|
@@ -1064,10 +1156,74 @@ def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
|
|
1064
1156
|
val2 = schubmult_one(tuple(permtrim(u3)),tuple(permtrim(v3)),var2,var3).get(tuple(permtrim(w3)),0)
|
1065
1157
|
val2 = posify(val2,u3,tuple(permtrim(v3)),w3,var2,var3,msg,do_pos_neg)
|
1066
1158
|
val += tomul*shiftsub(val2)
|
1159
|
+
elif inv(w)-inv(u)==2:
|
1160
|
+
indices = []
|
1161
|
+
for i in range(len(w)):
|
1162
|
+
if i>=len(u) or u[i]!=w[i]:
|
1163
|
+
indices += [i+1]
|
1164
|
+
arr = [[[],v]]
|
1165
|
+
d = -1
|
1166
|
+
for i in range(len(v)-1):
|
1167
|
+
if v[i]>v[i+1]:
|
1168
|
+
d = i + 1
|
1169
|
+
for i in range(d):
|
1170
|
+
arr2 = []
|
1171
|
+
|
1172
|
+
if i+1 in indices:
|
1173
|
+
continue
|
1174
|
+
i2 = 1
|
1175
|
+
i2 += len([aa for aa in indices if i+1>aa])
|
1176
|
+
for vr, v2 in arr:
|
1177
|
+
dpret = pull_out_var(i2,[*v2])
|
1178
|
+
for v3r, v3 in dpret:
|
1179
|
+
arr2 += [[vr + [(v3r,i+1)],v3]]
|
1180
|
+
arr = arr2
|
1181
|
+
val = 0
|
1182
|
+
|
1183
|
+
for L in arr:
|
1184
|
+
v3 = [*L[-1]]
|
1185
|
+
tomul = 1
|
1186
|
+
toadd = 1
|
1187
|
+
for i in range(len(L[0])):
|
1188
|
+
var_index = L[0][i][1]
|
1189
|
+
oaf = L[0][i][0]
|
1190
|
+
if var_index-1>=len(w):
|
1191
|
+
yv = var_index
|
1192
|
+
else:
|
1193
|
+
yv = w[var_index-1]
|
1194
|
+
for j in range(len(oaf)):
|
1195
|
+
toadd*= var2[yv] - var3[oaf[j]]
|
1196
|
+
pooly = skew_div_diff(u,w,schubpoly(v3,[0,*[var2[a] for a in indices]],var3))
|
1197
|
+
if toadd == 0:
|
1198
|
+
continue
|
1199
|
+
if pooly !=0:
|
1200
|
+
coeff = compute_positive_rep(pooly,var2,var3,msg,False)
|
1201
|
+
else:
|
1202
|
+
coeff = 0
|
1203
|
+
if coeff == -1:
|
1204
|
+
return -1
|
1205
|
+
tomul = sympify(coeff)
|
1206
|
+
toadd*=tomul#.subs(subs_dict3)
|
1207
|
+
val += toadd
|
1067
1208
|
else:
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1209
|
+
if not sign_only:
|
1210
|
+
if inv(u)+inv(v)-inv(w)==1:
|
1211
|
+
val2 = compute_positive_rep(val,var2,var3,msg,False)
|
1212
|
+
else:
|
1213
|
+
val2 = compute_positive_rep(val,var2,var3,msg,do_pos_neg)
|
1214
|
+
if val2 is not None:
|
1215
|
+
val = val2
|
1216
|
+
else:
|
1217
|
+
#st = str(expand(val))
|
1218
|
+
#if st.find("-")!=-1:
|
1219
|
+
# return -1
|
1220
|
+
#else:
|
1221
|
+
# return val
|
1222
|
+
d = expand(val).as_coefficients_dict()
|
1223
|
+
for v in d.values():
|
1224
|
+
if v<0:
|
1225
|
+
return -1
|
1226
|
+
return 1
|
1071
1227
|
return val
|
1072
1228
|
|
1073
1229
|
def split_perms(perms):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: schubmult
|
3
|
-
Version: 1.
|
3
|
+
Version: 1.3.0
|
4
4
|
Summary: Computing Littlewood-Richardson coefficients of Schubert polynomials
|
5
5
|
Home-page: https://github.com/matthematics/schubmult
|
6
6
|
Author: Matt Samuel
|
@@ -15,12 +15,13 @@ License-File: LICENSE
|
|
15
15
|
|
16
16
|
## Program and package for computing Littlewood-Richardson coefficients of Schubert polynomials
|
17
17
|
|
18
|
-
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
18
|
+
This is a set of python scripts written by Matt Samuel for computing Littlewood-Richardson coefficients of (ordinary or double) Schubert polynomials. Since version 1.3.0, it also handles quantum Schubert polynomials. It has the same command line syntax as the program "schubmult" in lrcalc by Anders Buch. Example:
|
19
19
|
|
20
20
|
```
|
21
21
|
schubmult_py 1 2 4 9 11 6 8 12 3 5 7 10 - 6 8 1 2 3 4 7 10 12 14 5 9 11 13
|
22
22
|
schubmult_double 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
23
23
|
schubmult_yz 1 3 4 6 2 5 - 2 1 5 7 3 4 6
|
24
|
+
schubmult_q 5 1 4 3 2 - 2 1 3 5 4
|
24
25
|
```
|
25
26
|
|
26
27
|
The same execution with the Lehmer code:
|
@@ -29,6 +30,7 @@ The same execution with the Lehmer code:
|
|
29
30
|
schubmult_py -code 0 0 1 5 6 2 3 4 - 5 6 0 0 0 0 1 2 3 4
|
30
31
|
schubmult_double -code 0 1 1 2 - 1 0 2 3
|
31
32
|
schubmult_yz -code 0 1 1 2 - 1 0 2 3
|
33
|
+
schubmult_q -code 4 0 2 1 - 1 0 0 1
|
32
34
|
```
|
33
35
|
|
34
36
|
For coproducts:
|
@@ -50,7 +52,7 @@ Runtime will vary tremendously by case. The general problem is #P-hard. Though t
|
|
50
52
|
|
51
53
|
schubmult_py is for multiplying ordinary Schubert polynomials. schubmult_yz is for multiplying double Schubert polynomials in different sets of coefficient variables (labeled y and z), and schubmult_double is for multiplying double Schubert polynomials in the same set of coefficient variables. Both have the same command line syntax as schubmult. schubmult_double displays the result with nonnegative coefficients in terms of the negative simple roots. Both are of course slower than schubmult_py, and expressing the result positively for schubmult_double slows it down even more.
|
52
54
|
|
53
|
-
New in version 1.1.0,
|
55
|
+
New in version 1.1.0, schubmult_xx -coprod allows you to split (double) Schubert polynomials along certain indices (not available for schubmult_q). It takes one permutation as an argument, followed by a dash -, then the set of indices you would like to split on. These coefficients are always nonnegative since they occur as product coefficients (this is actually how they are computed).
|
54
56
|
|
55
57
|
When imported as a python package, the relevant packages are schubmult.perm_lib, which has various permutation manipulation functions, and three modules that have functions of the same name (function name is "schubmult"): schubmult.schubmult_py, schubmult.schubmult_yz, schubmult.schubmult_double. Function takes a permutation dictionary (keys are tuples of ints, which must be trimmed permutations, and values are either integers or symengine values, which can also be integers) as well as a permutation as its second argument, which is the (double) Schubert polynomial to multiply by. Returns a dictionary of the same form with the coefficients.
|
56
58
|
|
@@ -16,6 +16,9 @@ schubmult/schubmult_double/schubmult_double.py
|
|
16
16
|
schubmult/schubmult_py/__init__.py
|
17
17
|
schubmult/schubmult_py/__main__.py
|
18
18
|
schubmult/schubmult_py/schubmult_py.py
|
19
|
+
schubmult/schubmult_q/__init__.py
|
20
|
+
schubmult/schubmult_q/__main__.py
|
21
|
+
schubmult/schubmult_q/schubmult_q.py
|
19
22
|
schubmult/schubmult_yz/__init__.py
|
20
23
|
schubmult/schubmult_yz/__main__.py
|
21
24
|
schubmult/schubmult_yz/schubmult_yz.py
|
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text()
|
|
6
6
|
|
7
7
|
setup(
|
8
8
|
name="schubmult",
|
9
|
-
version="1.
|
9
|
+
version="1.3.0",
|
10
10
|
description="Computing Littlewood-Richardson coefficients of Schubert polynomials",
|
11
11
|
long_description=long_description,
|
12
12
|
long_description_content_type='text/markdown',
|
@@ -30,6 +30,7 @@ setup(
|
|
30
30
|
],
|
31
31
|
entry_points={"console_scripts": ["schubmult_py=schubmult.schubmult_py.__main__:main",
|
32
32
|
"schubmult_double=schubmult.schubmult_double.__main__:main",
|
33
|
-
"schubmult_yz=schubmult.schubmult_yz.__main__:main"
|
33
|
+
"schubmult_yz=schubmult.schubmult_yz.__main__:main",
|
34
|
+
"schubmult_q=schubmult.schubmult_q.__main__:main"
|
34
35
|
]},
|
35
36
|
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|