/
FreeModElem.jl
293 lines (238 loc) · 7.85 KB
/
FreeModElem.jl
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
291
292
293
###############################################################################
# FreeModElem constructors
###############################################################################
@doc raw"""
FreeModElem(c::SRow{T}, parent::FreeMod{T}) where T
Return the element of `F` whose coefficients with respect to the basis of
standard unit vectors of `F` are given by the entries of `c`.
"""
FreeModElem(c::SRow{T}, parent::FreeMod{T}) where T = FreeModElem{T}(c, parent)
@doc raw"""
FreeModElem(c::Vector{T}, parent::FreeMod{T}) where T
Return the element of `F` whose coefficients with respect to the basis of
standard unit vectors of `F` are given by the entries of `c`.
"""
function FreeModElem(c::Vector{T}, parent::FreeMod{T}) where T
@assert length(c) == rank(parent)
sparse_coords = sparse_row(base_ring(parent), collect(1:rank(parent)), c)
return FreeModElem{T}(sparse_coords,parent)
end
#@doc raw"""
# (F::FreeMod{T})(c::SRow{T}) where T
#
#Return the element of `F` whose coefficients with respect to the basis of
#standard unit vectors of `F` are given by the entries of `c`.
#"""
function (F::FreeMod{T})(c::SRow{T}) where T
return FreeModElem(c, F)
end
#@doc raw"""
# (F::FreeMod{T})(c::Vector{T}) where T
#
#Return the element of `F` whose coefficients with respect to the basis of
#standard unit vectors of `F` are given by the entries of `c`.
#
## Examples
#```jldoctest
#julia> R, (x,y) = polynomial_ring(QQ, ["x", "y"])
#(Multivariate Polynomial Ring in x, y over Rational Field, QQMPolyRingElem[x, y])
#
#julia> F = FreeMod(R,3)
#Free module of rank 3 over Multivariate Polynomial Ring in x, y over Rational Field
#
#julia> V = [x, zero(R), y]
#3-element Vector{QQMPolyRingElem}:
# x
# 0
# y
#
#julia> f = F(V)
#x*e[1] + y*e[3]
#```
#"""
function (F::FreeMod{T})(c::Vector{T}) where T
return FreeModElem(c, F)
end
function (F::AbstractFreeMod{T})(v::AbstractFreeModElem{T}) where T
@assert parent(v) === F
return v
end
function in(v::AbstractFreeModElem, F::AbstractFreeMod)
return parent(v) === F
end
function in(v::AbstractFreeModElem, M::SubquoModule)
return represents_element(v, M)
end
@doc raw"""
coordinates(v::AbstractFreeModElem)
Return the entries (with respect to the standard basis) of `v` as a sparse row.
# Examples
```jldoctest
julia> R, (x, y) = polynomial_ring(QQ, ["x", "y"])
(Multivariate polynomial ring in 2 variables over QQ, QQMPolyRingElem[x, y])
julia> F = FreeMod(R,3)
Free module of rank 3 over Multivariate polynomial ring in 2 variables over QQ
julia> f = x*gen(F,1)+y*gen(F,3)
x*e[1] + y*e[3]
julia> coordinates(f)
Sparse row with positions [1, 3] and values QQMPolyRingElem[x, y]
```
"""
function coordinates(v::AbstractFreeModElem)
return v.coords
end
#########################################################
@doc raw"""
repres(v::AbstractFreeModElem)
Return just `v`. This function exists for compatibility (with subquotient elements) reasons.
"""
function repres(v::AbstractFreeModElem)
return v
end
function getindex(v::AbstractFreeModElem, i::Int)
if isempty(coordinates(v))
return zero(base_ring(parent(v)))
end
return coordinates(v)[i]
end
elem_type(::Type{FreeMod{T}}) where {T} = FreeModElem{T}
parent_type(::Type{FreeModElem{T}}) where {T} = FreeMod{T}
function generator_symbols(F::FreeMod)
return F.S
end
function expressify(e::AbstractFreeModElem; context = nothing)
sum = Expr(:call, :+)
for (pos, val) in e.coords
# assuming generator_symbols(parent(e)) is an array of strings/symbols
push!(sum.args, Expr(:call, :*, expressify(val, context = context), generator_symbols(parent(e))[pos]))
end
return sum
end
@enable_all_show_via_expressify FreeModElem
@doc raw"""
Vector(e::FreeModElem)
Return the coordinates of `e` as a Vector.
"""
function Vector(e::FreeModElem)
return [e[i] for i in 1:rank(parent(e))]
end
@doc raw"""
basis(F::AbstractFreeMod)
Return the standard basis of `F`.
"""
function basis(F::AbstractFreeMod)
bas = elem_type(F)[]
for i=1:dim(F)
s = Hecke.sparse_row(base_ring(F), [(i, base_ring(F)(1))])
push!(bas, F(s))
end
return bas
end
@doc raw"""
gens(F::AbstractFreeMod)
Return the (canonical) generators of the free module `F`.
"""
gens(F::AbstractFreeMod) = basis(F)
@doc raw"""
basis(F::AbstractFreeMod, i::Int)
gen(F::AbstractFreeMod, i::Int)
Return the `i`th basis vector of `F`, that is, return the `i`th standard unit vector.
"""
function basis(F::AbstractFreeMod, i::Int)
@assert 0 < i <= ngens(F)
s = Hecke.sparse_row(base_ring(F), [(i, base_ring(F)(1))])
return F(s)
end
gen(F::AbstractFreeMod, i::Int) = basis(F,i)
@doc raw"""
base_ring(F::AbstractFreeMod)
Return the underlying ring of `F`.
"""
base_ring(F::FreeMod) = (F.R)::base_ring_type(F)
#TODO: Parent - checks everywhere!!!
# the negative of a free module element
-(a::AbstractFreeModElem) = parent(a)(-coordinates(a))
# Addition of free module elements
function +(a::AbstractFreeModElem, b::AbstractFreeModElem)
check_parent(a, b)
return parent(a)(coordinates(a)+coordinates(b))
end
# Subtraction of free module elements
function -(a::AbstractFreeModElem, b::AbstractFreeModElem)
check_parent(a,b)
return parent(a)(coordinates(a)-coordinates(b))
end
# Equality of free module elements
function (==)(a::AbstractFreeModElem, b::AbstractFreeModElem)
if parent(a) !== parent(b)
return false
end
return a.coords == b.coords
end
function hash(a::AbstractFreeModElem, h::UInt)
b = 0xaa2ba4a32dd0b431 % UInt
h = hash(typeof(a), h)
h = hash(parent(a), h)
return xor(h, b)
end
# A special method for the case where we can safely assume
# that the coordinates of elements allow hashing.
function hash(a::AbstractFreeModElem{<:MPolyRingElem{<:FieldElem}}, h::UInt)
b = 0xaa2ba4a32dd0b431 % UInt
h = hash(typeof(a), h)
h = hash(parent(a), h)
h = hash(coordinates(a), h)
return xor(h, b)
end
# Once we have a suitable implementation of an in-place version
# of simplify! for sparse vectors of quotient ring elements, we
# should probably enable the hash method below.
# function hash(a::AbstractFreeModElem{<:MPolyQuoRingElem}, h::UInt)
# simplify!(a)
# b = 0xaa2ba4a32dd0b431 % UInt
# h = hash(typeof(a), h)
# h = hash(parent(a), h)
# h = hash(coordinates(a), h)
# return xor(h, b)
# end
simplify(a::AbstractFreeModElem{<:MPolyQuoRingElem}) = parent(a)(map_entries(simplify, coordinates(a)))
function Base.deepcopy_internal(a::AbstractFreeModElem, dict::IdDict)
return parent(a)(deepcopy_internal(coordinates(a), dict))
end
# scalar multiplication with polynomials, integers
function *(a::MPolyDecRingElem, b::AbstractFreeModElem)
@req parent(a) === base_ring(parent(b)) "elements not compatible"
return parent(b)(a*coordinates(b))
end
function *(a::MPolyRingElem, b::AbstractFreeModElem)
if parent(a) !== base_ring(parent(b))
return base_ring(parent(b))(a)*b # this will throw if conversion is not possible
end
return parent(b)(a*coordinates(b))
end
function *(a::RingElem, b::AbstractFreeModElem)
if parent(a) !== base_ring(parent(b))
return base_ring(parent(b))(a)*b # this will throw if conversion is not possible
end
return parent(b)(a*coordinates(b))
end
*(a::Int, b::AbstractFreeModElem) = parent(b)(a*coordinates(b))
*(a::Integer, b::AbstractFreeModElem) = parent(b)(base_ring(parent(b))(a)*coordinates(b))
*(a::QQFieldElem, b::AbstractFreeModElem) = parent(b)(base_ring(parent(b))(a)*coordinates(b))
@doc raw"""
zero(F::AbstractFreeMod)
Return the zero element of `F`.
"""
zero(F::AbstractFreeMod) = F(sparse_row(base_ring(F), Tuple{Int, elem_type(base_ring(F))}[]))
@doc raw"""
parent(a::AbstractFreeModElem)
Return the free module where `a` lives in.
"""
parent(a::AbstractFreeModElem) = a.parent
@doc raw"""
is_zero(f::AbstractFreeModElem)
Return `true` if `f` is zero, `false` otherwise.
"""
is_zero(f::AbstractFreeModElem) = iszero(coordinates(f))
simplify!(a::FreeModElem) = a
simplify(a::FreeModElem) = a