schubmult 2.0.3__py3-none-any.whl → 3.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 (59) hide show
  1. schubmult/__init__.py +94 -1
  2. schubmult/perm_lib.py +233 -880
  3. schubmult/poly_lib/__init__.py +31 -0
  4. schubmult/poly_lib/poly_lib.py +244 -0
  5. schubmult/poly_lib/schub_poly.py +148 -0
  6. schubmult/poly_lib/variables.py +204 -0
  7. schubmult/rings/__init__.py +17 -0
  8. schubmult/rings/_quantum_schubert_polynomial_ring.py +788 -0
  9. schubmult/rings/_schubert_polynomial_ring.py +1006 -0
  10. schubmult/rings/_tensor_schub_ring.py +128 -0
  11. schubmult/rings/_utils.py +55 -0
  12. schubmult/{sage_integration → sage}/__init__.py +17 -15
  13. schubmult/{sage_integration → sage}/_fast_double_schubert_polynomial_ring.py +142 -220
  14. schubmult/{sage_integration → sage}/_fast_schubert_polynomial_ring.py +78 -72
  15. schubmult/sage/_indexing.py +51 -0
  16. schubmult/schub_lib/__init__.py +51 -0
  17. schubmult/{schubmult_double/_funcs.py → schub_lib/double.py} +618 -798
  18. schubmult/{schubmult_q/_funcs.py → schub_lib/quantum.py} +70 -72
  19. schubmult/schub_lib/quantum_double.py +954 -0
  20. schubmult/schub_lib/schub_lib.py +659 -0
  21. schubmult/{schubmult_py/_funcs.py → schub_lib/single.py} +58 -48
  22. schubmult/schub_lib/tests/__init__.py +0 -0
  23. schubmult/schub_lib/tests/legacy_perm_lib.py +946 -0
  24. schubmult/schub_lib/tests/test_vs_old.py +109 -0
  25. schubmult/scripts/__init__.py +0 -0
  26. schubmult/scripts/schubmult_double.py +378 -0
  27. schubmult/scripts/schubmult_py.py +84 -0
  28. schubmult/scripts/schubmult_q.py +109 -0
  29. schubmult/scripts/schubmult_q_double.py +207 -0
  30. schubmult/utils/__init__.py +0 -0
  31. schubmult/{_base_argparse.py → utils/argparse.py} +40 -11
  32. schubmult/utils/logging.py +16 -0
  33. schubmult/utils/parsing.py +20 -0
  34. schubmult/utils/perm_utils.py +135 -0
  35. schubmult/utils/test_utils.py +65 -0
  36. schubmult-3.0.0.dist-info/METADATA +1234 -0
  37. schubmult-3.0.0.dist-info/RECORD +41 -0
  38. {schubmult-2.0.3.dist-info → schubmult-3.0.0.dist-info}/WHEEL +1 -1
  39. schubmult-3.0.0.dist-info/entry_points.txt +5 -0
  40. schubmult/_tests.py +0 -9
  41. schubmult/sage_integration/_indexing.py +0 -51
  42. schubmult/schubmult_double/__init__.py +0 -22
  43. schubmult/schubmult_double/__main__.py +0 -5
  44. schubmult/schubmult_double/_script.py +0 -474
  45. schubmult/schubmult_py/__init__.py +0 -13
  46. schubmult/schubmult_py/__main__.py +0 -5
  47. schubmult/schubmult_py/_script.py +0 -96
  48. schubmult/schubmult_q/__init__.py +0 -13
  49. schubmult/schubmult_q/__main__.py +0 -5
  50. schubmult/schubmult_q/_script.py +0 -160
  51. schubmult/schubmult_q_double/__init__.py +0 -17
  52. schubmult/schubmult_q_double/__main__.py +0 -5
  53. schubmult/schubmult_q_double/_funcs.py +0 -540
  54. schubmult/schubmult_q_double/_script.py +0 -398
  55. schubmult-2.0.3.dist-info/METADATA +0 -455
  56. schubmult-2.0.3.dist-info/RECORD +0 -30
  57. schubmult-2.0.3.dist-info/entry_points.txt +0 -5
  58. {schubmult-2.0.3.dist-info → schubmult-3.0.0.dist-info}/licenses/LICENSE +0 -0
  59. {schubmult-2.0.3.dist-info → schubmult-3.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,207 @@
1
+ import sys
2
+ from functools import cached_property
3
+
4
+ import sympy
5
+ from symengine import sympify
6
+
7
+ from schubmult import (
8
+ GeneratingSet,
9
+ Permutation,
10
+ apply_peterson_woodward,
11
+ div_diff,
12
+ efficient_subs,
13
+ nil_hecke,
14
+ permtrim,
15
+ q_posify,
16
+ schubmult_q_double,
17
+ schubmult_q_double_fast,
18
+ uncode,
19
+ )
20
+ from schubmult.utils.argparse import schub_argparse
21
+
22
+
23
+ class _gvars:
24
+ @cached_property
25
+ def n(self):
26
+ return 100
27
+
28
+ # @cached_property
29
+ # def fvar(self):
30
+ # return 100
31
+
32
+ @cached_property
33
+ def var1(self):
34
+ return GeneratingSet("x")
35
+
36
+ @cached_property
37
+ def var2(self):
38
+ return GeneratingSet("y")
39
+
40
+ @cached_property
41
+ def var3(self):
42
+ return GeneratingSet("z")
43
+
44
+ @cached_property
45
+ def var_r(self):
46
+ return GeneratingSet("r")
47
+
48
+ @cached_property
49
+ def var_g1(self):
50
+ return GeneratingSet("y")
51
+
52
+ @cached_property
53
+ def var_g2(self):
54
+ return GeneratingSet("z")
55
+
56
+ @cached_property
57
+ def q_var(self):
58
+ return GeneratingSet("q")
59
+
60
+
61
+ _vars = _gvars()
62
+
63
+ q_var = _vars.q_var
64
+
65
+ zero = sympify(0)
66
+
67
+ subs_dict2 = {}
68
+ for i in range(1, 100):
69
+ sm = _vars.var2[1]
70
+ for j in range(1, i):
71
+ sm += _vars.var_r[j]
72
+ subs_dict2[_vars.var2[i]] = sm
73
+
74
+
75
+ def _display_full(coeff_dict, args, formatter, var2=_vars.var2, var3=_vars.var3): # noqa: ARG001
76
+ ascode = args.ascode
77
+ Permutation.print_as_code = ascode
78
+ coeff_perms = list(coeff_dict.keys())
79
+ coeff_perms.sort(key=lambda x: (x.inv, *x))
80
+
81
+ raw_result_dict = {}
82
+
83
+ for perm in coeff_perms:
84
+ val = coeff_dict[perm]
85
+ if val != 0:
86
+ raw_result_dict[perm] = val
87
+ if formatter:
88
+ print(f"{sympy.sstr(perm)!s} {formatter(val)}")
89
+ return raw_result_dict
90
+
91
+
92
+ def sv_posify(val):
93
+ # this has just y's, we want to rearrange
94
+ # can we do this without an optimization
95
+ val = sympify(sympy.simplify(efficient_subs(val, subs_dict2)))
96
+ bingle_dict = {}
97
+ for i in range(1, len(_vars.var_r) - 1):
98
+ bingle_dict[_vars.var_r[i]] = _vars.var2[i + 1] - _vars.var2[i] # sympy.Add(*[_vars.var2[i+1], - _vars.var2[i]],evaluate=False)
99
+ # oh bay does that bar bangled banber bet bave space buckets of cheese
100
+ # val = sympy.simplify(val)
101
+ # return efficient_subs(val, bingle_dict)
102
+ return val.xreplace(bingle_dict)
103
+
104
+
105
+ def main(argv=None):
106
+ if argv is None:
107
+ argv = sys.argv
108
+ var2 = _vars.var2
109
+ var3 = _vars.var3
110
+ try:
111
+ sys.setrecursionlimit(1000000)
112
+
113
+ args, formatter = schub_argparse(
114
+ "schubmult_q_double",
115
+ "Compute coefficients of products of quantum double Schubert polynomials in the same or different sets of coefficient variables",
116
+ yz=True,
117
+ quantum=True,
118
+ argv=argv[1:],
119
+ )
120
+ subs_dict2 = {}
121
+ for i in range(1, 100):
122
+ sm = var2[1]
123
+ for j in range(1, i):
124
+ sm += _vars.var_r[j]
125
+ subs_dict2[var2[i]] = sm
126
+
127
+ mult = args.mult # noqa: F841
128
+ mulstring = args.mulstring # noqa: F841
129
+
130
+ perms = args.perms
131
+
132
+ ascode = args.ascode
133
+ msg = args.msg
134
+ display_positive = args.display_positive
135
+ pr = args.pr
136
+ parabolic_index = []
137
+ start = 0
138
+ # 1, 2 | 3
139
+ for i in range(len(args.parabolic)):
140
+ end = start + int(args.parabolic[i])
141
+ parabolic_index += list(range(start + 1, end))
142
+ # start += int(args.parabolic[i])
143
+ start = end
144
+ # [sum(int(args.parabolic[j]) for j in range(i+1)) for i in range(len(args.parabolic))]
145
+ parabolic = len(parabolic_index) != 0
146
+ slow = args.slow
147
+ nil_N = 0
148
+ nilhecke = False
149
+ nilhecke_apply = False
150
+ same = args.same
151
+ if same:
152
+ var3 = var2
153
+
154
+ if args.nilhecke is not None:
155
+ nilhecke = True
156
+ nil_N = args.nilhecke
157
+ if args.nilhecke_apply is not None:
158
+ nil_N = args.nilhecke_apply
159
+ nilhecke_apply = True
160
+
161
+ if ascode:
162
+ for i in range(len(perms)):
163
+ perms[i] = uncode(perms[i])
164
+ else:
165
+ for i in range(len(perms)):
166
+ if len(perms[i]) < 2 and (len(perms[i]) == 0 or perms[i][0] == 1):
167
+ perms[i] = Permutation([1, 2])
168
+ perms[i] = permtrim(perms[i])
169
+
170
+ if nilhecke:
171
+ coeff_dict = nil_hecke({Permutation([1, 2]): 1}, perms[0], nil_N)
172
+ elif nilhecke_apply:
173
+ coeff_dict0 = nil_hecke({Permutation([1, 2]): 1}, perms[0], nil_N, var2, var2)
174
+ coeff_dict = {Permutation([]): 0}
175
+ for v in coeff_dict0:
176
+ coeff_dict[Permutation([])] += coeff_dict0[v] * div_diff(v, perms[1], var2, var3)
177
+ else:
178
+ coeff_dict = {perms[0]: 1}
179
+ for perm in perms[1:]:
180
+ if not slow:
181
+ coeff_dict = schubmult_q_double_fast(coeff_dict, perm, var2, var3)
182
+ else:
183
+ coeff_dict = schubmult_q_double(coeff_dict, perm, var2, var3)
184
+
185
+ if parabolic:
186
+ coeff_dict = apply_peterson_woodward(coeff_dict, parabolic_index)
187
+
188
+ if display_positive and not nilhecke and not nilhecke_apply:
189
+ if same:
190
+ coeff_dict = {perm: sv_posify(val) for perm, val in coeff_dict.items()}
191
+ else:
192
+ coeff_dict = {perm: q_posify(perms[0], perms[1], perm, val, var2, var3, _vars.q_var, msg) for perm, val in coeff_dict.items()}
193
+
194
+ raw_result_dict = {}
195
+
196
+ if pr or formatter is None:
197
+ raw_result_dict = _display_full(coeff_dict, args, formatter)
198
+ if formatter is None:
199
+ return raw_result_dict
200
+ except BrokenPipeError:
201
+ pass
202
+
203
+
204
+ if __name__ == "__main__":
205
+ import sys
206
+
207
+ sys.exit(main(sys.argv))
File without changes
@@ -1,4 +1,16 @@
1
- from argparse import ArgumentParser, SUPPRESS, RawDescriptionHelpFormatter
1
+ import sys # noqa: F401
2
+ from argparse import SUPPRESS, ArgumentParser, RawDescriptionHelpFormatter
3
+
4
+ import sympy
5
+
6
+ # from sympy import Indexed, init_printing
7
+ from schubmult.utils.logging import init_logging
8
+
9
+ # Indexed._sympystr = lambda x, p: f"{p.doprint(x.args[0])}_{x.args[1]}"
10
+
11
+
12
+ def _sympy(obj):
13
+ return obj if not hasattr(obj, "_sympy_") else sympy.sympify(obj)
2
14
 
3
15
 
4
16
  def schub_argparse(prog_name, description, argv, quantum=False, yz=False):
@@ -74,7 +86,10 @@ def schub_argparse(prog_name, description, argv, quantum=False, yz=False):
74
86
  )
