passagemath-brial 10.6.31rc3__cp314-cp314-musllinux_1_2_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.
Potentially problematic release.
This version of passagemath-brial might be problematic. Click here for more details.
- passagemath_brial-10.6.31rc3.dist-info/METADATA +97 -0
- passagemath_brial-10.6.31rc3.dist-info/RECORD +39 -0
- passagemath_brial-10.6.31rc3.dist-info/WHEEL +5 -0
- passagemath_brial-10.6.31rc3.dist-info/top_level.txt +2 -0
- passagemath_brial.libs/libbrial-83985df5.so.3.0.7 +0 -0
- passagemath_brial.libs/libbrial_groebner-a6504217.so.3.0.7 +0 -0
- passagemath_brial.libs/libgcc_s-2d945d6c.so.1 +0 -0
- passagemath_brial.libs/libm4ri-5e907cd2.so.1.0.0 +0 -0
- passagemath_brial.libs/libpng16-09496a15.so.16.43.0 +0 -0
- passagemath_brial.libs/libstdc++-85f2cd6d.so.6.0.33 +0 -0
- sage/all__sagemath_brial.py +9 -0
- sage/libs/all__sagemath_brial.py +1 -0
- sage/libs/polybori/__init__.pxd +2 -0
- sage/libs/polybori/decl.pxd +401 -0
- sage/libs/polybori/pb_wrap.h +133 -0
- sage/rings/all__sagemath_brial.py +1 -0
- sage/rings/polynomial/all__sagemath_brial.py +1 -0
- sage/rings/polynomial/pbori/PyPolyBoRi.py +123 -0
- sage/rings/polynomial/pbori/__init__.py +44 -0
- sage/rings/polynomial/pbori/blocks.py +443 -0
- sage/rings/polynomial/pbori/cnf.py +241 -0
- sage/rings/polynomial/pbori/easy_polynomials.py +56 -0
- sage/rings/polynomial/pbori/fglm.py +93 -0
- sage/rings/polynomial/pbori/frontend.py +70 -0
- sage/rings/polynomial/pbori/gbcore.py +634 -0
- sage/rings/polynomial/pbori/gbrefs.py +127 -0
- sage/rings/polynomial/pbori/heuristics.py +35 -0
- sage/rings/polynomial/pbori/interpolate.py +115 -0
- sage/rings/polynomial/pbori/interred.py +35 -0
- sage/rings/polynomial/pbori/ll.py +292 -0
- sage/rings/polynomial/pbori/nf.py +662 -0
- sage/rings/polynomial/pbori/parallel.py +298 -0
- sage/rings/polynomial/pbori/pbori.cpython-314-aarch64-linux-musl.so +0 -0
- sage/rings/polynomial/pbori/pbori.pxd +127 -0
- sage/rings/polynomial/pbori/pbori.pyx +8107 -0
- sage/rings/polynomial/pbori/randompoly.py +105 -0
- sage/rings/polynomial/pbori/rank.py +27 -0
- sage/rings/polynomial/pbori/specialsets.py +112 -0
- sage/rings/polynomial/pbori/statistics.py +31 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-brial
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
import gzip
|
|
4
|
+
from io import StringIO
|
|
5
|
+
import base64 as uu
|
|
6
|
+
import re
|
|
7
|
+
from types import ModuleType
|
|
8
|
+
from .PyPolyBoRi import Polynomial
|
|
9
|
+
AUTO = "auto"
|
|
10
|
+
SINGLE = "single"
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# def ref_file_name(f):
|
|
14
|
+
# name=re.sub("data/","",f)
|
|
15
|
+
# name=sub(r"\.py","",name)
|
|
16
|
+
# l=name.split("/")[:-1]
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def reencode_blocks(block_str):
|
|
20
|
+
return str(block_str).replace(",", "_")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def parse_blocks(block_str, data):
|
|
24
|
+
if block_str == AUTO:
|
|
25
|
+
return data.block_start_hints
|
|
26
|
+
if block_str == SINGLE:
|
|
27
|
+
return []
|
|
28
|
+
return [int(i) for i in block_str.split(",")]
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def load_ref_raw(s):
|
|
32
|
+
s = re.sub("data/", "", s)
|
|
33
|
+
s = re.sub(r"data\.", "", s)
|
|
34
|
+
s = re.sub(r"\.py", "", s)
|
|
35
|
+
s = re.sub(r"\.", "/", s)
|
|
36
|
+
|
|
37
|
+
ref_file = "ref/" + s + ".ref"
|
|
38
|
+
with open(ref_file) as res_f:
|
|
39
|
+
res = res_f.read()
|
|
40
|
+
return res
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def load_ref(s, ordering='lp', blocks=SINGLE):
|
|
44
|
+
return load_ref_gz_uu(s, ordering, blocks)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def ordering_suffix(o, blocks=None):
|
|
48
|
+
if o == "lp":
|
|
49
|
+
return ""
|
|
50
|
+
if re.match("block", o):
|
|
51
|
+
return "." + o + "_" + reencode_blocks(blocks)
|
|
52
|
+
return "." + o
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def number_of_declared_vars(data):
|
|
56
|
+
try:
|
|
57
|
+
return data.number_of_declared_vars
|
|
58
|
+
except AttributeError:
|
|
59
|
+
return data.r.ngens()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def load_ref_gz_uu(s, o, b):
|
|
63
|
+
s = re.sub("data/", "", s)
|
|
64
|
+
s = re.sub(r"data\.", "", s)
|
|
65
|
+
s = re.sub(r"\.py", "", s)
|
|
66
|
+
s = re.sub(r"\.", "/", s)
|
|
67
|
+
|
|
68
|
+
ref_file = "ref/" + s + ordering_suffix(o, b) + ".ref.gz.uu"
|
|
69
|
+
res = StringIO()
|
|
70
|
+
uu.decode(ref_file, res)
|
|
71
|
+
res = res.getvalue()
|
|
72
|
+
res = StringIO(res)
|
|
73
|
+
res = gzip.GzipFile(fileobj=res, mode='r').read()
|
|
74
|
+
res = res.replace(" ", "")
|
|
75
|
+
return res
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def convert_refs(ref_file_orig):
|
|
79
|
+
with open(ref_file_orig) as file:
|
|
80
|
+
content = file.read()
|
|
81
|
+
buf_out = StringIO()
|
|
82
|
+
zipped = gzip.GzipFile(filename=ref_file_orig, mode='w', fileobj=buf_out)
|
|
83
|
+
zipped.write(content)
|
|
84
|
+
zipped.close()
|
|
85
|
+
val = buf_out.getvalue()
|
|
86
|
+
with open(ref_file_orig + ".gz.uu", "w") as out:
|
|
87
|
+
uu.encode(out_file=out, in_file=StringIO(val))
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def dyn_generate(content, name):
|
|
91
|
+
module = ModuleType(name)
|
|
92
|
+
import_header = """from .PyPolyBoRi import Variable,Monomial, Polynomial, Ring, OrderCode
|
|
93
|
+
from itertools import chain
|
|
94
|
+
from .blocks import AlternatingBlock,Block,AdderBlock,if_then,HigherOrderBlock,declare_ring as orig_declare_ring,declare_block_scheme,MacroBlock\n
|
|
95
|
+
def declare_ring(blocks, context=None):
|
|
96
|
+
if context is None:
|
|
97
|
+
context=globals()
|
|
98
|
+
return orig_declare_ring(blocks,context)
|
|
99
|
+
"""
|
|
100
|
+
exec(import_header + content, module.__dict__)
|
|
101
|
+
if hasattr(module, "ideal"):
|
|
102
|
+
module.ideal = [Polynomial(p) for p in module.ideal]
|
|
103
|
+
return module
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def clean_data(data):
|
|
107
|
+
for a in dir(data):
|
|
108
|
+
if a != "r":
|
|
109
|
+
delattr(data, a)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def load_data(file_name, base_dir='./'):
|
|
113
|
+
in_file = file_name
|
|
114
|
+
if not re.match("^data", in_file):
|
|
115
|
+
in_file = "data/" + in_file
|
|
116
|
+
in_file = re.sub(r".py$", "", in_file)
|
|
117
|
+
in_file = re.sub(r"\.", "/", in_file)
|
|
118
|
+
in_file = in_file + ".py"
|
|
119
|
+
with open(base_dir + in_file) as f:
|
|
120
|
+
in_file = f.read()
|
|
121
|
+
return dyn_generate(in_file, "pb_data")
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def load_file(file_name):
|
|
125
|
+
with open(file_name) as f:
|
|
126
|
+
in_file = f.read()
|
|
127
|
+
return dyn_generate(in_file, "pb_data")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-brial
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
from .PyPolyBoRi import Polynomial, gauss_on_polys
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def dense_system(I):
|
|
7
|
+
I = (Polynomial(p) for p in I)
|
|
8
|
+
I = (p for p in I if not p.is_zero())
|
|
9
|
+
for p in I:
|
|
10
|
+
d = p.deg()
|
|
11
|
+
if d == 1:
|
|
12
|
+
continue
|
|
13
|
+
try:
|
|
14
|
+
if len(p) > 2**d + 5:
|
|
15
|
+
return True
|
|
16
|
+
except OverflowError:
|
|
17
|
+
return True
|
|
18
|
+
return False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def gauss_on_linear(I):
|
|
22
|
+
I = (Polynomial(p) for p in I)
|
|
23
|
+
linear = []
|
|
24
|
+
non_linear = []
|
|
25
|
+
for p in I:
|
|
26
|
+
if p.is_zero():
|
|
27
|
+
continue
|
|
28
|
+
if p.deg() <= 1:
|
|
29
|
+
linear.append(p)
|
|
30
|
+
else:
|
|
31
|
+
non_linear.append(p)
|
|
32
|
+
if not linear:
|
|
33
|
+
return non_linear
|
|
34
|
+
linear = list(gauss_on_polys(linear))
|
|
35
|
+
return linear + non_linear
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-brial
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
# Copyright (c) 2005-2007 by The PolyBoRi Team
|
|
4
|
+
from time import process_time as clock
|
|
5
|
+
from random import Random
|
|
6
|
+
|
|
7
|
+
from .PyPolyBoRi import (Polynomial, Variable, Monomial,
|
|
8
|
+
BoolePolynomialVector)
|
|
9
|
+
from .randompoly import gen_random_poly
|
|
10
|
+
from .pbori import (BooleSet, add_up_polynomials, interpolate_smallest_lex,
|
|
11
|
+
interpolate)
|
|
12
|
+
from .blocks import Block, declare_ring
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
generator = Random()
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def add_up_poly_list(l, init):
|
|
19
|
+
v = BoolePolynomialVector()
|
|
20
|
+
for p in l:
|
|
21
|
+
v.append(p)
|
|
22
|
+
return add_up_polynomials(v, init)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def bench_interpolate(degree, nvariables, points):
|
|
26
|
+
c = points
|
|
27
|
+
h = len(points) / 2
|
|
28
|
+
terms = set(c.terms())
|
|
29
|
+
part1 = generator.sample(terms, h)
|
|
30
|
+
part1 = add_up_poly_list(part1, Polynomial(c.ring().zero()))
|
|
31
|
+
part2 = c + part1
|
|
32
|
+
p = part1
|
|
33
|
+
q = part2
|
|
34
|
+
assert part1.set().intersect(part2).empty()
|
|
35
|
+
c1 = clock()
|
|
36
|
+
res2 = interpolate_smallest_lex(p, q)
|
|
37
|
+
c2 = clock()
|
|
38
|
+
print("finished interpolate_smallest_lex(p,q),len:", len(res2),
|
|
39
|
+
"time", c2 - c1)
|
|
40
|
+
c1 = clock()
|
|
41
|
+
res1 = interpolate(p, q)
|
|
42
|
+
c2 = clock()
|
|
43
|
+
print("finished interpolate(p,q)" + len("_smallest_lex") * " " + ",len:",
|
|
44
|
+
res1.set().size_double(), "time:", c2 - c1)
|
|
45
|
+
return res2
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def nf_lex_points(f, p):
|
|
49
|
+
f = Polynomial(f)
|
|
50
|
+
p = BooleSet(p)
|
|
51
|
+
z = f.zeros_in(p)
|
|
52
|
+
return interpolate_smallest_lex(z, p.diff(z))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def gen_random_o_z(points, points_p):
|
|
56
|
+
k = generator.randrange(len(points) + 1)
|
|
57
|
+
ones = generator.sample(points, k)
|
|
58
|
+
vec = BoolePolynomialVector()
|
|
59
|
+
for p in ones:
|
|
60
|
+
vec.append(p)
|
|
61
|
+
ones = add_up_polynomials(vec, Polynomial(points_p.ring().zero()))
|
|
62
|
+
return interpolate_smallest_lex(points_p.set().diff(ones), ones)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def variety_lex_leading_terms(points, variables):
|
|
66
|
+
assert isinstance(points, BooleSet), "Points needs to be a BooleSet"
|
|
67
|
+
ring = variables.ring()
|
|
68
|
+
standards = BooleSet(ring.zero())
|
|
69
|
+
points_tuple = tuple(points)
|
|
70
|
+
myvars_div = variables.divisors()
|
|
71
|
+
if points != myvars_div:
|
|
72
|
+
standards = BooleSet(ring.one())
|
|
73
|
+
len_standards = len(standards)
|
|
74
|
+
standards_old = standards
|
|
75
|
+
while len_standards < len(points):
|
|
76
|
+
standards = standards.union(gen_random_o_z(points_tuple, points))
|
|
77
|
+
|
|
78
|
+
if standards_old != standards:
|
|
79
|
+
standards = BooleSet(standards).include_divisors()
|
|
80
|
+
len_standards = len(standards)
|
|
81
|
+
standards_old = standards
|
|
82
|
+
|
|
83
|
+
return BooleSet(myvars_div.diff(standards)).minimal_elements()
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def lex_groebner_basis_points(points, variables):
|
|
87
|
+
leads = variety_lex_leading_terms(points, variables)
|
|
88
|
+
return [nf_lex_points(l, points) + l for l in leads]
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def lex_groebner_basis_for_polynomial_via_variety(p):
|
|
92
|
+
variables = p.vars_as_monomial()
|
|
93
|
+
return lex_groebner_basis_points(p.zeros_in(variables.divisors()),
|
|
94
|
+
variables)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
if __name__ == '__main__':
|
|
98
|
+
nvariables = 100
|
|
99
|
+
r = declare_ring([Block("x", nvariables)])
|
|
100
|
+
for number_of_points in (100, 500, 1000, 2000, 3000,
|
|
101
|
+
4000, 5000, 10000,
|
|
102
|
+
20000, 50000, 100000):
|
|
103
|
+
print("----------")
|
|
104
|
+
print("number_of_points:", number_of_points)
|
|
105
|
+
print("generate points")
|
|
106
|
+
points = gen_random_poly(r, number_of_points,
|
|
107
|
+
nvariables,
|
|
108
|
+
[Variable(i, r) for i in range(nvariables)])
|
|
109
|
+
print("points generated")
|
|
110
|
+
bench_interpolate(nvariables, nvariables, points)
|
|
111
|
+
vars_mon = Monomial(r)
|
|
112
|
+
for i in reversed(range(nvariables)):
|
|
113
|
+
vars_mon = vars_mon * Variable(i, r)
|
|
114
|
+
print(len(variety_lex_leading_terms(points, vars_mon)),
|
|
115
|
+
"elements in groebner basis")
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-brial
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
from .pbori import ReductionStrategy
|
|
4
|
+
from .PyPolyBoRi import Polynomial
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def interred(l, completely=False):
|
|
8
|
+
r"""
|
|
9
|
+
Compute a new generating system (g1, ...,gn),
|
|
10
|
+
spanning the same ideal modulo field equations.
|
|
11
|
+
|
|
12
|
+
The system is interreduced: For i!=j:
|
|
13
|
+
gi.lead() does not divide any leading term of gj.
|
|
14
|
+
|
|
15
|
+
If completely is set to ``True``, then also terms in the
|
|
16
|
+
tail are not reducible by other polynomials.
|
|
17
|
+
"""
|
|
18
|
+
l = [Polynomial(p) for p in l if p != 0]
|
|
19
|
+
if not l:
|
|
20
|
+
return []
|
|
21
|
+
ring = l[0].ring()
|
|
22
|
+
l_old = None
|
|
23
|
+
l = tuple(l)
|
|
24
|
+
while l_old != l:
|
|
25
|
+
l_old = l
|
|
26
|
+
l = sorted(l, key=Polynomial.lead)
|
|
27
|
+
g = ReductionStrategy(ring)
|
|
28
|
+
if completely:
|
|
29
|
+
g.opt_red_tail = True
|
|
30
|
+
for p in l:
|
|
31
|
+
gp = g.nf(p)
|
|
32
|
+
if not gp.is_zero():
|
|
33
|
+
g.add_generator(gp)
|
|
34
|
+
l = tuple(e.p for e in g)
|
|
35
|
+
return l
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# sage_setup: distribution = sagemath-brial
|
|
2
|
+
# sage.doctest: needs sage.rings.polynomial.pbori
|
|
3
|
+
from .pbori import (top_index, if_then_else,
|
|
4
|
+
substitute_variables, BooleSet,
|
|
5
|
+
ll_red_nf_redsb, ll_red_nf_noredsb,
|
|
6
|
+
ll_red_nf_noredsb_single_recursive_call)
|
|
7
|
+
from .PyPolyBoRi import (Polynomial, Monomial, Ring, BoolePolynomialVector)
|
|
8
|
+
from .statistics import used_vars_set
|
|
9
|
+
from .rank import rank
|
|
10
|
+
|
|
11
|
+
lead_index = top_index
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def combine(reductors, p, reduce=None):
|
|
15
|
+
p_nav = p.navigation()
|
|
16
|
+
assert p_nav.value() < reductors.navigation().value()
|
|
17
|
+
p_else = BooleSet(p_nav.else_branch(), p.ring())
|
|
18
|
+
if reduce:
|
|
19
|
+
p_else = reduce(p_else, reductors)
|
|
20
|
+
return if_then_else(p_nav.value(), reductors, p_else)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def llredsb_Cudd_style(polys):
|
|
24
|
+
|
|
25
|
+
reductors = Polynomial(polys[0].ring().one()).set() if polys else None
|
|
26
|
+
|
|
27
|
+
linear_lead = sorted(polys, key=lead_index, reverse=True)
|
|
28
|
+
assert len({p.lex_lead() for p in linear_lead}) == len(polys)
|
|
29
|
+
assert not any(p.constant() for p in polys)
|
|
30
|
+
assert len([p for p in polys if p.lex_lead_deg() == 1]) == len(polys)
|
|
31
|
+
assert len({p.navigation().value() for p in polys}) == len(polys)
|
|
32
|
+
for p in linear_lead:
|
|
33
|
+
reductors = combine(reductors, p, reduce=ll_red_nf_redsb)
|
|
34
|
+
return reductors
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def ll_encode(polys, reduce=False, prot=False, reduce_by_linear=True):
|
|
38
|
+
polys = [Polynomial(p) for p in polys]
|
|
39
|
+
linear_lead = sorted(polys, key=lead_index, reverse=True)
|
|
40
|
+
assert len({p.lex_lead() for p in linear_lead}) == len(polys)
|
|
41
|
+
assert not any(p.constant() for p in polys)
|
|
42
|
+
assert len([p for p in polys if p.lex_lead_deg() == 1]) == len(polys)
|
|
43
|
+
assert len({p.navigation().value() for p in polys}) == len(polys)
|
|
44
|
+
if (not reduce) and reduce_by_linear:
|
|
45
|
+
linear_polys = [p for p in polys if p.deg() == 1]
|
|
46
|
+
if linear_polys:
|
|
47
|
+
linear_ll = ll_encode(linear_polys, reduce=True,
|
|
48
|
+
reduce_by_linear=False)
|
|
49
|
+
polys = [p.lex_lead() + ll_red_nf_redsb(p + p.lex_lead(),
|
|
50
|
+
linear_ll) for p in polys]
|
|
51
|
+
reduce = ll_red_nf_redsb if reduce else None
|
|
52
|
+
|
|
53
|
+
reductors = Polynomial(polys[0].ring().one()).set() if polys else None
|
|
54
|
+
|
|
55
|
+
last = None
|
|
56
|
+
counter = 0
|
|
57
|
+
for p in linear_lead:
|
|
58
|
+
|
|
59
|
+
if prot:
|
|
60
|
+
counter = counter + 1
|
|
61
|
+
progress = (counter * 100) / len(linear_lead)
|
|
62
|
+
if last != progress:
|
|
63
|
+
print(str(progress) + "%")
|
|
64
|
+
last = progress
|
|
65
|
+
reductors = combine(reductors, p, reduce=reduce)
|
|
66
|
+
return reductors
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def eliminate(polys, on_the_fly=False, prot=False, reduction_function=None,
|
|
70
|
+
optimized=True):
|
|
71
|
+
r"""
|
|
72
|
+
There exists an optimized variant, which reorders the variable in a different ring.
|
|
73
|
+
"""
|
|
74
|
+
polys = [Polynomial(p) for p in polys]
|
|
75
|
+
rest = []
|
|
76
|
+
linear_leads = []
|
|
77
|
+
linear_leading_monomials = set()
|
|
78
|
+
for p in polys:
|
|
79
|
+
if p.is_zero():
|
|
80
|
+
continue
|
|
81
|
+
lm = p.lex_lead()
|
|
82
|
+
if lm.deg() == 1:
|
|
83
|
+
|
|
84
|
+
if lm not in linear_leading_monomials:
|
|
85
|
+
linear_leading_monomials.add(lm)
|
|
86
|
+
linear_leads.append(p)
|
|
87
|
+
else:
|
|
88
|
+
rest.append(p)
|
|
89
|
+
else:
|
|
90
|
+
rest.append(p)
|
|
91
|
+
if not linear_leads:
|
|
92
|
+
def identity(p):
|
|
93
|
+
return p
|
|
94
|
+
return (linear_leads, identity, rest)
|
|
95
|
+
if reduction_function is None:
|
|
96
|
+
if on_the_fly:
|
|
97
|
+
if optimized:
|
|
98
|
+
reduction_function = ll_red_nf_noredsb_single_recursive_call
|
|
99
|
+
else:
|
|
100
|
+
reduction_function = ll_red_nf_noredsb
|
|
101
|
+
else:
|
|
102
|
+
reduction_function = ll_red_nf_redsb
|
|
103
|
+
|
|
104
|
+
if optimized:
|
|
105
|
+
llnf, reduced_list = eliminate_ll_ranked(linear_leads, rest,
|
|
106
|
+
reduction_function=reduction_function,
|
|
107
|
+
reduce_ll_system=(not on_the_fly),
|
|
108
|
+
prot=prot)
|
|
109
|
+
else:
|
|
110
|
+
def llnf(p):
|
|
111
|
+
return reduction_function(p, reductors)
|
|
112
|
+
reduced_list = []
|
|
113
|
+
reductors = ll_encode(linear_leads, reduce=(not on_the_fly), prot=prot)
|
|
114
|
+
for p in rest:
|
|
115
|
+
rp = reduction_function(p, reductors)
|
|
116
|
+
if rp.is_one():
|
|
117
|
+
reduced_list = [rp]
|
|
118
|
+
break
|
|
119
|
+
reduced_list.append(rp)
|
|
120
|
+
|
|
121
|
+
return (linear_leads, llnf, reduced_list)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def construct_map_by_indices(to_ring, idx_mapping):
|
|
125
|
+
v = BoolePolynomialVector((max(idx_mapping.keys()) + 1) * [to_ring.zero()])
|
|
126
|
+
for (from_idx, to_idx) in idx_mapping.items():
|
|
127
|
+
val = to_ring.variable(to_idx)
|
|
128
|
+
v[from_idx] = val
|
|
129
|
+
return v
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def eliminate_ll_ranked(ll_system, to_reduce,
|
|
133
|
+
reduction_function=ll_red_nf_noredsb,
|
|
134
|
+
reduce_ll_system=False, prot=False):
|
|
135
|
+
|
|
136
|
+
assert ll_system
|
|
137
|
+
from_ring = ll_system[0].ring()
|
|
138
|
+
|
|
139
|
+
ll_ranks = rank(ll_system)
|
|
140
|
+
add_vars = set(used_vars_set(to_reduce).variables()).difference(ll_ranks.
|
|
141
|
+
keys())
|
|
142
|
+
for v in add_vars:
|
|
143
|
+
ll_ranks[v] = -1
|
|
144
|
+
|
|
145
|
+
# pushing variables ignored by ll to the front means,
|
|
146
|
+
# that the routines will quickly eliminate them
|
|
147
|
+
# and they won't give any overhead
|
|
148
|
+
def sort_key(v):
|
|
149
|
+
return (ll_ranks[v], v.index())
|
|
150
|
+
sorted_vars = sorted(ll_ranks.keys(), key=sort_key)
|
|
151
|
+
|
|
152
|
+
def var_index(v):
|
|
153
|
+
return next(iter(Monomial(v).variables())).index()
|
|
154
|
+
|
|
155
|
+
to_ring = Ring(len(sorted_vars))
|
|
156
|
+
map_back_indices = {i: var_index(v) for i, v in enumerate(sorted_vars)}
|
|
157
|
+
map_from_indices = {var_index(v): i for i, v in enumerate(sorted_vars)}
|
|
158
|
+
|
|
159
|
+
var_names = [str(v) for v in sorted_vars]
|
|
160
|
+
try:
|
|
161
|
+
for (i, v) in enumerate(sorted_vars):
|
|
162
|
+
assert var_names[i] == str(v), (var_names[i], v, var_index(v), i)
|
|
163
|
+
|
|
164
|
+
finally:
|
|
165
|
+
pass
|
|
166
|
+
try:
|
|
167
|
+
map_from_vec = construct_map_by_indices(to_ring, map_from_indices)
|
|
168
|
+
finally:
|
|
169
|
+
pass
|
|
170
|
+
map_back_vec = construct_map_by_indices(from_ring, map_back_indices)
|
|
171
|
+
|
|
172
|
+
def map_from(p):
|
|
173
|
+
res = substitute_variables(to_ring, map_from_vec, p)
|
|
174
|
+
return res
|
|
175
|
+
|
|
176
|
+
def map_back(p):
|
|
177
|
+
return substitute_variables(from_ring, map_back_vec, p)
|
|
178
|
+
|
|
179
|
+
try:
|
|
180
|
+
ll_opt_encoded = ll_encode([map_from(p) for p in ll_system],
|
|
181
|
+
prot=False,
|
|
182
|
+
reduce=reduce_ll_system)
|
|
183
|
+
|
|
184
|
+
def llnf(p):
|
|
185
|
+
return map_back(reduction_function(map_from(p), ll_opt_encoded))
|
|
186
|
+
opt_eliminated = [llnf(p) for p in to_reduce]
|
|
187
|
+
finally:
|
|
188
|
+
pass
|
|
189
|
+
return (llnf, opt_eliminated)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class RingMap:
|
|
193
|
+
r"""
|
|
194
|
+
Define a mapping between two rings by common variable names.
|
|
195
|
+
|
|
196
|
+
TESTS::
|
|
197
|
+
|
|
198
|
+
sage: from sage.rings.polynomial.pbori.pbori import *
|
|
199
|
+
sage: from sage.rings.polynomial.pbori.blocks import declare_ring, Block
|
|
200
|
+
sage: to_ring = declare_ring([Block("x", 10)], globals())
|
|
201
|
+
sage: from_ring = declare_ring([Block("y", 5), Block("x", 10)], globals())
|
|
202
|
+
sage: from sage.rings.polynomial.pbori.ll import RingMap
|
|
203
|
+
sage: mapping = RingMap(to_ring, from_ring)
|
|
204
|
+
sage: (x(1)+1).navigation().value()
|
|
205
|
+
6
|
|
206
|
+
sage: mapping(x(1)+1)
|
|
207
|
+
x(1) + 1
|
|
208
|
+
sage: mapping(x(1)+1).navigation().value()
|
|
209
|
+
1
|
|
210
|
+
sage: mapping.invert(mapping(x(1)+1))
|
|
211
|
+
x(1) + 1
|
|
212
|
+
sage: mapping.invert(mapping(x(1)+1)).navigation().value()
|
|
213
|
+
6
|
|
214
|
+
sage: mapping(y(1)+1)
|
|
215
|
+
Traceback (most recent call last):
|
|
216
|
+
...
|
|
217
|
+
RuntimeError: Operands come from different manager.
|
|
218
|
+
"""
|
|
219
|
+
|
|
220
|
+
def __init__(self, to_ring, from_ring):
|
|
221
|
+
r"""
|
|
222
|
+
Initialize map by two given rings.
|
|
223
|
+
|
|
224
|
+
TESTS::
|
|
225
|
+
|
|
226
|
+
sage: from sage.rings.polynomial.pbori.pbori import *
|
|
227
|
+
sage: from sage.rings.polynomial.pbori.blocks import declare_ring, Block
|
|
228
|
+
sage: to_ring = declare_ring([Block("x", 10)], globals())
|
|
229
|
+
sage: from_ring = declare_ring([Block("y", 5), Block("x", 10)], globals())
|
|
230
|
+
sage: from sage.rings.polynomial.pbori.ll import RingMap
|
|
231
|
+
sage: mapping = RingMap(to_ring, from_ring)
|
|
232
|
+
sage: mapping(x(1)+1)
|
|
233
|
+
x(1) + 1
|
|
234
|
+
"""
|
|
235
|
+
def vars(ring):
|
|
236
|
+
return [ring.variable(i) for i in range(ring.n_variables())]
|
|
237
|
+
|
|
238
|
+
def indices(vars):
|
|
239
|
+
return {str(v): idx for idx, v in enumerate(vars)}
|
|
240
|
+
|
|
241
|
+
self.to_ring = to_ring
|
|
242
|
+
self.from_ring = from_ring
|
|
243
|
+
to_vars = vars(to_ring)
|
|
244
|
+
from_vars = vars(from_ring)
|
|
245
|
+
to_indices = indices(to_vars)
|
|
246
|
+
from_indices = indices(from_vars)
|
|
247
|
+
common = list(set(to_indices.keys()) & set(from_indices.keys()))
|
|
248
|
+
|
|
249
|
+
to_map = list(from_vars)
|
|
250
|
+
for elt in common:
|
|
251
|
+
to_map[from_indices[elt]] = to_vars[to_indices[elt]]
|
|
252
|
+
|
|
253
|
+
from_map = list(to_vars)
|
|
254
|
+
for elt in common:
|
|
255
|
+
from_map[to_indices[elt]] = from_vars[from_indices[elt]]
|
|
256
|
+
|
|
257
|
+
self.to_map = BoolePolynomialVector(to_map)
|
|
258
|
+
self.from_map = BoolePolynomialVector(from_map)
|
|
259
|
+
|
|
260
|
+
def __call__(self, poly):
|
|
261
|
+
r"""
|
|
262
|
+
Execute the map to change rings.
|
|
263
|
+
|
|
264
|
+
TESTS::
|
|
265
|
+
|
|
266
|
+
sage: from sage.rings.polynomial.pbori.pbori import *
|
|
267
|
+
sage: from sage.rings.polynomial.pbori.blocks import declare_ring, Block
|
|
268
|
+
sage: to_ring = declare_ring([Block("x", 10)], globals())
|
|
269
|
+
sage: from_ring = declare_ring([Block("y", 5), Block("x", 10)], globals())
|
|
270
|
+
sage: from sage.rings.polynomial.pbori.ll import RingMap
|
|
271
|
+
sage: mapping = RingMap(to_ring, from_ring)
|
|
272
|
+
sage: mapping(x(1)+1)
|
|
273
|
+
x(1) + 1
|
|
274
|
+
"""
|
|
275
|
+
return substitute_variables(self.to_ring, self.to_map, poly)
|
|
276
|
+
|
|
277
|
+
def invert(self, poly):
|
|
278
|
+
r"""
|
|
279
|
+
Inverted map to initial ring.
|
|
280
|
+
|
|
281
|
+
EXAMPLES::
|
|
282
|
+
|
|
283
|
+
sage: from sage.rings.polynomial.pbori.pbori import *
|
|
284
|
+
sage: from sage.rings.polynomial.pbori.blocks import declare_ring, Block
|
|
285
|
+
sage: to_ring = declare_ring([Block("x", 10)], globals())
|
|
286
|
+
sage: from_ring = declare_ring([Block("y", 5), Block("x", 10)], globals())
|
|
287
|
+
sage: from sage.rings.polynomial.pbori.ll import RingMap
|
|
288
|
+
sage: mapping = RingMap(to_ring, from_ring)
|
|
289
|
+
sage: mapping.invert(mapping(x(1)+1))
|
|
290
|
+
x(1) + 1
|
|
291
|
+
"""
|
|
292
|
+
return substitute_variables(self.from_ring, self.from_map, poly)
|