passagemath-brial 10.6.31rc3__cp314-cp314-macosx_13_0_arm64.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.

Potentially problematic release.


This version of passagemath-brial might be problematic. Click here for more details.

Files changed (39) hide show
  1. passagemath_brial-10.6.31rc3.dist-info/METADATA +97 -0
  2. passagemath_brial-10.6.31rc3.dist-info/RECORD +39 -0
  3. passagemath_brial-10.6.31rc3.dist-info/WHEEL +6 -0
  4. passagemath_brial-10.6.31rc3.dist-info/top_level.txt +2 -0
  5. passagemath_brial.dylibs/libbrial.3.0.7.dylib +0 -0
  6. passagemath_brial.dylibs/libbrial_groebner.3.0.7.dylib +0 -0
  7. passagemath_brial.dylibs/libgmp.10.dylib +0 -0
  8. passagemath_brial.dylibs/libm4ri.1.dylib +0 -0
  9. passagemath_brial.dylibs/libpng16.16.dylib +0 -0
  10. passagemath_brial.dylibs/libz.1.3.1.dylib +0 -0
  11. sage/all__sagemath_brial.py +9 -0
  12. sage/libs/all__sagemath_brial.py +1 -0
  13. sage/libs/polybori/__init__.pxd +2 -0
  14. sage/libs/polybori/decl.pxd +401 -0
  15. sage/libs/polybori/pb_wrap.h +133 -0
  16. sage/rings/all__sagemath_brial.py +1 -0
  17. sage/rings/polynomial/all__sagemath_brial.py +1 -0
  18. sage/rings/polynomial/pbori/PyPolyBoRi.py +123 -0
  19. sage/rings/polynomial/pbori/__init__.py +44 -0
  20. sage/rings/polynomial/pbori/blocks.py +443 -0
  21. sage/rings/polynomial/pbori/cnf.py +241 -0
  22. sage/rings/polynomial/pbori/easy_polynomials.py +56 -0
  23. sage/rings/polynomial/pbori/fglm.py +93 -0
  24. sage/rings/polynomial/pbori/frontend.py +70 -0
  25. sage/rings/polynomial/pbori/gbcore.py +634 -0
  26. sage/rings/polynomial/pbori/gbrefs.py +127 -0
  27. sage/rings/polynomial/pbori/heuristics.py +35 -0
  28. sage/rings/polynomial/pbori/interpolate.py +115 -0
  29. sage/rings/polynomial/pbori/interred.py +35 -0
  30. sage/rings/polynomial/pbori/ll.py +292 -0
  31. sage/rings/polynomial/pbori/nf.py +662 -0
  32. sage/rings/polynomial/pbori/parallel.py +298 -0
  33. sage/rings/polynomial/pbori/pbori.cpython-314-darwin.so +0 -0
  34. sage/rings/polynomial/pbori/pbori.pxd +127 -0
  35. sage/rings/polynomial/pbori/pbori.pyx +8107 -0
  36. sage/rings/polynomial/pbori/randompoly.py +105 -0
  37. sage/rings/polynomial/pbori/rank.py +27 -0
  38. sage/rings/polynomial/pbori/specialsets.py +112 -0
  39. sage/rings/polynomial/pbori/statistics.py +31 -0
