Skip to content

Commit 661da15

Browse files
implemented Trager's integral basis algorithm
1 parent eafc27f commit 661da15

File tree

1 file changed

+73
-2
lines changed

1 file changed

+73
-2
lines changed

src/algebraic_functions.jl

Lines changed: 73 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
function HermiteReduce(f::AbstractAlgebra.ResFieldElem{P}, DE::AlgebraicExtensionDerivation) where
3-
{T<:FieldElement, P<:PolyElem{T}}
3+
{T<:FieldElement, P<:PolyElem{T}}
4+
# "Lazy" Hermite reduction, see Section 2.1 of:
5+
# Manuel Bronstein. Symbolic integration tutorial. ISSAC’98, 1998.
46
iscompatible(f, DE) || error("rational function f must be in the domain of derivation D")
57

68
E = parent(f)
@@ -10,10 +12,10 @@ function HermiteReduce(f::AbstractAlgebra.ResFieldElem{P}, DE::AlgebraicExtensio
1012
n = degree(p)
1113
M_n_n = MatrixSpace(F, n, n)
1214
M_n = MatrixSpace(F, n, 1)
13-
1415
g = zero(E)
1516

1617
if all([iszero(coeff(p, j)) for j=1:n-1]) # simple radical extension
18+
# Simpler method for simple radical extensions, see Section 2.2. of Bronstein's tutorial.
1719
@assert isone(leading_coefficient(p))
1820
a = constant_coefficient(p)
1921
A = numerator(a)
@@ -128,4 +130,73 @@ function HermiteReduce(f::AbstractAlgebra.ResFieldElem{P}, DE::AlgebraicExtensio
128130
ws = [sum([C[i,j]*ws[j] for j=1:n])*1//F for i=1:n]
129131
Winv = inv(M_n_n([coeff(data(w), j) for j=0:n-1, w in ws]))
130132
end
133+
end
134+
135+
136+
function IntegralBasis(E::AbstractAlgebra.ResField{P}) where {T<:FieldElement, P<:PolyElem{T}}
137+
# Trager's algorithm, see Chapter 2 of
138+
# B.M. Trager. On the integration of algebraic functions. PhD thesis, MIT, Computer Science, 1984.
139+
Ky = base_ring(E)
140+
K = base_ring(Ky)
141+
y = E(gen(Ky))
142+
f = modulus(E)
143+
n = degree(f)
144+
M_n_n = MatrixSpace(K, n, n)
145+
MP_n_n = MatrixSpace(base_ring(K), n, n)
146+
D = resultant(f, derivative(f))
147+
println()
148+
@assert isone(denominator(D))
149+
D = numerator(D)
150+
D = 1//leading_coefficient(D) * D
151+
k = D
152+
bs = [y^j for j=0:n-1]
153+
B = M_n_n([coeff(data(bs[j]), i) for i=0:n-1, j=1:n])
154+
while true
155+
Ds = SI.Squarefree(D)
156+
if length(Ds)<2
157+
return bs
158+
end
159+
Q = gcd(prod(SI.Squarefree(D)[2:end]), k)
160+
if degree(Q)<=0
161+
return bs
162+
end
163+
164+
# Compute J, the Q-trace radical of V
165+
ZE = zero(E)
166+
S = [p<=q ? bs[p]*bs[q] : ZE for p=1:n, q=1:n] # only upper triangle needed
167+
ZK = zero(K)
168+
# TODO: optimize computation of TM, which is one of the bottlenecks.
169+
# Compute only upper triangle of TM, lower triangle by symmetry:
170+
TM = [p<=q ? numerator(sum([coeff(data(S[p,q]*y^j), j) for j=0:n-1])) : ZK for p=1:n, q=1:n]
171+
for p=1:n
172+
for q=1:p-1
173+
TM[p,q]=TM[q,p]
174+
end
175+
end
176+
H = hnf(vcat(MP_n_n(TM), MP_n_n(Q)))[1:n,:] # Hermite normal form
177+
J = inv(map(x->x//1, H)) # map(x->x/1, H) is H as element in FractionField
178+
179+
# Compute the idealizer of J
180+
JB = J*B
181+
ms = [E(Ky(reshape(Matrix(JB[:,k]), n))) for k=1:n]
182+
Minv = inv(M_n_n([coeff(data(m), i) for i=0:n-1, m in ms]))
183+
MM = 0
184+
for k=1:n
185+
mbs = [data(ms[k]*b) for b in bs]
186+
Mk = Minv*M_n_n([coeff(mbs[j], i) for i=0:n-1, j=1:n])
187+
MM = k==1 ? Mk : vcat(MM, Mk)
188+
end
189+
Mhat = hnf(map(x->numerator(x), MM))[1:n,:] # Hermite normal form
190+
Mhatinv = inv(map(x->x//1, Mhat))
191+
k = det(Mhat)
192+
193+
if degree(k)<=0 # is k a unit ?
194+
return bs
195+
end
196+
197+
#Update bs by applying the change of basis
198+
B = transpose(Mhatinv)*B
199+
bs = [E(Ky(reshape(Matrix(B[:,k]), n))) for k=1:n]
200+
D = divexact(D, k^2)
201+
end
131202
end

0 commit comments

Comments
 (0)