75
87
 
76
88
  parser.add_argument(
77
- "--down", action="store_true", default=False, help="Reverse multiplication"
89
+ "--down",
90
+ action="store_true",
91
+ default=False,
92
+ help="Reverse multiplication",
78
93
  )
79
94
 
80
95
  parser.add_argument(
@@ -160,6 +175,13 @@ def schub_argparse(prog_name, description, argv, quantum=False, yz=False):
160
175
  help=SUPPRESS,
161
176
  )
162
177
 
178
+ parser.add_argument(
179
+ "-debug",
180
+ action="store_true",
181
+ dest="debug",
182
+ help=SUPPRESS,
183
+ )
184
+
163
185
  args = parser.parse_args(argv)
164
186
  args.mulstring = ""
165
187
 
@@ -179,25 +201,32 @@ def schub_argparse(prog_name, description, argv, quantum=False, yz=False):
179
201
 
180
202
  if args.gen:
181
203
  import json
182
- import sys
183
204
 
184
205
  argv.pop(argv.index("-g"))
185
- args.__dict__["cmd_line"] = ["script"] + argv
206
+ args.__dict__["cmd_line"] = [prog_name, *argv]
186
207
  del args.__dict__["gen"]
187
- json.dump(args.__dict__, sys.stdout, ensure_ascii=False, indent=4)
208
+ cmd = " ".join(args.cmd_line)
209
+ cmd = cmd.replace("--", "").replace(" - ", "T").replace(" ", "_")
210
+ with open(f"{cmd}.json", "w") as js:
211
+ json.dump(args.__dict__, js, ensure_ascii=False, indent=1)
188
212
  exit(0)
