-
Notifications
You must be signed in to change notification settings - Fork 177
Expand file tree
/
Copy pathMPolyRing.jl
More file actions
290 lines (247 loc) · 8.76 KB
/
MPolyRing.jl
File metadata and controls
290 lines (247 loc) · 8.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
# Since coeff_map is at the third position, we wannot use a variable
# with default argument
################################################################################
#
# Domains of type MPolyRing
#
################################################################################
################################################################################
#
# Constructos
#
################################################################################
function _check_imgs(S::NCRing, imgs)
n = length(imgs)
for i in 2:n, j in 1:(i - 1)
@req imgs[i] * imgs[j] == imgs[j] * imgs[i] "Images $i and $j do not commute"
end
return nothing
end
# no check for commutative codomains
_check_imgs(S::Ring, imgs) = nothing
@doc raw"""
hom(R::MPolyRing, S::NCRing, coeff_map, images::Vector; check::Bool = true)
hom(R::MPolyRing, S::NCRing, images::Vector; check::Bool = true)
Given a homomorphism `coeff_map` from `C` to `S`, where `C` is the
coefficient ring of `R`, and given a vector `images` of `nvars(R)`
elements of `S`, return the homomorphism `R` $\to$ `S` whose restriction
to `C` is `coeff_map`, and which sends the `i`-th variable of `R` to the
`i`-th entry of `images`.
If no coefficient map is entered, invoke a canonical homomorphism of `C`
to `S`, if such a homomorphism exists, and throw an error, otherwise.
!!! note
In case `check = true` (default), the function checks the conditions below:
- If `S` is graded, the assigned images must be homogeneous with respect to the given grading.
- If `S` is noncommutative, the assigned images must pairwise commute.
# Examples
```jldoctest; filter = r"\#\d+" => "#"
julia> K, a = finite_field(2, 2, "a");
julia> R, (x, y) = polynomial_ring(K, [:x, :y]);
julia> F = hom(R, R, z -> z^2, [y, x])
Ring homomorphism
from multivariate polynomial ring in 2 variables over K
to multivariate polynomial ring in 2 variables over K
defined by
x -> y
y -> x
with map on coefficients
#1
julia> F(a * y)
(a + 1)*x
julia> Qi, i = quadratic_field(-1)
(Imaginary quadratic field defined by x^2 + 1, sqrt(-1))
julia> S, (x, y) = polynomial_ring(Qi, [:x, :y]);
julia> G = hom(S, S, hom(Qi, Qi, -i), [x^2, y^2])
Ring homomorphism
from multivariate polynomial ring in 2 variables over Qi
to multivariate polynomial ring in 2 variables over Qi
defined by
x -> x^2
y -> y^2
with map on coefficients
Map: Qi -> Qi
julia> G(x+i*y)
x^2 - sqrt(-1)*y^2
julia> R, (x, y) = polynomial_ring(ZZ, [:x, :y]);
julia> f = 3*x^2+2*x+1;
julia> S, (x, y) = polynomial_ring(GF(2), [:x, :y]);
julia> H = hom(R, S, gens(S))
Ring homomorphism
from multivariate polynomial ring in 2 variables over ZZ
to multivariate polynomial ring in 2 variables over GF(2)
defined by
x -> x
y -> y
julia> H(f)
x^2 + 1
```
"""
function hom(R::MPolyRing, S::NCRing, coeff_map, images::Vector; check::Bool = true)
n = ngens(R)
@req n == length(images) "Number of images must be $n"
# Now coerce into S or throw an error if not possible
imgs = _coerce(S, images)
@check begin
_check_imgs(S, imgs)
_check_homo(S, imgs) # defined in MPolyAnyMap.jl
end
return MPolyAnyMap(R, S, coeff_map, copy(imgs)) # copy because of #655
end
function hom(R::MPolyRing, S::NCRing, images::Vector; check::Bool = true)
n = ngens(R)
@req n == length(images) "Number of images must be $n"
# Now coerce into S or throw an error if not possible
imgs = _coerce(S, images)
@check begin
_check_imgs(S, imgs)
_check_homo(S, imgs) # defined in MPolyAnyMap.jl
end
return MPolyAnyMap(R, S, nothing, copy(imgs)) # copy because of #655
end
################################################################################
#
# Evaluation functions
#
################################################################################
# Some additional methods needed for the test in the constructor for MPolyAnyMap
_is_gen(x::MPolyQuoRingElem) = _is_gen(lift(x))
_is_gen(x::MPolyDecRingElem) = is_gen(forget_grading(x))
_is_gen(x::MPolyRingElem) = is_gen(x)
# default method; overwrite if you want this to work for your rings.
_is_gen(x::NCRingElem) = false
# In case there is a type of ring elements for which hashing is correctly implemented
# and does not throw an error, this gives the opportunity to overwrite the `allunique`
# to be used within the constructor for maps.
function _allunique(lst::Vector{T}) where {T<:MPolyRingElem}
return allunique(lst)
end
# We have a lot of rings which do/can not implement correct hashing.
# So we make the following the default.
function _allunique(lst::Vector{T}) where {T<:RingElem}
return all(!(x in lst[i+1:end]) for (i, x) in enumerate(lst))
end
function _allunique(lst::Vector{T}) where {T<:MPolyQuoRingElem}
rep_list = lift.(lst)
return _allunique(rep_list)
end
function _build_poly(u::MPolyRingElem, indices::Vector{Int}, S::MPolyRing)
kk = coefficient_ring(S)
r = ngens(S)
ctx = MPolyBuildCtx(S)
for (c, e) in zip(AbstractAlgebra.coefficients(u), AbstractAlgebra.exponent_vectors(u))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[indices[i]] = k
end
push_term!(ctx, kk(c), ee)
end
return finish(ctx)
end
function _evaluate_plain(F::MPolyAnyMap{<:MPolyRing, <:MPolyRing}, u)
fl, var_ind = _maps_variables_to_variables(F)
if fl
return _build_poly(u, var_ind, codomain(F))
end
return evaluate(u, F.img_gens)
end
function _evaluate_plain(F::MPolyAnyMap{<: MPolyRing}, u)
return evaluate(u, F.img_gens)
end
# See the comment in MPolyQuo.jl
function _evaluate_plain(F::MPolyAnyMap{<:MPolyRing, <:MPolyQuoRing}, u)
A = codomain(F)
R = base_ring(A)
fl, var_ind = _maps_variables_to_variables(F)
if fl
return A(_build_poly(u, var_ind, R))
end
v = evaluate(lift(u), lift.(_images(F)))
return simplify(A(v))
end
# The following assumes `p` to be in `S[x₁,…,xₙ]` where `S` is the
# actual codomain of the map.
function _evaluate_with_build_ctx(
p::MPolyRingElem, ind::Vector{Int}, cod_ring::MPolyRing
)
@assert cod_ring === coefficient_ring(parent(p))
r = ngens(cod_ring)
kk = coefficient_ring(cod_ring)
ctx = MPolyBuildCtx(cod_ring)
for (q, e) in zip(AbstractAlgebra.coefficients(p), AbstractAlgebra.exponent_vectors(p))
ee = [0 for _ in 1:r]
for (i, k) in enumerate(e)
ee[ind[i]] = k
end
for (c, d) in zip(AbstractAlgebra.coefficients(q), AbstractAlgebra.exponent_vectors(q))
push_term!(ctx, kk(c), ee+d)
end
end
return finish(ctx)
end
function _evaluate_general(F::MPolyAnyMap{<:MPolyRing, <:MPolyRing}, u)
if domain(F) === codomain(F) && coefficient_map(F) === nothing
return evaluate(map_coefficients(coefficient_map(F), u,
parent = domain(F)), F.img_gens)
else
S = temp_ring(F)
fl, var_ind = _maps_variables_to_variables(F)
if S !== nothing
if !fl || coefficient_ring(S) !== codomain(F)
return evaluate(map_coefficients(coefficient_map(F), u,
parent = S), F.img_gens)
else
tmp_poly = map_coefficients(coefficient_map(F), u, parent = S)
return _evaluate_with_build_ctx(tmp_poly, var_ind, codomain(F))
end
else
if !fl
return evaluate(map_coefficients(coefficient_map(F), u), F.img_gens)
else
# For the case where we can recycle the method above, do so.
tmp_poly = map_coefficients(coefficient_map(F), u)
coefficient_ring(parent(tmp_poly)) === codomain(F) && return _evaluate_with_build_ctx(
tmp_poly,
var_ind,
codomain(F)
)
# Otherwise default to the standard evaluation for the time being.
return evaluate(tmp_poly, F.img_gens)
end
end
end
end
function _evaluate_general(F::MPolyAnyMap{<: MPolyRing}, u)
if domain(F) === codomain(F) && coefficient_map(F) === nothing
return evaluate(map_coefficients(coefficient_map(F), u,
parent = domain(F)), F.img_gens)
else
S = temp_ring(F)
if S !== nothing
return evaluate(map_coefficients(coefficient_map(F), u,
parent = S), F.img_gens)
else
return evaluate(map_coefficients(coefficient_map(F), u), F.img_gens)
end
end
end
# one more intermediate function
function _evaluate_help(F::MPolyAnyMap{<: MPolyRing, <: Any, Nothing}, g)
return _evaluate_plain(F, g)
end
function _evaluate_help(F::MPolyAnyMap{<: MPolyRing}, g)
return _evaluate_general(F, g)
end
function (F::MPolyAnyMap{<: MPolyRing})(g)
parent(g) === domain(F) || return F(domain(F)(g))
if g isa elem_type(domain(F))
if coefficient_map(F) === nothing
return _evaluate_plain(F, g)
else
return _evaluate_general(F, g)
end
else
gg = domain(F)(g)
@assert parent(gg) === domain(F)
return F(gg)
end
end