schubmult 1.3.5__tar.gz → 1.3.7__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 (32) hide show
  1. {schubmult-1.3.5 → schubmult-1.3.7}/PKG-INFO +5 -2
  2. {schubmult-1.3.5 → schubmult-1.3.7}/README.md +4 -1
  3. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/perm_lib.py +39 -0
  4. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q/schubmult_q.py +1 -2
  5. schubmult-1.3.7/schubmult/schubmult_q_yz/schubmult_q_yz.py +337 -0
  6. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/PKG-INFO +5 -2
  7. {schubmult-1.3.5 → schubmult-1.3.7}/setup.py +1 -1
  8. schubmult-1.3.5/schubmult/schubmult_q_yz/schubmult_q_yz.py +0 -206
  9. {schubmult-1.3.5 → schubmult-1.3.7}/LICENSE +0 -0
  10. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/__init__.py +0 -0
  11. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_double/__init__.py +0 -0
  12. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_double/__main__.py +0 -0
  13. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_double/schubmult_double.py +0 -0
  14. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_py/__init__.py +0 -0
  15. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_py/__main__.py +0 -0
  16. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_py/schubmult_py.py +0 -0
  17. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q/__init__.py +0 -0
  18. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q/__main__.py +0 -0
  19. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q_double/__init__.py +0 -0
  20. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q_double/__main__.py +0 -0
  21. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q_double/schubmult_q_double.py +0 -0
  22. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q_yz/__init__.py +0 -0
  23. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_q_yz/__main__.py +0 -0
  24. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_yz/__init__.py +0 -0
  25. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_yz/__main__.py +0 -0
  26. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult/schubmult_yz/schubmult_yz.py +0 -0
  27. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/SOURCES.txt +0 -0
  28. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/dependency_links.txt +0 -0
  29. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/entry_points.txt +0 -0
  30. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/requires.txt +0 -0
  31. {schubmult-1.3.5 → schubmult-1.3.7}/schubmult.egg-info/top_level.txt +0 -0
  32. {schubmult-1.3.5 → schubmult-1.3.7}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schubmult
3
- Version: 1.3.5
3
+ Version: 1.3.7
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,19 @@ def elem_sym_perms(orig_perm,p,k):
139
139
  up_perm_list = perm_list
140
140
  return total_list
141
141
 
142
+ def strict_theta(u):
143
+ ret = [*trimcode(u)]
144
+ did_one = True
145
+ while did_one:
146
+ did_one = False
147
+ for i in range(len(ret)-2,-1,-1):
148
+ if ret[i+1]!=0 and ret[i] <= ret[i+1]:
149
+ ret[i], ret[i+1] = ret[i+1] + 1, ret[i]
150
+ did_one = True
151
+ break
152
+ while len(ret)>0 and ret[-1] == 0:
153
+ ret.pop()
154
+ return ret
142
155
 
143
156
  def elem_sym_perms_q(orig_perm,p,k):
144
157
  total_list = [(orig_perm,0,1)]
@@ -168,6 +181,32 @@ def elem_sym_perms_q(orig_perm,p,k):
168
181
  #print(f"{total_list=}")
169
182
  return total_list
170
183
 
184
+ def elem_sym_perms_q_op(orig_perm,p,k,n):
185
+ total_list = [(orig_perm,0,1)]
186
+ up_perm_list = [(orig_perm,1,k)]
187
+ for pp in range(p):
188
+ perm_list = []
189
+ for up_perm, val, last_j in up_perm_list:
190
+ up_perm2 = [*up_perm]
191
+ if len(up_perm) < n :
192
+ up_perm2 += [i+1 for i in range(len(up_perm2),n)]
193
+ 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])]
194
+ for j in range(last_j,n):
195
+ for i in pos_list:
196
+ ct = count_bruhat(up_perm2,i,j)
197
+ #print(f"{up_perm2=} {ct=} {i=} {j=} {k=} {pp=}")
198
+ if ct == -1 or ct == 2*(j-i)-1:
199
+ new_perm = [*up_perm2]
200
+ new_perm[i],new_perm[j] = new_perm[j],new_perm[i]
201
+ new_perm_add = tuple(permtrim(new_perm))
202
+ new_val = val
203
+ if ct>0:
204
+ new_val *= np.prod([q_var[index] for index in range(i+1,j+1)])
205
+ perm_list += [(new_perm_add,new_val,j)]
206
+ total_list+=[(new_perm_add,pp+1,new_val)]
207
+ up_perm_list = perm_list
208
+ return total_list
209
+
171
210
 
