schubmult 1.3.6__tar.gz → 1.3.8__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.
Files changed (31) hide show
  1. {schubmult-1.3.6 → schubmult-1.3.8}/PKG-INFO +5 -2
  2. {schubmult-1.3.6 → schubmult-1.3.8}/README.md +4 -1
  3. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/perm_lib.py +48 -0
  4. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_double/schubmult_double.py +15 -4
  5. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_py/schubmult_py.py +60 -4
  6. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q/schubmult_q.py +56 -0
  7. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_double/schubmult_q_double.py +13 -2
  8. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_yz/schubmult_q_yz.py +157 -26
  9. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_yz/schubmult_yz.py +181 -11
  10. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/PKG-INFO +5 -2
  11. {schubmult-1.3.6 → schubmult-1.3.8}/setup.py +1 -1
  12. {schubmult-1.3.6 → schubmult-1.3.8}/LICENSE +0 -0
  13. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/__init__.py +0 -0
  14. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_double/__init__.py +0 -0
  15. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_double/__main__.py +0 -0
  16. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_py/__init__.py +0 -0
  17. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_py/__main__.py +0 -0
  18. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q/__init__.py +0 -0
  19. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q/__main__.py +0 -0
  20. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_double/__init__.py +0 -0
  21. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_double/__main__.py +0 -0
  22. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_yz/__init__.py +0 -0
  23. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_q_yz/__main__.py +0 -0
  24. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_yz/__init__.py +0 -0
  25. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult/schubmult_yz/__main__.py +0 -0
  26. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/SOURCES.txt +0 -0
  27. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/dependency_links.txt +0 -0
  28. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/entry_points.txt +0 -0
  29. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/requires.txt +0 -0
  30. {schubmult-1.3.6 → schubmult-1.3.8}/schubmult.egg-info/top_level.txt +0 -0
  31. {schubmult-1.3.6 → schubmult-1.3.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schubmult
3
- Version: 1.3.6
3
+ Version: 1.3.8
4
4
  Summary: Computing Littlewood-Richardson coefficients of Schubert polynomials
5
5
  Home-page: https://github.com/matthematics/schubmult
6
6
  Author: Matt Samuel
@@ -50,7 +50,10 @@ schubmult_double -code -coprod 0 1 2 3 - 2 4
50
50
  schubmult_yz -code -coprod 0 1 2 3 - 2 4 --display-positive
51
51
  ```
52
52
 
53
-
53
+ Since version 1.3.7, schubmult_q_yz has a feature for displaying the coefficients of the divided difference operators in the evaluation of the quantum double Schubert polynomials on the commuting difference operators of Fomin, Gelfand, and Postnikov. It is necessary to cap the value of n in the group S_n we are working in because as n increases the expression does not stabilize.
54
+ ```
55
+ schubmult_q_yz -nil-hecke 6 -code 2 2 --display-positive
56
+ ```
54
57
 
55
58
  Runtime will vary tremendously by case. The general problem is #P-hard. Though the result is always nonnegative (which at least is known for schubmult_py, schubmult_q, schubmult_double, and schubmult_q_double) and the problem is in GapP, it is not known to be in #P at this time.
56
59
 
@@ -37,7 +37,10 @@ schubmult_double -code -coprod 0 1 2 3 - 2 4
37
37
  schubmult_yz -code -coprod 0 1 2 3 - 2 4 --display-positive
38
38
  ```
39
39
 
40
-
40
+ Since version 1.3.7, schubmult_q_yz has a feature for displaying the coefficients of the divided difference operators in the evaluation of the quantum double Schubert polynomials on the commuting difference operators of Fomin, Gelfand, and Postnikov. It is necessary to cap the value of n in the group S_n we are working in because as n increases the expression does not stabilize.
41
+ ```
42
+ schubmult_q_yz -nil-hecke 6 -code 2 2 --display-positive
43
+ ```
41
44
 
42
45
  Runtime will vary tremendously by case. The general problem is #P-hard. Though the result is always nonnegative (which at least is known for schubmult_py, schubmult_q, schubmult_double, and schubmult_q_double) and the problem is in GapP, it is not known to be in #P at this time.
43
46
 
@@ -139,6 +139,28 @@ def elem_sym_perms(orig_perm,p,k):
139
139
  up_perm_list = perm_list
140
140
  return total_list
141
141
 
142
+ def elem_sym_perms_op(orig_perm,p,k):
143
+ total_list = [(orig_perm,0)]
144
+ up_perm_list = [(orig_perm,k)]
145
+ for pp in range(p):
146
+ perm_list = []
147
+ for up_perm, last in up_perm_list:
148
+ up_perm2 = [*up_perm]
149
+ if len(up_perm2) < k + 1:
150
+ up_perm2 += [i+1 for i in range(len(up_perm2),k+2)]
151
+ pos_list = [i for i in range(k) if up_perm2[i] == orig_perm[i]]
152
+ for j in range(last,len(up_perm2)):
153
+ for i in pos_list:
154
+ if has_bruhat_descent(up_perm2,i,j):
155
+ new_perm = [*up_perm2]
156
+ new_perm[i],new_perm[j] = new_perm[j],new_perm[i]
157
+ new_perm_add = tuple(permtrim(new_perm))
158
+ perm_list += [(new_perm_add,j)]
159
+ total_list+=[(new_perm_add,pp+1)]
160
+ up_perm_list = perm_list
161
+ return total_list
162
+
163
+
142
164
  def strict_theta(u):
143
165
  ret = [*trimcode(u)]
144
166
  did_one = True
@@ -181,6 +203,32 @@ def elem_sym_perms_q(orig_perm,p,k):
181
203
  #print(f"{total_list=}")
182
204
  return total_list
183
205
 
206
+ def elem_sym_perms_q_op(orig_perm,p,k,n):
207
+ total_list = [(orig_perm,0,1)]
208
+ up_perm_list = [(orig_perm,1,k)]
209
+ for pp in range(p):
210
+ perm_list = []
211
+ for up_perm, val, last_j in up_perm_list:
212
+ up_perm2 = [*up_perm]
213
+ if len(up_perm) < n :
214
+ up_perm2 += [i+1 for i in range(len(up_perm2),n)]
215
+ pos_list = [i for i in range(k) if (i>=len(orig_perm) and up_perm2[i]==i+1) or (i<len(orig_perm) and up_perm2[i] == orig_perm[i])]
216
+ for j in range(last_j,n):
217
+ for i in pos_list:
218
+ ct = count_bruhat(up_perm2,i,j)
219
+ #print(f"{up_perm2=} {ct=} {i=} {j=} {k=} {pp=}")
220
+ if ct == -1 or ct == 2*(j-i)-1:
221
+ new_perm = [*up_perm2]
222
+ new_perm[i],new_perm[j] = new_perm[j],new_perm[i]
223
+ new_perm_add = tuple(permtrim(new_perm))
224
+ new_val = val
225
+ if ct>0:
226
+ new_val *= np.prod([q_var[index] for index in range(i+1,j+1)])
227
+ perm_list += [(new_perm_add,new_val,j)]
228
+ total_list+=[(new_perm_add,pp+1,new_val)]
229
+ up_perm_list = perm_list
230
+ return total_list
231
+
184
232
 
185
233
  # perms and inversion diff
186
234
  def kdown_perms(perm,monoperm,p,k):
@@ -2,7 +2,7 @@ from symengine import *
2
2
  from functools import cache
3
3
  from itertools import chain
4
4
  from schubmult.perm_lib import *
5
- from schubmult.schubmult_yz import schubmult
5
+ from schubmult.schubmult_yz import schubmult, mult_poly
6
6
  import sys
7
7
 
8
8
  n = 100
@@ -17,7 +17,7 @@ var_q = Symbol("q")
17
17
  subs_dict = {}
18
18
 
19
19
  for i in range(1,n):
20
- sm = var_r[0]
20
+ sm = var2[1]
21
21
  for j in range(1,i):
22
22
  sm += var_r[j]
23
23
  subs_dict[var2[i]] = sm
@@ -32,11 +32,16 @@ def main():
32
32
  pr = True
33
33
  ascode = False
34
34
  coprod = False
35
+ mult = False
36
+ mulstring = ""
35
37
  try:
36
38
  for s in sys.argv[1:]:
37
39
  if s == "-np" or s == "--no-print":
38
40
  pr = False
39
41
  continue
42
+ if mult:
43
+ mulstring+=s
44
+ continue
40
45
  if s == "-code":
41
46
  ascode = True
42
47
  continue
@@ -47,11 +52,14 @@ def main():
47
52
  perms += [curperm]
48
53
  curperm = []
49
54
  continue
55
+ if s == "-mult":
56
+ mult = True
57
+ continue
50
58
  curperm += [int(s)]
51
59
  except Exception:
52
60
  print("**** schubmult_double ****")
53
61
  print("Purpose: Compute products (and coproducts) of double Schubert polynomials in the same set of variables")
54
- print("Usage: schubmult_double <-np|--no-print> <-code> perm1 - perm2 < - perm 3 ... >")
62
+ print("Usage: schubmult_double <-np|--no-print> <-code> perm1 - perm2 < - perm 3 ... > <-mult poly>")
55
63
  print("Alternative usage: schubmult_double <-code> -coprod perm - indexlist")
56
64
  exit(1)
57
65
 
@@ -145,7 +153,10 @@ def main():
145
153
 
146
154
  for perm in perms[1:]:
147
155
  coeff_dict = schubmult(coeff_dict,tuple(permtrim([*perm])),var2,var2)
148
-
156
+ if mult:
157
+ mul_exp = sympify(mulstring)
158
+ coeff_dict = mult_poly(coeff_dict,mul_exp)
159
+
149
160
  if pr:
150
161
  if ascode:
151
162
  width = max([len(str(trimcode(perm))) for perm in coeff_dict.keys()])
@@ -2,6 +2,50 @@ import sys
2
2
  from functools import cache
3
3
  from itertools import chain
4
4
  from schubmult.perm_lib import *
5
+ from symengine import *
6
+
7
+ var_x = symarray("x",100).tolist()
8
+
9
+ def single_variable(coeff_dict,varnum):
10
+ ret = {}
11
+ for u in coeff_dict:
12
+ new_perms_k = elem_sym_perms(u,1,varnum)
13
+ new_perms_km1 = []
14
+ if varnum > 1:
15
+ new_perms_km1 = elem_sym_perms(u,1,varnum-1)
16
+ for perm, udiff in new_perms_k:
17
+ if udiff == 1:
18
+ ret[perm] = ret.get(perm,0) + coeff_dict[u]
19
+ for perm, udiff in new_perms_km1:
20
+ if udiff == 1:
21
+ ret[perm] = ret.get(perm,0) - coeff_dict[u]
22
+ return ret
23
+
24
+ def mult_poly(coeff_dict,poly):
25
+ if poly in var_x:
26
+ return single_variable(coeff_dict,var_x.index(poly))
27
+ elif isinstance(poly,Mul):
28
+ ret = coeff_dict
29
+ for a in poly.args:
30
+ ret = mult_poly(ret,a)
31
+ return ret
32
+ elif isinstance(poly,Pow):
33
+ base = poly.args[0]
34
+ exponent = int(poly.args[1])
35
+ ret = coeff_dict
36
+ for i in range(int(exponent)):
37
+ ret = mult_poly(ret,base)
38
+ return ret
39
+ elif isinstance(poly,Add):
40
+ ret = {}
41
+ for a in poly.args:
42
+ ret = add_perm_dict(ret,mult_poly(coeff_dict,a))
43
+ return ret
44
+ else:
45
+ ret = {}
46
+ for perm in coeff_dict:
47
+ ret[perm] = poly*coeff_dict[perm]
48
+ return ret
5
49
 
6
50
  def schubmult(perm_dict,v):
7
51
  vn1 = inverse(v)
@@ -58,9 +102,17 @@ def main():
58
102
  pr = True
59
103
  coprod = False
60
104
  ascode = False
105
+ mult = False
106
+ mulstring = ""
61
107
 
62
108
  try:
63
109
  for s in sys.argv[1:]:
110
+ if mult:
111
+ mulstring += s
112
+ continue
113
+ if s == "-mult":
114
+ mult = True
115
+ continue
64
116
  if s == "-np" or s == "--no-print":
65
117
  pr = False
66
118
  continue
@@ -73,8 +125,9 @@ def main():
73
125
  if s == "-":
74
126
  perms += [tuple(curperm)]
75
127
  curperm = []
76
- continue
77
- curperm += [int(s)]
128
+ continue
129
+ else:
130
+ curperm += [int(s)]
78
131
  except Exception:
79
132
  print("**** schubmult_py ****")
80
133
  print("Purpose: Compute products (and coproducts) of ordinary Schubert polynomials")
@@ -138,11 +191,14 @@ def main():
138
191
 
139
192
 
140
193
  perms.sort(reverse=True,key=lambda x: sum(theta(inverse(x)))-inv(x))
141
-
194
+
142
195
  coeff_dict = {tuple(permtrim([*perms[0]])): 1}
143
-
196
+
144
197
  for perm in perms[1:]:
145
198
  coeff_dict = schubmult(coeff_dict,tuple(permtrim([*perm])))
199
+ if mult:
200
+ mul_exp = sympify(mulstring)
201
+ coeff_dict = mult_poly(coeff_dict,mul_exp)
146
202
 
147
203
  if pr:
148
204
  for perm, val in coeff_dict.items():
@@ -14,6 +14,49 @@ var_q = Symbol("q")
14
14
 
15
15
  subs_dict = {}
16
16
 
17
+ var_x = symarray("x",100).tolist()
18
+
19
+ def single_variable(coeff_dict,varnum):
20
+ ret = {}
21
+ for u in coeff_dict:
22
+ new_perms_k = elem_sym_perms_q(u,1,varnum)
23
+ new_perms_km1 = []
24
+ if varnum > 1:
25
+ new_perms_km1 = elem_sym_perms_q(u,1,varnum-1)
26
+ for perm, udiff, mul_val in new_perms_k:
27
+ if udiff == 1:
28
+ ret[perm] = ret.get(perm,0) + coeff_dict[u]*mul_val
29
+ for perm, udiff, mul_val in new_perms_km1:
30
+ if udiff == 1:
31
+ ret[perm] = ret.get(perm,0) - coeff_dict[u]*mul_val
32
+ return ret
33
+
34
+ def mult_poly(coeff_dict,poly):
35
+ if poly in var_x:
36
+ return single_variable(coeff_dict,var_x.index(poly))
37
+ elif isinstance(poly,Mul):
38
+ ret = coeff_dict
39
+ for a in poly.args:
40
+ ret = mult_poly(ret,a)
41
+ return ret
42
+ elif isinstance(poly,Pow):
43
+ base = poly.args[0]
44
+ exponent = int(poly.args[1])
45
+ ret = coeff_dict
46
+ for i in range(int(exponent)):
47
+ ret = mult_poly(ret,base)
48
+ return ret
49
+ elif isinstance(poly,Add):
50
+ ret = {}
51
+ for a in poly.args:
52
+ ret = add_perm_dict(ret,mult_poly(coeff_dict,a))
53
+ return ret
54
+ else:
55
+ ret = {}
56
+ for perm in coeff_dict:
57
+ ret[perm] = poly*coeff_dict[perm]
58
+ return ret
59
+
17
60
  for i in range(1,n):
18
61
  sm = var_r[0]
19
62
  for j in range(1,i):
@@ -132,11 +175,17 @@ def main():
132
175
  grass = False
133
176
  grass_q_n = 0
134
177
  equiv = False
178
+ mult = False
179
+ mulstring = ""
180
+
135
181
  try:
136
182
  for s in sys.argv[1:]:
137
183
  if s == "-np" or s == "--no-print":
138
184
  pr = False
139
185
  continue
186
+ if mult:
187
+ mulstring += s
188
+ continue
140
189
  if s == "-code":
141
190
  ascode = True
142
191
  continue
@@ -150,6 +199,9 @@ def main():
150
199
  grass = True
151
200
  grass_q_n = int(s)
152
201
  continue
202
+ if s == "-mult":
203
+ mult = True
204
+ continue
153
205
  if s == "-":
154
206
  perms += [curperm]
155
207
  curperm = []
@@ -294,6 +346,10 @@ def main():
294
346
 
295
347
  for perm in perms[1:]:
296
348
  coeff_dict = schubmult(coeff_dict,tuple(permtrim([*perm])))
349
+
350
+ if mult:
351
+ mul_exp = sympify(mulstring)
352
+ coeff_dict = mult_poly(coeff_dict,mul_exp)
297
353
 
298
354
  if pr:
299
355
  if ascode:
@@ -1,5 +1,5 @@
1
1
  from schubmult.perm_lib import *
2
- from schubmult.schubmult_q_yz import schubmult
2
+ from schubmult.schubmult_q_yz import schubmult, mult_poly
3
3
  from symengine import *
4
4
  import sys
5
5
 
@@ -15,7 +15,7 @@ var_r = symarray('r',100)
15
15
  subs_dict = {}
16
16
 
17
17
  for i in range(1,100):
18
- sm = var_r[0]
18
+ sm = var2[1]
19
19
  for j in range(1,i):
20
20
  sm += var_r[j]
21
21
  subs_dict[var2[i]] = sm
@@ -36,11 +36,19 @@ def main():
36
36
  coprod = False
37
37
  check = True
38
38
  msg = False
39
+ mult = False
40
+ mulstring = ""
39
41
  try:
40
42
  for s in sys.argv[1:]:
41
43
  if s == "-np" or s == "--no-print":
42
44
  pr = False
43
45
  continue
46
+ if mult:
47
+ mulstring += s
48
+ continue
49
+ if s == "-mult":
50
+ mult = True
51
+ continue
44
52
  if s == "-nocheck":
45
53
  check = False
46
54
  continue
@@ -89,6 +97,9 @@ def main():
89
97
  coeff_dict = {perms[0]: 1}
90
98
  for perm in perms[1:]:
91
99
  coeff_dict = schubmult(coeff_dict,perm,var2,var2)
100
+ if mult:
101
+ mul_exp = sympify(mulstring)
102
+ coeff_dict = mult_poly(coeff_dict,mul_exp)
92
103
 
93
104
  if pr:
94
105
  if ascode:
@@ -3,18 +3,106 @@ from schubmult.schubmult_yz import compute_positive_rep, posify
3
3
  from symengine import *
4
4
  import sys
5
5
 
6
-
7
- #q_var = symarray("q",100)
8
-
9
6
  var2 = symarray("y",100)
10
7
  var3 = symarray("z",100)
11
8
 
12
-
9
+ var_y = var2.tolist()
10
+ var_z = var3.tolist()
11
+ var_x = symarray("x",100).tolist()
12
+
13
+ def single_variable(coeff_dict,varnum):
14
+ ret = {}
15
+ for u in coeff_dict:
16
+ if varnum -1 < len(u):
17
+ ret[u] = ret.get(u,0) + var2[u[varnum-1]]*coeff_dict[u]
18
+ else:
19
+ ret[u] = ret.get(u,0) + var2[varnum]*coeff_dict[u]
20
+ new_perms_k = elem_sym_perms_q(u,1,varnum)
21
+ new_perms_km1 = []
22
+ if varnum > 1:
23
+ new_perms_km1 = elem_sym_perms_q(u,1,varnum-1)
24
+ for perm, udiff, mul_val in new_perms_k:
25
+ if udiff == 1:
26
+ ret[perm] = ret.get(perm,0) + coeff_dict[u]*mul_val
27
+ for perm, udiff, mul_val in new_perms_km1:
28
+ if udiff == 1:
29
+ ret[perm] = ret.get(perm,0) - coeff_dict[u]*mul_val
30
+ return ret
31
+
32
+ def mult_poly(coeff_dict,poly):
33
+ if poly in var_x:
34
+ return single_variable(coeff_dict,var_x.index(poly))
35
+ elif isinstance(poly,Mul):
36
+ ret = coeff_dict
37
+ for a in poly.args:
38
+ ret = mult_poly(ret,a)
39
+ return ret
40
+ elif isinstance(poly,Pow):
41
+ base = poly.args[0]
42
+ exponent = int(poly.args[1])
43
+ ret = coeff_dict
44
+ for i in range(int(exponent)):
45
+ ret = mult_poly(ret,base)
46
+ return ret
47
+ elif isinstance(poly,Add):
48
+ ret = {}
49
+ for a in poly.args:
50
+ ret = add_perm_dict(ret,mult_poly(coeff_dict,a))
51
+ return ret
52
+ else:
53
+ ret = {}
54
+ for perm in coeff_dict:
55
+ ret[perm] = poly*coeff_dict[perm]
56
+ return ret
57
+
58
+
59
+ def nil_hecke(perm_dict,v,n,var2=var2,var3=var3):
60
+ if v == (1,2):
61
+ return perm_dict
62
+ th = strict_theta(inverse(v))
63
+ mu = permtrim(uncode(th))
64
+ vmu = permtrim(mulperm([*v],mu))
65
+ inv_vmu = inv(vmu)
66
+ inv_mu = inv(mu)
67
+ ret_dict = {}
68
+ vpaths = [([(vmu,0)],1)]
69
+ while th[-1] == 0:
70
+ th.pop()
71
+ thL = len(th)
72
+ vpathdicts = compute_vpathdicts(th,vmu,True)
73
+ for u,val in perm_dict.items():
74
+ inv_u = inv(u)
75
+ vpathsums = {u: {(1,2): val}}
76
+ for index in range(thL):
77
+ mx_th = 0
78
+ for vp in vpathdicts[index]:
79
+ for v2,vdiff,s in vpathdicts[index][vp]:
80
+ if th[index]-vdiff > mx_th:
81
+ mx_th = th[index] - vdiff
82
+ newpathsums = {}
83
+ for up in vpathsums:
84
+ inv_up = inv(up)
85
+ newperms = elem_sym_perms_q_op(up,mx_th,th[index],n)
86
+ for up2, udiff,mul_val in newperms:
87
+ if up2 not in newpathsums:
88
+ newpathsums[up2]={}
89
+ for v in vpathdicts[index]:
90
+ sumval = vpathsums[up].get(v,zero)*mul_val
91
+ if sumval == 0:
92
+ continue
93
+ for v2,vdiff,s in vpathdicts[index][v]:
94
+ #print(f"{code(up2)=} {elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)=} {mul_val=} {sumval=}")
95
+ newpathsums[up2][v2] = newpathsums[up2].get(v2,zero)+s*sumval*elem_sym_func_q(th[index],index+1,up2,up,v,v2,udiff,vdiff,var2,var3)
96
+ vpathsums = newpathsums
97
+ toget = tuple(vmu)
98
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
99
+ return ret_dict
13
100
 
14
-
15
101
 
16
102
 
17
103
  def schubmult(perm_dict,v,var2=var2,var3=var3):
104
+ if v == (1,2):
105
+ return perm_dict
18
106
  th = strict_theta(inverse(v))
19
107
  mu = permtrim(uncode(th))
20
108
  vmu = permtrim(mulperm([*v],mu))
@@ -150,6 +238,14 @@ def factor_out_q(poly):
150
238
  var2_t = tuple(var2.tolist())
151
239
  var3_t = tuple(var3.tolist())
152
240
 
241
+ def print_usage():
242
+ print("**** schubmult_q_yz ****")
243
+ print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
244
+ print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. > <-mult poly_expression>")
245
+ print(" *** Computes products")
246
+ print("Alternative usage: schubmult_q_yz -nil-hecke n <-code> <--display-positive> perm")
247
+ print(" *** Computes nil-Hecke representation of quantum double Schubert polynomial, limiting to the group S_n")
248
+
153
249
  def main():
154
250
  global var2
155
251
  try:
@@ -162,13 +258,31 @@ def main():
162
258
  display_positive = False
163
259
  ascode = False
164
260
  coprod = False
261
+ nilhecke = False
165
262
  check = True
166
263
  msg = False
264
+ just_nil = False
265
+ mult = False
266
+
267
+ nil_N = 0
268
+
269
+ mulstring = ""
270
+
167
271
  try:
168
272
  for s in sys.argv[1:]:
273
+ if just_nil:
274
+ just_nil = False
275
+ nil_N = int(s)
276
+ continue
169
277
  if s == "-np" or s == "--no-print":
170
278
  pr = False
171
279
  continue
280
+ if mult:
281
+ mulstring += s
282
+ continue
283
+ if s == "-mult":
284
+ mult = True
285
+ continue
172
286
  if s == "-nocheck":
173
287
  check = False
174
288
  continue
@@ -178,26 +292,26 @@ def main():
178
292
  if s == "--optimizer-message":
179
293
  msg = True
180
294
  continue
295
+ if s == "-nil-hecke":
296
+ nilhecke = True
297
+ just_nil = True
298
+ continue
181
299
  if s == "--version":
182
300
  print(f"Python version {sys.version}")
183
301
  exit(0)
184
302
  if s == "-code":
185
303
  ascode = True
186
304
  continue
187
- if s == "--usage":
188
- print("**** schubmult_q_yz ****")
189
- print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
190
- print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
191
- exit(0)
305
+ if s == "--usage" or s == "--help":
306
+ print_usage()
307
+ exit(0)
192
308
  if s == "-":
193
309
  perms += [curperm]
194
310
  curperm = []
195
- continue
311
+ continue
196
312
  curperm += [int(s)]
197
313
  except Exception:
198
- print("**** schubmult_q_yz ****")
199
- print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
200
- print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
314
+ print_usage()
201
315
  exit(1)
202
316
 
203
317
  perms += [curperm]
@@ -213,9 +327,18 @@ def main():
213
327
  size = 0
214
328
  L = len(perms)
215
329
 
216
- coeff_dict = {perms[0]: 1}
217
- for perm in perms[1:]:
218
- coeff_dict = schubmult(coeff_dict,perm)
330
+ if nilhecke:
331
+ coeff_dict = nil_hecke({(1,2): 1},perms[0],nil_N)
332
+ rep = ("y","x")
333
+ else:
334
+ coeff_dict = {perms[0]: 1}
335
+ for perm in perms[1:]:
336
+ coeff_dict = schubmult(coeff_dict,perm)
337
+ if mult:
338
+ mul_exp = sympify(mulstring)
339
+ coeff_dict = mult_poly(coeff_dict,mul_exp)
340
+ rep = ("","")
341
+ rep = ("","")
219
342
 
220
343
  if pr:
221
344
  if ascode:
@@ -243,11 +366,11 @@ def main():
243
366
  val2 += q_part*int(q_dict[q_part])
244
367
  except Exception:
245
368
  try:
246
- if len(perms) == 2 and q_part == 1:
369
+ if len(perms) == 2 and q_part == 1 and not mult:
247
370
  u = permtrim([*perms[0]])
248
371
  v = permtrim([*perms[1]])
249
372
  val2 += posify(q_dict[q_part],tuple(u),tuple(v),perm,var2_t,var3_t,msg,False)
250
- elif len(perms) == 2 and q_part in q_var2:
373
+ elif len(perms) == 2 and q_part in q_var2 and not mult:
251
374
  i = q_var2.index(q_part)
252
375
  u = permtrim([*perms[0]])
253
376
  v = permtrim([*perms[1]])
@@ -260,18 +383,26 @@ def main():
260
383
  else:
261
384
  val2 += q_part*compute_positive_rep(q_dict[q_part],var2_t,var3_t,msg,False)
262
385
  except Exception as e:
263
- print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
264
- print(f"Exception: {e}")
265
- exit(1)
386
+ if mult:
387
+ print("warning; --display-positive is on but result is not positive",file=sys.stderr)
388
+ val2 = val
389
+ break
390
+ else:
391
+ print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
392
+ print(f"Exception: {e}")
393
+ exit(1)
266
394
  if check and expand(val - val2)!=0:
267
- print(f"error: value not equal; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
268
- exit(1)
395
+ if mult:
396
+ val2 = val
397
+ else:
398
+ print(f"error: value not equal; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
399
+ exit(1)
269
400
  val = val2
270
401
  if val!=0:
271
402
  if ascode:
272
- print(f"{str(trimcode(perm)):>{width}} {str(val).replace('**','^').replace('*',' ')}")
403
+ print(f"{str(trimcode(perm)):>{width}} {str(val).replace('**','^').replace('*',' ').replace(*rep)}")
273
404
  else:
274
- print(f"{str(perm):>{width}} {str(val).replace('**','^').replace('*',' ')}")
405
+ print(f"{str(perm):>{width}} {str(val).replace('**','^').replace('*',' ').replace(*rep)}")
275
406
  except BrokenPipeError:
276
407
  pass
277
408
 
@@ -27,6 +27,99 @@ var = tuple(symarray('x',n).tolist())
27
27
  var2 = tuple(symarray('y',n).tolist())
28
28
  var3 = tuple(symarray('z',n).tolist())
29
29
 
30
+ var_x = symarray("x",100).tolist()
31
+
32
+ def single_variable(coeff_dict,varnum):
33
+ ret = {}
34
+ for u in coeff_dict:
35
+ if varnum -1 < len(u):
36
+ ret[u] = ret.get(u,0) + var2[u[varnum-1]]*coeff_dict[u]
37
+ else:
38
+ ret[u] = ret.get(u,0) + var2[varnum]*coeff_dict[u]
39
+ new_perms_k = elem_sym_perms(u,1,varnum)
40
+ new_perms_km1 = []
41
+ if varnum > 1:
42
+ new_perms_km1 = elem_sym_perms(u,1,varnum-1)
43
+ for perm, udiff in new_perms_k:
44
+ if udiff == 1:
45
+ ret[perm] = ret.get(perm,0) + coeff_dict[u]
46
+ for perm, udiff in new_perms_km1:
47
+ if udiff == 1:
48
+ ret[perm] = ret.get(perm,0) - coeff_dict[u]
49
+ return ret
50
+
51
+ def single_variable_down(coeff_dict,varnum):
52
+ ret = {}
53
+ for u in coeff_dict:
54
+ if varnum -1 < len(u):
55
+ ret[u] = ret.get(u,0) + var2[u[varnum-1]]*coeff_dict[u]
56
+ else:
57
+ ret[u] = ret.get(u,0) + var2[varnum]*coeff_dict[u]
58
+ new_perms_k = elem_sym_perms_op(u,1,varnum)
59
+ new_perms_km1 = []
60
+ if varnum > 1:
61
+ new_perms_km1 = elem_sym_perms_op(u,1,varnum-1)
62
+ for perm, udiff in new_perms_k:
63
+ if udiff == 1:
64
+ ret[perm] = ret.get(perm,0) + coeff_dict[u]
65
+ for perm, udiff in new_perms_km1:
66
+ if udiff == 1:
67
+ ret[perm] = ret.get(perm,0) - coeff_dict[u]
68
+ return ret
69
+
70
+
71
+ def mult_poly(coeff_dict,poly):
72
+ if poly in var_x:
73
+ return single_variable(coeff_dict,var_x.index(poly))
74
+ elif isinstance(poly,Mul):
75
+ ret = coeff_dict
76
+ for a in poly.args:
77
+ ret = mult_poly(ret,a)
78
+ return ret
79
+ elif isinstance(poly,Pow):
80
+ base = poly.args[0]
81
+ exponent = int(poly.args[1])
82
+ ret = coeff_dict
83
+ for i in range(int(exponent)):
84
+ ret = mult_poly(ret,base)
85
+ return ret
86
+ elif isinstance(poly,Add):
87
+ ret = {}
88
+ for a in poly.args:
89
+ ret = add_perm_dict(ret,mult_poly(coeff_dict,a))
90
+ return ret
91
+ else:
92
+ ret = {}
93
+ for perm in coeff_dict:
94
+ ret[perm] = poly*coeff_dict[perm]
95
+ return ret
96
+
97
+ def mult_poly_down(coeff_dict,poly):
98
+ if poly in var_x:
99
+ return single_variable_down(coeff_dict,var_x.index(poly))
100
+ elif isinstance(poly,Mul):
101
+ ret = coeff_dict
102
+ for a in poly.args:
103
+ ret = mult_poly_down(ret,a)
104
+ return ret
105
+ elif isinstance(poly,Pow):
106
+ base = poly.args[0]
107
+ exponent = int(poly.args[1])
108
+ ret = coeff_dict
109
+ for i in range(int(exponent)):
110
+ ret = mult_poly_down(ret,base)
111
+ return ret
112
+ elif isinstance(poly,Add):
113
+ ret = {}
114
+ for a in poly.args:
115
+ ret = add_perm_dict(ret,mult_poly_down(coeff_dict,a))
116
+ return ret
117
+ else:
118
+ ret = {}
119
+ for perm in coeff_dict:
120
+ ret[perm] = poly*coeff_dict[perm]
121
+ return ret
122
+
30
123
 
31
124
  def forwardcoeff(u,v,perm,var2=var2,var3=var3):
32
125
  th = theta(v)
@@ -160,6 +253,49 @@ def schubmult(perm_dict,v,var2=var2,var3=var3):
160
253
  ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
161
254
  return ret_dict
162
255
 
256
+ def schubmult_down(perm_dict,v,var2=var2,var3=var3):
257
+ vn1 = inverse(v)
258
+ th = theta(vn1)
259
+ if th[0]==0:
260
+ return perm_dict
261
+ mu = permtrim(uncode(th))
262
+ vmu = permtrim(mulperm([*v],mu))
263
+ inv_vmu = inv(vmu)
264
+ inv_mu = inv(mu)
265
+ ret_dict = {}
266
+ vpaths = [([(vmu,0)],1)]
267
+ while th[-1] == 0:
268
+ th.pop()
269
+ thL = len(th)
270
+ vpathdicts = compute_vpathdicts(th,vmu,True)
271
+ for u,val in perm_dict.items():
272
+ inv_u = inv(u)
273
+ vpathsums = {u: {(1,2): val}}
274
+ for index in range(thL):
275
+ mx_th = 0
276
+ for vp in vpathdicts[index]:
277
+ for v2,vdiff,s in vpathdicts[index][vp]:
278
+ if th[index]-vdiff > mx_th:
279
+ mx_th = th[index] - vdiff
280
+ newpathsums = {}
281
+ for up in vpathsums:
282
+ inv_up = inv(up)
283
+ newperms = elem_sym_perms_op(up,mx_th,th[index])
284
+ for up2, udiff in newperms:
285
+ if up2 not in newpathsums:
286
+ newpathsums[up2]={}
287
+ for v in vpathdicts[index]:
288
+ sumval = vpathsums[up].get(v,zero)
289
+ if sumval == 0:
290
+ continue
291
+ for v2,vdiff,s in vpathdicts[index][v]:
292
+ newpathsums[up2][v2] = newpathsums[up2].get(v2,zero)+s*sumval*elem_sym_func(th[index],index+1,up2,up,v,v2,udiff,vdiff,var2,var3)
293
+ vpathsums = newpathsums
294
+ toget = tuple(vmu)
295
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
296
+ return ret_dict
297
+
298
+
163
299
  fvar = 0
164
300
 
165
301
  def poly_to_vec(poly,vec0=None):
@@ -1294,11 +1430,24 @@ def main():
1294
1430
  coprod = False
1295
1431
  check = True
1296
1432
  msg = False
1433
+ mult = False
1434
+ mulstring = ""
1435
+ down = False
1436
+
1297
1437
  try:
1298
1438
  for s in sys.argv[1:]:
1299
1439
  if s == "-np" or s == "--no-print":
1300
1440
  pr = False
1301
1441
  continue
1442
+ if mult:
1443
+ mulstring += s
1444
+ continue
1445
+ if s == "-mult":
1446
+ mult = True
1447
+ continue
1448
+ if s == "-down":
1449
+ down = True
1450
+ continue
1302
1451
  if s == "-coprod":
1303
1452
  coprod = True
1304
1453
  continue
@@ -1318,7 +1467,7 @@ def main():
1318
1467
  ascode = True
1319
1468
  continue
1320
1469
  if s == "--usage":
1321
- print("Usage: schubmult_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
1470
+ print("Usage: schubmult_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. > <-mult poly_expression>")
1322
1471
  print("Alternative usage: schubmult_yz <-code> <--display-positive> -coprod perm - indexlist")
1323
1472
  exit(0)
1324
1473
  if s == "-":
@@ -1462,9 +1611,22 @@ def main():
1462
1611
 
1463
1612
  coeff_dict = {perms[0]: 1}
1464
1613
  check_coeff_dict = {perms[0]: 1}
1465
- for perm in orig_perms[1:]:
1466
- check_coeff_dict = schubmult(check_coeff_dict,perm)
1467
- if display_positive and len(perms)==2 and will_formula_work(perms[0],perms[1]):
1614
+
1615
+ if down:
1616
+ for perm in orig_perms[1:]:
1617
+ check_coeff_dict = schubmult_down(check_coeff_dict,perm)
1618
+ if mult:
1619
+ mul_exp = sympify(mulstring)
1620
+ check_coeff_dict = mult_poly_down(check_coeff_dict,mul_exp)
1621
+ else:
1622
+ for perm in orig_perms[1:]:
1623
+ check_coeff_dict = schubmult(check_coeff_dict,perm)
1624
+ if mult:
1625
+ mul_exp = sympify(mulstring)
1626
+ check_coeff_dict = mult_poly(check_coeff_dict,mul_exp)
1627
+
1628
+
1629
+ if display_positive and len(perms)==2 and will_formula_work(perms[0],perms[1]) and not mult and not down:
1468
1630
  coeff_dict = {}
1469
1631
  th = theta(perms[1])
1470
1632
  muv = uncode(th)
@@ -1477,7 +1639,7 @@ def main():
1477
1639
  coeff_dict[tuple(permtrim(w))] = val
1478
1640
  posified = True
1479
1641
 
1480
- if display_positive and len(perms)>2:
1642
+ if display_positive and len(perms)>2 and not mult:
1481
1643
  coeff_dict2 = dict(coeff_dict)
1482
1644
  for perm in perms[1:]:
1483
1645
  coeff_dict3 = {}
@@ -1513,13 +1675,21 @@ def main():
1513
1675
  if notint and display_positive:
1514
1676
  valu = val
1515
1677
  try:
1516
- if len(perms) == 2 and not posified:
1517
- val = posify(val,perms[0],perms[1],perm,var2,var3,msg)
1518
- elif not posified:
1678
+ if len(perms) == 2 and not posified and not mult:
1679
+ if not down:
1680
+ val = posify(val,perms[0],perms[1],perm,var2,var3,msg)
1681
+ else:
1682
+ val = posify(val,perm,perms[1],perms[0],var2,var3,msg)
1683
+ elif not posified and not mult:
1519
1684
  val = compute_positive_rep(val,var2,var3,msg)
1520
- except TypeError:
1521
- print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {check_coeff_dict.get(perm,0)=}")
1522
- exit(1)
1685
+ elif not posified:
1686
+ val = compute_positive_rep(val,var2,var3,msg,do_pos_neg=False)
1687
+ except Exception:
1688
+ if mult:
1689
+ print(f"warning; --display-positive is on but result is not positive",file=sys.stderr)
1690
+ else:
1691
+ print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {check_coeff_dict.get(perm,0)=}")
1692
+ exit(1)
1523
1693
  if check and expand(val - check_coeff_dict.get(perm,0))!=0:
1524
1694
  print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {check_coeff_dict.get(perm,0)=}")
1525
1695
  exit(1)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schubmult
3
- Version: 1.3.6
3
+ Version: 1.3.8
4
4
  Summary: Computing Littlewood-Richardson coefficients of Schubert polynomials
5
5
  Home-page: https://github.com/matthematics/schubmult
6
6
  Author: Matt Samuel
@@ -50,7 +50,10 @@ schubmult_double -code -coprod 0 1 2 3 - 2 4
50
50
  schubmult_yz -code -coprod 0 1 2 3 - 2 4 --display-positive
51
51
  ```
52
52
 
53
-
53
+ Since version 1.3.7, schubmult_q_yz has a feature for displaying the coefficients of the divided difference operators in the evaluation of the quantum double Schubert polynomials on the commuting difference operators of Fomin, Gelfand, and Postnikov. It is necessary to cap the value of n in the group S_n we are working in because as n increases the expression does not stabilize.
54
+ ```
55
+ schubmult_q_yz -nil-hecke 6 -code 2 2 --display-positive
56
+ ```
54
57
 
55
58
  Runtime will vary tremendously by case. The general problem is #P-hard. Though the result is always nonnegative (which at least is known for schubmult_py, schubmult_q, schubmult_double, and schubmult_q_double) and the problem is in GapP, it is not known to be in #P at this time.
56
59
 
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text()
6
6
 
7
7
  setup(
8
8
  name="schubmult",
9
- version="1.3.6",
9
+ version="1.3.8",
10
10
  description="Computing Littlewood-Richardson coefficients of Schubert polynomials",
11
11
  long_description=long_description,
12
12
  long_description_content_type='text/markdown',
File without changes
File without changes