189
213
 
190
- import sympy
214
+ sympy.init_printing()
191
215
 
192
216
  if args.disp_mode == "latex":
193
217
  formatter = ( # noqa: E731
194
- lambda bob: sympy.latex(sympy.sympify(bob)).replace("\\left", "").replace("\\right", "")
195
- ) # noqa: E731
218
+ lambda bob, width=None: sympy.latex(_sympy(bob)).replace("\\left", "").replace("\\right", "")
219
+ )
196
220
  elif args.disp_mode == "pretty":
197
- formatter = lambda bob: sympy.pretty(sympy.sympify(bob)) # noqa: E731
221
+ # pretty we need to keep centered
222
+ formatter = ( # noqa: E731
223
+ lambda bob, width=None: sympy.pretty(_sympy(bob))
224
+ if width is None
225
+ else sympy.pretty(_sympy(bob), order="rev-lex" if args.same else "none", use_unicode=False).replace("\n", "\n" + " ".join(["" for i in range(width)]))
226
+ )
198
227
  elif args.disp_mode == "basic":
199
- formatter = lambda bob: str(bob) # noqa: E731
228
+ formatter = lambda bob, width=None: sympy.sstr(_sympy(bob)) # , order="rev-lex" if args.same else "none") # noqa: E731
200
229
  elif args.disp_mode == "raw":