172
211
  # perms and inversion diff
173
212
  def kdown_perms(perm,monoperm,p,k):
@@ -21,8 +21,7 @@ for i in range(1,n):
21
21
  subs_dict[var2[i]] = sm
22
22
 
23
23
  def schubmult(perm_dict,v):
24
- vn1 = inverse(v)
25
- th = [len(v)-i for i in range(1,len(v)+1)]
24
+ th = strict_theta(inverse(v))
26
25
  mu = permtrim(uncode(th))
27
26
  vmu = permtrim(mulperm([*v],mu))
28
27
  #print(f"{th=} {mu=} {vmu=}")
@@ -0,0 +1,337 @@
1
+ from schubmult.perm_lib import *
2
+ from schubmult.schubmult_yz import compute_positive_rep, posify
3
+ from symengine import *
4
+ import sys
5
+
6
+ var2 = symarray("y",100)
7
+ var3 = symarray("z",100)
8
+
9
+ var_x = symarray("x",100)
10
+
11
+ def nil_hecke(perm_dict,v,n,var2=var2,var3=var3):
12
+ th = strict_theta(inverse(v))
13
+ mu = permtrim(uncode(th))
14
+ vmu = permtrim(mulperm([*v],mu))
15
+ inv_vmu = inv(vmu)
16
+ inv_mu = inv(mu)
17
+ ret_dict = {}
18
+ vpaths = [([(vmu,0)],1)]
19
+ while th[-1] == 0:
20
+ th.pop()
21
+ thL = len(th)
22
+ vpathdicts = compute_vpathdicts(th,vmu,True)
23
+ for u,val in perm_dict.items():
24
+ inv_u = inv(u)
25
+ vpathsums = {u: {(1,2): val}}
26
+ for index in range(thL):
27
+ mx_th = 0
28
+ for vp in vpathdicts[index]:
29
+ for v2,vdiff,s in vpathdicts[index][vp]:
30
+ if th[index]-vdiff > mx_th:
31
+ mx_th = th[index] - vdiff
32
+ newpathsums = {}
33
+ for up in vpathsums:
34
+ inv_up = inv(up)
35
+ newperms = elem_sym_perms_q_op(up,mx_th,th[index],n)
36
+ for up2, udiff,mul_val in newperms:
37
+ if up2 not in newpathsums:
38
+ newpathsums[up2]={}
39
+ for v in vpathdicts[index]:
40
+ sumval = vpathsums[up].get(v,zero)*mul_val
41
+ if sumval == 0:
42
+ continue
43
+ for v2,vdiff,s in vpathdicts[index][v]:
44
+ #print(f"{code(up2)=} {elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)=} {mul_val=} {sumval=}")
45
+ 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)
46
+ vpathsums = newpathsums
47
+ toget = tuple(vmu)
48
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
49
+ return ret_dict
50
+
51
+
52
+
53
+ def schubmult(perm_dict,v,var2=var2,var3=var3):
54
+ th = strict_theta(inverse(v))
55
+ mu = permtrim(uncode(th))
56
+ vmu = permtrim(mulperm([*v],mu))
57
+ inv_vmu = inv(vmu)
58
+ inv_mu = inv(mu)
59
+ ret_dict = {}
60
+ vpaths = [([(vmu,0)],1)]
61
+ while th[-1] == 0:
62
+ th.pop()
63
+ thL = len(th)
64
+ vpathdicts = compute_vpathdicts(th,vmu,True)
65
+ for u,val in perm_dict.items():
66
+ inv_u = inv(u)
67
+ vpathsums = {u: {(1,2): val}}
68
+ for index in range(thL):
69
+ mx_th = 0
70
+ for vp in vpathdicts[index]:
71
+ for v2,vdiff,s in vpathdicts[index][vp]:
72
+ if th[index]-vdiff > mx_th:
73
+ mx_th = th[index] - vdiff
74
+ newpathsums = {}
75
+ for up in vpathsums:
76
+ inv_up = inv(up)
77
+ newperms = elem_sym_perms_q(up,min(mx_th,(inv_mu-(inv_up-inv_u))-inv_vmu),th[index])
78
+ for up2, udiff,mul_val in newperms:
79
+ if up2 not in newpathsums:
80
+ newpathsums[up2]={}
81
+ for v in vpathdicts[index]:
82
+ sumval = vpathsums[up].get(v,zero)*mul_val
83
+ if sumval == 0:
84
+ continue
85
+ for v2,vdiff,s in vpathdicts[index][v]:
86
+ #print(f"{code(up2)=} {elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)=} {mul_val=} {sumval=}")
87
+ newpathsums[up2][v2] = newpathsums[up2].get(v2,zero)+s*sumval*elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)
88
+ vpathsums = newpathsums
89
+ toget = tuple(vmu)
90
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
91
+ return ret_dict
92
+
93
+ q_var2 = q_var.tolist()
94
+
95
+ def sum_q_dict(q_dict1,q_dict2):
96
+ ret = {**q_dict1}
97
+ for key in q_dict2:
98
+ ret[key] = ret.get(key,0) + q_dict2[key]
99
+ return ret
100
+
101
+ def mul_q_dict(q_dict1,q_dict2):
102
+ ret = {}
103
+ for key1 in q_dict1:
104
+ for key2 in q_dict2:
105
+ key3 = key1*key2
106
+ ret[key3] = ret.get(key3,0) + q_dict1[key1]*q_dict2[key2]
107
+ return ret
108
+
109
+ def factor_out_q_keep_factored(poly):
110
+ ret = {}
111
+ if str(poly).find("q") == -1:
112
+ ret[1] = poly
113
+ return ret
114
+ elif poly in q_var2:
115
+ ret[poly] = 1
116
+ return ret
117
+ elif isinstance(poly,Add):
118
+ ag = poly.args
119
+ ret = factor_out_q_keep_factored(ag[0])
120
+ for i in range(1,len(ag)):
121
+ ret = sum_q_dict(ret,factor_out_q_keep_factored(ag[i]))
122
+ return ret
123
+ elif isinstance(poly,Mul):
124
+ ag = poly.args
125
+ ret = factor_out_q_keep_factored(ag[0])
126
+ for i in range(1,len(ag)):
127
+ ret = mul_q_dict(ret,factor_out_q_keep_factored(ag[i]))
128
+ return ret
129
+ elif isinstance(poly,Pow):
130
+ base = poly.args[0]
131
+ exponent = int(poly.args[1])
132
+ #print(f"exponent {exponent}")
133
+ work_val = factor_out_q_keep_factored(base)
134
+ ret = {1: 1}
135
+ while exponent > 0:
136
+ if exponent % 2 == 1:
137
+ if ret == {1: 1}:
138
+ ret = {**work_val}
139
+ else:
140
+ ret = mul_q_dict(ret,work_val)
141
+ exponent -= 1
142
+ else:
143
+ work_val = mul_q_dict(work_val,work_val)
144
+ exponent //= 2
145
+ return ret
146
+ return ret
147
+
148
+ def factor_out_q(poly):
149
+ coeff_dict = expand(poly).as_coefficients_dict()
150
+ ret = {}
151
+ for key in coeff_dict:
152
+ coeff = coeff_dict[key]
153
+ if coeff == 0:
154
+ continue
155
+ q_part = 1
156
+ yz_part = coeff
157
+ if isinstance(key,Mul):
158
+ for var_maybe_pow in key.args:
159
+ if isinstance(var_maybe_pow,Pow):
160
+ real_var = var_maybe_pow.args[0]
161
+ if real_var in q_var2:
162
+ q_part*=var_maybe_pow
163
+ else:
164
+ yz_part*=var_maybe_pow
165
+ else:
166
+ real_var = var_maybe_pow
167
+ if real_var in q_var2:
168
+ q_part*=var_maybe_pow
169
+ else:
170
+ yz_part*=var_maybe_pow
171
+ elif isinstance(key,Pow):
172
+ real_var = key.args[0]
173
+ if real_var in q_var2:
174
+ q_part*=key
175
+ else:
176
+ yz_part*=key
177
+ else:
178
+ if key in q_var2:
179
+ q_part *= key
180
+ else:
181
+ yz_part*=key
182
+
183
+ ret[q_part] = ret.get(q_part,0) + yz_part
184
+ return ret
185
+
186
+ var2_t = tuple(var2.tolist())
187
+ var3_t = tuple(var3.tolist())
188
+
189
+ def print_usage():
190
+ print("**** schubmult_q_yz ****")
191
+ print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
192
+ print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
193
+ print(" *** Computes products")
194
+ print("Alternative usage: schubmult_q_yz -nil-hecke n <-code> <--display-positive> perm")
195
+ print(" *** Computes nil-Hecke representation of quantum double Schubert polynomial, limiting to the group S_n")
196
+
197
+ def main():
198
+ global var2
199
+ try:
200
+ sys.setrecursionlimit(1000000)
201
+
202
+ perms=[]
203
+ curperm = []
204
+
205
+ pr = True
206
+ display_positive = False
207
+ ascode = False
208
+ coprod = False
209
+ nilhecke = False
210
+ check = True
211
+ msg = False
212
+ just_nil = False
213
+
214
+ nil_N = 0
215
+
216
+ try:
217
+ for s in sys.argv[1:]:
218
+ if just_nil:
219
+ just_nil = False
220
+ nil_N = int(s)
221
+ continue
222
+ if s == "-np" or s == "--no-print":
223
+ pr = False
224
+ continue
225
+ if s == "-nocheck":
226
+ check = False
227
+ continue
228
+ if s == "--display-positive":
229
+ display_positive = True
230
+ continue
231
+ if s == "--optimizer-message":
232
+ msg = True
233
+ continue
234
+ if s == "-nil-hecke":
235
+ nilhecke = True
236
+ just_nil = True
237
+ continue
238
+ if s == "--version":
239
+ print(f"Python version {sys.version}")
240
+ exit(0)
241
+ if s == "-code":
242
+ ascode = True
243
+ continue
244
+ if s == "--usage" or s == "--help":
245
+ print_usage()
246
+ exit(0)
247
+ if s == "-":
248
+ perms += [curperm]
249
+ curperm = []
250
+ continue
251
+ curperm += [int(s)]
252
+ except Exception:
253
+ print_usage()
254
+ exit(1)
255
+
256
+ perms += [curperm]
257
+
258
+
259
+ if ascode:
260
+ for i in range(len(perms)):
261
+ perms[i] = tuple(permtrim(uncode(perms[i])))
262
+ else:
263
+ for i in range(len(perms)):
264
+ perms[i] = tuple(permtrim([*perms[i]]))
265
+
266
+ size = 0
267
+ L = len(perms)
268
+
269
+ if nilhecke:
270
+ coeff_dict = nil_hecke({(1,2): 1},perms[0],nil_N)
271
+ rep = ("y","x")
272
+ else:
273
+ coeff_dict = {perms[0]: 1}
274
+ for perm in perms[1:]:
275
+ coeff_dict = schubmult(coeff_dict,perm)
276
+ rep = ("","")
277
+
278
+ if pr:
279
+ if ascode:
280
+ width = max([len(str(trimcode(perm))) for perm in coeff_dict.keys() if expand(coeff_dict[perm])!=0])
281
+ else:
282
+ width = max([len(str(perm)) for perm in coeff_dict.keys() if expand(coeff_dict[perm])!=0])
283
+
284
+ coeff_perms = list(coeff_dict.keys())
285
+ coeff_perms.sort(key=lambda x: (inv(x),*x))
286
+
287
+ for perm in coeff_perms:
288
+ val = coeff_dict[perm]
289
+ if expand(val) != 0:
290
+ notint = False
291
+ try:
292
+ int(val)
293
+ except Exception:
294
+ notint = True
295
+ val2 = 0
296
+ if display_positive:
297
+ q_dict = factor_out_q_keep_factored(val)
298
+ for q_part in q_dict:
299
+ #print(f"{q_part=} {q_dict[q_part]=}")
300
+ try:
301
+ val2 += q_part*int(q_dict[q_part])
302
+ except Exception:
303
+ try:
304
+ if len(perms) == 2 and q_part == 1:
305
+ u = permtrim([*perms[0]])
306
+ v = permtrim([*perms[1]])
307
+ val2 += posify(q_dict[q_part],tuple(u),tuple(v),perm,var2_t,var3_t,msg,False)
308
+ elif len(perms) == 2 and q_part in q_var2:
309
+ i = q_var2.index(q_part)
310
+ u = permtrim([*perms[0]])
311
+ v = permtrim([*perms[1]])
312
+ #print(f"{u=} {v=} {q_part=} {q_dict[q_part]=}")
313
+ if i<len(u) and i<len(v) and u[i-1]>u[i] and v[i-1]>v[i]:
314
+ u[i], u[i-1] = u[i-1], u[i]
315
+ v[i], v[i-1] = v[i-1], v[i]
316
+ #print(f"new {u=} {v=}")
317
+ val2 += q_part*posify(q_dict[q_part],tuple(permtrim(u)),tuple(permtrim(v)),perm,var2_t,var3_t,msg,False)
318
+ else:
319
+ val2 += q_part*compute_positive_rep(q_dict[q_part],var2_t,var3_t,msg,False)
320
+ except Exception as e:
321
+ print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
322
+ print(f"Exception: {e}")
323
+ exit(1)
324
+ if check and expand(val - val2)!=0:
325
+ print(f"error: value not equal; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {coeff_dict.get(perm,0)=}")
326
+ exit(1)
327
+ val = val2
328
+ if val!=0:
329
+ if ascode:
330
+ print(f"{str(trimcode(perm)):>{width}} {str(val).replace('**','^').replace('*',' ').replace(*rep)}")
331
+ else:
332
+ print(f"{str(perm):>{width}} {str(val).replace('**','^').replace('*',' ').replace(*rep)}")
333
+ except BrokenPipeError:
334
+ pass
335
+
336
+ if __name__ == "__main__":
337
+ main()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: schubmult
3
- Version: 1.3.5
3
+ Version: 1.3.7
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.5",
9
+ version="1.3.7",
10
10
  description="Computing Littlewood-Richardson coefficients of Schubert polynomials",
