-
Notifications
You must be signed in to change notification settings - Fork 113
/
nmod-localizations.jl
167 lines (131 loc) · 6.71 KB
/
nmod-localizations.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
#################################################################
# Localizations of residue rings ℤ/nℤ #
#################################################################
using Oscar
import Oscar.Nemo.zzModRing
import Oscar: base_ring, inverted_set, ambient_ring, Localization, parent, numerator, denominator, one, zero
import Oscar.AbstractAlgebra: elem_type, parent_type
export NmodComplementOfPrimeIdeal, NmodLocalizedRing, NmodLocalizedRingElem
export generator, ambient_ring, Localization, parent, numerator, denominator
#######################################################################
# Types of multiplicatively closed sets in ℤ/nℤ #
#######################################################################
@doc raw"""
NmodComplementOfPrimeIdeal <: AbsMultSet{zzModRing, zzModRingElem}
Complement of a prime ideal in a quotient ring `ℤ/nℤ`.
"""
mutable struct NmodComplementOfPrimeIdeal <: AbsMultSet{zzModRing, zzModRingElem}
R::zzModRing # the ambient ring
gen::zzModRingElem # a generator of the prime ideal
function NmodComplementOfPrimeIdeal(gen::zzModRingElem)
R = parent(gen)
n = ZZ(modulus(R))
a = lift(gen)
r = gcd(n, a)
is_prime(r) || error("the given element does not generate a prime ideal")
return new{}(R, R(r))
end
end
### required functionality
function Base.in(b::zzModRingElem, S::NmodComplementOfPrimeIdeal)
return mod(lift(b), lift(generator(S))) != zero(b)
end
### required getter functions
ambient_ring(S::NmodComplementOfPrimeIdeal) = S.R
### additional constructors
NmodComplementOfPrimeIdeal(R::zzModRing, i::Oscar.IntegerUnion) = NmodComplementOfPrimeIdeal(R(i))
### additional functionality
generator(S::NmodComplementOfPrimeIdeal) = S.gen
Base.in(b::Oscar.IntegerUnion, S::NmodComplementOfPrimeIdeal) = (ambient_ring(S)(b) in S)
#######################################################################
# Localizations of ℤ/nℤ #
#######################################################################
@doc raw"""
NmodLocalizedRing{MultSetType <: AbsMultSet{zzModRing, zzModRingElem}} <: AbsLocalizedRing{zzModRing, zzModRingElem, MultSetType}
Localization of a ring `ℤ/nℤ` at a multiplicatively closed set of type `MultSetType`.
"""
mutable struct NmodLocalizedRing{MultSetType <: AbsMultSet{zzModRing, zzModRingElem}} <: AbsLocalizedRing{zzModRing, zzModRingElem, MultSetType}
R::zzModRing # the original ring before localization
S::MultSetType # the set at which has been localized
function NmodLocalizedRing(S::MultSetType) where {MultSetType <: AbsMultSet{zzModRing, zzModRingElem}}
return new{MultSetType}(ambient_ring(S), S)
end
end
### required getter functions
base_ring(W::NmodLocalizedRing) = W.R::zzModRing
inverted_set(W::NmodLocalizedRing{MultSetType}) where {MultSetType} = W.S::MultSetType
### required extension of the localization function
function Localization(S::NmodComplementOfPrimeIdeal)
L = NmodLocalizedRing(S)
return L, MapFromFunc(x->(L(x)), base_ring(L), L)
end
#######################################################################
# Elements in localizations of ℤ/nℤ #
#######################################################################
@doc raw"""
NmodLocalizedRingElem{MultSetType} <: AbsLocalizedRingElem{zzModRing, zzModRingElem, MultSetType}
Elements of localizations of quotient rings `ℤ/nℤ` at a
multiplicatively closed set of type `MultSetType`.
"""
mutable struct NmodLocalizedRingElem{MultSetType} <: AbsLocalizedRingElem{zzModRing, zzModRingElem, MultSetType}
numerator::zzModRingElem
denominator::zzModRingElem
W::NmodLocalizedRing{MultSetType} # the parent ring
function NmodLocalizedRingElem(W::NmodLocalizedRing{MultSetType}, a::zzModRingElem, b::zzModRingElem) where {MultSetType}
base_ring(W) == parent(a) == parent(b) || error("elements do not belong to the original ring")
b in inverted_set(W) || error("the given denominator is not an admissible unit in this ring")
return new{MultSetType}(a, b, W)
end
end
### required getter functions
parent(f::NmodLocalizedRingElem) = f.W
numerator(f::NmodLocalizedRingElem) = f.numerator
denominator(f::NmodLocalizedRingElem) = f.denominator
### required conversions
(W::NmodLocalizedRing)(a::zzModRingElem, b::zzModRingElem) = NmodLocalizedRingElem(W, a, b)
(W::NmodLocalizedRing)(a::zzModRingElem) = NmodLocalizedRingElem(W, a, one(parent(a)))
### required implementation of the arithmetic
Base.:(//)(a::Oscar.IntegerUnion, b::NmodLocalizedRingElem) = ((parent(b)(a))//b)
function Base.:(//)(a::T, b::T) where {T<:NmodLocalizedRingElem}
parent(a) == parent(b) || error("the arguments do not belong to the same ring")
g = gcd(numerator(a), numerator(b))
c = divexact(numerator(b), g)
c in inverted_set(parent(b)) || error("the second argument is not a unit in this local ring")
return reduce_fraction((parent(a))(divexact(numerator(a),g)*denominator(b), c*denominator(a)))
end
### additional conversions
(W::NmodLocalizedRing)(a::T, b::T) where {T<:Oscar.IntegerUnion} = W(base_ring(W)(a), base_ring(W)(b))
(W::NmodLocalizedRing)(a::Oscar.IntegerUnion) = W(base_ring(W)(a), one(base_ring(W)))
(W::NmodLocalizedRing)(q::QQFieldElem) = W(numerator(q), denominator(q))
(W::NmodLocalizedRing)(i::Int64) = W(base_ring(W)(i), one(base_ring(W)))
(W::NmodLocalizedRing)(q::Rational{T}) where {T<:Oscar.IntegerUnion} = W(numerator(q), denominator(q))
### implementation of Oscar's general ring interface
one(W::NmodLocalizedRing) = W(1)
zero(W::NmodLocalizedRing) = W(0)
elem_type(W::NmodLocalizedRing{MultSetType}) where {MultSetType} = NmodLocalizedRingElem{MultSetType}
elem_type(T::Type{NmodLocalizedRing{MultSetType}}) where {MultSetType} = NmodLocalizedRingElem{MultSetType}
parent_type(W::NmodLocalizedRingElem{MultSetType}) where {MultSetType} = NmodLocalizedRing{MultSetType}
parent_type(T::Type{NmodLocalizedRingElem{MultSetType}}) where {MultSetType} = NmodLocalizedRing{MultSetType}
########################################################################
# The actual tests for the above implementation #
########################################################################
@testset "zzModRingElem-localizations" begin
R, p = quo(ZZ, 101*13)
U = NmodComplementOfPrimeIdeal(R(13))
@test !(13^5 in U)
@test !(13*4289729837 in U)
@test 5783790198374098 in U
@test ambient_ring(U) == R
W, _ = Localization(U)
@test base_ring(W) == ambient_ring(U)
@test inverted_set(W) == U
a = W(4, 17)
b = W(4*17)
b = b//W(19)
@test a//b == W(19//17^2)
@test a - b == W( 4//17 - 4*17//19 )
@test a + b == W( 4//17 + 4*17//19 )
@test a * b == W( 4//17 * 4*17//19 )
b = W(13//19)
@test b//b == one(W)
end