@@ -0,0 +1,634 @@
1
+ # sage_setup: distribution = sagemath-brial
2
+ # sage.doctest: needs sage.rings.polynomial.pbori
3
+ import contextlib
4
+ from copy import copy
5
+ from itertools import chain
6
+ from inspect import getfullargspec as getargspec
7
+
8
+ from .nf import GeneratorLimitExceeded, symmGB_F2_C, symmGB_F2_python
9
+ from .pbori import GroebnerStrategy, ll_red_nf_redsb
10
+ from .PyPolyBoRi import (Monomial, Polynomial,
11
+ OrderCode)
12
+ from .ll import eliminate, ll_encode
13
+ from .statistics import used_vars_set
14
+ from .heuristics import dense_system, gauss_on_linear
15
+ from .easy_polynomials import easy_linear_polynomials
16
+ from .interpolate import lex_groebner_basis_for_polynomial_via_variety
17
+ from .fglm import _fglm
18
+
19
+
20
+ def get_options_from_function(f):
21
+ (argnames, varargs, varopts, defaults) = getargspec(f)[:4]
22
+ return dict(zip(argnames[-len(defaults):], defaults))
23
+
24
+
25
+ def filter_oldstyle_options(**options):
26
+ filtered = {}
27
+ for key in options:
28
+ newkey = key
29
+ for prefix in ['use_', 'opt_allow_', 'opt_']:
30
+ newkey = newkey.replace(prefix, '')
31
+ filtered[newkey] = options[key]
32
+ return filtered
33
+
34
+
35
+ def filter_newstyle_options(func, **options):
36
+ allowed = get_options_from_function(func).keys()
37
+ filtered = {}
38
+ for key in options:
39
+ for prefix in ['', 'use_', 'opt_', 'opt_allow_']:
40
+ if prefix + key in allowed:
41
+ filtered[prefix + key] = options[key]
42
+
43
+ return filtered
44
+
45
+
46
+ def want_interpolation_gb(G):
47
+ if not G or G[0].ring().get_order_code() != OrderCode.lp or len(G) != 1:
48
+ return False
49
+ p = Polynomial(G[0])
50
+ return not (p.lead_deg() <= 1 or p.set().n_nodes() > 1000)
51
+
52
+
53
+ def ll_is_good(I):
54
+ lex_lead = set()
55
+ for p in I:
56
+ if not p.is_zero():
57
+ m = p.lex_lead()
58
+ if m.deg() == 1:
59
+ lex_lead.add(next(iter(m.variables())).index())
60
+ if len(lex_lead) >= 0.8 * len(I):
61
+ uv = used_vars_set(I).deg() # don't use len here, which will yield 1
62
+ if len(lex_lead) > 0.9 * uv:
63
+ if uv - len(lex_lead) > 16:
64
+ return "llfirstonthefly"
65
+ return "llfirst"
66
+ return False
67
+
68
+
69
+ def ll_heuristic(d):
70
+ d = copy(d)
71
+ I = d["I"]
72
+ if ("llfirstonthefly" not in d) and ("llfirst" not in d):
73
+ hint = ll_is_good(I)
74
+ if hint:
75
+ d[hint] = True
76
+ return d
77
+
78
+
79
+ def change_order_heuristic(d):
80
+ d_orig = d
81
+ d = copy(d)
82
+ I = d["I"]
83
+ if not I:
84
+ return d
85
+ switch_table = {OrderCode.lp: OrderCode.dp_asc, OrderCode.dlex: OrderCode.
86
+ dp_asc}
87
+ if "other_ordering_first" not in d:
88
+ # TODO after ll situation might look much different, so heuristic is on
89
+ # wrong place
90
+ code = next(iter(I)).ring().get_order_code()
91
+ if code in switch_table:
92
+ max_non_linear = len(I) // 2
93
+ non_linear = 0
94
+ if code == OrderCode.lp:
95
+ for p in I:
96
+ if p.lead_deg() > 1:
97
+ non_linear = non_linear + 1
98
+ if non_linear > max_non_linear:
99
+ break
100
+ if (non_linear > max_non_linear) or (code != OrderCode.lp):
101
+ other_ordering_opts = copy(d_orig)
102
+ other_ordering_opts["switch_to"] = switch_table[code]
103
+ d["other_ordering_first"] = other_ordering_opts
104
+ return d
105
+
106
+
107
+ def interpolation_gb_heuristic(d):
108
+ d = copy(d)
109
+ I = d["I"]
110
+ if not d.get("other_ordering_opts", False) and want_interpolation_gb(I):
111
+ d["interpolation_gb"] = True
112
+ d["other_ordering_first"] = False
113
+ return d
114
+
115
+
116
+ def linear_algebra_heuristic(d):
117
+ d = copy(d)
118
+ I = d["I"]
119
+
120
+ def want_la():
121
+ if not I:
122
+ return False
123
+ n_used_vars = None
124
+ bound = None
125
+ if next(iter(I)).ring().has_degree_order():
126
+ new_bound = 200
127
+ n_used_vars = used_vars_set(I, bound=new_bound).deg()
128
+ if n_used_vars < new_bound:
129
+ return True
130
+ bound = new_bound
131
+ if dense_system(I):
132
+ new_bound = 100
133
+ if not (bound and new_bound < bound):
134
+ n_used_vars = used_vars_set(I, bound=new_bound).deg()
135
+ bound = new_bound
136
+ if n_used_vars < bound:
137
+ return True
138
+ return False
139
+ if not (("faugere" in d and not d["faugere"]) or
140
+ ("noro" in d and d["noro"])):
141
+ if ("faugere" in d and d["faugere"]) or want_la():
142
+
143
+ d["faugere"] = True
144
+ if "red_tail" not in d:
145
+ d["red_tail"] = False
146
+ if "selection_size" not in d:
147
+ d["selection_size"] = 10000
148
+ if "ll" not in d:
149
+ d["ll"] = True
150
+
151
+ return d
152
+
153
+
154
+ def trivial_heuristic(d):
155
+ return d
156
+
157
+
158
+ class HeuristicalFunction:
159
+ def __call__(self, *args, **kwds):
160
+ complete_dict = copy(kwds)
161
+ heuristic = True
162
+ with contextlib.suppress(KeyError):
163
+ heuristic = complete_dict["heuristic"]
164
+ for (k, v) in zip(self.argnames, args):
165
+ complete_dict[k] = v
166
+ if heuristic:
167
+ complete_dict = self.heuristicFunction(complete_dict)
168
+ return self.f(**complete_dict)
169
+
170
+ def __init__(self, f, heuristic_function):
171
+ self.argnames, self.varargs, self.varopts, self.defaults = getargspec(f)[:4]
172
+ if hasattr(f, "options"):
173
+ self.options = f.options
174
+ else:
175
+ self.options = dict(zip(self.argnames[-len(self.defaults):], self.
176
+ defaults))
177
+ self.heuristicFunction = heuristic_function
178
+ self.f = f
179
+ self.__doc__ = f.__doc__
180
+
181
+
182
+ def with_heuristic(heuristic_function):
183
+ def make_wrapper(f):
184
+ wrapped = HeuristicalFunction(f, heuristic_function)
185
+ wrapped.__name__ = f.__name__
186
+ return wrapped
187
+ return make_wrapper
188
+
189
+
190
+ def clean_polys_pre(I):
191
+ wrap = (Polynomial(p) for p in I)
192
+ return (list({p for p in wrap if not p.is_zero()}), None)
193
+
194
+
195
+ def gb_with_pre_post_option(option, pre=None,
196
+ post=None, if_not_option=(),
197
+ default=False):
198
+ def make_wrapper(f):
199
+ def wrapper(I, **kwds):
200
+ prot = kwds.get("prot", False)
201
+ for o in if_not_option:
202
+ if (o in kwds and kwds[o]) or (o not in kwds and
203
+ groebner_basis.options[o]):
204
+ option_set = False
205
+ if "option_set" not in locals():
206
+ option_set = kwds.get(option, default)
207
+ kwds = {o: kwds[o] for o in kwds if o != option}
208
+ state = None
209
+
210
+ if option_set and pre:
211
+ pre_args = getargspec(pre)[0]
212
+ if prot:
213
+ print("preprocessing for option:", option)
214
+
215
+ local_symbols = copy(locals())
216
+ (I, state) = pre(**{k: v for (k, v) in local_symbols.items()
217
+ if k in pre_args})
218
+ I = f(I, **kwds)
219
+ if option_set and post:
220
+ post_args = getargspec(post)[0]
221
+ if prot:
222
+ print("postprocessing for option:", option)
223
+ local_symbols = copy(locals())
224
+ I = post(**{k: v for (k, v) in local_symbols.items()
225
+ if k in post_args})
226
+
227
+ return I
228
+ wrapper.__name__ = f.__name__
229
+ wrapper.__doc__ = f.__doc__
230
+ if hasattr(f, "options"):
231
+ wrapper.options = copy(f.options)
232
+ else:
233
+
234
+ wrapper.options = get_options_from_function(f)
235
+
236
+ wrapper.options[option] = default
237
+ return wrapper
238
+ return make_wrapper
239
+
240
+
241
+ def redsb_post(I, state):
242
+ if not I:
243
+ return []
244
+ return I.minimalize_and_tail_reduce()
245
+
246
+
247
+ def minsb_post(I, state):
248
+ if not I:
249
+ return []
250
+ return I.minimalize()
251
+
252
+
253
+ def invert_all(I):
254
+ return [p.map_every_x_to_x_plus_one() for p in I]
255
+
256
+
257
+ def invert_all_pre(I):
258
+ return (invert_all(I), None)
259
+
260
+
261
+ def invert_all_post(I, state):
262
+ return invert_all(I)
263
+
264
+
265
+ def llfirst_pre(I, prot):
266
+ (eliminated, llnf, I) = eliminate(I, on_the_fly=False, prot=prot)
267
+ return (I, eliminated)
268
+
269
+
270
+ def ll_constants_pre(I):
271
+ ll_res = []
272
+
273
+ while any(p.lex_lead_deg() == 1 and (p + p.lex_lead()).constant()
274
+ for p in I):
275
+ I_new = []
276
+ ll = []
277
+ leads = set()
278
+ for p in I:
279
+ if p.lex_lead_deg() == 1:
280
+ l = p.lead()
281
+ if l not in leads and p.is_singleton_or_pair():
282
+ tail = p + l
283
+ if tail.deg() <= 0:
284
+ ll.append(p)
285
+ leads.add(l)
286
+ continue
287
+ I_new.append(p)
288
+ encoded = ll_encode(ll)
289
+ reduced = []
290
+ for p in I_new:
291
+ rp = ll_red_nf_redsb(p, encoded)
292
+ if not rp.is_zero():
293
+ reduced.append(rp)
294
+ I = reduced
295
+ ll_res.extend(ll)
296
+ return (I, ll_res)
297
+
298
+
299
+ def variety_size_from_gb(I):
300
+ """
301
+ TESTS::
302
+
303
+ sage: from sage.rings.polynomial.pbori import Ring, Monomial, Polynomial
304
+ sage: from sage.rings.polynomial.pbori.gbcore import variety_size_from_gb
305
+ sage: r = Ring(100)
306
+ sage: x = r.variable
307
+ sage: variety_size_from_gb([])
308
+ 1
309
+ sage: variety_size_from_gb([Polynomial(0, r)])
310
+ 1
311
+ sage: variety_size_from_gb([Polynomial(1, r)])
312
+ 0.0
313
+ sage: variety_size_from_gb([x(1)])
314
+ 1.0
315
+ sage: variety_size_from_gb([x(1), x(2)])
316
+ 1.0
317
+ sage: variety_size_from_gb([x(1), x(2)*x(3)])
318
+ 3.0
319
+ sage: variety_size_from_gb([x(1), x(1)*x(4), x(2)*x(3)])
320
+ 6.0
321
+ sage: variety_size_from_gb([x(1)*x(2), x(2)*x(3)])
322
+ 5.0
323
+ sage: mons = [Monomial([r.variable(i) for i in range(100) if i!=j])\
324
+ ....: for j in range(100)]
325
+ sage: variety_size_from_gb(mons)
326
+ 1.2676506002282294e+30
327
+ """
328
+ I = (Polynomial(p) for p in I)
329
+ I = [p for p in I if not p.is_zero()]
330
+ if not I:
331
+ return 1
332
+ # # TODO Here's something wrong! See the example with 5 solutions.
333
+ # # (reverting for now)
334
+ # number_of_used_vars = used_vars_set(I).deg()
335
+ # leads = set([p.lead() for p in I])
336
+ # minimal_leads = BooleSet(leads).minimal_elements()
337
+ # number_of_used_vars_minimal_leads =\
338
+ # minimal_leads.vars().deg()
339
+ # standard_monomials =\
340
+ # minimal_leads.include_divisors().diff(minimal_leads)
341
+ # return standard_monomials.size_double()*\
342
+ # 2**(number_of_used_vars-number_of_used_vars_minimal_leads)
343
+
344
+ sm = Monomial(used_vars_set(I)).divisors()
345
+ for p in I:
346
+ m = p.lead()
347
+ sm = sm.diff(sm.multiples_of(m))
348
+ return sm.size_double()
349
+
350
+
351
+ def other_ordering_pre(I, option_set, kwds):
352
+ """
353
+ TESTS::
354
+
355
+ sage: from sage.rings.polynomial.pbori.blocks import declare_ring
356
+ sage: r = declare_ring(['x0', 'x1', 'x2', 'x3', 'x4'], globals())
357
+ sage: id = [x1*x3 + x1 + x2*x3 + x3 + x4, x0*x3 + x0 + x1*x2 + x2 + 1, x1*x3 + x1*x4 + x3*x4 + x4 + 1, x0*x2 + x0*x4 + x1 + x3 + x4]
358
+ sage: from sage.rings.polynomial.pbori.gbcore import groebner_basis
359
+ sage: groebner_basis(id)
360
+ [1]
361
+ """
362
+ if not I:
363
+ return (I, None)
364
+
365
+ main_kwds = kwds
366
+ options = option_set
367
+
368
+ old_ring = next(iter(I)).ring()
369
+ try:
370
+ new_ring = old_ring.clone(ordering=options["switch_to"])
371
+
372
+ kwds = {k: options[k] for k in options
373
+ if k not in ("other_ordering_first", "switch_to", "I")}
374
+ kwds["redsb"] = True
375
+ I = groebner_basis([new_ring(poly) for poly in I], **kwds)
376
+ variety_size = variety_size_from_gb(I)
377
+
378
+ fglm_bound = options.get("fglm_bound") or groebner_basis.options["fglm_bound"]
379
+ if variety_size < fglm_bound:
380
+ main_kwds["convert_with_fglm_from_ring"] = new_ring
381
+ main_kwds["convert_with_fglm_to_ring"] = old_ring
382
+ else:
383
+ I = [old_ring(poly) for poly in I]
384
+ finally:
385
+ pass
386
+
387
+ return (I, None)
388
+
389
+
390
+ def llfirstonthefly_pre(I, prot):
391
+ (eliminated, llnf, I) = eliminate(I, on_the_fly=True)
392
+ return (I, eliminated)
393
+
394
+
395
+ def gauss_on_linear_pre(I, prot):
396
+ return (gauss_on_linear(I), None)
397
+
398
+
399
+ def easy_linear_polynomials_pre(I):
400
+ res = []
401
+ for p in I:
402
+ res.append(p)
403
+ res.extend(easy_linear_polynomials(p))
404
+
405
+ return (list(set(res)), None)
406
+
407
+
408
+ def llfirst_post(I, state, prot, kwds):
409
+ eliminated = state
410
+ for p in I:
411
+ if p.is_one():
412
+ return [p]
413
+
414
+ if eliminated:
415
+ I = list(chain(I, eliminated))
416
+ # redsb just for safety, as don't know how option is set
417
+ kwds = copy(kwds)
418
+ kwds.update(
419
+ {'llfirst': False,
420
+ 'llfirstonthefly': False,
421
+ 'll_constants': False,
422
+ 'deg_bound': False,
423
+ 'other_ordering_first': False,
424
+ 'eliminate_identical_variables': False, 'redsb': True})
425
+ I = groebner_basis(I, **kwds)
426
+ return I
427
+
428
+
429
+ def ll_constants_post(I, state):
430
+ eliminated = state
431
+ for p in I:
432
+ if p.is_one():
433
+ return [p]
434
+ if eliminated:
435
+ I = list(chain(I, eliminated))
436
+ # redsb just for safety, as don't know how option is set
437
+ return I
438
+
439
+
440
+ def result_to_list_post(I, state):
441
+ return list(I)
442
+
443
+
444
+ def fix_deg_bound_post(I, state):
445
+ if isinstance(I, GroebnerStrategy):
446
+ return I.all_generators()
447
+ return I
448
+
449
+
450
+ def incremental_pre(I, prot, kwds):
451
+ def sort_key(p):
452
+ p = Polynomial(p)
453
+ return (p.navigation().value(), -p.deg())
454
+ I = sorted(I, key=sort_key)
455
+ inc_sys = []
456
+ kwds = copy(kwds)
457
+ kwds['incremental'] = False
458
+
459
+ for p in I[:-1]:
460
+ inc_sys.append(p)
461
+ inc_sys = groebner_basis(inc_sys, **kwds)
462
+ if prot:
463
+ print("incrementally calculating GB, adding generator:", p)
464
+ inc_sys.append(I[:-1])
465
+ return (inc_sys, None)
466
+
467
+
468
+ def eliminate_identical_variables_pre(I, prot):
469
+ changed = True
470
+ ll_system = []
471
+ treated_linears = set()
472
+ while changed:
473
+ changed = False
474
+ rules = {}
475
+ for p in I:
476
+ t = p + p.lead()
477
+ if p.lead_deg() == 1:
478
+ l = p.lead()
479
+ if l in treated_linears:
480
+ continue
481
+ treated_linears.add(l)
482
+ if t.deg() > 0:
483
+ rules.setdefault(t, [])
484
+ leads = rules[t]
485
+ leads.append(l)
486
+
487
+ def my_sort_key(l):
488
+ return l.navigation().value()
489
+
490
+ for t, leads in rules.items():
491
+ if len(leads) > 1:
492
+ changed = True
493
+ sleads = sorted(leads, key=my_sort_key, reverse=True)
494
+ chosen = sleads[0]
495
+ ll_system.extend(chosen + v for v in sleads[1:])
496
+ if ll_system:
497
+ ll_encoded = ll_encode(ll_system, reduce=True)
498
+ I = {ll_red_nf_redsb(p, ll_encoded) for p in I}
499
+ return (I, ll_system)
500
+
501
+
502
+ @gb_with_pre_post_option("clean_arguments", pre=clean_polys_pre, default=True)
503
+ @gb_with_pre_post_option("easy_linear_polynomials",
504
+ pre=easy_linear_polynomials_pre, default=True)
505
+ @gb_with_pre_post_option("result_to_list", post=result_to_list_post,
506
+ default=True)
507
+ @with_heuristic(interpolation_gb_heuristic)
508
+ @gb_with_pre_post_option("invert", pre=invert_all_pre,
509
+ post=invert_all_post, default=False)
510
+ @gb_with_pre_post_option("gauss_on_linear", pre=gauss_on_linear_pre,
511
+ default=True)
512
+ @gb_with_pre_post_option("ll_constants", pre=ll_constants_pre,
513
+ post=ll_constants_post, default=True)
514
+ @gb_with_pre_post_option("eliminate_identical_variables",
515
+ pre=eliminate_identical_variables_pre,
516
+ post=llfirst_post, default=True)
517
+ @with_heuristic(ll_heuristic)
518
+ @gb_with_pre_post_option("llfirst", if_not_option=["llfirstonthefly"],
519
+ pre=llfirst_pre, post=llfirst_post, default=False)
520
+ @gb_with_pre_post_option("llfirstonthefly", pre=llfirstonthefly_pre,
521
+ post=llfirst_post, default=False)
522
+ @gb_with_pre_post_option("incremental", pre=incremental_pre)
523
+ @with_heuristic(change_order_heuristic)
524
+ @gb_with_pre_post_option("other_ordering_first", if_not_option=[
525
+ "interpolation_gb"], pre=other_ordering_pre, default=False)
526
+ @with_heuristic(linear_algebra_heuristic)
527
+ @gb_with_pre_post_option("fix_deg_bound", if_not_option=["interpolation_gb"],
528
+ post=fix_deg_bound_post, default=True)
529
+ @gb_with_pre_post_option("minsb", post=minsb_post,
530
+ if_not_option=["redsb", "deg_bound",
531
+ "interpolation_gb",
532
+ "convert_with_fglm_from_ring"],
533
+ default=True)
534
+ @gb_with_pre_post_option("redsb", post=redsb_post,
535
+ if_not_option=["deg_bound", "interpolation_gb",
536
+ "convert_with_fglm_from_ring"],
537
+ default=True)
538
+ def groebner_basis(I, heuristic=True, unique_ideal_generator=False,
539
+ interpolation_gb=False, clean_and_restart_algorithm=False,
540
+ convert_with_fglm_from_ring=None,
541
+ convert_with_fglm_to_ring=None,
542
+ fglm_bound=40000,
543
+ modified_linear_algebra=True, preprocessor=None,
544
+ deg_bound=False,
545
+ implementation='Python', full_prot=False, prot=False,
546
+ draw_matrices=False, preprocess_only=False, **impl_options):
547
+ """Computes a Groebner basis of a given ideal I, w.r.t options."""
548
+
549
+ if not I:
550
+ return I
551
+
552
+ if full_prot:
553
+ prot = True
554
+ if prot:
555
+ print("number of passed generators:", len(I))
556
+ if convert_with_fglm_from_ring is not None:
557
+ from_ring = convert_with_fglm_from_ring
558
+ to_ring = convert_with_fglm_to_ring
559
+ return _fglm(I, from_ring, to_ring)
560
+
561
+ if interpolation_gb:
562
+ first = next(iter(I))
563
+ if len(I) != 1 or first.ring().get_order_code() != OrderCode.lp:
564
+ raise ValueError
565
+ return lex_groebner_basis_for_polynomial_via_variety(first)
566
+ if deg_bound is False:
567
+ deg_bound = 100000000
568
+ I = [Polynomial(p) for p in I if not p.is_zero()]
569
+ if unique_ideal_generator and I:
570
+ prod = 1
571
+ for p in I:
572
+ prod = (p + 1) * prod
573
+ I = [prod + 1]
574
+
575
+ implementation = symmGB_F2_python if implementation == 'Python' else symmGB_F2_C
576
+
577
+ # custom preprocessing
578
+ if preprocessor:
579
+ I = preprocessor(I)
580
+
581
+ if preprocess_only:
582
+ for p in I:
583
+ print(p)
584
+ import sys
585
+ sys.exit(0)
586
+
587
+ def call_algorithm(I, max_generators=None):
588
+ return implementation(I,
589
+ deg_bound=deg_bound,
590
+ full_prot=full_prot,
591
+ prot=prot,
592
+ max_generators=max_generators,
593
+ draw_matrices=draw_matrices,
594
+ **filter_newstyle_options(implementation,
595
+ **impl_options))
596
+
597
+ if clean_and_restart_algorithm:
598
+ for max_generators in [1000, 10000, 50000, 100000, 200000, 300000,
599
+ 400000, None]:
600
+ try:
601
+ return call_algorithm(I, max_generators=max_generators)
602
+ except GeneratorLimitExceeded as e:
603
+ I = list(e.strat.all_generators())
604
+ del e.strat
605
+ if prot:
606
+ print("generator limit exceeded:", max_generators,
607
+ "restarting algorithm")
608
+ else:
609
+ return call_algorithm(I)
610
+
611
+
612
+ def build_groebner_basis_doc_string():
613
+ additional_options_from_buchberger = filter_oldstyle_options(
614
+ **get_options_from_function(symmGB_F2_python))
615
+ for k in list(additional_options_from_buchberger):
616
+ if k in groebner_basis.options:
617
+ del additional_options_from_buchberger[k]
618
+
619
+ gdoc = groebner_basis.__doc__
620
+ gdoc += "\nOptions are:\n"
621
+ gdoc += "\n".join(k + " : " + repr(groebner_basis.options[k])
622
+ for k in groebner_basis.options)
623
+ gdoc += """
624
+
625
+ Turn off heuristic by setting heuristic=False
626
+ Additional options come from the actual buchberger implementation.
627
+ In case of our standard Python implementation these are the following:
628
+ """
629
+ gdoc += "\n".join(k + " : " + repr(additional_options_from_buchberger[k])
630
+ for k in additional_options_from_buchberger)
631
+ groebner_basis.__doc__ = gdoc
632
+
633
+
634
+ build_groebner_basis_doc_string()