passagemath-brial 10.6.39__cp314-cp314t-manylinux_2_24_x86_64.manylinux_2_28_x86_64.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.6.39.dist-info/METADATA +97 -0
  3. passagemath_brial-10.6.39.dist-info/RECORD +39 -0
  4. passagemath_brial-10.6.39.dist-info/WHEEL +6 -0
  5. passagemath_brial-10.6.39.dist-info/top_level.txt +3 -0
  6. passagemath_brial.libs/libbrial-c4edc49f.so.3.0.7 +0 -0
  7. passagemath_brial.libs/libbrial_groebner-630cf042.so.3.0.7 +0 -0
  8. passagemath_brial.libs/libgmp-6e109695.so.10.5.0 +0 -0
  9. passagemath_brial.libs/libm4ri-9da2b874.so.1.0.0 +0 -0
  10. passagemath_brial.libs/libpng16-b4a91cd1.so.16.43.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 +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-314t-x86_64-linux-gnu.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,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)