11
11
  long_description=long_description,
12
12
  long_description_content_type='text/markdown',
@@ -1,206 +0,0 @@
1
- from schubmult.perm_lib import *
2
- from schubmult.schubmult_yz import compute_positive_rep
3
- from symengine import *
4
- import sys
5
-
6
-
7
- #q_var = symarray("q",100)
8
-
9
- var2 = symarray("y",100)
10
- var3 = symarray("z",100)
11
-
12
-
13
-
14
-
15
-
16
-
17
- def schubmult(perm_dict,v,var2=var2,var3=var3):
18
- th = [len(v)-i for i in range(1,len(v))]
19
- mu = permtrim(uncode(th))
20
- vmu = permtrim(mulperm([*v],mu))
21
- inv_vmu = inv(vmu)
22
- inv_mu = inv(mu)
23
- ret_dict = {}
24
- vpaths = [([(vmu,0)],1)]
25
- while th[-1] == 0:
26
- th.pop()
27
- thL = len(th)
28
- vpathdicts = compute_vpathdicts(th,vmu,True)
29
- for u,val in perm_dict.items():
30
- inv_u = inv(u)
31
- vpathsums = {u: {(1,2): val}}
32
- for index in range(thL):
33
- mx_th = 0
34
- for vp in vpathdicts[index]:
35
- for v2,vdiff,s in vpathdicts[index][vp]:
36
- if th[index]-vdiff > mx_th:
37
- mx_th = th[index] - vdiff
38
- newpathsums = {}
39
- for up in vpathsums:
40
- inv_up = inv(up)
41
- newperms = elem_sym_perms_q(up,min(mx_th,(inv_mu-(inv_up-inv_u))-inv_vmu),th[index])
42
- for up2, udiff,mul_val in newperms:
43
- if up2 not in newpathsums:
44
- newpathsums[up2]={}
45
- for v in vpathdicts[index]:
46
- sumval = vpathsums[up].get(v,zero)*mul_val
47
- if sumval == 0:
48
- continue
49
- for v2,vdiff,s in vpathdicts[index][v]:
50
- #print(f"{code(up2)=} {elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)=} {mul_val=} {sumval=}")
51
- newpathsums[up2][v2] = newpathsums[up2].get(v2,zero)+s*sumval*elem_sym_func_q(th[index],index+1,up,up2,v,v2,udiff,vdiff,var2,var3)
52
- vpathsums = newpathsums
53
- toget = tuple(vmu)
54
- ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget,0) for ep in vpathsums},ret_dict)
55
- return ret_dict
56
-
57
- def factor_out_q(poly):
58
- coeff_dict = expand(poly).as_coefficients_dict()
59
- ret = {}
60
- q_var2 = q_var.tolist()
61
- for key in coeff_dict:
62
- coeff = coeff_dict[key]
63
- if coeff == 0:
64
- continue
65
- q_part = 1
66
- yz_part = coeff
67
- if isinstance(key,Mul):
68
- for var_maybe_pow in key.args:
69
- if isinstance(var_maybe_pow,Pow):
70
- real_var = var_maybe_pow.args[0]
71
- if real_var in q_var2:
72
- q_part*=var_maybe_pow
73
- else:
74
- yz_part*=var_maybe_pow
75
- else:
76
- real_var = var_maybe_pow
77
- if real_var in q_var2:
78
- q_part*=var_maybe_pow
79
- else:
80
- yz_part*=var_maybe_pow
81
- elif isinstance(key,Pow):
82
- real_var = key.args[0]
83
- if real_var in q_var2:
84
- q_part*=key
85
- else:
86
- yz_part*=key
87
- else:
88
- if key in q_var2:
89
- q_part *= key
90
- else:
91
- yz_part*=key
92
-
93
- ret[q_part] = ret.get(q_part,0) + yz_part
94
- return ret
95
-
96
- def main():
97
- global var2
98
- try:
99
- sys.setrecursionlimit(1000000)
100
-
101
- perms=[]
102
- curperm = []
103
-
104
- pr = True
105
- display_positive = False
106
- ascode = False
107
- coprod = False
108
- check = True
109
- msg = False
110
- try:
111
- for s in sys.argv[1:]:
112
- if s == "-np" or s == "--no-print":
113
- pr = False
114
- continue
115
- if s == "-nocheck":
116
- check = False
117
- continue
118
- if s == "--display-positive":
119
- display_positive = True
120
- continue
121
- if s == "--optimizer-message":
122
- msg = True
123
- continue
124
- if s == "--version":
125
- print(f"Python version {sys.version}")
126
- exit(0)
127
- if s == "-code":
128
- ascode = True
129
- continue
130
- if s == "--usage":
131
- print("**** schubmult_q_yz ****")
132
- print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
133
- print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
134
- exit(0)
135
- if s == "-":
136
- perms += [curperm]
137
- curperm = []
138
- continue
139
- curperm += [int(s)]
140
- except Exception:
141
- print("**** schubmult_q_yz ****")
142
- print("Purpose: Compute Molev-Sagan coefficients of quantum double Schubert polynomials")
143
- print("Usage: schubmult_q_yz <-np|--no-print> <-code> <--display-positive> <--optimizer-message> perm1 - perm2 < - perm3 .. >")
144
- exit(1)
145
-
146
- perms += [curperm]
147
-
148
-
149
- if ascode:
150
- for i in range(len(perms)):
151
- perms[i] = tuple(permtrim(uncode(perms[i])))
152
- else:
153
- for i in range(len(perms)):
154
- perms[i] = tuple(permtrim([*perms[i]]))
155
-
156
- size = 0
157
- L = len(perms)
158
-
159
- coeff_dict = {perms[0]: 1}
160
- for perm in perms[1:]:
161
- coeff_dict = schubmult(coeff_dict,perm)
162
-
163
- if pr:
164
- if ascode:
165
- width = max([len(str(trimcode(perm))) for perm in coeff_dict.keys() if expand(coeff_dict[perm])!=0])
166
- else:
167
- width = max([len(str(perm)) for perm in coeff_dict.keys() if expand(coeff_dict[perm])!=0])
168
-
169
- coeff_perms = list(coeff_dict.keys())
170
- coeff_perms.sort(key=lambda x: (inv(x),*x))
171
-
172
- for perm in coeff_perms:
173
- val = coeff_dict[perm]
174
- if expand(val) != 0:
175
- notint = False
176
- try:
177
- int(val)
178
- except Exception:
179
- notint = True
180
- val2 = 0
181
- if display_positive:
182
- q_dict = factor_out_q(val)
183
- for q_part in q_dict:
184
- #print(f"{q_part=} {q_dict[q_part]=}")
185
- try:
186
- val2 += q_part*int(q_dict[q_part])
187
- except Exception:
188
- try:
189
- val2 += q_part*compute_positive_rep(q_dict[q_part],var2,var3,msg,False)
190
- except TypeError:
191
- print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {check_coeff_dict.get(perm,0)=}")
192
- exit(1)
193
- if check and expand(val - val2)!=0:
194
- print(f"error; write to schubmult@gmail.com with the case {perms=} {perm=} {val=} {check_coeff_dict.get(perm,0)=}")
195
- exit(1)
196
- val = val2
197
- if val!=0:
198
- if ascode:
199
- print(f"{str(trimcode(perm)):>{width}} {str(val).replace('**','^').replace('*',' ')}")
200
- else:
201
- print(f"{str(perm):>{width}} {str(val).replace('**','^').replace('*',' ')}")
202
- except BrokenPipeError:
203
- pass
204
-
205
- if __name__ == "__main__":
206
- main()
File without changes
File without changes