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.
Files changed (25) hide show
  1. {schubmult-1.2.11 → schubmult-1.3.0}/PKG-INFO +5 -3
  2. {schubmult-1.2.11 → schubmult-1.3.0}/README.md +4 -2
  3. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/perm_lib.py +46 -0
  4. schubmult-1.3.0/schubmult/schubmult_q/__init__.py +2 -0
  5. schubmult-1.3.0/schubmult/schubmult_q/__main__.py +5 -0
  6. schubmult-1.3.0/schubmult/schubmult_q/schubmult_q.py +105 -0
  7. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/schubmult_yz.py +165 -9
  8. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/PKG-INFO +5 -3
  9. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/SOURCES.txt +3 -0
  10. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/entry_points.txt +1 -0
  11. {schubmult-1.2.11 → schubmult-1.3.0}/setup.py +3 -2
  12. {schubmult-1.2.11 → schubmult-1.3.0}/LICENSE +0 -0
  13. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/__init__.py +0 -0
  14. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/__init__.py +0 -0
  15. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/__main__.py +0 -0
  16. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_double/schubmult_double.py +0 -0
  17. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/__init__.py +0 -0
  18. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/__main__.py +0 -0
  19. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_py/schubmult_py.py +0 -0
  20. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/__init__.py +0 -0
  21. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult/schubmult_yz/__main__.py +0 -0
  22. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/dependency_links.txt +0 -0
  23. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/requires.txt +0 -0
  24. {schubmult-1.2.11 → schubmult-1.3.0}/schubmult.egg-info/top_level.txt +0 -0
  25. {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.2.11
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, schubmult_py -coprod allows you to split Schubert polynomials along certain indices. 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).
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, schubmult_py -coprod allows you to split Schubert polynomials along certain indices. 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).
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,2 @@
1
+ from .schubmult_q import schubmult
2
+
@@ -0,0 +1,5 @@
1
+ import sys
2
+ from .schubmult_q import main
3
+
4
+ if __name__ == "__main__":
5
+ sys.exit(main())
@@ -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
- @cached(cache={}, key=lambda val, u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True: hashkey(u2,v2,w2,var2,var3,msg,do_pos_neg))
740
- def posify(val,u2,v2,w2,var2=var2,var3=var3,msg=False,do_pos_neg=True):
741
- if inv(u2)+inv(v2) - inv(w2)<=1:
742
- return expand(val)
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
- val2 = compute_positive_rep(val,var2,var3,msg,do_pos_neg)
1069
- if val2 is not None:
1070
- val = val2
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.2.11
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, schubmult_py -coprod allows you to split Schubert polynomials along certain indices. 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).
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
@@ -1,5 +1,6 @@
1
1
  [console_scripts]
2
2
  schubmult_double = schubmult.schubmult_double.__main__:main
3
3
  schubmult_py = schubmult.schubmult_py.__main__:main
4
+ schubmult_q = schubmult.schubmult_q.__main__:main
4
5
  schubmult_yz = schubmult.schubmult_yz.__main__:main
5
6
 
@@ -6,7 +6,7 @@ long_description = (this_directory / "README.md").read_text()
6
6
 
7
7
  setup(
8
8
  name="schubmult",
9
- version="1.2.11",
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