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.
Files changed (36) hide show
  1. schubmult/__init__.py +1 -0
  2. schubmult/_base_argparse.py +174 -0
  3. schubmult/perm_lib.py +999 -0
  4. schubmult/sage_integration/__init__.py +25 -0
  5. schubmult/sage_integration/_fast_double_schubert_polynomial_ring.py +528 -0
  6. schubmult/sage_integration/_fast_schubert_polynomial_ring.py +356 -0
  7. schubmult/sage_integration/_indexing.py +44 -0
  8. schubmult/schubmult_double/__init__.py +18 -0
  9. schubmult/schubmult_double/__main__.py +5 -0
  10. schubmult/schubmult_double/_funcs.py +1590 -0
  11. schubmult/schubmult_double/_script.py +407 -0
  12. schubmult/schubmult_double/_vars.py +16 -0
  13. schubmult/schubmult_py/__init__.py +10 -0
  14. schubmult/schubmult_py/__main__.py +5 -0
  15. schubmult/schubmult_py/_funcs.py +111 -0
  16. schubmult/schubmult_py/_script.py +115 -0
  17. schubmult/schubmult_py/_vars.py +3 -0
  18. schubmult/schubmult_q/__init__.py +12 -0
  19. schubmult/schubmult_q/__main__.py +5 -0
  20. schubmult/schubmult_q/_funcs.py +304 -0
  21. schubmult/schubmult_q/_script.py +157 -0
  22. schubmult/schubmult_q/_vars.py +18 -0
  23. schubmult/schubmult_q_double/__init__.py +14 -0
  24. schubmult/schubmult_q_double/__main__.py +5 -0
  25. schubmult/schubmult_q_double/_funcs.py +507 -0
  26. schubmult/schubmult_q_double/_script.py +337 -0
  27. schubmult/schubmult_q_double/_vars.py +21 -0
  28. schubmult-2.0.0.dist-info/METADATA +455 -0
  29. schubmult-2.0.0.dist-info/RECORD +36 -0
  30. schubmult-2.0.0.dist-info/WHEEL +5 -0
  31. schubmult-2.0.0.dist-info/entry_points.txt +5 -0
  32. schubmult-2.0.0.dist-info/licenses/LICENSE +674 -0
  33. schubmult-2.0.0.dist-info/top_level.txt +2 -0
  34. tests/__init__.py +0 -0
  35. tests/test_fast_double_schubert.py +145 -0
  36. tests/test_fast_schubert.py +38 -0