201
230
  formatter = None
202
-
231
+ init_logging(debug=args.debug)
203
232
  return args, formatter
@@ -0,0 +1,16 @@
1
+ import logging
2
+
3
+
4
+ def init_logging(debug=False):
5
+ if debug:
6
+ logging.basicConfig(format='%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
7
+ datefmt='%Y-%m-%d:%H:%M:%S',
8
+ level=logging.DEBUG)
9
+ else:
10
+ logging.basicConfig(format='%(asctime)s,%(msecs)03d %(levelname)-8s [%(filename)s:%(lineno)d] %(message)s',
11
+ datefmt='%Y-%m-%d:%H:%M:%S',
12
+ level=logging.ERROR)
13
+
14
+
15
+ def get_logger(name):
16
+ return logging.getLogger(name)
@@ -0,0 +1,20 @@
1
+ import symengine
2
+ from latex2sympy2_extended import latex2sympy # noqa: F401
3
+ from sympy.parsing.sympy_parser import parse_expr # noqa: F401
4
+
5
+ from schubmult.poly_lib.variables import GeneratingSet
6
+
7
+
8
+ def parse_coeff(coeff_str, latex=False):
9
+ if not latex:
10
+ result = symengine.sympify(coeff_str)
11
+ subs_dict = {}
12
+ for s in result.free_symbols:
13
+ if s.name.find("_") != -1:
14
+ base, index = s.name.split("_")
15
+ gset = GeneratingSet(base)
16
+ subs_dict[s] = gset[int(index)]
17
+ return result.subs(subs_dict)
18
+ return None
19
+
20
+
@@ -0,0 +1,135 @@
1
+ from bisect import bisect_left
2
+
3
+
4
+ def getpermval(perm, index):
5
+ if index < len(perm):
6
+ return perm[index]
7
+ return index + 1
8
+
9
+
10
+ def permtrim_list(perm):
11
+ L = len(perm)
12
+ while L > 0 and perm[-1] == L:
13
+ L = perm.pop() - 1
14
+ return perm
15
+
16
+
17
+ def has_bruhat_descent(perm, i, j):
18
+ if perm[i] < perm[j]:
19
+ return False
20
+ for p in range(i + 1, j):
21
+ if perm[i] > perm[p] and perm[p] > perm[j]:
22
+ return False
23
+ return True
24
+
25
+
26
+ def count_bruhat(perm, i, j):
27
+ up_amount = 0
28
+ if perm[i] < perm[j]:
29
+ up_amount = 1
30
+ else:
31
+ up_amount = -1
32
+ for k in range(i + 1, j):
33
+ if perm[i] < perm[k] and perm[k] < perm[j]:
34
+ up_amount += 2
35
+ elif perm[i] > perm[k] and perm[k] > perm[j]:
36
+ up_amount -= 2
37
+ return up_amount
38
+
39
+
40
+ def has_bruhat_ascent(perm, i, j):
41
+ if perm[i] > perm[j]:
42
+ return False
43
+ for p in range(i + 1, j):
44
+ if perm[i] < perm[p] and perm[p] < perm[j]:
45
+ return False
46
+ return True
47
+
48
+
49
+ def omega(i, qv):
50
+ i = i - 1
51
+ if len(qv) == 0 or i > len(qv):
52
+ return 0
53
+ if i == 0:
54
+ if len(qv) == 1:
55
+ return 2 * qv[0]
56
+ return 2 * qv[0] - qv[1]
57
+ if i == len(qv):
58
+ return -qv[-1]
59
+ if i == len(qv) - 1:
60
+ return 2 * qv[-1] - qv[-2]
61
+ return 2 * qv[i] - qv[i - 1] - qv[i + 1]
62
+
63
+
64
+ def sg(i, w):
65
+ if i >= len(w) - 1 or w[i] < w[i + 1]:
66
+ return 0
67
+ return 1
68
+
69
+
70
+ def count_less_than(arr, val):
71
+ ct = 0
72
+ i = 0
73
+ while i < len(arr) and arr[i] < val:
74
+ i += 1
75
+ ct += 1
76
+ return ct
77
+
78
+
79
+ def is_parabolic(w, parabolic_index):
80
+ for i in parabolic_index:
81
+ if sg(i - 1, w) == 1:
82
+ return False
83
+ return True
84
+
85
+
86
+ def add_perm_dict(d1, d2):
87
+ d_ret = {**d1}
88
+ for k, v in d2.items():
89
+ d_ret[k] = d_ret.get(k, 0) + v
90
+ return d_ret
91
+
92
+
93
+ def p_trans(part):
94
+ newpart = []
95
+ if len(part) == 0 or part[0] == 0:
96
+ return [0]
97
+ for i in range(1, part[0] + 1):
98
+ cnt = 0
99
+ for j in range(len(part)):
100
+ if part[j] >= i:
101
+ cnt += 1
102
+ if cnt == 0:
103
+ break
104
+ newpart += [cnt]
105
+ return newpart
106
+
107
+
108
+ def mu_A(mu, A):
109
+ mu_t = p_trans(mu)
110
+ mu_A_t = []
111
+ for i in range(len(A)):
112
+ if A[i] < len(mu_t):
113
+ mu_A_t += [mu_t[A[i]]]
114
+ return p_trans(mu_A_t)
115
+
116
+
117
+ def get_cycles(perm):
118
+ return perm.get_cycles()
119
+
120
+
121
+ def old_code(perm):
122
+ L = len(perm)
123
+ ret = []
124
+ v = list(range(1, L + 1))
125
+ for i in range(L - 1):
126
+ itr = bisect_left(v, perm[i])
127
+ ret += [itr]
128
+ v = v[:itr] + v[itr + 1 :]
129
+ return ret
130
+
131
+
132
+ def cyclic_sort(L):
133
+ m = max(L)
134
+ i = L.index(m)
135
+ return L[i + 1 :] + L[: i + 1]
@@ -0,0 +1,65 @@
1
+ import symengine
2
+
3
+
4
+ def generate_all(module, filename):
5
+ D = dir(module)
6
+ print(f"{D=}")
7
+ file_data = ""
8
+ with open(filename) as f:
9
+ file_data = str(f.read())
10
+ print(f"{file_data}")
11
+ real_d = [d for d in D if (file_data.find(f"def {d}")!=-1 or file_data.find(f"class {d}")!=-1) and d[0]!="_"]
12
+ print("from bob import (")
13
+ print(" ",end="")
14
+ print(",\n ".join(real_d))
15
+ print(",")
16
+ print(")")
17
+
18
+ print("__all__ =")
19
+ print("[")
20
+ print(" ",end="")
21
+ print("',\n '".join(real_d))
22
+ print(",")
23
+ print("]")
24
+
25
+ def get_json(file: str):
26
+ import json
27
+ import os
28
+
29
+ script_dir = os.path.dirname(__file__)
30
+ rel_path = f"../../tests/script_tests/data/{file}.json"
31
+ abs_file_path = os.path.join(script_dir, rel_path)
32
+ with open(abs_file_path) as f:
33
+ return json.load(f)
34
+
35
+
36
+ def load_json_test_names(this_dir):
37
+ import os
38
+ script_dir = os.path.dirname(__file__)
39
+ rel_path = f"../../tests/script_tests/data/{this_dir}"
40
+ abs_path = os.path.join(script_dir, rel_path)
41
+ files = os.listdir(abs_path)
42
+ ret = []
43
+ for file in files:
44
+ index = file.rfind(".json")
45
+ filename = file[:index]
46
+ ret += [filename]
47
+ return ret
48
+
49
+ def print_args(poly):
50
+ def _pr(ag):
51
+ if hasattr(ag, "__sympy__") and not ag.is_Atom:
52
+ return f"({type(ag)},{print_args(ag)})"
53
+ return str(type(ag))
54
+ return "["+",".join([_pr(arg) for arg in poly.args])+"]"
55
+
56
+ def sympify_args(poly):
57
+ try:
58
+ return symengine.sympify(poly)
59
+ except Exception:
60
+ if poly.is_Mul:
61
+ return symengine.Mul(*[sympify_args(arg) for arg in poly.args])
62
+ if poly.is_Pow:
63
+ return symengine.Pow(*[sympify_args(arg) for arg in poly.args])
64
+ if poly.is_Add:
65
+ return symengine.Add(*[sympify_args(arg) for arg in poly.args])