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