@@ -0,0 +1,507 @@
1
+ from ._vars import (
2
+ var_y,
3
+ var_x,
4
+ var2,
5
+ var3,
6
+ q_var2,
7
+ )
8
+ from symengine import Add, Mul, Pow, expand
9
+ from schubmult.perm_lib import (
10
+ elem_sym_perms_q,
11
+ add_perm_dict,
12
+ compute_vpathdicts,
13
+ inverse,
14
+ strict_theta,
15
+ medium_theta,
16
+ permtrim,
17
+ inv,
18
+ mulperm,
19
+ uncode,
20
+ double_elem_sym_q,
21
+ elem_sym_poly_q,
22
+ elem_sym_perms_q_op,
23
+ elem_sym_func_q,
24
+ call_zvars,
25
+ q_var,
26
+ )
27
+ import schubmult.schubmult_double as norm_yz
28
+
29
+
30
+ def E(p, k, varl=var_y[1:]):
31
+ return elem_sym_poly_q(p, k, var_x[1:], varl)
32
+
33
+
34
+ def single_variable(coeff_dict, varnum, var2=var2, q_var=q_var):
35
+ ret = {}
36
+ for u in coeff_dict:
37
+ if varnum - 1 < len(u):
38
+ ret[u] = ret.get(u, 0) + var2[u[varnum - 1]] * coeff_dict[u]
39
+ else:
40
+ ret[u] = ret.get(u, 0) + var2[varnum] * coeff_dict[u]
41
+ new_perms_k = elem_sym_perms_q(u, 1, varnum, q_var)
42
+ new_perms_km1 = []
43
+ if varnum > 1:
44
+ new_perms_km1 = elem_sym_perms_q(u, 1, varnum - 1, q_var)
45
+ for perm, udiff, mul_val in new_perms_k:
46
+ if udiff == 1:
47
+ ret[perm] = ret.get(perm, 0) + coeff_dict[u] * mul_val
48
+ for perm, udiff, mul_val in new_perms_km1:
49
+ if udiff == 1:
50
+ ret[perm] = ret.get(perm, 0) - coeff_dict[u] * mul_val
51
+ return ret
52
+
53
+
54
+ def mult_poly(coeff_dict, poly, var_x=var_x, var_y=var_y, q_var=q_var):
55
+ if poly in var_x:
56
+ return single_variable(coeff_dict, var_x.index(poly), var_y, q_var)
57
+ elif isinstance(poly, Mul):
58
+ ret = coeff_dict
59
+ for a in poly.args:
60
+ ret = mult_poly(ret, a, var_x, var_y, q_var)
61
+ return ret
62
+ elif isinstance(poly, Pow):
63
+ base = poly.args[0]
64
+ exponent = int(poly.args[1])
65
+ ret = coeff_dict
66
+ for i in range(int(exponent)):
67
+ ret = mult_poly(ret, base, var_x, var_y, q_var)
68
+ return ret
69
+ elif isinstance(poly, Add):
70
+ ret = {}
71
+ for a in poly.args:
72
+ ret = add_perm_dict(ret, mult_poly(coeff_dict, a, var_x, var_y, q_var))
73
+ return ret
74
+ else:
75
+ ret = {}
76
+ for perm in coeff_dict:
77
+ ret[perm] = poly * coeff_dict[perm]
78
+ return ret
79
+
80
+
81
+ def nil_hecke(perm_dict, v, n, var2=var2, var3=var3):
82
+ if v == (1, 2):
83
+ return perm_dict
84
+ th = strict_theta(inverse(v))
85
+ mu = permtrim(uncode(th))
86
+ vmu = permtrim(mulperm([*v], mu))
87
+
88
+ ret_dict = {}
89
+ while th[-1] == 0:
90
+ th.pop()
91
+ thL = len(th)
92
+ vpathdicts = compute_vpathdicts(th, vmu, True)
93
+ for u, val in perm_dict.items():
94
+ vpathsums = {u: {(1, 2): val}}
95
+ for index in range(thL):
96
+ mx_th = 0
97
+ for vp in vpathdicts[index]:
98
+ for v2, vdiff, s in vpathdicts[index][vp]:
99
+ if th[index] - vdiff > mx_th:
100
+ mx_th = th[index] - vdiff
101
+ newpathsums = {}
102
+ for up in vpathsums:
103
+ newperms = elem_sym_perms_q_op(up, mx_th, th[index], n)
104
+ for up2, udiff, mul_val in newperms:
105
+ if up2 not in newpathsums:
106
+ newpathsums[up2] = {}
107
+ for v in vpathdicts[index]:
108
+ sumval = vpathsums[up].get(v, 0) * mul_val
109
+ if sumval == 0:
110
+ continue
111
+ for v2, vdiff, s in vpathdicts[index][v]:
112
+ newpathsums[up2][v2] = newpathsums[up2].get(
113
+ v2, 0
114
+ ) + s * sumval * elem_sym_func_q(
115
+ th[index],
116
+ index + 1,
117
+ up2,
118
+ up,
119
+ v,
120
+ v2,
121
+ udiff,
122
+ vdiff,
123
+ var2,
124
+ var3,
125
+ )
126
+ vpathsums = newpathsums
127
+ toget = tuple(vmu)
128
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget, 0) for ep in vpathsums}, ret_dict)
129
+ return ret_dict
130
+
131
+
132
+ def elem_sym_func_q_q(k, i, u1, u2, v1, v2, udiff, vdiff, varl1, varl2, q_var=q_var):
133
+ newk = k - udiff
134
+ if newk < vdiff:
135
+ return 0
136
+ if newk == vdiff:
137
+ return 1
138
+ yvars = []
139
+ mlen = max(len(u1), len(u2))
140
+ u1 = [*u1] + [a + 1 for a in range(len(u1), mlen)]
141
+ u2 = [*u2] + [a + 1 for a in range(len(u2), mlen)]
142
+ for j in range(min(len(u1), k)):
143
+ if u1[j] == u2[j]:
144
+ yvars += [varl1[u2[j]]]
145
+ for j in range(len(u1), min(k, len(u2))):
146
+ if u2[j] == j + 1:
147
+ yvars += [varl1[u2[j]]]
148
+ for j in range(len(u2), k):
149
+ yvars += [varl1[j + 1]]
150
+ zvars = [varl2[a] for a in call_zvars(v1, v2, k, i)]
151
+ return elem_sym_poly_q(newk - vdiff, newk, yvars, zvars, q_var)
152
+
153
+
154
+ def schubpoly_quantum(v, var_x=var_x, var_y=var2, q_var=q_var, coeff=1):
155
+ th = strict_theta(inverse(v))
156
+ mu = permtrim(uncode(th))
157
+ vmu = permtrim(mulperm([*v], mu))
158
+ if len(th) == 0:
159
+ return coeff
160
+ while th[-1] == 0:
161
+ th.pop()
162
+ vpathdicts = compute_vpathdicts(th, vmu)
163
+ vpathsums = {(1, 2): {(1, 2): coeff}}
164
+ inv_mu = inv(mu)
165
+ inv_vmu = inv(vmu)
166
+ inv_u = 0
167
+ ret_dict = {}
168
+ for index in range(len(th)):
169
+ mx_th = 0
170
+ for vp in vpathdicts[index]:
171
+ for v2, vdiff, s in vpathdicts[index][vp]:
172
+ if th[index] - vdiff > mx_th:
173
+ mx_th = th[index] - vdiff
174
+ newpathsums = {}
175
+ for up in vpathsums:
176
+ inv_up = inv(up)
177
+ newperms = elem_sym_perms_q(
178
+ up, min(mx_th, (inv_mu - (inv_up - inv_u)) - inv_vmu), th[index], q_var
179
+ )
180
+ for up2, udiff, mul_val in newperms:
181
+ if up2 not in newpathsums:
182
+ newpathsums[up2] = {}
183
+ for v in vpathdicts[index]:
184
+ sumval = vpathsums[up].get(v, 0) * mul_val
185
+ if sumval == 0:
186
+ continue
187
+ for v2, vdiff, s in vpathdicts[index][v]:
188
+ newpathsums[up2][v2] = newpathsums[up2].get(
189
+ v2, 0
190
+ ) + s * sumval * elem_sym_func_q_q(
191
+ th[index],
192
+ index + 1,
193
+ up,
194
+ up2,
195
+ v,
196
+ v2,
197
+ udiff,
198
+ vdiff,
199
+ var_x,
200
+ var_y,
201
+ q_var,
202
+ )
203
+ vpathsums = newpathsums
204
+ toget = tuple(vmu)
205
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget, 0) for ep in vpathsums}, ret_dict)
206
+ return ret_dict[(1, 2)]
207
+
208
+
209
+ def schubmult(perm_dict, v, var2=var2, var3=var3, q_var=q_var):
210
+ if v == (1, 2):
211
+ return perm_dict
212
+ th = strict_theta(inverse(v))
213
+ mu = permtrim(uncode(th))
214
+ vmu = permtrim(mulperm([*v], mu))
215
+ inv_vmu = inv(vmu)
216
+ inv_mu = inv(mu)
217
+ ret_dict = {}
218
+ if len(th) == 0:
219
+ return perm_dict
220
+ while th[-1] == 0:
221
+ th.pop()
222
+ thL = len(th)
223
+ vpathdicts = compute_vpathdicts(th, vmu, True)
224
+ for u, val in perm_dict.items():
225
+ inv_u = inv(u)
226
+ vpathsums = {u: {(1, 2): val}}
227
+ for index in range(thL):
228
+ mx_th = 0
229
+ for vp in vpathdicts[index]:
230
+ for v2, vdiff, s in vpathdicts[index][vp]:
231
+ if th[index] - vdiff > mx_th:
232
+ mx_th = th[index] - vdiff
233
+ newpathsums = {}
234
+ for up in vpathsums:
235
+ inv_up = inv(up)
236
+ newperms = elem_sym_perms_q(
237
+ up,
238
+ min(mx_th, (inv_mu - (inv_up - inv_u)) - inv_vmu),
239
+ th[index],
240
+ q_var,
241
+ )
242
+ for up2, udiff, mul_val in newperms:
243
+ if up2 not in newpathsums:
244
+ newpathsums[up2] = {}
245
+ for v in vpathdicts[index]:
246
+ sumval = vpathsums[up].get(v, 0) * mul_val
247
+ if sumval == 0:
248
+ continue
249
+ for v2, vdiff, s in vpathdicts[index][v]:
250
+ newpathsums[up2][v2] = newpathsums[up2].get(
251
+ v2, 0
252
+ ) + s * sumval * elem_sym_func_q(
253
+ th[index],
254
+ index + 1,
255
+ up,
256
+ up2,
257
+ v,
258
+ v2,
259
+ udiff,
260
+ vdiff,
261
+ var2,
262
+ var3,
263
+ )
264
+ vpathsums = newpathsums
265
+ toget = tuple(vmu)
266
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget, 0) for ep in vpathsums}, ret_dict)
267
+ return ret_dict
268
+
269
+
270
+ def schubmult_db(perm_dict, v, var2=var2, var3=var3, q_var=q_var):
271
+ if v == (1, 2):
272
+ return perm_dict
273
+ th = medium_theta(inverse(v))
274
+ if len(th) == 0:
275
+ return perm_dict
276
+ while th[-1] == 0:
277
+ th.pop()
278
+ mu = permtrim(uncode(th))
279
+ vmu = permtrim(mulperm([*v], mu))
280
+ inv_vmu = inv(vmu)
281
+ inv_mu = inv(mu)
282
+ ret_dict = {}
283
+
284
+ thL = len(th)
285
+ vpathdicts = compute_vpathdicts(th, vmu, True)
286
+ for u, val in perm_dict.items():
287
+ inv_u = inv(u)
288
+ vpathsums = {u: {(1, 2): val}}
289
+ for index in range(thL):
290
+ if index > 0 and th[index - 1] == th[index]:
291
+ continue
292
+ mx_th = 0
293
+ for vp in vpathdicts[index]:
294
+ for v2, vdiff, s in vpathdicts[index][vp]:
295
+ if th[index] - vdiff > mx_th:
296
+ mx_th = th[index] - vdiff
297
+ if index < len(th) - 1 and th[index] == th[index + 1]:
298
+ mx_th1 = 0
299
+ for vp in vpathdicts[index + 1]:
300
+ for v2, vdiff, s in vpathdicts[index + 1][vp]:
301
+ if th[index + 1] - vdiff > mx_th1:
302
+ mx_th1 = th[index + 1] - vdiff
303
+ newpathsums = {}
304
+ for up in vpathsums:
305
+ newpathsums0 = {}
306
+ inv_up = inv(up)
307
+ newperms = double_elem_sym_q(up, mx_th, mx_th1, th[index], q_var)
308
+ for v in vpathdicts[index]:
309
+ sumval = vpathsums[up].get(v, 0)
310
+ if sumval == 0:
311
+ continue
312
+ for v2, vdiff2, s2 in vpathdicts[index][v]:
313
+ for up1, udiff1, mul_val1 in newperms:
314
+ esim1 = (
315
+ elem_sym_func_q(
316
+ th[index],
317
+ index + 1,
318
+ up,
319
+ up1,
320
+ v,
321
+ v2,
322
+ udiff1,
323
+ vdiff2,
324
+ var2,
325
+ var3,
326
+ )
327
+ * mul_val1
328
+ * s2
329
+ )
330
+ mulfac = sumval * esim1
331
+ if (up1, udiff1, mul_val1) not in newpathsums0:
332
+ newpathsums0[(up1, udiff1, mul_val1)] = {}
333
+ # newpathsums0[(up1, udiff1, mul_val1
334
+ newpathsums0[(up1, udiff1, mul_val1)][v2] = (
335
+ newpathsums0[(up1, udiff1, mul_val1)].get(v2, 0) + mulfac
336
+ )
337
+
338
+ for up1, udiff1, mul_val1 in newpathsums0:
339
+ for v in vpathdicts[index + 1]:
340
+ sumval = newpathsums0[(up1, udiff1, mul_val1)].get(v, 0)
341
+ if sumval == 0:
342
+ continue
343
+ for v2, vdiff2, s2 in vpathdicts[index + 1][v]:
344
+ for up2, udiff2, mul_val2 in newperms[(up1, udiff1, mul_val1)]:
345
+ esim1 = (
346
+ elem_sym_func_q(
347
+ th[index + 1],
348
+ index + 2,
349
+ up1,
350
+ up2,
351
+ v,
352
+ v2,
353
+ udiff2,
354
+ vdiff2,
355
+ var2,
356
+ var3,
357
+ )
358
+ * mul_val2
359
+ * s2
360
+ )
361
+ mulfac = sumval * esim1
362
+ if up2 not in newpathsums:
363
+ newpathsums[up2] = {}
364
+ newpathsums[up2][v2] = newpathsums[up2].get(v2, 0) + mulfac
365
+ else:
366
+ newpathsums = {}
367
+ for up in vpathsums:
368
+ inv_up = inv(up)
369
+ newperms = elem_sym_perms_q(
370
+ up,
371
+ min(mx_th, (inv_mu - (inv_up - inv_u)) - inv_vmu),
372
+ th[index],
373
+ q_var,
374
+ )
375
+ for up2, udiff, mul_val in newperms:
376
+ if up2 not in newpathsums:
377
+ newpathsums[up2] = {}
378
+ for v in vpathdicts[index]:
379
+ sumval = vpathsums[up].get(v, 0) * mul_val
380
+ if sumval == 0:
381
+ continue
382
+ for v2, vdiff, s in vpathdicts[index][v]:
383
+ newpathsums[up2][v2] = newpathsums[up2].get(
384
+ v2, 0
385
+ ) + s * sumval * elem_sym_func_q(
386
+ th[index],
387
+ index + 1,
388
+ up,
389
+ up2,
390
+ v,
391
+ v2,
392
+ udiff,
393
+ vdiff,
394
+ var2,
395
+ var3,
396
+ )
397
+ vpathsums = newpathsums
398
+ toget = tuple(vmu)
399
+ ret_dict = add_perm_dict({ep: vpathsums[ep].get(toget, 0) for ep in vpathsums}, ret_dict)
400
+ return ret_dict
401
+
402
+
403
+ def div_diff(v, w, var2=var2, var3=var3):
404
+ coeff_dict = {v: 1}
405
+ coeff_dict = norm_yz.schubmult_down(coeff_dict, w, var2, var3)
406
+ return coeff_dict.get((1, 2), 0)
407
+
408
+
409
+ def sum_q_dict(q_dict1, q_dict2):
410
+ ret = {**q_dict1}
411
+ for key in q_dict2:
412
+ ret[key] = ret.get(key, 0) + q_dict2[key]
413
+ return ret
414
+
415
+
416
+ def mul_q_dict(q_dict1, q_dict2):
417
+ ret = {}
418
+ for key1 in q_dict1:
419
+ for key2 in q_dict2:
420
+ key3 = key1 * key2
421
+ ret[key3] = ret.get(key3, 0) + q_dict1[key1] * q_dict2[key2]
422
+ return ret
423
+
424
+
425
+ def factor_out_q_keep_factored(poly):
426
+ ret = {}
427
+ if str(poly).find("q") == -1:
428
+ ret[1] = poly
429
+ return ret
430
+ elif poly in q_var2:
431
+ ret[poly] = 1
432
+ return ret
433
+ elif isinstance(poly, Add):
434
+ ag = poly.args
435
+ ret = factor_out_q_keep_factored(ag[0])
436
+ for i in range(1, len(ag)):
437
+ ret = sum_q_dict(ret, factor_out_q_keep_factored(ag[i]))
438
+ return ret
439
+ elif isinstance(poly, Mul):
440
+ ag = poly.args
441
+ ret = factor_out_q_keep_factored(ag[0])
442
+ for i in range(1, len(ag)):
443
+ ret = mul_q_dict(ret, factor_out_q_keep_factored(ag[i]))
444
+ return ret
445
+ elif isinstance(poly, Pow):
446
+ base = poly.args[0]
447
+ exponent = int(poly.args[1])
448
+
449
+ ret = factor_out_q_keep_factored(base)
450
+ ret0 = dict(ret)
451
+ for i in range(exponent - 1):
452
+ ret = mul_q_dict(ret, ret0)
453
+
454
+ # print(f"exponent {exponent}")
455
+ # work_val = factor_out_q_keep_factored(base)
456
+ # ret = {1: 1}
457
+ # while exponent > 0:
458
+ # if exponent % 2 == 1:
459
+ # if ret == {1: 1}:
460
+ # ret = {**work_val}
461
+ # else:
462
+ # ret = mul_q_dict(ret,work_val)
463
+ # exponent -= 1
464
+ # else:
465
+ # work_val = mul_q_dict(work_val,work_val)
466
+ # exponent //= 2
467
+ return ret
468
+ return ret
469
+
470
+
471
+ def factor_out_q(poly):
472
+ coeff_dict = expand(poly).as_coefficients_dict()
473
+ ret = {}
474
+ for key in coeff_dict:
475
+ coeff = coeff_dict[key]
476
+ if coeff == 0:
477
+ continue
478
+ q_part = 1
479
+ yz_part = coeff
480
+ if isinstance(key, Mul):
481
+ for var_maybe_pow in key.args:
482
+ if isinstance(var_maybe_pow, Pow):
483
+ real_var = var_maybe_pow.args[0]
484
+ if real_var in q_var2:
485
+ q_part *= var_maybe_pow
486
+ else:
487
+ yz_part *= var_maybe_pow
488
+ else:
489
+ real_var = var_maybe_pow
490
+ if real_var in q_var2:
491
+ q_part *= var_maybe_pow
492
+ else:
493
+ yz_part *= var_maybe_pow
494
+ elif isinstance(key, Pow):
495
+ real_var = key.args[0]
496
+ if real_var in q_var2:
497
+ q_part *= key
498
+ else:
499
+ yz_part *= key
500
+ else:
501
+ if key in q_var2:
502
+ q_part *= key
503
+ else:
504
+ yz_part *= key
505
+
506
+ ret[q_part] = ret.get(q_part, 0) + yz_part
507
+ return ret