467 lines
15 KiB
Python
467 lines
15 KiB
Python
###########################################################################
|
|
# Copyright (C) 2024 Mickaël Montessinos (mickael.montessinos@mif.vu.lt),#
|
|
# #
|
|
# Distributed under the terms of the GNU General Public License (GPL) #
|
|
# either version 3, or (at your option) any later version #
|
|
# #
|
|
# http://www.gnu.org/licenses/ #
|
|
###########################################################################
|
|
|
|
from sage.matrix.constructor import matrix
|
|
from sage.rings.infinity import Infinity
|
|
from copy import copy
|
|
from sage.misc.cachefunc import cached_function
|
|
from sage.misc.misc_c import prod
|
|
from sage.matrix.constructor import matrix
|
|
from sage.matrix.special import block_matrix, elementary_matrix,\
|
|
identity_matrix
|
|
from sage.rings.function_field.function_field_rational\
|
|
import RationalFunctionField
|
|
from sage.rings.function_field.order_rational\
|
|
import FunctionFieldMaximalOrderInfinite_rational
|
|
|
|
@cached_function
|
|
def all_infinite_places(K):
|
|
r"""
|
|
Return a list of the infinite places of K of all degrees
|
|
|
|
INPUT:
|
|
- ``K`` -- FunctionField
|
|
"""
|
|
if isinstance(K,RationalFunctionField):
|
|
return [K.gen().poles()[0]]
|
|
deg = K.degree()
|
|
return sum([K.places_infinite(degree = deg) for deg in range(1, deg + 1)],
|
|
[])
|
|
|
|
|
|
def infinite_valuation(a):
|
|
r"""
|
|
Returns the valuation -deg of an element of a rational function field
|
|
|
|
The degree method returns the "height" of the element.
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import infinite_valuation
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: infinite_valuation(x**-1 + x**-2)
|
|
1
|
|
"""
|
|
if a == 0:
|
|
return Infinity
|
|
return a.denominator().degree() - a.numerator().degree()
|
|
|
|
|
|
def infinite_mod(a,i):
|
|
r"""
|
|
Returns a mod x**-i
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import infinite_mod
|
|
sage: K.<x> = FunctionField(GF(3))
|
|
sage: infinite_mod(x**-1 + x**-3,2)
|
|
1/x
|
|
"""
|
|
x = a.parent().gen()
|
|
b = a * x**(i-1)
|
|
return x**(1-i) * (b.numerator() // b.denominator())
|
|
|
|
|
|
def infinite_integral_matrix(mat):
|
|
r"""
|
|
Return an matrix with coefficient in the infinite maximal order and its denominator.
|
|
|
|
INPUT:
|
|
|
|
- ``mat`` -- Matrix with coefficients in a rational function field K
|
|
|
|
OUTPUT:
|
|
|
|
- ``int_mat`` -- Matrix with coefficients in K.maximal_order_infinite()
|
|
- ``den`` -- Element of K.maximal_order_infinite such that mat = int_mat/den
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import infinite_integral_matrix
|
|
sage: F.<x> = FunctionField(GF(11))
|
|
sage: mat = matrix([[x, 1], [x**-1, 2]])
|
|
sage: infinite_integral_matrix(mat)
|
|
(
|
|
[ 1 1/x]
|
|
[1/x^2 2/x], 1/x
|
|
)
|
|
"""
|
|
K = mat[0,0].parent()
|
|
if isinstance(K,FunctionFieldMaximalOrderInfinite_rational):
|
|
return mat,1
|
|
if not isinstance(K,RationalFunctionField):
|
|
raise ValueError('mat must have coefficients in a rational function'
|
|
+ 'field or its infinite maximal order')
|
|
x = K.gen()
|
|
R = K.maximal_order_infinite()
|
|
den = x**min([infinite_valuation(e) for e in mat.list()])
|
|
int_mat = matrix(R,mat.nrows(),mat.ncols(),(den*mat).list())
|
|
return int_mat, den
|
|
|
|
|
|
def infinite_hermite_form(mat,include_zero_cols=True,transformation=False):
|
|
r"""
|
|
Return the hermite form of a matrix with coefficient in a rational infinite maximal order.
|
|
|
|
EXAMPLE:
|
|
|
|
sage: from vector_bundle.function_field_utility import infinite_hermite_form
|
|
sage: K.<x> = FunctionField(GF(3))
|
|
sage: R = K.maximal_order_infinite()
|
|
sage: mat = matrix(R,[[1, x**-1, x**-2, (x**3+1) / x**3], [(2*x+2) / (x**3+2), x**-2, (x**2+2) / (x**4+1), 1]])
|
|
sage: H,T = infinite_hermite_form(mat,transformation=True); H
|
|
[0 0 1 0]
|
|
[0 0 0 1]
|
|
sage: mat*T == H
|
|
True
|
|
|
|
TESTS:
|
|
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: R = F.maximal_order_infinite()
|
|
sage: mat = matrix(R,[[x**-1, 0, 2, 1], [0, x**-1, 1, 1], [0, 0, 1, 0], [0, 0, 0, 1]])
|
|
sage: infinite_hermite_form(mat) == mat
|
|
True
|
|
"""
|
|
R = mat.base_ring()
|
|
if not isinstance(R,FunctionFieldMaximalOrderInfinite_rational):
|
|
raise ValueError('mat must have base ring a rational infinite maximal'
|
|
+ ' order.')
|
|
n = mat.nrows()
|
|
r = mat.ncols()
|
|
x = R.function_field().gen()
|
|
H = copy(mat)
|
|
T = identity_matrix(R,r)
|
|
#First, make mat upper triangular with diagonal coefficient of the form
|
|
#x**-k.
|
|
for i in range(1,n+1):
|
|
degs = [infinite_valuation(H[-i,j]) for j in range(r+1-i)]
|
|
d0 = min(degs)
|
|
j0 = degs.index(d0)
|
|
E = elementary_matrix(R,r,row1=j0,row2=r-i)
|
|
T *= E
|
|
H *= E
|
|
E = elementary_matrix(R,r,row1=r-i,scale=(x**d0 * H[-i,-i])**-1)
|
|
T *= E
|
|
H *= E
|
|
for j in range(r-i):
|
|
E = elementary_matrix(R,r,row1=r-i,row2=j,scale=-H[-i,j]/H[-i,-i])
|
|
T *= E
|
|
H *= E
|
|
for i in range(2,n+1):
|
|
d = infinite_valuation(H[-i,-i])
|
|
for j in range(1,i):
|
|
E = elementary_matrix(
|
|
R,r,row1=r-i,row2=r-j,
|
|
scale=(infinite_mod(H[-i,-j],d)-H[-i,-j])/H[-i,-i])
|
|
T *= E
|
|
H *= E
|
|
if not include_zero_cols:
|
|
H = H[:,r-n:]
|
|
if transformation:
|
|
return H,T
|
|
return H
|
|
|
|
|
|
def infinite_ideal_hnf(I,transformation=False):
|
|
r"""
|
|
Return the Hermite form of an ideal of the infinite maximal order.
|
|
"""
|
|
O = I.ring()
|
|
K = O.function_field()
|
|
x = K.gen()
|
|
F = K.base_field()
|
|
R = F.maximal_order_infinite()
|
|
n = K.degree()
|
|
order_basis = O.basis()
|
|
order_matrix = matrix(R,[gen.list() for gen in O.basis()]).transpose()
|
|
ideal_basis = I.gens_over_base();
|
|
ideal_matrix = order_matrix**-1 * matrix(F,[gen.list()
|
|
for gen in ideal_basis]).transpose()
|
|
mat,den = infinite_integral_matrix(ideal_matrix)
|
|
#This is awkward but if transformation is False, hnf,U = ().hermite_form()
|
|
#will unpack the matrix.
|
|
if transformation:
|
|
hnf,U = infinite_hermite_form(mat, transformation=True)
|
|
return hnf/den,U
|
|
hnf = infinite_hermite_form(mat)
|
|
return hnf/den
|
|
|
|
def infinite_order_xgcd(ideals):
|
|
r"""
|
|
Performs the extended gcd algorithm for ideals in the infinite order.
|
|
|
|
INPUT:
|
|
|
|
- ``ideals`` -- list of ideals over the infinite maximal order of a function field
|
|
|
|
OUTPUT:
|
|
|
|
- ``coeffs`` --- list of elements of the function field such that as[i] in ideals[i] and sum(as) = 1
|
|
|
|
ALGORITHM:
|
|
|
|
Proposition 1.3.7 from [Coh00]
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import infinite_order_xgcd
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: R.<y> = F[]
|
|
sage: K.<y> = F.extension(y**2 - x**-5 - 1)
|
|
sage: primes = [p.prime_ideal() for p in K.places_infinite()]; len(primes)
|
|
2
|
|
sage: a = infinite_order_xgcd(primes); a
|
|
[2*y + 2, y + 2]
|
|
sage: sum(a)
|
|
1
|
|
sage: all([a[i] in primes[i] for i in range(2)])
|
|
True
|
|
"""
|
|
order_basis = ideals[0].ring().basis()
|
|
if order_basis[0] != 1:
|
|
raise ValueError('The first element of the basis of the order should'
|
|
+ ' be 1.')
|
|
n = len(order_basis)
|
|
k = len(ideals)
|
|
y = ideals[0].ring().function_field().gen()
|
|
ideals_hnf = [infinite_ideal_hnf(I) for I in ideals]
|
|
ideals_bases = [[sum([order_basis[i]*mat[i,j] for i in range(n)])
|
|
for j in range(n)]
|
|
for mat in ideals_hnf]
|
|
C = block_matrix([ideals_hnf])
|
|
C, den = infinite_integral_matrix(C)
|
|
H,U = infinite_hermite_form(C, include_zero_cols=False, transformation=True)
|
|
if not (H/den).is_one():
|
|
raise ValueError("The ideals should be coprime.")
|
|
v = U[:,-n].list()
|
|
return [sum([ideals_bases[i][j]*v[n*i+j] for j in range(n)]) for i in range(k)]
|
|
|
|
|
|
def infinite_approximation(places,valuations,residues):
|
|
r"""
|
|
Return a in the function field of places such that
|
|
(a - residues[i]) has valuation at least valuations[i] at places[i].
|
|
|
|
INPUT:
|
|
|
|
- ``places`` -- list of FunctionFieldPlace. Infinite places only.
|
|
- ``valuations`` -- list of integers of same length as places.
|
|
- ``residues`` -- list of elements of the function field.
|
|
|
|
ALGORITHM:
|
|
|
|
Proposition 1.3.11 from [Coh00]
|
|
"""
|
|
if len(places) == 1:
|
|
return residues[0]
|
|
valuations = [max(0,val) for val in valuations]
|
|
primes = [place.prime_ideal() for place in places]
|
|
I = prod([prime**(val+1) for prime, val in zip(primes, valuations)])
|
|
ideals = [I * prime**(-val-1)
|
|
for prime, val in zip(primes, valuations)]
|
|
coefficients = infinite_order_xgcd(ideals)
|
|
return sum([c * res for c,res in zip(coefficients,residues)])
|
|
|
|
|
|
@cached_function
|
|
def safe_uniformizer(K):
|
|
r"""
|
|
Return a safe uniformizer and an infinite place of self._function_field
|
|
A uniformizer is safe if its valuation at other infinite places is 0.
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import safe_uniformizer
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: R.<y> = F[]
|
|
sage: K.<y> = F.extension(y^2 - x**-5 - 1)
|
|
sage: places = K.places_infinite()
|
|
sage: pi, place = safe_uniformizer(K); pi
|
|
((2*x + 1)/x)*y + (2*x + 2)/x
|
|
sage: place == places[0]
|
|
True
|
|
sage: pi.valuation(place)
|
|
1
|
|
sage: pi.valuation(places[1])
|
|
0
|
|
|
|
TESTS:
|
|
|
|
sage: from vector_bundle.function_field_utility import all_infinite_places
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: R.<y> = F[]
|
|
sage: K.<y> = F.extension(y^2 + x + 2)
|
|
sage: places = K.places_infinite()
|
|
sage: pi, place = safe_uniformizer(K); pi
|
|
1/x*y
|
|
sage: place == places[0]
|
|
True
|
|
sage: pi.valuation(place)
|
|
1
|
|
sage: R.<y> = F[]
|
|
sage: K.<y> = F.extension(y^4 + (2*x^2 + 2)/x^2)
|
|
sage: pi, _ = safe_uniformizer(K)
|
|
sage: [pi.valuation(place) for place in all_infinite_places(K)]
|
|
[1, 0, 0]
|
|
sage: safe_uniformizer(F)
|
|
(1/x, Place (1/x))
|
|
"""
|
|
places = all_infinite_places(K)
|
|
n = len(places)
|
|
return (infinite_approximation(
|
|
places,
|
|
[2] + ([1]*(n-1)),
|
|
[places[0].local_uniformizer()] + ([1]*(n-1))),
|
|
places[0])
|
|
|
|
def local_expansion(place,pi,f):
|
|
r"""
|
|
Return a function giving the i-th coefficient of the expansion of f.
|
|
|
|
This uses code from sage.rings.function_field.maps.FunctionFieldCompletion.
|
|
While somewhat redundant, it adds the possibility to chose the uniformizer
|
|
with respect to which the expansion is computed.
|
|
|
|
INPUT:
|
|
|
|
- ``place`` -- FunctionFieldPlace; the place at which to expand
|
|
- ``pi`` -- The uniformizer giving variable for the power series
|
|
- ``f`` -- The function to expand
|
|
|
|
OUTPUT:
|
|
|
|
- a function taking as input an integer i and returning the coefficient of degree i
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import local_expansion
|
|
sage: from vector_bundle.function_field_utility import safe_uniformizer
|
|
sage: F.<x> = FunctionField(GF(3))
|
|
sage: R.<y> = F[]
|
|
sage: K.<y> = F.extension(y^2 - x**-5 - 1)
|
|
sage: pi, place = safe_uniformizer(K)
|
|
sage: f = 1 / (1-pi)
|
|
sage: exp = local_expansion(place, pi, f)
|
|
sage: all([exp(i) == 1 for i in range(20)])
|
|
True
|
|
"""
|
|
if f == 0:
|
|
return lambda i : 0
|
|
K = place.function_field()
|
|
der = K.higher_derivation()
|
|
k, _, to_k = place.residue_field()
|
|
val = f.valuation(place)
|
|
e = f * pi**(-val)
|
|
return lambda i : to_k(der._derive(e, i - val, pi)) if i >= val else 0
|
|
|
|
def residue(place,pi,f):
|
|
r"""
|
|
Return the residue of constant répartition f at place with respect
|
|
to local uniformizer pi.
|
|
"""
|
|
if pi.valuation(place) != 1:
|
|
raise ValueError('pi must be a local uniformizer at place')
|
|
k, _, _ = place.residue_field()
|
|
kc = place.function_field().constant_base_field()
|
|
exp = local_expansion(place,pi,f)
|
|
high_res = exp(-1)
|
|
return k.over(kc)(high_res).trace()
|
|
|
|
|
|
def invert_trace(field,base,target):
|
|
r"""
|
|
Find an element of trace 1 over base in field.
|
|
|
|
EXAMPLES:
|
|
sage: from vector_bundle.function_field_utility import invert_trace
|
|
sage: base = GF(9)
|
|
sage: field = GF(9**3)
|
|
sage: a = invert_trace(field, base, 1); a
|
|
2*z6^4 + 2*z6^3 + z6 + 1
|
|
sage: field.over(base)(a).trace()
|
|
1
|
|
"""
|
|
if field == base:
|
|
if target not in field:
|
|
raise ValueError('Since field = base, target should be an element'
|
|
+ ' of field')
|
|
return target
|
|
as_ext = field.over(base)
|
|
d = as_ext.degree(base)
|
|
t = as_ext.gen()
|
|
i = [(t**j).trace() != 0 for j in range(d)].index(True)
|
|
return field(target * t**i/((t**i).trace()))
|
|
|
|
def insert_row(mat,i,row):
|
|
r"""
|
|
Return matrix mat with row inserted in ith position.
|
|
|
|
EXAMPLES:
|
|
sage: from vector_bundle.function_field_utility import insert_row
|
|
sage: mat = matrix(GF(3), 2, 2, [1, 2, 2, 1])
|
|
sage: insert_row(mat, 1, [0, 1])
|
|
[1 2]
|
|
[0 1]
|
|
[2 1]
|
|
"""
|
|
return matrix([mat[j] for j in range(i)]
|
|
+ [row]
|
|
+ [mat[j] for j in range(i,mat.nrows())])
|
|
|
|
|
|
def norm(v):
|
|
r"""
|
|
Return the norm of vector v: the maximal degree of its coefficients.
|
|
|
|
Input:
|
|
|
|
- v -- vector with coefficients in a RationalFunctionField
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import norm
|
|
sage: R.<x> = GF(3)[]
|
|
sage: v = vector([x^3 + 3 + 1, x^2])
|
|
sage: norm(v)
|
|
3
|
|
"""
|
|
return max([c.degree() for c in v.list()])
|
|
|
|
def smallest_norm_first(mat,i = 0,norms=[]):
|
|
r"""
|
|
Swap rows of M so that the i-th row has smaller norm than rows below.
|
|
|
|
INPUT:
|
|
|
|
``mat`` -- matrix with coefficients in a RationalFunctionField
|
|
``i`` -- integer (default: `0`)
|
|
|
|
EXAMPLES:
|
|
|
|
sage: from vector_bundle.function_field_utility import smallest_norm_first
|
|
sage: R.<x> = GF(3)[]
|
|
sage: mat = matrix([[1, 1], [x^2, x^3], [1, x]])
|
|
sage: smallest_norm_first(mat, 1)
|
|
[0, 1, 3]
|
|
sage: mat
|
|
[ 1 1]
|
|
[ 1 x]
|
|
[x^2 x^3]
|
|
"""
|
|
if norms == []:
|
|
norms = [norm(row) for row in mat]
|
|
j = norms[i:].index(min(norms[i:]))
|
|
mat.swap_rows(i,i+j)
|
|
n = norms[i]
|
|
norms[i] = norms[j+i]
|
|
norms[j+i] = n
|
|
return norms
|